Add version epoch to status json

Adds a new `version_epoch` object to `status json`, which includes the
status of the feature, and the current epoch if it is enabled. If the
version epoch is disabled, the `epoch` field will not be present.

```
{
    "client" : {
        ...
    },
    "cluster" : {
        ...
        "version_epoch" : {
            "enabled" : "true",
            "epoch" : "100000"
        },
        ...
    }
}
```
This commit is contained in:
Lukas Joswiak 2023-01-24 11:01:23 -08:00
parent d7ebaad6ab
commit 2b5c0ebe7b
3 changed files with 54 additions and 3 deletions

View File

@ -909,6 +909,10 @@
"expired_age" : 0, // The age in seconds of expired_version.
"oldest_id_version" : 0, // The version of the oldest idempotency id still stored in the database.
"oldest_id_age" : 0 // The age in seconds of the oldest_id_version.
},
"version_epoch":{
"enabled": true,
"epoch": 0 // The version epoch, as an offset from the Unix epoch. This field will be excluded if enabled is false.
}
},
"client":{

View File

@ -981,6 +981,10 @@ const KeyRef JSONSchemas::statusSchema = R"statusSchema(
"expired_age": 0,
"oldest_id_version": 0,
"oldest_id_age": 0
},
"version_epoch":{
"enabled": false,
"epoch": 0
}
},
"client":{

View File

@ -1440,6 +1440,37 @@ ACTOR static Future<JsonBuilderObject> latencyProbeFetcher(Database cx,
return statusObj;
}
ACTOR static Future<JsonBuilderObject> versionEpochStatusFetcher(Database cx,
std::set<std::string>* incomplete_reasons) {
state JsonBuilderObject message;
try {
state Transaction tr(cx);
loop {
try {
tr.setOption(FDBTransactionOptions::PRIORITY_SYSTEM_IMMEDIATE);
tr.setOption(FDBTransactionOptions::LOCK_AWARE);
tr.setOption(FDBTransactionOptions::ACCESS_SYSTEM_KEYS);
Optional<Value> versionEpochVal = wait(timeoutError(BUGGIFY ? Never() : tr.get(versionEpochKey), 5.0));
message["enabled"] = versionEpochVal.present();
if (!versionEpochVal.present()) {
break;
}
int64_t versionEpoch = BinaryReader::fromStringRef<int64_t>(versionEpochVal.get(), Unversioned());
message["epoch"] = std::to_string(versionEpoch);
break;
} catch (Error& e) {
wait(tr.onError(e));
}
}
} catch (Error& e) {
if (e.code() == error_code_actor_cancelled) {
throw;
}
incomplete_reasons->insert(format("Unable to retrieve version epoch information (%s).", e.what()));
}
return message;
}
ACTOR static Future<Void> consistencyCheckStatusFetcher(Database cx,
JsonBuilderArray* messages,
std::set<std::string>* incomplete_reasons) {
@ -3130,10 +3161,20 @@ ACTOR Future<StatusReply> clusterGetStatus(
// construct status information for cluster subsections
state int statusCode = (int)RecoveryStatus::END;
state JsonBuilderObject recoveryStateStatus = wait(
recoveryStateStatusFetcher(cx, ccWorker, mWorker, workers.size(), &status_incomplete_reasons, &statusCode));
state Future<JsonBuilderObject> recoveryStateStatusFuture =
recoveryStateStatusFetcher(cx, ccWorker, mWorker, workers.size(), &status_incomplete_reasons, &statusCode);
state JsonBuilderObject idmpKeyStatus = wait(getIdmpKeyStatus(cx));
state Future<JsonBuilderObject> idmpKeyStatusFuture = getIdmpKeyStatus(cx);
state Future<JsonBuilderObject> versionEpochStatusFuture =
versionEpochStatusFetcher(cx, &status_incomplete_reasons);
wait(waitForAll<JsonBuilderObject>(
{ recoveryStateStatusFuture, idmpKeyStatusFuture, versionEpochStatusFuture }));
state JsonBuilderObject recoveryStateStatus = recoveryStateStatusFuture.get();
state JsonBuilderObject idmpKeyStatus = idmpKeyStatusFuture.get();
state JsonBuilderObject versionEpochStatus = versionEpochStatusFuture.get();
// machine metrics
state WorkerEvents mMetrics = workerEventsVec[0].present() ? workerEventsVec[0].get().first : WorkerEvents();
@ -3367,6 +3408,8 @@ ACTOR Future<StatusReply> clusterGetStatus(
if (!tenants.empty())
statusObj["tenants"] = tenants;
statusObj["version_epoch"] = versionEpochStatus;
// Merge dataOverlay into data
JsonBuilderObject& clusterDataSection = workerStatuses[0];