mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of github.com:triAGENS/ArangoDB into devel
This commit is contained in:
commit
4e10a5aa76
|
@ -7,6 +7,9 @@ mr-*.h
|
|||
*~
|
||||
*.pyc
|
||||
|
||||
*.orig
|
||||
*.rej
|
||||
|
||||
.libev-build-64
|
||||
.v8-build-64
|
||||
.icu-build-64
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
db._drop("demo");
|
||||
db._create("demo");
|
||||
db.demo.save({
|
||||
"_key" : "schlonz",
|
||||
"firstName" : "Hugo",
|
||||
"lastName" : "Schlonz",
|
||||
"address" : {
|
||||
"street" : "Strasse 1",
|
||||
"city" : "Hier"
|
||||
},
|
||||
"hobbies" : [
|
||||
"swimming",
|
||||
"biking",
|
||||
"programming"
|
||||
]
|
||||
});
|
||||
|
||||
db._drop("animals");
|
||||
db._create("animals");
|
|
@ -128,7 +128,7 @@ describe ArangoDB do
|
|||
|
||||
doc.code.should eq(400)
|
||||
doc.parsed_response['error'].should eq(true)
|
||||
doc.parsed_response['errorNum'].should eq(405)
|
||||
doc.parsed_response['errorNum'].should eq(1218)
|
||||
doc.parsed_response['code'].should eq(400)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
end
|
||||
|
|
|
@ -346,14 +346,14 @@ TRI_aql_index_t* TRI_DetermineIndexAql (TRI_aql_context_t* const context,
|
|||
|
||||
if (idx->_type == TRI_IDX_TYPE_PRIMARY_INDEX) {
|
||||
// primary index key names must be treated differently. _id and _key are the same
|
||||
if (! TRI_EqualString("_id", fieldName) && ! TRI_EqualString("_key", fieldName)) {
|
||||
if (! TRI_EqualString("_id", fieldName) && ! TRI_EqualString(TRI_VOC_ATTRIBUTE_KEY, fieldName)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (idx->_type == TRI_IDX_TYPE_EDGE_INDEX) {
|
||||
// edge index key names must be treated differently. _from and _to can be used independently
|
||||
if (! TRI_EqualString("_from", fieldName) &&
|
||||
! TRI_EqualString("_to", fieldName)) {
|
||||
if (! TRI_EqualString(TRI_VOC_ATTRIBUTE_FROM, fieldName) &&
|
||||
! TRI_EqualString(TRI_VOC_ATTRIBUTE_TO, fieldName)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,6 +77,7 @@ bin_arangod_SOURCES = \
|
|||
arangod/SkipLists/skiplistIndex.c \
|
||||
arangod/SkipListsEx/skiplistEx.c \
|
||||
arangod/SkipListsEx/skiplistExIndex.c \
|
||||
arangod/Utils/DocumentHelper.cpp \
|
||||
arangod/V8Server/ApplicationV8.cpp \
|
||||
arangod/V8Server/v8-actions.cpp \
|
||||
arangod/V8Server/v8-query.cpp \
|
||||
|
|
|
@ -28,15 +28,21 @@
|
|||
#include "ReplicationFetcher.h"
|
||||
|
||||
#include "BasicsC/json.h"
|
||||
#include "BasicsC/tri-strings.h"
|
||||
#include "Basics/JsonHelper.h"
|
||||
#include "Rest/HttpRequest.h"
|
||||
#include "Rest/SslInterface.h"
|
||||
#include "SimpleHttpClient/GeneralClientConnection.h"
|
||||
#include "SimpleHttpClient/SimpleHttpClient.h"
|
||||
#include "SimpleHttpClient/SimpleHttpResult.h"
|
||||
#include "Utils/DocumentHelper.h"
|
||||
#include "VocBase/collection.h"
|
||||
#include "VocBase/edge-collection.h"
|
||||
#include "VocBase/primary-collection.h"
|
||||
#include "VocBase/replication.h"
|
||||
#include "VocBase/server-id.h"
|
||||
#include "VocBase/transaction.h"
|
||||
#include "VocBase/update-policy.h"
|
||||
#include "VocBase/vocbase.h"
|
||||
|
||||
using namespace std;
|
||||
|
@ -45,13 +51,6 @@ using namespace triagens::rest;
|
|||
using namespace triagens::arango;
|
||||
using namespace triagens::httpclient;
|
||||
|
||||
#define ENSURE_JSON(what, check, msg) \
|
||||
if (what == 0 || ! JsonHelper::check(what)) { \
|
||||
errorMsg = msg; \
|
||||
\
|
||||
return TRI_ERROR_REPLICATION_INVALID_RESPONSE; \
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- constructors and destructors
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -169,6 +168,29 @@ int ReplicationFetcher::run () {
|
|||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief comparator to sort collections
|
||||
/// sort order is by collection type first (vertices before edges), then name
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int ReplicationFetcher::sortCollections (const void* l, const void* r) {
|
||||
TRI_json_t const* left = JsonHelper::getArrayElement((TRI_json_t const*) l, "parameters");
|
||||
TRI_json_t const* right = JsonHelper::getArrayElement((TRI_json_t const*) r, "parameters");
|
||||
|
||||
int leftType = (int) JsonHelper::getNumberValue(left, "type", 2);
|
||||
int rightType = (int) JsonHelper::getNumberValue(right, "type", 2);
|
||||
|
||||
|
||||
if (leftType != rightType) {
|
||||
return leftType - rightType;
|
||||
}
|
||||
|
||||
string leftName = JsonHelper::getStringValue(left, "name", "");
|
||||
string rightName = JsonHelper::getStringValue(right, "name", "");
|
||||
|
||||
return strcmp(leftName.c_str(), rightName.c_str());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -182,10 +204,134 @@ int ReplicationFetcher::run () {
|
|||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int ReplicationFetcher::applyCollectionDump (TRI_voc_cid_t cid,
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief apply the data from a collection dump
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int ReplicationFetcher::applyMarker (TRI_transaction_collection_t* trxCollection,
|
||||
char const* type,
|
||||
const TRI_voc_key_t key,
|
||||
TRI_json_t const* json,
|
||||
string& errorMsg) {
|
||||
|
||||
if (TRI_EqualString(type, "marker-document") ||
|
||||
TRI_EqualString(type, "marker-edge")) {
|
||||
// {"type":"marker-document","key":"230274209405676","doc":{"_key":"230274209405676","_rev":"230274209405676","foo":"bar"}}
|
||||
|
||||
TRI_primary_collection_t* primary = trxCollection->_collection->_collection;
|
||||
|
||||
TRI_shaped_json_t* shaped = TRI_ShapedJsonJson(primary->_shaper, json);
|
||||
|
||||
int res;
|
||||
|
||||
if (shaped != 0) {
|
||||
TRI_doc_mptr_t mptr;
|
||||
|
||||
res = primary->read(trxCollection, key, &mptr, false);
|
||||
|
||||
if (res == TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND) {
|
||||
// insert
|
||||
const TRI_voc_rid_t rid = StringUtils::uint64(JsonHelper::getStringValue(json, TRI_VOC_ATTRIBUTE_REV, ""));
|
||||
|
||||
if (type[7] == 'e') {
|
||||
// edge
|
||||
if (primary->base._info._type != TRI_COL_TYPE_EDGE) {
|
||||
res = TRI_ERROR_ARANGO_COLLECTION_TYPE_INVALID;
|
||||
}
|
||||
else {
|
||||
res = TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
string from = JsonHelper::getStringValue(json, TRI_VOC_ATTRIBUTE_FROM, "");
|
||||
string to = JsonHelper::getStringValue(json, TRI_VOC_ATTRIBUTE_TO, "");
|
||||
|
||||
|
||||
// parse _from
|
||||
TRI_document_edge_t edge;
|
||||
if (! DocumentHelper::parseDocumentId(from.c_str(), edge._fromCid, &edge._fromKey)) {
|
||||
res = TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD;
|
||||
}
|
||||
|
||||
// parse _to
|
||||
if (! DocumentHelper::parseDocumentId(to.c_str(), edge._toCid, &edge._toKey)) {
|
||||
res = TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD;
|
||||
}
|
||||
|
||||
if (res == TRI_ERROR_NO_ERROR) {
|
||||
res = primary->insert(trxCollection, key, rid, &mptr, TRI_DOC_MARKER_KEY_EDGE, shaped, &edge, false, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// document
|
||||
if (primary->base._info._type != TRI_COL_TYPE_DOCUMENT) {
|
||||
res = TRI_ERROR_ARANGO_COLLECTION_TYPE_INVALID;
|
||||
}
|
||||
else {
|
||||
res = primary->insert(trxCollection, key, rid, &mptr, TRI_DOC_MARKER_KEY_DOCUMENT, shaped, 0, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// update
|
||||
|
||||
TRI_doc_update_policy_t policy;
|
||||
TRI_InitUpdatePolicy(&policy, TRI_DOC_UPDATE_LAST_WRITE, 0, 0);
|
||||
|
||||
res = primary->update(trxCollection, key, &mptr, shaped, &policy, false, false);
|
||||
}
|
||||
|
||||
TRI_FreeShapedJson(primary->_shaper, shaped);
|
||||
}
|
||||
else {
|
||||
res = TRI_ERROR_OUT_OF_MEMORY;
|
||||
errorMsg = TRI_errno_string(res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
else if (TRI_EqualString(type, "marker-deletion")) {
|
||||
// {"type":"marker-deletion","key":"592063"}
|
||||
|
||||
TRI_doc_update_policy_t policy;
|
||||
TRI_InitUpdatePolicy(&policy, TRI_DOC_UPDATE_LAST_WRITE, 0, 0);
|
||||
|
||||
TRI_primary_collection_t* primary = trxCollection->_collection->_collection;
|
||||
|
||||
int res = primary->remove(trxCollection, key, &policy, false, false);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
if (res == TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND) {
|
||||
// ignore this error
|
||||
res = TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
else {
|
||||
errorMsg = "document removal operation failed: " + string(TRI_errno_string(res));
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
else {
|
||||
errorMsg = "unexpected marker type '" + string(type) + "'";
|
||||
|
||||
return TRI_ERROR_REPLICATION_UNEXPECTED_MARKER;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief apply the data from a collection dump
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int ReplicationFetcher::applyCollectionDump (TRI_transaction_collection_t* trxCollection,
|
||||
SimpleHttpResult* response,
|
||||
string& errorMsg) {
|
||||
string& errorMsg,
|
||||
uint64_t& markerCount) {
|
||||
|
||||
const string invalidMsg = "received invalid JSON data for collection " +
|
||||
StringUtils::itoa(trxCollection->_cid);
|
||||
|
||||
std::stringstream& data = response->getBody();
|
||||
|
||||
while (true) {
|
||||
|
@ -194,8 +340,11 @@ int ReplicationFetcher::applyCollectionDump (TRI_voc_cid_t cid,
|
|||
std::getline(data, line, '\n');
|
||||
|
||||
if (line.size() < 2) {
|
||||
// we are done
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
++markerCount;
|
||||
|
||||
TRI_json_t* json = TRI_JsonString(TRI_CORE_MEM_ZONE, line.c_str());
|
||||
|
||||
|
@ -204,24 +353,84 @@ int ReplicationFetcher::applyCollectionDump (TRI_voc_cid_t cid,
|
|||
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
|
||||
}
|
||||
|
||||
errorMsg = "received invalid JSON data for collection " + StringUtils::itoa(cid);
|
||||
errorMsg = invalidMsg;
|
||||
|
||||
return TRI_ERROR_REPLICATION_INVALID_RESPONSE;
|
||||
}
|
||||
|
||||
const char* type = 0;
|
||||
const char* key = 0;
|
||||
TRI_json_t const* doc = 0;
|
||||
bool isValid = true;
|
||||
|
||||
const size_t n = json->_value._objects._length;
|
||||
|
||||
for (size_t i = 0; i < n; i += 2) {
|
||||
TRI_json_t const* element = (TRI_json_t const*) TRI_AtVector(&json->_value._objects, i);
|
||||
|
||||
if (element == 0 ||
|
||||
element->_type != TRI_JSON_STRING ||
|
||||
element->_value._string.data == 0 ||
|
||||
(i + 1) == n) {
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
if (isValid) {
|
||||
const char* attributeName = element->_value._string.data;
|
||||
TRI_json_t const* value = (TRI_json_t const*) TRI_AtVector(&json->_value._objects, i + 1);
|
||||
|
||||
if (TRI_EqualString(attributeName, "type")) {
|
||||
if (value == 0 ||
|
||||
value->_type != TRI_JSON_STRING ||
|
||||
value->_value._string.data == 0) {
|
||||
isValid = false;
|
||||
}
|
||||
else {
|
||||
type = value->_value._string.data;
|
||||
}
|
||||
}
|
||||
|
||||
else if (TRI_EqualString(attributeName, "key")) {
|
||||
if (value == 0 ||
|
||||
value->_type != TRI_JSON_STRING ||
|
||||
value->_value._string.data == 0) {
|
||||
isValid = false;
|
||||
}
|
||||
else {
|
||||
key = value->_value._string.data;
|
||||
}
|
||||
}
|
||||
|
||||
else if (TRI_EqualString(attributeName, "doc")) {
|
||||
if (value == 0 ||
|
||||
value->_type != TRI_JSON_ARRAY) {
|
||||
isValid = false;
|
||||
}
|
||||
else {
|
||||
doc = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! isValid) {
|
||||
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
|
||||
errorMsg = invalidMsg;
|
||||
|
||||
return TRI_ERROR_REPLICATION_INVALID_RESPONSE;
|
||||
}
|
||||
|
||||
TRI_json_t* type = JsonHelper::getArrayElement(json, "type");
|
||||
|
||||
if (! JsonHelper::isString(type)) {
|
||||
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
|
||||
int res = applyMarker(trxCollection, type, (const TRI_voc_key_t) key, doc, errorMsg);
|
||||
|
||||
errorMsg = "received invalid JSON data for collection " + StringUtils::itoa(cid);
|
||||
|
||||
return TRI_ERROR_REPLICATION_INVALID_RESPONSE;
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
std::cout << JsonHelper::toString(json);
|
||||
}
|
||||
|
||||
// std::cout << "type: " << type->_value._string.data << "\n";
|
||||
|
||||
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -355,13 +564,18 @@ int ReplicationFetcher::getMasterInventory (string& errorMsg) {
|
|||
else {
|
||||
TRI_json_t* json = TRI_JsonString(TRI_UNKNOWN_MEM_ZONE, response->getBody().str().c_str());
|
||||
|
||||
if (json != 0) {
|
||||
if (json != 0 && json->_type == TRI_JSON_ARRAY) {
|
||||
res = handleInventoryResponse(json, errorMsg);
|
||||
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
}
|
||||
else {
|
||||
res = TRI_ERROR_REPLICATION_INVALID_RESPONSE;
|
||||
|
||||
errorMsg = "got invalid response from master at " + string(_masterInfo._endpoint) +
|
||||
": invalid JSON";
|
||||
}
|
||||
}
|
||||
// std::cout << response->getBody().str() << std::endl;
|
||||
}
|
||||
|
||||
delete response;
|
||||
|
@ -373,10 +587,10 @@ int ReplicationFetcher::getMasterInventory (string& errorMsg) {
|
|||
/// @brief incrementally fetch data from a collection
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int ReplicationFetcher::handleCollectionDump (TRI_voc_cid_t cid,
|
||||
int ReplicationFetcher::handleCollectionDump (TRI_transaction_collection_t* trxCollection,
|
||||
TRI_voc_tick_t maxTick,
|
||||
string& errorMsg) {
|
||||
static const uint64_t chunkSize = 1024 * 1024;
|
||||
static const uint64_t chunkSize = 2 * 1024 * 1024;
|
||||
|
||||
if (_client == 0) {
|
||||
return TRI_ERROR_INTERNAL;
|
||||
|
@ -384,12 +598,13 @@ int ReplicationFetcher::handleCollectionDump (TRI_voc_cid_t cid,
|
|||
|
||||
|
||||
const string baseUrl = "/_api/replication/dump"
|
||||
"?collection=" + StringUtils::itoa(cid) +
|
||||
"?collection=" + StringUtils::itoa(trxCollection->_cid) +
|
||||
"&chunkSize=" + StringUtils::itoa(chunkSize);
|
||||
|
||||
map<string, string> headers;
|
||||
|
||||
TRI_voc_tick_t fromTick = 0;
|
||||
TRI_voc_tick_t fromTick = 0;
|
||||
uint64_t markerCount = 0;
|
||||
|
||||
while (true) {
|
||||
string url = baseUrl +
|
||||
|
@ -428,16 +643,23 @@ int ReplicationFetcher::handleCollectionDump (TRI_voc_cid_t cid,
|
|||
return TRI_ERROR_REPLICATION_MASTER_ERROR;
|
||||
}
|
||||
|
||||
bool hasMore = false;
|
||||
int res;
|
||||
bool checkMore = false;
|
||||
bool found;
|
||||
string header = response->getHeaderField("x-arango-hasmore", found);
|
||||
string header = response->getHeaderField(TRI_REPLICATION_HEADER_CHECKMORE, found);
|
||||
|
||||
if (found) {
|
||||
hasMore = StringUtils::boolean(header);
|
||||
checkMore = StringUtils::boolean(header);
|
||||
res = TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
else {
|
||||
res = TRI_ERROR_REPLICATION_INVALID_RESPONSE;
|
||||
errorMsg = "got invalid response from master at " + string(_masterInfo._endpoint) +
|
||||
": header '" TRI_REPLICATION_HEADER_CHECKMORE "' is missing";
|
||||
}
|
||||
|
||||
if (hasMore) {
|
||||
header = response->getHeaderField("x-arango-lastfound", found);
|
||||
if (checkMore) {
|
||||
header = response->getHeaderField(TRI_REPLICATION_HEADER_LASTFOUND, found);
|
||||
|
||||
if (found) {
|
||||
TRI_voc_tick_t tick = StringUtils::uint64(header);
|
||||
|
@ -446,24 +668,33 @@ int ReplicationFetcher::handleCollectionDump (TRI_voc_cid_t cid,
|
|||
fromTick = tick;
|
||||
}
|
||||
else {
|
||||
// TODO: raise error
|
||||
hasMore = false;
|
||||
// we got the same tick again, this indicates we're at the end
|
||||
checkMore = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TODO: raise error
|
||||
hasMore = false;
|
||||
res = TRI_ERROR_REPLICATION_INVALID_RESPONSE;
|
||||
errorMsg = "got invalid response from master at " + string(_masterInfo._endpoint) +
|
||||
": header '" TRI_REPLICATION_HEADER_LASTFOUND "' is missing";
|
||||
}
|
||||
}
|
||||
|
||||
int res = applyCollectionDump(cid, response, errorMsg);
|
||||
if (res == TRI_ERROR_NO_ERROR) {
|
||||
res = applyCollectionDump(trxCollection, response, errorMsg, markerCount);
|
||||
}
|
||||
|
||||
delete response;
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR ||
|
||||
! hasMore ||
|
||||
fromTick == 0) {
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (! checkMore || fromTick == 0) {
|
||||
// done
|
||||
if (markerCount > 0) {
|
||||
LOGGER_INFO("successfully transferred " << markerCount << " data markers");
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
@ -476,49 +707,72 @@ int ReplicationFetcher::handleCollectionDump (TRI_voc_cid_t cid,
|
|||
/// @brief handle the information about a collection
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int ReplicationFetcher::handleCollectionInitial (TRI_json_t const* json,
|
||||
int ReplicationFetcher::handleCollectionInitial (TRI_json_t const* parameters,
|
||||
TRI_json_t const* indexes,
|
||||
string& errorMsg,
|
||||
setup_phase_e phase) {
|
||||
|
||||
TRI_json_t const* masterName = JsonHelper::getArrayElement(json, "name");
|
||||
ENSURE_JSON(masterName, isString, "collection name is missing in response");
|
||||
TRI_json_t const* masterName = JsonHelper::getArrayElement(parameters, "name");
|
||||
|
||||
if (! JsonHelper::isString(masterName)) {
|
||||
errorMsg = "collection name is missing in response";
|
||||
|
||||
return TRI_ERROR_REPLICATION_INVALID_RESPONSE;
|
||||
}
|
||||
|
||||
if (TRI_IsSystemCollectionName(masterName->_value._string.data)) {
|
||||
// we will not care about system collections
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
if (JsonHelper::getBooleanValue(json, "deleted", false)) {
|
||||
if (JsonHelper::getBooleanValue(parameters, "deleted", false)) {
|
||||
// we don't care about deleted collections
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
TRI_json_t const* masterId = JsonHelper::getArrayElement(json, "cid");
|
||||
ENSURE_JSON(masterId, isString, "collection id is missing in response");
|
||||
|
||||
TRI_json_t const* masterType = JsonHelper::getArrayElement(json, "type");
|
||||
ENSURE_JSON(masterType, isNumber, "collection type is missing in response");
|
||||
|
||||
TRI_voc_cid_t id = StringUtils::uint64(masterId->_value._string.data);
|
||||
TRI_json_t const* masterId = JsonHelper::getArrayElement(parameters, "cid");
|
||||
|
||||
TRI_vocbase_col_t* col;
|
||||
if (! JsonHelper::isString(masterId)) {
|
||||
errorMsg = "collection id is missing in response";
|
||||
|
||||
return TRI_ERROR_REPLICATION_INVALID_RESPONSE;
|
||||
}
|
||||
|
||||
// first look up the collection by the cid
|
||||
col = TRI_LookupCollectionByIdVocBase(_vocbase, id);
|
||||
TRI_voc_cid_t cid = StringUtils::uint64(masterId->_value._string.data, masterId->_value._string.length - 1);
|
||||
|
||||
TRI_json_t const* masterType = JsonHelper::getArrayElement(parameters, "type");
|
||||
|
||||
if (! JsonHelper::isNumber(masterType)) {
|
||||
errorMsg = "collection type is missing in response";
|
||||
|
||||
return TRI_ERROR_REPLICATION_INVALID_RESPONSE;
|
||||
}
|
||||
|
||||
// phase handling
|
||||
if (phase == PHASE_VALIDATE) {
|
||||
// validation phase just returns ok if we got here (aborts above if data is invalid)
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// drop collections locally
|
||||
// -------------------------------------------------------------------------------------
|
||||
|
||||
if (phase == PHASE_DROP) {
|
||||
// first look up the collection by the cid
|
||||
TRI_vocbase_col_t* col = TRI_LookupCollectionByIdVocBase(_vocbase, cid);
|
||||
|
||||
if (col == 0) {
|
||||
// not found, try name next
|
||||
col = TRI_LookupCollectionByNameVocBase(_vocbase, masterName->_value._string.data);
|
||||
}
|
||||
|
||||
if (col != 0) {
|
||||
LOGGER_INFO("dropping collection '" << col->_name << "', id " << id);
|
||||
LOGGER_INFO("dropping collection '" << col->_name << "', id " << cid);
|
||||
|
||||
int res = TRI_DropCollectionVocBase(_vocbase, col);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
LOGGER_ERROR("unable to drop collection " << id << ": " << TRI_errno_string(res));
|
||||
LOGGER_ERROR("unable to drop collection " << cid << ": " << TRI_errno_string(res));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -526,11 +780,15 @@ int ReplicationFetcher::handleCollectionInitial (TRI_json_t const* json,
|
|||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// re-create collections locally
|
||||
// -------------------------------------------------------------------------------------
|
||||
|
||||
else if (phase == PHASE_CREATE) {
|
||||
TRI_json_t* keyOptions = 0;
|
||||
|
||||
if (JsonHelper::isArray(JsonHelper::getArrayElement(json, "keyOptions"))) {
|
||||
keyOptions = TRI_CopyJson(TRI_CORE_MEM_ZONE, JsonHelper::getArrayElement(json, "keyOptions"));
|
||||
if (JsonHelper::isArray(JsonHelper::getArrayElement(parameters, "keyOptions"))) {
|
||||
keyOptions = TRI_CopyJson(TRI_CORE_MEM_ZONE, JsonHelper::getArrayElement(parameters, "keyOptions"));
|
||||
}
|
||||
|
||||
TRI_col_info_t params;
|
||||
|
@ -538,37 +796,129 @@ int ReplicationFetcher::handleCollectionInitial (TRI_json_t const* json,
|
|||
¶ms,
|
||||
masterName->_value._string.data,
|
||||
(TRI_col_type_e) masterType->_value._number,
|
||||
(TRI_voc_size_t) JsonHelper::getNumberValue(json, "maximalSize", (double) TRI_JOURNAL_DEFAULT_MAXIMAL_SIZE),
|
||||
(TRI_voc_size_t) JsonHelper::getNumberValue(parameters, "maximalSize", (double) TRI_JOURNAL_DEFAULT_MAXIMAL_SIZE),
|
||||
keyOptions);
|
||||
|
||||
params._doCompact = JsonHelper::getBooleanValue(json, "doCompact", true);
|
||||
params._waitForSync = JsonHelper::getBooleanValue(json, "waitForSync", _vocbase->_defaultWaitForSync);
|
||||
params._isVolatile = JsonHelper::getBooleanValue(json, "isVolatile", false);
|
||||
params._doCompact = JsonHelper::getBooleanValue(parameters, "doCompact", true);
|
||||
params._waitForSync = JsonHelper::getBooleanValue(parameters, "waitForSync", _vocbase->_defaultWaitForSync);
|
||||
params._isVolatile = JsonHelper::getBooleanValue(parameters, "isVolatile", false);
|
||||
|
||||
LOGGER_INFO("creating collection '" << masterName->_value._string.data << "', id " << id);
|
||||
LOGGER_INFO("creating collection '" << masterName->_value._string.data << "', id " << cid);
|
||||
|
||||
col = TRI_CreateCollectionVocBase(_vocbase, ¶ms, id);
|
||||
TRI_vocbase_col_t* col = TRI_CreateCollectionVocBase(_vocbase, ¶ms, cid);
|
||||
|
||||
if (col == 0) {
|
||||
int res = TRI_errno();
|
||||
|
||||
LOGGER_ERROR("unable to create collection " << id << ": " << TRI_errno_string(res));
|
||||
LOGGER_ERROR("unable to create collection " << cid << ": " << TRI_errno_string(res));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// sync collection data
|
||||
// -------------------------------------------------------------------------------------
|
||||
|
||||
else if (phase == PHASE_DATA) {
|
||||
int res;
|
||||
|
||||
LOGGER_INFO("syncing data for collection '" << masterName->_value._string.data << "', id " << id);
|
||||
LOGGER_INFO("syncing data for collection '" << masterName->_value._string.data << "', id " << cid);
|
||||
|
||||
res = handleCollectionDump(id, _masterInfo._state._lastTick, errorMsg);
|
||||
TRI_transaction_t* trx = TRI_CreateTransaction(_vocbase->_transactionContext, false, 0.0, false);
|
||||
|
||||
if (trx == 0) {
|
||||
errorMsg = "unable to start transaction";
|
||||
|
||||
return TRI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
res = TRI_AddCollectionTransaction(trx, cid, TRI_TRANSACTION_WRITE, TRI_TRANSACTION_TOP_LEVEL);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
TRI_FreeTransaction(trx);
|
||||
errorMsg = "unable to start transaction";
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
res = TRI_BeginTransaction(trx, (TRI_transaction_hint_t) TRI_TRANSACTION_HINT_SINGLE_OPERATION, TRI_TRANSACTION_TOP_LEVEL);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
TRI_FreeTransaction(trx);
|
||||
errorMsg = "unable to start transaction";
|
||||
|
||||
return TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
TRI_transaction_collection_t* trxCollection = TRI_GetCollectionTransaction(trx, cid, TRI_TRANSACTION_WRITE);
|
||||
|
||||
if (trxCollection == NULL) {
|
||||
res = TRI_ERROR_INTERNAL;
|
||||
}
|
||||
else {
|
||||
res = handleCollectionDump(trxCollection, _masterInfo._state._lastTick, errorMsg);
|
||||
}
|
||||
|
||||
|
||||
if (res == TRI_ERROR_NO_ERROR) {
|
||||
TRI_CommitTransaction(trx, 0);
|
||||
}
|
||||
|
||||
TRI_FreeTransaction(trx);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// create indexes
|
||||
// -------------------------------------------------------------------------------------
|
||||
|
||||
else if (phase == PHASE_INDEXES) {
|
||||
|
||||
const size_t n = indexes->_value._objects._length;
|
||||
int res = TRI_ERROR_NO_ERROR;
|
||||
|
||||
if (n > 0) {
|
||||
LOGGER_INFO("creating indexes for collection '" << masterName->_value._string.data << "', id " << cid);
|
||||
|
||||
TRI_vocbase_col_t* col = TRI_UseCollectionByIdVocBase(_vocbase, cid);
|
||||
|
||||
if (col == 0 || col->_collection == 0) {
|
||||
return TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
TRI_json_t const* idxDef = (TRI_json_t const*) TRI_AtVector(&indexes->_value._objects, i);
|
||||
TRI_index_t* idx = 0;
|
||||
|
||||
// {"id":"229907440927234","type":"hash","unique":false,"fields":["x","Y"]}
|
||||
|
||||
res = TRI_FromJsonIndexDocumentCollection((TRI_document_collection_t*) col->_collection, idxDef, &idx);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
errorMsg = "could not create index: " + string(TRI_errno_string(res));
|
||||
break;
|
||||
}
|
||||
else {
|
||||
assert(idx != 0);
|
||||
|
||||
res = TRI_SaveIndex((TRI_primary_collection_t*) col->_collection, idx);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
errorMsg = "could not save index: " + string(TRI_errno_string(res));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TRI_ReleaseCollectionVocBase(_vocbase, col);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// we won't get here
|
||||
assert(false);
|
||||
return TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
@ -582,31 +932,65 @@ int ReplicationFetcher::handleStateResponse (TRI_json_t const* json,
|
|||
|
||||
// process "state" section
|
||||
TRI_json_t const* state = JsonHelper::getArrayElement(json, "state");
|
||||
ENSURE_JSON(state, isArray, "state section is missing in response");
|
||||
|
||||
if (! JsonHelper::isArray(state)) {
|
||||
errorMsg = "state section is missing from response";
|
||||
|
||||
return TRI_ERROR_REPLICATION_INVALID_RESPONSE;
|
||||
}
|
||||
|
||||
// state."firstTick"
|
||||
TRI_json_t const* tick = JsonHelper::getArrayElement(state, "firstTick");
|
||||
ENSURE_JSON(tick, isString, "firstTick is missing in response");
|
||||
const TRI_voc_tick_t firstTick = StringUtils::uint64(tick->_value._string.data);
|
||||
|
||||
if (! JsonHelper::isString(tick)) {
|
||||
errorMsg = "firstTick is missing from response";
|
||||
|
||||
return TRI_ERROR_REPLICATION_INVALID_RESPONSE;
|
||||
}
|
||||
const TRI_voc_tick_t firstTick = StringUtils::uint64(tick->_value._string.data, tick->_value._string.length - 1);
|
||||
|
||||
// state."lastTick"
|
||||
tick = JsonHelper::getArrayElement(state, "lastTick");
|
||||
ENSURE_JSON(tick, isString, "lastTick is missing in response");
|
||||
const TRI_voc_tick_t lastTick = StringUtils::uint64(tick->_value._string.data);
|
||||
|
||||
if (! JsonHelper::isString(tick)) {
|
||||
errorMsg = "lastTick is missing from response";
|
||||
|
||||
return TRI_ERROR_REPLICATION_INVALID_RESPONSE;
|
||||
}
|
||||
const TRI_voc_tick_t lastTick = StringUtils::uint64(tick->_value._string.data, tick->_value._string.length - 1);
|
||||
|
||||
// state."running"
|
||||
bool running = JsonHelper::getBooleanValue(state, "running", false);
|
||||
|
||||
// process "server" section
|
||||
TRI_json_t const* server = JsonHelper::getArrayElement(json, "server");
|
||||
ENSURE_JSON(server, isArray, "server section is missing in response");
|
||||
|
||||
if (! JsonHelper::isArray(server)) {
|
||||
errorMsg = "server section is missing from response";
|
||||
|
||||
return TRI_ERROR_REPLICATION_INVALID_RESPONSE;
|
||||
}
|
||||
|
||||
// server."version"
|
||||
TRI_json_t const* version = JsonHelper::getArrayElement(server, "version");
|
||||
ENSURE_JSON(version, isString, "server version is missing in response");
|
||||
|
||||
TRI_json_t const* id = JsonHelper::getArrayElement(server, "serverId");
|
||||
ENSURE_JSON(id, isString, "server id is missing in response");
|
||||
|
||||
if (! JsonHelper::isString(version)) {
|
||||
errorMsg = "server version is missing from response";
|
||||
|
||||
return TRI_ERROR_REPLICATION_INVALID_RESPONSE;
|
||||
}
|
||||
|
||||
// server."serverId"
|
||||
TRI_json_t const* serverId = JsonHelper::getArrayElement(server, "serverId");
|
||||
|
||||
if (! JsonHelper::isString(serverId)) {
|
||||
errorMsg = "server id is missing from response";
|
||||
|
||||
return TRI_ERROR_REPLICATION_INVALID_RESPONSE;
|
||||
}
|
||||
|
||||
// validate all values we got
|
||||
const TRI_server_id_t masterId = StringUtils::uint64(id->_value._string.data);
|
||||
const TRI_server_id_t masterId = StringUtils::uint64(serverId->_value._string.data, serverId->_value._string.length);
|
||||
|
||||
if (masterId == 0) {
|
||||
// invalid master id
|
||||
|
@ -656,67 +1040,124 @@ int ReplicationFetcher::handleStateResponse (TRI_json_t const* json,
|
|||
|
||||
int ReplicationFetcher::handleInventoryResponse (TRI_json_t const* json,
|
||||
string& errorMsg) {
|
||||
TRI_json_t const* collections = JsonHelper::getArrayElement(json, "collections");
|
||||
ENSURE_JSON(collections, isList, "collections section is missing from response");
|
||||
TRI_json_t* collections = JsonHelper::getArrayElement(json, "collections");
|
||||
|
||||
if (! JsonHelper::isList(collections)) {
|
||||
errorMsg = "collections section is missing from response";
|
||||
|
||||
return TRI_ERROR_REPLICATION_INVALID_RESPONSE;
|
||||
}
|
||||
|
||||
const size_t n = collections->_value._objects._length;
|
||||
|
||||
// iterate over all collections from the master...
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
TRI_json_t const* collection = (TRI_json_t const*) TRI_AtVector(&collections->_value._objects, i);
|
||||
ENSURE_JSON(collection, isArray, "collection declaration is invalid in response");
|
||||
|
||||
TRI_json_t const* parameters = JsonHelper::getArrayElement(collection, "parameters");
|
||||
ENSURE_JSON(parameters, isArray, "parameters section is missing from response");
|
||||
|
||||
/* TODO: handle indexes
|
||||
TRI_json_t const* indexes = JsonHelper::getArrayElement(collection, "indexes");
|
||||
ENSURE_JSON(indexes, isList, "indexes section is missing from response");
|
||||
LOGGER_INFO(JsonHelper::toString(indexes));
|
||||
*/
|
||||
|
||||
// drop the collection if it exists locally
|
||||
int res = handleCollectionInitial(parameters, errorMsg, PHASE_DROP);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
if (n > 1) {
|
||||
// sort by collection type (vertices before edges), then name
|
||||
qsort(collections->_value._objects._buffer, n, sizeof(TRI_json_t), &ReplicationFetcher::sortCollections);
|
||||
}
|
||||
|
||||
// iterate over all collections from the master again
|
||||
int res;
|
||||
|
||||
// STEP 1: validate collection declarations from master
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
// iterate over all collections from the master...
|
||||
res = iterateCollections(collections, errorMsg, PHASE_VALIDATE);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// STEP 2: drop collections locally if they are also present on the master (clean up)
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
res = iterateCollections(collections, errorMsg, PHASE_DROP);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// STEP 3: re-create empty collections locally
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
if (n > 0) {
|
||||
// we'll sleep for a while to allow the collections to be dropped (asynchronously)
|
||||
// TODO: find a safer mechanism for waiting until we can beginning creating collections
|
||||
sleep(5);
|
||||
}
|
||||
|
||||
res = iterateCollections(collections, errorMsg, PHASE_CREATE);
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
TRI_json_t const* collection = (TRI_json_t const*) TRI_AtVector(&collections->_value._objects, i);
|
||||
|
||||
TRI_json_t const* parameters = JsonHelper::getArrayElement(collection, "parameters");
|
||||
|
||||
// now re-create the collection locally
|
||||
int res = handleCollectionInitial(parameters, errorMsg, PHASE_CREATE);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// all collections created. now sync collection data
|
||||
|
||||
// STEP 4: sync collection data from master
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
res = iterateCollections(collections, errorMsg, PHASE_DATA);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// STEP 5: create indexes
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
res = iterateCollections(collections, errorMsg, PHASE_INDEXES);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief iterate over all collections from a list and apply an action
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int ReplicationFetcher::iterateCollections (TRI_json_t const* collections,
|
||||
string& errorMsg,
|
||||
setup_phase_e phase) {
|
||||
const size_t n = collections->_value._objects._length;
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
TRI_json_t const* collection = (TRI_json_t const*) TRI_AtVector(&collections->_value._objects, i);
|
||||
|
||||
|
||||
if (! JsonHelper::isArray(collection)) {
|
||||
errorMsg = "collection declaration is invalid in response";
|
||||
|
||||
return TRI_ERROR_REPLICATION_INVALID_RESPONSE;
|
||||
}
|
||||
|
||||
TRI_json_t const* parameters = JsonHelper::getArrayElement(collection, "parameters");
|
||||
|
||||
// now sync collection data
|
||||
int res = handleCollectionInitial(parameters, errorMsg, PHASE_DATA);
|
||||
|
||||
if (! JsonHelper::isArray(parameters)) {
|
||||
errorMsg = "collection parameters declaration is invalid in response";
|
||||
|
||||
return TRI_ERROR_REPLICATION_INVALID_RESPONSE;
|
||||
}
|
||||
|
||||
TRI_json_t const* indexes = JsonHelper::getArrayElement(collection, "indexes");
|
||||
|
||||
if (! JsonHelper::isList(indexes)) {
|
||||
errorMsg = "collection indexes declaration is invalid in response";
|
||||
|
||||
return TRI_ERROR_REPLICATION_INVALID_RESPONSE;
|
||||
}
|
||||
|
||||
int res = handleCollectionInitial(parameters, indexes, errorMsg, phase);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
// all ok
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,9 @@
|
|||
// -----------------------------------------------------------------------------
|
||||
|
||||
struct TRI_json_s;
|
||||
struct TRI_transaction_collection_s;
|
||||
struct TRI_vocbase_s;
|
||||
struct TRI_vocbase_col_s;
|
||||
|
||||
namespace triagens {
|
||||
|
||||
|
@ -77,9 +79,11 @@ namespace triagens {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef enum {
|
||||
PHASE_VALIDATE,
|
||||
PHASE_DROP,
|
||||
PHASE_CREATE,
|
||||
PHASE_DATA
|
||||
PHASE_DATA,
|
||||
PHASE_INDEXES
|
||||
}
|
||||
setup_phase_e;
|
||||
|
||||
|
@ -133,6 +137,13 @@ namespace triagens {
|
|||
|
||||
int run ();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief comparator to sort collections
|
||||
/// sort order is by collection type first (vertices before edges), then name
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int sortCollections (const void*, const void*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -152,9 +163,20 @@ namespace triagens {
|
|||
/// @brief apply the data from a collection dump
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int applyCollectionDump (TRI_voc_cid_t,
|
||||
int applyMarker (struct TRI_transaction_collection_s*,
|
||||
char const*,
|
||||
const TRI_voc_key_t,
|
||||
struct TRI_json_s const*,
|
||||
string&);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief apply the data from a collection dump
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int applyCollectionDump (struct TRI_transaction_collection_s*,
|
||||
httpclient::SimpleHttpResult*,
|
||||
string&);
|
||||
string&,
|
||||
uint64_t&);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get local replication apply state
|
||||
|
@ -178,7 +200,7 @@ namespace triagens {
|
|||
/// @brief incrementally fetch data from a collection
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int handleCollectionDump (TRI_voc_cid_t,
|
||||
int handleCollectionDump (struct TRI_transaction_collection_s*,
|
||||
TRI_voc_tick_t,
|
||||
string&);
|
||||
|
||||
|
@ -186,7 +208,8 @@ namespace triagens {
|
|||
/// @brief handle the information about a collection
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int handleCollectionInitial (struct TRI_json_s const*,
|
||||
int handleCollectionInitial (struct TRI_json_s const*,
|
||||
struct TRI_json_s const*,
|
||||
string&,
|
||||
setup_phase_e);
|
||||
|
||||
|
@ -203,6 +226,14 @@ namespace triagens {
|
|||
|
||||
int handleInventoryResponse (struct TRI_json_s const*, string&);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief iterate over all collections from a list and apply an action
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int iterateCollections (struct TRI_json_s const*,
|
||||
string&,
|
||||
setup_phase_e);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -395,11 +395,9 @@ bool RestDocumentHandler::createDocument () {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (trx.primaryCollection()->base._info._type == TRI_COL_TYPE_EDGE) {
|
||||
// check if we are inserting with the DOCUMENT handler into an EDGE collection
|
||||
generateError(HttpResponse::BAD,
|
||||
TRI_ERROR_HTTP_METHOD_NOT_ALLOWED,
|
||||
"must not use the document handler to create an edge");
|
||||
if (trx.primaryCollection()->base._info._type != TRI_COL_TYPE_DOCUMENT) {
|
||||
// check if we are inserting with the DOCUMENT handler into a non-DOCUMENT collection
|
||||
generateError(HttpResponse::BAD, TRI_ERROR_ARANGO_COLLECTION_TYPE_INVALID);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -145,9 +145,6 @@ bool RestEdgeHandler::createDocument () {
|
|||
return false;
|
||||
}
|
||||
|
||||
// edge
|
||||
TRI_document_edge_t edge;
|
||||
|
||||
// extract the from
|
||||
bool found;
|
||||
char const* from = _request->value("from", found);
|
||||
|
@ -210,9 +207,17 @@ bool RestEdgeHandler::createDocument () {
|
|||
generateTransactionError(collection, res);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (trx.primaryCollection()->base._info._type != TRI_COL_TYPE_EDGE) {
|
||||
// check if we are inserting with the EDGE handler into a non-EDGE collection
|
||||
generateError(HttpResponse::BAD, TRI_ERROR_ARANGO_COLLECTION_TYPE_INVALID);
|
||||
return false;
|
||||
}
|
||||
|
||||
const TRI_voc_cid_t cid = trx.cid();
|
||||
|
||||
// edge
|
||||
TRI_document_edge_t edge;
|
||||
edge._fromCid = cid;
|
||||
edge._toCid = cid;
|
||||
edge._fromKey = 0;
|
||||
|
|
|
@ -275,7 +275,7 @@ bool RestImportHandler::createByDocumentsLines () {
|
|||
TRI_doc_mptr_t document;
|
||||
|
||||
if (isEdgeCollection) {
|
||||
const char* from = extractJsonStringValue(values, "_from");
|
||||
const char* from = extractJsonStringValue(values, TRI_VOC_ATTRIBUTE_FROM);
|
||||
|
||||
if (from == 0) {
|
||||
LOGGER_WARNING("missing '_from' attribute at position " << i);
|
||||
|
@ -284,7 +284,7 @@ bool RestImportHandler::createByDocumentsLines () {
|
|||
continue;
|
||||
}
|
||||
|
||||
const char* to = extractJsonStringValue(values, "_to");
|
||||
const char* to = extractJsonStringValue(values, TRI_VOC_ATTRIBUTE_TO);
|
||||
if (to == 0) {
|
||||
LOGGER_WARNING("missing '_to' attribute at position " << i);
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, values);
|
||||
|
@ -454,7 +454,7 @@ bool RestImportHandler::createByDocumentsList () {
|
|||
TRI_doc_mptr_t document;
|
||||
|
||||
if (isEdgeCollection) {
|
||||
const char* from = extractJsonStringValue(values, "_from");
|
||||
const char* from = extractJsonStringValue(values, TRI_VOC_ATTRIBUTE_FROM);
|
||||
|
||||
if (from == 0) {
|
||||
LOGGER_WARNING("missing '_from' attribute at position " << (i + 1));
|
||||
|
@ -462,7 +462,7 @@ bool RestImportHandler::createByDocumentsList () {
|
|||
continue;
|
||||
}
|
||||
|
||||
const char* to = extractJsonStringValue(values, "_to");
|
||||
const char* to = extractJsonStringValue(values, TRI_VOC_ATTRIBUTE_TO);
|
||||
if (to == 0) {
|
||||
LOGGER_WARNING("missing '_to' attribute at position " << (i + 1));
|
||||
++numError;
|
||||
|
@ -696,7 +696,7 @@ bool RestImportHandler::createByKeyValueList () {
|
|||
TRI_doc_mptr_t document;
|
||||
|
||||
if (isEdgeCollection) {
|
||||
const char* from = extractJsonStringValue(json, "_from");
|
||||
const char* from = extractJsonStringValue(json, TRI_VOC_ATTRIBUTE_FROM);
|
||||
|
||||
if (from == 0) {
|
||||
LOGGER_WARNING("missing '_from' attribute at line " << lineNumber);
|
||||
|
@ -705,7 +705,7 @@ bool RestImportHandler::createByKeyValueList () {
|
|||
continue;
|
||||
}
|
||||
|
||||
const char* to = extractJsonStringValue(json, "_to");
|
||||
const char* to = extractJsonStringValue(json, TRI_VOC_ATTRIBUTE_TO);
|
||||
if (to == 0) {
|
||||
LOGGER_WARNING("missing '_to' attribute at line " << lineNumber);
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
|
|
|
@ -401,7 +401,7 @@ void RestReplicationHandler::handleCommandInventory () {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void RestReplicationHandler::handleCommandDump () {
|
||||
static const uint64_t minChunkSize = 16 * 1024;
|
||||
static const uint64_t minChunkSize = 64 * 1024;
|
||||
|
||||
char const* collection = _request->value("collection");
|
||||
|
||||
|
@ -485,9 +485,16 @@ void RestReplicationHandler::handleCommandDump () {
|
|||
if (res == TRI_ERROR_NO_ERROR) {
|
||||
// generate the result
|
||||
_response = createResponse(HttpResponse::OK);
|
||||
|
||||
_response->setContentType("application/x-arango-dump; charset=utf-8");
|
||||
_response->setHeader("x-arango-hasmore", (dump._hasMore ? "true" : "false"));
|
||||
_response->setHeader("x-arango-lastfound", StringUtils::itoa(dump._lastFoundTick));
|
||||
|
||||
// set headers
|
||||
_response->setHeader(TRI_REPLICATION_HEADER_CHECKMORE,
|
||||
strlen(TRI_REPLICATION_HEADER_CHECKMORE),
|
||||
((dump._hasMore || dump._bufferFull) ? "true" : "false"));
|
||||
_response->setHeader(TRI_REPLICATION_HEADER_LASTFOUND,
|
||||
strlen(TRI_REPLICATION_HEADER_LASTFOUND),
|
||||
StringUtils::itoa(dump._lastFoundTick));
|
||||
|
||||
// transfer ownership of the buffer contents
|
||||
_response->body().appendText(TRI_BeginStringBuffer(dump._buffer), TRI_LengthStringBuffer(dump._buffer));
|
||||
|
|
|
@ -234,9 +234,9 @@ void RestVocbaseBaseHandler::generate20x (const HttpResponse::HttpResponseCode r
|
|||
_response->body()
|
||||
.appendText("{\"error\":false,\"_id\":\"")
|
||||
.appendText(handle)
|
||||
.appendText("\",\"_rev\":\"")
|
||||
.appendText("\",\"" TRI_VOC_ATTRIBUTE_REV "\":\"")
|
||||
.appendText(rev)
|
||||
.appendText("\",\"_key\":\"")
|
||||
.appendText("\",\"" TRI_VOC_ATTRIBUTE_KEY "\":\"")
|
||||
.appendText(key)
|
||||
.appendText("\"}");
|
||||
}
|
||||
|
@ -292,9 +292,9 @@ void RestVocbaseBaseHandler::generatePreconditionFailed (const TRI_voc_cid_t cid
|
|||
.appendText(",\"errorMessage\":\"precondition failed\"")
|
||||
.appendText(",\"_id\":\"")
|
||||
.appendText(DocumentHelper::assembleDocumentId(_resolver.getCollectionName(cid), key))
|
||||
.appendText("\",\"_rev\":\"")
|
||||
.appendText("\",\"" TRI_VOC_ATTRIBUTE_REV "\":\"")
|
||||
.appendText(StringUtils::itoa(rid))
|
||||
.appendText("\",\"_key\":\"")
|
||||
.appendText("\",\"" TRI_VOC_ATTRIBUTE_KEY "\":\"")
|
||||
.appendText(key)
|
||||
.appendText("\"}");
|
||||
}
|
||||
|
@ -341,13 +341,13 @@ void RestVocbaseBaseHandler::generateDocument (const TRI_voc_cid_t cid,
|
|||
TRI_json_t* _rev = TRI_CreateString2CopyJson(TRI_UNKNOWN_MEM_ZONE, rid.c_str(), rid.size());
|
||||
|
||||
if (_rev) {
|
||||
TRI_Insert2ArrayJson(TRI_UNKNOWN_MEM_ZONE, &augmented, "_rev", _rev);
|
||||
TRI_Insert2ArrayJson(TRI_UNKNOWN_MEM_ZONE, &augmented, TRI_VOC_ATTRIBUTE_REV, _rev);
|
||||
}
|
||||
|
||||
TRI_json_t* _key = TRI_CreateString2CopyJson(TRI_UNKNOWN_MEM_ZONE, document->_key, strlen(document->_key));
|
||||
|
||||
if (_key) {
|
||||
TRI_Insert2ArrayJson(TRI_UNKNOWN_MEM_ZONE, &augmented, "_key", _key);
|
||||
TRI_Insert2ArrayJson(TRI_UNKNOWN_MEM_ZONE, &augmented, TRI_VOC_ATTRIBUTE_KEY, _key);
|
||||
}
|
||||
|
||||
TRI_df_marker_type_t type = ((TRI_df_marker_t*) document->_data)->_type;
|
||||
|
@ -357,8 +357,8 @@ void RestVocbaseBaseHandler::generateDocument (const TRI_voc_cid_t cid,
|
|||
const string from = DocumentHelper::assembleDocumentId(_resolver.getCollectionName(marker->_fromCid), string((char*) marker + marker->_offsetFromKey));
|
||||
const string to = DocumentHelper::assembleDocumentId(_resolver.getCollectionName(marker->_toCid), string((char*) marker + marker->_offsetToKey));
|
||||
|
||||
TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, &augmented, "_from", TRI_CreateString2CopyJson(TRI_UNKNOWN_MEM_ZONE, from.c_str(), from.size()));
|
||||
TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, &augmented, "_to", TRI_CreateString2CopyJson(TRI_UNKNOWN_MEM_ZONE, to.c_str(), to.size()));
|
||||
TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, &augmented, TRI_VOC_ATTRIBUTE_FROM, TRI_CreateString2CopyJson(TRI_UNKNOWN_MEM_ZONE, from.c_str(), from.size()));
|
||||
TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, &augmented, TRI_VOC_ATTRIBUTE_TO, TRI_CreateString2CopyJson(TRI_UNKNOWN_MEM_ZONE, to.c_str(), to.size()));
|
||||
}
|
||||
|
||||
// add document identifier to buffer
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief document utility functions
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2004-2013 triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Jan Steemann
|
||||
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "DocumentHelper.h"
|
||||
|
||||
#include "BasicsC/json.h"
|
||||
#include "Basics/StringUtils.h"
|
||||
#include "VocBase/vocbase.h"
|
||||
|
||||
using namespace triagens::arango;
|
||||
using namespace triagens::basics;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- class DocumentHelper
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public static methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @addtogroup ArangoDB
|
||||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief assemble a document id from a string and a string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string DocumentHelper::assembleDocumentId (const std::string& collectionName,
|
||||
const std::string& key) {
|
||||
return collectionName + TRI_DOCUMENT_HANDLE_SEPARATOR_STR + key;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief assemble a document id from a string and a char* key
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string DocumentHelper::assembleDocumentId (const std::string& collectionName,
|
||||
const TRI_voc_key_t key) {
|
||||
if (key == 0) {
|
||||
return collectionName + TRI_DOCUMENT_HANDLE_SEPARATOR_STR + "_deleted";
|
||||
}
|
||||
|
||||
return collectionName + TRI_DOCUMENT_HANDLE_SEPARATOR_STR + key;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief extract the collection id and document key from an id
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool DocumentHelper::parseDocumentId (const std::string& input,
|
||||
TRI_voc_cid_t& cid,
|
||||
std::string& key) {
|
||||
size_t pos = input.find('/');
|
||||
|
||||
if (pos == input.npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cid = StringUtils::uint64(input.c_str(), pos);
|
||||
key = input.substr(pos + 1);
|
||||
|
||||
if (key.empty()) {
|
||||
// empty key
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief extract the collection id and document key from an id
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool DocumentHelper::parseDocumentId (const char* input,
|
||||
TRI_voc_cid_t& cid,
|
||||
char** key) {
|
||||
|
||||
if (input == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* pos = strchr(input, '/');
|
||||
|
||||
if (pos == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cid = StringUtils::uint64(input, pos - input);
|
||||
*key = (char*) (pos + 1);
|
||||
|
||||
if (**key == '\0') {
|
||||
// empty key
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief extract the "_key" attribute from a JSON object
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int DocumentHelper::getKey (TRI_json_t const* json,
|
||||
TRI_voc_key_t* key) {
|
||||
*key = 0;
|
||||
|
||||
// check type of json
|
||||
if (json == 0 || json->_type != TRI_JSON_ARRAY) {
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// check _key is there
|
||||
const TRI_json_t* k = TRI_LookupArrayJson((TRI_json_t*) json, TRI_VOC_ATTRIBUTE_KEY);
|
||||
|
||||
if (k == 0) {
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
if (k->_type != TRI_JSON_STRING) {
|
||||
// _key is there but not a string
|
||||
return TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD;
|
||||
}
|
||||
|
||||
// _key is there and a string
|
||||
*key = k->_value._string.data;
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}"
|
||||
// End:
|
|
@ -28,7 +28,10 @@
|
|||
#ifndef TRIAGENS_UTILS_DOCUMENT_HELPER_H
|
||||
#define TRIAGENS_UTILS_DOCUMENT_HELPER_H 1
|
||||
|
||||
#include "BasicsC/json.h"
|
||||
#include "Basics/Common.h"
|
||||
#include "VocBase/voc-types.h"
|
||||
|
||||
struct TRI_json_s;
|
||||
|
||||
namespace triagens {
|
||||
namespace arango {
|
||||
|
@ -73,53 +76,38 @@ namespace triagens {
|
|||
/// @brief assemble a document id from a string and a string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline string assembleDocumentId (const string& collectionName,
|
||||
const string& key) {
|
||||
return collectionName + TRI_DOCUMENT_HANDLE_SEPARATOR_STR + key;
|
||||
}
|
||||
static std::string assembleDocumentId (const std::string&,
|
||||
const std::string& key);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief assemble a document id from a string and a char* key
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline string assembleDocumentId (const string& collectionName,
|
||||
const TRI_voc_key_t key) {
|
||||
if (key == 0) {
|
||||
return collectionName + TRI_DOCUMENT_HANDLE_SEPARATOR_STR + "_deleted";
|
||||
}
|
||||
static std::string assembleDocumentId (const std::string&,
|
||||
const TRI_voc_key_t);
|
||||
|
||||
return collectionName + TRI_DOCUMENT_HANDLE_SEPARATOR_STR + key;
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief extract the collection id and document key from an id
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool parseDocumentId (const std::string&,
|
||||
TRI_voc_cid_t&,
|
||||
std::string&);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief extract the collection id and document key from an id
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool parseDocumentId (const char*,
|
||||
TRI_voc_cid_t&,
|
||||
char**);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief extract the "_key" attribute from a JSON object
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int getKey (TRI_json_t const* json, TRI_voc_key_t* key) {
|
||||
*key = 0;
|
||||
|
||||
// check type of json
|
||||
if (json == 0 || json->_type != TRI_JSON_ARRAY) {
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// check _key is there
|
||||
const TRI_json_t* k = TRI_LookupArrayJson((TRI_json_t*) json, "_key");
|
||||
|
||||
if (k == 0) {
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
if (k->_type != TRI_JSON_STRING) {
|
||||
// _key is there but not a string
|
||||
return TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD;
|
||||
}
|
||||
|
||||
// _key is there and a string
|
||||
*key = k->_value._string.data;
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
static int getKey (struct TRI_json_s const*,
|
||||
TRI_voc_key_t*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
|
|
|
@ -175,7 +175,7 @@ namespace triagens {
|
|||
return TRI_ERROR_TRANSACTION_INTERNAL;
|
||||
}
|
||||
|
||||
return this->create(this->trxCollection(), TRI_DOC_MARKER_KEY_DOCUMENT, key, mptr, shaped, 0, forceSync);
|
||||
return this->create(this->trxCollection(), key, 0, TRI_DOC_MARKER_KEY_DOCUMENT, mptr, shaped, 0, forceSync);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -191,7 +191,7 @@ namespace triagens {
|
|||
return TRI_ERROR_TRANSACTION_INTERNAL;
|
||||
}
|
||||
|
||||
return this->create(this->trxCollection(), TRI_DOC_MARKER_KEY_EDGE, key, mptr, shaped, data, forceSync);
|
||||
return this->create(this->trxCollection(), key, 0, TRI_DOC_MARKER_KEY_EDGE, mptr, shaped, data, forceSync);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -719,8 +719,9 @@ namespace triagens {
|
|||
}
|
||||
|
||||
res = create(trxCollection,
|
||||
markerType,
|
||||
key,
|
||||
0,
|
||||
markerType,
|
||||
mptr,
|
||||
shaped,
|
||||
data,
|
||||
|
@ -736,8 +737,9 @@ namespace triagens {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline int create (TRI_transaction_collection_t* trxCollection,
|
||||
const TRI_df_marker_type_e markerType,
|
||||
const TRI_voc_key_t key,
|
||||
TRI_voc_rid_t rid,
|
||||
const TRI_df_marker_type_e markerType,
|
||||
TRI_doc_mptr_t* mptr,
|
||||
TRI_shaped_json_t const* shaped,
|
||||
void const* data,
|
||||
|
@ -747,6 +749,7 @@ namespace triagens {
|
|||
|
||||
int res = primary->insert(trxCollection,
|
||||
key,
|
||||
rid,
|
||||
mptr,
|
||||
markerType,
|
||||
shaped,
|
||||
|
|
|
@ -7479,7 +7479,7 @@ static v8::Handle<v8::Integer> PropertyQueryShapedJson (v8::Local<v8::String> na
|
|||
}
|
||||
|
||||
if (key[0] == '_') {
|
||||
if (key == "_id" || key == "_rev" || key == "_key") {
|
||||
if (key == "_id" || key == TRI_VOC_ATTRIBUTE_REV || key == TRI_VOC_ATTRIBUTE_KEY) {
|
||||
return scope.Close(v8::Handle<v8::Integer>(v8::Integer::New(v8::ReadOnly)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1227,6 +1227,7 @@ int TRI_WriteElementDatafile (TRI_datafile_t* datafile,
|
|||
if (datafile->_tickMin == 0) {
|
||||
datafile->_tickMin = tick;
|
||||
}
|
||||
|
||||
datafile->_tickMax = tick;
|
||||
|
||||
assert(markerSize > 0);
|
||||
|
|
|
@ -53,32 +53,39 @@ static int FillIndex (TRI_document_collection_t*,
|
|||
TRI_index_t*);
|
||||
|
||||
static int CapConstraintFromJson (TRI_document_collection_t*,
|
||||
TRI_json_t*,
|
||||
TRI_idx_iid_t);
|
||||
TRI_json_t const*,
|
||||
TRI_idx_iid_t,
|
||||
TRI_index_t**);
|
||||
|
||||
static int BitarrayIndexFromJson (TRI_document_collection_t*,
|
||||
TRI_json_t*,
|
||||
TRI_idx_iid_t);
|
||||
TRI_json_t const*,
|
||||
TRI_idx_iid_t,
|
||||
TRI_index_t**);
|
||||
|
||||
static int GeoIndexFromJson (TRI_document_collection_t*,
|
||||
TRI_json_t*,
|
||||
TRI_idx_iid_t);
|
||||
TRI_json_t const*,
|
||||
TRI_idx_iid_t,
|
||||
TRI_index_t**);
|
||||
|
||||
static int HashIndexFromJson (TRI_document_collection_t*,
|
||||
TRI_json_t*,
|
||||
TRI_idx_iid_t);
|
||||
TRI_json_t const*,
|
||||
TRI_idx_iid_t,
|
||||
TRI_index_t**);
|
||||
|
||||
static int SkiplistIndexFromJson (TRI_document_collection_t*,
|
||||
TRI_json_t*,
|
||||
TRI_idx_iid_t);
|
||||
TRI_json_t const*,
|
||||
TRI_idx_iid_t,
|
||||
TRI_index_t**);
|
||||
|
||||
static int FulltextIndexFromJson (TRI_document_collection_t*,
|
||||
TRI_json_t*,
|
||||
TRI_idx_iid_t);
|
||||
TRI_json_t const*,
|
||||
TRI_idx_iid_t,
|
||||
TRI_index_t**);
|
||||
|
||||
static int PriorityQueueFromJson (TRI_document_collection_t*,
|
||||
TRI_json_t*,
|
||||
TRI_idx_iid_t);
|
||||
TRI_json_t const*,
|
||||
TRI_idx_iid_t,
|
||||
TRI_index_t**);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- HELPER FUNCTIONS
|
||||
|
@ -396,6 +403,7 @@ static int CloneDocumentMarker (TRI_voc_tid_t tid,
|
|||
|
||||
static int CreateDocumentMarker (TRI_primary_collection_t* primary,
|
||||
TRI_voc_tid_t tid,
|
||||
TRI_voc_tick_t tick,
|
||||
TRI_doc_document_key_marker_t** result,
|
||||
TRI_voc_size_t* totalSize,
|
||||
char** keyBody,
|
||||
|
@ -408,7 +416,6 @@ static int CreateDocumentMarker (TRI_primary_collection_t* primary,
|
|||
char* position;
|
||||
char keyBuffer[TRI_VOC_KEY_MAX_LENGTH + 1];
|
||||
TRI_voc_size_t keyBodySize;
|
||||
TRI_voc_tick_t tick;
|
||||
size_t markerSize;
|
||||
size_t keySize;
|
||||
size_t fromSize;
|
||||
|
@ -416,7 +423,10 @@ static int CreateDocumentMarker (TRI_primary_collection_t* primary,
|
|||
int res;
|
||||
|
||||
*result = NULL;
|
||||
tick = TRI_NewTickVocBase();
|
||||
|
||||
if (tick == 0) {
|
||||
tick = TRI_NewTickVocBase();
|
||||
}
|
||||
|
||||
// generate the key
|
||||
keyGenerator = (TRI_key_generator_t*) primary->_keyGenerator;
|
||||
|
@ -1477,6 +1487,7 @@ static int NotifyTransaction (TRI_primary_collection_t* primary,
|
|||
|
||||
static int InsertShapedJson (TRI_transaction_collection_t* trxCollection,
|
||||
const TRI_voc_key_t key,
|
||||
TRI_voc_rid_t rid,
|
||||
TRI_doc_mptr_t* mptr,
|
||||
TRI_df_marker_type_e markerType,
|
||||
TRI_shaped_json_t const* shaped,
|
||||
|
@ -1502,7 +1513,8 @@ static int InsertShapedJson (TRI_transaction_collection_t* trxCollection,
|
|||
// this does not require any locks
|
||||
|
||||
res = CreateDocumentMarker(primary,
|
||||
TRI_GetMarkerIdTransaction(trxCollection->_transaction),
|
||||
TRI_GetMarkerIdTransaction(trxCollection->_transaction),
|
||||
(TRI_voc_tick_t) rid,
|
||||
&marker,
|
||||
&totalSize,
|
||||
&keyBody,
|
||||
|
@ -2612,12 +2624,7 @@ static bool FillInternalIndexes (TRI_document_collection_t* document) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool OpenIndexIterator (char const* filename, void* data) {
|
||||
TRI_idx_iid_t iid;
|
||||
TRI_json_t* iis;
|
||||
TRI_json_t* json;
|
||||
TRI_json_t* type;
|
||||
TRI_document_collection_t* document;
|
||||
char const* typeStr;
|
||||
char* error;
|
||||
int res;
|
||||
|
||||
|
@ -2625,7 +2632,7 @@ static bool OpenIndexIterator (char const* filename, void* data) {
|
|||
|
||||
// load json description of the index
|
||||
json = TRI_JsonFile(TRI_CORE_MEM_ZONE, filename, &error);
|
||||
|
||||
|
||||
// json must be a index description
|
||||
if (json == NULL) {
|
||||
if (error != NULL) {
|
||||
|
@ -2637,147 +2644,24 @@ static bool OpenIndexIterator (char const* filename, void* data) {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (json->_type != TRI_JSON_ARRAY) {
|
||||
LOG_ERROR("cannot read index definition from '%s': expecting an array", filename);
|
||||
|
||||
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
|
||||
return false;
|
||||
}
|
||||
|
||||
// extract the type
|
||||
type = TRI_LookupArrayJson(json, "type");
|
||||
|
||||
if (type->_type != TRI_JSON_STRING) {
|
||||
LOG_ERROR("cannot read index definition from '%s': expecting a string for type", filename);
|
||||
|
||||
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
|
||||
return false;
|
||||
}
|
||||
|
||||
typeStr = type->_value._string.data;
|
||||
|
||||
// extract the index identifier
|
||||
iis = TRI_LookupArrayJson(json, "id");
|
||||
|
||||
if (iis != NULL && iis->_type == TRI_JSON_NUMBER) {
|
||||
iid = (TRI_idx_iid_t) iis->_value._number;
|
||||
}
|
||||
else if (iis != NULL && iis->_type == TRI_JSON_STRING) {
|
||||
iid = (TRI_idx_iid_t) TRI_UInt64String(iis->_value._string.data);
|
||||
}
|
||||
else {
|
||||
LOG_ERROR("ignoring index, index identifier could not be located");
|
||||
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
TRI_UpdateTickVocBase(iid);
|
||||
|
||||
// document collection of the index
|
||||
document = (TRI_document_collection_t*) data;
|
||||
res = TRI_FromJsonIndexDocumentCollection((TRI_document_collection_t*) data, json, NULL);
|
||||
TRI_Free(TRI_CORE_MEM_ZONE, json);
|
||||
|
||||
// ...........................................................................
|
||||
// CAP CONSTRAINT
|
||||
// ...........................................................................
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
LOG_ERROR("cannot read index definition from '%s': %s", filename, TRI_errno_string(res));
|
||||
|
||||
if (TRI_EqualString(typeStr, "cap")) {
|
||||
res = CapConstraintFromJson(document, json, iid);
|
||||
|
||||
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
|
||||
return res == TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
// ...........................................................................
|
||||
// BITARRAY INDEX
|
||||
// ...........................................................................
|
||||
|
||||
else if (TRI_EqualString(typeStr, "bitarray")) {
|
||||
res = BitarrayIndexFromJson(document, json, iid);
|
||||
|
||||
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
|
||||
return res == TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// ...........................................................................
|
||||
// GEO INDEX (list or attribute)
|
||||
// ...........................................................................
|
||||
|
||||
else if (TRI_EqualString(typeStr, "geo1") || TRI_EqualString(typeStr, "geo2")) {
|
||||
res = GeoIndexFromJson(document, json, iid);
|
||||
|
||||
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
|
||||
return res == TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// ...........................................................................
|
||||
// HASH INDEX
|
||||
// ...........................................................................
|
||||
|
||||
else if (TRI_EqualString(typeStr, "hash")) {
|
||||
res = HashIndexFromJson(document, json, iid);
|
||||
|
||||
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
|
||||
return res == TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// ...........................................................................
|
||||
// SKIPLIST INDEX
|
||||
// ...........................................................................
|
||||
|
||||
else if (TRI_EqualString(typeStr, "skiplist")) {
|
||||
res = SkiplistIndexFromJson(document, json, iid);
|
||||
|
||||
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
|
||||
return res == TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// ...........................................................................
|
||||
// FULLTEXT INDEX
|
||||
// ...........................................................................
|
||||
|
||||
else if (TRI_EqualString(typeStr, "fulltext")) {
|
||||
res = FulltextIndexFromJson(document, json, iid);
|
||||
|
||||
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
|
||||
return res == TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// ...........................................................................
|
||||
// PRIORITY QUEUE
|
||||
// ...........................................................................
|
||||
|
||||
else if (TRI_EqualString(typeStr, "priorityqueue")) {
|
||||
res = PriorityQueueFromJson(document, json, iid);
|
||||
|
||||
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
|
||||
return res == TRI_ERROR_NO_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
// ...........................................................................
|
||||
// EDGES INDEX
|
||||
// ...........................................................................
|
||||
|
||||
else if (TRI_EqualString(typeStr, "edge")) {
|
||||
// we should never get here, as users cannot create their own edge indexes
|
||||
LOG_ERROR("logic error. there should never be a JSON file describing an edges index");
|
||||
return false;
|
||||
}
|
||||
|
||||
// .........................................................................
|
||||
// oops, unknown index type
|
||||
// .........................................................................
|
||||
|
||||
else {
|
||||
LOG_ERROR("ignoring unknown index type '%s' for index %llu",
|
||||
typeStr,
|
||||
(unsigned long long) iid);
|
||||
|
||||
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -3113,6 +2997,145 @@ void TRI_FreeDocumentCollection (TRI_document_collection_t* document) {
|
|||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an index, based on a JSON description
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_FromJsonIndexDocumentCollection (TRI_document_collection_t* document,
|
||||
TRI_json_t const* json,
|
||||
TRI_index_t** idx) {
|
||||
TRI_json_t const* type;
|
||||
TRI_json_t const* iis;
|
||||
char const* typeStr;
|
||||
TRI_idx_iid_t iid;
|
||||
|
||||
assert(json != NULL);
|
||||
assert(json->_type == TRI_JSON_ARRAY);
|
||||
|
||||
if (idx != NULL) {
|
||||
*idx = NULL;
|
||||
}
|
||||
|
||||
// extract the type
|
||||
type = TRI_LookupArrayJson(json, "type");
|
||||
|
||||
if (type->_type != TRI_JSON_STRING || type->_value._string.data == NULL) {
|
||||
return TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
typeStr = type->_value._string.data;
|
||||
|
||||
// extract the index identifier
|
||||
iis = TRI_LookupArrayJson(json, "id");
|
||||
|
||||
if (iis != NULL && iis->_type == TRI_JSON_NUMBER) {
|
||||
iid = (TRI_idx_iid_t) iis->_value._number;
|
||||
}
|
||||
else if (iis != NULL && iis->_type == TRI_JSON_STRING) {
|
||||
iid = (TRI_idx_iid_t) TRI_UInt64String(iis->_value._string.data);
|
||||
}
|
||||
else {
|
||||
LOG_ERROR("ignoring index, index identifier could not be located");
|
||||
|
||||
return TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
TRI_UpdateTickVocBase(iid);
|
||||
|
||||
// ...........................................................................
|
||||
// CAP CONSTRAINT
|
||||
// ...........................................................................
|
||||
|
||||
if (TRI_EqualString(typeStr, "cap")) {
|
||||
int res = CapConstraintFromJson(document, json, iid, idx);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// ...........................................................................
|
||||
// BITARRAY INDEX
|
||||
// ...........................................................................
|
||||
|
||||
else if (TRI_EqualString(typeStr, "bitarray")) {
|
||||
int res = BitarrayIndexFromJson(document, json, iid, idx);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// ...........................................................................
|
||||
// GEO INDEX (list or attribute)
|
||||
// ...........................................................................
|
||||
|
||||
else if (TRI_EqualString(typeStr, "geo1") || TRI_EqualString(typeStr, "geo2")) {
|
||||
int res = GeoIndexFromJson(document, json, iid, idx);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// ...........................................................................
|
||||
// HASH INDEX
|
||||
// ...........................................................................
|
||||
|
||||
else if (TRI_EqualString(typeStr, "hash")) {
|
||||
int res = HashIndexFromJson(document, json, iid, idx);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// ...........................................................................
|
||||
// SKIPLIST INDEX
|
||||
// ...........................................................................
|
||||
|
||||
else if (TRI_EqualString(typeStr, "skiplist")) {
|
||||
int res = SkiplistIndexFromJson(document, json, iid, idx);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// ...........................................................................
|
||||
// FULLTEXT INDEX
|
||||
// ...........................................................................
|
||||
|
||||
else if (TRI_EqualString(typeStr, "fulltext")) {
|
||||
int res = FulltextIndexFromJson(document, json, iid, idx);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// ...........................................................................
|
||||
// PRIORITY QUEUE
|
||||
// ...........................................................................
|
||||
|
||||
else if (TRI_EqualString(typeStr, "priorityqueue")) {
|
||||
int res = PriorityQueueFromJson(document, json, iid, idx);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// ...........................................................................
|
||||
// EDGES INDEX
|
||||
// ...........................................................................
|
||||
|
||||
else if (TRI_EqualString(typeStr, "edge")) {
|
||||
// we should never get here, as users cannot create their own edge indexes
|
||||
LOG_ERROR("logic error. there should never be a JSON file describing an edges index");
|
||||
|
||||
return TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
// .........................................................................
|
||||
// oops, unknown index type
|
||||
// .........................................................................
|
||||
|
||||
else {
|
||||
LOG_ERROR("ignoring unknown index type '%s' for index %llu",
|
||||
typeStr,
|
||||
(unsigned long long) iid);
|
||||
|
||||
return TRI_ERROR_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief rolls back a document operation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -3441,7 +3464,9 @@ pid_name_t;
|
|||
/// @brief converts extracts a field list from a json object
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static TRI_json_t* ExtractFields (TRI_json_t* json, size_t* fieldCount, TRI_idx_iid_t iid) {
|
||||
static TRI_json_t* ExtractFields (TRI_json_t const* json,
|
||||
size_t* fieldCount,
|
||||
TRI_idx_iid_t iid) {
|
||||
TRI_json_t* fld;
|
||||
size_t j;
|
||||
|
||||
|
@ -3479,7 +3504,9 @@ static TRI_json_t* ExtractFields (TRI_json_t* json, size_t* fieldCount, TRI_idx_
|
|||
/// as a json object
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static TRI_json_t* ExtractFieldValues (TRI_json_t* jsonIndex, size_t* fieldCount, TRI_idx_iid_t iid) {
|
||||
static TRI_json_t* ExtractFieldValues (TRI_json_t const* jsonIndex,
|
||||
size_t* fieldCount,
|
||||
TRI_idx_iid_t iid) {
|
||||
TRI_json_t* keyValues;
|
||||
size_t j;
|
||||
|
||||
|
@ -3558,7 +3585,8 @@ static TRI_json_t* ExtractFieldValues (TRI_json_t* jsonIndex, size_t* fieldCount
|
|||
/// @brief initialises an index with all existing documents
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int FillIndex (TRI_document_collection_t* document, TRI_index_t* idx) {
|
||||
static int FillIndex (TRI_document_collection_t* document,
|
||||
TRI_index_t* idx) {
|
||||
TRI_doc_mptr_t const* mptr;
|
||||
TRI_primary_collection_t* primary;
|
||||
uint64_t inserted;
|
||||
|
@ -3724,14 +3752,15 @@ static TRI_index_t* LookupPathIndexDocumentCollection (TRI_document_collection_t
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int BitarrayBasedIndexFromJson (TRI_document_collection_t* document,
|
||||
TRI_json_t* definition,
|
||||
TRI_json_t const* definition,
|
||||
TRI_idx_iid_t iid,
|
||||
TRI_index_t* (*creator)(TRI_document_collection_t*,
|
||||
const TRI_vector_pointer_t*,
|
||||
const TRI_vector_pointer_t*,
|
||||
TRI_idx_iid_t,
|
||||
bool,
|
||||
bool*, int*, char**)) {
|
||||
bool*, int*, char**),
|
||||
TRI_index_t** dst) {
|
||||
TRI_index_t* idx;
|
||||
TRI_json_t* uniqueIndex;
|
||||
TRI_json_t* supportUndefIndex;
|
||||
|
@ -3746,11 +3775,16 @@ static int BitarrayBasedIndexFromJson (TRI_document_collection_t* document,
|
|||
int errorNum;
|
||||
char* errorStr;
|
||||
|
||||
if (dst != NULL) {
|
||||
*dst = NULL;
|
||||
}
|
||||
|
||||
// ...........................................................................
|
||||
// extract fields list (which is a list of key/value pairs for a bitarray index
|
||||
// ...........................................................................
|
||||
|
||||
keyValues = ExtractFieldValues(definition, &fieldCount, iid);
|
||||
|
||||
if (keyValues == NULL) {
|
||||
return TRI_errno();
|
||||
}
|
||||
|
@ -3850,6 +3884,10 @@ static int BitarrayBasedIndexFromJson (TRI_document_collection_t* document,
|
|||
return errorNum;
|
||||
}
|
||||
|
||||
if (dst != NULL) {
|
||||
*dst = idx;
|
||||
}
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
@ -3859,13 +3897,14 @@ static int BitarrayBasedIndexFromJson (TRI_document_collection_t* document,
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int PathBasedIndexFromJson (TRI_document_collection_t* document,
|
||||
TRI_json_t* definition,
|
||||
TRI_json_t const* definition,
|
||||
TRI_idx_iid_t iid,
|
||||
TRI_index_t* (*creator)(TRI_document_collection_t*,
|
||||
TRI_vector_pointer_t const*,
|
||||
TRI_idx_iid_t,
|
||||
bool,
|
||||
bool*)) {
|
||||
bool*),
|
||||
TRI_index_t** dst) {
|
||||
TRI_index_t* idx;
|
||||
TRI_json_t* bv;
|
||||
TRI_json_t* fld;
|
||||
|
@ -3875,6 +3914,10 @@ static int PathBasedIndexFromJson (TRI_document_collection_t* document,
|
|||
size_t fieldCount;
|
||||
size_t j;
|
||||
|
||||
if (dst != NULL) {
|
||||
*dst = NULL;
|
||||
}
|
||||
|
||||
// extract fields
|
||||
fld = ExtractFields(definition, &fieldCount, iid);
|
||||
|
||||
|
@ -3915,6 +3958,10 @@ static int PathBasedIndexFromJson (TRI_document_collection_t* document,
|
|||
// create the index
|
||||
idx = creator(document, &attributes, iid, unique, NULL);
|
||||
|
||||
if (dst != NULL) {
|
||||
*dst = idx;
|
||||
}
|
||||
|
||||
// cleanup
|
||||
TRI_DestroyVectorPointer(&attributes);
|
||||
|
||||
|
@ -4241,14 +4288,19 @@ static TRI_index_t* CreateCapConstraintDocumentCollection (TRI_document_collecti
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int CapConstraintFromJson (TRI_document_collection_t* document,
|
||||
TRI_json_t* definition,
|
||||
TRI_idx_iid_t iid) {
|
||||
TRI_json_t const* definition,
|
||||
TRI_idx_iid_t iid,
|
||||
TRI_index_t** dst) {
|
||||
TRI_json_t* val1;
|
||||
TRI_json_t* val2;
|
||||
TRI_index_t* idx;
|
||||
size_t count;
|
||||
int64_t size;
|
||||
|
||||
if (dst != NULL) {
|
||||
*dst = NULL;
|
||||
}
|
||||
|
||||
val1 = TRI_LookupArrayJson(definition, "size");
|
||||
val2 = TRI_LookupArrayJson(definition, "byteSize");
|
||||
|
||||
|
@ -4280,6 +4332,9 @@ static int CapConstraintFromJson (TRI_document_collection_t* document,
|
|||
}
|
||||
|
||||
idx = CreateCapConstraintDocumentCollection(document, count, size, iid, NULL);
|
||||
if (dst != NULL) {
|
||||
*dst = idx;
|
||||
}
|
||||
|
||||
return idx == NULL ? TRI_errno() : TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
@ -4499,8 +4554,9 @@ static TRI_index_t* CreateGeoIndexDocumentCollection (TRI_document_collection_t*
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int GeoIndexFromJson (TRI_document_collection_t* document,
|
||||
TRI_json_t* definition,
|
||||
TRI_idx_iid_t iid) {
|
||||
TRI_json_t const* definition,
|
||||
TRI_idx_iid_t iid,
|
||||
TRI_index_t** dst) {
|
||||
TRI_index_t* idx;
|
||||
TRI_json_t* bv;
|
||||
TRI_json_t* fld;
|
||||
|
@ -4509,6 +4565,10 @@ static int GeoIndexFromJson (TRI_document_collection_t* document,
|
|||
char const* typeStr;
|
||||
size_t fieldCount;
|
||||
|
||||
if (dst != NULL) {
|
||||
*dst = NULL;
|
||||
}
|
||||
|
||||
typeStr = TRI_LookupArrayJson(definition, "type")->_value._string.data;
|
||||
|
||||
// extract fields
|
||||
|
@ -4569,6 +4629,10 @@ static int GeoIndexFromJson (TRI_document_collection_t* document,
|
|||
ignoreNull,
|
||||
iid,
|
||||
NULL);
|
||||
|
||||
if (dst != NULL) {
|
||||
*dst = idx;
|
||||
}
|
||||
|
||||
return idx == NULL ? TRI_errno() : TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
@ -4598,6 +4662,10 @@ static int GeoIndexFromJson (TRI_document_collection_t* document,
|
|||
ignoreNull,
|
||||
iid,
|
||||
NULL);
|
||||
|
||||
if (dst != NULL) {
|
||||
*dst = idx;
|
||||
}
|
||||
|
||||
return idx == NULL ? TRI_errno() : TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
@ -4919,9 +4987,10 @@ static TRI_index_t* CreateHashIndexDocumentCollection (TRI_document_collection_t
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int HashIndexFromJson (TRI_document_collection_t* document,
|
||||
TRI_json_t* definition,
|
||||
TRI_idx_iid_t iid) {
|
||||
return PathBasedIndexFromJson(document, definition, iid, CreateHashIndexDocumentCollection);
|
||||
TRI_json_t const* definition,
|
||||
TRI_idx_iid_t iid,
|
||||
TRI_index_t** dst) {
|
||||
return PathBasedIndexFromJson(document, definition, iid, CreateHashIndexDocumentCollection, dst);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -5147,9 +5216,10 @@ static TRI_index_t* CreateSkiplistIndexDocumentCollection (TRI_document_collecti
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int SkiplistIndexFromJson (TRI_document_collection_t* document,
|
||||
TRI_json_t* definition,
|
||||
TRI_idx_iid_t iid) {
|
||||
return PathBasedIndexFromJson(document, definition, iid, CreateSkiplistIndexDocumentCollection);
|
||||
TRI_json_t const* definition,
|
||||
TRI_idx_iid_t iid,
|
||||
TRI_index_t** dst) {
|
||||
return PathBasedIndexFromJson(document, definition, iid, CreateSkiplistIndexDocumentCollection, dst);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -5390,8 +5460,9 @@ static TRI_index_t* CreateFulltextIndexDocumentCollection (TRI_document_collecti
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int FulltextIndexFromJson (TRI_document_collection_t* document,
|
||||
TRI_json_t* definition,
|
||||
TRI_idx_iid_t iid) {
|
||||
TRI_json_t const* definition,
|
||||
TRI_idx_iid_t iid,
|
||||
TRI_index_t** dst) {
|
||||
TRI_index_t* idx;
|
||||
TRI_json_t* attribute;
|
||||
TRI_json_t* fld;
|
||||
|
@ -5402,6 +5473,10 @@ static int FulltextIndexFromJson (TRI_document_collection_t* document,
|
|||
bool doIndexSubstrings;
|
||||
int minWordLengthValue;
|
||||
|
||||
if (dst != NULL) {
|
||||
*dst = NULL;
|
||||
}
|
||||
|
||||
// extract fields
|
||||
fld = ExtractFields(definition, &fieldCount, iid);
|
||||
|
||||
|
@ -5441,6 +5516,10 @@ static int FulltextIndexFromJson (TRI_document_collection_t* document,
|
|||
idx = CreateFulltextIndexDocumentCollection(document, attributeName, doIndexSubstrings, minWordLengthValue, iid, &created);
|
||||
}
|
||||
|
||||
if (dst != NULL) {
|
||||
*dst = idx;
|
||||
}
|
||||
|
||||
if (idx == NULL) {
|
||||
LOG_ERROR("cannot create fulltext index %llu", (unsigned long long) iid);
|
||||
return TRI_errno();
|
||||
|
@ -5683,9 +5762,10 @@ static TRI_index_t* CreatePriorityQueueIndexDocumentCollection (TRI_document_col
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int PriorityQueueFromJson (TRI_document_collection_t* document,
|
||||
TRI_json_t* definition,
|
||||
TRI_idx_iid_t iid) {
|
||||
return PathBasedIndexFromJson(document, definition, iid, CreatePriorityQueueIndexDocumentCollection);
|
||||
TRI_json_t const* definition,
|
||||
TRI_idx_iid_t iid,
|
||||
TRI_index_t** dst) {
|
||||
return PathBasedIndexFromJson(document, definition, iid, CreatePriorityQueueIndexDocumentCollection, dst);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -5976,9 +6056,10 @@ static TRI_index_t* CreateBitarrayIndexDocumentCollection (TRI_document_collecti
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int BitarrayIndexFromJson (TRI_document_collection_t* document,
|
||||
TRI_json_t* definition,
|
||||
TRI_idx_iid_t iid) {
|
||||
return BitarrayBasedIndexFromJson(document, definition, iid, CreateBitarrayIndexDocumentCollection);
|
||||
TRI_json_t const* definition,
|
||||
TRI_idx_iid_t iid,
|
||||
TRI_index_t** dst) {
|
||||
return BitarrayBasedIndexFromJson(document, definition, iid, CreateBitarrayIndexDocumentCollection, dst);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -45,6 +45,8 @@ extern "C" {
|
|||
// -----------------------------------------------------------------------------
|
||||
|
||||
struct TRI_df_marker_s;
|
||||
struct TRI_index_s;
|
||||
struct TRI_json_s;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- DOCUMENT COLLECTION
|
||||
|
@ -276,6 +278,14 @@ void TRI_FreeDocumentCollection (TRI_document_collection_t*);
|
|||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an index, based on a JSON description
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_FromJsonIndexDocumentCollection (TRI_document_collection_t*,
|
||||
struct TRI_json_s const*,
|
||||
struct TRI_index_s**);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief rolls back a document operation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -746,8 +746,8 @@ static TRI_json_t* JsonEdge (TRI_index_t* idx, TRI_primary_collection_t const* p
|
|||
json = TRI_JsonIndex(TRI_CORE_MEM_ZONE, idx);
|
||||
|
||||
fields = TRI_CreateListJson(TRI_CORE_MEM_ZONE);
|
||||
TRI_PushBack3ListJson(TRI_CORE_MEM_ZONE, fields, TRI_CreateStringCopyJson(TRI_CORE_MEM_ZONE, "_from"));
|
||||
TRI_PushBack3ListJson(TRI_CORE_MEM_ZONE, fields, TRI_CreateStringCopyJson(TRI_CORE_MEM_ZONE, "_to"));
|
||||
TRI_PushBack3ListJson(TRI_CORE_MEM_ZONE, fields, TRI_CreateStringCopyJson(TRI_CORE_MEM_ZONE, TRI_VOC_ATTRIBUTE_FROM));
|
||||
TRI_PushBack3ListJson(TRI_CORE_MEM_ZONE, fields, TRI_CreateStringCopyJson(TRI_CORE_MEM_ZONE, TRI_VOC_ATTRIBUTE_TO));
|
||||
TRI_Insert3ArrayJson(TRI_CORE_MEM_ZONE, json, "fields", fields);
|
||||
|
||||
return json;
|
||||
|
@ -800,7 +800,7 @@ TRI_index_t* TRI_CreateEdgeIndex (struct TRI_primary_collection_s* primary) {
|
|||
idx = &edgeIndex->base;
|
||||
|
||||
TRI_InitVectorString(&idx->_fields, TRI_CORE_MEM_ZONE);
|
||||
id = TRI_DuplicateStringZ(TRI_CORE_MEM_ZONE, "_from");
|
||||
id = TRI_DuplicateStringZ(TRI_CORE_MEM_ZONE, TRI_VOC_ATTRIBUTE_FROM);
|
||||
TRI_PushBackVectorString(&idx->_fields, id);
|
||||
|
||||
idx->typeName = TypeNameEdge;
|
||||
|
|
|
@ -317,7 +317,7 @@ typedef struct TRI_primary_collection_s {
|
|||
#endif
|
||||
int (*notifyTransaction) (struct TRI_primary_collection_s*, TRI_transaction_status_e);
|
||||
|
||||
int (*insert) (struct TRI_transaction_collection_s*, const TRI_voc_key_t, TRI_doc_mptr_t*, TRI_df_marker_type_e, TRI_shaped_json_t const*, void const*, const bool, const bool);
|
||||
int (*insert) (struct TRI_transaction_collection_s*, const TRI_voc_key_t, TRI_voc_rid_t, TRI_doc_mptr_t*, TRI_df_marker_type_e, TRI_shaped_json_t const*, void const*, const bool, const bool);
|
||||
|
||||
int (*read) (struct TRI_transaction_collection_s*, const TRI_voc_key_t, TRI_doc_mptr_t*, const bool);
|
||||
|
||||
|
|
|
@ -365,6 +365,7 @@ static int LogEvent (TRI_replication_logger_t* logger,
|
|||
|
||||
res = primary->insert(logger->_trxCollection,
|
||||
NULL,
|
||||
0,
|
||||
&mptr,
|
||||
TRI_DOC_MARKER_KEY_DOCUMENT,
|
||||
shaped,
|
||||
|
@ -565,6 +566,10 @@ static bool StringifyDocumentOperation (TRI_string_buffer_t* buffer,
|
|||
TRI_voc_key_t key;
|
||||
TRI_voc_rid_t oldRev;
|
||||
TRI_voc_rid_t rid;
|
||||
|
||||
if (! TRI_ReserveStringBuffer(buffer, 256)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type == TRI_VOC_DOCUMENT_OPERATION_INSERT) {
|
||||
oldRev = 0;
|
||||
|
@ -631,9 +636,9 @@ static bool StringifyDocumentOperation (TRI_string_buffer_t* buffer,
|
|||
APPEND_STRING(buffer, "\",\"doc\":{");
|
||||
|
||||
// common document meta-data
|
||||
APPEND_STRING(buffer, "\"_key\":\"");
|
||||
APPEND_STRING(buffer, "\"" TRI_VOC_ATTRIBUTE_KEY "\":\"");
|
||||
APPEND_STRING(buffer, key);
|
||||
APPEND_STRING(buffer, "\",\"_rev\":\"");
|
||||
APPEND_STRING(buffer, "\",\"" TRI_VOC_ATTRIBUTE_REV "\":\"");
|
||||
APPEND_UINT64(buffer, (uint64_t) rid);
|
||||
APPEND_CHAR(buffer, '"');
|
||||
|
||||
|
@ -642,11 +647,11 @@ static bool StringifyDocumentOperation (TRI_string_buffer_t* buffer,
|
|||
TRI_voc_key_t fromKey = ((char*) e) + e->_offsetFromKey;
|
||||
TRI_voc_key_t toKey = ((char*) e) + e->_offsetToKey;
|
||||
|
||||
APPEND_STRING(buffer, ",\"_from\":\"");
|
||||
APPEND_STRING(buffer, ",\"" TRI_VOC_ATTRIBUTE_FROM "\":\"");
|
||||
APPEND_UINT64(buffer, (uint64_t) e->_fromCid);
|
||||
APPEND_CHAR(buffer, '/');
|
||||
APPEND_STRING(buffer, fromKey);
|
||||
APPEND_STRING(buffer, "\",\"_to\":\"");
|
||||
APPEND_STRING(buffer, "\",\"" TRI_VOC_ATTRIBUTE_TO "\":\"");
|
||||
APPEND_UINT64(buffer, (uint64_t) e->_toCid);
|
||||
APPEND_CHAR(buffer, '/');
|
||||
APPEND_STRING(buffer, toKey);
|
||||
|
@ -757,8 +762,6 @@ static bool StringifyMarkerReplication (TRI_string_buffer_t* buffer,
|
|||
APPEND_STRING(buffer, "\",\"key\":\"");
|
||||
// key is user-defined, but does not need escaping
|
||||
APPEND_STRING(buffer, key);
|
||||
APPEND_STRING(buffer, "\",\"rid\":\"");
|
||||
APPEND_UINT64(buffer, (uint64_t) rid);
|
||||
|
||||
// document
|
||||
if (marker->_type == TRI_DOC_MARKER_KEY_DOCUMENT ||
|
||||
|
@ -769,9 +772,9 @@ static bool StringifyMarkerReplication (TRI_string_buffer_t* buffer,
|
|||
APPEND_STRING(buffer, "\",\"doc\":{");
|
||||
|
||||
// common document meta-data
|
||||
APPEND_STRING(buffer, "\"_key\":\"");
|
||||
APPEND_STRING(buffer, "\"" TRI_VOC_ATTRIBUTE_KEY "\":\"");
|
||||
APPEND_STRING(buffer, key);
|
||||
APPEND_STRING(buffer, "\",\"_rev\":\"");
|
||||
APPEND_STRING(buffer, "\",\"" TRI_VOC_ATTRIBUTE_REV "\":\"");
|
||||
APPEND_UINT64(buffer, (uint64_t) rid);
|
||||
APPEND_CHAR(buffer, '"');
|
||||
|
||||
|
@ -780,11 +783,11 @@ static bool StringifyMarkerReplication (TRI_string_buffer_t* buffer,
|
|||
TRI_voc_key_t fromKey = ((char*) e) + e->_offsetFromKey;
|
||||
TRI_voc_key_t toKey = ((char*) e) + e->_offsetToKey;
|
||||
|
||||
APPEND_STRING(buffer, ",\"_from\":\"");
|
||||
APPEND_STRING(buffer, ",\"" TRI_VOC_ATTRIBUTE_FROM "\":\"");
|
||||
APPEND_UINT64(buffer, (uint64_t) e->_fromCid);
|
||||
APPEND_CHAR(buffer, '/');
|
||||
APPEND_STRING(buffer, fromKey);
|
||||
APPEND_STRING(buffer, "\",\"_to\":\"");
|
||||
APPEND_STRING(buffer, "\",\"" TRI_VOC_ATTRIBUTE_TO "\":\"");
|
||||
APPEND_UINT64(buffer, (uint64_t) e->_toCid);
|
||||
APPEND_CHAR(buffer, '/');
|
||||
APPEND_STRING(buffer, toKey);
|
||||
|
@ -890,12 +893,12 @@ static int DumpCollection (TRI_replication_dump_t* dump,
|
|||
TRI_vector_t datafiles;
|
||||
TRI_document_collection_t* document;
|
||||
TRI_string_buffer_t* buffer;
|
||||
TRI_voc_tick_t firstFoundTick;
|
||||
TRI_voc_tick_t lastFoundTick;
|
||||
TRI_voc_tid_t lastTid;
|
||||
size_t i;
|
||||
int res;
|
||||
bool hasMore;
|
||||
bool bufferFull;
|
||||
bool ignoreMarkers;
|
||||
|
||||
LOG_TRACE("dumping collection %llu, tick range %llu - %llu, chunk size %llu",
|
||||
|
@ -909,11 +912,11 @@ static int DumpCollection (TRI_replication_dump_t* dump,
|
|||
document = (TRI_document_collection_t*) primary;
|
||||
|
||||
// setup some iteration state
|
||||
firstFoundTick = 0;
|
||||
lastFoundTick = 0;
|
||||
lastTid = 0;
|
||||
res = TRI_ERROR_NO_ERROR;
|
||||
hasMore = true;
|
||||
bufferFull = false;
|
||||
ignoreMarkers = false;
|
||||
|
||||
for (i = 0; i < datafiles._length; ++i) {
|
||||
|
@ -984,7 +987,7 @@ static int DumpCollection (TRI_replication_dump_t* dump,
|
|||
// get the marker's tick and check whether we should include it
|
||||
foundTick = marker->_tick;
|
||||
|
||||
if (foundTick < tickMin) {
|
||||
if (foundTick <= tickMin) {
|
||||
// marker too old
|
||||
continue;
|
||||
}
|
||||
|
@ -996,9 +999,6 @@ static int DumpCollection (TRI_replication_dump_t* dump,
|
|||
}
|
||||
|
||||
// note the last tick we processed
|
||||
if (firstFoundTick == 0) {
|
||||
firstFoundTick = foundTick;
|
||||
}
|
||||
lastFoundTick = foundTick;
|
||||
|
||||
|
||||
|
@ -1039,7 +1039,7 @@ static int DumpCollection (TRI_replication_dump_t* dump,
|
|||
|
||||
if ((uint64_t) TRI_LengthStringBuffer(buffer) > chunkSize) {
|
||||
// abort the iteration
|
||||
hasMore = ((ptr < end) || (i < datafiles._length - 1));
|
||||
bufferFull = true;
|
||||
|
||||
goto NEXT_DF;
|
||||
}
|
||||
|
@ -1057,7 +1057,7 @@ NEXT_DF:
|
|||
}
|
||||
}
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR || ! hasMore) {
|
||||
if (res != TRI_ERROR_NO_ERROR || ! hasMore || bufferFull) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1065,15 +1065,17 @@ NEXT_DF:
|
|||
TRI_DestroyVector(&datafiles);
|
||||
|
||||
if (res == TRI_ERROR_NO_ERROR) {
|
||||
if (datafiles._length > 0) {
|
||||
if (lastFoundTick > 0) {
|
||||
// data available for requested range
|
||||
dump->_lastFoundTick = lastFoundTick;
|
||||
dump->_hasMore = hasMore;
|
||||
dump->_bufferFull = bufferFull;
|
||||
}
|
||||
else {
|
||||
// no data available for requested range
|
||||
dump->_lastFoundTick = 0;
|
||||
dump->_hasMore = false;
|
||||
dump->_bufferFull = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1196,6 +1198,7 @@ static int StopReplicationLogger (TRI_replication_logger_t* logger) {
|
|||
|
||||
res = LogEvent(logger, 0, true, OPERATION_REPLICATION_STOP, buffer);
|
||||
|
||||
TRI_CommitTransaction(logger->_trx, 0);
|
||||
TRI_FreeTransaction(logger->_trx);
|
||||
|
||||
LOG_INFO("stopped replication logger for database '%s', last id: %llu",
|
||||
|
|
|
@ -71,7 +71,19 @@ struct TRI_vocbase_s;
|
|||
/// @brief default size for each log file
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define TRI_REPLICATION_DEFAULT_LOG_SIZE (64 * 1024 * 1024)
|
||||
#define TRI_REPLICATION_DEFAULT_LOG_SIZE (64 * 1024 * 1024)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief HTTP response header for "check for more data?"
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define TRI_REPLICATION_HEADER_CHECKMORE "x-arango-checkmore"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief HTTP response header for "last found tick"
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define TRI_REPLICATION_HEADER_LASTFOUND "x-arango-lastfound"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
|
@ -94,6 +106,7 @@ typedef struct TRI_replication_dump_s {
|
|||
struct TRI_string_buffer_s* _buffer;
|
||||
TRI_voc_tick_t _lastFoundTick;
|
||||
bool _hasMore;
|
||||
bool _bufferFull;
|
||||
}
|
||||
TRI_replication_dump_t;
|
||||
|
||||
|
|
|
@ -725,7 +725,16 @@ static int InsertTrxCallback (TRI_transaction_collection_t* trxCollection,
|
|||
return TRI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
res = primary->insert(trxCollection, coordinator->_key, &coordinator->_mptr, TRI_DOC_MARKER_KEY_DOCUMENT, shaped, NULL, false, false);
|
||||
res = primary->insert(trxCollection,
|
||||
coordinator->_key,
|
||||
0,
|
||||
&coordinator->_mptr,
|
||||
TRI_DOC_MARKER_KEY_DOCUMENT,
|
||||
shaped,
|
||||
NULL,
|
||||
false,
|
||||
false);
|
||||
|
||||
TRI_FreeShapedJson(primary->_shaper, shaped);
|
||||
|
||||
return res;
|
||||
|
|
|
@ -189,6 +189,30 @@ struct TRI_transaction_context_s;
|
|||
|
||||
extern size_t PageSize;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief name of the _from attribute
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define TRI_VOC_ATTRIBUTE_FROM "_from"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief name of the _to attribute
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define TRI_VOC_ATTRIBUTE_TO "_to"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief name of the _key attribute
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define TRI_VOC_ATTRIBUTE_KEY "_key"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief name of the _rev attribute
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define TRI_VOC_ATTRIBUTE_REV "_rev"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief name of the system database
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -94,6 +94,7 @@
|
|||
"ERROR_REPLICATION_MASTER_INCOMPATIBLE" : { "code" : 1403, "message" : "master incompatible" },
|
||||
"ERROR_REPLICATION_MASTER_CHANGE" : { "code" : 1404, "message" : "master change" },
|
||||
"ERROR_REPLICATION_LOOP" : { "code" : 1405, "message" : "loop detected" },
|
||||
"ERROR_REPLICATION_UNEXPECTED_MARKER" : { "code" : 1406, "message" : "unexpected marker" },
|
||||
"ERROR_QUERY_KILLED" : { "code" : 1500, "message" : "query killed" },
|
||||
"ERROR_QUERY_PARSE" : { "code" : 1501, "message" : "%s" },
|
||||
"ERROR_QUERY_EMPTY" : { "code" : 1502, "message" : "query is empty" },
|
||||
|
|
|
@ -94,6 +94,7 @@
|
|||
"ERROR_REPLICATION_MASTER_INCOMPATIBLE" : { "code" : 1403, "message" : "master incompatible" },
|
||||
"ERROR_REPLICATION_MASTER_CHANGE" : { "code" : 1404, "message" : "master change" },
|
||||
"ERROR_REPLICATION_LOOP" : { "code" : 1405, "message" : "loop detected" },
|
||||
"ERROR_REPLICATION_UNEXPECTED_MARKER" : { "code" : 1406, "message" : "unexpected marker" },
|
||||
"ERROR_QUERY_KILLED" : { "code" : 1500, "message" : "query killed" },
|
||||
"ERROR_QUERY_PARSE" : { "code" : 1501, "message" : "%s" },
|
||||
"ERROR_QUERY_EMPTY" : { "code" : 1502, "message" : "query is empty" },
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief json helper functions
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2004-2013 triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Jan Steemann
|
||||
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Basics/JsonHelper.h"
|
||||
|
||||
#include "BasicsC/json.h"
|
||||
#include "BasicsC/string-buffer.h"
|
||||
|
||||
using namespace triagens::basics;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- class JsonHelper
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public static methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @addtogroup ArangoDB
|
||||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief stringify json
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string JsonHelper::toString (TRI_json_t const* json) {
|
||||
TRI_string_buffer_t buffer;
|
||||
|
||||
TRI_InitStringBuffer(&buffer, TRI_UNKNOWN_MEM_ZONE);
|
||||
int res = TRI_StringifyJson(&buffer, json);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return "";
|
||||
}
|
||||
|
||||
string out(TRI_BeginStringBuffer(&buffer), TRI_LengthStringBuffer(&buffer));
|
||||
TRI_DestroyStringBuffer(&buffer);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns true for arrays
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool JsonHelper::isArray (TRI_json_t const* json) {
|
||||
return json != 0 && json->_type == TRI_JSON_ARRAY;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns true for lists
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool JsonHelper::isList (TRI_json_t const* json) {
|
||||
return json != 0 && json->_type == TRI_JSON_LIST;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns true for strings
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool JsonHelper::isString (TRI_json_t const* json) {
|
||||
return json != 0 && json->_type == TRI_JSON_STRING && json->_value._string.data != 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns true for numbers
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool JsonHelper::isNumber (TRI_json_t const* json) {
|
||||
return json != 0 && json->_type == TRI_JSON_NUMBER;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns true for booleans
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool JsonHelper::isBoolean (TRI_json_t const* json) {
|
||||
return json != 0 && json->_type == TRI_JSON_BOOLEAN;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns an array sub-element
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_json_t* JsonHelper::getArrayElement (TRI_json_t const* json,
|
||||
const char* name) {
|
||||
if (! isArray(json)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return TRI_LookupArrayJson(json, name);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns a string sub-element, or a default it is does not exist
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string JsonHelper::getStringValue (TRI_json_t const* json,
|
||||
const char* name,
|
||||
const std::string& defaultValue) {
|
||||
TRI_json_t const* sub = getArrayElement(json, name);
|
||||
|
||||
if (isString(sub)) {
|
||||
return string(sub->_value._string.data, sub->_value._string.length - 1);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns a numeric sub-element, or a default it is does not exist
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
double JsonHelper::getNumberValue (TRI_json_t const* json,
|
||||
const char* name,
|
||||
double defaultValue) {
|
||||
TRI_json_t const* sub = getArrayElement(json, name);
|
||||
|
||||
if (isNumber(sub)) {
|
||||
return sub->_value._number;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns a boolean sub-element, or a default it is does not exist
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
double JsonHelper::getBooleanValue (TRI_json_t const* json,
|
||||
const char* name,
|
||||
bool defaultValue) {
|
||||
TRI_json_t const* sub = getArrayElement(json, name);
|
||||
|
||||
if (isBoolean(sub)) {
|
||||
return sub->_value._boolean;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}"
|
||||
// End:
|
|
@ -28,8 +28,9 @@
|
|||
#ifndef TRIAGENS_BASICS_JSON_HELPER_H
|
||||
#define TRIAGENS_BASICS_JSON_HELPER_H 1
|
||||
|
||||
#include "BasicsC/json.h"
|
||||
#include "BasicsC/string-buffer.h"
|
||||
#include "Basics/Common.h"
|
||||
|
||||
struct TRI_json_s;
|
||||
|
||||
namespace triagens {
|
||||
namespace basics {
|
||||
|
@ -59,7 +60,7 @@ namespace triagens {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public methods
|
||||
// --SECTION-- public static methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -73,113 +74,68 @@ namespace triagens {
|
|||
/// @brief stringify json
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static string toString (TRI_json_t const* json) {
|
||||
TRI_string_buffer_t buffer;
|
||||
|
||||
TRI_InitStringBuffer(&buffer, TRI_UNKNOWN_MEM_ZONE);
|
||||
int res = TRI_StringifyJson(&buffer, json);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return "";
|
||||
}
|
||||
|
||||
string out(TRI_BeginStringBuffer(&buffer), TRI_LengthStringBuffer(&buffer));
|
||||
TRI_DestroyStringBuffer(&buffer);
|
||||
|
||||
return out;
|
||||
}
|
||||
static std::string toString (struct TRI_json_s const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns true for arrays
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool isArray (TRI_json_t const* json) {
|
||||
return json != 0 && json->_type == TRI_JSON_ARRAY;
|
||||
}
|
||||
static bool isArray (struct TRI_json_s const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns true for lists
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool isList (TRI_json_t const* json) {
|
||||
return json != 0 && json->_type == TRI_JSON_LIST;
|
||||
}
|
||||
static bool isList (struct TRI_json_s const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns true for strings
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool isString (TRI_json_t const* json) {
|
||||
return json != 0 && json->_type == TRI_JSON_STRING && json->_value._string.data != 0;
|
||||
}
|
||||
static bool isString (struct TRI_json_s const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns true for numbers
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool isNumber (TRI_json_t const* json) {
|
||||
return json != 0 && json->_type == TRI_JSON_NUMBER;
|
||||
}
|
||||
static bool isNumber (struct TRI_json_s const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns true for booleans
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool isBoolean (TRI_json_t const* json) {
|
||||
return json != 0 && json->_type == TRI_JSON_BOOLEAN;
|
||||
}
|
||||
static bool isBoolean (struct TRI_json_s const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns an array sub-element
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static TRI_json_t* getArrayElement (TRI_json_t const* json, const char* name) {
|
||||
if (! isArray(json)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return TRI_LookupArrayJson(json, name);
|
||||
}
|
||||
static struct TRI_json_s* getArrayElement (struct TRI_json_s const*,
|
||||
const char* name);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns a string sub-element, or a default it is does not exist
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static string getStringValue (TRI_json_t const* json, const char* name, const string& defaultValue) {
|
||||
TRI_json_t const* sub = getArrayElement(json, name);
|
||||
|
||||
if (isString(sub)) {
|
||||
return string(sub->_value._string.data, sub->_value._string.length - 1);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
static std::string getStringValue (struct TRI_json_s const*,
|
||||
const char*,
|
||||
const std::string&);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns a numeric sub-element, or a default it is does not exist
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static double getNumberValue (TRI_json_t const* json, const char* name, double defaultValue) {
|
||||
TRI_json_t const* sub = getArrayElement(json, name);
|
||||
|
||||
if (isNumber(sub)) {
|
||||
return sub->_value._number;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
static double getNumberValue (struct TRI_json_s const*,
|
||||
const char*,
|
||||
double);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns a boolean sub-element, or a default it is does not exist
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static double getBooleanValue (TRI_json_t const* json, const char* name, bool defaultValue) {
|
||||
TRI_json_t const* sub = getArrayElement(json, name);
|
||||
|
||||
if (isBoolean(sub)) {
|
||||
return sub->_value._boolean;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
static double getBooleanValue (struct TRI_json_s const*,
|
||||
const char*,
|
||||
bool);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
|
|
|
@ -3230,7 +3230,7 @@ namespace triagens {
|
|||
++k;
|
||||
|
||||
if (k == pos) {
|
||||
return sourceStr.substr(offSet,delPos - offSet);
|
||||
return sourceStr.substr(offSet, delPos - offSet);
|
||||
}
|
||||
|
||||
offSet = delPos + delLength;
|
||||
|
|
|
@ -124,6 +124,7 @@ ERROR_REPLICATION_MASTER_ERROR,1402,"master error","Will be raised when the repl
|
|||
ERROR_REPLICATION_MASTER_INCOMPATIBLE,1403,"master incompatible","Will be raised when the master the replica connects to has an incompatible version."
|
||||
ERROR_REPLICATION_MASTER_CHANGE,1404,"master change","Will be raised when the master the replica connects is changed."
|
||||
ERROR_REPLICATION_LOOP,1405,"loop detected","Will be raised when the replica connects to itself for replication."
|
||||
ERROR_REPLICATION_UNEXPECTED_MARKER,1406,"unexpected marker","Will be raised when an unexpected marker is found in the replication stream."
|
||||
|
||||
################################################################################
|
||||
## ArangoDB query errors
|
||||
|
|
|
@ -90,6 +90,7 @@ void TRI_InitialiseErrorMessages (void) {
|
|||
REG_ERROR(ERROR_REPLICATION_MASTER_INCOMPATIBLE, "master incompatible");
|
||||
REG_ERROR(ERROR_REPLICATION_MASTER_CHANGE, "master change");
|
||||
REG_ERROR(ERROR_REPLICATION_LOOP, "loop detected");
|
||||
REG_ERROR(ERROR_REPLICATION_UNEXPECTED_MARKER, "unexpected marker");
|
||||
REG_ERROR(ERROR_QUERY_KILLED, "query killed");
|
||||
REG_ERROR(ERROR_QUERY_PARSE, "%s");
|
||||
REG_ERROR(ERROR_QUERY_EMPTY, "query is empty");
|
||||
|
|
|
@ -188,6 +188,9 @@ extern "C" {
|
|||
/// Will be raised when the master the replica connects is changed.
|
||||
/// - 1405: @LIT{loop detected}
|
||||
/// Will be raised when the replica connects to itself for replication.
|
||||
/// - 1406: @LIT{unexpected marker}
|
||||
/// Will be raised when an unexpected marker is found in the replication
|
||||
/// stream.
|
||||
/// - 1500: @LIT{query killed}
|
||||
/// Will be raised when a running query is killed by an explicit admin
|
||||
/// command.
|
||||
|
@ -1260,6 +1263,16 @@ void TRI_InitialiseErrorMessages (void);
|
|||
|
||||
#define TRI_ERROR_REPLICATION_LOOP (1405)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief 1406: ERROR_REPLICATION_UNEXPECTED_MARKER
|
||||
///
|
||||
/// unexpected marker
|
||||
///
|
||||
/// Will be raised when an unexpected marker is found in the replication stream.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define TRI_ERROR_REPLICATION_UNEXPECTED_MARKER (1406)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief 1500: ERROR_QUERY_KILLED
|
||||
///
|
||||
|
|
|
@ -489,7 +489,7 @@ namespace triagens {
|
|||
response.setHeader("access-control-allow-headers", strlen("access-control-allow-headers"), allowHeaders);
|
||||
LOGGER_TRACE("client requested validation of the following headers " << allowHeaders);
|
||||
}
|
||||
// set caching time (hard-coded to 1 day)
|
||||
// set caching time (hard-coded value)
|
||||
response.setHeader("access-control-max-age", strlen("access-control-max-age"), "1800");
|
||||
}
|
||||
// End of CORS handling
|
||||
|
@ -604,12 +604,13 @@ namespace triagens {
|
|||
LOGGER_TRACE("HTTP WRITE FOR " << static_cast<Task*>(this) << ":\n" << buffer->c_str());
|
||||
|
||||
// disable the following statement to prevent excessive logging of incoming requests
|
||||
LOGGER_USAGE(this->_connectionInfo.clientAddress << " \"" <<
|
||||
HttpRequest::translateMethod(this->_requestType) << " " <<
|
||||
this->_fullUrl << " " <<
|
||||
HttpRequest::translateVersion(this->_httpVersion) << "\" " <<
|
||||
response->responseCode() << " " <<
|
||||
response->body().length());
|
||||
LOGGER_USAGE(",\"http-request\",\"" << this->_connectionInfo.clientAddress << "\",\"" <<
|
||||
HttpRequest::translateMethod(this->_requestType) << "\",\"" <<
|
||||
HttpRequest::translateVersion(this->_httpVersion) << "\"," <<
|
||||
response->responseCode() << "," <<
|
||||
this->_bodyLength << "," <<
|
||||
response->body().length() << ",\"" <<
|
||||
this->_fullUrl << "\"");
|
||||
|
||||
// clear body
|
||||
response->body().clear();
|
||||
|
|
|
@ -108,7 +108,7 @@ static string LoggerFormat = "%Z;1;%S;%C;%H;%p-%t;%F;%A;%f;%m;%K;%f:%l;%x;%P;%u;
|
|||
/// @brief logger format for raw logging
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static string LoggerRawFormat = "%Z %x";
|
||||
static string LoggerRawFormat = "\"%Z\"%x";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief special characters which must be escaped
|
||||
|
@ -406,7 +406,6 @@ static void OutputMachine (string const& text, LoggerData::Info const& info) {
|
|||
if (! info._prefix.empty()) {
|
||||
line.appendText(StringUtils::escapeHex(info._prefix, SpecialCharacters));
|
||||
}
|
||||
|
||||
line.appendText(StringUtils::escapeHex(text, SpecialCharacters));
|
||||
|
||||
break;
|
||||
|
@ -435,7 +434,7 @@ static void OutputMachine (string const& text, LoggerData::Info const& info) {
|
|||
}
|
||||
}
|
||||
|
||||
TRI_RawLog(info._level, info._severity, line.c_str(), line.length() - 1);
|
||||
TRI_RawLog(info._level, info._severity, line.c_str(), line.length());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -17,6 +17,7 @@ lib_libarango_a_SOURCES = \
|
|||
lib/Basics/Exceptions.cpp \
|
||||
lib/Basics/FileUtils.cpp \
|
||||
lib/Basics/InitialiseBasics.cpp \
|
||||
lib/Basics/JsonHelper.cpp \
|
||||
lib/Basics/LibraryLoader.cpp \
|
||||
lib/Basics/Mutex.cpp \
|
||||
lib/Basics/MutexLocker.cpp \
|
||||
|
|
Loading…
Reference in New Issue