Skip to content

Commit a3e836e

Browse files
authored
Don't allow replication to overconsume space on PDisk (#17418) (#18296)
2 parents 7a9a4c6 + 79a3c25 commit a3e836e

File tree

11 files changed

+557
-13
lines changed

11 files changed

+557
-13
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,28 @@ struct TPDiskMockState::TImpl {
7695
}
7796
}
7897

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

@@ -172,6 +213,7 @@ struct TPDiskMockState::TImpl {
172213
for (const TChunkIdx chunkIdx : owner.ReservedChunks) {
173214
owner.ChunkData.erase(chunkIdx);
174215
}
216+
175217
FreeChunks.merge(owner.ReservedChunks);
176218
AdjustFreeChunks();
177219
}
@@ -286,8 +328,9 @@ struct TPDiskMockState::TImpl {
286328
};
287329

288330
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))
331+
NPDisk::EDeviceType deviceType, ESpaceColorPolicy spaceColorPolicy)
332+
: TPDiskMockState(std::make_unique<TImpl>(nodeId, pdiskId, pdiskGuid, size, chunkSize, isDiskReadOnly, deviceType,
333+
spaceColorPolicy))
291334
{}
292335

293336
TPDiskMockState::TPDiskMockState(std::unique_ptr<TImpl>&& impl)
@@ -670,12 +713,14 @@ class TPDiskMockActor : public TActorBootstrapped<TPDiskMockActor> {
670713
if (Impl.GetNumFreeChunks() < msg->SizeChunks) {
671714
PDISK_MOCK_LOG(NOTICE, PDM09, "received TEvChunkReserve", (Msg, msg->ToString()), (Error, "no free chunks"));
672715
res->Status = NKikimrProto::OUT_OF_SPACE;
716+
res->StatusFlags = GetStatusFlags() | ui32(NKikimrBlobStorage::StatusNotEnoughDiskSpaceForOperation);
673717
res->ErrorReason = "no free chunks";
674718
} else {
675719
PDISK_MOCK_LOG(DEBUG, PDM07, "received TEvChunkReserve", (Msg, msg->ToString()), (VDiskId, owner->VDiskId));
676720
for (ui32 i = 0; i < msg->SizeChunks; ++i) {
677721
res->ChunkIds.push_back(Impl.AllocateChunk(*owner));
678722
}
723+
res->StatusFlags = GetStatusFlags();
679724
PDISK_MOCK_LOG(DEBUG, PDM10, "sending TEvChunkReserveResult", (Msg, res->ToString()));
680725
}
681726
}
@@ -742,9 +787,11 @@ class TPDiskMockActor : public TActorBootstrapped<TPDiskMockActor> {
742787
if (!msg->ChunkIdx) { // allocate chunk
743788
if (!Impl.GetNumFreeChunks()) {
744789
res->Status = NKikimrProto::OUT_OF_SPACE;
790+
res->StatusFlags = GetStatusFlags() | ui32(NKikimrBlobStorage::StatusNotEnoughDiskSpaceForOperation);
745791
res->ErrorReason = "no free chunks";
746792
} else {
747793
msg->ChunkIdx = res->ChunkIdx = Impl.AllocateChunk(*owner);
794+
res->StatusFlags = GetStatusFlags();
748795
}
749796
}
750797
if (msg->ChunkIdx) {
@@ -848,7 +895,7 @@ class TPDiskMockActor : public TActorBootstrapped<TPDiskMockActor> {
848895
auto res = std::make_unique<NPDisk::TEvCheckSpaceResult>(NKikimrProto::OK, GetStatusFlags(),
849896
Impl.GetNumFreeChunks(), Impl.TotalChunks, Impl.TotalChunks - Impl.GetNumFreeChunks(),
850897
Impl.Owners.size(), TString());
851-
res->Occupancy = (double)res->UsedChunks / res->TotalChunks;
898+
res->Occupancy = GetOccupancy();
852899
Impl.FindOwner(msg, res); // to ensure correct owner/round
853900
Send(ev->Sender, res.release());
854901
}
@@ -883,9 +930,16 @@ class TPDiskMockActor : public TActorBootstrapped<TPDiskMockActor> {
883930
}
884931

885932
NPDisk::TStatusFlags GetStatusFlags() {
933+
Impl.UpdateStatusFlags();
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: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ struct TEnvironmentSetup {
5454
const float VDiskPredictedDelayMultiplier = 1;
5555
const bool UseActorSystemTimeInBSQueue = true;
5656
const ui32 MaxNumOfSlowDisks = 2;
57+
const ui64 PDiskSize = 10_TB;
58+
const ui64 PDiskChunkSize = 0;
59+
const bool TrackSharedQuotaInPDiskMock = false;
5760
};
5861

5962
const TSettings Settings;
@@ -71,8 +74,12 @@ struct TEnvironmentSetup {
7174
const auto key = std::make_pair(nodeId, pdiskId);
7275
TIntrusivePtr<TPDiskMockState>& state = Env.PDiskMockStates[key];
7376
if (!state) {
74-
state.Reset(new TPDiskMockState(nodeId, pdiskId, cfg->PDiskGuid, ui64(10) << 40, cfg->ChunkSize,
75-
cfg->ReadOnly, Env.Settings.DiskType));
77+
ui64 chunkSize = Env.Settings.PDiskChunkSize ? Env.Settings.PDiskChunkSize : cfg->ChunkSize;
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, chunkSize,
82+
cfg->ReadOnly, Env.Settings.DiskType, spaceColorPolicy));
7683
}
7784
const TActorId& actorId = ctx.Register(CreatePDiskMockActor(state), TMailboxType::HTSwap, poolId);
7885
const TActorId& serviceId = MakeBlobStoragePDiskID(nodeId, pdiskId);

0 commit comments

Comments
 (0)