diff options
author | Ilia Shakhov <pixcc@ydb.tech> | 2025-03-14 11:33:25 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-03-14 11:33:25 +0300 |
commit | 3917ee3bf8708df6c1f97e3f5659c44272961fd3 (patch) | |
tree | e31c9d02614be6339437b11f88acd6081377a460 | |
parent | d843851178e39f1c590e0b4fe5adb96a4eaee240 (diff) | |
download | ydb-3917ee3bf8708df6c1f97e3f5659c44272961fd3.tar.gz |
Add create_time & last_refresh_time to Task in Maintenance API (#15690)
-rw-r--r-- | ydb/core/cms/api_adapters.cpp | 17 | ||||
-rw-r--r-- | ydb/core/cms/cms_maintenance_api_ut.cpp | 64 | ||||
-rw-r--r-- | ydb/core/cms/cms_state.h | 4 | ||||
-rw-r--r-- | ydb/core/cms/cms_tx_load_state.cpp | 6 | ||||
-rw-r--r-- | ydb/core/cms/cms_tx_store_permissions.cpp | 17 | ||||
-rw-r--r-- | ydb/core/cms/cms_ut_common.h | 36 | ||||
-rw-r--r-- | ydb/core/cms/scheme.h | 11 | ||||
-rw-r--r-- | ydb/public/api/protos/draft/ydb_maintenance.proto | 8 |
8 files changed, 159 insertions, 4 deletions
diff --git a/ydb/core/cms/api_adapters.cpp b/ydb/core/cms/api_adapters.cpp index cf416d3e88..0b2ebb8199 100644 --- a/ydb/core/cms/api_adapters.cpp +++ b/ydb/core/cms/api_adapters.cpp @@ -109,6 +109,11 @@ namespace { ConvertPermission(taskUid, protoPermission, actionState); } + void ConvertInstant(const TInstant& instant, google::protobuf::Timestamp& protoValue) { + protoValue.set_seconds(instant.Seconds()); + protoValue.set_nanos(instant.NanoSecondsOfSecond()); + } + } // anonymous template <typename TDerived, typename TEvRequest, typename TEvResponse> @@ -312,6 +317,10 @@ public: // performed actions: existing permissions if (cmsState->MaintenanceTasks.contains(taskUid)) { const auto& task = cmsState->MaintenanceTasks.at(taskUid); + + ConvertInstant(task.CreateTime, *result.mutable_create_time()); + ConvertInstant(task.LastRefreshTime, *result.mutable_last_refresh_time()); + for (const auto& id : task.Permissions) { if (!cmsState->Permissions.contains(id) || permissionsSeen.contains(id)) { continue; @@ -501,6 +510,8 @@ public: auto& result = *response->Record.MutableResult(); result.set_task_uid(taskUid); + ConvertInstant(task.CreateTime, *result.mutable_create_time()); + ConvertInstant(task.LastRefreshTime, *result.mutable_last_refresh_time()); // performed actions for (const auto& id : task.Permissions) { @@ -566,6 +577,8 @@ public: auto& result = *response->Record.MutableResult(); result.mutable_task_options()->set_task_uid(taskUid); + ConvertInstant(task.CreateTime, *result.mutable_create_time()); + ConvertInstant(task.LastRefreshTime, *result.mutable_last_refresh_time()); // performed actions for (const auto& id : task.Permissions) { @@ -633,6 +646,10 @@ public: // performed actions if (cmsState->MaintenanceTasks.contains(taskUid)) { const auto& task = cmsState->MaintenanceTasks.at(taskUid); + + ConvertInstant(task.CreateTime, *result.mutable_create_time()); + ConvertInstant(task.LastRefreshTime, *result.mutable_last_refresh_time()); + for (const auto& id : task.Permissions) { if (!cmsState->Permissions.contains(id)) { continue; diff --git a/ydb/core/cms/cms_maintenance_api_ut.cpp b/ydb/core/cms/cms_maintenance_api_ut.cpp index 52b8b37f81..823311191d 100644 --- a/ydb/core/cms/cms_maintenance_api_ut.cpp +++ b/ydb/core/cms/cms_maintenance_api_ut.cpp @@ -116,6 +116,70 @@ Y_UNIT_TEST_SUITE(TMaintenanceApiTest) { const auto &a = response.action_group_states(0).action_states(0); UNIT_ASSERT_VALUES_EQUAL(a.status(), ActionState::ACTION_STATUS_PERFORMED); } + + Y_UNIT_TEST(CreateTime) { + TCmsTestEnv env(8); + + // Move time to make it different from initial time + env.AdvanceCurrentTime(TDuration::MilliSeconds(5500)); + + // Create sets create time + auto createResult = env.CheckMaintenanceTaskCreate("task-1", Ydb::StatusIds::SUCCESS, + MakeActionGroup( + MakeLockAction(env.GetNodeId(0), TDuration::Minutes(10)) + ), + MakeActionGroup( + MakeLockAction(env.GetNodeId(1), TDuration::Minutes(10)) + ) + ); + UNIT_ASSERT_VALUES_UNEQUAL(createResult.create_time().seconds(), 0); + UNIT_ASSERT_VALUES_UNEQUAL(createResult.create_time().nanos(), 0); + + // Move time to make it different from create time + env.AdvanceCurrentTime(TDuration::MilliSeconds(5500)); + + // Get doesn't update create time + auto getResult = env.CheckMaintenanceTaskGet("task-1", Ydb::StatusIds::SUCCESS); + UNIT_ASSERT_VALUES_EQUAL(getResult.create_time().seconds(), createResult.create_time().seconds()); + UNIT_ASSERT_VALUES_EQUAL(getResult.create_time().nanos(), createResult.create_time().nanos()); + + // Refresh doesn't update create time + auto refreshResult = env.CheckMaintenanceTaskRefresh("task-1", Ydb::StatusIds::SUCCESS); + UNIT_ASSERT_VALUES_EQUAL(refreshResult.create_time().seconds(), createResult.create_time().seconds()); + UNIT_ASSERT_VALUES_EQUAL(refreshResult.create_time().nanos(), createResult.create_time().nanos()); + } + + Y_UNIT_TEST(LastRefreshTime) { + TCmsTestEnv env(8); + + // Move time to make it different from initial time + env.AdvanceCurrentTime(TDuration::MilliSeconds(5500)); + + // Create includes refresh, so create sets last refresh time + auto createResult = env.CheckMaintenanceTaskCreate("task-1", Ydb::StatusIds::SUCCESS, + MakeActionGroup( + MakeLockAction(env.GetNodeId(0), TDuration::Minutes(10)) + ), + MakeActionGroup( + MakeLockAction(env.GetNodeId(1), TDuration::Minutes(10)) + ) + ); + UNIT_ASSERT_VALUES_UNEQUAL(createResult.last_refresh_time().seconds(), 0); + UNIT_ASSERT_VALUES_UNEQUAL(createResult.last_refresh_time().nanos(), 0); + + // Move time to make it different from create time + env.AdvanceCurrentTime(TDuration::MilliSeconds(5500)); + + // Get doesn't update last refresh time + auto getResult = env.CheckMaintenanceTaskGet("task-1", Ydb::StatusIds::SUCCESS); + UNIT_ASSERT_VALUES_EQUAL(getResult.last_refresh_time().seconds(), createResult.last_refresh_time().seconds()); + UNIT_ASSERT_VALUES_EQUAL(getResult.last_refresh_time().nanos(), createResult.last_refresh_time().nanos()); + + // Refresh updates last refresh time + auto refreshResult = env.CheckMaintenanceTaskRefresh("task-1", Ydb::StatusIds::SUCCESS); + UNIT_ASSERT_VALUES_UNEQUAL(refreshResult.last_refresh_time().seconds(), createResult.last_refresh_time().seconds()); + UNIT_ASSERT_VALUES_UNEQUAL(refreshResult.last_refresh_time().nanos(), createResult.last_refresh_time().nanos()); + } } } // namespace NKikimr::NCmsTest diff --git a/ydb/core/cms/cms_state.h b/ydb/core/cms/cms_state.h index c6b5e5ba4d..328ba32719 100644 --- a/ydb/core/cms/cms_state.h +++ b/ydb/core/cms/cms_state.h @@ -16,6 +16,8 @@ struct TTaskInfo { TString Owner; TSet<TString> Permissions; bool HasSingleCompositeActionGroup = false; + TInstant CreateTime; + TInstant LastRefreshTime; TString ToString() const { return TStringBuilder() << "{" @@ -24,6 +26,8 @@ struct TTaskInfo { << " Owner: " << Owner << " Permissions: [" << JoinSeq(", ", Permissions) << "]" << " HasSingleCompositeActionGroup: " << HasSingleCompositeActionGroup + << " CreateTime: " << CreateTime + << " LastRefreshTime: " << LastRefreshTime << " }"; } }; diff --git a/ydb/core/cms/cms_tx_load_state.cpp b/ydb/core/cms/cms_tx_load_state.cpp index 5df136c557..62a8ad3019 100644 --- a/ydb/core/cms/cms_tx_load_state.cpp +++ b/ydb/core/cms/cms_tx_load_state.cpp @@ -135,13 +135,17 @@ public: TString requestId = maintenanceTasksRowset.GetValue<Schema::MaintenanceTasks::RequestID>(); TString owner = maintenanceTasksRowset.GetValue<Schema::MaintenanceTasks::Owner>(); bool hasSingleCompositeActionGroup = maintenanceTasksRowset.GetValue<Schema::MaintenanceTasks::HasSingleCompositeActionGroup>(); + ui64 createTime = maintenanceTasksRowset.GetValue<Schema::MaintenanceTasks::CreateTime>(); + ui64 lastRefreshTime = maintenanceTasksRowset.GetValue<Schema::MaintenanceTasks::LastRefreshTime>(); state->MaintenanceRequests.emplace(requestId, taskId); state->MaintenanceTasks.emplace(taskId, TTaskInfo{ .TaskId = taskId, .RequestId = requestId, .Owner = owner, - .HasSingleCompositeActionGroup = hasSingleCompositeActionGroup + .HasSingleCompositeActionGroup = hasSingleCompositeActionGroup, + .CreateTime = TInstant::MicroSeconds(createTime), + .LastRefreshTime = TInstant::MicroSeconds(lastRefreshTime) }); LOG_DEBUG(ctx, NKikimrServices::CMS, "Loaded maintenance task %s mapped to request %s", diff --git a/ydb/core/cms/cms_tx_store_permissions.cpp b/ydb/core/cms/cms_tx_store_permissions.cpp index b85160bac4..fd6086c3d6 100644 --- a/ydb/core/cms/cms_tx_store_permissions.cpp +++ b/ydb/core/cms/cms_tx_store_permissions.cpp @@ -31,6 +31,7 @@ public: const auto &rec = Response->Get<TEvCms::TEvPermissionResponse>()->Record; + auto now = ctx.Now(); if (MaintenanceTaskId) { Y_ABORT_UNLESS(Scheduled); @@ -39,13 +40,25 @@ public: .TaskId = *MaintenanceTaskId, .RequestId = Scheduled->RequestId, .Owner = Scheduled->Owner, - .HasSingleCompositeActionGroup = !Scheduled->Request.GetPartialPermissionAllowed() + .HasSingleCompositeActionGroup = !Scheduled->Request.GetPartialPermissionAllowed(), + .CreateTime = now, + .LastRefreshTime = now }); db.Table<Schema::MaintenanceTasks>().Key(*MaintenanceTaskId).Update( NIceDb::TUpdate<Schema::MaintenanceTasks::RequestID>(Scheduled->RequestId), NIceDb::TUpdate<Schema::MaintenanceTasks::Owner>(Scheduled->Owner), - NIceDb::TUpdate<Schema::MaintenanceTasks::HasSingleCompositeActionGroup>(!Scheduled->Request.GetPartialPermissionAllowed()) + NIceDb::TUpdate<Schema::MaintenanceTasks::HasSingleCompositeActionGroup>(!Scheduled->Request.GetPartialPermissionAllowed()), + NIceDb::TUpdate<Schema::MaintenanceTasks::CreateTime>(now.MicroSeconds()), + NIceDb::TUpdate<Schema::MaintenanceTasks::LastRefreshTime>(now.MicroSeconds()) + ); + } else if (Scheduled != nullptr && Self->State->MaintenanceRequests.contains(Scheduled->RequestId)) { + const auto& taskId = Self->State->MaintenanceRequests[Scheduled->RequestId]; + auto& task = Self->State->MaintenanceTasks.at(taskId); + + task.LastRefreshTime = now; + db.Table<Schema::MaintenanceTasks>().Key(taskId).Update( + NIceDb::TUpdate<Schema::MaintenanceTasks::LastRefreshTime>(now.MicroSeconds()) ); } diff --git a/ydb/core/cms/cms_ut_common.h b/ydb/core/cms/cms_ut_common.h index 9e502d59e2..f06fe90b79 100644 --- a/ydb/core/cms/cms_ut_common.h +++ b/ydb/core/cms/cms_ut_common.h @@ -407,6 +407,42 @@ public: return CheckResetMarker(req, code); } + Ydb::Maintenance::MaintenanceTaskResult CheckMaintenanceTaskRefresh( + const TString &taskUid, + Ydb::StatusIds::StatusCode code) + { + auto ev = std::make_unique<NCms::TEvCms::TEvRefreshMaintenanceTaskRequest>(); + + auto *req = ev->Record.MutableRequest(); + req->set_task_uid(taskUid); + + SendToPipe(CmsId, Sender, ev.release(), 0, GetPipeConfigWithRetries()); + TAutoPtr<IEventHandle> handle; + auto reply = GrabEdgeEventRethrow<NCms::TEvCms::TEvMaintenanceTaskResponse>(handle); + + const auto &rec = reply->Record; + UNIT_ASSERT_VALUES_EQUAL(rec.GetStatus(), code); + return rec.GetResult(); + } + + Ydb::Maintenance::GetMaintenanceTaskResult CheckMaintenanceTaskGet( + const TString &taskUid, + Ydb::StatusIds::StatusCode code) + { + auto ev = std::make_unique<NCms::TEvCms::TEvGetMaintenanceTaskRequest>(); + + auto *req = ev->Record.MutableRequest(); + req->set_task_uid(taskUid); + + SendToPipe(CmsId, Sender, ev.release(), 0, GetPipeConfigWithRetries()); + TAutoPtr<IEventHandle> handle; + auto reply = GrabEdgeEventRethrow<NCms::TEvCms::TEvGetMaintenanceTaskResponse>(handle); + + const auto &rec = reply->Record; + UNIT_ASSERT_VALUES_EQUAL(rec.GetStatus(), code); + return rec.GetResult(); + } + template <typename... Ts> Ydb::Maintenance::MaintenanceTaskResult CheckMaintenanceTaskCreate( const TString &taskUid, diff --git a/ydb/core/cms/scheme.h b/ydb/core/cms/scheme.h index bd9a4f38f2..672bac94fe 100644 --- a/ydb/core/cms/scheme.h +++ b/ydb/core/cms/scheme.h @@ -135,9 +135,18 @@ struct Schema : NIceDb::Schema { struct RequestID : Column<2, NScheme::NTypeIds::Utf8> {}; struct Owner : Column<3, NScheme::NTypeIds::Utf8> {}; struct HasSingleCompositeActionGroup : Column<4, NScheme::NTypeIds::Bool> {}; + struct CreateTime : Column<5, NScheme::NTypeIds::Uint64> {}; + struct LastRefreshTime : Column<6, NScheme::NTypeIds::Uint64> {}; using TKey = TableKey<TaskID>; - using TColumns = TableColumns<TaskID, RequestID, Owner, HasSingleCompositeActionGroup>; + using TColumns = TableColumns< + TaskID, + RequestID, + Owner, + HasSingleCompositeActionGroup, + CreateTime, + LastRefreshTime + >; }; using TTables = SchemaTables<Param, Permission, Request, WalleTask, Notification, NodeTenant, diff --git a/ydb/public/api/protos/draft/ydb_maintenance.proto b/ydb/public/api/protos/draft/ydb_maintenance.proto index 371f35db07..a77de97337 100644 --- a/ydb/public/api/protos/draft/ydb_maintenance.proto +++ b/ydb/public/api/protos/draft/ydb_maintenance.proto @@ -182,6 +182,10 @@ message MaintenanceTaskResult { repeated ActionGroupStates action_group_states = 2; // Try again after this deadline. Specified if there are no performed actions. optional google.protobuf.Timestamp retry_after = 3; + // The time when the mainteance task was created. + google.protobuf.Timestamp create_time = 4; + // The last time when the mainteance task was refreshed. Initially equals to create_time. + google.protobuf.Timestamp last_refresh_time = 5; } message MaintenanceTaskResponse { @@ -197,6 +201,10 @@ message GetMaintenanceTaskRequest { message GetMaintenanceTaskResult { MaintenanceTaskOptions task_options = 1; repeated ActionGroupStates action_group_states = 2; + // The time when the mainteance task was created. + google.protobuf.Timestamp create_time = 3; + // The last time when the mainteance task was refreshed. Initially equals to create_time. + google.protobuf.Timestamp last_refresh_time = 4; } message GetMaintenanceTaskResponse { |