mirror of https://gitee.com/bigwinds/arangodb
faster lookup for _key attribute
This commit is contained in:
parent
6912d6a34e
commit
e478c1ae11
|
@ -33,7 +33,6 @@ using namespace arangodb::aql;
|
|||
AttributeAccessor::AttributeAccessor(
|
||||
std::vector<std::string> const& attributeParts, Variable const* variable)
|
||||
: _attributeParts(attributeParts),
|
||||
_combinedName(),
|
||||
_variable(variable) {
|
||||
|
||||
TRI_ASSERT(_variable != nullptr);
|
||||
|
@ -59,7 +58,13 @@ AqlValue AttributeAccessor::get(arangodb::AqlTransaction* trx,
|
|||
for (auto it = vars.begin(); it != vars.end(); ++it, ++i) {
|
||||
if ((*it)->id == _variable->id) {
|
||||
// get the AQL value
|
||||
return argv->getValueReference(startPos, regs[i]).get(trx, _attributeParts, mustDestroy, true);
|
||||
if (_attributeParts.size() == 1) {
|
||||
// use optimized version for single attribute (e.g. variable.attr)
|
||||
return argv->getValueReference(startPos, regs[i]).get(trx, _attributeParts[0], mustDestroy, true);
|
||||
} else {
|
||||
// use general version for multiple attributes (e.g. variable.attr.subattr)
|
||||
return argv->getValueReference(startPos, regs[i]).get(trx, _attributeParts, mustDestroy, true);
|
||||
}
|
||||
}
|
||||
// fall-through intentional
|
||||
}
|
||||
|
|
|
@ -54,9 +54,6 @@ class AttributeAccessor {
|
|||
/// @brief the attribute names vector (e.g. [ "a", "b", "c" ] for a.b.c)
|
||||
std::vector<std::string> const _attributeParts;
|
||||
|
||||
/// @brief full attribute name (e.g. "a.b.c")
|
||||
std::string _combinedName;
|
||||
|
||||
/// @brief the accessed variable
|
||||
Variable const* _variable;
|
||||
|
||||
|
|
|
@ -59,10 +59,8 @@ static bool IsEqualKeyElement(void*, uint8_t const* key,
|
|||
if (hash != element->getHash()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
VPackSlice slice(key);
|
||||
VPackSlice other(element->vpack());
|
||||
return other.get(StaticStrings::KeyString).equals(slice);
|
||||
|
||||
return Transaction::extractKeyFromDocument(VPackSlice(element->vpack())).equals(VPackSlice(key));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -75,10 +73,9 @@ static bool IsEqualElementElement(void*, TRI_doc_mptr_t const* left,
|
|||
return false;
|
||||
}
|
||||
|
||||
VPackSlice l(left->vpack());
|
||||
VPackSlice r(right->vpack());
|
||||
|
||||
return l.get(StaticStrings::KeyString).equals(r.get(StaticStrings::KeyString));
|
||||
VPackSlice l = Transaction::extractKeyFromDocument(VPackSlice(left->vpack()));
|
||||
VPackSlice r = Transaction::extractKeyFromDocument(VPackSlice(right->vpack()));
|
||||
return l.equals(r);
|
||||
}
|
||||
|
||||
TRI_doc_mptr_t* PrimaryIndexIterator::next() {
|
||||
|
|
|
@ -384,7 +384,7 @@ bool RestDocumentHandler::modifyDocument(bool isPatch) {
|
|||
opOptions.silent = extractBooleanParameter("silent", false);
|
||||
|
||||
// extract the revision, if single document variant and header given:
|
||||
std::shared_ptr<VPackBuilder> builder(nullptr);
|
||||
std::shared_ptr<VPackBuilder> builder;
|
||||
if (!isArrayCase) {
|
||||
TRI_voc_rid_t revision = 0;
|
||||
bool isValidRevision;
|
||||
|
|
|
@ -673,47 +673,81 @@ std::string Transaction::extractIdString(CollectionNameResolver const* resolver,
|
|||
return std::string(&buffer[0], len + 1 + keyLength);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief quick access to the _key attribute in a database document
|
||||
/// requires _key to be the first attribute in the document
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
VPackSlice Transaction::extractKeyFromDocument(VPackSlice const& slice) {
|
||||
TRI_ASSERT(slice.isObject());
|
||||
// a regular document must have at least the three attributes
|
||||
// _key, _id and _rev (in this order). _key must be the first attribute
|
||||
// however this method may also be called for remove markers, which only
|
||||
// have _key and _rev. therefore the only assertion that we can make
|
||||
// here is that the document at least has two attributes
|
||||
TRI_ASSERT(slice.length() >= 2);
|
||||
|
||||
uint8_t const* p = slice.begin() + slice.findDataOffset(slice.head());
|
||||
|
||||
if (*p == 0x31) {
|
||||
return VPackSlice(p);
|
||||
if (*p == basics::VelocyPackHelper::KeyAttribute) {
|
||||
return VPackSlice(p + 1);
|
||||
}
|
||||
// we actually should not get here. however, if for some reason we do,
|
||||
// we simply fall back to the regular lookup method
|
||||
return slice.get(StaticStrings::KeyString);
|
||||
}
|
||||
|
||||
VPackSlice Transaction::extractIdFromDocument(VPackSlice const& slice) {
|
||||
TRI_ASSERT(slice.isObject());
|
||||
TRI_ASSERT(slice.length() >= 3); // must have at least _key, _id and _rev
|
||||
|
||||
uint8_t const* p = slice.begin() + slice.findDataOffset(slice.head());
|
||||
if (*p == basics::VelocyPackHelper::KeyAttribute) {
|
||||
// _key
|
||||
p += VPackSlice(p).byteSize();
|
||||
if (*p == basics::VelocyPackHelper::IdAttribute) {
|
||||
LOG(ERR) << "fast access to _id";
|
||||
return VPackSlice(p + 1);
|
||||
}
|
||||
}
|
||||
LOG(ERR) << "slow access to _id";
|
||||
return slice.get(StaticStrings::IdString);
|
||||
}
|
||||
|
||||
VPackSlice Transaction::extractFromFromDocument(VPackSlice const& slice) {
|
||||
TRI_ASSERT(slice.isObject());
|
||||
TRI_ASSERT(slice.length() >= 5); // must have at least _key, _id, _from, _to and _rev
|
||||
|
||||
uint8_t const* p = slice.begin() + slice.findDataOffset(slice.head());
|
||||
VPackValueLength l = slice.length();
|
||||
VPackValueLength count = 0;
|
||||
|
||||
while (*p <= 0x35 && count++ < l) {
|
||||
if (*p == 0x35) {
|
||||
return VPackSlice(p);
|
||||
while (*p <= basics::VelocyPackHelper::FromAttribute && ++count <= 3) {
|
||||
if (*p == basics::VelocyPackHelper::FromAttribute) {
|
||||
LOG(ERR) << "fast access to _from";
|
||||
return VPackSlice(p + 1);
|
||||
}
|
||||
p += VPackSlice(p).byteSize();
|
||||
}
|
||||
LOG(ERR) << "slow access to _from";
|
||||
return slice.get(StaticStrings::FromString);
|
||||
}
|
||||
|
||||
VPackSlice Transaction::extractToFromDocument(VPackSlice const& slice) {
|
||||
TRI_ASSERT(slice.isObject());
|
||||
TRI_ASSERT(slice.length() >= 5); // must have at least _key, _id, _from, _to and _rev
|
||||
|
||||
uint8_t const* p = slice.begin() + slice.findDataOffset(slice.head());
|
||||
VPackValueLength l = slice.length();
|
||||
VPackValueLength count = 0;
|
||||
|
||||
while (*p <= 0x34 && count++ < l) {
|
||||
if (*p == 0x34) {
|
||||
return VPackSlice(p);
|
||||
while (*p <= basics::VelocyPackHelper::ToAttribute && ++count <= 4) {
|
||||
if (*p == basics::VelocyPackHelper::ToAttribute) {
|
||||
LOG(ERR) << "quick access to _to";
|
||||
return VPackSlice(p + 1);
|
||||
}
|
||||
p += VPackSlice(p).byteSize();
|
||||
}
|
||||
return slice.get(StaticStrings::FromString);
|
||||
LOG(ERR) << "slow access to _to";
|
||||
return slice.get(StaticStrings::ToString);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1870,7 +1904,7 @@ OperationResult Transaction::removeLocal(std::string const& collectionName,
|
|||
key = value.copyString();
|
||||
size_t pos = key.find('/');
|
||||
if (pos != std::string::npos) {
|
||||
key = key.substr(pos+1);
|
||||
key = key.substr(pos + 1);
|
||||
builder = std::make_shared<VPackBuilder>();
|
||||
builder->add(VPackValue(key));
|
||||
value = builder->slice();
|
||||
|
|
|
@ -283,7 +283,8 @@ class Transaction {
|
|||
static std::string extractIdString(CollectionNameResolver const*,
|
||||
VPackSlice const&, VPackSlice const&);
|
||||
|
||||
VPackSlice extractKeyFromDocument(VPackSlice const&);
|
||||
static VPackSlice extractKeyFromDocument(VPackSlice const&);
|
||||
VPackSlice extractIdFromDocument(VPackSlice const&);
|
||||
VPackSlice extractFromFromDocument(VPackSlice const&);
|
||||
VPackSlice extractToFromDocument(VPackSlice const&);
|
||||
|
||||
|
|
|
@ -392,7 +392,7 @@ static bool Compactifier(TRI_df_marker_t const* marker, void* data,
|
|||
if (type == TRI_DF_MARKER_VPACK_DOCUMENT) {
|
||||
VPackSlice const slice(reinterpret_cast<char const*>(marker) + DatafileHelper::VPackOffset(type));
|
||||
TRI_ASSERT(slice.isObject());
|
||||
VPackSlice const keySlice(slice.get(StaticStrings::KeyString));
|
||||
VPackSlice const keySlice(Transaction::extractKeyFromDocument(slice));
|
||||
TRI_voc_rid_t const rid = std::stoull(slice.get(StaticStrings::RevString).copyString());
|
||||
|
||||
// check if the document is still active
|
||||
|
@ -542,7 +542,7 @@ static bool CalculateSize(TRI_df_marker_t const* marker, void* data,
|
|||
if (type == TRI_DF_MARKER_VPACK_DOCUMENT) {
|
||||
VPackSlice const slice(reinterpret_cast<char const*>(marker) + DatafileHelper::VPackOffset(type));
|
||||
TRI_ASSERT(slice.isObject());
|
||||
VPackSlice const keySlice(slice.get(StaticStrings::KeyString));
|
||||
VPackSlice const keySlice(Transaction::extractKeyFromDocument(slice));
|
||||
TRI_voc_rid_t const rid = std::stoull(slice.get(StaticStrings::RevString).copyString());
|
||||
|
||||
// check if the document is still active
|
||||
|
|
|
@ -287,6 +287,8 @@ struct TRI_df_marker_t {
|
|||
|
||||
};
|
||||
|
||||
static_assert(sizeof(TRI_df_marker_t) == 16, "invalid size for TRI_df_marker_t");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief datafile header marker
|
||||
///
|
||||
|
|
|
@ -786,12 +786,11 @@ static int OpenIteratorHandleDocumentMarker(TRI_df_marker_t const* marker,
|
|||
arangodb::Transaction* trx = state->_trx;
|
||||
|
||||
VPackSlice const slice(reinterpret_cast<char const*>(marker) + DatafileHelper::VPackOffset(TRI_DF_MARKER_VPACK_DOCUMENT));
|
||||
VPackSlice const keySlice = slice.get(StaticStrings::KeyString);
|
||||
std::string const key(keySlice.copyString());
|
||||
VPackSlice const keySlice = Transaction::extractKeyFromDocument(slice);
|
||||
TRI_voc_rid_t const rid = std::stoull(slice.get(StaticStrings::RevString).copyString());
|
||||
|
||||
SetRevision(document, rid, false);
|
||||
document->_keyGenerator->track(key);
|
||||
document->_keyGenerator->track(keySlice.copyString());
|
||||
|
||||
++state->_documents;
|
||||
|
||||
|
@ -890,12 +889,11 @@ static int OpenIteratorHandleDeletionMarker(TRI_df_marker_t const* marker,
|
|||
arangodb::Transaction* trx = state->_trx;
|
||||
|
||||
VPackSlice const slice(reinterpret_cast<char const*>(marker) + DatafileHelper::VPackOffset(TRI_DF_MARKER_VPACK_REMOVE));
|
||||
VPackSlice const keySlice = slice.get(StaticStrings::KeyString);
|
||||
std::string const key(keySlice.copyString());
|
||||
VPackSlice const keySlice = Transaction::extractKeyFromDocument(slice);
|
||||
TRI_voc_rid_t const rid = std::stoull(slice.get(StaticStrings::RevString).copyString());
|
||||
|
||||
document->setLastRevision(rid, false);
|
||||
document->_keyGenerator->track(key);
|
||||
document->_keyGenerator->track(keySlice.copyString());
|
||||
|
||||
++state->_deletions;
|
||||
|
||||
|
@ -3322,7 +3320,7 @@ int TRI_document_collection_t::insert(Transaction* trx, VPackSlice const slice,
|
|||
TRI_ASSERT(slice.isObject());
|
||||
// we can get away with the fast hash function here, as key values are
|
||||
// restricted to strings
|
||||
hash = slice.get(StaticStrings::KeyString).hash();
|
||||
hash = Transaction::extractKeyFromDocument(slice).hash();
|
||||
newSlice = slice;
|
||||
}
|
||||
|
||||
|
@ -4101,8 +4099,7 @@ int TRI_document_collection_t::deletePrimaryIndex(
|
|||
TRI_IF_FAILURE("DeletePrimaryIndex") { return TRI_ERROR_DEBUG; }
|
||||
|
||||
auto found = primaryIndex()->removeKey(
|
||||
trx,
|
||||
VPackSlice(header->vpack()).get(StaticStrings::KeyString));
|
||||
trx, Transaction::extractKeyFromDocument(VPackSlice(header->vpack())));
|
||||
|
||||
if (found == nullptr) {
|
||||
return TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND;
|
||||
|
@ -4424,6 +4421,7 @@ void TRI_document_collection_t::newObjectForRemove(
|
|||
std::string const& rev,
|
||||
VPackBuilder& builder) {
|
||||
|
||||
// create an object consisting of _key and _rev (in this order)
|
||||
builder.openObject();
|
||||
if (oldValue.isString()) {
|
||||
builder.add(StaticStrings::KeyString, oldValue);
|
||||
|
|
|
@ -174,7 +174,7 @@ static bool ScanMarker(TRI_df_marker_t const* marker, void* data,
|
|||
}
|
||||
|
||||
VPackSlice slice(reinterpret_cast<char const*>(marker) + DatafileHelper::VPackOffset(type));
|
||||
state->documentOperations[collectionId][slice.get(StaticStrings::KeyString).copyString()] = marker;
|
||||
state->documentOperations[collectionId][Transaction::extractKeyFromDocument(slice).copyString()] = marker;
|
||||
state->operationsCount[collectionId]++;
|
||||
break;
|
||||
}
|
||||
|
@ -592,7 +592,7 @@ void CollectorThread::processCollectionMarker(
|
|||
|
||||
TRI_voc_rid_t revisionId = arangodb::basics::VelocyPackHelper::stringUInt64(slice.get(StaticStrings::RevString));
|
||||
|
||||
auto found = document->primaryIndex()->lookupKey(&trx, slice.get(StaticStrings::KeyString));
|
||||
auto found = document->primaryIndex()->lookupKey(&trx, Transaction::extractKeyFromDocument(slice));
|
||||
|
||||
if (found == nullptr || found->revisionId() != revisionId ||
|
||||
found->getMarkerPtr() != walMarker) {
|
||||
|
@ -618,7 +618,7 @@ void CollectorThread::processCollectionMarker(
|
|||
|
||||
TRI_voc_rid_t revisionId = arangodb::basics::VelocyPackHelper::stringUInt64(slice.get(StaticStrings::RevString));
|
||||
|
||||
auto found = document->primaryIndex()->lookupKey(&trx, slice.get(StaticStrings::KeyString));
|
||||
auto found = document->primaryIndex()->lookupKey(&trx, Transaction::extractKeyFromDocument(slice));
|
||||
|
||||
if (found != nullptr && found->revisionId() > revisionId) {
|
||||
// somebody re-created the document with a newer revision
|
||||
|
|
|
@ -25,12 +25,13 @@
|
|||
#include "Basics/conversions.h"
|
||||
#include "Basics/Exceptions.h"
|
||||
#include "Logger/Logger.h"
|
||||
#include "Basics/files.h"
|
||||
#include "Basics/hashes.h"
|
||||
#include "Basics/StaticStrings.h"
|
||||
#include "Basics/StringUtils.h"
|
||||
#include "Basics/tri-strings.h"
|
||||
#include "Basics/Utf8Helper.h"
|
||||
#include "Basics/VPackStringBufferAdapter.h"
|
||||
#include "Basics/files.h"
|
||||
#include "Basics/hashes.h"
|
||||
#include "Basics/tri-strings.h"
|
||||
|
||||
#include <velocypack/AttributeTranslator.h>
|
||||
#include <velocypack/velocypack-common.h>
|
||||
|
@ -80,11 +81,11 @@ void VelocyPackHelper::initialize() {
|
|||
Translator.reset(new VPackAttributeTranslator);
|
||||
|
||||
// these attribute names will be translated into short integer values
|
||||
Translator->add("_key", 1); // TRI_VOC_ATTRIBUTE_KEY
|
||||
Translator->add("_rev", 2); // TRI_VOC_ATTRIBUTE_REV
|
||||
Translator->add("_id", 3); // TRI_VOC_ATTRIBUTE_ID
|
||||
Translator->add("_from", 4); // TRI_VOC_ATTRIBUTE_FROM
|
||||
Translator->add("_to", 5); // TRI_VOC_ATTRIBUTE_TO
|
||||
Translator->add(StaticStrings::KeyString, KeyAttribute - AttributeBase);
|
||||
Translator->add(StaticStrings::RevString, RevAttribute - AttributeBase);
|
||||
Translator->add(StaticStrings::IdString, IdAttribute - AttributeBase);
|
||||
Translator->add(StaticStrings::FromString, FromAttribute - AttributeBase);
|
||||
Translator->add(StaticStrings::ToString, ToAttribute - AttributeBase);
|
||||
|
||||
Translator->seal();
|
||||
|
||||
|
@ -92,10 +93,27 @@ void VelocyPackHelper::initialize() {
|
|||
VPackOptions::Defaults.attributeTranslator = Translator.get();
|
||||
// VPackOptions::Defaults.unsupportedTypeBehavior = VPackOptions::ConvertUnsupportedType;
|
||||
|
||||
// run quick selfs test with the attribute translator
|
||||
TRI_ASSERT(VPackSlice(Translator->translate(StaticStrings::KeyString)).getUInt() == KeyAttribute - AttributeBase);
|
||||
TRI_ASSERT(VPackSlice(Translator->translate(StaticStrings::RevString)).getUInt() == RevAttribute - AttributeBase);
|
||||
TRI_ASSERT(VPackSlice(Translator->translate(StaticStrings::IdString)).getUInt() == IdAttribute - AttributeBase);
|
||||
TRI_ASSERT(VPackSlice(Translator->translate(StaticStrings::FromString)).getUInt() == FromAttribute - AttributeBase);
|
||||
TRI_ASSERT(VPackSlice(Translator->translate(StaticStrings::ToString)).getUInt() == ToAttribute - AttributeBase);
|
||||
|
||||
TRI_ASSERT(VPackSlice(Translator->translate(KeyAttribute - AttributeBase)).copyString() == StaticStrings::KeyString);
|
||||
TRI_ASSERT(VPackSlice(Translator->translate(RevAttribute - AttributeBase)).copyString() == StaticStrings::RevString);
|
||||
TRI_ASSERT(VPackSlice(Translator->translate(IdAttribute - AttributeBase)).copyString() == StaticStrings::IdString);
|
||||
TRI_ASSERT(VPackSlice(Translator->translate(FromAttribute - AttributeBase)).copyString() == StaticStrings::FromString);
|
||||
TRI_ASSERT(VPackSlice(Translator->translate(ToAttribute - AttributeBase)).copyString() == StaticStrings::ToString);
|
||||
|
||||
// initialize exclude handler for system attributes
|
||||
ExcludeHandler.reset(new SystemAttributeExcludeHandler);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief turn off assembler optimizations in vpack
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void VelocyPackHelper::disableAssemblerFunctions() {
|
||||
arangodb::velocypack::disableAssemblerFunctions();
|
||||
}
|
||||
|
|
|
@ -287,6 +287,19 @@ class VelocyPackHelper {
|
|||
|
||||
static void SanitizeExternals(arangodb::velocypack::Slice const,
|
||||
arangodb::velocypack::Builder&);
|
||||
|
||||
static uint8_t const KeyAttribute = 0x31;
|
||||
static uint8_t const RevAttribute = 0x32;
|
||||
static uint8_t const IdAttribute = 0x33;
|
||||
static uint8_t const FromAttribute = 0x34;
|
||||
static uint8_t const ToAttribute = 0x35;
|
||||
|
||||
static uint8_t const AttributeBase = 0x30;
|
||||
|
||||
static_assert(KeyAttribute < RevAttribute, "invalid value for _key attribute");
|
||||
static_assert(RevAttribute < IdAttribute, "invalid value for _rev attribute");
|
||||
static_assert(IdAttribute < FromAttribute, "invalid value for _id attribute");
|
||||
static_assert(FromAttribute < ToAttribute, "invalid value for _from attribute");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue