diff options
| author | Dan Engelbrecht <[email protected]> | 2022-03-21 09:33:59 +0100 |
|---|---|---|
| committer | Dan Engelbrecht <[email protected]> | 2022-03-31 11:28:32 +0200 |
| commit | 9a85201337a554a36ffdf55c2e084462ec031d7d (patch) | |
| tree | 1c8bf6fdd05678a7a53370485fa99685ad631710 | |
| parent | ChunkBlock takes prepared path (diff) | |
| download | zen-9a85201337a554a36ffdf55c2e084462ec031d7d.tar.xz zen-9a85201337a554a36ffdf55c2e084462ec031d7d.zip | |
Add GC reserve block logic
| -rw-r--r-- | zenstore/compactcas.cpp | 81 |
1 files changed, 71 insertions, 10 deletions
diff --git a/zenstore/compactcas.cpp b/zenstore/compactcas.cpp index 8cf6fe229..99f00f5af 100644 --- a/zenstore/compactcas.cpp +++ b/zenstore/compactcas.cpp @@ -309,7 +309,7 @@ CasContainerStrategy::InsertChunk(const void* ChunkData, size_t ChunkSize, const WriteBlockIndex += WriteBlock ? 1 : 0; while (m_ChunkBlocks.contains(WriteBlockIndex)) { - WriteBlockIndex++; + WriteBlockIndex = (WriteBlockIndex + 1) & CasDiskLocation::MaxBlockIndex; } auto BlockPath = BuildUcasPath(m_BlocksBasePath, WriteBlockIndex); WriteBlock = std::make_shared<ChunkBlock>(BlockPath); @@ -678,6 +678,7 @@ CasContainerStrategy::CollectGarbage(GcContext& GcCtx) if (!NewBlockFile || (WriteOffset + Chunk.size() > m_MaxBlockSize)) { NewBlockIndex = m_WriteBlockIndex.load(); + { RwLock::ExclusiveLockScope _l(m_LocationMapLock); if (NewBlockFile) @@ -695,12 +696,16 @@ CasContainerStrategy::CollectGarbage(GcContext& GcCtx) return; } } + if (m_ChunkBlocks.size() == CasDiskLocation::MaxBlockIndex) + { + throw std::runtime_error(fmt::format("unable to allocate a new block in {}", m_ContainerBaseName)); + } while (m_ChunkBlocks.contains(NewBlockIndex)) { - NewBlockIndex++; + NewBlockIndex = (NewBlockIndex + 1) & CasDiskLocation::MaxBlockIndex; } - auto BlockPath = BuildUcasPath(m_BlocksBasePath, NewBlockIndex); - NewBlockFile = std::make_shared<ChunkBlock>(BlockPath); + auto NewBlockPath = BuildUcasPath(m_BlocksBasePath, NewBlockIndex); + NewBlockFile = std::make_shared<ChunkBlock>(NewBlockPath); m_ChunkBlocks[NewBlockIndex] = NewBlockFile; } @@ -714,16 +719,30 @@ CasContainerStrategy::CollectGarbage(GcContext& GcCtx) if (Space.Free < m_MaxBlockSize) { - ZEN_INFO("garbage collect from '{}' FAILED, required disk space {}, free {}", + std::filesystem::path GCReservePath = m_Config.RootDirectory / (m_ContainerBaseName + ".gc.reserve.ucas"); + if (!std::filesystem::is_regular_file(GCReservePath)) + { + ZEN_INFO("garbage collect from '{}' FAILED, required disk space {}, free {}", + m_Config.RootDirectory / m_ContainerBaseName, + m_MaxBlockSize, + NiceBytes(Space.Free)); + RwLock::ExclusiveLockScope _l(m_LocationMapLock); + m_ChunkBlocks.erase(NewBlockIndex); + return; + } + + ZEN_INFO("using gc reserve for '{}', disk free {}", m_Config.RootDirectory / m_ContainerBaseName, - m_MaxBlockSize * m_MaxBlockSize, NiceBytes(Space.Free)); - RwLock::ExclusiveLockScope _l(m_LocationMapLock); - m_ChunkBlocks.erase(NewBlockIndex); - return; + auto NewBlockPath = BuildUcasPath(m_BlocksBasePath, NewBlockIndex); + std::filesystem::rename(GCReservePath, NewBlockPath); + NewBlockFile->Open(); + } + else + { + NewBlockFile->Create(m_MaxBlockSize); } - NewBlockFile->Create(m_MaxBlockSize); MovedBlocks.clear(); WriteOffset = 0; } @@ -930,6 +949,7 @@ CasContainerStrategy::OpenContainer(bool IsNewStore) std::filesystem::path SidxPath = m_Config.RootDirectory / (m_ContainerBaseName + ".uidx"); std::filesystem::path SlogPath = m_Config.RootDirectory / (m_ContainerBaseName + ".ulog"); std::filesystem::path LegacySobsPath = m_Config.RootDirectory / (m_ContainerBaseName + ".ucas"); + if (IsNewStore) { if (std::filesystem::is_regular_file(LegacySobsPath)) @@ -1177,6 +1197,47 @@ CasContainerStrategy::OpenContainer(bool IsNewStore) m_CurrentInsertOffset = AlignPositon(SmallestBlockSize, m_PayloadAlignment); } + // Create GC reserve file if possible + std::filesystem::path GCReservePath = m_Config.RootDirectory / (m_ContainerBaseName + ".gc.reserve.ucas"); + + std::error_code Error; + DiskSpace Space = DiskSpaceInfo(m_Config.RootDirectory, Error); + if (Error) + { + ZEN_ERROR("get disk space in {} FAILED, reason '{}'", m_ContainerBaseName, Error.message()); + return; + } + + BasicFile GCReserveFile; + if (std::filesystem::is_regular_file(GCReservePath)) + { + GCReserveFile.Open(GCReservePath, false); + std::uint64_t CurrentSize = GCReserveFile.FileSize(); + if (CurrentSize != m_MaxBlockSize) + { + if (CurrentSize > m_MaxBlockSize) + { + GCReserveFile.SetFileSize(m_MaxBlockSize); + } + else + { + std::uint64_t ExtraSpace = m_MaxBlockSize - CurrentSize; + if (Space.Free >= ExtraSpace) + { + GCReserveFile.SetFileSize(m_MaxBlockSize); + } + } + } + } + else + { + if (Space.Free > m_MaxBlockSize) + { + GCReserveFile.Open(GCReservePath, true); + GCReserveFile.SetFileSize(m_MaxBlockSize); + } + } + // TODO: should validate integrity of container files here } |