diff --git a/CHANGELOG b/CHANGELOG index 1cb1452a39..e9897bf4bd 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,11 @@ devel ----- +* UI: document/edge editor now remembering their modes (e.g. code or tree) + +* UI: optimized error messages for invalid graph definitions. Also fixed a + graph renderer cleanrenderer cleanup error. + * UI: added a delay within the graph viewer while changing the colors of the graph. Necessary due different browser behaviour. diff --git a/Documentation/Books/AQL/Operators.md b/Documentation/Books/AQL/Operators.md index 91d25268bb..ee64c446ec 100644 --- a/Documentation/Books/AQL/Operators.md +++ b/Documentation/Books/AQL/Operators.md @@ -287,8 +287,8 @@ AQL supports expressing simple numeric ranges with the *..* operator. This operator can be used to easily iterate over a sequence of numeric values. -The *..* operator will produce an array of values in the defined range, with -both bounding values included. +The *..* operator will produce an array of the integer values in the +defined range, with both bounding values included. *Examples* @@ -302,6 +302,11 @@ will produce the following result: [ 2010, 2011, 2012, 2013 ] ``` +Using the range operator is equivalent to writing an array with the integer +values in the range specified by the bounds of the range. If the bounds of +the range operator are non-integers, they will be converted to integer +values first. + There is also a [RANGE() function](Functions/Numeric.md#range). #### Array operators diff --git a/Documentation/Books/HTTP/README.md b/Documentation/Books/HTTP/README.md index abffb242c8..38fc78bbe7 100644 --- a/Documentation/Books/HTTP/README.md +++ b/Documentation/Books/HTTP/README.md @@ -6,5 +6,5 @@ for API developers. As a user or administrator of ArangoDB you should not need the information provided herein. In general, as a user of ArangoDB you will use one of the language -[drivers](https://www.arangodb.com). +[drivers](https://www.arangodb.com/drivers/). diff --git a/Documentation/Books/Manual/Appendix/JavaScriptModules/FileSystem.md b/Documentation/Books/Manual/Appendix/JavaScriptModules/FileSystem.md index 2378ec2237..4f26479f6a 100644 --- a/Documentation/Books/Manual/Appendix/JavaScriptModules/FileSystem.md +++ b/Documentation/Books/Manual/Appendix/JavaScriptModules/FileSystem.md @@ -7,6 +7,16 @@ The implementation tries to follow the CommonJS [Filesystem/A/0](http://wiki.commonjs.org/wiki/Filesystem/A/0) specification where possible. +Working Directory +----------------- +The directory functions below shouldn't use the current working directory of the server like `.` or `./test`. +You will not be able to tell whether the environment the server is running in will permit directory listing, +reading or writing of files. + +You should either base your directories with `getTempPath()`, or as a foxx service use the +[module.context.basePath](../..//Foxx/Context.md). + + Single File Directory Manipulation ---------------------------------- diff --git a/README_maintainers.md b/README_maintainers.md index 8b7d2d3d5e..c5c27656e0 100644 --- a/README_maintainers.md +++ b/README_maintainers.md @@ -372,12 +372,28 @@ creating the file `/etc/sysctl.d/corepattern.conf` (or add the following lines t # and know the PID plus the process name for later use. kernel.core_uses_pid = 1 kernel.core_pattern = /var/tmp/core-%e-%p-%t + +to reload the above settings most systems support: -Note that the `proc` paths translate sub-directories to dots. The non permanent way of doing this in a running system is: + sudo sysctl -p + +Note that the `proc` paths translate sub-directories to dots. +The non permanent way of doing this in a running system is: echo 1 > /proc/sys/kernel/core_uses_pid echo '/var/tmp/core-%e-%p-%t' > /proc/sys/kernel/core_pattern +(you may also inspect these files to validate the current settings) + +More modern systems facilitate [`systemd-coredump`](https://www.freedesktop.org/software/systemd/man/systemd-coredump.html) (via a similar named package) to controll coredumps. +On most systems it will put compressed coredumps to `/var/lib/systemd/coredump`. + +In order to use automatic coredump analysis with the unittests you need to configure +`/etc/systemd/coredump.conf` and set `Compress=no` - so instant analysis may take place. + +Please note that we can't support [Ubuntu Apport](https://wiki.ubuntu.com/Apport). +Please use `apport-unpack` to send us the bare coredumps. + Solaris Coredumps ================= Solaris configures the system corefile behaviour via the `coreadm` programm. diff --git a/arangod/Agency/AgencyComm.cpp b/arangod/Agency/AgencyComm.cpp index 202f427828..3c716c3056 100644 --- a/arangod/Agency/AgencyComm.cpp +++ b/arangod/Agency/AgencyComm.cpp @@ -1334,13 +1334,31 @@ void AgencyComm::updateEndpoints(arangodb::velocypack::Slice const& current) { AgencyCommResult AgencyComm::sendWithFailover( arangodb::rest::RequestType method, double const timeout, - std::string const& initialUrl, VPackSlice body, - std::string const& clientId) { + std::string const& initialUrl, VPackSlice inBody, + std::string clientId) { std::string endpoint; std::unique_ptr connection = AgencyCommManager::MANAGER->acquire(endpoint); + std::vector clientIds; + clientId = ""; + VPackSlice body = inBody.resolveExternals(); + + if (body.isArray()) { + for (auto const& query : VPackArrayIterator(body)) { + if (query.length() == 3 && query[0].isObject() && query[2].isString()) { + auto const id = query[2].copyString(); + if (!id.empty()) { + if (!clientIds.empty()) { + clientId += " "; + } + clientIds.push_back(id); + clientId +=id; + } + } + } + } AgencyCommResult result; std::string url; @@ -1430,6 +1448,15 @@ AgencyCommResult AgencyComm::sendWithFailover( url = initialUrl; // Attention: overwritten by redirect below! result = send(connection.get(), method, conTimeout, url, bodyString, clientId); +#ifdef ARANGODB_ENABLE_MAINTAINER_MODE + if (!clientIds.empty()) { + if (clientIds[0] == "INTEGRATION_TEST_INQUIRY_ERROR_0") { + result._statusCode = 0; + } else if (clientIds[0] == "INTEGRATION_TEST_INQUIRY_ERROR_503") { + result._statusCode = 503; + } + } +#endif } catch (...) { // Rotate to new agent endpoint: AgencyCommManager::MANAGER->failed(std::move(connection), endpoint); @@ -1456,7 +1483,7 @@ AgencyCommResult AgencyComm::sendWithFailover( // the operation. If it actually was done, we are good. If not, we // can retry. If in doubt, we have to retry inquire until the global // timeout is reached. - if (!clientId.empty() && result._sent && + if (!clientIds.empty() && result._sent && (result._statusCode == 0 || result._statusCode == 503)) { isInquiry = true; } @@ -1468,14 +1495,14 @@ AgencyCommResult AgencyComm::sendWithFailover( // the transaction lead to isInquiry == true because we got a timeout // or a 503. VPackBuilder b; - { - VPackArrayBuilder ab(&b); - b.add(VPackValue(clientId)); - } + { VPackArrayBuilder ab(&b); + for (auto const& i : clientIds) { + b.add(VPackValue(i)); + }} LOG_TOPIC(DEBUG, Logger::AGENCYCOMM) << "Failed agency comm (" << result._statusCode << ")! " << - "Inquiring about clientId " << clientId << "."; + "Inquiring about clientIds " << clientId << "."; url = "/_api/agency/inquire"; // attention: overwritten by redirect! result = send( @@ -1499,7 +1526,11 @@ AgencyCommResult AgencyComm::sendWithFailover( if (outer.isObject() && outer.hasKey("results")) { VPackSlice results = outer.get("results"); if (results.length() > 0) { +#ifdef ARANGODB_ENABLE_MAINTAINER_MODE + LOG_TOPIC(WARN, Logger::AGENCYCOMM) +#else LOG_TOPIC(DEBUG, Logger::AGENCYCOMM) +#endif << "Inquired " << resultBody->toJson(); AgencyCommManager::MANAGER->release(std::move(connection), endpoint); break; @@ -1511,7 +1542,7 @@ AgencyCommResult AgencyComm::sendWithFailover( continue; } } else { - // How odd, we are supposed to get at least [[]], let's retry... + // How odd, we are supposed to get at least {results=[...]}, let's retry... isInquiry = false; continue; } diff --git a/arangod/Agency/AgencyComm.h b/arangod/Agency/AgencyComm.h index 48594f413a..5fdf3c9bf3 100644 --- a/arangod/Agency/AgencyComm.h +++ b/arangod/Agency/AgencyComm.h @@ -685,7 +685,7 @@ class AgencyComm { AgencyCommResult sendWithFailover(arangodb::rest::RequestType, double, std::string const&, VPackSlice, - std::string const& clientId = std::string()); + std::string clientId = std::string()); private: bool lock(std::string const&, double, double, diff --git a/arangod/Agency/State.cpp b/arangod/Agency/State.cpp index 354dbcfd35..1303a63762 100644 --- a/arangod/Agency/State.cpp +++ b/arangod/Agency/State.cpp @@ -914,7 +914,6 @@ bool State::loadRemaining() { // Dummy fill missing entries (Not good at all.) index_t index(basics::StringUtils::uint64( ii.get(StaticStrings::KeyString).copyString())); - term_t term(ii.get("term").getNumber()); // Ignore log entries, which are older than lastIndex: if (index >= lastIndex) { @@ -925,6 +924,7 @@ bool State::loadRemaining() { std::make_shared>(); VPackSlice value = arangodb::basics::VelocyPackHelper::EmptyObjectValue(); buf->append(value.startAs(), value.byteSize()); + term_t term(ii.get("term").getNumber()); for (index_t i = lastIndex+1; i < index; ++i) { LOG_TOPIC(WARN, Logger::AGENCY) << "Missing index " << i << " in RAFT log."; _log.push_back(log_t(i, term, buf, std::string())); diff --git a/arangod/Agency/Supervision.cpp b/arangod/Agency/Supervision.cpp index befb8746ac..6e2227fc8b 100644 --- a/arangod/Agency/Supervision.cpp +++ b/arangod/Agency/Supervision.cpp @@ -57,7 +57,7 @@ struct HealthRecord { HealthRecord( std::string const& sn, std::string const& ep, std::string const& ho) : - shortName(sn), endpoint(ep), hostId(ho) {} + shortName(sn), endpoint(ep), hostId(ho), version(0) {} HealthRecord(Node const& node) { *this = node; @@ -105,6 +105,7 @@ struct HealthRecord { status = other.status; endpoint = other.endpoint; hostId = other.hostId; + version = other.version; return *this; } diff --git a/arangod/Cluster/v8-cluster.cpp b/arangod/Cluster/v8-cluster.cpp index daabefd6dd..dabb34fd85 100644 --- a/arangod/Cluster/v8-cluster.cpp +++ b/arangod/Cluster/v8-cluster.cpp @@ -275,7 +275,7 @@ static void JS_APIAgency(std::string const& envelope, v8::HandleScope scope(isolate); if (args.Length() < 1) { - TRI_V8_THROW_EXCEPTION_USAGE("read([[...]])"); + TRI_V8_THROW_EXCEPTION_USAGE(std::string(envelope) + "([[...]])"); } VPackBuilder builder; diff --git a/arangod/RocksDBEngine/RocksDBEdgeIndex.cpp b/arangod/RocksDBEngine/RocksDBEdgeIndex.cpp index ad38bd0de8..2a63c84a64 100644 --- a/arangod/RocksDBEngine/RocksDBEdgeIndex.cpp +++ b/arangod/RocksDBEngine/RocksDBEdgeIndex.cpp @@ -126,7 +126,7 @@ void RocksDBEdgeIndexIterator::reset() { bool RocksDBEdgeIndexIterator::next(LocalDocumentIdCallback const& cb, size_t limit) { TRI_ASSERT(_trx->state()->isRunning()); -#ifdef USE_MAINTAINER_MODE +#ifdef ARANGODB_ENABLE_MAINTAINER_MODE TRI_ASSERT(limit > 0); // Someone called with limit == 0. Api broken #else // Gracefully return in production code @@ -229,7 +229,7 @@ bool RocksDBEdgeIndexIterator::next(LocalDocumentIdCallback const& cb, size_t li bool RocksDBEdgeIndexIterator::nextExtra(ExtraCallback const& cb, size_t limit) { TRI_ASSERT(_trx->state()->isRunning()); -#ifdef USE_MAINTAINER_MODE +#ifdef ARANGODB_ENABLE_MAINTAINER_MODE TRI_ASSERT(limit > 0); // Someone called with limit == 0. Api broken #else // Gracefully return in production code @@ -843,7 +843,7 @@ void RocksDBEdgeIndex::warmupInternal(transaction::Methods* trx, : transaction::helpers::extractFromFromDocument(doc); TRI_ASSERT(toFrom.isString()); builder.add(toFrom); -#ifdef USE_MAINTAINER_MODE +#ifdef ARANGODB_ENABLE_MAINTAINER_MODE } else { // Data Inconsistency. // We have a revision id without a document... diff --git a/js/apps/system/_admin/aardvark/APP/aardvark.js b/js/apps/system/_admin/aardvark/APP/aardvark.js index 4acfc00acc..8d260de886 100644 --- a/js/apps/system/_admin/aardvark/APP/aardvark.js +++ b/js/apps/system/_admin/aardvark/APP/aardvark.js @@ -348,7 +348,12 @@ authRouter.get('/graph/:name', function (req, res) { ] }; - var graph = gm._graph(name); + var graph; + try { + graph = gm._graph(name); + } catch (e) { + res.throw('bad request', e.errorMessage); + } var verticesCollections = graph._vertexCollections(); if (!verticesCollections || verticesCollections.length === 0) { diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/views/documentView.js b/js/apps/system/_admin/aardvark/APP/frontend/js/views/documentView.js index 167de375db..1c702b9897 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/views/documentView.js +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/views/documentView.js @@ -32,7 +32,6 @@ 'click #document-to': 'navigateToDocument', 'keydown #documentEditor .ace_editor': 'keyPress', 'keyup .jsoneditor .search input': 'checkSearchBox', - 'click .jsoneditor .modes': 'storeMode', 'click #addDocument': 'addDocument' }, @@ -63,14 +62,11 @@ } }, - storeMode: function () { + storeMode: function (mode) { var self = this; - - $('.type-modes').on('click', function (elem) { - var mode = $(elem.currentTarget).text().toLowerCase(); - localStorage.setItem('JSONEditorMode', mode); - self.defaultMode = mode; - }); + localStorage.setItem('JSONEditorMode', mode); + self.defaultMode = mode; + self.editor.setMode(this.defaultMode); }, keyPress: function (e) { @@ -222,6 +218,9 @@ onChange: function () { self.jsonContentChanged(); }, + onModeChange: function (newMode) { + self.storeMode(newMode); + }, search: true, mode: 'tree', modes: ['tree', 'code'], @@ -230,6 +229,10 @@ }; this.editor = new JSONEditor(container, options); + var testMode = localStorage.getItem('JSONEditorMode'); + if (testMode === 'code' || testMode === 'tree') { + this.defaultMode = testMode; + } if (this.defaultMode) { this.editor.setMode(this.defaultMode); } diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/views/graphViewer.js b/js/apps/system/_admin/aardvark/APP/frontend/js/views/graphViewer.js index 2fe526e156..04aad5c804 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/views/graphViewer.js +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/views/graphViewer.js @@ -276,12 +276,14 @@ }, killCurrentGraph: function () { - for (var i in this.currentGraph.renderers) { - try { - this.currentGraph.renderers[i].clear(); - this.currentGraph.kill(i); - } catch (ignore) { - // no need to cleanup + if (this.currentGraph && this.currentGraph.renderers) { + for (var i in this.currentGraph.renderers) { + try { + this.currentGraph.renderers[i].clear(); + this.currentGraph.kill(i); + } catch (ignore) { + // no need to cleanup + } } } },