1
0
Fork 0

Merge branch 'devel' of github.com:triAGENS/ArangoDB into devel

This commit is contained in:
Michael Hackstein 2013-07-08 08:45:55 +02:00
commit 4e10a5aa76
37 changed files with 1418 additions and 471 deletions

3
.gitignore vendored
View File

@ -7,6 +7,9 @@ mr-*.h
*~
*.pyc
*.orig
*.rej
.libev-build-64
.v8-build-64
.icu-build-64

View File

@ -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");

View File

@ -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

View File

@ -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;
}
}

View File

@ -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 \

View File

@ -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,
&params,
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, &params, id);
TRI_vocbase_col_t* col = TRI_CreateCollectionVocBase(_vocbase, &params, 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;
}

View File

@ -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);
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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));

View File

@ -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

View File

@ -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:

View File

@ -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*);
////////////////////////////////////////////////////////////////////////////////
/// @}

View File

@ -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);
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -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,

View File

@ -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)));
}
}

View File

@ -1227,6 +1227,7 @@ int TRI_WriteElementDatafile (TRI_datafile_t* datafile,
if (datafile->_tickMin == 0) {
datafile->_tickMin = tick;
}
datafile->_tickMax = tick;
assert(markerSize > 0);

View File

@ -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);
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -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
////////////////////////////////////////////////////////////////////////////////

View File

@ -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;

View File

@ -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);

View File

@ -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",

View File

@ -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;

View File

@ -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;

View File

@ -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
////////////////////////////////////////////////////////////////////////////////

View File

@ -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" },

View File

@ -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" },

173
lib/Basics/JsonHelper.cpp Normal file
View File

@ -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:

View File

@ -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);
////////////////////////////////////////////////////////////////////////////////
/// @}

View File

@ -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;

View File

@ -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

View File

@ -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");

View File

@ -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
///

View File

@ -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();

View File

@ -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());
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -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 \