Skip to content

Commit 7559f21

Browse files
jameseh96daverigby
authored andcommitted
MB-35979: Ensure SyncReplaces check for committed values
A SyncReplace should only succeed if there is a committed value which is not expired or deleted. This patch fixes a bug affecting ephemeral buckets allowing SyncReplaces even if there is no committed value in the presence of a completed prepare. Replace previously only tested the state of the passed stored value - this is insufficient as the passed value may be a completed prepare, which does not provide information on whether a _committed_ value exists. Change-Id: I219071b95b93d0f7abcc3b73a1d101f523ad04ed Reviewed-on: http://review.couchbase.org/114826 Tested-by: Build Bot <[email protected]> Reviewed-by: Dave Rigby <[email protected]>
1 parent 59b5eab commit 7559f21

File tree

2 files changed

+72
-1
lines changed

2 files changed

+72
-1
lines changed

engines/ep/src/vbucket.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1657,7 +1657,8 @@ ENGINE_ERROR_CODE VBucket::replace(
16571657
}
16581658

16591659
if (htRes.committed) {
1660-
if (isLogicallyNonExistent(*htRes.committed, cHandle)) {
1660+
if (isLogicallyNonExistent(*htRes.committed, cHandle) ||
1661+
htRes.committed->isExpired(ep_real_time())) {
16611662
ht.cleanupIfTemporaryItem(hbl, *htRes.committed);
16621663
return ENGINE_KEY_ENOENT;
16631664
}

engines/ep/tests/module_tests/evp_store_durability_test.cc

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,76 @@ TEST_P(DurabilityBucketTest, SyncWriteComparesToCorrectCas) {
843843
ASSERT_EQ(ENGINE_SYNC_WRITE_PENDING, store->set(*pending, cookie));
844844
}
845845

846+
TEST_P(DurabilityEphemeralBucketTest, SyncReplaceChecksCorrectSVExists) {
847+
setVBucketStateAndRunPersistTask(
848+
vbid,
849+
vbucket_state_active,
850+
{{"topology", nlohmann::json::array({{"active", "replica"}})}});
851+
852+
auto& vb = *store->getVBucket(vbid);
853+
854+
// prepare SyncWrite and commit.
855+
auto key = makeStoredDocKey("key");
856+
auto pending = makePendingItem(key, "value");
857+
858+
ASSERT_EQ(ENGINE_SYNC_WRITE_PENDING, store->set(*pending, cookie));
859+
ASSERT_EQ(ENGINE_SUCCESS,
860+
vb.commit(key,
861+
pending->getBySeqno(),
862+
{} /*commitSeqno*/,
863+
vb.lockCollections(key)));
864+
865+
vb.processResolvedSyncWrites();
866+
867+
// Non-durable delete
868+
mutation_descr_t delInfo;
869+
uint64_t cas = 0;
870+
ASSERT_EQ(ENGINE_SUCCESS,
871+
store->deleteItem(key, cas, vbid, cookie, {}, nullptr, delInfo));
872+
873+
// now do a SyncReplace. Should FAIL as the item was deleted
874+
pending = makePendingItem(key, "new_value");
875+
ASSERT_EQ(ENGINE_KEY_ENOENT, store->replace(*pending, cookie));
876+
}
877+
878+
TEST_P(DurabilityEphemeralBucketTest, SyncReplaceChecksCorrectExpiry) {
879+
setVBucketStateAndRunPersistTask(
880+
vbid,
881+
vbucket_state_active,
882+
{{"topology", nlohmann::json::array({{"active", "replica"}})}});
883+
884+
auto& vb = *store->getVBucket(vbid);
885+
886+
// prepare SyncWrite and commit.
887+
auto key = makeStoredDocKey("key");
888+
auto pending = makePendingItem(key, "value");
889+
890+
ASSERT_EQ(ENGINE_SYNC_WRITE_PENDING, store->set(*pending, cookie));
891+
ASSERT_EQ(ENGINE_SUCCESS,
892+
vb.commit(key,
893+
pending->getBySeqno(),
894+
{} /*commitSeqno*/,
895+
vb.lockCollections(key)));
896+
897+
vb.processResolvedSyncWrites();
898+
899+
// Non-durable write with expiry
900+
auto committed = makeCommittedItem(key, "some_other_value");
901+
902+
using namespace std::chrono;
903+
auto expiry = system_clock::now() + seconds(1);
904+
committed->setExpTime(system_clock::to_time_t(expiry));
905+
906+
ASSERT_EQ(ENGINE_SUCCESS, store->set(*committed, cookie));
907+
908+
// time travel to when the item has definitely expired
909+
TimeTraveller abe(10);
910+
911+
// now do a SyncReplace. Should fail, as the item has expired.
912+
pending = makePendingItem(key, "new_value");
913+
ASSERT_EQ(ENGINE_KEY_ENOENT, store->replace(*pending, cookie));
914+
}
915+
846916
TEST_P(DurabilityEphemeralBucketTest, SyncWriteChecksCorrectExpiry) {
847917
setVBucketStateAndRunPersistTask(
848918
vbid,

0 commit comments

Comments
 (0)