Skip to content

Commit d44df6c

Browse files
committed
Add UT
1 parent 29f5fc5 commit d44df6c

File tree

5 files changed

+265
-8
lines changed

5 files changed

+265
-8
lines changed

ydb/core/blobstorage/pdisk/mock/pdisk_mock.cpp

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <ydb/core/util/stlog.h>
44
#include <ydb/core/util/interval_set.h>
55

6+
#include <ydb/core/blobstorage/pdisk/blobstorage_pdisk_quota_record.h>
67
#include <ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_space_color.h>
78

89
namespace NKikimr {
@@ -50,7 +51,12 @@ struct TPDiskMockState::TImpl {
5051
NPDisk::EDeviceType DeviceType;
5152
std::optional<TRcBuf> Metadata;
5253

53-
TImpl(ui32 nodeId, ui32 pdiskId, ui64 pdiskGuid, ui64 size, ui32 chunkSize, bool isDiskReadOnly, NPDisk::EDeviceType deviceType)
54+
ESpaceColorPolicy SpaceColorPolicy;
55+
std::shared_ptr<NPDisk::TQuotaRecord> ChunkSharedQuota;
56+
double Occupancy = 0;
57+
58+
TImpl(ui32 nodeId, ui32 pdiskId, ui64 pdiskGuid, ui64 size, ui32 chunkSize, bool isDiskReadOnly, NPDisk::EDeviceType deviceType,
59+
ESpaceColorPolicy spaceColorPolicy)
5460
: NodeId(nodeId)
5561
, PDiskId(pdiskId)
5662
, PDiskGuid(pdiskGuid)
@@ -62,7 +68,20 @@ struct TPDiskMockState::TImpl {
6268
, NextFreeChunk(1)
6369
, StatusFlags(NPDisk::TStatusFlags{})
6470
, DeviceType(deviceType)
65-
{}
71+
, SpaceColorPolicy(spaceColorPolicy)
72+
{
73+
switch (SpaceColorPolicy) {
74+
case ESpaceColorPolicy::SharedQuota: {
75+
ChunkSharedQuota = std::make_shared<NPDisk::TQuotaRecord>();
76+
// 13% for CYAN is default value in prod
77+
ChunkSharedQuota->ForceHardLimit(TotalChunks, NPDisk::TColorLimits::MakeChunkLimits(130));
78+
break;
79+
}
80+
case ESpaceColorPolicy::None:
81+
default:
82+
break;
83+
}
84+
}
6685

6786
TImpl(const TImpl&) = default;
6887

@@ -76,6 +95,25 @@ struct TPDiskMockState::TImpl {
7695
}
7796
}
7897

98+
void UpdateStatusFlags(i64 chunksDelta) {
99+
switch (SpaceColorPolicy) {
100+
case ESpaceColorPolicy::SharedQuota: {
101+
NKikimrBlobStorage::TPDiskSpaceColor::E newColor =
102+
ChunkSharedQuota->EstimateSpaceColor(chunksDelta, &Occupancy);
103+
if (chunksDelta < 0) {
104+
ChunkSharedQuota->Release(-chunksDelta);
105+
} else if (chunksDelta > 0) {
106+
ChunkSharedQuota->ForceAllocate(chunksDelta);
107+
}
108+
SetStatusFlags(SpaceColorToStatusFlag(newColor));
109+
break;
110+
}
111+
case ESpaceColorPolicy::None:
112+
default:
113+
break;
114+
}
115+
}
116+
79117
ui32 AllocateChunk(TOwner& to) {
80118
ui32 chunkIdx = TotalChunks;
81119

@@ -89,6 +127,8 @@ struct TPDiskMockState::TImpl {
89127
}
90128

91129
Y_ABORT_UNLESS(chunkIdx != TotalChunks);
130+
131+
UpdateStatusFlags(1);
92132
return chunkIdx;
93133
}
94134

@@ -172,6 +212,8 @@ struct TPDiskMockState::TImpl {
172212
for (const TChunkIdx chunkIdx : owner.ReservedChunks) {
173213
owner.ChunkData.erase(chunkIdx);
174214
}
215+
216+
UpdateStatusFlags(-(i64)owner.ReservedChunks.size());
175217
FreeChunks.merge(owner.ReservedChunks);
176218
AdjustFreeChunks();
177219
}
@@ -189,6 +231,8 @@ struct TPDiskMockState::TImpl {
189231
owner.ChunkData.erase(chunkIdx);
190232
const bool inserted = FreeChunks.insert(chunkIdx).second;
191233
Y_ABORT_UNLESS(inserted);
234+
235+
UpdateStatusFlags(-1);
192236
AdjustFreeChunks();
193237
}
194238

@@ -286,8 +330,9 @@ struct TPDiskMockState::TImpl {
286330
};
287331

288332
TPDiskMockState::TPDiskMockState(ui32 nodeId, ui32 pdiskId, ui64 pdiskGuid, ui64 size, ui32 chunkSize, bool isDiskReadOnly,
289-
NPDisk::EDeviceType deviceType)
290-
: TPDiskMockState(std::make_unique<TImpl>(nodeId, pdiskId, pdiskGuid, size, chunkSize, isDiskReadOnly, deviceType))
333+
NPDisk::EDeviceType deviceType, ESpaceColorPolicy spaceColorPolicy)
334+
: TPDiskMockState(std::make_unique<TImpl>(nodeId, pdiskId, pdiskGuid, size, chunkSize, isDiskReadOnly, deviceType,
335+
spaceColorPolicy))
291336
{}
292337

293338
TPDiskMockState::TPDiskMockState(std::unique_ptr<TImpl>&& impl)
@@ -475,6 +520,8 @@ class TPDiskMockActor : public TActorBootstrapped<TPDiskMockActor> {
475520
break;
476521
} else {
477522
owner.Slain = true;
523+
Impl.UpdateStatusFlags(-(i64)owner.ReservedChunks.size());
524+
Impl.UpdateStatusFlags(-(i64)owner.CommittedChunks.size());
478525
Impl.FreeChunks.merge(owner.ReservedChunks);
479526
Impl.FreeChunks.merge(owner.CommittedChunks);
480527
Impl.AdjustFreeChunks();
@@ -676,6 +723,7 @@ class TPDiskMockActor : public TActorBootstrapped<TPDiskMockActor> {
676723
for (ui32 i = 0; i < msg->SizeChunks; ++i) {
677724
res->ChunkIds.push_back(Impl.AllocateChunk(*owner));
678725
}
726+
res->StatusFlags = GetStatusFlags();
679727
PDISK_MOCK_LOG(DEBUG, PDM10, "sending TEvChunkReserveResult", (Msg, res->ToString()));
680728
}
681729
}
@@ -848,7 +896,7 @@ class TPDiskMockActor : public TActorBootstrapped<TPDiskMockActor> {
848896
auto res = std::make_unique<NPDisk::TEvCheckSpaceResult>(NKikimrProto::OK, GetStatusFlags(),
849897
Impl.GetNumFreeChunks(), Impl.TotalChunks, Impl.TotalChunks - Impl.GetNumFreeChunks(),
850898
Impl.Owners.size(), TString());
851-
res->Occupancy = (double)res->UsedChunks / res->TotalChunks;
899+
res->Occupancy = GetOccupancy();
852900
Impl.FindOwner(msg, res); // to ensure correct owner/round
853901
Send(ev->Sender, res.release());
854902
}
@@ -886,6 +934,12 @@ class TPDiskMockActor : public TActorBootstrapped<TPDiskMockActor> {
886934
return Impl.StatusFlags;
887935
}
888936

937+
double GetOccupancy() {
938+
return (Impl.Occupancy == 0)
939+
? ((double)(Impl.TotalChunks - Impl.GetNumFreeChunks()) / Impl.TotalChunks)
940+
: Impl.Occupancy;
941+
}
942+
889943
void ErrorHandle(NPDisk::TEvYardInit::TPtr &ev) {
890944
Send(ev->Sender, new NPDisk::TEvYardInitResult(NKikimrProto::CORRUPTED, State->GetStateErrorReason()));
891945
}

ydb/core/blobstorage/pdisk/mock/pdisk_mock.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,19 @@ namespace NKikimr {
1717
std::unique_ptr<TImpl> Impl;
1818
friend class TPDiskMockActor;
1919

20+
public:
21+
enum class ESpaceColorPolicy {
22+
None = 0,
23+
SharedQuota,
24+
};
25+
2026
public:
2127
using TPtr = TIntrusivePtr<TPDiskMockState>;
2228

2329
public:
2430
TPDiskMockState(ui32 nodeId, ui32 pdiskId, ui64 pdiskGuid, ui64 size, ui32 chunkSize = 128 << 20,
25-
bool isDiskReadOnly = false, NPDisk::EDeviceType deviceType = NPDisk::EDeviceType::DEVICE_TYPE_NVME);
31+
bool isDiskReadOnly = false, NPDisk::EDeviceType deviceType = NPDisk::EDeviceType::DEVICE_TYPE_NVME,
32+
ESpaceColorPolicy spaceColorPolicy = ESpaceColorPolicy::None);
2633
TPDiskMockState(std::unique_ptr<TImpl>&& impl);
2734
~TPDiskMockState();
2835

ydb/core/blobstorage/ut_blobstorage/lib/env.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ struct TEnvironmentSetup {
5656
const ui32 MaxNumOfSlowDisks = 2;
5757
const ui32 ReplMaxQuantumBytes = 0;
5858
const ui32 ReplMaxDonorNotReadyCount = 0;
59+
const ui64 PDiskSize = 10_TB;
60+
const bool TrackSharedQuotaInPDiskMock = false;
5961
};
6062

6163
const TSettings Settings;
@@ -73,8 +75,11 @@ struct TEnvironmentSetup {
7375
const auto key = std::make_pair(nodeId, pdiskId);
7476
TIntrusivePtr<TPDiskMockState>& state = Env.PDiskMockStates[key];
7577
if (!state) {
76-
state.Reset(new TPDiskMockState(nodeId, pdiskId, cfg->PDiskGuid, ui64(10) << 40, cfg->ChunkSize,
77-
cfg->ReadOnly, Env.Settings.DiskType));
78+
TPDiskMockState::ESpaceColorPolicy spaceColorPolicy = Env.Settings.TrackSharedQuotaInPDiskMock
79+
? TPDiskMockState::ESpaceColorPolicy::SharedQuota
80+
: TPDiskMockState::ESpaceColorPolicy::None;
81+
state.Reset(new TPDiskMockState(nodeId, pdiskId, cfg->PDiskGuid, Env.Settings.PDiskSize, cfg->ChunkSize,
82+
cfg->ReadOnly, Env.Settings.DiskType, spaceColorPolicy));
7883
}
7984
const TActorId& actorId = ctx.Register(CreatePDiskMockActor(state), TMailboxType::HTSwap, poolId);
8085
const TActorId& serviceId = MakeBlobStoragePDiskID(nodeId, pdiskId);

ydb/core/blobstorage/ut_blobstorage/replication.cpp

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
#include <ydb/core/blobstorage/ut_blobstorage/lib/env.h>
22
#include <ydb/core/blobstorage/ut_blobstorage/lib/common.h>
33
#include <ydb/core/blobstorage/vdisk/hulldb/base/hullbase_barrier.h>
4+
45
#include <util/system/info.h>
6+
#include <util/stream/null.h>
7+
8+
#include "ut_helpers.h"
59

610
#define SINGLE_THREAD 1
711

12+
#define Ctest Cnull
13+
814
enum class EState {
915
OK,
1016
FORMAT,
@@ -350,3 +356,118 @@ Y_UNIT_TEST_SUITE(Replication) {
350356
DoTestCase(TBlobStorageGroupType::ErasureMirror3dc, {E::OK, E::FORMAT, E::OK, E::OK, E::OFFLINE, E::OK, E::OK, E::OFFLINE, E::OK}, true);
351357
}
352358
}
359+
360+
struct TTestCtx : public TTestCtxBase {
361+
public:
362+
TTestCtx(TBlobStorageGroupType erasure, ui64 pdiskSize, ui32 groupsCount = 3)
363+
: TTestCtxBase(TEnvironmentSetup::TSettings{
364+
.NodeCount = erasure.BlobSubgroupSize(),
365+
.Erasure = erasure,
366+
.PDiskSize = pdiskSize,
367+
.TrackSharedQuotaInPDiskMock = true,
368+
})
369+
, PDiskSize(pdiskSize)
370+
, GroupsCount(groupsCount)
371+
{}
372+
373+
void Initialize() override {
374+
Env->CreateBoxAndPool(GroupsCount, GroupsCount);
375+
Env->Sim(TDuration::Minutes(1));
376+
377+
BaseConfig = Env->FetchBaseConfig();
378+
UNIT_ASSERT_VALUES_EQUAL(BaseConfig.GroupSize(), GroupsCount);
379+
for (const auto& group : BaseConfig.GetGroup()) {
380+
Groups.push_back(group.GetGroupId());
381+
}
382+
383+
AllocateEdgeActor();
384+
for (const ui32 groupId : Groups) {
385+
GetGroupStatus(groupId);
386+
}
387+
}
388+
389+
public:
390+
ui64 PDiskSize;
391+
ui32 GroupsCount;
392+
std::vector<ui32> Groups;
393+
};
394+
395+
Y_UNIT_TEST_SUITE(ReplicationSpace) {
396+
void TestSpace() {
397+
TBlobStorageGroupType erasure = TBlobStorageGroupType::ErasureMirror3dc;
398+
ui64 diskSize = 3_GB;
399+
TTestCtx ctx(erasure, diskSize);
400+
ctx.Initialize();
401+
402+
ui32 chosenNodeId = 0;
403+
ui32 chosenPDiskId = 0;
404+
405+
for (const auto& vslot : ctx.BaseConfig.GetVSlot()) {
406+
if (vslot.GetGroupId() == ctx.Groups[0]) {
407+
chosenNodeId = vslot.GetVSlotId().GetNodeId();
408+
chosenPDiskId = vslot.GetVSlotId().GetPDiskId();
409+
break;
410+
}
411+
}
412+
413+
UNIT_ASSERT(chosenNodeId != 0);
414+
415+
// disable self-heal
416+
ctx.Env->UpdateSettings(false, true, false);
417+
418+
ui64 perDiskDataSize = diskSize * 0.6;
419+
ui64 dataSize = perDiskDataSize * ctx.NodeCount / 3;
420+
421+
for (ui32 groupId : ctx.Groups) {
422+
ctx.WriteCompressedData(groupId, dataSize, 8_MB);
423+
Ctest << "DATA WRITTEN FOR GROUP " << groupId << Endl;
424+
}
425+
426+
Ctest << "REASSIGN DISK" << Endl;
427+
428+
// find vdisk from another node and move it to the chosen
429+
{
430+
NKikimrBlobStorage::TConfigRequest request;
431+
ui32 groupToMove = 1;
432+
for (const auto& vslot : ctx.BaseConfig.GetVSlot()) {
433+
if (vslot.GetGroupId() != ctx.Groups[groupToMove]) {
434+
continue;
435+
}
436+
const ui32 nodeId = vslot.GetVSlotId().GetNodeId();
437+
if (nodeId != chosenNodeId) {
438+
NKikimrBlobStorage::TReassignGroupDisk* cmd = request.AddCommand()->MutableReassignGroupDisk();
439+
cmd->SetGroupId(vslot.GetGroupId());
440+
cmd->SetGroupGeneration(vslot.GetGroupGeneration());
441+
cmd->SetFailRealmIdx(vslot.GetFailRealmIdx());
442+
cmd->SetFailDomainIdx(vslot.GetFailDomainIdx());
443+
cmd->SetVDiskIdx(vslot.GetVDiskIdx());
444+
auto* target = cmd->MutableTargetPDiskId();
445+
target->SetNodeId(chosenNodeId);
446+
target->SetPDiskId(chosenPDiskId);
447+
if (++groupToMove == ctx.GroupsCount) {
448+
break;
449+
}
450+
}
451+
}
452+
auto res = ctx.Env->Invoke(request);
453+
UNIT_ASSERT_C(res.GetSuccess(), res.GetErrorDescription());
454+
UNIT_ASSERT_C(res.GetStatus(0).GetSuccess(), res.GetStatus(0).GetErrorDescription());
455+
}
456+
Ctest << "DISK REASSIGNED" << Endl;
457+
458+
ctx.Env->Sim(TDuration::Minutes(3600));
459+
460+
ctx.Env->Runtime->WrapInActorContext(ctx.Edge, [&] {
461+
SendToBSProxy(ctx.Edge, ctx.GroupId, new TEvBlobStorage::TEvStatus(TInstant::Max()));
462+
});
463+
auto res = ctx.Env->WaitForEdgeActorEvent<TEvBlobStorage::TEvStatusResult>(ctx.Edge,
464+
false, TInstant::Max());
465+
UNIT_ASSERT(res->Get()->Status == NKikimrProto::OK);
466+
Ctest << "FLAGS " << res->Get()->ToString() << Endl;
467+
UNIT_ASSERT(!res->Get()->StatusFlags.Check(NKikimrBlobStorage::StatusDiskSpaceRed));
468+
}
469+
470+
Y_UNIT_TEST(Mirror3dc) {
471+
TestSpace();
472+
}
473+
}

0 commit comments

Comments
 (0)