summaryrefslogtreecommitdiff
path: root/src/mongo/db/storage
diff options
context:
space:
mode:
authorMathias Stearn <mathias@10gen.com>2015-07-06 19:16:30 -0400
committerMathias Stearn <mathias@10gen.com>2015-07-16 14:37:02 -0400
commitb9d2e18ca68246e5d21ed42a846ff4094867f159 (patch)
treecdbbac6dc5ee00404cf6452f5dd70612983127e3 /src/mongo/db/storage
parentc832bc753c29f91597b75fa02c0d9019c3c20b0f (diff)
downloadmongo-b9d2e18ca68246e5d21ed42a846ff4094867f159.tar.gz
SERVER-17364 Don't stash RecoveryUnits across getMores
We now tell PlanExecutors to detach from their OperationContexts and to shed all storage engine resources before stashing the ClientCursor. This is a heavier weight operation than a normal save/restoreState which is no longer allowed to change the OperationContext.
Diffstat (limited to 'src/mongo/db/storage')
-rw-r--r--src/mongo/db/storage/devnull/devnull_kv_engine.cpp4
-rw-r--r--src/mongo/db/storage/in_memory/in_memory_btree_impl.cpp13
-rw-r--r--src/mongo/db/storage/in_memory/in_memory_record_store.cpp22
-rw-r--r--src/mongo/db/storage/mmap_v1/btree/btree_interface.cpp17
-rw-r--r--src/mongo/db/storage/mmap_v1/record_store_v1_base.h8
-rw-r--r--src/mongo/db/storage/mmap_v1/record_store_v1_capped_iterator.cpp7
-rw-r--r--src/mongo/db/storage/mmap_v1/record_store_v1_capped_iterator.h8
-rw-r--r--src/mongo/db/storage/mmap_v1/record_store_v1_repair_iterator.h9
-rw-r--r--src/mongo/db/storage/mmap_v1/record_store_v1_simple_iterator.cpp7
-rw-r--r--src/mongo/db/storage/mmap_v1/record_store_v1_simple_iterator.h8
-rw-r--r--src/mongo/db/storage/record_store.h19
-rw-r--r--src/mongo/db/storage/record_store_test_recorditer.cpp6
-rw-r--r--src/mongo/db/storage/record_store_test_repairiter.cpp2
-rw-r--r--src/mongo/db/storage/recovery_unit.h10
-rw-r--r--src/mongo/db/storage/sorted_data_interface.h19
-rw-r--r--src/mongo/db/storage/sorted_data_interface_test_cursor_end_position.cpp16
-rw-r--r--src/mongo/db/storage/sorted_data_interface_test_cursor_saverestore.cpp38
-rw-r--r--src/mongo/db/storage/sorted_data_interface_test_harness.cpp4
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp83
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp77
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_record_store_test.cpp4
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.cpp13
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.h6
23 files changed, 211 insertions, 189 deletions
diff --git a/src/mongo/db/storage/devnull/devnull_kv_engine.cpp b/src/mongo/db/storage/devnull/devnull_kv_engine.cpp
index 25ebf6a5de6..25a61a9edb2 100644
--- a/src/mongo/db/storage/devnull/devnull_kv_engine.cpp
+++ b/src/mongo/db/storage/devnull/devnull_kv_engine.cpp
@@ -47,9 +47,11 @@ public:
return {};
}
void savePositioned() final {}
- bool restore(OperationContext* txn) final {
+ bool restore() final {
return true;
}
+ void detachFromOperationContext() final {}
+ void reattachToOperationContext(OperationContext* txn) final {}
};
class DevNullRecordStore : public RecordStore {
diff --git a/src/mongo/db/storage/in_memory/in_memory_btree_impl.cpp b/src/mongo/db/storage/in_memory/in_memory_btree_impl.cpp
index f40dff8e7ff..30cabb59716 100644
--- a/src/mongo/db/storage/in_memory/in_memory_btree_impl.cpp
+++ b/src/mongo/db/storage/in_memory/in_memory_btree_impl.cpp
@@ -299,14 +299,11 @@ public:
}
void saveUnpositioned() override {
- _txn = nullptr;
_savedAtEnd = true;
// Doing nothing with end cursor since it will do full reseek on restore.
}
- void restore(OperationContext* txn) override {
- _txn = txn;
-
+ void restore() override {
// Always do a full seek on restore. We cannot use our last position since index
// entries may have been inserted closer to our endpoint and we would need to move
// over them.
@@ -324,6 +321,14 @@ public:
|| _data.value_comp().compare(*_it, {_savedKey, _savedLoc}) != 0;
}
+ void detachFromOperationContext() final {
+ _txn = nullptr;
+ }
+
+ void reattachToOperationContext(OperationContext* txn) final {
+ _txn = txn;
+ }
+
private:
bool atEndPoint() const {
return _endState && _it == _endState->it;
diff --git a/src/mongo/db/storage/in_memory/in_memory_record_store.cpp b/src/mongo/db/storage/in_memory/in_memory_record_store.cpp
index af596f7a569..7c3b708d513 100644
--- a/src/mongo/db/storage/in_memory/in_memory_record_store.cpp
+++ b/src/mongo/db/storage/in_memory/in_memory_record_store.cpp
@@ -112,7 +112,7 @@ private:
class InMemoryRecordStore::Cursor final : public RecordCursor {
public:
Cursor(OperationContext* txn, const InMemoryRecordStore& rs)
- : _txn(txn), _records(rs._data->records), _isCapped(rs.isCapped()) {}
+ : _records(rs._data->records), _isCapped(rs.isCapped()) {}
boost::optional<Record> next() final {
if (_needFirstSeek) {
@@ -138,18 +138,15 @@ public:
}
void savePositioned() final {
- _txn = nullptr;
if (!_needFirstSeek && !_lastMoveWasRestore)
_savedId = _it == _records.end() ? RecordId() : _it->first;
}
void saveUnpositioned() final {
- _txn = nullptr;
_savedId = RecordId();
}
- bool restore(OperationContext* txn) final {
- _txn = txn;
+ bool restore() final {
if (_savedId.isNull()) {
_it = _records.end();
return true;
@@ -162,8 +159,10 @@ public:
return !(_isCapped && _lastMoveWasRestore);
}
+ void detachFromOperationContext() final {}
+ void reattachToOperationContext(OperationContext* txn) final {}
+
private:
- unowned_ptr<OperationContext> _txn;
Records::const_iterator _it;
bool _needFirstSeek = true;
bool _lastMoveWasRestore = false;
@@ -176,7 +175,7 @@ private:
class InMemoryRecordStore::ReverseCursor final : public RecordCursor {
public:
ReverseCursor(OperationContext* txn, const InMemoryRecordStore& rs)
- : _txn(txn), _records(rs._data->records), _isCapped(rs.isCapped()) {}
+ : _records(rs._data->records), _isCapped(rs.isCapped()) {}
boost::optional<Record> next() final {
if (_needFirstSeek) {
@@ -212,18 +211,15 @@ public:
}
void savePositioned() final {
- _txn = nullptr;
if (!_needFirstSeek && !_lastMoveWasRestore)
_savedId = _it == _records.rend() ? RecordId() : _it->first;
}
void saveUnpositioned() final {
- _txn = nullptr;
_savedId = RecordId();
}
- bool restore(OperationContext* txn) final {
- _txn = txn;
+ bool restore() final {
if (_savedId.isNull()) {
_it = _records.rend();
return true;
@@ -239,8 +235,10 @@ public:
return !(_isCapped && _lastMoveWasRestore);
}
+ void detachFromOperationContext() final {}
+ void reattachToOperationContext(OperationContext* txn) final {}
+
private:
- unowned_ptr<OperationContext> _txn;
Records::const_reverse_iterator _it;
bool _needFirstSeek = true;
bool _lastMoveWasRestore = false;
diff --git a/src/mongo/db/storage/mmap_v1/btree/btree_interface.cpp b/src/mongo/db/storage/mmap_v1/btree/btree_interface.cpp
index ce1aa117fef..1154b296dcf 100644
--- a/src/mongo/db/storage/mmap_v1/btree/btree_interface.cpp
+++ b/src/mongo/db/storage/mmap_v1/btree/btree_interface.cpp
@@ -197,8 +197,6 @@ public:
}
void savePositioned() override {
- _txn = nullptr;
-
if (!_lastMoveWasRestore)
_savedEOF = isEOF();
@@ -215,7 +213,6 @@ public:
}
void saveUnpositioned() override {
- _txn = nullptr;
// Don't leak our registration if savePositioned() was previously called.
if (!_saved.bucket.isNull())
_btree->savedCursors()->unregisterCursor(&_saved);
@@ -224,11 +221,7 @@ public:
_savedEOF = true;
}
- void restore(OperationContext* txn) override {
- // guard against accidental double restore
- invariant(!_txn);
- _txn = txn;
-
+ void restore() override {
// Always do a full seek on restore. We cannot use our last position since index
// entries may have been inserted closer to our endpoint and we would need to move
// over them.
@@ -251,6 +244,14 @@ public:
|| getDiskLoc() != _saved.loc || compareKeys(getKey(), _saved.key) != 0;
}
+ void detachFromOperationContext() final {
+ _txn = nullptr;
+ }
+
+ void reattachToOperationContext(OperationContext* txn) final {
+ _txn = txn;
+ }
+
private:
bool isEOF() const {
return _bucket.isNull();
diff --git a/src/mongo/db/storage/mmap_v1/record_store_v1_base.h b/src/mongo/db/storage/mmap_v1/record_store_v1_base.h
index 5c0437cce56..7ba485d2a8b 100644
--- a/src/mongo/db/storage/mmap_v1/record_store_v1_base.h
+++ b/src/mongo/db/storage/mmap_v1/record_store_v1_base.h
@@ -336,9 +336,15 @@ public:
boost::optional<Record> seekExact(const RecordId& id) final;
void invalidate(const RecordId& dl) final;
void savePositioned() final {}
- bool restore(OperationContext* txn) final {
+ bool restore() final {
return true;
}
+ void detachFromOperationContext() final {
+ _txn = nullptr;
+ }
+ void reattachToOperationContext(OperationContext* txn) final {
+ _txn = txn;
+ }
std::unique_ptr<RecordFetcher> fetcherForNext() const final;
private:
diff --git a/src/mongo/db/storage/mmap_v1/record_store_v1_capped_iterator.cpp b/src/mongo/db/storage/mmap_v1/record_store_v1_capped_iterator.cpp
index 353a7f39c0c..e1487ee20fe 100644
--- a/src/mongo/db/storage/mmap_v1/record_store_v1_capped_iterator.cpp
+++ b/src/mongo/db/storage/mmap_v1/record_store_v1_capped_iterator.cpp
@@ -99,12 +99,9 @@ void CappedRecordStoreV1Iterator::invalidate(const RecordId& id) {
}
}
-void CappedRecordStoreV1Iterator::savePositioned() {
- _txn = nullptr;
-}
+void CappedRecordStoreV1Iterator::savePositioned() {}
-bool CappedRecordStoreV1Iterator::restore(OperationContext* txn) {
- _txn = txn;
+bool CappedRecordStoreV1Iterator::restore() {
return !_killedByInvalidate;
}
diff --git a/src/mongo/db/storage/mmap_v1/record_store_v1_capped_iterator.h b/src/mongo/db/storage/mmap_v1/record_store_v1_capped_iterator.h
index 0a366d9921a..3793c5cce4b 100644
--- a/src/mongo/db/storage/mmap_v1/record_store_v1_capped_iterator.h
+++ b/src/mongo/db/storage/mmap_v1/record_store_v1_capped_iterator.h
@@ -50,7 +50,13 @@ public:
boost::optional<Record> next() final;
boost::optional<Record> seekExact(const RecordId& id) final;
void savePositioned() final;
- bool restore(OperationContext* txn) final;
+ bool restore() final;
+ void detachFromOperationContext() final {
+ _txn = nullptr;
+ }
+ void reattachToOperationContext(OperationContext* txn) final {
+ _txn = txn;
+ }
void invalidate(const RecordId& dl) final;
std::unique_ptr<RecordFetcher> fetcherForNext() const final;
std::unique_ptr<RecordFetcher> fetcherForId(const RecordId& id) const final;
diff --git a/src/mongo/db/storage/mmap_v1/record_store_v1_repair_iterator.h b/src/mongo/db/storage/mmap_v1/record_store_v1_repair_iterator.h
index def5178ad8e..eb2dc6cb8e1 100644
--- a/src/mongo/db/storage/mmap_v1/record_store_v1_repair_iterator.h
+++ b/src/mongo/db/storage/mmap_v1/record_store_v1_repair_iterator.h
@@ -47,12 +47,15 @@ public:
boost::optional<Record> next() final;
boost::optional<Record> seekExact(const RecordId& id) final;
void invalidate(const RecordId& dl);
- void savePositioned() final {
+ void savePositioned() final {}
+ bool restore() final {
+ return true;
+ }
+ void detachFromOperationContext() final {
_txn = nullptr;
}
- bool restore(OperationContext* txn) final {
+ void reattachToOperationContext(OperationContext* txn) final {
_txn = txn;
- return true;
}
// Explicitly not supporting fetcherForNext(). The expected use case for this class is a
diff --git a/src/mongo/db/storage/mmap_v1/record_store_v1_simple_iterator.cpp b/src/mongo/db/storage/mmap_v1/record_store_v1_simple_iterator.cpp
index babfbcf26ea..5d668004b68 100644
--- a/src/mongo/db/storage/mmap_v1/record_store_v1_simple_iterator.cpp
+++ b/src/mongo/db/storage/mmap_v1/record_store_v1_simple_iterator.cpp
@@ -108,12 +108,9 @@ void SimpleRecordStoreV1Iterator::invalidate(const RecordId& dl) {
}
}
-void SimpleRecordStoreV1Iterator::savePositioned() {
- _txn = nullptr;
-}
+void SimpleRecordStoreV1Iterator::savePositioned() {}
-bool SimpleRecordStoreV1Iterator::restore(OperationContext* txn) {
- _txn = txn;
+bool SimpleRecordStoreV1Iterator::restore() {
// if the collection is dropped, then the cursor should be destroyed
return true;
}
diff --git a/src/mongo/db/storage/mmap_v1/record_store_v1_simple_iterator.h b/src/mongo/db/storage/mmap_v1/record_store_v1_simple_iterator.h
index 91b0088bf72..4b74864bf1c 100644
--- a/src/mongo/db/storage/mmap_v1/record_store_v1_simple_iterator.h
+++ b/src/mongo/db/storage/mmap_v1/record_store_v1_simple_iterator.h
@@ -50,7 +50,13 @@ public:
boost::optional<Record> next() final;
boost::optional<Record> seekExact(const RecordId& id) final;
void savePositioned() final;
- bool restore(OperationContext* txn) final;
+ bool restore() final;
+ void detachFromOperationContext() final {
+ _txn = nullptr;
+ }
+ void reattachToOperationContext(OperationContext* txn) final {
+ _txn = txn;
+ }
void invalidate(const RecordId& dl) final;
std::unique_ptr<RecordFetcher> fetcherForNext() const final;
std::unique_ptr<RecordFetcher> fetcherForId(const RecordId& id) const final;
diff --git a/src/mongo/db/storage/record_store.h b/src/mongo/db/storage/record_store.h
index c3226fa41e1..6d4fd9dae9f 100644
--- a/src/mongo/db/storage/record_store.h
+++ b/src/mongo/db/storage/record_store.h
@@ -196,7 +196,24 @@ public:
*
* This handles restoring after either savePositioned() or saveUnpositioned().
*/
- virtual bool restore(OperationContext* txn) = 0;
+ virtual bool restore() = 0;
+
+ /**
+ * Detaches from the OperationContext and releases any storage-engine state.
+ *
+ * It is only legal to call this when in a "saved" state. While in the "detached" state, it is
+ * only legal to call reattachToOperationContext or the destructor. It is not legal to call
+ * detachFromOperationContext() while already in the detached state.
+ */
+ virtual void detachFromOperationContext() = 0;
+
+ /**
+ * Reattaches to the OperationContext and reacquires any storage-engine state.
+ *
+ * It is only legal to call this in the "detached" state. On return, the cursor is left in a
+ * "saved" state, so callers must still call restoreState to use this object.
+ */
+ virtual void reattachToOperationContext(OperationContext* opCtx) = 0;
/**
* Inform the cursor that this id is being invalidated.
diff --git a/src/mongo/db/storage/record_store_test_recorditer.cpp b/src/mongo/db/storage/record_store_test_recorditer.cpp
index 3be72344c85..7d42c6bfe2a 100644
--- a/src/mongo/db/storage/record_store_test_recorditer.cpp
+++ b/src/mongo/db/storage/record_store_test_recorditer.cpp
@@ -316,7 +316,7 @@ TEST(RecordStoreTestHarness, RecordIteratorEOF) {
ASSERT_OK(res.getStatus());
uow.commit();
- ASSERT(cursor->restore(opCtx.get()));
+ ASSERT(cursor->restore());
// Iterator should still be EOF.
ASSERT(!cursor->next());
@@ -369,7 +369,7 @@ TEST(RecordStoreTestHarness, RecordIteratorSavePositionedRestore) {
for (int i = 0; i < nToInsert; i++) {
cursor->savePositioned();
cursor->savePositioned(); // It is legal to save twice in a row.
- cursor->restore(opCtx.get());
+ cursor->restore();
const auto record = cursor->next();
ASSERT(record);
@@ -379,7 +379,7 @@ TEST(RecordStoreTestHarness, RecordIteratorSavePositionedRestore) {
cursor->savePositioned();
cursor->savePositioned(); // It is legal to save twice in a row.
- cursor->restore(opCtx.get());
+ cursor->restore();
ASSERT(!cursor->next());
}
diff --git a/src/mongo/db/storage/record_store_test_repairiter.cpp b/src/mongo/db/storage/record_store_test_repairiter.cpp
index 56abdcb6b14..4e21eccc2e1 100644
--- a/src/mongo/db/storage/record_store_test_repairiter.cpp
+++ b/src/mongo/db/storage/record_store_test_repairiter.cpp
@@ -158,7 +158,7 @@ TEST(RecordStoreTestHarness, GetIteratorForRepairInvalidateSingleton) {
// Invalidate the record we're pointing at.
cursor->savePositioned();
cursor->invalidate(idToInvalidate);
- cursor->restore(opCtx.get());
+ cursor->restore();
// Iterator should be EOF now because the only thing in the collection got deleted.
ASSERT(!cursor->next());
diff --git a/src/mongo/db/storage/recovery_unit.h b/src/mongo/db/storage/recovery_unit.h
index 3bb9d3093ea..d50da13cb95 100644
--- a/src/mongo/db/storage/recovery_unit.h
+++ b/src/mongo/db/storage/recovery_unit.h
@@ -53,9 +53,6 @@ public:
virtual void reportState(BSONObjBuilder* b) const {}
- virtual void beingReleasedFromOperationContext() {}
- virtual void beingSetOnOperationContext() {}
-
/**
* These should be called through WriteUnitOfWork rather than directly.
*
@@ -109,6 +106,13 @@ public:
"Current storage engine does not support $readMajorityTemporaryName"};
}
+ /**
+ * Returns true if setReadFromMajorityCommittedSnapshot() has been called.
+ */
+ virtual bool isReadingFromMajorityCommittedSnapshot() {
+ return false;
+ }
+
virtual SnapshotId getSnapshotId() const = 0;
/**
diff --git a/src/mongo/db/storage/sorted_data_interface.h b/src/mongo/db/storage/sorted_data_interface.h
index 2836c7c4814..e373fa1ff44 100644
--- a/src/mongo/db/storage/sorted_data_interface.h
+++ b/src/mongo/db/storage/sorted_data_interface.h
@@ -327,7 +327,24 @@ public:
*
* This handles restoring after either savePositioned() or saveUnpositioned().
*/
- virtual void restore(OperationContext* txn) = 0;
+ virtual void restore() = 0;
+
+ /**
+ * Detaches from the OperationContext and releases any storage-engine state.
+ *
+ * It is only legal to call this when in a "saved" state. While in the "detached" state, it
+ * is only legal to call reattachToOperationContext or the destructor. It is not legal to
+ * call detachFromOperationContext() while already in the detached state.
+ */
+ virtual void detachFromOperationContext() = 0;
+
+ /**
+ * Reattaches to the OperationContext and reacquires any storage-engine state.
+ *
+ * It is only legal to call this in the "detached" state. On return, the cursor is left in a
+ * "saved" state, so callers must still call restoreState to use this object.
+ */
+ virtual void reattachToOperationContext(OperationContext* opCtx) = 0;
};
/**
diff --git a/src/mongo/db/storage/sorted_data_interface_test_cursor_end_position.cpp b/src/mongo/db/storage/sorted_data_interface_test_cursor_end_position.cpp
index 190f707c4c0..e0d31fa90d1 100644
--- a/src/mongo/db/storage/sorted_data_interface_test_cursor_end_position.cpp
+++ b/src/mongo/db/storage/sorted_data_interface_test_cursor_end_position.cpp
@@ -144,7 +144,7 @@ void testSetEndPosition_Seek_Forward(bool unique, bool inclusive) {
cursor->saveUnpositioned();
removeFromIndex(opCtx, sorted, {{key3, loc1}});
- cursor->restore(opCtx.get());
+ cursor->restore();
ASSERT_EQ(cursor->seek(key2, true), boost::none);
ASSERT_EQ(cursor->seek(key3, true), boost::none);
@@ -192,7 +192,7 @@ void testSetEndPosition_Seek_Reverse(bool unique, bool inclusive) {
cursor->saveUnpositioned();
removeFromIndex(opCtx, sorted, {{key2, loc1}});
- cursor->restore(opCtx.get());
+ cursor->restore();
ASSERT_EQ(cursor->seek(key3, true), boost::none);
ASSERT_EQ(cursor->seek(key2, true), boost::none);
@@ -226,7 +226,7 @@ void testSetEndPosition_Restore_Forward(bool unique) {
ASSERT_EQ(cursor->seek(key1, true), IndexKeyEntry(key1, loc1));
cursor->savePositioned();
- cursor->restore(opCtx.get());
+ cursor->restore();
ASSERT_EQ(cursor->next(), IndexKeyEntry(key2, loc1));
@@ -236,7 +236,7 @@ void testSetEndPosition_Restore_Forward(bool unique) {
{
{key2, loc1}, {key3, loc1},
});
- cursor->restore(opCtx.get());
+ cursor->restore();
ASSERT_EQ(cursor->next(), boost::none);
}
@@ -262,7 +262,7 @@ void testSetEndPosition_Restore_Reverse(bool unique) {
ASSERT_EQ(cursor->seek(key4, true), IndexKeyEntry(key4, loc1));
cursor->savePositioned();
- cursor->restore(opCtx.get());
+ cursor->restore();
ASSERT_EQ(cursor->next(), IndexKeyEntry(key3, loc1));
@@ -272,7 +272,7 @@ void testSetEndPosition_Restore_Reverse(bool unique) {
{
{key2, loc1}, {key3, loc1},
});
- cursor->restore(opCtx.get());
+ cursor->restore();
ASSERT_EQ(cursor->next(), boost::none);
}
@@ -309,7 +309,7 @@ void testSetEndPosition_RestoreEndCursor_Forward(bool unique) {
{key2, loc1}, // in range
{key3, loc1}, // out of range
});
- cursor->restore(opCtx.get());
+ cursor->restore();
ASSERT_EQ(cursor->seek(key1, true), IndexKeyEntry(key1, loc1));
ASSERT_EQ(cursor->next(), IndexKeyEntry(key2, loc1));
@@ -342,7 +342,7 @@ void testSetEndPosition_RestoreEndCursor_Reverse(bool unique) {
{key2, loc1}, // in range
{key3, loc1}, // out of range
});
- cursor->restore(opCtx.get()); // must restore end cursor even with saveUnpositioned().
+ cursor->restore(); // must restore end cursor even with saveUnpositioned().
ASSERT_EQ(cursor->seek(key4, true), IndexKeyEntry(key4, loc1));
ASSERT_EQ(cursor->next(), IndexKeyEntry(key3, loc1));
diff --git a/src/mongo/db/storage/sorted_data_interface_test_cursor_saverestore.cpp b/src/mongo/db/storage/sorted_data_interface_test_cursor_saverestore.cpp
index 679bb3f8c8b..c63e6ea15fe 100644
--- a/src/mongo/db/storage/sorted_data_interface_test_cursor_saverestore.cpp
+++ b/src/mongo/db/storage/sorted_data_interface_test_cursor_saverestore.cpp
@@ -75,7 +75,7 @@ TEST(SortedDataInterface, SaveAndRestorePositionWhileIterateCursor) {
ASSERT_EQ(entry, IndexKeyEntry(BSON("" << i), RecordId(42, i * 2)));
cursor->savePositioned();
- cursor->restore(opCtx.get());
+ cursor->restore();
}
ASSERT(!cursor->next());
ASSERT_EQ(i, nToInsert);
@@ -121,7 +121,7 @@ TEST(SortedDataInterface, SaveAndRestorePositionWhileIterateCursorReversed) {
ASSERT_EQ(entry, IndexKeyEntry(BSON("" << i), RecordId(42, i * 2)));
cursor->savePositioned();
- cursor->restore(opCtx.get());
+ cursor->restore();
}
ASSERT(!cursor->next());
ASSERT_EQ(i, -1);
@@ -166,7 +166,7 @@ TEST(SortedDataInterface, SaveAndRestorePositionWhileIterateCursorWithDupKeys) {
ASSERT_EQ(entry, IndexKeyEntry(key1, RecordId(42, i * 2)));
cursor->savePositioned();
- cursor->restore(opCtx.get());
+ cursor->restore();
}
ASSERT(!cursor->next());
ASSERT_EQ(i, nToInsert);
@@ -212,7 +212,7 @@ TEST(SortedDataInterface, SaveAndRestorePositionWhileIterateCursorWithDupKeysRev
ASSERT_EQ(entry, IndexKeyEntry(key1, RecordId(42, i * 2)));
cursor->savePositioned();
- cursor->restore(opCtx.get());
+ cursor->restore();
}
ASSERT(!cursor->next());
ASSERT_EQ(i, -1);
@@ -301,7 +301,7 @@ void testSaveAndRestorePositionSeesNewInserts(bool forward, bool unique) {
cursor->savePositioned();
insertToIndex(opCtx, sorted, {{key2, loc1}});
- cursor->restore(opCtx.get());
+ cursor->restore();
ASSERT_EQ(cursor->next(), IndexKeyEntry(key2, loc1));
}
@@ -335,12 +335,12 @@ void testSaveAndRestorePositionSeesNewInsertsAfterRemove(bool forward, bool uniq
cursor->savePositioned();
removeFromIndex(opCtx, sorted, {{key1, loc1}});
- cursor->restore(opCtx.get());
+ cursor->restore();
// The restore may have seeked since it can't return to the saved position.
cursor->savePositioned(); // Should still save originally saved key as "current position".
insertToIndex(opCtx, sorted, {{key2, loc1}});
- cursor->restore(opCtx.get());
+ cursor->restore();
ASSERT_EQ(cursor->next(), IndexKeyEntry(key2, loc1));
}
@@ -375,13 +375,13 @@ void testSaveAndRestorePositionSeesNewInsertsAfterEOF(bool forward, bool unique)
cursor->savePositioned();
removeFromIndex(opCtx, sorted, {{key1, loc1}});
- cursor->restore(opCtx.get());
+ cursor->restore();
// The restore may have seeked to EOF.
auto insertPoint = forward ? key2 : key0;
cursor->savePositioned(); // Should still save key1 as "current position".
insertToIndex(opCtx, sorted, {{insertPoint, loc1}});
- cursor->restore(opCtx.get());
+ cursor->restore();
ASSERT_EQ(cursor->next(), IndexKeyEntry(insertPoint, loc1));
}
@@ -415,24 +415,24 @@ void testSaveAndRestorePositionConsidersRecordId_Forward(bool unique) {
cursor->savePositioned();
removeFromIndex(opCtx, sorted, {{key1, loc1}});
insertToIndex(opCtx, sorted, {{key1, loc2}});
- cursor->restore(opCtx.get()); // Lands on inserted key.
+ cursor->restore(); // Lands on inserted key.
ASSERT_EQ(cursor->next(), IndexKeyEntry(key1, loc2));
cursor->savePositioned();
removeFromIndex(opCtx, sorted, {{key1, loc2}});
insertToIndex(opCtx, sorted, {{key1, loc1}});
- cursor->restore(opCtx.get()); // Lands after inserted.
+ cursor->restore(); // Lands after inserted.
ASSERT_EQ(cursor->next(), IndexKeyEntry(key2, loc1));
cursor->savePositioned();
removeFromIndex(opCtx, sorted, {{key2, loc1}});
- cursor->restore(opCtx.get());
+ cursor->restore();
cursor->savePositioned();
insertToIndex(opCtx, sorted, {{key2, loc1}});
- cursor->restore(opCtx.get()); // Lands at same point as initial save.
+ cursor->restore(); // Lands at same point as initial save.
// Advances from restore point since restore didn't move position.
ASSERT_EQ(cursor->next(), IndexKeyEntry(key3, loc1));
@@ -460,24 +460,24 @@ void testSaveAndRestorePositionConsidersRecordId_Reverse(bool unique) {
cursor->savePositioned();
removeFromIndex(opCtx, sorted, {{key2, loc2}});
insertToIndex(opCtx, sorted, {{key2, loc1}});
- cursor->restore(opCtx.get());
+ cursor->restore();
ASSERT_EQ(cursor->next(), IndexKeyEntry(key2, loc1));
cursor->savePositioned();
removeFromIndex(opCtx, sorted, {{key2, loc1}});
insertToIndex(opCtx, sorted, {{key2, loc2}});
- cursor->restore(opCtx.get());
+ cursor->restore();
ASSERT_EQ(cursor->next(), IndexKeyEntry(key1, loc1));
cursor->savePositioned();
removeFromIndex(opCtx, sorted, {{key1, loc1}});
- cursor->restore(opCtx.get());
+ cursor->restore();
cursor->savePositioned();
insertToIndex(opCtx, sorted, {{key1, loc1}});
- cursor->restore(opCtx.get()); // Lands at same point as initial save.
+ cursor->restore(); // Lands at same point as initial save.
// Advances from restore point since restore didn't move position.
ASSERT_EQ(cursor->next(), IndexKeyEntry(key0, loc1));
@@ -504,12 +504,12 @@ TEST(SortedDataInterface, SaveUnpositionedAndRestore) {
cursor->saveUnpositioned();
removeFromIndex(opCtx, sorted, {{key2, loc1}});
- cursor->restore(opCtx.get());
+ cursor->restore();
ASSERT_EQ(cursor->seek(key1, true), IndexKeyEntry(key1, loc1));
cursor->saveUnpositioned();
- cursor->restore(opCtx.get());
+ cursor->restore();
ASSERT_EQ(cursor->seek(key3, true), IndexKeyEntry(key3, loc1));
}
diff --git a/src/mongo/db/storage/sorted_data_interface_test_harness.cpp b/src/mongo/db/storage/sorted_data_interface_test_harness.cpp
index 13929c7eacc..7947aae82e5 100644
--- a/src/mongo/db/storage/sorted_data_interface_test_harness.cpp
+++ b/src/mongo/db/storage/sorted_data_interface_test_harness.cpp
@@ -359,7 +359,7 @@ TEST(SortedDataInterface, CursorIterate1WithSaveRestore) {
ASSERT_EQ(entry, IndexKeyEntry(BSON("" << n), RecordId(5, n * 2)));
n++;
cursor->savePositioned();
- cursor->restore(opCtx.get());
+ cursor->restore();
}
ASSERT_EQUALS(N, n);
}
@@ -388,7 +388,7 @@ TEST(SortedDataInterface, CursorIterateAllDupKeysWithSaveRestore) {
ASSERT_EQ(entry, IndexKeyEntry(BSON("" << 5), RecordId(5, n * 2)));
n++;
cursor->savePositioned();
- cursor->restore(opCtx.get());
+ cursor->restore();
}
ASSERT_EQUALS(N, n);
}
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp
index bd727575954..d824406dfae 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp
@@ -595,8 +595,9 @@ namespace {
class WiredTigerIndexCursorBase : public SortedDataInterface::Cursor {
public:
WiredTigerIndexCursorBase(const WiredTigerIndex& idx, OperationContext* txn, bool forward)
- : _txn(txn), _cursor(idx.uri(), idx.tableId(), false, txn), _idx(idx), _forward(forward) {}
-
+ : _txn(txn), _idx(idx), _forward(forward) {
+ _cursor.emplace(_idx.uri(), _idx.tableId(), false, _txn);
+ }
boost::optional<IndexKeyEntry> next(RequestedInfo parts) override {
// Advance on a cursor at the end is a no-op
if (_eof)
@@ -654,24 +655,16 @@ public:
}
void savePositioned() override {
- if (!_txn)
- return; // still saved
-
- _savedForCheck = _txn->recoveryUnit();
-
- if (!wt_keeptxnopen()) {
- try {
- _cursor.reset();
- } catch (const WriteConflictException& wce) {
- // Ignore since this is only called when we are about to kill our transaction
- // anyway.
- }
-
- // Our saved position is wherever we were when we last called updatePosition().
- // Any partially completed repositions should not effect our saved position.
+ try {
+ if (_cursor)
+ _cursor->reset();
+ } catch (const WriteConflictException& wce) {
+ // Ignore since this is only called when we are about to kill our transaction
+ // anyway.
}
- _txn = NULL;
+ // Our saved position is wherever we were when we last called updatePosition().
+ // Any partially completed repositions should not effect our saved position.
}
void saveUnpositioned() override {
@@ -679,21 +672,30 @@ public:
_eof = true;
}
- void restore(OperationContext* txn) override {
- // Update the session handle with our new operation context.
- invariant(_savedForCheck == txn->recoveryUnit());
- _txn = txn;
+ void restore() override {
+ if (!_cursor) {
+ _cursor.emplace(_idx.uri(), _idx.tableId(), false, _txn);
+ }
- if (!wt_keeptxnopen()) {
- if (!_eof) {
- // Ensure an active session exists, so any restored cursors will bind to it
- WiredTigerRecoveryUnit::get(txn)->getSession(txn);
- _lastMoveWasRestore = !seekWTCursor(_key);
- TRACE_CURSOR << "restore _lastMoveWasRestore:" << _lastMoveWasRestore;
- }
+ // Ensure an active session exists, so any restored cursors will bind to it
+ invariant(WiredTigerRecoveryUnit::get(_txn)->getSession(_txn) == _cursor->getSession());
+
+ if (!_eof) {
+ _lastMoveWasRestore = !seekWTCursor(_key);
+ TRACE_CURSOR << "restore _lastMoveWasRestore:" << _lastMoveWasRestore;
}
}
+ void detachFromOperationContext() final {
+ _txn = nullptr;
+ _cursor = {};
+ }
+
+ void reattachToOperationContext(OperationContext* txn) final {
+ _txn = txn;
+ // _cursor recreated in restore() to avoid risk of WT_ROLLBACK issues.
+ }
+
protected:
// Called after _key has been filled in. Must not throw WriteConflictException.
virtual void updateLocAndTypeBits() = 0;
@@ -738,7 +740,7 @@ protected:
}
void advanceWTCursor() {
- WT_CURSOR* c = _cursor.get();
+ WT_CURSOR* c = _cursor->get();
int ret = WT_OP_CHECK(_forward ? c->next(c) : c->prev(c));
if (ret == WT_NOTFOUND) {
_cursorAtEof = true;
@@ -750,7 +752,7 @@ protected:
// Seeks to query. Returns true on exact match.
bool seekWTCursor(const KeyString& query) {
- WT_CURSOR* c = _cursor.get();
+ WT_CURSOR* c = _cursor->get();
int cmp = -1;
const WiredTigerItem keyItem(query.getBuffer(), query.getSize());
@@ -795,7 +797,7 @@ protected:
_eof = false;
- WT_CURSOR* c = _cursor.get();
+ WT_CURSOR* c = _cursor->get();
WT_ITEM item;
invariantWTOK(c->get_key(c, &item));
_key.resetFromBuffer(item.data, item.size);
@@ -809,13 +811,10 @@ protected:
}
OperationContext* _txn;
- WiredTigerCursor _cursor;
+ boost::optional<WiredTigerCursor> _cursor;
const WiredTigerIndex& _idx; // not owned
const bool _forward;
- // Ensures we have the same RU at restore time.
- RecoveryUnit* _savedForCheck;
-
// These are where this cursor instance is. They are not changed in the face of a failing
// next().
KeyString _key;
@@ -844,7 +843,7 @@ public:
void updateLocAndTypeBits() override {
_loc = KeyString::decodeRecordIdAtEnd(_key.getBuffer(), _key.getSize());
- WT_CURSOR* c = _cursor.get();
+ WT_CURSOR* c = _cursor->get();
WT_ITEM item;
invariantWTOK(c->get_value(c, &item));
BufReader br(item.data, item.size);
@@ -857,8 +856,8 @@ public:
WiredTigerIndexUniqueCursor(const WiredTigerIndex& idx, OperationContext* txn, bool forward)
: WiredTigerIndexCursorBase(idx, txn, forward) {}
- void restore(OperationContext* txn) override {
- WiredTigerIndexCursorBase::restore(txn);
+ void restore() override {
+ WiredTigerIndexCursorBase::restore();
// In addition to seeking to the correct key, we also need to make sure that the loc is
// on the correct side of _loc.
@@ -869,7 +868,7 @@ public:
// If we get here we need to look at the actual RecordId for this key and make sure we
// are supposed to see it.
- WT_CURSOR* c = _cursor.get();
+ WT_CURSOR* c = _cursor->get();
WT_ITEM item;
invariantWTOK(c->get_value(c, &item));
@@ -893,7 +892,7 @@ public:
// We assume that cursors can only ever see unique indexes in their "pristine" state,
// where no duplicates are possible. The cases where dups are allowed should hold
// sufficient locks to ensure that no cursor ever sees them.
- WT_CURSOR* c = _cursor.get();
+ WT_CURSOR* c = _cursor->get();
WT_ITEM item;
invariantWTOK(c->get_value(c, &item));
@@ -912,7 +911,7 @@ public:
_query.resetToKey(stripFieldNames(key), _idx.ordering());
const WiredTigerItem keyItem(_query.getBuffer(), _query.getSize());
- WT_CURSOR* c = _cursor.get();
+ WT_CURSOR* c = _cursor->get();
c->set_key(c, keyItem.Get());
// Using search rather than search_near.
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp
index c423cd3e1f9..9008eb4ce2a 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp
@@ -93,16 +93,13 @@ const std::string kWiredTigerEngineName = "wiredTiger";
class WiredTigerRecordStore::Cursor final : public RecordCursor {
public:
- Cursor(OperationContext* txn,
- const WiredTigerRecordStore& rs,
- bool forward = true,
- bool forParallelCollectionScan = false)
+ Cursor(OperationContext* txn, const WiredTigerRecordStore& rs, bool forward = true)
: _rs(rs),
_txn(txn),
_forward(forward),
- _forParallelCollectionScan(forParallelCollectionScan),
- _cursor(new WiredTigerCursor(rs.getURI(), rs.tableId(), true, txn)),
- _readUntilForOplog(WiredTigerRecoveryUnit::get(txn)->getOplogReadTill()) {}
+ _readUntilForOplog(WiredTigerRecoveryUnit::get(txn)->getOplogReadTill()) {
+ _cursor.emplace(rs.getURI(), rs.tableId(), true, txn);
+ }
boost::optional<Record> next() final {
if (_eof)
@@ -186,27 +183,13 @@ public:
}
void savePositioned() final {
- // It must be safe to call save() twice in a row without calling restore().
- if (!_txn)
- return;
-
- // the cursor and recoveryUnit are valid on restore
- // so we just record the recoveryUnit to make sure
- _savedRecoveryUnit = _txn->recoveryUnit();
- if (_cursor && !wt_keeptxnopen()) {
- try {
+ try {
+ if (_cursor)
_cursor->reset();
- } catch (const WriteConflictException& wce) {
- // Ignore since this is only called when we are about to kill our transaction
- // anyway.
- }
+ } catch (const WriteConflictException& wce) {
+ // Ignore since this is only called when we are about to kill our transaction
+ // anyway.
}
-
- if (_forParallelCollectionScan) {
- // Delete the cursor since we may come back to a different RecoveryUnit
- _cursor.reset();
- }
- _txn = nullptr;
}
void saveUnpositioned() final {
@@ -214,31 +197,20 @@ public:
_lastReturnedId = RecordId();
}
- bool restore(OperationContext* txn) final {
- _txn = txn;
+ bool restore() final {
+ if (!_cursor)
+ _cursor.emplace(_rs.getURI(), _rs.tableId(), true, _txn);
+
+ // This will ensure an active session exists, so any restored cursors will bind to it
+ invariant(WiredTigerRecoveryUnit::get(_txn)->getSession(_txn) == _cursor->getSession());
// If we've hit EOF, then this iterator is done and need not be restored.
if (_eof)
return true;
- bool needRestore = false;
-
- if (_forParallelCollectionScan) {
- needRestore = true;
- _savedRecoveryUnit = txn->recoveryUnit();
- _cursor.reset(new WiredTigerCursor(_rs.getURI(), _rs.tableId(), true, txn));
- _forParallelCollectionScan = false; // we only do this the first time
- }
- invariant(_savedRecoveryUnit == txn->recoveryUnit());
-
- if (!needRestore && wt_keeptxnopen())
- return true;
if (_lastReturnedId.isNull())
return true;
- // This will ensure an active session exists, so any restored cursors will bind to it
- invariant(WiredTigerRecoveryUnit::get(txn)->getSession(txn) == _cursor->getSession());
-
WT_CURSOR* c = _cursor->get();
c->set_key(c, _makeKey(_lastReturnedId));
@@ -276,6 +248,16 @@ public:
return true;
}
+ void detachFromOperationContext() final {
+ _txn = nullptr;
+ _cursor = {};
+ }
+
+ void reattachToOperationContext(OperationContext* txn) final {
+ _txn = txn;
+ // _cursor recreated in restore() to avoid risk of WT_ROLLBACK issues.
+ }
+
private:
bool isVisible(const RecordId& id) {
if (!_rs._isCapped)
@@ -297,10 +279,8 @@ private:
const WiredTigerRecordStore& _rs;
OperationContext* _txn;
- RecoveryUnit* _savedRecoveryUnit; // only used to sanity check between save/restore.
const bool _forward;
- bool _forParallelCollectionScan; // This can go away once SERVER-17364 is resolved.
- std::unique_ptr<WiredTigerCursor> _cursor;
+ boost::optional<WiredTigerCursor> _cursor;
bool _eof = false;
RecordId _lastReturnedId; // If null, need to seek to first/last record.
const RecordId _readUntilForOplog;
@@ -906,10 +886,7 @@ std::unique_ptr<RecordCursor> WiredTigerRecordStore::getCursor(OperationContext*
std::vector<std::unique_ptr<RecordCursor>> WiredTigerRecordStore::getManyCursors(
OperationContext* txn) const {
std::vector<std::unique_ptr<RecordCursor>> cursors(1);
- cursors[0] = stdx::make_unique<Cursor>(txn,
- *this,
- /*forward=*/true,
- /*forParallelCollectionScan=*/true);
+ cursors[0] = stdx::make_unique<Cursor>(txn, *this, /*forward=*/true);
return cursors;
}
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_test.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_test.cpp
index 2dd31906af8..38447246664 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_test.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_test.cpp
@@ -735,7 +735,7 @@ TEST(WiredTigerRecordStoreTest, CappedCursorRollover) {
}
// cursor should now be dead
- ASSERT_FALSE(cursor->restore(cursorCtx.get()));
+ ASSERT_FALSE(cursor->restore());
ASSERT(!cursor->next());
}
@@ -871,7 +871,7 @@ TEST(WiredTigerRecordStoreTest, CappedCursorYieldFirst) {
// See that things work if you yield before you first call getNext().
cursor->savePositioned();
cursorCtx->recoveryUnit()->abandonSnapshot();
- ASSERT_TRUE(cursor->restore(cursorCtx.get()));
+ ASSERT_TRUE(cursor->restore());
auto record = cursor->next();
ASSERT_EQ(loc1, record->id);
ASSERT(!cursor->next());
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.cpp
index 8ee03af4311..cdc9981df78 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.cpp
@@ -378,19 +378,6 @@ void WiredTigerRecoveryUnit::_txnOpen(OperationContext* opCtx) {
_active = true;
}
-void WiredTigerRecoveryUnit::beingReleasedFromOperationContext() {
- LOG(2) << "WiredTigerRecoveryUnit::beingReleased";
- _currentlySquirreled = true;
- if (_active == false && !wt_keeptxnopen()) {
- _commit();
- }
-}
-void WiredTigerRecoveryUnit::beingSetOnOperationContext() {
- LOG(2) << "WiredTigerRecoveryUnit::broughtBack";
- _currentlySquirreled = false;
-}
-
-
// ---------------------
WiredTigerCursor::WiredTigerCursor(const std::string& uri,
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.h b/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.h
index d89ef1f3964..edd2085db29 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.h
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.h
@@ -65,9 +65,6 @@ public:
virtual void registerChange(Change*);
- virtual void beingReleasedFromOperationContext();
- virtual void beingSetOnOperationContext();
-
virtual void abandonSnapshot();
// un-used API
@@ -80,6 +77,9 @@ public:
virtual SnapshotId getSnapshotId() const;
Status setReadFromMajorityCommittedSnapshot() final;
+ bool isReadingFromMajorityCommittedSnapshot() final {
+ return _readFromMajorityCommittedSnapshot;
+ }
// ---- WT STUFF