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 17:04:00 -0500
commitc1c8778a5b7a1fa9f5cd5625fb3fd9dc7d667d37 (patch)
treec6ae51a91bc82e86e868886d141b9678cb83fe02
parent038ddab4c9144daed30d4c2982d5b3319d551e61 (diff)
downloadmongo-c1c8778a5b7a1fa9f5cd5625fb3fd9dc7d667d37.tar.gz
SERVER-14057 Changing TTL should invalidate catalog's cached spec obj
-rw-r--r--src/mongo/db/catalog/index_catalog.cpp32
-rw-r--r--src/mongo/db/catalog/index_catalog.h15
-rw-r--r--src/mongo/db/dbcommands.cpp7
-rw-r--r--src/mongo/dbtests/indexcatalogtests.cpp77
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>();
}
};