Skip to content

Commit d0ca520

Browse files
committed
MB-41405: Read persistedDeletes from RW store
Currently when we query the KVStore for the persisted deletes stat we query the RO store which has its own cache and does not track persisted deletes (as they are tracked in the RW store). This means that querying persisted deletes returns the first value correctly (as we read it from disk) but every subsequent query will return the same value. Correct this by querying persisted deletes from the RW store. Change-Id: I2524ca0df1b23a428a34bc645dd606ae48ddaefe Reviewed-on: http://review.couchbase.org/c/kv_engine/+/136523 Well-Formed: Build Bot <[email protected]> Tested-by: Build Bot <[email protected]> Reviewed-by: Paolo Cocchi <[email protected]> Reviewed-by: Jim Walker <[email protected]>
1 parent 50a894e commit d0ca520

File tree

5 files changed

+111
-5
lines changed

5 files changed

+111
-5
lines changed

engines/ep/src/couch-kvstore/couch-kvstore.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2811,6 +2811,10 @@ ENGINE_ERROR_CODE CouchKVStore::couchErr2EngineErr(couchstore_error_t errCode) {
28112811
}
28122812

28132813
size_t CouchKVStore::getNumPersistedDeletes(Vbid vbid) {
2814+
// cachedDeletes isn't tracked correctly for the RO store as it's only set
2815+
// on write so we can't read the stat from it.
2816+
Expects(!readOnly);
2817+
28142818
size_t delCount = cachedDeleteCount[vbid.get()];
28152819
if (delCount != (size_t) -1) {
28162820
return delCount;

engines/ep/src/ep_bucket.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ bool BloomFilterCallback::initTempFilter(Vbid vbucketId) {
118118
size_t estimated_count;
119119
size_t num_deletes = 0;
120120
try {
121-
num_deletes = store.getROUnderlying(vbucketId)->getNumPersistedDeletes(vbucketId);
121+
num_deletes = store.getRWUnderlying(vbucketId)->getNumPersistedDeletes(
122+
vbucketId);
122123
} catch (std::runtime_error& re) {
123124
EP_LOG_WARN(
124125
"BloomFilterCallback::initTempFilter: runtime error while "

engines/ep/src/ep_vb.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -809,7 +809,7 @@ size_t EPVBucket::getNumPersistedDeletes() const {
809809
// If creation is true then no disk file exists
810810
return 0;
811811
}
812-
return shard->getROUnderlying()->getNumPersistedDeletes(getId());
812+
return shard->getRWUnderlying()->getNumPersistedDeletes(getId());
813813
}
814814

815815
void EPVBucket::dropKey(int64_t bySeqno,

engines/ep/tests/module_tests/evp_store_single_threaded_test.cc

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,11 +320,12 @@ void SingleThreadedKVBucketTest::createDcpStream(MockDcpProducer& producer,
320320
}
321321

322322
void SingleThreadedKVBucketTest::runCompaction(uint64_t purgeBeforeTime,
323-
uint64_t purgeBeforeSeq) {
323+
uint64_t purgeBeforeSeq,
324+
bool dropDeletes) {
324325
CompactionConfig compactConfig;
325326
compactConfig.purge_before_ts = purgeBeforeTime;
326327
compactConfig.purge_before_seq = purgeBeforeSeq;
327-
compactConfig.drop_deletes = false;
328+
compactConfig.drop_deletes = dropDeletes;
328329
compactConfig.db_file_id = vbid;
329330
store->scheduleCompaction(vbid, compactConfig, nullptr);
330331
// run the compaction task
@@ -5151,6 +5152,97 @@ TEST_P(STParamPersistentBucketTest, FlushFailureAtPerstingDelete_VBDeletion) {
51515152
testFlushFailureAtPersistDelete(COUCHSTORE_ERROR_WRITE, true);
51525153
}
51535154

5155+
TEST_P(STParameterizedBucketTest, DeleteUpdatesPersistedDeletes) {
5156+
store->setVBucketState(vbid, vbucket_state_active);
5157+
5158+
auto vb = store->getVBucket(vbid);
5159+
ASSERT_TRUE(vb);
5160+
EXPECT_EQ(0, vb->getNumPersistedDeletes());
5161+
5162+
store_item(vbid,
5163+
makeStoredDocKey("keyA"),
5164+
"value",
5165+
0 /*exptime*/,
5166+
{cb::engine_errc::success} /*expected*/,
5167+
PROTOCOL_BINARY_RAW_BYTES);
5168+
delete_item(vbid, makeStoredDocKey("keyA"));
5169+
5170+
flushVBucketToDiskIfPersistent(vbid, 1);
5171+
5172+
// Before the bug fix the stat would be wrong as we'd read from the RO
5173+
// store but only update the cached value in the RW store.
5174+
EXPECT_EQ(1, vb->getNumPersistedDeletes());
5175+
}
5176+
5177+
void STParamPersistentBucketTest::testCompactionPersistedDeletes(
5178+
bool dropDeletes) {
5179+
store->setVBucketState(vbid, vbucket_state_active);
5180+
5181+
flushVBucketToDiskIfPersistent(vbid, 0);
5182+
5183+
auto vb = store->getVBucket(vbid);
5184+
ASSERT_TRUE(vb);
5185+
ASSERT_NE(0, vb->getFilterSize());
5186+
5187+
// Stat should be correct and we should populate the cached value
5188+
EXPECT_EQ(0, vb->getNumPersistedDeletes());
5189+
5190+
// Persist first delete
5191+
store_item(vbid,
5192+
makeStoredDocKey("keyA"),
5193+
"value",
5194+
0 /*exptime*/,
5195+
{cb::engine_errc::success} /*expected*/,
5196+
PROTOCOL_BINARY_RAW_BYTES);
5197+
delete_item(vbid, makeStoredDocKey("keyA"));
5198+
5199+
store_item(vbid,
5200+
makeStoredDocKey("keyB"),
5201+
"value",
5202+
0 /*exptime*/,
5203+
{cb::engine_errc::success} /*expected*/,
5204+
PROTOCOL_BINARY_RAW_BYTES);
5205+
delete_item(vbid, makeStoredDocKey("keyB"));
5206+
5207+
flushVBucketToDiskIfPersistent(vbid, 2);
5208+
5209+
EXPECT_EQ(2, vb->getNumPersistedDeletes());
5210+
5211+
runCompaction(0, 0, dropDeletes);
5212+
}
5213+
5214+
TEST_P(STParamPersistentBucketTest, CompactionUpdatesPersistedDeletes) {
5215+
testCompactionPersistedDeletes(true /*dropDeletes*/);
5216+
5217+
auto vb = store->getVBucket(vbid);
5218+
ASSERT_TRUE(vb);
5219+
5220+
// Before the bug fix the stat would be wrong as we'd read from the RO
5221+
// store but only update the cached value in the RW store. This won't be 0
5222+
// even though we have 2 deletes as we keep the last item during a
5223+
// compaction.
5224+
EXPECT_EQ(1, vb->getNumPersistedDeletes());
5225+
}
5226+
5227+
TEST_P(STParamPersistentBucketTest, CompactionUpdatesBloomFilter) {
5228+
engine->getConfiguration().setBfilterKeyCount(1);
5229+
5230+
testCompactionPersistedDeletes(false /*dropDeletes*/);
5231+
5232+
auto vb = store->getVBucket(vbid);
5233+
ASSERT_TRUE(vb);
5234+
5235+
// Before the bug fix the stat would be wrong as we'd read from the RO
5236+
// store but only update the cached value in the RW store.
5237+
EXPECT_EQ(2, vb->getNumPersistedDeletes());
5238+
5239+
auto expected = 29;
5240+
if (fullEviction()) {
5241+
expected = 10;
5242+
}
5243+
EXPECT_EQ(expected, vb->getFilterSize());
5244+
}
5245+
51545246
TEST_P(STParamPersistentBucketTest, FlusherMarksCleanBySeqno) {
51555247
setVBucketStateAndRunPersistTask(vbid, vbucket_state_active);
51565248

engines/ep/tests/module_tests/evp_store_single_threaded_test.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,11 @@ class SingleThreadedKVBucketTest : public KVBucketTest {
102102
* Run the compaction task
103103
* @param purgeBeforeTime purge tombstones with timestamps less than this
104104
* @param purgeBeforeSeq purge tombstones with seqnos less than this
105+
* @param dropDeletes drop all deletes
105106
*/
106107
void runCompaction(uint64_t purgeBeforeTime = 0,
107-
uint64_t purgeBeforeSeq = 0);
108+
uint64_t purgeBeforeSeq = 0,
109+
bool dropDeletes = false);
108110

109111
/**
110112
* Run the task responsible for iterating the documents and erasing them
@@ -364,4 +366,11 @@ class STParamPersistentBucketTest : public STParameterizedBucketTest {
364366
couchstore_error_t failureCode, bool vbDeletion = false);
365367
void testFlushFailureAtPersistDelete(couchstore_error_t failureCode,
366368
bool vbDeletion = false);
369+
370+
/**
371+
* Test to check that we update and use persistedDeletes correctly.
372+
*
373+
* @param dropDeletes compaction config param
374+
*/
375+
void testCompactionPersistedDeletes(bool dropDeletes);
367376
};

0 commit comments

Comments
 (0)