Skip to content

Commit 9dd333f

Browse files
committed
MB-34367 [SR]: Clear engineSpecific on non-success IO complete
For SyncWrites, ep-engine returns EWOULDBLOCK once the prepare has been accepted, in the golden path blocking the connection until the SyncWrite completes at which point notify_io_complete is called with ENGINE_SUCCESS. This results in memcached re-calling the same method again, which now returns success (as ep-engine records the fact a SyncWrite is in progrss via storeEngineSpecific(). If a SyncWrite is aborted then the notify_io_complete() is passed status:ambiguous; which memcached immediately returns to the client. However, in the non-success case the previous engineSpecific is *not* cleared. As a consequence the _next_ SyncWrite call by the same client will immediately return success. Fix by clearing the engineSpecific on a non-success status code for notify_IO_complete. Change-Id: Ie55f23d44e807e01dc16a861724c12cfeb6fe660 Reviewed-on: http://review.couchbase.org/109912 Tested-by: Build Bot <[email protected]> Reviewed-by: Jim Walker <[email protected]> Reviewed-by: Trond Norbye <[email protected]>
1 parent e696593 commit 9dd333f

File tree

2 files changed

+48
-0
lines changed

2 files changed

+48
-0
lines changed

engines/ep/src/kv_bucket.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2506,6 +2506,13 @@ uint16_t KVBucket::getNumOfVBucketsInState(vbucket_state_t state) const {
25062506
SyncWriteCompleteCallback KVBucket::makeSyncWriteCompleteCB() {
25072507
auto& engine = this->engine;
25082508
return [&engine](const void* cookie, ENGINE_ERROR_CODE status) {
2509+
if (status != ENGINE_SUCCESS) {
2510+
// For non-success status codes clear the cookie's engine_specific;
2511+
// as the operation is now complete. This ensures that any
2512+
// subsequent call by the same cookie to store() is treated as a new
2513+
// operation (and not the completion of the previous one).
2514+
engine.storeEngineSpecific(cookie, nullptr);
2515+
}
25092516
engine.notifyIOComplete(cookie, status);
25102517
};
25112518
}

engines/ep/tests/module_tests/evp_store_durability_test.cc

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,47 @@ TEST_P(DurabilityBucketTest, TakeoverSendsDurabilityAmbiguous) {
790790
EXPECT_EQ(ENGINE_SYNC_WRITE_AMBIGUOUS, mockCookie->status);
791791
}
792792

793+
// Test that if a SyncWrite times out, then a subsequent SyncWrite which
794+
// _should_ fail does indeed fail.
795+
// (Regression test for part of MB-34367 - after using notify_IO_complete
796+
// to report the SyncWrite was timed out with status eambiguous, the outstanding
797+
// cookie context was not correctly cleared.
798+
TEST_P(DurabilityBucketTest, MutationAfterTimeoutCorrect) {
799+
setVBucketStateAndRunPersistTask(
800+
vbid,
801+
vbucket_state_active,
802+
{{"topology", nlohmann::json::array({{"active", "replica"}})}});
803+
804+
// Setup: make pending item and store it; then abort it (at VBucket) level.
805+
auto key = makeStoredDocKey("key");
806+
auto pending = makePendingItem(key, "value");
807+
uint64_t cas;
808+
ASSERT_EQ(ENGINE_EWOULDBLOCK,
809+
engine->store(cookie,
810+
pending.get(),
811+
cas,
812+
OPERATION_SET,
813+
pending->getDurabilityReqs(),
814+
DocumentState::Alive));
815+
ASSERT_TRUE(engine->getEngineSpecific(cookie))
816+
<< "Expected engine specific to be set for cookie after "
817+
"EWOULDBLOCK";
818+
819+
auto& vb = *store->getVBucket(vbid);
820+
ASSERT_EQ(ENGINE_SUCCESS,
821+
vb.abort(key, {}, vb.lockCollections(key), cookie));
822+
823+
// Test: Attempt another SyncWrite, which _should_ fail (in this case just
824+
// use replace against the same non-existent key).
825+
ASSERT_EQ(ENGINE_KEY_ENOENT,
826+
engine->store(cookie,
827+
pending.get(),
828+
cas,
829+
OPERATION_REPLACE,
830+
pending->getDurabilityReqs(),
831+
DocumentState::Alive));
832+
}
833+
793834
// Test cases which run against all persistent storage backends.
794835
INSTANTIATE_TEST_CASE_P(
795836
AllBackends,

0 commit comments

Comments
 (0)