1
0
Fork 0

Merge branch 'aql2' of https://github.com/triAGENS/ArangoDB into aql2

This commit is contained in:
Jan Steemann 2014-07-29 14:49:25 +02:00
commit 8eb7f5bd8a
6 changed files with 321 additions and 83 deletions

View File

@ -48,6 +48,10 @@ int ExecutionBlock::bind (std::map<std::string, struct TRI_json_s*>* params) {
ExecutionBlock* ExecutionBlock::instanciatePlan (ExecutionPlan const* ep) { ExecutionBlock* ExecutionBlock::instanciatePlan (ExecutionPlan const* ep) {
ExecutionBlock* eb; ExecutionBlock* eb;
switch (ep->getType()) { switch (ep->getType()) {
case ExecutionPlan::SINGLETON: {
eb = new SingletonBlock(static_cast<SingletonPlan const*>(ep));
break;
}
case ExecutionPlan::ENUMERATE_COLLECTION: { case ExecutionPlan::ENUMERATE_COLLECTION: {
eb = new EnumerateCollectionBlock(static_cast<EnumerateCollectionPlan const*>(ep)); eb = new EnumerateCollectionBlock(static_cast<EnumerateCollectionPlan const*>(ep));
break; break;

View File

@ -35,6 +35,8 @@
#include "Aql/ExecutionPlan.h" #include "Aql/ExecutionPlan.h"
#include "Utils/transactions.h" #include "Utils/transactions.h"
using namespace triagens::basics;
struct TRI_json_s; struct TRI_json_s;
namespace triagens { namespace triagens {
@ -43,7 +45,7 @@ namespace triagens {
class ExecutionBlock { class ExecutionBlock {
public: public:
ExecutionBlock (ExecutionPlan const* ep) ExecutionBlock (ExecutionPlan const* ep)
: _exePlan(ep) { } : _exePlan(ep), _done(false) { }
virtual ~ExecutionBlock (); virtual ~ExecutionBlock ();
@ -99,6 +101,7 @@ namespace triagens {
for (auto it = _dependencies.begin(); it != _dependencies.end(); ++it) { for (auto it = _dependencies.begin(); it != _dependencies.end(); ++it) {
(*it)->initialize(); (*it)->initialize();
} }
// FIXME: report errors from above
return TRI_ERROR_NO_ERROR; return TRI_ERROR_NO_ERROR;
} }
@ -110,6 +113,8 @@ namespace triagens {
for (auto it = _dependencies.begin(); it != _dependencies.end(); ++it) { for (auto it = _dependencies.begin(); it != _dependencies.end(); ++it) {
(*it)->execute(); (*it)->execute();
} }
// FIXME: report errors from above
_done = false;
return TRI_ERROR_NO_ERROR; return TRI_ERROR_NO_ERROR;
} }
@ -117,12 +122,13 @@ namespace triagens {
for (auto it = _dependencies.begin(); it != _dependencies.end(); ++it) { for (auto it = _dependencies.begin(); it != _dependencies.end(); ++it) {
(*it)->shutdown(); (*it)->shutdown();
} }
// FIXME: report errors from above
return TRI_ERROR_NO_ERROR; return TRI_ERROR_NO_ERROR;
} }
virtual AqlValue* getOne () = 0; virtual AqlItem* getOne () = 0;
std::vector<AqlValue*> getSome (int atLeast, int atMost); std::vector<AqlItem*> getSome (int atLeast, int atMost);
bool skip (int number); bool skip (int number);
@ -133,7 +139,8 @@ namespace triagens {
protected: protected:
ExecutionPlan const* _exePlan; ExecutionPlan const* _exePlan;
std::vector<ExecutionBlock*> _dependencies; std::vector<ExecutionBlock*> _dependencies;
std::deque<AqlValue*> _buffer; std::deque<AqlItem*> _buffer;
bool _done;
public: public:
@ -142,12 +149,49 @@ namespace triagens {
}; };
class SingletonBlock : public ExecutionBlock {
public:
SingletonBlock (SingletonPlan const* ep)
: ExecutionBlock(ep) {
}
~SingletonBlock () {
}
int initialize () {
ExecutionBlock::initialize();
return TRI_ERROR_NO_ERROR;
}
int execute () {
ExecutionBlock::execute();
return TRI_ERROR_NO_ERROR;
}
int shutdown () {
return TRI_ERROR_NO_ERROR;
}
AqlItem* getOne () {
if (_done) {
return nullptr;
}
auto p = reinterpret_cast<SingletonPlan const*>(_exePlan);
AqlItem* res = new AqlItem(p->_nrVars);
return res;
}
};
class EnumerateCollectionBlock : public ExecutionBlock { class EnumerateCollectionBlock : public ExecutionBlock {
public: public:
EnumerateCollectionBlock (EnumerateCollectionPlan const* ep) EnumerateCollectionBlock (EnumerateCollectionPlan const* ep)
: ExecutionBlock(ep) { : ExecutionBlock(ep), _input(nullptr) {
} }
~EnumerateCollectionBlock () { ~EnumerateCollectionBlock () {
@ -156,11 +200,17 @@ namespace triagens {
int initialize () { int initialize () {
// TODO: this is very very inefficient // TODO: this is very very inefficient
// it must be implemented properly for production // it must be implemented properly for production
int res = ExecutionBlock::initialize();
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
auto p = reinterpret_cast<EnumerateCollectionPlan const*>(_exePlan); auto p = reinterpret_cast<EnumerateCollectionPlan const*>(_exePlan);
V8ReadTransaction trx(p->_vocbase, p->_collname); V8ReadTransaction trx(p->_vocbase, p->_collname);
int res = trx.begin(); res = trx.begin();
vector<TRI_doc_mptr_t*> docs; vector<TRI_doc_mptr_t*> docs;
res = trx.read(docs); res = trx.read(docs);
@ -168,32 +218,63 @@ namespace triagens {
auto shaper = trx.documentCollection()->getShaper(); auto shaper = trx.documentCollection()->getShaper();
_allDocs.clear();
for (size_t i = 0; i < n; ++i) { for (size_t i = 0; i < n; ++i) {
TRI_shaped_json_t shaped; TRI_shaped_json_t shaped;
TRI_EXTRACT_SHAPED_JSON_MARKER(shaped, docs[i]->getDataPtr()); TRI_EXTRACT_SHAPED_JSON_MARKER(shaped, docs[i]->getDataPtr());
triagens::basics::Json json(TRI_UNKNOWN_MEM_ZONE, TRI_JsonShapedJson(shaper, &shaped)); _allDocs.push_back(new Json(TRI_UNKNOWN_MEM_ZONE,
_buffer.push_back(new AqlValue(json)); TRI_JsonShapedJson(shaper, &shaped)));
} }
res = trx.finish(res); res = trx.finish(res);
_pos = 0;
if (_allDocs.size() == 0) {
_done = true;
}
_input = nullptr;
return res; return res;
} }
int shutdown () { int shutdown () {
return TRI_ERROR_NO_ERROR; int res = ExecutionBlock::shutdown(); // Tell all dependencies
_allDocs.clear();
return res;
} }
AqlValue* getOne () { AqlItem* getOne () {
std::cout << "getOne of EnumerateCollectionBlock" << std::endl; std::cout << "getOne of EnumerateCollectionBlock" << std::endl;
if (_buffer.empty()) { if (_done) {
return nullptr; return nullptr;
}
if (_input == nullptr) {
_input = _dependencies[0]->getOne();
if (_input == nullptr) {
_done = true;
return nullptr;
}
_pos = 0;
if (_allDocs.size() == 0) {
_done = true;
return nullptr;
}
}
AqlItem* res = new AqlItem(_input, 1);
res->setValue(0,0,new AqlValue(_allDocs[_pos]));
if (++_pos >= _allDocs.size()) {
_input = nullptr; // get a new item next time
} }
auto value = _buffer.front(); return res;
_buffer.pop_front();
return value;
} }
private:
vector<Json*> _allDocs;
size_t _pos;
AqlItem* _input;
bool _done;
}; };
class RootBlock : public ExecutionBlock { class RootBlock : public ExecutionBlock {
@ -208,7 +289,7 @@ namespace triagens {
~RootBlock () { ~RootBlock () {
} }
AqlValue* getOne () { AqlItem* getOne () {
std::cout << "getOne of RootBlock" << std::endl; std::cout << "getOne of RootBlock" << std::endl;
return _dependencies[0]->getOne(); return _dependencies[0]->getOne();
} }

View File

@ -91,6 +91,31 @@ void ExecutionPlan::appendAsString (std::string& st, int indent) {
st.push_back('>'); st.push_back('>');
} }
// -----------------------------------------------------------------------------
// --SECTION-- methods of SingletonPlan
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief toJson, for SingletonPlan
////////////////////////////////////////////////////////////////////////////////
Json SingletonPlan::toJson (TRI_memory_zone_t* zone) const {
Json json(ExecutionPlan::toJson(zone)); // call base class method
if (json.isEmpty()) {
return json;
}
// Now put info about number of vars:
try {
json("nrVariables", Json(_nrVars));
}
catch (std::exception& e) {
return Json();
}
// And return it:
return json;
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- methods of EnumerateCollectionPlan // --SECTION-- methods of EnumerateCollectionPlan
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -112,7 +137,8 @@ Json EnumerateCollectionPlan::toJson (TRI_memory_zone_t* zone) const {
else { else {
json("vocbase", Json(_vocbase->_name)); json("vocbase", Json(_vocbase->_name));
} }
json("collection", Json(_collname)); json("collection", Json(_collname))
("nrVariables", Json(_nrVars));
} }
catch (std::exception& e) { catch (std::exception& e) {
return Json(); return Json();
@ -240,7 +266,7 @@ void testExecutionPlans () {
std::cout << a.toString() << std::endl; std::cout << a.toString() << std::endl;
std::cout << "Got here" << std::endl; std::cout << "Got here" << std::endl;
auto ec = new EnumerateCollectionPlan(nullptr, "guck"); auto ec = new EnumerateCollectionPlan(nullptr, "guck", 1);
Json jjj(ec->toJson()); Json jjj(ec->toJson());
cout << jjj.toString() << endl; cout << jjj.toString() << endl;
auto li = new LimitPlan(12, 17); auto li = new LimitPlan(12, 17);

View File

@ -56,6 +56,7 @@ namespace triagens {
enum NodeType { enum NodeType {
ILLEGAL, ILLEGAL,
SINGLETON,
ENUMERATE_COLLECTION, ENUMERATE_COLLECTION,
INDEX_RANGE, INDEX_RANGE,
STATIC_LIST, STATIC_LIST,
@ -218,6 +219,71 @@ namespace triagens {
}; };
// -----------------------------------------------------------------------------
// --SECTION-- class SingletonPlan
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief class SingletonPlan, derived from ExecutionPlan
////////////////////////////////////////////////////////////////////////////////
class SingletonPlan : public ExecutionPlan {
friend class SingletonBlock;
////////////////////////////////////////////////////////////////////////////////
/// @brief constructor with a vocbase and a collection name
////////////////////////////////////////////////////////////////////////////////
public:
SingletonPlan (int32_t nrvars)
: ExecutionPlan(), _nrVars(nrvars) {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return the type of the node
////////////////////////////////////////////////////////////////////////////////
virtual NodeType getType () const {
return SINGLETON;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return the type of the node as a string
////////////////////////////////////////////////////////////////////////////////
virtual std::string getTypeString () const {
return std::string("SingletonPlan");
}
////////////////////////////////////////////////////////////////////////////////
/// @brief export to JSON
////////////////////////////////////////////////////////////////////////////////
virtual triagens::basics::Json toJson (
TRI_memory_zone_t* zone = TRI_UNKNOWN_MEM_ZONE) const;
////////////////////////////////////////////////////////////////////////////////
/// @brief clone execution plan recursively
////////////////////////////////////////////////////////////////////////////////
virtual ExecutionPlan* clone () const {
auto c = new SingletonPlan(_nrVars);
cloneDependencies(c);
return static_cast<ExecutionPlan*>(c);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief we need to know how many variables we have in this scope
////////////////////////////////////////////////////////////////////////////////
private:
int32_t _nrVars;
};
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- class EnumerateCollectionPlan // --SECTION-- class EnumerateCollectionPlan
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -236,8 +302,11 @@ namespace triagens {
public: public:
EnumerateCollectionPlan (TRI_vocbase_t* vocbase, std::string collname) EnumerateCollectionPlan (TRI_vocbase_t* vocbase,
: ExecutionPlan(), _vocbase(vocbase), _collname(collname) { std::string collname,
int32_t nrVars)
: ExecutionPlan(), _vocbase(vocbase), _collname(collname),
_nrVars(nrVars) {
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -268,15 +337,11 @@ namespace triagens {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual ExecutionPlan* clone () const { virtual ExecutionPlan* clone () const {
auto c = new EnumerateCollectionPlan(_vocbase, _collname); auto c = new EnumerateCollectionPlan(_vocbase, _collname, _nrVars);
cloneDependencies(c); cloneDependencies(c);
return static_cast<ExecutionPlan*>(c); return static_cast<ExecutionPlan*>(c);
} }
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief we need to know the database and the collection /// @brief we need to know the database and the collection
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -285,6 +350,7 @@ namespace triagens {
TRI_vocbase_t* _vocbase; TRI_vocbase_t* _vocbase;
std::string _collname; std::string _collname;
int32_t _nrVars;
}; };

View File

@ -37,88 +37,147 @@ namespace triagens {
namespace aql { namespace aql {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- AqlValues // --SECTION-- AqlDoc
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief struct AqlValue, used to pipe documents through executions struct AqlItem;
/// the execution engine keeps one AqlValue struct for each document
/// that is piped through the engine. Note that the document can exist
/// in one of two formats throughout its lifetime in the engine.
/// When it resides originally in the WAl or a datafile, it stays
/// there unchanged and we only store a (pointer to) a copy of the
/// TRI_doc_mptr_t struct. Sometimes, when it is modified (or created
/// on the fly anyway), we keep the document as a TRI_json_t, wrapped
/// by a Json struct. That is, the following struct has the following
/// invariant:
/// Either the whole struct is empty and thus _json is empty and _mptr
/// is a nullptr. Otherwise, either _json is empty and _mptr is not a
/// nullptr, or _json is non-empty and _mptr is anullptr.
/// Additionally, the struct contains another TRI_json_t holding
/// the current state of the LET variables (and possibly some other
/// computations). This is the _vars attribute.
/// Note that both Json subobjects are constructed as AUTOFREE.
////////////////////////////////////////////////////////////////////////////////
struct AqlValue { struct AqlValue {
triagens::basics::Json _json;
TRI_doc_mptr_t* _mptr;
triagens::basics::Json _vars;
//////////////////////////////////////////////////////////////////////////////// enum AqlValueType {
/// @brief convenience constructors JSON,
//////////////////////////////////////////////////////////////////////////////// DOCVEC,
RANGE
};
AqlValue () struct Range {
: _json(), _mptr(nullptr), _vars() { int64_t _low;
int64_t _high;
Range(int64_t low, int64_t high) : _low(low), _high(high) {}
};
union {
triagens::basics::Json* _json;
std::vector<AqlItem*>* _vector;
Range _range;
};
AqlValueType _type;
AqlValue (triagens::basics::Json* json)
: _json(json), _type(JSON) {
} }
AqlValue (TRI_doc_mptr_t* mptr) AqlValue (std::vector<AqlItem*>* vector)
: _json(), _mptr(mptr), _vars() { : _vector(vector), _type(DOCVEC) {
} }
AqlValue (triagens::basics::Json json) AqlValue (int64_t low, int64_t high)
: _json(json), _mptr(nullptr), _vars() { : _range(low, high), _type(RANGE) {
}
~AqlValue () {
switch (_type) {
case JSON:
delete _json;
break;
case DOCVEC:
delete _vector;
break;
case RANGE:
break;
}
}
std::string toString () {
switch (_type) {
case JSON:
return _json->toString();
case DOCVEC:
return "I am a DOCVEC.";
case RANGE:
std::stringstream s;
s << "I am a range: " << _range._low << " .. " << _range._high;
return s.str();
}
}
};
struct AqlItem {
AqlItem* _outer;
int32_t _refcount;
int32_t _nrvars;
AqlValue** _vars;
AqlItem (int nrvars)
: _outer(nullptr), _refcount(1), _nrvars(nrvars) {
if (nrvars > 0) {
_vars = new AqlValue* [nrvars];
}
else {
_vars = nullptr;
}
}
AqlItem (AqlItem* outer, int nrvars)
: _outer(outer), _refcount(1), _nrvars(nrvars) {
outer->_refcount++;
if (nrvars > 0) {
_vars = new AqlValue* [nrvars];
for (int i = 0; i < nrvars; i++) {
_vars[i] = nullptr;
}
}
else {
_vars = nullptr;
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief destructor /// @brief destructor
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
~AqlValue () { ~AqlItem () {
} if (_outer != nullptr) {
_outer->_refcount--;
//////////////////////////////////////////////////////////////////////////////// if (_outer->_refcount == 0) {
/// @brief return a string representation of the value delete _outer;
//////////////////////////////////////////////////////////////////////////////// }
_outer = nullptr;
std::string toString () const {
std::string out;
if (! _json.isEmpty()) {
out += _json.toString();
} }
else if (_mptr != nullptr) { if (_vars != nullptr) {
out.append("got a master pointer"); for (int i = 0; i < _nrvars; i++) {
delete _vars[i];
}
delete[] _vars;
} }
if (! _vars.isEmpty()) {
out += _vars.toString();
}
return out;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief getValue, get the current value of a variable or attribute /// @brief getValue, get the current value of a variable or attribute
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
triagens::basics::Json getValue (std::string name); AqlValue* getValue (int up, int index) {
AqlItem* p = this;
for (int i = 0; i < up; i++) {
p = p->_outer;
}
return p->_vars[index];
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief setValue, set the current value of a variable or attribute /// @brief setValue, set the current value of a variable or attribute
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void setValue (std::string name, triagens::basics::Json json); void setValue (int up, int index, AqlValue* zeug) {
AqlItem* p = this;
for (int i = 0; i < up; i++) {
p = p->_outer;
}
p->_vars[index] = zeug;
}
}; };
@ -173,7 +232,7 @@ namespace triagens {
/// @brief execute the expression /// @brief execute the expression
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
triagens::basics::Json execute (AqlValue* aqldoc); AqlValue* execute (AqlItem* aqldoc);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief private members /// @brief private members

View File

@ -5414,7 +5414,9 @@ static v8::Handle<v8::Value> JS_PengAql (v8::Arguments const& argv) {
TRI_V8_EXCEPTION_USAGE(scope, "AQL_PENG()"); TRI_V8_EXCEPTION_USAGE(scope, "AQL_PENG()");
} }
triagens::aql::ExecutionPlan* enumPlan = new triagens::aql::EnumerateCollectionPlan(vocbase, "fuxx"); triagens::aql::ExecutionPlan* singlePlan = new triagens::aql::SingletonPlan(0);
triagens::aql::ExecutionPlan* enumPlan = new triagens::aql::EnumerateCollectionPlan(vocbase, "fuxx", 1);
enumPlan->addDependency(singlePlan);
triagens::aql::ExecutionPlan* rootPlan = new triagens::aql::RootPlan(); triagens::aql::ExecutionPlan* rootPlan = new triagens::aql::RootPlan();
rootPlan->addDependency(enumPlan); rootPlan->addDependency(enumPlan);
@ -5423,10 +5425,10 @@ static v8::Handle<v8::Value> JS_PengAql (v8::Arguments const& argv) {
exec->initialize(); exec->initialize();
exec->execute(); exec->execute();
triagens::aql::AqlValue* value; triagens::aql::AqlItem* value;
while (nullptr != (value = exec->getOne())) { while (nullptr != (value = exec->getOne())) {
std::cout << "Peng" << std::endl; std::cout << "Peng" << std::endl;
std::cout << value->toString() << std::endl; std::cout << value->getValue(0,0)->toString() << std::endl;
delete value; delete value;
} }