1
0
Fork 0

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

This commit is contained in:
Jan Steemann 2015-11-19 13:28:57 +01:00
commit 59084c193d
22 changed files with 724 additions and 49 deletions

View File

@ -1,6 +1,8 @@
v2.8.0 (XXXX-XX-XX)
-------------------
* web interface: aql editor now supports bind parameters
* added startup option `--server.hide-product-header` to make the server not send
the HTTP response header `"Server: ArangoDB"` in its HTTP responses. By default,
the option is turned off so the header is still sent as usual.
@ -101,6 +103,9 @@ v2.8.0 (XXXX-XX-XX)
v2.7.2 (XXXX-XX-XX)
-------------------
* fixed undefined behavior when accessing the top level of a document with the `[*]`
operator
* fixed potentially invalid pointer access in shaper when the currently accessed
document got re-located by the WAL collector at the very same time

View File

@ -34,7 +34,6 @@
#include "Basics/AttributeNameParser.h"
#include "Basics/Exceptions.h"
#include "Basics/json.h"
#include "Basics/vector.h"
#include "Basics/JsonHelper.h"
#include <functional>

View File

@ -529,7 +529,7 @@ AqlValue Expression::executeSimpleExpression (AstNode const* node,
case NODE_TYPE_EXPANSION:
return executeSimpleExpressionExpansion(node, trx, argv, startPos, vars, regs);
case NODE_TYPE_ITERATOR:
return executeSimpleExpressionIterator(node, trx, argv, startPos, vars, regs);
return executeSimpleExpressionIterator(node, collection, trx, argv, startPos, vars, regs);
case NODE_TYPE_OPERATOR_BINARY_PLUS:
case NODE_TYPE_OPERATOR_BINARY_MINUS:
case NODE_TYPE_OPERATOR_BINARY_TIMES:
@ -1290,6 +1290,7 @@ AqlValue Expression::executeSimpleExpressionExpansion (AstNode const* node,
////////////////////////////////////////////////////////////////////////////////
AqlValue Expression::executeSimpleExpressionIterator (AstNode const* node,
TRI_document_collection_t const** collection,
triagens::arango::AqlTransaction* trx,
AqlItemBlock const* argv,
size_t startPos,
@ -1298,9 +1299,8 @@ AqlValue Expression::executeSimpleExpressionIterator (AstNode const* node,
TRI_ASSERT(node != nullptr);
TRI_ASSERT(node->numMembers() == 2);
// intentionally do not stringify node 0
TRI_document_collection_t const* myCollection = nullptr;
return executeSimpleExpression(node->getMember(1), &myCollection, trx, argv, startPos, vars, regs, true);
*collection = nullptr;
return executeSimpleExpression(node->getMember(1), collection, trx, argv, startPos, vars, regs, true);
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -485,6 +485,7 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
AqlValue executeSimpleExpressionIterator (AstNode const*,
TRI_document_collection_t const**,
triagens::arango::AqlTransaction*,
AqlItemBlock const*,
size_t,

View File

@ -241,6 +241,7 @@ add_executable(
VocBase/datafile.cpp
VocBase/Ditch.cpp
VocBase/document-collection.cpp
VocBase/DocumentAccessor.cpp
VocBase/ExampleMatcher.cpp
VocBase/edge-collection.cpp
VocBase/headers.cpp

View File

@ -383,10 +383,10 @@ std::list<AgencyEndpoint*> AgencyComm::_globalEndpoints;
////////////////////////////////////////////////////////////////////////////////
AgencyConnectionOptions AgencyComm::_globalConnectionOptions = {
15.0, // connectTimeout
9.0, // requestTimeout
5.0, // lockTimeout
3 // numRetries
15.0, // connectTimeout
120.0, // requestTimeout
120.0, // lockTimeout
10 // numRetries
};
// -----------------------------------------------------------------------------

View File

@ -34,7 +34,6 @@
#include "Basics/json.h"
#include "Basics/logging.h"
#include "Basics/tri-strings.h"
#include "Basics/vector.h"
#include "Basics/json-utilities.h"
#include "Basics/JsonHelper.h"
#include "Basics/MutexLocker.h"
@ -403,8 +402,8 @@ bool ClusterInfo::doesDatabaseExist (DatabaseID const& databaseID,
/// @brief get list of databases in the cluster
////////////////////////////////////////////////////////////////////////////////
vector<DatabaseID> ClusterInfo::listDatabases (bool reload) {
vector<DatabaseID> result;
std::vector<DatabaseID> ClusterInfo::listDatabases (bool reload) {
std::vector<DatabaseID> result;
if (reload ||
! _plannedDatabasesProt.isValid ||
@ -712,18 +711,18 @@ void ClusterInfo::loadPlannedCollections (bool acquireLock) {
(*it).second._json = nullptr;
shared_ptr<CollectionInfo> collectionData (new CollectionInfo(json));
vector<string>* shardKeys = new vector<string>;
std::vector<std::string>* shardKeys = new std::vector<std::string>;
*shardKeys = collectionData->shardKeys();
newShardKeys.insert(
make_pair(collection, shared_ptr<vector<string> > (shardKeys)));
make_pair(collection, shared_ptr<std::vector<std::string> > (shardKeys)));
map<ShardID, ServerID> shardIDs = collectionData->shardIds();
vector<string>* shards = new vector<string>;
std::vector<std::string>* shards = new std::vector<std::string>;
map<ShardID, ServerID>::iterator it3;
for (it3 = shardIDs.begin(); it3 != shardIDs.end(); ++it3) {
shards->push_back(it3->first);
}
newShards.emplace(
std::make_pair(collection, shared_ptr<vector<string> >(shards)));
std::make_pair(collection, shared_ptr<std::vector<std::string> >(shards)));
// insert the collection into the existing map, insert it under its
// ID as well as under its name, so that a lookup can be done with
@ -2260,7 +2259,7 @@ std::vector<ServerID> ClusterInfo::getCurrentDBServers () {
/// our id
////////////////////////////////////////////////////////////////////////////////
static const std::string prefixTargetServerEndoint = "Target/MapIDToEndpoint/";
static const std::string prefixTargetServerEndpoint = "Target/MapIDToEndpoint/";
std::string ClusterInfo::getTargetServerEndpoint (ServerID const& serverID) {
@ -2271,12 +2270,12 @@ std::string ClusterInfo::getTargetServerEndpoint (ServerID const& serverID) {
AgencyCommLocker locker("Target", "READ");
if (locker.successful()) {
result = _agency.getValues(prefixTargetServerEndoint + serverID, false);
result = _agency.getValues(prefixTargetServerEndpoint + serverID, false);
}
}
if (result.successful()) {
result.parse(prefixTargetServerEndoint, false);
result.parse(prefixTargetServerEndpoint, false);
// check if we can find ourselves in the list returned by the agency
std::map<std::string, AgencyCommResultEntry>::const_iterator it = result._values.find(serverID);
@ -2357,9 +2356,9 @@ int ClusterInfo::getResponsibleShard (CollectionID const& collectionID,
}
int tries = 0;
shared_ptr<vector<string> > shardKeysPtr;
shared_ptr<std::vector<std::string> > shardKeysPtr;
char const** shardKeys = nullptr;
shared_ptr<vector<ShardID> > shards;
shared_ptr<std::vector<ShardID> > shards;
bool found = false;
while (true) {

View File

@ -199,6 +199,7 @@ arangod_libarangod_a_SOURCES = \
arangod/VocBase/datafile.cpp \
arangod/VocBase/Ditch.cpp \
arangod/VocBase/document-collection.cpp \
arangod/VocBase/DocumentAccessor.cpp \
arangod/VocBase/ExampleMatcher.cpp \
arangod/VocBase/edge-collection.cpp \
arangod/VocBase/headers.cpp \

View File

@ -0,0 +1,301 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief read-accesses internals of a document
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2006-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "DocumentAccessor.h"
#include "Basics/conversions.h"
#include "Basics/Exceptions.h"
#include "Utils/CollectionNameResolver.h"
#include "VocBase/VocShaper.h"
// -----------------------------------------------------------------------------
// --SECTION-- DocumentAccessor
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
DocumentAccessor::DocumentAccessor (triagens::arango::CollectionNameResolver const* resolver,
TRI_document_collection_t* document,
TRI_doc_mptr_t const* mptr)
: _resolver(resolver),
_document(document),
_mptr(mptr),
_json(),
_current(nullptr) {
}
DocumentAccessor::~DocumentAccessor () {
}
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
bool DocumentAccessor::hasKey (std::string const& attribute) const {
if (! isObject()) {
return false;
}
return true;
}
bool DocumentAccessor::isObject () const {
if (_current != nullptr) {
return TRI_IsObjectJson(_current);
}
// ok, must be a document/edge
return true;
}
bool DocumentAccessor::isArray () const {
if (_current != nullptr) {
return TRI_IsArrayJson(_current);
}
// ok, must be a document/edge
return false;
}
size_t DocumentAccessor::length () const {
if (! isArray()) {
return 0;
}
// ok, we have confirmed this is an array
TRI_ASSERT(_current != nullptr);
if (_current != nullptr) {
return TRI_LengthArrayJson(_current);
}
return 0;
}
DocumentAccessor& DocumentAccessor::get (std::string const& name) {
return get(name.c_str(), name.size());
}
DocumentAccessor& DocumentAccessor::get (char const* name, size_t nameLength) {
if (_current == nullptr) {
// a document, we need the access its attributes using special methods
lookupDocumentAttribute(name, nameLength);
}
else {
// already a JSON
lookupJsonAttribute(name, nameLength);
}
return *this;
}
DocumentAccessor& DocumentAccessor::at (int64_t index) {
if (isArray()) {
size_t length = TRI_LengthArrayJson(_current);
if (index < 0) {
// a negative position is allowed
index = static_cast<int64_t>(length) + index;
}
if (index >= 0 && index < static_cast<int64_t>(length)) {
// only look up the value if it is within array bounds
TRI_json_t* found = TRI_LookupArrayJson(_current, static_cast<size_t>(index));
if (found != nullptr) {
_current = found;
return *this;
}
}
// fall-through intentional
}
setToNull();
return *this;
}
triagens::basics::Json DocumentAccessor::toJson () {
if (_current == nullptr) {
return triagens::basics::Json(triagens::basics::Json::Null);
}
// should always be true
if (_current == _json.get()) {
// _current points at the JSON that we own
TRI_json_t* value = _json.release();
setToNull();
return triagens::basics::Json(TRI_UNKNOWN_MEM_ZONE, value);
}
TRI_json_t* copy = TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, _current);
if (copy != nullptr) {
_json.release();
return triagens::basics::Json(TRI_UNKNOWN_MEM_ZONE, copy);
}
// fall-through intentional
return triagens::basics::Json(triagens::basics::Json::Null);
}
// -----------------------------------------------------------------------------
// --SECTION-- private methods
// -----------------------------------------------------------------------------
void DocumentAccessor::setToNull () {
// check if already null
if (! TRI_IsNullJson(_current)) {
_json.reset(TRI_CreateNullJson(TRI_UNKNOWN_MEM_ZONE));
_current = _json.get();
}
}
void DocumentAccessor::lookupJsonAttribute (char const* name, size_t nameLength) {
TRI_ASSERT(_current != nullptr);
TRI_json_t* value = TRI_LookupObjectJson(_current, name);
if (value == nullptr) {
// attribute not found
setToNull();
}
else {
// found
_current = value;
}
}
void DocumentAccessor::lookupDocumentAttribute (char const* name, size_t nameLength) {
if (*name == '_' && name[1] != '\0') {
if (name[1] == 'k' && nameLength == 4 && memcmp(name, TRI_VOC_ATTRIBUTE_KEY, nameLength) == 0) {
// _key value is copied into JSON
char const* key = TRI_EXTRACT_MARKER_KEY(_mptr);
if (key == nullptr) {
setToNull();
return;
}
_json.reset(TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, key, strlen(key)));
_current = _json.get();
return;
}
if (name[1] == 'i' && nameLength == 3 && memcmp(name, TRI_VOC_ATTRIBUTE_ID, nameLength) == 0) {
// _id
char buffer[512]; // big enough for max key length + max collection name length
size_t pos = _resolver->getCollectionName(&buffer[0], _document->_info._cid);
buffer[pos++] = '/';
char const* key = TRI_EXTRACT_MARKER_KEY(_mptr);
if (key == nullptr) {
setToNull();
return;
}
size_t len = strlen(key);
memcpy(&buffer[pos], key, len);
buffer[pos + len] = '\0';
_json.reset(TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, &buffer[0], pos + len));
_current = _json.get();
return;
}
if (name[1] == 'r' && nameLength == 4 && memcmp(name, TRI_VOC_ATTRIBUTE_REV, nameLength) == 0) {
// _rev
char buffer[21];
TRI_voc_rid_t rid = TRI_EXTRACT_MARKER_RID(_mptr);
size_t len = TRI_StringUInt64InPlace(rid, &buffer[0]);
_json.reset(TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, &buffer[0], len));
_current = _json.get();
return;
}
if (name[1] == 'f' && nameLength == 5 && memcmp(name, TRI_VOC_ATTRIBUTE_FROM, nameLength) == 0) {
// _from
char buffer[512]; // big enough for max key length + max collection name length
size_t pos = _resolver->getCollectionNameCluster(&buffer[0], TRI_EXTRACT_MARKER_FROM_CID(_mptr));
buffer[pos++] = '/';
char const* key = TRI_EXTRACT_MARKER_FROM_KEY(_mptr);
if (key == nullptr) {
setToNull();
return;
}
size_t len = strlen(key);
memcpy(&buffer[pos], key, len);
buffer[pos + len] = '\0';
_json.reset(TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, &buffer[0], pos + len));
_current = _json.get();
return;
}
if (name[1] == 't' && nameLength == 3 && memcmp(name, TRI_VOC_ATTRIBUTE_TO, nameLength) == 0) {
// to
char buffer[512]; // big enough for max key length + max collection name length
size_t pos = _resolver->getCollectionNameCluster(&buffer[0], TRI_EXTRACT_MARKER_TO_CID(_mptr));
buffer[pos++] = '/';
char const* key = TRI_EXTRACT_MARKER_TO_KEY(_mptr);
if (key == nullptr) {
setToNull();
return;
}
size_t len = strlen(key);
memcpy(&buffer[pos], key, len);
buffer[pos + len] = '\0';
_json.reset(TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, &buffer[0], pos + len));
_current = _json.get();
return;
}
// fall-through intentional
}
auto shaper = _document->getShaper();
TRI_shape_pid_t pid = shaper->lookupAttributePathByName(name);
if (pid == 0) {
// attribute does not exist
setToNull();
return;
}
// attribute exists
TRI_shaped_json_t document;
TRI_EXTRACT_SHAPED_JSON_MARKER(document, _mptr->getDataPtr());
TRI_shaped_json_t json;
TRI_shape_t const* shape;
bool ok = shaper->extractShapedJson(&document, 0, pid, &json, &shape);
if (ok && shape != nullptr) {
_json.reset(TRI_JsonShapedJson(shaper, &json));
_current = _json.get();
return;
}
// not found
setToNull();
}

View File

@ -0,0 +1,130 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief read-accesses internals of a document
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2006-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_VOC_BASE_DOCUMENT_ACCESSOR_H
#define ARANGODB_VOC_BASE_DOCUMENT_ACCESSOR_H 1
#include "Basics/Common.h"
#include "Basics/JsonHelper.h"
#include "VocBase/document-collection.h"
#include "VocBase/shape-accessor.h"
#include "VocBase/shaped-json.h"
#include "VocBase/Shaper.h"
struct TRI_doc_mptr_t;
namespace triagens {
namespace arango {
class CollectionNameResolver;
}
}
// -----------------------------------------------------------------------------
// --SECTION-- DocumentAccessor
// -----------------------------------------------------------------------------
class DocumentAccessor {
public:
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
DocumentAccessor (DocumentAccessor const&);
DocumentAccessor& operator= (DocumentAccessor const&);
DocumentAccessor (triagens::arango::CollectionNameResolver const* resolver,
TRI_document_collection_t* document,
TRI_doc_mptr_t const* mptr);
~DocumentAccessor ();
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
public:
bool hasKey (std::string const& attribute) const;
bool isObject () const;
bool isArray () const;
size_t length () const;
DocumentAccessor& get (char const* name, size_t nameLength);
DocumentAccessor& get (std::string const& name);
DocumentAccessor& at (int64_t index);
triagens::basics::Json toJson ();
// -----------------------------------------------------------------------------
// --SECTION-- private methods
// -----------------------------------------------------------------------------
private:
void setToNull ();
void lookupJsonAttribute (char const* name, size_t nameLength);
void lookupDocumentAttribute (char const* name, size_t nameLength);
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
private:
triagens::arango::CollectionNameResolver const* _resolver;
TRI_document_collection_t* _document;
TRI_doc_mptr_t const* _mptr;
std::unique_ptr<TRI_json_t> _json; // the JSON that we own
TRI_json_t* _current; // the JSON that we point to
};
#endif
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

View File

@ -700,6 +700,15 @@ static inline TRI_voc_rid_t TRI_EXTRACT_MARKER_RID (TRI_df_marker_t const* marke
return 0;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief extracts the revision id from a master pointer
////////////////////////////////////////////////////////////////////////////////
static inline TRI_voc_rid_t TRI_EXTRACT_MARKER_RID (TRI_doc_mptr_t const* mptr) {
TRI_df_marker_t const* marker = static_cast<TRI_df_marker_t const*>(mptr->getDataPtr());
return TRI_EXTRACT_MARKER_RID(marker);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief extracts the pointer to the key from a marker
////////////////////////////////////////////////////////////////////////////////

View File

@ -1,31 +1,36 @@
[
{
"name" : "FOR .. FILTER .. RETURN template",
"value": "/* Please insert some values for the @@collection and @value placeholders */\nFOR i IN @@collection\n FILTER i.`attribute` == @value\n RETURN i",
"value": "/* Please insert some values for the @@collection and @value bind parameters */\nFOR doc IN @@collection\n FILTER doc.`attribute` == @value\n RETURN doc",
"parameter": {"@collection": "my_collection", "value": "my_value"}
},
{
"name" : "Limit",
"value": "/* Please insert some values for the @@collection, @offset and @count placeholders */\nFOR i IN @@collection\n LIMIT @offset, @count\n RETURN i",
"parameter": {"@collection": "my_collection", "offset": "my_offset", "count": "my_count"}
"value": "/* Please insert some values for the @@collection, @offset and @count bind parameters */\nFOR doc IN @@collection\n LIMIT @offset, @count\n RETURN doc",
"parameter": {"@collection": "my_collection", "offset": 0, "count": 10}
},
{
"name" : "Inner join",
"value": "/* Please insert some values for the @@collection1 and @@collection2 bind parameters */\nFOR doc1 IN @@collection1\n FOR doc2 IN @@collection2\n FILTER doc1.`attribute` == doc2.`attribute`\n RETURN { doc1, doc2 }",
"parameter": {"@collection1": "collection1", "@collection2": "collection2"}
},
{
"name" : "Random document",
"value": "/* Please insert some value for the @@collection placeholder */\nFOR i IN @@collection\n SORT RAND()\n LIMIT 1\n RETURN i",
"value": "/* Please insert some value for the @@collection bind parameter */\nFOR doc IN @@collection\n SORT RAND()\n LIMIT 1\n RETURN doc",
"parameter": {"@collection": "my_collection"}
},
{
"name" : "Subquery example",
"value": "/* Please insert some values for the @@collection, @value and @count placeholders */\nFOR i IN @@collection\n LET values = (\n FOR s IN i.`attribute`\n FILTER s.`attribute` == @value\n RETURN s\n )\n FILTER LENGTH(values) > @count\n RETURN {\n i : i,\n values : values\n }",
"parameter": {"@collection": "my_collection", "value": "my_value", "count": "my_count"}
"value": "/* Please insert some values for the @@collection, @value and @count bind parameters */\nFOR doc IN @@collection\n LET values = (\n FOR s IN doc.`attribute`\n FILTER s.`attribute` == @value\n RETURN s\n )\n FILTER LENGTH(values) > @count\n RETURN {\n doc,\n values\n }",
"parameter": {"@collection": "my_collection", "value": "my_value", "count": 10}
},
{
"name" : "Sequences",
"value": "/* Returns the sequence of integers between 2010 and 2013 (including) */\nFOR year IN 2010..2013\n RETURN year"
"value": "/* Returns the sequence of integers between 2010 and 2015 (including) */\nFOR year IN 2010..2015\n RETURN year"
},
{
"name" : "Bind parameters",
"value": "/* There are two types of bind parameters:\n - bind parameter names starting with a single @ character, e.g. @count, @value, @test:\n These can be used to ship any JSON-encodable data to the server.\n - bind parameter names starting with two @ characters always refer to collections, e.g. @@collections, @@c:\n These can be used as placeholders for collection names.\n */\nFOR i IN @@collection\n FILTER i.value == @value\n RETURN i",
"value": "/* There are two types of bind parameters:\n - bind parameter names starting with a single @ character, e.g. @count, @value, @test:\n These can be used to ship any JSON-encodable data to the server.\n - bind parameter names starting with two @ characters always refer to collections, e.g. @@collections, @@c:\n These can be used as placeholders for collection names.\n */\nFOR doc IN @@collection\n FILTER doc.value == @value\n RETURN doc",
"parameter": {"@collection": "my_collection", "value": "my_value"}
}
]

View File

@ -678,7 +678,7 @@ function processQuery (query, explain) {
}
/* the exposed function */
function explain (data, options, shouldPrint) {
function explain (data, options, shouldPrint, bindVars) {
'use strict';
if (typeof data === "string") {
data = { query: data };
@ -687,10 +687,20 @@ function explain (data, options, shouldPrint) {
throw "ArangoStatement needs initial data";
}
if (options === undefined) {
options = data.options;
}
options = options || { };
setColors(options.colors === undefined ? true : options.colors);
var stmt = db._createStatement(data);
if (typeof bindVars === 'object') {
Object.keys(bindVars).forEach(function(key) {
stmt.bind(key, bindVars[key]);
});
}
var result = stmt.explain(options);
stringBuilder.clearOutput();

View File

@ -135,4 +135,86 @@
<% mediumChart("pageFaultsChart", "Major Page Faults") %>
<% mediumChart("systemUserTimeChart", "Used CPU Time per Second") %>
</div>
<div class="dashboard-headerbar headerBar">
<a class="arangoHeader">Replication</a>
</div>
<div class="dashboard-row">
<div class="dashboard-full-width-chart" id="replication-chart">
<div class="dashboard-full-width-chart-inner">
<div id="repl-numbers" class="dashboard-interior-chart">
<div class="inner">
<div class="top dashboard-subtitle-bar">Numbers</div>
<div class="bottom">
<table>
<tbody>
<tr>
<td>Events</td>
<td></td>
</tr>
<tr>
<td>Requests</td>
<td></td>
</tr>
<tr>
<td>Failed</td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div id="repl-ticks" class="dashboard-interior-chart">
<div class="inner">
<div class="top dashboard-subtitle-bar">Ticks</div>
<div class="bottom">
<table>
<tbody>
<tr>
<td>Applied</td>
<td></td>
</tr>
<tr>
<td>Processed</td>
<td></td>
</tr>
<tr>
<td>Available</td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div id="repl-progress" class="dashboard-interior-chart">
<div class="inner">
<div class="top dashboard-subtitle-bar">Progress</div>
<div class="bottom">
<table>
<tbody>
<tr>
<td>Message</td>
<td></td>
</tr>
<tr>
<td>Time</td>
<td></td>
</tr>
<tr>
<td>Failed</td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="dashboard-sub-bar"">Replication</div>
</div>
</div>
</script>

View File

@ -415,6 +415,45 @@
cuts[counter] : cuts[counter - 1] + " - " + cuts[counter];
},
renderReplicationStatistics: function(object) {
$('#repl-numbers table tr:nth-child(1) > td:nth-child(2)').html(object.state.totalEvents);
$('#repl-numbers table tr:nth-child(2) > td:nth-child(2)').html(object.state.totalRequests);
$('#repl-numbers table tr:nth-child(3) > td:nth-child(2)').html(object.state.totalFailedConnects);
$('#repl-ticks table tr:nth-child(1) > td:nth-child(2)').html(object.state.lastAppliedContinuousTick);
$('#repl-ticks table tr:nth-child(2) > td:nth-child(2)').html(object.state.lastProcessedContinuousTick);
$('#repl-ticks table tr:nth-child(3) > td:nth-child(2)').html(object.state.lastAvailableContinuousTick);
$('#repl-progress table tr:nth-child(1) > td:nth-child(2)').html(object.state.progress.message);
$('#repl-progress table tr:nth-child(2) > td:nth-child(2)').html(object.state.progress.time);
$('#repl-progress table tr:nth-child(3) > td:nth-child(2)').html(object.state.progress.failedConnects);
},
getReplicationStatistics: function() {
var self = this;
$.ajax(
'/_api/replication/applier-state',
{async: true}
).done(
function (d) {
console.log(d);
if (d.hasOwnProperty('state')) {
var running;
if (d.state.running) {
running = "Enabled";
}
else {
running = "Disabled";
}
running = '<span class="state">' + running + '</span>';
$('#replication-chart .dashboard-sub-bar').html("Replication " + running);
self.renderReplicationStatistics(d);
}
});
},
getStatistics: function (callback) {
var self = this;
var url = "/_db/_system/_admin/aardvark/statistics/short";
@ -453,6 +492,8 @@
}
self.updateCharts();
});
this.getReplicationStatistics();
},
getHistoryStatistics: function (figure) {

View File

@ -47,6 +47,74 @@
}
}
.dashboard-full-width-chart {
@extend %dashboard-chart-basic;
border: 1px solid rgba(104, 103, 102, .10);
border-radius: 3px;
margin-right: 12px;
.dashboard-full-width-chart-inner {
@extend %dashboard-chart-box;
@extend %pull-left;
background-color: $c-white;
border-left: $dashboard-borderwidth solid $c-white;
border-right: $dashboard-borderwidth solid $c-white;
border-top: $dashboard-borderwidth solid $c-white;
padding-bottom: $dashboard-padding;
padding-top: $dashboard-padding + 2px;
.dashboard-subtitle-bar {
&.top {
border-bottom: 1px solid $c-e1grey;
height: 48px;
line-height: 48px;
text-align: right;
}
}
.dashboard-interior-chart {
@extend %pull-left;
border-left: 1px solid $c-e1grey;
.inner {
margin-left: 10px;
margin-right: 10px;
table {
margin-top: 10px;
margin-bottom: 10px;
width: 100%;
td {
white-space: nowrap;
}
td:first-child {
width: 100px;
}
}
}
}
.dashboard-interior-chart:first-child {
border-left: 0;
}
}
.state {
background-color: $c-white;
border-radius: 5px;
color: $c-black;
margin-left: 5px;
padding-left: 3px;
padding-right: 5px;
}
}
.dashboard-large-chart {
@extend %dashboard-chart-basic;

View File

@ -147,6 +147,26 @@
width: $content-size;
}
.dashboard-full-width-chart {
$int-width: $content-size - 3px;
width: $int-width;
.dashboard-full-width-chart-inner {
width: $int-width - 10px;
.dashboard-interior-chart {
float: left;
$int-height: (($dashboard-height - 29px) / 2) - $tendency-height-corrector;
height: $int-height;
width: (($int-width - 11px) / 3) - 2px;
}
}
.dashboard-sub-bar {
width: $int-width - 11px;
}
}
.dashboard-large-chart {
$int-width: ($content-size * 2 / 3) - 4px - 2px;
width: $int-width;

View File

@ -88,14 +88,14 @@ var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
var AqlHighlightRules = function() {
var keywords = (
"for|return|filter|sort|limit|let|collect|asc|desc|if|in|into|insert|update|remove|replace|options|with|and|or|not|distinct"
"for|return|filter|sort|limit|let|collect|asc|desc|in|into|insert|update|remove|replace|upsert|options|with|and|or|not|distinct"
);
var builtinFunctions = (
"(to_bool|to_number|to_string|to_list|is_null|is_bool|is_number|is_string|is_list|is_document|" +
"concat|concat_separator|char_length|lower|upper|substring|left|right|trim|reverse|contains|" +
"like|floor|ceil|round|abs|rand|sqrt|length|min|max|average|sum|median|variance_population|" +
"variance_sample|first|last|unique|matches|merge|merge_recursive|has|attributes|values|unset|keep|" +
"variance_sample|first|last|unique|matches|merge|merge_recursive|has|attributes|values|unset|unset_recursive|keep|" +
"near|within|within_rectangle|is_in_polygon|fulltext|paths|traversal|traversal_tree|edges|stddev_sample|stddev_population|" +
"slice|nth|position|translate|zip|call|apply|push|append|pop|shift|unshift|remove_value|remove_values|" +
"remove_nth|graph_paths|shortest_path|graph_shortest_path|graph_distance_to|graph_traversal|graph_traversal_tree|graph_edges|" +
@ -107,7 +107,7 @@ var AqlHighlightRules = function() {
"date_add|date_subtract|date_diff|date_compare|date_format|fail|passthru|sleep|not_null|" +
"first_list|first_document|parse_identifier|current_user|current_database|" +
"collections|document|union|union_distinct|intersection|flatten|" +
"ltrim|rtrim|find_first|find_last|split|substitute|assemble|md5|sha1|random_token|AQL_LAST_ENTRY)"
"ltrim|rtrim|find_first|find_last|split|substitute|md5|sha1|random_token|AQL_LAST_ENTRY)"
);
var keywordMapper = this.createKeywordMapper({
@ -142,7 +142,7 @@ var AqlHighlightRules = function() {
regex : "[a-zA-Z_][a-zA-Z0-9_]*\\b"
}, {
token : "keyword.operator",
regex : "\\+|\\-|\\/|\\/\\/|%|@>|<@|&&|\\||!|<|>|<=|=>|==|!=|="
regex : "\\+|\\-|\\/|\\/\\/|%|@>|<@|&&|\\|\\||!|<|>|<=|=>|==|!=|=|\\[\\*\\]"
}, {
token : "paren.lparen",
regex : "[\\(\\{]"

View File

@ -686,6 +686,9 @@ function explain (data, options, shouldPrint, bindVars) {
throw "ArangoStatement needs initial data";
}
if (options === undefined) {
options = data.options;
}
options = options || { };
setColors(options.colors === undefined ? true : options.colors);

View File

@ -168,12 +168,12 @@ function getIndexMap (shard) {
function writeLocked (lockInfo, cb, args) {
var timeout = lockInfo.timeout;
if (timeout === undefined) {
timeout = 5;
timeout = 60;
}
var ttl = lockInfo.ttl;
if (ttl === undefined) {
ttl = 10;
ttl = 120;
}
if (require("internal").coverage || require("internal").valgrind) {
ttl *= 10;

View File

@ -165,9 +165,9 @@ function ReplicationSuite () {
break;
}
if (compareTicks(slaveState.state.lastAppliedContinuousTick, syncResult.lastLogTick) > 0 ||
compareTicks(slaveState.state.lastProcessedContinuousTick, syncResult.lastLogTick) > 0 ||
compareTicks(slaveState.state.lastAvailableContinuousTick, syncResult.lastLogTick) > 0) {
if (compareTicks(slaveState.state.lastAppliedContinuousTick, syncResult.lastLogTick) >= 0 ||
compareTicks(slaveState.state.lastProcessedContinuousTick, syncResult.lastLogTick) >= 0) { // ||
// compareTicks(slaveState.state.lastAvailableContinuousTick, syncResult.lastLogTick) > 0) {
break;
}
@ -226,11 +226,11 @@ function ReplicationSuite () {
function (state) {
// flush the wal logs on the master so the start tick is not available
// anymore when we start replicating
for (var i = 0; i < 25; ++i) {
for (var i = 0; i < 30; ++i) {
db._collection(cn).save({ value: i });
internal.wal.flush(); //true, true);
}
internal.wait(5, false);
internal.wait(6, false);
},
function (state) {
@ -239,7 +239,7 @@ function ReplicationSuite () {
function (state) {
// data loss on slave!
assertTrue(db._collection(cn).count() < 20);
assertTrue(db._collection(cn).count() < 25);
},
{
requireFromPresent: false
@ -262,16 +262,16 @@ function ReplicationSuite () {
function (state) {
// flush the wal logs on the master so the start tick is not available
// anymore when we start replicating
for (var i = 0; i < 25; ++i) {
for (var i = 0; i < 30; ++i) {
db._collection(cn).save({ value: i });
internal.wal.flush(); //true, true);
}
internal.wait(5, false);
internal.wait(6, false);
},
function (state) {
// wait for slave applier to have started and detect the mess
internal.wait(2, false);
internal.wait(3, false);
// slave should have stopped
assertFalse(replication.applier.state().state.running);
@ -282,7 +282,7 @@ function ReplicationSuite () {
function (state) {
// data loss on slave!
assertTrue(db._collection(cn).count() < 20);
assertTrue(db._collection(cn).count() < 25);
},
{
requireFromPresent: true

View File

@ -159,9 +159,9 @@ function ReplicationSuite () {
break;
}
if (compareTicks(slaveState.state.lastAppliedContinuousTick, syncResult.lastLogTick) > 0 ||
compareTicks(slaveState.state.lastProcessedContinuousTick, syncResult.lastLogTick) > 0 ||
compareTicks(slaveState.state.lastAvailableContinuousTick, syncResult.lastLogTick) > 0) {
if (compareTicks(slaveState.state.lastAppliedContinuousTick, syncResult.lastLogTick) >= 0 ||
compareTicks(slaveState.state.lastProcessedContinuousTick, syncResult.lastLogTick) >= 0) { //||
// compareTicks(slaveState.state.lastAvailableContinuousTick, syncResult.lastLogTick) > 0) {
break;
}