1
0
Fork 0

Bug fix/aql speedup (#7379)

This commit is contained in:
Jan 2018-11-20 16:07:40 +01:00 committed by GitHub
parent 56289dcdbb
commit bf2eeb16cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 296 additions and 105 deletions

View File

@ -3554,7 +3554,16 @@ AstNode* Ast::nodeFromVPack(VPackSlice const& slice, bool copyStringValues) {
if (slice.isNumber()) {
if (slice.isSmallInt() || slice.isInt()) {
// integer value
return createNodeValueInt(slice.getInt());
return createNodeValueInt(slice.getIntUnchecked());
}
if (slice.isUInt()) {
// check if we can safely convert the value from unsigned to signed
// without data loss
uint64_t v = slice.getUIntUnchecked();
if (v <= uint64_t(INT64_MAX)) {
return createNodeValueInt(static_cast<int64_t>(v));
}
// fall-through to floating point conversion
}
// floating point value
return createNodeValueDouble(slice.getNumber<double>());
@ -3562,7 +3571,7 @@ AstNode* Ast::nodeFromVPack(VPackSlice const& slice, bool copyStringValues) {
if (slice.isString()) {
VPackValueLength length;
char const* p = slice.getString(length);
char const* p = slice.getStringUnchecked(length);
if (copyStringValues) {
// we must copy string values!

View File

@ -471,8 +471,8 @@ class Ast {
static bool IsOrOperatorType(AstNodeType);
/// @brief create an AST node from vpack
AstNode* nodeFromVPack(arangodb::velocypack::Slice const&, bool);
AstNode* nodeFromVPack(arangodb::velocypack::Slice const&, bool copyStringValues);
/// @brief resolve an attribute access
static AstNode const* resolveConstAttributeAccess(AstNode const*);

View File

@ -1362,7 +1362,7 @@ bool AstNode::isAttributeAccessForVariable(
}
auto node = this;
basics::StringBuffer indexBuff(false);
basics::StringBuffer indexBuff;
while (node->type == NODE_TYPE_ATTRIBUTE_ACCESS ||
node->type == NODE_TYPE_INDEXED_ACCESS ||
@ -2601,8 +2601,9 @@ void AstNode::markFinalized(AstNode* subtreeRoot) {
}
subtreeRoot->setFlag(AstNodeFlagType::FLAG_FINALIZED);
for (size_t i = 0; i < subtreeRoot->numMembers(); ++i) {
markFinalized(subtreeRoot->getMember(i));
size_t const n = subtreeRoot->numMembers();
for (size_t i = 0; i < n; ++i) {
markFinalized(subtreeRoot->getMemberUnchecked(i));
}
}

View File

@ -544,7 +544,7 @@ struct AstNode {
if (i >= members.size()) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "member out of range");
}
members.at(i) = node;
members[i] = node;
}
/// @brief remove a member from the node

View File

@ -1115,45 +1115,54 @@ AqlValue Expression::executeSimpleExpressionOr(
/// @brief execute an expression of type SIMPLE with AND or OR
AqlValue Expression::executeSimpleExpressionNaryAndOr(
AstNode const* node, transaction::Methods* trx, bool& mustDestroy) {
mustDestroy = false;
size_t count = node->numMembers();
if (count == 0) {
// There is nothing to evaluate. So this is always true
mustDestroy = true;
return AqlValue(AqlValueHintBool(true));
}
// AND
if (node->type == NODE_TYPE_OPERATOR_NARY_AND) {
for (size_t i = 0; i < count; ++i) {
bool localMustDestroy = false;
AqlValue check =
executeSimpleExpression(node->getMemberUnchecked(i), trx, mustDestroy, true);
if (!check.toBoolean()) {
// Check is false. Return it.
return check;
}
executeSimpleExpression(node->getMemberUnchecked(i), trx, localMustDestroy, false);
bool result = check.toBoolean();
if (mustDestroy) {
if (localMustDestroy) {
check.destroy();
}
if (!result) {
// we are allowed to return early here, because this is only called
// in the context of index lookups
return AqlValue(AqlValueHintBool(false));
}
}
mustDestroy = true;
return AqlValue(AqlValueHintBool(true));
}
// OR
for (size_t i = 0; i < count; ++i) {
bool localMustDestroy = false;
AqlValue check =
executeSimpleExpression(node->getMemberUnchecked(i), trx, mustDestroy, true);
if (check.toBoolean()) {
// Check is true. Return it.
return check;
}
executeSimpleExpression(node->getMemberUnchecked(i), trx, localMustDestroy, true);
bool result = check.toBoolean();
if (mustDestroy) {
if (localMustDestroy) {
check.destroy();
}
if (result) {
// we are allowed to return early here, because this is only called
// in the context of index lookups
return AqlValue(AqlValueHintBool(true));
}
}
mustDestroy = true;
// anything else... we shouldn't get here
TRI_ASSERT(false);
return AqlValue(AqlValueHintBool(false));
}

View File

@ -182,11 +182,11 @@ void IndexBlock::executeExpressions() {
AqlItemBlock* cur = _buffer.front();
auto en = ExecutionNode::castTo<IndexNode const*>(getPlanNode());
auto ast = en->_plan->getAst();
AstNode const* oldCondition = _condition;
AstNode* newCondition = ast->shallowCopyForModify(oldCondition);
_condition = newCondition;
TRI_DEFER(FINALIZE_SUBTREE(newCondition));
AstNode* condition = const_cast<AstNode*>(_condition);
// modify the existing node in place
TEMPORARILY_UNLOCK_NODE(condition);
Query* query = _engine->getQuery();
for (size_t posInExpressions = 0;
@ -204,15 +204,18 @@ void IndexBlock::executeExpressions() {
VPackSlice slice = materializer.slice(a, false);
AstNode* evaluatedNode = ast->nodeFromVPack(slice, true);
AstNode* tmp = newCondition;
AstNode* tmp = condition;
for (size_t x = 0; x < toReplace->indexPath.size(); x++) {
size_t idx = toReplace->indexPath[x];
AstNode* old = tmp->getMember(idx);
// modify the node in place
TEMPORARILY_UNLOCK_NODE(tmp);
if (x + 1 < toReplace->indexPath.size()) {
AstNode* cpy = ast->shallowCopyForModify(old);
AstNode* cpy = old;
tmp->changeMember(idx, cpy);
tmp = cpy;
} else {
// insert the actual expression value
tmp->changeMember(idx, evaluatedNode);
}
}

View File

@ -981,7 +981,7 @@ void arangodb::aql::removeRedundantSortsRule(
}
std::unordered_set<ExecutionNode*> toUnlink;
arangodb::basics::StringBuffer buffer(false);
arangodb::basics::StringBuffer buffer;
for (auto const& n : nodes) {
if (toUnlink.find(n) != toUnlink.end()) {
@ -2523,7 +2523,7 @@ void arangodb::aql::removeRedundantCalculationsRule(
return;
}
arangodb::basics::StringBuffer buffer(false);
arangodb::basics::StringBuffer buffer;
std::unordered_map<VariableId, Variable const*> replacements;
for (auto const& n : nodes) {

View File

@ -480,7 +480,7 @@ std::unique_ptr<IndexIterator> ClusterCollection::getAnyIterator(
void ClusterCollection::invokeOnAllElements(
transaction::Methods* trx,
std::function<bool(LocalDocumentId const&)> callback) {
std::function<bool(LocalDocumentId const&)> /*callback*/) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
}
@ -532,7 +532,7 @@ Result ClusterCollection::update(
OperationOptions& options, TRI_voc_tick_t& resultMarkerTick, bool,
TRI_voc_rid_t& prevRev, ManagedDocumentResult& previous,
arangodb::velocypack::Slice const key,
std::function<Result(void)> callbackDuringLock) {
std::function<Result(void)> /*callbackDuringLock*/) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
}
@ -541,7 +541,7 @@ Result ClusterCollection::replace(
ManagedDocumentResult& mdr, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool, TRI_voc_rid_t& prevRev,
ManagedDocumentResult& previous,
std::function<Result(void)> callbackDuringLock) {
std::function<Result(void)> /*callbackDuringLock*/) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
}
@ -549,7 +549,7 @@ Result ClusterCollection::remove(
arangodb::transaction::Methods* trx, arangodb::velocypack::Slice slice,
arangodb::ManagedDocumentResult& previous, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool, TRI_voc_rid_t& prevRev,
TRI_voc_rid_t& revisionId, std::function<Result(void)> callbackDuringLock) {
TRI_voc_rid_t& revisionId, std::function<Result(void)> /*callbackDuringLock*/) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
}

View File

@ -285,6 +285,7 @@ bool MMFilesHashIndexIterator::nextDocument(DocumentCallback const& cb, size_t l
void MMFilesHashIndexIterator::reset() {
_buffer.clear();
_documentIds.clear();
_posInBuffer = 0;
_lookups.reset();
_index->lookup(_trx, _lookups.lookup(), _buffer);

View File

@ -57,7 +57,60 @@ static std::vector<std::vector<arangodb::basics::AttributeName>> const
IndexAttributes{{arangodb::basics::AttributeName("_id", false)},
{arangodb::basics::AttributeName("_key", false)}};
MMFilesPrimaryIndexIterator::MMFilesPrimaryIndexIterator(
MMFilesPrimaryIndexEqIterator::MMFilesPrimaryIndexEqIterator(
LogicalCollection* collection, transaction::Methods* trx,
MMFilesPrimaryIndex const* index,
std::unique_ptr<VPackBuilder> key)
: IndexIterator(collection, trx),
_index(index),
_key(std::move(key)),
_done(false) {
TRI_ASSERT(_key->slice().isString());
}
MMFilesPrimaryIndexEqIterator::~MMFilesPrimaryIndexEqIterator() {
if (_key != nullptr) {
// return the VPackBuilder to the transaction context
_trx->transactionContextPtr()->returnBuilder(_key.release());
}
}
bool MMFilesPrimaryIndexEqIterator::next(LocalDocumentIdCallback const& cb, size_t limit) {
TRI_ASSERT(limit > 0);
if (_done || limit == 0) {
return false;
}
_done = true;
TRI_ASSERT(_key->slice().isString());
MMFilesSimpleIndexElement result =
_index->lookupKey(_trx, _key->slice());
if (result) {
cb(LocalDocumentId{result.localDocumentId()});
}
return false;
}
bool MMFilesPrimaryIndexEqIterator::nextDocument(DocumentCallback const& cb, size_t limit) {
TRI_ASSERT(limit > 0);
if (_done || limit == 0) {
return false;
}
_done = true;
ManagedDocumentResult mdr;
TRI_ASSERT(_key->slice().isString());
MMFilesSimpleIndexElement result =
_index->lookupKey(_trx, _key->slice(), mdr);
if (result) {
cb(result.localDocumentId(), VPackSlice(mdr.vpack()));
}
return false;
}
void MMFilesPrimaryIndexEqIterator::reset() { _done = false; }
MMFilesPrimaryIndexInIterator::MMFilesPrimaryIndexInIterator(
LogicalCollection* collection, transaction::Methods* trx,
MMFilesPrimaryIndex const* index,
std::unique_ptr<VPackBuilder> keys)
@ -68,14 +121,14 @@ MMFilesPrimaryIndexIterator::MMFilesPrimaryIndexIterator(
TRI_ASSERT(_keys->slice().isArray());
}
MMFilesPrimaryIndexIterator::~MMFilesPrimaryIndexIterator() {
MMFilesPrimaryIndexInIterator::~MMFilesPrimaryIndexInIterator() {
if (_keys != nullptr) {
// return the VPackBuilder to the transaction context
_trx->transactionContextPtr()->returnBuilder(_keys.release());
}
}
bool MMFilesPrimaryIndexIterator::next(LocalDocumentIdCallback const& cb, size_t limit) {
bool MMFilesPrimaryIndexInIterator::next(LocalDocumentIdCallback const& cb, size_t limit) {
TRI_ASSERT(limit > 0);
if (!_iterator.valid() || limit == 0) {
return false;
@ -93,7 +146,7 @@ bool MMFilesPrimaryIndexIterator::next(LocalDocumentIdCallback const& cb, size_t
return _iterator.valid();
}
void MMFilesPrimaryIndexIterator::reset() { _iterator.reset(); }
void MMFilesPrimaryIndexInIterator::reset() { _iterator.reset(); }
MMFilesAllIndexIterator::MMFilesAllIndexIterator(
LogicalCollection* collection, transaction::Methods* trx,
@ -275,10 +328,7 @@ void MMFilesPrimaryIndex::unload() {
MMFilesSimpleIndexElement MMFilesPrimaryIndex::lookupKey(
transaction::Methods* trx, VPackSlice const& key) const {
ManagedDocumentResult mdr;
IndexLookupContext context(trx, &_collection, &mdr, 1);
TRI_ASSERT(key.isString());
return _primaryIndex->findByKey(&context, key.begin());
return lookupKey(trx, key, mdr);
}
/// @brief looks up an element given a key
@ -467,11 +517,12 @@ IndexIterator* MMFilesPrimaryIndex::iteratorForCondition(
arangodb::aql::Variable const* reference,
IndexIteratorOptions const& opts) {
TRI_ASSERT(!isSorted() || opts.sorted);
TRI_ASSERT(node->type == aql::NODE_TYPE_OPERATOR_NARY_AND);
TRI_ASSERT(node->numMembers() == 1);
auto comp = node->getMember(0);
auto comp = node;
if (node->type == aql::NODE_TYPE_OPERATOR_NARY_AND) {
TRI_ASSERT(node->numMembers() == 1);
comp = node->getMember(0);
}
// assume a.b == value
auto attrNode = comp->getMember(0);
@ -488,17 +539,17 @@ IndexIterator* MMFilesPrimaryIndex::iteratorForCondition(
if (comp->type == aql::NODE_TYPE_OPERATOR_BINARY_EQ) {
// a.b == value
return createEqIterator(trx, attrNode, valNode);
} else if (comp->type == aql::NODE_TYPE_OPERATOR_BINARY_IN) {
}
if (comp->type == aql::NODE_TYPE_OPERATOR_BINARY_IN) {
// a.b IN values
if (!valNode->isArray()) {
// a.b IN non-array
return new EmptyIndexIterator(&_collection, trx);
if (valNode->isArray()) {
// a.b IN array
return createInIterator(trx, attrNode, valNode);
}
return createInIterator(trx, attrNode, valNode);
}
// operator type unsupported
// operator type unsupported or IN used on non-array
return new EmptyIndexIterator(&_collection, trx);
}
@ -541,7 +592,7 @@ IndexIterator* MMFilesPrimaryIndex::createInIterator(
keys->close();
return new MMFilesPrimaryIndexIterator(
return new MMFilesPrimaryIndexInIterator(
&_collection, trx, this, std::move(keys)
);
}
@ -556,21 +607,22 @@ IndexIterator* MMFilesPrimaryIndex::createEqIterator(
// lease builder, but immediately pass it to the unique_ptr so we don't leak
transaction::BuilderLeaser builder(trx);
std::unique_ptr<VPackBuilder> keys(builder.steal());
keys->openArray();
std::unique_ptr<VPackBuilder> key(builder.steal());
// handle the sole element
handleValNode(trx, keys.get(), valNode, isId);
handleValNode(trx, key.get(), valNode, isId);
TRI_IF_FAILURE("PrimaryIndex::noIterator") {
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
}
keys->close();
return new MMFilesPrimaryIndexIterator(
&_collection, trx, this, std::move(keys)
);
if (!key->isEmpty()) {
return new MMFilesPrimaryIndexEqIterator(
&_collection, trx, this, std::move(key)
);
}
return new EmptyIndexIterator(&_collection, trx);
}
/// @brief add a single value node to the iterator's keys

View File

@ -97,16 +97,39 @@ struct MMFilesPrimaryIndexHelper {
typedef arangodb::basics::AssocUnique<uint8_t, MMFilesSimpleIndexElement, MMFilesPrimaryIndexHelper>
MMFilesPrimaryIndexImpl;
class MMFilesPrimaryIndexIterator final : public IndexIterator {
class MMFilesPrimaryIndexEqIterator final : public IndexIterator {
public:
MMFilesPrimaryIndexIterator(LogicalCollection* collection,
transaction::Methods* trx,
MMFilesPrimaryIndex const* index,
std::unique_ptr<VPackBuilder> keys);
MMFilesPrimaryIndexEqIterator(LogicalCollection* collection,
transaction::Methods* trx,
MMFilesPrimaryIndex const* index,
std::unique_ptr<VPackBuilder> keys);
~MMFilesPrimaryIndexIterator();
~MMFilesPrimaryIndexEqIterator();
char const* typeName() const override { return "primary-index-iterator"; }
char const* typeName() const override { return "primary-index-eq-iterator"; }
bool next(LocalDocumentIdCallback const& cb, size_t limit) override;
bool nextDocument(DocumentCallback const& cb, size_t limit) override;
void reset() override;
private:
MMFilesPrimaryIndex const* _index;
std::unique_ptr<VPackBuilder> _key;
bool _done;
};
class MMFilesPrimaryIndexInIterator final : public IndexIterator {
public:
MMFilesPrimaryIndexInIterator(LogicalCollection* collection,
transaction::Methods* trx,
MMFilesPrimaryIndex const* index,
std::unique_ptr<VPackBuilder> keys);
~MMFilesPrimaryIndexInIterator();
char const* typeName() const override { return "primary-index-in-iterator"; }
bool next(LocalDocumentIdCallback const& cb, size_t limit) override;

View File

@ -73,7 +73,62 @@ static std::vector<std::vector<arangodb::basics::AttributeName>> const
IndexAttributes{{arangodb::basics::AttributeName("_id", false)},
{arangodb::basics::AttributeName("_key", false)}};
RocksDBPrimaryIndexIterator::RocksDBPrimaryIndexIterator(
RocksDBPrimaryIndexEqIterator::RocksDBPrimaryIndexEqIterator(
LogicalCollection* collection, transaction::Methods* trx,
RocksDBPrimaryIndex* index,
std::unique_ptr<VPackBuilder> key,
bool allowCoveringIndexOptimization)
: IndexIterator(collection, trx),
_index(index),
_key(std::move(key)),
_done(false),
_allowCoveringIndexOptimization(allowCoveringIndexOptimization) {
TRI_ASSERT(_key->slice().isString());
}
RocksDBPrimaryIndexEqIterator::~RocksDBPrimaryIndexEqIterator() {
if (_key != nullptr) {
// return the VPackBuilder to the transaction context
_trx->transactionContextPtr()->returnBuilder(_key.release());
}
}
bool RocksDBPrimaryIndexEqIterator::next(LocalDocumentIdCallback const& cb, size_t limit) {
if (limit == 0 || _done) {
// No limit no data, or we are actually done. The last call should have
// returned false
TRI_ASSERT(limit > 0); // Someone called with limit == 0. Api broken
return false;
}
_done = true;
LocalDocumentId documentId = _index->lookupKey(_trx, StringRef(_key->slice()));
if (documentId.isSet()) {
cb(documentId);
}
return false;
}
bool RocksDBPrimaryIndexEqIterator::nextCovering(DocumentCallback const& cb, size_t limit) {
TRI_ASSERT(_allowCoveringIndexOptimization);
if (limit == 0 || _done) {
// No limit no data, or we are actually done. The last call should have
// returned false
TRI_ASSERT(limit > 0); // Someone called with limit == 0. Api broken
return false;
}
_done = true;
LocalDocumentId documentId = _index->lookupKey(_trx, StringRef(_key->slice()));
if (documentId.isSet()) {
cb(documentId, _key->slice());
}
return false;
}
void RocksDBPrimaryIndexEqIterator::reset() { _done = false; }
RocksDBPrimaryIndexInIterator::RocksDBPrimaryIndexInIterator(
LogicalCollection* collection, transaction::Methods* trx,
RocksDBPrimaryIndex* index,
std::unique_ptr<VPackBuilder> keys,
@ -86,14 +141,14 @@ RocksDBPrimaryIndexIterator::RocksDBPrimaryIndexIterator(
TRI_ASSERT(_keys->slice().isArray());
}
RocksDBPrimaryIndexIterator::~RocksDBPrimaryIndexIterator() {
RocksDBPrimaryIndexInIterator::~RocksDBPrimaryIndexInIterator() {
if (_keys != nullptr) {
// return the VPackBuilder to the transaction context
_trx->transactionContextPtr()->returnBuilder(_keys.release());
}
}
bool RocksDBPrimaryIndexIterator::next(LocalDocumentIdCallback const& cb, size_t limit) {
bool RocksDBPrimaryIndexInIterator::next(LocalDocumentIdCallback const& cb, size_t limit) {
if (limit == 0 || !_iterator.valid()) {
// No limit no data, or we are actually done. The last call should have
// returned false
@ -102,7 +157,6 @@ bool RocksDBPrimaryIndexIterator::next(LocalDocumentIdCallback const& cb, size_t
}
while (limit > 0) {
// TODO: prevent copying of the value into result, as we don't need it here!
LocalDocumentId documentId = _index->lookupKey(_trx, StringRef(*_iterator));
if (documentId.isSet()) {
cb(documentId);
@ -117,7 +171,8 @@ bool RocksDBPrimaryIndexIterator::next(LocalDocumentIdCallback const& cb, size_t
return true;
}
bool RocksDBPrimaryIndexIterator::nextCovering(DocumentCallback const& cb, size_t limit) {
bool RocksDBPrimaryIndexInIterator::nextCovering(DocumentCallback const& cb, size_t limit) {
TRI_ASSERT(_allowCoveringIndexOptimization);
if (limit == 0 || !_iterator.valid()) {
// No limit no data, or we are actually done. The last call should have
// returned false
@ -141,7 +196,7 @@ bool RocksDBPrimaryIndexIterator::nextCovering(DocumentCallback const& cb, size_
return true;
}
void RocksDBPrimaryIndexIterator::reset() { _iterator.reset(); }
void RocksDBPrimaryIndexInIterator::reset() { _iterator.reset(); }
// ================ PrimaryIndex ================
@ -385,17 +440,17 @@ IndexIterator* RocksDBPrimaryIndex::iteratorForCondition(
if (comp->type == aql::NODE_TYPE_OPERATOR_BINARY_EQ) {
// a.b == value
return createEqIterator(trx, attrNode, valNode);
} else if (comp->type == aql::NODE_TYPE_OPERATOR_BINARY_IN) {
}
if (comp->type == aql::NODE_TYPE_OPERATOR_BINARY_IN) {
// a.b IN values
if (!valNode->isArray()) {
// a.b IN non-array
return new EmptyIndexIterator(&_collection, trx);
if (valNode->isArray()) {
// a.b IN array
return createInIterator(trx, attrNode, valNode);
}
return createInIterator(trx, attrNode, valNode);
}
// operator type unsupported
// operator type unsupported or IN used on non-array
return new EmptyIndexIterator(&_collection, trx);
}
@ -438,7 +493,7 @@ IndexIterator* RocksDBPrimaryIndex::createInIterator(
keys->close();
return new RocksDBPrimaryIndexIterator(
return new RocksDBPrimaryIndexInIterator(
&_collection, trx, this, std::move(keys), !isId
);
}
@ -453,21 +508,22 @@ IndexIterator* RocksDBPrimaryIndex::createEqIterator(
// lease builder, but immediately pass it to the unique_ptr so we don't leak
transaction::BuilderLeaser builder(trx);
std::unique_ptr<VPackBuilder> keys(builder.steal());
keys->openArray();
std::unique_ptr<VPackBuilder> key(builder.steal());
// handle the sole element
handleValNode(trx, keys.get(), valNode, isId);
handleValNode(trx, key.get(), valNode, isId);
TRI_IF_FAILURE("PrimaryIndex::noIterator") {
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
}
keys->close();
return new RocksDBPrimaryIndexIterator(
&_collection, trx, this, std::move(keys), !isId
);
if (!key->isEmpty()) {
return new RocksDBPrimaryIndexEqIterator(
&_collection, trx, this, std::move(key), !isId
);
}
return new EmptyIndexIterator(&_collection, trx);
}
/// @brief add a single value node to the iterator's keys

View File

@ -47,17 +47,46 @@ namespace transaction {
class Methods;
}
class RocksDBPrimaryIndexIterator final : public IndexIterator {
class RocksDBPrimaryIndexEqIterator final : public IndexIterator {
public:
RocksDBPrimaryIndexIterator(LogicalCollection* collection,
transaction::Methods* trx,
RocksDBPrimaryIndex* index,
std::unique_ptr<VPackBuilder> keys,
bool allowCoveringIndexOptimization);
RocksDBPrimaryIndexEqIterator(LogicalCollection* collection,
transaction::Methods* trx,
RocksDBPrimaryIndex* index,
std::unique_ptr<VPackBuilder> key,
bool allowCoveringIndexOptimization);
~RocksDBPrimaryIndexIterator();
~RocksDBPrimaryIndexEqIterator();
char const* typeName() const override { return "primary-index-iterator"; }
char const* typeName() const override { return "primary-index-eq-iterator"; }
bool next(LocalDocumentIdCallback const& cb, size_t limit) override;
bool nextCovering(DocumentCallback const& cb, size_t limit) override;
void reset() override;
/// @brief we provide a method to provide the index attribute values
/// while scanning the index
bool hasCovering() const override { return _allowCoveringIndexOptimization; }
private:
RocksDBPrimaryIndex* _index;
std::unique_ptr<VPackBuilder> _key;
bool _done;
bool const _allowCoveringIndexOptimization;
};
class RocksDBPrimaryIndexInIterator final : public IndexIterator {
public:
RocksDBPrimaryIndexInIterator(LogicalCollection* collection,
transaction::Methods* trx,
RocksDBPrimaryIndex* index,
std::unique_ptr<VPackBuilder> keys,
bool allowCoveringIndexOptimization);
~RocksDBPrimaryIndexInIterator();
char const* typeName() const override { return "primary-index-in-iterator"; }
bool next(LocalDocumentIdCallback const& cb, size_t limit) override;
@ -77,7 +106,8 @@ class RocksDBPrimaryIndexIterator final : public IndexIterator {
};
class RocksDBPrimaryIndex final : public RocksDBIndex {
friend class RocksDBPrimaryIndexIterator;
friend class RocksDBPrimaryIndexEqIterator;
friend class RocksDBPrimaryIndexInIterator;
friend class RocksDBAllIndexIterator;
friend class RocksDBAnyIndexIterator;

View File

@ -241,11 +241,18 @@ namespace basics {
/// @brief string buffer with formatting routines
class StringBuffer {
StringBuffer() = delete;
StringBuffer(StringBuffer const&) = delete;
StringBuffer& operator=(StringBuffer const&) = delete;
public:
/// @brief creates an uninitialized string buffer
StringBuffer() {
_buffer._buffer = nullptr;
_buffer._current = nullptr;
_buffer._len = 0;
_buffer._initializeMemory = false;
}
/// @brief initializes the string buffer
explicit StringBuffer(bool initializeMemory) {
TRI_InitStringBuffer(&_buffer, initializeMemory);