1
0
Fork 0

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

This commit is contained in:
Max Neunhoeffer 2014-02-26 13:58:26 +01:00
commit c1ac5eeecf
13 changed files with 783 additions and 496 deletions

View File

@ -358,6 +358,7 @@ SHELL_COMMON = \
@top_srcdir@/js/common/tests/shell-collection.js \
@top_srcdir@/js/common/tests/shell-collection-volatile.js \
@top_srcdir@/js/common/tests/shell-crypto.js \
@top_srcdir@/js/common/tests/shell-noncluster-collection.js \
@top_srcdir@/js/common/tests/shell-noncluster-database.js \
@top_srcdir@/js/common/tests/shell-document.js \
@top_srcdir@/js/common/tests/shell-download.js \

View File

@ -2298,11 +2298,20 @@ template<bool WR, bool WD> static bool ChecksumCalculator (TRI_doc_mptr_t const*
/// If the optional argument @FA{withData} is set to @LIT{true}, then the
/// actual document data is also checksummed. Including the document data in
/// checksumming will make the calculation slower, but is more accurate.
///
/// Note: this method is not available in a cluster.
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> JS_ChecksumCollection (v8::Arguments const& argv) {
v8::HandleScope scope;
#ifdef TRI_ENABLE_CLUSTER
if (ServerState::instance()->isCoordinator()) {
// renaming a collection in a cluster is unsupported
TRI_V8_EXCEPTION(scope, TRI_ERROR_CLUSTER_UNSUPPORTED);
}
#endif
TRI_vocbase_col_t const* col;
col = TRI_UnwrapClass<TRI_vocbase_col_t>(argv.Holder(), TRI_GetVocBaseColType());

View File

@ -7204,6 +7204,8 @@ static v8::Handle<v8::Value> JS_RemoveVocbaseCol (v8::Arguments const& argv) {
///
/// If renaming fails for any reason, an error is thrown.
///
/// Note: this method is not available in a cluster.
///
/// @EXAMPLES
///
/// @verbinclude shell_collection-rename
@ -7216,7 +7218,14 @@ static v8::Handle<v8::Value> JS_RenameVocbaseCol (v8::Arguments const& argv) {
TRI_V8_EXCEPTION_USAGE(scope, "rename(<name>)");
}
string name = TRI_ObjectToString(argv[0]);
#ifdef TRI_ENABLE_CLUSTER
if (ServerState::instance()->isCoordinator()) {
// renaming a collection in a cluster is unsupported
TRI_V8_EXCEPTION(scope, TRI_ERROR_CLUSTER_UNSUPPORTED);
}
#endif
string const name = TRI_ObjectToString(argv[0]);
// second parameter "override" is to override renaming restrictions, e.g.
// renaming from a system collection name to a non-system collection name and
@ -7417,11 +7426,20 @@ static v8::Handle<v8::Value> JS_RevisionVocbaseCol (v8::Arguments const& argv) {
/// read-only datafile). The purpose of the rotation is to include the
/// datafile in a following compaction run and perform earlier garbage
/// collection.
///
/// Note: this method is not available in a cluster.
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> JS_RotateVocbaseCol (v8::Arguments const& argv) {
v8::HandleScope scope;
#ifdef TRI_ENABLE_CLUSTER
if (ServerState::instance()->isCoordinator()) {
// renaming a collection in a cluster is unsupported
TRI_V8_EXCEPTION(scope, TRI_ERROR_CLUSTER_UNSUPPORTED);
}
#endif
v8::Handle<v8::Object> err;
TRI_vocbase_col_t const* collection = UseCollection(argv.Holder(), &err);

View File

@ -750,6 +750,8 @@ function get_api_collections (req, res) {
///
/// - `revision`: The collection revision id as a string.
///
/// Note: this method is not available in a cluster.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{400}
@ -1301,6 +1303,8 @@ function put_api_collection_rename (req, res, collection) {
///
/// - `result`: will be `true` if rotation succeeded
///
/// Note: this method is not available in a cluster.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{400}

View File

@ -311,6 +311,8 @@ function get_api_index (req, res) {
/// `ignoreNull` is true, then documents with a null in `location` or at
/// least one null in `latitude` or `longitude` are ignored.
///
/// Note: unique indexes on non-shard keys are not supported in a cluster.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{200}
@ -386,6 +388,8 @@ function get_api_index (req, res) {
///
/// - `unique`: If `true`, then create a unique index.
///
/// Note: unique indexes on non-shard keys are not supported in a cluster.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{200}
@ -466,6 +470,8 @@ function get_api_index (req, res) {
///
/// - `unique`: If `true`, then create a unique index.
///
/// Note: unique indexes on non-shard keys are not supported in a cluster.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{200}
@ -674,6 +680,9 @@ function get_api_index (req, res) {
/// - fulltext indexes
/// - bitarray indexes
///
/// Note also that unique indexes on non-shard keys are not supported in a
/// cluster.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{200}

View File

@ -318,6 +318,7 @@ ArangoCollection.prototype.properties = function (properties) {
var attributes = {
"doCompact": true,
"journalSize": true,
"isVolatile": false,
"waitForSync": true,
"shardKeys": false,
"numberOfShards": false,
@ -350,15 +351,13 @@ ArangoCollection.prototype.properties = function (properties) {
var result = { };
for (a in attributes) {
if (attributes.hasOwnProperty(a) && requestResult.hasOwnProperty(a)) {
if (attributes.hasOwnProperty(a) &&
requestResult.hasOwnProperty(a) &&
requestResult[a] !== undefined) {
result[a] = requestResult[a];
}
}
if (requestResult.keyOptions !== undefined) {
result.keyOptions = requestResult.keyOptions;
}
return result;
};

View File

@ -1,6 +1,70 @@
.scenarioImage{
@extend %clickable;
height : 70%;
width : auto;
.machineClass {
@extend %clear-float;
padding: 10px;
float: left;
background-color: #E1E1E1;
width: 311px;
height: 175px;
margin-left: 8px;
}
.scenarioBox {
position: absolute;
margin-top: 10px;
width: auto;
height: 65px;
left: 10px;
right: 10px;
@include border-radius(3px 3px 0 0);
border: 1px solid rgba(0, 0, 0, 0.19);
background-color: white;
&.bottomBox {
bottom: 10px;
}
}
.scenarioBoxHeader {
width: auto;
height: 5px;
line-height: 5px;
text-align: right;
margin-top: -5px;
padding-bottom: 5px;
border-bottom: 1px solid rgba(0, 0, 0, 0.19);
}
.scenarioBoxText {
width: auto;
font-size: 30px;
font-weight: 700;
text-align: center;
margin-top: 17px;
}
.scenarioMachine {
@extend %pull-left;
position: relative;
margin-right: 20px;
height: 177px;
width: 87px;
@include border-radius(3px 3px 0 0);
border: 1px solid rgba(0, 0, 0, 0.19);
background-color: white;
&:last-child {
margin-right: 0px;
}
}
.scenarioSingleMachine {
@extend %clear-float;
border-radius: 3px 3px 0 0;
border: 1px solid rgba(0, 0, 0, 0.19);
background-color: white;
.scenarioMachine {
border: 1px solid transparent;
}
}

View File

@ -3,13 +3,13 @@ body, input, textarea, .page-title span, .pingback a.url {
font-family: 'Open Sans', sans-serif !important;
font-weight: 400; }
ul.link-dropdown-menu, ul.user-dropdown-menu, ul.gv-dropdown-menu, div.navlogo, ul.navlist li, div.footer-left, li.tile, li.bigtile, li.tile a span.add-Icon, li.bigtile a span.add-Icon {
ul.link-dropdown-menu, ul.user-dropdown-menu, ul.gv-dropdown-menu, div.navlogo, ul.navlist li, div.footer-left, li.tile, li.bigtile, li.tile a span.add-Icon, li.bigtile a span.add-Icon, .scenarioMachine {
float: left; }
div.navmenu, div.footer-right, li.tile div.iconSet span, li.bigtile div.iconSet span {
float: right; }
ul.tileList:after, div.resizecontainer:after {
ul.tileList:after, div.resizecontainer:after, .machineClass:after, .scenarioSingleMachine:after {
clear: both;
content: ".";
display: block;
@ -17,7 +17,7 @@ ul.tileList:after, div.resizecontainer:after {
height: 0px;
visibility: hidden; }
.addButton, .deleteButton, a.headerButton, div.toolbox > div.gv_action_button, li.tile div.iconSet span, li.bigtile div.iconSet span, .contentDiv .icon, div.headerDropdown.headerDropdown input[type=checkbox].css-checkbox + label.css-label, .scenarioImage {
.addButton, .deleteButton, a.headerButton, div.toolbox > div.gv_action_button, li.tile div.iconSet span, li.bigtile div.iconSet span, .contentDiv .icon, div.headerDropdown.headerDropdown input[type=checkbox].css-checkbox + label.css-label {
cursor: pointer; }
nav.navbar, footer.footer {
@ -780,6 +780,61 @@ select.filterSelect {
margin-top: 1px;
margin-left: 10px !important; }
.scenarioImage {
height: 70%;
width: auto; }
.machineClass {
padding: 10px;
float: left;
background-color: #E1E1E1;
width: 311px;
height: 175px;
margin-left: 8px; }
.scenarioBox {
position: absolute;
margin-top: 10px;
width: auto;
height: 65px;
left: 10px;
right: 10px;
-moz-border-radius: 3px 3px 0 0;
-webkit-border-radius: 3px 3px 0 0;
border-radius: 3px 3px 0 0;
border: 1px solid rgba(0, 0, 0, 0.19);
background-color: white; }
.scenarioBox.bottomBox {
bottom: 10px; }
.scenarioBoxHeader {
width: auto;
height: 5px;
line-height: 5px;
text-align: right;
margin-top: -5px;
padding-bottom: 5px;
border-bottom: 1px solid rgba(0, 0, 0, 0.19); }
.scenarioBoxText {
width: auto;
font-size: 30px;
font-weight: 700;
text-align: center;
margin-top: 17px; }
.scenarioMachine {
position: relative;
margin-right: 20px;
height: 177px;
width: 87px;
-moz-border-radius: 3px 3px 0 0;
-webkit-border-radius: 3px 3px 0 0;
border-radius: 3px 3px 0 0;
border: 1px solid rgba(0, 0, 0, 0.19);
background-color: white; }
.scenarioMachine:last-child {
margin-right: 0px; }
.scenarioSingleMachine {
border-radius: 3px 3px 0 0;
border: 1px solid rgba(0, 0, 0, 0.19);
background-color: white; }
.scenarioSingleMachine .scenarioMachine {
border: 1px solid transparent; }

View File

@ -1,4 +1,4 @@
//shared
@import "shared";
// the images used in the planner
@import "plannerImages";
@import "plannerImages";

View File

@ -1,52 +1,96 @@
<script id="planScenarioSelector.ejs" type="text/template">
<ul class="thumbnails2">
<div class="headerBar">
<a class="arangoHeader">Cluster Management</a>
<div class="headerButtonBar pull-right">
<ul class="headerButtonList">
<li class="enabled">
<% var box = function(c, btm) { %>
<div class="scenarioBox<%=btm?' bottomBox':''%>">
<div class="scenarioBoxHeader">...</div>
<div class="scenarioBoxText"><%=c%></div>
</div>
<% }
var row = function(c, d, noHead) { %>
<div class="scenarioMachine">
<% if (!noHead) { %>
<div class="scenarioBoxHeader">...</div>
<% } %>
<%
if (c) {box("C");}
if (d) {box("D", true);}
%>
</div>
<%
}
%>
<ul class="thumbnails2">
<div class="headerBar">
<a class="arangoHeader">Cluster Management</a>
<div class="headerButtonBar pull-right">
<ul class="headerButtonList">
<li class="enabled">
<a id="importConnectInfo" class="headerButton">
<span class="icon_arangodb_youtube" title="Connect to Cluster"></span>
</a>
<a id="importRunInfo" class="headerButton">
<span class="icon_arangodb_export" title="Upload Cluster Information"></span>
</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
<div id="runinfoDropdownImport" class="dropdownImport">
<div class="queryline">
<input id="importRunInfoFile" name="importRunInfo" type="file" accept="application/json" />
<button id="confirmRunInfoImport" class="button-success btn-old-padding" style="float:right">
<img id="uploadIndicator" style="display: none;" src="img/ajax-loader.gif"/>Import Plan
</button>
<div id="runinfoDropdownImport" class="dropdownImport">
<div class="queryline">
<input id="importRunInfoFile" name="importRunInfo" type="file" accept="application/json" />
<button id="confirmRunInfoImport" class="button-success btn-old-padding" style="float:right">
<img id="uploadIndicator" style="display: none;" src="img/ajax-loader.gif"/>Import Plan
</button>
</div>
</div>
</div>
<div id="connectDropdownImport" class="dropdownImport">
<div class="queryline">
<input id="connectInfoFile" name="connectionInfo" type="file" accept="application/json" />
<button id="confirmConnectImport" class="button-success btn-old-padding" style="float:right">
<img id="connectIndicator" style="display: none;" src="img/ajax-loader.gif"/>Connect to Cluster
</button>
<div id="connectDropdownImport" class="dropdownImport">
<div class="queryline">
<input id="connectInfoFile" name="connectionInfo" type="file" accept="application/json" />
<button id="confirmConnectImport" class="button-success btn-old-padding" style="float:right">
<img id="connectIndicator" style="display: none;" src="img/ajax-loader.gif"/>Connect to Cluster
</button>
</div>
</div>
</div>
</ul>
</ul>
<div class="tileList">
<legend class="gv_inner">Please select a cluster scenario:</legend>
<div class="tileList">
<legend class="gv_inner">Please select a cluster scenario:</legend>
<li class="bigtile" id="multiServerSymmetrical">
<img src="img/multiMachineSym.png" class="scenarioImage" alt="">
<li class="bigtile" id="multiServerSymmetrical">
<div id="multiMachineSym" class="machineClass">
<%
row(true, true);
row(true, true);
row(true, true);
%>
</div>
<h5 class="collectionName">Multi Machine Symmetrical</h5>
</li>
<li class="bigtile" id="multiServerAsymmetrical">
<img src="img/multiMachineAsym.png" class="scenarioImage" alt="">
</li>
<li class="bigtile" id="multiServerAsymmetrical">
<div id="multiMachineAsym" class="machineClass">
<%
row(true, true);
row(false, true);
row(true, false);
%>
</div>
<h5 class="collectionName">Multi Machine Asymmetrical</h5>
</li>
<li class="bigtile" id="singleServer">
<img src="img/singleMachine.png" class="scenarioImage" alt="">
</li>
<li class="bigtile" id="singleServer">
<div id="singleMachine" class="machineClass">
<div class="scenarioSingleMachine">
<div class="scenarioBoxHeader">...</div>
<%
row(true, true, true);
row(true, true, true);
row(true, false, true);
%>
</div>
</div>
<h5 class="collectionName">Single Machine</h5>
</li>
</div>
</li>
</div>
</script>

View File

@ -317,6 +317,7 @@ ArangoCollection.prototype.properties = function (properties) {
var attributes = {
"doCompact": true,
"journalSize": true,
"isVolatile": false,
"waitForSync": true,
"shardKeys": false,
"numberOfShards": false,
@ -349,15 +350,13 @@ ArangoCollection.prototype.properties = function (properties) {
var result = { };
for (a in attributes) {
if (attributes.hasOwnProperty(a) && requestResult.hasOwnProperty(a)) {
if (attributes.hasOwnProperty(a) &&
requestResult.hasOwnProperty(a) &&
requestResult[a] !== undefined) {
result[a] = requestResult[a];
}
}
if (requestResult.keyOptions !== undefined) {
result.keyOptions = requestResult.keyOptions;
}
return result;
};

View File

@ -631,64 +631,6 @@ function CollectionSuite () {
db._drop(cn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief rotate
////////////////////////////////////////////////////////////////////////////////
testRotate : function () {
var cn = "example";
db._drop(cn);
var c1 = db._create(cn);
c1.save({ _key: "test1" });
var f = c1.figures();
assertEqual(0, f.datafiles.count);
c1.rotate();
// must wait so the synchroniser can catch up
require("internal").wait(5);
f = c1.figures();
assertEqual(1, f.datafiles.count);
c1.save({ _key: "test2" });
c1.rotate();
// must wait so the synchroniser can catch up
require("internal").wait(5);
f = c1.figures();
// we may have one or two datafiles, depending on the compaction
assertTrue(f.datafiles.count >= 1);
c1.unload();
db._drop(cn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief rotate w/o journal
////////////////////////////////////////////////////////////////////////////////
testRotateNoJournal : function () {
var cn = "example";
db._drop(cn);
var c1 = db._create(cn);
try {
c1.rotate();
fail();
}
catch (err) {
assertEqual(ERRORS.ERROR_ARANGO_NO_JOURNAL.code, err.errorNum);
}
db._drop(cn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief figures
////////////////////////////////////////////////////////////////////////////////
@ -784,329 +726,6 @@ function CollectionSuite () {
db._drop(cn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief rename loaded collection
////////////////////////////////////////////////////////////////////////////////
testRenameLoaded : function () {
var cn = "example";
var nn = "example2";
db._drop(cn);
db._drop(nn);
var c1 = db._create(cn);
c1.save({ a : 1 });
assertTypeOf("string", c1._id);
assertEqual(cn, c1.name());
assertTypeOf("number", c1.status());
assertEqual(ArangoCollection.TYPE_DOCUMENT, c1.type());
assertTypeOf("number", c1.type());
var id = c1._id;
c1.rename(nn);
assertEqual(id, c1._id);
assertEqual(nn, c1.name());
assertTypeOf("number", c1.status());
assertEqual(ArangoCollection.TYPE_DOCUMENT, c1.type());
assertTypeOf("number", c1.type());
var c2 = db._collection(cn);
assertEqual(null, c2);
db._drop(nn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief rename unloaded collection
////////////////////////////////////////////////////////////////////////////////
testRenameUnloaded : function () {
var cn = "example";
var nn = "example2";
db._drop(cn);
db._drop(nn);
var c1 = db._create(cn);
c1.save({ a : 1 });
c1.unload();
assertTypeOf("string", c1._id);
assertEqual(cn, c1.name());
assertTypeOf("number", c1.status());
assertEqual(ArangoCollection.TYPE_DOCUMENT, c1.type());
assertTypeOf("number", c1.type());
var id = c1._id;
c1.rename(nn);
assertEqual(id, c1._id);
assertEqual(nn, c1.name());
assertTypeOf("number", c1.status());
assertEqual(ArangoCollection.TYPE_DOCUMENT, c1.type());
assertTypeOf("number", c1.type());
var c2 = db._collection(cn);
assertEqual(null, c2);
db._drop(nn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief rename a collection to an already existing collection
////////////////////////////////////////////////////////////////////////////////
testRenameExisting : function () {
var cn1 = "example";
var cn2 = "example2";
db._drop(cn1);
db._drop(cn2);
var c1 = db._create(cn1);
db._create(cn2);
try {
c1.rename(cn2);
}
catch (err) {
assertEqual(ERRORS.ERROR_ARANGO_DUPLICATE_NAME.code, err.errorNum);
}
db._drop(cn1);
db._drop(cn2);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test checksum
////////////////////////////////////////////////////////////////////////////////
testChecksum : function () {
var cn = "example";
db._drop(cn);
var c1 = db._create(cn);
// empty collection, checksum should be 0
var r1 = c1.checksum(true);
assertTypeOf("string", r1.revision);
assertTrue(r1.revision !== "");
assertTrue(r1.revision.match(/^[0-9]+$/));
assertTypeOf("number", r1.checksum);
assertEqual(0, r1.checksum);
// inserting a doc, checksum should change
c1.save({ a : 1 });
var r2 = c1.checksum(true);
assertNotEqual(r1.revision, r2.revision);
assertTypeOf("string", r2.revision);
assertTrue(r2.revision !== "");
assertTrue(r2.revision.match(/^[0-9]+$/));
assertTypeOf("number", r2.checksum);
assertNotEqual(0, r2.checksum);
// inserting another doc, checksum should change
c1.save({ a : 2 });
var r3 = c1.checksum(true);
assertNotEqual(r1.revision, r3.revision);
assertNotEqual(r2.revision, r3.revision);
assertTypeOf("string", r3.revision);
assertTrue(r3.revision !== "");
assertTrue(r3.revision.match(/^[0-9]+$/));
assertTypeOf("number", r3.checksum);
assertNotEqual(0, r3.checksum);
assertNotEqual(r2.checksum, r3.checksum);
// test after unloading
c1.unload();
var r4 = c1.checksum(true);
assertTypeOf("string", r4.revision);
assertEqual(r3.revision, r4.revision);
assertTypeOf("number", r4.checksum);
assertNotEqual(0, r4.checksum);
assertEqual(r3.checksum, r4.checksum);
// test withData
var r5 = c1.checksum(true, true);
assertTypeOf("string", r5.revision);
assertEqual(r4.revision, r5.revision);
assertTypeOf("number", r5.checksum);
assertNotEqual(0, r5.checksum);
assertNotEqual(r4.checksum, r5.checksum);
// test after truncation
c1.truncate();
var r6 = c1.checksum(true);
assertTypeOf("string", r6.revision);
assertNotEqual(r4.revision, r6.revision);
assertNotEqual(r5.revision, r6.revision);
assertTypeOf("number", r6.checksum);
assertEqual(0, r6.checksum);
db._drop(cn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test checksum
////////////////////////////////////////////////////////////////////////////////
testChecksumEdge : function () {
var cn = "example";
var vn = "example2";
db._drop(cn);
db._drop(vn);
db._create(vn);
var c1 = db._createEdgeCollection(cn);
var r1 = c1.checksum(true);
assertTypeOf("string", r1.revision);
assertTrue(r1.revision !== "");
assertTrue(r1.revision.match(/^[0-9]+$/));
assertTypeOf("number", r1.checksum);
assertEqual(0, r1.checksum);
c1.save(vn + "/1", vn + "/2", { a : 1 });
var r2 = c1.checksum(true);
assertNotEqual(r1.revision, r2.revision);
assertTypeOf("string", r2.revision);
assertTrue(r2.revision !== "");
assertTrue(r2.revision.match(/^[0-9]+$/));
assertTypeOf("number", r2.checksum);
assertNotEqual(0, r2.checksum);
c1.save(vn + "/1", vn + "/2", { a : 2 });
var r3 = c1.checksum(true);
assertNotEqual(r1.revision, r3.revision);
assertNotEqual(r2.revision, r3.revision);
assertTypeOf("string", r3.revision);
assertTrue(r3.revision !== "");
assertTrue(r3.revision.match(/^[0-9]+$/));
assertTypeOf("number", r3.checksum);
assertNotEqual(0, r3.checksum);
assertNotEqual(r2.checksum, r3.checksum);
c1.unload();
var r4 = c1.checksum(true);
assertTypeOf("string", r4.revision);
assertEqual(r3.revision, r4.revision);
assertTypeOf("number", r4.checksum);
assertEqual(r3.checksum, r4.checksum);
// test withData
var r5 = c1.checksum(true, true);
assertTypeOf("string", r5.revision);
assertEqual(r4.revision, r5.revision);
assertTypeOf("number", r5.checksum);
assertNotEqual(0, r5.checksum);
assertNotEqual(r4.checksum, r5.checksum);
// test after truncation
c1.truncate();
var r6 = c1.checksum(true);
assertTypeOf("string", r6.revision);
assertNotEqual(r4.revision, r6.revision);
assertNotEqual(r5.revision, r6.revision);
assertTypeOf("number", r6.checksum);
assertEqual(0, r6.checksum);
db._drop(cn);
db._drop(vn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test checksum two different collections
////////////////////////////////////////////////////////////////////////////////
testChecksumDifferent : function () {
var cn1 = "example";
var cn2 = "example2";
db._drop(cn1);
db._drop(cn2);
var c1 = db._create(cn1);
var c2 = db._create(cn2);
// collections are empty, checksums are identical
var cs1 = c1.checksum().checksum;
var cs2 = c2.checksum().checksum;
assertEqual(cs1, cs2);
c1.save({ _key: "foobar", value: 123 });
c2.save({ _key: "foobar", value: 123 });
// keys are the same
cs1 = c1.checksum().checksum;
cs2 = c2.checksum().checksum;
assertEqual(cs1, cs2);
// data is the same
cs1 = c1.checksum(false, true).checksum;
cs2 = c2.checksum(false, true).checksum;
assertEqual(cs1, cs2);
// revisions are different
cs1 = c1.checksum(true, false).checksum;
cs2 = c2.checksum(true, false).checksum;
assertNotEqual(cs1, cs2);
// revisions are still different
cs1 = c1.checksum(true, true).checksum;
cs2 = c2.checksum(true, true).checksum;
assertNotEqual(cs1, cs2);
// update document in c1, keep data
c1.replace("foobar", { value: 123 });
// keys are still the same
cs1 = c1.checksum().checksum;
cs2 = c2.checksum().checksum;
assertEqual(cs1, cs2);
// data is still the same
cs1 = c1.checksum(false, true).checksum;
cs2 = c2.checksum(false, true).checksum;
assertEqual(cs1, cs2);
// revisions are still different
cs1 = c1.checksum(true, false).checksum;
cs2 = c2.checksum(true, false).checksum;
// update document in c1, changing data
c1.replace("foobar", { value: 124 });
// keys are still the same
cs1 = c1.checksum().checksum;
cs2 = c2.checksum().checksum;
assertEqual(cs1, cs2);
// data is not the same
cs1 = c1.checksum(false, true).checksum;
cs2 = c2.checksum(false, true).checksum;
assertNotEqual(cs1, cs2);
// revisions are still different
cs1 = c1.checksum(true, false).checksum;
cs2 = c2.checksum(true, false).checksum;
db._drop(cn1);
db._drop(cn2);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test revision id
////////////////////////////////////////////////////////////////////////////////
@ -1417,69 +1036,17 @@ function CollectionSuite () {
////////////////////////////////////////////////////////////////////////////////
testSystemSpecial : function () {
[ '_trx', '_users' ].forEach(function(cn) {
var c = db._collection(cn);
var cn = "_users";
var c = db._collection(cn);
// drop
try {
c.drop();
fail();
}
catch (err1) {
assertEqual(ERRORS.ERROR_FORBIDDEN.code, err1.errorNum);
}
// rename
var cn = "example";
db._drop(cn);
try {
c.rename(cn);
fail();
}
catch (err2) {
assertEqual(ERRORS.ERROR_FORBIDDEN.code, err2.errorNum);
}
// unload is allowed
c.unload();
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test special properties of replication collection
////////////////////////////////////////////////////////////////////////////////
testSpecialReplication : function () {
var repl = db._collection('_replication');
// drop is not allowed
// drop
try {
repl.drop();
c.drop();
fail();
}
catch (err1) {
assertEqual(ERRORS.ERROR_FORBIDDEN.code, err1.errorNum);
}
// rename is not allowed
try {
var cn = "example";
db._drop(cn);
repl.rename(cn);
}
catch (err2) {
assertEqual(ERRORS.ERROR_FORBIDDEN.code, err2.errorNum);
}
// unload is not allowed
try {
repl.unload();
}
catch (err3) {
assertEqual(ERRORS.ERROR_FORBIDDEN.code, err3.errorNum);
}
}
};

View File

@ -0,0 +1,518 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief test the collection interface
///
/// @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 Dr. Frank Celler
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var jsunity = require("jsunity");
var arangodb = require("org/arangodb");
var internal = require("internal");
var ArangoCollection = arangodb.ArangoCollection;
var db = arangodb.db;
var ERRORS = arangodb.errors;
// -----------------------------------------------------------------------------
// --SECTION-- collection methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite: collection
////////////////////////////////////////////////////////////////////////////////
function CollectionSuite () {
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief rotate
////////////////////////////////////////////////////////////////////////////////
testRotate : function () {
var cn = "example";
db._drop(cn);
var c1 = db._create(cn);
c1.save({ _key: "test1" });
var f = c1.figures();
assertEqual(0, f.datafiles.count);
c1.rotate();
// must wait so the synchroniser can catch up
require("internal").wait(5);
f = c1.figures();
assertEqual(1, f.datafiles.count);
c1.save({ _key: "test2" });
c1.rotate();
// must wait so the synchroniser can catch up
require("internal").wait(5);
f = c1.figures();
// we may have one or two datafiles, depending on the compaction
assertTrue(f.datafiles.count >= 1);
c1.unload();
db._drop(cn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief rotate w/o journal
////////////////////////////////////////////////////////////////////////////////
testRotateNoJournal : function () {
var cn = "example";
db._drop(cn);
var c1 = db._create(cn);
try {
c1.rotate();
fail();
}
catch (err) {
assertEqual(ERRORS.ERROR_ARANGO_NO_JOURNAL.code, err.errorNum);
}
db._drop(cn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief rename loaded collection
////////////////////////////////////////////////////////////////////////////////
testRenameLoaded : function () {
var cn = "example";
var nn = "example2";
db._drop(cn);
db._drop(nn);
var c1 = db._create(cn);
c1.save({ a : 1 });
assertTypeOf("string", c1._id);
assertEqual(cn, c1.name());
assertTypeOf("number", c1.status());
assertEqual(ArangoCollection.TYPE_DOCUMENT, c1.type());
assertTypeOf("number", c1.type());
var id = c1._id;
c1.rename(nn);
assertEqual(id, c1._id);
assertEqual(nn, c1.name());
assertTypeOf("number", c1.status());
assertEqual(ArangoCollection.TYPE_DOCUMENT, c1.type());
assertTypeOf("number", c1.type());
var c2 = db._collection(cn);
assertEqual(null, c2);
db._drop(nn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief rename unloaded collection
////////////////////////////////////////////////////////////////////////////////
testRenameUnloaded : function () {
var cn = "example";
var nn = "example2";
db._drop(cn);
db._drop(nn);
var c1 = db._create(cn);
c1.save({ a : 1 });
c1.unload();
assertTypeOf("string", c1._id);
assertEqual(cn, c1.name());
assertTypeOf("number", c1.status());
assertEqual(ArangoCollection.TYPE_DOCUMENT, c1.type());
assertTypeOf("number", c1.type());
var id = c1._id;
c1.rename(nn);
assertEqual(id, c1._id);
assertEqual(nn, c1.name());
assertTypeOf("number", c1.status());
assertEqual(ArangoCollection.TYPE_DOCUMENT, c1.type());
assertTypeOf("number", c1.type());
var c2 = db._collection(cn);
assertEqual(null, c2);
db._drop(nn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief rename a collection to an already existing collection
////////////////////////////////////////////////////////////////////////////////
testRenameExisting : function () {
var cn1 = "example";
var cn2 = "example2";
db._drop(cn1);
db._drop(cn2);
var c1 = db._create(cn1);
db._create(cn2);
try {
c1.rename(cn2);
}
catch (err) {
assertEqual(ERRORS.ERROR_ARANGO_DUPLICATE_NAME.code, err.errorNum);
}
db._drop(cn1);
db._drop(cn2);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test checksum
////////////////////////////////////////////////////////////////////////////////
testChecksum : function () {
var cn = "example";
db._drop(cn);
var c1 = db._create(cn);
// empty collection, checksum should be 0
var r1 = c1.checksum(true);
assertTypeOf("string", r1.revision);
assertTrue(r1.revision !== "");
assertTrue(r1.revision.match(/^[0-9]+$/));
assertTypeOf("number", r1.checksum);
assertEqual(0, r1.checksum);
// inserting a doc, checksum should change
c1.save({ a : 1 });
var r2 = c1.checksum(true);
assertNotEqual(r1.revision, r2.revision);
assertTypeOf("string", r2.revision);
assertTrue(r2.revision !== "");
assertTrue(r2.revision.match(/^[0-9]+$/));
assertTypeOf("number", r2.checksum);
assertNotEqual(0, r2.checksum);
// inserting another doc, checksum should change
c1.save({ a : 2 });
var r3 = c1.checksum(true);
assertNotEqual(r1.revision, r3.revision);
assertNotEqual(r2.revision, r3.revision);
assertTypeOf("string", r3.revision);
assertTrue(r3.revision !== "");
assertTrue(r3.revision.match(/^[0-9]+$/));
assertTypeOf("number", r3.checksum);
assertNotEqual(0, r3.checksum);
assertNotEqual(r2.checksum, r3.checksum);
// test after unloading
c1.unload();
var r4 = c1.checksum(true);
assertTypeOf("string", r4.revision);
assertEqual(r3.revision, r4.revision);
assertTypeOf("number", r4.checksum);
assertNotEqual(0, r4.checksum);
assertEqual(r3.checksum, r4.checksum);
// test withData
var r5 = c1.checksum(true, true);
assertTypeOf("string", r5.revision);
assertEqual(r4.revision, r5.revision);
assertTypeOf("number", r5.checksum);
assertNotEqual(0, r5.checksum);
assertNotEqual(r4.checksum, r5.checksum);
// test after truncation
c1.truncate();
var r6 = c1.checksum(true);
assertTypeOf("string", r6.revision);
assertNotEqual(r4.revision, r6.revision);
assertNotEqual(r5.revision, r6.revision);
assertTypeOf("number", r6.checksum);
assertEqual(0, r6.checksum);
db._drop(cn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test checksum
////////////////////////////////////////////////////////////////////////////////
testChecksumEdge : function () {
var cn = "example";
var vn = "example2";
db._drop(cn);
db._drop(vn);
db._create(vn);
var c1 = db._createEdgeCollection(cn);
var r1 = c1.checksum(true);
assertTypeOf("string", r1.revision);
assertTrue(r1.revision !== "");
assertTrue(r1.revision.match(/^[0-9]+$/));
assertTypeOf("number", r1.checksum);
assertEqual(0, r1.checksum);
c1.save(vn + "/1", vn + "/2", { a : 1 });
var r2 = c1.checksum(true);
assertNotEqual(r1.revision, r2.revision);
assertTypeOf("string", r2.revision);
assertTrue(r2.revision !== "");
assertTrue(r2.revision.match(/^[0-9]+$/));
assertTypeOf("number", r2.checksum);
assertNotEqual(0, r2.checksum);
c1.save(vn + "/1", vn + "/2", { a : 2 });
var r3 = c1.checksum(true);
assertNotEqual(r1.revision, r3.revision);
assertNotEqual(r2.revision, r3.revision);
assertTypeOf("string", r3.revision);
assertTrue(r3.revision !== "");
assertTrue(r3.revision.match(/^[0-9]+$/));
assertTypeOf("number", r3.checksum);
assertNotEqual(0, r3.checksum);
assertNotEqual(r2.checksum, r3.checksum);
c1.unload();
var r4 = c1.checksum(true);
assertTypeOf("string", r4.revision);
assertEqual(r3.revision, r4.revision);
assertTypeOf("number", r4.checksum);
assertEqual(r3.checksum, r4.checksum);
// test withData
var r5 = c1.checksum(true, true);
assertTypeOf("string", r5.revision);
assertEqual(r4.revision, r5.revision);
assertTypeOf("number", r5.checksum);
assertNotEqual(0, r5.checksum);
assertNotEqual(r4.checksum, r5.checksum);
// test after truncation
c1.truncate();
var r6 = c1.checksum(true);
assertTypeOf("string", r6.revision);
assertNotEqual(r4.revision, r6.revision);
assertNotEqual(r5.revision, r6.revision);
assertTypeOf("number", r6.checksum);
assertEqual(0, r6.checksum);
db._drop(cn);
db._drop(vn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test checksum two different collections
////////////////////////////////////////////////////////////////////////////////
testChecksumDifferent : function () {
var cn1 = "example";
var cn2 = "example2";
db._drop(cn1);
db._drop(cn2);
var c1 = db._create(cn1);
var c2 = db._create(cn2);
// collections are empty, checksums are identical
var cs1 = c1.checksum().checksum;
var cs2 = c2.checksum().checksum;
assertEqual(cs1, cs2);
c1.save({ _key: "foobar", value: 123 });
c2.save({ _key: "foobar", value: 123 });
// keys are the same
cs1 = c1.checksum().checksum;
cs2 = c2.checksum().checksum;
assertEqual(cs1, cs2);
// data is the same
cs1 = c1.checksum(false, true).checksum;
cs2 = c2.checksum(false, true).checksum;
assertEqual(cs1, cs2);
// revisions are different
cs1 = c1.checksum(true, false).checksum;
cs2 = c2.checksum(true, false).checksum;
assertNotEqual(cs1, cs2);
// revisions are still different
cs1 = c1.checksum(true, true).checksum;
cs2 = c2.checksum(true, true).checksum;
assertNotEqual(cs1, cs2);
// update document in c1, keep data
c1.replace("foobar", { value: 123 });
// keys are still the same
cs1 = c1.checksum().checksum;
cs2 = c2.checksum().checksum;
assertEqual(cs1, cs2);
// data is still the same
cs1 = c1.checksum(false, true).checksum;
cs2 = c2.checksum(false, true).checksum;
assertEqual(cs1, cs2);
// revisions are still different
cs1 = c1.checksum(true, false).checksum;
cs2 = c2.checksum(true, false).checksum;
// update document in c1, changing data
c1.replace("foobar", { value: 124 });
// keys are still the same
cs1 = c1.checksum().checksum;
cs2 = c2.checksum().checksum;
assertEqual(cs1, cs2);
// data is not the same
cs1 = c1.checksum(false, true).checksum;
cs2 = c2.checksum(false, true).checksum;
assertNotEqual(cs1, cs2);
// revisions are still different
cs1 = c1.checksum(true, false).checksum;
cs2 = c2.checksum(true, false).checksum;
db._drop(cn1);
db._drop(cn2);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test system collection dropping / renaming / unloading
////////////////////////////////////////////////////////////////////////////////
testSystemSpecial : function () {
[ '_trx', '_users' ].forEach(function(cn) {
var c = db._collection(cn);
// drop
try {
c.drop();
fail();
}
catch (err1) {
assertEqual(ERRORS.ERROR_FORBIDDEN.code, err1.errorNum);
}
// rename
var cn = "example";
db._drop(cn);
try {
c.rename(cn);
fail();
}
catch (err2) {
assertEqual(ERRORS.ERROR_FORBIDDEN.code, err2.errorNum);
}
// unload is allowed
c.unload();
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test special properties of replication collection
////////////////////////////////////////////////////////////////////////////////
testSpecialReplication : function () {
var repl = db._collection('_replication');
// drop is not allowed
try {
repl.drop();
fail();
}
catch (err1) {
assertEqual(ERRORS.ERROR_FORBIDDEN.code, err1.errorNum);
}
// rename is not allowed
try {
var cn = "example";
db._drop(cn);
repl.rename(cn);
}
catch (err2) {
assertEqual(ERRORS.ERROR_FORBIDDEN.code, err2.errorNum);
}
// unload is not allowed
try {
repl.unload();
}
catch (err3) {
assertEqual(ERRORS.ERROR_FORBIDDEN.code, err3.errorNum);
}
}
};
}
// -----------------------------------------------------------------------------
// --SECTION-- main
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suites
////////////////////////////////////////////////////////////////////////////////
jsunity.run(CollectionSuite);
return jsunity.done();
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End: