1
0
Fork 0

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

This commit is contained in:
Willi Goesgens 2014-10-17 14:16:19 +02:00
commit 7f387d9ac8
27 changed files with 707 additions and 286 deletions

View File

@ -64,7 +64,7 @@ FOR u IN users
!SUBSECTION Horizontal lists
Note that in the above result, an user might be returned multiple times. This is the
Note that in the above result, a user might be returned multiple times. This is the
SQL way of returning data. If this is not desired, the friends' ids of each user
can be returned in a horizontal list. This will return each user at most once.

View File

@ -1,221 +1,221 @@
article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary {
display: block
display: block
}
audio,canvas,video {
display: inline-block
display: inline-block
}
audio:not([controls]) {
display: none;
height: 0
display: none;
height: 0
}
[hidden] {
display: none
display: none
}
html {
font-family: sans-serif;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%
font-family: sans-serif;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%
}
body {
margin: 0
margin: 0
}
a:focus {
outline: thin dotted
outline: thin dotted
}
a:active,a:hover {
outline: 0
outline: 0
}
h1 {
font-size: 2em;
margin: .67em 0
font-size: 2em;
margin: .67em 0
}
abbr[title] {
border-bottom: 1px dotted
border-bottom: 1px dotted
}
b,strong {
font-weight: bold
font-weight: bold
}
dfn {
font-style: italic
font-style: italic
}
hr {
-moz-box-sizing: content-box;
box-sizing: content-box;
height: 0
-moz-box-sizing: content-box;
box-sizing: content-box;
height: 0
}
mark {
background: #ff0;
color: #000
background: #ff0;
color: #000
}
code,kbd,pre,samp {
font-family: monospace,serif;
font-size: 1em
font-family: monospace,serif;
font-size: 1em
}
pre {
white-space: pre-wrap
white-space: pre-wrap
}
q {
quotes: "\201C" "\201D" "\2018" "\2019"
quotes: "\201C" "\201D" "\2018" "\2019"
}
small {
font-size: 80%
font-size: 80%
}
sub,sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline
}
sup {
top: -0.5em
top: -0.5em
}
sub {
bottom: -0.25em
bottom: -0.25em
}
img {
border: 0
border: 0
}
svg:not(:root) {
overflow: hidden
overflow: hidden
}
figure {
margin: 0
margin: 0
}
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: .35em .625em .75em
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: .35em .625em .75em
}
legend {
border: 0;
padding: 0
border: 0;
padding: 0
}
button,input,select,textarea {
font-family: inherit;
font-size: 100%;
margin: 0
font-family: inherit;
font-size: 100%;
margin: 0
}
button,input {
line-height: normal
line-height: normal
}
button,select {
text-transform: none
text-transform: none
}
button,html input[type="button"],input[type="reset"],input[type="submit"] {
-webkit-appearance: button;
cursor: pointer
-webkit-appearance: button;
cursor: pointer
}
button[disabled],html input[disabled] {
cursor: default
cursor: default
}
input[type="checkbox"],input[type="radio"] {
box-sizing: border-box;
padding: 0
box-sizing: border-box;
padding: 0
}
input[type="search"] {
-webkit-appearance: textfield;
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box;
box-sizing: content-box
-webkit-appearance: textfield;
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box;
box-sizing: content-box
}
input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none
-webkit-appearance: none
}
button::-moz-focus-inner,input::-moz-focus-inner {
border: 0;
padding: 0
border: 0;
padding: 0
}
textarea {
overflow: auto;
vertical-align: top
overflow: auto;
vertical-align: top
}
table {
border-collapse: collapse;
border-spacing: 0
border-collapse: collapse;
border-spacing: 0
}
@font-face {
font-family: 'FontAwesome';
src: url('.//fonts/fontawesome/fontawesome-webfont.eot?v=4.1.0');
src: url('.//fonts/fontawesome/fontawesome-webfont.eot?#iefix&v=4.1.0') format('embedded-opentype'),url('.//fonts/fontawesome/fontawesome-webfont.woff?v=4.1.0') format('woff'),url('.//fonts/fontawesome/fontawesome-webfont.ttf?v=4.1.0') format('truetype'),url('.//fonts/fontawesome/fontawesome-webfont.svg?v=4.1.0#fontawesomeregular') format('svg');
font-weight: normal;
font-style: normal
font-family: 'FontAwesome';
src: url('.//fonts/fontawesome/fontawesome-webfont.eot?v=4.1.0');
src: url('.//fonts/fontawesome/fontawesome-webfont.eot?#iefix&v=4.1.0') format('embedded-opentype'),url('.//fonts/fontawesome/fontawesome-webfont.woff?v=4.1.0') format('woff'),url('.//fonts/fontawesome/fontawesome-webfont.ttf?v=4.1.0') format('truetype'),url('.//fonts/fontawesome/fontawesome-webfont.svg?v=4.1.0#fontawesomeregular') format('svg');
font-weight: normal;
font-style: normal
}
.fa {
display: inline-block;
font-family: FontAwesome;
font-style: normal;
font-weight: normal;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale
display: inline-block;
font-family: FontAwesome;
font-style: normal;
font-weight: normal;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale
}
.fa-lg {
font-size: 1.3333333333333333em;
line-height: .75em;
vertical-align: -15%
font-size: 1.3333333333333333em;
line-height: .75em;
vertical-align: -15%
}
.fa-2x {
font-size: 2em
font-size: 2em
}
.fa-3x {
font-size: 3em
font-size: 3em
}
.fa-4x {
font-size: 4em
font-size: 4em
}
.fa-5x {
font-size: 5em
font-size: 5em
}
.fa-fw {
width: 1.2857142857142858em;
text-align: center
width: 1.2857142857142858em;
text-align: center
}
.fa-ul {
padding-left: 0;
margin-left: 2.142857142857143em;
list-style-type: none
padding-left: 0;
margin-left: 2.142857142857143em;
list-style-type: none
}
.fa-ul>li {
position: relative
position: relative
}
.fa-li {
position: absolute;
left: -2.142857142857143em;
width: 2.142857142857143em;
top: .14285714285714285em;
text-align: center
position: absolute;
left: -2.142857142857143em;
width: 2.142857142857143em;
top: .14285714285714285em;
text-align: center
}
.fa-li.fa-lg {
left: -1.8571428571428572em
left: -1.8571428571428572em
}
.fa-border {
padding: .2em .25em .15em;
border: solid .08em #eee;
border-radius: .1em
padding: .2em .25em .15em;
border: solid .08em #eee;
border-radius: .1em
}
.pull-right {
float: right
float: right
}
.pull-left {
float: left
float: left
}
.fa.pull-left {
margin-right: .3em
margin-right: .3em
}
.fa.pull-right {
margin-left: .3em
margin-left: .3em
}
.fa-spin {
-webkit-animation: spin 2s infinite linear;
-moz-animation: spin 2s infinite linear;
-o-animation: spin 2s infinite linear;
animation: spin 2s infinite linear
-webkit-animation: spin 2s infinite linear;
-moz-animation: spin 2s infinite linear;
-o-animation: spin 2s infinite linear;
animation: spin 2s infinite linear
}
@-moz-keyframes spin {0% {
-moz-transform: rotate(0deg)
-moz-transform: rotate(0deg)
}
100% {
-moz-transform: rotate(359deg)
-moz-transform: rotate(359deg)
}
}
@ -1634,6 +1634,9 @@ color: inherit
.hidden {
display: none
}
.lets-see-who-copies-this: {
font-family: 'proven!';
}
@font-face {
font-family: 'Merriweather';
font-style: normal;
@ -2904,10 +2907,10 @@ font-family: "Open Sans","Clear Sans","Helvetica Neue",Helvetica,Arial,sans-seri
font-size: 14px
}
div.example_show_button {
border: medium solid lightgray;
text-align: center;
position: relative;
top: -10px;
border: medium solid lightgray;
text-align: center;
position: relative;
top: -10px;
}
.book .book-body .page-wrapper .page-inner section.normal .deprecated{
@ -2919,26 +2922,26 @@ background-color: rgba(240,240,0,0.4);
}
#clear-search {
display: inline;
position: absolute;
top: 12px;
right: 9px;
font-size: 18pt;
line-height: 18pt;
color: #364149; // needs to be updated on theme change
display: inline;
position: absolute;
top: 12px;
right: 9px;
font-size: 18pt;
line-height: 18pt;
color: #364149; // needs to be updated on theme change
}
#clear-search:hover {
color: #008cff; // needs to be updated on theme change
text-decoration: none;
color: #008cff; // needs to be updated on theme change
text-decoration: none;
}
.book .book-summary .book-search input{
padding-right: 20px !important;
padding-right: 20px !important;
}
.book .book-header {
background-color: #FFFFFF !important;
width: 84%;
position:fixed !important;
}
background-color: #FFFFFF !important;
width: 84%;
position:fixed !important;
}

View File

@ -111,6 +111,23 @@ std::vector<std::string> Collection::shardIds () const {
return ids;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the shard keys of a collection
////////////////////////////////////////////////////////////////////////////////
std::vector<std::string> Collection::shardKeys () const {
auto clusterInfo = triagens::arango::ClusterInfo::instance();
auto collectionInfo = clusterInfo->getCollection(std::string(vocbase->_name), name);
if (collectionInfo.get() == nullptr) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "collection not found");
}
std::vector<std::string> keys;
for (auto const& x : collectionInfo.get()->shardKeys()) {
keys.emplace_back(x);
}
return keys;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the indexes of the collection
////////////////////////////////////////////////////////////////////////////////

View File

@ -145,6 +145,12 @@ namespace triagens {
std::vector<std::string> shardIds () const;
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the shard keys of a collection
////////////////////////////////////////////////////////////////////////////////
std::vector<std::string> shardKeys () const;
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the indexes of the collection
////////////////////////////////////////////////////////////////////////////////

View File

@ -3717,6 +3717,28 @@ size_t BlockWithClients::getClientId (std::string const& shardId) {
return ((*it).second);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief preInitCursor: check if we should really init the cursor, and reset
/// _doneForClient
////////////////////////////////////////////////////////////////////////////////
bool BlockWithClients::preInitCursor () {
if (!_initOrShutdown) {
return false;
}
_doneForClient.clear();
_doneForClient.reserve(_nrClients);
for (size_t i = 0; i < _nrClients; i++) {
_doneForClient.push_back(false);
}
_initOrShutdown = false;
return true;
}
// -----------------------------------------------------------------------------
// --SECTION-- class ScatterBlock
// -----------------------------------------------------------------------------
@ -3727,25 +3749,20 @@ size_t BlockWithClients::getClientId (std::string const& shardId) {
int ScatterBlock::initializeCursor (AqlItemBlock* items, size_t pos) {
if (!_initOrShutdown) {
if (!preInitCursor()) {
return TRI_ERROR_NO_ERROR;
}
int res = ExecutionBlock::initializeCursor(items, pos);
int res = ExecutionBlock::initializeCursor(items, pos);
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
_posForClient.clear();
_doneForClient.clear();
_doneForClient.reserve(_nrClients);
for (size_t i = 0; i < _nrClients; i++) {
_posForClient.push_back(std::make_pair(0, 0));
_doneForClient.push_back(false);
}
_initOrShutdown = false;
return TRI_ERROR_NO_ERROR;
}
@ -3896,27 +3913,18 @@ DistributeBlock::DistributeBlock (ExecutionEngine* engine,
int DistributeBlock::initializeCursor (AqlItemBlock* items, size_t pos) {
if (!_initOrShutdown) {
if (!preInitCursor()) {
return TRI_ERROR_NO_ERROR;
}
int res = ExecutionBlock::initializeCursor(items, pos);
int res = ExecutionBlock::initializeCursor(items, pos);
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
for (auto x: _distBuffer) {
x.clear();
}
_distBuffer.clear();
_distBuffer.reserve(_nrClients);
for (auto x: _doneForClient) {
x = false;
}
_initOrShutdown = false;
return TRI_ERROR_NO_ERROR;
}
@ -4114,11 +4122,18 @@ bool DistributeBlock::getBlockForClient (size_t atLeast,
////////////////////////////////////////////////////////////////////////////////
size_t DistributeBlock::sendToClient (AqlValue val) {
TRI_ASSERT(val._type == AqlValue::JSON);
//TODO should work for SHAPED too (maybe this requires converting it to TRI_json_t)
TRI_json_t const* json = val._json->json();
TRI_json_t const* json;
if (val._type == AqlValue::JSON) {
json = val._json->json();
}
else if (val._type == AqlValue::SHAPED) {
json = val.toJson(_trx, _collection->documentCollection()).json();
}
else {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_FAILED,
"DistributeBlock: can only send JSON or SHAPED");
}
std::string shardId;
bool usesDefaultShardingAttributes;

View File

@ -1613,6 +1613,13 @@ namespace triagens {
// --SECTION-- BlockWithClients protected methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief preInitCursor: check if we should really init the cursor, and reset
/// _doneForClient
////////////////////////////////////////////////////////////////////////////////
bool preInitCursor ();
////////////////////////////////////////////////////////////////////////////////
/// @brief getOrSkipSomeForShard
////////////////////////////////////////////////////////////////////////////////

View File

@ -2448,7 +2448,6 @@ void DistributeNode::toJsonHelper (triagens::basics::Json& nodes,
("collection", triagens::basics::Json(_collection->getName()))
("varId", triagens::basics::Json(static_cast<int>(_varId)));
// And add it:
nodes(json);
}

View File

@ -421,6 +421,16 @@ void Executor::generateCodeString (char const* value) {
_buffer->appendChar('"');
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generates code for a string value
////////////////////////////////////////////////////////////////////////////////
void Executor::generateCodeString (std::string const& value) {
_buffer->appendChar('"');
_buffer->appendJsonEncoded(value.c_str());
_buffer->appendChar('"');
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generate JavaScript code for a list
////////////////////////////////////////////////////////////////////////////////

View File

@ -27,8 +27,8 @@
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_AQL_V8_EXECUTOR_H
#define ARANGODB_AQL_V8_EXECUTOR_H 1
#ifndef ARANGODB_AQL_EXECUTOR_H
#define ARANGODB_AQL_EXECUTOR_H 1
#include "Basics/Common.h"
#include "Aql/Function.h"
@ -121,6 +121,12 @@ namespace triagens {
void generateCodeString (char const*);
////////////////////////////////////////////////////////////////////////////////
/// @brief generates code for a string value
////////////////////////////////////////////////////////////////////////////////
void generateCodeString (std::string const&);
////////////////////////////////////////////////////////////////////////////////
/// @brief generate JavaScript code for a list
////////////////////////////////////////////////////////////////////////////////

View File

@ -1688,7 +1688,6 @@ int triagens::aql::scatterInCluster (Optimizer* opt,
// re-link with the remote node
node->addDependency(remoteNode);
// insert another remote node
remoteNode = new RemoteNode(plan, plan->nextId(), vocbase, collection, "", "", "");
@ -1742,21 +1741,30 @@ int triagens::aql::distributeInCluster (Optimizer* opt,
auto const nodeType = node->getType();
if (nodeType != ExecutionNode::INSERT &&
nodeType != ExecutionNode::UPDATE &&
nodeType != ExecutionNode::REPLACE &&
nodeType != ExecutionNode::REMOVE) {
opt->addPlan(plan, rule->level, wasModified);
return TRI_ERROR_NO_ERROR;
}
Collection const* collection = static_cast<ModificationNode*>(node)->collection();
if (nodeType == ExecutionNode::REMOVE) {
// check if collection shard keys are only _key
std::vector<std::string> shardKeys = collection->shardKeys();
if (shardKeys.size() != 1 || shardKeys[0] != "_key") {
opt->addPlan(plan, rule->level, wasModified);
return TRI_ERROR_NO_ERROR;
}
}
auto deps = node->getDependencies();
TRI_ASSERT(deps.size() == 1);
// unlink the node
plan->unlinkNode(node, true);
// extract database and collection from plan node
// extract database from plan node
TRI_vocbase_t* vocbase = static_cast<ModificationNode*>(node)->vocbase();
Collection const* collection = static_cast<ModificationNode*>(node)->collection();
// insert a distribute node
TRI_ASSERT(node->getVariablesUsedHere().size() == 1);
@ -1782,6 +1790,7 @@ int triagens::aql::distributeInCluster (Optimizer* opt,
opt->addPlan(plan, rule->level, wasModified);
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief move filters up into the cluster distribution part of the plan
/// this rule modifies the plan in place

View File

@ -37,9 +37,11 @@
#include "Basics/JsonHelper.h"
#include "Basics/json.h"
#include "Basics/tri-strings.h"
#include "Cluster/ServerState.h"
#include "Utils/AqlTransaction.h"
#include "Utils/Exception.h"
#include "Utils/V8TransactionContext.h"
#include "V8Server/ApplicationV8.h"
#include "VocBase/vocbase.h"
using namespace triagens::aql;
@ -115,14 +117,18 @@ TRI_json_t* Profile::toJson (TRI_memory_zone_t*) {
/// @brief creates a query
////////////////////////////////////////////////////////////////////////////////
Query::Query (TRI_vocbase_t* vocbase,
Query::Query (triagens::arango::ApplicationV8* applicationV8,
bool contextOwnedByExterior,
TRI_vocbase_t* vocbase,
char const* queryString,
size_t queryLength,
TRI_json_t* bindParameters,
TRI_json_t* options,
QueryPart part)
: _vocbase(vocbase),
: _applicationV8(applicationV8),
_vocbase(vocbase),
_executor(nullptr),
_context(nullptr),
_queryString(queryString),
_queryLength(queryLength),
_queryJson(),
@ -137,7 +143,9 @@ Query::Query (TRI_vocbase_t* vocbase,
_parser(nullptr),
_trx(nullptr),
_engine(nullptr),
_part(part) {
_part(part),
_clusterStatus(-1),
_contextOwnedByExterior(contextOwnedByExterior) {
TRI_ASSERT(_vocbase != nullptr);
@ -156,12 +164,16 @@ Query::Query (TRI_vocbase_t* vocbase,
/// @brief creates a query from Json
////////////////////////////////////////////////////////////////////////////////
Query::Query (TRI_vocbase_t* vocbase,
Query::Query (triagens::arango::ApplicationV8* applicationV8,
bool contextOwnedByExterior,
TRI_vocbase_t* vocbase,
triagens::basics::Json queryStruct,
TRI_json_t* options,
QueryPart part)
: _vocbase(vocbase),
: _applicationV8(applicationV8),
_vocbase(vocbase),
_executor(nullptr),
_context(nullptr),
_queryString(nullptr),
_queryLength(0),
_queryJson(queryStruct),
@ -176,7 +188,9 @@ Query::Query (TRI_vocbase_t* vocbase,
_parser(nullptr),
_trx(nullptr),
_engine(nullptr),
_part(part) {
_part(part),
_clusterStatus(-1),
_contextOwnedByExterior(contextOwnedByExterior) {
TRI_ASSERT(_vocbase != nullptr);
@ -213,6 +227,12 @@ Query::~Query () {
_executor = nullptr;
}
if (_context != nullptr) {
TRI_ASSERT(! _contextOwnedByExterior);
_applicationV8->exitContext(_context);
_context = nullptr;
}
if (_ast != nullptr) {
delete _ast;
_ast = nullptr;
@ -242,7 +262,9 @@ Query* Query::clone (QueryPart part) {
std::unique_ptr<Query> clone;
try {
clone.reset(new Query(_vocbase,
clone.reset(new Query(_applicationV8,
false,
_vocbase,
_queryString,
_queryLength,
nullptr,
@ -759,6 +781,55 @@ char* Query::registerString (std::string const& p,
// --SECTION-- private methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not we are running in a cluster
////////////////////////////////////////////////////////////////////////////////
bool Query::isRunningInCluster () {
if (_clusterStatus == -1) {
// not yet determined
_clusterStatus = 0;
if (triagens::arango::ServerState::instance()->isRunningInCluster()) {
_clusterStatus = 1;
}
}
TRI_ASSERT(_clusterStatus == 0 || _clusterStatus == 1);
return (_clusterStatus == 1);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief enter a V8 context
////////////////////////////////////////////////////////////////////////////////
void Query::enterContext () {
if (! _contextOwnedByExterior) {
if (_context == nullptr) {
_context = _applicationV8->enterContext("STANDARD", _vocbase, false, false);
if (_context == nullptr) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "cannot enter V8 context");
}
}
TRI_ASSERT(_context != nullptr);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return a V8 context
////////////////////////////////////////////////////////////////////////////////
void Query::exitContext () {
if (! _contextOwnedByExterior) {
if (_context != nullptr) {
if (isRunningInCluster()) {
_applicationV8->exitContext(_context);
_context = nullptr;
}
}
TRI_ASSERT(_context == nullptr);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief fetch a boolean value from the options
////////////////////////////////////////////////////////////////////////////////

View File

@ -38,6 +38,7 @@
#include "Aql/types.h"
#include "Utils/AqlTransaction.h"
#include "Utils/V8TransactionContext.h"
#include "V8Server/ApplicationV8.h"
struct TRI_json_t;
struct TRI_vocbase_s;
@ -127,14 +128,18 @@ namespace triagens {
public:
Query (struct TRI_vocbase_s*,
Query (triagens::arango::ApplicationV8*,
bool,
struct TRI_vocbase_s*,
char const*,
size_t,
struct TRI_json_t*,
struct TRI_json_t*,
QueryPart);
Query (struct TRI_vocbase_s*,
Query (triagens::arango::ApplicationV8*,
bool,
struct TRI_vocbase_s*,
triagens::basics::Json queryStruct,
struct TRI_json_t*,
QueryPart);
@ -362,10 +367,28 @@ namespace triagens {
void setPlan (ExecutionPlan *plan);
////////////////////////////////////////////////////////////////////////////////
/// @brief enter a V8 context
////////////////////////////////////////////////////////////////////////////////
void enterContext ();
////////////////////////////////////////////////////////////////////////////////
/// @brief exits a V8 context
////////////////////////////////////////////////////////////////////////////////
void exitContext ();
// -----------------------------------------------------------------------------
// --SECTION-- private methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not we are running in a cluster
////////////////////////////////////////////////////////////////////////////////
bool isRunningInCluster ();
////////////////////////////////////////////////////////////////////////////////
/// @brief fetch a boolean value from the options
////////////////////////////////////////////////////////////////////////////////
@ -416,96 +439,108 @@ namespace triagens {
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief application v8 used in the query, we need this for V8 context access
////////////////////////////////////////////////////////////////////////////////
triagens::arango::ApplicationV8* _applicationV8;
////////////////////////////////////////////////////////////////////////////////
/// @brief all nodes created in the AST - will be used for freeing them later
////////////////////////////////////////////////////////////////////////////////
std::vector<AstNode*> _nodes;
std::vector<AstNode*> _nodes;
////////////////////////////////////////////////////////////////////////////////
/// @brief pointer to vocbase the query runs in
////////////////////////////////////////////////////////////////////////////////
struct TRI_vocbase_s* _vocbase;
struct TRI_vocbase_s* _vocbase;
////////////////////////////////////////////////////////////////////////////////
/// @brief V8 code executor
////////////////////////////////////////////////////////////////////////////////
Executor* _executor;
Executor* _executor;
////////////////////////////////////////////////////////////////////////////////
/// @brief the currently used V8 context
////////////////////////////////////////////////////////////////////////////////
triagens::arango::ApplicationV8::V8Context* _context;
////////////////////////////////////////////////////////////////////////////////
/// @brief the actual query string
////////////////////////////////////////////////////////////////////////////////
char const* _queryString;
char const* _queryString;
////////////////////////////////////////////////////////////////////////////////
/// @brief length of the query string in bytes
////////////////////////////////////////////////////////////////////////////////
size_t const _queryLength;
size_t const _queryLength;
////////////////////////////////////////////////////////////////////////////////
/// @brief query in a JSON structure
////////////////////////////////////////////////////////////////////////////////
triagens::basics::Json const _queryJson;
triagens::basics::Json const _queryJson;
////////////////////////////////////////////////////////////////////////////////
/// @brief bind parameters for the query
////////////////////////////////////////////////////////////////////////////////
BindParameters _bindParameters;
BindParameters _bindParameters;
////////////////////////////////////////////////////////////////////////////////
/// @brief query options
////////////////////////////////////////////////////////////////////////////////
TRI_json_t* _options;
TRI_json_t* _options;
////////////////////////////////////////////////////////////////////////////////
/// @brief collections used in the query
////////////////////////////////////////////////////////////////////////////////
Collections _collections;
Collections _collections;
////////////////////////////////////////////////////////////////////////////////
/// @brief all strings created in the query - used for easy memory deallocation
////////////////////////////////////////////////////////////////////////////////
std::vector<char const*> _strings;
std::vector<char const*> _strings;
////////////////////////////////////////////////////////////////////////////////
/// @brief _ast, we need an ast to manage the memory for AstNodes, even
/// if we do not have a parser, because AstNodes occur in plans and engines
////////////////////////////////////////////////////////////////////////////////
Ast* _ast;
Ast* _ast;
////////////////////////////////////////////////////////////////////////////////
/// @brief query execution profile
////////////////////////////////////////////////////////////////////////////////
Profile* _profile;
Profile* _profile;
////////////////////////////////////////////////////////////////////////////////
/// @brief current state the query is in (used for profiling and error messages)
////////////////////////////////////////////////////////////////////////////////
ExecutionState _state;
ExecutionState _state;
////////////////////////////////////////////////////////////////////////////////
/// @brief the ExecutionPlan object, if the query is prepared
////////////////////////////////////////////////////////////////////////////////
ExecutionPlan* _plan;
ExecutionPlan* _plan;
////////////////////////////////////////////////////////////////////////////////
/// @brief the Parser object, if the query is prepared
////////////////////////////////////////////////////////////////////////////////
Parser* _parser;
Parser* _parser;
////////////////////////////////////////////////////////////////////////////////
/// @brief the transaction object, in a distributed query every part of
@ -519,13 +554,25 @@ namespace triagens {
/// @brief the ExecutionEngine object, if the query is prepared
////////////////////////////////////////////////////////////////////////////////
ExecutionEngine* _engine;
ExecutionEngine* _engine;
////////////////////////////////////////////////////////////////////////////////
/// @brief the query part
////////////////////////////////////////////////////////////////////////////////
QueryPart const _part;
QueryPart const _part;
////////////////////////////////////////////////////////////////////////////////
/// @brief internal variable we use to determine whether we are in a cluster
////////////////////////////////////////////////////////////////////////////////
short int _clusterStatus;
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not someone else has acquired a V8 context for us
////////////////////////////////////////////////////////////////////////////////
bool const _contextOwnedByExterior;
};
}

View File

@ -127,7 +127,7 @@ void RestAqlHandler::createQueryFromJson () {
std::string const part = JsonHelper::getStringValue(queryJson.json(), "part", "");
auto query = new Query(_vocbase, plan, options.steal(), (part == "main" ? PART_MAIN : PART_DEPENDENT));
auto query = new Query(_applicationV8, false, _vocbase, plan, options.steal(), (part == "main" ? PART_MAIN : PART_DEPENDENT));
QueryResult res = query->prepare(_queryRegistry);
if (res.code != TRI_ERROR_NO_ERROR) {
generateError(HttpResponse::BAD, TRI_ERROR_QUERY_BAD_JSON_PLAN,
@ -188,7 +188,7 @@ void RestAqlHandler::parseQuery () {
return;
}
auto query = new Query(_vocbase, queryString.c_str(), queryString.size(),
auto query = new Query(_applicationV8, false, _vocbase, queryString.c_str(), queryString.size(),
nullptr, nullptr, PART_MAIN);
QueryResult res = query->parse();
if (res.code != TRI_ERROR_NO_ERROR) {
@ -244,7 +244,7 @@ void RestAqlHandler::explainQuery () {
Json options;
options = queryJson.get("options").copy(); // cannot throw
auto query = new Query(_vocbase, queryString.c_str(), queryString.size(),
auto query = new Query(_applicationV8, false, _vocbase, queryString.c_str(), queryString.size(),
parameters.steal(), options.steal(), PART_MAIN);
QueryResult res = query->explain();
if (res.code != TRI_ERROR_NO_ERROR) {
@ -304,7 +304,7 @@ void RestAqlHandler::createQueryFromString () {
Json options;
options = queryJson.get("options").copy(); // cannot throw
auto query = new Query(_vocbase, queryString.c_str(), queryString.size(),
auto query = new Query(_applicationV8, false, _vocbase, queryString.c_str(), queryString.size(),
parameters.steal(), options.steal(), (part == "main" ? PART_MAIN : PART_DEPENDENT));
QueryResult res = query->prepare(_queryRegistry);
if (res.code != TRI_ERROR_NO_ERROR) {
@ -586,84 +586,73 @@ void RestAqlHandler::getInfoQuery (std::string const& operation,
triagens::rest::HttpHandler::status_t RestAqlHandler::execute () {
//std::cout << "GOT INCOMING REQUEST: " << triagens::rest::HttpRequest::translateMethod(_request->requestType()) << ", " << triagens::arango::ServerState::instance()->getId() << ": " << _request->fullUrl() << ": " << _request->body() << "\n";
auto context = _applicationV8->enterContext("STANDARD", _vocbase,
false, false);
if (nullptr == context) {
generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL,
"cannot enter V8 context");
}
else {
std::vector<std::string> const& suffix = _request->suffix();
std::vector<std::string> const& suffix = _request->suffix();
// extract the sub-request type
HttpRequest::HttpRequestType type = _request->requestType();
// extract the sub-request type
HttpRequest::HttpRequestType type = _request->requestType();
// execute one of the CRUD methods
switch (type) {
case HttpRequest::HTTP_REQUEST_POST: {
if (suffix.size() != 1) {
generateError(HttpResponse::NOT_FOUND, TRI_ERROR_HTTP_NOT_FOUND);
}
else if (suffix[0] == "instanciate") {
createQueryFromJson();
}
else if (suffix[0] == "parse") {
parseQuery();
}
else if (suffix[0] == "explain") {
explainQuery();
}
else if (suffix[0] == "query") {
createQueryFromString();
}
else {
generateError(HttpResponse::NOT_FOUND, TRI_ERROR_HTTP_NOT_FOUND);
}
break;
// execute one of the CRUD methods
switch (type) {
case HttpRequest::HTTP_REQUEST_POST: {
if (suffix.size() != 1) {
generateError(HttpResponse::NOT_FOUND, TRI_ERROR_HTTP_NOT_FOUND);
}
case HttpRequest::HTTP_REQUEST_DELETE: {
if (suffix.size() != 1) {
generateError(HttpResponse::NOT_FOUND, TRI_ERROR_HTTP_NOT_FOUND);
}
else {
deleteQuery(suffix[0]);
}
break;
else if (suffix[0] == "instanciate") {
createQueryFromJson();
}
case HttpRequest::HTTP_REQUEST_PUT: {
if (suffix.size() != 2) {
generateError(HttpResponse::NOT_FOUND, TRI_ERROR_HTTP_NOT_FOUND);
}
else {
useQuery(suffix[0], suffix[1]);
}
break;
else if (suffix[0] == "parse") {
parseQuery();
}
case HttpRequest::HTTP_REQUEST_GET: {
if (suffix.size() != 2) {
generateError(HttpResponse::NOT_FOUND, TRI_ERROR_HTTP_NOT_FOUND);
}
else {
getInfoQuery(suffix[0], suffix[1]);
}
break;
else if (suffix[0] == "explain") {
explainQuery();
}
case HttpRequest::HTTP_REQUEST_HEAD:
case HttpRequest::HTTP_REQUEST_PATCH:
case HttpRequest::HTTP_REQUEST_OPTIONS:
case HttpRequest::HTTP_REQUEST_ILLEGAL: {
generateError(HttpResponse::METHOD_NOT_ALLOWED,
TRI_ERROR_NOT_IMPLEMENTED,
"illegal method for /_api/aql");
break;
else if (suffix[0] == "query") {
createQueryFromString();
}
else {
generateError(HttpResponse::NOT_FOUND, TRI_ERROR_HTTP_NOT_FOUND);
}
break;
}
case HttpRequest::HTTP_REQUEST_DELETE: {
if (suffix.size() != 1) {
generateError(HttpResponse::NOT_FOUND, TRI_ERROR_HTTP_NOT_FOUND);
}
else {
deleteQuery(suffix[0]);
}
break;
}
case HttpRequest::HTTP_REQUEST_PUT: {
if (suffix.size() != 2) {
generateError(HttpResponse::NOT_FOUND, TRI_ERROR_HTTP_NOT_FOUND);
}
else {
useQuery(suffix[0], suffix[1]);
}
break;
}
case HttpRequest::HTTP_REQUEST_GET: {
if (suffix.size() != 2) {
generateError(HttpResponse::NOT_FOUND, TRI_ERROR_HTTP_NOT_FOUND);
}
else {
getInfoQuery(suffix[0], suffix[1]);
}
break;
}
case HttpRequest::HTTP_REQUEST_HEAD:
case HttpRequest::HTTP_REQUEST_PATCH:
case HttpRequest::HTTP_REQUEST_OPTIONS:
case HttpRequest::HTTP_REQUEST_ILLEGAL: {
generateError(HttpResponse::METHOD_NOT_ALLOWED,
TRI_ERROR_NOT_IMPLEMENTED,
"illegal method for /_api/aql");
break;
}
}
_applicationV8->exitContext(context);
//std::cout << "REQUEST HANDLING DONE: " << triagens::arango::ServerState::instance()->getId() << ": " << _request->fullUrl() << ": " << _response->responseCode() << ", CONTENT-LENGTH: " << _response->contentLength() << "\n";
return status_t(HANDLER_DONE);

View File

@ -255,7 +255,6 @@ bool ServerState::isRunningInCluster () {
_role == ServerState::ROLE_COORDINATOR);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get the server id
////////////////////////////////////////////////////////////////////////////////

View File

@ -1224,7 +1224,7 @@ bool ApplicationV8::prepareV8Instance (const string& name, size_t i, bool useAct
context->_context->Enter();
TRI_InitV8VocBridge(context->_context, _queryRegistry, _server, _vocbase, &_startupLoader, i);
TRI_InitV8VocBridge(this, context->_context, _queryRegistry, _server, _vocbase, &_startupLoader, i);
TRI_InitV8Queries(context->_context);
TRI_InitV8UserStructures(context->_context);

View File

@ -1343,8 +1343,7 @@ void TRI_InitV8Actions (v8::Handle<v8::Context> context,
GlobalV8Dealer = applicationV8;
// check the isolate
v8::Isolate* isolate = v8::Isolate::GetCurrent();
/* TRI_v8_global_t* v8g = */ TRI_CreateV8Globals(isolate);
v8::Isolate::GetCurrent();
// .............................................................................
// create the global functions

View File

@ -462,8 +462,7 @@ void TRI_InitV8Dispatcher (v8::Handle<v8::Context> context,
GlobalV8Dealer = applicationV8;
// check the isolate
v8::Isolate* isolate = v8::Isolate::GetCurrent();
/* TRI_v8_global_t* v8g = */ TRI_CreateV8Globals(isolate);
v8::Isolate::GetCurrent();
// .............................................................................
// create the global functions

View File

@ -821,7 +821,8 @@ static v8::Handle<v8::Value> JS_ParseAql (v8::Arguments const& argv) {
string const&& queryString = TRI_ObjectToString(argv[0]);
triagens::aql::Query query(vocbase, queryString.c_str(), queryString.size(), nullptr, nullptr, triagens::aql::PART_MAIN);
TRI_v8_global_t* v8g = static_cast<TRI_v8_global_t*>(v8::Isolate::GetCurrent()->GetData());
triagens::aql::Query query(v8g->_applicationV8, true, vocbase, queryString.c_str(), queryString.size(), nullptr, nullptr, triagens::aql::PART_MAIN);
auto parseResult = query.parse();
@ -906,7 +907,8 @@ static v8::Handle<v8::Value> JS_ExplainAql (v8::Arguments const& argv) {
}
// bind parameters will be freed by the query later
triagens::aql::Query query(vocbase, queryString.c_str(), queryString.size(), parameters, options, triagens::aql::PART_MAIN);
TRI_v8_global_t* v8g = static_cast<TRI_v8_global_t*>(v8::Isolate::GetCurrent()->GetData());
triagens::aql::Query query(v8g->_applicationV8, true, vocbase, queryString.c_str(), queryString.size(), parameters, options, triagens::aql::PART_MAIN);
auto queryResult = query.explain();
@ -998,8 +1000,8 @@ static v8::Handle<v8::Value> JS_ExecuteAqlJson (v8::Arguments const& argv) {
}
TRI_v8_global_t* v8g = static_cast<TRI_v8_global_t*>(v8::Isolate::GetCurrent()->GetData());
triagens::aql::Query query(v8g->_applicationV8, true, vocbase, Json(TRI_UNKNOWN_MEM_ZONE, queryjson), options, triagens::aql::PART_MAIN);
triagens::aql::Query query(vocbase, Json(TRI_UNKNOWN_MEM_ZONE, queryjson), options, triagens::aql::PART_MAIN);
auto queryResult = query.execute(static_cast<triagens::aql::QueryRegistry*>(v8g->_queryRegistry));
if (queryResult.code != TRI_ERROR_NO_ERROR) {
@ -1133,10 +1135,10 @@ static v8::Handle<v8::Value> JS_ExecuteAql (v8::Arguments const& argv) {
options = TRI_ObjectToJson(argv[2]);
}
TRI_v8_global_t* v8g = static_cast<TRI_v8_global_t*>(v8::Isolate::GetCurrent()->GetData());
// bind parameters will be freed by the query later
triagens::aql::Query query(vocbase, queryString.c_str(), queryString.size(), parameters, options, triagens::aql::PART_MAIN);
TRI_v8_global_t* v8g = static_cast<TRI_v8_global_t*>(v8::Isolate::GetCurrent()->GetData());
triagens::aql::Query query(v8g->_applicationV8, true, vocbase, queryString.c_str(), queryString.size(), parameters, options, triagens::aql::PART_MAIN);
auto queryResult = query.execute(static_cast<triagens::aql::QueryRegistry*>(v8g->_queryRegistry));
if (queryResult.code != TRI_ERROR_NO_ERROR) {
@ -2489,7 +2491,8 @@ void TRI_V8ReloadRouting (v8::Handle<v8::Context> context) {
/// @brief creates a TRI_vocbase_t global context
////////////////////////////////////////////////////////////////////////////////
void TRI_InitV8VocBridge (v8::Handle<v8::Context> context,
void TRI_InitV8VocBridge (triagens::arango::ApplicationV8* applicationV8,
v8::Handle<v8::Context> context,
triagens::aql::QueryRegistry* queryRegistry,
TRI_server_t* server,
TRI_vocbase_t* vocbase,
@ -2502,7 +2505,6 @@ void TRI_InitV8VocBridge (v8::Handle<v8::Context> context,
TRI_v8_global_t* v8g = TRI_CreateV8Globals(isolate);
TRI_ASSERT(v8g->_transactionContext == nullptr);
v8g->_transactionContext = new V8TransactionContext(true);
static_cast<V8TransactionContext*>(v8g->_transactionContext)->makeGlobal();
@ -2517,6 +2519,9 @@ void TRI_InitV8VocBridge (v8::Handle<v8::Context> context,
// register the startup loader
v8g->_loader = loader;
// register the context dealer
v8g->_applicationV8 = applicationV8;
v8::Handle<v8::ObjectTemplate> ArangoNS;
v8::Handle<v8::ObjectTemplate> rt;

View File

@ -45,6 +45,7 @@ namespace triagens {
}
namespace arango {
class ApplicationV8;
class CollectionNameResolver;
class JSLoader;
}
@ -95,7 +96,8 @@ void TRI_V8ReloadRouting (v8::Handle<v8::Context>);
/// @brief creates a TRI_vocbase_t global context
////////////////////////////////////////////////////////////////////////////////
void TRI_InitV8VocBridge (v8::Handle<v8::Context>,
void TRI_InitV8VocBridge (triagens::arango::ApplicationV8*,
v8::Handle<v8::Context>,
triagens::aql::QueryRegistry*,
struct TRI_server_s*,
struct TRI_vocbase_s*,

View File

@ -159,7 +159,7 @@
"count": this.getPageSize()
};
query = "FOR x in @@collection";
query = "FOR x in @@collection let att = slice(ATTRIBUTES(x), 0, 10)";
query += this.setFiltersForQuery(bindVars);
// Sort result, only useful for a small number of docs
if (this.getTotal() < this.MAX_SORT) {
@ -173,14 +173,14 @@
}
if (bindVars.count !== 'all') {
query += " LIMIT @offset, @count RETURN x";
query += " LIMIT @offset, @count RETURN keep(x, att)";
}
else {
tmp = {
"@collection": this.collectionID
};
bindVars = tmp;
query += " RETURN x";
query += " RETURN keep(x, att)";
}
queryObj = {

View File

@ -106,7 +106,20 @@
visibility: [true, false],
labels: ["datetime", "Major Page", "Minor Page"],
div: "pageFaultsChart",
labelsKMG2: false
labelsKMG2: false,
axes: {
y: {
valueFormatter: function (y) {
return parseFloat(y.toPrecision(3));
},
axisLabelFormatter: function (y) {
if (y === 0) {
return 0;
}
return parseFloat(y.toPrecision(3));
}
}
}
},
systemUserTime: {

View File

@ -46,9 +46,15 @@
$('#collectionsToggle').addClass('activated');
}
var length = searchOptions.searchPhrase.length;
var length;
try {
length = searchOptions.searchPhrase.length;
}
catch (ignore) {
}
$('#searchInput').val(searchOptions.searchPhrase);
$('#searchInput').focus();
$('#searchInput').focus();
$('#searchInput')[0].setSelectionRange(length, length);
arangoHelper.fixTooltips(".icon_arangodb, .arangoicon", "left");

View File

@ -80,7 +80,7 @@ function optimizerRuleTestSuite () {
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test that rule does not fire when it is not enabled
/// @brief test that the rule fires when it is enabled
////////////////////////////////////////////////////////////////////////////////
testThisRuleEnabled : function () {
@ -89,10 +89,71 @@ function optimizerRuleTestSuite () {
[ "FOR d IN " + cn1 + " REMOVE d._key in " + cn1, 1],
[ "FOR d IN " + cn1 + " INSERT d in " + cn2, 2],
[ "FOR d IN " + cn1 + " INSERT d._key in " + cn2, 3],
[ "FOR d IN " + cn1 + " REPLACE d in " + cn1, 4],
[ "FOR d IN " + cn1 + " REPLACE d._key in " + cn1, 5],
[ "FOR d IN " + cn1 + " UPDATE d in " + cn1 , 6],
[ "FOR d IN " + cn1 + " UPDATE d._key in " + cn1 , 7]
];
var expectedRules = [
[
"distribute-in-cluster",
"scatter-in-cluster",
],
[
"distribute-in-cluster",
"scatter-in-cluster",
"distribute-filtercalc-to-cluster"
]
];
var expectedNodes = [
[
"SingletonNode",
"ScatterNode",
"RemoteNode",
"EnumerateCollectionNode",
"RemoteNode",
"GatherNode",
"DistributeNode",
"RemoteNode"
],
[
"SingletonNode",
"ScatterNode",
"RemoteNode",
"EnumerateCollectionNode",
"CalculationNode",
"RemoteNode",
"GatherNode",
"DistributeNode",
"RemoteNode"
]
];
var finalNodes = [
"RemoveNode", "RemoveNode",
"InsertNode", "InsertNode"
];
queries.forEach(function(query) {
// can't turn this rule off so should always get the same answer
var i = query[1] % 2;
var result = AQL_EXPLAIN(query[0], { }, thisRuleEnabled);
assertEqual(expectedRules[i], result.plan.rules, query);
expectedNodes[i].push(finalNodes[query[1]]);
assertEqual(expectedNodes[i], explain(result), query);
expectedNodes[i].pop();
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test that rule fires when it is disabled (i.e. it can't be disabled)
////////////////////////////////////////////////////////////////////////////////
testThisRuleDisabled : function () {
var queries = [
[ "FOR d IN " + cn1 + " REMOVE d in " + cn1, 0],
[ "FOR d IN " + cn1 + " REMOVE d._key in " + cn1, 1],
[ "FOR d IN " + cn1 + " INSERT d in " + cn2, 2],
[ "FOR d IN " + cn1 + " INSERT d._key in " + cn2, 3],
];
var expectedRules = [
@ -131,12 +192,74 @@ function optimizerRuleTestSuite () {
var finalNodes = [
"RemoveNode", "RemoveNode",
"InsertNode", "InsertNode",
"ReplaceNode", "ReplaceNode",
"UpdateNode", "UpdateNode"
"InsertNode", "InsertNode"
];
queries.forEach(function(query) {
// can't turn this rule off so should always get the same answer
var i = query[1] % 2;
var result = AQL_EXPLAIN(query[0], { }, rulesAll);
assertEqual(expectedRules[i], result.plan.rules, query);
expectedNodes[i].push(finalNodes[query[1]]);
result = AQL_EXPLAIN(query[0], { }, thisRuleDisabled);
assertEqual(expectedNodes[i], explain(result), query);
expectedNodes[i].pop();
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test that rule does not fire when it is not enabled
////////////////////////////////////////////////////////////////////////////////
testRulesAll : function () {
var queries = [
[ "FOR d IN " + cn1 + " REMOVE d in " + cn1, 0],
[ "FOR d IN " + cn1 + " REMOVE d._key in " + cn1, 1],
[ "FOR d IN " + cn1 + " INSERT d in " + cn2, 2],
[ "FOR d IN " + cn1 + " INSERT d._key in " + cn2, 3],
];
var expectedRules = [
[
"distribute-in-cluster",
"scatter-in-cluster",
"remove-unnecessary-remote-scatter"
],
[
"distribute-in-cluster",
"scatter-in-cluster",
"distribute-filtercalc-to-cluster",
"remove-unnecessary-remote-scatter"
]
];
var expectedNodes = [
[
"SingletonNode",
"EnumerateCollectionNode",
"RemoteNode",
"GatherNode",
"DistributeNode",
"RemoteNode"
],
[
"SingletonNode",
"EnumerateCollectionNode",
"CalculationNode",
"RemoteNode",
"GatherNode",
"DistributeNode",
"RemoteNode"
]
];
var finalNodes = [
"RemoveNode", "RemoveNode",
"InsertNode", "InsertNode"
];
queries.forEach(function(query) {
// can't turn this rule off so should always get the same answer
var i = query[1] % 2;
var result = AQL_EXPLAIN(query[0], { }, rulesAll);
assertEqual(expectedRules[i], result.plan.rules, query);
@ -146,6 +269,71 @@ function optimizerRuleTestSuite () {
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test that rule does not fire when it is not enabled
////////////////////////////////////////////////////////////////////////////////
testRulesNone : function () {
var queries = [
[ "FOR d IN " + cn1 + " REMOVE d in " + cn1, 0],
[ "FOR d IN " + cn1 + " REMOVE d._key in " + cn1, 1],
[ "FOR d IN " + cn1 + " INSERT d in " + cn2, 2],
[ "FOR d IN " + cn1 + " INSERT d._key in " + cn2, 3],
];
var expectedRules = [
[
"distribute-in-cluster",
"scatter-in-cluster",
],
[
"distribute-in-cluster",
"scatter-in-cluster",
"distribute-filtercalc-to-cluster",
]
];
var expectedNodes = [
[
"SingletonNode",
"ScatterNode",
"RemoteNode",
"EnumerateCollectionNode",
"RemoteNode",
"GatherNode",
"DistributeNode",
"RemoteNode"
],
[
"SingletonNode",
"ScatterNode",
"RemoteNode",
"EnumerateCollectionNode",
"CalculationNode",
"RemoteNode",
"GatherNode",
"DistributeNode",
"RemoteNode"
]
];
var finalNodes = [
"RemoveNode", "RemoveNode",
"InsertNode", "InsertNode"
];
queries.forEach(function(query) {
// can't turn this rule off so should always get the same answer
var i = query[1] % 2;
var result = AQL_EXPLAIN(query[0], { }, rulesNone);
assertEqual(expectedRules[i], result.plan.rules, query);
expectedNodes[i].push(finalNodes[query[1]]);
assertEqual(expectedNodes[i], explain(result), query);
expectedNodes[i].pop();
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test that rule has no effect
////////////////////////////////////////////////////////////////////////////////
@ -153,6 +341,10 @@ function optimizerRuleTestSuite () {
testRuleNoEffect : function () {
var queries = [
"FOR d IN " + cn1 + " RETURN d",
"FOR d IN " + cn1 + " REPLACE d in " + cn1,
"FOR d IN " + cn1 + " REPLACE d._key in " + cn1,
"FOR d IN " + cn1 + " UPDATE d in " + cn1,
"FOR d IN " + cn1 + " UPDATE d._key in " + cn1 ,
"FOR i IN 1..10 RETURN i" ];
queries.forEach(function(query) {

View File

@ -1625,7 +1625,7 @@ void TRI_InitV8Buffer (v8::Handle<v8::Context> context) {
// check the isolate
v8::Isolate* isolate = v8::Isolate::GetCurrent();
TRI_v8_global_t* v8g = TRI_CreateV8Globals(isolate);
TRI_v8_global_t* v8g = TRI_GetV8Globals(isolate);
// .............................................................................
// generate the general SlowBuffer template

View File

@ -134,6 +134,7 @@ TRI_v8_global_s::TRI_v8_global_s (v8::Isolate* isolate)
_vocbase(nullptr),
_allowUseDatabase(true),
_hasDeadObjects(false),
_applicationV8(nullptr),
_loader(nullptr),
_canceled(false) {
v8::HandleScope scope;
@ -228,11 +229,24 @@ TRI_v8_global_s::~TRI_v8_global_s () {
TRI_v8_global_t* TRI_CreateV8Globals (v8::Isolate* isolate) {
TRI_v8_global_t* v8g = static_cast<TRI_v8_global_t*>(isolate->GetData());
TRI_ASSERT(v8g == nullptr);
v8g = new TRI_v8_global_t(isolate);
isolate->SetData(v8g);
return v8g;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns a global context
////////////////////////////////////////////////////////////////////////////////
TRI_v8_global_t* TRI_GetV8Globals (v8::Isolate* isolate) {
TRI_v8_global_t* v8g = static_cast<TRI_v8_global_t*>(isolate->GetData());
if (v8g == nullptr) {
v8g = new TRI_v8_global_t(isolate);
isolate->SetData(v8g);
v8g = TRI_CreateV8Globals(isolate);
}
TRI_ASSERT(v8g != nullptr);
return v8g;
}

View File

@ -42,6 +42,7 @@ struct TRI_vocbase_s;
namespace triagens {
namespace arango {
class ApplicationV8;
class JSLoader;
}
}
@ -809,6 +810,12 @@ typedef struct TRI_v8_global_s {
// --SECTION-- GENERAL
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief pointer to the context dealer (ApplicationV8*)
////////////////////////////////////////////////////////////////////////////////
triagens::arango::ApplicationV8* _applicationV8;
////////////////////////////////////////////////////////////////////////////////
/// @brief pointer to the startup loader (JSLoader*)
////////////////////////////////////////////////////////////////////////////////
@ -833,6 +840,12 @@ TRI_v8_global_t;
TRI_v8_global_t* TRI_CreateV8Globals(v8::Isolate*);
////////////////////////////////////////////////////////////////////////////////
/// @brief gets the global context
////////////////////////////////////////////////////////////////////////////////
TRI_v8_global_t* TRI_GetV8Globals(v8::Isolate*);
////////////////////////////////////////////////////////////////////////////////
/// @brief adds a method to the prototype of an object
////////////////////////////////////////////////////////////////////////////////

View File

@ -3792,7 +3792,7 @@ void TRI_InitV8Utils (v8::Handle<v8::Context> context,
// check the isolate
v8::Isolate* isolate = v8::Isolate::GetCurrent();
TRI_v8_global_t* v8g = TRI_CreateV8Globals(isolate);
TRI_v8_global_t* v8g = TRI_GetV8Globals(isolate);
v8::Handle<v8::FunctionTemplate> ft;
v8::Handle<v8::ObjectTemplate> rt;