aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ydb/core/cms/console/console__alter_tenant.cpp11
-rw-r--r--ydb/core/cms/console/console__create_tenant.cpp2
-rw-r--r--ydb/core/cms/console/console__scheme.h3
-rw-r--r--ydb/core/cms/console/console_tenants_manager.cpp24
-rw-r--r--ydb/core/cms/console/console_tenants_manager.h17
-rw-r--r--ydb/core/cms/console/console_ut_tenants.cpp88
6 files changed, 126 insertions, 19 deletions
diff --git a/ydb/core/cms/console/console__alter_tenant.cpp b/ydb/core/cms/console/console__alter_tenant.cpp
index dc44c25082..c0011cb68b 100644
--- a/ydb/core/cms/console/console__alter_tenant.cpp
+++ b/ydb/core/cms/console/console__alter_tenant.cpp
@@ -121,9 +121,14 @@ public:
for (auto &unit : rec.storage_units_to_add()) {
auto &kind = unit.unit_kind();
- if (Tenant->AreResourcesShared && !Tenant->StoragePools.contains(kind))
+ if (Tenant->StoragePools.contains(kind)) {
+ if (Tenant->StoragePools.at(kind)->Borrowed)
+ return Error(Ydb::StatusIds::BAD_REQUEST,
+ Sprintf("Pool '%s' is borrowed, cannot alter", kind.data()), ctx);
+ } else if (Tenant->AreResourcesShared) {
return Error(Ydb::StatusIds::UNSUPPORTED,
Sprintf("Database '%s' is shared, cannot add new storage units", path.data()), ctx);
+ }
if (Tenant->SharedDomainId)
return Error(Ydb::StatusIds::BAD_REQUEST,
@@ -235,7 +240,9 @@ public:
auto &kind = pr.first;
auto size = pr.second;
if (Tenant->StoragePools.contains(kind)) {
- pool = new TStoragePool(*Tenant->StoragePools.at(kind));
+ auto cur = Tenant->StoragePools.at(kind);
+ Y_VERIFY(!cur->Borrowed);
+ pool = new TStoragePool(*cur);
pool->AddRequiredGroups(size);
pool->State = TStoragePool::NOT_UPDATED;
} else {
diff --git a/ydb/core/cms/console/console__create_tenant.cpp b/ydb/core/cms/console/console__create_tenant.cpp
index 77d8166d54..2f8676de35 100644
--- a/ydb/core/cms/console/console__create_tenant.cpp
+++ b/ydb/core/cms/console/console__create_tenant.cpp
@@ -183,7 +183,7 @@ public:
auto poolName = Tenant->MakeStoragePoolName(kind);
auto &config = Self->Domain->StoragePoolTypes.at(kind);
- TStoragePool::TPtr pool = new TStoragePool(poolName, kind, size, config);
+ TStoragePool::TPtr pool = new TStoragePool(poolName, size, kind, config, false);
Tenant->StoragePools.emplace(std::make_pair(kind, pool));
}
}
diff --git a/ydb/core/cms/console/console__scheme.h b/ydb/core/cms/console/console__scheme.h
index 29eb6c3035..c4b32b5294 100644
--- a/ydb/core/cms/console/console__scheme.h
+++ b/ydb/core/cms/console/console__scheme.h
@@ -63,9 +63,10 @@ struct Schema : NIceDb::Schema {
struct Config : Column<3, NScheme::NTypeIds::Utf8> {};
struct AllocatedNumGroups : Column<4, NScheme::NTypeIds::Uint32> {};
struct State : Column<5, NScheme::NTypeIds::Uint32> {};
+ struct Borrowed : Column<6, NScheme::NTypeIds::Bool> {};
using TKey = TableKey<Tenant, PoolType>;
- using TColumns = TableColumns<Tenant, PoolType, Config, AllocatedNumGroups, State>;
+ using TColumns = TableColumns<Tenant, PoolType, Config, AllocatedNumGroups, State, Borrowed>;
};
struct TenantUnits : Table<4> {
diff --git a/ydb/core/cms/console/console_tenants_manager.cpp b/ydb/core/cms/console/console_tenants_manager.cpp
index 0db3f5dced..1853394eb8 100644
--- a/ydb/core/cms/console/console_tenants_manager.cpp
+++ b/ydb/core/cms/console/console_tenants_manager.cpp
@@ -1719,7 +1719,7 @@ TTenantsManager::TStoragePool::TPtr TTenantsManager::MakeStoragePool(TTenant::TP
auto poolName = tenant->MakeStoragePoolName(kind);
auto &config = Domain->StoragePoolTypes.at(kind);
- TStoragePool::TPtr pool = new TStoragePool(poolName, kind, size, config);
+ TStoragePool::TPtr pool = new TStoragePool(poolName, size, kind, config, false);
if (tenant->HasSubDomainKey())
pool->SetScopeId(tenant->DomainId);
@@ -1774,8 +1774,20 @@ void TTenantsManager::DeleteTenantPools(TTenant::TPtr tenant, const TActorContex
}
for (auto &pr : tenant->StoragePools) {
- if (pr.second->State != TStoragePool::DELETED)
+ if (pr.second->State == TStoragePool::DELETED) {
+ continue;
+ }
+
+ if (pr.second->Borrowed) {
+ BLOG_D("Mark borrowed pool as deleted"
+ << ": tenant# " << tenant->Path
+ << ", pool# " << pr.second->Config.GetName());
+
+ pr.second->Worker = SelfId();
+ ctx.Send(SelfId(), new TTenantsManager::TEvPrivate::TEvPoolDeleted(tenant, pr.second));
+ } else {
pr.second->Worker = ctx.RegisterWithSameMailbox(new TPoolManip(SelfId(), Domain, tenant, pr.second, TPoolManip::DEALLOCATE));
+ }
}
}
@@ -2451,23 +2463,24 @@ bool TTenantsManager::DbLoadState(TTransactionContext &txc, const TActorContext
while (!poolRowset.EndOfSet()) {
TString path = poolRowset.GetValue<Schema::TenantPools::Tenant>();
- TString type = poolRowset.GetValue<Schema::TenantPools::PoolType>();
+ TString kind = poolRowset.GetValue<Schema::TenantPools::PoolType>();
TString configVal = poolRowset.GetValue<Schema::TenantPools::Config>();
ui32 allocated = poolRowset.GetValue<Schema::TenantPools::AllocatedNumGroups>();
ui32 stateVal = poolRowset.GetValue<Schema::TenantPools::State>();
+ bool borrowed = poolRowset.GetValueOrDefault<Schema::TenantPools::Borrowed>(false);
TStoragePool::EState state = static_cast<TStoragePool::EState>(stateVal);
NKikimrBlobStorage::TDefineStoragePool config;
Y_PROTOBUF_SUPPRESS_NODISCARD config.ParseFromArray(configVal.data(), configVal.size());
- TStoragePool::TPtr pool = new TStoragePool(type, config);
+ TStoragePool::TPtr pool = new TStoragePool(kind, config, borrowed);
pool->AllocatedNumGroups = allocated;
pool->State = state;
auto tenant = GetTenant(path);
Y_VERIFY_DEBUG(tenant, "loaded pool for unknown tenant %s", path.data());
if (tenant) {
- tenant->StoragePools[type] = pool;
+ tenant->StoragePools[kind] = pool;
Counters.Inc(pool->Kind, COUNTER_REQUESTED_STORAGE_UNITS, pool->GetGroups());
Counters.Inc(pool->Kind, COUNTER_ALLOCATED_STORAGE_UNITS, pool->AllocatedNumGroups);
@@ -3085,7 +3098,6 @@ void TTenantsManager::Handle(TEvConsole::TEvRemoveTenantRequest::TPtr &ev, const
{
Counters.Inc(COUNTER_REMOVE_REQUESTS);
- auto path = CanonizePath(ev->Get()->Record.GetRequest().path());
TxProcessor->ProcessTx(CreateTxRemoveTenant(ev), ctx);
}
diff --git a/ydb/core/cms/console/console_tenants_manager.h b/ydb/core/cms/console/console_tenants_manager.h
index a21615dd62..3a769a9d56 100644
--- a/ydb/core/cms/console/console_tenants_manager.h
+++ b/ydb/core/cms/console/console_tenants_manager.h
@@ -280,18 +280,26 @@ public:
DELETED,
};
- TStoragePool(const TString &kind, const NKikimrBlobStorage::TDefineStoragePool &config)
+ TStoragePool(
+ const TString &kind,
+ const NKikimrBlobStorage::TDefineStoragePool &config,
+ bool borrowed)
: Kind(kind)
, Config(config)
, AllocatedNumGroups(0)
, State(NOT_ALLOCATED)
+ , Borrowed(borrowed)
{
Config.SetKind(kind);
}
- TStoragePool(const TString &name, const TString &kind, ui64 size,
- const NKikimrBlobStorage::TDefineStoragePool &config)
- : TStoragePool(kind, config)
+ TStoragePool(
+ const TString &name,
+ ui64 size,
+ const TString &kind,
+ const NKikimrBlobStorage::TDefineStoragePool &config,
+ bool borrowed)
+ : TStoragePool(kind, config, borrowed)
{
Config.SetName(name);
Config.SetNumGroups(size);
@@ -337,6 +345,7 @@ public:
NKikimrBlobStorage::TDefineStoragePool Config;
ui64 AllocatedNumGroups;
EState State;
+ bool Borrowed;
TString Issue;
TActorId Worker;
size_t GroupFitErrors = 0;
diff --git a/ydb/core/cms/console/console_ut_tenants.cpp b/ydb/core/cms/console/console_ut_tenants.cpp
index 57e4820af7..f2709dbf6e 100644
--- a/ydb/core/cms/console/console_ut_tenants.cpp
+++ b/ydb/core/cms/console/console_ut_tenants.cpp
@@ -385,8 +385,7 @@ void CheckTenantGeneration(TTenantTestRuntime &runtime,
UNIT_ASSERT_VALUES_EQUAL(status.generation(), generation);
}
-void CheckPoolScope(TTenantTestRuntime &runtime,
- const TString &name)
+NKikimrBlobStorage::TEvControllerConfigResponse ReadPoolState(TTenantTestRuntime &runtime, const TString &name)
{
auto request = MakeHolder<TEvBlobStorage::TEvControllerConfigRequest>();
auto &read = *request->Record.MutableRequest()->AddCommand()->MutableReadStoragePool();
@@ -397,9 +396,14 @@ void CheckPoolScope(TTenantTestRuntime &runtime,
pipeConfig.RetryPolicy = NTabletPipe::TClientRetryPolicy::WithRetries();
runtime.SendToPipe(MakeBSControllerID(0), runtime.Sender, request.Release(), 0, pipeConfig);
- TAutoPtr<IEventHandle> handle;
- auto reply = runtime.GrabEdgeEventRethrow<TEvBlobStorage::TEvControllerConfigResponse>(handle);
- const auto &scope = reply->Record.GetResponse().GetStatus(0).GetStoragePool(0).GetScopeId();
+ auto ev = runtime.GrabEdgeEventRethrow<TEvBlobStorage::TEvControllerConfigResponse>(runtime.Sender);
+ return ev->Get()->Record;
+}
+
+void CheckPoolScope(TTenantTestRuntime &runtime, const TString &name)
+{
+ auto response = ReadPoolState(runtime, name);
+ const auto &scope = response.GetResponse().GetStatus(0).GetStoragePool(0).GetScopeId();
UNIT_ASSERT(scope.GetX1() != 0);
UNIT_ASSERT(scope.GetX2() != 0);
}
@@ -440,6 +444,27 @@ void SendCaptured(TTenantTestRuntime &runtime, TVector<TAutoPtr<IEventHandle>> &
events.clear();
}
+void LocalMiniKQL(TTenantTestRuntime& runtime, ui64 tabletId, const TString& query) {
+ auto request = MakeHolder<TEvTablet::TEvLocalMKQL>();
+ request->Record.MutableProgram()->MutableProgram()->SetText(query);
+ ForwardToTablet(runtime, tabletId, runtime.Sender, request.Release());
+
+ auto ev = runtime.GrabEdgeEventRethrow<TEvTablet::TEvLocalMKQLResponse>(runtime.Sender);
+ const auto& response = ev->Get()->Record;
+
+ UNIT_ASSERT_VALUES_EQUAL(response.GetStatus(), NKikimrProto::OK);
+}
+
+void MakePoolBorrowed(TTenantTestRuntime& runtime, const TString& tenant, const TString& pool) {
+ LocalMiniKQL(runtime, MakeConsoleID(0), Sprintf(R"(
+ (
+ (let key '('('Tenant (Utf8 '"%s")) '('PoolType (Utf8 '"%s"))))
+ (let row '('('Borrowed (Bool '1))))
+ (return (AsList (UpdateRow 'TenantPools key row)))
+ )
+ )", tenant.c_str(), pool.c_str()));
+}
+
} // anonymous namespace
Y_UNIT_TEST_SUITE(TConsoleTxProcessorTests) {
@@ -1159,6 +1184,59 @@ Y_UNIT_TEST_SUITE(TConsoleTests) {
RunTestAlterUnknownTenant(runtime);
}
+ Y_UNIT_TEST(TestAlterBorrowedStorage) {
+ TTenantTestRuntime runtime(DefaultConsoleTestConfig(), {}, true);
+
+ // create tenant
+ CheckCreateTenant(runtime, Ydb::StatusIds::SUCCESS,
+ TCreateTenantRequest(TENANT1_1_NAME, TCreateTenantRequest::EType::Common)
+ .WithPools({{"hdd", 1}})
+ .WithSlots(SLOT1_TYPE, ZONE1, 1));
+
+ CheckTenantStatus(runtime, TENANT1_1_NAME, Ydb::StatusIds::SUCCESS,
+ Ydb::Cms::GetDatabaseStatusResult::RUNNING,
+ {{"hdd", 1, 1}}, {},
+ SLOT1_TYPE, ZONE1, 1, 1);
+
+ // mark pool as borrowed
+ MakePoolBorrowed(runtime, TENANT1_1_NAME, "hdd");
+ // restart to changes take effect
+ RestartConsole(runtime);
+
+ // trying to extend pool
+ CheckAlterTenantPools(runtime, TENANT1_1_NAME, Ydb::StatusIds::BAD_REQUEST, {{"hdd", 1}}, {});
+ }
+
+ Y_UNIT_TEST(TestRemoveTenantWithBorrowedStorageUnits) {
+ TTenantTestRuntime runtime(DefaultConsoleTestConfig(), {}, true);
+ runtime.SetLogPriority(NKikimrServices::CMS_TENANTS, NActors::NLog::PRI_DEBUG);
+
+ // create tenant
+ CheckCreateTenant(runtime, Ydb::StatusIds::SUCCESS,
+ TCreateTenantRequest(TENANT1_1_NAME, TCreateTenantRequest::EType::Common)
+ .WithPools({{"hdd", 1}})
+ .WithSlots(SLOT1_TYPE, ZONE1, 1));
+
+ CheckTenantStatus(runtime, TENANT1_1_NAME, Ydb::StatusIds::SUCCESS,
+ Ydb::Cms::GetDatabaseStatusResult::RUNNING,
+ {{"hdd", 1, 1}}, {},
+ SLOT1_TYPE, ZONE1, 1, 1);
+
+ // mark pool as borrowed
+ MakePoolBorrowed(runtime, TENANT1_1_NAME, "hdd");
+ // restart to changes take effect
+ RestartConsole(runtime);
+
+ // remove tenant
+ CheckRemoveTenant(runtime, TENANT1_1_NAME, Ydb::StatusIds::SUCCESS);
+ CheckTenantStatus(runtime, TENANT1_1_NAME, Ydb::StatusIds::NOT_FOUND,
+ Ydb::Cms::GetDatabaseStatusResult::STATE_UNSPECIFIED, {}, {});
+
+ // check pool (should be alive)
+ auto poolState = ReadPoolState(runtime, TENANT1_1_NAME + ":hdd");
+ UNIT_ASSERT_VALUES_EQUAL(poolState.GetResponse().GetStatus(0).StoragePoolSize(), 1);
+ }
+
Y_UNIT_TEST(TestAlterStorageUnitsOfSharedTenant) {
TTenantTestRuntime runtime(DefaultConsoleTestConfig(), {}, true);
// create shared tenant