public class AtomicKVDatabase extends AbstractKVStore implements AtomicKVStore
AtomicKVStore
view of a KVDatabase
,
using individual transactions for each operation.
Warning: this class is only appropriate for use with KVDatabase
s that implement some form of MVCC;
KVDatabase
s that use locking will likely generate conflicts if snapshot()
is used concurrently
with other methods.
SnapshotKVDatabase
Modifier and Type | Field and Description |
---|---|
protected KVDatabase |
kvdb |
Constructor and Description |
---|
AtomicKVDatabase(KVDatabase kvdb)
Constructor.
|
Modifier and Type | Method and Description |
---|---|
void |
adjustCounter(byte[] key,
long amount)
Adjust the counter at the given key by the given amount.
|
long |
decodeCounter(byte[] bytes)
Decode a counter value previously encoded by
encodeCounter() . |
byte[] |
encodeCounter(long value)
Encode a counter value into a
byte[] value suitable for use with decodeCounter()
and/or adjustCounter() . |
byte[] |
get(byte[] key)
Get the value associated with the given key, if any.
|
KVPair |
getAtLeast(byte[] minKey,
byte[] maxKey)
Get the key/value pair having the smallest key greater than or equal to the given minimum, if any.
|
KVPair |
getAtMost(byte[] maxKey,
byte[] minKey)
Get the key/value pair having the largest key strictly less than the given maximum, if any.
|
KVPairIterator |
getRange(byte[] minKey,
byte[] maxKey,
boolean reverse)
Iterate the key/value pairs in the specified range.
|
void |
mutate(Mutations mutations,
boolean sync)
Apply a set of mutations to this instance atomically.
|
void |
put(byte[] key,
byte[] value)
Set the value associated with the given key.
|
void |
remove(byte[] key)
Remove the key/value pair with the given key, if it exists.
|
void |
removeRange(byte[] minKey,
byte[] maxKey)
Remove all key/value pairs whose keys are in a given range.
|
CloseableKVStore |
snapshot()
Acquire a read-only, snapshot view of this instance based on the current state.
|
void |
start()
Start this instance.
|
void |
stop()
Stop this instance.
|
String |
toString() |
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
apply, getRange, getRange, removeRange
protected final KVDatabase kvdb
public AtomicKVDatabase(KVDatabase kvdb)
kvdb
- underlying databaseIllegalArgumentException
- if kvdb
is nullpublic byte[] get(byte[] key)
KVStore
Modifications to the returned byte[]
array do not affect this instance.
get
in interface KVStore
get
in class AbstractKVStore
key
- keypublic KVPair getAtLeast(byte[] minKey, byte[] maxKey)
KVStore
An optional (exclusive) maximum key may also be specified; if maxKey
is null, there is no upper bound;
if maxKey <= minKey
, null is always returned.
If keys starting with 0xff
are not supported by this instance, and minKey
starts with 0xff
,
then this method returns null.
Modifications to the returned byte[]
arrays do not affect this instance.
getAtLeast
in interface KVStore
getAtLeast
in class AbstractKVStore
minKey
- minimum key (inclusive), or null for no minimum (get the smallest key)maxKey
- maximum key (exclusive), or null for no maximum (no upper bound)key >= minKey
and key < maxKey
, or null if none existspublic KVPair getAtMost(byte[] maxKey, byte[] minKey)
KVStore
An optional (inclusive) minimum key may also be specified; if minKey
is null, there is no lower bound
(equivalent to a lower bound of the empty byte array); if minKey >= maxKey
, null is always returned.
If keys starting with 0xff
are not supported by this instance, and maxKey
starts with 0xff
,
then this method behaves as if maxKey
were null.
Modifications to the returned byte[]
arrays do not affect this instance.
getAtMost
in interface KVStore
getAtMost
in class AbstractKVStore
maxKey
- maximum key (exclusive), or null for no maximum (get the largest key)minKey
- minimum key (inclusive), or null for no minimum (no lower bound)key < maxKey
and key >= minKey
, or null if none existspublic KVPairIterator getRange(byte[] minKey, byte[] maxKey, boolean reverse)
KVStore
Iterator
's
remove()
method must be supported and should have the same effect as
invoking remove()
on the corresponding key.
If keys starting with 0xff
are not supported by this instance, and minKey
starts with 0xff
,
then this method returns an empty iteration.
If keys starting with 0xff
are not supported by this instance, and maxKey
starts with 0xff
,
then this method behaves as if maxKey
were null.
The returned Iterator
must not throw ConcurrentModificationException
;
however, whether or not a "live" Iterator
reflects any modifications made after its creation is
implementation dependent. Implementations that do make post-creation updates visible in the Iterator
,
even if the update occurs after some delay, must preserve the order in which the modifications actually occurred.
The returned Iterator
itself is not guaranteed to be thread safe.
Invokers of this method are encouraged to close()
the returned iterators,
though this is not required for correct behavior.
Modifications to the returned KVPair
key and value byte[]
arrays do not affect this instance.
getRange
in interface KVStore
minKey
- minimum key (inclusive), or null for no minimum (start at the smallest key)maxKey
- maximum key (exclusive), or null for no maximum (end at the largest key)reverse
- true to return key/value pairs in reverse order (i.e., keys descending)minKey
(inclusive) to maxKey
(exclusive)public void put(byte[] key, byte[] value)
KVStore
put
in interface KVStore
put
in class AbstractKVStore
key
- keyvalue
- valuepublic void remove(byte[] key)
KVStore
remove
in interface KVStore
remove
in class AbstractKVStore
key
- keypublic void removeRange(byte[] minKey, byte[] maxKey)
KVStore
The minKey
must be less than or equal to maxKey
; if they equal (and not null)
then nothing happens; if they are both null then all entries are deleted.
If keys starting with 0xff
are not supported by this instance, then:
minKey
starts with 0xff
, then no change occursmaxKey
starts with 0xff
, then this method behaves as if maxKey
were nullremoveRange
in interface KVStore
removeRange
in class AbstractKVStore
minKey
- minimum key (inclusive), or null for no minimummaxKey
- maximum key (exclusive), or null for no maximumpublic void adjustCounter(byte[] key, long amount)
KVStore
Ideally this operation should behave in a lock-free manner, so that concurrent transactions can invoke it without conflict. However, when lock-free behavior occurs (if at all) depends on the implementation.
If there is no value associated with key
, or key
's value is not a valid counter encoding as
would be acceptable to decodeCounter()
, then how this operation affects key
's
value is undefined.
adjustCounter
in interface KVStore
adjustCounter
in class AbstractKVStore
key
- keyamount
- amount to adjust counter value bypublic byte[] encodeCounter(long value)
KVStore
byte[]
value suitable for use with decodeCounter()
and/or adjustCounter()
.encodeCounter
in interface KVStore
encodeCounter
in class AbstractKVStore
value
- desired counter valuepublic long decodeCounter(byte[] bytes)
KVStore
encodeCounter()
.decodeCounter
in interface KVStore
decodeCounter
in class AbstractKVStore
bytes
- encoded counter value@PostConstruct public void start()
AtomicKVStore
This method is idempotent: if this instance is already started, nothing happens.
Whether an instance that has been started and stopped can be restarted is implementation-dependent.
start
in interface AtomicKVStore
@PreDestroy public void stop()
AtomicKVStore
Any open AtomicKVStore.snapshot()
's should be close()
'd before invoking this method;
the behavior of those that are not is undefined.
This method is idempotent: if this instance has not been started, or is already stopped, nothing happens.
stop
in interface AtomicKVStore
public CloseableKVStore snapshot()
AtomicKVStore
The returned KVStore
view should remain constant even if this instance is subsequently mutated.
Note: callers are required to close
the returned instance when no longer in use.
snapshot
in interface AtomicKVStore
public void mutate(Mutations mutations, boolean sync)
AtomicKVStore
If this method returns normally, all of the given mutations will have been applied. If this method returns abnormally, then none of the given mutations will have been applied.
In any case, other threads observing this instance will never see a partial application of the given mutations.
This method is required to apply the mutations in this order: removes, puts, adjusts.
If sync
is true, the implementation must durably persist the changes before returning.
mutate
in interface AtomicKVStore
mutations
- the mutations to applysync
- if true, caller requires that the changes be durably persistedCopyright © 2022. All rights reserved.