summaryrefslogtreecommitdiff
path: root/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp
diff options
context:
space:
mode:
authorEric Milkie <milkie@10gen.com>2017-04-03 09:24:24 -0400
committerEric Milkie <milkie@10gen.com>2017-04-04 13:32:46 -0400
commit052345f6c592b1b5e626e05ed8c59e9b20b6d7ee (patch)
tree652a4bb97ddd3da23726c1d85c3696cf59f3ea7d /src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp
parent6b4a0c3395a541543b8fd5abd9c853fd04b8e80f (diff)
downloadmongo-052345f6c592b1b5e626e05ed8c59e9b20b6d7ee.tar.gz
SERVER-28546 confirm WiredTiger unindex operations remove the correct document
Previously, unindex operations on WiredTiger would not confirm the record id matches. This could result in erroroneous entries being removed from the index, for the case where an index with a unique constraint also had a partial filter expression.
Diffstat (limited to 'src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp')
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp42
1 files changed, 32 insertions, 10 deletions
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp
index 05bafb50c96..f9bdfb21c60 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp
@@ -1004,7 +1004,7 @@ public:
WiredTigerIndexUnique::WiredTigerIndexUnique(OperationContext* ctx,
const std::string& uri,
const IndexDescriptor* desc)
- : WiredTigerIndex(ctx, uri, desc) {}
+ : WiredTigerIndex(ctx, uri, desc), _partial(desc->isPartial()) {}
std::unique_ptr<SortedDataInterface::Cursor> WiredTigerIndexUnique::newCursor(
OperationContext* opCtx, bool forward) const {
@@ -1088,8 +1088,37 @@ void WiredTigerIndexUnique::_unindex(WT_CURSOR* c,
WiredTigerItem keyItem(data.getBuffer(), data.getSize());
c->set_key(c, keyItem.Get());
+ auto triggerWriteConflictAtPoint = [&keyItem](WT_CURSOR* point) {
+ // WT_NOTFOUND may occur during a background index build. Insert a dummy value and
+ // delete it again to trigger a write conflict in case this is being concurrently
+ // indexed by the background indexer.
+ point->set_key(point, keyItem.Get());
+ point->set_value(point, emptyItem.Get());
+ invariantWTOK(WT_OP_CHECK(point->insert(point)));
+ point->set_key(point, keyItem.Get());
+ invariantWTOK(WT_OP_CHECK(point->remove(point)));
+ };
+
if (!dupsAllowed) {
- // nice and clear
+ if (_partial) {
+ // Check that the record id matches. We may be called to unindex records that are not
+ // present in the index due to the partial filter expression.
+ int ret = WT_READ_CHECK(c->search(c));
+ if (ret == WT_NOTFOUND) {
+ triggerWriteConflictAtPoint(c);
+ return;
+ }
+ WT_ITEM value;
+ invariantWTOK(c->get_value(c, &value));
+ BufReader br(value.data, value.size);
+ fassert(40416, br.remaining());
+ if (KeyString::decodeRecordId(&br) != id) {
+ return;
+ }
+ // Ensure there aren't any other values in here.
+ KeyString::TypeBits::fromBuffer(keyStringVersion(), &br);
+ fassert(40417, !br.remaining());
+ }
int ret = WT_OP_CHECK(c->remove(c));
if (ret == WT_NOTFOUND) {
return;
@@ -1102,14 +1131,7 @@ void WiredTigerIndexUnique::_unindex(WT_CURSOR* c,
int ret = WT_READ_CHECK(c->search(c));
if (ret == WT_NOTFOUND) {
- // WT_NOTFOUND is only expected during a background index build. Insert a dummy value and
- // delete it again to trigger a write conflict in case this is being concurrently indexed by
- // the background indexer.
- c->set_key(c, keyItem.Get());
- c->set_value(c, emptyItem.Get());
- invariantWTOK(WT_OP_CHECK(c->insert(c)));
- c->set_key(c, keyItem.Get());
- invariantWTOK(WT_OP_CHECK(c->remove(c)));
+ triggerWriteConflictAtPoint(c);
return;
}
invariantWTOK(ret);