From 5b5502a6947d12356b1fd3e44ad07e4f2453be41 Mon Sep 17 00:00:00 2001 From: Dewal Gupta Date: Mon, 23 Jul 2018 17:46:33 -0400 Subject: SERVER-36005 Prevent unsafe IndexCatalogEntryImpl::_catalogIsReady call (cherry picked from commit dfdffb7e4588d41c99e625ade8e9aa638b0c3fd4) --- src/mongo/db/catalog/collection_catalog_entry.h | 2 ++ src/mongo/db/catalog/index_catalog_entry_impl.cpp | 14 ++++++++++---- src/mongo/db/catalog/index_catalog_entry_impl.h | 1 + src/mongo/db/storage/bson_collection_catalog_entry.cpp | 7 +++++++ src/mongo/db/storage/bson_collection_catalog_entry.h | 2 ++ .../mmap_v1/catalog/namespace_details_collection_entry.cpp | 6 ++++++ .../mmap_v1/catalog/namespace_details_collection_entry.h | 2 ++ 7 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/mongo/db/catalog/collection_catalog_entry.h b/src/mongo/db/catalog/collection_catalog_entry.h index a55280a6724..f08085d7710 100644 --- a/src/mongo/db/catalog/collection_catalog_entry.h +++ b/src/mongo/db/catalog/collection_catalog_entry.h @@ -109,6 +109,8 @@ public: virtual bool isIndexReady(OperationContext* opCtx, StringData indexName) const = 0; + virtual bool isIndexPresent(OperationContext* opCtx, StringData indexName) const = 0; + virtual KVPrefix getIndexPrefix(OperationContext* opCtx, StringData indexName) const = 0; virtual Status removeIndex(OperationContext* opCtx, StringData indexName) = 0; diff --git a/src/mongo/db/catalog/index_catalog_entry_impl.cpp b/src/mongo/db/catalog/index_catalog_entry_impl.cpp index f44e5a0f31e..09859e35b4c 100644 --- a/src/mongo/db/catalog/index_catalog_entry_impl.cpp +++ b/src/mongo/db/catalog/index_catalog_entry_impl.cpp @@ -167,10 +167,12 @@ bool IndexCatalogEntryImpl::isReady(OperationContext* opCtx) const { // minimumSnapshotVersion on a collection. This means we are unprotected from reading // out-of-sync index catalog entries. To fix this, we uassert if we detect that the // in-memory catalog is out-of-sync with the on-disk catalog. - if (session && session->inMultiDocumentTransaction() && _catalogIsReady(opCtx) != _isReady) { - uasserted(ErrorCodes::SnapshotUnavailable, - str::stream() << "Unable to read from a snapshot due to pending collection" - " catalog changes; please retry the operation."); + if (session && session->inMultiDocumentTransaction()) { + if (!_catalogIsPresent(opCtx) || _catalogIsReady(opCtx) != _isReady) { + uasserted(ErrorCodes::SnapshotUnavailable, + str::stream() << "Unable to read from a snapshot due to pending collection" + " catalog changes; please retry the operation."); + } } DEV invariant(_isReady == _catalogIsReady(opCtx)); @@ -360,6 +362,10 @@ RecordId IndexCatalogEntryImpl::_catalogHead(OperationContext* opCtx) const { return _collection->getIndexHead(opCtx, _descriptor->indexName()); } +bool IndexCatalogEntryImpl::_catalogIsPresent(OperationContext* opCtx) const { + return _collection->isIndexPresent(opCtx, _descriptor->indexName()); +} + bool IndexCatalogEntryImpl::_catalogIsMultikey(OperationContext* opCtx, MultikeyPaths* multikeyPaths) const { return _collection->isIndexMultikey(opCtx, _descriptor->indexName(), multikeyPaths); diff --git a/src/mongo/db/catalog/index_catalog_entry_impl.h b/src/mongo/db/catalog/index_catalog_entry_impl.h index 0564c35d7c0..86fa76c6101 100644 --- a/src/mongo/db/catalog/index_catalog_entry_impl.h +++ b/src/mongo/db/catalog/index_catalog_entry_impl.h @@ -170,6 +170,7 @@ private: class SetHeadChange; bool _catalogIsReady(OperationContext* opCtx) const; + bool _catalogIsPresent(OperationContext* opCtx) const; RecordId _catalogHead(OperationContext* opCtx) const; /** diff --git a/src/mongo/db/storage/bson_collection_catalog_entry.cpp b/src/mongo/db/storage/bson_collection_catalog_entry.cpp index 21c1530e00d..a518884be93 100644 --- a/src/mongo/db/storage/bson_collection_catalog_entry.cpp +++ b/src/mongo/db/storage/bson_collection_catalog_entry.cpp @@ -190,6 +190,13 @@ RecordId BSONCollectionCatalogEntry::getIndexHead(OperationContext* opCtx, return md.indexes[offset].head; } +bool BSONCollectionCatalogEntry::isIndexPresent(OperationContext* opCtx, + StringData indexName) const { + MetaData md = _getMetaData(opCtx); + int offset = md.findIndexOffset(indexName); + return offset >= 0; +} + bool BSONCollectionCatalogEntry::isIndexReady(OperationContext* opCtx, StringData indexName) const { MetaData md = _getMetaData(opCtx); diff --git a/src/mongo/db/storage/bson_collection_catalog_entry.h b/src/mongo/db/storage/bson_collection_catalog_entry.h index 4401c554775..ea3261350a2 100644 --- a/src/mongo/db/storage/bson_collection_catalog_entry.h +++ b/src/mongo/db/storage/bson_collection_catalog_entry.h @@ -72,6 +72,8 @@ public: virtual bool isIndexReady(OperationContext* opCtx, StringData indexName) const; + virtual bool isIndexPresent(OperationContext* opCtx, StringData indexName) const; + virtual KVPrefix getIndexPrefix(OperationContext* opCtx, StringData indexName) const; // ------ for implementors diff --git a/src/mongo/db/storage/mmap_v1/catalog/namespace_details_collection_entry.cpp b/src/mongo/db/storage/mmap_v1/catalog/namespace_details_collection_entry.cpp index 865d5fff00f..a2a31433a92 100644 --- a/src/mongo/db/storage/mmap_v1/catalog/namespace_details_collection_entry.cpp +++ b/src/mongo/db/storage/mmap_v1/catalog/namespace_details_collection_entry.cpp @@ -200,6 +200,12 @@ bool NamespaceDetailsCollectionCatalogEntry::isIndexReady(OperationContext* opCt return idxNo < getCompletedIndexCount(opCtx); } +bool NamespaceDetailsCollectionCatalogEntry::isIndexPresent(OperationContext* opCtx, + StringData idxName) const { + int idxNo = _findIndexNumber(opCtx, idxName); + return idxNo >= 0; +} + KVPrefix NamespaceDetailsCollectionCatalogEntry::getIndexPrefix(OperationContext* opCtx, StringData indexName) const { return KVPrefix::kNotPrefixed; diff --git a/src/mongo/db/storage/mmap_v1/catalog/namespace_details_collection_entry.h b/src/mongo/db/storage/mmap_v1/catalog/namespace_details_collection_entry.h index 517128ae26d..60cba15378b 100644 --- a/src/mongo/db/storage/mmap_v1/catalog/namespace_details_collection_entry.h +++ b/src/mongo/db/storage/mmap_v1/catalog/namespace_details_collection_entry.h @@ -86,6 +86,8 @@ public: bool isIndexReady(OperationContext* opCtx, StringData indexName) const final; + bool isIndexPresent(OperationContext* opCtx, StringData indexName) const final; + KVPrefix getIndexPrefix(OperationContext* opCtx, StringData indexName) const final; Status removeIndex(OperationContext* opCtx, StringData indexName) final; -- cgit v1.2.1