Transactions using LocalIdentier

36 views
Skip to first unread message

Henrik Uffe Jensen

unread,
Jun 30, 2012, 8:14:32 PM6/30/12
to rav...@googlegroups.com
Was looking at fiddler traces for the communication between client and server, when I noticed that I had a range of commits and/or rollbacks with the same transactionid.

I can see that in GetLocalOrDistributedTransactionId you actually use transactionInformation.LocalIdentifier.Split(':').First() to get the transactionid

Which means that f.x.

94A6606E-DD5E-44FF-BD24-2B314114BC37:1
94A6606E-DD5E-44FF-BD24-2B314114BC37:2
94A6606E-DD5E-44FF-BD24-2B314114BC37:3

All become 94A6606E-DD5E-44FF-BD24-2B314114BC37 as transactionid. Also wrote a little test deleting a document in one thread but rolling back after 10 seconds, but until the rollback I could not load the document in another thread, That doesn't seem as expected behavior. When forcing same test to use distributed transactions then the transactionid is unique for each thread and I see expected behavior,


Oren Eini (Ayende Rahien)

unread,
Jul 1, 2012, 12:53:31 AM7/1/12
to rav...@googlegroups.com
Can you share the failing test?

Henrik Uffe Jensen

unread,
Jul 1, 2012, 6:28:38 AM7/1/12
to rav...@googlegroups.com

It's here. What I bascially do is

1) I have a document in Raven (of type LocationView with given id)
2) I create a task (thread) in which I delete this document but after calling SaveChanges I wait for 10 seconds and then rollback the transaction (by not completing)
3) On the main thread I wait for 5 seconds after starting the above thread and try to read the document
4) I then wait another 10 seconds and try to read the document again.

The idea is that 3) will try to read the document after SaveChanges have been called on the deletion but before the transaction (and thereby the deletion) have rolledback. 4) will try to read the document after the deletion have rolledback.

By using forceDistributedTransaction (true/false) I control if a distributed transaction should be used (in my test simply by also using MSMQ as part of the transaction but that could be other RavenDb datatabase or any other resourcemanager that forces a distributed transaction).

Test is green for me no matter If I use distributed transaction or not, but that is just because I show the actual behavior, rather than testing the expected. If not using distributed transaction then I in 3) can not
read the document (because It has been deleted by other transaction and deletion has not rolledback yet).

        [Test, Explicit]
        public void TransactionTest()
        {
            var id = new Guid("9e15c907-68da-44a0-8197-81c0ef1d88c9");
            const bool forceDistributedTransaction = true;

            var documentStore = new DocumentStore() {Url = "http://localhost:8080", EnlistInDistributedTransactions = true}.Initialize();

            // Delete location (savechanges immediately) but rollback efter sleeping 10 seconds
            var task1 = new Task(() => DeleteLocationButRollback(documentStore, id, 10000, forceDistributedTransaction), TaskCreationOptions.LongRunning);
            task1.Start();

            // Try reading location after 5 seconds (deletion have been done by above thread but transaction not committed/rolledback yet)
            Thread.Sleep(5000);
            if (forceDistributedTransaction == false)
                Assert.That(CanReadLocation(documentStore, id, forceDistributedTransaction), Is.False);
                // !!!!! This is not expected behavior. This transaction should not be effected by the
                // deletion in the other transaction, before it's committed or rolledbck.
            else
                Assert.That(CanReadLocation(documentStore, id, forceDistributedTransaction), Is.True);

            // Try reading location after 15 seconds (now deletion should have rollback)
            Thread.Sleep(10000);
            Assert.That(CanReadLocation(documentStore, id, forceDistributedTransaction), Is.True);


        }

        private bool CanReadLocation(IDocumentStore documentStore, Guid locationId, bool forceDistributedTrasaction)
        {
            using (var tx = new TransactionScope())
            {
                if (forceDistributedTrasaction) ForceDistributedTransaction();

                using (var session = documentStore.OpenSession())
                {
                    session.Advanced.AllowNonAuthoritativeInformation = false;
                    var locationView = session.Load<LocationView>(locationId);
                    return locationView != null;
                }

                tx.Complete();
            }
        }   

        private void DeleteLocationButRollback(IDocumentStore documentStore, Guid locationId, Int32 rollbackDelay, bool forceDistributedTransaction)
        {
            using (var tx = new TransactionScope())
            {
                if (forceDistributedTransaction) ForceDistributedTransaction();

                using (var session = documentStore.OpenSession())
                {
                    session.Advanced.AllowNonAuthoritativeInformation = false;
                    var locationView = session.Load<LocationView>(locationId);
                    session.Delete(locationView);
                   
                    session.SaveChanges();
                }

                Thread.Sleep(rollbackDelay);
                // We don't complete so the deletion will rollback
            }

        }
       
        /// <summary>
        /// Force using distributed transaction by sending message to messagequeue
        /// </summary>
        private void ForceDistributedTransaction()
        {
            var messageQueue = new MessageQueue(TestConfiguration.MsmqQueueNameForDomainEvents1);
            var message = new Message() {Body = "test"};
            messageQueue.Send(message, MessageQueueTransactionType.Automatic);
        }

Oren Eini (Ayende Rahien)

unread,
Jul 1, 2012, 7:12:13 AM7/1/12
to rav...@googlegroups.com
Thanks, reproduced and fixed.
Reply all
Reply to author
Forward
0 new messages