diff options
author | Eric Milkie <milkie@10gen.com> | 2017-04-03 09:24:24 -0400 |
---|---|---|
committer | Eric Milkie <milkie@10gen.com> | 2017-04-04 13:32:46 -0400 |
commit | 052345f6c592b1b5e626e05ed8c59e9b20b6d7ee (patch) | |
tree | 652a4bb97ddd3da23726c1d85c3696cf59f3ea7d /src/mongo/db/storage | |
parent | 6b4a0c3395a541543b8fd5abd9c853fd04b8e80f (diff) | |
download | mongo-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')
-rw-r--r-- | src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp | 42 | ||||
-rw-r--r-- | src/mongo/db/storage/wiredtiger/wiredtiger_index.h | 3 |
2 files changed, 35 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); diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_index.h b/src/mongo/db/storage/wiredtiger/wiredtiger_index.h index 20485fa8f9d..78d8e788b07 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_index.h +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_index.h @@ -174,6 +174,9 @@ public: Status _insert(WT_CURSOR* c, const BSONObj& key, const RecordId& id, bool dupsAllowed) override; void _unindex(WT_CURSOR* c, const BSONObj& key, const RecordId& id, bool dupsAllowed) override; + +private: + bool _partial; }; class WiredTigerIndexStandard : public WiredTigerIndex { |