@API(value=MAINTAINED) public abstract class LocatableResolver extends Object
LocatableResolver
represents the concept of a locatable bi-directional mapping between Strings and Longs
that is rooted at some location in the FDB key space. Resolvers that are located at different positions will allocate
String to Long mappings independently. Subclasses of LocatableResolver
are responsible for implementing
create(FDBRecordContext, String)
, read(FDBRecordContext, String)
and readReverse(FDBStoreTimer, Long)
operations. See ScopedDirectoryLayer
for an implementation that leverages the FDB directory layer.
When initializing, a defaultWriteSafetyCheck
can be specified that will be evaluated on writes to determine
within the write transaction what the correct LocatableResolver
scope is for the write.Modifier and Type | Class and Description |
---|---|
static class |
LocatableResolver.LocatableResolverLockedException
Exception thrown when the locatable resolver is locked.
|
Modifier and Type | Field and Description |
---|---|
protected FDBDatabase |
database |
protected int |
hashCode |
protected com.apple.foundationdb.record.provider.foundationdb.keyspace.LocatableResolver.ResolverLocation |
location |
Modifier | Constructor and Description |
---|---|
protected |
LocatableResolver(FDBDatabase database,
KeySpacePath path,
CompletableFuture<ResolvedKeySpacePath> resolvedPath)
Created a locatable resolver.
|
Modifier and Type | Method and Description |
---|---|
protected CompletableFuture<ResolverResult> |
create(FDBRecordContext context,
String key) |
protected abstract CompletableFuture<ResolverResult> |
create(FDBRecordContext context,
String key,
byte[] metadata) |
abstract ResolverResult |
deserializeValue(byte[] value)
Deserialize the raw bytes value stored in the mapping subspace.
|
CompletableFuture<Void> |
disableWriteLock()
Unlocks this
LocatableResolver , so that calls to resolve(FDBStoreTimer, String) will create
entries if they do not exist. |
CompletableFuture<Void> |
enableWriteLock()
Puts this
LocatableResolver into a write locked state which will prevent any new entries from being created. |
boolean |
equals(Object obj) |
CompletableFuture<Void> |
exclusiveLock()
Checks the lock state for the resolver and if it is unlocked puts this
LocatableResolver into a write
locked state which will prevent any new entries from being created. |
Subspace |
getBaseSubspace()
Deprecated.
blocks until the mapping subspace is fetched from the database, instead use
getBaseSubspaceAsync() |
abstract CompletableFuture<Subspace> |
getBaseSubspaceAsync()
Get a
CompletableFuture that will contain the Subspace this resolver is rooted
at (e.g. |
FDBDatabase |
getDatabase() |
Subspace |
getMappingSubspace()
Deprecated.
blocks until the mapping subspace is fetched from the database, instead use
getMappingSubspaceAsync() |
abstract CompletableFuture<Subspace> |
getMappingSubspaceAsync()
Get a
CompletableFuture that will contain the Subspace where this resolver stores
the mappings from key String s to value Long . |
protected abstract CompletableFuture<Subspace> |
getStateSubspaceAsync() |
CompletableFuture<Integer> |
getVersion(FDBStoreTimer timer)
Gets the version as stored in the state key for this
LocatableResolver . |
int |
hashCode() |
CompletableFuture<Void> |
incrementVersion()
Increments the version of the data stored in this directory layer.
|
CompletableFuture<Long> |
mustResolve(FDBRecordContext context,
String name)
Lookup the mapping for
name within the scope of the path that this object was constructed with. |
CompletableFuture<ResolverResult> |
mustResolveWithMetadata(FDBRecordContext context,
String name)
Lookup the mapping and metadata for
name within the scope of the path that this object was constructed with. |
protected abstract CompletableFuture<Optional<ResolverResult>> |
read(FDBRecordContext context,
String key) |
protected abstract CompletableFuture<Optional<String>> |
readReverse(FDBStoreTimer timer,
Long value) |
CompletableFuture<Long> |
resolve(FDBStoreTimer timer,
String name)
Map the String
name to a Long within the scope of the path that this object was constructed with. |
CompletableFuture<Long> |
resolve(FDBStoreTimer timer,
String name,
ResolverCreateHooks hooks)
Map the String
name to a Long within the scope of the path that this object was constructed with. |
CompletableFuture<ResolverResult> |
resolveWithMetadata(FDBStoreTimer timer,
String name,
ResolverCreateHooks hooks)
Map the String
name to a ResolverResult within the scope of the path that this object was
constructed with. |
CompletableFuture<Boolean> |
retired(FDBStoreTimer timer)
Check whether this resolver has been retired.
|
CompletableFuture<Boolean> |
retiredSkipCache(FDBRecordContext context)
Check whether this resolver has been retired.
|
CompletableFuture<Void> |
retireLayer()
Retire this
LocatableResolver , indicating that it should not be used for any future resolve operations. |
CompletableFuture<String> |
reverseLookup(FDBStoreTimer timer,
Long value)
Lookup the String that maps to the provided value within the scope of the path that this object was constructed with.
|
CompletableFuture<Void> |
setMapping(FDBRecordContext context,
String key,
Long value) |
protected abstract CompletableFuture<Void> |
setMapping(FDBRecordContext context,
String key,
ResolverResult value) |
abstract CompletableFuture<Void> |
setWindow(long count) |
String |
toString() |
protected abstract CompletableFuture<Void> |
updateMetadata(FDBRecordContext context,
String key,
byte[] metadata) |
CompletableFuture<Void> |
updateMetadataAndVersion(String key,
byte[] metadata)
Transactionally update the metadata for the provided
key and (within the same transaction) increment
the version of the resolver state (see incrementVersion() . |
<T> ScopedValue<T> |
wrap(T value) |
@Nonnull protected final FDBDatabase database
@Nonnull protected final com.apple.foundationdb.record.provider.foundationdb.keyspace.LocatableResolver.ResolverLocation location
protected final int hashCode
protected LocatableResolver(@Nonnull FDBDatabase database, @Nullable KeySpacePath path, @Nullable CompletableFuture<ResolvedKeySpacePath> resolvedPath)
This constructor may seem a little strange in taking two paths that are, effectively, the same. The
encouraged behavior for your resolvers is to create them from a ResolvedKeySpacePath
, however for
backward compatibility we still allow resolvers to be created from a FDBRecordContext
and a KeySpacePath
.
All of the implementations of LocatableResolver
are built such that if they are starting
from a KeySpacePath
, they will then turn it into a resolved path, then use that to get the subspace,
but if they are created from a ResolvedKeySpacePath
, they will instead directly get the subspace.
This constructor is handed both the path and the potentially completed resolved form of that path, and when
logging the path, if the resolved path is completed, will log that since it provides more detail.
database
- the database to use for resolutionpath
- the path at which the resolver has its data locatedresolvedPath
- the resolved form of the pathpublic <T> ScopedValue<T> wrap(T value)
@Nonnull public FDBDatabase getDatabase()
public CompletableFuture<Long> resolve(@Nullable FDBStoreTimer timer, @Nonnull String name)
name
to a Long within the scope of the path that this object was constructed with.
Will return the value that's persisted in FDB or create it if it does not exist.
This method may create and commit a separate record context for the lookup.timer
- the FDBStoreTimer
used for collecting metricsname
- the value to resolvepublic CompletableFuture<Long> resolve(@Nullable FDBStoreTimer timer, @Nonnull String name, @Nonnull ResolverCreateHooks hooks)
name
to a Long within the scope of the path that this object was constructed with.
Will return the value that's persisted in FDB or create it if it does not exist.
This method may create and commit a separate record context for the lookup.timer
- the FDBStoreTimer
used for collecting metricsname
- the value to resolvehooks
- ResolverCreateHooks
to run on createpublic CompletableFuture<ResolverResult> resolveWithMetadata(@Nullable FDBStoreTimer timer, @Nonnull String name, @Nonnull ResolverCreateHooks hooks)
name
to a ResolverResult
within the scope of the path that this object was
constructed with. If we are creating the entry for name
, The ResolverCreateHooks
provided
as hooks
will be run. Any metadata that was already present or created can be seen by calling
ResolverResult.getMetadata()
on the returned result.
Will return the value that's persisted in FDB or create it if it does not exist.
This method may create and commit a separate record context for the lookup.timer
- the FDBStoreTimer
used for collecting metricsname
- the value to resolvehooks
- ResolverCreateHooks
to run on createResolverResult
containing the resolved value and metadatapublic CompletableFuture<ResolverResult> mustResolveWithMetadata(@Nonnull FDBRecordContext context, @Nonnull String name)
name
within the scope of the path that this object was constructed with.
Unlike resolveWithMetadata(FDBStoreTimer, String, ResolverCreateHooks)
this method will not attempt to
create the mapping if none exists.context
- the transaction to use to access the databasename
- the value to resolveResolverResult
NoSuchElementException
- if the value does not existpublic CompletableFuture<Long> mustResolve(@Nonnull FDBRecordContext context, @Nonnull String name)
name
within the scope of the path that this object was constructed with.
Unlike resolve(FDBStoreTimer, String)
this method will not attempt to create the mapping if none exists.context
- the transaction to use to access the databasename
- the value to resolveNoSuchElementException
- if the value does not existpublic CompletableFuture<String> reverseLookup(@Nullable FDBStoreTimer timer, @Nonnull Long value)
timer
- the FDBStoreTimer
used for collecting metricsvalue
- the value of the mapping to lookupNoSuchElementException
- if the value is not foundpublic CompletableFuture<Void> exclusiveLock()
LocatableResolver
into a write
locked state which will prevent any new entries from being created. If the resolver is not unlocked this will
throw a LocatableResolver.LocatableResolverLockedException
.
The lock state is cached for seconds. When changing the lock state,
transactions started at least seconds after this method succeeds should
see the updated state.public CompletableFuture<Void> enableWriteLock()
LocatableResolver
into a write locked state which will prevent any new entries from being created.
Does not perform any checks on the current lock state.
The lock state is cached for seconds. When changing the lock state,
transactions started at least seconds after this method succeeds should
see the updated state.public CompletableFuture<Void> disableWriteLock()
LocatableResolver
, so that calls to resolve(FDBStoreTimer, String)
will create
entries if they do not exist. The lock state is cached for seconds. When
changing the lock state, transactions started at least seconds after this
method succeeds should see the updated state.public CompletableFuture<Void> retireLayer()
LocatableResolver
, indicating that it should not be used for any future resolve operations.
This can be used to indicate that the current resolver has migrated to a new location and that clients should be
using that resolver instead.public CompletableFuture<Void> incrementVersion()
incrementVersion
to be seen by getVersion(FDBStoreTimer)
.public CompletableFuture<Integer> getVersion(@Nullable FDBStoreTimer timer)
LocatableResolver
. This is used in conjunction with
the version of the forward directory cache (see FDBDatabase.getDirectoryCacheVersion()
) to coordinate major changes
to data in the LocatableResolver
that require any future reads to directly consult FDB rather than relying
on the directory cache. On calls to resolve(FDBStoreTimer, String)
the cache version from the FDBDatabase
object is compared with the version stored in the resolver state. If the
version in the resolver state is ahead of the version in the database object, the cache associated with that database is
invalidated. Note: if the version known by the resolver is behind the version for the cache (e.g. our cached version
of the state hasn't been refreshed recently enough to see some change) we don't need to do anything special, we can trust
that values from a future version of the cache are backwards compatible to our current version.timer
- The store timer to instrument the transaction with.public CompletableFuture<Boolean> retired(@Nullable FDBStoreTimer timer)
timer
- The store timer to instrument the transaction with.public CompletableFuture<Boolean> retiredSkipCache(@Nonnull FDBRecordContext context)
context
- the transaction to use to access the databasepublic CompletableFuture<Void> updateMetadataAndVersion(@Nonnull String key, @Nullable byte[] metadata)
key
and (within the same transaction) increment
the version of the resolver state (see incrementVersion()
. An entry key
must
already exist in the directory, if it does not a NoSuchElementException
will be thrown. If you want to add
metadata to a key you are creating see the createHook
parameter in
resolveWithMetadata(FDBStoreTimer, String, ResolverCreateHooks)
.key
- the key in the directory to modifymetadata
- the new metadataprotected abstract CompletableFuture<Optional<ResolverResult>> read(@Nonnull FDBRecordContext context, String key)
protected abstract CompletableFuture<ResolverResult> create(@Nonnull FDBRecordContext context, @Nonnull String key, @Nullable byte[] metadata)
protected final CompletableFuture<ResolverResult> create(@Nonnull FDBRecordContext context, @Nonnull String key)
protected abstract CompletableFuture<Optional<String>> readReverse(FDBStoreTimer timer, Long value)
protected abstract CompletableFuture<Void> updateMetadata(FDBRecordContext context, String key, byte[] metadata)
protected abstract CompletableFuture<Void> setMapping(FDBRecordContext context, String key, ResolverResult value)
public final CompletableFuture<Void> setMapping(FDBRecordContext context, String key, Long value)
public abstract CompletableFuture<Void> setWindow(long count)
protected abstract CompletableFuture<Subspace> getStateSubspaceAsync()
@Nonnull @API(value=DEPRECATED) @Deprecated public Subspace getMappingSubspace()
getMappingSubspaceAsync()
Subspace
where this resolver stores the mappings from key
String
s to
value
Long
. Direct access to this subspace is not needed by general users and extreme care
should be taken when interacting with it.@Nonnull public abstract CompletableFuture<Subspace> getMappingSubspaceAsync()
CompletableFuture
that will contain the Subspace
where this resolver stores
the mappings from key
String
s to value
Long
. Direct access
to this subspace is not needed by general users and extreme care should be taken when interacting with it.@Nonnull @API(value=DEPRECATED) @Deprecated public Subspace getBaseSubspace()
getBaseSubspaceAsync()
Subspace
that this resolver is rooted at (e.g. the global resolver
ExtendedDirectoryLayer.global(FDBDatabase)
has a base subspace at the root of the FDB keyspace.
Note that this is not the subspace where the resolver maintains its allocation keys
(see getMappingSubspaceAsync()
).@Nonnull public abstract CompletableFuture<Subspace> getBaseSubspaceAsync()
CompletableFuture
that will contain the Subspace
this resolver is rooted
at (e.g. the global resolver ExtendedDirectoryLayer.global(FDBDatabase)
has a base
subspace at the root of the FDB keyspace. Note that this is not the subspace where the resolver
maintains its allocation keys (see getMappingSubspaceAsync()
).@Nonnull public abstract ResolverResult deserializeValue(byte[] value)
value
- raw value bytes.ResolverResult
.