From e3f54dba2f5154551b336e90c613fb713cdbd030 Mon Sep 17 00:00:00 2001 From: Jon Fu Date: Wed, 14 Sep 2022 10:22:51 -0700 Subject: [PATCH] throw invalid_tenant_configuration and add to metacluster management test --- fdbcli/TenantCommands.actor.cpp | 3 +- .../fdbclient/MetaclusterManagement.actor.h | 65 ++++++++++--------- .../MetaclusterManagementWorkload.actor.cpp | 19 +++++- 3 files changed, 51 insertions(+), 36 deletions(-) diff --git a/fdbcli/TenantCommands.actor.cpp b/fdbcli/TenantCommands.actor.cpp index 14134bf2c8..5aab8a0520 100644 --- a/fdbcli/TenantCommands.actor.cpp +++ b/fdbcli/TenantCommands.actor.cpp @@ -96,7 +96,8 @@ void applyConfigurationToSpecialKeys(Reference tr, std::map, Optional> configuration) { for (auto [configName, value] : configuration) { if (configName == "assigned_cluster"_sr) { - throw invalid_option(); + fmt::print(stderr, "ERROR: assigned_cluster is only valid in metacluster configuration.\n"); + throw invalid_tenant_configuration(); } if (value.present()) { tr->set(makeConfigKey(tenantName, configName), value.get()); diff --git a/fdbclient/include/fdbclient/MetaclusterManagement.actor.h b/fdbclient/include/fdbclient/MetaclusterManagement.actor.h index 8dda94b70e..5aa7122f1d 100644 --- a/fdbclient/include/fdbclient/MetaclusterManagement.actor.h +++ b/fdbclient/include/fdbclient/MetaclusterManagement.actor.h @@ -1074,8 +1074,12 @@ struct CreateTenantImpl { // Parameter set if tenant creation permanently fails on the data cluster Optional replaceExistingTenantId; - CreateTenantImpl(Reference managementDb, bool preferAssignedCluster, TenantName tenantName, TenantMapEntry tenantEntry) - : ctx(managementDb), preferAssignedCluster(preferAssignedCluster), tenantName(tenantName), tenantEntry(tenantEntry) {} + CreateTenantImpl(Reference managementDb, + bool preferAssignedCluster, + TenantName tenantName, + TenantMapEntry tenantEntry) + : ctx(managementDb), preferAssignedCluster(preferAssignedCluster), tenantName(tenantName), + tenantEntry(tenantEntry) {} ACTOR static Future checkClusterAvailability(Reference dataClusterDb, ClusterName clusterName) { @@ -1153,46 +1157,43 @@ struct CreateTenantImpl { if (groupEntry.present()) { ASSERT(groupEntry.get().assignedCluster.present()); - if (self->preferAssignedCluster) { - ASSERT(groupEntry.get().assignedCluster.get() == self->tenantEntry.assignedCluster.get()); + if (self->preferAssignedCluster && + groupEntry.get().assignedCluster.get() != self->tenantEntry.assignedCluster.get()) { + throw invalid_tenant_configuration(); } return std::make_pair(groupEntry.get().assignedCluster.get(), true); } } + state std::vector>> dataClusterDbs; + state std::vector dataClusterNames; + state std::vector> clusterAvailabilityChecks; // Get a set of the most full clusters that still have capacity // If preferred cluster is specified, look for that one. - state std::vector>> dataClusterDbs; - state std::vector> clusterAvailabilityChecks; - if (self->preferAssignedCluster) { - dataClusterDbs.push_back(getAndOpenDatabase(tr, self->tenantEntry.assignedCluster.get())); - wait(waitForAll(dataClusterDbs)); - clusterAvailabilityChecks.push_back( - checkClusterAvailability(dataClusterDbs[0].get(), self->tenantEntry.assignedCluster.get())); - } else { - state KeyBackedSet::RangeResultType availableClusters = - wait(ManagementClusterMetadata::clusterCapacityIndex.getRange( - tr, - {}, - {}, - CLIENT_KNOBS->METACLUSTER_ASSIGNMENT_CLUSTERS_TO_CHECK, - Snapshot::False, - Reverse::True)); + state KeyBackedSet::RangeResultType availableClusters = + wait(ManagementClusterMetadata::clusterCapacityIndex.getRange( + tr, {}, {}, CLIENT_KNOBS->METACLUSTER_ASSIGNMENT_CLUSTERS_TO_CHECK, Snapshot::False, Reverse::True)); + if (availableClusters.results.empty()) { + throw metacluster_no_capacity(); + } - if (availableClusters.results.empty()) { - throw metacluster_no_capacity(); + bool preferredClusterPresent = false; + for (auto clusterTuple : availableClusters.results) { + if (self->preferAssignedCluster && self->tenantEntry.assignedCluster.get() != clusterTuple.getString(1)) { + continue; } + preferredClusterPresent = true; + dataClusterDbs.push_back(getAndOpenDatabase(tr, clusterTuple.getString(1))); + dataClusterNames.push_back(clusterTuple.getString(1)); + } + if (self->preferAssignedCluster && !preferredClusterPresent) { + throw metacluster_no_capacity(); + } + wait(waitForAll(dataClusterDbs)); - for (auto clusterTuple : availableClusters.results) { - dataClusterDbs.push_back(getAndOpenDatabase(tr, clusterTuple.getString(1))); - } - wait(waitForAll(dataClusterDbs)); - - // Check the availability of our set of clusters - for (int i = 0; i < availableClusters.results.size(); ++i) { - clusterAvailabilityChecks.push_back( - checkClusterAvailability(dataClusterDbs[i].get(), availableClusters.results[i].getString(1))); - } + // Check the availability of our set of clusters + for (int i = 0; i < dataClusterDbs.size(); ++i) { + clusterAvailabilityChecks.push_back(checkClusterAvailability(dataClusterDbs[i].get(), dataClusterNames[i])); } // Wait for a successful availability check from some cluster. We prefer the most full cluster, but if it diff --git a/fdbserver/workloads/MetaclusterManagementWorkload.actor.cpp b/fdbserver/workloads/MetaclusterManagementWorkload.actor.cpp index 816c3a9d45..3768338d5b 100644 --- a/fdbserver/workloads/MetaclusterManagementWorkload.actor.cpp +++ b/fdbserver/workloads/MetaclusterManagementWorkload.actor.cpp @@ -388,12 +388,25 @@ struct MetaclusterManagementWorkload : TestWorkload { state bool exists = itr != self->createdTenants.end(); state bool hasCapacity = self->createdTenants.size() < self->totalTenantGroupCapacity; state bool retried = false; + state bool preferAssignedCluster = deterministicRandom()->coinflip(); try { loop { try { - Future createFuture = - MetaclusterAPI::createTenant(self->managementDb, tenant, TenantMapEntry()); + TenantMapEntry entry; + if (preferAssignedCluster) { + loop { + ClusterName clusterName = self->chooseClusterName(); + DataClusterData* dataDb = &self->dataDbs[clusterName]; + // Choose a registered cluster + // Still possible that the chosen cluster has no capacity. + if (dataDb->registered) { + entry.assignedCluster = clusterName; + break; + } + } + } + Future createFuture = MetaclusterAPI::createTenant(self->managementDb, tenant, entry); Optional result = wait(timeout(createFuture, deterministicRandom()->randomInt(1, 30))); if (result.present()) { break; @@ -431,7 +444,7 @@ struct MetaclusterManagementWorkload : TestWorkload { ASSERT(exists); return Void(); } else if (e.code() == error_code_metacluster_no_capacity) { - ASSERT(!hasCapacity && !exists); + ASSERT((!hasCapacity && !exists) || preferAssignedCluster); return Void(); }