summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Rassi <rassi@10gen.com>2014-12-01 03:21:02 -0500
committerJason Rassi <rassi@10gen.com>2014-12-01 11:04:50 -0500
commitd331763a98ba86dcbfceb155c77fb3cb65deac5d (patch)
tree9d3d46307daefbaa830d5106be76b70e2146c174
parent80afbf31aee7585814079cfdb1dc6281bd96a1e7 (diff)
downloadmongo-d331763a98ba86dcbfceb155c77fb3cb65deac5d.tar.gz
SERVER-14057 Changing TTL should invalidate catalog's cached spec obj
-rw-r--r--src/mongo/db/catalog/index_catalog.cpp30
-rw-r--r--src/mongo/db/catalog/index_catalog.h13
-rw-r--r--src/mongo/db/dbcommands.cpp6
-rw-r--r--src/mongo/dbtests/indexcatalogtests.cpp46
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;
}