++numTotalItems;
++datatypeCounts[v->getDatatype()];
}
+ if (v->isDeleted()) {
+ ++numDeletedItems;
+ }
values[hbl.getBucketNum()] = std::move(v);
return values[hbl.getBucketNum()].get();
void HashTable::unlocked_softDelete(const std::unique_lock<std::mutex>& htLock,
StoredValue& v,
bool onlyMarkDeleted) {
+ const bool alreadyDeleted = v.isDeleted();
if (!v.isResident() && !v.isDeleted() && !v.isTempItem()) {
decrNumNonResidentItems();
}
}
v.del(*this);
}
- ++numDeletedItems;
+ if (!alreadyDeleted) {
+ ++numDeletedItems;
+ }
}
StoredValue* HashTable::unlocked_find(const DocKey& key,
}
void StoredValue::deleteImpl(HashTable& ht) {
- if (isDeleted()) {
+ if (isDeleted() && !getValue()) {
+ // SV is already marked as deleted and has no value - no further
+ // deletion possible.
return;
}
reduceCacheSize(ht, valuelen());
- resetValue();
+ markNotResident();
+ // item no longer resident once value is reset
+ deleted = true;
markDirty();
}
}
/**
- * Reset the value of this item.
- */
- void resetValue() {
- if (isDeleted()) {
- throw std::logic_error("StoredValue::resetValue: Not possible to "
- "reset the value of a deleted item");
- }
- markNotResident();
- // item no longer resident once reset the value
- deleted = true;
- }
-
- /**
* Eject an item value from memory.
* @param ht the hashtable that contains this StoredValue instance
*/
virtual KVShard* getShard() = 0;
+ /**
+ * Returns the number of alive (non-deleted) Items the VBucket.
+ *
+ * Includes items which are not currently resident in memory (i.e. under
+ * Full eviction and have been fully evicted from memory).
+ * Does *not* include deleted items.
+ */
virtual size_t getNumItems() const = 0;
size_t getNumNonResidentItems() const;
EXPECT_TRUE(storedVal->isDeleted());
}
+
+// Verify that we can pageOut deleted items which have a value associated with
+// them - and afterwards the value is null.
+TEST_F(EphemeralVBucketTest, PageOutAfterDeleteWithValue) {
+ // Add an item which is marked as deleted, but has a body (e.g. system
+ // XATTR).
+ auto key = makeStoredDocKey("key");
+ std::string value = "deleted value";
+ Item item(key, 0, /*expiry*/0, value.data(), value.size());
+ item.setDeleted();
+ ASSERT_EQ(AddStatus::Success, public_processAdd(item));
+ ASSERT_EQ(0, vbucket->getNumItems());
+
+ // Check preconditions
+ auto lock_sv = lockAndFind(key);
+ auto* storedVal = lock_sv.second;
+ ASSERT_TRUE(storedVal->isDeleted());
+ ASSERT_EQ(value, storedVal->getValue()->to_s());
+
+ // Page it out.
+ EXPECT_TRUE(vbucket->pageOut(lock_sv.first, storedVal));
+ EXPECT_EQ(0, vbucket->getNumItems());
+ EXPECT_TRUE(storedVal->isDeleted());
+ EXPECT_FALSE(storedVal->getValue());
+}
+
TEST_F(EphemeralVBucketTest, SetItems) {
const int numItems = 3;