diff options
author | Jason Rassi <rassi@10gen.com> | 2014-12-01 03:21:02 -0500 |
---|---|---|
committer | Jason Rassi <rassi@10gen.com> | 2014-12-01 11:04:50 -0500 |
commit | d331763a98ba86dcbfceb155c77fb3cb65deac5d (patch) | |
tree | 9d3d46307daefbaa830d5106be76b70e2146c174 | |
parent | 80afbf31aee7585814079cfdb1dc6281bd96a1e7 (diff) | |
download | mongo-d331763a98ba86dcbfceb155c77fb3cb65deac5d.tar.gz |
SERVER-14057 Changing TTL should invalidate catalog's cached spec obj
-rw-r--r-- | src/mongo/db/catalog/index_catalog.cpp | 30 | ||||
-rw-r--r-- | src/mongo/db/catalog/index_catalog.h | 13 | ||||
-rw-r--r-- | src/mongo/db/dbcommands.cpp | 6 | ||||
-rw-r--r-- | src/mongo/dbtests/indexcatalogtests.cpp | 46 |
4 files changed, 87 insertions, 8 deletions
diff --git a/src/mongo/db/catalog/index_catalog.cpp b/src/mongo/db/catalog/index_catalog.cpp index 8614c368f91..72a9de02b09 100644 --- a/src/mongo/db/catalog/index_catalog.cpp +++ b/src/mongo/db/catalog/index_catalog.cpp @@ -929,8 +929,9 @@ namespace mongo { return toReturn; } - void IndexCatalog::updateTTLSetting( const IndexDescriptor* idx, long long newExpireSeconds ) { - IndexDetails* indexDetails = _getIndexDetails( idx ); + const IndexDescriptor* IndexCatalog::updateTTLSetting( const IndexDescriptor* oldDesc, + long long newExpireSeconds ) { + IndexDetails* indexDetails = _getIndexDetails( oldDesc ); BSONElement oldExpireSecs = indexDetails->info.obj().getField("expireAfterSeconds"); @@ -954,6 +955,31 @@ namespace mongo { default: massert( 16632, "current 'expireAfterSeconds' is not a number", false ); } + + // The value has now been updated on disk. We're now going to invalidate the index + // catalog's old IndexDescriptor, and register a new one with the updated spec object. + + BSONObj ownedInfoObj = indexDetails->info.obj().getOwned(); + BSONObj keyPattern = ownedInfoObj.getObjectField("key"); + + // 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 ); + + // Re-register this index in the index catalog with the new spec. + IndexDescriptor* newDesc = new IndexDescriptor( _collection, + _getAccessMethodName( keyPattern ), + ownedInfoObj ); + const IndexCatalogEntry* entry = _setupInMemoryStructures( newDesc ); + invariant( entry->isReady() ); + + // Return the new descriptor. + return entry->descriptor(); } bool IndexCatalog::isMultikey( const IndexDescriptor* idx ) { diff --git a/src/mongo/db/catalog/index_catalog.h b/src/mongo/db/catalog/index_catalog.h index 8d8c6a2942c..525ffbe416e 100644 --- a/src/mongo/db/catalog/index_catalog.h +++ b/src/mongo/db/catalog/index_catalog.h @@ -178,11 +178,18 @@ namespace mongo { // ---- modify single index - /* Updates the expireAfterSeconds field of the given index to the value in newExpireSecs. + /** + * Updates the expireAfterSeconds field of the given index to the value in newExpireSecs. * The specified index must already contain an expireAfterSeconds field, and the value in - * that field and newExpireSecs must both be numeric. + * that field and newExpireSecs must both be numeric. Returns an unowned pointer to the + * descriptor for the new index definition. + * + * 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. */ - void updateTTLSetting( const IndexDescriptor* idx, long long newExpireSeconds ); + const IndexDescriptor* updateTTLSetting( const IndexDescriptor* oldDesc, + long long newExpireSeconds ); bool isMultikey( const IndexDescriptor* idex ); diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp index edebcd96e7d..ef16d5aac9b 100644 --- a/src/mongo/db/dbcommands.cpp +++ b/src/mongo/db/dbcommands.cpp @@ -1175,7 +1175,8 @@ namespace mongo { continue; } - IndexDescriptor* idx = coll->getIndexCatalog()->findIndexByKeyPattern( keyPattern ); + const IndexDescriptor* idx = coll->getIndexCatalog() + ->findIndexByKeyPattern( keyPattern ); if ( idx == NULL ) { errmsg = str::stream() << "cannot find index " << keyPattern << " for ns " << ns; @@ -1197,7 +1198,8 @@ namespace mongo { if ( oldExpireSecs != newExpireSecs ) { // change expireAfterSeconds result.appendAs( oldExpireSecs, "expireAfterSeconds_old" ); - coll->getIndexCatalog()->updateTTLSetting( idx, newExpireSecs.numberLong() ); + idx = coll->getIndexCatalog() + ->updateTTLSetting( idx, newExpireSecs.numberLong() ); result.appendAs( newExpireSecs , "expireAfterSeconds_new" ); } } diff --git a/src/mongo/dbtests/indexcatalogtests.cpp b/src/mongo/dbtests/indexcatalogtests.cpp index 02ad7ee79d8..e1c02cb0200 100644 --- a/src/mongo/dbtests/indexcatalogtests.cpp +++ b/src/mongo/dbtests/indexcatalogtests.cpp @@ -16,10 +16,10 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "mongo/db/catalog/collection.h" #include "mongo/db/catalog/index_catalog.h" #include "mongo/db/db.h" #include "mongo/db/index/index_descriptor.h" -#include "mongo/db/catalog/collection.h" #include "mongo/dbtests/dbtests.h" @@ -86,12 +86,56 @@ namespace IndexCatalogTests { Database* _db; }; + /** + * Test for IndexCatalog::updateTTLSetting(). + */ + class UpdateTTLSetting { + public: + UpdateTTLSetting() { + Client::WriteContext ctx(_ns); + _db = ctx.ctx().db(); + _coll = _db->createCollection(_ns); + _catalog = _coll->getIndexCatalog(); + } + + ~UpdateTTLSetting () { + Client::WriteContext ctx(_ns); + _db->dropCollection(_ns); + } + + void run() { + Client::WriteContext ctx(_ns); + const std::string indexName = "x_1"; + + BSONObjBuilder indexSpecBuilder; + indexSpecBuilder.append("key", BSON("x" << 1)); + indexSpecBuilder.append("ns", _ns); + indexSpecBuilder.append("name", indexName); + indexSpecBuilder.append("expireAfterSeconds", 5); + _catalog->createIndex(indexSpecBuilder.obj(), true); + + const IndexDescriptor* desc = _catalog->findIndexByName(indexName); + ASSERT(desc); + ASSERT_EQUALS(5, desc->infoObj()["expireAfterSeconds"].numberLong()); + + desc = _catalog->updateTTLSetting(desc, 10); + + 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<UpdateTTLSetting>(); } } indexCatalogTests; } |