1
0
Fork 0

Merge branch 'devel' of https://github.com/arangodb/arangodb into FMH

This commit is contained in:
Kaveh Vahedipour 2016-04-20 11:23:10 +00:00
commit d53e47c7d5
17 changed files with 172 additions and 116 deletions

View File

@ -167,10 +167,18 @@ the sort parameter.
`json` option. The `body` instead contains the response body as a string.
v2.8.8 (????-??-??)
v2.8.9 (XXXX-XX-XX)
-------------------
* fixed issue #1805: Query: internal error (location: arangod/Aql/AqlValue.cpp:182). Please report this error to arangodb.com (while executing)
* fixed access to /_admin/statistics API in case statistics are disable via option
`--server.disable-statistics`
v2.8.8 (2016-04-19)
-------------------
* fixed issue #1805: Query: internal error (location: arangod/Aql/AqlValue.cpp:182).
Please report this error to arangodb.com (while executing)
* allow specifying collection name prefixes for `_from` and `_to` in arangoimp:

View File

@ -196,55 +196,39 @@ TRI_doc_mptr_t* EdgeIndexIterator::next() {
return nullptr;
}
if (_buffer == nullptr) {
if (_buffer.empty()) {
// We start a new lookup
TRI_ASSERT(_position == 0);
_posInBuffer = 0;
_last = nullptr;
VPackSlice tmp = _keys.at(_position);
if (tmp.isObject()) {
tmp = tmp.get(TRI_SLICE_KEY_EQUAL);
}
_buffer = _index->lookupByKey(_trx, &tmp, _batchSize);
_index->lookupByKey(_trx, &tmp, _buffer, _batchSize);
// fallthrough intentional
} else if (_posInBuffer >= _buffer->size()) {
} else if (_posInBuffer >= _buffer.size()) {
// We have to refill the buffer
delete _buffer;
_buffer = nullptr;
auto last = _buffer.back();
_buffer.clear();
_posInBuffer = 0;
if (_last != nullptr) {
_buffer = _index->lookupByKeyContinue(_trx, _last, _batchSize);
} else {
VPackSlice tmp = _keys.at(_position);
if (tmp.isObject()) {
tmp = tmp.get(TRI_SLICE_KEY_EQUAL);
}
_buffer = _index->lookupByKey(_trx, &tmp, _batchSize);
}
_index->lookupByKeyContinue(_trx, last, _buffer, _batchSize);
}
if (!_buffer->empty()) {
if (!_buffer.empty()) {
// found something
_last = _buffer->back();
return _buffer->at(_posInBuffer++);
return _buffer.at(_posInBuffer++);
}
// found no result. now go to next lookup value in _keys
++_position;
// reset the _last value
_last = nullptr;
}
}
void EdgeIndexIterator::reset() {
_last = nullptr;
_position = 0;
_posInBuffer = 0;
// Free the vector space, not the content
delete _buffer;
_buffer = nullptr;
_buffer.clear();
}
TRI_doc_mptr_t* AnyDirectionEdgeIndexIterator::next() {

View File

@ -51,11 +51,8 @@ class EdgeIndexIterator final : public IndexIterator {
_searchValues(searchValues),
_keys(_searchValues.slice()),
_position(0),
_last(nullptr),
_buffer(nullptr),
_posInBuffer(0),
_batchSize(50) { // This might be adjusted
}
_batchSize(1000) {}
EdgeIndexIterator(arangodb::Transaction* trx,
TRI_EdgeIndexHash_t const* index,
@ -65,16 +62,8 @@ class EdgeIndexIterator final : public IndexIterator {
_searchValues(arangodb::velocypack::Builder::clone(searchValues)),
_keys(_searchValues.slice()),
_position(0),
_last(nullptr),
_buffer(nullptr),
_posInBuffer(0),
_batchSize(50) { // This might be adjusted
}
~EdgeIndexIterator() {
// Free the vector space, not the content
delete _buffer;
}
_batchSize(1000) {}
private:
arangodb::Transaction* _trx;
@ -82,8 +71,7 @@ class EdgeIndexIterator final : public IndexIterator {
arangodb::velocypack::Builder const _searchValues;
arangodb::velocypack::Slice const _keys;
size_t _position;
TRI_doc_mptr_t* _last;
std::vector<TRI_doc_mptr_t*>* _buffer;
std::vector<TRI_doc_mptr_t*> _buffer;
size_t _posInBuffer;
size_t _batchSize;
};

View File

@ -469,6 +469,10 @@ bool NeighborsOptions::matchesVertex(std::string const& collectionName,
////////////////////////////////////////////////////////////////////////////////
bool NeighborsOptions::matchesVertex(std::string const& id) const {
if (!useVertexFilter) {
// Nothing to do
return true;
}
std::vector<std::string> parts =
arangodb::basics::StringUtils::split(id, "/");
TRI_ASSERT(parts.size() == 2);

View File

@ -155,13 +155,17 @@ authRouter.post('disableVersionCheck', function(req, res) {
authRouter.post('/query/explain', function(req, res) {
const bindVars = req.body.bindVars;
const query = req.body.query;
const id = req.body.id;
const batchSize = req.body.batchSize;
let msg = null;
try {
if (bindVars) {
msg = require('@arangodb/aql/explainer').explain({
query: query,
bindVars: bindVars
bindVars: bindVars,
batchSize: batchSize,
id: id
}, {colors: false}, false, bindVars);
} else {
msg = require('@arangodb/aql/explainer').explain(query, {colors: false}, false);
@ -174,7 +178,9 @@ authRouter.post('/query/explain', function(req, res) {
})
.body(joi.object({
query: joi.string().required(),
bindVars: joi.object().optional()
bindVars: joi.object().optional(),
batchSize: joi.number().optional(),
id: joi.string().optional()
}).required(), 'Query and bindVars to explain.')
.summary('Explains a query')
.description(dd`

View File

@ -145,7 +145,7 @@ installer.put('/zip', function (req) {
foxxRouter.delete('/', function (req, res) {
const mount = decodeURIComponent(req.queryParams.mount);
const runTeardown = req.parameters.teardown;
const runTeardown = req.queryParams.teardown;
const service = FoxxManager.uninstall(mount, {
teardown: runTeardown,
force: true

View File

@ -5,6 +5,7 @@ div.headerDropdown,
border-radius: 2px;
clear: both;
display: none;
margin-bottom: 15px;
padding: 10px;
position: relative;
width: auto;

View File

@ -346,15 +346,18 @@
@extend %pull-left;
margin-top: 5px;
padding: 0 8px;
width: 100%;
.percentage {
@extend %pull-left;
font-weight: 400;
width: 100%;
}
.absolut {
@extend %pull-left;
text-align: right;
text-align: center;
width: 100%;
}
}

View File

@ -302,6 +302,7 @@
.dashboard-bar-chart-container {
$int-width: ($content-size / 3) - 18px - 2px;
$int-height: (($dashboard-height - 30px) / 2) - $tendency-height-corrector;
$int-height2: ($int-height - 20px);
height: $int-height + 2px;
.dashboard-bar-chart {
@ -317,6 +318,7 @@
}
.absolut {
line-height: ($int-height2 * 2 / 3) - 10px;
width: ($int-width - (($int-width / 2) * 1.4)) - 6px;
}
}
@ -324,10 +326,11 @@
.dashboard-bar-chart-chart {
$int-height2: ($int-height - 20px);
box-sizing: border-box;
height: ($int-height2 * 2 / 3) - 5px;
line-height: ($int-height2 * 2 / 3) - 5px;
padding: 5px 8px 10px;
width: $int-width - 16px;
width: 100%;
#residentSizeChart {
height: ($int-height2 * 2 / 3);

View File

@ -45,28 +45,6 @@ global.clearInterval = global.clearInterval || function () {};
global.setTimeout = global.setTimeout || function () {};
global.clearTimeout = global.clearTimeout || function () {};
////////////////////////////////////////////////////////////////////////////////
/// @brief template string generator for building an AQL query
////////////////////////////////////////////////////////////////////////////////
global.aqlQuery = function () {
var strings = arguments[0];
var bindVars = {};
var query = strings[0];
var name, value, i;
for (i = 1; i < arguments.length; i++) {
value = arguments[i];
name = 'value' + (i - 1);
if (value && value.constructor && value.constructor.name === 'ArangoCollection') {
name = '@' + name;
value = value.name();
}
bindVars[name] = value;
query += '@' + name + strings[i];
}
return {query: query, bindVars: bindVars};
};
////////////////////////////////////////////////////////////////////////////////
/// @brief start paging
////////////////////////////////////////////////////////////////////////////////
@ -128,6 +106,12 @@ global.console = global.console || require("console");
global.db = require("@arangodb").db;
////////////////////////////////////////////////////////////////////////////////
/// @brief template string generator for building an AQL query
////////////////////////////////////////////////////////////////////////////////
global.aqlQuery = require("@arangodb").aql;
////////////////////////////////////////////////////////////////////////////////
/// @brief global 'arango'
////////////////////////////////////////////////////////////////////////////////

View File

@ -40,6 +40,23 @@ Object.keys(internal.errors).forEach(function (key) {
exports[key] = internal.errors[key].code;
});
exports.aql = function () {
let strings = arguments[0];
const bindVars = {};
let query = strings[0];
for (let i = 1; i < arguments.length; i++) {
let value = arguments[i];
let name = `value${i - 1}`;
if (value && value.isArangoCollection) {
name = `@${name}`;
value = value.name();
}
bindVars[name] = value;
query += `@${name}${strings[i]}`;
}
return {query, bindVars};
};
exports.errors = internal.errors;

View File

@ -1,5 +1,5 @@
/*jshint globalstrict:false, strict:false */
/*global assertEqual, assertTrue, assertFalse, assertUndefined, assertMatch, aqlQuery, fail */
/*global assertEqual, assertTrue, assertFalse, assertUndefined, assertMatch, fail */
////////////////////////////////////////////////////////////////////////////////
/// @brief test the statement class
@ -32,6 +32,7 @@ var jsunity = require("jsunity");
var arangodb = require("@arangodb");
var db = arangodb.db;
var aql = arangodb.aql;
var ERRORS = arangodb.errors;
@ -873,7 +874,7 @@ function StatementSuite () {
testTemplateStringBuilder : function () {
var foo = "foo-matic", bar = "BAR o MATIC", what = "' this string \\ \" is ' evil\n`";
var result = aqlQuery`FOR ${foo} IN ${bar} RETURN ${what}`;
var result = aql`FOR ${foo} IN ${bar} RETURN ${what}`;
assertEqual("FOR @value0 IN @value1 RETURN @value2", result.query);
assertEqual({ value0: foo, value1: bar, value2: what }, result.bindVars);
},
@ -884,7 +885,7 @@ function StatementSuite () {
testTemplateStringBuilderComplexTypes : function () {
var list = [ 1, 2, 3, 4 ], what = { foo: "bar", baz: "bark" };
var result = aqlQuery`FOR i IN ${list} RETURN ${what}`;
var result = aql`FOR i IN ${list} RETURN ${what}`;
assertEqual("FOR i IN @value0 RETURN @value1", result.query);
assertEqual({ value0: [ 1, 2, 3, 4 ], value1: { foo: "bar", baz: "bark" } }, result.bindVars);
},
@ -894,7 +895,7 @@ function StatementSuite () {
////////////////////////////////////////////////////////////////////////////////
testTemplateStringBuilderObject : function () {
var result = aqlQuery`RETURN ${new Date('2015-01-01').toISOString()}`;
var result = aql`RETURN ${new Date('2015-01-01').toISOString()}`;
assertEqual("RETURN @value0", result.query);
assertEqual({ value0 : "2015-01-01T00:00:00.000Z" }, result.bindVars);
},
@ -905,7 +906,7 @@ function StatementSuite () {
testTemplateString : function () {
var one = 1, two = 2, three = 3, add = 9;
var st = db._createStatement(aqlQuery`FOR u IN [ ${one}, ${two}, ${three} ] RETURN u + ${add}`);
var st = db._createStatement(aql`FOR u IN [ ${one}, ${two}, ${three} ] RETURN u + ${add}`);
var result = st.execute().toArray();
assertEqual([ 10, 11, 12 ], result);
@ -918,7 +919,7 @@ function StatementSuite () {
testTemplateStringStrings : function () {
var FOR = "FOR", RETURN = "RETURN", PLUS = "+";
try {
db._createStatement(aqlQuery`${FOR} i IN 1..2 ${RETURN} i ${PLUS} 1`).execute();
db._createStatement(aql`${FOR} i IN 1..2 ${RETURN} i ${PLUS} 1`).execute();
fail();
}
catch (err) {
@ -932,7 +933,7 @@ function StatementSuite () {
testTemplateStringString : function () {
var a = "FROM TO RETURN INSERT";
var st = db._createStatement(aqlQuery`RETURN ${a}`);
var st = db._createStatement(aql`RETURN ${a}`);
var result = st.execute().toArray();
assertEqual([ a ], result);
@ -945,7 +946,7 @@ function StatementSuite () {
testTemplateStringUndefined : function () {
try {
/*global foo */
db._createStatement(aqlQuery`FOR u IN ${foo} RETURN 1`);
db._createStatement(aql`FOR u IN ${foo} RETURN 1`);
fail();
}
catch (err) {

View File

@ -64,29 +64,8 @@ global.clearInterval = function () {};
global.setTimeout = function () {};
global.clearTimeout = function () {};
////////////////////////////////////////////////////////////////////////////////
/// @brief template string generator for building an AQL query
////////////////////////////////////////////////////////////////////////////////
global.aqlQuery = function () {
let strings = arguments[0];
const bindVars = {};
let query = strings[0];
for (let i = 1; i < arguments.length; i++) {
let value = arguments[i];
let name = `value${i - 1}`;
if (value && value.constructor && value.constructor.name === 'ArangoCollection') {
name = `@${name}`;
value = value.name();
}
bindVars[name] = value;
query += `@${name}${strings[i]}`;
}
return {query, bindVars};
};
// extend prototypes for internally defined classes
require('@arangodb');
// template string generator for building an AQL query
global.aqlQuery = require('@arangodb').aql;
// load the actions from the actions directory
require('@arangodb/actions').startup();

View File

@ -1,4 +1,3 @@
/*global aqlQuery */
'use strict';
////////////////////////////////////////////////////////////////////////////////
@ -28,6 +27,7 @@ const internal = require('internal');
const arangodb = require('@arangodb');
const NOT_FOUND = arangodb.errors.ERROR_ARANGO_DOCUMENT_NOT_FOUND.code;
const db = arangodb.db;
const aql = arangodb.aql;
module.exports = function systemStorage(cfg) {
@ -35,7 +35,7 @@ module.exports = function systemStorage(cfg) {
const expiry = Number(internal.options()['server.session-timeout']) * 1000;
return {
prune() {
return db._query(aqlQuery`
return db._query(aql`
FOR session IN _sessions
FILTER session.lastAccess < ${Date.now() - expiry}
REMOVE session IN _sessions

View File

@ -1,4 +1,3 @@
/*global aqlQuery */
'use strict';
////////////////////////////////////////////////////////////////////////////////
@ -27,6 +26,7 @@ const assert = require('assert');
const arangodb = require('@arangodb');
const NOT_FOUND = arangodb.errors.ERROR_ARANGO_DOCUMENT_NOT_FOUND.code;
const db = arangodb.db;
const aql = arangodb.aql;
module.exports = function collectionStorage(cfg) {
@ -47,7 +47,7 @@ module.exports = function collectionStorage(cfg) {
assert(collection.isArangoCollection, `No such collection: ${cfg.collection}`);
return {
prune() {
return db._query(aqlQuery`
return db._query(aql`
FOR session IN ${collection}
FILTER session.expires < DATE_NOW()
REMOVE session IN ${collection}

View File

@ -358,7 +358,8 @@ function optimizerRuleTestSuite () {
var queries = [
[ "FOR doc IN [ { a: 1, b: 2 }, { a: 2, b: 4 } ] LET a = doc.a RETURN a * 2", [ 2, 4 ] ],
[ "FOR doc IN [ { a: 1, b: 2 }, { a: 2, b: 4 } ] LET a = doc.a * 2 RETURN a * 2", [ 4, 8 ] ],
[ "FOR doc IN [ { a: 1, b: 2 }, { a: 2, b: 4 } ] LET a = doc RETURN a.a", [ 1, 2 ] ]
[ "FOR doc IN [ { a: 1, b: 2 }, { a: 2, b: 4 } ] LET a = doc RETURN a.a", [ 1, 2 ] ],
[ "FOR doc IN [ { a: 1, b: 2 }, { a: 2, b: 4 } ] LET a = SLICE(ATTRIBUTES(doc), 0, 1) RETURN KEEP(doc, a)", [ { a: 1 }, { a: 2 } ] ]
];
queries.forEach(function(query) {
var result = AQL_EXPLAIN(query[0]);

View File

@ -776,6 +776,25 @@ class AssocMulti {
std::vector<Element*>* lookupByKey(UserData* userData, Key const* key,
size_t limit = 0) const {
auto result = std::make_unique<std::vector<Element*>>();
lookupByKey(userData, key, *result, limit);
return result.release();
}
//////////////////////////////////////////////////////////////////////////////
/// @brief lookups an element given a key
/// Accepts a result vector as input. The result of this lookup will
/// be appended to the given vector.
/// This function returns as soon as limit many elements are inside
/// the given vector, no matter if the come from this lookup or
/// have been in the result before.
//////////////////////////////////////////////////////////////////////////////
void lookupByKey(UserData* userData, Key const* key,
std::vector<Element*>& result, size_t limit = 0) const {
if (limit > 0 && result.size() >= limit) {
return;
}
// compute the hash
uint64_t hashByKey = _hashKey(userData, key);
@ -803,13 +822,12 @@ class AssocMulti {
// We found the beginning of the linked list:
do {
result->push_back(b._table[i].ptr);
result.push_back(b._table[i].ptr);
i = b._table[i].next;
} while (i != INVALID_INDEX && (limit == 0 || result->size() < limit));
} while (i != INVALID_INDEX && (limit == 0 || result.size() < limit));
}
// return whatever we found
return result.release();
}
//////////////////////////////////////////////////////////////////////////////
@ -820,6 +838,28 @@ class AssocMulti {
Element const* element,
size_t limit = 0) const {
auto result = std::make_unique<std::vector<Element*>>();
lookupWithElementByKey(userData, element, *result, limit);
return result.release();
}
//////////////////////////////////////////////////////////////////////////////
/// @brief looks up all elements with the same key as a given element
/// Accepts a result vector as input. The result of this lookup will
/// be appended to the given vector.
/// This function returns as soon as limit many elements are inside
/// the given vector, no matter if the come from this lookup or
/// have been in the result before.
//////////////////////////////////////////////////////////////////////////////
void lookupWithElementByKey(UserData* userData, Element const* element,
std::vector<Element*>& result,
size_t limit = 0) const {
if (limit > 0 && result.size() >= limit) {
// The vector is full, nothing to do.
return;
}
// compute the hash
uint64_t hashByKey = _hashElement(userData, element, true);
@ -847,13 +887,11 @@ class AssocMulti {
// We found the beginning of the linked list:
do {
result->push_back(b._table[i].ptr);
result.push_back(b._table[i].ptr);
i = b._table[i].next;
} while (i != INVALID_INDEX && (limit == 0 || result->size() < limit));
} while (i != INVALID_INDEX && (limit == 0 || result.size() < limit));
}
// return whatever we found
return result.release();
}
//////////////////////////////////////////////////////////////////////////////
@ -864,6 +902,28 @@ class AssocMulti {
std::vector<Element*>* lookupWithElementByKeyContinue(
UserData* userData, Element const* element, size_t limit = 0) const {
auto result = std::make_unique<std::vector<Element*>>();
lookupWithElementByKeyContinue(userData, element, limit);
return result.release();
}
//////////////////////////////////////////////////////////////////////////////
/// @brief looks up all elements with the same key as a given element,
/// continuation.
/// Accepts a result vector as input. The result of this lookup will
/// be appended to the given vector.
/// This function returns as soon as limit many elements are inside
/// the given vector, no matter if the come from this lookup or
/// have been in the result before.
//////////////////////////////////////////////////////////////////////////////
void lookupWithElementByKeyContinue(UserData* userData,
Element const* element,
std::vector<Element*>& result,
size_t limit = 0) const {
if (limit > 0 && result.size() >= limit) {
// The vector is full, nothing to do.
return;
}
uint64_t hashByKey = _hashElement(userData, element, true);
Bucket const& b = _buckets[hashByKey & _bucketsMask];
@ -891,21 +951,21 @@ class AssocMulti {
if (b._table[i].ptr == nullptr) {
// This cannot really happen, but we handle it gracefully anyway
return nullptr;
return;
}
}
// continue search of the table
while (true) {
i = b._table[i].next;
if (i == INVALID_INDEX || (limit != 0 && result->size() >= limit)) {
if (i == INVALID_INDEX || (limit != 0 && result.size() >= limit)) {
break;
}
result->push_back(b._table[i].ptr);
result.push_back(b._table[i].ptr);
}
// return whatever we found
return result.release();
return;
}
//////////////////////////////////////////////////////////////////////////////
@ -919,6 +979,23 @@ class AssocMulti {
return lookupWithElementByKeyContinue(userData, element, limit);
}
//////////////////////////////////////////////////////////////////////////////
/// @brief looks up all elements with the same key as a given element,
/// continuation
/// Accepts a result vector as input. The result of this lookup will
/// be appended to the given vector.
/// This function returns as soon as limit many elements are inside
/// the given vector, no matter if the come from this lookup or
/// have been in the result before.
//////////////////////////////////////////////////////////////////////////////
void lookupByKeyContinue(UserData* userData, Element const* element,
std::vector<Element*>& result,
size_t limit = 0) const {
lookupWithElementByKeyContinue(userData, element, result, limit);
}
//////////////////////////////////////////////////////////////////////////////
/// @brief removes an element from the array, caller is responsible to free it
//////////////////////////////////////////////////////////////////////////////