const bool oldValueDeleted = v.isDeleted();
const bool recreatingDeletedItem = v.isDeleted() && !itm.isDeleted();
- /* Update the OrderedStoredValue in hash table + Ordered data structure
- (list) */
- auto res = seqList->updateListElem(lh, *(v.toOrderedStoredValue()));
-
+ SequenceList::UpdateStatus res;
+ VBNotifyCtx notifyCtx;
StoredValue* newSv = &v;
StoredValue::UniquePtr ownedSv;
MutationStatus status(MutationStatus::WasClean);
- switch (res) {
- case SequenceList::UpdateStatus::Success:
- /* OrderedStoredValue moved to end of the list, just update its
- value */
- status = ht.unlocked_updateStoredValue(hbl.getHTLock(), v, itm);
- break;
-
- case SequenceList::UpdateStatus::Append: {
- /* OrderedStoredValue cannot be moved to end of the list,
- due to a range read. Hence, release the storedvalue from the
- hash table, indicate the list to mark the OrderedStoredValue
- stale (old duplicate) and add a new StoredValue for the itm.
-
- Note: It is important to remove item from hash table before
- marking stale because once marked stale list assumes the
- ownership of the item and may delete it anytime. */
- /* Release current storedValue from hash table */
- /* [EPHE TODO]: Write a HT func to release the StoredValue directly
- than taking key as a param and deleting
- (MB-23184) */
- ownedSv = ht.unlocked_release(hbl, v.getKey());
-
- /* Add a new storedvalue for the item */
- newSv = ht.unlocked_addNewStoredValue(hbl, itm);
-
- seqList->appendToList(lh, *(newSv->toOrderedStoredValue()));
- } break;
- }
+ {
+ // Once we update the seqList, there is a short period where the
+ // highSeqno and highestDedupedSeqno are both incorrect. We have to hold
+ // this lock to prevent a new rangeRead starting, and covering an
+ // inconsistent range.
+ std::lock_guard<std::mutex> highSeqnoLh(seqList->getHighSeqnosLock());
+
+ /* Update the OrderedStoredValue in hash table + Ordered data structure
+ (list) */
+ res = seqList->updateListElem(lh, *(v.toOrderedStoredValue()));
+
+ switch (res) {
+ case SequenceList::UpdateStatus::Success:
+ /* OrderedStoredValue moved to end of the list, just update its
+ value */
+ status = ht.unlocked_updateStoredValue(hbl.getHTLock(), v, itm);
+ break;
+
+ case SequenceList::UpdateStatus::Append: {
+ /* OrderedStoredValue cannot be moved to end of the list,
+ due to a range read. Hence, release the storedvalue from the
+ hash table, indicate the list to mark the OrderedStoredValue
+ stale (old duplicate) and add a new StoredValue for the itm.
+
+ Note: It is important to remove item from hash table before
+ marking stale because once marked stale list assumes the
+ ownership of the item and may delete it anytime. */
+ /* Release current storedValue from hash table */
+ /* [EPHE TODO]: Write a HT func to release the StoredValue directly
+ than taking key as a param and deleting
+ (MB-23184) */
+ ownedSv = ht.unlocked_release(hbl, v.getKey());
+
+ /* Add a new storedvalue for the item */
+ newSv = ht.unlocked_addNewStoredValue(hbl, itm);
+
+ seqList->appendToList(lh, *(newSv->toOrderedStoredValue()));
+ } break;
+ }
- VBNotifyCtx notifyCtx;
- if (queueItmCtx) {
- /* Put on checkpoint mgr */
- notifyCtx = queueDirty(*newSv, *queueItmCtx);
+ if (queueItmCtx) {
+ /* Put on checkpoint mgr */
+ notifyCtx = queueDirty(*newSv, *queueItmCtx);
+ }
+
+ /* Update the high seqno in the sequential storage */
+ auto& osv = *(newSv->toOrderedStoredValue());
+ seqList->updateHighSeqno(highSeqnoLh, osv);
+ seqList->updateHighestDedupedSeqno(highSeqnoLh, osv);
}
- /* Update the high seqno in the sequential storage */
- seqList->updateHighSeqno(*(newSv->toOrderedStoredValue()));
if (recreatingDeletedItem) {
++opsCreate;
} else {
}
/* Update the high seqno in the sequential storage */
- seqList->updateHighSeqno(*(v->toOrderedStoredValue()));
+ std::lock_guard<std::mutex> highSeqnoLh(seqList->getHighSeqnosLock());
+ seqList->updateHighSeqno(highSeqnoLh, *(v->toOrderedStoredValue()));
++opsCreate;
seqList->updateNumDeletedItems(false, itm.isDeleted());
const bool oldValueDeleted = v.isDeleted();
- /* Update the OrderedStoredValue in hash table + Ordered data structure
- (list) */
- auto res = seqList->updateListElem(lh, *(v.toOrderedStoredValue()));
-
- switch (res) {
- case SequenceList::UpdateStatus::Success:
- /* OrderedStoredValue is moved to end of the list, do nothing */
- break;
-
- case SequenceList::UpdateStatus::Append: {
- /* OrderedStoredValue cannot be moved to end of the list,
- due to a range read. Hence, replace the storedvalue in the
- hash table with its copy and indicate the list to mark the
- OrderedStoredValue stale (old duplicate).
-
- Note: It is important to remove item from hash table before
- marking stale because once marked stale list assumes the
- ownership of the item and may delete it anytime. */
+ SequenceList::UpdateStatus res;
+ VBNotifyCtx notifyCtx;
+ {
+ // Once we update the seqList, there is a short period where the
+ // highSeqno and highestDedupedSeqno are both incorrect. We have to hold
+ // this lock to prevent a new rangeRead starting, and covering an
+ // inconsistent range.
+ std::lock_guard<std::mutex> highSeqnoLh(seqList->getHighSeqnosLock());
+
+ /* Update the OrderedStoredValue in hash table + Ordered data structure
+ (list) */
+ res = seqList->updateListElem(lh, *(v.toOrderedStoredValue()));
+
+ switch (res) {
+ case SequenceList::UpdateStatus::Success:
+ /* OrderedStoredValue is moved to end of the list, do nothing */
+ break;
+
+ case SequenceList::UpdateStatus::Append: {
+ /* OrderedStoredValue cannot be moved to end of the list,
+ due to a range read. Hence, replace the storedvalue in the
+ hash table with its copy and indicate the list to mark the
+ OrderedStoredValue stale (old duplicate).
+
+ Note: It is important to remove item from hash table before
+ marking stale because once marked stale list assumes the
+ ownership of the item and may delete it anytime. */
+
+ /* Release current storedValue from hash table */
+ /* [EPHE TODO]: Write a HT func to replace the StoredValue directly
+ than taking key as a param and deleting (MB-23184)
+ */
+ std::tie(newSv, ownedSv) = ht.unlocked_replaceByCopy(hbl, v);
+
+ seqList->appendToList(lh, *(newSv->toOrderedStoredValue()));
+ } break;
+ }
- /* Release current storedValue from hash table */
- /* [EPHE TODO]: Write a HT func to replace the StoredValue directly
- than taking key as a param and deleting (MB-23184) */
- std::tie(newSv, ownedSv) = ht.unlocked_replaceByCopy(hbl, v);
+ /* Delete the storedvalue */
+ ht.unlocked_softDelete(hbl.getHTLock(), *newSv, onlyMarkDeleted);
- seqList->appendToList(lh, *(newSv->toOrderedStoredValue()));
- } break;
- }
+ if (queueItmCtx.genBySeqno == GenerateBySeqno::No) {
+ newSv->setBySeqno(bySeqno);
+ }
- /* Delete the storedvalue */
- ht.unlocked_softDelete(hbl.getHTLock(), *newSv, onlyMarkDeleted);
+ notifyCtx = queueDirty(*newSv, queueItmCtx);
- if (queueItmCtx.genBySeqno == GenerateBySeqno::No) {
- newSv->setBySeqno(bySeqno);
+ /* Update the high seqno in the sequential storage */
+ auto& osv = *(newSv->toOrderedStoredValue());
+ seqList->updateHighSeqno(highSeqnoLh, osv);
+ seqList->updateHighestDedupedSeqno(highSeqnoLh, osv);
}
- VBNotifyCtx notifyCtx = queueDirty(*newSv, queueItmCtx);
-
- /* Update the high seqno in the sequential storage */
- seqList->updateHighSeqno(*(newSv->toOrderedStoredValue()));
++opsDelete;
seqList->updateNumDeletedItems(oldValueDeleted, true);
auto secondDelTime = delOSV->getDeletedTime();
EXPECT_GE(secondDelTime, initialDelTime + timeJump);
}
+
+TEST_F(EphemeralVBucketTest, UpdateUpdatesHighestDedupedSeqno) {
+ /* Add 3 items and then update all of them */
+ const int numItems = 3;
+
+ auto keys = generateKeys(numItems);
+ setMany(keys, MutationStatus::WasClean);
+
+ ASSERT_EQ(0, mockEpheVB->getLL()->getHighestDedupedSeqno());
+
+ /* Update the items */
+ setMany(keys, MutationStatus::WasDirty);
+
+ EXPECT_EQ(6, mockEpheVB->getLL()->getHighestDedupedSeqno());
+}
+
+TEST_F(EphemeralVBucketTest, AppendUpdatesHighestDedupedSeqno) {
+ /* Add 3 items and then update all of them */
+ const int numItems = 3;
+
+ auto keys = generateKeys(numItems);
+ setMany(keys, MutationStatus::WasClean);
+
+ ASSERT_EQ(0, mockEpheVB->getLL()->getHighestDedupedSeqno());
+
+ /* Set up a mock backfill by setting the range of the backfill */
+ mockEpheVB->registerFakeReadRange(1, numItems);
+
+ /* Update the items */
+ setMany(keys, MutationStatus::WasClean);
+
+ mockEpheVB->resetReadRange();
+
+ // TODO: expect 0 once the purger handles updating the HDDS
+ // Updating the HDDS at append time is only a temporary measure - this will
+ // be changed to having the tombstone purger update the HDDS shortly. Once
+ // that is done, we would expect HDDS == 0 at this point, and HDDS == 6 only
+ // after the purger runs.
+
+ EXPECT_EQ(6, mockEpheVB->getLL()->getHighestDedupedSeqno());
+
+ EXPECT_EQ(3, mockEpheVB->purgeTombstones(0));
+
+ EXPECT_EQ(6, mockEpheVB->getLL()->getHighestDedupedSeqno());
+}
\ No newline at end of file