1
0
Fork 0

Merge branch 'devel' into ClustUp1

This commit is contained in:
Max Neunhoeffer 2015-12-09 15:19:11 +01:00
commit 7a91accb71
13 changed files with 192 additions and 66 deletions

View File

@ -67,6 +67,8 @@ class Builder {
// open objects/arrays
std::vector<std::vector<ValueLength>> _index; // Indices for starts
// of subindex
bool _keyWritten; // indicates that in the current object the key
// has been written but the value not yet
// Here are the mechanics of how this building process works:
// The whole VPack being built starts at where _start points to
@ -131,7 +133,7 @@ class Builder {
// Constructor and destructor:
explicit Builder(std::shared_ptr<Buffer<uint8_t>>& buffer,
Options const* options = &Options::Defaults)
: _buffer(buffer), _pos(0), options(options) {
: _buffer(buffer), _pos(0), _keyWritten(false), options(options) {
if (_buffer.get() == nullptr) {
throw Exception(Exception::InternalError, "Buffer cannot be a nullptr");
}
@ -144,7 +146,8 @@ class Builder {
}
explicit Builder(Options const* options = &Options::Defaults)
: _buffer(new Buffer<uint8_t>()), _pos(0), options(options) {
: _buffer(new Buffer<uint8_t>()), _pos(0), _keyWritten(false),
options(options) {
_start = _buffer->data();
_size = _buffer->size();
@ -164,6 +167,7 @@ class Builder {
_pos(that._pos),
_stack(that._stack),
_index(that._index),
_keyWritten(that._keyWritten),
options(that.options) {
if (options == nullptr) {
throw Exception(Exception::InternalError, "Options cannot be a nullptr");
@ -180,6 +184,7 @@ class Builder {
_pos = that._pos;
_stack = that._stack;
_index = that._index;
_keyWritten = that._keyWritten;
options = that.options;
return *this;
}
@ -197,10 +202,12 @@ class Builder {
_stack.swap(that._stack);
_index.clear();
_index.swap(that._index);
_keyWritten = that._keyWritten;
options = that.options;
that._start = that._buffer->data();
that._size = 0;
that._pos = 0;
that._keyWritten = false;
}
Builder& operator=(Builder&& that) {
@ -216,10 +223,12 @@ class Builder {
_stack.swap(that._stack);
_index.clear();
_index.swap(that._index);
_keyWritten = that._keyWritten;
options = that.options;
that._start = that._buffer->data();
that._size = 0;
that._pos = 0;
that._keyWritten = false;
return *this;
}
@ -238,6 +247,8 @@ class Builder {
std::string toString() const;
std::string toJson() const;
static Builder clone(Slice const& slice,
Options const* options = &Options::Defaults) {
if (options == nullptr) {
@ -246,7 +257,7 @@ class Builder {
Builder b(options);
b.add(slice);
return std::move(b);
return b; // Use return value optimization
}
// Clear and start from scratch:
@ -276,6 +287,22 @@ class Builder {
bool isClosed() const throw() { return _stack.empty(); }
bool isOpenArray() const throw() {
if (_stack.empty()) {
return false;
}
ValueLength const tos = _stack.back();
return _start[tos] == 0x06 || _start[tos] == 0x13;
}
bool isOpenObject() const throw() {
if (_stack.empty()) {
return false;
}
ValueLength const tos = _stack.back();
return _start[tos] == 0x0b || _start[tos] == 0x14;
}
// Add a subvalue into an object from a Value:
uint8_t* add(std::string const& attrName, Value const& sub);
@ -435,6 +462,25 @@ private:
private:
inline void checkKeyIsString(bool isString) {
if (! _stack.empty()) {
ValueLength const tos = _stack.back();
if (_start[tos] == 0x0b || _start[tos] == 0x14) {
if (! _keyWritten) {
if (isString) {
_keyWritten = true;
}
else {
throw Exception(Exception::BuilderKeyMustBeString);
}
}
else {
_keyWritten = false;
}
}
}
}
inline void addArray(bool unindexed = false) {
addCompoundValue(unindexed ? 0x13 : 0x06);
}
@ -447,12 +493,10 @@ private:
uint8_t* addInternal(T const& sub) {
bool haveReported = false;
if (!_stack.empty()) {
ValueLength& tos = _stack.back();
if (_start[tos] != 0x06 && _start[tos] != 0x13) {
throw Exception(Exception::BuilderNeedOpenArray);
if (! _keyWritten) {
reportAdd();
haveReported = true;
}
reportAdd(tos);
haveReported = true;
}
try {
return set(sub);
@ -473,7 +517,10 @@ private:
if (_start[tos] != 0x0b && _start[tos] != 0x14) {
throw Exception(Exception::BuilderNeedOpenObject);
}
reportAdd(tos);
if (_keyWritten) {
throw Exception(Exception::BuilderKeyAlreadyWritten);
}
reportAdd();
haveReported = true;
}
@ -484,13 +531,19 @@ private:
options->attributeTranslator->translate(attrName);
if (translated != nullptr) {
set(Slice(translated, options));
Slice item(translated);
ValueLength const l = item.byteSize();
reserveSpace(l);
memcpy(_start + _pos, translated, checkOverflow(l));
_pos += l;
_keyWritten = true;
return set(sub);
}
// otherwise fall through to regular behavior
}
set(Value(attrName, ValueType::String));
_keyWritten = true;
return set(sub);
} catch (...) {
// clean up in case of an exception
@ -518,11 +571,16 @@ private:
bool haveReported = false;
if (!_stack.empty()) {
ValueLength& tos = _stack.back();
if (_start[tos] != 0x06 && _start[tos] != 0x13) {
throw Exception(Exception::BuilderNeedOpenCompound);
if (! _keyWritten) {
if (_start[tos] != 0x06 && _start[tos] != 0x13) {
throw Exception(Exception::BuilderNeedOpenArray);
}
reportAdd();
haveReported = true;
}
else {
_keyWritten = false;
}
reportAdd(tos);
haveReported = true;
}
try {
addCompoundValue(type);
@ -547,9 +605,9 @@ private:
_index[depth].pop_back();
}
void reportAdd(ValueLength base) {
void reportAdd() {
size_t depth = _stack.size() - 1;
_index[depth].push_back(_pos - base);
_index[depth].push_back(_pos - _stack[depth]);
}
void appendLength(ValueLength v, uint64_t n) {
@ -644,7 +702,12 @@ struct ObjectBuilder final : public BuilderContainer, public NoHeapAllocation {
builder->add(attributeName, Value(ValueType::Object, allowUnindexed));
}
~ObjectBuilder() {
builder->close();
try {
builder->close();
}
catch (...) {
// destructors must not throw
}
}
};
@ -654,7 +717,12 @@ struct ArrayBuilder final : public BuilderContainer, public NoHeapAllocation {
builder->openArray(allowUnindexed);
}
~ArrayBuilder() {
builder->close();
try {
builder->close();
}
catch (...) {
// destructors must not throw
}
}
};

View File

@ -65,6 +65,8 @@ struct Exception : std::exception {
BuilderUnexpectedValue = 35,
BuilderNeedSubvalue = 36,
BuilderExternalsDisallowed = 37,
BuilderKeyAlreadyWritten = 38,
BuilderKeyMustBeString = 39,
UnknownError = 999
};
@ -133,6 +135,10 @@ struct Exception : std::exception {
return "Unexpected value";
case BuilderExternalsDisallowed:
return "Externals are not allowed in this configuration";
case BuilderKeyAlreadyWritten:
return "The key of the next key/value pair is already written";
case BuilderKeyMustBeString:
return "The key of the next key/value pair must be a string";
case UnknownError:
default:

View File

@ -43,6 +43,13 @@ std::string Builder::toString() const {
return std::move(buffer);
}
std::string Builder::toJson() const {
std::string buffer;
StringSink sink(&buffer);
Dumper::dump(slice(), &sink);
return std::move(buffer);
}
void Builder::doActualSort(std::vector<SortEntry>& entries) {
VELOCYPACK_ASSERT(entries.size() > 1);
std::sort(entries.begin(), entries.end(),
@ -401,7 +408,7 @@ Slice Builder::getKey(std::string const& key) const {
if (_stack.empty()) {
throw Exception(Exception::BuilderNeedOpenObject);
}
ValueLength const& tos = _stack.back();
ValueLength const tos = _stack.back();
if (_start[tos] != 0x0b && _start[tos] != 0x14) {
throw Exception(Exception::BuilderNeedOpenObject);
}
@ -422,6 +429,8 @@ uint8_t* Builder::set(Value const& item) {
auto const oldPos = _start + _pos;
auto ctype = item.cType();
checkKeyIsString(item.valueType() == ValueType::String);
// This method builds a single further VPack item at the current
// append position. If this is an array or object, then an index
// table is created and a new ValueLength is pushed onto the stack.
@ -666,6 +675,9 @@ uint8_t* Builder::set(Value const& item) {
}
uint8_t* Builder::set(Slice const& item) {
checkKeyIsString(item.isString());
ValueLength const l = item.byteSize();
reserveSpace(l);
memcpy(_start + _pos, item.start(), checkOverflow(l));
@ -678,6 +690,9 @@ uint8_t* Builder::set(ValuePair const& pair) {
// append position. This is the case for ValueType::String,
// ValueType::Binary, or ValueType::Custom, which can be built
// with two pieces of information
checkKeyIsString(pair.valueType() == ValueType::String);
if (pair.valueType() == ValueType::Binary) {
uint64_t v = pair.getSize();
appendUInt(v, 0xbf);

View File

@ -49,8 +49,19 @@ ValueLength Parser::parseInternal(bool multi) {
do {
bool haveReported = false;
if (!_b->_stack.empty()) {
_b->reportAdd(_b->_stack.back());
haveReported = true;
ValueLength const tos = _b->_stack.back();
if (_b->_start[tos] == 0x0b || _b->_start[tos] == 0x14) {
if (! _b->_keyWritten) {
throw Exception(Exception::BuilderKeyMustBeString);
}
else {
_b->_keyWritten = false;
}
}
else {
_b->reportAdd();
haveReported = true;
}
}
try {
parseJson();
@ -400,7 +411,6 @@ void Parser::parseString() {
}
void Parser::parseArray() {
ValueLength base = _b->_pos;
_b->addArray();
int i = skipWhiteSpace("Expecting item or ']'");
@ -415,7 +425,7 @@ void Parser::parseArray() {
while (true) {
// parse array element itself
_b->reportAdd(base);
_b->reportAdd();
parseJson();
i = skipWhiteSpace("Expecting ',' or ']'");
if (i == ']') {
@ -437,7 +447,6 @@ void Parser::parseArray() {
}
void Parser::parseObject() {
ValueLength base = _b->_pos;
_b->addObject();
int i = skipWhiteSpace("Expecting item or '}'");
@ -461,7 +470,7 @@ void Parser::parseObject() {
// get past the initial '"'
++_pos;
_b->reportAdd(base);
_b->reportAdd();
bool excludeAttribute = false;
auto const lastPos = _b->_pos;
if (options->attributeExcludeHandler == nullptr) {

View File

@ -616,8 +616,7 @@ v8::Handle<v8::Value> AqlValue::toV8 (v8::Isolate* isolate,
}
case EMPTY: {
return v8::Null(isolate); // TODO: FIXME decide if we really want this...---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
return v8::Undefined(isolate);
return v8::Null(isolate);
}
}
@ -693,8 +692,7 @@ Json AqlValue::toJson (triagens::arango::AqlTransaction* trx,
}
case EMPTY: {
return Json(Json::Null); // TODO FIXME: decide if we really want this...--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
return triagens::basics::Json();
return Json(Json::Null);
}
}

View File

@ -3085,7 +3085,7 @@ static Json getDocumentByIdentifier (triagens::arango::AqlTransaction* trx,
if (ex.code() == TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND) {
return Json(Json::Null);
}
throw ex;
throw;
}
TRI_doc_mptr_copy_t mptr;
@ -3165,7 +3165,7 @@ AqlValue Functions::Document (triagens::aql::Query* query,
catch (triagens::basics::Exception const& ex) {
// don't throw if collection is not found
if (ex.code() != TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND) {
throw ex;
throw;
}
notFound = true;
}

View File

@ -266,6 +266,10 @@ var unregisterFunctionsGroup = function (group) {
/// The registered function is stored in the selected database's system
/// collection *_aqlfunctions*.
///
/// The function returns *true* when it updates/replaces an existing AQL
/// function of the same name, and *false* otherwise. It will throw an exception
/// when it detects syntactially invalid function code.
///
/// @EXAMPLES
///
/// ```js

View File

@ -101,12 +101,12 @@ function createRequire(module) {
// Enable support to add extra extension types
require.extensions = Module._extensions;
require.cache = Module._cache;
require.cache = module.cache;
return require;
}
function Module(id, parent) {
function Module(id, parent, cache) {
this.id = id;
this.exports = {};
this.parent = parent;
@ -114,6 +114,8 @@ function Module(id, parent) {
parent.children.push(this);
}
this.cache = cache || (parent ? parent.cache : Module._cache);
this.context = {
print: internal.print,
process: NATIVE_MODULES.process,
@ -126,6 +128,7 @@ function Module(id, parent) {
};
if (parent) {
this.root = parent.root;
this.preprocess = parent.preprocess;
Object.keys(parent.context).forEach(function (key) {
if (!hasOwnProperty(this.context, key)) {
@ -292,7 +295,7 @@ Module._findPath = function(request, paths) {
};
// 'from' is the __dirname of the module.
Module._nodeModulePaths = function(from) {
Module._nodeModulePaths = function(from, root) {
// guarantee that 'from' is absolute.
from = path.resolve(from);
@ -302,11 +305,13 @@ Module._nodeModulePaths = function(from) {
var splitRe = (internal.platform === 'win32' || internal.platform === 'win64') ? /[\/\\]/ : /\//;
var paths = [];
var parts = from.split(splitRe);
var inRoot = root && from.indexOf(root) === 0;
for (var tip = parts.length - 1; tip >= 0; tip--) {
// don't search in .../node_modules/node_modules
if (parts[tip] === 'node_modules') continue;
var dir = parts.slice(0, tip + 1).concat('node_modules').join(path.sep);
if (inRoot && dir.indexOf(root) !== 0) break;
paths.push(dir);
}
@ -386,6 +391,13 @@ Module._resolveDbModule = function (request) {
};
function isGlobalModule(filename) {
return modulePaths.some(function (modulePath) {
return filename.indexOf(modulePath) === 0;
});
}
// Check the cache for the requested file.
// 1. If a module already exists in the cache: return its exports object.
// 2. If the module is native: call `NativeModule.require()` with the
@ -394,6 +406,7 @@ Module._resolveDbModule = function (request) {
// Then have it load the file contents before returning its exports
// object.
Module._load = function(request, parent, isMain) {
var filename = request;
var dbModule = false;
var match = request.match(/^\/?db:(\/(\/_modules)?)?(\/.+)/);
@ -420,7 +433,11 @@ Module._load = function(request, parent, isMain) {
filename = dbModule.path;
}
var cachedModule = Module._cache[filename];
var cache;
if (parent && (dbModule || !isGlobalModule(filename))) cache = parent.cache;
else cache = Module._cache;
var cachedModule = cache[filename];
if (cachedModule) {
return cachedModule.exports;
}
@ -435,8 +452,8 @@ Module._load = function(request, parent, isMain) {
module.id = '.';
}
Module._cache[filename] = module;
LOADING.push(filename);
cache[filename] = module;
LOADING.push({cache, filename});
var hadException = true;
@ -449,7 +466,7 @@ Module._load = function(request, parent, isMain) {
hadException = false;
} finally {
if (hadException) {
delete Module._cache[filename];
delete cache[filename];
}
var i = LOADING.indexOf(filename);
if (i !== -1) {
@ -462,8 +479,8 @@ Module._load = function(request, parent, isMain) {
Module._cleanupCancelation = function () {
while (LOADING.length) {
var filename = LOADING.pop();
delete Module._cache[filename];
let loading = LOADING.pop();
delete loading.cache[loading.filename];
}
};
@ -491,7 +508,7 @@ Module._resolveFilename = function(request, parent) {
Module.prototype.load = function(filename) {
assert(!this.loaded);
this.filename = filename;
this.paths = Module._nodeModulePaths(path.dirname(filename));
this.paths = Module._nodeModulePaths(path.dirname(filename), this.root);
var extension = path.extname(filename) || '.js';
if (!Module._extensions[extension]) extension = '.js';
@ -526,7 +543,7 @@ Module.prototype._compile = function(content, filename) {
// remove shebang
content = content.replace(/^\#\!.*/, '');
if (this.preprocess) {
content = this.preprocess(content);
content = this.preprocess(content, filename);
}
// test for parse errors first and fail early if a parse error detected

View File

@ -265,6 +265,10 @@ var unregisterFunctionsGroup = function (group) {
/// The registered function is stored in the selected database's system
/// collection *_aqlfunctions*.
///
/// The function returns *true* when it updates/replaces an existing AQL
/// function of the same name, and *false* otherwise. It will throw an exception
/// when it detects syntactially invalid function code.
///
/// @EXAMPLES
///
/// ```js

View File

@ -27,8 +27,7 @@
/// @author Copyright 2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var extend = require("underscore").extend,
coffeeScript = require("coffee-script");
var extend = require('underscore').extend;
function ArrayIterator(arr) {
this.array = arr;
@ -54,7 +53,7 @@ extend(ArrayIterator.prototype, {
},
entireString: function () {
return this.array.join("\n");
return this.array.join('\n');
},
getCurrentLineNumber: function () {
@ -64,22 +63,21 @@ extend(ArrayIterator.prototype, {
}
});
function Preprocessor(input, type) {
if (type === 'coffee') {
input = coffeeScript.compile(input, {bare: true});
}
this.iterator = new ArrayIterator(input.replace('\r', '').split("\n"));
function Preprocessor(input) {
this.iterator = new ArrayIterator(input.replace('\r', '').split('\n'));
this.inJSDoc = false;
}
extend(Preprocessor.prototype, {
result: function () {
return this.iterator.entireString();
return this.iterator.entireString();
},
convert: function () {
while (this.searchNext()) {
convert: function (filename) {
if (filename && filename.indexOf('node_modules') !== -1) {
return this;
}
while (this.searchNext()) {
this.convertLine();
}
return this;
@ -94,8 +92,8 @@ extend(Preprocessor.prototype, {
},
convertLine: function () {
this.iterator.replaceWith(
"applicationContext.comment(\"" + this.stripComment(this.iterator.current()) + "\");"
this.iterator.replaceWith(
`applicationContext.comment("${this.stripComment(this.iterator.current())}");`
);
},
@ -139,9 +137,9 @@ extend(Preprocessor.prototype, {
}
});
function preprocess(input, type) {
var processor = new Preprocessor(input, type);
return processor.convert().result();
function preprocess(input, filename) {
var processor = new Preprocessor(input);
return processor.convert(filename).result();
}
// Only Exported for Tests, please use `process`

View File

@ -627,6 +627,10 @@ var routeApp = function (app, isInstallProcess) {
try {
if (controllers) {
Object.keys(app.moduleCache).forEach(function (filename) {
// Clear the module cache to force re-evaluation
delete app.moduleCache[filename];
});
Object.keys(controllers).forEach(function (key) {
mountController(app, routes, key, controllers[key]);
});

View File

@ -191,8 +191,11 @@ class FoxxService {
}
let lib = this.manifest.lib || '.';
this.main = new Module(`foxx:${data.mount}`);
this.main.filename = path.resolve(this.root, this.path, lib, '.foxx');
let moduleRoot = path.resolve(this.root, this.path, lib);
this.moduleCache = {};
this.main = new Module(`foxx:${data.mount}`, undefined, this.moduleCache);
this.main.root = moduleRoot;
this.main.filename = path.resolve(moduleRoot, '.foxx');
this.main.context.applicationContext = new AppContext(this);
this.main.context.console = require('org/arangodb/foxx/console')(this.mount);
}

View File

@ -1052,7 +1052,7 @@ function performTests(options, testList, testname, remote) {
print("Skipping, " + te + " server is gone.");
results[te] = {status: false, message: instanceInfo.exitStatus};
instanceInfo.exitStatus = "server is gone.";
continue;
break;
}
print("\n" + Date() + " arangod: Trying",te,"...");
@ -1290,7 +1290,7 @@ testFuncs.shell_client = function(options) {
print("Skipping, " + te + " server is gone.");
results[te] = {status: false, message: instanceInfo.exitStatus};
instanceInfo.exitStatus = "server is gone.";
continue;
break;
}
print("\narangosh: Trying",te,"...");
@ -1444,7 +1444,7 @@ function rubyTests (options, ssl) {
print("Skipping " + te + " server is gone.");
result[te] = {status: false, message: instanceInfo.exitStatus};
instanceInfo.exitStatus = "server is gone.";
continue;
break;
}
print("\n"+ Date() + " rspec Trying ",te,"...");
@ -1973,7 +1973,7 @@ testFuncs.arangob = function (options) {
print("Skipping " + benchTodo[i] + ", server is gone.");
results[i] = {status: false, message: instanceInfo.exitStatus};
instanceInfo.exitStatus = "server is gone.";
continue;
break;
}
var args = benchTodo[i];
if (options.hasOwnProperty('benchargs')) {
@ -2097,7 +2097,7 @@ testFuncs.authentication_parameters = function (options) {
};
instanceInfo.exitStatus = "server is gone.";
all_ok = false;
continue;
break;
}
r = download(instanceInfo.url + urlsTodo[i],"", downloadOptions);