diff --git a/arangod/MMFiles/MMFilesCollection.cpp b/arangod/MMFiles/MMFilesCollection.cpp index e9af5b753e..b5ea670171 100644 --- a/arangod/MMFiles/MMFilesCollection.cpp +++ b/arangod/MMFiles/MMFilesCollection.cpp @@ -1558,7 +1558,7 @@ int MMFilesCollection::update(arangodb::transaction::Methods* trx, if (newSlice.isObject()) { expectedRev = TRI_ExtractRevisionId(newSlice); } - int res = _logicalCollection->checkRevision(trx, expectedRev, prevRev); + int res = checkRevision(trx, expectedRev, prevRev); if (res != TRI_ERROR_NO_ERROR) { return res; } @@ -1616,9 +1616,8 @@ int MMFilesCollection::update(arangodb::transaction::Methods* trx, result.clear(); } - res = _logicalCollection->updateDocument(trx, oldRevisionId, oldDoc, - revisionId, newDoc, operation, - marker, options.waitForSync); + res = updateDocument(trx, oldRevisionId, oldDoc, revisionId, newDoc, + operation, marker, options.waitForSync); } catch (basics::Exception const& ex) { res = ex.code(); } catch (std::bad_alloc const&) { @@ -1690,7 +1689,7 @@ int MMFilesCollection::replace( if (newSlice.isObject()) { expectedRev = TRI_ExtractRevisionId(newSlice); } - int res = _logicalCollection->checkRevision(trx, expectedRev, prevRev); + int res = checkRevision(trx, expectedRev, prevRev); if (res != TRI_ERROR_NO_ERROR) { return res; } @@ -1739,9 +1738,8 @@ int MMFilesCollection::replace( result.clear(); } - res = _logicalCollection->updateDocument(trx, oldRevisionId, oldDoc, - revisionId, newDoc, operation, - marker, options.waitForSync); + res = updateDocument(trx, oldRevisionId, oldDoc, revisionId, newDoc, + operation, marker, options.waitForSync); } catch (basics::Exception const& ex) { res = ex.code(); } catch (std::bad_alloc const&) { @@ -1836,8 +1834,7 @@ int MMFilesCollection::remove(arangodb::transaction::Methods* trx, VPackSlice co // Check old revision: if (!options.ignoreRevs && slice.isObject()) { TRI_voc_rid_t expectedRevisionId = TRI_ExtractRevisionId(slice); - int res = _logicalCollection->checkRevision(trx, expectedRevisionId, - oldRevisionId); + int res = checkRevision(trx, expectedRevisionId, oldRevisionId); if (res != TRI_ERROR_NO_ERROR) { return res; @@ -2018,4 +2015,70 @@ int MMFilesCollection::lookupDocument(transaction::Methods* trx, return TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND; } +/// @brief updates an existing document, low level worker +/// the caller must make sure the write lock on the collection is held +int MMFilesCollection::updateDocument( + transaction::Methods* trx, TRI_voc_rid_t oldRevisionId, + VPackSlice const& oldDoc, TRI_voc_rid_t newRevisionId, + VPackSlice const& newDoc, MMFilesDocumentOperation& operation, + MMFilesWalMarker const* marker, bool& waitForSync) { + // remove old document from secondary indexes + // (it will stay in the primary index as the key won't change) + int res = deleteSecondaryIndexes(trx, oldRevisionId, oldDoc, false); + + if (res != TRI_ERROR_NO_ERROR) { + // re-enter the document in case of failure, ignore errors during rollback + insertSecondaryIndexes(trx, oldRevisionId, oldDoc, true); + return res; + } + + // insert new document into secondary indexes + res = insertSecondaryIndexes(trx, newRevisionId, newDoc, false); + + if (res != TRI_ERROR_NO_ERROR) { + // rollback + deleteSecondaryIndexes(trx, newRevisionId, newDoc, true); + insertSecondaryIndexes(trx, oldRevisionId, oldDoc, true); + return res; + } + + // update the index element (primary index only - other index have been + // adjusted) + VPackSlice keySlice(transaction::Methods::extractKeyFromDocument(newDoc)); + MMFilesSimpleIndexElement* element = + _logicalCollection->primaryIndex()->lookupKeyRef(trx, keySlice); + if (element != nullptr && element->revisionId() != 0) { + element->updateRevisionId( + newRevisionId, + static_cast(keySlice.begin() - newDoc.begin())); + } + + operation.indexed(); + + if (oldRevisionId != newRevisionId) { + try { + removeRevision(oldRevisionId, true); + } catch (...) { + } + } + + TRI_IF_FAILURE("UpdateDocumentNoOperation") { return TRI_ERROR_DEBUG; } + + TRI_IF_FAILURE("UpdateDocumentNoOperationExcept") { + THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG); + } + + return static_cast(trx->state())->addOperation(newRevisionId, operation, marker, waitForSync); +} + +/// @brief creates a new entry in the primary index +int LogicalCollection::insertPrimaryIndex(transaction::Methods* trx, + TRI_voc_rid_t revisionId, + VPackSlice const& doc) { + TRI_IF_FAILURE("InsertPrimaryIndex") { return TRI_ERROR_DEBUG; } + + // insert into primary index + return primaryIndex()->insertKey(trx, revisionId, doc); +} + diff --git a/arangod/MMFiles/MMFilesCollection.h b/arangod/MMFiles/MMFilesCollection.h index 020ddccc93..d25ffa4781 100644 --- a/arangod/MMFiles/MMFilesCollection.h +++ b/arangod/MMFiles/MMFilesCollection.h @@ -308,6 +308,13 @@ class MMFilesCollection final : public PhysicalCollection { int lookupDocument(transaction::Methods*, velocypack::Slice const, ManagedDocumentResult& result); + int updateDocument(transaction::Methods*, TRI_voc_rid_t oldRevisionId, + velocypack::Slice const& oldDoc, + TRI_voc_rid_t newRevisionId, + velocypack::Slice const& newDoc, + MMFilesDocumentOperation&, MMFilesWalMarker const*, + bool& waitForSync); + private: mutable arangodb::Ditches _ditches; diff --git a/arangod/VocBase/LogicalCollection.cpp b/arangod/VocBase/LogicalCollection.cpp index 037dd3f00d..b19f8ce8b8 100644 --- a/arangod/VocBase/LogicalCollection.cpp +++ b/arangod/VocBase/LogicalCollection.cpp @@ -2488,80 +2488,6 @@ int LogicalCollection::beginWriteTimed(bool useDeadlockDetector, } } -/// @brief checks the revision of a document -int LogicalCollection::checkRevision(transaction::Methods* trx, TRI_voc_rid_t expected, - TRI_voc_rid_t found) { - if (expected != 0 && found != expected) { - return TRI_ERROR_ARANGO_CONFLICT; - } - return TRI_ERROR_NO_ERROR; -} - -/// @brief updates an existing document, low level worker -/// the caller must make sure the write lock on the collection is held -int LogicalCollection::updateDocument( - transaction::Methods* trx, TRI_voc_rid_t oldRevisionId, - VPackSlice const& oldDoc, TRI_voc_rid_t newRevisionId, - VPackSlice const& newDoc, MMFilesDocumentOperation& operation, - MMFilesWalMarker const* marker, bool& waitForSync) { - // remove old document from secondary indexes - // (it will stay in the primary index as the key won't change) - int res = deleteSecondaryIndexes(trx, oldRevisionId, oldDoc, false); - - if (res != TRI_ERROR_NO_ERROR) { - // re-enter the document in case of failure, ignore errors during rollback - insertSecondaryIndexes(trx, oldRevisionId, oldDoc, true); - return res; - } - - // insert new document into secondary indexes - res = insertSecondaryIndexes(trx, newRevisionId, newDoc, false); - - if (res != TRI_ERROR_NO_ERROR) { - // rollback - deleteSecondaryIndexes(trx, newRevisionId, newDoc, true); - insertSecondaryIndexes(trx, oldRevisionId, oldDoc, true); - return res; - } - - // update the index element (primary index only - other index have been - // adjusted) - VPackSlice keySlice(transaction::Methods::extractKeyFromDocument(newDoc)); - MMFilesSimpleIndexElement* element = primaryIndex()->lookupKeyRef(trx, keySlice); - if (element != nullptr && element->revisionId() != 0) { - element->updateRevisionId( - newRevisionId, - static_cast(keySlice.begin() - newDoc.begin())); - } - - operation.indexed(); - - if (oldRevisionId != newRevisionId) { - try { - removeRevision(oldRevisionId, true); - } catch (...) { - } - } - - TRI_IF_FAILURE("UpdateDocumentNoOperation") { return TRI_ERROR_DEBUG; } - - TRI_IF_FAILURE("UpdateDocumentNoOperationExcept") { - THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG); - } - - return static_cast(trx->state())->addOperation(newRevisionId, operation, marker, waitForSync); -} - -/// @brief creates a new entry in the primary index -int LogicalCollection::insertPrimaryIndex(transaction::Methods* trx, - TRI_voc_rid_t revisionId, - VPackSlice const& doc) { - TRI_IF_FAILURE("InsertPrimaryIndex") { return TRI_ERROR_DEBUG; } - - // insert into primary index - return primaryIndex()->insertKey(trx, revisionId, doc); -} - /// @brief deletes an entry from the primary index int LogicalCollection::deletePrimaryIndex(transaction::Methods* trx, TRI_voc_rid_t revisionId, diff --git a/arangod/VocBase/LogicalCollection.h b/arangod/VocBase/LogicalCollection.h index fdde51d560..93333de112 100644 --- a/arangod/VocBase/LogicalCollection.h +++ b/arangod/VocBase/LogicalCollection.h @@ -447,20 +447,6 @@ class LogicalCollection { // @brief create index with the given definition. bool openIndex(velocypack::Slice const&, transaction::Methods*); - // SECTION: Index access (local only) - // Needs to be moved to SE specific Part - public: - int checkRevision(transaction::Methods*, TRI_voc_rid_t expected, - TRI_voc_rid_t found); - - int updateDocument(transaction::Methods*, TRI_voc_rid_t oldRevisionId, - velocypack::Slice const& oldDoc, - TRI_voc_rid_t newRevisionId, - velocypack::Slice const& newDoc, - MMFilesDocumentOperation&, MMFilesWalMarker const*, - bool& waitForSync); - - private: // TODO REMOVE HERE is now in SE Collection int insertPrimaryIndex(transaction::Methods*, TRI_voc_rid_t revisionId, velocypack::Slice const&); diff --git a/arangod/VocBase/PhysicalCollection.cpp b/arangod/VocBase/PhysicalCollection.cpp index c0c418f0b4..27efee6375 100644 --- a/arangod/VocBase/PhysicalCollection.cpp +++ b/arangod/VocBase/PhysicalCollection.cpp @@ -40,7 +40,7 @@ using namespace arangodb; void PhysicalCollection::mergeObjectsForUpdate( transaction::Methods* trx, VPackSlice const& oldValue, VPackSlice const& newValue, bool isEdgeCollection, std::string const& rev, - bool mergeObjects, bool keepNull, VPackBuilder& b) { + bool mergeObjects, bool keepNull, VPackBuilder& b) const { b.openObject(); VPackSlice keySlice = oldValue.get(StaticStrings::KeyString); @@ -171,7 +171,7 @@ void PhysicalCollection::newObjectForReplace( transaction::Methods* trx, VPackSlice const& oldValue, VPackSlice const& newValue, VPackSlice const& fromSlice, VPackSlice const& toSlice, bool isEdgeCollection, std::string const& rev, - VPackBuilder& builder) { + VPackBuilder& builder) const { builder.openObject(); // add system attributes first, in this order: @@ -203,3 +203,13 @@ void PhysicalCollection::newObjectForReplace( builder.close(); } + +/// @brief checks the revision of a document +int PhysicalCollection::checkRevision(transaction::Methods* trx, + TRI_voc_rid_t expected, + TRI_voc_rid_t found) const { + if (expected != 0 && found != expected) { + return TRI_ERROR_ARANGO_CONFLICT; + } + return TRI_ERROR_NO_ERROR; +} diff --git a/arangod/VocBase/PhysicalCollection.h b/arangod/VocBase/PhysicalCollection.h index 8573cd8f19..731ec9b336 100644 --- a/arangod/VocBase/PhysicalCollection.h +++ b/arangod/VocBase/PhysicalCollection.h @@ -159,7 +159,7 @@ class PhysicalCollection { velocypack::Slice const& newValue, bool isEdgeCollection, std::string const& rev, bool mergeObjects, bool keepNull, - velocypack::Builder& builder); + velocypack::Builder& builder) const; /// @brief new object for replace void newObjectForReplace(transaction::Methods* trx, @@ -168,8 +168,11 @@ class PhysicalCollection { velocypack::Slice const& fromSlice, velocypack::Slice const& toSlice, bool isEdgeCollection, std::string const& rev, - velocypack::Builder& builder); - + velocypack::Builder& builder) const; + + int checkRevision(transaction::Methods* trx, TRI_voc_rid_t expected, + TRI_voc_rid_t found) const; + protected: LogicalCollection* _logicalCollection; };