throw invalid_tenant_configuration and add to metacluster management test

This commit is contained in:
Jon Fu 2022-09-14 10:22:51 -07:00
parent bfd2d138f7
commit e3f54dba2f
3 changed files with 51 additions and 36 deletions

View File

@ -96,7 +96,8 @@ void applyConfigurationToSpecialKeys(Reference<ITransaction> tr,
std::map<Standalone<StringRef>, Optional<Value>> configuration) { std::map<Standalone<StringRef>, Optional<Value>> configuration) {
for (auto [configName, value] : configuration) { for (auto [configName, value] : configuration) {
if (configName == "assigned_cluster"_sr) { 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()) { if (value.present()) {
tr->set(makeConfigKey(tenantName, configName), value.get()); tr->set(makeConfigKey(tenantName, configName), value.get());

View File

@ -1074,8 +1074,12 @@ struct CreateTenantImpl {
// Parameter set if tenant creation permanently fails on the data cluster // Parameter set if tenant creation permanently fails on the data cluster
Optional<int64_t> replaceExistingTenantId; Optional<int64_t> replaceExistingTenantId;
CreateTenantImpl(Reference<DB> managementDb, bool preferAssignedCluster, TenantName tenantName, TenantMapEntry tenantEntry) CreateTenantImpl(Reference<DB> managementDb,
: ctx(managementDb), preferAssignedCluster(preferAssignedCluster), tenantName(tenantName), tenantEntry(tenantEntry) {} bool preferAssignedCluster,
TenantName tenantName,
TenantMapEntry tenantEntry)
: ctx(managementDb), preferAssignedCluster(preferAssignedCluster), tenantName(tenantName),
tenantEntry(tenantEntry) {}
ACTOR static Future<ClusterName> checkClusterAvailability(Reference<IDatabase> dataClusterDb, ACTOR static Future<ClusterName> checkClusterAvailability(Reference<IDatabase> dataClusterDb,
ClusterName clusterName) { ClusterName clusterName) {
@ -1153,46 +1157,43 @@ struct CreateTenantImpl {
if (groupEntry.present()) { if (groupEntry.present()) {
ASSERT(groupEntry.get().assignedCluster.present()); ASSERT(groupEntry.get().assignedCluster.present());
if (self->preferAssignedCluster) { if (self->preferAssignedCluster &&
ASSERT(groupEntry.get().assignedCluster.get() == self->tenantEntry.assignedCluster.get()); groupEntry.get().assignedCluster.get() != self->tenantEntry.assignedCluster.get()) {
throw invalid_tenant_configuration();
} }
return std::make_pair(groupEntry.get().assignedCluster.get(), true); return std::make_pair(groupEntry.get().assignedCluster.get(), true);
} }
} }
state std::vector<Future<Reference<IDatabase>>> dataClusterDbs;
state std::vector<ClusterName> dataClusterNames;
state std::vector<Future<ClusterName>> clusterAvailabilityChecks;
// Get a set of the most full clusters that still have capacity // Get a set of the most full clusters that still have capacity
// If preferred cluster is specified, look for that one. // If preferred cluster is specified, look for that one.
state std::vector<Future<Reference<IDatabase>>> dataClusterDbs; state KeyBackedSet<Tuple>::RangeResultType availableClusters =
state std::vector<Future<ClusterName>> clusterAvailabilityChecks; wait(ManagementClusterMetadata::clusterCapacityIndex.getRange(
if (self->preferAssignedCluster) { tr, {}, {}, CLIENT_KNOBS->METACLUSTER_ASSIGNMENT_CLUSTERS_TO_CHECK, Snapshot::False, Reverse::True));
dataClusterDbs.push_back(getAndOpenDatabase(tr, self->tenantEntry.assignedCluster.get())); if (availableClusters.results.empty()) {
wait(waitForAll(dataClusterDbs)); throw metacluster_no_capacity();
clusterAvailabilityChecks.push_back( }
checkClusterAvailability(dataClusterDbs[0].get(), self->tenantEntry.assignedCluster.get()));
} else {
state KeyBackedSet<Tuple>::RangeResultType availableClusters =
wait(ManagementClusterMetadata::clusterCapacityIndex.getRange(
tr,
{},
{},
CLIENT_KNOBS->METACLUSTER_ASSIGNMENT_CLUSTERS_TO_CHECK,
Snapshot::False,
Reverse::True));
if (availableClusters.results.empty()) { bool preferredClusterPresent = false;
throw metacluster_no_capacity(); 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) { // Check the availability of our set of clusters
dataClusterDbs.push_back(getAndOpenDatabase(tr, clusterTuple.getString(1))); for (int i = 0; i < dataClusterDbs.size(); ++i) {
} clusterAvailabilityChecks.push_back(checkClusterAvailability(dataClusterDbs[i].get(), dataClusterNames[i]));
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)));
}
} }
// Wait for a successful availability check from some cluster. We prefer the most full cluster, but if it // Wait for a successful availability check from some cluster. We prefer the most full cluster, but if it

View File

@ -388,12 +388,25 @@ struct MetaclusterManagementWorkload : TestWorkload {
state bool exists = itr != self->createdTenants.end(); state bool exists = itr != self->createdTenants.end();
state bool hasCapacity = self->createdTenants.size() < self->totalTenantGroupCapacity; state bool hasCapacity = self->createdTenants.size() < self->totalTenantGroupCapacity;
state bool retried = false; state bool retried = false;
state bool preferAssignedCluster = deterministicRandom()->coinflip();
try { try {
loop { loop {
try { try {
Future<Void> createFuture = TenantMapEntry entry;
MetaclusterAPI::createTenant(self->managementDb, tenant, TenantMapEntry()); 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<Void> createFuture = MetaclusterAPI::createTenant(self->managementDb, tenant, entry);
Optional<Void> result = wait(timeout(createFuture, deterministicRandom()->randomInt(1, 30))); Optional<Void> result = wait(timeout(createFuture, deterministicRandom()->randomInt(1, 30)));
if (result.present()) { if (result.present()) {
break; break;
@ -431,7 +444,7 @@ struct MetaclusterManagementWorkload : TestWorkload {
ASSERT(exists); ASSERT(exists);
return Void(); return Void();
} else if (e.code() == error_code_metacluster_no_capacity) { } else if (e.code() == error_code_metacluster_no_capacity) {
ASSERT(!hasCapacity && !exists); ASSERT((!hasCapacity && !exists) || preferAssignedCluster);
return Void(); return Void();
} }