javatransactionsmvcctokumx

TokuMX MVCC Transactions in Java


How are highly contended records saved when running concurrent transactions on the same document(s)?

It appears that this is happening:

  1. MVCC Transaction A begins.
  2. MVCC Transaction B begins.
  3. Transaction A updates docA and docB.
  4. Transaction A commits.
  5. Transaction B updates docA and docC - locks are gained as Transaction A has committed and holds no locks.
  6. Transaction B commits overwriting the work transition A has done on docA.

Here is the example code:

        mongoClient = new MongoClient( "localhost" , 27017 );
        db = mongoClient.getDB("test");
        collection = db.getCollection("testData");

        //Create usable Mongo key from key String (i.e {_id:ObjectId("53b4477d44aef43e83c18922")})
        String key = "53b4477d44aef43e83c18922";
        String key2 = "53bfff9e44aedb6d98a5c578";
        ObjectId keyObj = new ObjectId(key);
        ObjectId keyObj2 = new ObjectId(key2);

        //Set up the transaction
        BasicDBObject transaction = new BasicDBObject();
        transaction.append("beginTransaction", 1);
        transaction.append("isolation", "mvcc");
        db.command(transaction);

        //Create search query
        BasicDBObject query = new BasicDBObject().append("_id",keyObj);
        BasicDBObject query2 = new BasicDBObject().append("_id",keyObj2);

        //Create set  
        BasicDBObject set = new BasicDBObject();
        set.append("$inc", new BasicDBObject().append("balance",50));

        //Run command
        collection.update(query, set);
        collection.update(query2, set);

        //Commit the transactions
        BasicDBObject commitTransaction = new BasicDBObject();
        commitTransaction.append("commitTransaction", 1);
        db.command(commitTransaction);

Is there a check I can do to decide whether or not to commit the transaction? Or is this intended behaviour of TokuMX (or am I doing something wrong)?


Solution

  • TokuMX multi-statement transactions are very similar to MySQL multi-statement transactions. In your example, a document-level lock will be held while the update is happening, so updates to that record will be serialized.

    If there is a conflict because two transactions are updating the same document at the same time, the update method will return an error that says there is a lock conflict.

    To help you understand what happens, have two threads run this, but have neither commit. You will see one thread wait and eventually time out with a lock timeout error.

    Also, if your transaction is a single update, you can just run it, you don't need to wrap it in a transaction. If you want to use a multi-statement transaction, you may want "serializable" isolation rather than MVCC, if you'll be doing reads as part of the transaction: http://docs.tokutek.com/tokumx/tokumx-transactions.html#tokumx-transactions-isolation-serializable Also, you will need to reserve a connection for the transaction, or the connection pool can make your transactions behave improperly: http://docs.tokutek.com/tokumx/tokumx-transactions.html#tokumx-transactions-multi-statement-drivers