1
0
Fork 0

faster lookup for _key attribute

This commit is contained in:
jsteemann 2016-04-30 13:25:06 +02:00
parent 6912d6a34e
commit e478c1ae11
12 changed files with 114 additions and 49 deletions

View File

@ -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
}

View File

@ -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;

View File

@ -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() {

View File

@ -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;

View File

@ -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();

View File

@ -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&);

View File

@ -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

View File

@ -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
///

View File

@ -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);

View File

@ -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

View File

@ -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();
}

View File

@ -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");
};
}
}