diff --git a/arangod/Cluster/TraverserEngine.h b/arangod/Cluster/TraverserEngine.h index e40972f132..8b59df2e35 100644 --- a/arangod/Cluster/TraverserEngine.h +++ b/arangod/Cluster/TraverserEngine.h @@ -49,7 +49,7 @@ struct TraverserOptions; class TraverserEngine { friend class TraverserEngineRegistry; - private: + protected: // These are private on purpose. // Only the Registry (friend) is allowed // to create and destroy engines. @@ -61,7 +61,6 @@ class TraverserEngine { public: virtual ~TraverserEngine(); - public: // The engine is NOT copyable. TraverserEngine(TraverserEngine const&) = delete; diff --git a/arangod/Indexes/HashIndex.h b/arangod/Indexes/HashIndex.h index 30094b2a0f..253481107c 100644 --- a/arangod/Indexes/HashIndex.h +++ b/arangod/Indexes/HashIndex.h @@ -28,6 +28,7 @@ #include "Basics/AssocMulti.h" #include "Basics/AssocUnique.h" #include "Basics/VelocyPackHelper.h" +#include "Basics/fasthash.h" #include "Indexes/PathBasedIndex.h" #include "Indexes/IndexIterator.h" #include "Utils/Transaction.h" diff --git a/arangod/Utils/Transaction.cpp b/arangod/Utils/Transaction.cpp index 319d7bc3bf..4f03614f42 100644 --- a/arangod/Utils/Transaction.cpp +++ b/arangod/Utils/Transaction.cpp @@ -986,7 +986,9 @@ void Transaction::extractKeyAndRevFromDocument(VPackSlice slice, VPackSlice revSlice(p + 1); if (revSlice.isString()) { bool isOld; - revisionId = TRI_StringToRid(revSlice.copyString(), isOld); + VPackValueLength l; + char const* p = revSlice.getString(l); + revisionId = TRI_StringToRid(p, l, isOld); } else if (revSlice.isNumber()) { revisionId = revSlice.getNumericValue(); } @@ -1002,10 +1004,48 @@ void Transaction::extractKeyAndRevFromDocument(VPackSlice slice, } // fall back to regular lookup - keySlice = slice.get(StaticStrings::KeyString); - bool isOld; - revisionId = TRI_StringToRid(slice.get(StaticStrings::RevString).copyString(), - isOld); + { + keySlice = slice.get(StaticStrings::KeyString); + bool isOld; + VPackValueLength l; + char const* p = slice.get(StaticStrings::RevString).getString(l); + revisionId = TRI_StringToRid(p, l, isOld); + } +} + +////////////////////////////////////////////////////////////////////////////// +/// @brief extract _rev from a database document +////////////////////////////////////////////////////////////////////////////// + +TRI_voc_rid_t Transaction::extractRevFromDocument(VPackSlice slice) { + TRI_ASSERT(slice.isObject()); + TRI_ASSERT(slice.length() >= 2); + + uint8_t const* p = slice.begin() + slice.findDataOffset(slice.head()); + VPackValueLength count = 0; + + while (*p <= basics::VelocyPackHelper::ToAttribute && ++count <= 5) { + if (*p == basics::VelocyPackHelper::RevAttribute) { + VPackSlice revSlice(p + 1); + if (revSlice.isString()) { + bool isOld; + VPackValueLength l; + char const* p = revSlice.getString(l); + return TRI_StringToRid(p, l, isOld); + } else if (revSlice.isNumber()) { + return revSlice.getNumericValue(); + } + // invalid type for revision id + return 0; + } + // skip over the attribute name + ++p; + // skip over the attribute value + p += VPackSlice(p).byteSize(); + } + + TRI_ASSERT(false); + return 0; } ////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Utils/Transaction.h b/arangod/Utils/Transaction.h index d94fe2283d..3be19b3174 100644 --- a/arangod/Utils/Transaction.h +++ b/arangod/Utils/Transaction.h @@ -359,6 +359,12 @@ class Transaction { static void extractKeyAndRevFromDocument(VPackSlice slice, VPackSlice& keySlice, TRI_voc_rid_t& revisionId); + + ////////////////////////////////////////////////////////////////////////////// + /// @brief extract _rev from a database document + ////////////////////////////////////////////////////////////////////////////// + + static TRI_voc_rid_t extractRevFromDocument(VPackSlice slice); ////////////////////////////////////////////////////////////////////////////// /// @brief read any (random) document diff --git a/arangod/V8Server/v8-query.cpp b/arangod/V8Server/v8-query.cpp index bd5ac9ecb7..32a883c04a 100644 --- a/arangod/V8Server/v8-query.cpp +++ b/arangod/V8Server/v8-query.cpp @@ -26,6 +26,7 @@ #include "Aql/QueryResultV8.h" #include "Basics/StaticStrings.h" #include "Basics/VelocyPackHelper.h" +#include "Basics/fasthash.h" #include "Indexes/GeoIndex.h" #include "Utils/OperationCursor.h" #include "Utils/SingleCollectionTransaction.h" diff --git a/arangod/VocBase/LogicalCollection.cpp b/arangod/VocBase/LogicalCollection.cpp index 405a6f5415..2003389c37 100644 --- a/arangod/VocBase/LogicalCollection.cpp +++ b/arangod/VocBase/LogicalCollection.cpp @@ -1913,7 +1913,9 @@ int LogicalCollection::update(Transaction* trx, VPackSlice const newSlice, return TRI_ERROR_ARANGO_DOCUMENT_REV_BAD; } bool isOld; - revisionId = TRI_StringToRid(oldRev.copyString(), isOld); + VPackValueLength l; + char const* p = oldRev.getString(l); + revisionId = TRI_StringToRid(p, l, isOld); if (isOld) { // Do not tolerate old revision IDs revisionId = TRI_HybridLogicalClock(); @@ -2067,7 +2069,9 @@ int LogicalCollection::replace(Transaction* trx, VPackSlice const newSlice, return TRI_ERROR_ARANGO_DOCUMENT_REV_BAD; } bool isOld; - revisionId = TRI_StringToRid(oldRev.copyString(), isOld); + VPackValueLength l; + char const* p = oldRev.getString(l); + revisionId = TRI_StringToRid(p, l, isOld); if (isOld) { // Do not tolerate old revision ticks: revisionId = TRI_HybridLogicalClock(); @@ -2183,7 +2187,9 @@ int LogicalCollection::remove(arangodb::Transaction* trx, revisionId = TRI_HybridLogicalClock(); } else { bool isOld; - revisionId = TRI_StringToRid(oldRev.copyString(), isOld); + VPackValueLength l; + char const* p = oldRev.getString(l); + revisionId = TRI_StringToRid(p, l, isOld); if (isOld) { // Do not tolerate old revisions revisionId = TRI_HybridLogicalClock(); @@ -3090,7 +3096,9 @@ int LogicalCollection::newObjectForInsert( return TRI_ERROR_ARANGO_DOCUMENT_REV_BAD; } bool isOld; - TRI_voc_rid_t oldRevision = TRI_StringToRid(oldRev.copyString(), isOld); + VPackValueLength l; + char const* p = oldRev.getString(l); + TRI_voc_rid_t oldRevision = TRI_StringToRid(p, l, isOld); if (isOld) { oldRevision = TRI_HybridLogicalClock(); } diff --git a/arangod/VocBase/MasterPointer.h b/arangod/VocBase/MasterPointer.h index d6e0c3c3dd..28feb8882b 100644 --- a/arangod/VocBase/MasterPointer.h +++ b/arangod/VocBase/MasterPointer.h @@ -26,7 +26,7 @@ #include "Basics/Common.h" #include "Basics/StaticStrings.h" -#include "Basics/fasthash.h" +#include "Utils/Transaction.h" #include "VocBase/DatafileHelper.h" #include "VocBase/voc-types.h" @@ -152,7 +152,7 @@ struct TRI_doc_mptr_t { // return the marker's revision id as string slice or None slice if not there TRI_voc_rid_t revisionId() const { - return TRI_ExtractRevisionId(VPackSlice(vpack())); + return arangodb::Transaction::extractRevFromDocument(VPackSlice(vpack())); } }; diff --git a/arangod/VocBase/PathEnumerator.cpp b/arangod/VocBase/PathEnumerator.cpp index 818b412121..00e333d1ae 100644 --- a/arangod/VocBase/PathEnumerator.cpp +++ b/arangod/VocBase/PathEnumerator.cpp @@ -53,6 +53,7 @@ bool DepthFirstEnumerator::next() { _edgeCursors.emplace(cursor); } } else { + TRI_ASSERT(!_enumeratedPath.edges.empty()); // This path is at the end. cut the last step _enumeratedPath.vertices.pop_back(); _enumeratedPath.edges.pop_back(); @@ -70,6 +71,7 @@ bool DepthFirstEnumerator::next() { _returnedEdges.emplace(_enumeratedPath.edges.back()); } else { _traverser->_filteredPaths++; + TRI_ASSERT(!_enumeratedPath.edges.empty()); _enumeratedPath.edges.pop_back(); continue; } @@ -79,6 +81,7 @@ bool DepthFirstEnumerator::next() { _enumeratedPath.edges.size() - 1, cursorId)) { // This edge does not pass the filtering + TRI_ASSERT(!_enumeratedPath.edges.empty()); _enumeratedPath.edges.pop_back(); continue; } @@ -98,6 +101,7 @@ bool DepthFirstEnumerator::next() { if (!foundOnce) { // We found it and it was not the last element (expected) // This edge is allready on the path + TRI_ASSERT(!_enumeratedPath.edges.empty()); _enumeratedPath.edges.pop_back(); continue; } @@ -123,6 +127,7 @@ bool DepthFirstEnumerator::next() { if (!foundOnce) { // We found it and it was not the last element (expected) // This vertex is allready on the path + TRI_ASSERT(!_enumeratedPath.edges.empty()); _enumeratedPath.vertices.pop_back(); _enumeratedPath.edges.pop_back(); continue; @@ -136,13 +141,16 @@ bool DepthFirstEnumerator::next() { return true; } // Vertex Invalid. Revoke edge + TRI_ASSERT(!_enumeratedPath.edges.empty()); _enumeratedPath.edges.pop_back(); continue; } else { // cursor is empty. _edgeCursors.pop(); - _enumeratedPath.edges.pop_back(); - _enumeratedPath.vertices.pop_back(); + if (!_enumeratedPath.edges.empty()) { + _enumeratedPath.edges.pop_back(); + _enumeratedPath.vertices.pop_back(); + } } } if (_edgeCursors.empty()) { diff --git a/arangod/VocBase/vocbase.cpp b/arangod/VocBase/vocbase.cpp index 65b0788d70..e4298e9945 100644 --- a/arangod/VocBase/vocbase.cpp +++ b/arangod/VocBase/vocbase.cpp @@ -1250,7 +1250,9 @@ TRI_voc_rid_t TRI_ExtractRevisionId(VPackSlice slice) { VPackSlice r(slice.get(StaticStrings::RevString)); if (r.isString()) { bool isOld; - return TRI_StringToRid(r.copyString(), isOld); + VPackValueLength l; + char const* p = r.getString(l); + return TRI_StringToRid(p, l, isOld); } if (r.isInteger()) { return r.getNumber(); @@ -1325,7 +1327,15 @@ TRI_voc_rid_t TRI_StringToRid(char const* p, size_t len, bool& isOld) { if (len > 0 && *p >= '1' && *p <= '9') { // Remove this case before the year 3887 AD because then it will // start to clash with encoded timestamps: - TRI_voc_rid_t r = arangodb::basics::StringUtils::uint64(p, len); + char const* e = p + len; + TRI_voc_rid_t r = 0; + do { + r += *p - '0'; + if (++p == e) { + break; + } + r *= 10; + } while (true); if (r > tickLimit) { // An old tick value that could be confused with a time stamp LOG(WARN) diff --git a/arangod/Wal/DocumentOperation.h b/arangod/Wal/DocumentOperation.h index 7a2fbac34c..4bfa10691f 100644 --- a/arangod/Wal/DocumentOperation.h +++ b/arangod/Wal/DocumentOperation.h @@ -38,7 +38,9 @@ struct DocumentOperation { TRI_ASSERT(marker != nullptr); VPackSlice s(static_cast(marker->vpack())); bool isOld; - rid = TRI_StringToRid(s.get(StaticStrings::RevString).copyString(), isOld); + VPackValueLength l; + char const* p = s.get(StaticStrings::RevString).getString(l); + rid = TRI_StringToRid(p, l, isOld); } ~DocumentOperation() {