rescrv/HyperDex — Issue #7: Conditional Modification Operations (CAS)
Author: roja
Created: 2012-02-25 14:32:17+00:00
State: open

Immediate consistency makes operations easy to reason about, however without the ability to conditionally modify, some of it's advantage is lost. Would it be possible to extend the public API to return, and accept for comparison, some hash value of a current dataset entry such that conditional update can be performed?

In each case the hash would be a small, base64 encoded, constant length hash of the entries attributes. The following should be valid for all modifiers, i.e. insertion and deletion.

* A null hash field would indicate to perform the modification without condition, as per the current implementation.
* A hash with any value should only perform it's intended operation if the hash given to the command is identical to the hash contained within the current entry.
* An empty hash (empty string) matches with the intentional non-existence of an entry (i.e. insert would fail if an entry for that key currently existed with the space.)

An example interaction may be:

Insert entry, now returns special ```_hash``` value.
```
>>> import hyperclient
>>> c = hyperclient.Client('127.0.0.1', 1234)
>>> c.insert('phonebook', 'jsmith1', {'first': 'John', 'last': 'Smith', 'phone': 6075551024})
True

>>> c.lookup('phonebook', 'jsmith1')
phonebook(first='John', last='Smith', phone='0\x8d!j\x01', username='jsmith1', _hash: 'a6n9bf')
```

Attempt to modify with incorrect hash fails:
```
>>> c.insert('phonebook', 'jsmith1', {'phone': 6075552048}, 'zzz9bf')
False
>>> c.lookup('phonebook', 'jsmith1')
phonebook(first='John', last='Smith', phone='0\x8d!j\x01', _hash: 'a6n9bf')
```

Attempt to modify with correct hash succeeds:
```
>>> c.insert('phonebook', 'jsmith1', {'phone': 6075552048}, 'a6n9bf')
True
>>> c.lookup('phonebook', 'jsmith1')
phonebook(first='John', last='Smith', phone='0\x91!j\x01', _hash: 'q8bbo0')
```

Attempt to modify with null hash succeeds:
```
>>> c.insert('phonebook', 'jsmith1', {'phone': 6075551024})
True
>>> c.lookup('phonebook', 'jsmith1')
phonebook(first='John', last='Smith', phone='0\x8d!j\x01', _hash: 'q8bbo0')
```

Attempt to modify with empty hash fails as key already in use:
```
>>> c.insert('phonebook', 'jsmith1', {'first': 'Johnny', 'last': 'Smithton', 'phone': 923478383}, "")
False
>>> c.lookup('phonebook', 'jsmith1')
phonebook(first='John', last='Smith', phone='0\x8d!j\x01', _hash: 'q8bbo0')
```

Attempt to modify with null hash succeeds, overwriting the current entry:
```
>>> c.insert('phonebook', 'jsmith1', {'first': 'Johnny', 'last': 'Smithton', 'phone': 6075551024})
False
>>> c.lookup('phonebook', 'jsmith1')
phonebook(first='Johnny', last='Smithton', phone='0\x6f!j\x01', _hash: '93jj7d')
```

I think that this adds a huge use-case for the store.