1
0
Fork 0

less copying of RangeInfoBounds

This commit is contained in:
Jan Steemann 2015-03-31 14:53:14 +02:00
parent 6f4fadd630
commit 3f913f96d7
4 changed files with 286 additions and 219 deletions

View File

@ -999,7 +999,8 @@ IndexRangeBlock::IndexRangeBlock (ExecutionEngine* engine,
_condition(new IndexOrCondition()),
_posInRanges(0),
_sortCoords(),
_freeCondition(true) {
_freeCondition(true),
_hasV8Expression(false) {
auto trxCollection = _trx->trxCollection(_collection->cid());
if (trxCollection != nullptr) {
@ -1031,7 +1032,7 @@ IndexRangeBlock::IndexRangeBlock (ExecutionEngine* engine,
isConstant &= r.isConstant();
}
_anyBoundVariable |= ! isConstant;
_allBoundsConstant.push_back(isConstant);
_allBoundsConstant.emplace_back(isConstant);
}
}
@ -1053,6 +1054,191 @@ IndexRangeBlock::~IndexRangeBlock () {
delete _edgeIndexIterator;
}
bool IndexRangeBlock::hasV8Expression () const {
for (auto expression : _allVariableBoundExpressions) {
TRI_ASSERT(expression != nullptr);
if (expression->isV8()) {
return true;
}
}
return false;
}
void IndexRangeBlock::buildExpressions () {
auto en = static_cast<IndexRangeNode const*>(getPlanNode());
size_t posInExpressions = 0;
// The following are needed to evaluate expressions with local data from
// the current incoming item:
AqlItemBlock* cur = _buffer.front();
vector<AqlValue>& data(cur->getData());
vector<TRI_document_collection_t const*>& docColls(cur->getDocumentCollections());
RegisterId nrRegs = cur->getNrRegs();
IndexOrCondition* newCondition = nullptr;
for (size_t i = 0; i < en->_ranges.size(); i++) {
size_t const n = en->_ranges[i].size();
// prefill with n default-constructed vectors
std::vector<std::vector<RangeInfo>> collector(n);
// collect the evaluated bounds here
for (size_t k = 0; k < n; k++) {
auto r = en->_ranges[i][k];
// First create a new RangeInfo containing only the constant
// low and high bound of r:
RangeInfo riConst(r._var, r._attr, r._lowConst, r._highConst,
r.is1ValueRangeInfo());
collector[k].emplace_back(riConst);
// Now work the actual values of the variable lows and highs into
// this constant range:
for (auto l : r._lows) {
Expression* e = _allVariableBoundExpressions[posInExpressions];
TRI_ASSERT(e != nullptr);
TRI_document_collection_t const* myCollection = nullptr;
AqlValue a = e->execute(_trx, docColls, data, nrRegs * _pos,
_inVars[posInExpressions],
_inRegs[posInExpressions],
&myCollection);
posInExpressions++;
Json bound;
if (a._type == AqlValue::JSON) {
bound = *(a._json);
a.destroy(); // the TRI_json_t* of a._json has been stolen
}
else if (a._type == AqlValue::SHAPED || a._type == AqlValue::DOCVEC) {
bound = a.toJson(_trx, myCollection);
a.destroy(); // the TRI_json_t* of a._json has been stolen
}
else {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
"AQL: computed a variable bound and got non-JSON");
}
if (! bound.isArray()) {
auto b(bound.copy());
RangeInfo ri(r._var,
r._attr,
RangeInfoBound(l.inclusive(), true, b), // will steal b's JSON
RangeInfoBound(),
false);
for (size_t j = 0; j < collector[k].size(); j++) {
collector[k][j].fuse(ri);
}
}
else {
std::vector<RangeInfo> riv;
riv.reserve(bound.size());
for (size_t j = 0; j < bound.size(); j++) {
auto b1(bound.at(static_cast<int>(j)).copy()); // first instance of bound
auto b2(bound.at(static_cast<int>(j)).copy()); // second instance of same bound
riv.emplace_back(RangeInfo(r._var,
r._attr,
RangeInfoBound(l.inclusive(), true, b1), // will steal b1's JSON
RangeInfoBound(l.inclusive(), true, b2), // will steal b2's JSON
true));
}
collector[k] = andCombineRangeInfoVecs(collector[k], riv);
}
}
for (auto h : r._highs) {
Expression* e = _allVariableBoundExpressions[posInExpressions];
TRI_ASSERT(e != nullptr);
TRI_document_collection_t const* myCollection = nullptr;
AqlValue a = e->execute(_trx, docColls, data, nrRegs * _pos,
_inVars[posInExpressions],
_inRegs[posInExpressions],
&myCollection);
posInExpressions++;
Json bound;
if (a._type == AqlValue::JSON) {
bound = *(a._json);
a.destroy(); // the TRI_json_t* of a._json has been stolen
}
else if (a._type == AqlValue::SHAPED || a._type == AqlValue::DOCVEC) {
bound = a.toJson(_trx, myCollection);
a.destroy(); // the TRI_json_t* of a._json has been stolen
}
else {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
"AQL: computed a variable bound and got non-JSON");
}
if (! bound.isArray()) {
auto b(bound.copy());
RangeInfo ri(r._var,
r._attr,
RangeInfoBound(),
RangeInfoBound(h.inclusive(), true, b), // will steal b's JSON
false);
for (size_t j = 0; j < collector[k].size(); j++) {
collector[k][j].fuse(ri);
}
}
else {
std::vector<RangeInfo> riv;
riv.reserve(bound.size());
for (size_t j = 0; j < bound.size(); j++) {
auto b1(bound.at(static_cast<int>(j)).copy()); // first instance of bound
auto b2(bound.at(static_cast<int>(j)).copy()); // second instance of same bound
riv.emplace_back(RangeInfo(r._var,
r._attr,
RangeInfoBound(h.inclusive(), true, b1), // will steal b1's JSON
RangeInfoBound(h.inclusive(), true, b2), // will steal b2's JSON
true));
}
collector[k] = andCombineRangeInfoVecs(collector[k], riv);
}
}
}
bool isEmpty = false;
for (auto x: collector) {
if (x.empty()) {
isEmpty = true;
break;
}
}
if (! isEmpty) {
// otherwise the condition is impossible to fulfill
// the elements of the direct product of the collector are and
// conditions which should be added to newCondition
auto indexAnds = cartesian(collector);
if (newCondition != nullptr) {
for (auto indexAnd: *indexAnds) {
newCondition->push_back(indexAnd);
}
delete indexAnds;
}
else {
newCondition = indexAnds;
}
}
}
//_condition = newCondition.release();
if (newCondition != nullptr) {
freeCondition();
_condition = newCondition;
_freeCondition = true;
}
// remove duplicates . . .
removeOverlapsIndexOr(*_condition);
}
int IndexRangeBlock::initialize () {
ENTER_BLOCK
int res = ExecutionBlock::initialize();
@ -1063,6 +1249,8 @@ int IndexRangeBlock::initialize () {
}
}
_allVariableBoundExpressions.clear();
// instanciate expressions:
auto instanciateExpression = [&] (RangeInfoBound& b) -> void {
AstNode const* a = b.getExpressionAst(_engine->getQuery()->ast());
@ -1078,6 +1266,7 @@ int IndexRangeBlock::initialize () {
delete e;
throw;
}
// Prepare _inVars and _inRegs:
_inVars.emplace_back();
std::vector<Variable*>& inVarsCur = _inVars.back();
@ -1124,6 +1313,8 @@ int IndexRangeBlock::initialize () {
}
}
_hasV8Expression = hasV8Expression();
return res;
LEAVE_BLOCK;
}
@ -1147,22 +1338,11 @@ int IndexRangeBlock::initialize () {
bool IndexRangeBlock::initRanges () {
ENTER_BLOCK
_flag = true;
auto en = static_cast<IndexRangeNode const*>(getPlanNode());
TRI_ASSERT(en->_index != nullptr);
// Find out about the actual values for the bounds in the variable bound case:
if (_anyBoundVariable) {
size_t posInExpressions = 0;
// The following are needed to evaluate expressions with local data from
// the current incoming item:
AqlItemBlock* cur = _buffer.front();
vector<AqlValue>& data(cur->getData());
vector<TRI_document_collection_t const*>& docColls(cur->getDocumentCollections());
RegisterId nrRegs = cur->getNrRegs();
if (_hasV8Expression) {
// must have a V8 context here to protect Expression::execute()
auto engine = _engine;
triagens::basics::ScopeGuard guard{
@ -1170,7 +1350,6 @@ bool IndexRangeBlock::initRanges () {
engine->getQuery()->enterContext();
},
[&]() -> void {
// must invalidate the expression now as we might be called from
// different threads
if (triagens::arango::ServerState::instance()->isRunningInCluster()) {
@ -1186,167 +1365,16 @@ bool IndexRangeBlock::initRanges () {
ISOLATE;
v8::HandleScope scope(isolate); // do not delete this!
IndexOrCondition* newCondition = nullptr;
for (size_t i = 0; i < en->_ranges.size(); i++) {
std::vector<std::vector<RangeInfo>> collector;
//collect the evaluated bounds here
for (size_t k = 0; k < en->_ranges[i].size(); k++) {
auto r = en->_ranges[i][k];
collector.emplace_back(std::vector<RangeInfo>());
// First create a new RangeInfo containing only the constant
// low and high bound of r:
RangeInfo riConst(r._var, r._attr, r._lowConst, r._highConst,
r.is1ValueRangeInfo());
collector[k].emplace_back(riConst);
// Now work the actual values of the variable lows and highs into
// this constant range:
for (auto l : r._lows) {
Expression* e = _allVariableBoundExpressions[posInExpressions];
TRI_ASSERT(e != nullptr);
TRI_document_collection_t const* myCollection = nullptr;
AqlValue a = e->execute(_trx, docColls, data, nrRegs * _pos,
_inVars[posInExpressions],
_inRegs[posInExpressions],
&myCollection);
posInExpressions++;
Json bound;
if (a._type == AqlValue::JSON) {
bound = *(a._json);
a.destroy(); // the TRI_json_t* of a._json has been stolen
}
else if (a._type == AqlValue::SHAPED || a._type == AqlValue::DOCVEC) {
bound = a.toJson(_trx, myCollection);
a.destroy(); // the TRI_json_t* of a._json has been stolen
buildExpressions();
}
else {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
"AQL: computed a variable bound and got non-JSON");
}
if (! bound.isArray()) {
Json json(Json::Object, 3);
json("include", Json(l.inclusive()))
("isConstant", Json(true))
("bound", bound.copy());
RangeInfo ri = RangeInfo(r._var,
r._attr,
RangeInfoBound(json),
RangeInfoBound(),
false);
for (size_t j = 0; j < collector[k].size(); j++) {
collector[k][j].fuse(ri);
}
}
else {
std::vector<RangeInfo> riv;
for (size_t j = 0; j < bound.size(); j++) {
Json json(Json::Object, 3);
json("include", Json(l.inclusive()))
("isConstant", Json(true))
("bound", bound.at(static_cast<int>(j)).copy());
riv.emplace_back(RangeInfo(r._var,
r._attr,
RangeInfoBound(json),
RangeInfoBound(json),
true));
}
collector[k] = andCombineRangeInfoVecs(collector[k], riv);
// no V8 context required!
buildExpressions();
}
}
for (auto h : r._highs) {
Expression* e = _allVariableBoundExpressions[posInExpressions];
TRI_ASSERT(e != nullptr);
TRI_document_collection_t const* myCollection = nullptr;
AqlValue a = e->execute(_trx, docColls, data, nrRegs * _pos,
_inVars[posInExpressions],
_inRegs[posInExpressions],
&myCollection);
posInExpressions++;
Json bound;
if (a._type == AqlValue::JSON) {
bound = *(a._json);
a.destroy(); // the TRI_json_t* of a._json has been stolen
}
else if (a._type == AqlValue::SHAPED || a._type == AqlValue::DOCVEC) {
bound = a.toJson(_trx, myCollection);
a.destroy(); // the TRI_json_t* of a._json has been stolen
}
else {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
"AQL: computed a variable bound and got non-JSON");
}
if (! bound.isArray()) {
Json json(Json::Object, 3);
json("include", Json(h.inclusive()))
("isConstant", Json(true))
("bound", bound.copy());
RangeInfo ri = RangeInfo(r._var,
r._attr,
RangeInfoBound(),
RangeInfoBound(json),
false);
for (size_t j = 0; j < collector[k].size(); j++) {
collector[k][j].fuse(ri);
}
}
else {
std::vector<RangeInfo> riv;
for (size_t j = 0; j < bound.size(); j++) {
Json json(Json::Object, 3);
json("include", Json(h.inclusive()))
("isConstant", Json(true))
("bound", bound.at(static_cast<int>(j)).copy());
riv.emplace_back(RangeInfo(r._var,
r._attr,
RangeInfoBound(json),
RangeInfoBound(json),
true));
}
collector[k] = andCombineRangeInfoVecs(collector[k], riv);
}
}
}
bool isEmpty = false;
for (auto x: collector) {
if (x.empty()) {
isEmpty = true;
break;
}
}
if (! isEmpty) {
// otherwise the condition is impossible to fulfil
// the elements of the direct product of the collector are and
// conditions which should be added to newCondition
auto indexAnds = cartesian(collector);
if (newCondition != nullptr) {
for (auto indexAnd: *indexAnds) {
newCondition->push_back(indexAnd);
}
delete indexAnds;
}
else {
newCondition = indexAnds;
}
}
}
//_condition = newCondition.release();
if (newCondition != nullptr) {
freeCondition();
_condition = newCondition;
_freeCondition = true;
}
// remove duplicates . . .
removeOverlapsIndexOr(*_condition);
}
auto en = static_cast<IndexRangeNode const*>(getPlanNode());
TRI_ASSERT(en->_index != nullptr);
if (en->_index->type == TRI_IDX_TYPE_PRIMARY_INDEX) {
return true; //no initialization here!

View File

@ -595,6 +595,18 @@ namespace triagens {
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not one of the bounds expressions requires V8
////////////////////////////////////////////////////////////////////////////////
bool hasV8Expression () const;
////////////////////////////////////////////////////////////////////////////////
/// @brief build the bounds expressions
////////////////////////////////////////////////////////////////////////////////
void buildExpressions ();
////////////////////////////////////////////////////////////////////////////////
/// @brief free _condition if it belongs to us
////////////////////////////////////////////////////////////////////////////////
@ -829,6 +841,7 @@ namespace triagens {
bool _freeCondition;
bool _hasV8Expression;
};

View File

@ -652,8 +652,9 @@ QueryResult Query::execute (QueryRegistry* registry) {
triagens::basics::Json jsonResult(triagens::basics::Json::Array, 16);
triagens::basics::Json stats;
AqlItemBlock* value;
AqlItemBlock* value = nullptr;
try {
while (nullptr != (value = _engine->getSome(1, ExecutionBlock::DefaultBatchSize))) {
auto doc = value->getDocumentCollection(0);
size_t const n = value->size();
@ -668,6 +669,12 @@ QueryResult Query::execute (QueryRegistry* registry) {
}
}
delete value;
value = nullptr;
}
}
catch (...) {
delete value;
throw;
}
stats = _engine->_stats.toJson();
@ -726,13 +733,13 @@ QueryResultV8 Query::executeV8 (v8::Isolate* isolate, QueryRegistry* registry) {
result.result = v8::Array::New(isolate);
triagens::basics::Json stats;
AqlItemBlock* value;
AqlItemBlock* value = nullptr;
try {
while (nullptr != (value = _engine->getSome(1, ExecutionBlock::DefaultBatchSize))) {
auto doc = value->getDocumentCollection(0);
size_t const n = value->size();
// reserve space for n additional results at once
/// json.reserve(n);
for (size_t i = 0; i < n; ++i) {
AqlValue val = value->getValueReference(i, 0);
@ -742,6 +749,12 @@ QueryResultV8 Query::executeV8 (v8::Isolate* isolate, QueryRegistry* registry) {
}
}
delete value;
value = nullptr;
}
}
catch (...) {
delete value;
throw;
}
stats = _engine->_stats.toJson();

View File

@ -28,11 +28,9 @@
#ifndef ARANGODB_AQL_RANGE_INFO_H
#define ARANGODB_AQL_RANGE_INFO_H 1
#include <Basics/Common.h>
#include <Basics/JsonHelper.h>
#include "Basics/Common.h"
#include "Aql/AstNode.h"
#include "Basics/JsonHelper.h"
#include "Basics/json-utilities.h"
namespace triagens {
@ -99,6 +97,21 @@ namespace triagens {
}
}
RangeInfoBound (bool include,
bool isConstant,
triagens::basics::Json& json)
: _bound(),
_include(include),
_isConstant(isConstant),
_defined(false),
_expressionAst(nullptr) {
if (! json.isEmpty()) {
_bound = triagens::basics::Json(TRI_UNKNOWN_MEM_ZONE, json.steal());
_defined = true;
}
}
RangeInfoBound ()
: _bound(),
_include(false),