1

I'm looking for an efficient way to implement compare-and-swap operation in Berkeley DB. Right now I'm using really old version, however at first glance even the latest one (distributed from Oracle website) does not have a single method for such operation.

I was looking for a some kind of method like

replace(Transaction, Key, ExpectedValue, NewValue) 

with the following semantics: DB gets value associated with a given key, if this value exists and it is equal to ExpectedValue then this value will be changed to NewValue, otherwise method returns unsuccessful OperationStatus.

Looks like there is no method like that, so I'm wondering how is this supposed to be done in the most efficient way.

Right now I'm using the following approach: I do

db.get(null, key) -> {currentValue, version}
db.put(null, key, {currentValue, newRandomIdVersion}) 
db.get(null, key)

I compare value and version, if they match I do final update erasing old version. If any step fail, the whole process restarts.

I feel that this is very suboptimal - am I wrong?

Jim Garrison
  • 85,615
  • 20
  • 155
  • 190
Alex
  • 2,916
  • 3
  • 22
  • 27
  • Have you tried anything? – Jim Garrison Jul 11 '16 at 05:36
  • As a first crack, try using a transaction and see if the performance is sufficient at scale. – Mike Andrews Jul 11 '16 at 14:11
  • Do you mean just merely update counter within transaction? It wouldn't help - concurrent transactions will just override themselves. – Alex Jul 12 '16 at 04:42
  • Well, I'm not sure what you mean by override - but they'd provide atomicity. On a conflict, one transaction wins and N lose, to be retried by your application. If you really need concurrent writes to the same "record", see if you can figure out how to split it into multiple records. With what you've got here, you might be better off with a ring log, and sorting out the correct application-level state on recovery. – Mike Andrews Jul 12 '16 at 12:33
  • Yes, you're right, transactions are atomic, but again, if they start simultaneously updating the same record, first transaction may not "see" results of updating record by second transaction and vice versa. At the same time compare-and-swap assumes that no updates will be lost. – Alex Jul 17 '16 at 23:25

1 Answers1

0

My solution in update to my question is wrong - however only slight modification is required to make it better.

The solution might be as follows: create separate DB for storing locks that will hold associations of key to some counter. This DB should allow sorted duplicates (so that Database.get would return smallest value associated with a given key). Then use shared monotonically increasing counter. Multiple threads attempting to do CAS will get values from this counter and store key-value pairs in that lock DB. Thread that stored lowest value associated with a key, assumes that it has permission to write and goes ahead with compare-and-swap for desired record, then deletes its entry from the lock DB, other threads simply retry.

Alex
  • 2,916
  • 3
  • 22
  • 27