1
0
Fork 0

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

This commit is contained in:
Frank Celler 2013-01-17 10:30:48 +01:00
commit 632b9bc430
17 changed files with 479 additions and 226 deletions

View File

@ -685,7 +685,7 @@ v1.0.beta1 (2012-07-29)
- tcp://[host]:port or http@tcp://[host]:port (HTTP over IPv6)
- ssl://host:port or http@tcp://host:port (HTTP over SSL-encrypted IPv4)
- ssl://[host]:port or http@tcp://[host]:port (HTTP over SSL-encrypted IPv6)
- unix://path/to/socket or http@unix:///path/to/socket (HTTP over UNIX socket)
- unix:///path/to/socket or http@unix:///path/to/socket (HTTP over UNIX socket)
If no port is specified, the default port of 8529 will be used.

View File

@ -8,7 +8,3 @@ arango> db.five.all().toArray();
arango> db.five.all().limit(2).toArray();
[ { _id : 159896:1798296, _rev : 1798296, doc : 3 },
{ _id : 159896:1732760, _rev : 1732760, doc : 2 } ]
arango> db.five.all().limit(-2);
[ { _id : 159896:1667224, _rev : 1667224, doc : 1 },
{ _id : 159896:1929368, _rev : 1929368, doc : 5 } ]

View File

@ -253,7 +253,7 @@ following specification syntax:
- `tcp://[host]:port (HTTP over IPv6)`
- `ssl://host:port (HTTP over SSL-encrypted IPv4)`
- `ssl://[host]:port (HTTP over SSL-encrypted IPv6)`
- `unix://path/to/socket (HTTP over Unix domain socket)`
- `unix:///path/to/socket (HTTP over Unix domain socket)`
### TCP endpoints

View File

@ -105,7 +105,7 @@ following endpoint specification sytnax is currently supported:
- `tcp://[host]:port` (HTTP over IPv6)
- `ssl://host:port` (HTTP over SSL-encrypted IPv4)
- `ssl://[host]:port` (HTTP over SSL-encrypted IPv6)
- `unix://path/to/socket` (HTTP over UNIX socket)
- `unix:///path/to/socket` (HTTP over UNIX socket)
An example value for the option is `--server.endpoint
tcp://127.0.0.1:8529`. This will make the server listen to requests

View File

@ -207,6 +207,7 @@ SHELL_COMMON = @top_srcdir@/js/common/tests/shell-document.js \
@top_srcdir@/js/common/tests/shell-edge.js \
@top_srcdir@/js/common/tests/shell-database.js \
@top_srcdir@/js/common/tests/shell-collection.js \
@top_srcdir@/js/common/tests/shell-collection-volatile.js \
@top_srcdir@/js/common/tests/shell-compactor.js \
@top_srcdir@/js/common/tests/shell-graph-traversal.js \
@top_srcdir@/js/common/tests/shell-simple-query.js \

View File

@ -1031,6 +1031,7 @@ static v8::Handle<v8::Value> SaveEdgeCol (SingleCollectionWriteTransaction<Embed
const bool forceSync = ExtractForceSync(argv, 4);
TRI_document_edge_t edge;
// the following values are defaults that will be overridden below
edge._fromCid = trx->cid();
edge._toCid = trx->cid();
edge._fromKey = 0;
@ -6119,15 +6120,15 @@ v8::Handle<v8::Value> TRI_ParseDocumentOrDocumentHandle (TRI_vocbase_t* vocbase,
// use the collection
int res = TRI_UseCollectionVocBase(vocbase, col);
if (res == TRI_ERROR_NO_ERROR && col->_collection == 0) {
res = TRI_ERROR_INTERNAL;
}
if (res != TRI_ERROR_NO_ERROR) {
return scope.Close(TRI_CreateErrorObject(res, "cannot use/load collection", true));
}
}
if (col->_collection == 0) {
return scope.Close(TRI_CreateErrorObject(TRI_ERROR_INTERNAL, "cannot use/load collection"));
}
collection = col;
}

View File

@ -54,7 +54,7 @@
static void InitCollection (TRI_vocbase_t* vocbase,
TRI_collection_t* collection,
char* directory,
TRI_col_info_t* info) {
const TRI_col_info_t* const info) {
assert(collection);
memset(collection, 0, sizeof(TRI_collection_t));
@ -510,7 +510,7 @@ void TRI_InitCollectionInfo (TRI_vocbase_t* vocbase,
/// @brief copy a collection info block
////////////////////////////////////////////////////////////////////////////////
void TRI_CopyCollectionInfo (TRI_col_info_t* dst, TRI_col_info_t* src) {
void TRI_CopyCollectionInfo (TRI_col_info_t* dst, const TRI_col_info_t* const src) {
assert(dst);
memset(dst, 0, sizeof(TRI_col_info_t));
@ -545,6 +545,63 @@ void TRI_FreeCollectionInfoOptions (TRI_col_info_t* parameter) {
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get the full directory name for a collection
///
/// it is the caller's responsibility to check if the returned string is NULL
/// and to free it if not.
////////////////////////////////////////////////////////////////////////////////
char* TRI_GetDirectoryCollection (char const* path,
const TRI_col_info_t* const parameter) {
char* filename;
assert(path);
assert(parameter);
// shape collections use just the name, e.g. path/SHAPES
if (parameter->_type == TRI_COL_TYPE_SHAPE) {
filename = TRI_Concatenate2File(path, parameter->_name);
}
// other collections use the collection identifier
else if (TRI_IS_DOCUMENT_COLLECTION(parameter->_type)) {
char* tmp1;
char* tmp2;
tmp1 = TRI_StringUInt64(parameter->_cid);
if (tmp1 == NULL) {
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
return NULL;
}
tmp2 = TRI_Concatenate2String("collection-", tmp1);
if (tmp2 == NULL) {
TRI_FreeString(TRI_CORE_MEM_ZONE, tmp1);
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
return NULL;
}
filename = TRI_Concatenate2File(path, tmp2);
TRI_FreeString(TRI_CORE_MEM_ZONE, tmp1);
TRI_FreeString(TRI_CORE_MEM_ZONE, tmp2);
}
// oops, unknown collection type
else {
TRI_set_errno(TRI_ERROR_ARANGO_UNKNOWN_COLLECTION_TYPE);
return NULL;
}
if (filename == NULL) {
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
}
// might be NULL
return filename;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a new collection
////////////////////////////////////////////////////////////////////////////////
@ -552,9 +609,8 @@ void TRI_FreeCollectionInfoOptions (TRI_col_info_t* parameter) {
TRI_collection_t* TRI_CreateCollection (TRI_vocbase_t* vocbase,
TRI_collection_t* collection,
char const* path,
TRI_col_info_t* parameter) {
const TRI_col_info_t* const parameter) {
char* filename;
int res;
// sanity check
if (sizeof(TRI_df_header_marker_t) + sizeof(TRI_df_footer_marker_t) > parameter->_maximalSize) {
@ -576,58 +632,10 @@ TRI_collection_t* TRI_CreateCollection (TRI_vocbase_t* vocbase,
return NULL;
}
// shape collection use the name
if (parameter->_type == TRI_COL_TYPE_SHAPE) {
filename = TRI_Concatenate2File(path, parameter->_name);
if (filename == NULL) {
LOG_ERROR("cannot create collection '%s', out of memory", path);
return NULL;
}
}
// simple collection use the collection identifier
else if (TRI_IS_DOCUMENT_COLLECTION(parameter->_type)) {
char* tmp1;
char* tmp2;
tmp1 = TRI_StringUInt64(parameter->_cid);
if (tmp1 == NULL) {
LOG_ERROR("cannot create collection '%s', out of memory", path);
return NULL;
}
tmp2 = TRI_Concatenate2String("collection-", tmp1);
if (tmp2 == NULL) {
TRI_FreeString(TRI_CORE_MEM_ZONE, tmp1);
LOG_ERROR("cannot create collection '%s', out of memory", path);
return NULL;
}
filename = TRI_Concatenate2File(path, tmp2);
if (filename == NULL) {
TRI_FreeString(TRI_CORE_MEM_ZONE, tmp1);
TRI_FreeString(TRI_CORE_MEM_ZONE, tmp2);
LOG_ERROR("cannot create collection '%s', out of memory", path);
return NULL;
}
TRI_FreeString(TRI_CORE_MEM_ZONE, tmp2);
TRI_FreeString(TRI_CORE_MEM_ZONE, tmp1);
}
// uups
else {
TRI_set_errno(TRI_ERROR_ARANGO_UNKNOWN_COLLECTION_TYPE);
LOG_ERROR("cannot create collection '%s' in '%s': unknown type '%d'",
parameter->_name,
path,
(unsigned int) parameter->_type);
filename = TRI_GetDirectoryCollection(path, parameter);
if (filename == NULL) {
LOG_ERROR("cannot create collection '%s'", TRI_last_error());
return NULL;
}
@ -635,7 +643,7 @@ TRI_collection_t* TRI_CreateCollection (TRI_vocbase_t* vocbase,
if (TRI_ExistsFile(filename)) {
TRI_set_errno(TRI_ERROR_ARANGO_COLLECTION_DIRECTORY_ALREADY_EXISTS);
LOG_ERROR("cannot create collection '%s' in '%s', filename already exists",
LOG_ERROR("cannot create collection '%s' in '%s', directory already exists",
parameter->_name, filename);
TRI_FreeString(TRI_CORE_MEM_ZONE, filename);
@ -656,16 +664,6 @@ TRI_collection_t* TRI_CreateCollection (TRI_vocbase_t* vocbase,
return NULL;
}
// save the parameter block (within create, no need to lock)
res = TRI_SaveCollectionInfo(filename, parameter);
if (res != TRI_ERROR_NO_ERROR) {
LOG_ERROR("cannot save collection parameter '%s': '%s'", filename, TRI_last_error());
TRI_FreeString(TRI_CORE_MEM_ZONE, filename);
return NULL;
}
// create collection structure
if (collection == NULL) {
collection = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_collection_t), false);
@ -678,11 +676,12 @@ TRI_collection_t* TRI_CreateCollection (TRI_vocbase_t* vocbase,
}
}
// we are passing filename to this struct, so we must not free it if you use the struct later
InitCollection(vocbase, collection, filename, parameter);
/* PANAIA: 1) the parameter file if it exists must be removed
2) if collection
*/
// return collection
return collection;
}
@ -839,7 +838,7 @@ int TRI_LoadCollectionInfo (char const* path, TRI_col_info_t* parameter) {
/// function.
////////////////////////////////////////////////////////////////////////////////
int TRI_SaveCollectionInfo (char const* path, TRI_col_info_t* info) {
int TRI_SaveCollectionInfo (char const* path, const TRI_col_info_t* const info) {
TRI_json_t* json;
char* filename;
bool ok;

View File

@ -283,7 +283,7 @@ void TRI_InitCollectionInfo (TRI_vocbase_t*,
/// @brief copy a collection info block
////////////////////////////////////////////////////////////////////////////////
void TRI_CopyCollectionInfo (TRI_col_info_t*, TRI_col_info_t*);
void TRI_CopyCollectionInfo (TRI_col_info_t*, const TRI_col_info_t* const);
////////////////////////////////////////////////////////////////////////////////
/// @brief free a collection info block
@ -291,6 +291,15 @@ void TRI_CopyCollectionInfo (TRI_col_info_t*, TRI_col_info_t*);
void TRI_FreeCollectionInfoOptions (TRI_col_info_t*);
////////////////////////////////////////////////////////////////////////////////
/// @brief get the full directory name for a collection
///
/// it is the caller's responsibility to check if the returned string is NULL
/// and to free it if not.
////////////////////////////////////////////////////////////////////////////////
char* TRI_GetDirectoryCollection (char const*, const TRI_col_info_t* const);
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a new collection
////////////////////////////////////////////////////////////////////////////////
@ -298,7 +307,7 @@ void TRI_FreeCollectionInfoOptions (TRI_col_info_t*);
TRI_collection_t* TRI_CreateCollection (TRI_vocbase_t*,
TRI_collection_t*,
char const*,
TRI_col_info_t*);
const TRI_col_info_t* const);
////////////////////////////////////////////////////////////////////////////////
/// @brief frees the memory allocated, but does not free the pointer
@ -337,7 +346,7 @@ int TRI_LoadCollectionInfo (char const*, TRI_col_info_t*);
/// @brief saves a parameter info block to file
////////////////////////////////////////////////////////////////////////////////
int TRI_SaveCollectionInfo (char const*, TRI_col_info_t*);
int TRI_SaveCollectionInfo (char const*, const TRI_col_info_t* const);
////////////////////////////////////////////////////////////////////////////////
/// @brief updates the parameter info block

View File

@ -1895,6 +1895,7 @@ TRI_document_collection_t* TRI_CreateDocumentCollection (TRI_vocbase_t* vocbase,
TRI_collection_t* collection;
TRI_shaper_t* shaper;
TRI_document_collection_t* document;
int res;
bool waitForSync;
bool isVolatile;
@ -1949,6 +1950,18 @@ TRI_document_collection_t* TRI_CreateDocumentCollection (TRI_vocbase_t* vocbase,
return NULL;
}
// save the parameter block (within create, no need to lock)
res = TRI_SaveCollectionInfo(collection->_directory, parameter);
if (res != TRI_ERROR_NO_ERROR) {
LOG_ERROR("cannot save collection parameters in directory '%s': '%s'", collection->_directory, TRI_last_error());
TRI_CloseCollection(collection);
TRI_FreeCollection(collection); // will free document
return NULL;
}
return document;
}

View File

@ -920,6 +920,7 @@ TRI_shaper_t* TRI_CreateVocShaper (TRI_vocbase_t* vocbase,
voc_shaper_t* shaper;
TRI_shape_collection_t* collection;
TRI_col_info_t parameter;
int res;
bool ok;
TRI_InitCollectionInfo(vocbase, &parameter, name, TRI_COL_TYPE_SHAPE, SHAPER_DATAFILE_SIZE, 0);
@ -951,6 +952,13 @@ TRI_shaper_t* TRI_CreateVocShaper (TRI_vocbase_t* vocbase,
TRI_FreeVocShaper(&shaper->base);
return NULL;
}
res = TRI_SaveCollectionInfo(collection->base._directory, &parameter);
if (res != TRI_ERROR_NO_ERROR) {
LOG_ERROR("cannot save collection parameters in directory '%s': '%s'", collection->base._directory, TRI_last_error());
TRI_FreeVocShaper(&shaper->base);
return NULL;
}
// and return
return &shaper->base;

View File

@ -1452,7 +1452,6 @@ TRI_vocbase_col_t* TRI_CreateCollectionVocBase (TRI_vocbase_t* vocbase,
assert(parameter);
name = parameter->_name;
// check that the name does not contain any strange characters
if (! TRI_IsAllowedCollectionName(parameter->_isSystem, name)) {
TRI_set_errno(TRI_ERROR_ARANGO_ILLEGAL_NAME);
@ -1644,7 +1643,7 @@ int TRI_DropCollectionVocBase (TRI_vocbase_t* vocbase, TRI_vocbase_col_t* collec
}
// remove dangling .json.tmp file if it exists
tmpFile = TRI_Concatenate4String(collection->_path, "/", TRI_COL_PARAMETER_FILE, ".tmp");
tmpFile = TRI_Concatenate4String(collection->_path, TRI_DIR_SEPARATOR_STR, TRI_COL_PARAMETER_FILE, ".tmp");
if (tmpFile != NULL) {
if (TRI_ExistsFile(tmpFile)) {
TRI_UnlinkFile(tmpFile);

View File

@ -784,14 +784,15 @@ function IncludeMatchingAttributesFilter (config, vertex, path) {
////////////////////////////////////////////////////////////////////////////////
function CombineFilters (filters, config, vertex, path) {
var result = [];
var result = [ ];
filters.forEach( function (f) {
var tmp = f(config, vertex, path);
if (!Array.isArray(tmp)) {
tmp = [tmp];
if (! Array.isArray(tmp)) {
tmp = [ tmp ];
}
result = result.concat(tmp);
});
return result;
}

View File

@ -0,0 +1,188 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief test the collection interface w/ volatile collections
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2012 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 triAGENS GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var jsunity = require("jsunity");
var internal = require("internal");
// -----------------------------------------------------------------------------
// --SECTION-- collection methods
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- volatile collections
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite: volatile collections
////////////////////////////////////////////////////////////////////////////////
function CollectionVolatileSuite () {
var ERRORS = require("internal").errors;
var cn = "UnittestsVolatileCollection";
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
setUp : function () {
internal.db._drop(cn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
tearDown : function () {
internal.db._drop(cn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief create a volatile collection
////////////////////////////////////////////////////////////////////////////////
testCreation1 : function () {
var c = internal.db._create(cn, { isVolatile : true, waitForSync : false });
assertEqual(cn, c.name());
assertEqual(true, c.properties().isVolatile);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief create a volatile collection
////////////////////////////////////////////////////////////////////////////////
testCreation2 : function () {
var c = internal.db._create(cn, { isVolatile : true });
assertEqual(cn, c.name());
assertEqual(true, c.properties().isVolatile);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief create w/ error
////////////////////////////////////////////////////////////////////////////////
testCreationError : function () {
try {
// cannot set isVolatile and waitForSync at the same time
var c = internal.db._create(cn, { isVolatile : true, waitForSync : true });
fail();
}
catch (err) {
assertEqual(ERRORS.ERROR_BAD_PARAMETER.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test property change
////////////////////////////////////////////////////////////////////////////////
testPropertyChange : function () {
var c = internal.db._create(cn, { isVolatile : true, waitForSync : false });
try {
// cannot set isVolatile and waitForSync at the same time
c.properties({ waitForSync : true });
fail();
}
catch (err) {
assertEqual(ERRORS.ERROR_BAD_PARAMETER.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief load/unload
////////////////////////////////////////////////////////////////////////////////
testLoadUnload : function () {
var c = internal.db._create(cn, { isVolatile : true });
assertEqual(cn, c.name());
assertEqual(true, c.properties().isVolatile);
c.unload();
internal.wait(4);
assertEqual(true, c.properties().isVolatile);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief data storage
////////////////////////////////////////////////////////////////////////////////
testStorage : function () {
var c = internal.db._create(cn, { isVolatile : true });
assertEqual(true, c.properties().isVolatile);
c.save({"test": true});
assertEqual(1, c.count());
c.unload();
internal.wait(4);
assertEqual(true, c.properties().isVolatile);
assertEqual(0, c.count());
},
////////////////////////////////////////////////////////////////////////////////
/// @brief data storage
////////////////////////////////////////////////////////////////////////////////
testStorageMany : function () {
var c = internal.db._create(cn, { isVolatile : true, journalSize: 1024 * 1024 });
assertEqual(true, c.properties().isVolatile);
for (var i = 0; i < 10000; ++i) {
c.save({"test": true, "foo" : "bar"});
}
assertEqual(10000, c.count());
c.unload();
internal.wait(4);
assertEqual(true, c.properties().isVolatile);
assertEqual(0, c.count());
}
};
}
// -----------------------------------------------------------------------------
// --SECTION-- main
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suites
////////////////////////////////////////////////////////////////////////////////
jsunity.run(CollectionVolatileSuite);
return jsunity.done();
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:

View File

@ -776,143 +776,6 @@ function CollectionSuite () {
};
}
// -----------------------------------------------------------------------------
// --SECTION-- volatile collections
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite: volatile collections
////////////////////////////////////////////////////////////////////////////////
function CollectionVolatileSuite () {
var ERRORS = require("internal").errors;
var cn = "UnittestsVolatileCollection";
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
setUp : function () {
internal.db._drop(cn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
tearDown : function () {
internal.db._drop(cn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief create a volatile collection
////////////////////////////////////////////////////////////////////////////////
testCreation1 : function () {
var c = internal.db._create(cn, { isVolatile : true, waitForSync : false });
assertEqual(cn, c.name());
assertEqual(true, c.properties().isVolatile);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief create a volatile collection
////////////////////////////////////////////////////////////////////////////////
testCreation2 : function () {
var c = internal.db._create(cn, { isVolatile : true });
assertEqual(cn, c.name());
assertEqual(true, c.properties().isVolatile);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief create w/ error
////////////////////////////////////////////////////////////////////////////////
testCreationError : function () {
try {
// cannot set isVolatile and waitForSync at the same time
var c = internal.db._create(cn, { isVolatile : true, waitForSync : true });
fail();
}
catch (err) {
assertEqual(ERRORS.ERROR_BAD_PARAMETER.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test property change
////////////////////////////////////////////////////////////////////////////////
testPropertyChange : function () {
var c = internal.db._create(cn, { isVolatile : true, waitForSync : false });
try {
// cannot set isVolatile and waitForSync at the same time
c.properties({ waitForSync : true });
fail();
}
catch (err) {
assertEqual(ERRORS.ERROR_BAD_PARAMETER.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief load/unload
////////////////////////////////////////////////////////////////////////////////
testLoadUnload : function () {
var c = internal.db._create(cn, { isVolatile : true });
assertEqual(cn, c.name());
assertEqual(true, c.properties().isVolatile);
c.unload();
internal.wait(4);
assertEqual(true, c.properties().isVolatile);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief data storage
////////////////////////////////////////////////////////////////////////////////
testStorage : function () {
var c = internal.db._create(cn, { isVolatile : true });
assertEqual(true, c.properties().isVolatile);
c.save({"test": true});
assertEqual(1, c.count());
c.unload();
internal.wait(4);
assertEqual(true, c.properties().isVolatile);
assertEqual(0, c.count());
},
////////////////////////////////////////////////////////////////////////////////
/// @brief data storage
////////////////////////////////////////////////////////////////////////////////
testStorageMany : function () {
var c = internal.db._create(cn, { isVolatile : true, journalSize: 1024 * 1024 });
assertEqual(true, c.properties().isVolatile);
for (var i = 0; i < 10000; ++i) {
c.save({"test": true, "foo" : "bar"});
}
assertEqual(10000, c.count());
c.unload();
internal.wait(4);
assertEqual(true, c.properties().isVolatile);
assertEqual(0, c.count());
}
};
}
// -----------------------------------------------------------------------------
// --SECTION-- vocbase methods
// -----------------------------------------------------------------------------
@ -1134,7 +997,6 @@ function CollectionDbSuite () {
jsunity.run(CollectionSuiteErrorHandling);
jsunity.run(CollectionSuite);
jsunity.run(CollectionVolatileSuite);
jsunity.run(CollectionDbSuite);
return jsunity.done();

View File

@ -160,6 +160,125 @@ function CollectionEdgeSuite () {
internal.wait(0.0);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief create an edge referring to a vertex documents by keys
////////////////////////////////////////////////////////////////////////////////
testSaveEdgeKeys : function () {
var k1 = vertex.save({ _key: "vx1", vx: 1 });
var k2 = vertex.save({ _key: "vx2", vx: 2 });
var k3 = vertex.save({ _key: "vx3", vx: 3 });
var d1 = vertex.document(k1._key);
assertEqual("vx1", k1._key);
assertEqual(vn + "/vx1", k1._id);
assertEqual("vx1", d1._key);
assertEqual(1, d1.vx);
assertEqual(vn + "/vx1", d1._id);
var d2 = vertex.document(k2._key);
assertEqual("vx2", k2._key);
assertEqual(vn + "/vx2", k2._id);
assertEqual("vx2", d2._key);
assertEqual(2, d2.vx);
assertEqual(vn + "/vx2", d2._id);
var d3 = vertex.document(vn + "/vx3");
assertEqual("vx3", k3._key);
assertEqual(vn + "/vx3", k3._id);
assertEqual("vx3", d3._key);
assertEqual(3, d3.vx);
assertEqual(vn + "/vx3", d3._id);
var e1 = edge.save(vn + "/vx1", vn + "/vx2", { _key: "ex1", connect: "vx1->vx2" });
var e2 = edge.save(vn + "/vx2", vn + "/vx1", { _key: "ex2", connect: "vx2->vx1" });
var e3 = edge.save(vn + "/vx3", vn + "/vx1", { _key: "ex3", connect: "vx3->vx1" });
d1 = edge.document("ex1");
assertEqual("ex1", d1._key);
assertEqual(en + "/ex1", d1._id);
assertEqual(vn + "/vx1", d1._from);
assertEqual(vn + "/vx2", d1._to);
assertEqual("vx1->vx2", d1.connect);
assertEqual("ex1", e1._key);
assertEqual(en + "/ex1", e1._id);
d2 = edge.document("ex2");
assertEqual("ex2", d2._key);
assertEqual(en + "/ex2", d2._id);
assertEqual(vn + "/vx2", d2._from);
assertEqual(vn + "/vx1", d2._to);
assertEqual("vx2->vx1", d2.connect);
assertEqual("ex2", e2._key);
assertEqual(en + "/ex2", e2._id);
d3 = edge.document(en + "/ex3");
assertEqual("ex3", d3._key);
assertEqual(en + "/ex3", d3._id);
assertEqual(vn + "/vx3", d3._from);
assertEqual(vn + "/vx1", d3._to);
assertEqual("vx3->vx1", d3.connect);
assertEqual("ex3", e3._key);
assertEqual(en + "/ex3", e3._id);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief create an edge referring to an unloaded vertex collection
////////////////////////////////////////////////////////////////////////////////
testSaveEdgeUnloaded : function () {
var k1 = vertex.save({ _key: "vx1", vx: 1 });
var k2 = vertex.save({ _key: "vx2", vx: 2 });
assertEqual("vx1", k1._key);
assertEqual(vn + "/vx1", k1._id);
assertEqual("vx2", k2._key);
assertEqual(vn + "/vx2", k2._id);
vertex.unload();
edge.unload();
console.log("waiting for collections to unload");
internal.wait(4);
var e1 = edge.save(vn + "/vx1", vn + "/vx2", { _key: "ex1", connect: "vx1->vx2" });
var e2 = edge.save(vn + "/vx2", vn + "/vx1", { _key: "ex2", connect: "vx2->vx1" });
vertex.unload();
edge.unload();
console.log("waiting for collections to unload");
internal.wait(4);
var e3 = edge.save(k1, k2, { _key: "ex3", connect: "vx1->vx2" });
d1 = edge.document("ex1");
assertEqual("ex1", d1._key);
assertEqual(en + "/ex1", d1._id);
assertEqual(vn + "/vx1", d1._from);
assertEqual(vn + "/vx2", d1._to);
assertEqual("vx1->vx2", d1.connect);
assertEqual("ex1", e1._key);
assertEqual(en + "/ex1", e1._id);
d2 = edge.document("ex2");
assertEqual("ex2", d2._key);
assertEqual(en + "/ex2", d2._id);
assertEqual(vn + "/vx2", d2._from);
assertEqual(vn + "/vx1", d2._to);
assertEqual("vx2->vx1", d2.connect);
assertEqual("ex2", e2._key);
assertEqual(en + "/ex2", e2._id);
d3 = edge.document("ex3");
assertEqual("ex3", d3._key);
assertEqual(en + "/ex3", d3._id);
assertEqual(vn + "/vx1", d3._from);
assertEqual(vn + "/vx2", d3._to);
assertEqual("vx1->vx2", d3.connect);
assertEqual("ex3", e3._key);
assertEqual(en + "/ex3", e3._id);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief create an edge
////////////////////////////////////////////////////////////////////////////////

View File

@ -2347,6 +2347,23 @@ function AHUACATL_GRAPH_TRAVERSE () {
AHUACATL_THROW(internal.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "TRAVERSE");
}
if (params.maxDepth <= 0) {
// we need to have at least SOME limit to prevent endless iteration
params.maxDepth = 1024;
}
// prepare an array of filters
var filter = [ ];
if (params.minDepth != undefined) {
filter.push(traversal.MinDepthFilter);
}
if (params.maxDepth != undefined) {
filter.push(traversal.MaxDepthFilter);
}
if (filter.length == 0) {
filter.push(traversal.VisitAllFilter);
}
var config = {
datasource: traversal.CollectionDatasourceFactory(edgeCollection),
strategy: validate(params.strategy, {
@ -2364,7 +2381,7 @@ function AHUACATL_GRAPH_TRAVERSE () {
trackPaths: params.paths || false,
visitor: AHUACATL_TRAVERSE_VISITOR,
maxDepth: params.maxDepth,
filter: params.maxDepth != undefined ? traversal.MaxDepthFilter : traversal.VisitAllFilter,
filter: filter,
uniqueness: {
vertices: validate(params.uniqueness && params.uniqueness.vertices, {
'none': traversal.Traverser.UNIQUE_NONE,

View File

@ -330,6 +330,27 @@ function ahuacatlQueryTraverseTestSuite () {
db._drop(en);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test min-depth filtering
////////////////////////////////////////////////////////////////////////////////
testTraversalDepthFirstMin : function () {
var config = {
strategy: "depthfirst",
order: "preorder",
itemOrder: "forward",
minDepth: 1,
uniqueness: {
vertices: "global"
},
_sort: true
};
var actual = executeQuery("FOR p IN TRAVERSE(@@v, @@e, '" + vn + "/A', 'outbound', " + JSON.stringify(config) + ") RETURN p.vertex._key", { "@v" : vn, "@e" : en }).getRows();
assertEqual([ "A", "B", "C", "D" ], actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test max-depth filtering
////////////////////////////////////////////////////////////////////////////////
@ -366,6 +387,25 @@ function ahuacatlQueryTraverseTestSuite () {
assertEqual([ "A", "B", "C", "A", "D", "C", "A" ], actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test min-/max-depth filtering
////////////////////////////////////////////////////////////////////////////////
testTraversalDepthFirstMinMax : function () {
var config = {
strategy: "depthfirst",
order: "preorder",
itemOrder: "forward",
minDepth: 1,
maxDepth: 3,
_sort: true
};
var actual = executeQuery("FOR p IN TRAVERSE(@@v, @@e, '" + vn + "/A', 'outbound', " + JSON.stringify(config) + ") RETURN p.vertex._key", { "@v" : vn, "@e" : en }).getRows();
assertEqual([ "A", "B", "C", "A", "D", "C", "A" ], actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test max-depth filtering
////////////////////////////////////////////////////////////////////////////////