foundationdb/fdbclient/BlobMetadataUtils.cpp

132 lines
4.8 KiB
C++

/*
* BlobMetadataUtils.cpp
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2013-2022 Apple Inc. and the FoundationDB project authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "fdbclient/BlobMetadataUtils.h"
#include "fmt/format.h"
#include "flow/IRandom.h"
#include "flow/flow.h"
#include "fdbclient/Knobs.h"
#include "flow/IConnection.h"
#include "fdbclient/S3BlobStore.h"
std::string buildPartitionPath(const std::string& url, const std::string& partition) {
ASSERT(!partition.empty());
ASSERT(partition.front() != '/');
ASSERT(partition.back() == '/');
StringRef u(url);
if (u.startsWith("file://"_sr)) {
ASSERT(u.endsWith("/"_sr));
return url + partition;
} else if (u.startsWith("blobstore://"_sr)) {
std::string resource;
std::string lastOpenError;
S3BlobStoreEndpoint::ParametersT backupParams;
std::string urlCopy = url;
Reference<S3BlobStoreEndpoint> bstore =
S3BlobStoreEndpoint::fromString(url, {}, &resource, &lastOpenError, &backupParams);
ASSERT(!resource.empty());
ASSERT(resource.back() != '/');
size_t resourceStart = url.find(resource);
ASSERT(resourceStart != std::string::npos);
return urlCopy.insert(resourceStart + resource.size(), "/" + partition);
} else {
// FIXME: support azure
throw backup_invalid_url();
}
}
Standalone<BlobMetadataDetailsRef> createRandomTestBlobMetadata(const std::string& baseUrl,
BlobMetadataDomainId domainId) {
Standalone<BlobMetadataDetailsRef> metadata;
metadata.domainId = domainId;
// 0 == no partition, 1 == suffix partitioned, 2 == storage location partitioned
int type;
if (CLIENT_KNOBS->DETERMINISTIC_BLOB_METADATA) {
type = domainId % 3;
} else {
type = deterministicRandom()->randomInt(0, 3);
}
int partitionCount;
if (type == 0) {
partitionCount = 0;
} else if (CLIENT_KNOBS->DETERMINISTIC_BLOB_METADATA) {
partitionCount = 2 + domainId % 5;
} else {
partitionCount = deterministicRandom()->randomInt(2, 12);
}
// guarantee unique location for each domain for now
BlobMetadataLocationId locIdBase = domainId * 100;
TraceEvent ev(SevDebug, "SimBlobMetadata");
ev.detail("DomainId", domainId).detail("TypeNum", type).detail("PartitionCount", partitionCount);
if (type == 0) {
// single storage location
std::string partition = std::to_string(domainId) + "/";
metadata.locations.emplace_back_deep(metadata.arena(), locIdBase, buildPartitionPath(baseUrl, partition));
ev.detail("Location", metadata.locations.back().path);
}
if (type == 1) {
// simulate hash prefixing in s3
for (int i = 0; i < partitionCount; i++) {
std::string partitionName;
if (CLIENT_KNOBS->DETERMINISTIC_BLOB_METADATA) {
partitionName = std::to_string(i);
} else {
partitionName = deterministicRandom()->randomUniqueID().shortString();
}
std::string partition = partitionName + "-" + std::to_string(domainId) + "/";
metadata.locations.emplace_back_deep(
metadata.arena(), locIdBase + i, buildPartitionPath(baseUrl, partition));
ev.detail("P" + std::to_string(i), metadata.locations.back().path);
}
}
if (type == 2) {
// simulate separate storage location per partition
for (int i = 0; i < partitionCount; i++) {
std::string partition = std::to_string(domainId) + "_" + std::to_string(i) + "/";
metadata.locations.emplace_back_deep(
metadata.arena(), locIdBase + i, buildPartitionPath(baseUrl, partition));
ev.detail("P" + std::to_string(i), metadata.locations.back().path);
}
}
// set random refresh + expire time
bool doExpire = CLIENT_KNOBS->DETERMINISTIC_BLOB_METADATA ? domainId % 2 : deterministicRandom()->coinflip();
if (doExpire) {
if (CLIENT_KNOBS->DETERMINISTIC_BLOB_METADATA) {
metadata.refreshAt = now() + CLIENT_KNOBS->BLOB_METADATA_REFRESH_INTERVAL;
metadata.expireAt = metadata.refreshAt + 0.2 * CLIENT_KNOBS->BLOB_METADATA_REFRESH_INTERVAL;
} else {
metadata.refreshAt =
now() + deterministicRandom()->random01() * CLIENT_KNOBS->BLOB_METADATA_REFRESH_INTERVAL;
metadata.expireAt =
metadata.refreshAt + deterministicRandom()->random01() * CLIENT_KNOBS->BLOB_METADATA_REFRESH_INTERVAL;
}
} else {
metadata.refreshAt = std::numeric_limits<double>::max();
metadata.expireAt = metadata.refreshAt;
}
return metadata;
}