mirror of
https://github.com/apple/foundationdb.git
synced 2025-05-18 20:12:13 +08:00
MVC2.0: Addressing code review comments for client lib management operations
This commit is contained in:
parent
4bc798cd57
commit
ec307b3f2c
@ -43,16 +43,20 @@ struct ClientLibBinaryInfo {
|
||||
Standalone<StringRef> sumBytes;
|
||||
};
|
||||
|
||||
#define ASSERT_INDEX_IN_RANGE(idx, arr) ASSERT(idx >= 0 && idx < sizeof(arr) / sizeof(arr[0]))
|
||||
|
||||
const std::string& getStatusName(ClientLibStatus status) {
|
||||
static const std::string statusNames[] = { "disabled", "available", "uploading", "deleting" };
|
||||
return statusNames[status];
|
||||
int idx = static_cast<int>(status);
|
||||
ASSERT_INDEX_IN_RANGE(idx, statusNames);
|
||||
return statusNames[idx];
|
||||
}
|
||||
|
||||
ClientLibStatus getStatusByName(std::string_view statusName) {
|
||||
static std::map<std::string_view, ClientLibStatus> statusByName;
|
||||
// initialize the map on demand
|
||||
if (statusByName.empty()) {
|
||||
for (int i = 0; i < CLIENTLIB_STATUS_COUNT; i++) {
|
||||
for (int i = 0; i < static_cast<int>(ClientLibStatus::COUNT); i++) {
|
||||
ClientLibStatus status = static_cast<ClientLibStatus>(i);
|
||||
statusByName[getStatusName(status)] = status;
|
||||
}
|
||||
@ -68,14 +72,16 @@ ClientLibStatus getStatusByName(std::string_view statusName) {
|
||||
|
||||
const std::string& getPlatformName(ClientLibPlatform platform) {
|
||||
static const std::string platformNames[] = { "unknown", "x84_64-linux", "x86_64-windows", "x86_64-macos" };
|
||||
return platformNames[platform];
|
||||
int idx = static_cast<int>(platform);
|
||||
ASSERT_INDEX_IN_RANGE(idx, platformNames);
|
||||
return platformNames[idx];
|
||||
}
|
||||
|
||||
ClientLibPlatform getPlatformByName(std::string_view platformName) {
|
||||
static std::map<std::string_view, ClientLibPlatform> platformByName;
|
||||
// initialize the map on demand
|
||||
if (platformByName.empty()) {
|
||||
for (int i = 0; i < CLIENTLIB_PLATFORM_COUNT; i++) {
|
||||
for (int i = 0; i < static_cast<int>(ClientLibStatus::COUNT); i++) {
|
||||
ClientLibPlatform platform = static_cast<ClientLibPlatform>(i);
|
||||
platformByName[getPlatformName(platform)] = platform;
|
||||
}
|
||||
@ -91,14 +97,16 @@ ClientLibPlatform getPlatformByName(std::string_view platformName) {
|
||||
|
||||
const std::string& getChecksumAlgName(ClientLibChecksumAlg checksumAlg) {
|
||||
static const std::string checksumAlgNames[] = { "md5" };
|
||||
return checksumAlgNames[checksumAlg];
|
||||
int idx = static_cast<int>(checksumAlg);
|
||||
ASSERT_INDEX_IN_RANGE(idx, checksumAlgNames);
|
||||
return checksumAlgNames[idx];
|
||||
}
|
||||
|
||||
ClientLibChecksumAlg getChecksumAlgByName(std::string_view checksumAlgName) {
|
||||
static std::map<std::string_view, ClientLibChecksumAlg> checksumAlgByName;
|
||||
// initialize the map on demand
|
||||
if (checksumAlgByName.empty()) {
|
||||
for (int i = 0; i < CLIENTLIB_CHECKSUM_ALG_COUNT; i++) {
|
||||
for (int i = 0; i < (int)ClientLibChecksumAlg::COUNT; i++) {
|
||||
ClientLibChecksumAlg checksumAlg = static_cast<ClientLibChecksumAlg>(i);
|
||||
checksumAlgByName[getChecksumAlgName(checksumAlg)] = checksumAlg;
|
||||
}
|
||||
@ -115,7 +123,7 @@ ClientLibChecksumAlg getChecksumAlgByName(std::string_view checksumAlgName) {
|
||||
namespace {
|
||||
|
||||
bool isValidTargetStatus(ClientLibStatus status) {
|
||||
return status == CLIENTLIB_AVAILABLE || status == CLIENTLIB_DISABLED;
|
||||
return status == ClientLibStatus::AVAILABLE || status == ClientLibStatus::DISABLED;
|
||||
}
|
||||
|
||||
void parseMetadataJson(StringRef metadataString, json_spirit::mObject& metadataJson) {
|
||||
@ -157,8 +165,10 @@ bool validVersionPartNum(int num) {
|
||||
|
||||
int getNumericVersionEncoding(const std::string& versionStr) {
|
||||
int major, minor, patch;
|
||||
int numScanned = sscanf(versionStr.c_str(), "%d.%d.%d", &major, &minor, &patch);
|
||||
if (numScanned != 3 || !validVersionPartNum(major) || !validVersionPartNum(minor) || !validVersionPartNum(patch)) {
|
||||
int charsScanned;
|
||||
int numScanned = sscanf(versionStr.c_str(), "%d.%d.%d%n", &major, &minor, &patch, &charsScanned);
|
||||
if (numScanned != 3 || !validVersionPartNum(major) || !validVersionPartNum(minor) || !validVersionPartNum(patch) ||
|
||||
charsScanned != versionStr.size()) {
|
||||
TraceEvent(SevWarnAlways, "ClientLibraryInvalidMetadata")
|
||||
.detail("Error", format("Invalid version string %s", versionStr.c_str()));
|
||||
throw client_lib_invalid_metadata();
|
||||
@ -166,22 +176,22 @@ int getNumericVersionEncoding(const std::string& versionStr) {
|
||||
return ((major * 1000) + minor) * 1000 + patch;
|
||||
}
|
||||
|
||||
void getIdFromMetadataJson(const json_spirit::mObject& metadataJson, std::string& clientLibId) {
|
||||
Standalone<StringRef> getIdFromMetadataJson(const json_spirit::mObject& metadataJson) {
|
||||
std::ostringstream libIdBuilder;
|
||||
libIdBuilder << getMetadataStrAttr(metadataJson, CLIENTLIB_ATTR_PLATFORM) << "/";
|
||||
libIdBuilder << format("%09d", getNumericVersionEncoding(getMetadataStrAttr(metadataJson, CLIENTLIB_ATTR_VERSION)))
|
||||
<< "/";
|
||||
libIdBuilder << getMetadataStrAttr(metadataJson, CLIENTLIB_ATTR_TYPE) << "/";
|
||||
libIdBuilder << getMetadataStrAttr(metadataJson, CLIENTLIB_ATTR_CHECKSUM);
|
||||
clientLibId = libIdBuilder.str();
|
||||
return Standalone<StringRef>(libIdBuilder.str());
|
||||
}
|
||||
|
||||
Key metadataKeyFromId(const std::string& clientLibId) {
|
||||
return StringRef(clientLibId).withPrefix(clientLibMetadataPrefix);
|
||||
Key metadataKeyFromId(StringRef clientLibId) {
|
||||
return clientLibId.withPrefix(clientLibMetadataPrefix);
|
||||
}
|
||||
|
||||
Key chunkKeyPrefixFromId(const std::string& clientLibId) {
|
||||
return StringRef(clientLibId).withPrefix(clientLibBinaryPrefix).withSuffix(LiteralStringRef("/"));
|
||||
Key chunkKeyPrefixFromId(StringRef clientLibId) {
|
||||
return clientLibId.withPrefix(clientLibBinaryPrefix).withSuffix(LiteralStringRef("/"));
|
||||
}
|
||||
|
||||
KeyRef chunkKeyFromNo(StringRef clientLibBinPrefix, size_t chunkNo, Arena& arena) {
|
||||
@ -191,16 +201,16 @@ KeyRef chunkKeyFromNo(StringRef clientLibBinPrefix, size_t chunkNo, Arena& arena
|
||||
ClientLibPlatform getCurrentClientPlatform() {
|
||||
#ifdef __x86_64__
|
||||
#if defined(_WIN32)
|
||||
return CLIENTLIB_X86_64_WINDOWS;
|
||||
return ClientLibPlatform::X86_64_WINDOWS;
|
||||
#elif defined(__linux__)
|
||||
return CLIENTLIB_X86_64_LINUX;
|
||||
return ClientLibPlatform::X86_64_LINUX;
|
||||
#elif defined(__FreeBSD__) || defined(__APPLE__)
|
||||
return CLIENTLIB_X86_64_MACOS;
|
||||
return ClientLibPlatform::X86_64_MACOS;
|
||||
#else
|
||||
return CLIENTLIB_UNKNOWN_PLATFORM;
|
||||
return ClientLibPlatform::UNKNOWN;
|
||||
#endif
|
||||
#else // not __x86_64__
|
||||
return CLIENTLIB_UNKNOWN_PLATFORM;
|
||||
return ClientLibPlatform::UNKNOWN;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -217,7 +227,7 @@ Standalone<StringRef> byteArrayToHexString(StringRef input) {
|
||||
|
||||
} // namespace
|
||||
|
||||
Standalone<StringRef> MD5SumToHexString(MD5_CTX& sum) {
|
||||
Standalone<StringRef> md5SumToHexString(MD5_CTX& sum) {
|
||||
Standalone<StringRef> sumBytes = makeString(16);
|
||||
::MD5_Final(mutateString(sumBytes), &sum);
|
||||
return byteArrayToHexString(sumBytes);
|
||||
@ -229,10 +239,10 @@ ClientLibFilter& ClientLibFilter::filterNewerPackageVersion(const std::string& v
|
||||
return *this;
|
||||
}
|
||||
|
||||
void getClientLibIdFromMetadataJson(StringRef metadataString, std::string& clientLibId) {
|
||||
Standalone<StringRef> getClientLibIdFromMetadataJson(StringRef metadataString) {
|
||||
json_spirit::mObject parsedMetadata;
|
||||
parseMetadataJson(metadataString, parsedMetadata);
|
||||
getIdFromMetadataJson(parsedMetadata, clientLibId);
|
||||
return getIdFromMetadataJson(parsedMetadata);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -253,8 +263,9 @@ ACTOR Future<Void> uploadClientLibBinary(Database db,
|
||||
state size_t firstChunkNo;
|
||||
|
||||
if (transactionSize % chunkSize != 0) {
|
||||
TraceEvent(SevError, "ClientLibraryInvalidConfig")
|
||||
.detail("Reason", format("Invalid chunk size configuration, falling back to %d", _PAGE_SIZE));
|
||||
TraceEvent(SevWarnAlways, "ClientLibraryInvalidConfig")
|
||||
.detail("Reason",
|
||||
format("Invalid chunk size configuration (%d), falling back to %d", chunkSize, _PAGE_SIZE));
|
||||
chunkSize = _PAGE_SIZE;
|
||||
}
|
||||
|
||||
@ -303,7 +314,7 @@ ACTOR Future<Void> uploadClientLibBinary(Database db,
|
||||
binInfo->totalBytes = fileOffset;
|
||||
binInfo->chunkCnt = chunkNo;
|
||||
binInfo->chunkSize = chunkSize;
|
||||
binInfo->sumBytes = MD5SumToHexString(sum);
|
||||
binInfo->sumBytes = md5SumToHexString(sum);
|
||||
return Void();
|
||||
}
|
||||
|
||||
@ -354,9 +365,11 @@ ACTOR Future<Void> deleteClientLibMetadataEntry(Database db, Key clientLibMetaKe
|
||||
|
||||
} // namespace
|
||||
|
||||
ACTOR Future<Void> uploadClientLibrary(Database db, StringRef metadataString, StringRef libFilePath) {
|
||||
ACTOR Future<Void> uploadClientLibrary(Database db,
|
||||
Standalone<StringRef> metadataString,
|
||||
Standalone<StringRef> libFilePath) {
|
||||
state json_spirit::mObject metadataJson;
|
||||
state std::string clientLibId;
|
||||
state Standalone<StringRef> clientLibId;
|
||||
state Key clientLibMetaKey;
|
||||
state Key clientLibBinPrefix;
|
||||
state std::string jsStr;
|
||||
@ -380,7 +393,7 @@ ACTOR Future<Void> uploadClientLibrary(Database db, StringRef metadataString, St
|
||||
throw client_lib_invalid_metadata();
|
||||
}
|
||||
|
||||
getIdFromMetadataJson(metadataJson, clientLibId);
|
||||
clientLibId = getIdFromMetadataJson(metadataJson);
|
||||
clientLibMetaKey = metadataKeyFromId(clientLibId);
|
||||
clientLibBinPrefix = chunkKeyPrefixFromId(clientLibId);
|
||||
|
||||
@ -401,7 +414,7 @@ ACTOR Future<Void> uploadClientLibrary(Database db, StringRef metadataString, St
|
||||
getMetadataStrAttr(metadataJson, CLIENTLIB_ATTR_PROTOCOL);
|
||||
getMetadataIntAttr(metadataJson, CLIENTLIB_ATTR_API_VERSION);
|
||||
|
||||
metadataJson[CLIENTLIB_ATTR_STATUS] = getStatusName(CLIENTLIB_UPLOADING);
|
||||
metadataJson[CLIENTLIB_ATTR_STATUS] = getStatusName(ClientLibStatus::UPLOADING);
|
||||
jsStr = json_spirit::write_string(json_spirit::mValue(metadataJson));
|
||||
|
||||
/*
|
||||
@ -426,9 +439,6 @@ ACTOR Future<Void> uploadClientLibrary(Database db, StringRef metadataString, St
|
||||
wait(tr.commit());
|
||||
break;
|
||||
} catch (Error& e) {
|
||||
if (e.code() == error_code_client_lib_already_exists) {
|
||||
throw;
|
||||
}
|
||||
wait(tr.onError(e));
|
||||
}
|
||||
}
|
||||
@ -481,9 +491,11 @@ ACTOR Future<Void> uploadClientLibrary(Database db, StringRef metadataString, St
|
||||
return Void();
|
||||
}
|
||||
|
||||
ACTOR Future<Void> downloadClientLibrary(Database db, StringRef clientLibId, StringRef libFilePath) {
|
||||
state Key clientLibMetaKey = metadataKeyFromId(clientLibId.toString());
|
||||
state Key chunkKeyPrefix = chunkKeyPrefixFromId(clientLibId.toString());
|
||||
ACTOR Future<Void> downloadClientLibrary(Database db,
|
||||
Standalone<StringRef> clientLibId,
|
||||
Standalone<StringRef> libFilePath) {
|
||||
state Key clientLibMetaKey = metadataKeyFromId(clientLibId);
|
||||
state Key chunkKeyPrefix = chunkKeyPrefixFromId(clientLibId);
|
||||
state int transactionSize = getAlignedUpperBound(CLIENT_KNOBS->MVC_CLIENTLIB_TRANSACTION_SIZE, _PAGE_SIZE);
|
||||
state json_spirit::mObject metadataJson;
|
||||
state std::string checkSum;
|
||||
@ -518,15 +530,12 @@ ACTOR Future<Void> downloadClientLibrary(Database db, StringRef clientLibId, Str
|
||||
parseMetadataJson(metadataOpt.get(), metadataJson);
|
||||
break;
|
||||
} catch (Error& e) {
|
||||
if (e.code() == error_code_client_lib_not_found) {
|
||||
throw;
|
||||
}
|
||||
wait(tr.onError(e));
|
||||
}
|
||||
}
|
||||
|
||||
// Allow downloading only libraries in the available state
|
||||
if (getStatusByName(getMetadataStrAttr(metadataJson, CLIENTLIB_ATTR_STATUS)) != CLIENTLIB_AVAILABLE) {
|
||||
if (getStatusByName(getMetadataStrAttr(metadataJson, CLIENTLIB_ATTR_STATUS)) != ClientLibStatus::AVAILABLE) {
|
||||
throw client_lib_not_available();
|
||||
}
|
||||
|
||||
@ -540,7 +549,20 @@ ACTOR Future<Void> downloadClientLibrary(Database db, StringRef clientLibId, Str
|
||||
chunkCount = getMetadataIntAttr(metadataJson, CLIENTLIB_ATTR_CHUNK_COUNT);
|
||||
binarySize = getMetadataIntAttr(metadataJson, CLIENTLIB_ATTR_SIZE);
|
||||
expectedChunkSize = getMetadataIntAttr(metadataJson, CLIENTLIB_ATTR_CHUNK_SIZE);
|
||||
ASSERT(transactionSize % expectedChunkSize == 0);
|
||||
|
||||
if (transactionSize % expectedChunkSize != 0) {
|
||||
// Make sure the transaction size alignes both by chunk size and the page size
|
||||
int fixedSize = getAlignedUpperBound(transactionSize, std::lcm((int)expectedChunkSize, _PAGE_SIZE));
|
||||
TraceEvent(SevWarnAlways, "ClientLibraryInvalidConfig")
|
||||
.detail("Reason",
|
||||
format("Configured transaction size %d does not align "
|
||||
"with the stored chunk size%zu, falling back to %d",
|
||||
transactionSize,
|
||||
expectedChunkSize,
|
||||
fixedSize));
|
||||
// make sure transactionSize assiz
|
||||
transactionSize = fixedSize;
|
||||
}
|
||||
fileOffset = 0;
|
||||
chunkNo = 0;
|
||||
|
||||
@ -591,9 +613,6 @@ ACTOR Future<Void> downloadClientLibrary(Database db, StringRef clientLibId, Str
|
||||
}
|
||||
break;
|
||||
} catch (Error& e) {
|
||||
if (e.code() == error_code_client_lib_invalid_binary) {
|
||||
throw;
|
||||
}
|
||||
wait(tr.onError(e));
|
||||
}
|
||||
}
|
||||
@ -612,7 +631,7 @@ ACTOR Future<Void> downloadClientLibrary(Database db, StringRef clientLibId, Str
|
||||
throw client_lib_invalid_binary();
|
||||
}
|
||||
|
||||
Standalone<StringRef> sumBytesStr = MD5SumToHexString(sum);
|
||||
Standalone<StringRef> sumBytesStr = md5SumToHexString(sum);
|
||||
if (sumBytesStr != StringRef(checkSum)) {
|
||||
TraceEvent(SevWarnAlways, "ClientLibraryChecksumMismatch")
|
||||
.detail("Expected", checkSum)
|
||||
@ -627,7 +646,7 @@ ACTOR Future<Void> downloadClientLibrary(Database db, StringRef clientLibId, Str
|
||||
return Void();
|
||||
}
|
||||
|
||||
ACTOR Future<Void> deleteClientLibrary(Database db, StringRef clientLibId) {
|
||||
ACTOR Future<Void> deleteClientLibrary(Database db, Standalone<StringRef> clientLibId) {
|
||||
state Key clientLibMetaKey = metadataKeyFromId(clientLibId.toString());
|
||||
state Key chunkKeyPrefix = chunkKeyPrefixFromId(clientLibId.toString());
|
||||
state json_spirit::mObject metadataJson;
|
||||
@ -649,15 +668,12 @@ ACTOR Future<Void> deleteClientLibrary(Database db, StringRef clientLibId) {
|
||||
throw client_lib_not_found();
|
||||
}
|
||||
parseMetadataJson(metadataOpt.get(), metadataJson);
|
||||
metadataJson[CLIENTLIB_ATTR_STATUS] = getStatusName(CLIENTLIB_DELETING);
|
||||
metadataJson[CLIENTLIB_ATTR_STATUS] = getStatusName(ClientLibStatus::DELETING);
|
||||
jsStr = json_spirit::write_string(json_spirit::mValue(metadataJson));
|
||||
tr.set(clientLibMetaKey, ValueRef(jsStr));
|
||||
wait(tr.commit());
|
||||
break;
|
||||
} catch (Error& e) {
|
||||
if (e.code() == error_code_client_lib_not_found) {
|
||||
throw;
|
||||
}
|
||||
wait(tr.onError(e));
|
||||
}
|
||||
}
|
||||
@ -679,8 +695,8 @@ void applyClientLibFilter(const ClientLibFilter& filter,
|
||||
try {
|
||||
json_spirit::mObject metadataJson;
|
||||
parseMetadataJson(v, metadataJson);
|
||||
if (filter.matchAvailableOnly &&
|
||||
getStatusByName(getMetadataStrAttr(metadataJson, CLIENTLIB_ATTR_STATUS)) != CLIENTLIB_AVAILABLE) {
|
||||
if (filter.matchAvailableOnly && getStatusByName(getMetadataStrAttr(metadataJson, CLIENTLIB_ATTR_STATUS)) !=
|
||||
ClientLibStatus::AVAILABLE) {
|
||||
continue;
|
||||
}
|
||||
if (filter.matchCompatibleAPI &&
|
||||
@ -724,7 +740,7 @@ ACTOR Future<Standalone<VectorRef<StringRef>>> listClientLibraries(Database db,
|
||||
fromKey = fromKey.withSuffix(format("%09d", filter.numericPkgVersion + 1));
|
||||
}
|
||||
toKey = prefixWithPlatform.withSuffix(LiteralStringRef("0"));
|
||||
scanRange = KeyRangeRef(StringRef(fromKey), toKey);
|
||||
scanRange = KeyRangeRef(fromKey, toKey);
|
||||
} else {
|
||||
scanRange = clientLibMetadataKeys;
|
||||
}
|
||||
@ -744,10 +760,4 @@ ACTOR Future<Standalone<VectorRef<StringRef>>> listClientLibraries(Database db,
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<Standalone<VectorRef<StringRef>>> listCompatibleClientLibraries(Database db, int apiVersion) {
|
||||
return listClientLibraries(
|
||||
db,
|
||||
ClientLibFilter().filterAvailable().filterCompatibleAPI(apiVersion).filterPlatform(getCurrentClientPlatform()));
|
||||
}
|
||||
|
||||
} // namespace ClientLibManagement
|
@ -33,27 +33,27 @@
|
||||
|
||||
namespace ClientLibManagement {
|
||||
|
||||
enum ClientLibStatus {
|
||||
CLIENTLIB_DISABLED = 0,
|
||||
CLIENTLIB_AVAILABLE, // 1
|
||||
CLIENTLIB_UPLOADING, // 2
|
||||
CLIENTLIB_DELETING, // 3
|
||||
CLIENTLIB_STATUS_COUNT // must be the last one
|
||||
enum class ClientLibStatus {
|
||||
DISABLED = 0,
|
||||
AVAILABLE, // 1
|
||||
UPLOADING, // 2
|
||||
DELETING, // 3
|
||||
COUNT // must be the last one
|
||||
};
|
||||
|
||||
enum ClientLibPlatform {
|
||||
CLIENTLIB_UNKNOWN_PLATFORM = 0,
|
||||
CLIENTLIB_X86_64_LINUX,
|
||||
CLIENTLIB_X86_64_WINDOWS,
|
||||
CLIENTLIB_X86_64_MACOS,
|
||||
CLIENTLIB_PLATFORM_COUNT // must be the last one
|
||||
enum class ClientLibPlatform {
|
||||
UNKNOWN = 0,
|
||||
X86_64_LINUX,
|
||||
X86_64_WINDOWS,
|
||||
X86_64_MACOS,
|
||||
COUNT // must be the last one
|
||||
};
|
||||
|
||||
// Currently we support only one,
|
||||
// but we may want to change it in the future
|
||||
enum ClientLibChecksumAlg {
|
||||
CLIENTLIB_CHECKSUM_ALG_MD5 = 0,
|
||||
CLIENTLIB_CHECKSUM_ALG_COUNT // must be the last one
|
||||
enum class ClientLibChecksumAlg {
|
||||
MD5 = 0,
|
||||
COUNT // must be the last one
|
||||
};
|
||||
|
||||
inline const std::string CLIENTLIB_ATTR_PLATFORM{ "platform" };
|
||||
@ -75,7 +75,7 @@ struct ClientLibFilter {
|
||||
bool matchPlatform = false;
|
||||
bool matchCompatibleAPI = false;
|
||||
bool matchNewerPackageVersion = false;
|
||||
ClientLibPlatform platformVal = CLIENTLIB_UNKNOWN_PLATFORM;
|
||||
ClientLibPlatform platformVal = ClientLibPlatform::UNKNOWN;
|
||||
int apiVersion = 0;
|
||||
int numericPkgVersion = 0;
|
||||
|
||||
@ -110,29 +110,30 @@ const std::string& getChecksumAlgName(ClientLibChecksumAlg checksumAlg);
|
||||
ClientLibChecksumAlg getChecksumAlgByName(std::string_view checksumAlgName);
|
||||
|
||||
// encodes MD5 result to a hexadecimal string to be provided in the checksum attribute
|
||||
Standalone<StringRef> MD5SumToHexString(MD5_CTX& sum);
|
||||
Standalone<StringRef> md5SumToHexString(MD5_CTX& sum);
|
||||
|
||||
// Upload a client library binary from a file and associated metadata JSON
|
||||
// to the system keyspace of the database
|
||||
ACTOR Future<Void> uploadClientLibrary(Database db, StringRef metadataString, StringRef libFilePath);
|
||||
ACTOR Future<Void> uploadClientLibrary(Database db,
|
||||
Standalone<StringRef> metadataString,
|
||||
Standalone<StringRef> libFilePath);
|
||||
|
||||
// Determine clientLibId from the relevant attributes of the metadata JSON
|
||||
void getClientLibIdFromMetadataJson(StringRef metadataString, std::string& clientLibId);
|
||||
Standalone<StringRef> getClientLibIdFromMetadataJson(StringRef metadataString);
|
||||
|
||||
// Download a client library binary from the system keyspace of the database
|
||||
// and save it at the given file path
|
||||
ACTOR Future<Void> downloadClientLibrary(Database db, StringRef clientLibId, StringRef libFilePath);
|
||||
ACTOR Future<Void> downloadClientLibrary(Database db,
|
||||
Standalone<StringRef> clientLibId,
|
||||
Standalone<StringRef> libFilePath);
|
||||
|
||||
// Delete the client library binary from to the system keyspace of the database
|
||||
ACTOR Future<Void> deleteClientLibrary(Database db, StringRef clientLibId);
|
||||
ACTOR Future<Void> deleteClientLibrary(Database db, Standalone<StringRef> clientLibId);
|
||||
|
||||
// List client libraries available on the cluster, with the specified filter
|
||||
// Returns metadata JSON of each library
|
||||
ACTOR Future<Standalone<VectorRef<StringRef>>> listClientLibraries(Database db, ClientLibFilter filter);
|
||||
|
||||
// List available client libraries that are compatible with the current client
|
||||
Future<Standalone<VectorRef<StringRef>>> listAvailableCompatibleClientLibraries(Database db, int apiVersion);
|
||||
|
||||
} // namespace ClientLibManagement
|
||||
|
||||
#include "flow/unactorcompiler.h"
|
||||
|
@ -1707,10 +1707,10 @@ ACTOR Future<Void> runTests(Reference<ClusterConnectionFile> connFile,
|
||||
namespace {
|
||||
ACTOR Future<Void> testExpectedErrorImpl(Future<Void> test,
|
||||
const char* testDescr,
|
||||
Error expectedError,
|
||||
bool* successFlag,
|
||||
Optional<Error> expectedError,
|
||||
Optional<bool*> successFlag,
|
||||
std::map<std::string, std::string> details,
|
||||
Error throwOnError,
|
||||
Optional<Error> throwOnError,
|
||||
UID id) {
|
||||
state Error actualError;
|
||||
try {
|
||||
@ -1721,19 +1721,21 @@ ACTOR Future<Void> testExpectedErrorImpl(Future<Void> test,
|
||||
}
|
||||
actualError = e;
|
||||
// The test failed as expected
|
||||
if (!expectedError.isValid() || actualError.code() == expectedError.code()) {
|
||||
if (!expectedError.present() || actualError.code() == expectedError.get().code()) {
|
||||
return Void();
|
||||
}
|
||||
}
|
||||
|
||||
// The test has failed
|
||||
if (successFlag != nullptr) {
|
||||
*successFlag = false;
|
||||
if (successFlag.present()) {
|
||||
*(successFlag.get()) = false;
|
||||
}
|
||||
TraceEvent evt(SevError, "TestErrorFailed", id);
|
||||
evt.detail("TestDescr", testDescr);
|
||||
evt.detail("ExpectedError", expectedError.name());
|
||||
evt.detail("ExpectedErrorCode", expectedError.code());
|
||||
evt.detail("TestDescription", testDescr);
|
||||
if (expectedError.present()) {
|
||||
evt.detail("ExpectedError", expectedError.get().name());
|
||||
evt.detail("ExpectedErrorCode", expectedError.get().code());
|
||||
}
|
||||
if (actualError.isValid()) {
|
||||
evt.detail("ActualError", actualError.name());
|
||||
evt.detail("ActualErrorCode", actualError.code());
|
||||
@ -1743,8 +1745,8 @@ ACTOR Future<Void> testExpectedErrorImpl(Future<Void> test,
|
||||
for (auto& p : details) {
|
||||
evt.detail(p.first.c_str(), p.second);
|
||||
}
|
||||
if (throwOnError.isValid()) {
|
||||
throw throwOnError;
|
||||
if (throwOnError.present()) {
|
||||
throw throwOnError.get();
|
||||
}
|
||||
return Void();
|
||||
}
|
||||
@ -1752,10 +1754,10 @@ ACTOR Future<Void> testExpectedErrorImpl(Future<Void> test,
|
||||
|
||||
Future<Void> testExpectedError(Future<Void> test,
|
||||
const char* testDescr,
|
||||
Error expectedError,
|
||||
bool* successFlag,
|
||||
Optional<Error> expectedError,
|
||||
Optional<bool*> successFlag,
|
||||
std::map<std::string, std::string> details,
|
||||
Error throwOnError,
|
||||
Optional<Error> throwOnError,
|
||||
UID id) {
|
||||
return testExpectedErrorImpl(test, testDescr, expectedError, successFlag, details, throwOnError, id);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* This source file is part of the FoundationDB open source project
|
||||
*
|
||||
* Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
|
||||
* Copyright 2013-2021 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.
|
||||
@ -38,7 +38,7 @@ struct ClientLibManagementWorkload : public TestWorkload {
|
||||
|
||||
size_t testFileSize = 0;
|
||||
RandomByteGenerator rbg;
|
||||
std::string uploadedClientLibId;
|
||||
Standalone<StringRef> uploadedClientLibId;
|
||||
json_spirit::mObject uploadedMetadataJson;
|
||||
Standalone<StringRef> generatedChecksum;
|
||||
std::string generatedFileName;
|
||||
@ -91,7 +91,7 @@ struct ClientLibManagementWorkload : public TestWorkload {
|
||||
}
|
||||
wait(file->sync());
|
||||
|
||||
self->generatedChecksum = MD5SumToHexString(sum);
|
||||
self->generatedChecksum = md5SumToHexString(sum);
|
||||
|
||||
return Void();
|
||||
}
|
||||
@ -138,7 +138,7 @@ struct ClientLibManagementWorkload : public TestWorkload {
|
||||
|
||||
for (auto& testMetadataStr : invalidMetadataStrs) {
|
||||
metadataStr = StringRef(testMetadataStr);
|
||||
wait(testExpectedError(uploadClientLibrary(cx, metadataStr, self->generatedFileName),
|
||||
wait(testExpectedError(uploadClientLibrary(cx, metadataStr, StringRef(self->generatedFileName)),
|
||||
"uploadClientLibrary with invalid metadata",
|
||||
client_lib_invalid_metadata(),
|
||||
&self->success,
|
||||
@ -164,8 +164,8 @@ struct ClientLibManagementWorkload : public TestWorkload {
|
||||
state Standalone<StringRef> metadataStr;
|
||||
validClientLibMetadataSample(self->uploadedMetadataJson);
|
||||
metadataStr = StringRef(json_spirit::write_string(json_spirit::mValue(self->uploadedMetadataJson)));
|
||||
getClientLibIdFromMetadataJson(metadataStr, self->uploadedClientLibId);
|
||||
wait(testExpectedError(uploadClientLibrary(cx, metadataStr, self->generatedFileName),
|
||||
self->uploadedClientLibId = getClientLibIdFromMetadataJson(metadataStr);
|
||||
wait(testExpectedError(uploadClientLibrary(cx, metadataStr, StringRef(self->generatedFileName)),
|
||||
"uploadClientLibrary wrong checksum",
|
||||
client_lib_invalid_binary(),
|
||||
&self->success));
|
||||
@ -181,11 +181,11 @@ struct ClientLibManagementWorkload : public TestWorkload {
|
||||
// avoid clientLibId clashes, when multiple clients try to upload the same file
|
||||
self->uploadedMetadataJson[CLIENTLIB_ATTR_TYPE] = format("devbuild%d", self->clientId);
|
||||
metadataStr = StringRef(json_spirit::write_string(json_spirit::mValue(self->uploadedMetadataJson)));
|
||||
getClientLibIdFromMetadataJson(metadataStr, self->uploadedClientLibId);
|
||||
self->uploadedClientLibId = getClientLibIdFromMetadataJson(metadataStr);
|
||||
|
||||
// Test two concurrent uploads of the same library, one of the must fail and another succeed
|
||||
for (int i1 = 0; i1 < 2; i1++) {
|
||||
Future<Void> uploadActor = uploadClientLibrary(cx, metadataStr, self->generatedFileName);
|
||||
Future<Void> uploadActor = uploadClientLibrary(cx, metadataStr, StringRef(self->generatedFileName));
|
||||
concurrentUploads.push_back(errorOr(uploadActor));
|
||||
}
|
||||
|
||||
@ -214,15 +214,15 @@ struct ClientLibManagementWorkload : public TestWorkload {
|
||||
|
||||
ACTOR static Future<Void> testClientLibDownloadNotExisting(ClientLibManagementWorkload* self, Database cx) {
|
||||
// Generate a random valid clientLibId
|
||||
state std::string clientLibId;
|
||||
state Standalone<StringRef> clientLibId;
|
||||
state std::string destFileName;
|
||||
json_spirit::mObject metadataJson;
|
||||
validClientLibMetadataSample(metadataJson);
|
||||
Standalone<StringRef> metadataStr = StringRef(json_spirit::write_string(json_spirit::mValue(metadataJson)));
|
||||
getClientLibIdFromMetadataJson(metadataStr, clientLibId);
|
||||
clientLibId = getClientLibIdFromMetadataJson(metadataStr);
|
||||
|
||||
destFileName = format("clientLibDownload%d", self->clientId);
|
||||
wait(testExpectedError(downloadClientLibrary(cx, clientLibId, destFileName),
|
||||
wait(testExpectedError(downloadClientLibrary(cx, StringRef(clientLibId), StringRef(destFileName)),
|
||||
"download not existing client library",
|
||||
client_lib_not_found(),
|
||||
&self->success));
|
||||
@ -274,8 +274,8 @@ struct ClientLibManagementWorkload : public TestWorkload {
|
||||
wait(testUploadedClientLibInList(self, cx, filter, false, "Filter available, newer API"));
|
||||
filter = ClientLibFilter().filterCompatibleAPI(uploadedApiVersion).filterPlatform(uploadedPlatform);
|
||||
wait(testUploadedClientLibInList(self, cx, filter, true, "Filter the same API, the same platform"));
|
||||
ASSERT(uploadedPlatform != CLIENTLIB_X86_64_WINDOWS);
|
||||
filter = ClientLibFilter().filterAvailable().filterPlatform(CLIENTLIB_X86_64_WINDOWS);
|
||||
ASSERT(uploadedPlatform != ClientLibPlatform::X86_64_WINDOWS);
|
||||
filter = ClientLibFilter().filterAvailable().filterPlatform(ClientLibPlatform::X86_64_WINDOWS);
|
||||
wait(testUploadedClientLibInList(self, cx, filter, false, "Filter available, different platform"));
|
||||
filter = ClientLibFilter().filterAvailable().filterNewerPackageVersion(uploadedVersion);
|
||||
wait(testUploadedClientLibInList(self, cx, filter, false, "Filter available, the same version"));
|
||||
@ -304,8 +304,8 @@ struct ClientLibManagementWorkload : public TestWorkload {
|
||||
Standalone<VectorRef<StringRef>> allLibs = wait(listClientLibraries(cx, filter));
|
||||
bool found = false;
|
||||
for (StringRef metadataJson : allLibs) {
|
||||
std::string clientLibId;
|
||||
getClientLibIdFromMetadataJson(metadataJson, clientLibId);
|
||||
Standalone<StringRef> clientLibId;
|
||||
clientLibId = getClientLibIdFromMetadataJson(metadataJson);
|
||||
if (clientLibId == self->uploadedClientLibId) {
|
||||
found = true;
|
||||
}
|
||||
@ -340,12 +340,12 @@ struct ClientLibManagementWorkload : public TestWorkload {
|
||||
|
||||
static void validClientLibMetadataSample(json_spirit::mObject& metadataJson) {
|
||||
metadataJson.clear();
|
||||
metadataJson[CLIENTLIB_ATTR_PLATFORM] = getPlatformName(CLIENTLIB_X86_64_LINUX);
|
||||
metadataJson[CLIENTLIB_ATTR_PLATFORM] = getPlatformName(ClientLibPlatform::X86_64_LINUX);
|
||||
metadataJson[CLIENTLIB_ATTR_VERSION] = "7.1.0";
|
||||
metadataJson[CLIENTLIB_ATTR_GIT_HASH] = randomHexadecimalStr(40);
|
||||
metadataJson[CLIENTLIB_ATTR_TYPE] = "debug";
|
||||
metadataJson[CLIENTLIB_ATTR_CHECKSUM] = randomHexadecimalStr(32);
|
||||
metadataJson[CLIENTLIB_ATTR_STATUS] = getStatusName(CLIENTLIB_AVAILABLE);
|
||||
metadataJson[CLIENTLIB_ATTR_STATUS] = getStatusName(ClientLibStatus::AVAILABLE);
|
||||
metadataJson[CLIENTLIB_ATTR_API_VERSION] = 710;
|
||||
metadataJson[CLIENTLIB_ATTR_PROTOCOL] = "fdb00b07001001";
|
||||
metadataJson[CLIENTLIB_ATTR_CHECKSUM_ALG] = "md5";
|
||||
@ -360,7 +360,7 @@ struct ClientLibManagementWorkload : public TestWorkload {
|
||||
ASSERT(actualError.isValid());
|
||||
if (expectedError.code() != actualError.code()) {
|
||||
TraceEvent evt(SevError, "TestErrorCodeFailed", id);
|
||||
evt.detail("TestDesc", testDescr);
|
||||
evt.detail("TestDescription", testDescr);
|
||||
evt.detail("ExpectedError", expectedError.code());
|
||||
evt.error(actualError);
|
||||
for (auto& p : details) {
|
||||
|
@ -237,14 +237,15 @@ Future<Void> quietDatabase(Database const& cx,
|
||||
*
|
||||
* In case of a failure, logs an corresponding error in the trace with the given
|
||||
* description and details, sets the given success flag to false (optional)
|
||||
* and throws the given exception (optional).
|
||||
* and throws the given exception (optional). Note that in case of a successful
|
||||
* test execution, the success flag is kept unchanged.
|
||||
*/
|
||||
Future<Void> testExpectedError(Future<Void> test,
|
||||
const char* testDescr,
|
||||
Error expectedError = Error(),
|
||||
bool* successFlag = nullptr,
|
||||
Optional<Error> expectedError = Optional<Error>(),
|
||||
Optional<bool*> successFlag = Optional<bool*>(),
|
||||
std::map<std::string, std::string> details = {},
|
||||
Error throwOnError = Error(),
|
||||
Optional<Error> throwOnError = Optional<Error>(),
|
||||
UID id = UID());
|
||||
|
||||
#include "flow/unactorcompiler.h"
|
||||
|
Loading…
x
Reference in New Issue
Block a user