const VBQueueItemCtx* queueItmCtx) {
std::lock_guard<std::mutex> lh(sequenceLock);
- const bool recreatingDeletedItem = v.isDeleted();
+ const bool oldValueDeleted = v.isDeleted();
+ const bool recreatingDeletedItem = v.isDeleted() && !itm.isDeleted();
/* Update the OrderedStoredValue in hash table + Ordered data structure
(list) */
++opsUpdate;
}
+ seqList->updateNumDeletedItems(oldValueDeleted, itm.isDeleted());
+
if (res == SequenceList::UpdateStatus::Append) {
/* Mark the un-updated storedValue as stale. This must be done after
the new storedvalue for the item is visible for range read in the
seqList->updateHighSeqno(*(v->toOrderedStoredValue()));
++opsCreate;
+ seqList->updateNumDeletedItems(false, itm.isDeleted());
+
return {v, notifyCtx};
}
StoredValue* newSv = &v;
StoredValue::UniquePtr ownedSv;
+ const bool oldValueDeleted = v.isDeleted();
+
/* Update the OrderedStoredValue in hash table + Ordered data structure
(list) */
auto res = seqList->updateListElem(lh, *(v.toOrderedStoredValue()));
seqList->updateHighSeqno(*(newSv->toOrderedStoredValue()));
++opsDelete;
+ seqList->updateNumDeletedItems(oldValueDeleted, true);
+
if (res == SequenceList::UpdateStatus::Append) {
/* Mark the un-updated storedValue as stale. This must be done after
the new storedvalue for the item is visible for range read in the
void BasicLinkedList::updateHighSeqno(const OrderedStoredValue& v) {
std::lock_guard<SpinLock> lh(rangeLock);
highSeqno = v.getBySeqno();
- if (v.isDeleted()) {
- ++numDeletedItems;
- }
}
void BasicLinkedList::markItemStale(StoredValue::UniquePtr ownedSv) {
return purgedCount;
}
+void BasicLinkedList::updateNumDeletedItems(bool oldDeleted, bool newDeleted) {
+ if (oldDeleted && !newDeleted) {
+ --numDeletedItems;
+ } else if (!oldDeleted && newDeleted) {
+ ++numDeletedItems;
+ }
+}
+
uint64_t BasicLinkedList::getNumStaleItems() const {
return numStaleItems;
}
size_t purgeTombstones() override;
+ void updateNumDeletedItems(bool oldDeleted, bool newDeleted) override;
+
uint64_t getNumStaleItems() const override;
size_t getStaleValueBytes() const override;
* Updates the highSeqno in the list. Since seqno is generated and managed
* outside the list, the module managing it must update this after the seqno
* is generated for the item already put in the list.
- * If the last OrderedStoredValue added to the list is soft deleted then
- * it also updates the deleted items count in the list
*
* @param v Ref to orderedStoredValue
*/
virtual size_t purgeTombstones() = 0;
/**
+ * Updates the number of deleted items in the sequence list whenever
+ * an item is modified.
+ *
+ * @param oldDeleted Was the old item deleted?
+ * @param newDeleted Was the new item replacing it deleted?
+ */
+ virtual void updateNumDeletedItems(bool oldDeleted, bool newDeleted) = 0;
+
+ /**
* Returns the number of stale items in the list.
*
* @return count of stale items
/* Delete the item */
softDeleteItem(numItems, keyPrefix + std::to_string(numItems));
+ basicLL->updateNumDeletedItems(false, true);
/* Check if the delete is added correctly */
std::vector<seqno_t> expectedSeqno = {numItems + 1};
EXPECT_FALSE(storedVal->getValue());
}
+// NRU: check the seqlist has correct statistics for a create, pageout,
+// and (re)create of the same key.
+TEST_F(EphemeralVBucketTest, CreatePageoutCreate) {
+ auto key = makeStoredDocKey("key");
+
+ // Add a key, then page out.
+ ASSERT_EQ(AddStatus::Success, addOne(key));
+ {
+ auto lock_sv = lockAndFind(key);
+ EXPECT_TRUE(vbucket->pageOut(lock_sv.first, lock_sv.second));
+ }
+ // Sanity check - should have just the one deleted item.
+ ASSERT_EQ(0, vbucket->getNumItems());
+ ASSERT_EQ(1, mockEpheVB->getLL()->getNumDeletedItems());
+
+ // Test: Set the key again.
+ ASSERT_EQ(MutationStatus::WasDirty, setOne(key));
+
+ EXPECT_EQ(1, vbucket->getNumItems());
+ EXPECT_EQ(0, mockEpheVB->getLL()->getNumDeletedItems());
+
+ // Finally for good measure, delete again and check the numbers are correct.
+ {
+ auto lock_sv = lockAndFind(key);
+ EXPECT_TRUE(vbucket->pageOut(lock_sv.first, lock_sv.second));
+ }
+ EXPECT_EQ(0, vbucket->getNumItems());
+ EXPECT_EQ(1, mockEpheVB->getLL()->getNumDeletedItems());
+}
+
TEST_F(EphemeralVBucketTest, SetItems) {
const int numItems = 3;