Skip to content

Commit 496664e

Browse files
committed
MB-41989: document_pre_expiry() operates on a copy
Expiration removes the UserXattrs (if any) from the item's payload. Currently we modify the shared blob pointed by the item in the HT and CM, which is incorrect as changes may reflect on the pre-existing mutation being persisted, replicated and exposed on the frontend. Change-Id: I5fd2d3d039a4f0949f6e823592513098b457b09d Reviewed-on: http://review.couchbase.org/c/kv_engine/+/137972 Tested-by: Build Bot <[email protected]> Reviewed-by: Trond Norbye <[email protected]> Well-Formed: Build Bot <[email protected]>
1 parent 897cd88 commit 496664e

File tree

2 files changed

+18
-5
lines changed

2 files changed

+18
-5
lines changed

daemon/doc_pre_expiry.cc

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,20 @@ std::string document_pre_expiry(const item_info& itm_info) {
3030
return {};
3131
}
3232

33+
// Operate on a copy
3334
cb::char_buffer payload{static_cast<char*>(itm_info.value[0].iov_base),
3435
itm_info.value[0].iov_len};
36+
cb::xattr::Blob originalBlob(payload,
37+
mcbp::datatype::is_snappy(itm_info.datatype));
38+
auto copy = cb::xattr::Blob(originalBlob);
39+
copy.prune_user_keys();
40+
const auto final = copy.finalize();
3541

36-
cb::xattr::Blob blob(payload, mcbp::datatype::is_snappy(itm_info.datatype));
37-
blob.prune_user_keys();
38-
auto pruned = blob.finalize();
39-
if (pruned.size() == 0) {
42+
if (final.size() == 0) {
4043
// The old payload only contained user xattrs and
4144
// we removed everything
4245
return {};
4346
}
4447

45-
return {pruned.data(), pruned.size()};
48+
return {final.data(), final.size()};
4649
}

engines/ep/tests/module_tests/dcp_stream_test.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3334,6 +3334,16 @@ void SingleThreadedActiveStreamTest::testExpirationRemovesBody(uint32_t flags,
33343334
GetValue gv = store->get(docKey, vbid, nullptr, get_options_t::NONE);
33353335
EXPECT_EQ(ENGINE_KEY_ENOENT, gv.getStatus());
33363336

3337+
// MB-41989: Expiration removes UserXattrs (if any), but it must do that on
3338+
// a copy of the payload that is then enqueued in the new expired item. So,
3339+
// the payload of the original mutation must be untouched here.
3340+
// Note: 'it' still points to the original mutation in the first checkpoint
3341+
// in CM.
3342+
EXPECT_EQ(queue_op::mutation, (*it)->getOperation());
3343+
EXPECT_FALSE((*it)->isDeleted());
3344+
EXPECT_EQ(cb::const_char_buffer(value.c_str(), value.size()),
3345+
cb::const_char_buffer((*it)->getData(), (*it)->getNBytes()));
3346+
33373347
ASSERT_EQ(2, list.size());
33383348
ckpt = list.back().get();
33393349
ASSERT_EQ(checkpoint_state::CHECKPOINT_OPEN, ckpt->getState());

0 commit comments

Comments
 (0)