Fix persistent cache on windows (#6932)

Summary:
Persistent cache feature caused rocks db crash on windows. I posted a issue for it, https://github.com/facebook/rocksdb/issues/6919. I found this is because no "persistent_cache_key_prefix" is generated for persistent cache. Looking repo history, "GetUniqueIdFromFile" is not implemented on Windows. So my fix is adding "NewId()" function in "persistent_cache" and using it to generate prefix for persistent cache. In this PR, i also re-enable related test cases defined in "db_test2" and "persistent_cache_test" for windows.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/6932

Test Plan:
1. run related test cases in "db_test2" and "persistent_cache_test" on windows and see it passed.
2. manually run db_bench.exe with "read_cache_path" and verified.

Reviewed By: riversand963

Differential Revision: D21911608

Pulled By: cheng-chang

fbshipit-source-id: cdfd938d54a385edbb2836b13aaa1d39b0a6f1c2
This commit is contained in:
Zhen Li 2020-06-13 13:26:03 -07:00 committed by Facebook GitHub Bot
parent f7613e2a9e
commit 9c24a5cb4d
9 changed files with 49 additions and 50 deletions

View File

@ -12,6 +12,7 @@
* Fix false negative from the VerifyChecksum() API when there is a checksum mismatch in an index partition block in a BlockBasedTable format table file (index_type is kTwoLevelIndexSearch).
* Fix sst_dump to return non-zero exit code if the specified file is not a recognized SST file or fails requested checks.
* Fix incorrect results from batched MultiGet for duplicate keys, when the duplicate key matches the largest key of an SST file and the value type for the key in the file is a merge value.
* Fix "bad block type" error from persistent cache on Windows.
### Public API Change
* Flush(..., column_family) may return Status::ColumnFamilyDropped() instead of Status::InvalidArgument() if column_family is dropped while processing the flush request.

View File

@ -2010,6 +2010,10 @@ class MockPersistentCache : public PersistentCache {
return PersistentCache::StatsType();
}
uint64_t NewId() override {
return last_id_.fetch_add(1, std::memory_order_relaxed);
}
Status Insert(const Slice& page_key, const char* data,
const size_t size) override {
MutexLock _(&lock_);
@ -2050,6 +2054,7 @@ class MockPersistentCache : public PersistentCache {
const bool is_compressed_ = true;
size_t size_ = 0;
const size_t max_size_ = 10 * 1024; // 10KiB
std::atomic<uint64_t> last_id_{1};
};
#ifdef OS_LINUX
@ -2173,10 +2178,7 @@ TEST_F(DBTest2, TestPerfContextIterCpuTime) {
}
#endif // OS_LINUX
// GetUniqueIdFromFile is not implemented on these platforms. Persistent cache
// breaks when that function is not implemented and no regular block cache is
// provided.
#if !defined(OS_SOLARIS) && !defined(OS_WIN)
#if !defined OS_SOLARIS
TEST_F(DBTest2, PersistentCache) {
int num_iter = 80;
@ -2240,7 +2242,7 @@ TEST_F(DBTest2, PersistentCache) {
}
}
}
#endif // !defined(OS_SOLARIS) && !defined(OS_WIN)
#endif // !defined OS_SOLARIS
namespace {
void CountSyncPoint() {

View File

@ -56,6 +56,12 @@ class PersistentCache {
virtual StatsType Stats() = 0;
virtual std::string GetPrintableOptions() const = 0;
// Return a new numeric id. May be used by multiple clients who are
// sharding the same persistent cache to partition the key space. Typically
// the client will allocate a new id at startup and prepend the id to its
// cache keys.
virtual uint64_t NewId() = 0;
};
// Factor method to create a new persistent cache

View File

@ -722,7 +722,7 @@ BlockBasedTableBuilder::BlockBasedTableBuilder(
rep_->filter_builder->StartBlock(0);
}
if (table_options.block_cache_compressed.get() != nullptr) {
BlockBasedTable::GenerateCachePrefix(
BlockBasedTable::GenerateCachePrefix<Cache, FSWritableFile>(
table_options.block_cache_compressed.get(), file->writable_file(),
&rep_->compressed_cache_key_prefix[0],
&rep_->compressed_cache_key_prefix_size);

View File

@ -452,44 +452,21 @@ void BlockBasedTable::SetupCacheKeyPrefix(Rep* rep) {
rep->cache_key_prefix_size = 0;
rep->compressed_cache_key_prefix_size = 0;
if (rep->table_options.block_cache != nullptr) {
GenerateCachePrefix(rep->table_options.block_cache.get(), rep->file->file(),
&rep->cache_key_prefix[0], &rep->cache_key_prefix_size);
GenerateCachePrefix<Cache, FSRandomAccessFile>(
rep->table_options.block_cache.get(), rep->file->file(),
&rep->cache_key_prefix[0], &rep->cache_key_prefix_size);
}
if (rep->table_options.persistent_cache != nullptr) {
GenerateCachePrefix(/*cache=*/nullptr, rep->file->file(),
&rep->persistent_cache_key_prefix[0],
&rep->persistent_cache_key_prefix_size);
GenerateCachePrefix<PersistentCache, FSRandomAccessFile>(
rep->table_options.persistent_cache.get(), rep->file->file(),
&rep->persistent_cache_key_prefix[0],
&rep->persistent_cache_key_prefix_size);
}
if (rep->table_options.block_cache_compressed != nullptr) {
GenerateCachePrefix(rep->table_options.block_cache_compressed.get(),
rep->file->file(), &rep->compressed_cache_key_prefix[0],
&rep->compressed_cache_key_prefix_size);
}
}
void BlockBasedTable::GenerateCachePrefix(Cache* cc, FSRandomAccessFile* file,
char* buffer, size_t* size) {
// generate an id from the file
*size = file->GetUniqueId(buffer, kMaxCacheKeyPrefixSize);
// If the prefix wasn't generated or was too long,
// create one from the cache.
if (cc != nullptr && *size == 0) {
char* end = EncodeVarint64(buffer, cc->NewId());
*size = static_cast<size_t>(end - buffer);
}
}
void BlockBasedTable::GenerateCachePrefix(Cache* cc, FSWritableFile* file,
char* buffer, size_t* size) {
// generate an id from the file
*size = file->GetUniqueId(buffer, kMaxCacheKeyPrefixSize);
// If the prefix wasn't generated or was too long,
// create one from the cache.
if (cc != nullptr && *size == 0) {
char* end = EncodeVarint64(buffer, cc->NewId());
*size = static_cast<size_t>(end - buffer);
GenerateCachePrefix<Cache, FSRandomAccessFile>(
rep->table_options.block_cache_compressed.get(), rep->file->file(),
&rep->compressed_cache_key_prefix[0],
&rep->compressed_cache_key_prefix_size);
}
}

View File

@ -439,10 +439,19 @@ class BlockBasedTable : public TableReader {
static void SetupCacheKeyPrefix(Rep* rep);
// Generate a cache key prefix from the file
static void GenerateCachePrefix(Cache* cc, FSRandomAccessFile* file,
char* buffer, size_t* size);
static void GenerateCachePrefix(Cache* cc, FSWritableFile* file, char* buffer,
size_t* size);
template <typename TCache, typename TFile>
static void GenerateCachePrefix(TCache* cc, TFile* file, char* buffer,
size_t* size) {
// generate an id from the file
*size = file->GetUniqueId(buffer, kMaxCacheKeyPrefixSize);
// If the prefix wasn't generated or was too long,
// create one from the cache.
if (cc != nullptr && *size == 0) {
char* end = EncodeVarint64(buffer, cc->NewId());
*size = static_cast<size_t>(end - buffer);
}
}
// Size of all data blocks, maybe approximate
uint64_t GetApproximateDataSize();

View File

@ -6,10 +6,7 @@
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.
// GetUniqueIdFromFile is not implemented on Windows. Persistent cache
// breaks when that function is not implemented
#if !defined(ROCKSDB_LITE) && !defined(OS_WIN)
#if !defined ROCKSDB_LITE
#include "utilities/persistent_cache/persistent_cache_test.h"
@ -472,6 +469,6 @@ int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
#else // !defined(ROCKSDB_LITE) && !defined(OS_WIN)
#else // !defined ROCKSDB_LITE
int main() { return 0; }
#endif // !defined(ROCKSDB_LITE) && !defined(OS_WIN)
#endif // !defined ROCKSDB_LITE

View File

@ -99,6 +99,10 @@ PersistentCache::StatsType PersistentCacheTier::Stats() {
return PersistentCache::StatsType{};
}
uint64_t PersistentCacheTier::NewId() {
return last_id_.fetch_add(1, std::memory_order_relaxed);
}
//
// PersistentTieredCache implementation
//

View File

@ -266,6 +266,8 @@ class PersistentCacheTier : public PersistentCache {
virtual std::string GetPrintableOptions() const override = 0;
virtual uint64_t NewId() override;
// Return a reference to next tier
virtual Tier& next_tier() { return next_tier_; }
@ -283,6 +285,7 @@ class PersistentCacheTier : public PersistentCache {
private:
Tier next_tier_; // next tier
std::atomic<uint64_t> last_id_{1};
};
// PersistentTieredCache