diff --git a/CHANGELOG b/CHANGELOG index 74c7b6d847..c11d63908d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,24 @@ v2.0.0-alpha1 (2014-02-28) -------------------------- +* added sharding :-) + +* INCOMPATIBLE CHANGE: using complex values in AQL filter conditions with operators other + than equality (e.g. >=, >, <=, <) will disable usage of skiplist indexes for filter + evaluation. + + For example, the following queries will be affected by change: + + FOR doc IN docs FILTER doc.value < { foo: "bar" } RETURN doc + FOR doc IN docs FILTER doc.value >= [ 1, 2, 3 ] RETURN doc + + The following queries will not be affected by the change: + + FOR doc IN docs FILTER doc.value == 1 RETURN doc + FOR doc IN docs FILTER doc.value == "foo" RETURN doc + FOR doc IN docs FILTER doc.value == [ 1, 2, 3 ] RETURN doc + FOR doc IN docs FILTER doc.value == { foo: "bar" } RETURN doc + * added explicit startup parameter `--server.reuse-address` * removed undocumented REST API method GET `/_admin/database-name` diff --git a/arangod/Ahuacatl/ahuacatl-index.c b/arangod/Ahuacatl/ahuacatl-index.c index 9795661917..ff53c9e441 100644 --- a/arangod/Ahuacatl/ahuacatl-index.c +++ b/arangod/Ahuacatl/ahuacatl-index.c @@ -452,6 +452,31 @@ TRI_aql_index_t* TRI_DetermineIndexAql (TRI_aql_context_t* const context, continue; } + if (candidate->_type == TRI_AQL_ACCESS_RANGE_SINGLE) { + // range type. check if the compare value is a list or an object + TRI_json_t* value = candidate->_value._singleRange._value; + + if (TRI_IsListJson(value) || TRI_IsArrayJson(value)) { + // list or object, we cannot use this for comparison in a skiplist + continue; + } + } + else if (candidate->_type == TRI_AQL_ACCESS_RANGE_DOUBLE) { + // range type. check if the compare value is a list or an object + TRI_json_t* value = candidate->_value._between._lower._value; + + if (TRI_IsListJson(value) || TRI_IsArrayJson(value)) { + // list or object, we cannot use this for comparison in a skiplist + continue; + } + + value = candidate->_value._between._upper._value; + if (TRI_IsListJson(value) || TRI_IsArrayJson(value)) { + // list or object, we cannot use this for comparison in a skiplist + continue; + } + } + lastTypeWasExact = candidateIsExact; TRI_PushBackVectorPointer(&matches, candidate); diff --git a/arangod/IndexOperators/index-operator.c b/arangod/IndexOperators/index-operator.c index 077145fe77..10de6ab031 100644 --- a/arangod/IndexOperators/index-operator.c +++ b/arangod/IndexOperators/index-operator.c @@ -161,8 +161,7 @@ void TRI_ClearIndexOperator(TRI_index_operator_t* indexOperator) { case TRI_GT_INDEX_OPERATOR: case TRI_NE_INDEX_OPERATOR: case TRI_LE_INDEX_OPERATOR: - case TRI_LT_INDEX_OPERATOR: - case TRI_IN_INDEX_OPERATOR: { + case TRI_LT_INDEX_OPERATOR: { relationOperator = (TRI_relation_index_operator_t*)(indexOperator); if (relationOperator->_parameters != NULL) { TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, relationOperator->_parameters); @@ -233,9 +232,7 @@ TRI_index_operator_t* TRI_CopyIndexOperator(TRI_index_operator_t* indexOperator) case TRI_GT_INDEX_OPERATOR: case TRI_NE_INDEX_OPERATOR: case TRI_LE_INDEX_OPERATOR: - case TRI_LT_INDEX_OPERATOR: - case TRI_IN_INDEX_OPERATOR: { - + case TRI_LT_INDEX_OPERATOR: { oldRelationOperator = (TRI_relation_index_operator_t*)(indexOperator); newRelationOperator = (TRI_relation_index_operator_t*) (TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_relation_index_operator_t), false)); diff --git a/arangod/IndexOperators/index-operator.h b/arangod/IndexOperators/index-operator.h index 214743dd74..97f5ac7dbc 100644 --- a/arangod/IndexOperators/index-operator.h +++ b/arangod/IndexOperators/index-operator.h @@ -59,7 +59,6 @@ typedef enum { TRI_LT_INDEX_OPERATOR, TRI_GE_INDEX_OPERATOR, TRI_GT_INDEX_OPERATOR, - TRI_IN_INDEX_OPERATOR, TRI_AND_INDEX_OPERATOR, TRI_NOT_INDEX_OPERATOR, diff --git a/arangod/Replication/Syncer.cpp b/arangod/Replication/Syncer.cpp index e1bb5e7aa9..962fc6b16f 100644 --- a/arangod/Replication/Syncer.cpp +++ b/arangod/Replication/Syncer.cpp @@ -268,7 +268,7 @@ int Syncer::applyCollectionDumpMarker (TRI_transaction_collection_t* trxCollecti TRI_primary_collection_t* primary = trxCollection->_collection->_collection; TRI_memory_zone_t* zone = primary->_shaper->_memoryZone; - TRI_shaped_json_t* shaped = TRI_ShapedJsonJson(primary->_shaper, json); + TRI_shaped_json_t* shaped = TRI_ShapedJsonJson(primary->_shaper, json, true, true); if (shaped != 0) { TRI_doc_mptr_t mptr; diff --git a/arangod/RestHandler/RestReplicationHandler.cpp b/arangod/RestHandler/RestReplicationHandler.cpp index c5998ee270..a264909672 100644 --- a/arangod/RestHandler/RestReplicationHandler.cpp +++ b/arangod/RestHandler/RestReplicationHandler.cpp @@ -1895,7 +1895,7 @@ int RestReplicationHandler::applyCollectionDumpMarker (CollectionNameResolver co TRI_primary_collection_t* primary = trxCollection->_collection->_collection; TRI_memory_zone_t* zone = primary->_shaper->_memoryZone; - TRI_shaped_json_t* shaped = TRI_ShapedJsonJson(primary->_shaper, json); + TRI_shaped_json_t* shaped = TRI_ShapedJsonJson(primary->_shaper, json, true, true); if (shaped != 0) { TRI_doc_mptr_t mptr; diff --git a/arangod/SkipLists/skiplistIndex.c b/arangod/SkipLists/skiplistIndex.c index 51811d5a44..7d3493fa89 100644 --- a/arangod/SkipLists/skiplistIndex.c +++ b/arangod/SkipLists/skiplistIndex.c @@ -207,7 +207,7 @@ static int CmpElmElm(void* sli, void* left, void* right, /// @brief compares a key with an element in a skip list, generic callback //////////////////////////////////////////////////////////////////////////////// -static int CmpKeyElm(void* sli, void* left, void* right) { +static int CmpKeyElm (void* sli, void* left, void* right) { SkiplistIndex* skiplistindex = sli; TRI_skiplist_index_key_t* leftKey = left; diff --git a/arangod/Utils/Transaction.h b/arangod/Utils/Transaction.h index 54caea5aa2..a6523c90eb 100644 --- a/arangod/Utils/Transaction.h +++ b/arangod/Utils/Transaction.h @@ -844,7 +844,7 @@ namespace triagens { TRI_shaper_t* shaper = this->shaper(trxCollection); TRI_memory_zone_t* zone = shaper->_memoryZone; - TRI_shaped_json_t* shaped = TRI_ShapedJsonJson(shaper, json); + TRI_shaped_json_t* shaped = TRI_ShapedJsonJson(shaper, json, true, isLocked(trxCollection, TRI_TRANSACTION_WRITE)); if (shaped == 0) { return TRI_ERROR_ARANGO_SHAPER_FAILED; @@ -909,7 +909,7 @@ namespace triagens { TRI_shaper_t* shaper = this->shaper(trxCollection); TRI_memory_zone_t* zone = shaper->_memoryZone; - TRI_shaped_json_t* shaped = TRI_ShapedJsonJson(shaper, json); + TRI_shaped_json_t* shaped = TRI_ShapedJsonJson(shaper, json, true, isLocked(trxCollection, TRI_TRANSACTION_WRITE)); if (shaped == 0) { return TRI_ERROR_ARANGO_SHAPER_FAILED; diff --git a/arangod/V8Server/v8-query.cpp b/arangod/V8Server/v8-query.cpp index 921d6e6856..2af2521f3a 100644 --- a/arangod/V8Server/v8-query.cpp +++ b/arangod/V8Server/v8-query.cpp @@ -122,6 +122,21 @@ query_t; /// @{ //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// @brief return an empty result set +//////////////////////////////////////////////////////////////////////////////// + +static v8::Handle EmptyResult () { + v8::HandleScope scope; + + v8::Handle result = v8::Object::New(); + result->Set(v8::String::New("documents"), v8::Array::New()); + result->Set(v8::String::New("total"), v8::Number::New(0)); + result->Set(v8::String::New("count"), v8::Number::New(0)); + + return scope.Close(result); +} + //////////////////////////////////////////////////////////////////////////////// /// @brief extracts skip and limit //////////////////////////////////////////////////////////////////////////////// @@ -212,7 +227,7 @@ static void CleanupExampleObject (TRI_memory_zone_t* zone, /// @brief sets up the example object //////////////////////////////////////////////////////////////////////////////// -static int SetupExampleObject (v8::Handle example, +static int SetupExampleObject (v8::Handle const& example, TRI_shaper_t* shaper, size_t& n, TRI_shape_pid_t*& pids, @@ -250,8 +265,15 @@ static int SetupExampleObject (v8::Handle example, TRI_Utf8ValueNFC keyStr(TRI_UNKNOWN_MEM_ZONE, key); if (*keyStr != 0) { - pids[i] = shaper->findAttributePathByName(shaper, *keyStr); - values[i] = TRI_ShapedJsonV8Object(val, shaper); + pids[i] = shaper->lookupAttributePathByName(shaper, *keyStr); + + if (pids[i] == 0) { + // no attribute path found. this means the result will be empty + CleanupExampleObject(shaper->_memoryZone, i, pids, values); + return TRI_RESULT_ELEMENT_NOT_FOUND; + } + + values[i] = TRI_ShapedJsonV8Object(val, shaper, false, false); } if (*keyStr == 0 || pids[i] == 0 || values[i] == 0) { @@ -951,6 +973,8 @@ static int SetupSearchValue (TRI_vector_t const* paths, // convert for (size_t i = 0; i < n; ++i) { TRI_shape_pid_t pid = * (TRI_shape_pid_t*) TRI_AtVector(paths, i); + + assert(pid != 0); char const* name = TRI_AttributeNameShapePid(shaper, pid); if (name == NULL) { @@ -965,15 +989,18 @@ static int SetupSearchValue (TRI_vector_t const* paths, if (example->HasOwnProperty(key)) { v8::Handle val = example->Get(key); - res = TRI_FillShapedJsonV8Object(val, &result._values[i], shaper); + res = TRI_FillShapedJsonV8Object(val, &result._values[i], shaper, false, false); } else { - res = TRI_FillShapedJsonV8Object(v8::Null(), &result._values[i], shaper); + res = TRI_FillShapedJsonV8Object(v8::Null(), &result._values[i], shaper, false, false); } if (res != TRI_ERROR_NO_ERROR) { DestroySearchValue(shaper->_memoryZone, result); - *err = TRI_CreateErrorObject(res, "cannot convert value to JSON"); + + if (res != TRI_RESULT_ELEMENT_NOT_FOUND) { + *err = TRI_CreateErrorObject(res, "cannot convert value to JSON"); + } return res; } } @@ -1078,6 +1105,11 @@ static v8::Handle ExecuteSkiplistQuery (v8::Arguments const& argv, TRI_skiplist_iterator_t* skiplistIterator = TRI_LookupSkiplistIndex(idx, skiplistOperator); if (skiplistIterator == 0) { + int res = TRI_errno(); + if (res == TRI_RESULT_ELEMENT_NOT_FOUND) { + return scope.Close(EmptyResult()); + } + TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_NO_INDEX); } @@ -1953,6 +1985,11 @@ static v8::Handle JS_ByExampleQuery (v8::Arguments const& argv) { v8::Handle err; res = SetupExampleObject(example, shaper, n, pids, values, &err); + if (res == TRI_RESULT_ELEMENT_NOT_FOUND) { + // empty result + return scope.Close(EmptyResult()); + } + if (res != TRI_ERROR_NO_ERROR) { return scope.Close(v8::ThrowException(err)); } @@ -2085,6 +2122,10 @@ static v8::Handle ByExampleHashIndexQuery (ReadTransactionType& trx, int res = SetupSearchValue(&hashIndex->_paths, example, shaper, searchValue, err); if (res != TRI_ERROR_NO_ERROR) { + if (res == TRI_RESULT_ELEMENT_NOT_FOUND) { + return scope.Close(EmptyResult()); + } + return scope.Close(v8::ThrowException(*err)); } diff --git a/arangod/V8Server/v8-vocbase.cpp b/arangod/V8Server/v8-vocbase.cpp index 9436dec5fb..86dff1394c 100644 --- a/arangod/V8Server/v8-vocbase.cpp +++ b/arangod/V8Server/v8-vocbase.cpp @@ -2465,6 +2465,11 @@ static v8::Handle ReplaceVocbaseCol (bool useCollection, TRI_memory_zone_t* zone = primary->_shaper->_memoryZone; TRI_doc_mptr_t document; + + // we must lock here, because below we are + // - reading the old document in coordinator case + // - creating a shape, which might trigger a write into the collection + trx.lockWrite(); #ifdef TRI_ENABLE_CLUSTER if (ServerState::instance()->isDBserver()) { @@ -2478,7 +2483,6 @@ static v8::Handle ReplaceVocbaseCol (bool useCollection, TRI_V8_EXCEPTION_MEMORY(scope); } - trx.lockWrite(); res = trx.read(&document, key); if (res != TRI_ERROR_NO_ERROR || document._key == 0 || document._data == 0) { @@ -2509,8 +2513,7 @@ static v8::Handle ReplaceVocbaseCol (bool useCollection, } #endif - - TRI_shaped_json_t* shaped = TRI_ShapedJsonV8Object(argv[1], primary->_shaper); + TRI_shaped_json_t* shaped = TRI_ShapedJsonV8Object(argv[1], primary->_shaper, true, true); if (shaped == 0) { TRI_FreeString(TRI_CORE_MEM_ZONE, key); @@ -2575,12 +2578,13 @@ static v8::Handle SaveVocbaseCol ( TRI_primary_collection_t* primary = trx->primaryCollection(); TRI_memory_zone_t* zone = primary->_shaper->_memoryZone; - TRI_shaped_json_t* shaped = TRI_ShapedJsonV8Object(argv[0], primary->_shaper); + + trx->lockWrite(); + + TRI_shaped_json_t* shaped = TRI_ShapedJsonV8Object(argv[0], primary->_shaper, true, true); if (shaped == 0) { - if (key != 0) { - TRI_FreeString(TRI_CORE_MEM_ZONE, key); - } + FREE_STRING(TRI_CORE_MEM_ZONE, key); TRI_V8_EXCEPTION_MESSAGE(scope, TRI_errno(), " cannot be converted into JSON shape"); } @@ -2593,9 +2597,7 @@ static v8::Handle SaveVocbaseCol ( TRI_FreeShapedJson(zone, shaped); - if (key != 0) { - TRI_FreeString(TRI_CORE_MEM_ZONE, key); - } + FREE_STRING(TRI_CORE_MEM_ZONE, key); if (res != TRI_ERROR_NO_ERROR) { TRI_V8_EXCEPTION(scope, res); @@ -2695,8 +2697,9 @@ static v8::Handle SaveEdgeCol ( TRI_primary_collection_t* primary = trx->primaryCollection(); TRI_memory_zone_t* zone = primary->_shaper->_memoryZone; + trx->lockWrite(); // extract shaped data - TRI_shaped_json_t* shaped = TRI_ShapedJsonV8Object(argv[2], primary->_shaper); + TRI_shaped_json_t* shaped = TRI_ShapedJsonV8Object(argv[2], primary->_shaper, true, true); if (shaped == 0) { FREE_STRING(TRI_CORE_MEM_ZONE, edge._fromKey); @@ -10065,7 +10068,11 @@ static v8::Handle PropertyQueryShapedJson (v8::Local na // get shape accessor TRI_shaper_t* shaper = collection->_shaper; - TRI_shape_pid_t pid = shaper->findAttributePathByName(shaper, key.c_str()); + TRI_shape_pid_t pid = shaper->lookupAttributePathByName(shaper, key.c_str()); + + if (pid == 0) { + return scope.Close(v8::Handle()); + } TRI_shape_sid_t sid; TRI_EXTRACT_SHAPE_IDENTIFIER_MARKER(sid, marker); diff --git a/arangod/VocBase/auth.c b/arangod/VocBase/auth.c index cefe3e9f95..bd77b228b0 100644 --- a/arangod/VocBase/auth.c +++ b/arangod/VocBase/auth.c @@ -118,7 +118,11 @@ static char* ExtractStringShapedJson (TRI_shaper_t* shaper, bool ok; char* result; - pid = shaper->findAttributePathByName(shaper, path); + pid = shaper->lookupAttributePathByName(shaper, path); + + if (pid == 0) { + return NULL; + } ok = TRI_ExtractShapedJsonVocShaper(shaper, document, 0, pid, &shaped, &shape); @@ -165,7 +169,12 @@ static bool ExtractBooleanShapedJson (TRI_shaper_t* shaper, *found = false; } - pid = shaper->findAttributePathByName(shaper, path); + pid = shaper->lookupAttributePathByName(shaper, path); + + if (pid == 0) { + return false; + } + ok = TRI_ExtractShapedJsonVocShaper(shaper, document, 0, pid, &shaped, &shape); if (! ok || shape == NULL) { diff --git a/arangod/VocBase/datafile.c b/arangod/VocBase/datafile.c index 31de8aa5a1..fa97dd4e15 100644 --- a/arangod/VocBase/datafile.c +++ b/arangod/VocBase/datafile.c @@ -1214,21 +1214,23 @@ int TRI_WriteElementDatafile (TRI_datafile_t* datafile, #ifdef TRI_ENABLE_MAINTAINER_MODE // check _tick value of marker and set min/max tick values for datafile if (tick <= datafile->_tickMin || tick <= (TRI_voc_tick_t) datafile->_fid) { - LOG_WARNING("logic error. invalid tick value %llu encountered when writing marker of type %d into datafile '%s'. " + LOG_FATAL_AND_EXIT("logic error. invalid tick value %llu encountered when writing marker of type %d into datafile '%s'. " "expected tick value > tickMin %llu", (unsigned long long) tick, (int) marker->_type, datafile->getName(datafile), (unsigned long long) datafile->_tickMin); + assert(false); } if (tick <= datafile->_tickMax) { - LOG_WARNING("logic error. invalid tick value %llu encountered when writing marker of type %d into datafile '%s'. " + LOG_FATAL_AND_EXIT("logic error. invalid tick value %llu encountered when writing marker of type %d into datafile '%s'. " "expected tick value > tickMax %llu", (unsigned long long) tick, (int) marker->_type, datafile->getName(datafile), (unsigned long long) datafile->_tickMax); + assert(false); } #endif diff --git a/arangod/VocBase/document-collection.c b/arangod/VocBase/document-collection.c index 7362a9ab55..6ec55ce35b 100644 --- a/arangod/VocBase/document-collection.c +++ b/arangod/VocBase/document-collection.c @@ -4210,11 +4210,12 @@ bool TRI_DropIndex2DocumentCollection (TRI_document_collection_t* document, /// freed. //////////////////////////////////////////////////////////////////////////////// -int TRI_PidNamesByAttributeNames (TRI_vector_pointer_t const* attributes, - TRI_shaper_t* shaper, - TRI_vector_t* pids, - TRI_vector_pointer_t* names, - bool sorted) { +static int PidNamesByAttributeNames (TRI_vector_pointer_t const* attributes, + TRI_shaper_t* shaper, + TRI_vector_t* pids, + TRI_vector_pointer_t* names, + bool sorted, + bool create) { pid_name_t* pidnames; size_t j; @@ -4223,17 +4224,23 @@ int TRI_PidNamesByAttributeNames (TRI_vector_pointer_t const* attributes, // ............................................................................. if (sorted) { - // combine name and pid pidnames = TRI_Allocate(TRI_CORE_MEM_ZONE, sizeof(pid_name_t) * attributes->_length, false); + if (pidnames == NULL) { - LOG_ERROR("out of memory in TRI_PidNamesByAttributeNames"); + LOG_ERROR("out of memory in PidNamesByAttributeNames"); return TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); } for (j = 0; j < attributes->_length; ++j) { pidnames[j]._name = attributes->_buffer[j]; - pidnames[j]._pid = shaper->findAttributePathByName(shaper, pidnames[j]._name); + + if (create) { + pidnames[j]._pid = shaper->findOrCreateAttributePathByName(shaper, pidnames[j]._name, true); + } + else { + pidnames[j]._pid = shaper->lookupAttributePathByName(shaper, pidnames[j]._name); + } if (pidnames[j]._pid == 0) { TRI_Free(TRI_CORE_MEM_ZONE, pidnames); @@ -4270,7 +4277,13 @@ int TRI_PidNamesByAttributeNames (TRI_vector_pointer_t const* attributes, TRI_shape_pid_t pid; name = attributes->_buffer[j]; - pid = shaper->findAttributePathByName(shaper, name); + + if (create) { + pid = shaper->findOrCreateAttributePathByName(shaper, name, true); + } + else { + pid = shaper->lookupAttributePathByName(shaper, name); + } if (pid == 0) { TRI_DestroyVector(pids); @@ -4550,7 +4563,7 @@ static TRI_index_t* CreateGeoIndexDocumentCollection (TRI_document_collection_t* shaper = primary->_shaper; if (location != NULL) { - loc = shaper->findAttributePathByName(shaper, location); + loc = shaper->findOrCreateAttributePathByName(shaper, location, true); if (loc == 0) { TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); @@ -4559,7 +4572,7 @@ static TRI_index_t* CreateGeoIndexDocumentCollection (TRI_document_collection_t* } if (latitude != NULL) { - lat = shaper->findAttributePathByName(shaper, latitude); + lat = shaper->findOrCreateAttributePathByName(shaper, latitude, true); if (lat == 0) { TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); @@ -4568,7 +4581,7 @@ static TRI_index_t* CreateGeoIndexDocumentCollection (TRI_document_collection_t* } if (longitude != NULL) { - lon = shaper->findAttributePathByName(shaper, longitude); + lon = shaper->findOrCreateAttributePathByName(shaper, longitude, true); if (lon == 0) { TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); @@ -4817,10 +4830,9 @@ TRI_index_t* TRI_LookupGeoIndex1DocumentCollection (TRI_document_collection_t* d shaper = document->base._shaper; - loc = shaper->findAttributePathByName(shaper, location); + loc = shaper->lookupAttributePathByName(shaper, location); if (loc == 0) { - TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); return NULL; } @@ -4863,11 +4875,10 @@ TRI_index_t* TRI_LookupGeoIndex2DocumentCollection (TRI_document_collection_t* d shaper = document->base._shaper; - lat = shaper->findAttributePathByName(shaper, latitude); - lon = shaper->findAttributePathByName(shaper, longitude); + lat = shaper->lookupAttributePathByName(shaper, latitude); + lon = shaper->lookupAttributePathByName(shaper, longitude); if (lat == 0 || lon == 0) { - TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); return NULL; } @@ -5030,11 +5041,12 @@ static TRI_index_t* CreateHashIndexDocumentCollection (TRI_document_collection_t idx = NULL; // determine the sorted shape ids for the attributes - res = TRI_PidNamesByAttributeNames(attributes, - document->base._shaper, - &paths, - &fields, - true); + res = PidNamesByAttributeNames(attributes, + document->base._shaper, + &paths, + &fields, + true, + true); if (res != TRI_ERROR_NO_ERROR) { if (created != NULL) { @@ -5142,19 +5154,17 @@ TRI_index_t* TRI_LookupHashIndexDocumentCollection (TRI_document_collection_t* d TRI_vector_pointer_t const* attributes, bool unique) { TRI_index_t* idx; - TRI_primary_collection_t* primary; TRI_vector_pointer_t fields; TRI_vector_t paths; int res; - primary = &document->base; - // determine the sorted shape ids for the attributes - res = TRI_PidNamesByAttributeNames(attributes, - primary->_shaper, - &paths, - &fields, - true); + res = PidNamesByAttributeNames(attributes, + document->base._shaper, + &paths, + &fields, + true, + false); if (res != TRI_ERROR_NO_ERROR) { return NULL; @@ -5249,11 +5259,12 @@ static TRI_index_t* CreateSkiplistIndexDocumentCollection (TRI_document_collecti TRI_vector_t paths; int res; - res = TRI_PidNamesByAttributeNames(attributes, - document->base._shaper, - &paths, - &fields, - false); + res = PidNamesByAttributeNames(attributes, + document->base._shaper, + &paths, + &fields, + false, + true); if (res != TRI_ERROR_NO_ERROR) { if (created != NULL) { @@ -5354,19 +5365,17 @@ TRI_index_t* TRI_LookupSkiplistIndexDocumentCollection (TRI_document_collection_ TRI_vector_pointer_t const* attributes, bool unique) { TRI_index_t* idx; - TRI_primary_collection_t* primary; TRI_vector_pointer_t fields; TRI_vector_t paths; int res; - primary = &document->base; - // determine the unsorted shape ids for the attributes - res = TRI_PidNamesByAttributeNames(attributes, - primary->_shaper, - &paths, - &fields, - false); + res = PidNamesByAttributeNames(attributes, + document->base._shaper, + &paths, + &fields, + false, + false); if (res != TRI_ERROR_NO_ERROR) { return NULL; @@ -5738,11 +5747,12 @@ static TRI_index_t* CreateBitarrayIndexDocumentCollection (TRI_document_collecti TRI_vector_t paths; int res; - res = TRI_PidNamesByAttributeNames(attributes, - document->base._shaper, - &paths, - &fields, - false); + res = PidNamesByAttributeNames(attributes, + document->base._shaper, + &paths, + &fields, + false, + true); if (res != TRI_ERROR_NO_ERROR) { if (created != NULL) { @@ -5883,7 +5893,12 @@ TRI_index_t* TRI_LookupBitarrayIndexDocumentCollection (TRI_document_collection_ // determine the unsorted shape ids for the attributes // ........................................................................... - result = TRI_PidNamesByAttributeNames(attributes, primary->_shaper, &paths, &fields, false); + result = PidNamesByAttributeNames(attributes, + primary->_shaper, + &paths, + &fields, + false, + false); if (result != TRI_ERROR_NO_ERROR) { return NULL; diff --git a/arangod/VocBase/document-collection.h b/arangod/VocBase/document-collection.h index d78e294734..ebce9322d7 100644 --- a/arangod/VocBase/document-collection.h +++ b/arangod/VocBase/document-collection.h @@ -558,16 +558,6 @@ struct TRI_index_s* TRI_EnsureGeoIndex2DocumentCollection (TRI_document_collecti /// @{ //////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -/// @brief converts attribute names to sorted lists of pids and names -//////////////////////////////////////////////////////////////////////////////// - -int TRI_PidNamesByAttributeNames (TRI_vector_pointer_t const*, - TRI_shaper_t*, - TRI_vector_t*, - TRI_vector_pointer_t*, - bool); - //////////////////////////////////////////////////////////////////////////////// /// @brief finds a hash index /// diff --git a/arangod/VocBase/index.c b/arangod/VocBase/index.c index de9bb3636b..ab8fb83571 100644 --- a/arangod/VocBase/index.c +++ b/arangod/VocBase/index.c @@ -1031,8 +1031,7 @@ static int FillLookupSLOperator (TRI_index_operator_t* slOperator, case TRI_AND_INDEX_OPERATOR: case TRI_NOT_INDEX_OPERATOR: case TRI_OR_INDEX_OPERATOR: { - - logicalOperator = (TRI_logical_index_operator_t*)(slOperator); + logicalOperator = (TRI_logical_index_operator_t*) slOperator; result = FillLookupSLOperator(logicalOperator->_left, primary); if (result == TRI_ERROR_NO_ERROR) { result = FillLookupSLOperator(logicalOperator->_right, primary); @@ -1049,19 +1048,29 @@ static int FillLookupSLOperator (TRI_index_operator_t* slOperator, case TRI_NE_INDEX_OPERATOR: case TRI_LE_INDEX_OPERATOR: case TRI_LT_INDEX_OPERATOR: { - - relationOperator = (TRI_relation_index_operator_t*)(slOperator); + relationOperator = (TRI_relation_index_operator_t*) slOperator; relationOperator->_numFields = relationOperator->_parameters->_value._objects._length; - relationOperator->_fields = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_shaped_json_t) * relationOperator->_numFields, false); + if (relationOperator->_fields != NULL) { for (j = 0; j < relationOperator->_numFields; ++j) { - jsonObject = (TRI_json_t*) (TRI_AtVector(&(relationOperator->_parameters->_value._objects),j)); - shapedObject = TRI_ShapedJsonJson(primary->_shaper, jsonObject); - if (shapedObject) { + jsonObject = (TRI_json_t*) (TRI_AtVector(&(relationOperator->_parameters->_value._objects), j)); + + if ((TRI_IsListJson(jsonObject) || TRI_IsArrayJson(jsonObject)) && + slOperator->_type != TRI_EQ_INDEX_OPERATOR) { + // non-equality operator used on complex data type, this is disallowed + return TRI_ERROR_BAD_PARAMETER; + } + + shapedObject = TRI_ShapedJsonJson(primary->_shaper, jsonObject, false, false); + + if (shapedObject != NULL) { relationOperator->_fields[j] = *shapedObject; // shallow copy here is ok TRI_Free(TRI_UNKNOWN_MEM_ZONE, shapedObject); // don't require storage anymore } + else { + return TRI_RESULT_ELEMENT_NOT_FOUND; + } } } else { @@ -1069,103 +1078,6 @@ static int FillLookupSLOperator (TRI_index_operator_t* slOperator, } break; } - - // ......................................................................... - // This index operator is special - // The parameters are given to us as a list of json objects for EQ(...), - // however for the IN(...) operator each parameter in the parameters list - // is itself a list. For skiplists, the number of parameters is a - // decreasing sequence. That is, for a skiplist with 3 attributes, - // the parameters [ ["a","b","c","d"],["x","y"],[0] ] are allowed, whereas - // the parameters [ ["a","b","c"], ["x","y"], [0,1,2] ] are not allowed. - // ......................................................................... - - case TRI_IN_INDEX_OPERATOR: { - int maxEntries; - - relationOperator = (TRI_relation_index_operator_t*)(slOperator); - relationOperator->_numFields = 0; - relationOperator->_fields = NULL; - - // ....................................................................... - // check that the parameters field is not null - // ....................................................................... - - if (relationOperator->_parameters == NULL) { - LOG_WARNING("No parameters given when using Skiplist lookup index"); - return TRI_ERROR_INTERNAL; - } - - - // ....................................................................... - // check that the parameters json object is of the type list - // ....................................................................... - - if (relationOperator->_parameters->_type != TRI_JSON_LIST) { - LOG_WARNING("Format of parameters given when using Skiplist lookup index are invalid (a)"); - return TRI_ERROR_INTERNAL; - } - - // ....................................................................... - // Each entry in the list is itself a list - // ....................................................................... - - relationOperator->_numFields = relationOperator->_parameters->_value._objects._length; - relationOperator->_fields = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_shaped_json_t) * relationOperator->_numFields, false); - - if (relationOperator->_fields == NULL) { - relationOperator->_numFields = 0; // out of memory? - return TRI_ERROR_OUT_OF_MEMORY; - } - - result = 0; - maxEntries = -1; - - for (j = 0; j < relationOperator->_numFields; ++j) { - jsonObject = (TRI_json_t*) (TRI_AtVector(&(relationOperator->_parameters->_value._objects),j)); - - if (jsonObject == NULL) { - result = -1; - break; - } - - if (jsonObject->_type != TRI_JSON_LIST) { - result = -2; - break; - } - - // check and see that entries are non-increasing - if ((int) jsonObject->_value._objects._length > maxEntries) { - if (maxEntries > 0) { - result = -3; - break; - } - maxEntries = (int) jsonObject->_value._objects._length; - } - - // convert json to shaped json - shapedObject = TRI_ShapedJsonJson(primary->_shaper, jsonObject); - if (shapedObject == NULL) { - result = -4; - break; - } - - // store shaped json list - relationOperator->_fields[j] = *shapedObject; // shallow copy here is ok - TRI_Free(TRI_UNKNOWN_MEM_ZONE, shapedObject); // don't require storage anymore - } - - if (result != 0) { - TRI_Free(TRI_UNKNOWN_MEM_ZONE,relationOperator->_fields); - relationOperator->_fields = NULL; - relationOperator->_numFields = 0; - LOG_WARNING("Format of parameters given when using Skiplist lookup index are invalid (b)"); - return TRI_ERROR_INTERNAL; - } - - } - - } return TRI_ERROR_NO_ERROR; @@ -1199,11 +1111,14 @@ TRI_skiplist_iterator_t* TRI_LookupSkiplistIndex (TRI_index_t* idx, errorResult = FillLookupSLOperator(slOperator, skiplistIndex->base._collection); if (errorResult != TRI_ERROR_NO_ERROR) { + TRI_set_errno(errorResult); + return NULL; } iteratorResult = SkiplistIndex_find(skiplistIndex->_skiplistIndex, - &skiplistIndex->_paths, slOperator); + &skiplistIndex->_paths, + slOperator); // ......................................................................... // we must deallocate any memory we allocated in FillLookupSLOperator @@ -1837,7 +1752,7 @@ TRI_index_t* TRI_CreateFulltextIndex (struct TRI_primary_collection_s* primary, // look up the attribute shaper = primary->_shaper; - attribute = shaper->findAttributePathByName(shaper, attributeName); + attribute = shaper->findOrCreateAttributePathByName(shaper, attributeName, true); if (attribute == 0) { return NULL; @@ -1991,14 +1906,6 @@ static int FillLookupBitarrayOperator(TRI_index_operator_t* indexOperator, TRI_p } - - // ......................................................................... - // This index operator is special - // ......................................................................... - - case TRI_IN_INDEX_OPERATOR: { - assert(false); - } } return TRI_ERROR_NO_ERROR; diff --git a/arangod/VocBase/replication-logger.c b/arangod/VocBase/replication-logger.c index 4940fbfc5b..b11b2051f1 100644 --- a/arangod/VocBase/replication-logger.c +++ b/arangod/VocBase/replication-logger.c @@ -440,6 +440,7 @@ static int LogEvent (TRI_replication_logger_t* logger, int res; bool forceSync; bool withTid; + bool lock; assert(logger != NULL); assert(buffer != NULL); @@ -506,10 +507,12 @@ static int LogEvent (TRI_replication_logger_t* logger, (unsigned long long) tid, (int) forceSync, TRI_BeginStringBuffer(buffer)); + + lock = isStandaloneOperation; primary = logger->_trxCollection->_collection->_collection; zone = primary->_shaper->_memoryZone; - shaped = TRI_ShapedJsonJson(primary->_shaper, &json); + shaped = TRI_ShapedJsonJson(primary->_shaper, &json, true, ! lock); TRI_DestroyJson(TRI_CORE_MEM_ZONE, &json); ReturnBuffer(logger, buffer); @@ -525,7 +528,7 @@ static int LogEvent (TRI_replication_logger_t* logger, TRI_DOC_MARKER_KEY_DOCUMENT, shaped, NULL, - isStandaloneOperation, + lock, forceSync, false); diff --git a/arangod/VocBase/transaction.c b/arangod/VocBase/transaction.c index 05a952ed1b..7c1c423ded 100644 --- a/arangod/VocBase/transaction.c +++ b/arangod/VocBase/transaction.c @@ -426,7 +426,7 @@ static int InsertTrxCallback (TRI_transaction_collection_t* trxCollection, return TRI_ERROR_OUT_OF_MEMORY; } - shaped = TRI_ShapedJsonJson(primary->_shaper, coordinator->_json); + shaped = TRI_ShapedJsonJson(primary->_shaper, coordinator->_json, true, true); if (shaped == NULL) { return TRI_ERROR_OUT_OF_MEMORY; diff --git a/arangod/VocBase/voc-shaper.c b/arangod/VocBase/voc-shaper.c index a41eff6c76..becbefbddc 100644 --- a/arangod/VocBase/voc-shaper.c +++ b/arangod/VocBase/voc-shaper.c @@ -343,9 +343,30 @@ static void FullSetAttributeWeight (voc_shaper_t* shaper) { /// @brief finds an attribute identifier by name //////////////////////////////////////////////////////////////////////////////// -static TRI_shape_aid_t FindAttributeByName (TRI_shaper_t* shaper, - char const* name, - bool create) { +static TRI_shape_aid_t LookupAttributeByName (TRI_shaper_t* shaper, + char const* name) { + voc_shaper_t* s; + void const* p; + + assert(name != NULL); + + s = (voc_shaper_t*) shaper; + p = TRI_LookupByKeyAssociativeSynced(&s->_attributeNames, name); + + if (p != NULL) { + return ((TRI_df_attribute_marker_t const*) p)->_aid; + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief finds an attribute identifier by name +//////////////////////////////////////////////////////////////////////////////// + +static TRI_shape_aid_t FindOrCreateAttributeByName (TRI_shaper_t* shaper, + char const* name, + bool isLocked) { char* mem; TRI_df_attribute_marker_t* marker; TRI_df_marker_t* result; @@ -372,10 +393,6 @@ static TRI_shape_aid_t FindAttributeByName (TRI_shaper_t* shaper, return ((TRI_df_attribute_marker_t const*) p)->_aid; } - if (! create) { - return 0; - } - // create a new attribute name n = strlen(name) + 1; @@ -415,9 +432,18 @@ static TRI_shape_aid_t FindAttributeByName (TRI_shaper_t* shaper, // get next attribute id and write into marker aid = s->_nextAid++; marker->_aid = aid; - + + if (! isLocked) { + // write-lock + s->_collection->base.beginWrite(&s->_collection->base); + } + // write attribute into the collection res = TRI_WriteMarkerDocumentCollection(s->_collection, &marker->base, totalSize, &fid, &result, false); + + if (! isLocked) { + s->_collection->base.endWrite(&s->_collection->base); + } TRI_Free(TRI_UNKNOWN_MEM_ZONE, mem); @@ -548,7 +574,6 @@ static char const* LookupAttributeId (TRI_shaper_t* shaper, TRI_shape_aid_t aid) } } - //////////////////////////////////////////////////////////////////////////////// /// @brief looks up an attribute weight by identifier //////////////////////////////////////////////////////////////////////////////// @@ -617,7 +642,9 @@ static bool EqualElementShape (TRI_associative_synced_t* array, void const* left //////////////////////////////////////////////////////////////////////////////// static TRI_shape_t const* FindShape (TRI_shaper_t* shaper, - TRI_shape_t* shape) { + TRI_shape_t* shape, + bool create, + bool isLocked) { char* mem; TRI_df_marker_t* result; TRI_df_shape_marker_t* marker; @@ -645,6 +672,11 @@ static TRI_shape_t const* FindShape (TRI_shaper_t* shaper, return found; } + // not found + if (! create) { + return 0; + } + // initialise a new shape marker totalSize = sizeof(TRI_df_shape_marker_t) + shape->_size; mem = (char*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, totalSize, false); @@ -681,9 +713,19 @@ static TRI_shape_t const* FindShape (TRI_shaper_t* shaper, // get next shape number and write into marker ((TRI_shape_t*) (mem + sizeof(TRI_df_shape_marker_t)))->_sid = s->_nextSid++; + if (! isLocked) { + // write-lock + s->_collection->base.beginWrite(&s->_collection->base); + } + // write shape into the collection res = TRI_WriteMarkerDocumentCollection(s->_collection, &marker->base, totalSize, &fid, &result, false); + if (! isLocked) { + // write-unlock + s->_collection->base.endWrite(&s->_collection->base); + } + if (res != TRI_ERROR_NO_ERROR) { TRI_UnlockMutex(&s->_shapeLock); @@ -953,10 +995,11 @@ static uint64_t HashElementWeightedAttribute (TRI_associative_pointer_t* array, static int InitStep1VocShaper (voc_shaper_t* shaper) { int res; - shaper->base.findAttributeByName = FindAttributeByName; - shaper->base.lookupAttributeId = LookupAttributeId; - shaper->base.findShape = FindShape; - shaper->base.lookupShapeId = LookupShapeId; + shaper->base.findOrCreateAttributeByName = FindOrCreateAttributeByName; + shaper->base.lookupAttributeByName = LookupAttributeByName; + shaper->base.lookupAttributeId = LookupAttributeId; + shaper->base.findShape = FindShape; + shaper->base.lookupShapeId = LookupShapeId; res = TRI_InitAssociativeSynced(&shaper->_attributeNames, TRI_UNKNOWN_MEM_ZONE, diff --git a/etc/arangodb/arangod.conf.in b/etc/arangodb/arangod.conf.in index 448c9b5b0b..b951341dba 100644 --- a/etc/arangodb/arangod.conf.in +++ b/etc/arangodb/arangod.conf.in @@ -60,8 +60,8 @@ severity = human file = @LOCALSTATEDIR@/log/arangodb/arangod.log [cluster] -disable-dispatcher-kickstarter = false -disable-dispatcher-frontend = false +disable-dispatcher-kickstarter = yes +disable-dispatcher-frontend = yes data-path = @LOCALSTATEDIR@/lib/arangodb/cluster log-path = @LOCALSTATEDIR@/log/arangodb/cluster agent-path = @LIBEXECDIR@/arangodb/etcd-arango@PROGRAM_SUFFIX@ diff --git a/js/apps/system/aardvark/clusterFrontend/js/models/clusterPlan.js b/js/apps/system/aardvark/clusterFrontend/js/models/clusterPlan.js index ed2fa22b45..7c24d789e0 100644 --- a/js/apps/system/aardvark/clusterFrontend/js/models/clusterPlan.js +++ b/js/apps/system/aardvark/clusterFrontend/js/models/clusterPlan.js @@ -19,19 +19,21 @@ var i,j,r; r = this.get("runInfo"); j = r.length-1; - while (j > 0 && r[j].isStartServers === undefined) { - j--; - } - var l = r[j]; - if (l.endpoints) { - for (i = 0; i < l.endpoints.length;i++) { - if (l.roles[i] === "Coordinator") { - this._coord = l.endpoints[i] - .replace("tcp://","http://") - .replace("ssl://", "https://"); - return this._coord; + while (j > 0) { + if(r[j].isStartServers) { + var l = r[j]; + if (l.endpoints) { + for (i = 0; i < l.endpoints.length;i++) { + if (l.roles[i] === "Coordinator") { + this._coord = l.endpoints[i] + .replace("tcp://","http://") + .replace("ssl://", "https://"); + return this._coord; + } + } } } + j--; } }, diff --git a/js/apps/system/aardvark/clusterFrontend/js/templates/serverEntry.ejs b/js/apps/system/aardvark/clusterFrontend/js/templates/serverEntry.ejs index 3ef379fe72..3f30df58d5 100644 --- a/js/apps/system/aardvark/clusterFrontend/js/templates/serverEntry.ejs +++ b/js/apps/system/aardvark/clusterFrontend/js/templates/serverEntry.ejs @@ -14,10 +14,10 @@ <% if (!isSymmetric) { %>
<% } %> diff --git a/js/apps/system/aardvark/clusterFrontend/js/views/planSymmetricView.js b/js/apps/system/aardvark/clusterFrontend/js/views/planSymmetricView.js index 4075e889a8..0198ddb7e0 100644 --- a/js/apps/system/aardvark/clusterFrontend/js/views/planSymmetricView.js +++ b/js/apps/system/aardvark/clusterFrontend/js/views/planSymmetricView.js @@ -17,8 +17,6 @@ }, startPlan: function() { - $('#waitModalLayer').modal('show'); - $('#waitModalMessage').html('Please be patient while your cluster will be launched'); var isDBServer; var isCoordinator; var self = this; @@ -33,8 +31,8 @@ } var hostObject = {host : host + ":" + port}; if (!self.isSymmetric) { - hostObject.isDBServer = !!$(".isDBServer", dispatcher).attr('checked'); - hostObject.isCoordinator = !!$(".isCoordinator", dispatcher).attr('checked'); + hostObject.isDBServer = !!$(".isDBServer", dispatcher).prop('checked'); + hostObject.isCoordinator = !!$(".isCoordinator", dispatcher).prop('checked'); } else { hostObject.isDBServer = true; hostObject.isCoordinator = true; @@ -63,6 +61,8 @@ } data.type = this.isSymmetric ? "symmetricalSetup" : "asymmetricalSetup"; + $('#waitModalLayer').modal('show'); + $('#waitModalMessage').html('Please be patient while your cluster will be launched'); this.model.save( data, { diff --git a/js/apps/system/aardvark/frontend/js/collections/arangoDocuments.js b/js/apps/system/aardvark/frontend/js/collections/arangoDocuments.js index 68abc8017c..79f0fe4ad6 100644 --- a/js/apps/system/aardvark/frontend/js/collections/arangoDocuments.js +++ b/js/apps/system/aardvark/frontend/js/collections/arangoDocuments.js @@ -226,13 +226,12 @@ if (endDate) { filterString += " filter u.time < " + endDate; } - var returnValue = " return u" + var returnValue = " return u"; if (figures) { - var returnValue = " return {time : u.time, server : {uptime : u.server.uptime} ," + returnValue = " return {time : u.time, server : {uptime : u.server.uptime} ,"; var groups = {}; figures.forEach(function(f) { var g = f.split(".")[0]; - console.log("ggg", g); if (!groups[g]) { groups[g] = []; } diff --git a/js/server/tests/shell-skiplist-index.js b/js/server/tests/shell-skiplist-index.js index 6a95520b2f..1141951c1d 100644 --- a/js/server/tests/shell-skiplist-index.js +++ b/js/server/tests/shell-skiplist-index.js @@ -30,6 +30,7 @@ var jsunity = require("jsunity"); var internal = require("internal"); +var errors = internal.errors; // ----------------------------------------------------------------------------- // --SECTION-- basic methods @@ -253,10 +254,22 @@ function SkipListSuite() { var val = values[i].a; var expect = documents.slice(i); - var res = collection.byConditionSkiplist(idx.id, { a: [[">=", val]] }, 0, null ).toArray(); - var result = res.map(function(a) { return a._key; }); + var isValid = ! ((val !== null && typeof val === 'object')); + if (isValid) { + var res = collection.byConditionSkiplist(idx.id, { a: [[">=", val]] }).toArray(); + var result = res.map(function(a) { return a._key; }); - assertEqual([i, ">=", expect], [i, ">=", result]); + assertEqual([i, ">=", expect], [i, ">=", result]); + } + else { + try { + collection.byConditionSkiplist(idx.id, { a: [[">=", val]] }).toArray(); + fail(); + } + catch (err1) { + assertEqual(errors.ERROR_ARANGO_NO_INDEX.code, err1.errorNum); + } + } } // GREATER THAN @@ -264,10 +277,22 @@ function SkipListSuite() { var val = values[i].a; var expect = documents.slice(i + 1); - var res = collection.byConditionSkiplist(idx.id, { a: [[">", val]] }, 0, null ).toArray(); - var result = res.map(function(a) { return a._key; }); + var isValid = ! ((val !== null && typeof val === 'object')); + if (isValid) { + var res = collection.byConditionSkiplist(idx.id, { a: [[">", val]] }).toArray(); + var result = res.map(function(a) { return a._key; }); - assertEqual([i, ">", expect], [i, ">", result]); + assertEqual([i, ">", expect], [i, ">", result]); + } + else { + try { + collection.byConditionSkiplist(idx.id, { a: [[">", val]] }).toArray(); + fail(); + } + catch (err2) { + assertEqual(errors.ERROR_ARANGO_NO_INDEX.code, err2.errorNum); + } + } } // LESS THAN OR EQUAL @@ -275,10 +300,22 @@ function SkipListSuite() { var val = values[i].a; var expect = documents.slice(1, i + 1); - var res = collection.byConditionSkiplist(idx.id, { a: [["<=", val]] }, 0, null ).toArray(); - var result = res.map(function(a) { return a._key; }); + var isValid = ! ((val !== null && typeof val === 'object')); + if (isValid) { + var res = collection.byConditionSkiplist(idx.id, { a: [["<=", val]] }).toArray(); + var result = res.map(function(a) { return a._key; }); - assertEqual([i, "<=", expect], [i, "<=", result]); + assertEqual([i, "<=", expect], [i, "<=", result]); + } + else { + try { + collection.byConditionSkiplist(idx.id, { a: [["<=", val]] }).toArray(); + fail(); + } + catch (err3) { + assertEqual(errors.ERROR_ARANGO_NO_INDEX.code, err3.errorNum); + } + } } @@ -287,10 +324,22 @@ function SkipListSuite() { var val = values[i].a; var expect = documents.slice(1, i); - var res = collection.byConditionSkiplist(idx.id, { a: [["<", val]] }, 0, null ).toArray(); - var result = res.map(function(a) { return a._key; }); + var isValid = ! ((val !== null && typeof val === 'object')); + if (isValid) { + var res = collection.byConditionSkiplist(idx.id, { a: [["<", val]] }).toArray(); + var result = res.map(function(a) { return a._key; }); - assertEqual([i, "<", expect], [i, "<", result]); + assertEqual([i, "<", expect], [i, "<", result]); + } + else { + try { + collection.byConditionSkiplist(idx.id, { a: [["<", val]] }).toArray(); + fail(); + } + catch (err4) { + assertEqual(errors.ERROR_ARANGO_NO_INDEX.code, err4.errorNum); + } + } } // BETWEEN @@ -300,11 +349,27 @@ function SkipListSuite() { for (j = 1; j < documents.length; ++j) { var valj = values[j].a; var expect = documents.slice(i, j + 1); + + var isValid = ! ((vali !== null && typeof vali === 'object')); + if (isValid) { + isValid &= ! ((valj !== null && typeof valj === 'object')); + } - var res = collection.byConditionSkiplist(idx.id, { a: [[">=", vali], ["<=", valj]] }, 0, null ).toArray(); - var result = res.map(function(a) { return a._key; }); + if (isValid) { + var res = collection.byConditionSkiplist(idx.id, { a: [[">=", vali], ["<=", valj]] }).toArray(); + var result = res.map(function(a) { return a._key; }); - assertEqual([i, ">= <=", expect], [i, ">= <=", result]); + assertEqual([i, ">= <=", expect], [i, ">= <=", result]); + } + else { + try { + collection.byConditionSkiplist(idx.id, { a: [[">=", vali], ["<=", valj]] }).toArray(); + fail(); + } + catch (err5) { + assertEqual(errors.ERROR_ARANGO_NO_INDEX.code, err5.errorNum); + } + } } } } diff --git a/lib/ShapedJson/json-shaper.c b/lib/ShapedJson/json-shaper.c index 9b8821cf5a..e7be7c6285 100644 --- a/lib/ShapedJson/json-shaper.c +++ b/lib/ShapedJson/json-shaper.c @@ -179,7 +179,8 @@ static bool EqualNameKeyAttributePath (TRI_associative_synced_t* array, void con static TRI_shape_path_t const* FindShapePathByName (TRI_shaper_t* shaper, char const* name, - bool create) { + bool create, + bool isLocked) { TRI_shape_aid_t* aids; TRI_shape_path_t* result; size_t count; @@ -242,10 +243,10 @@ static TRI_shape_path_t const* FindShapePathByName (TRI_shaper_t* shaper, if (ptr != prev) { if (create) { - aids[count++] = shaper->findAttributeByName(shaper, prev, true); + aids[count++] = shaper->findOrCreateAttributeByName(shaper, prev, isLocked); } else { - aids[count] = shaper->findAttributeByName(shaper, prev, false); + aids[count] = shaper->lookupAttributeByName(shaper, prev); if (aids[count] == 0) { TRI_FreeString(shaper->_memoryZone, buffer); @@ -299,8 +300,10 @@ static TRI_shape_path_t const* FindShapePathByName (TRI_shaper_t* shaper, /// @brief finds an attribute path by identifier //////////////////////////////////////////////////////////////////////////////// -static TRI_shape_pid_t FindAttributePathByName (TRI_shaper_t* shaper, char const* name) { - TRI_shape_path_t const* path = FindShapePathByName(shaper, name, true); +static TRI_shape_pid_t FindOrCreateAttributePathByName (TRI_shaper_t* shaper, + char const* name, + bool isLocked) { + TRI_shape_path_t const* path = FindShapePathByName(shaper, name, true, isLocked); return path == NULL ? 0 : path->_pid; } @@ -309,8 +312,9 @@ static TRI_shape_pid_t FindAttributePathByName (TRI_shaper_t* shaper, char const /// @brief looks up an attribute path by identifier //////////////////////////////////////////////////////////////////////////////// -static TRI_shape_pid_t LookupAttributePathByName (TRI_shaper_t* shaper, char const* name) { - TRI_shape_path_t const* path = FindShapePathByName(shaper, name, false); +static TRI_shape_pid_t LookupAttributePathByName (TRI_shaper_t* shaper, + char const* name) { + TRI_shape_path_t const* path = FindShapePathByName(shaper, name, false, true); return path == NULL ? 0 : path->_pid; } @@ -327,7 +331,8 @@ static TRI_shape_pid_t LookupAttributePathByName (TRI_shaper_t* shaper, char con /// @brief creates the attribute path //////////////////////////////////////////////////////////////////////////////// -char const* TRI_AttributeNameShapePid (TRI_shaper_t* shaper, TRI_shape_pid_t pid) { +char const* TRI_AttributeNameShapePid (TRI_shaper_t* shaper, + TRI_shape_pid_t pid) { TRI_shape_path_t const* path; char const* e; @@ -379,7 +384,7 @@ int TRI_InitShaper (TRI_shaper_t* shaper, TRI_memory_zone_t* zone) { shaper->_nextPid = 1; shaper->lookupAttributePathByPid = LookupPidAttributePath; - shaper->findAttributePathByName = FindAttributePathByName; + shaper->findOrCreateAttributePathByName = FindOrCreateAttributePathByName; shaper->lookupAttributePathByName = LookupAttributePathByName; return TRI_ERROR_NO_ERROR; diff --git a/lib/ShapedJson/json-shaper.h b/lib/ShapedJson/json-shaper.h index 234ecd7850..affa6f47f0 100644 --- a/lib/ShapedJson/json-shaper.h +++ b/lib/ShapedJson/json-shaper.h @@ -91,13 +91,14 @@ TRI_basic_shapes_t; //////////////////////////////////////////////////////////////////////////////// typedef struct TRI_shaper_s { - TRI_shape_aid_t (*findAttributeByName) (struct TRI_shaper_s*, char const*, bool); + TRI_shape_aid_t (*findOrCreateAttributeByName) (struct TRI_shaper_s*, char const*, bool); + TRI_shape_aid_t (*lookupAttributeByName) (struct TRI_shaper_s*, char const*); char const* (*lookupAttributeId) (struct TRI_shaper_s*, TRI_shape_aid_t); - TRI_shape_t const* (*findShape) (struct TRI_shaper_s*, TRI_shape_t*); + TRI_shape_t const* (*findShape) (struct TRI_shaper_s*, TRI_shape_t*, bool, bool); TRI_shape_t const* (*lookupShapeId) (struct TRI_shaper_s*, TRI_shape_sid_t); int64_t (*lookupAttributeWeight) (struct TRI_shaper_s*, TRI_shape_aid_t); TRI_shape_path_t const* (*lookupAttributePathByPid) (struct TRI_shaper_s*, TRI_shape_pid_t); - TRI_shape_pid_t (*findAttributePathByName) (struct TRI_shaper_s*, char const*); + TRI_shape_pid_t (*findOrCreateAttributePathByName) (struct TRI_shaper_s*, char const*, bool); TRI_shape_pid_t (*lookupAttributePathByName) (struct TRI_shaper_s*, char const*); TRI_associative_synced_t _attributePathsByName; diff --git a/lib/ShapedJson/shaped-json.c b/lib/ShapedJson/shaped-json.c index 32342296bd..488f0c94fa 100644 --- a/lib/ShapedJson/shaped-json.c +++ b/lib/ShapedJson/shaped-json.c @@ -42,7 +42,7 @@ // --SECTION-- forward declarations // ----------------------------------------------------------------------------- -static bool FillShapeValueJson (TRI_shaper_t* shaper, TRI_shape_value_t* dst, TRI_json_t const* json); +static bool FillShapeValueJson (TRI_shaper_t* shaper, TRI_shape_value_t* dst, TRI_json_t const* json, bool, bool); static TRI_json_t* JsonShapeData (TRI_shaper_t* shaper, TRI_shape_t const* shape, char const* data, uint64_t size); static bool StringifyJsonShapeData (TRI_shaper_t* shaper, TRI_string_buffer_t* buffer, TRI_shape_t const* shape, char const* data, uint64_t size); @@ -463,7 +463,11 @@ static bool FillShapeValueString (TRI_shaper_t* shaper, TRI_shape_value_t* dst, /// @brief converts a json list into TRI_shape_value_t //////////////////////////////////////////////////////////////////////////////// -static bool FillShapeValueList (TRI_shaper_t* shaper, TRI_shape_value_t* dst, TRI_json_t const* json) { +static bool FillShapeValueList (TRI_shaper_t* shaper, + TRI_shape_value_t* dst, + TRI_json_t const* json, + bool create, + bool isLocked) { size_t i, n; uint64_t total; @@ -520,7 +524,7 @@ static bool FillShapeValueList (TRI_shaper_t* shaper, TRI_shape_value_t* dst, TR for (i = 0; i < n; ++i, ++p) { TRI_json_t const* el = (TRI_json_t const*) TRI_AtVector(&json->_value._objects, i); - bool ok = FillShapeValueJson(shaper, p, el); + bool ok = FillShapeValueJson(shaper, p, el, create, isLocked); if (! ok) { for (e = p, p = values; p < e; ++p) { @@ -580,7 +584,7 @@ static bool FillShapeValueList (TRI_shaper_t* shaper, TRI_shape_value_t* dst, TR shape->_sidEntry = s; shape->_sizeEntry = l; - found = shaper->findShape(shaper, &shape->base); + found = shaper->findShape(shaper, &shape->base, create, isLocked); if (found == NULL) { for (p = values; p < e; ++p) { @@ -649,7 +653,7 @@ static bool FillShapeValueList (TRI_shaper_t* shaper, TRI_shape_value_t* dst, TR shape->base._dataSize = TRI_SHAPE_SIZE_VARIABLE; shape->_sidEntry = s; - found = shaper->findShape(shaper, &shape->base); + found = shaper->findShape(shaper, &shape->base, create, isLocked); if (found == NULL) { for (p = values; p < e; ++p) { @@ -770,7 +774,9 @@ static bool FillShapeValueList (TRI_shaper_t* shaper, TRI_shape_value_t* dst, TR static bool FillShapeValueArray (TRI_shaper_t* shaper, TRI_shape_value_t* dst, - TRI_json_t const* json) { + TRI_json_t const* json, + bool create, + bool isLocked) { size_t i, n; uint64_t total; @@ -831,14 +837,14 @@ static bool FillShapeValueArray (TRI_shaper_t* shaper, } // first find an identifier for the name - p->_aid = shaper->findAttributeByName(shaper, key->_value._string.data, true); + p->_aid = shaper->findOrCreateAttributeByName(shaper, key->_value._string.data, isLocked); // convert value if (p->_aid == 0) { ok = false; } else { - ok = FillShapeValueJson(shaper, p, val); + ok = FillShapeValueJson(shaper, p, val, create, isLocked); } if (! ok) { @@ -987,7 +993,7 @@ static bool FillShapeValueArray (TRI_shaper_t* shaper, TRI_Free(shaper->_memoryZone, values); // lookup this shape - found = shaper->findShape(shaper, &a->base); + found = shaper->findShape(shaper, &a->base, create, isLocked); if (found == NULL) { TRI_Free(shaper->_memoryZone, a); @@ -1003,7 +1009,11 @@ static bool FillShapeValueArray (TRI_shaper_t* shaper, /// @brief converts a json object into TRI_shape_value_t //////////////////////////////////////////////////////////////////////////////// -static bool FillShapeValueJson (TRI_shaper_t* shaper, TRI_shape_value_t* dst, TRI_json_t const* json) { +static bool FillShapeValueJson (TRI_shaper_t* shaper, + TRI_shape_value_t* dst, + TRI_json_t const* json, + bool create, + bool isLocked) { switch (json->_type) { case TRI_JSON_UNUSED: return false; @@ -1022,10 +1032,10 @@ static bool FillShapeValueJson (TRI_shaper_t* shaper, TRI_shape_value_t* dst, TR return FillShapeValueString(shaper, dst, json); case TRI_JSON_ARRAY: - return FillShapeValueArray(shaper, dst, json); + return FillShapeValueArray(shaper, dst, json, create, isLocked); case TRI_JSON_LIST: - return FillShapeValueList(shaper, dst, json); + return FillShapeValueList(shaper, dst, json, create, isLocked); } return false; @@ -2259,13 +2269,15 @@ void TRI_SortShapeValues (TRI_shape_value_t* values, //////////////////////////////////////////////////////////////////////////////// TRI_shaped_json_t* TRI_ShapedJsonJson (TRI_shaper_t* shaper, - TRI_json_t const* json) { + TRI_json_t const* json, + bool create, + bool isLocked) { TRI_shaped_json_t* shaped; TRI_shape_value_t dst; bool ok; dst._value = 0; - ok = FillShapeValueJson(shaper, &dst, json); + ok = FillShapeValueJson(shaper, &dst, json, create, isLocked); if (! ok) { return NULL; @@ -2296,7 +2308,8 @@ TRI_shaped_json_t* TRI_ShapedJsonJson (TRI_shaper_t* shaper, /// @brief converts a shaped json object into a json object //////////////////////////////////////////////////////////////////////////////// -TRI_json_t* TRI_JsonShapedJson (TRI_shaper_t* shaper, TRI_shaped_json_t const* shaped) { +TRI_json_t* TRI_JsonShapedJson (TRI_shaper_t* shaper, + TRI_shaped_json_t const* shaped) { TRI_shape_t const* shape; shape = shaper->lookupShapeId(shaper, shaped->_sid); diff --git a/lib/ShapedJson/shaped-json.h b/lib/ShapedJson/shaped-json.h index e5e7819890..2c6aa6a322 100644 --- a/lib/ShapedJson/shaped-json.h +++ b/lib/ShapedJson/shaped-json.h @@ -954,7 +954,8 @@ void TRI_DestroyShapedJson (struct TRI_memory_zone_s*, TRI_shaped_json_t*); /// @brief destroys a json object and frees the pointer //////////////////////////////////////////////////////////////////////////////// -void TRI_FreeShapedJson (struct TRI_memory_zone_s*, TRI_shaped_json_t*); +void TRI_FreeShapedJson (struct TRI_memory_zone_s*, + TRI_shaped_json_t*); //////////////////////////////////////////////////////////////////////////////// /// @} @@ -973,19 +974,24 @@ void TRI_FreeShapedJson (struct TRI_memory_zone_s*, TRI_shaped_json_t*); /// @brief sorts a list of TRI_shape_value_t //////////////////////////////////////////////////////////////////////////////// -void TRI_SortShapeValues (TRI_shape_value_t* values, size_t n); +void TRI_SortShapeValues (TRI_shape_value_t* values, + size_t n); //////////////////////////////////////////////////////////////////////////////// /// @brief converts a json object into a shaped json object //////////////////////////////////////////////////////////////////////////////// -TRI_shaped_json_t* TRI_ShapedJsonJson (struct TRI_shaper_s*, TRI_json_t const*); +TRI_shaped_json_t* TRI_ShapedJsonJson (struct TRI_shaper_s*, + TRI_json_t const*, + bool, + bool); //////////////////////////////////////////////////////////////////////////////// /// @brief converts a shaped json object into a json object //////////////////////////////////////////////////////////////////////////////// -TRI_json_t* TRI_JsonShapedJson (struct TRI_shaper_s*, TRI_shaped_json_t const*); +TRI_json_t* TRI_JsonShapedJson (struct TRI_shaper_s*, + TRI_shaped_json_t const*); //////////////////////////////////////////////////////////////////////////////// /// @brief prints a shaped json to a string buffer, without the outer braces diff --git a/lib/V8/v8-conv.cpp b/lib/V8/v8-conv.cpp index 4b16335057..f83a657d3e 100644 --- a/lib/V8/v8-conv.cpp +++ b/lib/V8/v8-conv.cpp @@ -46,11 +46,13 @@ using namespace triagens::basics; // --SECTION-- forward declarations // ----------------------------------------------------------------------------- -static bool FillShapeValueJson (TRI_shaper_t* shaper, - TRI_shape_value_t* dst, - v8::Handle const& json, - set& seenHashes, - vector< v8::Handle >& seenObjects); +static int FillShapeValueJson (TRI_shaper_t* shaper, + TRI_shape_value_t* dst, + v8::Handle const& json, + set& seenHashes, + vector< v8::Handle >& seenObjects, + bool create, + bool isLocked); static v8::Handle JsonShapeData (TRI_shaper_t* shaper, TRI_shape_t const* shape, @@ -83,7 +85,7 @@ shape_cache_t; /// @brief converts a null into TRI_shape_value_t //////////////////////////////////////////////////////////////////////////////// -static bool FillShapeValueNull (TRI_shaper_t* shaper, +static int FillShapeValueNull (TRI_shaper_t* shaper, TRI_shape_value_t* dst) { dst->_type = TRI_SHAPE_NULL; dst->_sid = TRI_LookupBasicSidShaper(TRI_SHAPE_NULL); @@ -91,16 +93,16 @@ static bool FillShapeValueNull (TRI_shaper_t* shaper, dst->_size = 0; dst->_value = 0; - return true; + return TRI_ERROR_NO_ERROR; } //////////////////////////////////////////////////////////////////////////////// /// @brief converts a boolean into TRI_shape_value_t //////////////////////////////////////////////////////////////////////////////// -static bool FillShapeValueBoolean (TRI_shaper_t* shaper, - TRI_shape_value_t* dst, - v8::Handle const& json) { +static int FillShapeValueBoolean (TRI_shaper_t* shaper, + TRI_shape_value_t* dst, + v8::Handle const& json) { TRI_shape_boolean_t* ptr; dst->_type = TRI_SHAPE_BOOLEAN; @@ -109,22 +111,22 @@ static bool FillShapeValueBoolean (TRI_shaper_t* shaper, dst->_size = sizeof(TRI_shape_boolean_t); dst->_value = (char*) (ptr = (TRI_shape_boolean_t*) TRI_Allocate(shaper->_memoryZone, dst->_size, false)); - if (dst->_value == NULL) { - return false; + if (dst->_value == 0) { + return TRI_ERROR_OUT_OF_MEMORY; } *ptr = json->Value() ? 1 : 0; - return true; + return TRI_ERROR_NO_ERROR; } //////////////////////////////////////////////////////////////////////////////// /// @brief converts a boolean into TRI_shape_value_t //////////////////////////////////////////////////////////////////////////////// -static bool FillShapeValueBoolean (TRI_shaper_t* shaper, - TRI_shape_value_t* dst, - v8::Handle const& json) { +static int FillShapeValueBoolean (TRI_shaper_t* shaper, + TRI_shape_value_t* dst, + v8::Handle const& json) { TRI_shape_boolean_t* ptr; dst->_type = TRI_SHAPE_BOOLEAN; @@ -133,22 +135,22 @@ static bool FillShapeValueBoolean (TRI_shaper_t* shaper, dst->_size = sizeof(TRI_shape_boolean_t); dst->_value = (char*) (ptr = (TRI_shape_boolean_t*) TRI_Allocate(shaper->_memoryZone, dst->_size, false)); - if (dst->_value == NULL) { - return false; + if (dst->_value == 0) { + return TRI_ERROR_OUT_OF_MEMORY; } *ptr = json->BooleanValue() ? 1 : 0; - return true; + return TRI_ERROR_NO_ERROR; } //////////////////////////////////////////////////////////////////////////////// /// @brief converts a number into TRI_shape_value_t //////////////////////////////////////////////////////////////////////////////// -static bool FillShapeValueNumber (TRI_shaper_t* shaper, - TRI_shape_value_t* dst, - v8::Handle const& json) { +static int FillShapeValueNumber (TRI_shaper_t* shaper, + TRI_shape_value_t* dst, + v8::Handle const& json) { TRI_shape_number_t* ptr; dst->_type = TRI_SHAPE_NUMBER; @@ -157,22 +159,22 @@ static bool FillShapeValueNumber (TRI_shaper_t* shaper, dst->_size = sizeof(TRI_shape_number_t); dst->_value = (char*) (ptr = (TRI_shape_number_t*) TRI_Allocate(shaper->_memoryZone, dst->_size, false)); - if (dst->_value == NULL) { - return false; + if (dst->_value == 0) { + return TRI_ERROR_OUT_OF_MEMORY; } *ptr = json->Value(); - return true; + return TRI_ERROR_NO_ERROR; } //////////////////////////////////////////////////////////////////////////////// /// @brief converts a number into TRI_shape_value_t //////////////////////////////////////////////////////////////////////////////// -static bool FillShapeValueNumber (TRI_shaper_t* shaper, - TRI_shape_value_t* dst, - v8::Handle const& json) { +static int FillShapeValueNumber (TRI_shaper_t* shaper, + TRI_shape_value_t* dst, + v8::Handle const& json) { TRI_shape_number_t* ptr; dst->_type = TRI_SHAPE_NUMBER; @@ -181,22 +183,22 @@ static bool FillShapeValueNumber (TRI_shaper_t* shaper, dst->_size = sizeof(TRI_shape_number_t); dst->_value = (char*) (ptr = (TRI_shape_number_t*) TRI_Allocate(shaper->_memoryZone, dst->_size, false)); - if (dst->_value == NULL) { - return false; + if (dst->_value == 0) { + return TRI_ERROR_OUT_OF_MEMORY; } *ptr = json->NumberValue(); - return true; + return TRI_ERROR_NO_ERROR; } //////////////////////////////////////////////////////////////////////////////// /// @brief converts a string into TRI_shape_value_t //////////////////////////////////////////////////////////////////////////////// -static bool FillShapeValueString (TRI_shaper_t* shaper, - TRI_shape_value_t* dst, - v8::Handle const& json) { +static int FillShapeValueString (TRI_shaper_t* shaper, + TRI_shape_value_t* dst, + v8::Handle const& json) { char* ptr; TRI_Utf8ValueNFC str(TRI_UNKNOWN_MEM_ZONE, json); @@ -208,8 +210,8 @@ static bool FillShapeValueString (TRI_shaper_t* shaper, dst->_size = sizeof(TRI_shape_length_short_string_t) + TRI_SHAPE_SHORT_STRING_CUT; dst->_value = (ptr = (char*) TRI_Allocate(shaper->_memoryZone, dst->_size, true)); - if (dst->_value == NULL) { - return false; + if (dst->_value == 0) { + return TRI_ERROR_OUT_OF_MEMORY; } * ((TRI_shape_length_short_string_t*) ptr) = 1; @@ -225,8 +227,8 @@ static bool FillShapeValueString (TRI_shaper_t* shaper, dst->_size = sizeof(TRI_shape_length_short_string_t) + TRI_SHAPE_SHORT_STRING_CUT; dst->_value = (ptr = (char*) TRI_Allocate(shaper->_memoryZone, dst->_size, true)); - if (dst->_value == NULL) { - return false; + if (dst->_value == 0) { + return TRI_ERROR_OUT_OF_MEMORY; } * ((TRI_shape_length_short_string_t*) ptr) = size + 1; @@ -239,8 +241,8 @@ static bool FillShapeValueString (TRI_shaper_t* shaper, dst->_size = sizeof(TRI_shape_length_long_string_t) + size + 1; dst->_value = (ptr = (char*) TRI_Allocate(shaper->_memoryZone, dst->_size, true)); - if (dst->_value == NULL) { - return false; + if (dst->_value == 0) { + return TRI_ERROR_OUT_OF_MEMORY; } * ((TRI_shape_length_long_string_t*) ptr) = size + 1; @@ -248,18 +250,20 @@ static bool FillShapeValueString (TRI_shaper_t* shaper, } } - return true; + return TRI_ERROR_NO_ERROR; } //////////////////////////////////////////////////////////////////////////////// /// @brief converts a json list into TRI_shape_value_t //////////////////////////////////////////////////////////////////////////////// -static bool FillShapeValueList (TRI_shaper_t* shaper, - TRI_shape_value_t* dst, - v8::Handle const& json, - set& seenHashes, - vector< v8::Handle >& seenObjects) { +static int FillShapeValueList (TRI_shaper_t* shaper, + TRI_shape_value_t* dst, + v8::Handle const& json, + set& seenHashes, + vector< v8::Handle >& seenObjects, + bool create, + bool isLocked) { size_t i, n; size_t total; @@ -292,20 +296,20 @@ static bool FillShapeValueList (TRI_shaper_t* shaper, dst->_size = sizeof(TRI_shape_length_list_t); dst->_value = (ptr = (char*) TRI_Allocate(shaper->_memoryZone, dst->_size, false)); - if (dst->_value == NULL) { - return false; + if (dst->_value == 0) { + return TRI_ERROR_OUT_OF_MEMORY; } * (TRI_shape_length_list_t*) ptr = 0; - return true; + return TRI_ERROR_NO_ERROR; } // convert into TRI_shape_value_t array p = (values = (TRI_shape_value_t*) TRI_Allocate(shaper->_memoryZone, sizeof(TRI_shape_value_t) * n, true)); - if (p == NULL) { - return false; + if (p == 0) { + return TRI_ERROR_OUT_OF_MEMORY; } total = 0; @@ -313,13 +317,9 @@ static bool FillShapeValueList (TRI_shaper_t* shaper, for (i = 0; i < n; ++i, ++p) { v8::Handle el = json->Get(i); - bool ok = FillShapeValueJson(shaper, p, el, seenHashes, seenObjects); - - if (! ok) { - if (! ok) { - LOG_TRACE("failed to convert position '%d'", (int) i); - } + int res = FillShapeValueJson(shaper, p, el, seenHashes, seenObjects, create, isLocked); + if (res != TRI_ERROR_NO_ERROR) { for (e = p, p = values; p < e; ++p) { if (p->_value != 0) { TRI_Free(shaper->_memoryZone, p->_value); @@ -327,7 +327,7 @@ static bool FillShapeValueList (TRI_shaper_t* shaper, } TRI_Free(shaper->_memoryZone, values); - return false; + return res; } total += p->_size; @@ -358,7 +358,7 @@ static bool FillShapeValueList (TRI_shaper_t* shaper, shape = (TRI_homogeneous_sized_list_shape_t*) TRI_Allocate(shaper->_memoryZone, sizeof(TRI_homogeneous_sized_list_shape_t), true); - if (shape == NULL) { + if (shape == 0) { for (p = values; p < e; ++p) { if (p->_value != 0) { TRI_Free(shaper->_memoryZone, p->_value); @@ -366,8 +366,7 @@ static bool FillShapeValueList (TRI_shaper_t* shaper, } TRI_Free(shaper->_memoryZone, values); - - return false; + return TRI_ERROR_OUT_OF_MEMORY; } shape->base._size = sizeof(TRI_homogeneous_sized_list_shape_t); @@ -376,7 +375,7 @@ static bool FillShapeValueList (TRI_shaper_t* shaper, shape->_sidEntry = s; shape->_sizeEntry = l; - found = shaper->findShape(shaper, &shape->base); + found = shaper->findShape(shaper, &shape->base, create, isLocked); if (found == 0) { for (p = values; p < e; ++p) { @@ -389,7 +388,12 @@ static bool FillShapeValueList (TRI_shaper_t* shaper, TRI_Free(shaper->_memoryZone, shape); LOG_TRACE("shaper failed to find shape of type %d", (int) shape->base._type); - return false; + + if (! create) { + return TRI_RESULT_ELEMENT_NOT_FOUND; + } + + return TRI_ERROR_INTERNAL; } assert(found != 0); @@ -410,7 +414,7 @@ static bool FillShapeValueList (TRI_shaper_t* shaper, TRI_Free(shaper->_memoryZone, values); - return false; + return TRI_ERROR_OUT_OF_MEMORY; } // copy sub-objects into data space @@ -438,7 +442,7 @@ static bool FillShapeValueList (TRI_shaper_t* shaper, TRI_Free(shaper->_memoryZone, values); - return false; + return TRI_ERROR_OUT_OF_MEMORY; } shape->base._size = sizeof(TRI_homogeneous_list_shape_t); @@ -447,7 +451,7 @@ static bool FillShapeValueList (TRI_shaper_t* shaper, shape->_sidEntry = s; // if found returns non-NULL, it will free the shape!! - found = shaper->findShape(shaper, &shape->base); + found = shaper->findShape(shaper, &shape->base, create, isLocked); if (found == 0) { for (p = values; p < e; ++p) { @@ -460,7 +464,12 @@ static bool FillShapeValueList (TRI_shaper_t* shaper, TRI_Free(shaper->_memoryZone, values); TRI_Free(shaper->_memoryZone, shape); - return false; + + if (! create) { + return TRI_RESULT_ELEMENT_NOT_FOUND; + } + + return TRI_ERROR_INTERNAL; } assert(found != 0); @@ -483,7 +492,7 @@ static bool FillShapeValueList (TRI_shaper_t* shaper, TRI_Free(shaper->_memoryZone, values); - return false; + return TRI_ERROR_OUT_OF_MEMORY; } // copy sub-objects into data space @@ -526,7 +535,7 @@ static bool FillShapeValueList (TRI_shaper_t* shaper, } TRI_Free(shaper->_memoryZone, values); - return false; + return TRI_ERROR_OUT_OF_MEMORY; } // copy sub-objects into data space @@ -560,18 +569,20 @@ static bool FillShapeValueList (TRI_shaper_t* shaper, } TRI_Free(shaper->_memoryZone, values); - return true; + return TRI_ERROR_NO_ERROR; } //////////////////////////////////////////////////////////////////////////////// /// @brief converts a json array into TRI_shape_value_t //////////////////////////////////////////////////////////////////////////////// -static bool FillShapeValueArray (TRI_shaper_t* shaper, - TRI_shape_value_t* dst, - v8::Handle const& json, - set& seenHashes, - vector< v8::Handle >& seenObjects) { +static int FillShapeValueArray (TRI_shaper_t* shaper, + TRI_shape_value_t* dst, + v8::Handle const& json, + set& seenHashes, + vector< v8::Handle >& seenObjects, + bool create, + bool isLocked) { size_t i, n; size_t total; @@ -601,8 +612,8 @@ static bool FillShapeValueArray (TRI_shaper_t* shaper, // convert into TRI_shape_value_t array p = (values = (TRI_shape_value_t*) TRI_Allocate(shaper->_memoryZone, n * sizeof(TRI_shape_value_t), true)); - if (p == NULL) { - return false; + if (p == 0) { + return TRI_ERROR_OUT_OF_MEMORY; } total = 0; @@ -612,7 +623,7 @@ static bool FillShapeValueArray (TRI_shaper_t* shaper, for (i = 0; i < n; ++i, ++p) { v8::Handle key = names->Get(i); v8::Handle val = json->Get(key); - bool ok; + int res; // first find an identifier for the name TRI_Utf8ValueNFC keyStr(TRI_UNKNOWN_MEM_ZONE, key); @@ -627,21 +638,27 @@ static bool FillShapeValueArray (TRI_shaper_t* shaper, continue; } - p->_aid = shaper->findAttributeByName(shaper, *keyStr, true); + if (create) { + p->_aid = shaper->findOrCreateAttributeByName(shaper, *keyStr, isLocked); + } + else { + p->_aid = shaper->lookupAttributeByName(shaper, *keyStr); + } // convert value if (p->_aid == 0) { - ok = false; - } - else { - ok = FillShapeValueJson(shaper, p, val, seenHashes, seenObjects); - - if (! ok) { - LOG_TRACE("failed to convert attribute '%s'", *keyStr); + if (create) { + res = TRI_ERROR_INTERNAL; + } + else { + res = TRI_RESULT_ELEMENT_NOT_FOUND; } } + else { + res = FillShapeValueJson(shaper, p, val, seenHashes, seenObjects, create, isLocked); + } - if (! ok) { + if (res != TRI_ERROR_NO_ERROR) { for (e = p, p = values; p < e; ++p) { if (p->_value != 0) { TRI_Free(shaper->_memoryZone, p->_value); @@ -649,7 +666,7 @@ static bool FillShapeValueArray (TRI_shaper_t* shaper, } TRI_Free(shaper->_memoryZone, values); - return false; + return res; } total += p->_size; @@ -703,7 +720,7 @@ static bool FillShapeValueArray (TRI_shaper_t* shaper, TRI_Free(shaper->_memoryZone, values); - return false; + return TRI_ERROR_OUT_OF_MEMORY; } a->base._type = TRI_SHAPE_ARRAY; @@ -734,11 +751,11 @@ static bool FillShapeValueArray (TRI_shaper_t* shaper, dst->_size = total; dst->_value = (ptr = (char*) TRI_Allocate(shaper->_memoryZone, dst->_size, true)); - if (ptr == NULL) { + if (ptr == 0) { e = values + n; for (p = values; p < e; ++p) { - if (p->_value != NULL) { + if (p->_value != 0) { TRI_Free(shaper->_memoryZone, p->_value); } } @@ -746,7 +763,7 @@ static bool FillShapeValueArray (TRI_shaper_t* shaper, TRI_Free(shaper->_memoryZone, values); TRI_Free(shaper->_memoryZone, a); - return false; + return TRI_ERROR_OUT_OF_MEMORY; } // array of offsets for variable part (within the value) @@ -787,30 +804,35 @@ static bool FillShapeValueArray (TRI_shaper_t* shaper, TRI_Free(shaper->_memoryZone, values); // lookup this shape - found = shaper->findShape(shaper, &a->base); + found = shaper->findShape(shaper, &a->base, create, isLocked); if (found == 0) { LOG_TRACE("shaper failed to find shape %d", (int) a->base._type); TRI_Free(shaper->_memoryZone, a); - return false; + + if (! create) { + return TRI_RESULT_ELEMENT_NOT_FOUND; + } + + return TRI_ERROR_INTERNAL; } // and finally add the sid dst->_sid = found->_sid; - return true; + return TRI_ERROR_NO_ERROR; } //////////////////////////////////////////////////////////////////////////////// /// @brief converts a json object into TRI_shape_value_t //////////////////////////////////////////////////////////////////////////////// -static bool FillShapeValueJson (TRI_shaper_t* shaper, - TRI_shape_value_t* dst, - v8::Handle const& json, - set& seenHashes, - vector< v8::Handle >& seenObjects) { - bool result = false; - +static int FillShapeValueJson (TRI_shaper_t* shaper, + TRI_shape_value_t* dst, + v8::Handle const& json, + set& seenHashes, + vector< v8::Handle >& seenObjects, + bool create, + bool isLocked) { // check for cycles if (json->IsObject()) { v8::Handle o = json->ToObject(); @@ -822,7 +844,7 @@ static bool FillShapeValueJson (TRI_shaper_t* shaper, for (vector< v8::Handle >::iterator i = seenObjects.begin(); i != seenObjects.end(); ++i) { if (json->StrictEquals(*i)) { LOG_TRACE("found duplicate for hash %d", hash); - return false; + return TRI_ERROR_ARANGO_SHAPER_FAILED; } } } @@ -834,68 +856,70 @@ static bool FillShapeValueJson (TRI_shaper_t* shaper, } if (json->IsNull()) { - result = FillShapeValueNull(shaper, dst); + return FillShapeValueNull(shaper, dst); } else if (json->IsBoolean()) { - result = FillShapeValueBoolean(shaper, dst, json->ToBoolean()); + return FillShapeValueBoolean(shaper, dst, json->ToBoolean()); } else if (json->IsBooleanObject()) { - result = FillShapeValueBoolean(shaper, dst, v8::Handle::Cast(json)); + return FillShapeValueBoolean(shaper, dst, v8::Handle::Cast(json)); } else if (json->IsNumber()) { - result = FillShapeValueNumber(shaper, dst, json->ToNumber()); + return FillShapeValueNumber(shaper, dst, json->ToNumber()); } else if (json->IsNumberObject()) { - result = FillShapeValueNumber(shaper, dst, v8::Handle::Cast(json)); + return FillShapeValueNumber(shaper, dst, v8::Handle::Cast(json)); } else if (json->IsString()) { - result = FillShapeValueString(shaper, dst, json->ToString()); + return FillShapeValueString(shaper, dst, json->ToString()); } else if (json->IsStringObject()) { - result = FillShapeValueString(shaper, dst, v8::Handle::Cast(json)->StringValue()); + return FillShapeValueString(shaper, dst, v8::Handle::Cast(json)->StringValue()); } else if (json->IsArray()) { - result = FillShapeValueList(shaper, dst, v8::Handle::Cast(json), seenHashes, seenObjects); + return FillShapeValueList(shaper, dst, v8::Handle::Cast(json), seenHashes, seenObjects, create, isLocked); } - - else if (json->IsObject()) { - result = FillShapeValueArray(shaper, dst, json->ToObject(), seenHashes, seenObjects); + + else if (json->IsObject()) { + int res = FillShapeValueArray(shaper, dst, json->ToObject(), seenHashes, seenObjects, create, isLocked); seenObjects.pop_back(); + return res; } else if (json->IsRegExp()) { LOG_TRACE("shaper failed because a regexp cannot be converted"); + return TRI_ERROR_BAD_PARAMETER; } else if (json->IsFunction()) { LOG_TRACE("shaper failed because a function cannot be converted"); + return TRI_ERROR_BAD_PARAMETER; } else if (json->IsExternal()) { LOG_TRACE("shaper failed because an external cannot be converted"); + return TRI_ERROR_BAD_PARAMETER; } else if (json->IsDate()) { LOG_TRACE("shaper failed because a date cannot be converted"); + return TRI_ERROR_BAD_PARAMETER; } // treat undefined as null value else if (json->IsUndefined()) { - result = FillShapeValueNull(shaper, dst); + return FillShapeValueNull(shaper, dst); } - else { - LOG_TRACE("shaper failed to convert object"); - } - - return result; + LOG_TRACE("shaper failed to convert object"); + return TRI_ERROR_BAD_PARAMETER; } //////////////////////////////////////////////////////////////////////////////// @@ -1430,14 +1454,22 @@ v8::Handle TRI_JsonShapeData (TRI_shaper_t* shaper, //////////////////////////////////////////////////////////////////////////////// TRI_shaped_json_t* TRI_ShapedJsonV8Object (v8::Handle const& object, - TRI_shaper_t* shaper) { + TRI_shaper_t* shaper, + bool create, + bool isLocked) { TRI_shape_value_t dst; set seenHashes; vector< v8::Handle > seenObjects; - bool ok = FillShapeValueJson(shaper, &dst, object, seenHashes, seenObjects); - if (! ok) { - TRI_set_errno(TRI_ERROR_ARANGO_SHAPER_FAILED); + int res = FillShapeValueJson(shaper, &dst, object, seenHashes, seenObjects, create, isLocked); + + if (res != TRI_ERROR_NO_ERROR) { + if (res == TRI_RESULT_ELEMENT_NOT_FOUND) { + TRI_set_errno(res); + } + else { + TRI_set_errno(TRI_ERROR_ARANGO_SHAPER_FAILED); + } return 0; } @@ -1460,14 +1492,20 @@ TRI_shaped_json_t* TRI_ShapedJsonV8Object (v8::Handle const& object, int TRI_FillShapedJsonV8Object (v8::Handle const& object, TRI_shaped_json_t* result, - TRI_shaper_t* shaper) { + TRI_shaper_t* shaper, + bool create, + bool isLocked) { TRI_shape_value_t dst; set seenHashes; vector< v8::Handle > seenObjects; - bool ok = FillShapeValueJson(shaper, &dst, object, seenHashes, seenObjects); - if (! ok) { - return TRI_set_errno(TRI_ERROR_BAD_PARAMETER); + int res = FillShapeValueJson(shaper, &dst, object, seenHashes, seenObjects, create, isLocked); + + if (res != TRI_ERROR_NO_ERROR) { + if (res != TRI_RESULT_ELEMENT_NOT_FOUND) { + res = TRI_ERROR_BAD_PARAMETER; + } + return TRI_set_errno(res); } result->_sid = dst._sid; diff --git a/lib/V8/v8-conv.h b/lib/V8/v8-conv.h index e006e359d1..6b028a70a7 100644 --- a/lib/V8/v8-conv.h +++ b/lib/V8/v8-conv.h @@ -67,15 +67,19 @@ v8::Handle TRI_JsonShapeData (TRI_shaper_t*, //////////////////////////////////////////////////////////////////////////////// TRI_shaped_json_t* TRI_ShapedJsonV8Object (v8::Handle const&, - TRI_shaper_t*); + TRI_shaper_t*, + bool, + bool); //////////////////////////////////////////////////////////////////////////////// /// @brief converts a V8 object to a TRI_shaped_json_t in place //////////////////////////////////////////////////////////////////////////////// -int TRI_FillShapedJsonV8Object (v8::Handle const& object, - TRI_shaped_json_t* result, - TRI_shaper_t*); +int TRI_FillShapedJsonV8Object (v8::Handle const&, + TRI_shaped_json_t*, + TRI_shaper_t*, + bool, + bool); //////////////////////////////////////////////////////////////////////////////// /// @brief convert a V8 value to a json_t value