MVC2.0: Introducing client library status values for instructing clients to download and activate a library; Operations to read and change client library status

This commit is contained in:
Vaidas Gasiunas 2021-10-12 17:29:09 +02:00
parent 6174229a1b
commit 4f0991eb67
3 changed files with 112 additions and 3 deletions

View File

@ -46,7 +46,7 @@ struct ClientLibBinaryInfo {
#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" };
static const std::string statusNames[] = { "disabled", "available", "uploading", "download", "active" };
int idx = static_cast<int>(status);
ASSERT_INDEX_IN_RANGE(idx, statusNames);
return statusNames[idx];
@ -123,7 +123,13 @@ ClientLibChecksumAlg getChecksumAlgByName(std::string_view checksumAlgName) {
namespace {
bool isValidTargetStatus(ClientLibStatus status) {
return status == ClientLibStatus::AVAILABLE || status == ClientLibStatus::DISABLED;
return status == ClientLibStatus::AVAILABLE || status == ClientLibStatus::DISABLED ||
status == ClientLibStatus::DOWNLOAD || status == ClientLibStatus::ACTIVE;
}
bool isAvailableForDownload(ClientLibStatus status) {
return status == ClientLibStatus::AVAILABLE || status == ClientLibStatus::DOWNLOAD ||
status == ClientLibStatus::ACTIVE;
}
json_spirit::mObject parseMetadataJson(StringRef metadataString) {
@ -489,7 +495,7 @@ ACTOR Future<Void> downloadClientLibrary(Database db,
}
// Allow downloading only libraries in the available state
if (getStatusByName(getMetadataStrAttr(metadataJson, CLIENTLIB_ATTR_STATUS)) != ClientLibStatus::AVAILABLE) {
if (!isAvailableForDownload(getStatusByName(getMetadataStrAttr(metadataJson, CLIENTLIB_ATTR_STATUS)))) {
throw client_lib_not_available();
}
@ -707,4 +713,62 @@ ACTOR Future<Standalone<VectorRef<StringRef>>> listClientLibraries(Database db,
return result;
}
ACTOR Future<ClientLibStatus> getClientLibraryStatus(Database db, StringRef clientLibId) {
state Key clientLibMetaKey = metadataKeyFromId(clientLibId.toString());
state Transaction tr(db);
loop {
try {
tr.setOption(FDBTransactionOptions::READ_SYSTEM_KEYS);
Optional<Value> metadataOpt = wait(tr.get(clientLibMetaKey));
if (!metadataOpt.present()) {
TraceEvent(SevWarnAlways, "ClientLibraryNotFound").detail("Key", clientLibMetaKey);
throw client_lib_not_found();
}
json_spirit::mObject metadataJson = parseMetadataJson(metadataOpt.get());
return getStatusByName(getMetadataStrAttr(metadataJson, CLIENTLIB_ATTR_STATUS));
} catch (Error& e) {
wait(tr.onError(e));
}
}
}
ACTOR Future<Void> changeClientLibraryStatus(Database db, StringRef clientLibId, ClientLibStatus newStatus) {
state Key clientLibMetaKey = metadataKeyFromId(clientLibId.toString());
state json_spirit::mObject metadataJson;
state std::string jsStr;
if (!isValidTargetStatus(newStatus)) {
TraceEvent(SevWarnAlways, "ClientLibraryInvalidMetadata")
.detail("Reason", "InvalidTargetStatus")
.detail("Status", getStatusName(newStatus));
throw client_lib_invalid_metadata();
}
loop {
state Transaction tr(db);
try {
tr.setOption(FDBTransactionOptions::ACCESS_SYSTEM_KEYS);
Optional<Value> metadataOpt = wait(tr.get(clientLibMetaKey));
if (!metadataOpt.present()) {
TraceEvent(SevWarnAlways, "ClientLibraryNotFound").detail("Key", clientLibMetaKey);
throw client_lib_not_found();
}
metadataJson = parseMetadataJson(metadataOpt.get());
metadataJson[CLIENTLIB_ATTR_STATUS] = getStatusName(newStatus);
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));
}
}
TraceEvent("ClientLibraryStatusChanged").detail("Key", clientLibMetaKey).detail("Status", getStatusName(newStatus));
return Void();
}
} // namespace ClientLibManagement

View File

@ -37,6 +37,8 @@ enum class ClientLibStatus {
DISABLED = 0,
AVAILABLE, // 1
UPLOADING, // 2
DOWNLOAD, // 3
ACTIVE, // 4
COUNT // must be the last one
};
@ -133,6 +135,12 @@ ACTOR Future<Void> deleteClientLibrary(Database db, Standalone<StringRef> client
// Returns metadata JSON of each library
ACTOR Future<Standalone<VectorRef<StringRef>>> listClientLibraries(Database db, ClientLibFilter filter);
// Get the current status of an uploaded client library
ACTOR Future<ClientLibStatus> getClientLibraryStatus(Database db, StringRef clientLibId);
// Change client library metadata status
ACTOR Future<Void> changeClientLibraryStatus(Database db, StringRef clientLibId, ClientLibStatus newStatus);
} // namespace ClientLibManagement
#include "flow/unactorcompiler.h"

View File

@ -107,6 +107,8 @@ struct ClientLibManagementWorkload : public TestWorkload {
wait(testClientLibListAfterUpload(self, cx));
wait(testDownloadClientLib(self, cx));
wait(testClientLibDownloadNotExisting(self, cx));
wait(testChangeClientLibStatusErrors(self, cx));
wait(testDisableClientLib(self, cx));
wait(testDeleteClientLib(self, cx));
wait(testUploadedClientLibInList(self, cx, ClientLibFilter(), false, "No filter, after delete"));
return Void();
@ -321,6 +323,41 @@ struct ClientLibManagementWorkload : public TestWorkload {
return Void();
}
ACTOR static Future<Void> testChangeClientLibStatusErrors(ClientLibManagementWorkload* self, Database cx) {
wait(testExpectedError(changeClientLibraryStatus(cx, self->uploadedClientLibId, ClientLibStatus::UPLOADING),
"Setting invalid client library status",
client_lib_invalid_metadata(),
&self->success));
wait(testExpectedError(changeClientLibraryStatus(cx, "notExistingClientLib"_sr, ClientLibStatus::DOWNLOAD),
"Changing not existing client library status",
client_lib_not_found(),
&self->success));
return Void();
}
ACTOR static Future<Void> testDisableClientLib(ClientLibManagementWorkload* self, Database cx) {
state std::string destFileName = format("clientLibDownload%d", self->clientId);
// Set disabled status on the uploaded library
wait(changeClientLibraryStatus(cx, self->uploadedClientLibId, ClientLibStatus::DISABLED));
state ClientLibStatus newStatus = wait(getClientLibraryStatus(cx, self->uploadedClientLibId));
if (newStatus != ClientLibStatus::DISABLED) {
TraceEvent(SevError, "ClientLibDisableClientLibFailed")
.detail("Reason", "Unexpected status")
.detail("Expected", ClientLibStatus::DISABLED)
.detail("Actual", newStatus);
self->success = false;
}
// It should not be possible to download a disabled client library
wait(testExpectedError(downloadClientLibrary(cx, self->uploadedClientLibId, StringRef(destFileName)),
"Downloading disabled client library",
client_lib_not_available(),
&self->success));
return Void();
}
/* ----------------------------------------------------------------
* Utility methods
*/