diff --git a/V8/v8-vocbase.cpp b/V8/v8-vocbase.cpp index 0a64c33cca..2650dd32e6 100644 --- a/V8/v8-vocbase.cpp +++ b/V8/v8-vocbase.cpp @@ -327,11 +327,11 @@ int FillVectorPointerFromArguments (v8::Arguments const& argv, /// @brief ensure a hash or skip-list index //////////////////////////////////////////////////////////////////////////////// -static v8::Handle EnsureHashSkipListIndex (string const& cmd, - v8::Arguments const& argv, - bool unique, - bool create, - TRI_idx_type_e type) { +static v8::Handle EnsurePathIndex (string const& cmd, + v8::Arguments const& argv, + bool unique, + bool create, + TRI_idx_type_e type) { v8::HandleScope scope; // ............................................................................. @@ -411,10 +411,15 @@ static v8::Handle EnsureHashSkipListIndex (string const& cmd, } } else if (type == TRI_IDX_TYPE_SKIPLIST_INDEX) { - idx = TRI_EnsureSkiplistIndexSimCollection(sim, &attributes, unique, &created); + if (create) { + idx = TRI_EnsureSkiplistIndexSimCollection(sim, &attributes, unique, &created); - if (idx == 0) { - res = TRI_errno(); + if (idx == 0) { + res = TRI_errno(); + } + } + else { + idx = TRI_LookupSkiplistIndexSimCollection(sim, &attributes, unique); } } else { @@ -2260,7 +2265,7 @@ static v8::Handle JS_EnsureGeoConstraintVocbaseCol (v8::Arguments con //////////////////////////////////////////////////////////////////////////////// static v8::Handle JS_EnsureUniqueConstraintVocbaseCol (v8::Arguments const& argv) { - return EnsureHashSkipListIndex("ensureUniqueConstraint", argv, true, true, TRI_IDX_TYPE_HASH_INDEX); + return EnsurePathIndex("ensureUniqueConstraint", argv, true, true, TRI_IDX_TYPE_HASH_INDEX); } //////////////////////////////////////////////////////////////////////////////// @@ -2268,7 +2273,7 @@ static v8::Handle JS_EnsureUniqueConstraintVocbaseCol (v8::Arguments //////////////////////////////////////////////////////////////////////////////// static v8::Handle JS_LookupUniqueConstraintVocbaseCol (v8::Arguments const& argv) { - return EnsureHashSkipListIndex("lookupUniqueConstraint", argv, true, false, TRI_IDX_TYPE_HASH_INDEX); + return EnsurePathIndex("lookupUniqueConstraint", argv, true, false, TRI_IDX_TYPE_HASH_INDEX); } //////////////////////////////////////////////////////////////////////////////// @@ -2291,7 +2296,7 @@ static v8::Handle JS_LookupUniqueConstraintVocbaseCol (v8::Arguments //////////////////////////////////////////////////////////////////////////////// static v8::Handle JS_EnsureHashIndexVocbaseCol (v8::Arguments const& argv) { - return EnsureHashSkipListIndex("ensureHashIndex", argv, false, true, TRI_IDX_TYPE_HASH_INDEX); + return EnsurePathIndex("ensureHashIndex", argv, false, true, TRI_IDX_TYPE_HASH_INDEX); } //////////////////////////////////////////////////////////////////////////////// @@ -2299,7 +2304,7 @@ static v8::Handle JS_EnsureHashIndexVocbaseCol (v8::Arguments const& //////////////////////////////////////////////////////////////////////////////// static v8::Handle JS_LookupHashIndexVocbaseCol (v8::Arguments const& argv) { - return EnsureHashSkipListIndex("lookupHashIndex", argv, false, false, TRI_IDX_TYPE_HASH_INDEX); + return EnsurePathIndex("lookupHashIndex", argv, false, false, TRI_IDX_TYPE_HASH_INDEX); } //////////////////////////////////////////////////////////////////////////////// @@ -2439,7 +2444,15 @@ static v8::Handle JS_EnsurePriorityQueueIndexVocbaseCol (v8::Argument //////////////////////////////////////////////////////////////////////////////// static v8::Handle JS_EnsureUniqueSkiplistVocbaseCol (v8::Arguments const& argv) { - return EnsureHashSkipListIndex("ensureUniqueSkipList", argv, true, true, TRI_IDX_TYPE_SKIPLIST_INDEX); + return EnsurePathIndex("ensureUniqueSkiplist", argv, true, true, TRI_IDX_TYPE_SKIPLIST_INDEX); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief looks up a skiplist index +//////////////////////////////////////////////////////////////////////////////// + +static v8::Handle JS_LookupUniqueSkiplistVocbaseCol (v8::Arguments const& argv) { + return EnsurePathIndex("lookupUniqueSkiplist", argv, true, false, TRI_IDX_TYPE_SKIPLIST_INDEX); } //////////////////////////////////////////////////////////////////////////////// @@ -2459,7 +2472,15 @@ static v8::Handle JS_EnsureUniqueSkiplistVocbaseCol (v8::Arguments co //////////////////////////////////////////////////////////////////////////////// static v8::Handle JS_EnsureSkiplistVocbaseCol (v8::Arguments const& argv) { - return EnsureHashSkipListIndex("ensureSkipList", argv, false, true, TRI_IDX_TYPE_SKIPLIST_INDEX); + return EnsurePathIndex("ensureSkiplist", argv, false, true, TRI_IDX_TYPE_SKIPLIST_INDEX); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief looks up a multi skiplist index +//////////////////////////////////////////////////////////////////////////////// + +static v8::Handle JS_LookupSkiplistVocbaseCol (v8::Arguments const& argv) { + return EnsurePathIndex("lookupSkiplist", argv, false, false, TRI_IDX_TYPE_SKIPLIST_INDEX); } //////////////////////////////////////////////////////////////////////////////// @@ -4285,7 +4306,9 @@ void TRI_InitV8VocBridge (v8::Handle context, TRI_vocbase_t* vocbas v8::Handle IdFuncName = v8::Persistent::New(v8::String::New("id")); v8::Handle LoadFuncName = v8::Persistent::New(v8::String::New("load")); v8::Handle LookupHashIndexFuncName = v8::Persistent::New(v8::String::New("lookupHashIndex")); + v8::Handle LookupSkiplistFuncName = v8::Persistent::New(v8::String::New("lookupSkiplist")); v8::Handle LookupUniqueConstraintFuncName = v8::Persistent::New(v8::String::New("lookupUniqueConstraint")); + v8::Handle LookupUniqueSkiplistFuncName = v8::Persistent::New(v8::String::New("lookupUniqueSkiplist")); v8::Handle NameFuncName = v8::Persistent::New(v8::String::New("name")); v8::Handle NextFuncName = v8::Persistent::New(v8::String::New("next")); v8::Handle PersistFuncName = v8::Persistent::New(v8::String::New("persist")); @@ -4449,7 +4472,9 @@ void TRI_InitV8VocBridge (v8::Handle context, TRI_vocbase_t* vocbas rt->Set(GetIndexesFuncName, v8::FunctionTemplate::New(JS_GetIndexesVocbaseCol)); rt->Set(LoadFuncName, v8::FunctionTemplate::New(JS_LoadVocbaseCol)); rt->Set(LookupHashIndexFuncName, v8::FunctionTemplate::New(JS_LookupHashIndexVocbaseCol)); + rt->Set(LookupSkiplistFuncName, v8::FunctionTemplate::New(JS_LookupSkiplistVocbaseCol)); rt->Set(LookupUniqueConstraintFuncName, v8::FunctionTemplate::New(JS_LookupUniqueConstraintVocbaseCol)); + rt->Set(LookupUniqueSkiplistFuncName, v8::FunctionTemplate::New(JS_LookupUniqueSkiplistVocbaseCol)); rt->Set(NameFuncName, v8::FunctionTemplate::New(JS_NameVocbaseCol)); rt->Set(PropertiesFuncName, v8::FunctionTemplate::New(JS_PropertiesVocbaseCol)); rt->Set(RemoveFuncName, v8::FunctionTemplate::New(JS_RemoveVocbaseCol)); @@ -4492,7 +4517,9 @@ void TRI_InitV8VocBridge (v8::Handle context, TRI_vocbase_t* vocbas rt->Set(GetIndexesFuncName, v8::FunctionTemplate::New(JS_GetIndexesVocbaseCol)); rt->Set(LoadFuncName, v8::FunctionTemplate::New(JS_LoadVocbaseCol)); rt->Set(LookupHashIndexFuncName, v8::FunctionTemplate::New(JS_LookupHashIndexVocbaseCol)); + rt->Set(LookupSkiplistFuncName, v8::FunctionTemplate::New(JS_LookupSkiplistVocbaseCol)); rt->Set(LookupUniqueConstraintFuncName, v8::FunctionTemplate::New(JS_LookupUniqueConstraintVocbaseCol)); + rt->Set(LookupUniqueSkiplistFuncName, v8::FunctionTemplate::New(JS_LookupUniqueSkiplistVocbaseCol)); rt->Set(NameFuncName, v8::FunctionTemplate::New(JS_NameVocbaseCol)); rt->Set(PropertiesFuncName, v8::FunctionTemplate::New(JS_PropertiesVocbaseCol)); rt->Set(RemoveFuncName, v8::FunctionTemplate::New(JS_RemoveVocbaseCol)); diff --git a/VocBase/simple-collection.c b/VocBase/simple-collection.c index 323fb00295..64c26fb1d8 100644 --- a/VocBase/simple-collection.c +++ b/VocBase/simple-collection.c @@ -1924,6 +1924,29 @@ int TRI_CloseSimCollection (TRI_sim_collection_t* collection) { // --SECTION-- INDEXES // ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// --SECTION-- private types +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup VocBase +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief pid name structure +//////////////////////////////////////////////////////////////////////////////// + +typedef struct pid_name_s { + TRI_shape_pid_t _pid; + char* _name; +} +pid_name_t; + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + // ----------------------------------------------------------------------------- // --SECTION-- private functions // ----------------------------------------------------------------------------- @@ -2332,6 +2355,144 @@ static int FillIndex (TRI_sim_collection_t* collection, return TRI_ERROR_NO_ERROR; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief finds a path based, unique or non-unique index +//////////////////////////////////////////////////////////////////////////////// + +static TRI_index_t* LookupPathIndexSimCollection (TRI_sim_collection_t* collection, + TRI_vector_t const* paths, + TRI_idx_type_e type, + bool unique) { + TRI_index_t* matchedIndex = NULL; + size_t j; + size_t k; + + // go through every index and see if we have a match + for (j = 0; j < collection->_indexes._length; ++j) { + TRI_index_t* idx = collection->_indexes._buffer[j]; + TRI_hash_index_t* hashIndex = (TRI_hash_index_t*) idx; + bool found = true; + + // check that the type of the index is in fact a hash index + if (idx->_type != type) { + continue; + } + + // check that the uniqueness is the same + if (idx->_unique != unique) { + continue; + } + + // check that the number of paths (fields) in the hash index matches that + // of the number of attributes + if (paths->_length != hashIndex->_paths._length) { + continue; + } + + // go through all the attributes and see if they match + for (k = 0; k < paths->_length; ++k) { + TRI_shape_pid_t field = *((TRI_shape_pid_t*)(TRI_AtVector(&hashIndex->_paths, k))); + TRI_shape_pid_t shape = *((TRI_shape_pid_t*)(TRI_AtVector(paths, k))); + + if (field != shape) { + found = false; + break; + } + } + + // stop if we found a match + if (found) { + matchedIndex = idx; + break; + } + } + + return matchedIndex; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief restores a path based index (template) +//////////////////////////////////////////////////////////////////////////////// + +static int PathBasedIndexFromJson (TRI_sim_collection_t* sim, + TRI_json_t* definition, + TRI_idx_iid_t iid, + TRI_index_t* (*creator)(TRI_sim_collection_t*, + TRI_vector_pointer_t const*, + TRI_idx_iid_t, + bool, + bool*)) { + TRI_index_t* idx; + TRI_json_t* bv; + TRI_json_t* fld; + TRI_json_t* fieldStr; + TRI_vector_pointer_t attributes; + bool unique; + size_t fieldCount; + size_t j; + + // extract fields + fld = ExtractFields(definition, &fieldCount, iid); + + if (fld == NULL) { + return TRI_errno(); + } + + // extract the list of fields + if (fieldCount < 1) { + LOG_ERROR("ignoring index %lu, need at least von attribute path",(unsigned long) iid); + + return TRI_set_errno(TRI_ERROR_BAD_PARAMETER); + } + + // determine if the hash index is unique or non-unique + unique = false; + bv = TRI_LookupArrayJson(definition, "unique"); + + if (bv != NULL && bv->_type == TRI_JSON_BOOLEAN) { + unique = bv->_value._boolean; + } + else { + LOG_ERROR("ignoring index %lu, could not determine if unique or non-unique", (unsigned long) iid); + return TRI_set_errno(TRI_ERROR_BAD_PARAMETER); + } + + // Initialise the vector in which we store the fields on which the hashing + // will be based. + TRI_InitVectorPointer(&attributes, TRI_CORE_MEM_ZONE); + + // find fields + for (j = 0; j < fieldCount; ++j) { + fieldStr = TRI_AtVector(&fld->_value._objects, j); + + TRI_PushBackVectorPointer(&attributes, fieldStr->_value._string.data); + } + + // create the index + idx = creator(sim, &attributes, iid, unique, NULL); + + // cleanup + TRI_DestroyVectorPointer(&attributes); + + if (idx == NULL) { + LOG_ERROR("cannot create hash index %lu", (unsigned long) iid); + return TRI_errno(); + } + + return TRI_ERROR_NO_ERROR; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief compares pid and name +//////////////////////////////////////////////////////////////////////////////// + +static int ComparePidName (void const* left, void const* right) { + pid_name_t const* l = left; + pid_name_t const* r = right; + + return l->_pid - r->_pid; +} + //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// @@ -2481,6 +2642,86 @@ bool TRI_DropIndexSimCollection (TRI_sim_collection_t* sim, TRI_idx_iid_t iid) { } } +//////////////////////////////////////////////////////////////////////////////// +/// @brief converts attribute names to lists of pids and names +/// +/// In case of an error, all allocated memory in pids and names will be +/// 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) { + pid_name_t* pidnames; + size_t j; + + // ............................................................................. + // sorted case + // ............................................................................. + + if (sorted) { + + // combine name and pid + pidnames = TRI_Allocate(TRI_CORE_MEM_ZONE, sizeof(pid_name_t) * attributes->_length, false); + + for (j = 0; j < attributes->_length; ++j) { + pidnames[j]._name = attributes->_buffer[j]; + pidnames[j]._pid = shaper->findAttributePathByName(shaper, pidnames[j]._name); + + if (pidnames[j]._pid == 0) { + TRI_Free(TRI_CORE_MEM_ZONE, pidnames); + + return TRI_set_errno(TRI_ERROR_ARANGO_ILLEGAL_NAME); + } + } + + // sort according to pid + qsort(pidnames, attributes->_length, sizeof(pid_name_t), ComparePidName); + + // split again + TRI_InitVector(pids, TRI_CORE_MEM_ZONE, sizeof(TRI_shape_pid_t)); + TRI_InitVectorPointer(names, TRI_CORE_MEM_ZONE); + + for (j = 0; j < attributes->_length; ++j) { + TRI_PushBackVector(pids, &pidnames[j]._pid); + TRI_PushBackVectorPointer(names, pidnames[j]._name); + } + + TRI_Free(TRI_CORE_MEM_ZONE, pidnames); + } + + // ............................................................................. + // unsorted case + // ............................................................................. + + else { + TRI_InitVector(pids, TRI_CORE_MEM_ZONE, sizeof(TRI_shape_pid_t)); + TRI_InitVectorPointer(names, TRI_CORE_MEM_ZONE); + + for (j = 0; j < attributes->_length; ++j) { + char* name; + TRI_shape_pid_t pid; + + name = attributes->_buffer[j]; + pid = shaper->findAttributePathByName(shaper, name); + + if (pid == 0) { + TRI_DestroyVector(pids); + TRI_DestroyVectorPointer(names); + + return TRI_set_errno(TRI_ERROR_ARANGO_ILLEGAL_NAME); + } + + TRI_PushBackVector(pids, &pid); + TRI_PushBackVectorPointer(names, name); + } + } + + return TRI_ERROR_NO_ERROR; +} + //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// @@ -3191,29 +3432,6 @@ TRI_index_t* TRI_EnsureGeoIndex2SimCollection (TRI_sim_collection_t* sim, // --SECTION-- HASH INDEX // ----------------------------------------------------------------------------- -// ----------------------------------------------------------------------------- -// --SECTION-- private types -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup VocBase -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief pid name structure -//////////////////////////////////////////////////////////////////////////////// - -typedef struct pid_name_s { - TRI_shape_pid_t _pid; - char* _name; -} -pid_name_t; - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- private functions // ----------------------------------------------------------------------------- @@ -3223,60 +3441,6 @@ pid_name_t; /// @{ //////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -/// @brief finds a hash index (unique or non-unique) -//////////////////////////////////////////////////////////////////////////////// - -static TRI_index_t* LookupHashIndexSimCollection (TRI_sim_collection_t* collection, - TRI_vector_t const* paths, - bool unique) { - TRI_index_t* matchedIndex = NULL; - size_t j; - size_t k; - - // go through every index and see if we have a match - for (j = 0; j < collection->_indexes._length; ++j) { - TRI_index_t* idx = collection->_indexes._buffer[j]; - TRI_hash_index_t* hashIndex = (TRI_hash_index_t*) idx; - bool found = true; - - // check that the type of the index is in fact a hash index - if (idx->_type != TRI_IDX_TYPE_HASH_INDEX) { - continue; - } - - // check that the uniqueness is the same - if (idx->_unique != unique) { - continue; - } - - // check that the number of paths (fields) in the hash index matches that - // of the number of attributes - if (paths->_length != hashIndex->_paths._length) { - continue; - } - - // go through all the attributes and see if they match - for (k = 0; k < paths->_length; ++k) { - TRI_shape_pid_t field = *((TRI_shape_pid_t*)(TRI_AtVector(&hashIndex->_paths, k))); - TRI_shape_pid_t shape = *((TRI_shape_pid_t*)(TRI_AtVector(paths, k))); - - if (field != shape) { - found = false; - break; - } - } - - // stop if we found a match - if (found) { - matchedIndex = idx; - break; - } - } - - return matchedIndex; -} - //////////////////////////////////////////////////////////////////////////////// /// @brief adds a hash index to the collection //////////////////////////////////////////////////////////////////////////////// @@ -3297,7 +3461,8 @@ static TRI_index_t* CreateHashIndexSimCollection (TRI_sim_collection_t* collecti res = TRI_PidNamesByAttributeNames(attributes, collection->base._shaper, &paths, - &fields); + &fields, + true); if (res != TRI_ERROR_NO_ERROR) { if (created != NULL) { @@ -3313,7 +3478,7 @@ static TRI_index_t* CreateHashIndexSimCollection (TRI_sim_collection_t* collecti // a new one. // ........................................................................... - idx = LookupHashIndexSimCollection(collection, &paths, unique); + idx = LookupPathIndexSimCollection(collection, &paths, TRI_IDX_TYPE_HASH_INDEX, unique); if (idx != NULL) { TRI_DestroyVector(&paths); @@ -3357,78 +3522,6 @@ static TRI_index_t* CreateHashIndexSimCollection (TRI_sim_collection_t* collecti return idx; } -//////////////////////////////////////////////////////////////////////////////// -/// @brief restores an index (template) -//////////////////////////////////////////////////////////////////////////////// - -static int FieldBasedIndexFromJson (TRI_sim_collection_t* sim, - TRI_json_t* definition, - TRI_idx_iid_t iid, - TRI_index_t* (*creator)(TRI_sim_collection_t*, - TRI_vector_pointer_t const*, - TRI_idx_iid_t, - bool, - bool*)) { - TRI_index_t* idx; - TRI_json_t* bv; - TRI_json_t* fld; - TRI_json_t* fieldStr; - TRI_vector_pointer_t attributes; - bool unique; - size_t fieldCount; - size_t j; - - // extract fields - fld = ExtractFields(definition, &fieldCount, iid); - - if (fld == NULL) { - return TRI_errno(); - } - - // extract the list of fields - if (fieldCount < 1) { - LOG_ERROR("ignoring index %lu, need at least von attribute path",(unsigned long) iid); - - return TRI_set_errno(TRI_ERROR_BAD_PARAMETER); - } - - // determine if the hash index is unique or non-unique - unique = false; - bv = TRI_LookupArrayJson(definition, "unique"); - - if (bv != NULL && bv->_type == TRI_JSON_BOOLEAN) { - unique = bv->_value._boolean; - } - else { - LOG_ERROR("ignoring index %lu, could not determine if unique or non-unique", (unsigned long) iid); - return TRI_set_errno(TRI_ERROR_BAD_PARAMETER); - } - - // Initialise the vector in which we store the fields on which the hashing - // will be based. - TRI_InitVectorPointer(&attributes, TRI_CORE_MEM_ZONE); - - // find fields - for (j = 0; j < fieldCount; ++j) { - fieldStr = TRI_AtVector(&fld->_value._objects, j); - - TRI_PushBackVectorPointer(&attributes, fieldStr->_value._string.data); - } - - // create the index - idx = creator(sim, &attributes, iid, unique, NULL); - - // cleanup - TRI_DestroyVectorPointer(&attributes); - - if (idx == NULL) { - LOG_ERROR("cannot create hash index %lu", (unsigned long) iid); - return TRI_errno(); - } - - return TRI_ERROR_NO_ERROR; -} - //////////////////////////////////////////////////////////////////////////////// /// @brief restores an index //////////////////////////////////////////////////////////////////////////////// @@ -3436,18 +3529,7 @@ static int FieldBasedIndexFromJson (TRI_sim_collection_t* sim, static int HashIndexFromJson (TRI_sim_collection_t* sim, TRI_json_t* definition, TRI_idx_iid_t iid) { - return FieldBasedIndexFromJson(sim, definition, iid, CreateHashIndexSimCollection); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief compares pid and name -//////////////////////////////////////////////////////////////////////////////// - -static int ComparePidName (void const* left, void const* right) { - pid_name_t const* l = left; - pid_name_t const* r = right; - - return l->_pid - r->_pid; + return PathBasedIndexFromJson(sim, definition, iid, CreateHashIndexSimCollection); } //////////////////////////////////////////////////////////////////////////////// @@ -3463,47 +3545,6 @@ static int ComparePidName (void const* left, void const* right) { /// @{ //////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -/// @brief converts attribute names to sorted lists of pids and names -//////////////////////////////////////////////////////////////////////////////// - -int TRI_PidNamesByAttributeNames (TRI_vector_pointer_t const* attributes, - TRI_shaper_t* shaper, - TRI_vector_t* pids, - TRI_vector_pointer_t* names) { - pid_name_t* pidnames; - size_t j; - - // combine name and pid - pidnames = TRI_Allocate(TRI_CORE_MEM_ZONE, sizeof(pid_name_t) * attributes->_length, false); - - for (j = 0; j < attributes->_length; ++j) { - pidnames[j]._name = attributes->_buffer[j]; - pidnames[j]._pid = shaper->findAttributePathByName(shaper, pidnames[j]._name); - - if (pidnames[j]._pid == 0) { - TRI_Free(TRI_CORE_MEM_ZONE, pidnames); - - return TRI_set_errno(TRI_ERROR_ARANGO_ILLEGAL_NAME); - } - } - - // sort according to pid - qsort(pidnames, attributes->_length, sizeof(pid_name_t), ComparePidName); - - // split again - TRI_InitVector(pids, TRI_CORE_MEM_ZONE, sizeof(TRI_shape_pid_t)); - TRI_InitVectorPointer(names, TRI_CORE_MEM_ZONE); - - for (j = 0; j < attributes->_length; ++j) { - TRI_PushBackVector(pids, &pidnames[j]._pid); - TRI_PushBackVectorPointer(names, pidnames[j]._name); - } - - TRI_Free(TRI_CORE_MEM_ZONE, pidnames); - return TRI_ERROR_NO_ERROR; -} - //////////////////////////////////////////////////////////////////////////////// /// @brief finds a hash index (unique or non-unique) //////////////////////////////////////////////////////////////////////////////// @@ -3520,7 +3561,8 @@ TRI_index_t* TRI_LookupHashIndexSimCollection (TRI_sim_collection_t* sim, res = TRI_PidNamesByAttributeNames(attributes, sim->base._shaper, &paths, - &fields); + &fields, + true); if (res != TRI_ERROR_NO_ERROR) { return NULL; @@ -3532,7 +3574,7 @@ TRI_index_t* TRI_LookupHashIndexSimCollection (TRI_sim_collection_t* sim, TRI_READ_LOCK_DOCUMENTS_INDEXES_SIM_COLLECTION(sim); - idx = LookupHashIndexSimCollection(sim, &paths, unique); + idx = LookupPathIndexSimCollection(sim, &paths, TRI_IDX_TYPE_HASH_INDEX, unique); TRI_READ_UNLOCK_DOCUMENTS_INDEXES_SIM_COLLECTION(sim); @@ -3614,42 +3656,32 @@ static TRI_index_t* CreateSkiplistIndexSimCollection (TRI_sim_collection_t* coll TRI_idx_iid_t iid, bool unique, bool* created) { - TRI_index_t* idx = NULL; - TRI_shaper_t* shaper = collection->base._shaper; - TRI_vector_t paths; + TRI_index_t* idx; TRI_vector_pointer_t fields; + TRI_vector_t paths; int res; - size_t j; - - TRI_InitVector(&paths, TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_shape_pid_t)); - TRI_InitVectorPointer(&fields, TRI_UNKNOWN_MEM_ZONE); - // ........................................................................... - // Determine the shape ids for the attributes - // ........................................................................... + res = TRI_PidNamesByAttributeNames(attributes, + collection->base._shaper, + &paths, + &fields, + false); - for (j = 0; j < attributes->_length; ++j) { - char* path = attributes->_buffer[j]; - TRI_shape_pid_t shape = shaper->findAttributePathByName(shaper, path); - - if (shape == 0) { - TRI_DestroyVector(&paths); - TRI_DestroyVectorPointer(&fields); - - return NULL; + if (res != TRI_ERROR_NO_ERROR) { + if (created != NULL) { + *created = false; } - TRI_PushBackVector(&paths, &shape); - TRI_PushBackVectorPointer(&fields, path); + return NULL; } - + // ........................................................................... // Attempt to find an existing index which matches the attributes above. // If a suitable index is found, return that one otherwise we need to create // a new one. // ........................................................................... - idx = TRI_LookupSkiplistIndexSimCollection(collection, &paths); + idx = LookupPathIndexSimCollection(collection, &paths, TRI_IDX_TYPE_SKIPLIST_INDEX, unique); if (idx != NULL) { TRI_DestroyVector(&paths); @@ -3663,24 +3695,19 @@ static TRI_index_t* CreateSkiplistIndexSimCollection (TRI_sim_collection_t* coll return idx; } - // ........................................................................... // Create the skiplist index - // ........................................................................... - idx = TRI_CreateSkiplistIndex(&collection->base, &fields, &paths, unique); - // ........................................................................... + // release memory allocated to vector + TRI_DestroyVector(&paths); + TRI_DestroyVectorPointer(&fields); + // If index id given, use it otherwise use the default. - // ........................................................................... - if (iid) { idx->_iid = iid; } - // ........................................................................... // initialises the index with all existing documents - // ........................................................................... - res = FillIndex(collection, idx); if (res != TRI_ERROR_NO_ERROR) { @@ -3688,19 +3715,9 @@ static TRI_index_t* CreateSkiplistIndexSimCollection (TRI_sim_collection_t* coll return NULL; } - // ........................................................................... - // store index - // ........................................................................... - + // store index and return TRI_PushBackVectorPointer(&collection->_indexes, idx); - // ........................................................................... - // release memory allocated to vector - // ........................................................................... - - TRI_DestroyVector(&paths); - TRI_DestroyVectorPointer(&fields); - if (created != NULL) { *created = true; } @@ -3715,7 +3732,7 @@ static TRI_index_t* CreateSkiplistIndexSimCollection (TRI_sim_collection_t* coll static int SkiplistIndexFromJson (TRI_sim_collection_t* sim, TRI_json_t* definition, TRI_idx_iid_t iid) { - return FieldBasedIndexFromJson(sim, definition, iid, CreateSkiplistIndexSimCollection); + return PathBasedIndexFromJson(sim, definition, iid, CreateSkiplistIndexSimCollection); } //////////////////////////////////////////////////////////////////////////////// @@ -3735,76 +3752,54 @@ static int SkiplistIndexFromJson (TRI_sim_collection_t* sim, /// @brief finds a skiplist index (unique or non-unique) //////////////////////////////////////////////////////////////////////////////// -TRI_index_t* TRI_LookupSkiplistIndexSimCollection (TRI_sim_collection_t* collection, - const TRI_vector_t* paths) { - TRI_index_t* matchedIndex = NULL; - size_t j, k; +TRI_index_t* TRI_LookupSkiplistIndexSimCollection (TRI_sim_collection_t* sim, + TRI_vector_pointer_t const* attributes, + bool unique) { + TRI_index_t* idx; + TRI_vector_pointer_t fields; + TRI_vector_t paths; + int res; - // ........................................................................... - // Note: This function does NOT differentiate between non-unique and unique - // skiplist indexes. The first index which matches the attributes - // (paths parameter) will be returned. - // ........................................................................... - - - // ........................................................................... - // go through every index and see if we have a match - // ........................................................................... - - for (j = 0; j < collection->_indexes._length; ++j) { - TRI_index_t* idx = collection->_indexes._buffer[j]; - TRI_skiplist_index_t* skiplistIndex = (TRI_skiplist_index_t*) idx; - bool found = true; + // determine the unsorted shape ids for the attributes + res = TRI_PidNamesByAttributeNames(attributes, + sim->base._shaper, + &paths, + &fields, + false); - // ......................................................................... - // check that the type of the index is in fact a skiplist index - // ......................................................................... - - if (idx->_type != TRI_IDX_TYPE_SKIPLIST_INDEX) { - continue; - } - - // ......................................................................... - // check that the number of paths (fields) in the index matches that - // of the number of attributes - // ......................................................................... - - if (paths->_length != skiplistIndex->_paths._length) { - continue; - } - - // ......................................................................... - // Go through all the attributes and see if they match - // ......................................................................... - - for (k = 0; k < paths->_length; ++k) { - TRI_shape_pid_t field = *((TRI_shape_pid_t*)(TRI_AtVector(&skiplistIndex->_paths,k))); - TRI_shape_pid_t shape = *((TRI_shape_pid_t*)(TRI_AtVector(paths,k))); - - if (field != shape) { - found = false; - break; - } - } - - - if (found) { - matchedIndex = idx; - break; - } + if (res != TRI_ERROR_NO_ERROR) { + return NULL; } + + // ............................................................................. + // inside write-lock + // ............................................................................. + + TRI_READ_LOCK_DOCUMENTS_INDEXES_SIM_COLLECTION(sim); - return matchedIndex; + idx = LookupPathIndexSimCollection(sim, &paths, TRI_IDX_TYPE_SKIPLIST_INDEX, unique); + + TRI_READ_UNLOCK_DOCUMENTS_INDEXES_SIM_COLLECTION(sim); + + // ............................................................................. + // outside write-lock + // ............................................................................. + + // release memory allocated to vector + TRI_DestroyVector(&paths); + TRI_DestroyVectorPointer(&fields); + + return idx; } //////////////////////////////////////////////////////////////////////////////// /// @brief ensures that a skiplist index exists //////////////////////////////////////////////////////////////////////////////// -TRI_index_t* TRI_EnsureSkiplistIndexSimCollection(TRI_sim_collection_t* sim, - TRI_vector_pointer_t const* attributes, - bool unique, - bool* created) { +TRI_index_t* TRI_EnsureSkiplistIndexSimCollection (TRI_sim_collection_t* sim, + TRI_vector_pointer_t const* attributes, + bool unique, + bool* created) { TRI_index_t* idx; int res; @@ -3814,10 +3809,6 @@ TRI_index_t* TRI_EnsureSkiplistIndexSimCollection(TRI_sim_collection_t* sim, TRI_WRITE_LOCK_DOCUMENTS_INDEXES_SIM_COLLECTION(sim); - // ............................................................................. - // Given the list of attributes (as strings) - // ............................................................................. - idx = CreateSkiplistIndexSimCollection(sim, attributes, 0, unique, created); if (idx == NULL) { @@ -3968,7 +3959,7 @@ static TRI_index_t* CreatePriorityQueueIndexSimCollection (TRI_sim_collection_t* static int PriorityQueueFromJson (TRI_sim_collection_t* sim, TRI_json_t* definition, TRI_idx_iid_t iid) { - return FieldBasedIndexFromJson(sim, definition, iid, CreatePriorityQueueIndexSimCollection); + return PathBasedIndexFromJson(sim, definition, iid, CreatePriorityQueueIndexSimCollection); } //////////////////////////////////////////////////////////////////////////////// diff --git a/VocBase/simple-collection.h b/VocBase/simple-collection.h index 11dd070bb6..93008d2fff 100644 --- a/VocBase/simple-collection.h +++ b/VocBase/simple-collection.h @@ -501,7 +501,8 @@ struct TRI_index_s* TRI_EnsureGeoIndex2SimCollection (TRI_sim_collection_t* coll int TRI_PidNamesByAttributeNames (TRI_vector_pointer_t const* attributes, TRI_shaper_t* shaper, TRI_vector_t* pids, - TRI_vector_pointer_t* names); + TRI_vector_pointer_t* names, + bool sorted); //////////////////////////////////////////////////////////////////////////////// /// @brief finds a hash index @@ -548,13 +549,14 @@ struct TRI_index_s* TRI_EnsureHashIndexSimCollection (TRI_sim_collection_t* coll //////////////////////////////////////////////////////////////////////////////// struct TRI_index_s* TRI_LookupSkiplistIndexSimCollection (TRI_sim_collection_t*, - TRI_vector_t const*); + TRI_vector_pointer_t const* attributes, + bool unique); //////////////////////////////////////////////////////////////////////////////// /// @brief ensures that a skiplist index exists //////////////////////////////////////////////////////////////////////////////// -struct TRI_index_s* TRI_EnsureSkiplistIndexSimCollection (TRI_sim_collection_t* collection, +struct TRI_index_s* TRI_EnsureSkiplistIndexSimCollection (TRI_sim_collection_t*, TRI_vector_pointer_t const* attributes, bool unique, bool* created); diff --git a/js/common/modules/simple-query-basics.js b/js/common/modules/simple-query-basics.js index 394a111b3a..62e7092879 100644 --- a/js/common/modules/simple-query-basics.js +++ b/js/common/modules/simple-query-basics.js @@ -273,7 +273,7 @@ ArangoEdgesCollection.prototype.geo = ArangoCollection.geo; /// An attribute name of the form @LIT{a.b} is interpreted as attribute path, /// not as attribute. If you use /// -/// @LIT{{ a : { c : 1 }}} +/// @LIT{{ a : { c : 1 } }} /// /// as example, then you will find all documents, such that the attribute /// @LIT{a} contains a document of the form @LIT{{c : 1 }}. E.g., the document @@ -282,7 +282,7 @@ ArangoEdgesCollection.prototype.geo = ArangoCollection.geo; /// /// will match, but the document /// -/// @LIT{{ a : { c : 1\, b : 1 }}} +/// @LIT{{ a : { c : 1\, b : 1 } }} /// /// will not. /// @@ -295,7 +295,7 @@ ArangoEdgesCollection.prototype.geo = ArangoCollection.geo; /// /// @LIT{{ a : { c : 1 }\, b : 1 }} and /// -/// @LIT{{ a : { c : 1\, b : 1 }}} +/// @LIT{{ a : { c : 1\, b : 1 } }} /// /// will match. /// diff --git a/js/server/js-server.h b/js/server/js-server.h index a809e59567..5bcc7525d4 100644 --- a/js/server/js-server.h +++ b/js/server/js-server.h @@ -553,7 +553,7 @@ static string JS_server_server = "};\n" "\n" "////////////////////////////////////////////////////////////////////////////////\n" - "/// @brief strng representation of a collection\n" + "/// @brief string representation of a collection\n" "////////////////////////////////////////////////////////////////////////////////\n" "\n" "ArangoCollection.prototype.toString = function(seen, path, names, level) {\n" @@ -564,6 +564,83 @@ static string JS_server_server = "/// @}\n" "////////////////////////////////////////////////////////////////////////////////\n" "\n" + "// -----------------------------------------------------------------------------\n" + "// --SECTION-- skip-list helper\n" + "// -----------------------------------------------------------------------------\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "/// @addtogroup V8Shell\n" + "/// @{\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "/// @brief equal\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "EQ = ModuleCache[\"/internal\"].exports.EQ = function (value) {\n" + " return [ [ \"==\", value ] ];\n" + "}\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "/// @brief less than\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "LT = ModuleCache[\"/internal\"].exports.LT = function (value) {\n" + " return [ [ \"<\", value ] ];\n" + "}\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "/// @brief less than or equal\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "LE = ModuleCache[\"/internal\"].exports.LE = function (value) {\n" + " return [ [ \"<=\", value ] ];\n" + "}\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "/// @brief greater than\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "GT = ModuleCache[\"/internal\"].exports.GT = function (value) {\n" + " return [ [ \">\", value ] ];\n" + "}\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "/// @brief greater than or equal\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "GE = ModuleCache[\"/internal\"].exports.GE = function (value) {\n" + " return [ [ \">=\", value ] ];\n" + "}\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "/// @brief range (left closed, right open)\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "RANGE = ModuleCache[\"/internal\"].exports.RANGE = function (left, right) {\n" + " return [ [ \">=\", left ], [ \"<\", right ] ];\n" + "}\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "/// @brief open range\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "ORANGE = ModuleCache[\"/internal\"].exports.ORANGE = function (left, right) {\n" + " return [ [ \">\", left ], [ \"<\", right ] ];\n" + "}\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "/// @brief closed range\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "CRANGE = ModuleCache[\"/internal\"].exports.CRANGE = function (left, right) {\n" + " return [ [ \">=\", left ], [ \"<=\", right ] ];\n" + "}\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "/// @}\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" "// Local Variables:\n" "// mode: outline-minor\n" "// outline-regexp: \"^\\\\(/// @brief\\\\|/// @addtogroup\\\\|// --SECTION--\\\\|/// @page\\\\|/// @}\\\\)\"\n" diff --git a/js/server/server.js b/js/server/server.js index d45a6b5c2f..03a580e2de 100644 --- a/js/server/server.js +++ b/js/server/server.js @@ -552,7 +552,7 @@ ArangoEdgesCollection.prototype._PRINT = function() { }; //////////////////////////////////////////////////////////////////////////////// -/// @brief strng representation of a collection +/// @brief string representation of a collection //////////////////////////////////////////////////////////////////////////////// ArangoCollection.prototype.toString = function(seen, path, names, level) { @@ -563,6 +563,83 @@ ArangoCollection.prototype.toString = function(seen, path, names, level) { /// @} //////////////////////////////////////////////////////////////////////////////// +// ----------------------------------------------------------------------------- +// --SECTION-- skip-list helper +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup V8Shell +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief equal +//////////////////////////////////////////////////////////////////////////////// + +EQ = ModuleCache["/internal"].exports.EQ = function (value) { + return [ [ "==", value ] ]; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief less than +//////////////////////////////////////////////////////////////////////////////// + +LT = ModuleCache["/internal"].exports.LT = function (value) { + return [ [ "<", value ] ]; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief less than or equal +//////////////////////////////////////////////////////////////////////////////// + +LE = ModuleCache["/internal"].exports.LE = function (value) { + return [ [ "<=", value ] ]; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief greater than +//////////////////////////////////////////////////////////////////////////////// + +GT = ModuleCache["/internal"].exports.GT = function (value) { + return [ [ ">", value ] ]; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief greater than or equal +//////////////////////////////////////////////////////////////////////////////// + +GE = ModuleCache["/internal"].exports.GE = function (value) { + return [ [ ">=", value ] ]; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief range (left closed, right open) +//////////////////////////////////////////////////////////////////////////////// + +RANGE = ModuleCache["/internal"].exports.RANGE = function (left, right) { + return [ [ ">=", left ], [ "<", right ] ]; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief open range +//////////////////////////////////////////////////////////////////////////////// + +ORANGE = ModuleCache["/internal"].exports.ORANGE = function (left, right) { + return [ [ ">", left ], [ "<", right ] ]; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief closed range +//////////////////////////////////////////////////////////////////////////////// + +CRANGE = ModuleCache["/internal"].exports.CRANGE = function (left, right) { + return [ [ ">=", left ], [ "<=", right ] ]; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + // Local Variables: // mode: outline-minor // outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"