Server processes send unknown_tenant responses back to clients, which is meant to be retried after updating the tenant cache. Fix bug where key selectors could be truncated after applying the tenant prefix.

This commit is contained in:
A.J. Beamon 2022-03-04 12:22:05 -08:00
parent 72a34945ce
commit 3ae98189af
7 changed files with 37 additions and 23 deletions

View File

@ -76,7 +76,8 @@ extern "C" DLLEXPORT fdb_bool_t fdb_error_predicate(int predicate_test, fdb_erro
return code == error_code_not_committed || code == error_code_transaction_too_old ||
code == error_code_future_version || code == error_code_database_locked ||
code == error_code_proxy_memory_limit_exceeded || code == error_code_batch_transaction_throttled ||
code == error_code_process_behind || code == error_code_tag_throttled;
code == error_code_process_behind || code == error_code_tag_throttled ||
code == error_code_unknown_tenant;
}
return false;
}

View File

@ -160,6 +160,20 @@ FoundationDB may return the following error codes from API functions. If you nee
| special_keys_api_failure | 2117| Api call through special keys failed. For more information, read the |
| | | ``0xff0xff/error_message`` key |
+-----------------------------------------------+-----+--------------------------------------------------------------------------------+
| tenant_name_required | 2130| Tenant name must be specified to access data in the cluster |
+-----------------------------------------------+-----+--------------------------------------------------------------------------------+
| tenant_not_found | 2131| Tenant does not exist |
+-----------------------------------------------+-----+--------------------------------------------------------------------------------+
| tenant_already_exists | 2132| A tenant with the given name already exists |
+-----------------------------------------------+-----+--------------------------------------------------------------------------------+
| tenant_not_empty | 2133| Cannot delete a non-empty tenant |
+-----------------------------------------------+-----+--------------------------------------------------------------------------------+
| invalid_tenant_name | 2134| Tenant name cannot begin with \xff |
+-----------------------------------------------+-----+--------------------------------------------------------------------------------+
| tenant_prefix_allocator_conflict | 2135| The database already has keys stored at the prefix allocated for the tenant |
+-----------------------------------------------+-----+--------------------------------------------------------------------------------+
| tenants_disabled | 2136| Tenants have been disabled in the cluster |
+-----------------------------------------------+-----+--------------------------------------------------------------------------------+
| api_version_unset | 2200| API version is not set |
+-----------------------------------------------+-----+--------------------------------------------------------------------------------+
| api_version_already_set | 2201| API version may be set only once |

View File

@ -52,6 +52,10 @@ void KeySelectorRef::setKey(KeyRef const& key) {
this->key = key;
}
void KeySelectorRef::setKeyUnlimited(KeyRef const& key) {
this->key = key;
}
std::string KeySelectorRef::toString() const {
if (offset > 0) {
if (orEqual)

View File

@ -550,6 +550,7 @@ public:
KeyRef getKey() const { return key; }
void setKey(KeyRef const& key);
void setKeyUnlimited(KeyRef const& key);
std::string toString() const;

View File

@ -419,12 +419,12 @@ ErrorOr<Optional<TenantMapEntry>> getTenantEntry(ProxyCommitData* commitData,
auto itr = view.find(tenant.get());
if (itr == view.end()) {
if (commitVersion != latestVersion) {
TraceEvent(SevWarn, "CommitProxyTenantNotFound", commitData->dbgid)
TraceEvent(SevWarn, "CommitProxyUnknownTenant", commitData->dbgid)
.detail("Tenant", tenant.get())
.detail("Version", commitVersion);
}
return tenant_not_found();
return unknown_tenant();
} else if (tenantId.present() && tenantId.get() != itr->id) {
if (commitVersion != latestVersion) {
TraceEvent(SevWarn, "CommitProxyTenantIdMismatch", commitData->dbgid)
@ -434,7 +434,7 @@ ErrorOr<Optional<TenantMapEntry>> getTenantEntry(ProxyCommitData* commitData,
.detail("Version", commitVersion);
}
return tenant_not_found();
return unknown_tenant();
}
return ErrorOr<Optional<TenantMapEntry>>(Optional<TenantMapEntry>(*itr));

View File

@ -87,7 +87,7 @@ bool canReplyWith(Error e) {
case error_code_unknown_change_feed:
case error_code_server_overloaded:
case error_code_tenant_name_required:
case error_code_tenant_not_found:
case error_code_unknown_tenant:
// getRangeAndMap related exceptions that are not retriable:
case error_code_mapper_bad_index:
case error_code_mapper_no_such_key:
@ -1377,15 +1377,15 @@ Optional<TenantMapEntry> StorageServer::getTenantEntry(Version version, TenantIn
auto view = tenantMap.at(version);
auto itr = view.find(tenantInfo.name.get());
if (itr == view.end()) {
TraceEvent(SevWarn, "StorageTenantNotFound", thisServerID).detail("Tenant", tenantInfo.name).backtrace();
throw tenant_not_found();
TraceEvent(SevWarn, "StorageUnknownTenant", thisServerID).detail("Tenant", tenantInfo.name).backtrace();
throw unknown_tenant();
} else if (itr->id != tenantInfo.tenantId) {
TraceEvent(SevWarn, "StorageTenantIdMismatch", thisServerID)
.detail("Tenant", tenantInfo.name)
.detail("TenantId", tenantInfo.tenantId)
.detail("ExistingId", itr->id)
.backtrace();
throw tenant_not_found();
throw unknown_tenant();
}
return *itr;
@ -2636,10 +2636,8 @@ ACTOR Future<Void> getKeyValuesQ(StorageServer* data, GetKeyValuesRequest req)
Optional<TenantMapEntry> entry = data->getTenantEntry(version, req.tenantInfo);
state Optional<Key> tenantPrefix = entry.map<Key>([](TenantMapEntry e) { return e.prefix; });
if (tenantPrefix.present()) {
req.begin = KeySelectorRef(
req.begin.getKey().withPrefix(tenantPrefix.get(), req.arena), req.begin.orEqual, req.begin.offset);
req.end = KeySelectorRef(
req.end.getKey().withPrefix(tenantPrefix.get(), req.arena), req.end.orEqual, req.end.offset);
req.begin.setKeyUnlimited(req.begin.getKey().withPrefix(tenantPrefix.get(), req.arena));
req.end.setKeyUnlimited(req.end.getKey().withPrefix(tenantPrefix.get(), req.arena));
}
state uint64_t changeCounter = data->shardChangeCounter;
@ -3145,10 +3143,8 @@ ACTOR Future<Void> getKeyValuesAndFlatMapQ(StorageServer* data, GetKeyValuesAndF
Optional<TenantMapEntry> entry = data->getTenantEntry(req.version, req.tenantInfo);
state Optional<Key> tenantPrefix = entry.map<Key>([](TenantMapEntry e) { return e.prefix; });
if (tenantPrefix.present()) {
req.begin = KeySelectorRef(
req.begin.getKey().withPrefix(tenantPrefix.get(), req.arena), req.begin.orEqual, req.begin.offset);
req.end = KeySelectorRef(
req.end.getKey().withPrefix(tenantPrefix.get(), req.arena), req.end.orEqual, req.end.offset);
req.begin.setKeyUnlimited(req.begin.getKey().withPrefix(tenantPrefix.get(), req.arena));
req.end.setKeyUnlimited(req.end.getKey().withPrefix(tenantPrefix.get(), req.arena));
}
state uint64_t changeCounter = data->shardChangeCounter;
@ -3358,10 +3354,8 @@ ACTOR Future<Void> getKeyValuesStreamQ(StorageServer* data, GetKeyValuesStreamRe
Optional<TenantMapEntry> entry = data->getTenantEntry(version, req.tenantInfo);
state Optional<Key> tenantPrefix = entry.map<Key>([](TenantMapEntry e) { return e.prefix; });
if (tenantPrefix.present()) {
req.begin = KeySelectorRef(
req.begin.getKey().withPrefix(tenantPrefix.get(), req.arena), req.begin.orEqual, req.begin.offset);
req.end = KeySelectorRef(
req.end.getKey().withPrefix(tenantPrefix.get(), req.arena), req.end.orEqual, req.end.offset);
req.begin.setKeyUnlimited(req.begin.getKey().withPrefix(tenantPrefix.get(), req.arena));
req.end.setKeyUnlimited(req.end.getKey().withPrefix(tenantPrefix.get(), req.arena));
}
state uint64_t changeCounter = data->shardChangeCounter;
@ -3551,8 +3545,7 @@ ACTOR Future<Void> getKeyQ(StorageServer* data, GetKeyRequest req) {
state Optional<TenantMapEntry> tenantEntry = data->getTenantEntry(version, req.tenantInfo);
if (tenantEntry.present()) {
req.sel = KeySelectorRef(
req.sel.getKey().withPrefix(tenantEntry.get().prefix, req.arena), req.sel.orEqual, req.sel.offset);
req.sel.setKeyUnlimited(req.sel.getKey().withPrefix(tenantEntry.get().prefix, req.arena));
}
state uint64_t changeCounter = data->shardChangeCounter;

View File

@ -199,12 +199,13 @@ ERROR( client_lib_not_available, 2121, "Client library exists, but is not availa
ERROR( client_lib_invalid_binary, 2122, "Invalid client library binary." )
ERROR( tenant_name_required, 2130, "Tenant name must be specified to access data in the cluster" )
ERROR( tenant_not_found, 2131, "Tenant not found on the cluster" )
ERROR( tenant_not_found, 2131, "Tenant does not exist" )
ERROR( tenant_already_exists, 2132, "A tenant with the given name already exists" )
ERROR( tenant_not_empty, 2133, "Cannot delete a non-empty tenant" )
ERROR( invalid_tenant_name, 2134, "Tenant name cannot begin with \\xff");
ERROR( tenant_prefix_allocator_conflict, 2135, "The database already has keys stored at the prefix allocated for the tenant");
ERROR( tenants_disabled, 2136, "Tenants have been disabled in the cluster");
ERROR( unknown_tenant, 2137, "Tenant is not available from this server")
// 2200 - errors from bindings and official APIs
ERROR( api_version_unset, 2200, "API version is not set" )