The Oracle NoSQL Database Blog covers all things Oracle NoSQL Database. On-Prem, Cloud and more.

  • September 26, 2016

Oracle NoSQL Database - putIfVersion() API for read-modify-write operations

Mayuresh Nirhali
Principal Product Manager

I read an interesting article about how hackers were able to steal 896 BTC and caused Flexcoin to shut down because the loss was too large for the company to bear.  The article highlights the need for software implementers to provide APIs designed to prevent unexpected behavior for read-modify-write (RMW) operations.  For example, if you need to update an account balance, you need to perform the following sequence of operations:

Step 1: curr_value = get(key, "my_account_no"); // read from the database into the application

Step 2: new_value = curr_value - amount_to_be_deducted;  // update the value in the application

Step 3: put(key, new_value);  // store the updated value in the database

A database system that supports multi-statement transactions ensures that the account balance for my_account_no in the database cannot be changed by another user until the update has been committed.

Unfortunately, most NoSQL database systems do not support multi-statement transactions.  If concurrent users perform RMW operations like the one described above and on the same record, it is possible to get incorrect results, as the flexcoin article illustrates.

Oracle NoSQL Database provides APIs that help prevent this problem, even in the presence of concurrent activity. In this blog, we are going to talk about one such useful API, putIfVersion.

KVStore.PutIfVersion is a simple, yet powerful API that can be used when updating a value to ensure that it has not changed since the last time it was read. 

Version putIfVersion(Key key,Value value,Version matchVersion)

          Put a key/value pair, but only if the version of the existing value
matches the matchVersion argument.
Version putIfVersion(Key key,Value value,Version matchVersion,ReturnValueVersion prevValue,Durability durability,
long timeout,TimeUnit timeoutUnit)

          Put a key/value pair, but only if the version of the existing value
matches the matchVersion argument.

Let us see, how putIfVersion can be used to avoid consistency issues in the application. Consider the same sequence of RMW operations:

Step 1: curr_value = get(key, "my_account_no");

Step 2: new_value = curr_value - amount_to_be_deducted;

Step 3: put(key, new_value);

The step two can be more elaborate, with checks to ensure that the new_value is still valid (e.g. non-zero, above certain limit etc.)

Now, if there are two or more application threads that are updating the same value at the same time, it is possible that both the threads have read the current value before the put() operation is executed. At the end of this operation from both the threads, the value would be incorrect as the amount would have been deducted twice but updated in the database to have been deducted only once.

putIfVersion() API solves the problem above. It protects the application by making an additional check during updates ensuring that the value has not changed since the last time.

putIfVersion(key, new_value, curr_value);

Although the example above illustrates usage of putIfVersion() for Key/Value data model, Oracle NoSQL Database implements putIfVersion() API for both Key/Value as well as Table data model.

Refer the sample code here, to leverage putIfVersion() API in your application.

Happy (and safe) coding!

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.Captcha