diff options
author | Jason Rassi <rassi@10gen.com> | 2014-12-01 03:21:02 -0500 |
---|---|---|
committer | Jason Rassi <rassi@10gen.com> | 2014-12-01 17:04:00 -0500 |
commit | c1c8778a5b7a1fa9f5cd5625fb3fd9dc7d667d37 (patch) | |
tree | c6ae51a91bc82e86e868886d141b9678cb83fe02 | |
parent | 038ddab4c9144daed30d4c2982d5b3319d551e61 (diff) | |
download | mongo-c1c8778a5b7a1fa9f5cd5625fb3fd9dc7d667d37.tar.gz |
SERVER-14057 Changing TTL should invalidate catalog's cached spec obj
-rw-r--r-- | src/mongo/db/catalog/index_catalog.cpp | 32 | ||||
-rw-r--r-- | src/mongo/db/catalog/index_catalog.h | 15 | ||||
-rw-r--r-- | src/mongo/db/dbcommands.cpp | 7 | ||||
-rw-r--r-- | src/mongo/dbtests/indexcatalogtests.cpp | 77 |
4 files changed, 123 insertions, 8 deletions
diff --git a/src/mongo/db/catalog/index_catalog.cpp b/src/mongo/db/catalog/index_catalog.cpp index 2a4f1ed04d7..c2360ea12d6 100644 --- a/src/mongo/db/catalog/index_catalog.cpp +++ b/src/mongo/db/catalog/index_catalog.cpp @@ -1014,6 +1014,38 @@ namespace { return entry; } + + const IndexDescriptor* IndexCatalog::refreshEntry( OperationContext* txn, + const IndexDescriptor* oldDesc ) { + txn->lockState()->assertWriteLocked( _collection->_database->name() ); + + std::string indexName = oldDesc->indexName(); + invariant( _collection->getCatalogEntry()->isIndexReady( txn, indexName ) ); + + // Notify other users of the IndexCatalog that we're about to invalidate 'oldDesc'. + const bool collectionGoingAway = false; + _collection->cursorCache()->invalidateAll( collectionGoingAway ); + + // Delete the IndexCatalogEntry that owns this descriptor. After deletion, 'oldDesc' is + // invalid and should not be dereferenced. + const bool removed = _entries.remove( oldDesc ); + invariant( removed ); + + // Ask the CollectionCatalogEntry for the new index spec. + BSONObj spec = _collection->getCatalogEntry()->getIndexSpec( txn, indexName ).getOwned(); + BSONObj keyPattern = spec.getObjectField( "key" ); + + // Re-register this index in the index catalog with the new spec. + IndexDescriptor* newDesc = new IndexDescriptor( _collection, + _getAccessMethodName( txn, keyPattern ), + spec ); + const IndexCatalogEntry* entry = _setupInMemoryStructures( txn, newDesc ); + invariant( entry->isReady( txn ) ); + + // Return the new descriptor. + return entry->descriptor(); + } + // --------------------------- namespace { diff --git a/src/mongo/db/catalog/index_catalog.h b/src/mongo/db/catalog/index_catalog.h index 9c890b5a6fd..8c2f924682b 100644 --- a/src/mongo/db/catalog/index_catalog.h +++ b/src/mongo/db/catalog/index_catalog.h @@ -110,6 +110,21 @@ namespace mongo { std::vector<IndexDescriptor*>& matches, bool includeUnfinishedIndexes = false ) const; + + /** + * Reload the index definition for 'oldDesc' from the CollectionCatalogEntry. 'oldDesc' + * must be a ready index that is already registered with the index catalog. Returns an + * unowned pointer to the descriptor for the new index definition. + * + * Use this method to notify the IndexCatalog that the spec for this index has changed. + * + * It is invalid to dereference 'oldDesc' after calling this method. This method broadcasts + * an invalidateAll() on the cursor cache to notify other users of the IndexCatalog that + * this descriptor is now invalid. + */ + const IndexDescriptor* refreshEntry( OperationContext* txn, + const IndexDescriptor* oldDesc ); + // never returns NULL const IndexCatalogEntry* getEntry( const IndexDescriptor* desc ) const; diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp index 2655ca810a9..625ccc4a89f 100644 --- a/src/mongo/db/dbcommands.cpp +++ b/src/mongo/db/dbcommands.cpp @@ -1046,7 +1046,8 @@ namespace mongo { continue; } - IndexDescriptor* idx = coll->getIndexCatalog()->findIndexByKeyPattern( txn, keyPattern ); + const IndexDescriptor* idx = coll->getIndexCatalog() + ->findIndexByKeyPattern( txn, keyPattern ); if ( idx == NULL ) { errmsg = str::stream() << "cannot find index " << keyPattern << " for ns " << ns; @@ -1066,11 +1067,13 @@ namespace mongo { } if ( oldExpireSecs != newExpireSecs ) { - // change expireAfterSeconds result.appendAs( oldExpireSecs, "expireAfterSeconds_old" ); + // Change the value of "expireAfterSeconds" on disk. coll->getCatalogEntry()->updateTTLSetting( txn, idx->indexName(), newExpireSecs.numberLong() ); + // Notify the index catalog that the definition of this index changed. + idx = coll->getIndexCatalog()->refreshEntry( txn, idx ); result.appendAs( newExpireSecs , "expireAfterSeconds_new" ); } } diff --git a/src/mongo/dbtests/indexcatalogtests.cpp b/src/mongo/dbtests/indexcatalogtests.cpp index a9819ba10b3..346ba85a799 100644 --- a/src/mongo/dbtests/indexcatalogtests.cpp +++ b/src/mongo/dbtests/indexcatalogtests.cpp @@ -16,11 +16,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "mongo/db/catalog/collection.h" +#include "mongo/db/catalog/collection_catalog_entry.h" #include "mongo/db/catalog/index_catalog.h" #include "mongo/db/db.h" #include "mongo/db/dbhelpers.h" #include "mongo/db/index/index_descriptor.h" -#include "mongo/db/catalog/collection.h" #include "mongo/db/operation_context_impl.h" #include "mongo/dbtests/dbtests.h" @@ -61,10 +62,8 @@ namespace IndexCatalogTests { int numFinishedIndexesStart = _catalog->numIndexesReady(&txn); - WriteUnitOfWork wuow(&txn); - Helpers::ensureIndex(&txn, _coll, BSON("x" << 1), false, "_x_0"); - Helpers::ensureIndex(&txn, _coll, BSON("y" << 1), false, "_y_0"); - wuow.commit(); + dbtests::createIndex(&txn, _ns, BSON("x" << 1)); + dbtests::createIndex(&txn, _ns, BSON("y" << 1)); ASSERT_TRUE(_catalog->numIndexesReady(&txn) == numFinishedIndexesStart+2); @@ -78,7 +77,7 @@ namespace IndexCatalogTests { while (boit.more() && !foundIndex) { BSONElement e = boit.next(); if (str::equals(e.fieldName(), "name") && - str::equals(e.valuestrsafe(), "_y_0")) { + str::equals(e.valuestrsafe(), "y_1")) { foundIndex = true; break; } @@ -95,12 +94,78 @@ namespace IndexCatalogTests { Database* _db; }; + /** + * Test for IndexCatalog::refreshEntry(). + */ + class RefreshEntry { + public: + RefreshEntry() { + OperationContextImpl txn; + ScopedTransaction transaction(&txn, MODE_IX); + Lock::DBLock lk(txn.lockState(), nsToDatabaseSubstring(_ns), MODE_X); + Client::Context ctx(&txn, _ns); + WriteUnitOfWork wuow(&txn); + + _db = ctx.db(); + _coll = _db->createCollection(&txn, _ns); + _catalog = _coll->getIndexCatalog(); + wuow.commit(); + } + + ~RefreshEntry () { + OperationContextImpl txn; + ScopedTransaction transaction(&txn, MODE_IX); + Lock::DBLock lk(txn.lockState(), nsToDatabaseSubstring(_ns), MODE_X); + Client::Context ctx(&txn, _ns); + WriteUnitOfWork wuow(&txn); + + _db->dropCollection(&txn, _ns); + wuow.commit(); + } + + void run() { + OperationContextImpl txn; + Client::WriteContext ctx(&txn, _ns); + const std::string indexName = "x_1"; + + ASSERT_OK(dbtests::createIndexFromSpec(&txn, _ns, BSON("name" << indexName << + "ns" << _ns << + "key" << BSON("x" << 1) << + "expireAfterSeconds" << 5))); + + const IndexDescriptor* desc = _catalog->findIndexByName(&txn, indexName); + ASSERT(desc); + ASSERT_EQUALS(5, desc->infoObj()["expireAfterSeconds"].numberLong()); + + // Change value of "expireAfterSeconds" on disk. + WriteUnitOfWork wuow(&txn); + _coll->getCatalogEntry()->updateTTLSetting(&txn, "x_1", 10); + wuow.commit(); + + // Verify that the catalog does not yet know of the change. + desc = _catalog->findIndexByName(&txn, indexName); + ASSERT_EQUALS(5, desc->infoObj()["expireAfterSeconds"].numberLong()); + + // Notify the catalog of the change. + desc = _catalog->refreshEntry(&txn, desc); + + // Test that the catalog reflects the change. + ASSERT_EQUALS(10, desc->infoObj()["expireAfterSeconds"].numberLong()); + } + + private: + IndexCatalog* _catalog; + Collection* _coll; + Database* _db; + }; + class IndexCatalogTests : public Suite { public: IndexCatalogTests() : Suite( "indexcatalogtests" ) { } void setupTests() { add<IndexIteratorTests>(); + add<RefreshEntry>(); } }; |