Skip to content

Commit af01fe1

Browse files
committed
MB-68655: Test more than CAS when considering Item/SV equality
In the processExpiredItem path there is a StoredValue vs Item compare that considers same CAS being same Item. This is not correct - SetWithMeta could create a new mutation that differs from what Item in the expiry pager is holding onto - but the CAS could match. This commit ensures all metadata is compared (and seqno) when considering if an Item matches the StoredValue. Change-Id: I7fa20a4b9156cf12ad3c0e7c782e1751994ed735 Reviewed-on: https://review.couchbase.org/c/kv_engine/+/234233 Reviewed-by: Mohammad Zaeem <[email protected]> Well-Formed: Restriction Checker Tested-by: Jim Walker <[email protected]>
1 parent 256ae4a commit af01fe1

File tree

5 files changed

+28
-3
lines changed

5 files changed

+28
-3
lines changed

engines/ep/src/stored-value.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,13 @@ void StoredValue::setCompletedOrDeletedTime(time_t time) {
515515
}
516516
}
517517

518+
bool StoredValue::compareSeqnoAndMetaData(const Item& itm) const {
519+
const auto metaData = itm.getMetaData();
520+
return itm.getBySeqno() == getBySeqno() && getCas() == metaData.cas &&
521+
getRevSeqno() == metaData.revSeqno &&
522+
getExptime() == metaData.exptime && getFlags() == metaData.flags;
523+
}
524+
518525
void to_json(nlohmann::json& json, const StoredValue& sv) {
519526
// Add any additional OrderedStoredValue data if required.
520527
if (sv.isOrdered()) {

engines/ep/src/stored-value.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,16 @@ class StoredValue {
910910
*/
911911
void setCompletedOrDeletedTime(time_t time);
912912

913+
/**
914+
* Compare an Item againt a StoredValue (the key is not compared and is
915+
* assumed the caller found this StoredValue from the key)
916+
*
917+
* @param itm The Item to compare against
918+
* @return True if the Item's seqno, cas, revSeqno, exptime, and flags
919+
* match the StoredValue's seqno, cas, revSeqno, exptime, and flags
920+
*/
921+
bool compareSeqnoAndMetaData(const Item& itm) const;
922+
913923
protected:
914924
/**
915925
* Constructor - protected as allocation needs to be done via

engines/ep/src/vbucket.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2552,7 +2552,7 @@ std::unique_ptr<CompactionBGFetchItem> VBucket::processExpiredItem(
25522552
auto& hbl = htRes.getHBL();
25532553

25542554
if (v) {
2555-
if (v->getCas() != it.getCas()) {
2555+
if (!v->compareSeqnoAndMetaData(it)) {
25562556
return nullptr;
25572557
}
25582558

engines/ep/tests/module_tests/kv_bucket_test.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1393,8 +1393,9 @@ TEST_P(KVBucketParamTest, unlockKeyTempDeletedTest) {
13931393
EXPECT_EQ(cb::engine_errc::success, gv.getStatus());
13941394

13951395
// Need the "real" documents' CAS for expiry.
1396-
itm.setCas(docCas);
1397-
store->processExpiredItem(itm, ep_real_time() + 10001, ExpireBy::Pager);
1396+
gv.item->setCas(docCas);
1397+
store->processExpiredItem(
1398+
*gv.item, ep_real_time() + 10001, ExpireBy::Pager);
13981399

13991400
flushVBucketToDiskIfPersistent(vbid, 1);
14001401

engines/ep/tests/module_tests/stored_value_test.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,3 +565,10 @@ TYPED_TEST(StoredValueProtectedTest, MB_32835) {
565565

566566
EXPECT_EQ(*this->sv, *sv2);
567567
}
568+
569+
TYPED_TEST(ValueTest, MB_68655_compareSvAndItem) {
570+
auto sv2 = this->factory(this->item, {});
571+
EXPECT_TRUE(this->sv->compareSeqnoAndMetaData(this->item));
572+
this->item.setBySeqno(this->item.getBySeqno() + 1);
573+
EXPECT_FALSE(this->sv->compareSeqnoAndMetaData(this->item));
574+
}

0 commit comments

Comments
 (0)