From 471537b0a31885e9ef0eadb773b73d7fe62f98e1 Mon Sep 17 00:00:00 2001 From: ya-ksgamora Date: Mon, 27 Jan 2025 15:18:29 +0000 Subject: [PATCH] Pending allocation unit tests --- .../disk_registry/disk_registry_state.h | 2 +- .../disk_registry_state_ut_create.cpp | 277 ++++++++++++++++++ ...disk_registry_state_ut_pending_cleanup.cpp | 110 +++++++ 3 files changed, 388 insertions(+), 1 deletion(-) diff --git a/cloud/blockstore/libs/storage/disk_registry/disk_registry_state.h b/cloud/blockstore/libs/storage/disk_registry/disk_registry_state.h index db43cdf4d0f..31a09cc106d 100644 --- a/cloud/blockstore/libs/storage/disk_registry/disk_registry_state.h +++ b/cloud/blockstore/libs/storage/disk_registry/disk_registry_state.h @@ -516,7 +516,7 @@ class TDiskRegistryState /// Mark selected device as clean and remove it /// from lists of suspended/dirty/pending cleanup devices - /// @return deallocated disk id of where selected device was deallocated + /// @return disk id where selected device was deallocated TDiskId MarkDeviceAsClean( TInstant now, TDiskRegistryDatabase& db, diff --git a/cloud/blockstore/libs/storage/disk_registry/disk_registry_state_ut_create.cpp b/cloud/blockstore/libs/storage/disk_registry/disk_registry_state_ut_create.cpp index 52db53ee190..568935722a5 100644 --- a/cloud/blockstore/libs/storage/disk_registry/disk_registry_state_ut_create.cpp +++ b/cloud/blockstore/libs/storage/disk_registry/disk_registry_state_ut_create.cpp @@ -492,6 +492,283 @@ Y_UNIT_TEST_SUITE(TDiskRegistryStateCreateTest) } } + Y_UNIT_TEST(ShouldAllocateLocalWithDirtyDevices) + { + TTestExecutor executor; + executor.WriteTx([&](TDiskRegistryDatabase db) { db.InitSchema(); }); + + constexpr ui64 LocalDeviceSize = 99999997952; // ~ 93.13 GiB + + auto makeLocalDevice = [](const auto* name, const auto* uuid) + { + return Device(name, uuid) | + WithPool("local-ssd", NProto::DEVICE_POOL_KIND_LOCAL) | + WithTotalSize(LocalDeviceSize); + }; + + auto agentConfig = AgentConfig( + 1, + { + makeLocalDevice("NVMELOCAL01", "uuid-1"), + makeLocalDevice("NVMELOCAL02", "uuid-2"), + makeLocalDevice("NVMELOCAL03", "uuid-3"), + }); + const TVector agents{ + agentConfig, + }; + + TDiskRegistryState state = + TDiskRegistryStateBuilder() + .WithConfig( + [&] + { + auto config = MakeConfig(0, agents); + + auto* pool = config.AddDevicePoolConfigs(); + pool->SetName("local-ssd"); + pool->SetKind(NProto::DEVICE_POOL_KIND_LOCAL); + pool->SetAllocationUnit(LocalDeviceSize); + + return config; + }()) + .WithAgents(agents) + .WithDirtyDevices( + {TDirtyDevice{"uuid-1", {}}, + TDirtyDevice{"uuid-2", {}}, + TDirtyDevice{"uuid-3", {}}}) + .Build(); + + auto allocate = [&](auto db, ui32 deviceCount) + { + TDiskRegistryState::TAllocateDiskResult result; + + auto error = state.AllocateDisk( + TInstant::Zero(), + db, + TDiskRegistryState::TAllocateDiskParams{ + .DiskId = "local0", + .BlockSize = DefaultLogicalBlockSize, + .BlocksCount = + deviceCount * LocalDeviceSize / DefaultLogicalBlockSize, + .MediaKind = NProto::STORAGE_MEDIA_SSD_LOCAL}, + &result); + + return std::make_pair(std::move(result), error); + }; + + // Register agents. + executor.WriteTx( + [&](TDiskRegistryDatabase db) { + UNIT_ASSERT_SUCCESS( + RegisterAgent(state, db, agentConfig, Now())); + }); + + UNIT_ASSERT_VALUES_EQUAL(1, state.GetConfig().KnownAgentsSize()); + UNIT_ASSERT_VALUES_EQUAL(1, state.GetAgents().size()); + UNIT_ASSERT_VALUES_EQUAL(0, state.GetSuspendedDevices().size()); + UNIT_ASSERT_VALUES_EQUAL(3, state.GetDirtyDevices().size()); + UNIT_ASSERT_VALUES_EQUAL(0, state.GetBrokenDevices().size()); + + // Allocate disk with dirty devices + executor.WriteTx( + [&](TDiskRegistryDatabase db) + { + auto [result, error] = allocate(db, 3U); + UNIT_ASSERT_SUCCESS(error); + UNIT_ASSERT_VALUES_EQUAL(3U, result.Devices.size()); + UNIT_ASSERT_VALUES_EQUAL(3U, result.DirtyDevices.size()); + UNIT_ASSERT_VALUES_EQUAL( + "NVMELOCAL01", + result.Devices[0].GetDeviceName()); + }); + } + + Y_UNIT_TEST(ShouldFavorCleanLocalDevices) + { + TTestExecutor executor; + executor.WriteTx([&](TDiskRegistryDatabase db) { db.InitSchema(); }); + + constexpr ui64 LocalDeviceSize = 99999997952; // ~ 93.13 GiB + + auto makeLocalDevice = [](const auto* name, const auto* uuid) + { + return Device(name, uuid) | + WithPool("local-ssd", NProto::DEVICE_POOL_KIND_LOCAL) | + WithTotalSize(LocalDeviceSize); + }; + + auto agentConfig = AgentConfig( + 1, + { + makeLocalDevice("NVMELOCAL01", "uuid-1"), + makeLocalDevice("NVMELOCAL02", "uuid-2"), + makeLocalDevice("NVMELOCAL03", "uuid-3"), + }); + const TVector agents{ + agentConfig, + }; + + TDiskRegistryState state = + TDiskRegistryStateBuilder() + .WithConfig( + [&] + { + auto config = MakeConfig(0, agents); + + auto* pool = config.AddDevicePoolConfigs(); + pool->SetName("local-ssd"); + pool->SetKind(NProto::DEVICE_POOL_KIND_LOCAL); + pool->SetAllocationUnit(LocalDeviceSize); + + return config; + }()) + .WithAgents(agents) + .WithDirtyDevices( + {TDirtyDevice{"uuid-1", {}}, + TDirtyDevice{"uuid-3", {}}}) + .Build(); + + auto allocate = [&](auto db, ui32 deviceCount) + { + TDiskRegistryState::TAllocateDiskResult result; + + auto error = state.AllocateDisk( + TInstant::Zero(), + db, + TDiskRegistryState::TAllocateDiskParams{ + .DiskId = "local0", + .BlockSize = DefaultLogicalBlockSize, + .BlocksCount = + deviceCount * LocalDeviceSize / DefaultLogicalBlockSize, + .MediaKind = NProto::STORAGE_MEDIA_SSD_LOCAL}, + &result); + + return std::make_pair(std::move(result), error); + }; + + // Register agents. + executor.WriteTx( + [&](TDiskRegistryDatabase db) { + UNIT_ASSERT_SUCCESS( + RegisterAgent(state, db, agentConfig, Now())); + }); + + UNIT_ASSERT_VALUES_EQUAL(1, state.GetConfig().KnownAgentsSize()); + UNIT_ASSERT_VALUES_EQUAL(1, state.GetAgents().size()); + UNIT_ASSERT_VALUES_EQUAL(0, state.GetSuspendedDevices().size()); + UNIT_ASSERT_VALUES_EQUAL(2, state.GetDirtyDevices().size()); + UNIT_ASSERT_VALUES_EQUAL(0, state.GetBrokenDevices().size()); + + // Allocate disk with dirty devices + executor.WriteTx( + [&](TDiskRegistryDatabase db) + { + auto [result, error] = allocate(db, 1U); + UNIT_ASSERT_SUCCESS(error); + UNIT_ASSERT_VALUES_EQUAL(1U, result.Devices.size()); + UNIT_ASSERT_VALUES_EQUAL(0U, result.DirtyDevices.size()); + UNIT_ASSERT_VALUES_EQUAL( + "NVMELOCAL02", + result.Devices[0].GetDeviceName()); + }); + } + + Y_UNIT_TEST(ShouldFavorCleanDevicesAndAllocateDirty) + { + TTestExecutor executor; + executor.WriteTx([&](TDiskRegistryDatabase db) { db.InitSchema(); }); + + constexpr ui64 LocalDeviceSize = 99999997952; // ~ 93.13 GiB + + auto makeLocalDevice = [](const auto* name, const auto* uuid) + { + return Device(name, uuid) | + WithPool("local-ssd", NProto::DEVICE_POOL_KIND_LOCAL) | + WithTotalSize(LocalDeviceSize); + }; + + auto agentConfig = AgentConfig( + 1, + { + makeLocalDevice("NVMELOCAL01", "uuid-1"), + makeLocalDevice("NVMELOCAL02", "uuid-2"), + makeLocalDevice("NVMELOCAL03", "uuid-3"), + }); + const TVector agents{ + agentConfig, + }; + + TDiskRegistryState state = + TDiskRegistryStateBuilder() + .WithConfig( + [&] + { + auto config = MakeConfig(0, agents); + + auto* pool = config.AddDevicePoolConfigs(); + pool->SetName("local-ssd"); + pool->SetKind(NProto::DEVICE_POOL_KIND_LOCAL); + pool->SetAllocationUnit(LocalDeviceSize); + + return config; + }()) + .WithAgents(agents) + .WithDirtyDevices( + {TDirtyDevice{"uuid-1", {}}, + TDirtyDevice{"uuid-3", {}}}) + .Build(); + + auto allocate = [&](auto db, ui32 deviceCount) + { + TDiskRegistryState::TAllocateDiskResult result; + + auto error = state.AllocateDisk( + TInstant::Zero(), + db, + TDiskRegistryState::TAllocateDiskParams{ + .DiskId = "local0", + .BlockSize = DefaultLogicalBlockSize, + .BlocksCount = + deviceCount * LocalDeviceSize / DefaultLogicalBlockSize, + .MediaKind = NProto::STORAGE_MEDIA_SSD_LOCAL}, + &result); + + return std::make_pair(std::move(result), error); + }; + + // Register agents. + executor.WriteTx( + [&](TDiskRegistryDatabase db) { + UNIT_ASSERT_SUCCESS( + RegisterAgent(state, db, agentConfig, Now())); + }); + + UNIT_ASSERT_VALUES_EQUAL(1, state.GetConfig().KnownAgentsSize()); + UNIT_ASSERT_VALUES_EQUAL(1, state.GetAgents().size()); + UNIT_ASSERT_VALUES_EQUAL(0, state.GetSuspendedDevices().size()); + UNIT_ASSERT_VALUES_EQUAL(2, state.GetDirtyDevices().size()); + UNIT_ASSERT_VALUES_EQUAL(0, state.GetBrokenDevices().size()); + + // Allocate disk with dirty devices + executor.WriteTx( + [&](TDiskRegistryDatabase db) + { + auto [result, error] = allocate(db, 2U); + UNIT_ASSERT_SUCCESS(error); + UNIT_ASSERT_VALUES_EQUAL(2U, result.Devices.size()); + UNIT_ASSERT_VALUES_EQUAL(1U, result.DirtyDevices.size()); + UNIT_ASSERT_VALUES_EQUAL( + "NVMELOCAL01", + result.DirtyDevices[0].GetDeviceName()); + UNIT_ASSERT_VALUES_EQUAL( + "NVMELOCAL02", + result.Devices[0].GetDeviceName()); + UNIT_ASSERT_VALUES_EQUAL( + "NVMELOCAL01", + result.Devices[1].GetDeviceName()); + }); + } + Y_UNIT_TEST(ShouldAllocateDiskWithAdjustedBlockCount) { TTestExecutor executor; diff --git a/cloud/blockstore/libs/storage/disk_registry/disk_registry_state_ut_pending_cleanup.cpp b/cloud/blockstore/libs/storage/disk_registry/disk_registry_state_ut_pending_cleanup.cpp index eba9d0bd536..5ae7a1590c8 100644 --- a/cloud/blockstore/libs/storage/disk_registry/disk_registry_state_ut_pending_cleanup.cpp +++ b/cloud/blockstore/libs/storage/disk_registry/disk_registry_state_ut_pending_cleanup.cpp @@ -209,6 +209,116 @@ Y_UNIT_TEST_SUITE(TDiskRegistryStatePendingCleanupTest) UNIT_ASSERT_VALUES_EQUAL("vol0", diskId); }); } + + Y_UNIT_TEST(ShouldCreateLocalDiskFromDirtyDevicesAndWaitForCleanup) + { + TTestExecutor executor; + executor.WriteTx([&](TDiskRegistryDatabase db) { db.InitSchema(); }); + + constexpr ui64 LocalDeviceSize = 99999997952; // ~ 93.13 GiB + + auto makeLocalDevice = [](const auto* name, const auto* uuid) + { + return Device(name, uuid) | + WithPool("local-ssd", NProto::DEVICE_POOL_KIND_LOCAL) | + WithTotalSize(LocalDeviceSize); + }; + + const TVector agents{ + AgentConfig( + 1, + { + makeLocalDevice("NVMELOCAL01", "uuid-1"), + makeLocalDevice("NVMELOCAL02", "uuid-2"), + makeLocalDevice("NVMELOCAL03", "uuid-3"), + }), + }; + + TDiskRegistryState state = + TDiskRegistryStateBuilder() + .WithConfig( + [&] + { + auto config = MakeConfig(0, agents); + + auto* pool = config.AddDevicePoolConfigs(); + pool->SetName("local-ssd"); + pool->SetKind(NProto::DEVICE_POOL_KIND_LOCAL); + pool->SetAllocationUnit(LocalDeviceSize); + + return config; + }()) + .WithAgents(agents) + .WithDirtyDevices( + {TDirtyDevice{"uuid-1", {}}, + TDirtyDevice{"uuid-3", {}},}) + .Build(); + + auto allocate = [&](auto db, ui32 deviceCount) + { + TDiskRegistryState::TAllocateDiskResult result; + + auto error = state.AllocateDisk( + TInstant::Zero(), + db, + TDiskRegistryState::TAllocateDiskParams{ + .DiskId = "local0", + .BlockSize = DefaultLogicalBlockSize, + .BlocksCount = + deviceCount * LocalDeviceSize / DefaultLogicalBlockSize, + .MediaKind = NProto::STORAGE_MEDIA_SSD_LOCAL}, + &result); + + return std::make_pair(std::move(result), error); + }; + + // Register agents. + executor.WriteTx( + [&](TDiskRegistryDatabase db) { + UNIT_ASSERT_SUCCESS( + RegisterAgent(state, db, agents[0], Now())); + }); + + UNIT_ASSERT_VALUES_EQUAL(1, state.GetConfig().KnownAgentsSize()); + UNIT_ASSERT_VALUES_EQUAL(1, state.GetAgents().size()); + UNIT_ASSERT_VALUES_EQUAL(0, state.GetSuspendedDevices().size()); + UNIT_ASSERT_VALUES_EQUAL(2, state.GetDirtyDevices().size()); + UNIT_ASSERT_VALUES_EQUAL(0, state.GetBrokenDevices().size()); + + // Create a disk creates pending allocation with the disk + executor.WriteTx( + [&](TDiskRegistryDatabase db) + { + auto [result, error] = allocate(db, 3U); + UNIT_ASSERT_SUCCESS(error); + UNIT_ASSERT_VALUES_EQUAL(3U, result.Devices.size()); + UNIT_ASSERT_VALUES_EQUAL(2U, result.DirtyDevices.size()); + UNIT_ASSERT_VALUES_EQUAL( + "NVMELOCAL02", + result.Devices[0].GetDeviceName()); + UNIT_ASSERT_VALUES_EQUAL( + "NVMELOCAL01", + result.DirtyDevices[0].GetDeviceName()); + UNIT_ASSERT_VALUES_EQUAL( + "NVMELOCAL03", + result.DirtyDevices[1].GetDeviceName()); + }); + + // Marking devices as clean removes the disk from PendingCleanup. + executor.WriteTx( + [&](TDiskRegistryDatabase db) + { + auto [allocatingDisks, deallocatingDisks] = state.MarkDevicesAsClean(Now(), db, {"uuid-1"}); + TVector empty; + UNIT_ASSERT_VALUES_EQUAL(empty, allocatingDisks); + UNIT_ASSERT_VALUES_EQUAL(empty, deallocatingDisks); + + std::tie(allocatingDisks, deallocatingDisks) = state.MarkDevicesAsClean(Now(), db, {"uuid-3"}); + TVector expectedAllocatedDisks {"local0",}; + UNIT_ASSERT_VALUES_EQUAL(empty, deallocatingDisks); + UNIT_ASSERT_VALUES_EQUAL(expectedAllocatedDisks, allocatingDisks); + }); + } } } // namespace NCloud::NBlockStore::NStorage