aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Rutkovsky <alexvru@ydb.tech>2024-11-25 21:25:12 +0300
committerGitHub <noreply@github.com>2024-11-25 21:25:12 +0300
commita328b3002af3e74977283814bdeeb064c3b83645 (patch)
tree1315195d228c1bbbe82a56b2eaa1513764a317c9
parentec75229918d0b7357a38e7aa1e92556429ea58a7 (diff)
downloadydb-a328b3002af3e74977283814bdeeb064c3b83645.tar.gz
Revert "Support arbitrary chain set in huge blob keeper heap" (#11961)
-rw-r--r--ydb/core/blobstorage/ut_vdisk/lib/test_huge.cpp3
-rw-r--r--ydb/core/blobstorage/vdisk/common/vdisk_config.cpp2
-rw-r--r--ydb/core/blobstorage/vdisk/common/vdisk_config.h1
-rw-r--r--ydb/core/blobstorage/vdisk/common/vdisk_hugeblobctx.cpp20
-rw-r--r--ydb/core/blobstorage/vdisk/common/vdisk_hugeblobctx.h10
-rw-r--r--ydb/core/blobstorage/vdisk/huge/blobstorage_hullhuge_ut.cpp5
-rw-r--r--ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugeheap.cpp601
-rw-r--r--ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugeheap.h139
-rw-r--r--ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugeheap_ctx_ut.cpp1
-rw-r--r--ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugeheap_ut.cpp110
-rw-r--r--ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugerecovery.cpp12
-rw-r--r--ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugerecovery.h3
-rw-r--r--ydb/core/blobstorage/vdisk/localrecovery/localrecovery_public.cpp12
13 files changed, 529 insertions, 390 deletions
diff --git a/ydb/core/blobstorage/ut_vdisk/lib/test_huge.cpp b/ydb/core/blobstorage/ut_vdisk/lib/test_huge.cpp
index 5fabd73846..ad9b486e67 100644
--- a/ydb/core/blobstorage/ut_vdisk/lib/test_huge.cpp
+++ b/ydb/core/blobstorage/ut_vdisk/lib/test_huge.cpp
@@ -137,6 +137,7 @@ class THugeModuleRecoveryActor : public TActorBootstrapped<THugeModuleRecoveryAc
bool InitHugeBlobKeeper(const TActorContext &ctx, const TStartingPoints &startingPoints) {
Y_UNUSED(ctx);
+ const ui32 oldMinHugeBlobInBytes = 64 << 10;
const ui32 milestoneHugeBlobInBytes = 64 << 10;
const ui32 maxBlobInBytes = 128 << 10;
auto logFunc = [] (const TString) { /* empty */ };
@@ -149,6 +150,7 @@ class THugeModuleRecoveryActor : public TActorBootstrapped<THugeModuleRecoveryAc
HmCtx->PDiskCtx->Dsk->ChunkSize,
HmCtx->PDiskCtx->Dsk->AppendBlockSize,
HmCtx->PDiskCtx->Dsk->AppendBlockSize,
+ oldMinHugeBlobInBytes,
milestoneHugeBlobInBytes,
maxBlobInBytes,
HmCtx->Config->HugeBlobOverhead,
@@ -167,6 +169,7 @@ class THugeModuleRecoveryActor : public TActorBootstrapped<THugeModuleRecoveryAc
HmCtx->PDiskCtx->Dsk->ChunkSize,
HmCtx->PDiskCtx->Dsk->AppendBlockSize,
HmCtx->PDiskCtx->Dsk->AppendBlockSize,
+ oldMinHugeBlobInBytes,
milestoneHugeBlobInBytes,
maxBlobInBytes,
HmCtx->Config->HugeBlobOverhead,
diff --git a/ydb/core/blobstorage/vdisk/common/vdisk_config.cpp b/ydb/core/blobstorage/vdisk/common/vdisk_config.cpp
index edfcd7c452..540edfaac5 100644
--- a/ydb/core/blobstorage/vdisk/common/vdisk_config.cpp
+++ b/ydb/core/blobstorage/vdisk/common/vdisk_config.cpp
@@ -136,7 +136,9 @@ namespace NKikimr {
MinHugeBlobInBytes = 512u << 10u;
break;
}
+ OldMinHugeBlobInBytes = MinHugeBlobInBytes; // preserved to migrate entry point state correctly
MilestoneHugeBlobInBytes = 512u << 10u; // for compatibility reasons it must be 512KB
+
}
void TVDiskConfig::Merge(const NKikimrBlobStorage::TVDiskConfig &update) {
diff --git a/ydb/core/blobstorage/vdisk/common/vdisk_config.h b/ydb/core/blobstorage/vdisk/common/vdisk_config.h
index 70bfdd1ee1..dd80ff86ce 100644
--- a/ydb/core/blobstorage/vdisk/common/vdisk_config.h
+++ b/ydb/core/blobstorage/vdisk/common/vdisk_config.h
@@ -120,6 +120,7 @@ namespace NKikimr {
ui32 HullSstSizeInChunksLevel;
ui32 HugeBlobsFreeChunkReservation;
ui32 MinHugeBlobInBytes;
+ ui32 OldMinHugeBlobInBytes;
ui32 MilestoneHugeBlobInBytes;
ui32 HugeBlobOverhead;
ui32 HullCompLevel0MaxSstsAtOnce;
diff --git a/ydb/core/blobstorage/vdisk/common/vdisk_hugeblobctx.cpp b/ydb/core/blobstorage/vdisk/common/vdisk_hugeblobctx.cpp
index d2f1ad450e..55b168cb33 100644
--- a/ydb/core/blobstorage/vdisk/common/vdisk_hugeblobctx.cpp
+++ b/ydb/core/blobstorage/vdisk/common/vdisk_hugeblobctx.cpp
@@ -3,23 +3,23 @@
namespace NKikimr {
- THugeSlotsMap::THugeSlotsMap(ui32 appendBlockSize, ui32 minHugeBlobInBlocks, TAllSlotsInfo &&slotsInfo,
- TSearchTable &&searchTable)
+ THugeSlotsMap::THugeSlotsMap(ui32 appendBlockSize, TAllSlotsInfo &&slotsInfo, TSearchTable &&searchTable)
: AppendBlockSize(appendBlockSize)
- , MinHugeBlobInBlocks(minHugeBlobInBlocks)
, AllSlotsInfo(std::move(slotsInfo))
, SearchTable(std::move(searchTable))
{}
const THugeSlotsMap::TSlotInfo *THugeSlotsMap::GetSlotInfo(ui32 size) const {
- const ui32 sizeInBlocks = (size + AppendBlockSize - 1) / AppendBlockSize;
- Y_ABORT_UNLESS(MinHugeBlobInBlocks <= sizeInBlocks);
- const ui64 idx = SearchTable.at(sizeInBlocks - MinHugeBlobInBlocks);
+ ui32 sizeInBlocks = size / AppendBlockSize;
+ sizeInBlocks += !(sizeInBlocks * AppendBlockSize == size);
+ const ui64 idx = SearchTable.at(sizeInBlocks);
return &AllSlotsInfo.at(idx);
}
ui32 THugeSlotsMap::AlignByBlockSize(ui32 size) const {
- return Max(MinHugeBlobInBlocks * AppendBlockSize, size - size % AppendBlockSize);
+ ui32 sizeInBlocks = size / AppendBlockSize;
+ Y_ABORT_UNLESS(sizeInBlocks, "Blob size to align is smaller than a single block. BlobSize# %" PRIu32, size);
+ return sizeInBlocks * AppendBlockSize;
}
void THugeSlotsMap::Output(IOutputStream &str) const {
@@ -31,7 +31,11 @@ namespace NKikimr {
str << "]}\n";
str << "{SearchTable# [";
for (const auto &idx : SearchTable) {
- AllSlotsInfo.at(idx).Output(str);
+ if (idx != NoOpIdx) {
+ AllSlotsInfo.at(idx).Output(str);
+ } else {
+ str << "null";
+ }
str << "\n";
}
str << "]}";
diff --git a/ydb/core/blobstorage/vdisk/common/vdisk_hugeblobctx.h b/ydb/core/blobstorage/vdisk/common/vdisk_hugeblobctx.h
index 1d7e61f04e..b6d4f8527b 100644
--- a/ydb/core/blobstorage/vdisk/common/vdisk_hugeblobctx.h
+++ b/ydb/core/blobstorage/vdisk/common/vdisk_hugeblobctx.h
@@ -38,13 +38,16 @@ namespace NKikimr {
};
// All slot types
- using TAllSlotsInfo = std::vector<TSlotInfo>;
+ using TAllSlotsInfo = TVector<TSlotInfo>;
// Type to address TAllSlotsInfo
using TIndex = ui16;
// Size in AppendBlockSize -> index in TAllSlotsInfo
- using TSearchTable = std::vector<TIndex>;
+ using TSearchTable = TVector<TIndex>;
+ // Idx that indicates there is no record for it in TAllSlotsInfo
+ static constexpr TIndex NoOpIdx = Max<TIndex>();
- THugeSlotsMap(ui32 appendBlockSize, ui32 minHugeBlobInBlocks, TAllSlotsInfo &&slotsInfo, TSearchTable &&searchTable);
+
+ THugeSlotsMap(ui32 appendBlockSize, TAllSlotsInfo &&slotsInfo, TSearchTable &&searchTable);
const TSlotInfo *GetSlotInfo(ui32 size) const;
ui32 AlignByBlockSize(ui32 size) const;
void Output(IOutputStream &str) const;
@@ -52,7 +55,6 @@ namespace NKikimr {
private:
const ui32 AppendBlockSize;
- const ui32 MinHugeBlobInBlocks;
TAllSlotsInfo AllSlotsInfo;
TSearchTable SearchTable;
};
diff --git a/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhuge_ut.cpp b/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhuge_ut.cpp
index 699f5ca6ef..2aa98ea92c 100644
--- a/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhuge_ut.cpp
+++ b/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhuge_ut.cpp
@@ -17,6 +17,7 @@ namespace NKikimr {
Y_UNIT_TEST(SerializeParse) {
ui32 chunkSize = 134274560u;
ui32 appendBlockSize = 56896u;
+ ui32 minHugeBlobInBytes = 512u << 10u;
ui32 milestoneHugeBlobInBytes = 512u << 10u;
ui32 maxBlobInBytes = 10u << 20u;
ui32 overhead = 8;
@@ -28,8 +29,8 @@ namespace NKikimr {
auto vctx = MakeIntrusive<TVDiskContext>(TActorId(), info->PickTopology(), counters, TVDiskID(0, 1, 0, 0, 0),
nullptr, NPDisk::DEVICE_TYPE_UNKNOWN);
std::unique_ptr<THullHugeKeeperPersState> state(
- new THullHugeKeeperPersState(vctx, chunkSize, appendBlockSize,
- appendBlockSize, milestoneHugeBlobInBytes, maxBlobInBytes,
+ new THullHugeKeeperPersState(vctx, chunkSize, appendBlockSize, appendBlockSize,
+ minHugeBlobInBytes, milestoneHugeBlobInBytes, maxBlobInBytes,
overhead, freeChunksReservation, logf));
state->LogPos = THullHugeRecoveryLogPos(0, 0, 100500, 50000, 70000, 56789, 39482);
diff --git a/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugeheap.cpp b/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugeheap.cpp
index d7973d1d2c..be27874e3f 100644
--- a/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugeheap.cpp
+++ b/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugeheap.cpp
@@ -2,8 +2,6 @@
#include <library/cpp/monlib/service/pages/templates.h>
-#include <ranges>
-
namespace NKikimr {
namespace NHuge {
@@ -26,7 +24,7 @@ namespace NKikimr {
}
void TChainLayoutBuilder::Output(IOutputStream &str, ui32 appendBlockSize) const {
- str << "CHAIN TABLE (MilestoneId=" << MilestoneId << " rows=" << Layout.size() << "):\n";
+ str << "CHAIN TABLE (MilesoneId=" << MilesoneId << " rows=" << Layout.size() << "):\n";
for (const auto &x : Layout) {
str << "Blocks# (" << x.Left << ", " << x.Right << "]";
if (appendBlockSize) {
@@ -66,7 +64,7 @@ namespace NKikimr {
}
void TChainLayoutBuilder::BuildUpward(ui32 left, ui32 right, ui32 overhead) {
- MilestoneId = Layout.size();
+ MilesoneId = Layout.size();
ui32 valBlocks = left;
ui32 shiftBlocks = 0;
@@ -85,21 +83,6 @@ namespace NKikimr {
////////////////////////////////////////////////////////////////////////////
// TChain
////////////////////////////////////////////////////////////////////////////
- THugeSlot TChain::Convert(const NPrivate::TChunkSlot& id) const {
- return THugeSlot(id.GetChunkId(), id.GetSlotId() * SlotSize, SlotSize);
- }
-
- NPrivate::TChunkSlot TChain::Convert(const TDiskPart& addr) const {
- ui32 slotId = addr.Offset / SlotSize;
- Y_VERIFY_S(slotId * SlotSize == addr.Offset, VDiskLogPrefix << "slotId# " << slotId
- << " addr# " << addr.ToString() << " State# " << ToString());
- return NPrivate::TChunkSlot(addr.ChunkIdx, slotId);
- }
-
- NPrivate::TChunkSlot TChain::Convert(const THugeSlot& slot) const {
- return Convert(slot.GetDiskPart());
- }
-
TMask TChain::BuildConstMask(const TString &prefix, ui32 slotsInChunk) {
Y_VERIFY_S(1 < slotsInChunk && slotsInChunk <= MaxNumberOfSlots,
prefix << "It's not a good idea to have so many slots in chunk;"
@@ -267,103 +250,73 @@ namespace NKikimr {
void TChain::Save(IOutputStream *s) const {
::Save(s, SlotsInChunk);
::Save(s, AllocatedSlots);
- ::SaveSize(s, FreeSpace.size() + LockedChunks.size());
- ForEachFreeSpaceChunk(std::bind(&::Save<TFreeSpace::value_type>, s, std::placeholders::_1));
+ if (LockedChunks) {
+ TFreeSpace temp(FreeSpace);
+ temp.insert(LockedChunks.begin(), LockedChunks.end());
+ ::Save(s, temp);
+ } else {
+ ::Save(s, FreeSpace);
+ }
}
- TChain TChain::Load(IInputStream *s, TString vdiskLogPrefix, ui32 appendBlockSize, ui32 blocksInChunk) {
- ui32 slotsInChunk;
+ void TChain::Load(IInputStream *s) {
+ FreeSpace.clear();
+ ui32 slotsInChunk = 0;
::Load(s, slotsInChunk);
-
- // calculate optimal slot size for this number of slots per chunk; it may differ from builder's one,
- // this will be fixed in caller function
- const ui32 slotSizeInBlocks = blocksInChunk / slotsInChunk;
- Y_ABORT_UNLESS(slotSizeInBlocks);
- ui32 slotSize = slotSizeInBlocks * appendBlockSize;
-
- TChain res{
- std::move(vdiskLogPrefix),
- slotsInChunk,
- slotSize, // in bytes
- };
-
- ::Load(s, res.AllocatedSlots);
- ::Load(s, res.FreeSpace);
- for (const auto& [chunkId, mask] : res.FreeSpace) {
- res.FreeSlotsInFreeSpace += mask.Count();
+ Y_VERIFY_S(slotsInChunk == SlotsInChunk, VDiskLogPrefix
+ << "slotsInChunk# " << slotsInChunk << " SlotsInChunk# " << SlotsInChunk);
+ ::Load(s, AllocatedSlots);
+ ::Load(s, FreeSpace);
+ FreeSlotsInFreeSpace = 0;
+ for (const auto &[chunkId, mask] : FreeSpace) {
+ // all 1 in mask -- free slots
+ // 0 - slot is in use
+ FreeSlotsInFreeSpace += mask.Count();
}
-
- return res;
}
bool TChain::HaveBeenUsed() const {
- return AllocatedSlots; // chain is considered to be used if it contains any allocated slots
+ return AllocatedSlots != 0 || !FreeSpace.empty();
}
TString TChain::ToString() const {
TStringStream str;
-
- str << "{" << SlotSize << '/' << SlotsInChunk << " AllocatedSlots# " << AllocatedSlots << " Free#";
-
- bool any = false;
- ForEachFreeSpaceChunk([&](const auto& value) {
- const auto& [chunk, bitmap] = value;
- str << " {" << chunk;
- ui32 begin;
- ui32 prev = Max<ui32>();
- Y_FOR_EACH_BIT(i, bitmap) {
- if (prev == Max<ui32>()) {
- begin = i;
- } else if (i != prev + 1) {
- str << ' ' << begin;
- if (begin != prev) {
- str << '-' << prev;
- }
- begin = prev;
+ auto output = [&str] (const TFreeSpace &c) {
+ for (const auto &x : c) {
+ for (size_t i = 0; i < x.second.Size(); i++) {
+ if (x.second.Test(i))
+ str << " [" << x.first << " " << i << "]";
}
- prev = i;
}
- str << ' ' << begin;
- if (begin != prev) {
- str << '-' << prev;
- }
- str << '}';
-
- any = true;
- });
-
- if (!any) {
- str << " none";
- }
+ };
+ str << "{AllocatedSlots# " << AllocatedSlots << " [ChunkId FreeSlot]:";
+ output(FreeSpace);
+ output(LockedChunks);
str << "}";
return str.Str();
}
void TChain::RenderHtml(IOutputStream &str) const {
- HTML(str) {
- TABLER() {
- TABLED() {
- str << SlotSize << "/" << SlotsInChunk;
+ auto output = [&str] (const TFreeSpace &c) {
+ for (const auto &x : c) {
+ size_t freeSlots = 0;
+ for (size_t i = 0; i < x.second.Size(); i++) {
+ if (x.second.Test(i))
+ ++freeSlots;
}
- TABLED() {
- ForEachFreeSpaceChunk([&](const auto& value) {
- const auto& [chunk, bitmap] = value;
- str << " [" << chunk << " " << bitmap.Count() << "]";
- });
+ if (freeSlots) {
+ str << " [" << x.first << " " << freeSlots << "]";
}
}
- }
+ };
+
+ output(FreeSpace);
+ output(LockedChunks);
}
- void TChain::RenderHtmlForUsage(IOutputStream &str) const {
- HTML(str) {
- TABLER() {
- TABLED() { str << SlotSize; }
- TABLED() { str << SlotsInChunk; }
- TABLED() { str << AllocatedSlots; }
- }
- }
+ ui32 TChain::GetAllocatedSlots() const {
+ return AllocatedSlots;
}
void TChain::GetOwnedChunks(TSet<TChunkIdx>& chunks) const {
@@ -377,6 +330,87 @@ namespace NKikimr {
}
////////////////////////////////////////////////////////////////////////////
+ // TChainDelegator
+ ////////////////////////////////////////////////////////////////////////////
+ TChainDelegator::TChainDelegator(const TString &vdiskLogPrefix, ui32 valBlocks, ui32 shiftBlocks,
+ ui32 chunkSize, ui32 appendBlockSize)
+ : VDiskLogPrefix(vdiskLogPrefix)
+ , Blocks(valBlocks)
+ , ShiftInBlocks(shiftBlocks)
+ , SlotsInChunk(0)
+ , SlotSize(0)
+ {
+ ui32 slotSizeInBlocks = Blocks + ShiftInBlocks;
+ ui32 blocksInChunk = chunkSize / appendBlockSize;
+ Y_VERIFY_S(appendBlockSize * blocksInChunk == chunkSize, VDiskLogPrefix
+ << "Blocks# " << Blocks << " ShiftInBlocks# " << ShiftInBlocks
+ << " chunkSize# " << chunkSize << " appendBlockSize# " << appendBlockSize);
+
+ SlotsInChunk = blocksInChunk / slotSizeInBlocks;
+ SlotSize = slotSizeInBlocks * appendBlockSize;
+
+ ChainPtr = MakeIntrusive<TChain>(vdiskLogPrefix, SlotsInChunk);
+ }
+
+ THugeSlot TChainDelegator::Convert(const NPrivate::TChunkSlot &id) const {
+ return THugeSlot(id.GetChunkId(), id.GetSlotId() * SlotSize, SlotSize);
+ }
+
+ NPrivate::TChunkSlot TChainDelegator::Convert(const TDiskPart &addr) const {
+ ui32 slotId = addr.Offset / SlotSize;
+ Y_VERIFY_S(slotId * SlotSize == addr.Offset, VDiskLogPrefix
+ << "slotId# " << slotId << " addr# " << addr.ToString() << " State# " << ToString());
+ return NPrivate::TChunkSlot(addr.ChunkIdx, slotId);
+ }
+
+ NPrivate::TChunkSlot TChainDelegator::Convert(const THugeSlot &slot) const {
+ return Convert(slot.GetDiskPart());
+ }
+
+ void TChainDelegator::Save(IOutputStream *s) const {
+ ::Save(s, *ChainPtr);
+ }
+
+ void TChainDelegator::Load(IInputStream *s) {
+ ::Load(s, *ChainPtr);
+ }
+
+ bool TChainDelegator::HaveBeenUsed() const {
+ return ChainPtr->HaveBeenUsed();
+ }
+
+ TString TChainDelegator::ToString() const {
+ TStringStream str;
+ str << "{[SlotSize, SlotsInChunk]: [" << SlotSize << ", " << SlotsInChunk << "] "
+ << ChainPtr->ToString() << "}";
+ return str.Str();
+ }
+
+ void TChainDelegator::GetOwnedChunks(TSet<TChunkIdx>& chunks) const {
+ ChainPtr->GetOwnedChunks(chunks);
+ }
+
+ void TChainDelegator::RenderHtml(IOutputStream &str) const {
+ HTML(str) {
+ TABLER() {
+ TABLED() {str << SlotSize << " / " << SlotsInChunk;}
+ TABLED() {ChainPtr->RenderHtml(str);}
+ }
+ }
+ }
+
+ void TChainDelegator::RenderHtmlForUsage(IOutputStream &str) const {
+ HTML(str) {
+ TABLER() {
+ TABLED() {str << SlotSize;}
+ TABLED() {str << SlotsInChunk;}
+ TABLED() {str << ChainPtr->GetAllocatedSlots();}
+ }
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////
// TAllChains
////////////////////////////////////////////////////////////////////////////
TAllChains::TAllChains(
@@ -384,6 +418,7 @@ namespace NKikimr {
ui32 chunkSize,
ui32 appendBlockSize,
ui32 minHugeBlobInBytes,
+ ui32 oldMinHugeBlobSizeInBytes,
ui32 milestoneBlobInBytes,
ui32 maxBlobInBytes,
ui32 overhead)
@@ -391,136 +426,143 @@ namespace NKikimr {
, ChunkSize(chunkSize)
, AppendBlockSize(appendBlockSize)
, MinHugeBlobInBytes(minHugeBlobInBytes)
+ , OldMinHugeBlobSizeInBytes(oldMinHugeBlobSizeInBytes)
, MilestoneBlobInBytes(milestoneBlobInBytes)
+ , MaxBlobInBytes(maxBlobInBytes)
, Overhead(overhead)
- , MinHugeBlobInBlocks(MinHugeBlobInBytes / AppendBlockSize)
- , MaxHugeBlobInBlocks(SizeToBlocks(maxBlobInBytes))
{
- Y_VERIFY_S(MinHugeBlobInBytes &&
+ Y_VERIFY_S(MinHugeBlobInBytes != 0 &&
+ MinHugeBlobInBytes >= AppendBlockSize &&
MinHugeBlobInBytes <= MilestoneBlobInBytes &&
- MilestoneBlobInBytes < maxBlobInBytes, "INVALID CONFIGURATION! (SETTINGS ARE:"
- << " MaxBlobInBytes# " << maxBlobInBytes << " MinHugeBlobInBytes# " << MinHugeBlobInBytes
+ MinHugeBlobInBytes <= OldMinHugeBlobSizeInBytes &&
+ MilestoneBlobInBytes < MaxBlobInBytes, "INVALID CONFIGURATION! (SETTINGS ARE:"
+ << " MaxBlobInBytes# " << MaxBlobInBytes << " MinHugeBlobInBytes# " << MinHugeBlobInBytes << " OldMinHugeBlobSizeInBytes# " << OldMinHugeBlobSizeInBytes
<< " MilestoneBlobInBytes# " << MilestoneBlobInBytes << " ChunkSize# " << ChunkSize
<< " AppendBlockSize# " << AppendBlockSize << ")");
-
- BuildChains();
+ BuildLayout();
}
- TChain *TAllChains::GetChain(ui32 size) {
- if (size < MinHugeBlobInBytes || MaxHugeBlobInBlocks * AppendBlockSize < size) {
- return nullptr;
- }
- const size_t index = SizeToBlocks(size) - MinHugeBlobInBlocks;
- Y_DEBUG_ABORT_UNLESS(index < SearchTable.size());
- const size_t chainIndex = SearchTable[index];
- Y_DEBUG_ABORT_UNLESS(chainIndex < Chains.size());
- return &Chains[chainIndex];
+ TChainDelegator *TAllChains::GetChain(ui32 size) {
+ return SearchTable.at(SizeToBlocks(size));
}
- const TChain *TAllChains::GetChain(ui32 size) const {
- if (size < MinHugeBlobInBytes || MaxHugeBlobInBlocks * AppendBlockSize < size) {
- return nullptr;
- }
- Y_ABORT_UNLESS(MinHugeBlobInBytes <= size);
- const size_t index = SizeToBlocks(size) - MinHugeBlobInBlocks;
- Y_DEBUG_ABORT_UNLESS(index < SearchTable.size());
- const size_t chainIndex = SearchTable[index];
- Y_DEBUG_ABORT_UNLESS(chainIndex < Chains.size());
- return &Chains[chainIndex];
+ const TChainDelegator *TAllChains::GetChain(ui32 size) const {
+ return SearchTable.at(SizeToBlocks(size));
}
THeapStat TAllChains::GetStat() const {
THeapStat stat;
- for (const auto& chain : Chains) {
- stat += chain.GetStat();
+ for (const auto &x : ChainDelegators) {
+ stat += x.ChainPtr->GetStat();
}
return stat;
}
- void TAllChains::Save(IOutputStream *s) const {
- // check if we can write compatible entrypoint (with exactly the same set of chains)
- bool writeCompatible = true;
- ui32 numChains = 0;
- if (DeserializedChains.Empty()) { // if this was initially empty heap, write it fully
- writeCompatible = false;
- } else {
- for (size_t i = 0; i < Chains.size(); ++i) {
- if (DeserializedChains[i]) {
- ++numChains;
- } else if (Chains[i].HaveBeenUsed()) {
- writeCompatible = false;
- break;
- }
- }
+ void TAllChains::PrintOutChains(IOutputStream &str) const {
+ str << "CHAIN TABLE (rows=" << ChainDelegators.size() << "):\n";
+ for (const auto &x : ChainDelegators) {
+ str << "Blocks# (" << x.Blocks << ", " << (x.Blocks + x.ShiftInBlocks) << "] "
+ << "Bytes# (" << (x.Blocks * AppendBlockSize) << ", "
+ << ((x.Blocks + x.ShiftInBlocks) * AppendBlockSize) << "] "
+ << " SlotSize# " << x.SlotSize << " SlotsInChunk# " << x.SlotsInChunk << "\n";
}
+ }
- if (!writeCompatible) { // we can't, so we serialize all our chains anyway
- numChains = Chains.size();
+ void TAllChains::PrintOutSearchTable(IOutputStream &str) const {
+ str << "SEARCH TABLE:\n";
+ for (const auto &x : SearchTable) {
+ str << (&x - &SearchTable[0]) << " idx: ";
+ if (x) {
+ str << x - &ChainDelegators[0];
+ } else {
+ str << "null";
+ }
+ str << "\n";
}
- ::Save(s, numChains);
+ }
- // serialize selected chains
- for (size_t i = 0; i < Chains.size(); ++i) {
- if (!writeCompatible || DeserializedChains[i]) {
- ::Save(s, Chains[i]);
+ void TAllChains::Save(IOutputStream *s) const {
+ if (StartMode == EStartMode::Loaded) {
+ ui32 size = ChainDelegators.size();
+ ::Save(s, size);
+ for (auto& d : ChainDelegators) {
+ ::Save(s, d);
+ }
+ } else {
+ std::vector<const TChainDelegator*> delegators;
+ for (auto &x : ChainDelegators) {
+ if (!x.HaveBeenUsed() && x.SlotSize < FirstLoadedSlotSize) {
+ continue; // preserving backward compatibility until no allocations
+ }
+ delegators.emplace_back(&x);
+ }
+
+ ui32 size = delegators.size();
+ ::Save(s, size);
+ for (auto x : delegators) {
+ ::Save(s, *x);
}
}
}
void TAllChains::Load(IInputStream *s) {
- std::vector<TChain> newChains;
- newChains.reserve(Chains.size());
-
- Y_DEBUG_ABORT_UNLESS(ChunkSize % AppendBlockSize == 0);
- Y_DEBUG_ABORT_UNLESS(AppendBlockSize <= ChunkSize);
- const ui32 blocksInChunk = ChunkSize / AppendBlockSize;
-
- auto chainsIt = Chains.begin();
- const auto chainsEnd = Chains.end();
-
- ui32 prevSlotSize = 0;
- ui32 numChains;
- for (::Load(s, numChains); numChains; --numChains) {
- auto chain = TChain::Load(s, VDiskLogPrefix, AppendBlockSize, blocksInChunk);
-
- // merge new item with originating ones from TChainLayoutBuilder -- we may have not every one of them
- // serialized
- for (; chainsIt != chainsEnd && chain.SlotsInChunk < chainsIt->SlotsInChunk; ++chainsIt) {
- newChains.push_back(std::move(*chainsIt));
+ ui32 size = 0;
+ // load array size
+ ::Load(s, size);
+ if (size == ChainDelegators.size()) {
+ StartMode = EStartMode::Loaded;
+ // load map and current map are of the same size, just load it
+ for (auto &x : ChainDelegators) {
+ ::Load(s, x);
}
- if (chainsIt != chainsEnd && chainsIt->SlotsInChunk == chain.SlotsInChunk) {
- // reuse slot size from the builder's one to retain compatibility
- chain.SlotSize = chainsIt->SlotSize;
- ++chainsIt;
+ } else if (size < ChainDelegators.size()) {
+ // map size has been changed, run migration
+ StartMode = EStartMode::Migrated;
+ TAllChainDelegators chainDelegators = BuildChains(OldMinHugeBlobSizeInBytes);
+ Y_VERIFY_S(size > 0 && size == chainDelegators.size(), "size# " << size
+ << " chainDelegators.size()# " << chainDelegators.size());
+
+ // load into temporary delegators
+ for (auto &x : chainDelegators) {
+ ::Load(s, x);
}
- // assert SlotSize-s are coming in strictly increasing order
- Y_ABORT_UNLESS(std::exchange(prevSlotSize, chain.SlotSize) < chain.SlotSize);
-
- DeserializedChains.Set(newChains.size());
- newChains.push_back(std::move(chain));
+ // migrate
+ using TIt = TAllChainDelegators::iterator;
+ TIt loadedIt = chainDelegators.begin();
+ TIt loadedEnd = chainDelegators.end();
+ FirstLoadedSlotSize = loadedIt->SlotSize;
+ for (TIt it = ChainDelegators.begin(); it != ChainDelegators.end(); ++it) {
+ Y_ABORT_UNLESS(loadedIt != loadedEnd);
+ if (loadedIt->SlotSize == it->SlotSize) {
+ *it = std::move(*loadedIt);
+ ++loadedIt;
+ }
+ }
+ Y_ABORT_UNLESS(loadedIt == loadedEnd);
+ } else {
+ // entry point size rollback case
+ Y_ABORT_UNLESS(size > ChainDelegators.size());
+ ui32 curChainDelegatorsSize = ChainDelegators.size();
+ Y_FAIL_S("Impossible case; MinHugeBlobInBytes# " << MinHugeBlobInBytes
+ << " MilestoneBlobInBytes# " << MilestoneBlobInBytes
+ << " loadedSize# " << size
+ << " curChainDelegatorsSize# " << curChainDelegatorsSize);
}
-
- std::ranges::move(chainsIt, chainsEnd, std::back_inserter(newChains));
-
- Chains = std::move(newChains);
}
void TAllChains::GetOwnedChunks(TSet<TChunkIdx>& chunks) const {
- for (const TChain& chain : Chains) {
- chain.GetOwnedChunks(chunks);
+ for (const TChainDelegator& delegator : ChainDelegators) {
+ delegator.GetOwnedChunks(chunks);
}
}
TString TAllChains::ToString() const {
TStringStream str;
- str << "{ChunkSize# " << ChunkSize
- << " AppendBlockSize# " << AppendBlockSize
- << " MinHugeBlobInBytes# " << MinHugeBlobInBytes
- << " MinHugeBlobInBlocks# " << MinHugeBlobInBlocks
- << " MaxHugeBlobInBlocks# " << MaxHugeBlobInBlocks;
- for (const auto& chain : Chains) {
- str << " {CHAIN " << chain.ToString() << "}";
+ str << "{ChunkSize# " << ChunkSize << " AppendBlockSize# " << AppendBlockSize
+ << " MinHugeBlobInBytes# " << MinHugeBlobInBytes << " MaxBlobInBytes# " << MaxBlobInBytes;
+ for (const auto & x : ChainDelegators) {
+ str << " {CHAIN " << x.ToString() << "}";
}
str << "}";
return str.Str();
@@ -536,9 +578,8 @@ namespace NKikimr {
}
}
TABLEBODY() {
- for (const auto& chain : Chains) {
- chain.RenderHtml(str);
- }
+ for (const auto & x : ChainDelegators)
+ x.RenderHtml(str);
}
}
}
@@ -555,9 +596,8 @@ namespace NKikimr {
}
}
TABLEBODY() {
- for (const auto& chain : Chains) {
- chain.RenderHtmlForUsage(str);
- }
+ for (const auto & x : ChainDelegators)
+ x.RenderHtmlForUsage(str);
}
}
}
@@ -565,83 +605,91 @@ namespace NKikimr {
TVector<NPrivate::TChainLayoutBuilder::TSeg> TAllChains::GetLayout() const {
TVector<NPrivate::TChainLayoutBuilder::TSeg> res;
- res.reserve(Chains.size());
- ui32 prevSlotSizeInBlocks = MinHugeBlobInBlocks;
- for (const auto& chain : Chains) {
- const ui32 slotSizeInBlocks = chain.SlotSize / AppendBlockSize;
- res.push_back({
- prevSlotSizeInBlocks,
- slotSizeInBlocks - prevSlotSizeInBlocks,
- });
- prevSlotSizeInBlocks = slotSizeInBlocks;
+ res.reserve(ChainDelegators.size());
+ for (const auto &x : ChainDelegators) {
+ res.push_back(NPrivate::TChainLayoutBuilder::TSeg {x.Blocks, x.Blocks + x.ShiftInBlocks} );
}
return res;
}
std::shared_ptr<THugeSlotsMap> TAllChains::BuildHugeSlotsMap() const {
- THugeSlotsMap::TAllSlotsInfo allSlotsInfo;
- for (const auto& chain : Chains) {
- allSlotsInfo.emplace_back(chain.SlotSize, chain.SlotsInChunk);
+ THugeSlotsMap::TAllSlotsInfo targetAllSlotsInfo;
+ THugeSlotsMap::TSearchTable targetSearchTable;
+
+ for (const auto &x : SearchTable) {
+ if (!x) {
+ // first records in SearchTable are equal to nullptr
+ targetSearchTable.push_back(THugeSlotsMap::NoOpIdx);
+ continue;
+ }
+
+ if (targetAllSlotsInfo.empty() || targetAllSlotsInfo.back().SlotSize != x->SlotSize) {
+ targetAllSlotsInfo.emplace_back(x->SlotSize, x->SlotsInChunk);
+ }
+ targetSearchTable.push_back(THugeSlotsMap::TIndex(targetAllSlotsInfo.size() - 1));
}
- return std::make_shared<THugeSlotsMap>(AppendBlockSize, MinHugeBlobInBlocks, std::move(allSlotsInfo),
- THugeSlotsMap::TSearchTable(SearchTable));
+
+ return std::make_shared<THugeSlotsMap>(AppendBlockSize, std::move(targetAllSlotsInfo),
+ std::move(targetSearchTable));
}
////////////////////////////////////////////////////////////////////////////
// TAllChains: Private
////////////////////////////////////////////////////////////////////////////
- void TAllChains::BuildChains() {
- const ui32 startBlocks = MinHugeBlobInBlocks;
- const ui32 milestoneBlocks = MilestoneBlobInBytes / AppendBlockSize;
- const ui32 endBlocks = MaxHugeBlobInBlocks;
+ TAllChains::TAllChainDelegators TAllChains::BuildChains(ui32 minHugeBlobInBytes) const {
+ // minHugeBlobInBytes -- is the only variable parameter, used for migration
+ const ui32 startBlocks = minHugeBlobInBytes / AppendBlockSize;
+ const ui32 mileStoneBlocks = MilestoneBlobInBytes / AppendBlockSize;
+ const ui32 endBlocks = GetEndBlocks();
- NPrivate::TChainLayoutBuilder builder(startBlocks, milestoneBlocks, endBlocks, Overhead);
- const ui32 blocksInChunk = ChunkSize / AppendBlockSize;
+ NPrivate::TChainLayoutBuilder builder(startBlocks, mileStoneBlocks, endBlocks, Overhead);
+ Y_ABORT_UNLESS(!builder.GetLayout().empty());
+ TAllChainDelegators result;
for (auto x : builder.GetLayout()) {
- const ui32 slotSizeInBlocks = x.Right;
- const ui32 slotSize = slotSizeInBlocks * AppendBlockSize;
- const ui32 slotsInChunk = blocksInChunk / slotSizeInBlocks;
- Chains.emplace_back(VDiskLogPrefix, slotsInChunk, slotSize);
+ result.emplace_back(VDiskLogPrefix, x.Left, x.Right - x.Left,
+ ChunkSize, AppendBlockSize);
}
-
- Y_ABORT_UNLESS(!Chains.empty());
+ return result;
}
void TAllChains::BuildSearchTable() {
- Y_ABORT_UNLESS(SearchTable.empty());
- Y_ABORT_UNLESS(!Chains.empty());
-
- const ui32 startBlocks = MinHugeBlobInBlocks;
- const ui32 minSize = startBlocks * AppendBlockSize;
- const ui32 endBlocks = MaxHugeBlobInBlocks; // maximum possible number of blocks per huge blob
- auto it = Chains.begin();
- ui16 index = 0;
-
- SearchTable.reserve(endBlocks - startBlocks + 1);
- for (ui32 i = startBlocks, size = minSize; i <= endBlocks; ++i, size += AppendBlockSize) {
- if (it->SlotSize < size) { // size doesn't fit in current chain, but it must fit into next one
+ const ui32 endBlocks = GetEndBlocks();
+ Y_DEBUG_ABORT_UNLESS(!ChainDelegators.empty());
+ TAllChainDelegators::iterator it = ChainDelegators.begin();
+ TChainDelegator *ptr = nullptr;
+ ui32 blocks = it->Blocks;
+ for (ui32 i = 0; i <= endBlocks; i++) {
+ if (i <= blocks) {
+ } else {
+ ptr = &(*it);
++it;
- Y_ABORT_UNLESS(it != Chains.end());
- Y_ABORT_UNLESS(size <= it->SlotSize);
- Y_ABORT_UNLESS(index != Max<ui16>());
- ++index;
+ if (it == ChainDelegators.end())
+ blocks = ui32(-1);
+ else
+ blocks = it->Blocks;
}
- SearchTable.push_back(index);
+ SearchTable.push_back(ptr);
}
}
- ui32 TAllChains::SizeToBlocks(ui32 size) const {
- return (size + AppendBlockSize - 1) / AppendBlockSize;
+ void TAllChains::BuildLayout()
+ {
+ ChainDelegators = BuildChains(MinHugeBlobInBytes);
+ Y_ABORT_UNLESS(!ChainDelegators.empty());
+ BuildSearchTable();
+ }
+
+ inline ui32 TAllChains::SizeToBlocks(ui32 size) const {
+ ui32 sizeInBlocks = size / AppendBlockSize;
+ sizeInBlocks += !(sizeInBlocks * AppendBlockSize == size);
+ return sizeInBlocks;
}
- void TAllChains::FinishRecovery() {
- ui32 prevSlotSize = 0;
- for (const TChain& chain : Chains) {
- Y_ABORT_UNLESS(prevSlotSize < chain.SlotSize);
- prevSlotSize = chain.SlotSize;
- }
- BuildSearchTable();
+ inline ui32 TAllChains::GetEndBlocks() const {
+ ui32 endBlocks = MaxBlobInBytes / AppendBlockSize;
+ endBlocks += !(endBlocks * AppendBlockSize == MaxBlobInBytes);
+ return endBlocks;
}
////////////////////////////////////////////////////////////////////////////
@@ -653,6 +701,7 @@ namespace NKikimr {
ui32 chunkSize,
ui32 appendBlockSize,
ui32 minHugeBlobInBytes,
+ ui32 oldMinHugeBlobSizeInBytes,
ui32 mileStoneBlobInBytes,
ui32 maxBlobInBytes,
ui32 overhead,
@@ -660,41 +709,42 @@ namespace NKikimr {
: VDiskLogPrefix(vdiskLogPrefix)
, FreeChunksReservation(freeChunksReservation)
, FreeChunks()
- , Chains(vdiskLogPrefix, chunkSize, appendBlockSize, minHugeBlobInBytes, mileStoneBlobInBytes,
- maxBlobInBytes, overhead)
+ , Chains(vdiskLogPrefix, chunkSize, appendBlockSize, minHugeBlobInBytes, oldMinHugeBlobSizeInBytes,
+ mileStoneBlobInBytes, maxBlobInBytes, overhead)
{}
//////////////////////////////////////////////////////////////////////////////////////////
// THeap: main functions
//////////////////////////////////////////////////////////////////////////////////////////
- THugeSlot THeap::ConvertDiskPartToHugeSlot(const TDiskPart& addr) const {
- const TChain *chain = Chains.GetChain(addr.Size);
- Y_ABORT_UNLESS(chain);
- return chain->Convert(chain->Convert(addr));
+ THugeSlot THeap::ConvertDiskPartToHugeSlot(const TDiskPart &addr) const {
+ const TChainDelegator *chainD = Chains.GetChain(addr.Size);
+ Y_VERIFY_S(chainD && (addr.Offset / chainD->SlotSize * chainD->SlotSize == addr.Offset), VDiskLogPrefix
+ << "chainD# " << (chainD ? chainD->ToString() : "nullptr") << " addr# " << addr.ToString());
+ return THugeSlot(addr.ChunkIdx, addr.Offset, chainD->SlotSize);
}
bool THeap::Allocate(ui32 size, THugeSlot *hugeSlot, ui32 *slotSize) {
- TChain *chain = Chains.GetChain(size);
- Y_VERIFY_S(chain, VDiskLogPrefix << "size# " << size << " Heap# " << ToString());
- *slotSize = chain->SlotSize;
+ TChainDelegator *chainD = Chains.GetChain(size);
+ Y_VERIFY_S(chainD, VDiskLogPrefix << "size# " << size << " Heap# " << ToString());
+ *slotSize = chainD->SlotSize;
NPrivate::TChunkSlot id;
- if (!chain->Allocate(&id)) { // no available slot in free space of the chain
+ if (!chainD->ChainPtr->Allocate(&id)) { // no available slot in free space of the chain
if (FreeChunks.empty()) { // no free chunks left for reuse -- request a new chunk
return false;
}
- chain->Allocate(&id, GetChunkIdFromFreeChunks()); // reuse free chunk for this chain
+ chainD->ChainPtr->Allocate(&id, GetChunkIdFromFreeChunks()); // reuse free chunk for this chain
}
- *hugeSlot = chain->Convert(id);
+ *hugeSlot = chainD->Convert(id);
return true;
}
TFreeRes THeap::Free(const TDiskPart &addr) {
ui32 size = addr.Size;
- TChain *chain = Chains.GetChain(size);
- Y_ABORT_UNLESS(chain);
+ TChainDelegator *chainD = Chains.GetChain(size);
+ Y_ABORT_UNLESS(chainD);
- TFreeRes res = chain->Free(chain->Convert(addr));
+ TFreeRes res = chainD->ChainPtr->Free(chainD->Convert(addr));
if (res.ChunkId) {
PutChunkIdToFreeChunks(res.ChunkId);
}
@@ -716,19 +766,13 @@ namespace NKikimr {
}
bool THeap::LockChunkForAllocation(ui32 chunkId, ui32 slotSize) {
- TChain *chain = Chains.GetChain(slotSize);
- Y_ABORT_UNLESS(chain);
- return chain->LockChunkForAllocation(chunkId);
+ TChainDelegator *cd = Chains.GetChain(slotSize);
+ return cd->ChainPtr->LockChunkForAllocation(chunkId);
}
void THeap::UnlockChunk(ui32 chunkId, ui32 slotSize) {
- TChain *chain = Chains.GetChain(slotSize);
- Y_ABORT_UNLESS(chain);
- chain->UnlockChunk(chunkId);
- }
-
- void THeap::FinishRecovery() {
- Chains.FinishRecovery();
+ TChainDelegator *cd = Chains.GetChain(slotSize);
+ cd->ChainPtr->UnlockChunk(chunkId);
}
THeapStat THeap::GetStat() const {
@@ -744,11 +788,11 @@ namespace NKikimr {
void THeap::RecoveryModeAllocate(const TDiskPart &addr) {
ui32 size = addr.Size;
- TChain *chain = Chains.GetChain(size);
- Y_VERIFY_S(chain, VDiskLogPrefix << "State# " << ToString());
+ TChainDelegator *chainD = Chains.GetChain(size);
+ Y_VERIFY_S(chainD, VDiskLogPrefix << "State# " << ToString());
- NPrivate::TChunkSlot id(chain->Convert(addr));
- bool allocated = chain->RecoveryModeAllocate(id);
+ NPrivate::TChunkSlot id(chainD->Convert(addr));
+ bool allocated = chainD->ChainPtr->RecoveryModeAllocate(id);
if (allocated) {
return;
} else {
@@ -756,7 +800,7 @@ namespace NKikimr {
TFreeChunks::iterator it = FreeChunks.find(chunkId);
Y_VERIFY_S(it != FreeChunks.end(), VDiskLogPrefix << "addr# " << addr.ToString() << " State# " << ToString());
FreeChunks.erase(it);
- chain->RecoveryModeAllocate(id, chunkId, false);
+ chainD->ChainPtr->RecoveryModeAllocate(id, chunkId, false);
}
}
@@ -773,9 +817,9 @@ namespace NKikimr {
}
bool THeap::ReleaseSlot(THugeSlot slot) {
- TChain* const chain = Chains.GetChain(slot.GetSize());
+ TChainDelegator* const chain = Chains.GetChain(slot.GetSize());
Y_VERIFY_S(chain, VDiskLogPrefix << "State# " << ToString() << " slot# " << slot.ToString());
- if (TFreeRes res = chain->Free(chain->Convert(slot)); res.ChunkId) {
+ if (TFreeRes res = chain->ChainPtr->Free(chain->Convert(slot)); res.ChunkId) {
PutChunkIdToFreeChunks(res.ChunkId);
return res.InLockedChunks;
}
@@ -783,12 +827,12 @@ namespace NKikimr {
}
void THeap::OccupySlot(THugeSlot slot, bool inLockedChunks) {
- TChain* const chain = Chains.GetChain(slot.GetSize());
+ TChainDelegator* const chain = Chains.GetChain(slot.GetSize());
Y_VERIFY_S(chain, VDiskLogPrefix << "State# " << ToString() << " slot# " << slot.ToString());
- if (!chain->RecoveryModeAllocate(chain->Convert(slot))) {
+ if (!chain->ChainPtr->RecoveryModeAllocate(chain->Convert(slot))) {
const size_t numErased = FreeChunks.erase(slot.GetChunkId());
Y_VERIFY_S(numErased, VDiskLogPrefix << "State# " << ToString() << " slot# " << slot.ToString());
- chain->RecoveryModeAllocate(chain->Convert(slot), slot.GetChunkId(), inLockedChunks);
+ chain->ChainPtr->RecoveryModeAllocate(chain->Convert(slot), slot.GetChunkId(), inLockedChunks);
}
}
@@ -855,8 +899,9 @@ namespace NKikimr {
TString THeap::ToString() const {
TStringStream str;
- str << "FreeChunks# " << FormatList(FreeChunks)
- << " Chains# {" << Chains.ToString() << '}';
+ str << "FreeChunks: ";
+ str << FormatList(FreeChunks);
+ str << " CHAINS: " << Chains.ToString();
return str.Str();
}
diff --git a/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugeheap.h b/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugeheap.h
index c7f987b5bb..6fbae987e4 100644
--- a/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugeheap.h
+++ b/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugeheap.h
@@ -70,7 +70,7 @@ namespace NKikimr {
TChainLayoutBuilder(ui32 left, ui32 milestone, ui32 right, ui32 overhead);
const TVector<TSeg> &GetLayout() const { return Layout; }
- const TSeg &GetMilestoneSegment() const { return Layout.at(MilestoneId); }
+ const TSeg &GetMilestoneSegment() const { return Layout.at(MilesoneId); }
TString ToString(ui32 appendBlockSize = 0) const;
void Output(IOutputStream &str, ui32 appendBlockSize = 0) const;
@@ -81,7 +81,7 @@ namespace NKikimr {
TVector<TSeg> Layout;
// An index in Layout vector, where milestone segment starts
- size_t MilestoneId = Max<size_t>();
+ size_t MilesoneId = Max<size_t>();
};
} // NPrivate
@@ -90,43 +90,29 @@ namespace NKikimr {
// TChain
// It manages all slots of some fixed size.
////////////////////////////////////////////////////////////////////////////
- class TChain {
+ class TChain : public TThrRefBase {
using TChunkID = ui32;
using TFreeSpace = TMap<TChunkID, TMask>;
static constexpr ui32 MaxNumberOfSlots = 32768; // it's not a good idea to have more slots than this
- TString VDiskLogPrefix;
- TMask ConstMask; // mask of 'all slots are free'
+ const TString VDiskLogPrefix;
+ const ui32 SlotsInChunk;
+ const TMask ConstMask; // mask of 'all slots are free'
TFreeSpace FreeSpace;
TFreeSpace LockedChunks;
ui32 AllocatedSlots = 0;
ui32 FreeSlotsInFreeSpace = 0;
public:
- ui32 SlotsInChunk;
- ui32 SlotSize; // may be adjusted during deserialization
-
- public:
static TMask BuildConstMask(const TString &prefix, ui32 slotsInChunk);
public:
- TChain(TString vdiskLogPrefix, ui32 slotsInChunk, ui32 slotSize)
- : VDiskLogPrefix(std::move(vdiskLogPrefix))
- , ConstMask(BuildConstMask(vdiskLogPrefix, slotsInChunk))
+ TChain(const TString &vdiskLogPrefix, const ui32 slotsInChunk)
+ : VDiskLogPrefix(vdiskLogPrefix)
, SlotsInChunk(slotsInChunk)
- , SlotSize(slotSize)
+ , ConstMask(BuildConstMask(vdiskLogPrefix, slotsInChunk))
{}
- TChain(TChain&&) = default;
- TChain(const TChain&) = delete;
-
- TChain& operator=(TChain&&) = default;
- TChain& operator=(const TChain&) = delete;
-
- THugeSlot Convert(const NPrivate::TChunkSlot& id) const;
- NPrivate::TChunkSlot Convert(const TDiskPart& addr) const;
- NPrivate::TChunkSlot Convert(const THugeSlot& slot) const;
-
// returns true if allocated, false -- if no free slots
bool Allocate(NPrivate::TChunkSlot *id);
// allocate id, but we know that this chain doesn't have free slots, so add a chunk to it
@@ -140,48 +126,71 @@ namespace NKikimr {
bool RecoveryModeAllocate(const NPrivate::TChunkSlot &id);
void RecoveryModeAllocate(const NPrivate::TChunkSlot &id, TChunkID chunkId, bool inLockedChunks);
void Save(IOutputStream *s) const;
+ void Load(IInputStream *s);
bool HaveBeenUsed() const;
TString ToString() const;
void RenderHtml(IOutputStream &str) const;
- void RenderHtmlForUsage(IOutputStream &str) const;
+ ui32 GetAllocatedSlots() const;
void GetOwnedChunks(TSet<TChunkIdx>& chunks) const;
+ };
- static TChain Load(IInputStream *s, TString vdiskLogPrefix, ui32 appendBlockSize, ui32 blocksInChunk);
-
- template<typename T>
- void ForEachFreeSpaceChunk(T&& callback) const {
- auto freeIt = FreeSpace.begin();
- const auto freeEnd = FreeSpace.end();
- auto lockedIt = LockedChunks.begin();
- const auto lockedEnd = LockedChunks.end();
- while (freeIt != freeEnd || lockedIt != lockedEnd) {
- if (lockedIt == lockedEnd || freeIt->first < lockedIt->first) {
- std::invoke(callback, *freeIt++);
- } else if (freeIt == freeEnd || lockedIt->first < freeIt->first) {
- std::invoke(callback, *lockedIt++);
- } else {
- Y_ABORT("intersecting sets of keys for FreeSpace and LockedChunks");
- }
- }
- }
+ using TChainPtr = TIntrusivePtr<TChain>;
+
+ ////////////////////////////////////////////////////////////////////////////
+ // TChainDelegator
+ ////////////////////////////////////////////////////////////////////////////
+ struct TChainDelegator {
+ TString VDiskLogPrefix;
+ ui32 Blocks;
+ ui32 ShiftInBlocks;
+ ui32 SlotsInChunk;
+ ui32 SlotSize;
+ TChainPtr ChainPtr;
+
+ TChainDelegator(const TString &vdiskLogPrefix,
+ ui32 valBlocks,
+ ui32 shiftBlocks,
+ ui32 chunkSize,
+ ui32 appendBlockSize);
+ TChainDelegator(TChainDelegator &&) = default;
+ TChainDelegator &operator =(TChainDelegator &&) = default;
+ TChainDelegator(const TChainDelegator &) = delete;
+ TChainDelegator &operator =(const TChainDelegator &) = delete;
+ THugeSlot Convert(const NPrivate::TChunkSlot &id) const;
+ NPrivate::TChunkSlot Convert(const TDiskPart &addr) const;
+ NPrivate::TChunkSlot Convert(const THugeSlot &slot) const;
+ void Save(IOutputStream *s) const;
+ void Load(IInputStream *s);
+ bool HaveBeenUsed() const;
+ TString ToString() const;
+ void GetOwnedChunks(TSet<TChunkIdx>& chunks) const;
+ void RenderHtml(IOutputStream &str) const;
+ void RenderHtmlForUsage(IOutputStream &str) const;
};
+
////////////////////////////////////////////////////////////////////////////
// TAllChains
////////////////////////////////////////////////////////////////////////////
class TAllChains {
public:
+ using TAllChainDelegators = TVector<TChainDelegator>;
+ using TSearchTable = TVector<TChainDelegator*>;
+
TAllChains(const TString &vdiskLogPrefix,
ui32 chunkSize,
ui32 appendBlockSize,
ui32 minHugeBlobInBytes,
+ ui32 oldMinHugeBlobSizeInBytes,
ui32 milestoneBlobInBytes,
ui32 maxBlobInBytes,
ui32 overhead);
// return a pointer to corresponding chain delegator by object byte size
- TChain *GetChain(ui32 size);
- const TChain *GetChain(ui32 size) const;
+ TChainDelegator *GetChain(ui32 size);
+ const TChainDelegator *GetChain(ui32 size) const;
THeapStat GetStat() const;
+ void PrintOutChains(IOutputStream &str) const;
+ void PrintOutSearchTable(IOutputStream &str) const;
void Save(IOutputStream *s) const;
void Load(IInputStream *s);
void GetOwnedChunks(TSet<TChunkIdx>& chunks) const;
@@ -190,27 +199,39 @@ namespace NKikimr {
void RenderHtmlForUsage(IOutputStream &str) const;
// for testing purposes
TVector<NPrivate::TChainLayoutBuilder::TSeg> GetLayout() const;
+ // returns (ChainsSize, SearchTableSize)
+ std::pair<ui32, ui32> GetTablesSize() const {
+ return std::pair<ui32, ui32>(ChainDelegators.size(), SearchTable.size());
+ }
// Builds a map of BlobSize -> THugeSlotsMap::TSlotInfo for THugeBlobCtx
std::shared_ptr<THugeSlotsMap> BuildHugeSlotsMap() const;
- void FinishRecovery();
-
private:
- void BuildChains();
+
+ TAllChainDelegators BuildChains(ui32 minHugeBlobInBytes) const;
void BuildSearchTable();
+ void BuildLayout();
inline ui32 SizeToBlocks(ui32 size) const;
+ inline ui32 GetEndBlocks() const;
+
+ enum class EStartMode {
+ Empty = 1,
+ Loaded = 2,
+ Migrated = 3,
+ };
const TString VDiskLogPrefix;
const ui32 ChunkSize;
const ui32 AppendBlockSize;
const ui32 MinHugeBlobInBytes;
+ const ui32 OldMinHugeBlobSizeInBytes;
const ui32 MilestoneBlobInBytes;
+ const ui32 MaxBlobInBytes;
const ui32 Overhead;
- const ui32 MinHugeBlobInBlocks;
- const ui32 MaxHugeBlobInBlocks;
- TDynBitMap DeserializedChains; // a bit mask of chains that were deserialized from the origin stream
- std::vector<TChain> Chains;
- std::vector<ui16> SearchTable; // (NumFullBlocks - 1) -> Chain index
+ EStartMode StartMode = EStartMode::Empty;
+ ui32 FirstLoadedSlotSize = 0;
+ TAllChainDelegators ChainDelegators;
+ TSearchTable SearchTable;
};
@@ -234,6 +255,7 @@ namespace NKikimr {
ui32 appendBlockSize,
// min size of the huge blob
ui32 minHugeBlobInBytes,
+ ui32 oldMinHugeBlobSizeInBytes,
// fixed point to calculate layout (for backward compatibility)
ui32 mileStoneBlobInBytes,
// max size of the blob
@@ -244,13 +266,13 @@ namespace NKikimr {
ui32 SlotNumberOfThisSize(ui32 size) const {
- const TChain *chain = Chains.GetChain(size);
- return chain ? chain->SlotsInChunk : 0;
+ const TChainDelegator *chainD = Chains.GetChain(size);
+ return chainD ? chainD->SlotsInChunk : 0;
}
ui32 SlotSizeOfThisSize(ui32 size) const {
- const TChain *chain = Chains.GetChain(size);
- return chain ? chain->SlotSize : 0;
+ const TChainDelegator *chainD = Chains.GetChain(size);
+ return chainD ? chainD->SlotSize : 0;
}
// Builds a map of BlobSize -> THugeSlotsMap::TSlotInfo for THugeBlobCtx
@@ -280,7 +302,6 @@ namespace NKikimr {
void RecoveryModeRemoveChunks(const TVector<ui32> &chunkIds);
bool ReleaseSlot(THugeSlot slot);
void OccupySlot(THugeSlot slot, bool inLockedChunks);
- void FinishRecovery();
//////////////////////////////////////////////////////////////////////////////////////////
// Serialize/Parse/Check
@@ -296,6 +317,10 @@ namespace NKikimr {
void RenderHtml(IOutputStream &str) const;
TString ToString() const;
+ void PrintOutSearchTable(IOutputStream &str) {
+ Chains.PrintOutSearchTable(str);
+ }
+
private:
inline ui32 GetChunkIdFromFreeChunks();
inline void PutChunkIdToFreeChunks(ui32 chunkId);
diff --git a/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugeheap_ctx_ut.cpp b/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugeheap_ctx_ut.cpp
index 865bf38513..df27d118e9 100644
--- a/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugeheap_ctx_ut.cpp
+++ b/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugeheap_ctx_ut.cpp
@@ -26,6 +26,7 @@ namespace NKikimr {
Contexts.GetVCtx(),
ChunkSize,
AppendBlockSize,
+ AppendBlockSize,
cfg.MinHugeBlobInBytes,
cfg.MilestoneHugeBlobInBytes,
cfg.MaxLogoBlobDataSize,
diff --git a/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugeheap_ut.cpp b/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugeheap_ut.cpp
index 2a07af1013..967a1e2e0d 100644
--- a/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugeheap_ut.cpp
+++ b/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugeheap_ut.cpp
@@ -79,7 +79,7 @@ namespace NKikimr {
}
void AllocFreeOneChunk(ui32 slotsInChunk) {
- TChain chain("vdisk", slotsInChunk, 1);
+ TChain chain("vdisk", slotsInChunk);
TVector<NPrivate::TChunkSlot> arr;
AllocateScenaryOneChunk(chain, arr, slotsInChunk);
FreeScenaryOneChunk(chain, arr, slotsInChunk);
@@ -156,7 +156,7 @@ namespace NKikimr {
}
void AllocFreeAlloc(ui32 slotsInChunk) {
- TChain chain("vdisk", slotsInChunk, 1);
+ TChain chain("vdisk", slotsInChunk);
TVector<NPrivate::TChunkSlot> arr;
TVector<ui32> chunks;
@@ -171,13 +171,17 @@ namespace NKikimr {
TStringStream serialized;
- TChain chain("vdisk", slotsInChunk, 1);
- PreliminaryAllocate(24, chain, arr);
- FreeChunksScenary(chain, arr, chunks);
- chain.Save(&serialized);
-
- TStringInput str(serialized.Str());
- TChain chain2 = TChain::Load(&str, "vdisk", 1 /*appendBlockSize*/, slotsInChunk);
+ {
+ TChain chain("vdisk", slotsInChunk);
+ PreliminaryAllocate(24, chain, arr);
+ FreeChunksScenary(chain, arr, chunks);
+ chain.Save(&serialized);
+ }
+ {
+ TChain chain("vdisk", slotsInChunk);
+ TStringInput str(serialized.Str());
+ chain.Load(&str);
+ }
}
Y_UNIT_TEST(AllocFreeAllocTest) {
@@ -244,6 +248,38 @@ namespace NKikimr {
}
}
+ Y_UNIT_TEST_SUITE(TBlobStorageHullHugeLayout) {
+
+ Y_UNIT_TEST(TestOldAppendBlockSize) {
+ TAllChains all("vdisk", 134274560, 56896, 512 << 10, 512 << 10, 512 << 10, 10 << 20, 8);
+ all.PrintOutChains(STR);
+ all.PrintOutSearchTable(STR);
+ std::pair<ui32, ui32> p = all.GetTablesSize();
+ TVector<NPrivate::TChainLayoutBuilder::TSeg> canonical = {
+ {9, 10}, {10, 11}, {11, 12}, {12, 13}, {13, 14}, {14, 15}, {15, 16}, {16, 18}, {18, 20},
+ {20, 22}, {22, 24}, {24, 27}, {27, 30}, {30, 33}, {33, 37}, {37, 41}, {41, 46}, {46, 51},
+ {51, 57}, {57, 64}, {64, 72}, {72, 81}, {81, 91}, {91, 102}, {102, 114}, {114, 128},
+ {128, 144}, {144, 162}, {162, 182}, {182, 204}
+ };
+ UNIT_ASSERT_EQUAL(all.GetLayout(), canonical);
+ UNIT_ASSERT_EQUAL(p, (std::pair<ui32, ui32>(30, 186)));
+ }
+
+ Y_UNIT_TEST(TestNewAppendBlockSize) {
+ TAllChains all("vdisk", 134274560, 4064, 512 << 10, 512 << 10, 512 << 10, 10 << 20, 8);
+ all.PrintOutChains(STR);
+ all.PrintOutSearchTable(STR);
+ TVector<NPrivate::TChainLayoutBuilder::TSeg> canonical = {
+ {129, 145}, {145, 163}, {163, 183}, {183, 205}, {205, 230}, {230, 258}, {258, 290},
+ {290, 326}, {326, 366}, {366, 411}, {411, 462}, {462, 519}, {519, 583}, {583, 655},
+ {655, 736}, {736, 828}, {828, 931}, {931, 1047}, {1047, 1177}, {1177, 1324},
+ {1324, 1489}, {1489, 1675}, {1675, 1884}, {1884, 2119}, {2119, 2383}, {2383, 2680}
+ };
+ UNIT_ASSERT_EQUAL(all.GetLayout(), canonical);
+ }
+ }
+
+
Y_UNIT_TEST_SUITE(TBlobStorageHullHugeHeap) {
Y_UNIT_TEST(AllocateAllFromOneChunk) {
@@ -254,9 +290,8 @@ namespace NKikimr {
ui32 maxBlobInBytes = 10u << 20u;
ui32 overhead = 8;
ui32 freeChunksReservation = 0;
- THeap heap("vdisk", chunkSize, appendBlockSize, minHugeBlobInBytes, mileStoneBlobInBytes,
+ THeap heap("vdisk", chunkSize, appendBlockSize, appendBlockSize, minHugeBlobInBytes, mileStoneBlobInBytes,
maxBlobInBytes, overhead, freeChunksReservation);
- heap.FinishRecovery();
ui32 hugeBlobSize = 6u << 20u;
heap.AddChunk(5);
@@ -279,10 +314,9 @@ namespace NKikimr {
// just serialize/deserialize
TString serialized = heap.Serialize();
- THeap newHeap("vdisk", chunkSize, appendBlockSize, minHugeBlobInBytes, mileStoneBlobInBytes,
+ THeap newHeap("vdisk", chunkSize, appendBlockSize, minHugeBlobInBytes, minHugeBlobInBytes, mileStoneBlobInBytes,
maxBlobInBytes, overhead, freeChunksReservation);
newHeap.ParseFromString(serialized);
- newHeap.FinishRecovery();
}
void AllocateScenary(THeap &heap, ui32 hugeBlobSize, TVector<THugeSlot> &arr) {
@@ -323,9 +357,8 @@ namespace NKikimr {
ui32 maxBlobInBytes = 10u << 20u;
ui32 overhead = 8;
ui32 freeChunksReservation = 0;
- THeap heap("vdisk", chunkSize, appendBlockSize, minHugeBlobInBytes, minHugeBlobInBytes,
+ THeap heap("vdisk", chunkSize, appendBlockSize, minHugeBlobInBytes, minHugeBlobInBytes, minHugeBlobInBytes,
maxBlobInBytes, overhead, freeChunksReservation);
- heap.FinishRecovery();
TVector<THugeSlot> arr;
AllocateScenary(heap, 6u << 20u, arr);
@@ -339,21 +372,16 @@ namespace NKikimr {
ui32 maxBlobInBytes = 10u << 20u;
ui32 overhead = 8;
ui32 freeChunksReservation = 0;
- THeap heap("vdisk", chunkSize, appendBlockSize, minHugeBlobInBytes, minHugeBlobInBytes,
+ THeap heap("vdisk", chunkSize, appendBlockSize, minHugeBlobInBytes, minHugeBlobInBytes, minHugeBlobInBytes,
maxBlobInBytes, overhead, freeChunksReservation);
- heap.FinishRecovery();
TVector<THugeSlot> arr;
AllocateScenary(heap, 6u << 20u, arr);
- TString heap1 = heap.ToString();
TString serialized = heap.Serialize();
UNIT_ASSERT(THeap::CheckEntryPoint(serialized));
- THeap newHeap("vdisk", chunkSize, appendBlockSize, minHugeBlobInBytes, minHugeBlobInBytes,
+ THeap newHeap("vdisk", chunkSize, appendBlockSize, minHugeBlobInBytes, minHugeBlobInBytes, minHugeBlobInBytes,
maxBlobInBytes, overhead, freeChunksReservation);
newHeap.ParseFromString(serialized);
- newHeap.FinishRecovery();
- TString heap2 = newHeap.ToString();
- UNIT_ASSERT_VALUES_EQUAL(heap1, heap2);
FreeScenary(newHeap, arr);
}
@@ -364,9 +392,8 @@ namespace NKikimr {
ui32 maxBlobInBytes = 10u << 20u;
ui32 overhead = 8;
ui32 freeChunksReservation = 0;
- THeap heap("vdisk", chunkSize, appendBlockSize, minHugeBlobInBytes, minHugeBlobInBytes,
+ THeap heap("vdisk", chunkSize, appendBlockSize, minHugeBlobInBytes, minHugeBlobInBytes, minHugeBlobInBytes,
maxBlobInBytes, overhead, freeChunksReservation);
- heap.FinishRecovery();
heap.RecoveryModeAddChunk(2);
heap.RecoveryModeAddChunk(34);
@@ -394,9 +421,8 @@ namespace NKikimr {
ui32 maxBlobInBytes = MaxVDiskBlobSize;
ui32 overhead = 8u;
ui32 freeChunksReservation = 1;
- THeap heap("vdisk", chunkSize, appendBlockSize, minHugeBlobInBytes, minHugeBlobInBytes,
+ THeap heap("vdisk", chunkSize, appendBlockSize, minHugeBlobInBytes, minHugeBlobInBytes, minHugeBlobInBytes,
maxBlobInBytes, overhead, freeChunksReservation);
- heap.FinishRecovery();
THugeSlot hugeSlot;
ui32 slotSize;
@@ -412,34 +438,52 @@ namespace NKikimr {
RollbackFrom_New_To_Old,
};
- Y_UNIT_TEST(WriteRestore) {
+ void Write_SaveEntryPoint_Restart(EWrite_SaveEntryPoint_Restart mode) {
ui32 chunkSize = 134274560u;
ui32 appendBlockSize = 4064u;
ui32 minHugeBlobInBytes = appendBlockSize;
+ ui32 oldMinHugeBlobInBytes = 64u << 10u;
ui32 mileStoneBlobInBytes = 512u << 10u;
ui32 maxBlobInBytes = 10u << 20u;
ui32 overhead = 8;
ui32 freeChunksReservation = 0;
- THeap oldHeap("vdisk", chunkSize, appendBlockSize, minHugeBlobInBytes, mileStoneBlobInBytes,
+ ui32 fromMin = 0;
+ ui32 toMin = 0;
+ switch (mode) {
+ case EWrite_SaveEntryPoint_Restart::MigrateFrom_Old_To_New:
+ fromMin = oldMinHugeBlobInBytes;
+ toMin = minHugeBlobInBytes;
+ break;
+ case EWrite_SaveEntryPoint_Restart::RollbackFrom_New_To_Old:
+ fromMin = minHugeBlobInBytes;
+ toMin = oldMinHugeBlobInBytes;
+ break;
+ }
+ THeap oldHeap("vdisk", chunkSize, appendBlockSize, oldMinHugeBlobInBytes, oldMinHugeBlobInBytes, mileStoneBlobInBytes,
maxBlobInBytes, overhead, freeChunksReservation);
- oldHeap.FinishRecovery();
- THeap fromHeap("vdisk", chunkSize, appendBlockSize, minHugeBlobInBytes, mileStoneBlobInBytes,
+ THeap fromHeap("vdisk", chunkSize, appendBlockSize, fromMin, oldMinHugeBlobInBytes, mileStoneBlobInBytes,
maxBlobInBytes, overhead, freeChunksReservation);
fromHeap.ParseFromString(oldHeap.Serialize());
- fromHeap.FinishRecovery();
TVector<THugeSlot> arr;
AllocateScenary(fromHeap, 6u << 20u, arr);
TString serialized = fromHeap.Serialize();
UNIT_ASSERT(THeap::CheckEntryPoint(serialized));
- THeap toHeap("vdisk", chunkSize, appendBlockSize, minHugeBlobInBytes, mileStoneBlobInBytes,
+ THeap toHeap("vdisk", chunkSize, appendBlockSize, toMin, oldMinHugeBlobInBytes, mileStoneBlobInBytes,
maxBlobInBytes, overhead, freeChunksReservation);
toHeap.ParseFromString(serialized);
- toHeap.FinishRecovery();
FreeScenary(toHeap, arr);
}
+
+ Y_UNIT_TEST(MigrateFrom_Old_To_New) {
+ Write_SaveEntryPoint_Restart(EWrite_SaveEntryPoint_Restart::MigrateFrom_Old_To_New);
+ }
+
+ Y_UNIT_TEST(RollbackFrom_New_To_Old) {
+ Write_SaveEntryPoint_Restart(EWrite_SaveEntryPoint_Restart::RollbackFrom_New_To_Old);
+ }
}
} // NKikimr
diff --git a/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugerecovery.cpp b/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugerecovery.cpp
index f5aa9d561f..898271ef6d 100644
--- a/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugerecovery.cpp
+++ b/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugerecovery.cpp
@@ -64,6 +64,7 @@ namespace NKikimr {
const ui32 chunkSize,
const ui32 appendBlockSize,
const ui32 minHugeBlobInBytes,
+ const ui32 oldMinHugeBlobInBytes,
const ui32 milestoneHugeBlobInBytes,
const ui32 maxBlobInBytes,
const ui32 overhead,
@@ -72,11 +73,10 @@ namespace NKikimr {
: VCtx(std::move(vctx))
, LogPos(THullHugeRecoveryLogPos::Default())
, Heap(new NHuge::THeap(VCtx->VDiskLogPrefix, chunkSize, appendBlockSize,
- minHugeBlobInBytes, milestoneHugeBlobInBytes,
+ minHugeBlobInBytes, oldMinHugeBlobInBytes, milestoneHugeBlobInBytes,
maxBlobInBytes, overhead, freeChunksReservation))
, Guid(TAppData::RandomProvider->GenRand64())
{
- Heap->FinishRecovery();
logFunc(VDISKP(VCtx->VDiskLogPrefix,
"Recovery started (guid# %" PRIu64 " entryLsn# null): State# %s",
Guid, ToString().data()));
@@ -86,6 +86,7 @@ namespace NKikimr {
const ui32 chunkSize,
const ui32 appendBlockSize,
const ui32 minHugeBlobInBytes,
+ const ui32 oldMinHugeBlobInBytes,
const ui32 milestoneHugeBlobInBytes,
const ui32 maxBlobInBytes,
const ui32 overhead,
@@ -96,13 +97,12 @@ namespace NKikimr {
: VCtx(std::move(vctx))
, LogPos(THullHugeRecoveryLogPos::Default())
, Heap(new NHuge::THeap(VCtx->VDiskLogPrefix, chunkSize, appendBlockSize,
- minHugeBlobInBytes, milestoneHugeBlobInBytes,
+ minHugeBlobInBytes, oldMinHugeBlobInBytes, milestoneHugeBlobInBytes,
maxBlobInBytes, overhead, freeChunksReservation))
, Guid(TAppData::RandomProvider->GenRand64())
, PersistentLsn(entryPointLsn)
{
ParseFromString(entryPointData);
- Heap->FinishRecovery();
Y_ABORT_UNLESS(entryPointLsn == LogPos.EntryPointLsn);
logFunc(VDISKP(VCtx->VDiskLogPrefix,
"Recovery started (guid# %" PRIu64 " entryLsn# %" PRIu64 "): State# %s",
@@ -113,6 +113,7 @@ namespace NKikimr {
const ui32 chunkSize,
const ui32 appendBlockSize,
const ui32 minHugeBlobInBytes,
+ const ui32 oldMinHugeBlobInBytes,
const ui32 milestoneHugeBlobInBytes,
const ui32 maxBlobInBytes,
const ui32 overhead,
@@ -123,13 +124,12 @@ namespace NKikimr {
: VCtx(std::move(vctx))
, LogPos(THullHugeRecoveryLogPos::Default())
, Heap(new NHuge::THeap(VCtx->VDiskLogPrefix, chunkSize, appendBlockSize,
- minHugeBlobInBytes, milestoneHugeBlobInBytes,
+ minHugeBlobInBytes, oldMinHugeBlobInBytes, milestoneHugeBlobInBytes,
maxBlobInBytes, overhead, freeChunksReservation))
, Guid(TAppData::RandomProvider->GenRand64())
, PersistentLsn(entryPointLsn)
{
ParseFromArray(entryPointData.GetData(), entryPointData.GetSize());
- Heap->FinishRecovery();
Y_ABORT_UNLESS(entryPointLsn == LogPos.EntryPointLsn);
logFunc(VDISKP(VCtx->VDiskLogPrefix,
"Recovery started (guid# %" PRIu64 " entryLsn# %" PRIu64 "): State# %s",
diff --git a/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugerecovery.h b/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugerecovery.h
index cea53fbe31..548a4997c2 100644
--- a/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugerecovery.h
+++ b/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugerecovery.h
@@ -92,6 +92,7 @@ namespace NKikimr {
const ui32 chunkSize,
const ui32 appendBlockSize,
const ui32 minHugeBlobInBytes,
+ const ui32 oldMinHugeBlobInBytes,
const ui32 milestoneHugeBlobInBytes,
const ui32 maxBlobInBytes,
const ui32 overhead,
@@ -101,6 +102,7 @@ namespace NKikimr {
const ui32 chunkSize,
const ui32 appendBlockSize,
const ui32 minHugeBlobInBytes,
+ const ui32 oldMinHugeBlobInBytes,
const ui32 milestoneHugeBlobInBytes,
const ui32 maxBlobInBytes,
const ui32 overhead,
@@ -112,6 +114,7 @@ namespace NKikimr {
const ui32 chunkSize,
const ui32 appendBlockSize,
const ui32 minHugeBlobInBytes,
+ const ui32 oldMinHugeBlobInBytes,
const ui32 milestoneHugeBlobInBytes,
const ui32 maxBlobInBytes,
const ui32 overhead,
diff --git a/ydb/core/blobstorage/vdisk/localrecovery/localrecovery_public.cpp b/ydb/core/blobstorage/vdisk/localrecovery/localrecovery_public.cpp
index 7d1028e64e..cda349b521 100644
--- a/ydb/core/blobstorage/vdisk/localrecovery/localrecovery_public.cpp
+++ b/ydb/core/blobstorage/vdisk/localrecovery/localrecovery_public.cpp
@@ -425,6 +425,12 @@ namespace NKikimr {
const ui32 blocksInChunk = LocRecCtx->PDiskCtx->Dsk->ChunkSize / LocRecCtx->PDiskCtx->Dsk->AppendBlockSize;
Y_ABORT_UNLESS(LocRecCtx->PDiskCtx->Dsk->AppendBlockSize * blocksInChunk == LocRecCtx->PDiskCtx->Dsk->ChunkSize);
+ ui32 MaxLogoBlobDataSizeInBlocks = Config->MaxLogoBlobDataSize / LocRecCtx->PDiskCtx->Dsk->AppendBlockSize;
+ MaxLogoBlobDataSizeInBlocks += !!(Config->MaxLogoBlobDataSize -
+ MaxLogoBlobDataSizeInBlocks * LocRecCtx->PDiskCtx->Dsk->AppendBlockSize);
+ const ui32 slotsInChunk = blocksInChunk / MaxLogoBlobDataSizeInBlocks;
+ Y_ABORT_UNLESS(slotsInChunk > 1);
+
auto logFunc = [&] (const TString &msg) {
LOG_DEBUG(ctx, BS_HULLHUGE, msg);
};
@@ -438,8 +444,9 @@ namespace NKikimr {
LocRecCtx->PDiskCtx->Dsk->ChunkSize,
LocRecCtx->PDiskCtx->Dsk->AppendBlockSize,
LocRecCtx->PDiskCtx->Dsk->AppendBlockSize,
+ Config->OldMinHugeBlobInBytes,
Config->MilestoneHugeBlobInBytes,
- Config->MaxLogoBlobDataSize + TDiskBlob::HeaderSize,
+ Config->MaxLogoBlobDataSize,
Config->HugeBlobOverhead,
Config->HugeBlobsFreeChunkReservation,
logFunc);
@@ -459,8 +466,9 @@ namespace NKikimr {
LocRecCtx->PDiskCtx->Dsk->ChunkSize,
LocRecCtx->PDiskCtx->Dsk->AppendBlockSize,
LocRecCtx->PDiskCtx->Dsk->AppendBlockSize,
+ Config->OldMinHugeBlobInBytes,
Config->MilestoneHugeBlobInBytes,
- Config->MaxLogoBlobDataSize + TDiskBlob::HeaderSize,
+ Config->MaxLogoBlobDataSize,
Config->HugeBlobOverhead,
Config->HugeBlobsFreeChunkReservation,
lsn, entryPoint, logFunc);