mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of https://github.com/triAGENS/ArangoDB into devel
This commit is contained in:
commit
5e2fa60521
|
@ -50,7 +50,6 @@ After having introduced edge definitions and orphan collections a graph can be c
|
||||||
|
|
||||||
@startDocuBlock JSF_general_graph_create
|
@startDocuBlock JSF_general_graph_create
|
||||||
|
|
||||||
|
|
||||||
!SUBSUBSECTION Complete Example to create a graph
|
!SUBSUBSECTION Complete Example to create a graph
|
||||||
|
|
||||||
Example Call:
|
Example Call:
|
||||||
|
|
|
@ -1,141 +0,0 @@
|
||||||
!CHAPTER Graph Management
|
|
||||||
|
|
||||||
In order to create a graph the philosophy of handling the graph content has to introduced.
|
|
||||||
A graph contains a set of edge definitions each referring to one edge collection and
|
|
||||||
defining constraints on the vertex collections used as start and end points of the edges.
|
|
||||||
Furthermore a graph can contain an arbitrary amount of vertex collections, called orphan collections, that are not used in any edge definition but should be managed by the graph.
|
|
||||||
In order to create a graph the functionality to create edge definitions has to be introduced first:
|
|
||||||
|
|
||||||
!SECTION Edge Definitions
|
|
||||||
|
|
||||||
The edge definitions for a graph is an Array containing arbitrary many directed and/or undirected relations as defined below.
|
|
||||||
|
|
||||||
!SUBSECTION Initialize the list
|
|
||||||
|
|
||||||
<!-- @startDocuBlock JSF_general_graph_edge_definitions -->
|
|
||||||
|
|
||||||
!SUBSECTION Extend the list
|
|
||||||
|
|
||||||
<!-- @startDocuBlock JSF_general_graph_extend_edge_definitions -->
|
|
||||||
|
|
||||||
!SUBSUBSECTION Undirected Relation
|
|
||||||
|
|
||||||
<!-- @startDocuBlock JSF_general_graph_undirectedRelation -->
|
|
||||||
|
|
||||||
!SUBSUBSECTION Directed Relation
|
|
||||||
|
|
||||||
<!-- @startDocuBlock JSF_general_graph_directedRelation -->
|
|
||||||
|
|
||||||
!SUBSECTION Orphan Collections
|
|
||||||
|
|
||||||
Each graph has an orphan collection. It consists of arbitrary many vertex collection (type *document*), that are not
|
|
||||||
used in an edge definition of the graph. If the graph is extended with an edge definition using one of the orphans,
|
|
||||||
it will be removed from the orphan collection automatically.
|
|
||||||
|
|
||||||
!SUBSUBSECTION Add
|
|
||||||
|
|
||||||
<!-- @startDocuBlock JSF_general_graph__addOrphanCollection -->
|
|
||||||
|
|
||||||
!SUBSUBSECTION Read
|
|
||||||
|
|
||||||
<!-- @startDocuBlock JSF_general_graph__getOrphanCollections -->
|
|
||||||
|
|
||||||
!SUBSUBSECTION Remove
|
|
||||||
|
|
||||||
<!-- @startDocuBlock JSF_general_graph__removeOrphanCollection -->
|
|
||||||
|
|
||||||
!SECTION Create a graph
|
|
||||||
|
|
||||||
After having introduced edge definitions and orphan collections a graph can be created.
|
|
||||||
|
|
||||||
<!-- @startDocuBlock JSF_general_graph_create -->
|
|
||||||
|
|
||||||
|
|
||||||
!SUBSUBSECTION Complete Example to create a graph
|
|
||||||
|
|
||||||
Example Call:
|
|
||||||
|
|
||||||
```js
|
|
||||||
> var graph = require("org/arangodb/graph");
|
|
||||||
> var edgeDefinitions = graph._edgeDefinitions();
|
|
||||||
> graph._extendEdgeDefinitions(edgeDefinitions, graph._undirectedRelation("friend_of", ["Customer"]));
|
|
||||||
> graph._extendEdgeDefinitions(edgeDefinitions, graph._directedRelation("has_bought", ["Customer", "Company"], ["Groceries", "Electronics"]));
|
|
||||||
> graph._create("myStore", edgeDefinitions);
|
|
||||||
{
|
|
||||||
_id: "_graphs/123",
|
|
||||||
_rev: "123",
|
|
||||||
_key: "123"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
alternative call:
|
|
||||||
|
|
||||||
```js
|
|
||||||
> var graph = require("org/arangodb/graph");
|
|
||||||
> var edgeDefinitions = graph._edgeDefinitions(graph._undirectedRelation("friend_of", ["Customer"]), graph._directedRelation("has_bought", ["Customer", "Company"], ["Groceries", "Electronics"]));
|
|
||||||
> graph._create("myStore", edgeDefinitions);
|
|
||||||
{
|
|
||||||
_id: "_graphs/123",
|
|
||||||
_rev: "123",
|
|
||||||
_key: "123"
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
!SUBSECTION List available graphs
|
|
||||||
|
|
||||||
<!-- @startDocuBlock JSF_general_graph_list_call -->
|
|
||||||
`general-graph._list()` *List all graphs.*
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
|
|
||||||
<!-- @startDocuBlock JSF_general_graph_list_info -->
|
|
||||||
|
|
||||||
<br />
|
|
||||||
@EXAMPLES
|
|
||||||
<br />
|
|
||||||
|
|
||||||
<!-- @startDocuBlock JSF_general_graph_list_examples -->
|
|
||||||
|
|
||||||
!SUBSECTION Load a graph
|
|
||||||
|
|
||||||
<!-- @startDocuBlock JSF_general_graph_graph -->
|
|
||||||
|
|
||||||
!SUBSECTION Remove a graph
|
|
||||||
|
|
||||||
<!-- @startDocuBlock JSF_general_graph_drop -->
|
|
||||||
|
|
||||||
!SECTION Edge
|
|
||||||
|
|
||||||
!SUBSECTION Save
|
|
||||||
|
|
||||||
<!-- @startDocuBlock JSF_general_graph_vertex_collection_save -->
|
|
||||||
|
|
||||||
!SUBSECTION Replace
|
|
||||||
|
|
||||||
<!-- @startDocuBlock JSF_general_graph_vertex_collection_replace -->
|
|
||||||
|
|
||||||
!SUBSECTION Update
|
|
||||||
|
|
||||||
<!-- @startDocuBlock JSF_general_graph_vertex_collection_update -->
|
|
||||||
|
|
||||||
!SUBSECTION Remove
|
|
||||||
|
|
||||||
<!-- @startDocuBlock JSF_general_graph_vertex_collection_remove -->
|
|
||||||
|
|
||||||
!SECTION Edge
|
|
||||||
|
|
||||||
!SUBSECTION Save
|
|
||||||
|
|
||||||
<!-- @startDocuBlock JSF_general_graph_edge_collection_save -->
|
|
||||||
|
|
||||||
!SUBSECTION Replace
|
|
||||||
|
|
||||||
<!-- @startDocuBlock JSF_general_graph_edge_collection_replace -->
|
|
||||||
|
|
||||||
!SUBSECTION Update
|
|
||||||
|
|
||||||
<!-- @startDocuBlock JSF_general_graph_edge_collection_update -->
|
|
||||||
|
|
||||||
!SUBSECTION Remove
|
|
||||||
|
|
||||||
<!-- @startDocuBlock JSF_general_graph_edge_collection_remove -->
|
|
|
@ -31,15 +31,20 @@ def example_content(filepath, fh, tag):
|
||||||
""" Fetches an example file and inserts it using code
|
""" Fetches an example file and inserts it using code
|
||||||
"""
|
"""
|
||||||
|
|
||||||
first = True
|
|
||||||
arangosh = False
|
arangosh = False
|
||||||
showdots = True
|
curl = False
|
||||||
|
first = True
|
||||||
lastline = None
|
lastline = None
|
||||||
short = ""
|
|
||||||
shortLines = 0
|
|
||||||
long = ""
|
long = ""
|
||||||
longLines = 0
|
longLines = 0
|
||||||
|
short = ""
|
||||||
|
shortLines = 0
|
||||||
shortable = False
|
shortable = False
|
||||||
|
showdots = True
|
||||||
|
|
||||||
|
CURL_STATE_CMD = 1
|
||||||
|
CURL_STATE_HEADER = 2
|
||||||
|
CURL_STATE_BODY = 3
|
||||||
|
|
||||||
# read in the context, split into long and short
|
# read in the context, split into long and short
|
||||||
infile = open(filepath, 'r')
|
infile = open(filepath, 'r')
|
||||||
|
@ -47,6 +52,7 @@ def example_content(filepath, fh, tag):
|
||||||
for line in infile:
|
for line in infile:
|
||||||
if first:
|
if first:
|
||||||
arangosh = line.startswith("arangosh>")
|
arangosh = line.startswith("arangosh>")
|
||||||
|
curl = line.startswith("shell> curl")
|
||||||
first = False
|
first = False
|
||||||
|
|
||||||
if arangosh:
|
if arangosh:
|
||||||
|
@ -57,11 +63,15 @@ def example_content(filepath, fh, tag):
|
||||||
lastline = None
|
lastline = None
|
||||||
|
|
||||||
short = short + line
|
short = short + line
|
||||||
|
shortLines = shortLines + 1
|
||||||
showdots = True
|
showdots = True
|
||||||
else:
|
else:
|
||||||
if showdots:
|
if showdots:
|
||||||
if lastline == None:
|
if lastline == None:
|
||||||
lastline = line
|
# lastline = line
|
||||||
|
shortable = True
|
||||||
|
showdots = False
|
||||||
|
lastline = None
|
||||||
else:
|
else:
|
||||||
# short = short + "~~~hidden~~~\n"
|
# short = short + "~~~hidden~~~\n"
|
||||||
# shortLines = shortLines + 1
|
# shortLines = shortLines + 1
|
||||||
|
@ -69,12 +79,26 @@ def example_content(filepath, fh, tag):
|
||||||
showdots = False
|
showdots = False
|
||||||
lastline = None
|
lastline = None
|
||||||
|
|
||||||
|
if curl:
|
||||||
|
if line.startswith("shell> curl"):
|
||||||
|
curlState = CURL_STATE_CMD
|
||||||
|
elif curlState == CURL_STATE_CMD and line.startswith("HTTP/1.1 "):
|
||||||
|
curlState = CURL_STATE_HEADER
|
||||||
|
elif curlState == CURL_STATE_HEADER and line.startswith("{"):
|
||||||
|
curlState = CURL_STATE_BODY
|
||||||
|
|
||||||
|
if curlState == CURL_STATE_CMD or curlState == CURL_STATE_HEADER:
|
||||||
|
short = short + line
|
||||||
|
shortLines = shortLines + 1
|
||||||
|
else:
|
||||||
|
shortable = True
|
||||||
|
|
||||||
long = long + line
|
long = long + line
|
||||||
longLines = longLines + 1
|
longLines = longLines + 1
|
||||||
|
|
||||||
# if lastline != None:
|
if lastline != None:
|
||||||
# short = short + lastline
|
short = short + lastline
|
||||||
# shortLines = shortLines + 1
|
shortLines = shortLines + 1
|
||||||
|
|
||||||
infile.close()
|
infile.close()
|
||||||
|
|
||||||
|
@ -109,7 +133,14 @@ def example_content(filepath, fh, tag):
|
||||||
fh.write("```\n")
|
fh.write("```\n")
|
||||||
fh.write("%s" % short)
|
fh.write("%s" % short)
|
||||||
fh.write("```\n")
|
fh.write("```\n")
|
||||||
fh.write("</pre><div class=\"example_show_button\">show execution results</div>\n")
|
|
||||||
|
if arangosh:
|
||||||
|
fh.write("</pre><div class=\"example_show_button\">show execution results</div>\n")
|
||||||
|
elif curl:
|
||||||
|
fh.write("</pre><div class=\"example_show_button\">show response body</div>\n")
|
||||||
|
else:
|
||||||
|
fh.write("</pre><div class=\"example_show_button\">show</div>\n")
|
||||||
|
|
||||||
fh.write("</div>\n")
|
fh.write("</div>\n")
|
||||||
|
|
||||||
fh.write("</div>\n")
|
fh.write("</div>\n")
|
||||||
|
|
|
@ -350,6 +350,7 @@ examples:
|
||||||
@srcdir@/js/client \
|
@srcdir@/js/client \
|
||||||
@srcdir@/js/common \
|
@srcdir@/js/common \
|
||||||
@srcdir@/js/server \
|
@srcdir@/js/server \
|
||||||
|
@srcdir@/js/apps/system/gharial \
|
||||||
@srcdir@/Documentation/Books/Users \
|
@srcdir@/Documentation/Books/Users \
|
||||||
@srcdir@/arangod/RestHandler \
|
@srcdir@/arangod/RestHandler \
|
||||||
@srcdir@/lib/Admin \
|
@srcdir@/lib/Admin \
|
||||||
|
|
|
@ -1331,64 +1331,68 @@ void RestReplicationHandler::handleCommandLoggerFollow () {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t const chunkSize = determineChunkSize();
|
int res = TRI_ERROR_NO_ERROR;
|
||||||
|
|
||||||
// initialise the dump container
|
try {
|
||||||
TRI_replication_dump_t dump;
|
// initialise the dump container
|
||||||
if (TRI_InitDumpReplication(&dump, _vocbase, (size_t) defaultChunkSize) != TRI_ERROR_NO_ERROR) {
|
TRI_replication_dump_t dump(_vocbase, (size_t) determineChunkSize());
|
||||||
generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_OUT_OF_MEMORY);
|
|
||||||
return;
|
// and dump
|
||||||
|
res = TRI_DumpLogReplication(_vocbase, &dump, tickStart, tickEnd);
|
||||||
|
|
||||||
|
if (res == TRI_ERROR_NO_ERROR) {
|
||||||
|
bool const checkMore = (dump._lastFoundTick > 0 && dump._lastFoundTick != state.lastDataTick);
|
||||||
|
|
||||||
|
// generate the result
|
||||||
|
size_t const length = TRI_LengthStringBuffer(dump._buffer);
|
||||||
|
|
||||||
|
if (length == 0) {
|
||||||
|
_response = createResponse(HttpResponse::NO_CONTENT);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_response = createResponse(HttpResponse::OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
_response->setContentType("application/x-arango-dump; charset=utf-8");
|
||||||
|
|
||||||
|
// set headers
|
||||||
|
_response->setHeader(TRI_REPLICATION_HEADER_CHECKMORE,
|
||||||
|
strlen(TRI_REPLICATION_HEADER_CHECKMORE),
|
||||||
|
checkMore ? "true" : "false");
|
||||||
|
|
||||||
|
_response->setHeader(TRI_REPLICATION_HEADER_LASTINCLUDED,
|
||||||
|
strlen(TRI_REPLICATION_HEADER_LASTINCLUDED),
|
||||||
|
StringUtils::itoa(dump._lastFoundTick));
|
||||||
|
|
||||||
|
_response->setHeader(TRI_REPLICATION_HEADER_LASTTICK,
|
||||||
|
strlen(TRI_REPLICATION_HEADER_LASTTICK),
|
||||||
|
StringUtils::itoa(state.lastTick));
|
||||||
|
|
||||||
|
_response->setHeader(TRI_REPLICATION_HEADER_ACTIVE,
|
||||||
|
strlen(TRI_REPLICATION_HEADER_ACTIVE),
|
||||||
|
"true");
|
||||||
|
|
||||||
|
if (length > 0) {
|
||||||
|
// transfer ownership of the buffer contents
|
||||||
|
_response->body().set(dump._buffer);
|
||||||
|
|
||||||
|
// to avoid double freeing
|
||||||
|
TRI_StealStringBuffer(dump._buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
insertClient(dump._lastFoundTick);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (triagens::arango::Exception const& ex) {
|
||||||
|
res = ex.code();
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
res = TRI_ERROR_INTERNAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int res = TRI_DumpLogReplication(_vocbase, &dump, tickStart, tickEnd, chunkSize);
|
if (res != TRI_ERROR_NO_ERROR) {
|
||||||
|
|
||||||
if (res == TRI_ERROR_NO_ERROR) {
|
|
||||||
bool const checkMore = (dump._lastFoundTick > 0 && dump._lastFoundTick != state.lastDataTick);
|
|
||||||
|
|
||||||
// generate the result
|
|
||||||
size_t const length = TRI_LengthStringBuffer(dump._buffer);
|
|
||||||
|
|
||||||
if (length == 0) {
|
|
||||||
_response = createResponse(HttpResponse::NO_CONTENT);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_response = createResponse(HttpResponse::OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
_response->setContentType("application/x-arango-dump; charset=utf-8");
|
|
||||||
|
|
||||||
// set headers
|
|
||||||
_response->setHeader(TRI_REPLICATION_HEADER_CHECKMORE,
|
|
||||||
strlen(TRI_REPLICATION_HEADER_CHECKMORE),
|
|
||||||
checkMore ? "true" : "false");
|
|
||||||
|
|
||||||
_response->setHeader(TRI_REPLICATION_HEADER_LASTINCLUDED,
|
|
||||||
strlen(TRI_REPLICATION_HEADER_LASTINCLUDED),
|
|
||||||
StringUtils::itoa(dump._lastFoundTick));
|
|
||||||
|
|
||||||
_response->setHeader(TRI_REPLICATION_HEADER_LASTTICK,
|
|
||||||
strlen(TRI_REPLICATION_HEADER_LASTTICK),
|
|
||||||
StringUtils::itoa(state.lastTick));
|
|
||||||
|
|
||||||
_response->setHeader(TRI_REPLICATION_HEADER_ACTIVE,
|
|
||||||
strlen(TRI_REPLICATION_HEADER_ACTIVE),
|
|
||||||
"true");
|
|
||||||
|
|
||||||
if (length > 0) {
|
|
||||||
// transfer ownership of the buffer contents
|
|
||||||
_response->body().set(dump._buffer);
|
|
||||||
|
|
||||||
// avoid double freeing
|
|
||||||
TRI_StealStringBuffer(dump._buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
insertClient(dump._lastFoundTick);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
generateError(HttpResponse::SERVER_ERROR, res);
|
generateError(HttpResponse::SERVER_ERROR, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
TRI_DestroyDumpReplication(&dump);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -3177,8 +3181,6 @@ void RestReplicationHandler::handleCommandDump () {
|
||||||
translateCollectionIds = StringUtils::boolean(value);
|
translateCollectionIds = StringUtils::boolean(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t const chunkSize = determineChunkSize();
|
|
||||||
|
|
||||||
TRI_vocbase_col_t* c = TRI_LookupCollectionByNameVocBase(_vocbase, collection);
|
TRI_vocbase_col_t* c = TRI_LookupCollectionByNameVocBase(_vocbase, collection);
|
||||||
|
|
||||||
if (c == nullptr) {
|
if (c == nullptr) {
|
||||||
|
@ -3204,20 +3206,14 @@ void RestReplicationHandler::handleCommandDump () {
|
||||||
TRI_ASSERT(col != nullptr);
|
TRI_ASSERT(col != nullptr);
|
||||||
|
|
||||||
// initialise the dump container
|
// initialise the dump container
|
||||||
TRI_replication_dump_t dump;
|
TRI_replication_dump_t dump(_vocbase, (size_t) determineChunkSize());
|
||||||
res = TRI_InitDumpReplication(&dump, _vocbase, (size_t) defaultChunkSize);
|
|
||||||
|
res = TRI_DumpCollectionReplication(&dump, col, tickStart, tickEnd, withTicks, translateCollectionIds);
|
||||||
|
|
||||||
if (res != TRI_ERROR_NO_ERROR) {
|
if (res != TRI_ERROR_NO_ERROR) {
|
||||||
THROW_ARANGO_EXCEPTION(res);
|
THROW_ARANGO_EXCEPTION(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = TRI_DumpCollectionReplication(&dump, col, tickStart, tickEnd, chunkSize, withTicks, translateCollectionIds);
|
|
||||||
|
|
||||||
if (res != TRI_ERROR_NO_ERROR) {
|
|
||||||
TRI_DestroyDumpReplication(&dump);
|
|
||||||
THROW_ARANGO_EXCEPTION(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
// generate the result
|
// generate the result
|
||||||
size_t const length = TRI_LengthStringBuffer(dump._buffer);
|
size_t const length = TRI_LengthStringBuffer(dump._buffer);
|
||||||
|
|
||||||
|
@ -3244,8 +3240,6 @@ void RestReplicationHandler::handleCommandDump () {
|
||||||
|
|
||||||
// avoid double freeing
|
// avoid double freeing
|
||||||
TRI_StealStringBuffer(dump._buffer);
|
TRI_StealStringBuffer(dump._buffer);
|
||||||
|
|
||||||
TRI_DestroyDumpReplication(&dump);
|
|
||||||
}
|
}
|
||||||
catch (triagens::arango::Exception const& ex) {
|
catch (triagens::arango::Exception const& ex) {
|
||||||
res = ex.code();
|
res = ex.code();
|
||||||
|
|
|
@ -100,6 +100,12 @@ struct TRI_vocbase_col_s;
|
||||||
|
|
||||||
#define TRI_COL_NAME_TRANSACTION "_trx"
|
#define TRI_COL_NAME_TRANSACTION "_trx"
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief predefined system collection name for replication
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define TRI_COL_NAME_REPLICATION "_replication"
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief predefined collection name for users
|
/// @brief predefined collection name for users
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -62,7 +62,7 @@ void TRI_GetTimeStampReplication (char* dst,
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
bool TRI_ExcludeCollectionReplication (const char* name) {
|
bool TRI_ExcludeCollectionReplication (const char* name) {
|
||||||
if (name == NULL) {
|
if (name == nullptr) {
|
||||||
// name invalid
|
// name invalid
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,9 @@ bool TRI_ExcludeCollectionReplication (const char* name) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TRI_EqualString(name, TRI_COL_NAME_USERS) ||
|
if (TRI_EqualString(name, TRI_COL_NAME_REPLICATION) ||
|
||||||
|
TRI_EqualString(name, TRI_COL_NAME_TRANSACTION) ||
|
||||||
|
TRI_EqualString(name, TRI_COL_NAME_USERS) ||
|
||||||
TRI_IsPrefixString(name, TRI_COL_NAME_STATISTICS) ||
|
TRI_IsPrefixString(name, TRI_COL_NAME_STATISTICS) ||
|
||||||
TRI_EqualString(name, "_aal") ||
|
TRI_EqualString(name, "_aal") ||
|
||||||
TRI_EqualString(name, "_fishbowl") ||
|
TRI_EqualString(name, "_fishbowl") ||
|
||||||
|
|
|
@ -33,7 +33,6 @@
|
||||||
#include "BasicsC/files.h"
|
#include "BasicsC/files.h"
|
||||||
#include "BasicsC/json.h"
|
#include "BasicsC/json.h"
|
||||||
#include "BasicsC/logging.h"
|
#include "BasicsC/logging.h"
|
||||||
#include "BasicsC/string-buffer.h"
|
|
||||||
#include "BasicsC/tri-strings.h"
|
#include "BasicsC/tri-strings.h"
|
||||||
|
|
||||||
#include "VocBase/collection.h"
|
#include "VocBase/collection.h"
|
||||||
|
@ -42,8 +41,6 @@
|
||||||
#include "VocBase/transaction.h"
|
#include "VocBase/transaction.h"
|
||||||
#include "VocBase/vocbase.h"
|
#include "VocBase/vocbase.h"
|
||||||
#include "VocBase/voc-shaper.h"
|
#include "VocBase/voc-shaper.h"
|
||||||
#include "Utils/Exception.h"
|
|
||||||
#include "Utils/transactions.h"
|
|
||||||
#include "Wal/Logfile.h"
|
#include "Wal/Logfile.h"
|
||||||
#include "Wal/LogfileManager.h"
|
#include "Wal/LogfileManager.h"
|
||||||
#include "Wal/Marker.h"
|
#include "Wal/Marker.h"
|
||||||
|
@ -108,86 +105,36 @@ typedef struct df_entry_s {
|
||||||
}
|
}
|
||||||
df_entry_t;
|
df_entry_t;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief container for a resolved collection name (cid => name)
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
typedef struct resolved_name_s {
|
|
||||||
TRI_voc_cid_t _cid;
|
|
||||||
char* _name;
|
|
||||||
}
|
|
||||||
resolved_name_t;
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- private functions
|
// --SECTION-- private functions
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief hashes a collection id
|
/// @brief translate a collection id into a collection name
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static uint64_t HashKeyCid (TRI_associative_pointer_t* array,
|
char const* NameFromCid (TRI_replication_dump_t* dump,
|
||||||
void const* key) {
|
TRI_voc_cid_t cid) {
|
||||||
TRI_voc_cid_t const* k = static_cast<TRI_voc_cid_t const*>(key);
|
auto it = dump->_collectionNames.find(cid);
|
||||||
|
|
||||||
return *k;
|
if (it != dump->_collectionNames.end()) {
|
||||||
}
|
// collection name is in cache already
|
||||||
|
return (*it).second.c_str();
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief hashes a collection name
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static uint64_t HashElementCid (TRI_associative_pointer_t* array,
|
|
||||||
void const* element) {
|
|
||||||
resolved_name_t const* e = static_cast<resolved_name_t const*>(element);
|
|
||||||
|
|
||||||
return e->_cid;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief compares a collection
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static bool IsEqualKeyElementCid (TRI_associative_pointer_t* array,
|
|
||||||
void const* key,
|
|
||||||
void const* element) {
|
|
||||||
TRI_voc_cid_t const* k = static_cast<TRI_voc_cid_t const*>(key);
|
|
||||||
resolved_name_t const* e = static_cast<resolved_name_t const*>(element);
|
|
||||||
|
|
||||||
return *k == e->_cid;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief lookup a collection name
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static bool LookupCollectionName (TRI_replication_dump_t* dump,
|
|
||||||
TRI_voc_cid_t cid,
|
|
||||||
char** result) {
|
|
||||||
|
|
||||||
TRI_ASSERT(cid > 0);
|
|
||||||
|
|
||||||
resolved_name_t* found = static_cast<resolved_name_t*>(TRI_LookupByKeyAssociativePointer(&dump->_collectionNames, &cid));
|
|
||||||
|
|
||||||
if (found == NULL) {
|
|
||||||
found = static_cast<resolved_name_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(resolved_name_t), false));
|
|
||||||
|
|
||||||
if (found == NULL) {
|
|
||||||
// out of memory;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
found->_cid = cid;
|
|
||||||
// name can be NULL if collection is not found.
|
|
||||||
// but we will still cache a NULL result!
|
|
||||||
found->_name = TRI_GetCollectionNameByIdVocBase(dump->_vocbase, cid);
|
|
||||||
|
|
||||||
TRI_InsertKeyAssociativePointer(&dump->_collectionNames, &found->_cid, found, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*result = found->_name;
|
// collection name not in cache yet
|
||||||
|
char* name = TRI_GetCollectionNameByIdVocBase(dump->_vocbase, cid);
|
||||||
|
|
||||||
return true;
|
if (name != nullptr) {
|
||||||
|
// insert into cache
|
||||||
|
dump->_collectionNames.insert(it, std::make_pair(cid, std::string(name)));
|
||||||
|
TRI_FreeString(TRI_UNKNOWN_MEM_ZONE, name);
|
||||||
|
|
||||||
|
// and look it up again
|
||||||
|
return NameFromCid(dump, cid);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -199,13 +146,9 @@ static bool AppendCollection (TRI_replication_dump_t* dump,
|
||||||
bool translateCollectionIds) {
|
bool translateCollectionIds) {
|
||||||
if (translateCollectionIds) {
|
if (translateCollectionIds) {
|
||||||
if (cid > 0) {
|
if (cid > 0) {
|
||||||
char* name;
|
char const* name = NameFromCid(dump, cid);
|
||||||
|
|
||||||
if (! LookupCollectionName(dump, cid, &name)) {
|
if (name != nullptr) {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name != NULL) {
|
|
||||||
APPEND_STRING(dump->_buffer, name);
|
APPEND_STRING(dump->_buffer, name);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -306,6 +249,21 @@ static TRI_vector_t GetRangeDatafiles (TRI_document_collection_t* document,
|
||||||
return datafiles;
|
return datafiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief append database id plus collection id
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static bool AppendContext (TRI_replication_dump_t* dump,
|
||||||
|
TRI_voc_tick_t databaseId,
|
||||||
|
TRI_voc_cid_t collectionId) {
|
||||||
|
APPEND_STRING(dump->_buffer, "\"database\":\"");
|
||||||
|
APPEND_UINT64(dump->_buffer, databaseId);
|
||||||
|
APPEND_STRING(dump->_buffer, "\",\"cid\":\"");
|
||||||
|
APPEND_UINT64(dump->_buffer, collectionId);
|
||||||
|
APPEND_STRING(dump->_buffer, "\",");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief stringify a raw marker from a datafile for a collection dump
|
/// @brief stringify a raw marker from a datafile for a collection dump
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -488,11 +446,11 @@ static bool StringifyWalMarkerDocument (TRI_replication_dump_t* dump,
|
||||||
TRI_df_marker_t const* marker) {
|
TRI_df_marker_t const* marker) {
|
||||||
auto m = reinterpret_cast<triagens::wal::document_marker_t const*>(marker);
|
auto m = reinterpret_cast<triagens::wal::document_marker_t const*>(marker);
|
||||||
|
|
||||||
APPEND_STRING(dump->_buffer, "\"database\":\"");
|
if (! AppendContext(dump, m->_databaseId, m->_collectionId)) {
|
||||||
APPEND_UINT64(dump->_buffer, m->_databaseId);
|
return false;
|
||||||
APPEND_STRING(dump->_buffer, "\",\"cid\":\"");
|
}
|
||||||
APPEND_UINT64(dump->_buffer, m->_collectionId);
|
|
||||||
APPEND_STRING(dump->_buffer, "\",\"tid\":\"");
|
APPEND_STRING(dump->_buffer, "\"tid\":\"");
|
||||||
APPEND_UINT64(dump->_buffer, m->_transactionId);
|
APPEND_UINT64(dump->_buffer, m->_transactionId);
|
||||||
APPEND_STRING(dump->_buffer, "\",\"key\":\"");
|
APPEND_STRING(dump->_buffer, "\",\"key\":\"");
|
||||||
APPEND_STRING(dump->_buffer, (char const*) m + m->_offsetKey);
|
APPEND_STRING(dump->_buffer, (char const*) m + m->_offsetKey);
|
||||||
|
@ -513,7 +471,7 @@ static bool StringifyWalMarkerDocument (TRI_replication_dump_t* dump,
|
||||||
shaped._data.data = (char*) m + m->_offsetJson;
|
shaped._data.data = (char*) m + m->_offsetJson;
|
||||||
|
|
||||||
triagens::basics::LegendReader lr((char const*) m + m->_offsetLegend);
|
triagens::basics::LegendReader lr((char const*) m + m->_offsetLegend);
|
||||||
if (! TRI_StringifyArrayShapedJson(&lr, dump->_buffer, &shaped, false)) {
|
if (! TRI_StringifyArrayShapedJson(&lr, dump->_buffer, &shaped, true)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -530,11 +488,11 @@ static bool StringifyWalMarkerEdge (TRI_replication_dump_t* dump,
|
||||||
TRI_df_marker_t const* marker) {
|
TRI_df_marker_t const* marker) {
|
||||||
auto m = reinterpret_cast<triagens::wal::edge_marker_t const*>(marker);
|
auto m = reinterpret_cast<triagens::wal::edge_marker_t const*>(marker);
|
||||||
|
|
||||||
APPEND_STRING(dump->_buffer, "\"database\":\"");
|
if (! AppendContext(dump, m->_databaseId, m->_collectionId)) {
|
||||||
APPEND_UINT64(dump->_buffer, m->_databaseId);
|
return false;
|
||||||
APPEND_STRING(dump->_buffer, "\",\"cid\":\"");
|
}
|
||||||
APPEND_UINT64(dump->_buffer, m->_collectionId);
|
|
||||||
APPEND_STRING(dump->_buffer, "\",\"tid\":\"");
|
APPEND_STRING(dump->_buffer, "\"tid\":\"");
|
||||||
APPEND_UINT64(dump->_buffer, m->_transactionId);
|
APPEND_UINT64(dump->_buffer, m->_transactionId);
|
||||||
APPEND_STRING(dump->_buffer, "\",\"key\":\"");
|
APPEND_STRING(dump->_buffer, "\",\"key\":\"");
|
||||||
APPEND_STRING(dump->_buffer, (char const*) m + m->_offsetKey);
|
APPEND_STRING(dump->_buffer, (char const*) m + m->_offsetKey);
|
||||||
|
@ -550,13 +508,13 @@ static bool StringifyWalMarkerEdge (TRI_replication_dump_t* dump,
|
||||||
|
|
||||||
// from
|
// from
|
||||||
APPEND_STRING(dump->_buffer, ",\"" TRI_VOC_ATTRIBUTE_FROM "\":\"");
|
APPEND_STRING(dump->_buffer, ",\"" TRI_VOC_ATTRIBUTE_FROM "\":\"");
|
||||||
APPEND_UINT64(dump->_buffer, m->_fromCid);
|
APPEND_UINT64(dump->_buffer, (uint64_t) m->_fromCid);
|
||||||
APPEND_STRING(dump->_buffer, "\\/");
|
APPEND_STRING(dump->_buffer, "\\/");
|
||||||
APPEND_STRING(dump->_buffer, (char const*) m + m->_offsetFromKey);
|
APPEND_STRING(dump->_buffer, (char const*) m + m->_offsetFromKey);
|
||||||
|
|
||||||
// to
|
// to
|
||||||
APPEND_STRING(dump->_buffer, "\",\"" TRI_VOC_ATTRIBUTE_TO "\":\"");
|
APPEND_STRING(dump->_buffer, "\",\"" TRI_VOC_ATTRIBUTE_TO "\":\"");
|
||||||
APPEND_UINT64(dump->_buffer, m->_toCid);
|
APPEND_UINT64(dump->_buffer, (uint64_t) m->_toCid);
|
||||||
APPEND_STRING(dump->_buffer, "\\/");
|
APPEND_STRING(dump->_buffer, "\\/");
|
||||||
APPEND_STRING(dump->_buffer, (char const*) m + m->_offsetFromKey);
|
APPEND_STRING(dump->_buffer, (char const*) m + m->_offsetFromKey);
|
||||||
APPEND_STRING(dump->_buffer, "\"");
|
APPEND_STRING(dump->_buffer, "\"");
|
||||||
|
@ -567,7 +525,7 @@ static bool StringifyWalMarkerEdge (TRI_replication_dump_t* dump,
|
||||||
shaped._data.data = (char*) m + m->_offsetJson;
|
shaped._data.data = (char*) m + m->_offsetJson;
|
||||||
|
|
||||||
triagens::basics::LegendReader lr((char const*) m + m->_offsetLegend);
|
triagens::basics::LegendReader lr((char const*) m + m->_offsetLegend);
|
||||||
if (! TRI_StringifyArrayShapedJson(&lr, dump->_buffer, &shaped, false)) {
|
if (! TRI_StringifyArrayShapedJson(&lr, dump->_buffer, &shaped, true)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -584,11 +542,10 @@ static bool StringifyWalMarkerRemove (TRI_replication_dump_t* dump,
|
||||||
TRI_df_marker_t const* marker) {
|
TRI_df_marker_t const* marker) {
|
||||||
auto m = reinterpret_cast<triagens::wal::remove_marker_t const*>(marker);
|
auto m = reinterpret_cast<triagens::wal::remove_marker_t const*>(marker);
|
||||||
|
|
||||||
APPEND_STRING(dump->_buffer, "\"database\":\"");
|
if (! AppendContext(dump, m->_databaseId, m->_collectionId)) {
|
||||||
APPEND_UINT64(dump->_buffer, m->_databaseId);
|
return false;
|
||||||
APPEND_STRING(dump->_buffer, "\",\"cid\":\"");
|
}
|
||||||
APPEND_UINT64(dump->_buffer, m->_collectionId);
|
APPEND_STRING(dump->_buffer, "\"tid\":\"");
|
||||||
APPEND_STRING(dump->_buffer, "\",\"tid\":\"");
|
|
||||||
APPEND_UINT64(dump->_buffer, m->_transactionId);
|
APPEND_UINT64(dump->_buffer, m->_transactionId);
|
||||||
APPEND_STRING(dump->_buffer, "\",\"key\":\"");
|
APPEND_STRING(dump->_buffer, "\",\"key\":\"");
|
||||||
APPEND_STRING(dump->_buffer, (char const*) m + sizeof(triagens::wal::remove_marker_t));
|
APPEND_STRING(dump->_buffer, (char const*) m + sizeof(triagens::wal::remove_marker_t));
|
||||||
|
@ -845,10 +802,108 @@ static bool StringifyWalMarker (TRI_replication_dump_t* dump,
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief whether or not a marker is replicated
|
/// @brief helper function to extract a database id from a marker
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static inline bool MustReplicateMarker (TRI_df_marker_t const* marker) {
|
template<typename T>
|
||||||
|
static TRI_voc_tick_t GetDatabaseId (TRI_df_marker_t const* marker) {
|
||||||
|
T const* m = reinterpret_cast<T const*>(marker);
|
||||||
|
return m->_databaseId;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief get the database id from a marker
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static TRI_voc_tick_t GetDatabaseFromWalMarker (TRI_df_marker_t const* marker) {
|
||||||
|
switch (marker->_type) {
|
||||||
|
case TRI_WAL_MARKER_ATTRIBUTE:
|
||||||
|
return GetDatabaseId<triagens::wal::attribute_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_SHAPE:
|
||||||
|
return GetDatabaseId<triagens::wal::shape_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_DOCUMENT:
|
||||||
|
return GetDatabaseId<triagens::wal::document_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_EDGE:
|
||||||
|
return GetDatabaseId<triagens::wal::edge_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_REMOVE:
|
||||||
|
return GetDatabaseId<triagens::wal::remove_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_BEGIN_TRANSACTION:
|
||||||
|
return GetDatabaseId<triagens::wal::transaction_begin_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_COMMIT_TRANSACTION:
|
||||||
|
return GetDatabaseId<triagens::wal::transaction_commit_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_ABORT_TRANSACTION:
|
||||||
|
return GetDatabaseId<triagens::wal::transaction_abort_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_CREATE_COLLECTION:
|
||||||
|
return GetDatabaseId<triagens::wal::collection_create_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_DROP_COLLECTION:
|
||||||
|
return GetDatabaseId<triagens::wal::collection_drop_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_RENAME_COLLECTION:
|
||||||
|
return GetDatabaseId<triagens::wal::collection_rename_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_CHANGE_COLLECTION:
|
||||||
|
return GetDatabaseId<triagens::wal::collection_change_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_CREATE_INDEX:
|
||||||
|
return GetDatabaseId<triagens::wal::index_create_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_DROP_INDEX:
|
||||||
|
return GetDatabaseId<triagens::wal::index_drop_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_CREATE_DATABASE:
|
||||||
|
return GetDatabaseId<triagens::wal::database_create_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_DROP_DATABASE:
|
||||||
|
return GetDatabaseId<triagens::wal::database_drop_marker_t>(marker);
|
||||||
|
default: {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief helper function to extract a collection id from a marker
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static TRI_voc_tick_t GetCollectionId (TRI_df_marker_t const* marker) {
|
||||||
|
T const* m = reinterpret_cast<T const*>(marker);
|
||||||
|
return m->_collectionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief get the collection id from a marker
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static TRI_voc_tick_t GetCollectionFromWalMarker (TRI_df_marker_t const* marker) {
|
||||||
|
switch (marker->_type) {
|
||||||
|
case TRI_WAL_MARKER_ATTRIBUTE:
|
||||||
|
return GetCollectionId<triagens::wal::attribute_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_SHAPE:
|
||||||
|
return GetCollectionId<triagens::wal::shape_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_DOCUMENT:
|
||||||
|
return GetCollectionId<triagens::wal::document_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_EDGE:
|
||||||
|
return GetCollectionId<triagens::wal::edge_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_REMOVE:
|
||||||
|
return GetCollectionId<triagens::wal::remove_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_CREATE_COLLECTION:
|
||||||
|
return GetCollectionId<triagens::wal::collection_create_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_DROP_COLLECTION:
|
||||||
|
return GetCollectionId<triagens::wal::collection_drop_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_RENAME_COLLECTION:
|
||||||
|
return GetCollectionId<triagens::wal::collection_rename_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_CHANGE_COLLECTION:
|
||||||
|
return GetCollectionId<triagens::wal::collection_change_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_CREATE_INDEX:
|
||||||
|
return GetCollectionId<triagens::wal::index_create_marker_t>(marker);
|
||||||
|
case TRI_WAL_MARKER_DROP_INDEX:
|
||||||
|
return GetCollectionId<triagens::wal::index_drop_marker_t>(marker);
|
||||||
|
default: {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief whether or not a marker should be replicated
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static inline bool MustReplicateWalMarkerType (TRI_df_marker_t const* marker) {
|
||||||
return (marker->_type == TRI_WAL_MARKER_DOCUMENT ||
|
return (marker->_type == TRI_WAL_MARKER_DOCUMENT ||
|
||||||
marker->_type == TRI_WAL_MARKER_EDGE ||
|
marker->_type == TRI_WAL_MARKER_EDGE ||
|
||||||
marker->_type == TRI_WAL_MARKER_REMOVE ||
|
marker->_type == TRI_WAL_MARKER_REMOVE ||
|
||||||
|
@ -863,6 +918,35 @@ static inline bool MustReplicateMarker (TRI_df_marker_t const* marker) {
|
||||||
marker->_type == TRI_WAL_MARKER_DROP_INDEX);
|
marker->_type == TRI_WAL_MARKER_DROP_INDEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief whether or not a marker is replicated
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static bool MustReplicateWalMarker (TRI_replication_dump_t* dump,
|
||||||
|
TRI_df_marker_t const* marker) {
|
||||||
|
// first check the marker type
|
||||||
|
if (! MustReplicateWalMarkerType(marker)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// then check if the marker belongs to the "correct" database
|
||||||
|
if (dump->_vocbase->_id != GetDatabaseFromWalMarker(marker)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// finally check if the marker is for a collection that we want to ignore
|
||||||
|
TRI_voc_cid_t cid = GetCollectionFromWalMarker(marker);
|
||||||
|
if (cid != 0) {
|
||||||
|
char const* name = NameFromCid(dump, cid);
|
||||||
|
|
||||||
|
if (name != nullptr && TRI_ExcludeCollectionReplication(name)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief dump data from a collection
|
/// @brief dump data from a collection
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -871,7 +955,6 @@ static int DumpCollection (TRI_replication_dump_t* dump,
|
||||||
TRI_document_collection_t* document,
|
TRI_document_collection_t* document,
|
||||||
TRI_voc_tick_t dataMin,
|
TRI_voc_tick_t dataMin,
|
||||||
TRI_voc_tick_t dataMax,
|
TRI_voc_tick_t dataMax,
|
||||||
uint64_t chunkSize,
|
|
||||||
bool withTicks,
|
bool withTicks,
|
||||||
bool translateCollectionIds) {
|
bool translateCollectionIds) {
|
||||||
TRI_vector_t datafiles;
|
TRI_vector_t datafiles;
|
||||||
|
@ -892,11 +975,10 @@ static int DumpCollection (TRI_replication_dump_t* dump,
|
||||||
// until a certain tick.
|
// until a certain tick.
|
||||||
triagens::arango::TransactionBase trx(true);
|
triagens::arango::TransactionBase trx(true);
|
||||||
|
|
||||||
LOG_TRACE("dumping collection %llu, tick range %llu - %llu, chunk size %llu",
|
LOG_TRACE("dumping collection %llu, tick range %llu - %llu",
|
||||||
(unsigned long long) document->_info._cid,
|
(unsigned long long) document->_info._cid,
|
||||||
(unsigned long long) dataMin,
|
(unsigned long long) dataMin,
|
||||||
(unsigned long long) dataMax,
|
(unsigned long long) dataMax);
|
||||||
(unsigned long long) chunkSize);
|
|
||||||
|
|
||||||
buffer = dump->_buffer;
|
buffer = dump->_buffer;
|
||||||
datafiles = GetRangeDatafiles(document, dataMin, dataMax);
|
datafiles = GetRangeDatafiles(document, dataMin, dataMax);
|
||||||
|
@ -1034,7 +1116,7 @@ static int DumpCollection (TRI_replication_dump_t* dump,
|
||||||
goto NEXT_DF;
|
goto NEXT_DF;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((uint64_t) TRI_LengthStringBuffer(buffer) > chunkSize) {
|
if ((uint64_t) TRI_LengthStringBuffer(buffer) > dump->_chunkSize) {
|
||||||
// abort the iteration
|
// abort the iteration
|
||||||
bufferFull = true;
|
bufferFull = true;
|
||||||
|
|
||||||
|
@ -1085,7 +1167,6 @@ int TRI_DumpCollectionReplication (TRI_replication_dump_t* dump,
|
||||||
TRI_vocbase_col_t* col,
|
TRI_vocbase_col_t* col,
|
||||||
TRI_voc_tick_t dataMin,
|
TRI_voc_tick_t dataMin,
|
||||||
TRI_voc_tick_t dataMax,
|
TRI_voc_tick_t dataMax,
|
||||||
uint64_t chunkSize,
|
|
||||||
bool withTicks,
|
bool withTicks,
|
||||||
bool translateCollectionIds) {
|
bool translateCollectionIds) {
|
||||||
TRI_ASSERT(col != nullptr);
|
TRI_ASSERT(col != nullptr);
|
||||||
|
@ -1103,7 +1184,7 @@ int TRI_DumpCollectionReplication (TRI_replication_dump_t* dump,
|
||||||
// block compaction
|
// block compaction
|
||||||
TRI_ReadLockReadWriteLock(&document->_compactionLock);
|
TRI_ReadLockReadWriteLock(&document->_compactionLock);
|
||||||
|
|
||||||
int res = DumpCollection(dump, document, dataMin, dataMax, chunkSize, withTicks, translateCollectionIds);
|
int res = DumpCollection(dump, document, dataMin, dataMax, withTicks, translateCollectionIds);
|
||||||
|
|
||||||
TRI_ReadUnlockReadWriteLock(&document->_compactionLock);
|
TRI_ReadUnlockReadWriteLock(&document->_compactionLock);
|
||||||
|
|
||||||
|
@ -1119,12 +1200,10 @@ int TRI_DumpCollectionReplication (TRI_replication_dump_t* dump,
|
||||||
int TRI_DumpLogReplication (TRI_vocbase_t* vocbase,
|
int TRI_DumpLogReplication (TRI_vocbase_t* vocbase,
|
||||||
TRI_replication_dump_t* dump,
|
TRI_replication_dump_t* dump,
|
||||||
TRI_voc_tick_t tickMin,
|
TRI_voc_tick_t tickMin,
|
||||||
TRI_voc_tick_t tickMax,
|
TRI_voc_tick_t tickMax) {
|
||||||
uint64_t chunkSize) {
|
LOG_TRACE("dumping log, tick range %llu - %llu",
|
||||||
LOG_TRACE("dumping log, tick range %llu - %llu, chunk size %llu",
|
|
||||||
(unsigned long long) tickMin,
|
(unsigned long long) tickMin,
|
||||||
(unsigned long long) tickMax,
|
(unsigned long long) tickMax);
|
||||||
(unsigned long long) chunkSize);
|
|
||||||
|
|
||||||
// ask the logfile manager which datafiles qualify
|
// ask the logfile manager which datafiles qualify
|
||||||
std::vector<triagens::wal::Logfile*> logfiles = triagens::wal::LogfileManager::instance()->getLogfilesForTickRange(tickMin, tickMax);
|
std::vector<triagens::wal::Logfile*> logfiles = triagens::wal::LogfileManager::instance()->getLogfilesForTickRange(tickMin, tickMax);
|
||||||
|
@ -1173,7 +1252,7 @@ int TRI_DumpLogReplication (TRI_vocbase_t* vocbase,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! MustReplicateMarker(marker)) {
|
if (! MustReplicateWalMarker(dump, marker)) {
|
||||||
// check if we can abort searching
|
// check if we can abort searching
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1185,7 +1264,7 @@ int TRI_DumpLogReplication (TRI_vocbase_t* vocbase,
|
||||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
|
THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((uint64_t) TRI_LengthStringBuffer(dump->_buffer) > chunkSize) {
|
if ((uint64_t) TRI_LengthStringBuffer(dump->_buffer) > dump->_chunkSize) {
|
||||||
// abort the iteration
|
// abort the iteration
|
||||||
bufferFull = true;
|
bufferFull = true;
|
||||||
break;
|
break;
|
||||||
|
@ -1227,66 +1306,6 @@ int TRI_DumpLogReplication (TRI_vocbase_t* vocbase,
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief initialise a replication dump container
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
int TRI_InitDumpReplication (TRI_replication_dump_t* dump,
|
|
||||||
TRI_vocbase_t* vocbase,
|
|
||||||
size_t bufferSize) {
|
|
||||||
int res;
|
|
||||||
|
|
||||||
TRI_ASSERT(vocbase != nullptr);
|
|
||||||
|
|
||||||
dump->_vocbase = vocbase;
|
|
||||||
dump->_lastFoundTick = 0;
|
|
||||||
dump->_lastSid = 0;
|
|
||||||
dump->_lastShape = nullptr;
|
|
||||||
dump->_failed = false;
|
|
||||||
dump->_bufferFull = false;
|
|
||||||
dump->_hasMore = false;
|
|
||||||
|
|
||||||
dump->_buffer = TRI_CreateSizedStringBuffer(TRI_CORE_MEM_ZONE, bufferSize);
|
|
||||||
|
|
||||||
if (dump->_buffer == nullptr) {
|
|
||||||
return TRI_ERROR_OUT_OF_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = TRI_InitAssociativePointer(&dump->_collectionNames,
|
|
||||||
TRI_UNKNOWN_MEM_ZONE,
|
|
||||||
HashKeyCid,
|
|
||||||
HashElementCid,
|
|
||||||
IsEqualKeyElementCid,
|
|
||||||
nullptr);
|
|
||||||
|
|
||||||
if (res != TRI_ERROR_NO_ERROR) {
|
|
||||||
TRI_FreeStringBuffer(TRI_CORE_MEM_ZONE, dump->_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief destroy a replication dump container
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void TRI_DestroyDumpReplication (TRI_replication_dump_t* dump) {
|
|
||||||
for (size_t i = 0; i < dump->_collectionNames._nrAlloc; ++i) {
|
|
||||||
resolved_name_t* found = static_cast<resolved_name_t*>(dump->_collectionNames._table[i]);
|
|
||||||
|
|
||||||
if (found != nullptr) {
|
|
||||||
if (found->_name != nullptr) {
|
|
||||||
// name can be NULL
|
|
||||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, found->_name);
|
|
||||||
}
|
|
||||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, found);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TRI_DestroyAssociativePointer(&dump->_collectionNames);
|
|
||||||
TRI_FreeStringBuffer(TRI_CORE_MEM_ZONE, dump->_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- END-OF-FILE
|
// --SECTION-- END-OF-FILE
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
|
@ -33,18 +33,19 @@
|
||||||
#include "Basics/Common.h"
|
#include "Basics/Common.h"
|
||||||
|
|
||||||
#include "BasicsC/associative.h"
|
#include "BasicsC/associative.h"
|
||||||
|
#include "BasicsC/string-buffer.h"
|
||||||
#include "ShapedJson/shaped-json.h"
|
#include "ShapedJson/shaped-json.h"
|
||||||
|
#include "Utils/Exception.h"
|
||||||
#include "VocBase/replication-common.h"
|
#include "VocBase/replication-common.h"
|
||||||
#include "VocBase/voc-types.h"
|
#include "VocBase/voc-types.h"
|
||||||
|
#include "VocBase/vocbase.h"
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- forward declarations
|
// --SECTION-- forward declarations
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
struct TRI_shape_s;
|
struct TRI_shape_s;
|
||||||
struct TRI_string_buffer_s;
|
|
||||||
struct TRI_vocbase_col_s;
|
struct TRI_vocbase_col_s;
|
||||||
struct TRI_vocbase_s;
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- REPLICATION LOGGER
|
// --SECTION-- REPLICATION LOGGER
|
||||||
|
@ -58,18 +59,43 @@ struct TRI_vocbase_s;
|
||||||
/// @brief replication dump container
|
/// @brief replication dump container
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
typedef struct TRI_replication_dump_s {
|
struct TRI_replication_dump_t {
|
||||||
struct TRI_string_buffer_s* _buffer;
|
TRI_replication_dump_t (TRI_vocbase_t* vocbase,
|
||||||
|
size_t chunkSize)
|
||||||
|
: _vocbase(vocbase),
|
||||||
|
_buffer(nullptr),
|
||||||
|
_chunkSize(chunkSize),
|
||||||
|
_lastFoundTick(0),
|
||||||
|
_lastSid(0),
|
||||||
|
_lastShape(nullptr),
|
||||||
|
_collectionNames(),
|
||||||
|
_failed(false),
|
||||||
|
_bufferFull(false),
|
||||||
|
_hasMore(false) {
|
||||||
|
|
||||||
|
_buffer = TRI_CreateSizedStringBuffer(TRI_UNKNOWN_MEM_ZONE, chunkSize);
|
||||||
|
|
||||||
|
if (_buffer == nullptr) {
|
||||||
|
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~TRI_replication_dump_t () {
|
||||||
|
TRI_FreeStringBuffer(TRI_UNKNOWN_MEM_ZONE, _buffer);
|
||||||
|
_buffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRI_vocbase_t* _vocbase;
|
||||||
|
TRI_string_buffer_t* _buffer;
|
||||||
|
size_t _chunkSize;
|
||||||
TRI_voc_tick_t _lastFoundTick;
|
TRI_voc_tick_t _lastFoundTick;
|
||||||
TRI_shape_sid_t _lastSid;
|
TRI_shape_sid_t _lastSid;
|
||||||
struct TRI_shape_s const* _lastShape;
|
struct TRI_shape_s const* _lastShape;
|
||||||
struct TRI_vocbase_s* _vocbase;
|
std::unordered_map<TRI_voc_cid_t, std::string> _collectionNames;
|
||||||
TRI_associative_pointer_t _collectionNames;
|
|
||||||
bool _failed;
|
bool _failed;
|
||||||
bool _hasMore;
|
|
||||||
bool _bufferFull;
|
bool _bufferFull;
|
||||||
}
|
bool _hasMore;
|
||||||
TRI_replication_dump_t;
|
};
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- public functions
|
// --SECTION-- public functions
|
||||||
|
@ -83,7 +109,6 @@ int TRI_DumpCollectionReplication (TRI_replication_dump_t*,
|
||||||
struct TRI_vocbase_col_s*,
|
struct TRI_vocbase_col_s*,
|
||||||
TRI_voc_tick_t,
|
TRI_voc_tick_t,
|
||||||
TRI_voc_tick_t,
|
TRI_voc_tick_t,
|
||||||
uint64_t,
|
|
||||||
bool,
|
bool,
|
||||||
bool);
|
bool);
|
||||||
|
|
||||||
|
@ -94,22 +119,7 @@ int TRI_DumpCollectionReplication (TRI_replication_dump_t*,
|
||||||
int TRI_DumpLogReplication (struct TRI_vocbase_s*,
|
int TRI_DumpLogReplication (struct TRI_vocbase_s*,
|
||||||
TRI_replication_dump_t*,
|
TRI_replication_dump_t*,
|
||||||
TRI_voc_tick_t,
|
TRI_voc_tick_t,
|
||||||
TRI_voc_tick_t,
|
TRI_voc_tick_t);
|
||||||
uint64_t);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief initialise a replication dump container
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
int TRI_InitDumpReplication (TRI_replication_dump_t*,
|
|
||||||
struct TRI_vocbase_s*,
|
|
||||||
size_t);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief destroy a replication dump container
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void TRI_DestroyDumpReplication (TRI_replication_dump_t*);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1839,8 +1839,8 @@ char* TRI_GetCollectionNameByIdVocBase (TRI_vocbase_t* vocbase,
|
||||||
|
|
||||||
TRI_vocbase_col_t* found = static_cast<TRI_vocbase_col_t*>(TRI_LookupByKeyAssociativePointer(&vocbase->_collectionsById, &id));
|
TRI_vocbase_col_t* found = static_cast<TRI_vocbase_col_t*>(TRI_LookupByKeyAssociativePointer(&vocbase->_collectionsById, &id));
|
||||||
|
|
||||||
if (found == NULL) {
|
if (found == nullptr) {
|
||||||
name = NULL;
|
name = nullptr;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
name = TRI_DuplicateStringZ(TRI_UNKNOWN_MEM_ZONE, found->_name);
|
name = TRI_DuplicateStringZ(TRI_UNKNOWN_MEM_ZONE, found->_name);
|
||||||
|
|
|
@ -275,11 +275,7 @@ namespace triagens {
|
||||||
inline char* end () const {
|
inline char* end () const {
|
||||||
return _buffer + _size;
|
return _buffer + _size;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
inline char* payload () const {
|
|
||||||
return begin() + sizeof(TRI_df_marker_t);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief return the size of the marker
|
/// @brief return the size of the marker
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -160,10 +160,12 @@
|
||||||
var i;
|
var i;
|
||||||
|
|
||||||
if (typeof body !== 'string') {
|
if (typeof body !== 'string') {
|
||||||
body = JSON.stringify(body);
|
internal.startCaptureMode();
|
||||||
|
print(body);
|
||||||
|
body = internal.stopCaptureMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
curl = "unix> curl ";
|
curl = "shell> curl ";
|
||||||
|
|
||||||
if (method === 'POST') {
|
if (method === 'POST') {
|
||||||
response = internal.arango.POST_RAW(url, body, headers);
|
response = internal.arango.POST_RAW(url, body, headers);
|
||||||
|
|
|
@ -1548,8 +1548,8 @@ var _extendEdgeDefinitions = function (edgeDefinition) {
|
||||||
/// The creation of a graph requires the name of the graph and a definition of its edges.
|
/// The creation of a graph requires the name of the graph and a definition of its edges.
|
||||||
///
|
///
|
||||||
/// For every type of edge definition a convenience method exists that can be used to create a graph.
|
/// For every type of edge definition a convenience method exists that can be used to create a graph.
|
||||||
/// Optionaly a list of vertex collections can be added, which are not used in any edge definition.
|
/// Optionally a list of vertex collections can be added, which are not used in any edge definition.
|
||||||
/// These collections are refered to as orphan collections within this chapter.
|
/// These collections are referred to as orphan collections within this chapter.
|
||||||
/// All collections used within the creation process are created if they do not exist.
|
/// All collections used within the creation process are created if they do not exist.
|
||||||
///
|
///
|
||||||
/// *Parameter*
|
/// *Parameter*
|
||||||
|
@ -2009,7 +2009,7 @@ var sortEdgeDefinition = function(edgeDefinition) {
|
||||||
/// g.relation.save("male/bob", "female/alice", {type: "married", _key: "bobAndAlice"});
|
/// g.relation.save("male/bob", "female/alice", {type: "married", _key: "bobAndAlice"});
|
||||||
/// @END_EXAMPLE_ARANGOSH_OUTPUT
|
/// @END_EXAMPLE_ARANGOSH_OUTPUT
|
||||||
///
|
///
|
||||||
/// If the collections of *from* and *to* are not defined in an edgeDefinition of the graph,
|
/// If the collections of *from* and *to* are not defined in an edge definition of the graph,
|
||||||
/// the edge will not be stored.
|
/// the edge will not be stored.
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
|
@ -2226,7 +2226,7 @@ var checkIfMayBeDropped = function(colName, graphName, graphs) {
|
||||||
/// *Remove a graph*
|
/// *Remove a graph*
|
||||||
///
|
///
|
||||||
/// A graph can be dropped by its name.
|
/// A graph can be dropped by its name.
|
||||||
/// This will automatically drop al collections contained in the graph as
|
/// This will automatically drop all collections contained in the graph as
|
||||||
/// long as they are not used within other graphs.
|
/// long as they are not used within other graphs.
|
||||||
/// To drop the collections, the optional parameter *drop-collections* can be set to *true*.
|
/// To drop the collections, the optional parameter *drop-collections* can be set to *true*.
|
||||||
///
|
///
|
||||||
|
|
|
@ -160,10 +160,12 @@
|
||||||
var i;
|
var i;
|
||||||
|
|
||||||
if (typeof body !== 'string') {
|
if (typeof body !== 'string') {
|
||||||
body = JSON.stringify(body);
|
internal.startCaptureMode();
|
||||||
|
print(body);
|
||||||
|
body = internal.stopCaptureMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
curl = "unix> curl ";
|
curl = "shell> curl ";
|
||||||
|
|
||||||
if (method === 'POST') {
|
if (method === 'POST') {
|
||||||
response = internal.arango.POST_RAW(url, body, headers);
|
response = internal.arango.POST_RAW(url, body, headers);
|
||||||
|
|
|
@ -2008,7 +2008,7 @@ var sortEdgeDefinition = function(edgeDefinition) {
|
||||||
/// g.relation.save("male/bob", "female/alice", {type: "married", _key: "bobAndAlice"});
|
/// g.relation.save("male/bob", "female/alice", {type: "married", _key: "bobAndAlice"});
|
||||||
/// @END_EXAMPLE_ARANGOSH_OUTPUT
|
/// @END_EXAMPLE_ARANGOSH_OUTPUT
|
||||||
///
|
///
|
||||||
/// If the collections of *from* and *to* are not defined in an edgeDefinition of the graph,
|
/// If the collections of *from* and *to* are not defined in an edge definition of the graph,
|
||||||
/// the edge will not be stored.
|
/// the edge will not be stored.
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
|
|
|
@ -61,7 +61,8 @@ BaseMiddleware = function () {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
body: function () {
|
body: function () {
|
||||||
return JSON.parse(this.requestBody);
|
var requestBody = this.requestBody || '{}';
|
||||||
|
return JSON.parse(requestBody);
|
||||||
},
|
},
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -102,6 +102,7 @@ Model = function (attributes) {
|
||||||
|
|
||||||
this.attributes = whitelistProperties(attributes, this.constructor.attributes, true);
|
this.attributes = whitelistProperties(attributes, this.constructor.attributes, true);
|
||||||
this.attributes = fillInDefaults(this.attributes, this.constructor.attributes);
|
this.attributes = fillInDefaults(this.attributes, this.constructor.attributes);
|
||||||
|
this.whitelistedAttributes = whitelistProperties(this.attributes, this.constructor.attributes);
|
||||||
};
|
};
|
||||||
|
|
||||||
Model.fromClient = function (attributes) {
|
Model.fromClient = function (attributes) {
|
||||||
|
@ -269,8 +270,7 @@ _.extend(Model.prototype, {
|
||||||
|
|
||||||
forClient: function () {
|
forClient: function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
var result = whitelistProperties(this.attributes, this.constructor.attributes);
|
return this.whitelistedAttributes;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue