@API(value=STABLE) public class FDBRecordContext extends FDBTransactionContext implements AutoCloseable
All reads and writes to the database are transactional: an open FDBRecordContext
is needed.
An FDBDatabase
is needed to open an FDBRecordContext
.
final FDBDatabase fdb = FDBDatabaseFactory.instance().getDatabase();
try (FDBRecordContext ctx = fdb.openContext()) {
...
}
FDBRecordStore
Modifier and Type | Class and Description |
---|---|
static interface |
FDBRecordContext.AfterCommit
A hook to run after commit has completed successfully.
|
static interface |
FDBRecordContext.CommitCheck
A synchronous
FDBRecordContext.CommitCheckAsync . |
static interface |
FDBRecordContext.CommitCheckAsync
A consistency check, such as uniqueness, that can execute asynchronously and is finally checked at or before commit time.
|
static interface |
FDBRecordContext.PostCommit
A supplier of a future to be executed after the transaction has been successfully committed.
|
Modifier and Type | Field and Description |
---|---|
static int |
MAX_TR_ID_SIZE
The maximum size for a transaction ID in bytes when serialized as UTF-8.
|
database, timer, transaction
Modifier | Constructor and Description |
---|---|
protected |
FDBRecordContext(FDBDatabase fdb,
Transaction transaction,
FDBRecordContextConfig config,
boolean transactionIsTraced) |
Modifier and Type | Method and Description |
---|---|
void |
addAfterCommit(FDBRecordContext.AfterCommit afterCommit)
Adds code to be executed immediately following a successful commit.
|
void |
addCommitCheck(CompletableFuture<Void> check)
Add a check to be completed before
commit() finishes. |
void |
addCommitCheck(FDBRecordContext.CommitCheckAsync check)
Add a
FDBRecordContext.CommitCheckAsync to be performed before commit() finishes. |
void |
addPostCommit(FDBRecordContext.PostCommit postCommit)
Install an anonymous post-commit hook.
|
void |
addPostCommit(String name,
FDBRecordContext.PostCommit postCommit)
Adds a new post-commit hook.
|
void |
addToLocalVersionCache(Tuple primaryKey,
int version)
Register that a specific primary key used a given local version.
|
byte[] |
addVersionMutation(byte[] key,
byte[] value)
Deprecated.
use #addVersionMutation(MutationType, byte[], byte[]) instead
|
byte[] |
addVersionMutation(MutationType mutationType,
byte[] key,
byte[] value)
Add a
SET_VERSIONSTAMPED_KEY
or SET_VERSIONTSTAMPED_VALUE
mutation to be run at commit time. |
<T> T |
asyncToSync(StoreTimer.Wait event,
CompletableFuture<T> async) |
int |
claimLocalVersion()
Claims a local version that is unique within a single transaction.
|
void |
close() |
void |
commit()
Commit an open transaction.
|
CompletableFuture<Void> |
commitAsync()
Async version of
commit() . |
Transaction |
ensureActive() |
<T> T |
get(CompletableFuture<T> future)
Get a future following the same logic that
asyncToSync() uses to validate that the operation
isn't blocking in an asynchronous context. |
long |
getCommittedVersion()
Return the eight byte version assigned to this context at commit time.
|
Optional<Integer> |
getLocalVersion(Tuple primaryKey)
Get a local version assigned to some primary key used within this context.
|
Map<String,String> |
getMdcContext() |
byte[] |
getMetaDataVersionStamp(IsolationLevel isolationLevel)
A blocking version of
getMetaDataVersionStampAsync(IsolationLevel) . |
CompletableFuture<byte[]> |
getMetaDataVersionStampAsync(IsolationLevel isolationLevel)
Get the database's meta-data version-stamp.
|
FDBRecordContext.PostCommit |
getOrCreatePostCommit(String name,
Function<String,FDBRecordContext.PostCommit> ifNotExists)
Fetches a post-commit hook, creating a new one if it does not already exist.
|
FDBRecordContext.PostCommit |
getPostCommit(String name)
Fetches a previously installed post-commit hook.
|
FDBTransactionPriority |
getPriority()
Get the priority of this transaction.
|
long |
getReadVersion()
Get the read version used by this transaction.
|
CompletableFuture<Long> |
getReadVersionAsync()
Get the read version used by this transaction.
|
long |
getTimeoutMillis()
Get the timeout time for the underlying transaction.
|
long |
getTransactionAge()
Get the number of milliseconds since context was created.
|
long |
getTransactionCreateTime() |
String |
getTransactionId()
Get the ID used by FoundationDB to track this transaction.
|
byte[] |
getVersionStamp()
Return the ten byte version-stamp assigned to this context at commit time.
|
FDBDatabase.WeakReadSemantics |
getWeakReadSemantics() |
boolean |
hasDirtyStoreState()
Return whether any record store opened with this context has had its cache-able store state modified.
|
boolean |
hasHookForAsyncToSync() |
boolean |
hasReadVersion()
Get whether this transaction's read version has already been set.
|
boolean |
isClosed() |
boolean |
isLogged()
Get whether the current transaction details are logged to the client trace logs.
|
<T> T |
join(CompletableFuture<T> future)
Join a future following the same logic that
asyncToSync() uses to validate that the operation
isn't blocking in an asynchronous context. |
<T> T |
joinNow(CompletableFuture<T> future)
Join a future but validate that the future is already completed.
|
void |
logTransaction()
Write the details of this transaction to the FoundationDB client logs.
|
FDBDatabaseRunner |
newRunner()
Get a new
FDBDatabaseRunner that will run contexts similar to this one. |
ReadTransaction |
readTransaction(boolean snapshot) |
boolean |
removeLocalVersion(Tuple primaryKey)
Remove the local version associated with a single primary key.
|
FDBRecordContext.PostCommit |
removePostCommit(String name)
Remove a previously installed post-commit hook.
|
byte[] |
removeVersionMutation(byte[] key)
Remove a
SET_VERSIONSTAMPED_KEY
mutation that would have been run at commit time. |
void |
runAfterCommits()
Deprecated.
this method probably should never have been public
|
CompletableFuture<Void> |
runCommitChecks()
Run any
FDBRecordContext.CommitCheckAsync s that are still outstanding. |
void |
setDirtyStoreState(boolean dirtyStoreState) |
void |
setHookForAsyncToSync(Consumer<StoreTimer.Wait> hook) |
void |
setMetaDataVersionStamp()
Update the meta-data version-stamp.
|
long |
setReadVersion(long readVersion)
Set the read version used by this transaction.
|
void |
timeReadSampleKey(byte[] key) |
byte[] |
updateVersionMutation(MutationType mutationType,
byte[] key,
byte[] value,
BiFunction<byte[],byte[],byte[]> remappingFunction) |
getDatabase, getExecutor, getTimer, increment, increment, instrument, instrument, instrument, instrument, record, record, setTimer
public static final int MAX_TR_ID_SIZE
FDBDatabase.openContext(Map, FDBStoreTimer, FDBDatabase.WeakReadSemantics, FDBTransactionPriority, String)
should be truncated or dropped. Note that Java String
s are encoded using UTF-16, so using
String.length()
is insufficient to know if the transaction ID will be too large if it contains
any non-ASCII characters (though it is recommended that all transaction IDs be printable ASCII characters
as those are the ones that render well in the logs). To get the size in UTF-8, one can serialize the
string to UTF-8 using String.getBytes(Charset)
or check its encoded size using
Utf8.encodedLength(CharSequence)
or an equivalent function.
Note that this limit is inherited by the Record Layer from the FoundationDB client. In particular, the
TransactionOptions.setDebugTransactionIdentifier(String)
method will
not accept IDs longer than 100 bytes in length.
protected FDBRecordContext(@Nonnull FDBDatabase fdb, @Nonnull Transaction transaction, @Nonnull FDBRecordContextConfig config, boolean transactionIsTraced)
@Nullable public String getTransactionId()
null
, then no ID has been set. This means that
it is unsafe to call logTransaction()
on this context if this method returns null
.
This ID is used by FoundationDB internally in a few different places, including the transaction sample, large transaction monitoring, and client trace logs if transaction logging is enabled for that transaction. If the caller already has a notion of "request ID", then one strategy might be to set the transaction's ID to the initiating request's ID so that one can correlate requests and transactions.
The transaction ID is limited in size to 100 bytes when encoded as UTF-8. In general, most callers should limit IDs to printable ASCII characters (as those are the only characters that are easily readable in the client trace logs). If the provided ID exceeds 100 bytes, it will be truncated or possibly ignored if truncating the ID cannot be done safely.
To set this ID, the user can call either FDBDatabase.openContext(Map, FDBStoreTimer, FDBDatabase.WeakReadSemantics, FDBTransactionPriority, String)
and provided a non-null
transaction ID as a parameter, or the user can call
FDBDatabase.openContext(Map, FDBStoreTimer)
or FDBDatabase.openContext(Map, FDBStoreTimer, FDBDatabase.WeakReadSemantics)
and set the "uuid" key to the desired transaction ID in the MDC context. In either case, note that the
transaction ID is limited in size to 100 bytes when encoded in UTF-8. In general, most callers should limit
IDs to printable ASCII characters (as those are the only characters that are easily readable in the client trace
logs). If the provided ID exceeds 100 bytes, it will be truncated or possibly ignored if truncating the ID
cannot be done safely.
null
if not setlogTransaction()
public long getTimeoutMillis()
FDBDatabaseFactory
, an FDBDatabaseRunner
, or an FDBRecordContextConfig
. If this
returns FDBDatabaseFactory.DEFAULT_TR_TIMEOUT_MILLIS
, then this indicates that the transaction was
set using the default system timeout, which is configured with DatabaseOptions.setTransactionTimeout(long)
.
As those options can not be inspected through FoundationDB Java bindings, this method cannot return an
accurate result. Likewise, if a user explicitly sets the underlying option using TransactionOptions.setTimeout(long)
,
then this method will not return an accurate result.FDBDatabaseFactory.setTransactionTimeoutMillis(long)
,
FDBDatabaseRunner.setTransactionTimeoutMillis(long)
,
FDBRecordContextConfig.Builder.setTransactionTimeoutMillis(long)
,
FDBExceptions.FDBStoreTransactionTimeoutException
public final void logTransaction()
All of the transaction's entries will be tagged with this transaction's ID. If an ID has not been set, this
method will throw a RecordCoreException
. As a result, the user is encouraged to call
getTransactionId()
before calling this method.
public boolean isLogged()
logTransaction()
.
See logTransaction()
for more details.logTransaction()
public boolean isClosed()
public void close()
close
in interface AutoCloseable
public void commit()
public CompletableFuture<Void> commitAsync()
commit()
.@Nonnull public Transaction ensureActive()
ensureActive
in class FDBTransactionContext
public long setReadVersion(long readVersion)
getReadVersionAsync()
or getReadVersion()
, this method may throw a
RecordCoreException
indicating that there is already an outstanding read version request
if that request has not yet completed.readVersion
- the read version this transaction should use if is not already setReadTransaction.setReadVersion(long)
@Nonnull public CompletableFuture<Long> getReadVersionAsync()
Note that this method is synchronized
, but only creating the future (not waiting on
the future) will block other threads. Thus, while it is advised that this method only be called once
and by only one caller at a time, if it safe to use this method in asynchronous contexts. If this method is
called multiple times, then the same future will be returned each time.
ReadTransaction.getReadVersion()
public long getReadVersion()
getReadVersionAsync()
.
Note that if the read version has already been set or gotten (either by calling setReadVersion(long)
or
getReadVersionAsync()
or this method), then the previously set read version is returned immediately,
and this method will not block. One can check if the read version has already been set by calling
hasReadVersion()
.getReadVersionAsync()
,
ReadTransaction.getReadVersion()
public boolean hasReadVersion()
true
if someone has explicitly called setReadVersion(long)
or
getReadVersion()
on this context or if a getReadVersionAsync()
call has completed, and it will
return false
otherwise. If this returns true
, then getReadVersionAsync()
will return
an immediately ready future and getReadVersion()
is non-blocking.getReadVersionAsync()
,
setReadVersion(long)
,
ReadTransaction.getReadVersion()
@Nonnull public ReadTransaction readTransaction(boolean snapshot)
public long getTransactionAge()
public long getTransactionCreateTime()
@API(value=INTERNAL) public boolean hasDirtyStoreState()
This method is internal to the Record Layer and should not be used by external consumers.
public void addCommitCheck(@Nonnull FDBRecordContext.CommitCheckAsync check)
FDBRecordContext.CommitCheckAsync
to be performed before commit()
finishes.
This method is suitable for checks that cannot be started until just before commit.
For checks that can be started before addCommitCheck
time, addCommitCheck(CompletableFuture)
may be more convenient.
It is possible for this method to throw an exception caused by an earlier unsuccessful check that has become ready in the meantime.
check
- the check to be performedpublic void addCommitCheck(@Nonnull CompletableFuture<Void> check)
commit()
finishes.
commit()
will wait for the future to be completed (exceptionally if the check fails)
before committing the underlying transaction.
It is possible for this method to throw an exception caused by an earlier unsuccessful check that has become ready in the meantime.
check
- the check to be performed@Nonnull public CompletableFuture<Void> runCommitChecks()
FDBRecordContext.CommitCheckAsync
s that are still outstanding.@Nonnull public FDBRecordContext.PostCommit getOrCreatePostCommit(@Nonnull String name, @Nonnull Function<String,FDBRecordContext.PostCommit> ifNotExists)
name
- name of the post-commit hookifNotExists
- if the post-commit hook has not been previously installed, a function that will be
called to install a new hook by the provided name@Nullable public FDBRecordContext.PostCommit getPostCommit(@Nonnull String name)
name
- the name of the post-commit hooknull
if there is no hook by the
provided name
public void addPostCommit(@Nonnull String name, @Nonnull FDBRecordContext.PostCommit postCommit)
if (context.getPostCommit("myPostCommit")) { context.addPostCommit("myPostCommit", () -> ..); }if you need this behavior use
getOrCreatePostCommit(String, Function)
instead.name
- name of the post-commitpostCommit
- the post commit to installpublic void addPostCommit(@Nonnull FDBRecordContext.PostCommit postCommit)
getPostCommit(String)
.postCommit
- post-commit hook to install@Nullable public FDBRecordContext.PostCommit removePostCommit(@Nonnull String name)
name
- the name of the hook to removenull
if the hook does not exist, otherwise the handle to the previously installed hookpublic void addAfterCommit(@Nonnull FDBRecordContext.AfterCommit afterCommit)
afterCommit
- code to be executed following successful commit@Deprecated @API(value=DEPRECATED) public void runAfterCommits()
public long getCommittedVersion()
null
IllegalStateException
- if this is called prior to the transaction being committed@Nullable public byte[] getVersionStamp()
getCommittedVersion()
. This version is
compatible with the "global version" that is required by the FDBRecordVersion
class and can be used to construct a complete record version from an incomplete one.
If this transaction is read only, then no version will ever be assigned to this commit, so this
function will return null
.null
IllegalStateException
- if this is called prior to the transaction being committed@Nonnull public CompletableFuture<byte[]> getMetaDataVersionStampAsync(@Nonnull IsolationLevel isolationLevel)
This key can only be updated by calling setMetaDataVersionStamp()
, which will set the key
to the transaction's version-stamp when the transaction is committed.
If the key is set within the context of this transaction, this method will return null
.
isolationLevel
- the isolation level at which to read the keynull
if it is
unset or has been updated during the course of this transaction@Nullable public byte[] getMetaDataVersionStamp(@Nonnull IsolationLevel isolationLevel)
getMetaDataVersionStampAsync(IsolationLevel)
.isolationLevel
- the isolation level at which to read the keynull
if it is unset or has been updated during the course of this transactiongetMetaDataVersionStampAsync(IsolationLevel)
public void setMetaDataVersionStamp()
getMetaDataVersionStamp(IsolationLevel)
,
and those transactions may use that value to invalidate any stale cache entries using the
meta-data version-stamp key. After this method has been called, any calls to getMetaDataVersionStamp()
will return null
. After this context has been committed, one may call getVersionStamp()
to get the value that this transaction wrote to the database.@Nullable public <T> T asyncToSync(StoreTimer.Wait event, @Nonnull CompletableFuture<T> async)
public <T> T join(CompletableFuture<T> future)
asyncToSync()
uses to validate that the operation
isn't blocking in an asynchronous context.T
- the type of the value produced by the futurefuture
- the future to be completedFDBDatabase.join(CompletableFuture)
public <T> T joinNow(CompletableFuture<T> future)
BlockingInAsyncDetection
behavior is set
to throw an exception on incomplete futures and otherwise just log that future was waited on.T
- the type of the value produced by the futurefuture
- the future that should already be completedFDBDatabase.joinNow(CompletableFuture)
public <T> T get(CompletableFuture<T> future) throws InterruptedException, ExecutionException
asyncToSync()
uses to validate that the operation
isn't blocking in an asynchronous context.T
- the type of the value produced by the futurefuture
- the future to be completedCancellationException
- if the future was cancelledExecutionException
- if the future completed exceptionallyInterruptedException
- if the current thread was interruptedFDBDatabase.get(CompletableFuture)
public void timeReadSampleKey(byte[] key)
@Nonnull public FDBDatabaseRunner newRunner()
FDBDatabaseRunner
that will run contexts similar to this one.
public int claimLocalVersion()
public void addToLocalVersionCache(@Nonnull Tuple primaryKey, int version)
getLocalVersion
.primaryKey
- key to associate with the local versionversion
- the local version of the keypublic boolean removeLocalVersion(@Nonnull Tuple primaryKey)
primaryKey
- the key associated with the local version being cleared@Nonnull public Optional<Integer> getLocalVersion(@Nonnull Tuple primaryKey)
addToLocalVersion
, then this
will return an unset Optional
.primaryKey
- key to retrieve the local version ofOptional
@Deprecated @Nullable public byte[] addVersionMutation(@Nonnull byte[] key, @Nonnull byte[] value)
SET_VERSIONSTAMPED_KEY
mutation to be run at commit time. This method is deprecated in favor of
addVersionMutation(MutationType, byte[], byte[])
which
behaves like this method except that the choice of SET_VERSIONSTAMPED_KEY
as the mutation type must be made explicitly.key
- key bytes for the mutationvalue
- parameter bytes for the mutationnull
if unset@Nullable public byte[] addVersionMutation(@Nonnull MutationType mutationType, @Nonnull byte[] key, @Nonnull byte[] value)
SET_VERSIONSTAMPED_KEY
or SET_VERSIONTSTAMPED_VALUE
mutation to be run at commit time. When called, this updates a local
cache of these mutations. The commitAsync
method
will then be sure to flush these mutations to the transaction prior to
calling commit.mutationType
- the type of versionstamp mutationkey
- key bytes for the mutationvalue
- parameter bytes for the mutationnull
if unset@Nullable public byte[] removeVersionMutation(@Nonnull byte[] key)
SET_VERSIONSTAMPED_KEY
mutation that would have been run at commit time. When called, this updates a local
cache of these mutations. This will only work as expected if the dummy
bytes included that stand in for the versionstamp within the key bytes
are equal to the dummy bytes for whatever key is included in the
cache already. (For example, one might use entirely 0xff
bytes for those dummy bytes for all incomplete versions. This is what
the FDBRecordVersion
class does.)key
- key bytes appropriate for mutation to setnull
if unset@Nullable public byte[] updateVersionMutation(@Nonnull MutationType mutationType, @Nonnull byte[] key, @Nonnull byte[] value, @Nonnull BiFunction<byte[],byte[],byte[]> remappingFunction)
@Nullable public FDBDatabase.WeakReadSemantics getWeakReadSemantics()
@Nonnull public FDBTransactionPriority getPriority()
DEFAULT
priority transactions are favored over BATCH
priority transactions.FDBTransactionPriority
public void setHookForAsyncToSync(@Nonnull Consumer<StoreTimer.Wait> hook)
public boolean hasHookForAsyncToSync()