Class CachingKVStore
- All Implemented Interfaces:
CachingConfig
,CloseableKVStore
,KVStore
,Closeable
,AutoCloseable
KVStore
's that have high latency for individual reads but low
latency for consecutive key/value pairs in a KVStore.getRange()
range read.
An example is a KVStore
backed by a service provided over the network. Reading one key/value pair
costs a network round trip, whereas when reading a whole range of keys the round trip time is amortized over
the whole range because many key/value pairs can be streamed in a single response.
Caching and Read-Ahead
All queries to the underlying KVStore
are range queries. Internally, instances store the results from
these queries as contiguous key ranges with the associated values. Queries contained within a known range can
be answered immediately; other queries trigger the creation of a new range or the extension of an existing range.
By default, instances are configured for read ahead, so that underlying range reads extend past the end of the requested limit, in anticipation of further queries from the nearby region of the key space.
These underlying queries are performed asynchronously in background tasks, and multiple background range queries may be running at the same time. To avoid creating redundant background queries, when handling a query for a key/value pair that may possibly be answered by an existing but uncompleted background range query (depending on key/value pairs yet to arrive), instances will sometimes speculatively delay creating a new task. This decision is based on an ongoing estimation of round-trip time, and the uncompleted background query's data arrival rate.
Configuration
Instances are configured with limits on the maximum number of contiguous key/value ranges, the maximum amount of data to preload into a single contiguous key/value range, and the maximum total amount of data to cache. Once these limits are exceeded, stored ranges are discarded on a least-recently-used basis.
Consistency Assumptions
This class assumes the underlying key/value store is read-only and unchanging, so that cached values are always
up-to-date. Attempts to modify the key/value store will result in an UnsupportedOperationException
.
Warning: this class assumes that the underlying KVStore
provides fully consistent
reads: the data returned by any two read operations, no matter when they occur, will be consistent.
Enabling assertions on this package may detect some violations of this assumption.
- See Also:
-
Field Summary
Modifier and TypeFieldDescriptionstatic final long
Default maximum number of bytes to cache in a single contiguous range of key/value pairs (10485760L).static final int
Default maximum number of contiguous ranges of key/value pairs to allow before we start purging the least recently used ones (256).static final long
Default maximum total number of bytes to cache including all ranges (104857600L).Fields inherited from interface io.permazen.kv.caching.CachingConfig
DEFAULT_READ_AHEAD, DEFAULT_WAIT_FACTOR
-
Constructor Summary
ConstructorDescriptionCachingKVStore
(CloseableKVStore kvstore, ExecutorService executor, long rttEstimate) Constructor for when the underlyingKVStore
should be closed when this instance is closed.CachingKVStore
(KVStore kvstore, ExecutorService executor, long rttEstimate) Constructor. -
Method Summary
Modifier and TypeMethodDescriptionvoid
close()
Close this instance and release any resources associated with it.byte[]
get
(byte[] key) Get the value associated with the given key, if any.getAtLeast
(byte[] minKey, byte[] maxKey) Get the key/value pair having the smallest key greater than or equal to the given minimum, if any.getAtMost
(byte[] maxKey, byte[] minKey) Get the key/value pair having the largest key strictly less than the given maximum, if any.long
Get the maximum number of bytes to cache in a single contiguous range of key/value pairs.int
Get the maximum number of contiguous ranges of key/value pairs to allow before we start purging the least recently used ones.long
Get the total number of bytes to cache.getRange
(byte[] minKey, byte[] maxKey, boolean reverse) Iterate the key/value pairs in the specified range.double
Get the current round trip time estimate.double
Get the wait factor.boolean
Get whether this instance is configured to perform read-ahead.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.void
setMaxRangeBytes
(long maxRangeBytes) Configure the maximum number of bytes to cache in a single contiguous range of key/value pairs.void
setMaxRanges
(int maxRanges) Configure the maximum number of contiguous ranges of key/value pairs to allow before we start purging the least recently used ones.void
setMaxTotalBytes
(long maxTotalBytes) Configure the total number of bytes to cache.void
setReadAhead
(boolean readAhead) Configure whether read-ahead is enabled.void
setWaitFactor
(double waitFactor) Set the wait factor.Methods inherited from class io.permazen.kv.util.CloseableForwardingKVStore
delegate, finalize
Methods inherited from class io.permazen.kv.util.ForwardingKVStore
adjustCounter, apply, decodeCounter, encodeCounter
Methods inherited from class java.lang.Object
clone, equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
Methods inherited from interface io.permazen.kv.caching.CachingConfig
copyCachingConfigTo
Methods inherited from interface io.permazen.kv.KVStore
adjustCounter, apply, decodeCounter, encodeCounter, getRange, getRange, removeRange
-
Field Details
-
DEFAULT_MAX_RANGES
public static final int DEFAULT_MAX_RANGESDefault maximum number of contiguous ranges of key/value pairs to allow before we start purging the least recently used ones (256).- See Also:
-
DEFAULT_MAX_RANGE_BYTES
public static final long DEFAULT_MAX_RANGE_BYTESDefault maximum number of bytes to cache in a single contiguous range of key/value pairs (10485760L).- See Also:
-
DEFAULT_MAX_TOTAL_BYTES
public static final long DEFAULT_MAX_TOTAL_BYTESDefault maximum total number of bytes to cache including all ranges (104857600L).- See Also:
-
-
Constructor Details
-
CachingKVStore
Constructor.- Parameters:
kvstore
- underlying key/value storeexecutor
- executor for performing asynchronous batch queriesrttEstimate
- initial round trip time estimate in nanoseconds- Throws:
IllegalArgumentException
- if either parameter is nullIllegalArgumentException
- ifrttEstimate
is negative
-
CachingKVStore
Constructor for when the underlyingKVStore
should be closed when this instance is closed.- Parameters:
kvstore
- underlying key/value store; will be closed onclose()
executor
- executor for performing asynchronous batch queriesrttEstimate
- initial round trip time estimate in nanoseconds- Throws:
IllegalArgumentException
- if either parameter is nullIllegalArgumentException
- ifrttEstimate
is negative
-
-
Method Details
-
getMaxRangeBytes
public long getMaxRangeBytes()Description copied from interface:CachingConfig
Get the maximum number of bytes to cache in a single contiguous range of key/value pairs.Default is 10485760L.
- Specified by:
getMaxRangeBytes
in interfaceCachingConfig
- Returns:
- maximum bytes in any one range
-
setMaxRangeBytes
public void setMaxRangeBytes(long maxRangeBytes) Description copied from interface:CachingConfig
Configure the maximum number of bytes to cache in a single contiguous range of key/value pairs.Default is 10485760L.
- Specified by:
setMaxRangeBytes
in interfaceCachingConfig
- Parameters:
maxRangeBytes
- maximum bytes in any one range
-
getMaxTotalBytes
public long getMaxTotalBytes()Description copied from interface:CachingConfig
Get the total number of bytes to cache. This is an overal maximum incluging all ranges.Default is 104857600L.
- Specified by:
getMaxTotalBytes
in interfaceCachingConfig
- Returns:
- maximum cached ranges
-
setMaxTotalBytes
public void setMaxTotalBytes(long maxTotalBytes) Description copied from interface:CachingConfig
Configure the total number of bytes to cache. This is an overal maximum incluging all ranges.Default is 104857600L.
- Specified by:
setMaxTotalBytes
in interfaceCachingConfig
- Parameters:
maxTotalBytes
- maximum cached ranges
-
getMaxRanges
public int getMaxRanges()Description copied from interface:CachingConfig
Get the maximum number of contiguous ranges of key/value pairs to allow before we start purging the least recently used ones.Default is 256.
- Specified by:
getMaxRanges
in interfaceCachingConfig
- Returns:
- maximum cached ranges
-
setMaxRanges
public void setMaxRanges(int maxRanges) Description copied from interface:CachingConfig
Configure the maximum number of contiguous ranges of key/value pairs to allow before we start purging the least recently used ones.Default is 256.
- Specified by:
setMaxRanges
in interfaceCachingConfig
- Parameters:
maxRanges
- maximum cached ranges
-
getWaitFactor
public double getWaitFactor()Description copied from interface:CachingConfig
Get the wait factor.The wait factor, when multiplied by the estimated amount of time we expect to have to wait for incoming data that's already on its way, is how long we will actually wait for that data before initiating a new query. A value of zero means never wait, i.e., always start a new query immediately; a value of 1.0 would mean to wait up to the estimated amount of time; a very high value would mean wait until the outstanding query either produces the data or completes.
Default is 1.5.
- Specified by:
getWaitFactor
in interfaceCachingConfig
- Returns:
- wait factor
-
setWaitFactor
public void setWaitFactor(double waitFactor) Description copied from interface:CachingConfig
Set the wait factor.Default is 1.5.
- Specified by:
setWaitFactor
in interfaceCachingConfig
- Parameters:
waitFactor
- wait factor
-
isReadAhead
public boolean isReadAhead()Description copied from interface:CachingConfig
Get whether this instance is configured to perform read-ahead.Default is true.
- Specified by:
isReadAhead
in interfaceCachingConfig
- Returns:
- true if read-ahead is enabled, otherwise false
-
setReadAhead
public void setReadAhead(boolean readAhead) Description copied from interface:CachingConfig
Configure whether read-ahead is enabled.Default is true.
- Specified by:
setReadAhead
in interfaceCachingConfig
- Parameters:
readAhead
- true to enable read-ahead, false to disable
-
get
public byte[] get(byte[] key) Description copied from interface:KVStore
Get the value associated with the given key, if any.Modifications to the returned
byte[]
array do not affect this instance.- Specified by:
get
in interfaceKVStore
- Overrides:
get
in classForwardingKVStore
- Parameters:
key
- key- Returns:
- value associated with key, or null if not found
-
getRange
Description copied from interface:KVStore
Iterate the key/value pairs in the specified range. The returnedCloseableIterator
'sremove()
method must be supported and should have the same effect as invokingremove()
on the corresponding key.If keys starting with
0xff
are not supported by this instance, andminKey
starts with0xff
, then this method returns an empty iteration.If keys starting with
0xff
are not supported by this instance, andmaxKey
starts with0xff
, then this method behaves as ifmaxKey
were null.The returned
CloseableIterator
is weakly consistent (seejava.util.concurrent
). In short, the returnedCloseableIterator
must not throwConcurrentModificationException
; however, whether or not a "live"CloseableIterator
reflects any modifications made after its creation is implementation dependent. Implementations that do make post-creation updates visible in theCloseableIterator
, even if the update occurs after some delay, must preserve the order in which the modifications actually occurred.The returned
CloseableIterator
itself is not guaranteed to be thread safe; is should only be used in the thread that created it.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 valuebyte[]
arrays do not affect this instance.- Specified by:
getRange
in interfaceKVStore
- Overrides:
getRange
in classForwardingKVStore
- Parameters:
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)- Returns:
- iteration of key/value pairs in the range
minKey
(inclusive) tomaxKey
(exclusive)
-
getAtLeast
Description copied from interface:KVStore
Get the key/value pair having the smallest key greater than or equal to the given minimum, if any.An optional (exclusive) maximum key may also be specified; if
maxKey
is null, there is no upper bound; ifmaxKey <= minKey
, null is always returned.If keys starting with
0xff
are not supported by this instance, andminKey
starts with0xff
, then this method returns null.Modifications to the returned
byte[]
arrays do not affect this instance.- Specified by:
getAtLeast
in interfaceKVStore
- Overrides:
getAtLeast
in classForwardingKVStore
- Parameters:
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)- Returns:
- smallest key/value pair with
key >= minKey
andkey < maxKey
, or null if none exists
-
getAtMost
Description copied from interface:KVStore
Get the key/value pair having the largest key strictly less than the given maximum, if any.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); ifminKey >= maxKey
, null is always returned.If keys starting with
0xff
are not supported by this instance, andmaxKey
starts with0xff
, then this method behaves as ifmaxKey
were null.Modifications to the returned
byte[]
arrays do not affect this instance.- Specified by:
getAtMost
in interfaceKVStore
- Overrides:
getAtMost
in classForwardingKVStore
- Parameters:
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)- Returns:
- largest key/value pair with
key < maxKey
andkey >= minKey
, or null if none exists
-
put
public void put(byte[] key, byte[] value) Description copied from interface:KVStore
Set the value associated with the given key.- Specified by:
put
in interfaceKVStore
- Overrides:
put
in classForwardingKVStore
- Parameters:
key
- keyvalue
- value
-
remove
public void remove(byte[] key) Description copied from interface:KVStore
Remove the key/value pair with the given key, if it exists.- Specified by:
remove
in interfaceKVStore
- Overrides:
remove
in classForwardingKVStore
- Parameters:
key
- key
-
removeRange
public void removeRange(byte[] minKey, byte[] maxKey) Description copied from interface:KVStore
Remove all key/value pairs whose keys are in a given range.The
minKey
must be less than or equal tomaxKey
; 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:- If
minKey
starts with0xff
, then no change occurs - If
maxKey
starts with0xff
, then this method behaves as ifmaxKey
were null
- Specified by:
removeRange
in interfaceKVStore
- Overrides:
removeRange
in classForwardingKVStore
- Parameters:
minKey
- minimum key (inclusive), or null for no minimummaxKey
- maximum key (exclusive), or null for no maximum
- If
-
close
public void close()Close this instance and release any resources associated with it.This does not shutdown the
ExecutorService
provided to the constructor.If this instance is already closed, then nothing happens.
- Specified by:
close
in interfaceAutoCloseable
- Specified by:
close
in interfaceCloseable
- Specified by:
close
in interfaceCloseableKVStore
- Overrides:
close
in classCloseableForwardingKVStore
-
getRttEstimate
public double getRttEstimate()Get the current round trip time estimate.- Returns:
- current RTT estimate in nanoseconds
-