Skip to content

Commit 07cbd65

Browse files
BenHuddlestondaverigby
authored andcommitted
MB-35631: Read vbstate from disk in initScanContext
We should not read the vbucket state from cache when creating a ScanContext as the cached value may be ahead. Change-Id: Ia991218251cbeff6aa5c47c17af5ea2176e68b45 Reviewed-on: http://review.couchbase.org/113698 Reviewed-by: Dave Rigby <[email protected]> Tested-by: Build Bot <[email protected]>
1 parent 3d63468 commit 07cbd65

File tree

3 files changed

+83
-57
lines changed

3 files changed

+83
-57
lines changed

engines/ep/src/couch-kvstore/couch-kvstore.cc

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ void CouchKVStore::initialize() {
382382
DbHolder db(*this);
383383
errorCode = openDB(id, db, COUCHSTORE_OPEN_FLAG_RDONLY);
384384
if (errorCode == COUCHSTORE_SUCCESS) {
385-
auto readStatus = readVBState(db, id);
385+
auto readStatus = readVBStateAndUpdateCache(db, id).status;
386386
if (readStatus == ReadVBStateStatus::Success) {
387387
/* update stat */
388388
++st.numLoadedVb;
@@ -1457,17 +1457,12 @@ ScanContext* CouchKVStore::initScanContext(
14571457
return NULL;
14581458
}
14591459

1460-
auto* vbState = getVBucketState(vbid);
1461-
if (!vbState) {
1462-
if (readVBState(db, vbid) == CouchKVStore::ReadVBStateStatus::Success) {
1463-
vbState = getVBucketState(vbid);
1464-
}
1465-
if (!vbState) {
1466-
EP_LOG_WARN(
1467-
"CouchKVStore::initScanContext:Failed to obtain vbState for"
1468-
"the highCompletedSeqno");
1469-
return NULL;
1470-
}
1460+
auto readVbStateResult = readVBState(db, vbid);
1461+
if (readVbStateResult.status != ReadVBStateStatus::Success) {
1462+
EP_LOG_WARN(
1463+
"CouchKVStore::initScanContext:Failed to obtain vbState for"
1464+
"the highCompletedSeqno");
1465+
return NULL;
14711466
}
14721467

14731468
size_t scanId = scanCounter++;
@@ -1479,19 +1474,20 @@ ScanContext* CouchKVStore::initScanContext(
14791474
scans[scanId] = db.releaseDb();
14801475
}
14811476

1482-
ScanContext* sctx = new ScanContext(cb,
1483-
cl,
1484-
vbid,
1485-
scanId,
1486-
startSeqno,
1487-
info.last_sequence,
1488-
info.purge_seq,
1489-
options,
1490-
valOptions,
1491-
count,
1492-
vbState->highCompletedSeqno,
1493-
configuration,
1494-
collectionsManifest);
1477+
ScanContext* sctx =
1478+
new ScanContext(cb,
1479+
cl,
1480+
vbid,
1481+
scanId,
1482+
startSeqno,
1483+
info.last_sequence,
1484+
info.purge_seq,
1485+
options,
1486+
valOptions,
1487+
count,
1488+
readVbStateResult.state.highCompletedSeqno,
1489+
configuration,
1490+
collectionsManifest);
14951491
sctx->logger = &logger;
14961492
return sctx;
14971493
}
@@ -2358,7 +2354,7 @@ CouchKVStore::processVbstateSnapshot(Vbid vb,
23582354
return {status, snapStart, snapEnd};
23592355
}
23602356

2361-
CouchKVStore::ReadVBStateStatus CouchKVStore::readVBState(Db* db, Vbid vbId) {
2357+
CouchKVStore::ReadVBStateResult CouchKVStore::readVBState(Db* db, Vbid vbId) {
23622358
sized_buf id;
23632359
LocalDoc *ldoc = NULL;
23642360
ReadVBStateStatus status = ReadVBStateStatus::Success;
@@ -2378,7 +2374,7 @@ CouchKVStore::ReadVBStateStatus CouchKVStore::readVBState(Db* db, Vbid vbId) {
23782374
", {}",
23792375
couchstore_strerror(couchStoreStatus),
23802376
vbId);
2381-
return ReadVBStateStatus::CouchstoreError;
2377+
return {ReadVBStateStatus::CouchstoreError, {}};
23822378
}
23832379

23842380
vbucket_state vbState;
@@ -2399,7 +2395,7 @@ CouchKVStore::ReadVBStateStatus CouchKVStore::readVBState(Db* db, Vbid vbId) {
23992395
" error:{}, {}",
24002396
couchstore_strerror(couchStoreStatus),
24012397
vbId);
2402-
return ReadVBStateStatus::CouchstoreError;
2398+
return {ReadVBStateStatus::CouchstoreError, {}};
24032399
}
24042400

24052401
// Proceed to read/parse the vbstate if success
@@ -2418,7 +2414,7 @@ CouchKVStore::ReadVBStateStatus CouchKVStore::readVBState(Db* db, Vbid vbId) {
24182414
vbId,
24192415
statjson,
24202416
e.what());
2421-
return ReadVBStateStatus::JsonInvalid;
2417+
return {ReadVBStateStatus::JsonInvalid, {}};
24222418
}
24232419

24242420
// Merge in the high_seqno & purge_seqno read previously from db info.
@@ -2437,7 +2433,7 @@ CouchKVStore::ReadVBStateStatus CouchKVStore::readVBState(Db* db, Vbid vbId) {
24372433
vbId,
24382434
json.dump(),
24392435
e.what());
2440-
return ReadVBStateStatus::JsonInvalid;
2436+
return {ReadVBStateStatus::JsonInvalid, {}};
24412437
}
24422438

24432439
// MB-17517: If the maxCas on disk was invalid then don't use it -
@@ -2465,12 +2461,18 @@ CouchKVStore::ReadVBStateStatus CouchKVStore::readVBState(Db* db, Vbid vbId) {
24652461
couchstore_free_local_document(ldoc);
24662462
}
24672463

2468-
if (status == ReadVBStateStatus::Success) {
2464+
return {status, vbState};
2465+
}
2466+
2467+
CouchKVStore::ReadVBStateResult CouchKVStore::readVBStateAndUpdateCache(
2468+
Db* db, Vbid vbid) {
2469+
auto res = readVBState(db, vbid);
2470+
if (res.status == ReadVBStateStatus::Success) {
24692471
// Cannot use make_unique here as it doesn't support
24702472
// brace-initialization until C++20.
2471-
cachedVBStates[vbId.get()].reset(new vbucket_state(vbState));
2473+
cachedVBStates[vbid.get()].reset(new vbucket_state(res.state));
24722474
}
2473-
return status;
2475+
return res;
24742476
}
24752477

24762478
couchstore_error_t CouchKVStore::saveVBState(Db *db,
@@ -2876,7 +2878,8 @@ RollbackResult CouchKVStore::rollback(Vbid vbid,
28762878
return RollbackResult(false);
28772879
}
28782880

2879-
if (readVBState(newdb, vbid) != ReadVBStateStatus::Success) {
2881+
if (readVBStateAndUpdateCache(newdb, vbid).status !=
2882+
ReadVBStateStatus::Success) {
28802883
return RollbackResult(false);
28812884
}
28822885
cachedDeleteCount[vbid.get()] = info.deleted_count;

engines/ep/src/couch-kvstore/couch-kvstore.h

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@
2929
#include <platform/strerror.h>
3030
#include <relaxed_atomic.h>
3131

32+
#include <engines/ep/src/vbucket_state.h>
3233
#include <map>
3334
#include <memory>
3435
#include <string>
3536
#include <vector>
3637

37-
3838
#define COUCHSTORE_NO_OPTIONS 0
3939

4040
class EventuallyPersistentEngine;
@@ -341,27 +341,6 @@ class CouchKVStore : public KVStore
341341
static int recordDbStat(Db *db, DocInfo *docinfo, void *ctx);
342342
static int getMultiCb(Db *db, DocInfo *docinfo, void *ctx);
343343

344-
enum class ReadVBStateStatus {
345-
Success,
346-
JsonInvalid,
347-
CorruptSnapshot,
348-
CouchstoreError
349-
};
350-
351-
ReadVBStateStatus readVBState(Db* db, Vbid vbId);
352-
353-
/**
354-
* Process the vbstate snapshot strings which are stored in the vbstate
355-
* document. Check for validity and return a status + decoded snapshot.
356-
*/
357-
std::tuple<ReadVBStateStatus, uint64_t, uint64_t> processVbstateSnapshot(
358-
Vbid vb,
359-
vbucket_state_t state,
360-
int64_t version,
361-
uint64_t snapStart,
362-
uint64_t snapEnd,
363-
uint64_t highSeqno);
364-
365344
couchstore_error_t fetchDoc(Db* db,
366345
DocInfo* docinfo,
367346
GetValue& docValue,
@@ -757,6 +736,45 @@ class CouchKVStore : public KVStore
757736
/// Copy relevant DbInfo stats to the common FileStats struct
758737
static FileInfo toFileInfo(const DbInfo& info);
759738

739+
enum class ReadVBStateStatus {
740+
Success,
741+
JsonInvalid,
742+
CorruptSnapshot,
743+
CouchstoreError
744+
};
745+
746+
/**
747+
* Result of the readVBState function
748+
*/
749+
struct ReadVBStateResult {
750+
ReadVBStateStatus status;
751+
752+
// Only valid if status == ReadVBStateStatus::Success
753+
vbucket_state state;
754+
};
755+
756+
/**
757+
* Process the vbstate snapshot strings which are stored in the vbstate
758+
* document. Check for validity and return a status + decoded snapshot.
759+
*/
760+
std::tuple<ReadVBStateStatus, uint64_t, uint64_t> processVbstateSnapshot(
761+
Vbid vb,
762+
vbucket_state_t state,
763+
int64_t version,
764+
uint64_t snapStart,
765+
uint64_t snapEnd,
766+
uint64_t highSeqno);
767+
768+
/**
769+
* Read the vbucket_state from disk.
770+
*/
771+
ReadVBStateResult readVBState(Db* db, Vbid vbid);
772+
773+
/**
774+
* Read the vbucket_state from disk and update the cache if successful
775+
*/
776+
ReadVBStateResult readVBStateAndUpdateCache(Db* db, Vbid vbid);
777+
760778
const std::string dbname;
761779

762780
using MonotonicRevision = AtomicMonotonic<uint64_t, ThrowExceptionPolicy>;

engines/ep/tests/module_tests/kvstore_test.cc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1137,8 +1137,13 @@ TEST_F(CouchKVStoreErrorInjectionTest, readVBState_open_local_document) {
11371137
.RetiresOnSaturation();
11381138

11391139
/* Establish FileOps expectation */
1140+
// Called twice, once when we read the vbstate from disk in
1141+
// initScanContext, and again when we read the vbstate as part of
1142+
// rollback.
11401143
EXPECT_CALL(ops, pread(_, _, _, _, _))
1141-
.WillOnce(Return(COUCHSTORE_ERROR_READ)).RetiresOnSaturation();
1144+
.Times(2)
1145+
.WillRepeatedly(Return(COUCHSTORE_ERROR_READ))
1146+
.RetiresOnSaturation();
11421147
EXPECT_CALL(ops, pread(_, _, _, _, _)).Times(20).RetiresOnSaturation();
11431148

11441149
kvstore->rollback(Vbid(0), 5, rcb);

0 commit comments

Comments
 (0)