Interface KeyValueTable
-
- All Superinterfaces:
java.lang.AutoCloseable
@Beta public interface KeyValueTable extends java.lang.AutoCloseableDefines all operations that are supported on a Key-Value Table.A Key-Value Table is a distributed Key-Value Store that indexes Entries by Keys. It uses Table Segments (non-distributed Key-Value Store backed by a single Pravega Segment) as the fundamental storage primitive and provides a unified view of all Table Segments involved. Each
TableKeyis hashed to a Table Partition which may be represented by one or more Table Segments (depending on the Key-Value Table configuration chosen when it was created). Such partitioning enables the Key-Value Table to be distributed across the Pravega cluster but also introduces some constraints for certain operations (such as multi-key/entry atomic updates). See below for details.TableKeys are made up of two components: Primary Key and Secondary Key.- The Primary Key is mandatory and is used to group all
TableKeys with the same Primary Key together in the same Table Partition; this allows multiple keys/entries sharing the same Primary Key to be updated/removed atomically. The Primary Keys must all have the same length throughout the Key-Value Table. This needs to be configured when the Key-Value Table is created (SeeKeyValueTableConfiguration.getPrimaryKeyLength()and must be greater than 0. - The Secondary Key is optional. The Secondary Keys must all have the same length throughout the Key-Value Table.
This needs to be configured when the Key-Value Table is created (See
KeyValueTableConfiguration.getSecondaryKeyLength()and must be at least 0. For Key-Value Tables with no Secondary Keys, set this value to 0. It is important to note that if specifying a non-zero value, then allTableKeys must have both the Primary Key and Secondary Key set; so we may not haveTableKeys without Secondary Keys in this case. The Secondary Key is optional at the Table level, not at the Key level. - Two
TableKeyinstances are considered equal if they have the same Primary Key and same Secondary Key. The same Secondary Key may be "associated" with different Primary Keys, in which case the resultingTableKeys will be distinct. For example, if we consider Primary Keys PK1 != PK2 and Secondary Key SK1, then key PK1.SK1 is different from key PK2.SK1. - Multiple
TableKey/TableEntryinstances with the same Primary Key can be updated or removed atomically (either all changes will be applied or none will). However, it is important to note that it is not possible to mix updates with removals in the same atomic operation. -
TableKeys that do not share the same Primary Key may be hashed to different Key-Value Table Partitions and cannot be used for multi-key/entry atomic updates or removals. -
TableKeys sharing the same Primary Key are grouped into the same Table Segment; as such, the choice of Table Key can have performance implications. As Primary Keys are hashed to Table Segments, a large number of Primary Keys (larger than the number of Table Segments) and a uniform distribution of operations across keys leads to an even distribution of load across Table Segments. Many realistic workloads are skewed, however, and can lead to an uneven load distribution across Table Segments. The use of Secondary Keys also has implications to the load balance. All keys containing a given Primary Key map to the same Table Segment independent of Secondary Key. In the presence of Secondary Keys, the total load for a given Primary Key depends on the load aggregate across all of its Secondary Keys. When the load distribution is highly skewed, one option to consider is eliminating Secondary Keys and only using Primary Keys. The application must be able to encode the key into a single one rather than split into two parts. To illustrate, if we have two Table Keys "A.B" and "A.C", "." representing the separation between Primary and Secondary Keys, then they map to the same Table Segment because they have the same Primary Key "A". If instead, we use "AB" and "AC" as keys, eliminating the Secondary Keys but retaining the necessary information in the Primary Key, then we should be able to map those keys to different Table Segments depending on the hashing.
Types of Updates:
- Unconditional Updates will update a value associated with a
TableKey, regardless of whether thatTableKeypreviously existed or not, or what what itsVersionis. Note that Unconditional Updates will either update an existing value or insert a newTableEntryinto the table if the specifiedTableKeydoes not already exist. Unconditional Updates can be performed usingupdate(io.pravega.client.tables.TableModification)by passingPutinstances with a null (Put.getVersion(). - Conditional Updates will only overwrite an existing value if the specified
Put.getVersion()matches the one that is currently present on the server. Conditional updates can performed usingupdate(io.pravega.client.tables.TableModification)by passingPutinstances with a non-nullPut.getVersion(). Conditional inserts can be performed using the same methods by passing anInsertinstance and will only succeed if the associatedTableKeydoes not already exist. - Unconditional Removals will remove a
TableKeyif it exists. Such removals can be performed usingupdate(io.pravega.client.tables.TableModification)by passing aRemovehavingRemove.getVersion()be null. The operation will also succeed (albeit with no effect) if theTableModification.getKey()does not exist. - Conditional Removals will remove a
TableKeyonly if the specifiedRemove.getVersion()matches the one that is currently present on the server. Such removals can be performed usingupdate(io.pravega.client.tables.TableModification)by passing aRemovehavingRemove.getVersion()non-null. - Multi-key updates allow any number of conditions to be specified (including no conditions) in the same atomic
batch. All the conditions that are present in the update batch must be satisfied in order for the update batch to be
accepted - the condition checks and updates are performed atomically.
Inserts may be mixed withPuthavingPut.getVersion()either null or non-null.Removes may not be mixed with anything else (i.e.,InsertorRemove). Useupdate(Iterable)for such an update.
Conditional Update Responses:
- Success: the update or removal has been atomically validated and performed; all updates or removals in the request have been accepted.
- Failure: the update or removal has been rejected due to version mismatch; no update or removal has been performed.
-
NoSuchKeyException: the update or removal has been conditioned on a specific version (different fromVersion.NOT_EXISTSorVersion.NO_VERSION) but the Key does not exist in theKeyValueTable. -
BadKeyVersionException: the update or removal has been conditioned on a specific version (different fromVersion.NO_VERSIONbut the Key exists in theKeyValueTablewith a different version.
-
-
Field Summary
Fields Modifier and Type Field Description static intMAXIMUM_VALUE_LENGTHThe maximum length of a Table Segment Value.
-
Method Summary
All Methods Instance Methods Abstract Methods Modifier and Type Method Description voidclose()Closes theKeyValueTable.java.util.concurrent.CompletableFuture<java.lang.Boolean>exists(@NonNull TableKey key)Determines if the givenTableKeyexists or not.java.util.concurrent.CompletableFuture<TableEntry>get(@NonNull TableKey key)Gets the latest value for aTableKey.java.util.concurrent.CompletableFuture<java.util.List<TableEntry>>getAll(@NonNull java.lang.Iterable<TableKey> keys)Gets the latest values for a set ofTableKeys.KeyValueTableIterator.Builderiterator()Creates a newKeyValueTableIterator.Builderthat can be used to construct and execute an Iterator over theTableKey/TableEntryinstances in thisKeyValueTable.java.util.concurrent.CompletableFuture<Version>update(@NonNull TableModification update)Performs a specificTableModificationto theKeyValueTable, as described below: Ifupdateis aInsert, this will be interpreted as a Conditional Insert, so theTableEntryUpdate.getValue()will only be inserted (and associated withTableModification.getKey()if there doesn't already exist aTableKeyin theKeyValueTablethat matchesTableModification.getKey().java.util.concurrent.CompletableFuture<java.util.List<Version>>update(@NonNull java.lang.Iterable<TableModification> updates)Performs a batch ofTableModifications to theKeyValueTableforTableKeys that have the sameTableKey.getPrimaryKey().
-
-
-
Field Detail
-
MAXIMUM_VALUE_LENGTH
static final int MAXIMUM_VALUE_LENGTH
The maximum length of a Table Segment Value.- See Also:
- Constant Field Values
-
-
Method Detail
-
update
java.util.concurrent.CompletableFuture<Version> update(@NonNull @NonNull TableModification update)
Performs a specificTableModificationto theKeyValueTable, as described below:- If
updateis aInsert, this will be interpreted as a Conditional Insert, so theTableEntryUpdate.getValue()will only be inserted (and associated withTableModification.getKey()if there doesn't already exist aTableKeyin theKeyValueTablethat matchesTableModification.getKey(). - If
updateis aPut, this will be an update. IfPut.getVersion()is null, this will be interpreted as an Unconditional Update, and theTableEntryUpdate.getValue()will be associated withTableModification.getKey()in theKeyValueTableregardless of whether the Key existed before or not. IfPut.getVersion()is non-null, this will be interpreted as a Conditional Update, and theTableEntryUpdate.getValue()will only be associated withTableModification.getKey()if there exists aTableKeyin theKeyValueTablewhoseVersionmatchesPut.getVersion(). NOTE: ifPut.getVersion()equalsVersion.NOT_EXISTS, this is equivalent toInsert(i.e., it will be a Conditional Insert). - If
updateis aRemove, this will remove theTableModification.getKey()from theKeyValueTable. IfRemove.getVersion()is null, this will be interpreted as an Unconditional Removal, so the Key will be removed regardless of itsVersion(and the operation will also be successful if theTableModification.getKey()does not exist). IfRemove.getVersion()is non-null, this will be interpreted as a Conditional Removal, and the Key will only be removed if it exists and itsVersionmatchesRemove.getVersion().
- Parameters:
update- TheTableModificationto apply to theKeyValueTable.- Returns:
- A CompletableFuture that, when completed, will contain the
Versionassociated with any newly updated or inserted entry (forInsertorPut) ornullforRemove.
- If
-
update
java.util.concurrent.CompletableFuture<java.util.List<Version>> update(@NonNull @NonNull java.lang.Iterable<TableModification> updates)
Performs a batch ofTableModifications to theKeyValueTableforTableKeys that have the sameTableKey.getPrimaryKey(). All changes are performed atomically (either all or none will be accepted).See
update(TableModification)for details on Conditional/Unconditional Updates. Conditional and unconditional updates may be mixed together in this call. Each individualTableModificationwill be individually assessed (from a conditional point of view) and will prevent the entire batch from committing if it fails to meet the condition.- Parameters:
updates- AnIterableofTableModifications to apply to theKeyValueTable. Note thatRemoveinstances may not be mixed together withInsertorPutinstances, butInserts andPuts may be mixed together.- Returns:
- A CompletableFuture that, when completed, will contain a List of
Versioninstances which represent the versions for the updated or inserted keys. The size of this list will be the same as the number of items inupdatesand the versions will be in the same order as theupdates. This list will be empty ifupdatescontains onlyRemoveinstances. - Throws:
java.lang.IllegalArgumentException- If there exist two or moreTableModifications inupdatesthat refer toTableKeys with differentTableKey.getPrimaryKey().java.lang.IllegalArgumentException- Ifupdatescontains at least oneRemoveinstance and at least oneTableModificationthat is notRemove.
-
exists
java.util.concurrent.CompletableFuture<java.lang.Boolean> exists(@NonNull @NonNull TableKey key)Determines if the givenTableKeyexists or not.- Parameters:
key- TheTableKeyto check.- Returns:
- A CompletableFuture that, when completed, will contain a
Booleanrepresenting the result.
-
get
java.util.concurrent.CompletableFuture<TableEntry> get(@NonNull @NonNull TableKey key)
Gets the latest value for aTableKey.
-
getAll
java.util.concurrent.CompletableFuture<java.util.List<TableEntry>> getAll(@NonNull @NonNull java.lang.Iterable<TableKey> keys)
Gets the latest values for a set ofTableKeys.- Parameters:
keys- AnIterableof @link TableKey} to get values for.- Returns:
- A CompletableFuture that, when completed, will contain a List of
TableEntryinstances for the requested keys. The size of the list will be the same askeys.size()and the results will be in the same order as the requested keys. Any keys which do not have a value will have a null entry at their index.
-
iterator
KeyValueTableIterator.Builder iterator()
Creates a newKeyValueTableIterator.Builderthat can be used to construct and execute an Iterator over theTableKey/TableEntryinstances in thisKeyValueTable.- Returns:
- A new instance of a
KeyValueTableIterator.Builder.
-
close
void close()
Closes theKeyValueTable. No more updates, removals, retrievals or iterators may be performed using it.- Specified by:
closein interfacejava.lang.AutoCloseable- See Also:
AutoCloseable.close()
-
-