1
0
Fork 0

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

This commit is contained in:
Andreas Streichardt 2016-06-07 18:22:00 +02:00
commit 98ef80ab29
37 changed files with 1345 additions and 1986 deletions

0
CMakeLists.txt Executable file → Normal file
View File

View File

@ -0,0 +1,7 @@
!CHAPTER Working with Persistent Indexes
If a suitable persistent index exists, then /_api/simple/range and other operations
will use this index to execute queries.
<!-- js/actions/api-index.js -->
@startDocuBlock JSF_post_api_index_persistent

View File

@ -1,6 +1,7 @@
!CHAPTER Working with Skiplist Indexes
If a suitable skip-list index exists, then /_api/simple/range will use this index to execute a range query.
If a suitable skip-list index exists, then /_api/simple/range and other operations
will use this index to execute queries.
<!-- js/actions/api-index.js -->
@startDocuBlock JSF_post_api_index_skiplist
@startDocuBlock JSF_post_api_index_skiplist

View File

@ -38,6 +38,7 @@
* [Working with Indexes](Indexes/WorkingWith.md)
* [Hash](Indexes/Hash.md)
* [Skiplist](Indexes/Skiplist.md)
* [Persistent](Indexes/Persistent.md)
* [Geo](Indexes/Geo.md)
* [Fulltext](Indexes/Fulltext.md)
* [Transactions](Transaction/README.md)

View File

@ -28,9 +28,9 @@ of the index details. Depending on the index type, a single attribute or
multiple attributes can be indexed. In the latter case, an array of
strings is expected.
Indexing system attributes such as *_id*, *_key*, *_from*, and *_to*
is not supported for user-defined indexes. Manually creating an index using
any of these attributes will fail with an error.
Indexing the system attribute *_id* is not supported for user-defined indexes.
Manually creating an index using *_id* as an index attribute will fail with
an error.
Some indexes can be created as unique or non-unique variants. Uniqueness
can be controlled for most indexes by specifying the *unique* flag in the
@ -41,12 +41,13 @@ create a non-unique index.
**Note**: The following index types do not support uniqueness, and using
the *unique* attribute with these types may lead to an error:
- geo indexes
- fulltext indexes
**Note**: Unique indexes on non-shard keys are not supported in a
cluster.
Hash and skiplist indexes can optionally be created in a sparse
Hash, skiplist and persistent indexes can optionally be created in a sparse
variant. A sparse index will be created if the *sparse* attribute in
the index details is set to *true*. Sparse indexes do not index documents
for which any of the index attributes is either not set or is *null*.

View File

@ -0,0 +1,107 @@
@startDocuBlock JSF_post_api_index_persistent
@brief creates a persistent index
@RESTHEADER{POST /_api/index#persistent, Create a persistent index}
@RESTQUERYPARAMETERS
@RESTQUERYPARAM{collection-name,string,required}
The collection name.
@RESTBODYPARAM{type,string,required,string}
must be equal to *"persistent"*.
@RESTBODYPARAM{fields,array,required,string}
an array of attribute paths.
@RESTBODYPARAM{unique,boolean,required,}
if *true*, then create a unique index.
@RESTBODYPARAM{sparse,boolean,required,}
if *true*, then create a sparse index.
@RESTDESCRIPTION
Creates a persistent index for the collection *collection-name*, if
it does not already exist. The call expects an object containing the index
details.
In a sparse index all documents will be excluded from the index that do not
contain at least one of the specified index attributes (i.e. *fields*) or that
have a value of *null* in any of the specified index attributes. Such documents
will not be indexed, and not be taken into account for uniqueness checks if
the *unique* flag is set.
In a non-sparse index, these documents will be indexed (for non-present
indexed attributes, a value of *null* will be used) and will be taken into
account for uniqueness checks if the *unique* flag is set.
**Note**: unique indexes on non-shard keys are not supported in a cluster.
@RESTRETURNCODES
@RESTRETURNCODE{200}
If the index already exists, then a *HTTP 200* is
returned.
@RESTRETURNCODE{201}
If the index does not already exist and could be created, then a *HTTP 201*
is returned.
@RESTRETURNCODE{400}
If the collection already contains documents and you try to create a unique
persistent index in such a way that there are documents violating the
uniqueness, then a *HTTP 400* is returned.
@RESTRETURNCODE{404}
If the *collection-name* is unknown, then a *HTTP 404* is returned.
@EXAMPLES
Creating a persistent index
@EXAMPLE_ARANGOSH_RUN{RestIndexCreateNewPersistent}
var cn = "products";
db._drop(cn);
db._create(cn);
var url = "/_api/index?collection=" + cn;
var body = {
type: "persistent",
unique: false,
fields: [ "a", "b" ]
};
var response = logCurlRequest('POST', url, body);
assert(response.code === 201);
logJsonResponse(response);
~ db._drop(cn);
@END_EXAMPLE_ARANGOSH_RUN
Creating a sparse persistent index
@EXAMPLE_ARANGOSH_RUN{RestIndexCreateSparsePersistent}
var cn = "products";
db._drop(cn);
db._create(cn);
var url = "/_api/index?collection=" + cn;
var body = {
type: "persistent",
unique: false,
sparse: true,
fields: [ "a" ]
};
var response = logCurlRequest('POST', url, body);
assert(response.code === 201);
logJsonResponse(response);
~ db._drop(cn);
@END_EXAMPLE_ARANGOSH_RUN
@endDocuBlock

View File

@ -2,14 +2,13 @@
@startDocuBlock JSF_post_api_index_skiplist
@brief creates a skip-list
@RESTHEADER{POST /_api/index, Create skip list}
@RESTHEADER{POST /_api/index#skiplist, Create skip list}
@RESTQUERYPARAMETERS
@RESTQUERYPARAM{collection-name,string,required}
The collection name.
@RESTBODYPARAM{type,string,required,string}
must be equal to *"skiplist"*.

View File

@ -0,0 +1,579 @@
# coding: utf-8
require 'rspec'
require 'arangodb.rb'
describe ArangoDB do
prefix = "api-index-persistent"
################################################################################
## unique constraints during create
################################################################################
context "creating persistent index:" do
context "dealing with unique constraints violation:" do
before do
@cn = "UnitTestsCollectionIndexes"
ArangoDB.drop_collection(@cn)
@cid = ArangoDB.create_collection(@cn)
end
after do
ArangoDB.drop_collection(@cn)
end
it "does not create the index in case of violation" do
# create a document
cmd1 = "/_api/document?collection=#{@cn}"
body = "{ \"a\" : 1, \"b\" : 1 }"
doc = ArangoDB.log_post("#{prefix}-create2", cmd1, :body => body)
doc.code.should eq(201)
# create another document
body = "{ \"a\" : 1, \"b\" : 1 }"
doc = ArangoDB.log_post("#{prefix}-create2", cmd1, :body => body)
doc.code.should eq(201)
# try to create the index
cmd = "/_api/index?collection=#{@cn}"
body = "{ \"type\" : \"persistent\", \"unique\" : true, \"fields\" : [ \"a\" ] }"
doc = ArangoDB.log_post("#{prefix}-fail", cmd, :body => body)
doc.code.should eq(400)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['code'].should eq(400)
doc.parsed_response['errorNum'].should eq(1210)
end
it "does not create the index in case of violation, null attributes" do
# create a document
cmd1 = "/_api/document?collection=#{@cn}"
body = "{ \"a\" : null, \"b\" : 1 }"
doc = ArangoDB.log_post("#{prefix}-create2", cmd1, :body => body)
doc.code.should eq(201)
# create another document
body = "{ \"a\" : null, \"b\" : 1 }"
doc = ArangoDB.log_post("#{prefix}-create2", cmd1, :body => body)
doc.code.should eq(201)
# try to create the index
cmd = "/_api/index?collection=#{@cn}"
body = "{ \"type\" : \"persistent\", \"unique\" : true, \"fields\" : [ \"a\" ] }"
doc = ArangoDB.log_post("#{prefix}-fail", cmd, :body => body)
doc.code.should eq(400)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['code'].should eq(400)
doc.parsed_response['errorNum'].should eq(1210)
end
it "does not create the index in case of violation, sparse index" do
# create a document
cmd1 = "/_api/document?collection=#{@cn}"
body = "{ \"a\" : 1, \"b\" : 1 }"
doc = ArangoDB.log_post("#{prefix}-create2", cmd1, :body => body)
doc.code.should eq(201)
# create another document
body = "{ \"a\" : 1, \"b\" : 1 }"
doc = ArangoDB.log_post("#{prefix}-create2", cmd1, :body => body)
doc.code.should eq(201)
# try to create the index
cmd = "/_api/index?collection=#{@cn}"
body = "{ \"type\" : \"persistent\", \"unique\" : true, \"fields\" : [ \"a\" ], \"sparse\" : true }"
doc = ArangoDB.log_post("#{prefix}-fail", cmd, :body => body)
doc.code.should eq(400)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['code'].should eq(400)
doc.parsed_response['errorNum'].should eq(1210)
end
it "creates the index in case of null attributes, sparse index" do
# create a document
cmd1 = "/_api/document?collection=#{@cn}"
body = "{ \"a\" : null, \"b\" : 1 }"
doc = ArangoDB.log_post("#{prefix}-create2", cmd1, :body => body)
doc.code.should eq(201)
# create another document
body = "{ \"a\" : null, \"b\" : 1 }"
doc = ArangoDB.log_post("#{prefix}-create2", cmd1, :body => body)
doc.code.should eq(201)
# try to create the index
cmd = "/_api/index?collection=#{@cn}"
body = "{ \"type\" : \"persistent\", \"unique\" : true, \"fields\" : [ \"a\" ], \"sparse\" : true }"
doc = ArangoDB.log_post("#{prefix}-fail", cmd, :body => body)
doc.code.should eq(201)
doc.parsed_response['error'].should eq(false)
end
end
end
################################################################################
## unique constraints during create
################################################################################
context "creating documents:" do
context "dealing with unique constraints:" do
before do
@cn = "UnitTestsCollectionIndexes"
ArangoDB.drop_collection(@cn)
@cid = ArangoDB.create_collection(@cn)
end
after do
ArangoDB.drop_collection(@cn)
end
it "rolls back in case of violation" do
cmd = "/_api/index?collection=#{@cn}"
body = "{ \"type\" : \"persistent\", \"unique\" : true, \"fields\" : [ \"a\" ] }"
doc = ArangoDB.log_post("#{prefix}-create1", cmd, :body => body)
doc.code.should eq(201)
doc.parsed_response['type'].should eq("persistent")
doc.parsed_response['unique'].should eq(true)
# create a document
cmd1 = "/_api/document?collection=#{@cn}"
body = "{ \"a\" : 1, \"b\" : 1 }"
doc = ArangoDB.log_post("#{prefix}-create2", cmd1, :body => body)
doc.code.should eq(201)
id1 = doc.parsed_response['_id']
id1.should be_kind_of(String)
rev1 = doc.parsed_response['_rev']
rev1.should be_kind_of(String)
# check it
cmd2 = "/_api/document/#{id1}"
doc = ArangoDB.log_get("#{prefix}", cmd2)
doc.code.should eq(200)
doc.parsed_response['a'].should eq(1)
doc.parsed_response['b'].should eq(1)
doc.parsed_response['_id'].should eq(id1)
doc.parsed_response['_rev'].should eq(rev1)
# create a unique constraint violation
body = "{ \"a\" : 1, \"b\" : 2 }"
doc = ArangoDB.log_post("#{prefix}-create3", cmd1, :body => body)
doc.code.should eq(409)
# check it again
doc = ArangoDB.log_get("#{prefix}", cmd2)
doc.code.should eq(200)
doc.parsed_response['a'].should eq(1)
doc.parsed_response['b'].should eq(1)
doc.parsed_response['_id'].should eq(id1)
doc.parsed_response['_rev'].should eq(rev1)
# third try (make sure the rollback has not destroyed anything)
body = "{ \"a\" : 1, \"b\" : 3 }"
doc = ArangoDB.log_post("#{prefix}-create4", cmd1, :body => body)
doc.code.should eq(409)
# check it again
doc = ArangoDB.log_get("#{prefix}", cmd2)
doc.code.should eq(200)
doc.parsed_response['a'].should eq(1)
doc.parsed_response['b'].should eq(1)
doc.parsed_response['_id'].should eq(id1)
doc.parsed_response['_rev'].should eq(rev1)
# unload collection
cmd3 = "/_api/collection/#{@cn}/unload"
doc = ArangoDB.log_put("#{prefix}", cmd3)
doc.code.should eq(200)
# flush wal
doc = ArangoDB.put("/_admin/wal/flush");
doc.code.should eq(200)
cmd3 = "/_api/collection/#{@cn}"
doc = ArangoDB.log_get("#{prefix}", cmd3)
doc.code.should eq(200)
while doc.parsed_response['status'] != 2
doc = ArangoDB.get(cmd3)
doc.code.should eq(200)
sleep 1
end
# check it again
doc = ArangoDB.log_get("#{prefix}", cmd2)
doc.code.should eq(200)
doc.parsed_response['a'].should eq(1)
doc.parsed_response['b'].should eq(1)
doc.parsed_response['_id'].should eq(id1)
doc.parsed_response['_rev'].should eq(rev1)
end
it "rolls back in case of violation, sparse index" do
cmd = "/_api/index?collection=#{@cn}"
body = "{ \"type\" : \"persistent\", \"unique\" : true, \"fields\" : [ \"a\" ], \"sparse\" : true }"
doc = ArangoDB.log_post("#{prefix}-create1", cmd, :body => body)
doc.code.should eq(201)
doc.parsed_response['type'].should eq("persistent")
doc.parsed_response['unique'].should eq(true)
# create a document
cmd1 = "/_api/document?collection=#{@cn}"
body = "{ \"a\" : 1, \"b\" : 1 }"
doc = ArangoDB.log_post("#{prefix}-create2", cmd1, :body => body)
doc.code.should eq(201)
id1 = doc.parsed_response['_id']
id1.should be_kind_of(String)
rev1 = doc.parsed_response['_rev']
rev1.should be_kind_of(String)
# check it
cmd2 = "/_api/document/#{id1}"
doc = ArangoDB.log_get("#{prefix}", cmd2)
doc.code.should eq(200)
doc.parsed_response['a'].should eq(1)
doc.parsed_response['b'].should eq(1)
doc.parsed_response['_id'].should eq(id1)
doc.parsed_response['_rev'].should eq(rev1)
# create a unique constraint violation
body = "{ \"a\" : 1, \"b\" : 2 }"
doc = ArangoDB.log_post("#{prefix}-create3", cmd1, :body => body)
doc.code.should eq(409)
# check it again
doc = ArangoDB.log_get("#{prefix}", cmd2)
doc.code.should eq(200)
doc.parsed_response['a'].should eq(1)
doc.parsed_response['b'].should eq(1)
doc.parsed_response['_id'].should eq(id1)
doc.parsed_response['_rev'].should eq(rev1)
# third try (make sure the rollback has not destroyed anything)
body = "{ \"a\" : 1, \"b\" : 3 }"
doc = ArangoDB.log_post("#{prefix}-create4", cmd1, :body => body)
doc.code.should eq(409)
# check it again
doc = ArangoDB.log_get("#{prefix}", cmd2)
doc.code.should eq(200)
doc.parsed_response['a'].should eq(1)
doc.parsed_response['b'].should eq(1)
doc.parsed_response['_id'].should eq(id1)
doc.parsed_response['_rev'].should eq(rev1)
# unload collection
cmd3 = "/_api/collection/#{@cn}/unload"
doc = ArangoDB.log_put("#{prefix}", cmd3)
doc.code.should eq(200)
# flush wal
doc = ArangoDB.put("/_admin/wal/flush");
doc.code.should eq(200)
cmd3 = "/_api/collection/#{@cn}"
doc = ArangoDB.log_get("#{prefix}", cmd3)
doc.code.should eq(200)
while doc.parsed_response['status'] != 2
doc = ArangoDB.get(cmd3)
doc.code.should eq(200)
sleep 1
end
# check it again
doc = ArangoDB.log_get("#{prefix}", cmd2)
doc.code.should eq(200)
doc.parsed_response['a'].should eq(1)
doc.parsed_response['b'].should eq(1)
doc.parsed_response['_id'].should eq(id1)
doc.parsed_response['_rev'].should eq(rev1)
end
end
end
################################################################################
## unique constraints during update
################################################################################
context "updating documents:" do
context "dealing with unique constraints:" do
before do
@cn = "UnitTestsCollectionIndexes"
ArangoDB.drop_collection(@cn)
@cid = ArangoDB.create_collection(@cn)
end
after do
ArangoDB.drop_collection(@cn)
end
it "rolls back in case of violation" do
cmd = "/_api/index?collection=#{@cn}"
body = "{ \"type\" : \"persistent\", \"unique\" : true, \"fields\" : [ \"a\" ] }"
doc = ArangoDB.log_post("#{prefix}-update1", cmd, :body => body)
doc.code.should eq(201)
doc.parsed_response['type'].should eq("persistent")
doc.parsed_response['unique'].should eq(true)
# create a document
cmd1 = "/_api/document?collection=#{@cn}"
body = "{ \"a\" : 1, \"b\" : 1 }"
doc = ArangoDB.log_post("#{prefix}-update2", cmd1, :body => body)
doc.code.should eq(201)
id1 = doc.parsed_response['_id']
id1.should be_kind_of(String)
rev1 = doc.parsed_response['_rev']
rev1.should be_kind_of(String)
# check it
cmd2 = "/_api/document/#{id1}"
doc = ArangoDB.log_get("#{prefix}", cmd2)
doc.code.should eq(200)
doc.parsed_response['a'].should eq(1)
doc.parsed_response['b'].should eq(1)
doc.parsed_response['_id'].should eq(id1)
doc.parsed_response['_rev'].should eq(rev1)
# create a second document
body = "{ \"a\" : 2, \"b\" : 2 }"
doc = ArangoDB.log_post("#{prefix}-update3", cmd1, :body => body)
doc.code.should eq(201)
id2 = doc.parsed_response['_id']
id2.should be_kind_of(String)
rev2 = doc.parsed_response['_rev']
rev2.should be_kind_of(String)
# create a unique constraint violation during update
body = "{ \"a\" : 2, \"b\" : 3 }"
doc = ArangoDB.log_put("#{prefix}", cmd2, :body => body)
doc.code.should eq(409)
# check first document again
doc = ArangoDB.log_get("#{prefix}", cmd2)
doc.code.should eq(200)
doc.parsed_response['a'].should eq(1)
doc.parsed_response['b'].should eq(1)
doc.parsed_response['_id'].should eq(id1)
doc.parsed_response['_rev'].should eq(rev1)
rev3 = doc.parsed_response['_rev']
rev3.should be_kind_of(String)
# check second document again
cmd3 = "/_api/document/#{id2}"
doc = ArangoDB.log_get("#{prefix}", cmd3)
doc.code.should eq(200)
doc.parsed_response['a'].should eq(2)
doc.parsed_response['b'].should eq(2)
doc.parsed_response['_id'].should eq(id2)
doc.parsed_response['_rev'].should eq(rev2)
# third try (make sure the rollback has not destroyed anything)
body = "{ \"a\" : 2, \"b\" : 4 }"
doc = ArangoDB.log_put("#{prefix}", cmd2, :body => body)
doc.code.should eq(409)
# check the first document again
doc = ArangoDB.log_get("#{prefix}", cmd2)
doc.code.should eq(200)
doc.parsed_response['a'].should eq(1)
doc.parsed_response['b'].should eq(1)
doc.parsed_response['_id'].should eq(id1)
doc.parsed_response['_rev'].should eq(rev1)
doc.parsed_response['_rev'].should_not eq(rev2)
# unload collection
cmd4 = "/_api/collection/#{@cn}/unload"
doc = ArangoDB.log_put("#{prefix}", cmd4)
doc.code.should eq(200)
# flush wal
doc = ArangoDB.put("/_admin/wal/flush");
doc.code.should eq(200)
cmd4 = "/_api/collection/#{@cn}"
doc = ArangoDB.log_get("#{prefix}", cmd4)
doc.code.should eq(200)
while doc.parsed_response['status'] != 2
doc = ArangoDB.get(cmd4)
doc.code.should eq(200)
sleep 1
end
# check the first document again
doc = ArangoDB.log_get("#{prefix}", cmd2)
doc.code.should eq(200)
doc.parsed_response['a'].should eq(1)
doc.parsed_response['b'].should eq(1)
doc.parsed_response['_id'].should eq(id1)
doc.parsed_response['_rev'].should eq(rev1)
doc.parsed_response['_rev'].should_not eq(rev2)
end
it "rolls back in case of violation, sparse index" do
cmd = "/_api/index?collection=#{@cn}"
body = "{ \"type\" : \"persistent\", \"unique\" : true, \"fields\" : [ \"a\" ], \"sparse\" : true }"
doc = ArangoDB.log_post("#{prefix}-update1", cmd, :body => body)
doc.code.should eq(201)
doc.parsed_response['type'].should eq("persistent")
doc.parsed_response['unique'].should eq(true)
# create a document
cmd1 = "/_api/document?collection=#{@cn}"
body = "{ \"a\" : 1, \"b\" : 1 }"
doc = ArangoDB.log_post("#{prefix}-update2", cmd1, :body => body)
doc.code.should eq(201)
id1 = doc.parsed_response['_id']
id1.should be_kind_of(String)
rev1 = doc.parsed_response['_rev']
rev1.should be_kind_of(String)
# check it
cmd2 = "/_api/document/#{id1}"
doc = ArangoDB.log_get("#{prefix}", cmd2)
doc.code.should eq(200)
doc.parsed_response['a'].should eq(1)
doc.parsed_response['b'].should eq(1)
doc.parsed_response['_id'].should eq(id1)
doc.parsed_response['_rev'].should eq(rev1)
# create a second document
body = "{ \"a\" : 2, \"b\" : 2 }"
doc = ArangoDB.log_post("#{prefix}-update3", cmd1, :body => body)
doc.code.should eq(201)
id2 = doc.parsed_response['_id']
id2.should be_kind_of(String)
rev2 = doc.parsed_response['_rev']
rev2.should be_kind_of(String)
# create a unique constraint violation during update
body = "{ \"a\" : 2, \"b\" : 3 }"
doc = ArangoDB.log_put("#{prefix}", cmd2, :body => body)
doc.code.should eq(409)
# check first document again
doc = ArangoDB.log_get("#{prefix}", cmd2)
doc.code.should eq(200)
doc.parsed_response['a'].should eq(1)
doc.parsed_response['b'].should eq(1)
doc.parsed_response['_id'].should eq(id1)
doc.parsed_response['_rev'].should eq(rev1)
rev3 = doc.parsed_response['_rev']
rev3.should be_kind_of(String)
# check second document again
cmd3 = "/_api/document/#{id2}"
doc = ArangoDB.log_get("#{prefix}", cmd3)
doc.code.should eq(200)
doc.parsed_response['a'].should eq(2)
doc.parsed_response['b'].should eq(2)
doc.parsed_response['_id'].should eq(id2)
doc.parsed_response['_rev'].should eq(rev2)
# third try (make sure the rollback has not destroyed anything)
body = "{ \"a\" : 2, \"b\" : 4 }"
doc = ArangoDB.log_put("#{prefix}", cmd2, :body => body)
doc.code.should eq(409)
# check the first document again
doc = ArangoDB.log_get("#{prefix}", cmd2)
doc.code.should eq(200)
doc.parsed_response['a'].should eq(1)
doc.parsed_response['b'].should eq(1)
doc.parsed_response['_id'].should eq(id1)
doc.parsed_response['_rev'].should eq(rev1)
doc.parsed_response['_rev'].should_not eq(rev2)
# unload collection
cmd4 = "/_api/collection/#{@cn}/unload"
doc = ArangoDB.log_put("#{prefix}", cmd4)
doc.code.should eq(200)
# flush wal
doc = ArangoDB.put("/_admin/wal/flush");
doc.code.should eq(200)
cmd4 = "/_api/collection/#{@cn}"
doc = ArangoDB.log_get("#{prefix}", cmd4)
doc.code.should eq(200)
while doc.parsed_response['status'] != 2
doc = ArangoDB.get(cmd4)
doc.code.should eq(200)
sleep 1
end
# check the first document again
doc = ArangoDB.log_get("#{prefix}", cmd2)
doc.code.should eq(200)
doc.parsed_response['a'].should eq(1)
doc.parsed_response['b'].should eq(1)
doc.parsed_response['_id'].should eq(id1)
doc.parsed_response['_rev'].should eq(rev1)
doc.parsed_response['_rev'].should_not eq(rev2)
end
end
end
end

View File

@ -363,7 +363,7 @@ void Agent::run() {
while (!this->isStopping() && size() > 1) { // need only to run in multi-host
if (leading())
_appendCV.wait(500000); // Only if leading
_appendCV.wait(25000); // Only if leading
else
_appendCV.wait(); // Just sit there doing nothing

View File

@ -767,7 +767,6 @@ AstNode const* ExecutionPlan::parseTraversalVertexNode(ExecutionNode* previous,
// operand is some misc expression
auto calc = createTemporaryCalculation(vertex, previous);
vertex = _ast->createNodeReference(getOutVariable(calc));
previous = calc;
}
return vertex;

View File

@ -601,6 +601,10 @@ bool AgencyComm::tryInitializeStructure(std::string const& jwtSecret) {
}
builder.add("NumberOfCoordinators", VPackSlice::nullSlice());
builder.add("NumberOfDBServers", VPackSlice::nullSlice());
builder.add(VPackValue("CleanedServers"));
{
VPackArrayBuilder dd(&builder);
}
builder.add("Lock", VPackValue("UNLOCKED"));
addEmptyVPackObject("MapLocalToID", builder);
addEmptyVPackObject("Failed", builder);

View File

@ -258,6 +258,7 @@ void RocksDBIndex::toVelocyPackFigures(VPackBuilder& builder) const {
int RocksDBIndex::insert(arangodb::Transaction* trx, TRI_doc_mptr_t const* doc,
bool) {
auto comparator = RocksDBFeature::instance()->comparator();
std::vector<TRI_index_element_t*> elements;
int res;
@ -281,9 +282,18 @@ int RocksDBIndex::insert(arangodb::Transaction* trx, TRI_doc_mptr_t const* doc,
}
VPackSlice const key = Transaction::extractKeyFromDocument(VPackSlice(doc->vpack()));
std::string const prefix = buildPrefix(trx->vocbase()->_id, _collection->_info.id(), _iid);
VPackBuilder builder;
std::vector<std::string> values;
values.reserve(elements.size());
// lower and upper bounds, only required if the index is unique
std::vector<std::pair<std::string, std::string>> bounds;
if (_unique) {
bounds.reserve(elements.size());
}
for (auto& it : elements) {
builder.clear();
builder.openArray();
@ -296,9 +306,44 @@ int RocksDBIndex::insert(arangodb::Transaction* trx, TRI_doc_mptr_t const* doc,
VPackSlice const s = builder.slice();
std::string value;
value.reserve(keyPrefixSize() + s.byteSize());
value += buildPrefix(trx->vocbase()->_id, _collection->_info.id(), _iid);
value += prefix;
value.append(s.startAs<char const>(), s.byteSize());
values.emplace_back(std::move(value));
if (_unique) {
builder.clear();
builder.openArray();
for (size_t i = 0; i < _fields.size(); ++i) {
builder.add(it->subObjects()[i].slice(doc));
}
builder.add(VPackSlice::minKeySlice());
builder.close();
VPackSlice s = builder.slice();
std::string value;
value.reserve(keyPrefixSize() + s.byteSize());
value += prefix;
value.append(s.startAs<char const>(), s.byteSize());
std::pair<std::string, std::string> p;
p.first = value;
builder.clear();
builder.openArray();
for (size_t i = 0; i < _fields.size(); ++i) {
builder.add(it->subObjects()[i].slice(doc));
}
builder.add(VPackSlice::maxKeySlice());
builder.close();
s = builder.slice();
value.clear();
value += prefix;
value.append(s.startAs<char const>(), s.byteSize());
p.second = value;
bounds.emplace_back(std::move(p));
}
}
auto rocksTransaction = trx->rocksTransaction();
@ -309,10 +354,28 @@ int RocksDBIndex::insert(arangodb::Transaction* trx, TRI_doc_mptr_t const* doc,
size_t const count = elements.size();
for (size_t i = 0; i < count; ++i) {
if (_unique) {
std::string existing;
auto status = rocksTransaction->Get(readOptions, values[i], &existing);
bool uniqueConstraintViolated = false;
auto iterator = rocksTransaction->GetIterator(readOptions);
if (status.ok()) {
if (iterator != nullptr) {
auto& bound = bounds[i];
iterator->Seek(rocksdb::Slice(bound.first.c_str(), bound.first.size()));
while (iterator->Valid()) {
int res = comparator->Compare(iterator->key(), rocksdb::Slice(bound.second.c_str(), bound.second.size()));
if (res > 0) {
break;
}
uniqueConstraintViolated = true;
break;
}
delete iterator;
}
if (uniqueConstraintViolated) {
// duplicate key
res = TRI_ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED;
if (!_collection->useSecondaryIndexes()) {
@ -324,6 +387,7 @@ int RocksDBIndex::insert(arangodb::Transaction* trx, TRI_doc_mptr_t const* doc,
if (res == TRI_ERROR_NO_ERROR) {
auto status = rocksTransaction->Put(values[i], std::string());
if (! status.ok()) {
res = TRI_ERROR_INTERNAL;
}

View File

@ -46,6 +46,7 @@ RestCursorHandler::RestCursorHandler(
_queryRegistry(queryRegistry),
_queryLock(),
_query(nullptr),
_hasStarted(false),
_queryKilled(false) {}
HttpHandler::status_t RestCursorHandler::execute() {
@ -235,6 +236,10 @@ void RestCursorHandler::processQuery(VPackSlice const& slice) {
void RestCursorHandler::registerQuery(arangodb::aql::Query* query) {
MUTEX_LOCKER(mutexLocker, _queryLock);
if (_queryKilled) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_REQUEST_CANCELED);
}
TRI_ASSERT(_query == nullptr);
_query = query;
@ -259,6 +264,10 @@ bool RestCursorHandler::cancelQuery() {
if (_query != nullptr) {
_query->killed(true);
_queryKilled = true;
_hasStarted = true;
return true;
} else if (!_hasStarted) {
_queryKilled = true;
return true;
}

View File

@ -151,6 +151,12 @@ class RestCursorHandler : public RestVocbaseBaseHandler {
//////////////////////////////////////////////////////////////////////////////
arangodb::aql::Query* _query;
//////////////////////////////////////////////////////////////////////////////
/// @brief whether or not the query has already started executing
//////////////////////////////////////////////////////////////////////////////
bool _hasStarted;
//////////////////////////////////////////////////////////////////////////////
/// @brief whether or not the query was killed

View File

@ -1045,11 +1045,14 @@ actions.defineHttp({
if (req.requestType === actions.GET) {
var nrCoordinators;
var nrDBServers;
var cleanedServers;
try {
nrCoordinators = ArangoAgency.get("Target/NumberOfCoordinators");
nrCoordinators = nrCoordinators.arango.Target.NumberOfCoordinators;
nrDBServers = ArangoAgency.get("Target/NumberOfDBServers");
nrDBServers = nrDBServers.arango.Target.NumberOfDBServers;
cleanedServers = ArangoAgency.get("Target/CleanedServers");
cleanedServers = cleanedServers.arango.Target.CleanedServers;
}
catch (e1) {
actions.resultError(req, res, actions.HTTP_SERVICE_UNAVAILABLE,
@ -1058,7 +1061,8 @@ actions.defineHttp({
}
actions.resultOk(req, res, actions.HTTP_OK,
{numberOfCoordinators: nrCoordinators,
numberOfDBServers: nrDBServers});
numberOfDBServers: nrDBServers,
cleanedServers});
} else {
var body = actions.getJsonBody(req, res);
if (body === undefined) {
@ -1102,3 +1106,196 @@ actions.defineHttp({
}
});
////////////////////////////////////////////////////////////////////////////////
/// @start Docu Block JSF_postCleanOutServer
/// (intentionally not in manual)
/// @brief triggers activities to clean out a DBServer
///
/// @ RESTHEADER{POST /_admin/cluster/cleanOutServer, Trigger activities to clean out a DBServers.}
///
/// @ RESTQUERYPARAMETERS
///
/// @ RESTDESCRIPTION Triggers activities to clean out a DBServer.
/// The body must be a JSON object with attribute "server" that is a string
/// with the ID of the server to be cleaned out.
///
/// @ RESTRETURNCODES
///
/// @ RESTRETURNCODE{202} is returned when everything went well and the
/// job is scheduled.
///
/// @ RESTRETURNCODE{400} body is not valid JSON.
///
/// @ RESTRETURNCODE{403} server is not a coordinator or method was not POST.
///
/// @ RESTRETURNCODE{503} the agency operation did not work.
///
/// @end Docu Block
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url: "_admin/cluster/cleanOutServer",
allowUseDatabase: true,
prefix: false,
callback: function (req, res) {
if (!require("@arangodb/cluster").isCoordinator()) {
actions.resultError(req, res, actions.HTTP_FORBIDDEN, 0,
"only coordinators can serve this request");
return;
}
if (req.requestType !== actions.POST) {
actions.resultError(req, res, actions.HTTP_FORBIDDEN, 0,
"only the POST method is allowed");
return;
}
var timeout = 60.0;
// Now get to work:
var body = actions.getJsonBody(req, res);
if (body === undefined) {
return;
}
if (typeof body !== "object" ||
! body.hasOwnProperty("server") ||
typeof body.server !== "string") {
actions.resultError(req, res, actions.HTTP_BAD,
"body must be an object with a string attribute 'server'");
return;
}
var ok = true;
try {
var id = ArangoClusterInfo.uniqid();
var todo = { "type": "cleanOutServer",
"server": body.server,
"jobId": id,
"timeCreated": (new Date()).toISOString(),
"creator": ArangoServerState.id() };
ArangoAgency.set("Target/ToDo/" + id, todo);
}
catch (e1) {
ok = false;
}
if (!ok) {
actions.resultError(req, res, actions.HTTP_SERVICE_UNAVAILABLE,
"Cannot write to agency.");
return;
}
actions.resultOk(req, res, actions.HTTP_ACCEPTED, true);
}
});
////////////////////////////////////////////////////////////////////////////////
/// @start Docu Block JSF_postMoveShard
/// (intentionally not in manual)
/// @brief triggers activities to move a shard
///
/// @ RESTHEADER{POST /_admin/cluster/moveShard, Trigger activities to move a shard.}
///
/// @ RESTQUERYPARAMETERS
///
/// @ RESTDESCRIPTION Triggers activities to move a shard.
/// The body must be a JSON document with the following attributes:
/// - `"database"`: a string with the name of the database
/// - `"collection"`: a string with the name of the collection
/// - `"shard"`: a string with the name of the shard to move
/// - `"fromServer"`: a string with the ID of a server that is currently
/// the leader or a follower for this shard
/// - `"toServer"`: a string with the ID of a server that is currently
/// not the leader and not a follower for this shard
///
/// @ RESTRETURNCODES
///
/// @ RESTRETURNCODE{202} is returned when everything went well and the
/// job is scheduled.
///
/// @ RESTRETURNCODE{400} body is not valid JSON.
///
/// @ RESTRETURNCODE{403} server is not a coordinator or method was not POST.
///
/// @ RESTRETURNCODE{503} the agency operation did not work.
///
/// @end Docu Block
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url: "_admin/cluster/moveShard",
allowUseDatabase: true,
prefix: false,
callback: function (req, res) {
if (!require("@arangodb/cluster").isCoordinator()) {
actions.resultError(req, res, actions.HTTP_FORBIDDEN, 0,
"only coordinators can serve this request");
return;
}
if (req.requestType !== actions.POST) {
actions.resultError(req, res, actions.HTTP_FORBIDDEN, 0,
"only the POST method is allowed");
return;
}
var timeout = 60.0;
// Now get to work:
var body = actions.getJsonBody(req, res);
if (body === undefined) {
return;
}
if (typeof body !== "object" ||
! body.hasOwnProperty("database") ||
typeof body.database !== "string" ||
! body.hasOwnProperty("collection") ||
typeof body.collection !== "string" ||
! body.hasOwnProperty("shard") ||
typeof body.shard !== "string" ||
! body.hasOwnProperty("fromServer") ||
typeof body.fromServer !== "string" ||
! body.hasOwnProperty("toServer") ||
typeof body.toServer !== "string") {
actions.resultError(req, res, actions.HTTP_BAD,
"body must be an object with string attributes 'database', 'collection', 'shard', 'fromServer' and 'toServer'");
return;
}
var ok = true;
var isLeader;
try {
var coll = ArangoClusterInfo.getCollectionInfo(body.database,
body.collection);
var shards = coll.shards;
var shard = shards[body.shard];
var pos = shard.indexOf(body.fromServer);
if (pos === -1) {
throw "Banana";
} else if (pos === 0) {
isLeader = true;
} else {
isLeader = false;
}
} catch (e2) {
actions.resultError(req, res, actions.HTTP_BAD,
"Combination of database, collection, shard and fromServer does not make sense.");
return;
}
try {
var id = ArangoClusterInfo.uniqid();
var todo = { "type": "moveShard",
"database": body.database,
"collection": body.collection,
"shard": body.shard,
"fromServer": body.fromServer,
"toServer": body.toServer,
"jobId": id,
"timeCreated": (new Date()).toISOString(),
"creator": ArangoServerState.id() };
ArangoAgency.set("Target/ToDo/" + id, todo);
} catch (e1) {
actions.resultError(req, res, actions.HTTP_SERVICE_UNAVAILABLE,
"Cannot write to agency.");
return;
}
actions.resultOk(req, res, actions.HTTP_ACCEPTED, true);
}
});

View File

@ -33,7 +33,6 @@ var actions = require("@arangodb/actions");
var API = "_api/index";
////////////////////////////////////////////////////////////////////////////////
/// @brief was docuBlock JSF_get_api_index
////////////////////////////////////////////////////////////////////////////////
@ -111,10 +110,6 @@ function get_api_index (req, res) {
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief was docuBlock JSF_post_api_index_cap
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief was docuBlock JSF_post_api_index_geo
////////////////////////////////////////////////////////////////////////////////

File diff suppressed because one or more lines are too long

View File

@ -2517,9 +2517,9 @@ if (list.length > 0) {
<div class="<%=genClass%> mid"><%= node.role %></div>
<% if(node.status === 'ok') { %>
<div class="<%= genClass %> mid"><i class="fa fa-check-circle"></i></div>
<div class="<%= genClass %> mid state"><i class="fa fa-check-circle"></i></div>
<% } else { %>
<div class="<%= genClass %> mid"><i class="fa fa-exclamation-circle"></i></div>
<div class="<%= genClass %> mid state"><i class="fa fa-exclamation-circle"></i></div>
<% } %>
</div>
@ -3129,4 +3129,4 @@ var cutByResolution = function (str) {
</div>
<div id="workMonitorContent" class="innerContent">
</div></script></head><body><nav class="navbar" style="display: none"><div class="primary"><div class="navlogo"><a class="logo big" href="#"><img class="arangodbLogo" src="img/arangodb_logo_big.png"></a> <a class="logo small" href="#"><img class="arangodbLogo" src="img/arangodb_logo_small.png"></a> <a class="version"><span>VERSION:</span><span id="currentVersion"></span></a></div><div class="statmenu" id="statisticBar"></div><div class="navmenu" id="navigationBar"></div></div></nav><div id="modalPlaceholder"></div><div class="bodyWrapper" style="display: none"><div class="centralRow"><div id="navbar2" class="navbarWrapper secondary"><div class="subnavmenu" id="subNavigationBar"></div></div><div class="resizecontainer contentWrapper"><div id="loadingScreen" class="loadingScreen" style="display: none"><i class="fa fa-circle-o-notch fa-spin fa-3x fa-fw margin-bottom"></i> <span class="sr-only">Loading...</span></div><div id="content" class="centralContent"></div><footer class="footer"><div id="footerBar"></div></footer></div></div></div><div id="progressPlaceholder" style="display:none"></div><div id="spotlightPlaceholder" style="display:none"></div><div id="offlinePlaceholder" style="display:none"><div class="offline-div"><div class="pure-u"><div class="pure-u-1-4"></div><div class="pure-u-1-2 offline-window"><div class="offline-header"><h3>You have been disconnected from the server</h3></div><div class="offline-body"><p>The connection to the server has been lost. The server may be under heavy load.</p><p>Trying to reconnect in <span id="offlineSeconds">10</span> seconds.</p><p class="animation_state"><span><button class="button-success">Reconnect now</button></span></p></div></div><div class="pure-u-1-4"></div></div></div></div><div class="arangoFrame" style=""><div class="outerDiv"><div class="innerDiv"></div></div></div><script src="libs.js?version=1465305299972"></script><script src="app.js?version=1465305299972"></script></body></html>
</div></script></head><body><nav class="navbar" style="display: none"><div class="primary"><div class="navlogo"><a class="logo big" href="#"><img class="arangodbLogo" src="img/arangodb_logo_big.png"></a> <a class="logo small" href="#"><img class="arangodbLogo" src="img/arangodb_logo_small.png"></a> <a class="version"><span>VERSION:</span><span id="currentVersion"></span></a></div><div class="statmenu" id="statisticBar"></div><div class="navmenu" id="navigationBar"></div></div></nav><div id="modalPlaceholder"></div><div class="bodyWrapper" style="display: none"><div class="centralRow"><div id="navbar2" class="navbarWrapper secondary"><div class="subnavmenu" id="subNavigationBar"></div></div><div class="resizecontainer contentWrapper"><div id="loadingScreen" class="loadingScreen" style="display: none"><i class="fa fa-circle-o-notch fa-spin fa-3x fa-fw margin-bottom"></i> <span class="sr-only">Loading...</span></div><div id="content" class="centralContent"></div><footer class="footer"><div id="footerBar"></div></footer></div></div></div><div id="progressPlaceholder" style="display:none"></div><div id="spotlightPlaceholder" style="display:none"></div><div id="offlinePlaceholder" style="display:none"><div class="offline-div"><div class="pure-u"><div class="pure-u-1-4"></div><div class="pure-u-1-2 offline-window"><div class="offline-header"><h3>You have been disconnected from the server</h3></div><div class="offline-body"><p>The connection to the server has been lost. The server may be under heavy load.</p><p>Trying to reconnect in <span id="offlineSeconds">10</span> seconds.</p><p class="animation_state"><span><button class="button-success">Reconnect now</button></span></p></div></div><div class="pure-u-1-4"></div></div></div></div><div class="arangoFrame" style=""><div class="outerDiv"><div class="innerDiv"></div></div></div><script src="libs.js?version=1465314759214"></script><script src="app.js?version=1465314759214"></script></body></html>

File diff suppressed because one or more lines are too long

View File

@ -286,6 +286,11 @@
//nav for cluster/nodes view
buildNodesSubNav: function(type) {
//if nothing is set, set default to coordinator
if (type === undefined) {
type = 'coordinator';
}
if (this.scaleability === undefined) {
var self = this;
@ -298,7 +303,7 @@
success: function(data) {
if (data.numberOfCoordinators !== null && data.numberOfDBServers !== null) {
self.scaleability = true;
self.buildNodesSubNav();
self.buildNodesSubNav(type);
}
else {
self.scaleability = false;

View File

@ -36,9 +36,9 @@
<div class="<%=genClass%> mid"><%= node.role %></div>
<% if(node.status === 'ok') { %>
<div class="<%= genClass %> mid"><i class="fa fa-check-circle"></i></div>
<div class="<%= genClass %> mid state"><i class="fa fa-check-circle"></i></div>
<% } else { %>
<div class="<%= genClass %> mid"><i class="fa fa-exclamation-circle"></i></div>
<div class="<%= genClass %> mid state"><i class="fa fa-exclamation-circle"></i></div>
<% } %>
</div>

View File

@ -1,6 +1,6 @@
/*jshint browser: true */
/*jshint unused: false */
/*global Backbone, document, templateEngine, $, arangoHelper, window*/
/*global _, Backbone, document, templateEngine, $, arangoHelper, window*/
(function() {
"use strict";
@ -61,14 +61,7 @@
}
}
else {
self.collection.fetch({
success: function() {
self.renderClusterState(true);
},
error: function() {
self.renderClusterState(false);
}
});
this.renderClusterState(isOnline);
}
},
@ -97,34 +90,54 @@
},
renderClusterState: function(connection) {
var error = 0;
if (connection) {
$('#offlinePlaceholder').hide();
this.collection.each(function(value) {
if (value.toJSON().status !== 'ok') {
error++;
var callbackFunction = function(data) {
var health = data.Health;
var error = 0;
_.each(health, function(node) {
if (node.Status !== 'GOOD') {
error++;
}
});
if (error > 0) {
$('#healthStatus').removeClass('positive');
$('#healthStatus').addClass('negative');
if (error === 1) {
$('.health-state').html(error + ' NODE ERROR');
}
else {
$('.health-state').html(error + ' NODES ERROR');
}
$('.health-icon').html('<i class="fa fa-exclamation-circle"></i>');
}
else {
$('#healthStatus').removeClass('negative');
$('#healthStatus').addClass('positive');
$('.health-state').html('NODES OK');
$('.health-icon').html('<i class="fa fa-check-circle"></i>');
}
}.bind(this);
//check cluster state
$.ajax({
type: "GET",
cache: false,
url: arangoHelper.databaseUrl("/_admin/cluster/health"),
contentType: "application/json",
processData: false,
async: true,
success: function(data) {
callbackFunction(data);
}
});
if (error > 0) {
$('#healthStatus').removeClass('positive');
$('#healthStatus').addClass('negative');
if (error === 1) {
$('.health-state').html(error + ' NODE ERROR');
}
else {
$('.health-state').html(error + ' NODES ERROR');
}
$('.health-icon').html('<i class="fa fa-exclamation-circle"></i>');
}
else {
$('#healthStatus').removeClass('negative');
$('#healthStatus').addClass('positive');
$('.health-state').html('NODES OK');
$('.health-icon').html('<i class="fa fa-check-circle"></i>');
}
}
else {
$('#healthStatus').removeClass('positive');

View File

@ -16,6 +16,7 @@
},
initialize: function (options) {
var self = this;
clearInterval(this.intervalFunction);
if (window.App.isCluster) {
@ -27,20 +28,56 @@
//start polling with interval
this.intervalFunction = window.setInterval(function() {
if (window.location.hash === '#cNodes' || window.location.hash === '#dNodes' || window.location.hash === '#nodes') {
console.log("rerender health");
self.checkNodesState();
}
}, this.interval);
}
},
checkNodesState: function() {
var callbackFunction = function(nodes) {
_.each(nodes, function(node, name) {
_.each($('.pure-table-row'), function(element) {
if ($(element).attr('node') === name) {
if (node.Status === "GOOD") {
$(element).removeClass("noHover");
$(element).find('.state').html('<i class="fa fa-check-circle"></i>');
}
else {
$(element).addClass("noHover");
$(element).find('.state').html('<i class="fa fa-exclamation-circle"></i>');
}
}
});
});
}.bind(this);
//check cluster state
$.ajax({
type: "GET",
cache: false,
url: arangoHelper.databaseUrl("/_admin/cluster/health"),
contentType: "application/json",
processData: false,
async: true,
success: function(data) {
callbackFunction(data.Health);
}
});
},
navigateToNode: function(elem) {
if (window.location.hash === '#dNodes') {
return;
}
if ($(elem.currentTarget).hasClass('noHover')) {
return;
}
var name = $(elem.currentTarget).attr('node');
window.App.navigate("#node/" + encodeURIComponent(name), {trigger: true});
},
@ -76,6 +113,7 @@
}));
window.arangoHelper.buildNodesSubNav(this.toRender);
this.checkNodesState();
},
waitForCoordinators: function(callback) {

View File

@ -0,0 +1,13 @@
.cluster-nodes {
.pure-table-row {
&.noHover {
cursor: not-allowed !important;
}
&.noHover:hover {
cursor: not-allowed !important;
}
}
}

View File

@ -79,6 +79,8 @@
@import 'pure';
// screen hotkeys
@import 'hotkeys';
// screen nodes
@import 'nodes';
//arangoTable Template
@import 'arangoTable';

View File

@ -42,8 +42,8 @@ function agencyTestSuite () {
/// @brief the agency servers
////////////////////////////////////////////////////////////////////////////////
var agencyServers = ARGUMENTS;
var whoseTurn = 0; // used to do round robin on agencyServers
var agencyServers = ARGUMENTS[0].split(" ");
var whoseTurn = 0;
var request = require("@arangodb/request");
@ -53,6 +53,7 @@ function agencyTestSuite () {
var res = request({url: agencyServers[whoseTurn] + "/_api/agency/read", method: "POST",
followRedirects: true, body: JSON.stringify(list),
headers: {"Content-Type": "application/json"}});
res.bodyParsed = JSON.parse(res.body);
return res;
}
@ -62,8 +63,10 @@ function agencyTestSuite () {
// response:
var res = request({url: agencyServers[whoseTurn] + "/_api/agency/write", method: "POST",
followRedirects: true, body: JSON.stringify(list),
headers: {"Content-Type": "application/json"}});
headers: {"Content-Type": "application/json",
"x-arangodb-agency-mode": "waitForCommitted"}});
res.bodyParsed = JSON.parse(res.body);
wait(0.1);
return res;
}
@ -100,7 +103,7 @@ function agencyTestSuite () {
////////////////////////////////////////////////////////////////////////////////
testSingleTopLevel : function () {
wait(10);
wait(1);
assertEqual(readAndCheck([["/x"]]), [{}]);
writeAndCheck([[{x:12}]]);
assertEqual(readAndCheck([["/x"]]), [{x:12}]);

View File

@ -789,7 +789,8 @@ function processQuery (query, explain) {
};
var label = function (node) {
var label = function (node) {
var rc, v, e, edgeCols;
switch (node.type) {
case "SingletonNode":
return keyword("ROOT");
@ -832,7 +833,8 @@ function processQuery (query, explain) {
node.minMaxDepth = node.minDepth + ".." + node.maxDepth;
node.minMaxDepthLen = node.minMaxDepth.length;
var rc = keyword("FOR "), parts = [];
rc = keyword("FOR ");
var parts = [];
if (node.hasOwnProperty('vertexOutVariable')) {
parts.push(variableName(node.vertexOutVariable) + " " + annotation("/* vertex */"));
}
@ -876,9 +878,9 @@ function processQuery (query, explain) {
node.ConditionStr = buildSimpleExpression(node.simpleExpressions);
}
var e = [];
e = [];
if (node.hasOwnProperty('graphDefinition')) {
var v = [];
v = [];
node.graphDefinition.vertexCollectionNames.forEach(function(vcn) {
v.push(collection(vcn));
});
@ -892,7 +894,7 @@ function processQuery (query, explain) {
node.edgeCollectionNameStrLen = node.graphDefinition.edgeCollectionNames.join(", ").length;
}
else {
var edgeCols = node.graph || [ ];
edgeCols = node.graph || [ ];
edgeCols.forEach(function(ecn) {
e.push(collection(ecn));
});
@ -902,16 +904,15 @@ function processQuery (query, explain) {
}
return rc;
case "ShortestPathNode":
var rc = keyword("FOR "), parts = [];
if (node.hasOwnProperty('vertexOutVariable')) {
parts.push(variableName(node.vertexOutVariable) + " " + annotation("/* vertex */"));
}
if (node.hasOwnProperty('edgeOutVariable')) {
parts.push(variableName(node.edgeOutVariable) + " " + annotation("/* edge */"));
}
var translate = ["ANY", "INBOUND", "OUTBOUND"];
var defaultDirection = node.directions[0];
var rc = `${keyword("FOR")} ${parts.join(", ")} ${keyword("IN") } ${keyword(translate[defaultDirection])} `;
translate = ["ANY", "INBOUND", "OUTBOUND"];
defaultDirection = node.directions[0];
rc = `${keyword("FOR")} ${parts.join(", ")} ${keyword("IN") } ${keyword(translate[defaultDirection])} `;
if (node.hasOwnProperty("startVertexId")) {
rc += `'${value(node.startVertexId)}'`;
} else {
@ -941,9 +942,9 @@ function processQuery (query, explain) {
}
shortestPathDetails.push(node);
var e = [];
e = [];
if (node.hasOwnProperty('graphDefinition')) {
var v = [];
v = [];
node.graphDefinition.vertexCollectionNames.forEach(function(vcn) {
v.push(collection(vcn));
});
@ -957,7 +958,7 @@ function processQuery (query, explain) {
node.edgeCollectionNameStrLen = node.graphDefinition.edgeCollectionNames.join(", ").length;
}
else {
var edgeCols = node.graph || [ ];
edgeCols = node.graph || [ ];
edgeCols.forEach(function(ecn) {
e.push(collection(ecn));
});

File diff suppressed because it is too large Load Diff

View File

@ -67,7 +67,7 @@ function DatabaseSuite () {
////////////////////////////////////////////////////////////////////////////////
testVersion : function () {
assertMatch(/(^2\.[78])|(-devel$)/, internal.db._version());
assertMatch(/(^3\.[0])|(-devel$)/, internal.db._version());
},
////////////////////////////////////////////////////////////////////////////////

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*jshint globalstrict:false, strict:false, maxlen: 500 */
/*global assertEqual, assertTrue, fail */
/*global assertEqual, assertTrue */
////////////////////////////////////////////////////////////////////////////////
/// @brief tests for query language, graph functions

View File

@ -36,7 +36,6 @@ var helper = require("@arangodb/aql-helper");
var cluster = require("@arangodb/cluster");
var getQueryResults = helper.getQueryResults;
var getRawQueryResults = helper.getRawQueryResults;
var assertQueryError = helper.assertQueryError;
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite for graph features
@ -463,7 +462,7 @@ function ahuacatlQueryNeighborsTestSuite () {
var v7 = "UnitTestsAhuacatlVertex/v7";
var v8 = "UnitTestsAhuacatlVertex/v8";
var theFox = "UnitTestsAhuacatlVertex/thefox";
var queryStart = `FOR n IN ANY "`
var queryStart = `FOR n IN ANY "`;
var queryEnd = `" UnitTestsAhuacatlEdge OPTIONS {bfs: true, uniqueVertices: "global"} SORT n._id RETURN n._id`;
var queryEndData = `" UnitTestsAhuacatlEdge OPTIONS {bfs: true, uniqueVertices: "global"} SORT n RETURN n`;
@ -518,7 +517,7 @@ function ahuacatlQueryNeighborsTestSuite () {
var v8 = "UnitTestsAhuacatlVertex/v8";
var theFox = "UnitTestsAhuacatlVertex/thefox";
var queryStart = `FOR n IN INBOUND "`
var queryStart = `FOR n IN INBOUND "`;
var queryEnd = `" UnitTestsAhuacatlEdge OPTIONS {bfs: true, uniqueVertices: "global"} SORT n._id RETURN n._id`;
var queryEndData = `" UnitTestsAhuacatlEdge OPTIONS {bfs: true, uniqueVertices: "global"} SORT n RETURN n`;
@ -570,7 +569,7 @@ function ahuacatlQueryNeighborsTestSuite () {
var v7 = "UnitTestsAhuacatlVertex/v7";
var v8 = "UnitTestsAhuacatlVertex/v8";
var theFox = "UnitTestsAhuacatlVertex/thefox";
var queryStart = `FOR n IN OUTBOUND "`
var queryStart = `FOR n IN OUTBOUND "`;
var queryEnd = `" UnitTestsAhuacatlEdge OPTIONS {bfs: true, uniqueVertices: "global"} SORT n._id RETURN n._id`;
var queryEndData = `" UnitTestsAhuacatlEdge OPTIONS {bfs: true, uniqueVertices: "global"} SORT n RETURN n`;
@ -656,8 +655,6 @@ function ahuacatlQueryShortestPathTestSuite () {
var vertexCollection;
var edgeCollection;
var aqlfunctions = require("@arangodb/aql/functions");
return {
////////////////////////////////////////////////////////////////////////////////

View File

@ -510,6 +510,9 @@ def restheader(cargo, r=Regexen()):
(fp, last) = cargo
temp = parameters(last).split(',')
if temp == "":
raise Exception("Invalid restheader value. got empty string. Maybe missing closing bracket? " + path)
(ucmethod, path) = temp[0].split()
#TODO: hier checken, ob der letzte alles hatte (responses)
@ -528,7 +531,7 @@ def restheader(cargo, r=Regexen()):
raise Exception("Duplicate route")
if currentDocuBlock == None:
raise Exception("No docublock started for this restheader: " + ucmethod + " " + path )
raise Exception("No docublock started for this restheader: " + ucmethod + " " + path)
if lastDocuBlock != None and currentDocuBlock == lastDocuBlock:
raise Exception("No new docublock started for this restheader: " + ucmethod + " " + path + ' : ' + currentDocuBlock)