MB-14859: Handle quick successive BG Fetch of a key interleaved with exp pager 29/64929/2
authorManu Dhundi <manu@couchbase.com>
Tue, 23 Jun 2015 20:38:28 +0000 (13:38 -0700)
committerDave Rigby <daver@couchbase.com>
Fri, 17 Jun 2016 08:19:27 +0000 (08:19 +0000)
If two bgfetch are scheduled for a non existing key, and one bgfetch completes
and marks the key as non existant in the hash table, and subsequently expiry
pager removes it from the hash table before the second bgfetch completes,
we need to handle the case appropriately in the complete bgfetch code as
notify the memcached with appropriate return value.

(cherry picked from commit f9402cb0ee6a3592413e43855b0a48b7c0202a5b)

Change-Id: I8eaf54319014ea4039c74d2cbfab21ef275939fe
Reviewed-on: http://review.couchbase.org/64929
Tested-by: buildbot <build@couchbase.com>
Reviewed-by: Manu Dhundi <manu@couchbase.com>
Well-Formed: buildbot <build@couchbase.com>

src/ep.cc

index f2c115d..11e6e8f 100644 (file)
--- a/src/ep.cc
+++ b/src/ep.cc
@@ -1442,8 +1442,15 @@ void EventuallyPersistentStore::completeBGFetch(const std::string &key,
         LockHolder hlh = vb->ht.getLockedBucket(key, &bucket_num);
         StoredValue *v = fetchValidValue(vb, key, bucket_num, true);
         if (isMeta) {
-            if (v && v->unlocked_restoreMeta(gcb.val.getValue(),
-                                             gcb.val.getStatus(), vb->ht)) {
+            if ((v && v->unlocked_restoreMeta(gcb.val.getValue(),
+                                              gcb.val.getStatus(), vb->ht))
+                || ENGINE_KEY_ENOENT == status) {
+                /* If ENGINE_KEY_ENOENT is the status from storage and the temp
+                 key is removed from hash table by the time bgfetch returns
+                 (in case multiple bgfetch is scheduled for a key), we still
+                 need to return ENGINE_SUCCESS to the memcached worker thread,
+                 so that the worker thread can visit the ep-engine and figure
+                 out the correct flow */
                 status = ENGINE_SUCCESS;
             }
         } else {
@@ -1550,7 +1557,14 @@ void EventuallyPersistentStore::completeBGFetchMulti(uint16_t vbId,
             LockHolder blh = vb->ht.getLockedBucket(key, &bucket);
             StoredValue *v = fetchValidValue(vb, key, bucket, true);
             if (bgitem->metaDataOnly) {
-                if (v && v->unlocked_restoreMeta(fetchedValue, status, vb->ht)) {
+                if ((v && v->unlocked_restoreMeta(fetchedValue, status, vb->ht))
+                    || ENGINE_KEY_ENOENT == status) {
+                    /* If ENGINE_KEY_ENOENT is the status from storage and the temp
+                     key is removed from hash table by the time bgfetch returns
+                     (in case multiple bgfetch is scheduled for a key), we still
+                     need to return ENGINE_SUCCESS to the memcached worker thread,
+                     so that the worker thread can visit the ep-engine and figure
+                     out the correct flow */
                     status = ENGINE_SUCCESS;
                 }
             } else {