Class MutableView

java.lang.Object
io.permazen.kv.AbstractKVStore
io.permazen.kv.mvcc.MutableView
All Implemented Interfaces:
KVStore, DeltaKVStore, Cloneable
Direct Known Subclasses:
ReadWriteSpannerView

@ThreadSafe public class MutableView extends AbstractKVStore implements DeltaKVStore, Cloneable
Straightforward implementation of the DeltaKVStore interface.

The amount of memory required scales in proportion to the number of distinct key ranges that are read or removed (if tracking reads) plus the total lengths of all keys and values written.

  • Constructor Details

  • Method Details

    • getBaseKVStore

      public KVStore getBaseKVStore()
      Description copied from interface: DeltaKVStore
      Get the KVStore that underlies this instance.

      Note that in some implementations the returned object and/or its contents may change over time, for example, if this instance gets "rebased" on a newer underlying KVStore.

      Specified by:
      getBaseKVStore in interface DeltaKVStore
      Returns:
      underlying KVStore
    • setKVStore

      public void setKVStore(KVStore kv)
      Swap out the underlying KVStore associated with this instance.

      Note: the new KVStore should have a consistent encoding of counter values as the previous KVStore, otherwise a concurrent thread may read previously written counter values back incorrectly.

      Parameters:
      kv - new underlying KVStore
      Throws:
      IllegalArgumentException - if kv is null
    • getReads

      public Reads getReads()
      Description copied from interface: DeltaKVStore
      Get the Reads associated with this instance.

      This includes all keys explicitly or implicitly read by calls to get(), getAtLeast(), getAtMost(), and getRange().

      The returned object is "live" and should only be accessed while synchronized on this instance.

      The read tracking may be imprecise, as long as all actual reads are included. For example, if keys 10001, 100002, and 100003 were read, the returned Reads may contain those three keys, or it may contain the entire range 10001-10003, even though some keys in that range were not actually read in order to save memory. This optimization is acceptable as long as the keys that were actually read are always included.

      Specified by:
      getReads in interface DeltaKVStore
      Returns:
      reads recorded, or null if this instance is not configured to record reads or read tracking has been permanently disabled via DeltaKVStore.disableReadTracking()
    • getWrites

      public Writes getWrites()
      Description copied from interface: DeltaKVStore
      Get the Writes associated with this instance.

      The returned object is "live" and should only be accessed while synchronized on this instance.

      Specified by:
      getWrites in interface DeltaKVStore
      Returns:
      writes recorded
    • disableReadTracking

      public void disableReadTracking()
      Description copied from interface: DeltaKVStore
      Permanently disable read tracking and discard the Reads associated with this instance.

      This can be used to save some memory when read tracking information is no longer needed.

      Does nothing if read tracking is already disabled.

      Specified by:
      disableReadTracking in interface DeltaKVStore
    • withoutReadTracking

      public void withoutReadTracking(boolean allowWrites, Runnable action)
      Description copied from interface: DeltaKVStore
      Temporarily disable read tracking in the current thread while performing the given action.

      If allowWrites is false, then any write attempts by action will provoke an IllegalStateException.

      Read tracking is disabled only for the current thread, and it ends when this method returns.

      Specified by:
      withoutReadTracking in interface DeltaKVStore
      Parameters:
      allowWrites - whether to allow writes (usually this is a bad idea)
      action - the action to perform
    • isReadOnly

      public boolean isReadOnly()
      Description copied from interface: DeltaKVStore
      Determine if this instance is read-only.
      Specified by:
      isReadOnly in interface DeltaKVStore
      Returns:
      true if this instance is read-only, otherwise false
    • setReadOnly

      public void setReadOnly()
      Description copied from interface: DeltaKVStore
      Configure this instance as read-only.

      Any subsequent write attempts will result in an IllegalStateException.

      This operation cannot be un-done.

      Specified by:
      setReadOnly in interface DeltaKVStore
    • 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 interface KVStore
      Overrides:
      get in class AbstractKVStore
      Parameters:
      key - key
      Returns:
      value associated with key, or null if not found
    • getRange

      public CloseableIterator<KVPair> getRange(byte[] minKey, byte[] maxKey, boolean reverse)
      Description copied from interface: KVStore
      Iterate the key/value pairs in the specified range. The returned CloseableIterator'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 CloseableIterator is weakly consistent (see java.util.concurrent). In short, the returned CloseableIterator must not throw ConcurrentModificationException; 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 the CloseableIterator, 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 value byte[] arrays do not affect this instance.

      Specified by:
      getRange in interface KVStore
      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) to maxKey (exclusive)
    • 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 interface KVStore
      Overrides:
      put in class AbstractKVStore
      Parameters:
      key - key
      value - 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 interface KVStore
      Overrides:
      remove in class AbstractKVStore
      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 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:

      • If minKey starts with 0xff, then no change occurs
      • If maxKey starts with 0xff, then this method behaves as if maxKey were null
      Specified by:
      removeRange in interface KVStore
      Overrides:
      removeRange in class AbstractKVStore
      Parameters:
      minKey - minimum key (inclusive), or null for no minimum
      maxKey - maximum key (exclusive), or null for no maximum
    • encodeCounter

      public byte[] encodeCounter(long value)
      Description copied from interface: KVStore
      Encode a counter value into a byte[] value suitable for use with decodeCounter() and/or adjustCounter().
      Specified by:
      encodeCounter in interface KVStore
      Overrides:
      encodeCounter in class AbstractKVStore
      Parameters:
      value - desired counter value
      Returns:
      encoded counter value
    • decodeCounter

      public long decodeCounter(byte[] bytes)
      Description copied from interface: KVStore
      Decode a counter value previously encoded by encodeCounter().
      Specified by:
      decodeCounter in interface KVStore
      Overrides:
      decodeCounter in class AbstractKVStore
      Parameters:
      bytes - encoded counter value
      Returns:
      decoded counter value
    • adjustCounter

      public void adjustCounter(byte[] key, long amount)
      Description copied from interface: KVStore
      Adjust the counter at the given key by the given amount.

      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.

      Specified by:
      adjustCounter in interface KVStore
      Overrides:
      adjustCounter in class AbstractKVStore
      Parameters:
      key - key
      amount - amount to adjust counter value by
    • apply

      public void apply(Mutations mutations)
      Description copied from interface: KVStore
      Apply all the given Mutations to this instance.

      Mutations are always to be applied in this order: removes, puts, counter adjustments.

      The implementation in KVStore simply iterates over the individual changes and applies them via remove() (for removals of a single key), removeRange(), put(), and/or adjustCounter(). Implementations that can process batch updates more efficiently are encouraged to override this method.

      Unlike AtomicKVStore.apply(), this method is not required to apply the mutations atomically.

      Specified by:
      apply in interface KVStore
      Parameters:
      mutations - mutations to apply
    • clone

      public MutableView clone()
      Clone this instance.

      The clone will have the same underlying KVStore, but its own Reads and Writes, which will themselves be cloned from this instance's copies.

      Overrides:
      clone in class Object
      Returns:
      clone of this instance
    • toString

      public String toString()
      Overrides:
      toString in class Object