From b51d95a2dcb4baba377f0331e673e30263ef0ae5 Mon Sep 17 00:00:00 2001 From: Jakub Schmiegel Date: Fri, 29 Sep 2017 09:50:26 +0200 Subject: [PATCH] Insert to index with read lock and write lock --- src/pmse_change.cpp | 2 +- src/pmse_index_cursor.cpp | 40 ++++----- src/pmse_index_cursor.h | 12 +-- src/pmse_sorted_data_interface.cpp | 2 +- src/pmse_tree.cpp | 128 +++++++++++++++++++++-------- src/pmse_tree.h | 17 ++-- 6 files changed, 128 insertions(+), 73 deletions(-) diff --git a/src/pmse_change.cpp b/src/pmse_change.cpp index 79ad234..a8f7361 100644 --- a/src/pmse_change.cpp +++ b/src/pmse_change.cpp @@ -161,7 +161,7 @@ void InsertIndexChange::rollback() { try { transaction::exec_tx(_pop, [this] { IndexKeyEntry entry(_key.getOwned(), _loc); - _tree->remove(_pop, entry, _dupsAllowed, _desc->keyPattern(), nullptr); + _tree->remove(_pop, entry, _dupsAllowed, _desc->keyPattern()); }); } catch (std::exception &e) { log() << e.what(); diff --git a/src/pmse_index_cursor.cpp b/src/pmse_index_cursor.cpp index b67444a..395edf1 100644 --- a/src/pmse_index_cursor.cpp +++ b/src/pmse_index_cursor.cpp @@ -55,21 +55,20 @@ PmseCursor::PmseCursor(OperationContext* txn, bool isForward, _ordering(ordering), _first(tree->_first), _last(tree->_last), - _unique(unique), _tree(tree), _endPositionIsDataEnd(false), _locateFoundDataEnd(false), - _wasMoved(false), _eofRestore(false) {} // Find entry in tree which is equal or bigger to input entry // Locates input cursor on that entry // Sets _locateFoundDataEnd when result is after last entry in tree -bool PmseCursor::lower_bound(IndexKeyEntry entry, CursorObject& cursor, std::list& locks) { +bool PmseCursor::lower_bound(IndexKeyEntry entry, CursorObject& cursor, std::list& locks) { uint64_t i = 0; int64_t cmp; - (_tree->_root->_pmutex).lock_shared(); persistent_ptr current = _tree->_root; + (current->_pmutex).lock_shared(); + persistent_ptr child; while (!current->is_leaf) { i = 0; while (i < current->num_keys) { @@ -81,11 +80,12 @@ bool PmseCursor::lower_bound(IndexKeyEntry entry, CursorObject& cursor, std::lis break; } } - (current->children_array[i]->_pmutex).lock_shared(); - current = current->children_array[i]; - current->parent->_pmutex.unlock_shared(); + child = current->children_array[i]; + child->_pmutex.lock_shared(); + current->_pmutex.unlock_shared(); + current = child; } - locks.push_back(LocksPtr(&(current->_pmutex))); + locks.push_back(&(current->_pmutex)); i = 0; IndexEntryComparison c(Ordering::make(_ordering)); @@ -100,8 +100,10 @@ bool PmseCursor::lower_bound(IndexKeyEntry entry, CursorObject& cursor, std::lis cursor.index = 0; return true; } - _locateFoundDataEnd = true; - return false; + else{ + _locateFoundDataEnd = true; + return false; + } } cursor.node = current; cursor.index = i; @@ -133,7 +135,7 @@ bool PmseCursor::atOrPastEndPointAfterSeeking() { } } -void PmseCursor::locate(const BSONObj& key, const RecordId& loc, std::list& locks) { +void PmseCursor::locate(const BSONObj& key, const RecordId& loc, std::list& locks) { bool locateFound; CursorObject locateCursor; _isEOF = false; @@ -182,7 +184,7 @@ void PmseCursor::seekEndCursor() { if (!_endState || !_tree->_root) return; - std::list locks; + std::list locks; found = lower_bound(_endState->query, endCursor, locks); if (_locateFoundDataEnd) { _endPositionIsDataEnd = true; @@ -251,7 +253,7 @@ bool PmseCursor::atEndPoint() { boost::optional PmseCursor::next( RequestedInfo parts = kKeyAndLoc) { - std::list locks; + std::list locks; if (_wasRestore) { locate(_cursorKey, RecordId(_cursorId), locks); moveToNext(); @@ -319,14 +321,14 @@ void PmseCursor::moveToNext() { } } -void PmseCursor::unlockTree(std::list& locks) { - std::list::const_iterator iterator; +void PmseCursor::unlockTree(std::list& locks) { + std::list::const_iterator iterator; try { for (iterator = locks.begin(); iterator != locks.end(); ++iterator) { - iterator->ptr->unlock_shared(); + (*iterator)->unlock_shared(); } locks.erase(locks.begin(), locks.end()); - }catch(std::exception &e) {} + } catch (std::exception &e) {} } boost::optional PmseCursor::seek(const BSONObj& key, @@ -334,7 +336,7 @@ boost::optional PmseCursor::seek(const BSONObj& key, RequestedInfo parts = kKeyAndLoc) { if (!_tree->_root) return {}; - std::list locks; + std::list locks; if (key.isEmpty()) { if (inclusive) { @@ -372,7 +374,7 @@ boost::optional PmseCursor::seek(const IndexSeekPoint& seekPoint, const BSONObj query = IndexEntryComparison::makeQueryObject(seekPoint, _forward); auto discriminator = RecordId::min(); - std::list locks; + std::list locks; locate(query, _forward ? RecordId::min() : RecordId::max(), locks); if (_isEOF) { diff --git a/src/pmse_index_cursor.h b/src/pmse_index_cursor.h index 2eda317..3887a19 100644 --- a/src/pmse_index_cursor.h +++ b/src/pmse_index_cursor.h @@ -95,11 +95,10 @@ class PmseCursor final : public SortedDataInterface::Cursor { } return bb.obj(); } - void locate(const BSONObj& key, const RecordId& loc, std::list& locks); - void unlockTree(std::list& locks); + void locate(const BSONObj& key, const RecordId& loc, std::list& locks); + void unlockTree(std::list& locks); void seekEndCursor(); - bool lower_bound(IndexKeyEntry entry, CursorObject& cursor, std::list& locks); - bool previous(CursorObject&); + bool lower_bound(IndexKeyEntry entry, CursorObject& cursor, std::list& locks); void moveToNext(); bool atOrPastEndPointAfterSeeking(); bool atEndPoint(); @@ -107,7 +106,6 @@ class PmseCursor final : public SortedDataInterface::Cursor { const BSONObj& _ordering; persistent_ptr _first; persistent_ptr _last; - const bool _unique; persistent_ptr _tree; bool _isEOF = true; /* @@ -115,9 +113,6 @@ class PmseCursor final : public SortedDataInterface::Cursor { */ boost::optional _endPosition; CursorObject _cursor; - CursorObject _returnValue; - static IndexKeyEntry_PM min; - static IndexKeyEntry_PM max; struct EndState { EndState(BSONObj key, RecordId loc) : query(std::move(key), loc) {} @@ -128,7 +123,6 @@ class PmseCursor final : public SortedDataInterface::Cursor { int64_t _cursorId; bool _endPositionIsDataEnd; bool _locateFoundDataEnd; - bool _wasMoved; bool _eofRestore; bool _wasRestore = false; }; diff --git a/src/pmse_sorted_data_interface.cpp b/src/pmse_sorted_data_interface.cpp index 0e28c33..7204ded 100644 --- a/src/pmse_sorted_data_interface.cpp +++ b/src/pmse_sorted_data_interface.cpp @@ -114,7 +114,7 @@ void PmseSortedDataInterface::unindex(OperationContext* txn, const BSONObj& key, IndexKeyEntry entry(key.getOwned(), loc); try { transaction::exec_tx(_pm_pool, [this, &entry, dupsAllowed, txn] { - _tree->remove(_pm_pool, entry, dupsAllowed, _desc->keyPattern(), txn); + _tree->remove(_pm_pool, entry, dupsAllowed, _desc->keyPattern()); }); } catch (std::exception &e) { log() << e.what(); diff --git a/src/pmse_tree.cpp b/src/pmse_tree.cpp index 24aa8ad..6f2d644 100644 --- a/src/pmse_tree.cpp +++ b/src/pmse_tree.cpp @@ -73,12 +73,11 @@ BSONObj IndexKeyEntry_PM::getBSON() { } bool PmseTree::remove(pool_base pop, IndexKeyEntry& entry, - bool dupsAllowed, const BSONObj& ordering, - OperationContext* txn = nullptr) { + bool dupsAllowed, const BSONObj& ordering) { persistent_ptr node; uint64_t i; int64_t cmp; - std::list locks; + std::list locks; persistent_ptr lockNode; _ordering = ordering; // find node with key @@ -498,17 +497,35 @@ bool PmseTree::nodeIsSafeForOperation(persistent_ptr node, bool in persistent_ptr PmseTree::locateLeafWithKeyPM( persistent_ptr node, IndexKeyEntry& entry, - const BSONObj& ordering, std::list& locks, + const BSONObj& ordering, std::list& locks, persistent_ptr& lockNode, bool insert) { uint64_t i = 0; int64_t cmp; - (node->_pmutex).lock(); - locks.push_back(LocksPtr(&(node->_pmutex))); - persistent_ptr current = node; + persistent_ptr current = _root; + persistent_ptr child; if (current == nullptr) - return current; - + return nullptr; + + if (current->is_leaf){ + (current->_pmutex).lock(); + if (current.raw_ptr()->off != _root.raw_ptr()->off) + { + (current->_pmutex).unlock(); + current = _root; + } + else{ + locks.push_back(&(_root->_pmutex)); + return _root; + } + } + (current->_pmutex).lock_shared(); + if (current.raw_ptr()->off != _root.raw_ptr()->off) + { + (current->_pmutex).unlock_shared(); + (_root->_pmutex).lock_shared(); + current = _root; + } while (!current->is_leaf) { i = 0; while (i < current->num_keys) { @@ -519,12 +536,49 @@ persistent_ptr PmseTree::locateLeafWithKeyPM( break; } } + if (current->children_array[i]->is_leaf){ (current->children_array[i]->_pmutex).lock(); - current = current->children_array[i]; - if (nodeIsSafeForOperation(current, insert)) { - unlockTree(locks); + locks.push_back(&(current->children_array[i]->_pmutex)); + } + else{ + (current->children_array[i]->_pmutex).lock_shared(); + } + + current = current->children_array[i]; + current->parent->_pmutex.unlock_shared(); + } + if (!nodeIsSafeForOperation(current, insert)){ + unlockTree(locks); + current = _root; + (current->_pmutex).lock(); + while (current.raw_ptr()->off != _root.raw_ptr()->off) + { + (current->_pmutex).unlock(); + current = _root; + (current->_pmutex).lock(); + } + locks.push_back(&(current->_pmutex)); + if (current == nullptr) + return nullptr; + + while (!current->is_leaf) { + i = 0; + while (i < current->num_keys) { + cmp = IndexKeyEntry_PM::compareEntries(entry, current->keys[i], ordering); + if (cmp >= 0) { + i++; + } else { + break; + } + } + child = current->children_array[i]; + (child->_pmutex).lock(); + current = child; + if (nodeIsSafeForOperation(current, insert)) { + unlockTree(locks); + } + locks.push_back(&(current->_pmutex)); } - locks.push_back(LocksPtr(&(current->_pmutex))); } if (current->next) { current->next->_pmutex.lock(); @@ -533,6 +587,7 @@ persistent_ptr PmseTree::locateLeafWithKeyPM( return current; } + /* * Insert leaf into correct place. */ @@ -572,7 +627,8 @@ uint64_t PmseTree::cut(uint64_t length) { */ persistent_ptr PmseTree::splitFullNodeAndInsert( pool_base pop, persistent_ptr node, - IndexKeyEntry& entry, const BSONObj& _ordering) { + IndexKeyEntry& entry, const BSONObj& _ordering, + std::list& locks) { persistent_ptr new_leaf; IndexKeyEntry_PM new_entry; uint64_t insertion_index = 0; @@ -633,6 +689,11 @@ persistent_ptr PmseTree::splitFullNodeAndInsert( new_leaf->parent = node->parent; new_entry = new_leaf->keys[0]; new_root = insertIntoNodeParent(pop, _root, node, new_entry, new_leaf); + if(new_root.raw_ptr()->off!=_root.raw_ptr()->off) + { + new_root->_pmutex.lock(); + locks.push_back(&(new_root->_pmutex)); + } new_leaf->_pmutex.unlock(); _last = new_leaf; return new_root; @@ -788,11 +849,11 @@ persistent_ptr PmseTree::allocateNewRoot( return new_root; } -void PmseTree::unlockTree(std::list& locks) { - std::list::const_iterator iterator; +void PmseTree::unlockTree(std::list& locks) { + std::list::const_iterator iterator; try { for (iterator = locks.begin(); iterator != locks.end(); ++iterator) { - iterator->ptr->unlock(); + (*iterator)->unlock(); } locks.erase(locks.begin(), locks.end()); }catch(std::exception &e) {} @@ -804,25 +865,26 @@ Status PmseTree::insert(pool_base pop, IndexKeyEntry& entry, Status status = Status::OK(); uint64_t i; int64_t cmp; - std::list locks; + std::list locks; persistent_ptr lockNode; - if (!_root) { - // root not allocated yet - try { - transaction::exec_tx(pop, [this, &entry] { - _root = makeTreeRoot(entry); - _first = _root; - _last = _root; - }); - } catch (std::exception &e) { - log() << "Index: " << e.what(); - status = Status(ErrorCodes::CommandFailed, e.what()); + stdx::lock_guard guard(globalMutex); + if(!_root){ + // root not allocated yet + try { + transaction::exec_tx(pop, [this, &entry] { + _root = makeTreeRoot(entry); + _first = _root; + _last = _root; + }); + } catch (std::exception &e) { + log() << "Index: " << e.what(); + status = Status(ErrorCodes::CommandFailed, e.what()); + } + return status; } - return status; } node = locateLeafWithKeyPM(_root, entry, ordering, locks, lockNode, true); - /* * Duplicate key check */ @@ -870,8 +932,8 @@ Status PmseTree::insert(pool_base pop, IndexKeyEntry& entry, * splitting */ try { - transaction::exec_tx(pop, [this, pop, &node, &entry, ordering] { - _root = splitFullNodeAndInsert(pop, node, entry, ordering); + transaction::exec_tx(pop, [this, pop, &node, &entry, ordering, &locks] { + _root = splitFullNodeAndInsert(pop, node, entry, ordering, locks); }); } catch (std::exception &e) { log() << "Index: " << e.what(); diff --git a/src/pmse_tree.h b/src/pmse_tree.h index a876095..ffa9854 100644 --- a/src/pmse_tree.h +++ b/src/pmse_tree.h @@ -42,6 +42,7 @@ #include #include #include +#include #include "mongo/db/storage/sorted_data_interface.h" #include "mongo/db/index/index_descriptor.h" @@ -97,12 +98,6 @@ struct CursorObject { uint64_t index; }; -class LocksPtr { - public: - LocksPtr(nvml::obj::shared_mutex *_ptr) : ptr(_ptr) {} - nvml::obj::shared_mutex *ptr; -}; - class PmseTree { friend class PmseCursor; @@ -110,14 +105,15 @@ class PmseTree { Status insert(pool_base pop, IndexKeyEntry& entry, const BSONObj& _ordering, bool dupsAllowed); bool remove(pool_base pop, IndexKeyEntry& entry, - bool dupsAllowed, const BSONObj& _ordering, OperationContext* txn); + bool dupsAllowed, const BSONObj& _ordering); uint64_t countElements(); bool isEmpty(); private: - void unlockTree(std::list& locks); + nvml::obj::mutex globalMutex; + void unlockTree(std::list& locks); bool nodeIsSafeForOperation(persistent_ptr node, bool insert); uint64_t cut(uint64_t length); int64_t getNeighborIndex(persistent_ptr node); @@ -137,11 +133,12 @@ class PmseTree { const BSONObj& _ordering); persistent_ptr locateLeafWithKeyPM( persistent_ptr node, IndexKeyEntry& entry, - const BSONObj& _ordering, std::list& locks, + const BSONObj& _ordering, std::list& locks, persistent_ptr& lockNode, bool insert); persistent_ptr splitFullNodeAndInsert( pool_base pop, persistent_ptr node, - IndexKeyEntry& entry, const BSONObj& _ordering); + IndexKeyEntry& entry, const BSONObj& _ordering, + std::list& locks); persistent_ptr insertIntoNodeParent( pool_base pop, persistent_ptr root, persistent_ptr node, IndexKeyEntry_PM& new_key,