Skip to content

Commit fa48d60

Browse files
Support multiple range
1 parent c289917 commit fa48d60

File tree

4 files changed

+127
-24
lines changed

4 files changed

+127
-24
lines changed

fdbclient/ServerKnobs.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,7 @@ void ServerKnobs::initialize(Randomize randomize, ClientKnobs* clientKnobs, IsSi
623623
// Block cache key-value checksum. Checksum is validated during read, so has non-trivial impact on read performance.
624624
init( ROCKSDB_BLOCK_PROTECTION_BYTES_PER_KEY, 0 ); if ( randomize && BUGGIFY ) ROCKSDB_BLOCK_PROTECTION_BYTES_PER_KEY = 8; // Default: 0 (disabled). Supported values: 0, 1, 2, 4, 8.
625625
init( ROCKSDB_ENABLE_NONDETERMINISM, false );
626+
init( SHARDED_ROCKSDB_ALLOW_MULTIPLE_RANGES, false );
626627
init( SHARDED_ROCKSDB_ALLOW_WRITE_STALL_ON_FLUSH, false );
627628
init( SHARDED_ROCKSDB_VALIDATE_MAPPING_RATIO, 0.01 ); if (isSimulated) SHARDED_ROCKSDB_VALIDATE_MAPPING_RATIO = deterministicRandom()->random01();
628629
init( SHARD_METADATA_SCAN_BYTES_LIMIT, 10485760 ); // 10MB

fdbclient/include/fdbclient/ServerKnobs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,7 @@ class SWIFT_CXX_IMMORTAL_SINGLETON_TYPE ServerKnobs : public KnobsImpl<ServerKno
607607
// Note that turning this on in simulation could lead to non-deterministic runs
608608
// since we rely on rocksdb metadata. This knob also applies to sharded rocks
609609
// storage engine.
610+
bool SHARDED_ROCKSDB_ALLOW_MULTIPLE_RANGES;
610611
bool SHARDED_ROCKSDB_ALLOW_WRITE_STALL_ON_FLUSH;
611612
int SHARDED_ROCKSDB_MEMTABLE_MAX_RANGE_DELETIONS;
612613
double SHARDED_ROCKSDB_VALIDATE_MAPPING_RATIO;

fdbserver/KeyValueStoreShardedRocksDB.actor.cpp

Lines changed: 121 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,7 +1546,7 @@ class ShardManager {
15461546
for (auto it = ranges.begin(); it != ranges.end(); ++it) {
15471547
if (it.value()) {
15481548
if (it.value()->physicalShard->id == id) {
1549-
TraceEvent(SevError, "ShardedRocksDBAddRange")
1549+
TraceEvent(SevWarn, "ShardedRocksDBAddRange")
15501550
.detail("ErrorType", "RangeAlreadyExist")
15511551
.detail("IntersectingRange", it->range())
15521552
.detail("DataShardRange", it->value()->range)
@@ -1564,15 +1564,21 @@ class ShardManager {
15641564
}
15651565
}
15661566

1567-
auto currentCfOptions = active ? rState->getCFOptions() : rState->getCFOptionsForInactiveShard();
1568-
auto [it, inserted] = physicalShards.emplace(id, std::make_shared<PhysicalShard>(db, id, currentCfOptions));
1569-
std::shared_ptr<PhysicalShard>& shard = it->second;
1570-
1571-
activePhysicalShardIds.emplace(id);
1567+
auto it = physicalShards.find(id);
1568+
std::shared_ptr<PhysicalShard> physicalShard = nullptr;
1569+
if (it != physicalShards.end()) {
1570+
physicalShard = it->second;
1571+
ASSERT(SERVER_KNOBS->SHARDED_ROCKSDB_ALLOW_MULTIPLE_RANGES);
1572+
} else {
1573+
auto currentCfOptions = active ? rState->getCFOptions() : rState->getCFOptionsForInactiveShard();
1574+
auto [it, inserted] = physicalShards.emplace(id, std::make_shared<PhysicalShard>(db, id, currentCfOptions));
1575+
physicalShard = it->second;
1576+
activePhysicalShardIds.emplace(id);
1577+
}
15721578

1573-
auto dataShard = std::make_unique<DataShard>(range, shard.get());
1579+
auto dataShard = std::make_unique<DataShard>(range, physicalShard.get());
15741580
dataShardMap.insert(range, dataShard.get());
1575-
shard->dataShards[range.begin.toString()] = std::move(dataShard);
1581+
physicalShard->dataShards[range.begin.toString()] = std::move(dataShard);
15761582

15771583
validate();
15781584

@@ -1581,7 +1587,7 @@ class ShardManager {
15811587
.detail("ShardId", id)
15821588
.detail("Active", active);
15831589

1584-
return shard.get();
1590+
return physicalShard.get();
15851591
}
15861592

15871593
std::vector<std::string> removeRange(KeyRange range) {
@@ -1636,6 +1642,7 @@ class ShardManager {
16361642

16371643
// Range modification could result in more than one segments. Remove the original segment key here.
16381644
existingShard->dataShards.erase(shardRange.begin.toString());
1645+
int count = 0;
16391646
if (shardRange.begin < range.begin) {
16401647
auto dataShard =
16411648
std::make_unique<DataShard>(KeyRange(KeyRangeRef(shardRange.begin, range.begin)), existingShard);
@@ -1646,6 +1653,7 @@ class ShardManager {
16461653

16471654
existingShard->dataShards[shardRange.begin.toString()] = std::move(dataShard);
16481655
logShardEvent(existingShard->id, shardRange, ShardOp::MODIFY_RANGE, SevInfo, msg);
1656+
count++;
16491657
}
16501658

16511659
if (shardRange.end > range.end) {
@@ -1658,6 +1666,12 @@ class ShardManager {
16581666

16591667
existingShard->dataShards[range.end.toString()] = std::move(dataShard);
16601668
logShardEvent(existingShard->id, shardRange, ShardOp::MODIFY_RANGE, SevInfo, msg);
1669+
count++;
1670+
}
1671+
1672+
if (count > 1) {
1673+
TraceEvent("RangeSplit").detail("OriginalRange", shardRange).detail("RemovedRange", range);
1674+
ASSERT(SERVER_KNOBS->SHARDED_ROCKSDB_ALLOW_MULTIPLE_RANGES);
16611675
}
16621676
}
16631677

@@ -1986,28 +2000,37 @@ class ShardManager {
19862000
}
19872001

19882002
TraceEvent(SevVerbose, "ShardedRocksValidateShardManager", this->logId);
2003+
int totalDataShards = 0;
2004+
int expectedDataShards = 0;
19892005
for (auto s = dataShardMap.ranges().begin(); s != dataShardMap.ranges().end(); ++s) {
19902006
TraceEvent e(SevVerbose, "ShardedRocksValidateDataShardMap", this->logId);
19912007
e.detail("Range", s->range());
19922008
const DataShard* shard = s->value();
19932009
e.detail("ShardAddress", reinterpret_cast<std::uintptr_t>(shard));
1994-
if (shard != nullptr) {
1995-
e.detail("PhysicalShard", shard->physicalShard->id);
1996-
} else {
1997-
e.detail("Shard", "Empty");
2010+
if (shard == nullptr) {
2011+
e.detail("RangeUnassigned", "True");
2012+
continue;
19982013
}
1999-
if (shard != nullptr) {
2000-
if (shard->range != static_cast<KeyRangeRef>(s->range())) {
2001-
TraceEvent(SevWarnAlways, "ShardRangeMismatch").detail("Range", s->range());
2002-
}
2003-
2004-
ASSERT(shard->range == static_cast<KeyRangeRef>(s->range()));
2005-
ASSERT(shard->physicalShard != nullptr);
2006-
auto it = shard->physicalShard->dataShards.find(shard->range.begin.toString());
2007-
ASSERT(it != shard->physicalShard->dataShards.end());
2008-
ASSERT(it->second.get() == shard);
2014+
totalDataShards++;
2015+
if (shard->range != static_cast<KeyRangeRef>(s->range())) {
2016+
TraceEvent(SevWarnAlways, "ShardRangeMismatch")
2017+
.detail("Range", s->range())
2018+
.detail("DataShardRange", shard->range)
2019+
.detail("PhysicalShardId", shard->physicalShard->id);
20092020
}
2021+
2022+
ASSERT(shard->range == static_cast<KeyRangeRef>(s->range()));
2023+
ASSERT(shard->physicalShard != nullptr);
2024+
auto it = shard->physicalShard->dataShards.find(shard->range.begin.toString());
2025+
ASSERT(it != shard->physicalShard->dataShards.end());
2026+
ASSERT(it->second.get() == shard);
2027+
}
2028+
2029+
for (auto [shardId, physicalShard] : physicalShards) {
2030+
ASSERT(physicalShard);
2031+
expectedDataShards += physicalShard->dataShards.size();
20102032
}
2033+
ASSERT_EQ(expectedDataShards, totalDataShards);
20112034
}
20122035

20132036
private:
@@ -4403,6 +4426,81 @@ TEST_CASE("noSim/ShardedRocksDB/Metadata") {
44034426
return Void();
44044427
}
44054428

4429+
TEST_CASE("noSim/ShardedRocksDBRangeOps/RemoveSplitRange") {
4430+
state std::string rocksDBTestDir = "sharded-rocksdb-kvs-test-db";
4431+
platform::eraseDirectoryRecursive(rocksDBTestDir);
4432+
4433+
state ShardedRocksDBKeyValueStore* rocksdbStore =
4434+
new ShardedRocksDBKeyValueStore(rocksDBTestDir, deterministicRandom()->randomUniqueID());
4435+
state IKeyValueStore* kvStore = rocksdbStore;
4436+
wait(kvStore->init());
4437+
4438+
// Add two ranges to the same shard.
4439+
{
4440+
std::vector<Future<Void>> addRangeFutures;
4441+
addRangeFutures.push_back(kvStore->addRange(KeyRangeRef("a"_sr, "d"_sr), "shard-1"));
4442+
addRangeFutures.push_back(kvStore->addRange(KeyRangeRef("g"_sr, "n"_sr), "shard-1"));
4443+
4444+
wait(waitForAll(addRangeFutures));
4445+
}
4446+
4447+
state std::set<std::string> originalKeys = { "a", "b", "c", "g", "h", "m" };
4448+
state std::set<std::string> currentKeys = originalKeys;
4449+
for (auto key : originalKeys) {
4450+
kvStore->set(KeyValueRef(key, key));
4451+
}
4452+
wait(kvStore->commit());
4453+
4454+
state std::string key;
4455+
for (key : currentKeys) {
4456+
Optional<Value> val = wait(kvStore->readValue(key));
4457+
ASSERT(val.present());
4458+
ASSERT(val.get().toString() == key);
4459+
}
4460+
4461+
// Remove single range.
4462+
std::vector<std::string> shardsToCleanUp;
4463+
auto shardIds = kvStore->removeRange(KeyRangeRef("b"_sr, "c"_sr));
4464+
// Remove range didn't create empty shard.
4465+
ASSERT_EQ(shardIds.size(), 0);
4466+
4467+
currentKeys.erase("b");
4468+
for (key : originalKeys) {
4469+
Optional<Value> val = wait(kvStore->readValue(key));
4470+
if (currentKeys.contains(key)) {
4471+
ASSERT(val.present());
4472+
ASSERT(val.get().toString() == key);
4473+
} else {
4474+
ASSERT(!val.present());
4475+
}
4476+
}
4477+
4478+
// Remove range spanning on multple sub range.
4479+
auto shardIds = kvStore->removeRange(KeyRangeRef("c"_sr, "k"_sr));
4480+
ASSERT(shardIds.empty());
4481+
4482+
currentKeys.erase("c");
4483+
currentKeys.erase("g");
4484+
currentKeys.erase("h");
4485+
for (key : originalKeys) {
4486+
Optional<Value> val = wait(kvStore->readValue(key));
4487+
if (currentKeys.contains(key)) {
4488+
ASSERT(val.present());
4489+
ASSERT(val.get().toString() == key);
4490+
} else {
4491+
ASSERT(!val.present());
4492+
}
4493+
}
4494+
4495+
{
4496+
Future<Void> closed = kvStore->onClosed();
4497+
kvStore->dispose();
4498+
wait(closed);
4499+
}
4500+
ASSERT(!directoryExists(rocksDBTestDir));
4501+
return Void();
4502+
}
4503+
44064504
TEST_CASE("noSim/ShardedRocksDBCheckpoint/CheckpointBasic") {
44074505
state std::string rocksDBTestDir = "sharded-rocks-checkpoint-restore";
44084506
state std::map<Key, Value> kvs({ { "a"_sr, "TestValueA"_sr },

tests/noSim/ShardedRocksDBTest.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
rocksdb_disable_auto_compactions = true
33
rocksdb_suggest_compact_clear_range = false
44
rocksdb_empty_range_check = false
5+
sharded_rocksdb_validate_mapping_ratio=1.0
6+
sharded_rocksdb_allow_multiple_ranges=true
57

68
[[test]]
79
testTitle = 'UnitTests'
@@ -11,4 +13,5 @@ rocksdb_empty_range_check = false
1113
[[test.workload]]
1214
testName = 'UnitTests'
1315
maxTestCases = 10
14-
testsMatching = 'noSim/ShardedRocksDB/'
16+
# testsMatching = 'noSim/ShardedRocksDB/'
17+
testsMatching = 'noSim/ShardedRocksDBRangeOps/RemoveSplitRange'

0 commit comments

Comments
 (0)