aboutsummaryrefslogtreecommitdiff
path: root/zenserver/cache/structuredcachestore.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'zenserver/cache/structuredcachestore.cpp')
-rw-r--r--zenserver/cache/structuredcachestore.cpp446
1 files changed, 352 insertions, 94 deletions
diff --git a/zenserver/cache/structuredcachestore.cpp b/zenserver/cache/structuredcachestore.cpp
index 3189a14cc..e4dbf390a 100644
--- a/zenserver/cache/structuredcachestore.cpp
+++ b/zenserver/cache/structuredcachestore.cpp
@@ -205,6 +205,36 @@ namespace {
return true;
}
+ bool MoveAndDeleteDirectory(const std::filesystem::path& Dir)
+ {
+ int DropIndex = 0;
+ do
+ {
+ if (!std::filesystem::exists(Dir))
+ {
+ return false;
+ }
+
+ std::string DroppedName = fmt::format("[dropped]{}({})", Dir.filename().string(), DropIndex);
+ std::filesystem::path DroppedBucketPath = Dir.parent_path() / DroppedName;
+ if (std::filesystem::exists(DroppedBucketPath))
+ {
+ DropIndex++;
+ continue;
+ }
+
+ std::error_code Ec;
+ std::filesystem::rename(Dir, DroppedBucketPath, Ec);
+ if (!Ec)
+ {
+ DeleteDirectories(DroppedBucketPath);
+ return true;
+ }
+ // TODO: Do we need to bail at some point?
+ zen::Sleep(100);
+ } while (true);
+ }
+
} // namespace
namespace fs = std::filesystem;
@@ -342,6 +372,13 @@ ZenCacheNamespace::DropBucket(std::string_view Bucket)
return AnyDropped;
}
+bool
+ZenCacheNamespace::Drop()
+{
+ m_MemLayer.Drop();
+ return m_DiskLayer.Drop();
+}
+
void
ZenCacheNamespace::Flush()
{
@@ -404,14 +441,14 @@ ZenCacheMemoryLayer::Get(std::string_view InBucket, const IoHash& HashKey, ZenCa
{
RwLock::SharedLockScope _(m_Lock);
- auto it = m_Buckets.find(std::string(InBucket));
+ auto It = m_Buckets.find(std::string(InBucket));
- if (it == m_Buckets.end())
+ if (It == m_Buckets.end())
{
return false;
}
- CacheBucket* Bucket = &it->second;
+ CacheBucket* Bucket = It->second.get();
_.ReleaseNow();
@@ -425,14 +462,15 @@ ZenCacheMemoryLayer::Get(std::string_view InBucket, const IoHash& HashKey, ZenCa
void
ZenCacheMemoryLayer::Put(std::string_view InBucket, const IoHash& HashKey, const ZenCacheValue& Value)
{
- CacheBucket* Bucket = nullptr;
+ const auto BucketName = std::string(InBucket);
+ CacheBucket* Bucket = nullptr;
{
RwLock::SharedLockScope _(m_Lock);
if (auto It = m_Buckets.find(std::string(InBucket)); It != m_Buckets.end())
{
- Bucket = &It->second;
+ Bucket = It->second.get();
}
}
@@ -444,11 +482,12 @@ ZenCacheMemoryLayer::Put(std::string_view InBucket, const IoHash& HashKey, const
if (auto It = m_Buckets.find(std::string(InBucket)); It != m_Buckets.end())
{
- Bucket = &It->second;
+ Bucket = It->second.get();
}
else
{
- Bucket = &m_Buckets[std::string(InBucket)];
+ auto InsertResult = m_Buckets.emplace(BucketName, std::make_unique<CacheBucket>());
+ Bucket = InsertResult.first->second.get();
}
}
@@ -458,11 +497,37 @@ ZenCacheMemoryLayer::Put(std::string_view InBucket, const IoHash& HashKey, const
}
bool
-ZenCacheMemoryLayer::DropBucket(std::string_view Bucket)
+ZenCacheMemoryLayer::DropBucket(std::string_view InBucket)
{
RwLock::ExclusiveLockScope _(m_Lock);
- return !!m_Buckets.erase(std::string(Bucket));
+ auto It = m_Buckets.find(std::string(InBucket));
+
+ if (It != m_Buckets.end())
+ {
+ CacheBucket& Bucket = *It->second;
+ m_DroppedBuckets.push_back(std::move(It->second));
+ m_Buckets.erase(It);
+ Bucket.Drop();
+ return true;
+ }
+ return false;
+}
+
+void
+ZenCacheMemoryLayer::Drop()
+{
+ RwLock::ExclusiveLockScope _(m_Lock);
+ std::vector<std::unique_ptr<CacheBucket>> Buckets;
+ Buckets.reserve(m_Buckets.size());
+ while (!m_Buckets.empty())
+ {
+ const auto& It = m_Buckets.begin();
+ CacheBucket& Bucket = *It->second;
+ m_DroppedBuckets.push_back(std::move(It->second));
+ m_Buckets.erase(It->first);
+ Bucket.Drop();
+ }
}
void
@@ -472,7 +537,7 @@ ZenCacheMemoryLayer::Scrub(ScrubContext& Ctx)
for (auto& Kv : m_Buckets)
{
- Kv.second.Scrub(Ctx);
+ Kv.second->Scrub(Ctx);
}
}
@@ -486,7 +551,7 @@ ZenCacheMemoryLayer::GatherAccessTimes(zen::access_tracking::AccessTimes& Access
for (auto& Kv : m_Buckets)
{
std::vector<KeyAccessTime>& Bucket = AccessTimes.Buckets[Kv.first];
- Kv.second.GatherAccessTimes(Bucket);
+ Kv.second->GatherAccessTimes(Bucket);
}
}
@@ -505,7 +570,7 @@ ZenCacheMemoryLayer::TotalSize() const
for (auto& Kv : m_Buckets)
{
- TotalSize += Kv.second.TotalSize();
+ TotalSize += Kv.second->TotalSize();
}
return TotalSize;
@@ -570,9 +635,16 @@ ZenCacheMemoryLayer::CacheBucket::Put(const IoHash& HashKey, const ZenCacheValue
m_TotalSize.fetch_add(Value.Value.GetSize(), std::memory_order::relaxed);
}
+void
+ZenCacheMemoryLayer::CacheBucket::Drop()
+{
+ RwLock::ExclusiveLockScope _(m_BucketLock);
+ m_CacheMap.clear();
+}
+
//////////////////////////////////////////////////////////////////////////
-ZenCacheDiskLayer::CacheBucket::CacheBucket(std::string BucketName) : m_BucketName(std::move(BucketName))
+ZenCacheDiskLayer::CacheBucket::CacheBucket(std::string BucketName) : m_BucketName(std::move(BucketName)), m_BucketId(Oid::Zero)
{
}
@@ -581,19 +653,6 @@ ZenCacheDiskLayer::CacheBucket::~CacheBucket()
}
bool
-ZenCacheDiskLayer::CacheBucket::Delete(std::filesystem::path BucketDir)
-{
- if (std::filesystem::exists(BucketDir))
- {
- DeleteDirectories(BucketDir);
-
- return true;
- }
-
- return false;
-}
-
-void
ZenCacheDiskLayer::CacheBucket::OpenOrCreate(std::filesystem::path BucketDir, bool AllowCreate)
{
using namespace std::literals;
@@ -611,7 +670,10 @@ ZenCacheDiskLayer::CacheBucket::OpenOrCreate(std::filesystem::path BucketDir, bo
if (Manifest)
{
m_BucketId = Manifest["BucketId"].AsObjectId();
- m_IsOk = m_BucketId != Oid::Zero;
+ if (m_BucketId == Oid::Zero)
+ {
+ return false;
+ }
}
else if (AllowCreate)
{
@@ -625,7 +687,7 @@ ZenCacheDiskLayer::CacheBucket::OpenOrCreate(std::filesystem::path BucketDir, bo
}
else
{
- return;
+ return false;
}
OpenLog(BucketDir, IsNew);
@@ -641,7 +703,7 @@ ZenCacheDiskLayer::CacheBucket::OpenOrCreate(std::filesystem::path BucketDir, bo
}
}
- m_IsOk = true;
+ return true;
}
void
@@ -1158,11 +1220,6 @@ ZenCacheDiskLayer::CacheBucket::GetStandaloneCacheValue(const DiskLocation& Loc,
bool
ZenCacheDiskLayer::CacheBucket::Get(const IoHash& HashKey, ZenCacheValue& OutValue)
{
- if (!m_IsOk)
- {
- return false;
- }
-
RwLock::SharedLockScope _(m_IndexLock);
auto It = m_Index.find(HashKey);
if (It == m_Index.end())
@@ -1184,11 +1241,6 @@ ZenCacheDiskLayer::CacheBucket::Get(const IoHash& HashKey, ZenCacheValue& OutVal
void
ZenCacheDiskLayer::CacheBucket::Put(const IoHash& HashKey, const ZenCacheValue& Value)
{
- if (!m_IsOk)
- {
- return;
- }
-
if (Value.Value.Size() >= m_LargeObjectThreshold)
{
return PutStandaloneCacheValue(HashKey, Value);
@@ -1196,12 +1248,24 @@ ZenCacheDiskLayer::CacheBucket::Put(const IoHash& HashKey, const ZenCacheValue&
PutInlineCacheValue(HashKey, Value);
}
-void
+bool
ZenCacheDiskLayer::CacheBucket::Drop()
{
+ RwLock::ExclusiveLockScope _(m_IndexLock);
+
+ std::vector<std::unique_ptr<RwLock::ExclusiveLockScope>> ShardLocks;
+ ShardLocks.reserve(256);
+ for (RwLock& Lock : m_ShardedLocks)
+ {
+ ShardLocks.push_back(std::make_unique<RwLock::ExclusiveLockScope>(Lock));
+ }
m_BlockStore.Close();
m_SlogFile.Close();
- DeleteDirectories(m_BucketDir);
+
+ bool Deleted = MoveAndDeleteDirectory(m_BucketDir);
+
+ m_Index.clear();
+ return Deleted;
}
void
@@ -1703,7 +1767,8 @@ ZenCacheDiskLayer::CollectGarbage(GcContext& GcCtx)
for (auto& Kv : m_Buckets)
{
- Kv.second.CollectGarbage(GcCtx);
+ CacheBucket& Bucket = *Kv.second;
+ Bucket.CollectGarbage(GcCtx);
}
}
@@ -1716,7 +1781,7 @@ ZenCacheDiskLayer::UpdateAccessTimes(const zen::access_tracking::AccessTimes& Ac
{
if (auto It = m_Buckets.find(Kv.first); It != m_Buckets.end())
{
- CacheBucket& Bucket = It->second;
+ CacheBucket& Bucket = *It->second;
Bucket.UpdateAccessTimes(Kv.second);
}
}
@@ -1925,11 +1990,11 @@ ZenCacheDiskLayer::Get(std::string_view InBucket, const IoHash& HashKey, ZenCach
{
RwLock::SharedLockScope _(m_Lock);
- auto it = m_Buckets.find(BucketName);
+ auto It = m_Buckets.find(BucketName);
- if (it != m_Buckets.end())
+ if (It != m_Buckets.end())
{
- Bucket = &it->second;
+ Bucket = It->second.get();
}
}
@@ -1939,24 +2004,27 @@ ZenCacheDiskLayer::Get(std::string_view InBucket, const IoHash& HashKey, ZenCach
RwLock::ExclusiveLockScope _(m_Lock);
- if (auto it = m_Buckets.find(BucketName); it != m_Buckets.end())
+ if (auto It = m_Buckets.find(BucketName); It != m_Buckets.end())
{
- Bucket = &it->second;
+ Bucket = It->second.get();
}
else
{
- auto It = m_Buckets.try_emplace(BucketName, BucketName);
- Bucket = &It.first->second;
+ auto InsertResult = m_Buckets.emplace(BucketName, std::make_unique<CacheBucket>(BucketName));
+ Bucket = InsertResult.first->second.get();
std::filesystem::path BucketPath = m_RootDir;
BucketPath /= BucketName;
- Bucket->OpenOrCreate(BucketPath);
+ if (!Bucket->OpenOrCreate(BucketPath))
+ {
+ m_Buckets.erase(BucketName);
+ return false;
+ }
}
}
ZEN_ASSERT(Bucket != nullptr);
-
return Bucket->Get(HashKey, OutValue);
}
@@ -1969,11 +2037,11 @@ ZenCacheDiskLayer::Put(std::string_view InBucket, const IoHash& HashKey, const Z
{
RwLock::SharedLockScope _(m_Lock);
- auto it = m_Buckets.find(BucketName);
+ auto It = m_Buckets.find(BucketName);
- if (it != m_Buckets.end())
+ if (It != m_Buckets.end())
{
- Bucket = &it->second;
+ Bucket = It->second.get();
}
}
@@ -1983,28 +2051,29 @@ ZenCacheDiskLayer::Put(std::string_view InBucket, const IoHash& HashKey, const Z
RwLock::ExclusiveLockScope _(m_Lock);
- if (auto it = m_Buckets.find(BucketName); it != m_Buckets.end())
+ if (auto It = m_Buckets.find(BucketName); It != m_Buckets.end())
{
- Bucket = &it->second;
+ Bucket = It->second.get();
}
else
{
- auto It = m_Buckets.try_emplace(BucketName, BucketName);
- Bucket = &It.first->second;
+ auto InsertResult = m_Buckets.emplace(BucketName, std::make_unique<CacheBucket>(BucketName));
+ Bucket = InsertResult.first->second.get();
std::filesystem::path BucketPath = m_RootDir;
BucketPath /= BucketName;
- Bucket->OpenOrCreate(BucketPath);
+ if (!Bucket->OpenOrCreate(BucketPath))
+ {
+ m_Buckets.erase(BucketName);
+ return;
+ }
}
}
ZEN_ASSERT(Bucket != nullptr);
- if (Bucket->IsOk())
- {
- Bucket->Put(HashKey, Value);
- }
+ Bucket->Put(HashKey, Value);
}
void
@@ -2023,26 +2092,20 @@ ZenCacheDiskLayer::DiscoverBuckets()
// New bucket needs to be created
if (auto It = m_Buckets.find(BucketName); It != m_Buckets.end())
{
+ continue;
}
- else
- {
- auto InsertResult = m_Buckets.try_emplace(BucketName, BucketName);
-
- CacheBucket& Bucket = InsertResult.first->second;
- Bucket.OpenOrCreate(BucketPath, /* AllowCreate */ false);
+ auto InsertResult = m_Buckets.emplace(BucketName, std::make_unique<CacheBucket>(BucketName));
+ CacheBucket& Bucket = *InsertResult.first->second;
- if (Bucket.IsOk())
- {
- ZEN_INFO("Discovered bucket '{}'", BucketName);
- }
- else
- {
- ZEN_WARN("Found directory '{}' in our base directory '{}' but it is not a valid bucket", BucketName, m_RootDir);
+ if (!Bucket.OpenOrCreate(BucketPath, /* AllowCreate */ false))
+ {
+ ZEN_WARN("Found directory '{}' in our base directory '{}' but it is not a valid bucket", BucketName, m_RootDir);
- m_Buckets.erase(InsertResult.first);
- }
+ m_Buckets.erase(InsertResult.first);
+ continue;
}
+ ZEN_INFO("Discovered bucket '{}'", BucketName);
}
}
@@ -2051,23 +2114,42 @@ ZenCacheDiskLayer::DropBucket(std::string_view InBucket)
{
RwLock::ExclusiveLockScope _(m_Lock);
- auto it = m_Buckets.find(std::string(InBucket));
+ auto It = m_Buckets.find(std::string(InBucket));
- if (it != m_Buckets.end())
+ if (It != m_Buckets.end())
{
- CacheBucket* Bucket = &it->second;
-
- Bucket->Drop();
+ CacheBucket& Bucket = *It->second;
+ m_DroppedBuckets.push_back(std::move(It->second));
+ m_Buckets.erase(It);
- m_Buckets.erase(it);
-
- return true;
+ return Bucket.Drop();
}
+ // Make sure we remove the folder even if we don't know about the bucket
std::filesystem::path BucketPath = m_RootDir;
BucketPath /= std::string(InBucket);
+ return MoveAndDeleteDirectory(BucketPath);
+}
+
+bool
+ZenCacheDiskLayer::Drop()
+{
+ RwLock::ExclusiveLockScope _(m_Lock);
- return CacheBucket::Delete(BucketPath);
+ std::vector<std::unique_ptr<CacheBucket>> Buckets;
+ Buckets.reserve(m_Buckets.size());
+ while (!m_Buckets.empty())
+ {
+ const auto& It = m_Buckets.begin();
+ CacheBucket& Bucket = *It->second;
+ m_DroppedBuckets.push_back(std::move(It->second));
+ m_Buckets.erase(It->first);
+ if (!Bucket.Drop())
+ {
+ return false;
+ }
+ }
+ return MoveAndDeleteDirectory(m_RootDir);
}
void
@@ -2080,7 +2162,8 @@ ZenCacheDiskLayer::Flush()
Buckets.reserve(m_Buckets.size());
for (auto& Kv : m_Buckets)
{
- Buckets.push_back(&Kv.second);
+ CacheBucket* Bucket = Kv.second.get();
+ Buckets.push_back(Bucket);
}
}
@@ -2097,7 +2180,8 @@ ZenCacheDiskLayer::Scrub(ScrubContext& Ctx)
for (auto& Kv : m_Buckets)
{
- Kv.second.Scrub(Ctx);
+ CacheBucket& Bucket = *Kv.second;
+ Bucket.Scrub(Ctx);
}
}
@@ -2108,7 +2192,8 @@ ZenCacheDiskLayer::GatherReferences(GcContext& GcCtx)
for (auto& Kv : m_Buckets)
{
- Kv.second.GatherReferences(GcCtx);
+ CacheBucket& Bucket = *Kv.second;
+ Bucket.GatherReferences(GcCtx);
}
}
@@ -2120,7 +2205,7 @@ ZenCacheDiskLayer::TotalSize() const
for (auto& Kv : m_Buckets)
{
- TotalSize += Kv.second.TotalSize();
+ TotalSize += Kv.second->TotalSize();
}
return TotalSize;
@@ -2221,7 +2306,22 @@ ZenCacheStore::DropBucket(std::string_view Namespace, std::string_view Bucket)
{
return Store->DropBucket(Bucket);
}
- ZEN_WARN("request for unknown namespace '{}' in ZenCacheStore::Put, bucket '{}'", Namespace, Bucket);
+ ZEN_WARN("request for unknown namespace '{}' in ZenCacheStore::DropBucket, bucket '{}'", Namespace, Bucket);
+ return false;
+}
+
+bool
+ZenCacheStore::DropNamespace(std::string_view InNamespace)
+{
+ RwLock::SharedLockScope _(m_NamespacesLock);
+ if (auto It = m_Namespaces.find(std::string(InNamespace)); It != m_Namespaces.end())
+ {
+ ZenCacheNamespace& Namespace = *It->second;
+ m_DroppedNamespaces.push_back(std::move(It->second));
+ m_Namespaces.erase(It);
+ return Namespace.Drop();
+ }
+ ZEN_WARN("request for unknown namespace '{}' in ZenCacheStore::DropNamespace", InNamespace);
return false;
}
@@ -2274,7 +2374,7 @@ ZenCacheStore::GetNamespace(std::string_view Namespace)
void
ZenCacheStore::IterateNamespaces(const std::function<void(std::string_view Namespace, ZenCacheNamespace& Store)>& Callback) const
{
- std::vector<std::pair<std::string, ZenCacheNamespace&> > Namespaces;
+ std::vector<std::pair<std::string, ZenCacheNamespace&>> Namespaces;
{
RwLock::SharedLockScope _(m_NamespacesLock);
Namespaces.reserve(m_Namespaces.size());
@@ -3118,6 +3218,164 @@ TEST_CASE("z$.namespaces")
}
}
+TEST_CASE("z$.drop.bucket")
+{
+ using namespace testutils;
+
+ const auto CreateCacheValue = [](size_t Size) -> CbObject {
+ std::vector<uint8_t> Buf;
+ Buf.resize(Size);
+
+ CbObjectWriter Writer;
+ Writer.AddBinary("Binary"sv, Buf.data(), Buf.size());
+ return Writer.Save();
+ };
+
+ ScopedTemporaryDirectory TempDir;
+ CreateDirectories(TempDir.Path());
+
+ IoHash Key1;
+ IoHash Key2;
+
+ auto PutValue =
+ [&CreateCacheValue](ZenCacheStore& Zcs, std::string_view Namespace, std::string_view Bucket, size_t KeyIndex, size_t Size) {
+ // Create a cache record
+ IoHash Key = CreateKey(KeyIndex);
+ CbObject CacheValue = CreateCacheValue(Size);
+
+ IoBuffer Buffer = CacheValue.GetBuffer().AsIoBuffer();
+ Buffer.SetContentType(ZenContentType::kCbObject);
+
+ ZenCacheValue PutValue = {.Value = Buffer};
+ Zcs.Put(Namespace, Bucket, Key, PutValue);
+ return Key;
+ };
+ auto GetValue = [](ZenCacheStore& Zcs, std::string_view Namespace, std::string_view Bucket, const IoHash& Key) {
+ ZenCacheValue GetValue;
+ Zcs.Get(Namespace, Bucket, Key, GetValue);
+ return GetValue;
+ };
+ WorkerThreadPool Workers(1);
+ {
+ CasGc Gc;
+ ZenCacheStore Zcs(Gc, {.BasePath = TempDir.Path() / "cache", .AllowAutomaticCreationOfNamespaces = true});
+ const auto Bucket = "teardrinker"sv;
+ const auto Namespace = "mynamespace"sv;
+
+ Key1 = PutValue(Zcs, Namespace, Bucket, 42, 4096);
+ Key2 = PutValue(Zcs, Namespace, Bucket, 43, 2048);
+
+ ZenCacheValue Value1 = GetValue(Zcs, Namespace, Bucket, Key1);
+ CHECK(Value1.Value);
+
+ std::atomic_bool WorkComplete = false;
+ Workers.ScheduleWork([&]() {
+ zen::Sleep(100);
+ Value1.Value = IoBuffer{};
+ WorkComplete = true;
+ });
+ // On Windows, DropBucket() will be blocked as long as we hold a reference to a buffer in the bucket
+ // Our DropBucket execution blocks any incoming request from completing until we are done with the drop
+ CHECK(Zcs.DropBucket(Namespace, Bucket));
+ while (!WorkComplete)
+ {
+ zen::Sleep(1);
+ }
+
+ // Entire bucket should be dropped, but doing a request should will re-create the namespace but it must still be empty
+ Value1 = GetValue(Zcs, Namespace, Bucket, Key1);
+ CHECK(!Value1.Value);
+ ZenCacheValue Value2 = GetValue(Zcs, Namespace, Bucket, Key2);
+ CHECK(!Value2.Value);
+ }
+}
+
+TEST_CASE("z$.drop.namespace")
+{
+ using namespace testutils;
+
+ const auto CreateCacheValue = [](size_t Size) -> CbObject {
+ std::vector<uint8_t> Buf;
+ Buf.resize(Size);
+
+ CbObjectWriter Writer;
+ Writer.AddBinary("Binary"sv, Buf.data(), Buf.size());
+ return Writer.Save();
+ };
+
+ ScopedTemporaryDirectory TempDir;
+ CreateDirectories(TempDir.Path());
+
+ auto PutValue =
+ [&CreateCacheValue](ZenCacheStore& Zcs, std::string_view Namespace, std::string_view Bucket, size_t KeyIndex, size_t Size) {
+ // Create a cache record
+ IoHash Key = CreateKey(KeyIndex);
+ CbObject CacheValue = CreateCacheValue(Size);
+
+ IoBuffer Buffer = CacheValue.GetBuffer().AsIoBuffer();
+ Buffer.SetContentType(ZenContentType::kCbObject);
+
+ ZenCacheValue PutValue = {.Value = Buffer};
+ Zcs.Put(Namespace, Bucket, Key, PutValue);
+ return Key;
+ };
+ auto GetValue = [](ZenCacheStore& Zcs, std::string_view Namespace, std::string_view Bucket, const IoHash& Key) {
+ ZenCacheValue GetValue;
+ Zcs.Get(Namespace, Bucket, Key, GetValue);
+ return GetValue;
+ };
+ WorkerThreadPool Workers(1);
+ {
+ CasGc Gc;
+ ZenCacheStore Zcs(Gc, {.BasePath = TempDir.Path() / "cache", .AllowAutomaticCreationOfNamespaces = true});
+ const auto Bucket1 = "teardrinker1"sv;
+ const auto Bucket2 = "teardrinker2"sv;
+ const auto Namespace1 = "mynamespace1"sv;
+ const auto Namespace2 = "mynamespace2"sv;
+
+ IoHash Key1 = PutValue(Zcs, Namespace1, Bucket1, 42, 4096);
+ IoHash Key2 = PutValue(Zcs, Namespace1, Bucket2, 43, 2048);
+ IoHash Key3 = PutValue(Zcs, Namespace2, Bucket1, 44, 4096);
+ IoHash Key4 = PutValue(Zcs, Namespace2, Bucket2, 45, 2048);
+
+ ZenCacheValue Value1 = GetValue(Zcs, Namespace1, Bucket1, Key1);
+ CHECK(Value1.Value);
+ ZenCacheValue Value2 = GetValue(Zcs, Namespace1, Bucket2, Key2);
+ CHECK(Value2.Value);
+ ZenCacheValue Value3 = GetValue(Zcs, Namespace2, Bucket1, Key3);
+ CHECK(Value3.Value);
+ ZenCacheValue Value4 = GetValue(Zcs, Namespace2, Bucket2, Key4);
+ CHECK(Value4.Value);
+
+ std::atomic_bool WorkComplete = false;
+ Workers.ScheduleWork([&]() {
+ zen::Sleep(100);
+ Value1.Value = IoBuffer{};
+ Value2.Value = IoBuffer{};
+ Value3.Value = IoBuffer{};
+ Value4.Value = IoBuffer{};
+ WorkComplete = true;
+ });
+ // On Windows, DropBucket() will be blocked as long as we hold a reference to a buffer in the bucket
+ // Our DropBucket execution blocks any incoming request from completing until we are done with the drop
+ CHECK(Zcs.DropNamespace(Namespace1));
+ while (!WorkComplete)
+ {
+ zen::Sleep(1);
+ }
+
+ // Entire namespace should be dropped, but doing a request should will re-create the namespace but it must still be empty
+ Value1 = GetValue(Zcs, Namespace1, Bucket1, Key1);
+ CHECK(!Value1.Value);
+ Value2 = GetValue(Zcs, Namespace1, Bucket2, Key2);
+ CHECK(!Value2.Value);
+ Value3 = GetValue(Zcs, Namespace2, Bucket1, Key3);
+ CHECK(Value3.Value);
+ Value4 = GetValue(Zcs, Namespace2, Bucket2, Key4);
+ CHECK(Value4.Value);
+ }
+}
+
TEST_CASE("z$.blocked.disklayer.put")
{
ScopedTemporaryDirectory TempDir;