1
0
Fork 0

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

This commit is contained in:
jsteemann 2016-10-31 16:49:15 +01:00
commit f51871c599
8 changed files with 278 additions and 51 deletions

View File

@ -914,20 +914,6 @@ if( EXISTS "${CMAKE_CURRENT_BINARY_DIR}/compile_commands.json" )
)
endif()
################################################################################
## SNAPCRAFT PACKAGE
################################################################################
#set(USE_SNAPCRAFT "ON")
if (USE_SNAPCRAFT)
if(NOT DEFINED SNAP_PORT)
set(SNAP_PORT 8529)
endif()
include(packages/snap)
endif ()
add_custom_target(packages
DEPENDS ${PACKAGES_LIST}
)

View File

@ -483,6 +483,9 @@ if test -n "${ENTERPRISE_GIT_URL}" ; then
echo "I'm on tag: ${GITARGS}"
else
GITARGS=`git branch --no-color -q| grep '^\*' | sed "s;\* *;;"`
if echo $GITARGS |grep -q ' '; then
GITARGS=devel
fi
echo "I'm on Branch: ${GITARGS}"
fi
# clean up if we're commanded to:

View File

@ -1,4 +1,4 @@
name: @CMAKE_PROJECT_NAME@
name: @CPACK_PACKAGE_NAME@
version: @CPACK_PACKAGE_VERSION@
description: "ArangoDB is a native multi-model database with flexible data models for
documents, graphs, and key-values. Build high performance applications using a convenient
@ -12,7 +12,7 @@ grade: stable
#grade: devel
parts:
arangodb3:
@CPACK_PACKAGE_NAME@:
source: @CPACK_PACKAGE_TGZ@
plugin: dump
snap:

View File

@ -554,6 +554,11 @@ static void EnsureIndex(v8::FunctionCallbackInfo<v8::Value> const& args,
VPackBuilder builder;
int res = EnhanceIndexJson(args, builder, create);
if (res != TRI_ERROR_NO_ERROR) {
TRI_V8_THROW_EXCEPTION(res);
}
VPackSlice slice = builder.slice();
if (res == TRI_ERROR_NO_ERROR && ServerState::instance()->isCoordinator()) {
TRI_ASSERT(slice.isObject());
@ -568,27 +573,41 @@ static void EnsureIndex(v8::FunctionCallbackInfo<v8::Value> const& args,
VPackSlice v = slice.get("unique");
/* the following combinations of shardKeys and indexKeys are allowed/not allowed:
shardKeys indexKeys
a a ok
a b not ok
a a b ok
a b a not ok
a b b not ok
a b a b ok
a b a b c ok
a b c a b not ok
a b c a b c ok
*/
if (v.isBoolean() && v.getBoolean()) {
// unique index, now check if fields and shard keys match
VPackSlice flds = slice.get("fields");
if (flds.isArray() && c->numberOfShards() > 1) {
std::vector<std::string> const& shardKeys = c->shardKeys();
std::unordered_set<std::string> indexKeys;
size_t n = static_cast<size_t>(flds.length());
if (shardKeys.size() != n) {
res = TRI_ERROR_CLUSTER_UNSUPPORTED;
} else {
for (size_t i = 0; i < n; ++i) {
VPackSlice f = flds.at(i);
if (!f.isString()) {
res = TRI_ERROR_INTERNAL;
continue;
} else {
std::string tmp = f.copyString();
if (tmp != shardKeys[i]) {
res = TRI_ERROR_CLUSTER_UNSUPPORTED;
}
}
for (size_t i = 0; i < n; ++i) {
VPackSlice f = flds.at(i);
if (!f.isString()) {
// index attributes must be strings
TRI_V8_THROW_EXCEPTION(TRI_ERROR_INTERNAL);
}
indexKeys.emplace(f.copyString());
}
// all shard-keys must be covered by the index
for (auto& it : shardKeys) {
if (indexKeys.find(it) == indexKeys.end()) {
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_CLUSTER_UNSUPPORTED, "shard key '" + it + "' must be present in unique index");
}
}
}
@ -596,10 +615,6 @@ static void EnsureIndex(v8::FunctionCallbackInfo<v8::Value> const& args,
}
}
if (res != TRI_ERROR_NO_ERROR) {
TRI_V8_THROW_EXCEPTION(res);
}
TRI_ASSERT(!slice.isNone());
events::CreateIndex(collection->name(), slice);

View File

@ -37,6 +37,17 @@ elseif (MSVC)
include(packages/nsis)
endif ()
################################################################################
## SNAPCRAFT PACKAGE
################################################################################
if (USE_SNAPCRAFT)
if(NOT DEFINED SNAP_PORT)
set(SNAP_PORT 8529)
endif()
include(packages/snap)
endif ()
configure_file(
"${CMAKE_SOURCE_DIR}/Installation/cmake/CMakeCPackOptions.cmake.in"
"${CMAKE_BINARY_DIR}/CMakeCPackOptions.cmake" @ONLY)

View File

@ -67,11 +67,17 @@ router.post((req, res) => {
if (source instanceof Buffer) {
source = writeUploadToTempFile(source);
}
const service = fm.install(
source,
req.queryParams.mount,
_.omit(req.queryParams, ['mount'])
);
const dependencies = req.body.dependencies && JSON.parse(req.body.dependencies);
const configuration = req.body.configuration && JSON.parse(req.body.configuration);
const mount = req.queryParams.mount;
fm.install(source, mount, _.omit(req.queryParams, ['mount']));
if (configuration) {
fm.setConfiguration(mount, {configuration, replace: true});
}
if (dependencies) {
fm.setDependencies(mount, {dependencies, replace: true});
}
const service = fm.lookupService(mount);
res.json(serviceToJson(service));
})
.body(schemas.service, ['multipart/form-data', 'application/json'], `Service to be installed.`)
@ -121,11 +127,17 @@ serviceRouter.patch((req, res) => {
if (source instanceof Buffer) {
source = writeUploadToTempFile(source);
}
const service = fm.upgrade(
source,
req.queryParams.mount,
_.omit(req.queryParams, ['mount'])
);
const dependencies = req.body.dependencies && JSON.parse(req.body.dependencies);
const configuration = req.body.configuration && JSON.parse(req.body.configuration);
const mount = req.queryParams.mount;
fm.upgrade(source, mount, _.omit(req.queryParams, ['mount']));
if (configuration) {
fm.setConfiguration(mount, {configuration, replace: false});
}
if (dependencies) {
fm.setDependencies(mount, {dependencies, replace: false});
}
const service = fm.lookupService(mount);
res.json(serviceToJson(service));
})
.body(schemas.service, ['multipart/form-data', 'application/json'], `Service to be installed.`)
@ -149,11 +161,17 @@ serviceRouter.put((req, res) => {
if (source instanceof Buffer) {
source = writeUploadToTempFile(source);
}
const service = fm.replace(
source,
req.queryParams.mount,
_.omit(req.queryParams, ['mount'])
);
const dependencies = req.body.dependencies && JSON.parse(req.body.dependencies);
const configuration = req.body.configuration && JSON.parse(req.body.configuration);
const mount = req.queryParams.mount;
fm.replace(source, mount, _.omit(req.queryParams, ['mount']));
if (configuration) {
fm.setConfiguration(mount, {configuration, replace: true});
}
if (dependencies) {
fm.setDependencies(mount, {dependencies, replace: true});
}
const service = fm.lookupService(mount);
res.json(serviceToJson(service));
})
.body(schemas.service, ['multipart/form-data', 'application/json'], `Service to be installed.`)

View File

@ -42,5 +42,7 @@ exports.service = joi.object({
source: joi.alternatives(
joi.string().description(`Local file path or URL of the service to be installed`),
joi.object().type(Buffer).description(`Zip bundle of the service to be installed`)
).required().description(`Local file path, URL or zip bundle of the service to be installed`)
).required().description(`Local file path, URL or zip bundle of the service to be installed`),
configuration: joi.string().optional().description(`Configuration to use for the service (JSON)`),
dependencies: joi.string().optional().description(`Dependency options to use for the service (JSON)`)
}).required();

View File

@ -0,0 +1,192 @@
/*jshint globalstrict:false, strict:false */
/*global assertEqual, assertNotEqual, assertTrue, assertFalse, fail */
////////////////////////////////////////////////////////////////////////////////
/// @brief test the index
///
/// @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");
var errors = internal.errors;
var db = require("@arangodb").db;
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite: check unique indexes
////////////////////////////////////////////////////////////////////////////////
function uniqueIndexSuite() {
'use strict';
var cn = "UnitTestsCollectionIdx";
var runTest = function(indexType) {
var tests = [
{ shardKeys: ["a"], indexKeys: ["a"], result: true },
{ shardKeys: ["b"], indexKeys: ["b"], result: true },
{ shardKeys: ["a"], indexKeys: ["b"], result: false },
{ shardKeys: ["b"], indexKeys: ["a"], result: false },
{ shardKeys: ["a"], indexKeys: ["a", "b"], result: true },
{ shardKeys: ["a"], indexKeys: ["b", "a"], result: true },
{ shardKeys: ["a", "b"], indexKeys: ["c"], result: false },
{ shardKeys: ["a", "b"], indexKeys: ["b"], result: false },
{ shardKeys: ["a", "b"], indexKeys: ["a"], result: false },
{ shardKeys: ["a", "b"], indexKeys: ["a", "c"], result: false },
{ shardKeys: ["a", "b"], indexKeys: ["c", "a"], result: false },
{ shardKeys: ["a", "b"], indexKeys: ["a", "b"], result: true },
{ shardKeys: ["a", "b"], indexKeys: ["b", "a"], result: true },
{ shardKeys: ["a", "b"], indexKeys: ["a", "b", "c"], result: true },
{ shardKeys: ["a", "b"], indexKeys: ["b", "a", "c"], result: true },
{ shardKeys: ["a", "b"], indexKeys: ["c", "b", "a"], result: true },
{ shardKeys: ["a", "b"], indexKeys: ["b", "c", "a"], result: true },
{ shardKeys: ["a", "b"], indexKeys: ["a", "b", "c", "d"], result: true },
{ shardKeys: ["a", "b", "c"], indexKeys: ["a"], result: false },
{ shardKeys: ["a", "b", "c"], indexKeys: ["b"], result: false },
{ shardKeys: ["a", "b", "c"], indexKeys: ["c"], result: false },
{ shardKeys: ["a", "b", "c"], indexKeys: ["a", "b"], result: false },
{ shardKeys: ["a", "b", "c"], indexKeys: ["a", "c"], result: false },
{ shardKeys: ["a", "b", "c"], indexKeys: ["b", "c"], result: false },
{ shardKeys: ["a", "b", "c"], indexKeys: ["a", "b", "c"], result: true },
{ shardKeys: ["a", "b", "c"], indexKeys: ["a", "b", "c", "d"], result: true },
{ shardKeys: ["a", "b", "c"], indexKeys: ["a", "b", "d"], result: false },
{ shardKeys: ["a", "b", "c"], indexKeys: ["a", "b", "d", "c"], result: true }
];
tests.forEach(function(test) {
// drop collection first in case it already exists
internal.db._drop(cn);
var collection = internal.db._create(cn, { shardKeys: test.shardKeys, numberOfShards: 4 });
if (test.result) {
// index creation should work
var idx = collection.ensureIndex({ type: indexType, fields: test.indexKeys, unique: true });
assertTrue(idx.isNewlyCreated);
assertTrue(idx.unique);
assertEqual(test.indexKeys, idx.fields);
// now actually insert unique values
var n = 1000;
var threshold = 2;
while (n > Math.pow(threshold, test.indexKeys.length)) {
threshold += 2;
}
var initState = function(indexKeys) {
var state = { };
for (var key in indexKeys) {
state[indexKeys[key]] = 0;
}
return state;
};
var permute = function(state, indexKeys) {
for (var key in indexKeys) {
if (++state[indexKeys[key]] >= threshold) {
state[indexKeys[key]] = 0;
} else {
break;
}
}
return state;
};
var state = initState(test.indexKeys), i;
for (i = 0; i < n; ++i) {
collection.insert(state);
permute(state, test.indexKeys);
}
var filter = function(state) {
var parts = [];
for (var key in state) {
parts.push("doc." + key + " == " + state[key]);
}
return parts.join(" && ");
};
state = initState(test.indexKeys);
for (i = 0; i < n;) {
var query = "FOR doc IN " + collection.name() + " FILTER " + filter(state) + " RETURN 1";
if (i === 0) {
// on first invocation check that the index is actually used
assertNotEqual(-1, db._createStatement(query).explain().plan.nodes.map(function(node) { return node.type; }).indexOf("IndexNode"));
}
// expect exactly one result
assertEqual(1, db._query(query).toArray().length);
// query some random elements only to save time
var skip = Math.floor(Math.random() * 15) + 1;
while (skip > 0) {
permute(state, test.indexKeys);
--skip;
++i;
}
if (i >= n) {
break;
}
}
} else {
// index creation should fail
try {
collection.ensureIndex({ type: indexType, fields: test.indexKeys, unique: true });
fail();
} catch (err) {
assertEqual(errors.ERROR_CLUSTER_UNSUPPORTED.code, err.errorNum);
}
}
});
};
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
setUp : function () {
},
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
tearDown : function () {
internal.db._drop(cn);
},
testUniqueHashIndexes : function () {
runTest("hash");
},
testUniqueSkiplistIndexes : function () {
runTest("skiplist");
}
};
}
jsunity.run(uniqueIndexSuite);
return jsunity.done();