mirror of
https://github.com/apple/foundationdb.git
synced 2025-05-31 10:14:52 +08:00
The tenant cache uses a simpler eviction policy. Some various improvement around the use of futures. Add documentation for C API and fix inaccurate statement in special keys documentation.
This commit is contained in:
parent
06f088e088
commit
0536e56725
documentation/sphinx/source
fdbclient
@ -6,6 +6,7 @@
|
||||
.. |database-type| replace:: ``FDBDatabase``
|
||||
.. |database-class| replace:: :type:`FDBDatabase`
|
||||
.. |database-auto| replace:: FIXME
|
||||
.. |tenant-type| replace:: `FDBTenant``
|
||||
.. |transaction-class| replace:: FIXME
|
||||
.. |get-key-func| replace:: :func:`fdb_transaction_get_key()`
|
||||
.. |get-range-func| replace:: :func:`fdb_transaction_get_range()`
|
||||
@ -419,9 +420,20 @@ An |database-blurb1| Modifications to a database are performed via transactions.
|
||||
|
||||
|option-doc|
|
||||
|
||||
.. function:: fdb_error_t fdb_database_open_tenant(FDBDatabase* database, uint8_t const* tenant_name, int tenant_name_length, FDBTenant** out_tenant)
|
||||
|
||||
Opens a tenant on the given database. All transactions created by this tenant will operate on the tenant's key-space. The caller assumes ownership of the :type:`FDBTenant` object and must destroy it with :func:`fdb_tenant_destroy()`.
|
||||
|
||||
``tenant_name``
|
||||
The name of the tenant being accessed, as a byte string.
|
||||
``tenant_name_length``
|
||||
The length of the tenant name byte string.
|
||||
``*out_tenant``
|
||||
Set to point to the newly created :type:`FDBTenant`.
|
||||
|
||||
.. function:: fdb_error_t fdb_database_create_transaction(FDBDatabase* database, FDBTransaction** out_transaction)
|
||||
|
||||
Creates a new transaction on the given database. The caller assumes ownership of the :type:`FDBTransaction` object and must destroy it with :func:`fdb_transaction_destroy()`.
|
||||
Creates a new transaction on the given database without using a tenant, meaning that it will operate on the entire database key-space. The caller assumes ownership of the :type:`FDBTransaction` object and must destroy it with :func:`fdb_transaction_destroy()`.
|
||||
|
||||
``*out_transaction``
|
||||
Set to point to the newly created :type:`FDBTransaction`.
|
||||
@ -486,6 +498,26 @@ An |database-blurb1| Modifications to a database are performed via transactions.
|
||||
|
||||
Returns a value where 0 indicates that the client is idle and 1 (or larger) indicates that the client is saturated. By default, this value is updated every second.
|
||||
|
||||
Tenant
|
||||
======
|
||||
|
||||
|tenant-blurb1|
|
||||
|
||||
.. type:: FDBTenant
|
||||
|
||||
An opaque type that represents a tenant in the FoundationDB C API.
|
||||
|
||||
.. function:: void fdb_tenant_destroy(FDBTenant* tenant)
|
||||
|
||||
Destroys an :type:`FDBTenant` object. It must be called exactly once for each successful call to :func:`fdb_database_create_tenant()`. This function only destroys a handle to the tenant -- the tenant and its data will be fine!
|
||||
|
||||
.. function:: fdb_error_t fdb_tenant_create_transaction(FDBTenant* tenant, FDBTronsaction **out_transaction)
|
||||
|
||||
Creates a new transaction on the given tenant. This transaction will operate within the tenant's key-space and cannot access data outside the tenant. The caller assumes ownership of the :type:`FDBTransaction` object and must destroy it with :func:`fdb_transaction_destroy()`.
|
||||
|
||||
``*out_transaction``
|
||||
Set to point to the newly created :type:`FDBTransaction`.
|
||||
|
||||
Transaction
|
||||
===========
|
||||
|
||||
|
@ -74,6 +74,9 @@
|
||||
.. |database-sync| replace::
|
||||
The convenience methods provided by |database-type| have the same signature as the corresponding methods of ``Transaction``. However, most of the |database-type| methods are fully synchronous. (An exception is the methods for watches.) As a result, the |database-type| methods do not support the use of :ref:`implicit parallelism with futures <developer-guide-programming-with-futures>`.
|
||||
|
||||
.. |tenant-blurb1| replace::
|
||||
|tenant-type| represents a FoundationDB tenant. Tenants are optional named transaction domains that can be used to provide multiple disjoint key-spaces to client applications. A transaction created in a tenant will be limited to the keys contained within that tenant, and transactions operating on different tenants can use the same key names without interfering with each other.
|
||||
|
||||
.. |keysel-blurb1| replace::
|
||||
FoundationDB's lexicographically ordered data model permits finding keys based on their order (for example, finding the first key in the database greater than a given key). Key selectors represent a description of a key in the database that could be resolved to an actual key by |get-key-func| or used directly as the beginning or end of a range in |get-range-func|.
|
||||
|
||||
@ -627,4 +630,4 @@
|
||||
|
||||
.. |option-set-distributed-client-tracer| replace::
|
||||
|
||||
Sets a tracer to run on the client. Should be set to the same value as the tracer set on the server.
|
||||
Sets a tracer to run on the client. Should be set to the same value as the tracer set on the server.
|
||||
|
@ -205,7 +205,7 @@ that process, and wait for necessary data to be moved away.
|
||||
#. ``\xff\xff/management/failed_locality/<locality>`` Read/write. Indicates that the cluster should consider matching processes as permanently failed. This allows the cluster to avoid maintaining extra state and doing extra work in the hope that these processes come back. See :ref:`removing machines from a cluster <removing-machines-from-a-cluster>` for documentation for the corresponding fdbcli command.
|
||||
#. ``\xff\xff/management/options/excluded_locality/force`` Read/write. Setting this key disables safety checks for writes to ``\xff\xff/management/excluded_locality/<locality>``. Setting this key only has an effect in the current transaction and is not persisted on commit.
|
||||
#. ``\xff\xff/management/options/failed_locality/force`` Read/write. Setting this key disables safety checks for writes to ``\xff\xff/management/failed_locality/<locality>``. Setting this key only has an effect in the current transaction and is not persisted on commit.
|
||||
#. ``\xff\xff/management/tenant_map/<tenant>`` Read/write. Setting a key in this range to any value will result in a tenant being created with name ``<tenant>``. Clearing a key in this range will delete the tenant with name ``<tenant>``. Reading all or a portion of this range will return the list of tenants currently present in the cluster, excluding any changes in this transaction. Values read in this range will be JSON objects containing the metadata for the associated tenants. Note: the tenants key-space does not support range clears.
|
||||
#. ``\xff\xff/management/tenant_map/<tenant>`` Read/write. Setting a key in this range to any value will result in a tenant being created with name ``<tenant>``. Clearing a key in this range will delete the tenant with name ``<tenant>``. Reading all or a portion of this range will return the list of tenants currently present in the cluster, excluding any changes in this transaction. Values read in this range will be JSON objects containing the metadata for the associated tenants.
|
||||
|
||||
An exclusion is syntactically either an ip address (e.g. ``127.0.0.1``), or
|
||||
an ip address and port (e.g. ``127.0.0.1:4500``) or any locality (e.g ``locality_dcid:primary-satellite`` or
|
||||
|
@ -431,7 +431,6 @@ public:
|
||||
CoalescedKeyRangeMap<Reference<LocationInfo>> locationCache;
|
||||
std::unordered_map<Endpoint, EndpointFailureInfo> failedEndpointsOnHealthyServersInfo;
|
||||
std::unordered_map<TenantName, TenantMapEntry> tenantCache;
|
||||
std::vector<TenantNameRef> tenantCacheList;
|
||||
|
||||
std::map<UID, StorageServerInfo*> server_interf;
|
||||
std::map<UID, BlobWorkerInterface> blobWorker_interf; // blob workers don't change endpoints for the same ID
|
||||
|
@ -643,7 +643,6 @@ Future<Optional<TenantMapEntry>> tryGetTenantTransaction(Transaction tr, TenantN
|
||||
ACTOR template <class DB>
|
||||
Future<Optional<TenantMapEntry>> tryGetTenant(Reference<DB> db, TenantName name) {
|
||||
state Reference<typename DB::TransactionT> tr = db->createTransaction();
|
||||
state Key tenantMapKey = name.withPrefix(tenantMapPrefix);
|
||||
|
||||
loop {
|
||||
try {
|
||||
@ -675,6 +674,7 @@ Future<TenantMapEntry> getTenant(Reference<DB> db, TenantName name) {
|
||||
return entry.get();
|
||||
}
|
||||
|
||||
// Creates a tenant with the given name. If the tenant already exists, an empty optional will be returned.
|
||||
ACTOR template <class Transaction>
|
||||
Future<Optional<TenantMapEntry>> createTenantTransaction(Transaction tr, TenantNameRef name) {
|
||||
state Key tenantMapKey = name.withPrefix(tenantMapPrefix);
|
||||
@ -686,10 +686,9 @@ Future<Optional<TenantMapEntry>> createTenantTransaction(Transaction tr, TenantN
|
||||
tr->setOption(FDBTransactionOptions::ACCESS_SYSTEM_KEYS);
|
||||
tr->setOption(FDBTransactionOptions::LOCK_AWARE);
|
||||
|
||||
state Optional<TenantMapEntry> tenantEntry = wait(tryGetTenantTransaction(tr, name));
|
||||
if (tenantEntry.present()) {
|
||||
return Optional<TenantMapEntry>();
|
||||
}
|
||||
state Future<Optional<TenantMapEntry>> tenantEntryFuture = tryGetTenantTransaction(tr, name);
|
||||
state Future<Optional<Value>> tenantDataPrefixFuture = safeThreadFutureToFuture(tr->get(tenantDataPrefixKey));
|
||||
state Future<Optional<Value>> lastIdFuture = safeThreadFutureToFuture(tr->get(tenantLastIdKey));
|
||||
|
||||
Optional<Value> tenantMode = wait(safeThreadFutureToFuture(tr->get(configKeysPrefix.withSuffix("tenant_mode"_sr))));
|
||||
|
||||
@ -697,9 +696,12 @@ Future<Optional<TenantMapEntry>> createTenantTransaction(Transaction tr, TenantN
|
||||
throw tenants_disabled();
|
||||
}
|
||||
|
||||
state Future<Optional<Value>> tenantDataPrefixFuture = safeThreadFutureToFuture(tr->get(tenantDataPrefixKey));
|
||||
Optional<TenantMapEntry> tenantEntry = wait(tenantEntryFuture);
|
||||
if (tenantEntry.present()) {
|
||||
return Optional<TenantMapEntry>();
|
||||
}
|
||||
|
||||
state Optional<Value> lastIdVal = wait(safeThreadFutureToFuture(tr->get(tenantLastIdKey)));
|
||||
state Optional<Value> lastIdVal = wait(lastIdFuture);
|
||||
Optional<Value> tenantDataPrefix = wait(tenantDataPrefixFuture);
|
||||
|
||||
state TenantMapEntry newTenant(lastIdVal.present() ? TenantMapEntry::prefixToId(lastIdVal.get()) + 1 : 0,
|
||||
|
@ -1714,16 +1714,13 @@ bool DatabaseContext::getCachedLocations(const Optional<TenantName>& tenantName,
|
||||
|
||||
void DatabaseContext::cacheTenant(const TenantName& tenant, const TenantMapEntry& tenantEntry) {
|
||||
if (tenantCacheSize > 0) {
|
||||
int attempts = 0;
|
||||
while (tenantCache.size() > tenantCacheSize && attempts++ < 100) {
|
||||
int randomEntry = deterministicRandom()->randomInt(0, tenantCacheList.size());
|
||||
tenantCache.erase(tenantCacheList[randomEntry]);
|
||||
tenantCacheList[randomEntry] = tenantCacheList.back();
|
||||
tenantCacheList.pop_back();
|
||||
// Naive cache eviction just erases the entire cache when it gets full.
|
||||
// We don't expect a single client to fill the tenant cache typically, so this should work reasonably well.
|
||||
if (tenantCache.size() > tenantCacheSize) {
|
||||
tenantCache.clear();
|
||||
}
|
||||
|
||||
tenantCache[tenant] = tenantEntry;
|
||||
tenantCacheList.push_back(tenant);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4924,7 +4921,11 @@ Future<Optional<Value>> Transaction::get(const Key& key, Snapshot snapshot) {
|
||||
if (!snapshot)
|
||||
tr.transaction.read_conflict_ranges.push_back(tr.arena, singleKeyRange(key, tr.arena));
|
||||
|
||||
UseTenant useTenant = UseTenant::True;
|
||||
if (key == metadataVersionKey) {
|
||||
// It is legal to read the metadata version key inside of a tenant.
|
||||
// This will return the global metadata version key.
|
||||
useTenant = UseTenant::False;
|
||||
++trState->cx->transactionMetadataVersionReads;
|
||||
if (!ver.isReady() || metadataVersion.isSet()) {
|
||||
return metadataVersion.getFuture();
|
||||
@ -4958,7 +4959,7 @@ Future<Optional<Value>> Transaction::get(const Key& key, Snapshot snapshot) {
|
||||
}
|
||||
}
|
||||
|
||||
return getValue(trState, key, ver);
|
||||
return getValue(trState, key, ver, useTenant);
|
||||
}
|
||||
|
||||
void Watch::setWatch(Future<Void> watchFuture) {
|
||||
@ -4968,14 +4969,13 @@ void Watch::setWatch(Future<Void> watchFuture) {
|
||||
onSetWatchTrigger.send(Void());
|
||||
}
|
||||
|
||||
ACTOR Future<TenantInfo> getTenantMetadata(Reference<TransactionState> trState, Key key, Future<Version> fVersion) {
|
||||
state Version version = wait(fVersion);
|
||||
ACTOR Future<TenantInfo> getTenantMetadata(Reference<TransactionState> trState, Key key, Version version) {
|
||||
KeyRangeLocationInfo locationInfo =
|
||||
wait(getKeyLocation(trState, key, &StorageServerInterface::getValue, Reverse::False, UseTenant::True, version));
|
||||
return trState->getTenantInfo();
|
||||
}
|
||||
|
||||
Future<TenantInfo> populateAndGetTenant(Reference<TransactionState> trState, Key const& key, Future<Version> version) {
|
||||
Future<TenantInfo> populateAndGetTenant(Reference<TransactionState> trState, Key const& key, Version version) {
|
||||
if (!trState->tenant.present()) {
|
||||
return TenantInfo();
|
||||
} else if (trState->tenantId != TenantInfo::INVALID_TENANT) {
|
||||
@ -5048,7 +5048,8 @@ Future<Void> Transaction::watch(Reference<Watch> watch) {
|
||||
return ::watch(
|
||||
watch,
|
||||
trState->cx,
|
||||
populateAndGetTenant(trState, watch->key, readVersion.isValid() ? readVersion : Future<Version>(latestVersion)),
|
||||
populateAndGetTenant(
|
||||
trState, watch->key, readVersion.isValid() && readVersion.isReady() ? readVersion.get() : latestVersion),
|
||||
trState->options.readTags,
|
||||
trState->spanID,
|
||||
trState->taskID,
|
||||
|
Loading…
x
Reference in New Issue
Block a user