Interface Transaction
- All Superinterfaces:
AutoCloseable
,ReadTransaction
,ReadTransactionContext
,TransactionContext
In FoundationDB, a transaction is a mutable snapshot of a database. All read and write operations on a transaction see and modify an otherwise-unchanging version of the database and only change the underlying database if and when the transaction is committed. Read operations do see the effects of previous write operations on the same transaction. Committing a transaction usually succeeds in the absence of conflicts.
Transactions group operations into a unit with the properties of atomicity, isolation, and durability. Transactions also provide the ability to maintain an application's invariants or integrity constraints, supporting the property of consistency. Together these properties are known as ACID.
Transactions are also causally consistent: once a transaction has been successfully committed, all subsequently created transactions will see the modifications made by it. The most convenient way for a developer to manage the lifecycle and retrying of a
Transaction
is to use Database.run(Function)
. Otherwise, the client
must have retry logic for fatal failures, failures to commit, and other transient errors.Keys and values in FoundationDB are byte arrays. To encode other data types, see the
Tuple API
and
tuple layer documentation.When used as a
TransactionContext
, the methods run()
and
runAsync()
on a Transaction
will simply attempt the operations
without any retry loop.Note: Client must call
commit()
and wait on the result on all transactions, even
ones that only read. This is done automatically when using the retry loops from
Database.run(Function)
. This is because outstanding reads originating from a
Transaction
will be cancelled when a Transaction
is garbage collected.
Since the garbage collector reserves the right to collect an in-scope object if it
determines that there are no subsequent references it it, this can happen in seemingly
innocuous situations. CompletableFuture
s returned from commit()
will block until
all reads are complete, thereby saving the calling code from this potentially confusing
situation.Note: All keys with a first byte of
0xff
are reserved for internal use.Note: Java transactions automatically set the
TransactionOptions.setUsedDuringCommitProtectionDisable()
option. This is because the Java bindings disallow use of Transaction
objects after onError(java.lang.Throwable)
is called.Note:
Transaction
objects must be closed
when no longer
in use in order to free any associated resources.-
Field Summary
Fields inherited from interface com.apple.foundationdb.ReadTransaction
ROW_LIMIT_UNLIMITED
-
Method Summary
Modifier and TypeMethodDescriptionvoid
addReadConflictKey
(byte[] key) Adds a key to the transaction's read conflict ranges as if you had read the key.void
addReadConflictRange
(byte[] keyBegin, byte[] keyEnd) Adds a range of keys to the transaction's read conflict ranges as if you had read the range.void
addWriteConflictKey
(byte[] key) Adds a key to the transaction's write conflict ranges as if you had written the key.void
addWriteConflictRange
(byte[] keyBegin, byte[] keyEnd) Adds a range of keys to the transaction's write conflict ranges as if you had cleared the range.void
cancel()
Cancels theTransaction
.void
clear
(byte[] key) Clears a given key from the database.void
clear
(byte[] beginKey, byte[] endKey) Clears a range of keys in the database.void
Clears a range of keys in the database.void
clearRangeStartsWith
(byte[] prefix) Deprecated.void
close()
Close theTransaction
object and release any associated resources.commit()
Commit thisTransaction
.Returns a future that will contain the approximated size of the commit, which is the summation of mutations, read conflict ranges, and write conflict ranges.Gets the version number at which a successful commit modified the database.Returns theDatabase
that thisTransaction
is interacting with.CompletableFuture<byte[]>
Returns a future which will contain the versionstamp which was used by any versionstamp operations in this transaction.void
mutate
(MutationType optype, byte[] key, byte[] param) An atomic operation is a single database command that carries out several logical steps: reading the value of a key, performing a transformation on that value, and writing the result.Resets a transaction and returns a delayed signal for error recovery.<T> T
run
(Function<? super Transaction, T> retryable) Run a function once against thisTransaction
.<T> CompletableFuture<T>
runAsync
(Function<? super Transaction, ? extends CompletableFuture<T>> retryable) Run a function once against thisTransaction
.void
set
(byte[] key, byte[] value) Sets the value for a given key.watch
(byte[] key) Creates a watch that will become ready when it reports a change to the value of the specified key.
A watch's behavior is relative to the transaction that created it.Methods inherited from interface com.apple.foundationdb.ReadTransaction
addReadConflictKeyIfNotSnapshot, addReadConflictRangeIfNotSnapshot, get, getBlobGranuleRanges, getEstimatedRangeSizeBytes, getEstimatedRangeSizeBytes, getKey, getMappedRange, getRange, getRange, getRange, getRange, getRange, getRange, getRange, getRange, getRange, getRange, getRange, getRange, getRangeSplitPoints, getRangeSplitPoints, getReadVersion, isSnapshot, options, setReadVersion, snapshot
Methods inherited from interface com.apple.foundationdb.ReadTransactionContext
getExecutor, read, readAsync
-
Method Details
-
addReadConflictRange
void addReadConflictRange(byte[] keyBegin, byte[] keyEnd) Adds a range of keys to the transaction's read conflict ranges as if you had read the range. As a result, other transactions that write a key in this range could cause the transaction to fail with a conflict.- Parameters:
keyBegin
- the first key in the range (inclusive)keyEnd
- the ending key for the range (exclusive)
-
addReadConflictKey
void addReadConflictKey(byte[] key) Adds a key to the transaction's read conflict ranges as if you had read the key. As a result, other transactions that concurrently write this key could cause the transaction to fail with a conflict.- Parameters:
key
- the key to be added to the read conflict range set
-
addWriteConflictRange
void addWriteConflictRange(byte[] keyBegin, byte[] keyEnd) Adds a range of keys to the transaction's write conflict ranges as if you had cleared the range. As a result, other transactions that concurrently read a key in this range could fail with a conflict.- Parameters:
keyBegin
- the first key in the range (inclusive)keyEnd
- the ending key for the range (exclusive)
-
addWriteConflictKey
void addWriteConflictKey(byte[] key) Adds a key to the transaction's write conflict ranges as if you had written the key. As a result, other transactions that concurrently read this key could fail with a conflict.- Parameters:
key
- the key to be added to the range
-
set
void set(byte[] key, byte[] value) Sets the value for a given key. This will not affect the database untilcommit()
is called.- Parameters:
key
- the key whose value is to be setvalue
- the value to set in the database- Throws:
IllegalArgumentException
- ifkey
orvalue
isnull
FDBException
- if the set operation otherwise fails
-
clear
void clear(byte[] key) Clears a given key from the database. This will not affect the database untilcommit()
is called.- Parameters:
key
- the key whose value is to be cleared- Throws:
IllegalArgumentException
- ifkey
isnull
FDBException
- if clear operation otherwise fails
-
clear
void clear(byte[] beginKey, byte[] endKey) Clears a range of keys in the database. The upper bound of the range is exclusive; that is, the key (if one exists) that is specified as the end of the range will NOT be cleared as part of this operation. Range clears are efficient with FoundationDB -- clearing large amounts of data will be fast. This will not affect the database untilcommit()
is called.- Parameters:
beginKey
- the first clearendKey
- the key one past the last key to clear- Throws:
IllegalArgumentException
- ifbeginKey
orendKey
isnull
FDBException
- if the clear operation otherwise fails
-
clear
Clears a range of keys in the database. The upper bound of the range is exclusive; that is, the key (if one exists) that is specified as the end of the range will NOT be cleared as part of this operation. Range clears are efficient with FoundationDB -- clearing large amounts of data will be fast. However, this will not immediately free up disk - data for the deleted range is cleaned up in the background. This will not affect the database untilcommit()
is called.
For purposes of computing the transaction size, only the begin and end keys of a clear range are counted. The size of the data stored in the range does not count against the transaction size limit.- Parameters:
range
- the range of keys to clear- Throws:
FDBException
- if the clear operation fails
-
clearRangeStartsWith
Deprecated.Replace with calls toclear(Range)
with a parameter from a call toRange.startsWith(byte[])
.- Parameters:
prefix
- the starting bytes from the keys to be cleared.- Throws:
FDBException
- if the clear-range operation fails
-
mutate
An atomic operation is a single database command that carries out several logical steps: reading the value of a key, performing a transformation on that value, and writing the result. Different atomic operations perform different transformations. Like other database operations, an atomic operation is used within a transaction.
Atomic operations do not expose the current value of the key to the client but simply send the database the transformation to apply. In regard to conflict checking, an atomic operation is equivalent to a write without a read. It can only cause other transactions performing reads of the key to conflict.
By combining these logical steps into a single, read-free operation, FoundationDB can guarantee that the transaction will not conflict due to the operation. This makes atomic operations ideal for operating on keys that are frequently modified. A common example is the use of a key-value pair as a counter.
Note: If a transaction uses both an atomic operation and a serializable read on the same key, the benefits of using the atomic operation (for both conflict checking and performance) are lost. The behavior of eachMutationType
is documented at its definition.- Parameters:
optype
- the operation to performkey
- the target of the operationparam
- the value with which to modify the key
-
commit
CompletableFuture<Void> commit()Commit thisTransaction
. See notes in class description. Consider usingDatabase
'srun()
calls for managing transactional access to FoundationDB.As with other client/server databases, in some failure scenarios a client may be unable to determine whether a transaction succeeded. In these cases, an
FDBException
will be thrown with error codecommit_unknown_result
(1021). TheonError(java.lang.Throwable)
function regards this exception as a retryable one, so retry loops that don't specifically detectcommit_unknown_result
could end up executing a transaction twice. For more information, see the FoundationDB Developer Guide documentation.If any operation is performed on a transaction after a commit has been issued but before it has returned, both the commit and the operation will throw an error code
used_during_commit
(2017). In this case, all subsequent operations on this transaction will throw this error.- Returns:
- a
CompletableFuture
that, when set without error, guarantees theTransaction
's modifications committed durably to the database. If the commit failed, it will throw anFDBException
.
-
getCommittedVersion
Long getCommittedVersion()Gets the version number at which a successful commit modified the database. This must be called only after the successful (non-error) completion of a call tocommit()
on thisTransaction
, or the behavior is undefined. Read-only transactions do not modify the database when committed and will have a committed version of -1. Keep in mind that a transaction which reads keys and then sets them to their current values may be optimized to a read-only transaction.- Returns:
- the database version at which the commit succeeded
-
getVersionstamp
CompletableFuture<byte[]> getVersionstamp()Returns a future which will contain the versionstamp which was used by any versionstamp operations in this transaction. The future will be ready only after the successful completion of a call tocommit()
on thisTransaction
. Read-only transactions do not modify the database when committed and will result in the future completing with an error. Keep in mind that a transaction which reads keys and then sets them to their current values may be optimized to a read-only transaction.- Returns:
- a future containing the versionstamp which was used for any versionstamp operations in this transaction
-
getApproximateSize
CompletableFuture<Long> getApproximateSize()Returns a future that will contain the approximated size of the commit, which is the summation of mutations, read conflict ranges, and write conflict ranges. This can be called multiple times before transaction commit.- Returns:
- a future that will contain the approximated size of the commit.
-
onError
Resets a transaction and returns a delayed signal for error recovery. If the error encountered by theTransaction
could not be recovered from, the returnedCompletableFuture
will be set to an error state. The currentTransaction
object will be invalidated by this call and will throw errors when used. The newly resetTransaction
will be returned through theCompletableFuture
if the error was retryable. If the error is not retryable, then no resetTransaction
is returned, leaving thisTransaction
permanently invalidated.- Parameters:
e
- the error caught while executing get()s and set()s on thisTransaction
- Returns:
- a
CompletableFuture
to be set with a resetTransaction
object to retry the transaction
-
cancel
void cancel()Cancels theTransaction
. All pending and any future uses of theTransaction
will throw anRuntimeException
. -
watch
Creates a watch that will become ready when it reports a change to the value of the specified key.
A watch's behavior is relative to the transaction that created it. A watch will report a change in relation to the key's value as readable by that transaction. The initial value used for comparison is either that of the transaction's read version or the value as modified by the transaction itself prior to the creation of the watch. If the value changes and then changes back to its initial value, the watch might not report the change.
Until the transaction that created it has been committed, a watch will not report changes made by other transactions. In contrast, a watch will immediately report changes made by the transaction itself. Watches cannot be created if the transaction has setTransactionOptions.setReadYourWritesDisable()
, and an attempt to do so will raise awatches_disabled
exception.
If the transaction used to create a watch encounters an exception during commit, then the watch will be set with that exception. A transaction whose commit result is unknown will set all of its watches with thecommit_unknown_result
exception. If an uncommitted transaction is reset viaonError(java.lang.Throwable)
or destroyed, then any watches it created will be set with thetransaction_cancelled
exception.
By default, each database connection can have no more than 10,000 watches that have not yet reported a change. When this number is exceeded, an attempt to create a watch will raise atoo_many_watches
exception. Because a watch outlives the transaction that creates it, any watch that is no longer needed should be cancelled.
NOTE: calling code must callcommit()
for the watch to be registered with the database.- Parameters:
key
- the key to watch for changes in value- Returns:
- a
CompletableFuture
that will become ready when the value changes - Throws:
FDBException
- if too many watches have been created on this database. The limit defaults to 10,000 and can be modified with a call toDatabaseOptions.setMaxWatches(long)
.
-
getDatabase
Database getDatabase()Returns theDatabase
that thisTransaction
is interacting with.- Returns:
- the
Database
object
-
run
Run a function once against thisTransaction
. This call blocks while user code is executing, returning the result of that code on completion.- Specified by:
run
in interfaceTransactionContext
- Type Parameters:
T
- the return type ofretryable
- Parameters:
retryable
- the block of logic to execute against thisTransaction
- Returns:
- a result of the single call to
retryable
-
runAsync
<T> CompletableFuture<T> runAsync(Function<? super Transaction, ? extends CompletableFuture<T>> retryable) Run a function once against thisTransaction
. This call returns immediately with aCompletableFuture
handle to the result.- Specified by:
runAsync
in interfaceTransactionContext
- Type Parameters:
T
- the return type ofretryable
- Parameters:
retryable
- the block of logic to execute against thisTransaction
- Returns:
- a
CompletableFuture
that will be set to the return value ofretryable
-
close
void close()Close theTransaction
object and release any associated resources. This must be called at least once after theTransaction
object is no longer in use. This can be called multiple times, but care should be taken that it is not in use in another thread at the time of the call.- Specified by:
close
in interfaceAutoCloseable
-