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

View File

@ -111,6 +111,23 @@ std::vector<std::string> Collection::shardIds () const {
return ids; 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 /// @brief returns the indexes of the collection
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -145,6 +145,12 @@ namespace triagens {
std::vector<std::string> shardIds () const; 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 /// @brief returns the indexes of the collection
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -3717,6 +3717,28 @@ size_t BlockWithClients::getClientId (std::string const& shardId) {
return ((*it).second); 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 // --SECTION-- class ScatterBlock
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -3727,25 +3749,20 @@ size_t BlockWithClients::getClientId (std::string const& shardId) {
int ScatterBlock::initializeCursor (AqlItemBlock* items, size_t pos) { int ScatterBlock::initializeCursor (AqlItemBlock* items, size_t pos) {
if (!_initOrShutdown) { if (!preInitCursor()) {
return TRI_ERROR_NO_ERROR; return TRI_ERROR_NO_ERROR;
} }
int res = ExecutionBlock::initializeCursor(items, pos); int res = ExecutionBlock::initializeCursor(items, pos);
if (res != TRI_ERROR_NO_ERROR) { if (res != TRI_ERROR_NO_ERROR) {
return res; return res;
} }
_posForClient.clear(); _posForClient.clear();
_doneForClient.clear();
_doneForClient.reserve(_nrClients);
for (size_t i = 0; i < _nrClients; i++) { for (size_t i = 0; i < _nrClients; i++) {
_posForClient.push_back(std::make_pair(0, 0)); _posForClient.push_back(std::make_pair(0, 0));
_doneForClient.push_back(false);
} }
_initOrShutdown = false;
return TRI_ERROR_NO_ERROR; return TRI_ERROR_NO_ERROR;
} }
@ -3896,27 +3913,18 @@ DistributeBlock::DistributeBlock (ExecutionEngine* engine,
int DistributeBlock::initializeCursor (AqlItemBlock* items, size_t pos) { int DistributeBlock::initializeCursor (AqlItemBlock* items, size_t pos) {
if (!_initOrShutdown) { if (!preInitCursor()) {
return TRI_ERROR_NO_ERROR; return TRI_ERROR_NO_ERROR;
} }
int res = ExecutionBlock::initializeCursor(items, pos); int res = ExecutionBlock::initializeCursor(items, pos);
if (res != TRI_ERROR_NO_ERROR) { if (res != TRI_ERROR_NO_ERROR) {
return res; return res;
} }
for (auto x: _distBuffer) {
x.clear();
}
_distBuffer.clear(); _distBuffer.clear();
_distBuffer.reserve(_nrClients); _distBuffer.reserve(_nrClients);
for (auto x: _doneForClient) {
x = false;
}
_initOrShutdown = false;
return TRI_ERROR_NO_ERROR; return TRI_ERROR_NO_ERROR;
} }
@ -4115,10 +4123,17 @@ bool DistributeBlock::getBlockForClient (size_t atLeast,
size_t DistributeBlock::sendToClient (AqlValue val) { size_t DistributeBlock::sendToClient (AqlValue val) {
TRI_ASSERT(val._type == AqlValue::JSON); TRI_json_t const* json;
//TODO should work for SHAPED too (maybe this requires converting it to TRI_json_t) if (val._type == AqlValue::JSON) {
json = val._json->json();
TRI_json_t const* 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; std::string shardId;
bool usesDefaultShardingAttributes; bool usesDefaultShardingAttributes;

View File

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

View File

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

View File

@ -421,6 +421,16 @@ void Executor::generateCodeString (char const* value) {
_buffer->appendChar('"'); _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 /// @brief generate JavaScript code for a list
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

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

View File

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

View File

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

View File

@ -38,6 +38,7 @@
#include "Aql/types.h" #include "Aql/types.h"
#include "Utils/AqlTransaction.h" #include "Utils/AqlTransaction.h"
#include "Utils/V8TransactionContext.h" #include "Utils/V8TransactionContext.h"
#include "V8Server/ApplicationV8.h"
struct TRI_json_t; struct TRI_json_t;
struct TRI_vocbase_s; struct TRI_vocbase_s;
@ -127,14 +128,18 @@ namespace triagens {
public: public:
Query (struct TRI_vocbase_s*, Query (triagens::arango::ApplicationV8*,
bool,
struct TRI_vocbase_s*,
char const*, char const*,
size_t, size_t,
struct TRI_json_t*, struct TRI_json_t*,
struct TRI_json_t*, struct TRI_json_t*,
QueryPart); QueryPart);
Query (struct TRI_vocbase_s*, Query (triagens::arango::ApplicationV8*,
bool,
struct TRI_vocbase_s*,
triagens::basics::Json queryStruct, triagens::basics::Json queryStruct,
struct TRI_json_t*, struct TRI_json_t*,
QueryPart); QueryPart);
@ -362,10 +367,28 @@ namespace triagens {
void setPlan (ExecutionPlan *plan); void setPlan (ExecutionPlan *plan);
////////////////////////////////////////////////////////////////////////////////
/// @brief enter a V8 context
////////////////////////////////////////////////////////////////////////////////
void enterContext ();
////////////////////////////////////////////////////////////////////////////////
/// @brief exits a V8 context
////////////////////////////////////////////////////////////////////////////////
void exitContext ();
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- private methods // --SECTION-- private methods
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not we are running in a cluster
////////////////////////////////////////////////////////////////////////////////
bool isRunningInCluster ();
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief fetch a boolean value from the options /// @brief fetch a boolean value from the options
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -416,6 +439,12 @@ namespace triagens {
private: 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 /// @brief all nodes created in the AST - will be used for freeing them later
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -434,6 +463,12 @@ namespace triagens {
Executor* _executor; Executor* _executor;
////////////////////////////////////////////////////////////////////////////////
/// @brief the currently used V8 context
////////////////////////////////////////////////////////////////////////////////
triagens::arango::ApplicationV8::V8Context* _context;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief the actual query string /// @brief the actual query string
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -526,6 +561,18 @@ namespace triagens {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
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", ""); 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); QueryResult res = query->prepare(_queryRegistry);
if (res.code != TRI_ERROR_NO_ERROR) { if (res.code != TRI_ERROR_NO_ERROR) {
generateError(HttpResponse::BAD, TRI_ERROR_QUERY_BAD_JSON_PLAN, generateError(HttpResponse::BAD, TRI_ERROR_QUERY_BAD_JSON_PLAN,
@ -188,7 +188,7 @@ void RestAqlHandler::parseQuery () {
return; 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); nullptr, nullptr, PART_MAIN);
QueryResult res = query->parse(); QueryResult res = query->parse();
if (res.code != TRI_ERROR_NO_ERROR) { if (res.code != TRI_ERROR_NO_ERROR) {
@ -244,7 +244,7 @@ void RestAqlHandler::explainQuery () {
Json options; Json options;
options = queryJson.get("options").copy(); // cannot throw 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); parameters.steal(), options.steal(), PART_MAIN);
QueryResult res = query->explain(); QueryResult res = query->explain();
if (res.code != TRI_ERROR_NO_ERROR) { if (res.code != TRI_ERROR_NO_ERROR) {
@ -304,7 +304,7 @@ void RestAqlHandler::createQueryFromString () {
Json options; Json options;
options = queryJson.get("options").copy(); // cannot throw 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)); parameters.steal(), options.steal(), (part == "main" ? PART_MAIN : PART_DEPENDENT));
QueryResult res = query->prepare(_queryRegistry); QueryResult res = query->prepare(_queryRegistry);
if (res.code != TRI_ERROR_NO_ERROR) { if (res.code != TRI_ERROR_NO_ERROR) {
@ -586,14 +586,6 @@ void RestAqlHandler::getInfoQuery (std::string const& operation,
triagens::rest::HttpHandler::status_t RestAqlHandler::execute () { 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"; //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 // extract the sub-request type
@ -661,9 +653,6 @@ triagens::rest::HttpHandler::status_t RestAqlHandler::execute () {
} }
} }
}
_applicationV8->exitContext(context);
//std::cout << "REQUEST HANDLING DONE: " << triagens::arango::ServerState::instance()->getId() << ": " << _request->fullUrl() << ": " << _response->responseCode() << ", CONTENT-LENGTH: " << _response->contentLength() << "\n"; //std::cout << "REQUEST HANDLING DONE: " << triagens::arango::ServerState::instance()->getId() << ": " << _request->fullUrl() << ": " << _response->responseCode() << ", CONTENT-LENGTH: " << _response->contentLength() << "\n";
return status_t(HANDLER_DONE); return status_t(HANDLER_DONE);

View File

@ -255,7 +255,6 @@ bool ServerState::isRunningInCluster () {
_role == ServerState::ROLE_COORDINATOR); _role == ServerState::ROLE_COORDINATOR);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief get the server id /// @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(); 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_InitV8Queries(context->_context);
TRI_InitV8UserStructures(context->_context); TRI_InitV8UserStructures(context->_context);

View File

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

View File

@ -462,8 +462,7 @@ void TRI_InitV8Dispatcher (v8::Handle<v8::Context> context,
GlobalV8Dealer = applicationV8; GlobalV8Dealer = applicationV8;
// check the isolate // check the isolate
v8::Isolate* isolate = v8::Isolate::GetCurrent(); v8::Isolate::GetCurrent();
/* TRI_v8_global_t* v8g = */ TRI_CreateV8Globals(isolate);
// ............................................................................. // .............................................................................
// create the global functions // 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]); 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(); 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 // 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(); 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()); 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)); auto queryResult = query.execute(static_cast<triagens::aql::QueryRegistry*>(v8g->_queryRegistry));
if (queryResult.code != TRI_ERROR_NO_ERROR) { 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]); 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 // 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)); auto queryResult = query.execute(static_cast<triagens::aql::QueryRegistry*>(v8g->_queryRegistry));
if (queryResult.code != TRI_ERROR_NO_ERROR) { 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 /// @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, triagens::aql::QueryRegistry* queryRegistry,
TRI_server_t* server, TRI_server_t* server,
TRI_vocbase_t* vocbase, 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_v8_global_t* v8g = TRI_CreateV8Globals(isolate);
TRI_ASSERT(v8g->_transactionContext == nullptr); TRI_ASSERT(v8g->_transactionContext == nullptr);
v8g->_transactionContext = new V8TransactionContext(true); v8g->_transactionContext = new V8TransactionContext(true);
static_cast<V8TransactionContext*>(v8g->_transactionContext)->makeGlobal(); static_cast<V8TransactionContext*>(v8g->_transactionContext)->makeGlobal();
@ -2518,6 +2520,9 @@ void TRI_InitV8VocBridge (v8::Handle<v8::Context> context,
// register the startup loader // register the startup loader
v8g->_loader = loader; v8g->_loader = loader;
// register the context dealer
v8g->_applicationV8 = applicationV8;
v8::Handle<v8::ObjectTemplate> ArangoNS; v8::Handle<v8::ObjectTemplate> ArangoNS;
v8::Handle<v8::ObjectTemplate> rt; v8::Handle<v8::ObjectTemplate> rt;
v8::Handle<v8::FunctionTemplate> ft; v8::Handle<v8::FunctionTemplate> ft;

View File

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

View File

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

View File

@ -106,7 +106,20 @@
visibility: [true, false], visibility: [true, false],
labels: ["datetime", "Major Page", "Minor Page"], labels: ["datetime", "Major Page", "Minor Page"],
div: "pageFaultsChart", 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: { systemUserTime: {

View File

@ -46,7 +46,13 @@
$('#collectionsToggle').addClass('activated'); $('#collectionsToggle').addClass('activated');
} }
var length = searchOptions.searchPhrase.length; var length;
try {
length = searchOptions.searchPhrase.length;
}
catch (ignore) {
}
$('#searchInput').val(searchOptions.searchPhrase); $('#searchInput').val(searchOptions.searchPhrase);
$('#searchInput').focus(); $('#searchInput').focus();
$('#searchInput')[0].setSelectionRange(length, length); $('#searchInput')[0].setSelectionRange(length, length);

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 () { testThisRuleEnabled : function () {
@ -89,10 +89,71 @@ function optimizerRuleTestSuite () {
[ "FOR d IN " + cn1 + " REMOVE d._key in " + cn1, 1], [ "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 in " + cn2, 2],
[ "FOR d IN " + cn1 + " INSERT d._key in " + cn2, 3], [ "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], var expectedRules = [
[ "FOR d IN " + cn1 + " UPDATE d._key in " + cn1 , 7] [
"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 = [ var expectedRules = [
@ -131,12 +192,74 @@ function optimizerRuleTestSuite () {
var finalNodes = [ var finalNodes = [
"RemoveNode", "RemoveNode", "RemoveNode", "RemoveNode",
"InsertNode", "InsertNode", "InsertNode", "InsertNode"
"ReplaceNode", "ReplaceNode",
"UpdateNode", "UpdateNode"
]; ];
queries.forEach(function(query) { 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 i = query[1] % 2;
var result = AQL_EXPLAIN(query[0], { }, rulesAll); var result = AQL_EXPLAIN(query[0], { }, rulesAll);
assertEqual(expectedRules[i], result.plan.rules, query); 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 /// @brief test that rule has no effect
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -153,6 +341,10 @@ function optimizerRuleTestSuite () {
testRuleNoEffect : function () { testRuleNoEffect : function () {
var queries = [ var queries = [
"FOR d IN " + cn1 + " RETURN d", "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" ]; "FOR i IN 1..10 RETURN i" ];
queries.forEach(function(query) { queries.forEach(function(query) {

View File

@ -1625,7 +1625,7 @@ void TRI_InitV8Buffer (v8::Handle<v8::Context> context) {
// check the isolate // check the isolate
v8::Isolate* isolate = v8::Isolate::GetCurrent(); 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 // generate the general SlowBuffer template

View File

@ -134,6 +134,7 @@ TRI_v8_global_s::TRI_v8_global_s (v8::Isolate* isolate)
_vocbase(nullptr), _vocbase(nullptr),
_allowUseDatabase(true), _allowUseDatabase(true),
_hasDeadObjects(false), _hasDeadObjects(false),
_applicationV8(nullptr),
_loader(nullptr), _loader(nullptr),
_canceled(false) { _canceled(false) {
v8::HandleScope scope; 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* TRI_CreateV8Globals (v8::Isolate* isolate) {
TRI_v8_global_t* v8g = static_cast<TRI_v8_global_t*>(isolate->GetData()); TRI_v8_global_t* v8g = static_cast<TRI_v8_global_t*>(isolate->GetData());
if (v8g == nullptr) { TRI_ASSERT(v8g == nullptr);
v8g = new TRI_v8_global_t(isolate); v8g = new TRI_v8_global_t(isolate);
isolate->SetData(v8g); 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 = TRI_CreateV8Globals(isolate);
} }
TRI_ASSERT(v8g != nullptr);
return v8g; return v8g;
} }

View File

@ -42,6 +42,7 @@ struct TRI_vocbase_s;
namespace triagens { namespace triagens {
namespace arango { namespace arango {
class ApplicationV8;
class JSLoader; class JSLoader;
} }
} }
@ -809,6 +810,12 @@ typedef struct TRI_v8_global_s {
// --SECTION-- GENERAL // --SECTION-- GENERAL
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief pointer to the context dealer (ApplicationV8*)
////////////////////////////////////////////////////////////////////////////////
triagens::arango::ApplicationV8* _applicationV8;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief pointer to the startup loader (JSLoader*) /// @brief pointer to the startup loader (JSLoader*)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -833,6 +840,12 @@ TRI_v8_global_t;
TRI_v8_global_t* TRI_CreateV8Globals(v8::Isolate*); 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 /// @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 // check the isolate
v8::Isolate* isolate = v8::Isolate::GetCurrent(); 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::FunctionTemplate> ft;
v8::Handle<v8::ObjectTemplate> rt; v8::Handle<v8::ObjectTemplate> rt;