From 2dcc40e0ffd4c5ba3657b6969fcf5e015f03215c Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Tue, 10 Apr 2012 12:33:29 +0200 Subject: [PATCH] merge with SVN, fixed issue #43 --- BasicsC/voc-errors.c | 2 + BasicsC/voc-errors.h | 28 + ...api-collection-identifier-properties-sync} | 2 +- Doxygen/Examples.Durham/admin1 | 2 +- Doxygen/Examples.Durham/admin2 | 2 +- Makefile.files | 2 + Makefile.in | 26 +- PriorityQueue/pqueueindex.c | 1062 +++++++++++++++++ PriorityQueue/pqueueindex.h | 189 +++ PriorityQueue/priorityqueue.c | 584 +++++++++ PriorityQueue/priorityqueue.h | 204 ++++ ShapedJson/json-shaper.c | 9 +- ShapedJson/shaped-json.h | 5 - .../HttpInterface/api-collection_spec.rb | 22 +- V8/v8-vocbase.cpp | 366 +++++- V8Client/V8ClientConnection.cpp | 5 + V8Client/shell.cpp | 6 +- VocBase/index.c | 790 +++++++++++- VocBase/index.h | 68 ++ VocBase/query-where.h | 14 + VocBase/query.c | 217 +++- VocBase/query.h | 8 + VocBase/simple-collection.c | 225 +++- VocBase/simple-collection.h | 23 +- js/actions/system/api-collection.js | 50 +- js/client/client.js | 26 +- js/client/js-client.h | 26 +- js/common/bootstrap/errors.js | 2 + js/common/bootstrap/js-errors.h | 2 + 29 files changed, 3871 insertions(+), 96 deletions(-) rename Doxygen/Examples.AvocadoDB/{api-collection-identifier-parameter-sync => api-collection-identifier-properties-sync} (91%) create mode 100755 PriorityQueue/pqueueindex.c create mode 100755 PriorityQueue/pqueueindex.h create mode 100755 PriorityQueue/priorityqueue.c create mode 100755 PriorityQueue/priorityqueue.h diff --git a/BasicsC/voc-errors.c b/BasicsC/voc-errors.c index 3ecb865154..89d1e8e69d 100644 --- a/BasicsC/voc-errors.c +++ b/BasicsC/voc-errors.c @@ -107,6 +107,8 @@ void TRI_InitialiseErrorMessages (void) { REG_ERROR(SIMPLE_CLIENT_COULD_NOT_WRITE, "could not write to server"); REG_ERROR(SIMPLE_CLIENT_COULD_NOT_READ, "could not read from server"); REG_ERROR(ERROR_AVOCADO_INDEX_PQ_INSERT_FAILED, "priority queue insert failure"); + REG_ERROR(ERROR_AVOCADO_INDEX_PQ_REMOVE_FAILED, "priority queue remove failure"); + REG_ERROR(ERROR_AVOCADO_INDEX_PQ_REMOVE_ITEM_MISSING, "priority queue remove failure - item missing in index"); } //////////////////////////////////////////////////////////////////////////////// diff --git a/BasicsC/voc-errors.h b/BasicsC/voc-errors.h index 4d7ab3195c..33a6f30597 100644 --- a/BasicsC/voc-errors.h +++ b/BasicsC/voc-errors.h @@ -232,6 +232,12 @@ extern "C" { /// - 3100: @CODE{priority queue insert failure} /// Will be raised when an attempt to insert a document into a priority queue /// index fails for some reason. +/// - 3110: @CODE{priority queue remove failure} +/// Will be raised when an attempt to remove a document from a priority queue +/// index fails for some reason. +/// - 3111: @CODE{priority queue remove failure - item missing in index} +/// Will be raised when an attempt to remove a document from a priority queue +/// index fails when document can not be located within the index. //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -1234,6 +1240,28 @@ void TRI_InitialiseErrorMessages (void); #define TRI_ERROR_AVOCADO_INDEX_PQ_INSERT_FAILED (3100) +//////////////////////////////////////////////////////////////////////////////// +/// @brief 3110: ERROR_AVOCADO_INDEX_PQ_REMOVE_FAILED +/// +/// priority queue remove failure +/// +/// Will be raised when an attempt to remove a document from a priority queue +/// index fails for some reason. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_AVOCADO_INDEX_PQ_REMOVE_FAILED (3110) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 3111: ERROR_AVOCADO_INDEX_PQ_REMOVE_ITEM_MISSING +/// +/// priority queue remove failure - item missing in index +/// +/// Will be raised when an attempt to remove a document from a priority queue +/// index fails when document can not be located within the index. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_AVOCADO_INDEX_PQ_REMOVE_ITEM_MISSING (3111) + //////////////////////////////////////////////////////////////////////////////// /// @} diff --git a/Doxygen/Examples.AvocadoDB/api-collection-identifier-parameter-sync b/Doxygen/Examples.AvocadoDB/api-collection-identifier-properties-sync similarity index 91% rename from Doxygen/Examples.AvocadoDB/api-collection-identifier-parameter-sync rename to Doxygen/Examples.AvocadoDB/api-collection-identifier-properties-sync index c8fbcb06e6..f2f5ffb2c0 100644 --- a/Doxygen/Examples.AvocadoDB/api-collection-identifier-parameter-sync +++ b/Doxygen/Examples.AvocadoDB/api-collection-identifier-properties-sync @@ -1,4 +1,4 @@ -> curl --data @- -X PUT --dump - http://localhost:8529/_api/collection/70109828/parameter +> curl --data @- -X PUT --dump - http://localhost:8529/_api/collection/70109828/properties { "waitForSync" : true } HTTP/1.1 200 OK diff --git a/Doxygen/Examples.Durham/admin1 b/Doxygen/Examples.Durham/admin1 index 790c42d2d7..04eefeeb7d 100644 --- a/Doxygen/Examples.Durham/admin1 +++ b/Doxygen/Examples.Durham/admin1 @@ -1,4 +1,4 @@ -avocado> db.examples.parameter(); +avocado> db.examples.properties(); { "waitForSync" : false, "journalSize" : 134217728 diff --git a/Doxygen/Examples.Durham/admin2 b/Doxygen/Examples.Durham/admin2 index 4c1ddf22ba..5f99829e5d 100644 --- a/Doxygen/Examples.Durham/admin2 +++ b/Doxygen/Examples.Durham/admin2 @@ -1,4 +1,4 @@ -avocado> db.examples.parameter({ waitForSync : true }); +avocado> db.examples.properties({ waitForSync : true }); { "waitForSync" : true, "journalSize" : 134217728 diff --git a/Makefile.files b/Makefile.files index 94e17bff72..fb93ab46db 100644 --- a/Makefile.files +++ b/Makefile.files @@ -135,6 +135,8 @@ avocado_SOURCES = \ HttpsServer/HttpsAsyncCommTask.cpp \ HttpsServer/HttpsServer.cpp \ HttpsServer/HttpsServerImpl.cpp \ + PriorityQueue/pqueueindex.c \ + PriorityQueue/priorityqueue.c \ QL/ast-query.c \ QL/formatter.c \ QL/optimize.c \ diff --git a/Makefile.in b/Makefile.in index 024f4d6d78..7723b199d9 100644 --- a/Makefile.in +++ b/Makefile.in @@ -239,7 +239,9 @@ am_avocado_OBJECTS = Admin/ApplicationAdminServer.$(OBJEXT) \ HttpsServer/ApplicationHttpsServerImpl.$(OBJEXT) \ HttpsServer/HttpsAsyncCommTask.$(OBJEXT) \ HttpsServer/HttpsServer.$(OBJEXT) \ - HttpsServer/HttpsServerImpl.$(OBJEXT) QL/ast-query.$(OBJEXT) \ + HttpsServer/HttpsServerImpl.$(OBJEXT) \ + PriorityQueue/pqueueindex.$(OBJEXT) \ + PriorityQueue/priorityqueue.$(OBJEXT) QL/ast-query.$(OBJEXT) \ QL/formatter.$(OBJEXT) QL/optimize.$(OBJEXT) \ QL/parser.$(OBJEXT) QL/tokens.$(OBJEXT) \ RestHandler/RestActionHandler.$(OBJEXT) \ @@ -688,6 +690,8 @@ avocado_SOURCES = \ HttpsServer/HttpsAsyncCommTask.cpp \ HttpsServer/HttpsServer.cpp \ HttpsServer/HttpsServerImpl.cpp \ + PriorityQueue/pqueueindex.c \ + PriorityQueue/priorityqueue.c \ QL/ast-query.c \ QL/formatter.c \ QL/optimize.c \ @@ -1448,6 +1452,16 @@ HttpsServer/HttpsServer.$(OBJEXT): HttpsServer/$(am__dirstamp) \ HttpsServer/$(DEPDIR)/$(am__dirstamp) HttpsServer/HttpsServerImpl.$(OBJEXT): HttpsServer/$(am__dirstamp) \ HttpsServer/$(DEPDIR)/$(am__dirstamp) +PriorityQueue/$(am__dirstamp): + @$(MKDIR_P) PriorityQueue + @: > PriorityQueue/$(am__dirstamp) +PriorityQueue/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) PriorityQueue/$(DEPDIR) + @: > PriorityQueue/$(DEPDIR)/$(am__dirstamp) +PriorityQueue/pqueueindex.$(OBJEXT): PriorityQueue/$(am__dirstamp) \ + PriorityQueue/$(DEPDIR)/$(am__dirstamp) +PriorityQueue/priorityqueue.$(OBJEXT): PriorityQueue/$(am__dirstamp) \ + PriorityQueue/$(DEPDIR)/$(am__dirstamp) QL/$(am__dirstamp): @$(MKDIR_P) QL @: > QL/$(am__dirstamp) @@ -1744,6 +1758,8 @@ mostlyclean-compile: -rm -f Logger/LoggerInfo.$(OBJEXT) -rm -f Logger/LoggerStream.$(OBJEXT) -rm -f Logger/LoggerTiming.$(OBJEXT) + -rm -f PriorityQueue/pqueueindex.$(OBJEXT) + -rm -f PriorityQueue/priorityqueue.$(OBJEXT) -rm -f ProgramOptions/program-options.$(OBJEXT) -rm -f QL/ast-query.$(OBJEXT) -rm -f QL/formatter.$(OBJEXT) @@ -1944,6 +1960,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@Logger/$(DEPDIR)/LoggerInfo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@Logger/$(DEPDIR)/LoggerStream.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@Logger/$(DEPDIR)/LoggerTiming.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@PriorityQueue/$(DEPDIR)/pqueueindex.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@PriorityQueue/$(DEPDIR)/priorityqueue.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@ProgramOptions/$(DEPDIR)/program-options.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@QL/$(DEPDIR)/ast-query.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@QL/$(DEPDIR)/formatter.Po@am__quote@ @@ -2371,6 +2389,8 @@ distclean-generic: -rm -f JsonParserX/$(am__dirstamp) -rm -f Logger/$(DEPDIR)/$(am__dirstamp) -rm -f Logger/$(am__dirstamp) + -rm -f PriorityQueue/$(DEPDIR)/$(am__dirstamp) + -rm -f PriorityQueue/$(am__dirstamp) -rm -f ProgramOptions/$(DEPDIR)/$(am__dirstamp) -rm -f ProgramOptions/$(am__dirstamp) -rm -f QL/$(DEPDIR)/$(am__dirstamp) @@ -2419,7 +2439,7 @@ clean-am: clean-binPROGRAMS clean-generic clean-local \ distclean: distclean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -rf Admin/$(DEPDIR) ApplicationServer/$(DEPDIR) Basics/$(DEPDIR) BasicsC/$(DEPDIR) Dispatcher/$(DEPDIR) GeneralServer/$(DEPDIR) GeoIndex/$(DEPDIR) HashIndex/$(DEPDIR) HttpServer/$(DEPDIR) HttpsServer/$(DEPDIR) JsonParser/$(DEPDIR) JsonParserX/$(DEPDIR) Logger/$(DEPDIR) ProgramOptions/$(DEPDIR) QL/$(DEPDIR) Rest/$(DEPDIR) RestHandler/$(DEPDIR) RestServer/$(DEPDIR) ResultGenerator/$(DEPDIR) Scheduler/$(DEPDIR) ShapedJson/$(DEPDIR) SimpleHttpClient/$(DEPDIR) SkipLists/$(DEPDIR) UnitTests/$(DEPDIR) UnitTests/Jutland/$(DEPDIR) UnitTests/Philadelphia/$(DEPDIR) V8/$(DEPDIR) V8Client/$(DEPDIR) Variant/$(DEPDIR) VocBase/$(DEPDIR) + -rm -rf Admin/$(DEPDIR) ApplicationServer/$(DEPDIR) Basics/$(DEPDIR) BasicsC/$(DEPDIR) Dispatcher/$(DEPDIR) GeneralServer/$(DEPDIR) GeoIndex/$(DEPDIR) HashIndex/$(DEPDIR) HttpServer/$(DEPDIR) HttpsServer/$(DEPDIR) JsonParser/$(DEPDIR) JsonParserX/$(DEPDIR) Logger/$(DEPDIR) PriorityQueue/$(DEPDIR) ProgramOptions/$(DEPDIR) QL/$(DEPDIR) Rest/$(DEPDIR) RestHandler/$(DEPDIR) RestServer/$(DEPDIR) ResultGenerator/$(DEPDIR) Scheduler/$(DEPDIR) ShapedJson/$(DEPDIR) SimpleHttpClient/$(DEPDIR) SkipLists/$(DEPDIR) UnitTests/$(DEPDIR) UnitTests/Jutland/$(DEPDIR) UnitTests/Philadelphia/$(DEPDIR) V8/$(DEPDIR) V8Client/$(DEPDIR) Variant/$(DEPDIR) VocBase/$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-hdr distclean-tags @@ -2467,7 +2487,7 @@ installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache - -rm -rf Admin/$(DEPDIR) ApplicationServer/$(DEPDIR) Basics/$(DEPDIR) BasicsC/$(DEPDIR) Dispatcher/$(DEPDIR) GeneralServer/$(DEPDIR) GeoIndex/$(DEPDIR) HashIndex/$(DEPDIR) HttpServer/$(DEPDIR) HttpsServer/$(DEPDIR) JsonParser/$(DEPDIR) JsonParserX/$(DEPDIR) Logger/$(DEPDIR) ProgramOptions/$(DEPDIR) QL/$(DEPDIR) Rest/$(DEPDIR) RestHandler/$(DEPDIR) RestServer/$(DEPDIR) ResultGenerator/$(DEPDIR) Scheduler/$(DEPDIR) ShapedJson/$(DEPDIR) SimpleHttpClient/$(DEPDIR) SkipLists/$(DEPDIR) UnitTests/$(DEPDIR) UnitTests/Jutland/$(DEPDIR) UnitTests/Philadelphia/$(DEPDIR) V8/$(DEPDIR) V8Client/$(DEPDIR) Variant/$(DEPDIR) VocBase/$(DEPDIR) + -rm -rf Admin/$(DEPDIR) ApplicationServer/$(DEPDIR) Basics/$(DEPDIR) BasicsC/$(DEPDIR) Dispatcher/$(DEPDIR) GeneralServer/$(DEPDIR) GeoIndex/$(DEPDIR) HashIndex/$(DEPDIR) HttpServer/$(DEPDIR) HttpsServer/$(DEPDIR) JsonParser/$(DEPDIR) JsonParserX/$(DEPDIR) Logger/$(DEPDIR) PriorityQueue/$(DEPDIR) ProgramOptions/$(DEPDIR) QL/$(DEPDIR) Rest/$(DEPDIR) RestHandler/$(DEPDIR) RestServer/$(DEPDIR) ResultGenerator/$(DEPDIR) Scheduler/$(DEPDIR) ShapedJson/$(DEPDIR) SimpleHttpClient/$(DEPDIR) SkipLists/$(DEPDIR) UnitTests/$(DEPDIR) UnitTests/Jutland/$(DEPDIR) UnitTests/Philadelphia/$(DEPDIR) V8/$(DEPDIR) V8Client/$(DEPDIR) Variant/$(DEPDIR) VocBase/$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic diff --git a/PriorityQueue/pqueueindex.c b/PriorityQueue/pqueueindex.c new file mode 100755 index 0000000000..7647ffed3b --- /dev/null +++ b/PriorityQueue/pqueueindex.c @@ -0,0 +1,1062 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief priority queue index +/// +/// @file +/// +/// DISCLAIMER +/// +/// Copyright by triAGENS GmbH - All rights reserved. +/// +/// The Programs (which include both the software and documentation) +/// contain proprietary information of triAGENS GmbH; they are +/// provided under a license agreement containing restrictions on use and +/// disclosure and are also protected by copyright, patent and other +/// intellectual and industrial property laws. Reverse engineering, +/// disassembly or decompilation of the Programs, except to the extent +/// required to obtain interoperability with other independently created +/// software or as specified by law, is prohibited. +/// +/// The Programs are not intended for use in any nuclear, aviation, mass +/// transit, medical, or other inherently dangerous applications. It shall +/// be the licensee's responsibility to take all appropriate fail-safe, +/// backup, redundancy, and other measures to ensure the safe use of such +/// applications if the Programs are used for such purposes, and triAGENS +/// GmbH disclaims liability for any damages caused by such use of +/// the Programs. +/// +/// This software is the confidential and proprietary information of +/// triAGENS GmbH. You shall not disclose such confidential and +/// proprietary information and shall use it only in accordance with the +/// terms of the license agreement you entered into with triAGENS GmbH. +/// +/// Copyright holder is triAGENS GmbH, Cologne, Germany +/// +/// @author Dr. O +/// @author Copyright 2011, triagens GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + +#include "pqueueindex.h" +#include "ShapedJson/shaped-json.h" +#include "ShapedJson/json-shaper.h" +#include "VocBase/document-collection.h" +#include +#include + +// ----------------------------------------------------------------------------- +// --SECTION-- priority queue index some useful forward declarations +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup PriorityQueueIndex +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +// callbacks for the priority queue +static void ClearStoragePQIndex(TRI_pqueue_t*, void*); +static uint64_t GetStoragePQIndex(TRI_pqueue_t*, void*); +static bool IsLessPQIndex(TRI_pqueue_t*,void*, void*); +static void UpdateStoragePQIndex(TRI_pqueue_t*, void*, uint64_t); + + +// callbacks for the associative array +static void ClearElementPQIndex(TRI_associative_array_t*, void*); +static uint64_t HashKeyPQIndex(TRI_associative_array_t*, void*); +static uint64_t HashElementPQIndex(TRI_associative_array_t*, void*); +static bool IsEmptyElementPQIndex(TRI_associative_array_t*, void*); +static bool IsEqualElementElementPQIndex(TRI_associative_array_t*, void*, void*); +static bool IsEqualKeyElementPQIndex(TRI_associative_array_t*, void*, void*); + + +// comparison helpers +static int CompareShapedJsonShapedJson (const TRI_shaped_json_t* left, const TRI_shaped_json_t* right, + TRI_shaper_t* leftShaper, TRI_shaper_t* rightShaper); +static int CompareShapeTypes (const TRI_shaped_json_t* left, const TRI_shaped_json_t* right, + TRI_shaper_t* leftShaper, TRI_shaper_t* rightShaper); + +// ............................................................................... +// some internal error numbers which can be mapped later to global error numbers +// ............................................................................... +enum { + PQIndex_InvalidIndexError = -1, + PQIndex_InvalidElementError = -10, + + PQIndex_ElementMissingAssociativeArrayError = 1, + PQIndex_DuplicateElement = 10, + + PQIndex_RemoveInternalError = 1001 +} PQueueIndexErrors; + + + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +// ----------------------------------------------------------------------------- +// --SECTION-- priority queue index constructors and destructors +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup PriorityQueueIndex +/// @{ +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief removes any allocated memory internal to the index structure +//////////////////////////////////////////////////////////////////////////////// + +void PQueueIndex_destroy(PQIndex* idx) { + if (idx == NULL) { + return; + } + TRI_FreePQueue(idx->_pq); + TRI_FreeAssociativeArray(idx->_aa); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief destroy the index and frees any allocated memory +//////////////////////////////////////////////////////////////////////////////// + +void PQueueIndex_free(PQIndex* idx) { + if (idx == NULL) { + return; + } + PQueueIndex_destroy(idx); + TRI_Free(idx); +} + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief creates a priority queue index +//////////////////////////////////////////////////////////////////////////////// + + + +PQIndex* PQueueIndex_new (void) { + + PQIndex* idx; + bool ok; + char* hiddenStructure; + + // .......................................................................... + // Allocate the Priority Que Index + // .......................................................................... + + idx = TRI_Allocate(sizeof(PQIndex)); + if (idx == NULL) { + TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); + LOG_ERROR("out of memory when creating priority queue index"); + return NULL; + } + + + // .......................................................................... + // Allocate the priority que + // Remember to add any additional structure you need + // .......................................................................... + + idx->_pq = TRI_Allocate(sizeof(TRI_pqueue_t) + sizeof(void*)); + if (idx->_pq == NULL) { + TRI_Free(idx); + TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); + LOG_ERROR("out of memory when creating priority queue index"); + return NULL; + } + + + // .......................................................................... + // Allocate the associative array + // .......................................................................... + + idx->_aa = TRI_Allocate(sizeof(TRI_associative_array_t)); + if (idx->_aa == NULL) { + TRI_Free(idx); + TRI_Free(idx->_pq); + TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); + LOG_ERROR("out of memory when creating priority queue index"); + return NULL; + } + + + // .......................................................................... + // Initialise the priority que + // .......................................................................... + + ok = TRI_InitPQueue(idx->_pq, 100, sizeof(PQIndexElement), false, + ClearStoragePQIndex, + GetStoragePQIndex, + IsLessPQIndex, + UpdateStoragePQIndex); + if (! ok) { + TRI_Free(idx); + TRI_Free(idx->_pq); + TRI_Free(idx->_aa); + return NULL; + } + + + // .......................................................................... + // Initialise the associative array + // .......................................................................... + + TRI_InitAssociativeArray(idx->_aa, sizeof(PQIndexElement), + HashKeyPQIndex, HashElementPQIndex, + ClearElementPQIndex, + IsEmptyElementPQIndex, + IsEqualKeyElementPQIndex, + IsEqualElementElementPQIndex); + + + // .......................................................................... + // Add the associative array at the end of the pq so that we can access later + //memcpy((char*)(idx->_pq) + sizeof(TRI_pqueue_t),&(idx->_aa),sizeof(TRI_associative_array_t*)); + // .......................................................................... + + *((TRI_associative_array_t**)((char*)(idx->_pq) + sizeof(TRI_pqueue_t))) = idx->_aa; + + + return idx; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + + + +// ----------------------------------------------------------------------------- +// --SECTION-- Priority Queue Index public methods +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup PriorityQueueIndex +/// @{ +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief inserts an item into a priority queue +//////////////////////////////////////////////////////////////////////////////// + +int PQIndex_add(PQIndex* idx, PQIndexElement* element) { + + if (idx == NULL) { + return TRI_ERROR_INTERNAL; + } + + if (element == NULL) { + return TRI_ERROR_INTERNAL; + } + + // ........................................................................... + // Check if item is already added to the associative array + // ........................................................................... + + if (TRI_FindByKeyAssociativeArray(idx->_aa, element->data) != NULL) { + // attempt to add duplicate document to the priority queue + return TRI_ERROR_AVOCADO_INDEX_PQ_INSERT_FAILED; + } + + + // ........................................................................... + // Initialise the priority queue array storage pointer + // ........................................................................... + element->pqSlot = 0; + + // ........................................................................... + // Add item to associative array + // ........................................................................... + if (!TRI_InsertElementAssociativeArray(idx->_aa, element, false)) { + // can not add item to associative array -- give up on insert + return TRI_ERROR_AVOCADO_INDEX_PQ_INSERT_FAILED; + } + + + if (!idx->_pq->add(idx->_pq, element)) { + TRI_RemoveElementAssociativeArray(idx->_aa, element, NULL); + // can not add item to priority queue array -- give up on insert + return TRI_ERROR_AVOCADO_INDEX_PQ_INSERT_FAILED; + } + + return TRI_ERROR_NO_ERROR; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief inserts an item into a priority queue (same as add method above) +//////////////////////////////////////////////////////////////////////////////// + +int PQIndex_insert(PQIndex* idx, PQIndexElement* element) { + return PQIndex_add(idx, element); +} + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief removes an item from the priority queue (not necessarily the top most) +//////////////////////////////////////////////////////////////////////////////// + +int PQIndex_remove(PQIndex* idx, PQIndexElement* element) { + + PQIndexElement* item; + bool ok; + + if (idx == NULL) { + return TRI_ERROR_AVOCADO_INDEX_PQ_REMOVE_FAILED; + } + + if (element == NULL) { + return TRI_ERROR_AVOCADO_INDEX_PQ_REMOVE_FAILED; + } + + // ........................................................................... + // Check if item exists in the associative array. + // ........................................................................... + + item = TRI_FindByKeyAssociativeArray(idx->_aa, element->data); + if (item == NULL) { + return TRI_ERROR_AVOCADO_INDEX_PQ_REMOVE_ITEM_MISSING; + } + + + // ........................................................................... + // Remove item from the priority queue + // ........................................................................... + + ok = idx->_pq->remove(idx->_pq,item->pqSlot, true) && ok; + + + // ........................................................................... + // Remove item from associative array + // Must come after remove above, since update storage will be called. + // ........................................................................... + + ok = TRI_RemoveElementAssociativeArray(idx->_aa,item,NULL); + + + if (!ok) { + return TRI_ERROR_AVOCADO_INDEX_PQ_REMOVE_FAILED; + } + + return TRI_ERROR_NO_ERROR; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief returns the top most item without removing it from the queue +//////////////////////////////////////////////////////////////////////////////// + +PQIndexElements* PQIndex_top(PQIndex* idx, uint64_t numElements) { + + PQIndexElements* result; + PQIndexElements tempResult; + PQIndexElement* element; + uint64_t j; + bool ok; + uint64_t numCopied; + + + if (idx == NULL) { + return NULL; + } + + if (numElements < 1) { + return NULL; + } + + + // ............................................................................. + // Optimise for the common case where we remove only a single element + // ............................................................................. + + if (numElements == 1) { + result = TRI_Allocate(sizeof(PQIndexElements)); + if (result == NULL) { + TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); + return NULL; + } + result->_elements = TRI_Allocate(sizeof(PQIndexElement) * numElements); + if (result->_elements == NULL) { + TRI_Free(result); + TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); + return NULL; + } + result->_numElements = numElements; + result->_elements[0] = *((PQIndexElement*)(idx->_pq->top(idx->_pq))); + return result; + } + + + + // ............................................................................. + // Two or more elements are 'topped' + // ............................................................................. + + tempResult._elements = TRI_Allocate(sizeof(PQIndexElement) * numElements); + if (tempResult._elements == NULL) { + TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); + return NULL; + } + + ok = true; + numCopied = 0; + for (j = 0; j < numElements; ++j) { + element = (PQIndexElement*)(idx->_pq->top(idx->_pq)); + if (element == NULL) { + break; + } + + + tempResult._elements[j] = *element; + ok = idx->_pq->remove(idx->_pq,element->pqSlot, false); + if (!ok) { + break; + } + ++numCopied; + } + + + result = TRI_Allocate(sizeof(PQIndexElements)); + if (result == NULL) { + TRI_Free(tempResult._elements); + TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); + return NULL; + } + + result->_elements = TRI_Allocate(sizeof(PQIndexElement) * numCopied); + if (result->_elements == NULL) { + TRI_Free(tempResult._elements); + TRI_Free(result); + TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); + return NULL; + } + + result->_numElements = numCopied; + + for (j = 0; j < numCopied; ++j) { + result->_elements[j] = tempResult._elements[j]; + result->_elements[j].pqSlot = 0; + idx->_pq->add(idx->_pq, &(result->_elements[j])); + } + + TRI_Free(tempResult._elements); + + return result; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief removes an item and inserts a new item +//////////////////////////////////////////////////////////////////////////////// + +bool PQIndex_update(PQIndex* idx, const PQIndexElement* oldElement, const PQIndexElement* newElement) { + assert(false); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + + + + + +// ----------------------------------------------------------------------------- +// --SECTION-- priority queue index implementation of callbacks +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup PriorityQueueIndex +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +// ............................................................................. +// callbacks for the priority queue +// ............................................................................. + + +static void ClearStoragePQIndex(TRI_pqueue_t* pq, void* item) { + PQIndexElement* element; + + element = (PQIndexElement*)(item); + if (element == 0) { + return; + } + TRI_Free(element->fields); + return; +} + + +static uint64_t GetStoragePQIndex(TRI_pqueue_t* pq, void* item) { + PQIndexElement* element; + + element = (PQIndexElement*)(item); + if (element == 0) { + return 0; + } + return element->pqSlot; +} + + +// ............................................................................. +// True if the leftItem is less than the rightItem +// ............................................................................. + +static bool IsLessPQIndex(TRI_pqueue_t* pq, void* leftItem, void* rightItem) { + size_t maxNumFields; + PQIndexElement* leftElement = (PQIndexElement*)(leftItem); + PQIndexElement* rightElement = (PQIndexElement*)(rightItem); + TRI_shaper_t* leftShaper; + TRI_shaper_t* rightShaper; + size_t j; + int compareResult; + + if (leftElement == NULL && rightElement == NULL) { + return false; + } + + if (leftElement == NULL && rightElement != NULL) { + return true; + } + + if (leftElement != NULL && rightElement == NULL) { + return false; + } + + if (leftElement == rightElement) { + return false; + } + + // ............................................................................ + // The document could be the same -- so no further comparison is required. + // ............................................................................ + if (leftElement->data == rightElement->data) { + return false; + } + + if (leftElement->numFields < rightElement->numFields) { + maxNumFields = leftElement->numFields; + } + else { + maxNumFields = rightElement->numFields; + } + + leftShaper = ((TRI_doc_collection_t*)(leftElement->collection))->_shaper; + rightShaper = ((TRI_doc_collection_t*)(rightElement->collection))->_shaper; + + compareResult = 0; + + leftShaper->lookupShapeId(leftShaper, (leftElement->fields)->_sid); + + for (j = 0; j < maxNumFields; j++) { + /* + printf("%s:%u:%f:%f,%u:%u\n",__FILE__,__LINE__, + *((double*)((j + leftElement->fields)->_data.data)), + *((double*)((j + rightElement->fields)->_data.data)), + (uint64_t)(leftElement->data), + (uint64_t)(rightElement->data) + ); + */ + compareResult = CompareShapedJsonShapedJson((j + leftElement->fields), + (j + rightElement->fields), + leftShaper, rightShaper); + if (compareResult != 0) { + break; + } + } + + if (compareResult < 0) { + return true; + } + + return false; +} + + +static void UpdateStoragePQIndex(TRI_pqueue_t* pq, void* item, uint64_t position) { + PQIndexElement* element; + TRI_associative_array_t* aa; + + element = (PQIndexElement*)(item); + if (element == 0) { + LOG_ERROR("invalid priority queue element received"); + return; + } + + element->pqSlot = position; + + // ........................................................................... + // Since the items stored in the hash array are pointers, we must update these + // as well. The associative array is stored at the end of the Priority Queue + // structure. + // ........................................................................... + aa = *((TRI_associative_array_t**)((char*)(pq) + sizeof(TRI_pqueue_t))); + element = (PQIndexElement*)(TRI_FindByElementAssociativeArray(aa, item)); + if (element == 0) { + LOG_ERROR("invalid priority queue/ associative array element received"); + return; + } + element->pqSlot = position; +} + + +// ............................................................................. +// callbacks for the associative array +// ............................................................................. + + +static void ClearElementPQIndex(TRI_associative_array_t* aa, void* item) { + if (item == NULL) { + return; + } + memset(item, 0, sizeof(PQIndexElement)); +} + + +static uint64_t HashKeyPQIndex(TRI_associative_array_t* aa, void* key) { + uint64_t hash; + + hash = TRI_FnvHashBlockInitial(); + hash = TRI_FnvHashBlock(hash, key, sizeof(void*)); + + return hash; +} + + +static uint64_t HashElementPQIndex(TRI_associative_array_t* aa, void* item) { + PQIndexElement* element; + uint64_t hash; + + element = (PQIndexElement*)(item); + if (element == 0) { + return 0; + } + + hash = TRI_FnvHashBlockInitial(); + hash = TRI_FnvHashBlock(hash, element->data, sizeof(void*)); + + return hash; +} + + +static bool IsEmptyElementPQIndex(TRI_associative_array_t* aa, void* item) { + PQIndexElement* element; + + if (item == NULL) { + // should never happen + return false; + } + + element = (PQIndexElement*)(item); + if (element->data == NULL) { + return true; + } + return false; +} + + +static bool IsEqualElementElementPQIndex(TRI_associative_array_t* aa, void* leftItem, void* rightItem) { + PQIndexElement* leftElement; + PQIndexElement* rightElement; + + if (leftItem == NULL || rightItem == NULL) { + // should never happen + return false; + } + + leftElement = (PQIndexElement*)(leftItem); + rightElement = (PQIndexElement*)(rightItem); + if (leftElement->data == rightElement->data) { + return true; + } + return false; +} + + +static bool IsEqualKeyElementPQIndex(TRI_associative_array_t* aa, void* key, void* item) { + PQIndexElement* element; + + if (item == NULL) { + return false; // should never happen + } + element = (PQIndexElement*)(item); + if (element->data == key) { + return true; + } + return false; +} + + +// ............................................................................. +// implementation of compare functions +// ............................................................................. + +static int CompareShapeTypes (const TRI_shaped_json_t* left, const TRI_shaped_json_t* right, TRI_shaper_t* leftShaper, TRI_shaper_t* rightShaper) { + + int result; + size_t j; + TRI_shape_type_t leftType; + TRI_shape_type_t rightType; + const TRI_shape_t* leftShape; + const TRI_shape_t* rightShape; + size_t leftListLength; + size_t rightListLength; + size_t listLength; + TRI_shaped_json_t leftElement; + TRI_shaped_json_t rightElement; + char* leftString; + char* rightString; + + + leftShape = leftShaper->lookupShapeId(leftShaper, left->_sid); + rightShape = rightShaper->lookupShapeId(rightShaper, right->_sid); + leftType = leftShape->_type; + rightType = rightShape->_type; + + switch (leftType) { + + case TRI_SHAPE_ILLEGAL: { + switch (rightType) { + case TRI_SHAPE_ILLEGAL: + { + return 0; + } + case TRI_SHAPE_NULL: + case TRI_SHAPE_BOOLEAN: + case TRI_SHAPE_NUMBER: + case TRI_SHAPE_SHORT_STRING: + case TRI_SHAPE_LONG_STRING: + case TRI_SHAPE_ARRAY: + case TRI_SHAPE_LIST: + case TRI_SHAPE_HOMOGENEOUS_LIST: + case TRI_SHAPE_HOMOGENEOUS_SIZED_LIST: + { + return -1; + } + } // end of switch (rightType) + } + + case TRI_SHAPE_NULL: { + switch (rightType) { + case TRI_SHAPE_ILLEGAL: + { + return 1; + } + case TRI_SHAPE_NULL: + { + return 0; + } + case TRI_SHAPE_BOOLEAN: + case TRI_SHAPE_NUMBER: + case TRI_SHAPE_SHORT_STRING: + case TRI_SHAPE_LONG_STRING: + case TRI_SHAPE_ARRAY: + case TRI_SHAPE_LIST: + case TRI_SHAPE_HOMOGENEOUS_LIST: + case TRI_SHAPE_HOMOGENEOUS_SIZED_LIST: + { + return -1; + } + } // end of switch (rightType) + } + + case TRI_SHAPE_BOOLEAN: { + switch (rightType) { + case TRI_SHAPE_ILLEGAL: + case TRI_SHAPE_NULL: + { + return 1; + } + case TRI_SHAPE_BOOLEAN: + { + // check which is false and which is true! + if ( *((TRI_shape_boolean_t*)(left->_data.data)) == *((TRI_shape_boolean_t*)(right->_data.data)) ) { + return 0; + } + if ( *((TRI_shape_boolean_t*)(left->_data.data)) < *((TRI_shape_boolean_t*)(right->_data.data)) ) { + return -1; + } + return 1; + } + case TRI_SHAPE_NUMBER: + case TRI_SHAPE_SHORT_STRING: + case TRI_SHAPE_LONG_STRING: + case TRI_SHAPE_ARRAY: + case TRI_SHAPE_LIST: + case TRI_SHAPE_HOMOGENEOUS_LIST: + case TRI_SHAPE_HOMOGENEOUS_SIZED_LIST: + { + return -1; + } + } // end of switch (rightType) + } + + case TRI_SHAPE_NUMBER: { + switch (rightType) { + case TRI_SHAPE_ILLEGAL: + case TRI_SHAPE_NULL: + case TRI_SHAPE_BOOLEAN: + { + return 1; + } + case TRI_SHAPE_NUMBER: + { + // compare the numbers. + if ( *((TRI_shape_number_t*)(left->_data.data)) == *((TRI_shape_number_t*)(right->_data.data)) ) { + return 0; + } + if ( *((TRI_shape_number_t*)(left->_data.data)) < *((TRI_shape_number_t*)(right->_data.data)) ) { + return -1; + } + return 1; + } + case TRI_SHAPE_SHORT_STRING: + case TRI_SHAPE_LONG_STRING: + case TRI_SHAPE_ARRAY: + case TRI_SHAPE_LIST: + case TRI_SHAPE_HOMOGENEOUS_LIST: + case TRI_SHAPE_HOMOGENEOUS_SIZED_LIST: + { + return -1; + } + } // end of switch (rightType) + } + + case TRI_SHAPE_SHORT_STRING: + case TRI_SHAPE_LONG_STRING: + { + switch (rightType) { + case TRI_SHAPE_ILLEGAL: + case TRI_SHAPE_NULL: + case TRI_SHAPE_BOOLEAN: + case TRI_SHAPE_NUMBER: + { + return 1; + } + case TRI_SHAPE_SHORT_STRING: + case TRI_SHAPE_LONG_STRING: + { + // compare strings + // extract the strings + if (leftType == TRI_SHAPE_SHORT_STRING) { + leftString = (char*)(sizeof(TRI_shape_length_short_string_t) + left->_data.data); + } + else { + leftString = (char*)(sizeof(TRI_shape_length_long_string_t) + left->_data.data); + } + + if (rightType == TRI_SHAPE_SHORT_STRING) { + rightString = (char*)(sizeof(TRI_shape_length_short_string_t) + right->_data.data); + } + else { + rightString = (char*)(sizeof(TRI_shape_length_long_string_t) + right->_data.data); + } + + result = strcmp(leftString,rightString); + return result; + } + case TRI_SHAPE_ARRAY: + case TRI_SHAPE_LIST: + case TRI_SHAPE_HOMOGENEOUS_LIST: + case TRI_SHAPE_HOMOGENEOUS_SIZED_LIST: + { + return -1; + } + } // end of switch (rightType) + } + + case TRI_SHAPE_HOMOGENEOUS_LIST: + case TRI_SHAPE_HOMOGENEOUS_SIZED_LIST: + case TRI_SHAPE_LIST: + { + switch (rightType) { + case TRI_SHAPE_ILLEGAL: + case TRI_SHAPE_NULL: + case TRI_SHAPE_BOOLEAN: + case TRI_SHAPE_NUMBER: + case TRI_SHAPE_SHORT_STRING: + case TRI_SHAPE_LONG_STRING: + { + return 1; + } + case TRI_SHAPE_HOMOGENEOUS_LIST: + case TRI_SHAPE_HOMOGENEOUS_SIZED_LIST: + case TRI_SHAPE_LIST: + { + // unfortunately recursion: check the types of all the entries + leftListLength = *((TRI_shape_length_list_t*)(left->_data.data)); + rightListLength = *((TRI_shape_length_list_t*)(right->_data.data)); + + // determine the smallest list + if (leftListLength > rightListLength) { + listLength = rightListLength; + } + else { + listLength = leftListLength; + } + + for (j = 0; j < listLength; ++j) { + + if (leftType == TRI_SHAPE_HOMOGENEOUS_LIST) { + TRI_AtHomogeneousListShapedJson((const TRI_homogeneous_list_shape_t*)(leftShape), + left,j,&leftElement); + } + else if (leftType == TRI_SHAPE_HOMOGENEOUS_SIZED_LIST) { + TRI_AtHomogeneousSizedListShapedJson((const TRI_homogeneous_sized_list_shape_t*)(leftShape), + left,j,&leftElement); + } + else { + TRI_AtListShapedJson((const TRI_list_shape_t*)(leftShape),left,j,&leftElement); + } + + + if (rightType == TRI_SHAPE_HOMOGENEOUS_LIST) { + TRI_AtHomogeneousListShapedJson((const TRI_homogeneous_list_shape_t*)(rightShape), + right,j,&rightElement); + } + else if (rightType == TRI_SHAPE_HOMOGENEOUS_SIZED_LIST) { + TRI_AtHomogeneousSizedListShapedJson((const TRI_homogeneous_sized_list_shape_t*)(rightShape), + right,j,&rightElement); + } + else { + TRI_AtListShapedJson((const TRI_list_shape_t*)(rightShape),right,j,&rightElement); + } + + result = CompareShapeTypes (&leftElement, &rightElement, leftShaper, rightShaper); + if (result != 0) { + return result; + } + } + + // up to listLength everything matches + if (leftListLength < rightListLength) { + return -1; + } + else if (leftListLength > rightListLength) { + return 1; + } + return 0; + } + + + case TRI_SHAPE_ARRAY: + { + return -1; + } + } // end of switch (rightType) + } + + case TRI_SHAPE_ARRAY: + { + /* start oreste: + char* shape = (char*)(leftShape); + uint64_t fixedEntries; + uint64_t variableEntries; + uint64_t ssid; + uint64_t aaid; + char* name; + TRI_shape_t* newShape; + + shape = shape + sizeof(TRI_shape_t); + fixedEntries = *((TRI_shape_size_t*)(shape)); + shape = shape + sizeof(TRI_shape_size_t); + variableEntries = *((TRI_shape_size_t*)(shape)); + shape = shape + sizeof(TRI_shape_size_t); + ssid = *((TRI_shape_sid_t*)(shape)); + shape = shape + (sizeof(TRI_shape_sid_t) * (fixedEntries + variableEntries)); + aaid = *((TRI_shape_aid_t*)(shape)); + shape = shape + (sizeof(TRI_shape_aid_t) * (fixedEntries + variableEntries)); + + name = leftShaper->lookupAttributeId(leftShaper,aaid); + newShape = leftShaper->lookupShapeId(leftShaper, ssid); + + + printf("%s:%u:_fixedEntries:%u\n",__FILE__,__LINE__,fixedEntries); + printf("%s:%u:_variableEntries:%u\n",__FILE__,__LINE__,variableEntries); + printf("%s:%u:_sids[0]:%u\n",__FILE__,__LINE__,ssid); + printf("%s:%u:_aids[0]:%u\n",__FILE__,__LINE__,aaid); + printf("%s:%u:name:%s\n",__FILE__,__LINE__,name); + printf("%s:%u:type:%d\n",__FILE__,__LINE__,newShape->_type); + + end oreste */ + assert(false); + switch (rightType) { + case TRI_SHAPE_ILLEGAL: + case TRI_SHAPE_NULL: + case TRI_SHAPE_BOOLEAN: + case TRI_SHAPE_NUMBER: + case TRI_SHAPE_SHORT_STRING: + case TRI_SHAPE_LONG_STRING: + case TRI_SHAPE_HOMOGENEOUS_LIST: + case TRI_SHAPE_HOMOGENEOUS_SIZED_LIST: + case TRI_SHAPE_LIST: + { + return 1; + } + case TRI_SHAPE_ARRAY: + { + assert(false); + result = 0; + return result; + } + } // end of switch (rightType) + } + + } + assert(false); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Compare a shapded json object recursively if necessary +//////////////////////////////////////////////////////////////////////////////// + +static int CompareShapedJsonShapedJson (const TRI_shaped_json_t* left, const TRI_shaped_json_t* right, TRI_shaper_t* leftShaper, TRI_shaper_t* rightShaper) { + + int result; + + // ............................................................................ + // the following order is currently defined for placing an order on documents + // undef < null < boolean < number < strings < lists < hash arrays + // note: undefined will be treated as NULL pointer not NULL JSON OBJECT + // within each type class we have the following order + // boolean: false < true + // number: natural order + // strings: lexicographical + // lists: lexicorgraphically and within each slot according to these rules. + // ............................................................................ + + + if (left == NULL && right == NULL) { + return 0; + } + + if (left == NULL && right != NULL) { + return -1; + } + + if (left != NULL && right == NULL) { + return 1; + } + + result = CompareShapeTypes (left, right, leftShaper, rightShaper); + + return result; + +} // end of function CompareShapedJsonShapedJson + + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +// Local Variables: +// mode: outline-minor +// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" +// End: + + diff --git a/PriorityQueue/pqueueindex.h b/PriorityQueue/pqueueindex.h new file mode 100755 index 0000000000..6175a98c4a --- /dev/null +++ b/PriorityQueue/pqueueindex.h @@ -0,0 +1,189 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief priority queue index +/// +/// @file +/// +/// DISCLAIMER +/// +/// Copyright by triAGENS GmbH - All rights reserved. +/// +/// The Programs (which include both the software and documentation) +/// contain proprietary information of triAGENS GmbH; they are +/// provided under a license agreement containing restrictions on use and +/// disclosure and are also protected by copyright, patent and other +/// intellectual and industrial property laws. Reverse engineering, +/// disassembly or decompilation of the Programs, except to the extent +/// required to obtain interoperability with other independently created +/// software or as specified by law, is prohibited. +/// +/// The Programs are not intended for use in any nuclear, aviation, mass +/// transit, medical, or other inherently dangerous applications. It shall +/// be the licensee's responsibility to take all appropriate fail-safe, +/// backup, redundancy, and other measures to ensure the safe use of such +/// applications if the Programs are used for such purposes, and triAGENS +/// GmbH disclaims liability for any damages caused by such use of +/// the Programs. +/// +/// This software is the confidential and proprietary information of +/// triAGENS GmbH. You shall not disclose such confidential and +/// proprietary information and shall use it only in accordance with the +/// terms of the license agreement you entered into with triAGENS GmbH. +/// +/// Copyright holder is triAGENS GmbH, Cologne, Germany +/// +/// @author Dr. O +/// @author Copyright 2011, triagens GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + +#ifndef TRIAGENS_DURHAM_VOC_BASE_PRIORITY_QUEUE_INDEX_H +#define TRIAGENS_DURHAM_VOC_BASE_PRIORITY_QUEUE_INDEX_H 1 + +#include +#include "PriorityQueue/priorityqueue.h" +#include "ShapedJson/shaped-json.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +// ----------------------------------------------------------------------------- +// --SECTION-- priority queue index public types +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup PriorityQueueIndex +/// @{ +//////////////////////////////////////////////////////////////////////////////// + + +// ............................................................................... +// Define the structure of a priority queue index +// Currently the priority queue defines its own storage for the position integer +// into the priority queue array. That is, we do not store a 'hidden' attribute +// in the doc. +// ............................................................................... + +typedef struct { + TRI_pqueue_t* _pq; // the actual priority queue + TRI_associative_array_t* _aa; // storage for the pointer into the pq array +} PQIndex; + +// ............................................................................... +// Currently only support one shaped_json field (attribute) of the type 'number' +// Can extend later +// ............................................................................... + +typedef struct { + size_t numFields; // the number of fields + TRI_shaped_json_t* fields; // list of shaped json objects which the collection should know about + void* data; // master document pointer + void* collection; // pointer to the collection; + uint64_t pqSlot; // int pointer to the position in the pq array +} PQIndexElement; + + +typedef struct { + size_t _numElements; + PQIndexElement* _elements; // simple list of elements +} PQIndexElements; + + + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + + + +// ----------------------------------------------------------------------------- +// --SECTION-- Priority Queue Index constructors and destructors +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup PriorityQueueIndex +/// @{ +//////////////////////////////////////////////////////////////////////////////// + + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief reclaims memory allocated for the index, releasing the Priority +/// Queue storage and Associative Array storage. +//////////////////////////////////////////////////////////////////////////////// + +void PQueueIndex_destroy (PQIndex*); + +void PQueueIndex_free (PQIndex*); + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief initialises the index +//////////////////////////////////////////////////////////////////////////////// + +PQIndex* PQueueIndex_new (void); + + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + + + +// ----------------------------------------------------------------------------- +// --SECTION-- Priority Queue Index public methods +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup PriorityQueueIndex +/// @{ +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief inserts an item into a priority queue +//////////////////////////////////////////////////////////////////////////////// + +int PQIndex_add (PQIndex*, PQIndexElement*); + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief inserts an item into a priority queue (same as add method above) +//////////////////////////////////////////////////////////////////////////////// + +int PQIndex_insert (PQIndex*, PQIndexElement*); + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief removes an item from the priority queue (not necessarily the top most) +//////////////////////////////////////////////////////////////////////////////// + +int PQIndex_remove (PQIndex*, PQIndexElement*); + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief returns the top most item without removing it from the queue +//////////////////////////////////////////////////////////////////////////////// + +PQIndexElements* PQIndex_top (PQIndex*, uint64_t); + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief removes an item and inserts a new item +//////////////////////////////////////////////////////////////////////////////// + +bool PQIndex_update (PQIndex*, const PQIndexElement*, const PQIndexElement*); + + + +#ifdef __cplusplus +} +#endif + +#endif + +// Local Variables: +// mode: outline-minor +// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" +// End: + diff --git a/PriorityQueue/priorityqueue.c b/PriorityQueue/priorityqueue.c new file mode 100755 index 0000000000..b8c4865bf5 --- /dev/null +++ b/PriorityQueue/priorityqueue.c @@ -0,0 +1,584 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief priorty queue +/// +/// @file +/// +/// +/// DISCLAIMER +/// +/// Copyright by triAGENS GmbH - All rights reserved. +/// +/// The Programs (which include both the software and documentation) +/// contain proprietary information of triAGENS GmbH; they are +/// provided under a license agreement containing restrictions on use and +/// disclosure and are also protected by copyright, patent and other +/// intellectual and industrial property laws. Reverse engineering, +/// disassembly or decompilation of the Programs, except to the extent +/// required to obtain interoperability with other independently created +/// software or as specified by law, is prohibited. +/// +/// The Programs are not intended for use in any nuclear, aviation, mass +/// transit, medical, or other inherently dangerous applications. It shall +/// be the licensee's responsibility to take all appropriate fail-safe, +/// backup, redundancy, and other measures to ensure the safe use of such +/// applications if the Programs are used for such purposes, and triAGENS +/// GmbH disclaims liability for any damages caused by such use of +/// the Programs. +/// +/// This software is the confidential and proprietary information of +/// triAGENS GmbH. You shall not disclose such confidential and +/// proprietary information and shall use it only in accordance with the +/// terms of the license agreement you entered into with triAGENS GmbH. +/// +/// Copyright holder is triAGENS GmbH, Cologne, Germany +/// +/// @author Dr. Frank Celler +/// @author Dr. O +/// @author Martin Schoenert +/// @author Copyright 2009-2012, triagens GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + + +#include "priorityqueue.h" +#include "ShapedJson/shaped-json.h" +#include + +// ----------------------------------------------------------------------------- +// --SECTION-- useful forward declarations +// ----------------------------------------------------------------------------- + +/* +oreste's debug only +typedef struct { + size_t numFields; // the number of fields + TRI_shaped_json_t* fields; // list of shaped json objects which the collection should know about + void* data; // master document pointer + void* collection; // pointer to the collection; + uint64_t pqSlot; // int pointer to the position in the pq array +} xx; +*/ + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup PriorityQueue +/// @{ +//////////////////////////////////////////////////////////////////////////////// +static bool AddPQueue (TRI_pqueue_t*, void*); +static bool CheckPQSize (TRI_pqueue_t*); +static bool CompareIsLess (TRI_pqueue_t*, void*, void*); +static bool FixPQ (TRI_pqueue_t*, uint64_t); +static char* GetItemAddress (TRI_pqueue_t*, uint64_t); +static bool RemovePQueue (TRI_pqueue_t*, uint64_t, bool); +static void* TopPQueue (TRI_pqueue_t*); + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +// ----------------------------------------------------------------------------- +// --SECTION-- priority queue constructors and destructors +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup PriorityQueue +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief initialises a priority queue +//////////////////////////////////////////////////////////////////////////////// + +bool TRI_InitPQueue (TRI_pqueue_t* pq, size_t initialCapacity, size_t itemSize, bool reverse, + void (*clearStorage) (struct TRI_pqueue_s*, void*), + uint64_t (*getStorage) (struct TRI_pqueue_s*, void*), + bool (*isLess) (struct TRI_pqueue_s*, void*, void*), + void (*updateStorage) (struct TRI_pqueue_s*, void*, uint64_t pos)) { + + if (pq == NULL) { + return false; + } + + // .......................................................................... + // Assign the call back functions + // .......................................................................... + + + // .......................................................................... + // This callback is used to remove any memory which may be used as part of + // the storage within the array _items. Callback required since we do not + // know if there is any internal structure. + // .......................................................................... + pq->clearStoragePQ = clearStorage; + + + // .......................................................................... + // Returns the position within the _items array the element is. + // Currently this simply is used to perform a consistency check. + // .......................................................................... + pq->getStoragePQ = getStorage; + + + // .......................................................................... + // The actual comparison function which returns true if left item is + // less than right item (otherwise false). + // .......................................................................... + pq->isLessPQ = isLess; + + + // .......................................................................... + // Stores the position of the element within the _items array. Its purpose + // is to allow the storage position to be located independent of the + // priority queue _items array. + // .......................................................................... + pq->updateStoragePQ = updateStorage; + + + // .......................................................................... + // Assign the element size + // .......................................................................... + pq->_base._itemSize = itemSize; + + + // .......................................................................... + // Initialise invalid access counters + // .......................................................................... + pq->_base._nrFalseRemoves = 0; + pq->_base._nrFalseAdds = 0; + + + // .......................................................................... + // Set the capacity and assign memeory for storage + // .......................................................................... + pq->_base._capacity = initialCapacity; + pq->_base._items = TRI_Allocate(pq->_base._itemSize * pq->_base._capacity); + if (pq->_base._items == NULL) { + TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); + LOG_ERROR("out of memory when creating priority queue storage"); + return false; + } + + // .......................................................................... + // Initialise the memory allcoated for the storage of pq (0 filled) + // .......................................................................... + + memset(pq->_base._items, 0, pq->_base._itemSize * pq->_base._capacity); + + + // .......................................................................... + // initialise the number of items stored + // .......................................................................... + pq->_base._count = 0; + + // .......................................................................... + // Determines if the pq should be reversed + // .......................................................................... + pq->_base._reverse = reverse; + + + // .......................................................................... + // The static call back functions to query, modifiy the pq + // .......................................................................... + pq->add = AddPQueue; + pq->remove = RemovePQueue; + pq->top = TopPQueue; + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief destroys a priority queue, but does not free the pointer +//////////////////////////////////////////////////////////////////////////////// + +void TRI_DestroyPQueue(TRI_pqueue_t* pq) { + size_t j; + void* thisItem; + + if (pq == NULL) { + return; + } + + for (j = 0; j < pq->_base._count; ++j) { + thisItem = (j * pq->_base._itemSize) + pq->_base._items; + pq->clearStoragePQ(pq,thisItem); + } + TRI_Free(pq->_base._items); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief destroys a priority queue and frees the pointer +//////////////////////////////////////////////////////////////////////////////// + +void TRI_FreePQueue(TRI_pqueue_t* pq) { + if (pq == NULL) { + return; + } + TRI_DestroyPQueue(pq); + TRI_Free(pq); +} + + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + + + +// ----------------------------------------------------------------------------- +// --SECTION-- priority queue callback functions +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup PriorityQueue +/// @{ +//////////////////////////////////////////////////////////////////////////////// + + + + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief inserts an item into the priority queue +//////////////////////////////////////////////////////////////////////////////// + +static bool AddPQueue(TRI_pqueue_t* pq, void* item) { + size_t k; + + + // ........................................................................... + // Some basic checks for consistency + // ........................................................................... + + if (pq == NULL) { + return false; + } + + if (pq->getStoragePQ(pq,item) != 0) { + pq->_base._nrFalseAdds++; + } + + + // ........................................................................... + // handle case that pq is too small + // ........................................................................... + + if (!CheckPQSize(pq)) { + return false; + } + + + // ........................................................................... + // increase the number of items in the queue + // ........................................................................... + + pq->_base._count++; + + + // ........................................................................... + // add the item to the end + // ........................................................................... + k = (pq->_base._count - 1) * pq->_base._itemSize; + memcpy( k + pq->_base._items, item, pq->_base._itemSize); + + + // ........................................................................... + // call back so that the item can store the position of the entry into the + // pq array back into the document (row, whatever). + // ........................................................................... + pq->updateStoragePQ(pq, k + pq->_base._items, pq->_base._count); + + + // ........................................................................... + // and fix the priority queue (re-sort) + // ........................................................................... + FixPQ(pq, pq->_base._count); + + /* + for (k = 0; k < pq->_base._count; ++k) { + tt = (xx*)( (k * pq->_base._itemSize) + pq->_base._items); + printf("%s:%u:zzzzzzzzzzzzzzzzzzzzzz:%f:%u;%u\n",__FILE__,__LINE__, + *((double*)((tt->fields)->_data.data)), + tt->pqSlot, + tt->numFields); + } + */ + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief rmeoves an item from the pq -- needs the position +//////////////////////////////////////////////////////////////////////////////// + +static bool RemovePQueue(TRI_pqueue_t* pq, uint64_t position, bool destroyItem) { + + char* lastItem; + char* thisItem; + + if (pq == NULL) { + return false; + } + + + // ........................................................................... + // Check that the position sent is valid + // ........................................................................... + + if (position == 0 || position > pq->_base._count) { + pq->_base._nrFalseRemoves++; + return false; + } + + + // ........................................................................... + // obtain the pointer positions + // ........................................................................... + + thisItem = ((position - 1) * pq->_base._itemSize) + pq->_base._items; + lastItem = ((pq->_base._count - 1) * pq->_base._itemSize) + pq->_base._items; + + + // ........................................................................... + // Set the position in the priority queue array back in the document + // ........................................................................... + + pq->updateStoragePQ(pq, thisItem, 0); + if (destroyItem) { + pq->clearStoragePQ(pq,thisItem); + } + + + // ........................................................................... + // perhaps we are lucky and the item to be removed is at the end of queue? + // ........................................................................... + + if (position == pq->_base._count) { + memset(thisItem, 0, pq->_base._itemSize); + pq->_base._count--; + return true; + } + + + // ........................................................................... + // No such luck - so work a little harder. + // ........................................................................... + + memcpy(thisItem, lastItem, pq->_base._itemSize); + memset(lastItem, 0, pq->_base._itemSize); + pq->_base._count--; + FixPQ(pq,position); + + return true; +} + + + + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief returns the top most item in the priority queue +//////////////////////////////////////////////////////////////////////////////// + +static void* TopPQueue(TRI_pqueue_t* pq) { + + if ( (pq == NULL) || (pq->_base._count == 0) ) { + return NULL; + } + + return (pq->_base._items); +} + + + + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + + +// ----------------------------------------------------------------------------- +// --SECTION-- priority queue helper functions +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup PriorityQueue +/// @{ +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief checks if additional capacity is required and extends if so +//////////////////////////////////////////////////////////////////////////////// + +static bool CheckPQSize(TRI_pqueue_t* pq) { + char* newItems; + + if (pq == NULL) { + return false; + } + + if (pq->_base._capacity > (pq->_base._count + 1) ) { + return true; + } + + pq->_base._capacity = pq->_base._capacity * 2; + newItems = TRI_Allocate(pq->_base._capacity * pq->_base._itemSize); + if (newItems == NULL) { + return false; + } + + memset(newItems, 0, pq->_base._itemSize * pq->_base._capacity); + memcpy(newItems, pq->_base._items, (pq->_base._count * pq->_base._itemSize) ); + + TRI_Free(pq->_base._items); + pq->_base._items = newItems; + + return true; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief rebalances the heap (priority queue storage) using partial order +//////////////////////////////////////////////////////////////////////////////// + +static bool FixPQ(TRI_pqueue_t* pq, uint64_t position) { + + char* currentItem; // the element which may be out of place in the heap + uint64_t currentPos; // the current item we are checking against. + char* parentItem; + char* itemAddress; + char* leftChildItem; + char* rightChildItem; + + currentPos = position; + currentItem = (char*)(TRI_Allocate(pq->_base._itemSize)); + if (currentItem == NULL) { // out of memory + return false; + } + + itemAddress = GetItemAddress(pq,currentPos); + if (itemAddress == NULL) { + TRI_Free(currentItem); + return false; + } + + + // ........................................................................... + // Temporarily save our item just changed (via removal or addition) + // ........................................................................... + + memcpy(currentItem,itemAddress,pq->_base._itemSize); + + + // ........................................................................... + // Remember that given position m, it's parent in the heap is given by m/2 + // Remember that the item we have to fix can be in the wrong place either because + // it is less than it's parent or because it is greater than its children. + // ........................................................................... + + + // ........................................................................... + // item is moved up if the item is LESS than its parent. + // ........................................................................... + + while ((currentPos / 2) >= 1) { + parentItem = GetItemAddress(pq, currentPos / 2); + if (!pq->isLessPQ(pq,currentItem,parentItem)) { + break; + } + itemAddress = GetItemAddress(pq,currentPos); + memcpy(itemAddress,parentItem,pq->_base._itemSize); + pq->updateStoragePQ(pq, itemAddress, currentPos); + currentPos = currentPos / 2; + } + + + // ........................................................................... + // If the position has changed, then we moved the item up somewhere + // ........................................................................... + + if (currentPos != position) { + itemAddress = GetItemAddress(pq,currentPos); + memcpy(itemAddress,currentItem,pq->_base._itemSize); + pq->updateStoragePQ(pq, itemAddress, currentPos); + TRI_Free(currentItem); + return true; + } + + + // ........................................................................... + // ok perhaps item has to move down the heap since it is too heavy + // ........................................................................... + + while (pq->_base._count >= (2 * currentPos)) { + leftChildItem = GetItemAddress(pq, (currentPos * 2)); + rightChildItem = GetItemAddress(pq, (currentPos * 2) + 1); + + // this is to keep the heap balanced + if ( (pq->_base._count > (2 * currentPos)) && + (pq->isLessPQ(pq, rightChildItem,leftChildItem)) && + (pq->isLessPQ(pq, rightChildItem, currentItem)) + ) { + itemAddress = GetItemAddress(pq,currentPos); + memcpy(itemAddress,rightChildItem,pq->_base._itemSize); + pq->updateStoragePQ(pq, itemAddress, currentPos); + currentPos = (2 * currentPos) + 1; + } + + // move item down + else if (pq->isLessPQ(pq, leftChildItem, currentItem)) { + itemAddress = GetItemAddress(pq,currentPos); + memcpy(itemAddress,leftChildItem,pq->_base._itemSize); + pq->updateStoragePQ(pq, itemAddress, currentPos); + currentPos = 2 * currentPos; + } + else { + break; + } + } + + itemAddress = GetItemAddress(pq,currentPos); + memcpy(itemAddress,currentItem,pq->_base._itemSize); + pq->updateStoragePQ(pq, itemAddress, currentPos); + TRI_Free(currentItem); + return true; +} + + + +static bool CompareIsLess(TRI_pqueue_t* pq, void* leftItem, void* rightItem) { + if (pq->_base._reverse) { + return !pq->isLessPQ(pq, leftItem, rightItem); + } + return pq->isLessPQ(pq, leftItem, rightItem); +} + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief given a position returns the element stored in the priorty queue +//////////////////////////////////////////////////////////////////////////////// + +static char* GetItemAddress(TRI_pqueue_t* pq, uint64_t position) { + if (position < 1 || position > pq->_base._count) { + return NULL; + } + + return ((position - 1) * pq->_base._itemSize) + pq->_base._items; + +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + + +// Local Variables: +// mode: outline-minor +// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" +// End: diff --git a/PriorityQueue/priorityqueue.h b/PriorityQueue/priorityqueue.h new file mode 100755 index 0000000000..edb7ae427e --- /dev/null +++ b/PriorityQueue/priorityqueue.h @@ -0,0 +1,204 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief priorty queue +/// +/// @file +/// +/// +/// DISCLAIMER +/// +/// Copyright by triAGENS GmbH - All rights reserved. +/// +/// The Programs (which include both the software and documentation) +/// contain proprietary information of triAGENS GmbH; they are +/// provided under a license agreement containing restrictions on use and +/// disclosure and are also protected by copyright, patent and other +/// intellectual and industrial property laws. Reverse engineering, +/// disassembly or decompilation of the Programs, except to the extent +/// required to obtain interoperability with other independently created +/// software or as specified by law, is prohibited. +/// +/// The Programs are not intended for use in any nuclear, aviation, mass +/// transit, medical, or other inherently dangerous applications. It shall +/// be the licensee's responsibility to take all appropriate fail-safe, +/// backup, redundancy, and other measures to ensure the safe use of such +/// applications if the Programs are used for such purposes, and triAGENS +/// GmbH disclaims liability for any damages caused by such use of +/// the Programs. +/// +/// This software is the confidential and proprietary information of +/// triAGENS GmbH. You shall not disclose such confidential and +/// proprietary information and shall use it only in accordance with the +/// terms of the license agreement you entered into with triAGENS GmbH. +/// +/// Copyright holder is triAGENS GmbH, Cologne, Germany +/// +/// @author Dr. Frank Celler +/// @author Dr. O +/// @author Martin Schoenert +/// @author Copyright 2009-2012, triagens GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + +#ifndef TRIAGENS_BASICS_C_PRIORITY_QUEUE_H +#define TRIAGENS_BASICS_C_PRIORITY_QUEUE_H 1 + +#include "BasicsC/common.h" +#include "BasicsC/locks.h" +#include "BasicsC/vector.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +// ----------------------------------------------------------------------------- +// Currently only double values are supported. +// ----------------------------------------------------------------------------- + + + + +// ----------------------------------------------------------------------------- +// --SECTION-- skiplist public types +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup PriorityQueue +/// @{ +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief The base structure of a priority queue (pq) +//////////////////////////////////////////////////////////////////////////////// + +typedef struct TRI_pqueue_base_s { + // ........................................................................... + // The current storage allocated to the pq. This is NOT the number of items + // in the queue. + // ........................................................................... + size_t _capacity; + + // ........................................................................... + // The storage of the items as an array of element size + // ........................................................................... + char* _items; + + // ........................................................................... + // Size of each item (element) + // ........................................................................... + uint32_t _itemSize; + + // ........................................................................... + // The number of actual elements in the pq + // ........................................................................... + size_t _count; + + // ........................................................................... + // A counter which indicates the number of removals which are invalid. + // ........................................................................... + size_t _nrFalseRemoves; + + // ........................................................................... + // A counter which indicates the number of inserts which are invalid. + // ........................................................................... + size_t _nrFalseAdds; + + // ........................................................................... + // by default (reverse = false), items are stored from lowest to highest + // so that the items which sort lowest are the ones which are removed first. + // When this is set to true, the ... reverse is true ...eh? This can also + // be achieved by the call back comparision function + // ........................................................................... + bool _reverse; + + + // ........................................................................... + // Additional hidden extenral structure used outside this priority queue + // This hidden structure is not available within this priority queue + // ........................................................................... + // char[n] + +} +TRI_pqueue_base_t; + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief The structure of a priority queue (pq) +//////////////////////////////////////////////////////////////////////////////// +typedef struct TRI_pqueue_s { + TRI_pqueue_base_t _base; + void (*clearStoragePQ) (struct TRI_pqueue_s*, void*); + uint64_t (*getStoragePQ) (struct TRI_pqueue_s*, void*); + bool (*isLessPQ) (struct TRI_pqueue_s*, void*, void*); + void (*updateStoragePQ) (struct TRI_pqueue_s*, void*, uint64_t pos); + + + // ........................................................................... + // default pq add, remove ,top methods + // ........................................................................... + + bool (*add) (struct TRI_pqueue_s*, void*); + bool (*remove) (struct TRI_pqueue_s*, uint64_t, bool); + void* (*top) (struct TRI_pqueue_s*); + +} +TRI_pqueue_t; + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + + + + +// ----------------------------------------------------------------------------- +// --SECTION-- Priority Queue constructors and destructors +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup PriorityQueue +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief initialises a priority queue +//////////////////////////////////////////////////////////////////////////////// + +bool TRI_InitPQueue (TRI_pqueue_t*, size_t, size_t, bool, + void (*clearStoragePQ) (struct TRI_pqueue_s*, void*), + uint64_t (*getStoragePQ) (struct TRI_pqueue_s*, void*), + bool (*isLessPQ) (struct TRI_pqueue_s*, void*, void*), + void (*updateStoragePQ) (struct TRI_pqueue_s*, void*, uint64_t pos)); + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief destroys a skip list, but does not free the pointer +//////////////////////////////////////////////////////////////////////////////// + +void TRI_DestroyPQueue (TRI_pqueue_t*); + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief destroys a skip list and frees the pointer +//////////////////////////////////////////////////////////////////////////////// + +void TRI_FreePQueue (TRI_pqueue_t*); + + + + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + + +#ifdef __cplusplus +} +#endif + +#endif + +// Local Variables: +// mode: outline-minor +// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" +// End: diff --git a/ShapedJson/json-shaper.c b/ShapedJson/json-shaper.c index 78c35b842f..ff63d23e1a 100644 --- a/ShapedJson/json-shaper.c +++ b/ShapedJson/json-shaper.c @@ -140,7 +140,7 @@ static uint64_t HashNameKeyAttributePath (TRI_associative_synced_t* array, void char const* k; k = (char const*) key; - + return TRI_FnvHashString(k); } @@ -171,10 +171,13 @@ static bool EqualNameKeyAttributePath (TRI_associative_synced_t* array, void con k = (char const*) key; e = (char const*) element; ee = (TRI_shape_path_t const*) element; - + + return TRI_EqualString(k,e + sizeof(TRI_shape_path_t) + ee->_aidLength * sizeof(TRI_shape_aid_t)); + /* return TRI_EqualString2(k, e + sizeof(TRI_shape_path_t) + ee->_aidLength * sizeof(TRI_shape_aid_t), ee->_nameLength - 1); + */ } //////////////////////////////////////////////////////////////////////////////// @@ -195,7 +198,7 @@ static TRI_shape_pid_t FindNameAttributePath (TRI_shaper_t* shaper, char const* void const* p; p = TRI_LookupByKeyAssociativeSynced(&shaper->_attributePathsByName, name); - + if (p != NULL) { return ((TRI_shape_path_t const*) p)->_pid; } diff --git a/ShapedJson/shaped-json.h b/ShapedJson/shaped-json.h index 40e60d9da7..0175457004 100644 --- a/ShapedJson/shaped-json.h +++ b/ShapedJson/shaped-json.h @@ -580,11 +580,6 @@ TRI_long_string_shape_t; /// number of variable attributes /// /// -/// @c TRI_shape_size_t -/// _variableEntries -/// number of variable attributes -/// -/// /// @c TRI_shape_sid_t /// _sids[_fixedEntries + _variableEntries] /// shape identifier of the corresponding attribute diff --git a/UnitTests/HttpInterface/api-collection_spec.rb b/UnitTests/HttpInterface/api-collection_spec.rb index d0c33c0fb0..e2629e3b8f 100644 --- a/UnitTests/HttpInterface/api-collection_spec.rb +++ b/UnitTests/HttpInterface/api-collection_spec.rb @@ -213,9 +213,9 @@ describe AvocadoDB do end # get count - it "checks the parameter of a collection" do - cmd = api + "/" + String(@cid) + "/parameter" - doc = AvocadoDB.log_get("#{prefix}-get-collection-parameter", cmd) + it "checks the properties of a collection" do + cmd = api + "/" + String(@cid) + "/properties" + doc = AvocadoDB.log_get("#{prefix}-get-collection-properties", cmd) doc.code.should eq(200) doc.headers['content-type'].should eq("application/json") @@ -226,7 +226,7 @@ describe AvocadoDB do doc.parsed_response['status'].should eq(3) doc.parsed_response['waitForSync'].should eq(true) doc.parsed_response['journalSize'].should be_kind_of(Integer) - doc.headers['location'].should eq(api + "/" + String(@cid) + "/parameter") + doc.headers['location'].should eq(api + "/" + String(@cid) + "/properties") end # get figures @@ -654,11 +654,11 @@ describe AvocadoDB do end ################################################################################ -## parameter a collection +## properties of a collection ################################################################################ - context "parameter:" do - it "changing the parameter of a collection by identifier" do + context "properties:" do + it "changing the properties of a collection by identifier" do cn = "UnitTestsCollectionBasics" AvocadoDB.drop_collection(cn) cid = AvocadoDB.create_collection(cn) @@ -673,9 +673,9 @@ describe AvocadoDB do AvocadoDB.size_collection(cid).should eq(10) AvocadoDB.size_collection(cn).should eq(10) - cmd = api + "/" + String(cid) + "/parameter" + cmd = api + "/" + String(cid) + "/properties" body = "{ \"waitForSync\" : true }" - doc = AvocadoDB.log_put("#{prefix}-identifier-parameter-sync", cmd, :body => body) + doc = AvocadoDB.log_put("#{prefix}-identifier-properties-sync", cmd, :body => body) doc.code.should eq(200) doc.headers['content-type'].should eq("application/json") @@ -686,9 +686,9 @@ describe AvocadoDB do doc.parsed_response['status'].should eq(3) doc.parsed_response['waitForSync'].should eq(true) - cmd = api + "/" + String(cid) + "/parameter" + cmd = api + "/" + String(cid) + "/properties" body = "{ \"waitForSync\" : false }" - doc = AvocadoDB.log_put("#{prefix}-identifier-parameter-no-sync", cmd, :body => body) + doc = AvocadoDB.log_put("#{prefix}-identifier-properties-no-sync", cmd, :body => body) doc.code.should eq(200) doc.headers['content-type'].should eq("application/json") diff --git a/V8/v8-vocbase.cpp b/V8/v8-vocbase.cpp index dd4b470c80..598a994434 100644 --- a/V8/v8-vocbase.cpp +++ b/V8/v8-vocbase.cpp @@ -2133,6 +2133,70 @@ static v8::Handle JS_WhereHashConstAql (const v8::Arguments& argv) { } +//////////////////////////////////////////////////////////////////////////////// +/// @brief DEPRECATED +//////////////////////////////////////////////////////////////////////////////// + +static v8::Handle JS_WherePQConstAql (const v8::Arguments& argv) { + v8::HandleScope scope; + TRI_json_t* parameterList; + + if (argv.Length() > 2 || argv.Length() == 0) { + return scope.Close(v8::ThrowException(v8::String::New("usage: AQL_WHERE_PQ_CONST( {,})"))); + } + + + // .......................................................................... + // check that the first parameter sent is a double value -- the index id + // .......................................................................... + + bool inValidType = true; + TRI_idx_iid_t iid = TRI_ObjectToDouble(argv[0], inValidType); + + if (inValidType || iid == 0) { + return scope.Close(v8::ThrowException(v8::String::New(" must be an positive integer"))); + } + + + // .......................................................................... + // Store the index field parameters in a json object -- there is only one + // possible parameter to be sent - the number of top documents to query. + // .......................................................................... + + parameterList = TRI_CreateListJson(); + if (!parameterList) { + return scope.Close(v8::ThrowException(v8::String::New("out of memory in JS_WherePQConstAql"))); + } + + + if (argv.Length() == 1) { + TRI_json_t* jsonParameter = TRI_CreateNumberJson(1); + if (jsonParameter == NULL) { // failure of some sort + return scope.Close(v8::ThrowException(v8::String::New("internal error in JS_WherePQConstAql"))); + } + TRI_PushBackListJson(parameterList, jsonParameter); + } + + else { + for (int j = 1; j < argv.Length(); ++j) { + v8::Handle parameter = argv[j]; + TRI_json_t* jsonParameter = ConvertHelper(parameter); + if (jsonParameter == NULL) { // NOT the null json value! + return scope.Close(v8::ThrowException(v8::String::New("type value not currently supported for priority queue index"))); + } + TRI_PushBackListJson(parameterList, jsonParameter); + } + } + + // build document priority queue access + TRI_qry_where_t* where = TRI_CreateQueryWherePQConstant(iid, parameterList); + + // wrap it up + return scope.Close(WrapWhere(where)); + +} + + //////////////////////////////////////////////////////////////////////////////// /// @brief DEPRECATED //////////////////////////////////////////////////////////////////////////////// @@ -2359,6 +2423,79 @@ static v8::Handle JS_HashSelectAql (v8::Arguments const& argv) { return scope.Close(WrapQuery(query)); } + + + + +static v8::Handle JS_PQSelectAql (v8::Arguments const& argv) { + v8::HandleScope scope; + + if (argv.Length() != 2) { + return scope.Close(v8::ThrowException(v8::String::New("usage: AQL_PQ_SELECT(collection, where)"))); + } + + // ........................................................................... + // extract the primary collection + // ........................................................................... + v8::Handle collectionArg = argv[0]; + if (! collectionArg->IsObject()) { + return scope.Close(v8::ThrowException(v8::String::New("expecting a COLLECTION as first argument"))); + } + v8::Handle collectionObj = collectionArg->ToObject(); + + v8::Handle err; + const TRI_vocbase_col_t* collection = UseCollection(collectionObj, &err); + + if (collection == 0) { + return scope.Close(v8::ThrowException(err)); + } + + // ........................................................................... + // Extract the where clause + // ........................................................................... + v8::Handle whereArg = argv[1]; + TRI_qry_where_t* where = 0; + if (whereArg->IsNull()) { + ReleaseCollection(collection); + return scope.Close(v8::ThrowException(v8::String::New("expecting a WHERE object as second argument"))); + } + v8::Handle whereObj = whereArg->ToObject(); + where = UnwrapClass(whereObj, WRP_QRY_WHERE_TYPE); + if (where == 0) { + ReleaseCollection(collection); + return scope.Close(v8::ThrowException(v8::String::New("corrupted WHERE"))); + } + + // ........................................................................... + // Check the operators + // ........................................................................... + TRI_qry_where_priorityqueue_const_t* pqWhere = (TRI_qry_where_priorityqueue_const_t*)(where); + TRI_priorityqueue_index_t* idx = (TRI_priorityqueue_index_t*)(TRI_LookupIndex(collection->_collection, pqWhere->_iid)); + if (idx == NULL) { + ReleaseCollection(collection); + return scope.Close(v8::ThrowException(v8::String::New("invalid index in where statement"))); + } + + // ........................................................................... + // Create the skiplist query + // ........................................................................... + TRI_query_t* query = TRI_CreatePriorityQueueQuery(where, collection->_collection); + if (!query) { + ReleaseCollection(collection); + return scope.Close(v8::ThrowException(v8::String::New("could not create query object"))); + } + + + // ........................................................................... + // wrap it up + // ........................................................................... + + ReleaseCollection(collection); + return scope.Close(WrapQuery(query)); +} + + + //////////////////////////////////////////////////////////////////////////////// /// @brief constructs a new query from given parts - DEPRECATED //////////////////////////////////////////////////////////////////////////////// @@ -3850,6 +3987,179 @@ static v8::Handle JS_EnsureHashIndexVocbaseCol (v8::Arguments const& return EnsureHashSkipListIndex("ensureHashIndex", argv, false, 0); } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief ensures that a priority queue index exists +/// +/// @FUN{ensureSLIndex(@FA{field1})} +/// +/// Creates a priority queue index on all documents using attributes as paths to +/// the fields. Currently only supports one attribute of the type double. +/// All documents, which do not have the attribute path are ignored. +/// +/// In case that the index was successfully created, the index indetifier +/// is returned. +/// +/// @verbinclude fluent14 +//////////////////////////////////////////////////////////////////////////////// + +static v8::Handle JS_EnsurePriorityQueueIndexVocbaseCol (v8::Arguments const& argv) { + v8::HandleScope scope; + bool created = false; + TRI_index_t* idx; + + + // ............................................................................. + // Check that we have a valid collection + // ............................................................................. + + v8::Handle err; + TRI_vocbase_col_t const* collection = UseCollection(argv.Holder(), &err); + + if (collection == 0) { + return scope.Close(v8::ThrowException(err)); + } + + // ............................................................................. + // Check collection type + // ............................................................................. + + TRI_doc_collection_t* doc = collection->_collection; + + if (doc->base._type != TRI_COL_TYPE_SIMPLE_DOCUMENT) { + ReleaseCollection(collection); + return scope.Close(v8::ThrowException(v8::String::New("unknown collection type"))); + } + + TRI_sim_collection_t* sim = (TRI_sim_collection_t*) doc; + + // ............................................................................. + // Return string when there is an error of some sort. + // ............................................................................. + + string errorString; + + // ............................................................................. + // Ensure that there is at least one string parameter sent to this method + // ............................................................................. + + if (argv.Length() != 1) { + ReleaseCollection(collection); + + errorString = "one string parameter required for the ensurePQIndex(...) command"; + return scope.Close(v8::String::New(errorString.c_str(),errorString.length())); + } + + + // ............................................................................. + // Create a list of paths, these will be used to create a list of shapes + // which will be used by the priority queue index. + // ............................................................................. + + TRI_vector_t attributes; + TRI_InitVector(&attributes,sizeof(char*)); + + bool ok = true; + + for (int j = 0; j < argv.Length(); ++j) { + + v8::Handle argument = argv[j]; + if (! argument->IsString() ) { + errorString = "invalid parameter passed to ensurePQIndex(...) command"; + ok = false; + break; + } + + // ........................................................................... + // convert the argument into a "C" string + // ........................................................................... + + v8::String::Utf8Value argumentString(argument); + char* cArgument = (char*) (TRI_Allocate(argumentString.length() + 1)); + if (cArgument == NULL) { + errorString = "insuffient memory to complete ensurePQIndex(...) command"; + ok = false; + break; + } + + memcpy(cArgument, *argumentString, argumentString.length()); + TRI_PushBackVector(&attributes,&cArgument); + } + + // ............................................................................. + // Check that each parameter is unique + // ............................................................................. + + for (size_t j = 0; j < attributes._length; ++j) { + char* left = *((char**) (TRI_AtVector(&attributes, j))); + for (size_t k = j + 1; k < attributes._length; ++k) { + char* right = *((char**) (TRI_AtVector(&attributes, k))); + if (strcmp(left,right) == 0) { + errorString = "duplicate parameters sent to ensurePQIndex(...) command"; + ok = false; + break; + } + } + } + + // ............................................................................. + // Some sort of error occurred -- display error message and abort index creation + // (or index retrieval). + // ............................................................................. + + if (!ok) { + // ........................................................................... + // Remove the memory allocated to the list of attributes used for the hash index + // ........................................................................... + for (size_t j = 0; j < attributes._length; ++j) { + char* cArgument = *((char**) (TRI_AtVector(&attributes, j))); + TRI_Free(cArgument); + } + TRI_DestroyVector(&attributes); + + ReleaseCollection(collection); + return scope.Close(v8::String::New(errorString.c_str(),errorString.length())); + } + + // ............................................................................. + // Actually create the index here. Note that priority queue is never unique. + // ............................................................................. + + idx = TRI_EnsurePriorityQueueIndexSimCollection(sim, &attributes, false, &created); + + // ............................................................................. + // Remove the memory allocated to the list of attributes used for the hash index + // ............................................................................. + + for (size_t j = 0; j < attributes._length; ++j) { + char* cArgument = *((char**) (TRI_AtVector(&attributes, j))); + TRI_Free(cArgument); + } + + TRI_DestroyVector(&attributes); + + if (idx == NULL) { + ReleaseCollection(collection); + return scope.Close(v8::String::New("Priority Queue index could not be created")); + } + + // ............................................................................. + // Return the newly assigned index identifier + // ............................................................................. + + TRI_json_t* json = idx->json(idx, collection->_collection); + v8::Handle index = TRI_ObjectJson(json); + + if (index->IsObject()) { + index->ToObject()->Set(v8::String::New("isNewlyCreated"), created ? v8::True() : v8::False()); + } + + ReleaseCollection(collection); + return scope.Close(index); +} + + + //////////////////////////////////////////////////////////////////////////////// /// @brief ensures that a skiplist index exists /// @@ -3870,6 +4180,8 @@ static v8::Handle JS_EnsureUniqueSkiplistVocbaseCol (v8::Arguments co return EnsureHashSkipListIndex("ensureUniqueSkipList", argv, true, 1); } + + //////////////////////////////////////////////////////////////////////////////// /// @brief ensures that a multi skiplist index exists /// @@ -4026,32 +4338,32 @@ static v8::Handle JS_NameVocbaseCol (v8::Arguments const& argv) { } //////////////////////////////////////////////////////////////////////////////// -/// @brief gets or sets the parameters of a collection +/// @brief gets or sets the properties of a collection /// -/// @FUN{parameter()} +/// @FUN{properties()} /// -/// Returns an object containing all collection parameters. +/// Returns an object containing all collection properties. /// /// - @LIT{waitForSync}: If @LIT{true} creating a document will only return /// after the data was synced to disk. /// - @LIT{journalSize} : The size of the journal in bytes. /// -/// @FUN{parameter(@FA{parameter-array})} +/// @FUN{properties(@FA{properties-array})} /// -/// Changes the collection parameters. +/// Changes the collection properties. /// /// @EXAMPLES /// -/// Read all parameters +/// Read all properties /// /// @verbinclude admin1 /// -/// Change a parameter +/// Change a property /// /// @verbinclude admin2 //////////////////////////////////////////////////////////////////////////////// -static v8::Handle JS_ParameterVocbaseCol (v8::Arguments const& argv) { +static v8::Handle JS_PropertiesVocbaseCol (v8::Arguments const& argv) { TRI_v8_global_t* v8g; v8::HandleScope scope; @@ -5296,10 +5608,18 @@ void TRI_InitV8VocBridge (v8::Handle context, TRI_vocbase_t* vocbas v8::Handle DropIndexFuncName = v8::Persistent::New(v8::String::New("dropIndex")); v8::Handle EdgesFuncName = v8::Persistent::New(v8::String::New("edges")); v8::Handle EnsureGeoIndexFuncName = v8::Persistent::New(v8::String::New("ensureGeoIndex")); +/* + oreste: + v8::Handle EnsureMultiHashIndexFuncName = v8::Persistent::New(v8::String::New("ensureMultiHashIndex")); + v8::Handle EnsureMultiSkiplistIndexFuncName = v8::Persistent::New(v8::String::New("ensureMultiSLIndex")); + v8::Handle EnsureSkiplistIndexFuncName = v8::Persistent::New(v8::String::New("ensureSLIndex")); +*/ v8::Handle EnsureHashIndexFuncName = v8::Persistent::New(v8::String::New("ensureHashIndex")); + v8::Handle EnsurePriorityQueueIndexFuncName = v8::Persistent::New(v8::String::New("ensurePQIndex")); v8::Handle EnsureSkiplistFuncName = v8::Persistent::New(v8::String::New("ensureSkiplist")); v8::Handle EnsureUniqueConstraintFuncName = v8::Persistent::New(v8::String::New("ensureUniqueConstraint")); v8::Handle EnsureUniqueSkiplistFuncName = v8::Persistent::New(v8::String::New("ensureUniqueSkiplist")); + v8::Handle ExecuteFuncName = v8::Persistent::New(v8::String::New("execute")); v8::Handle FiguresFuncName = v8::Persistent::New(v8::String::New("figures")); v8::Handle GetBatchSizeFuncName = v8::Persistent::New(v8::String::New("getBatchSize")); @@ -5314,8 +5634,8 @@ void TRI_InitV8VocBridge (v8::Handle context, TRI_vocbase_t* vocbas v8::Handle NextFuncName = v8::Persistent::New(v8::String::New("next")); v8::Handle NextRefFuncName = v8::Persistent::New(v8::String::New("nextRef")); v8::Handle OutEdgesFuncName = v8::Persistent::New(v8::String::New("outEdges")); - v8::Handle ParameterFuncName = v8::Persistent::New(v8::String::New("parameter")); v8::Handle PersistFuncName = v8::Persistent::New(v8::String::New("persist")); + v8::Handle PropertiesFuncName = v8::Persistent::New(v8::String::New("properties")); v8::Handle RenameFuncName = v8::Persistent::New(v8::String::New("rename")); v8::Handle ReplaceFuncName = v8::Persistent::New(v8::String::New("replace")); v8::Handle SaveFuncName = v8::Persistent::New(v8::String::New("save")); @@ -5473,16 +5793,25 @@ void TRI_InitV8VocBridge (v8::Handle context, TRI_vocbase_t* vocbas rt->Set(DropFuncName, v8::FunctionTemplate::New(JS_DropVocbaseCol)); rt->Set(DropIndexFuncName, v8::FunctionTemplate::New(JS_DropIndexVocbaseCol)); rt->Set(EnsureGeoIndexFuncName, v8::FunctionTemplate::New(JS_EnsureGeoIndexVocbaseCol)); + + /* oreste: + rt->Set(EnsureMultiHashIndexFuncName, v8::FunctionTemplate::New(JS_EnsureMultiHashIndexVocbaseCol)); + rt->Set(EnsureMultiSkiplistIndexFuncName, v8::FunctionTemplate::New(JS_EnsureMultiSkiplistIndexVocbaseCol)); + rt->Set(EnsureSkiplistIndexFuncName, v8::FunctionTemplate::New(JS_EnsureSkiplistIndexVocbaseCol)); + */ + rt->Set(EnsureHashIndexFuncName, v8::FunctionTemplate::New(JS_EnsureHashIndexVocbaseCol)); + rt->Set(EnsurePriorityQueueIndexFuncName, v8::FunctionTemplate::New(JS_EnsurePriorityQueueIndexVocbaseCol)); rt->Set(EnsureSkiplistFuncName, v8::FunctionTemplate::New(JS_EnsureSkiplistVocbaseCol)); rt->Set(EnsureUniqueSkiplistFuncName, v8::FunctionTemplate::New(JS_EnsureUniqueSkiplistVocbaseCol)); rt->Set(EnsureUniqueConstraintFuncName, v8::FunctionTemplate::New(JS_EnsureUniqueConstraintVocbaseCol)); + rt->Set(FiguresFuncName, v8::FunctionTemplate::New(JS_FiguresVocbaseCol)); rt->Set(GetIndexesFuncName, v8::FunctionTemplate::New(JS_GetIndexesVocbaseCol)); rt->Set(LoadFuncName, v8::FunctionTemplate::New(JS_LoadVocbaseCol)); rt->Set(NameFuncName, v8::FunctionTemplate::New(JS_NameVocbaseCol)); rt->Set(NearFuncName, v8::FunctionTemplate::New(JS_NearQuery)); - rt->Set(ParameterFuncName, v8::FunctionTemplate::New(JS_ParameterVocbaseCol)); + rt->Set(PropertiesFuncName, v8::FunctionTemplate::New(JS_PropertiesVocbaseCol)); rt->Set(RenameFuncName, v8::FunctionTemplate::New(JS_RenameVocbaseCol)); rt->Set(StatusFuncName, v8::FunctionTemplate::New(JS_StatusVocbaseCol)); rt->Set(UnloadFuncName, v8::FunctionTemplate::New(JS_UnloadVocbaseCol)); @@ -5512,16 +5841,23 @@ void TRI_InitV8VocBridge (v8::Handle context, TRI_vocbase_t* vocbas rt->Set(DropFuncName, v8::FunctionTemplate::New(JS_DropVocbaseCol)); rt->Set(DropIndexFuncName, v8::FunctionTemplate::New(JS_DropIndexVocbaseCol)); rt->Set(EnsureGeoIndexFuncName, v8::FunctionTemplate::New(JS_EnsureGeoIndexVocbaseCol)); + /* oreste + rt->Set(EnsureMultiHashIndexFuncName, v8::FunctionTemplate::New(JS_EnsureMultiHashIndexVocbaseCol)); + rt->Set(EnsureMultiSkiplistIndexFuncName, v8::FunctionTemplate::New(JS_EnsureMultiSkiplistIndexVocbaseCol)); + rt->Set(EnsureSkiplistIndexFuncName, v8::FunctionTemplate::New(JS_EnsureSkiplistIndexVocbaseCol)); + */ rt->Set(EnsureHashIndexFuncName, v8::FunctionTemplate::New(JS_EnsureHashIndexVocbaseCol)); + rt->Set(EnsurePriorityQueueIndexFuncName, v8::FunctionTemplate::New(JS_EnsurePriorityQueueIndexVocbaseCol)); rt->Set(EnsureSkiplistFuncName, v8::FunctionTemplate::New(JS_EnsureSkiplistVocbaseCol)); rt->Set(EnsureUniqueConstraintFuncName, v8::FunctionTemplate::New(JS_EnsureUniqueConstraintVocbaseCol)); rt->Set(EnsureUniqueSkiplistFuncName, v8::FunctionTemplate::New(JS_EnsureUniqueSkiplistVocbaseCol)); + rt->Set(FiguresFuncName, v8::FunctionTemplate::New(JS_FiguresVocbaseCol)); rt->Set(GetIndexesFuncName, v8::FunctionTemplate::New(JS_GetIndexesVocbaseCol)); rt->Set(LoadFuncName, v8::FunctionTemplate::New(JS_LoadVocbaseCol)); rt->Set(NameFuncName, v8::FunctionTemplate::New(JS_NameVocbaseCol)); rt->Set(NearFuncName, v8::FunctionTemplate::New(JS_NearQuery)); - rt->Set(ParameterFuncName, v8::FunctionTemplate::New(JS_ParameterVocbaseCol)); + rt->Set(PropertiesFuncName, v8::FunctionTemplate::New(JS_PropertiesVocbaseCol)); rt->Set(RenameFuncName, v8::FunctionTemplate::New(JS_RenameVocbaseCol)); rt->Set(ReplaceFuncName, v8::FunctionTemplate::New(JS_ReplaceVocbaseCol)); rt->Set(StatusFuncName, v8::FunctionTemplate::New(JS_StatusVocbaseCol)); @@ -5671,6 +6007,10 @@ void TRI_InitV8VocBridge (v8::Handle context, TRI_vocbase_t* vocbas v8::FunctionTemplate::New(JS_WhereHashConstAql)->GetFunction(), v8::ReadOnly); + context->Global()->Set(v8::String::New("AQL_WHERE_PQ_CONST"), + v8::FunctionTemplate::New(JS_WherePQConstAql)->GetFunction(), + v8::ReadOnly); + context->Global()->Set(v8::String::New("AQL_WHERE_SL_CONST"), v8::FunctionTemplate::New(JS_WhereSkiplistConstAql)->GetFunction(), v8::ReadOnly); @@ -5691,6 +6031,10 @@ void TRI_InitV8VocBridge (v8::Handle context, TRI_vocbase_t* vocbas v8::FunctionTemplate::New(JS_HashSelectAql)->GetFunction(), v8::ReadOnly); + context->Global()->Set(v8::String::New("AQL_PQ_SELECT"), + v8::FunctionTemplate::New(JS_PQSelectAql)->GetFunction(), + v8::ReadOnly); + context->Global()->Set(v8::String::New("AQL_SL_SELECT"), v8::FunctionTemplate::New(JS_SkiplistSelectAql)->GetFunction(), v8::ReadOnly); diff --git a/V8Client/V8ClientConnection.cpp b/V8Client/V8ClientConnection.cpp index 8050d83f59..f0f3864ee7 100644 --- a/V8Client/V8ClientConnection.cpp +++ b/V8Client/V8ClientConnection.cpp @@ -161,6 +161,11 @@ namespace triagens { if (!_httpResult->isComplete()) { // not complete _lastErrorMessage = _client->getErrorMessage(); + + if (_lastErrorMessage == "") { + _lastErrorMessage = "Unknown error"; + } + _lastHttpReturnCode = SimpleHttpResult::HTTP_STATUS_SERVER_ERROR; v8::Handle result = v8::Object::New(); diff --git a/V8Client/shell.cpp b/V8Client/shell.cpp index d11db07ed1..59180dcb54 100644 --- a/V8Client/shell.cpp +++ b/V8Client/shell.cpp @@ -206,7 +206,7 @@ static v8::Handle JS_PagerOutput (v8::Arguments const& argv) { /// @brief starts the output pager //////////////////////////////////////////////////////////////////////////////// -static v8::Handle JS_StartOutputPager (v8::Arguments const& argv) { +static v8::Handle JS_StartOutputPager (v8::Arguments const& ) { if (usePager) { internalPrint("Using pager already.\n"); } @@ -221,7 +221,7 @@ static v8::Handle JS_StartOutputPager (v8::Arguments const& argv) { /// @brief stops the output pager //////////////////////////////////////////////////////////////////////////////// -static v8::Handle JS_StopOutputPager (v8::Arguments const& argv) { +static v8::Handle JS_StopOutputPager (v8::Arguments const& ) { if (usePager) { internalPrint("Stopping pager.\n"); } @@ -421,7 +421,7 @@ enum WRAP_CLASS_TYPES {WRAP_TYPE_CONNECTION = 1}; /// @brief weak reference callback for queries (call the destructor here) //////////////////////////////////////////////////////////////////////////////// -static void ClientConnection_DestructorCallback (v8::Persistent object, void* parameter) { +static void ClientConnection_DestructorCallback (v8::Persistent , void* parameter) { V8ClientConnection* client = (V8ClientConnection*) parameter; delete(client); } diff --git a/VocBase/index.c b/VocBase/index.c index 7904987d9d..fadbbf2055 100644 --- a/VocBase/index.c +++ b/VocBase/index.c @@ -215,6 +215,9 @@ char const* TRI_TypeNameIndex (const TRI_index_t* const idx) { case TRI_IDX_TYPE_HASH_INDEX: return "hash"; + case TRI_IDX_TYPE_PRIORITY_QUEUE_INDEX: + return "priorityqueue"; + case TRI_IDX_TYPE_SKIPLIST_INDEX: return "skiplist"; @@ -1005,7 +1008,7 @@ static int HashIndexHelper (const TRI_hash_index_t* hashIndex, } TRI_Free(hashElement->fields); - return TRI_set_errno(TRI_ERROR_INTERNAL); + return -1; } // .......................................................................... @@ -1043,6 +1046,7 @@ static int HashIndexHelper (const TRI_hash_index_t* hashIndex, // .......................................................................... // Determine if document has that particular shape + // It is not an error if the document DOES NOT have the particular shape // .......................................................................... acc = TRI_ShapeAccessor(hashIndex->base._collection->_shaper, document->_document._sid, shape); @@ -1054,7 +1058,7 @@ static int HashIndexHelper (const TRI_hash_index_t* hashIndex, TRI_Free(hashElement->fields); - return TRI_set_errno(TRI_ERROR_INTERNAL); + return -1; } // .......................................................................... @@ -1119,8 +1123,17 @@ static int InsertHashIndex (TRI_index_t* idx, TRI_doc_mptr_t const* doc) { } res = HashIndexHelper(hashIndex, &hashElement, doc, NULL); - - if (res != TRI_ERROR_NO_ERROR) { + + + // ............................................................................ + // It is possible that this document does not have the necessary attributes + // (keys) to participate in this index. + // ............................................................................ + + if (res == -1) { + return TRI_ERROR_NO_ERROR; + } + else if (res != TRI_ERROR_NO_ERROR) { return res; } @@ -1260,7 +1273,18 @@ static int RemoveHashIndex (TRI_index_t* idx, TRI_doc_mptr_t const* doc) { res = HashIndexHelper(hashIndex, &hashElement, doc, NULL); - if (res != TRI_ERROR_NO_ERROR) { + + // .......................................................................... + // It may happen that the document does not have attributes which match + // For now return internal error, there needs to be its own error number + // and the appropriate action needs to be taken by the calling function in + // such cases. + // .......................................................................... + + if (res == -1) { + return TRI_set_errno(TRI_ERROR_INTERNAL); + } + else if (res != TRI_ERROR_NO_ERROR) { return res; } @@ -1334,7 +1358,9 @@ static int UpdateHashIndex (TRI_index_t* idx, // ............................................................................ if (hashIndex->base._unique) { + res = HashIndexHelper(hashIndex, &hashElement, NULL, oldDoc); + if (res == TRI_ERROR_NO_ERROR) { // ............................................................................ @@ -1366,12 +1392,16 @@ static int UpdateHashIndex (TRI_index_t* idx, res = HashIndexHelper(hashIndex, &hashElement, newDoc, NULL); - if (res != TRI_ERROR_NO_ERROR) { - + if (res == -1) { + // .......................................................................... - // probably fields do not match + // probably fields do not match. For now just return internal error // .......................................................................... - + return TRI_ERROR_INTERNAL; + + } + + else if (res != TRI_ERROR_NO_ERROR) { return res; } @@ -1394,7 +1424,7 @@ static int UpdateHashIndex (TRI_index_t* idx, res = HashIndexHelper(hashIndex, &hashElement, NULL, oldDoc); - if (res != TRI_ERROR_NO_ERROR) { + if (res == TRI_ERROR_NO_ERROR) { // ............................................................................ // We must fill the hashElement with the value of the document shape -- this @@ -1415,18 +1445,26 @@ static int UpdateHashIndex (TRI_index_t* idx, } } + else { + LOG_WARNING("existing document could not be removed"); + } + // ............................................................................ // Fill the shaped json simple list from the document // ............................................................................ res = HashIndexHelper(hashIndex, &hashElement, newDoc, NULL); - if (res != TRI_ERROR_NO_ERROR) { + if (res == -1) { // .......................................................................... - // probably fields do not match + // probably fields do not match -- report internal error for now // .......................................................................... - + + return TRI_ERROR_INTERNAL; + } + + else if (res != TRI_ERROR_NO_ERROR) { return res; } @@ -1605,6 +1643,732 @@ HashIndexElements* TRI_LookupHashIndex(TRI_index_t* idx, TRI_json_t* parameterLi /// @} //////////////////////////////////////////////////////////////////////////////// + + +// ----------------------------------------------------------------------------- +// --SECTION-- PRIORITY QUEUE INDEX +// ----------------------------------------------------------------------------- + + + +// ----------------------------------------------------------------------------- +// --SECTION-- PRIVATE FUNCTIONS +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup VocBase +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief helper for priority queue index +//////////////////////////////////////////////////////////////////////////////// + +static int PriorityQueueIndexHelper (const TRI_priorityqueue_index_t* pqIndex, + PQIndexElement* pqElement, + const TRI_doc_mptr_t* document, + const TRI_shaped_json_t* shapedDoc) { + union { void* p; void const* c; } cnv; + TRI_shaped_json_t shapedObject; + TRI_shape_access_t* acc; + size_t j; + + // ............................................................................ + // TODO: allow documents to be indexed on other keys (attributes) besides + // doubles. For now, documents which do have an attribute of double, will be + // be skipped. We return -2 to indicate this. + // ............................................................................ + + if (shapedDoc != NULL) { + + // .......................................................................... + // Attempting to locate a priority queue entry using TRI_shaped_json_t object. + // Use this when we wish to remove a priority queue entry and we only have + // the "keys" rather than having the document (from which the keys would follow). + // .......................................................................... + + pqElement->data = NULL; + + + + for (j = 0; j < pqIndex->_paths._length; ++j) { + TRI_shape_pid_t shape = *((TRI_shape_pid_t*)(TRI_AtVector(&pqIndex->_paths,j))); + + // .......................................................................... + // Determine if document has that particular shape + // .......................................................................... + + acc = TRI_ShapeAccessor(pqIndex->base._collection->_shaper, shapedDoc->_sid, shape); + + if (acc == NULL || acc->_shape == NULL) { + if (acc != NULL) { + TRI_FreeShapeAccessor(acc); + } + + TRI_Free(pqElement->fields); + // the attribute does not exist in the document + return -1; + } + + + // .......................................................................... + // Determine if the attribute is of the type double -- if not for now + // ignore this document + // .......................................................................... + + if (acc->_shape->_type != TRI_SHAPE_NUMBER) { + TRI_FreeShapeAccessor(acc); + TRI_Free(pqElement->fields); + return -2; + } + + + // .......................................................................... + // Extract the field + // .......................................................................... + + if (! TRI_ExecuteShapeAccessor(acc, shapedDoc, &shapedObject)) { + TRI_FreeShapeAccessor(acc); + TRI_Free(pqElement->fields); + + return TRI_set_errno(TRI_ERROR_INTERNAL); + } + + // .......................................................................... + // Store the json shaped Object -- this is what will be hashed + // .......................................................................... + + pqElement->fields[j] = shapedObject; + TRI_FreeShapeAccessor(acc); + } // end of for loop + } + + else if (document != NULL) { + + // .......................................................................... + // Assign the document to the PQIndexElement structure - so that it can later + // be retreived. + // .......................................................................... + + cnv.c = document; + pqElement->data = cnv.p; + + for (j = 0; j < pqIndex->_paths._length; ++j) { + TRI_shape_pid_t shape = *((TRI_shape_pid_t*)(TRI_AtVector(&pqIndex->_paths,j))); + + // .......................................................................... + // Determine if document has that particular shape + // It is not an error if the document DOES NOT have the particular shape + // .......................................................................... + + acc = TRI_ShapeAccessor(pqIndex->base._collection->_shaper, document->_document._sid, shape); + + if (acc == NULL || acc->_shape == NULL) { + if (acc != NULL) { + TRI_FreeShapeAccessor(acc); + } + + TRI_Free(pqElement->fields); + + return -1; + } + + + // .......................................................................... + // Determine if the attribute is of the type double -- if not for now + // ignore this document + // .......................................................................... + + if (acc->_shape->_type != TRI_SHAPE_NUMBER) { + TRI_FreeShapeAccessor(acc); + TRI_Free(pqElement->fields); + return -2; + } + + + // .......................................................................... + // Extract the field + // .......................................................................... + + if (! TRI_ExecuteShapeAccessor(acc, &(document->_document), &shapedObject)) { + TRI_FreeShapeAccessor(acc); + TRI_Free(pqElement->fields); + + return TRI_set_errno(TRI_ERROR_INTERNAL); + } + + // .......................................................................... + // Store the field + // .......................................................................... + + pqElement->fields[j] = shapedObject; + + TRI_FreeShapeAccessor(acc); + } // end of for loop + } + + else { + return TRI_set_errno(TRI_ERROR_INTERNAL); + } + + return TRI_ERROR_NO_ERROR; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief attempts to add a document to a priority queue index +//////////////////////////////////////////////////////////////////////////////// + +static int InsertPriorityQueueIndex (TRI_index_t* idx, TRI_doc_mptr_t const* doc) { + PQIndexElement pqElement; + TRI_priorityqueue_index_t* pqIndex; + int res; + + // ............................................................................ + // Obtain the priority queue index structure + // ............................................................................ + + pqIndex = (TRI_priorityqueue_index_t*) idx; + + if (idx == NULL) { + LOG_WARNING("internal error in InsertPriorityQueueIndex"); + return TRI_set_errno(TRI_ERROR_INTERNAL); + } + + // ............................................................................ + // Allocate storage to shaped json objects stored as a simple list. + // These will be used for adding the document to the priority queue + // ............................................................................ + + pqElement.numFields = pqIndex->_paths._length; + pqElement.fields = TRI_Allocate(sizeof(TRI_shaped_json_t) * pqElement.numFields); + pqElement.collection = pqIndex->base._collection; + + + if (pqElement.fields == NULL) { + LOG_WARNING("out-of-memory in InsertPriorityQueueIndex"); + return TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); + } + + res = PriorityQueueIndexHelper(pqIndex, &pqElement, doc, NULL); + + + // ............................................................................ + // It is possible that this document does not have the necessary attributes + // (keys) to participate in this index. Skip this document for now. + // ............................................................................ + + if (res == -1) { + return TRI_ERROR_NO_ERROR; + } + + + // ............................................................................ + // It is possible that while we have the correct attribute name, the type is + // not double. Skip this document for now. + // ............................................................................ + + else if (res == -2) { + return TRI_ERROR_NO_ERROR; + } + + + // ............................................................................ + // Some other error has occurred - report this error to the calling function + // ............................................................................ + + else if (res != TRI_ERROR_NO_ERROR) { + return res; + } + + // ............................................................................ + // Attempt to insert document into priority queue index + // ............................................................................ + + res = PQIndex_insert(pqIndex->_pqIndex, &pqElement); + + if (res == TRI_ERROR_AVOCADO_INDEX_PQ_INSERT_FAILED) { + LOG_WARNING("priority queue insert failure"); + } + + return res; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief describes a priority queue index as a json object +//////////////////////////////////////////////////////////////////////////////// + +static TRI_json_t* JsonPriorityQueueIndex (TRI_index_t* idx, TRI_doc_collection_t const* collection) { + TRI_json_t* json; + TRI_json_t* fields; + const TRI_shape_path_t* path; + TRI_priorityqueue_index_t* pqIndex; + char const** fieldList; + size_t j; + + // .......................................................................... + // Recast as a priority queue index + // .......................................................................... + + pqIndex = (TRI_priorityqueue_index_t*) idx; + + if (pqIndex == NULL) { + TRI_set_errno(TRI_ERROR_INTERNAL); + return NULL; + } + + // .......................................................................... + // Allocate sufficent memory for the field list + // .......................................................................... + + fieldList = TRI_Allocate( (sizeof(char*) * pqIndex->_paths._length) ); + + if (fieldList == NULL) { + TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); + return NULL; + } + + // .......................................................................... + // Convert the attributes (field list of the hash index) into strings + // .......................................................................... + + for (j = 0; j < pqIndex->_paths._length; ++j) { + TRI_shape_pid_t shape = *((TRI_shape_pid_t*)(TRI_AtVector(&pqIndex->_paths,j))); + path = collection->_shaper->lookupAttributePathByPid(collection->_shaper, shape); + + if (path == NULL) { + TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); + TRI_Free(fieldList); + return NULL; + } + + fieldList[j] = ((const char*) path) + sizeof(TRI_shape_path_t) + path->_aidLength * sizeof(TRI_shape_aid_t); + } + + // .......................................................................... + // create json object and fill it + // .......................................................................... + + json = TRI_CreateArrayJson(); + + if (json == NULL) { + TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); + TRI_Free(fieldList); + return NULL; + } + + fields = TRI_CreateListJson(); + + for (j = 0; j < pqIndex->_paths._length; ++j) { + TRI_PushBack3ListJson(fields, TRI_CreateStringCopyJson(fieldList[j])); + } + + TRI_Insert3ArrayJson(json, "id", TRI_CreateNumberJson(idx->_iid)); + TRI_Insert3ArrayJson(json, "unique", TRI_CreateBooleanJson(pqIndex->base._unique)); + TRI_Insert3ArrayJson(json, "type", TRI_CreateStringCopyJson(TRI_TypeNameIndex(idx))); + TRI_Insert3ArrayJson(json, "fields", fields); + + TRI_Free(fieldList); + + return json; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief removes a document from a priority queue index +//////////////////////////////////////////////////////////////////////////////// + +static int RemovePriorityQueueIndex (TRI_index_t* idx, TRI_doc_mptr_t const* doc) { + PQIndexElement pqElement; + TRI_priorityqueue_index_t* pqIndex; + int res; + + // ............................................................................ + // Obtain the priority queue index structure + // ............................................................................ + + pqIndex = (TRI_priorityqueue_index_t*) idx; + + if (idx == NULL) { + LOG_WARNING("internal error in RemovePriorityQueueIndex"); + return TRI_set_errno(TRI_ERROR_INTERNAL); + } + + // ............................................................................ + // Allocate some memory for the PQIndexElement structure + // ............................................................................ + + pqElement.numFields = pqIndex->_paths._length; + pqElement.fields = TRI_Allocate( sizeof(TRI_shaped_json_t) * pqElement.numFields); + pqElement.collection = pqIndex->base._collection; + + if (pqElement.fields == NULL) { + LOG_WARNING("out-of-memory in RemovePriorityQueueIndex"); + return TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); + } + + // .......................................................................... + // Fill the json field list from the document + // .......................................................................... + + res = PriorityQueueIndexHelper(pqIndex, &pqElement, doc, NULL); + + + // ............................................................................ + // It is possible that this document does not have the necessary attributes + // (keys) to participate in this index. For now report this as an error. Todo, + // add its own unique error code so that the calling function can take the + // appropriate action. + // ............................................................................ + + if (res == -1) { + return TRI_set_errno(TRI_ERROR_INTERNAL); + } + + // ............................................................................ + // It is possible that while we have the correct attribute name, the type is + // not double. Skip this document for now. + // ............................................................................ + + else if (res == -2) { + return TRI_ERROR_NO_ERROR; + } + + + else if (res != TRI_ERROR_NO_ERROR) { + return res; + } + + // ............................................................................ + // Attempt the removal for unique/non-unique priority queue indexes + // ............................................................................ + + res = PQIndex_remove(pqIndex->_pqIndex, &pqElement); + + return res; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief updates a document from a priority queue index +//////////////////////////////////////////////////////////////////////////////// + +static int UpdatePriorityQueueIndex (TRI_index_t* idx, + const TRI_doc_mptr_t* newDoc, + const TRI_shaped_json_t* oldDoc) { + + // .......................................................................... + // Note: The oldDoc is represented by the TRI_shaped_json_t rather than by + // a TRI_doc_mptr_t object. However for non-unique indexes (such as this + // one) we must pass the document shape to the hash remove function. + // .......................................................................... + + union { void* p; void const* c; } cnv; + PQIndexElement pqElement; + TRI_priorityqueue_index_t* pqIndex; + int res; + + // ............................................................................ + // Obtain the priority queue index structure + // ............................................................................ + + pqIndex = (TRI_priorityqueue_index_t*) idx; + + if (idx == NULL) { + LOG_WARNING("internal error in UpdatePriorityQueueIndex"); + return TRI_ERROR_INTERNAL; + } + + // ............................................................................ + // Allocate some memory for the HashIndexElement structure + // ............................................................................ + + pqElement.numFields = pqIndex->_paths._length; + pqElement.fields = TRI_Allocate(sizeof(TRI_shaped_json_t) * pqElement.numFields); + pqElement.collection = pqIndex->base._collection; + + if (pqElement.fields == NULL) { + LOG_WARNING("out-of-memory in UpdatePriorityQueueIndex"); + return TRI_ERROR_OUT_OF_MEMORY; + } + + + // ............................................................................ + // Fill in the fields with the values from oldDoc + // ............................................................................ + + res = PriorityQueueIndexHelper(pqIndex, &pqElement, NULL, oldDoc); + + if (res == TRI_ERROR_NO_ERROR) { + + cnv.c = newDoc; + pqElement.data = cnv.p; + + // ............................................................................ + // Remove the priority queue index entry and return. + // ............................................................................ + + res = PQIndex_remove(pqIndex->_pqIndex, &pqElement); + + if (res != TRI_ERROR_NO_ERROR) { + LOG_WARNING("could not remove old document from priority queue index in UpdatePriorityQueueIndex"); + } + } + + else { + LOG_WARNING("could not remove old document from priority queue index in UpdatePriorityQueueIndex"); + } + + // ............................................................................ + // Fill the shaped json simple list from the document + // ............................................................................ + + res = PriorityQueueIndexHelper(pqIndex, &pqElement, newDoc, NULL); + + if (res == -1) { + + // .......................................................................... + // probably fields do not match + // .......................................................................... + + return TRI_ERROR_INTERNAL; + } + + // ............................................................................ + // It is possible that while we have the correct attribute name, the type is + // not double. Skip this document for now. + // ............................................................................ + + else if (res == -2) { + return TRI_ERROR_NO_ERROR; + } + + + else if (res != TRI_ERROR_NO_ERROR) { + + return res; + } + + // ............................................................................ + // Attempt to add the priority queue entry from the new doc + // ............................................................................ + + res = PQIndex_insert(pqIndex->_pqIndex, &pqElement); + + return res; +} + + + +// ----------------------------------------------------------------------------- +// --SECTION-- constructors and destructors +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup VocBase +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief creates a priority queue index +//////////////////////////////////////////////////////////////////////////////// + +TRI_index_t* TRI_CreatePriorityQueueIndex (struct TRI_doc_collection_s* collection, + TRI_vector_pointer_t* fields, + TRI_vector_t* paths, + bool unique) { + TRI_priorityqueue_index_t* pqIndex; + size_t j; + + if (paths == NULL) { + LOG_WARNING("Internal error in TRI_CreatePriorityQueueIndex. PriorityQueue index creation failed."); + return NULL; + } + + // ........................................................................... + // TODO: Allow priority queue index to be indexed on more than one field. For + // now report an error. + // ........................................................................... + + if (paths->_length != 1) { + LOG_WARNING("Currently only one attribute of the tye 'double' can be used for an index. PriorityQueue index creation failed."); + return NULL; + } + + pqIndex = TRI_Allocate(sizeof(TRI_priorityqueue_index_t)); + + if (pqIndex == NULL) { + TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); + return NULL; + } + + pqIndex->base._iid = TRI_NewTickVocBase(); + pqIndex->base._type = TRI_IDX_TYPE_PRIORITY_QUEUE_INDEX; + pqIndex->base._collection = collection; + pqIndex->base._unique = unique; + + pqIndex->base.insert = InsertPriorityQueueIndex; + pqIndex->base.json = JsonPriorityQueueIndex; + pqIndex->base.remove = RemovePriorityQueueIndex; + pqIndex->base.update = UpdatePriorityQueueIndex; + + // ........................................................................... + // Copy the contents of the path list vector into a new vector and store this + // ........................................................................... + + TRI_InitVector(&pqIndex->_paths, sizeof(TRI_shape_pid_t)); + + for (j = 0; j < paths->_length; ++j) { + TRI_shape_pid_t shape = *((TRI_shape_pid_t*)(TRI_AtVector(paths,j))); + + TRI_PushBackVector(&pqIndex->_paths, &shape); + } + + TRI_InitVectorString(&pqIndex->base._fields); + + for (j = 0; j < fields->_length; ++j) { + char const* name = fields->_buffer[j]; + + TRI_PushBackVectorString(&pqIndex->base._fields, TRI_DuplicateString(name)); + } + + if (!unique) { + pqIndex->_pqIndex = PQueueIndex_new(); + } + else { + assert(false); + } + + return &pqIndex->base; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief frees the memory allocated, but does not free the pointer +//////////////////////////////////////////////////////////////////////////////// + +void TRI_DestroyPriorityQueueIndex(TRI_index_t* idx) { + TRI_priorityqueue_index_t* pqIndex; + + if (idx == NULL) { + return; + } + + TRI_DestroyVectorString(&idx->_fields); + + pqIndex = (TRI_priorityqueue_index_t*) idx; + + TRI_DestroyVector(&pqIndex->_paths); + + PQueueIndex_free(pqIndex->_pqIndex); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief frees the memory allocated and frees the pointer +//////////////////////////////////////////////////////////////////////////////// + +void TRI_FreePriorityQueueIndex(TRI_index_t* idx) { + if (idx == NULL) { + return; + } + TRI_DestroyPriorityQueueIndex(idx); + TRI_Free(idx); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +// ----------------------------------------------------------------------------- +// --SECTION-- public functions +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup VocBase +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief attempts to locate an entry in the priority queue index +/// A priority queue index lookup however only allows the 'top' most element +/// of the queue to be located. +/// +/// @warning who ever calls this function is responsible for destroying +/// PQIndexElement* result (which could be null) +//////////////////////////////////////////////////////////////////////////////// + +PQIndexElements* TRI_LookupPriorityQueueIndex(TRI_index_t* idx, TRI_json_t* parameterList) { + + TRI_priorityqueue_index_t* pqIndex; + PQIndexElements* result; + TRI_shaper_t* shaper; + size_t j; + uint64_t numElements; + TRI_json_t* jsonObject; + + + if (idx == NULL) { + return NULL; + } + + pqIndex = (TRI_priorityqueue_index_t*) idx; + + + // .............................................................................. + // The parameter list should consist of exactly one parameter of the type number + // which represents the first 'n' elements on the priority queue. If the + // parameter list is empty, then 'n' defaults to 1. + // .............................................................................. + + if (parameterList == NULL) { + result = PQIndex_top(pqIndex->_pqIndex,1); + return result; + } + + + if (parameterList->_value._objects._length == 0) { + result = PQIndex_top(pqIndex->_pqIndex,1); + return result; + } + + if (parameterList->_value._objects._length != 1) { + TRI_set_errno(TRI_ERROR_INTERNAL); + LOG_WARNING("invalid parameter sent to LookupPriorityQueueIndex"); + return NULL; + } + + + shaper = pqIndex->base._collection->_shaper; + numElements = 0; + + for (j = 0; j < parameterList->_value._objects._length; ++j) { + jsonObject = (TRI_json_t*) (TRI_AtVector(&(parameterList->_value._objects),j)); + if (jsonObject->_type == TRI_JSON_NUMBER) { + numElements = jsonObject->_value._number; + break; + } + } + + if (numElements == 0) { + TRI_set_errno(TRI_ERROR_INTERNAL); + LOG_WARNING("invalid parameter sent to LookupPriorityQueueIndex - request ignored"); + return NULL; + } + + result = PQIndex_top(pqIndex->_pqIndex,numElements); + return result; + +} + + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + + + // ----------------------------------------------------------------------------- // --SECTION-- SKIPLIST INDEX // ----------------------------------------------------------------------------- diff --git a/VocBase/index.h b/VocBase/index.h index fdc93ffd53..99d1482c24 100644 --- a/VocBase/index.h +++ b/VocBase/index.h @@ -34,6 +34,7 @@ #include "ShapedJson/shaped-json.h" #include "GeoIndex/GeoIndex.h" #include "HashIndex/hashindex.h" +#include "PriorityQueue/pqueueindex.h" #include "SkipLists/skiplistIndex.h" #include "SkipLists/sl-operator.h" @@ -73,6 +74,7 @@ typedef enum { TRI_IDX_TYPE_PRIMARY_INDEX, TRI_IDX_TYPE_GEO_INDEX, TRI_IDX_TYPE_HASH_INDEX, + TRI_IDX_TYPE_PRIORITY_QUEUE_INDEX, TRI_IDX_TYPE_SKIPLIST_INDEX } TRI_idx_type_e; @@ -138,6 +140,19 @@ typedef struct TRI_hash_index_s { } TRI_hash_index_t; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief skiplist index +//////////////////////////////////////////////////////////////////////////////// + +typedef struct TRI_priorityqueue_index_s { + TRI_index_t base; + PQIndex* _pqIndex; + TRI_vector_t _paths; // a list of shape pid which identifies the fields of the index +} +TRI_priorityqueue_index_t; + + //////////////////////////////////////////////////////////////////////////////// /// @brief skiplist index //////////////////////////////////////////////////////////////////////////////// @@ -369,6 +384,59 @@ HashIndexElements* TRI_LookupHashIndex (TRI_index_t*, TRI_json_t*); /// @} //////////////////////////////////////////////////////////////////////////////// + + + +// ----------------------------------------------------------------------------- +// --SECTION-- PRIORITY QUEUE INDEX +// ----------------------------------------------------------------------------- + +// ----------------------------------------------------------------------------- +// --SECTION-- constructors and destructors +// ----------------------------------------------------------------------------- + + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup VocBase +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +PQIndexElements* TRI_LookupPriorityQueueIndex (TRI_index_t*, TRI_json_t*); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief creates a priority queue index +//////////////////////////////////////////////////////////////////////////////// + +TRI_index_t* TRI_CreatePriorityQueueIndex (struct TRI_doc_collection_s*, + TRI_vector_pointer_t*, + TRI_vector_t*, + bool); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief frees the memory allocated, but does not free the pointer +//////////////////////////////////////////////////////////////////////////////// + +void TRI_DestroyPriorityQueueIndex (TRI_index_t*); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief frees the memory allocated and frees the pointer +//////////////////////////////////////////////////////////////////////////////// + +void TRI_FreePriorityQueueIndex (TRI_index_t*); + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + + + + + + + + + + // ----------------------------------------------------------------------------- // --SECTION-- SKIPLIST INDEX // ----------------------------------------------------------------------------- diff --git a/VocBase/query-where.h b/VocBase/query-where.h index 05e3daa531..f066afe8ac 100644 --- a/VocBase/query-where.h +++ b/VocBase/query-where.h @@ -51,6 +51,7 @@ typedef enum { TRI_QRY_WHERE_BOOLEAN, TRI_QRY_WHERE_GENERAL, TRI_QRY_WHERE_HASH_CONSTANT, + TRI_QRY_WHERE_PRIORITY_QUEUE_CONSTANT, TRI_QRY_WHERE_SKIPLIST_CONSTANT, TRI_QRY_WHERE_WITHIN_CONSTANT, TRI_QRY_WHERE_PRIMARY_CONSTANT @@ -162,6 +163,19 @@ typedef struct TRI_qry_where_hash_const_s { TRI_qry_where_hash_const_t; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief skiplist index where +//////////////////////////////////////////////////////////////////////////////// + +typedef struct TRI_qry_where_priorityqueue_const_s { + TRI_qry_where_t base; + TRI_idx_iid_t _iid; + TRI_json_t* _parameters; +} +TRI_qry_where_priorityqueue_const_t; + + //////////////////////////////////////////////////////////////////////////////// /// @brief skiplist index where //////////////////////////////////////////////////////////////////////////////// diff --git a/VocBase/query.c b/VocBase/query.c index f212469073..9edc59500d 100644 --- a/VocBase/query.c +++ b/VocBase/query.c @@ -352,6 +352,45 @@ static TRI_rc_result_t* NextHashCollectionCursor (TRI_rc_cursor_t* c) { } +//////////////////////////////////////////////////////////////////////////////// +/// @brief DEPRECATED +//////////////////////////////////////////////////////////////////////////////// + +static bool ToJavaScriptPQDocument (TRI_qry_select_t* s, + TRI_rc_result_t* result, + void* storage) { + + TRI_doc_mptr_t* document; + TRI_doc_collection_t* collection; + + collection = result->_context->_primary; + + document = (TRI_doc_mptr_t*) result->_dataPtr; + return TRI_ObjectDocumentPointer(collection, document, storage); +} + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief DEPRECATED +//////////////////////////////////////////////////////////////////////////////// + +static TRI_rc_result_t* NextPQCollectionCursor (TRI_rc_cursor_t* c) { + collection_cursor_t* cursor; + + cursor = (collection_cursor_t*) c; + + if (cursor->_currentRow == cursor->_length) { + return NULL; + } + + cursor->_current = &(cursor->_documents[cursor->_currentRow]); + cursor->_result._dataPtr = (TRI_sr_documents_t*) (cursor->_current); + ++(cursor->_currentRow); + + return &cursor->_result; +} + + //////////////////////////////////////////////////////////////////////////////// // For a collection, advances a given cursor by one. Cursor is associated with // a skip list index. Note: for now the field will store @@ -762,6 +801,18 @@ static TRI_qry_where_t* CloneQueryWhereHashConstant (const TRI_qry_where_t* w) { return TRI_CreateQueryWhereHashConstant(whereClause->_iid, whereClause->_parameters); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief clones a query condition - DEPRECATED +//////////////////////////////////////////////////////////////////////////////// + +static TRI_qry_where_t* CloneQueryWherePQConstant (const TRI_qry_where_t* w) { + TRI_qry_where_priorityqueue_const_t* whereClause; + + whereClause = (TRI_qry_where_priorityqueue_const_t*) w; + + return TRI_CreateQueryWherePQConstant(whereClause->_iid, whereClause->_parameters); +} + //////////////////////////////////////////////////////////////////////////////// /// DEPRECATED //////////////////////////////////////////////////////////////////////////////// @@ -801,6 +852,17 @@ static void FreeQueryWhereHashConstant (TRI_qry_where_t* w) { TRI_Free(whereClause); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief frees a query condition priority queue - DEPRECATED +//////////////////////////////////////////////////////////////////////////////// + +static void FreeQueryWherePQConstant (TRI_qry_where_t* w) { + TRI_qry_where_priorityqueue_const_t* whereClause; + whereClause = (TRI_qry_where_priorityqueue_const_t*) w; + TRI_FreeJson(whereClause->_parameters); + TRI_Free(whereClause); +} + //////////////////////////////////////////////////////////////////////////////// /// @brief DEPRECATED //////////////////////////////////////////////////////////////////////////////// @@ -903,7 +965,23 @@ TRI_qry_where_t* TRI_CreateQueryWhereHashConstant (TRI_idx_iid_t iid, TRI_json_t result = TRI_Allocate(sizeof(TRI_qry_where_hash_const_t)); result->base._type = TRI_QRY_WHERE_HASH_CONSTANT; result->base.clone = CloneQueryWhereHashConstant; - result->base.free = FreeQueryWhereHashConstant; + result->base.free = FreeQueryWhereHashConstant; + result->_iid = iid; + result->_parameters = TRI_CopyJson(parameters); + return &result->base; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief creates a query condition for priority queue index - DEPRECATED +//////////////////////////////////////////////////////////////////////////////// + +TRI_qry_where_t* TRI_CreateQueryWherePQConstant (TRI_idx_iid_t iid, TRI_json_t* parameters) { + TRI_qry_where_priorityqueue_const_t* result; + result = TRI_Allocate(sizeof(TRI_qry_where_priorityqueue_const_t)); + result->base._type = TRI_QRY_WHERE_PRIORITY_QUEUE_CONSTANT; + result->base.clone = CloneQueryWherePQConstant; + result->base.free = FreeQueryWherePQConstant; result->_iid = iid; result->_parameters = TRI_CopyJson(parameters); return &result->base; @@ -1004,6 +1082,28 @@ TRI_query_t* TRI_CreateHashQuery(const TRI_qry_where_t* whereStmt, return query; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief creates a priority queue query - DEPRECATED +//////////////////////////////////////////////////////////////////////////////// + +TRI_query_t* TRI_CreatePriorityQueueQuery(const TRI_qry_where_t* whereStmt, + TRI_doc_collection_t* collection) { + TRI_query_t* query; + + query = TRI_Allocate(sizeof(TRI_query_t)); + if (!query) { + return NULL; + } + + query->_where = ( whereStmt == NULL ? NULL : whereStmt->clone(whereStmt)); + query->_skip = TRI_QRY_NO_SKIP; + query->_limit = TRI_QRY_NO_LIMIT; + query->_primary = collection; + query->_joins = NULL; + query->_select = TRI_CreateQuerySelectDocument(); + return query; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief creates a skiplist query - DEPRECATED @@ -1339,6 +1439,105 @@ static void FilterDataHashQuery(collection_cursor_t* cursor,TRI_query_t* query, } + + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief executes a query - DEPRECATED +//////////////////////////////////////////////////////////////////////////////// + +static void FilterDataPQQuery(collection_cursor_t* cursor,TRI_query_t* query, + TRI_rc_context_t* context) { + + bool ok; + TRI_index_t* idx; + TRI_qry_where_priorityqueue_const_t* where; + TRI_sim_collection_t* collection; + PQIndexElements* pqElements; + TRI_doc_mptr_t* wtr; + TRI_doc_mptr_t* doc; + size_t j; + + cursor->base._context = context; + cursor->base._select = query->_select->clone(query->_select); + + cursor->base.next = NextPQCollectionCursor; + cursor->base.hasNext = HasNextCollectionCursor; + cursor->base.free = FreeCollectionCursor; + cursor->_result._selectResult = NULL; + + cursor->_result._context = context; + cursor->_result._dataPtr = NULL; + + cursor->base._select->toJavaScript = ToJavaScriptPQDocument; + + TRI_InitVectorPointer(&cursor->base._containers); + + TRI_ReadLockCollectionsQuery(query); + + TRI_AddCollectionsCursor(&cursor->base, query); + + + ok = (query->_primary->base._type == TRI_COL_TYPE_SIMPLE_DOCUMENT); + + if (ok) { + where = (TRI_qry_where_priorityqueue_const_t*)(query->_where); + ok = (where->base._type == TRI_QRY_WHERE_PRIORITY_QUEUE_CONSTANT); + } + + if (ok) { + collection = (TRI_sim_collection_t*) query->_primary; + idx = TRI_IndexSimCollection(collection, where->_iid); + ok = (idx != NULL); + } + + if (ok) { + pqElements = TRI_LookupPriorityQueueIndex(idx,where->_parameters); + ok = (pqElements != NULL); + } + + + if (ok) { + cursor->_documents = (TRI_doc_mptr_t*) (TRI_Allocate(sizeof(TRI_doc_mptr_t) * pqElements->_numElements)); + + wtr = cursor->_documents; + cursor->_length = 0; + cursor->base._matchedDocuments = 0; + cursor->_current = 0; + cursor->_currentRow = 0; + + for (j = 0; j < pqElements->_numElements; ++j) { + // should not be necessary to check that documents have not been deleted + doc = (TRI_doc_mptr_t*)((pqElements->_elements[j]).data); + if (doc->_deletion) { + continue; + } + if (cursor->_current == 0) { + cursor->_current = wtr; + } + ++cursor->base._matchedDocuments; + ++cursor->_length; + *wtr = *doc; + ++wtr; + } + + + if (pqElements->_elements != NULL) { + TRI_Free(pqElements->_elements); + TRI_Free(pqElements); + } + } + + TRI_ReadUnlockCollectionsQuery(query); + + if (!ok) { + cursor->_length = 0; + cursor->_currentRow = 0; + } + +} + + //////////////////////////////////////////////////////////////////////////////// /// @brief DEPRECATED //////////////////////////////////////////////////////////////////////////////// @@ -1424,7 +1623,6 @@ TRI_rc_cursor_t* TRI_ExecuteQueryAql (TRI_query_t* query, TRI_rc_context_t* cont limit = query->_limit; applyPostSkipLimit = false; - if (limit < 0) { limit = TRI_QRY_NO_LIMIT; skip = 0; @@ -1436,7 +1634,9 @@ TRI_rc_cursor_t* TRI_ExecuteQueryAql (TRI_query_t* query, TRI_rc_context_t* cont where = 0; if (query->_where != NULL) { + where = query->_where; + if (where->_type == TRI_QRY_WHERE_BOOLEAN) { TRI_qry_where_boolean_t* b; b = (TRI_qry_where_boolean_t*) where; @@ -1445,12 +1645,15 @@ TRI_rc_cursor_t* TRI_ExecuteQueryAql (TRI_query_t* query, TRI_rc_context_t* cont } where = NULL; } + else if (where->_type == TRI_QRY_WHERE_PRIMARY_CONSTANT) { assert(false); } + else if (where->_type == TRI_QRY_WHERE_WITHIN_CONSTANT) { assert(false); } + else if (where->_type == TRI_QRY_WHERE_HASH_CONSTANT) { cursor = TRI_Allocate(sizeof(collection_cursor_t)); if (cursor == NULL) { @@ -1459,6 +1662,16 @@ TRI_rc_cursor_t* TRI_ExecuteQueryAql (TRI_query_t* query, TRI_rc_context_t* cont FilterDataHashQuery(cursor,query,context); return &cursor->base; } + + else if (where->_type == TRI_QRY_WHERE_PRIORITY_QUEUE_CONSTANT) { + cursor = TRI_Allocate(sizeof(collection_cursor_t)); + if (cursor == NULL) { + return NULL; + } + FilterDataPQQuery(cursor,query,context); + return &cursor->base; + } + else if (where->_type == TRI_QRY_WHERE_SKIPLIST_CONSTANT) { cursor = TRI_Allocate(sizeof(collection_cursor_t)); if (cursor == NULL) { diff --git a/VocBase/query.h b/VocBase/query.h index a3fe9babe7..bd188c23e7 100644 --- a/VocBase/query.h +++ b/VocBase/query.h @@ -316,6 +316,8 @@ TRI_rc_cursor_t; TRI_query_t* TRI_CreateHashQuery (const TRI_qry_where_t*, TRI_doc_collection_t*); +TRI_query_t* TRI_CreatePriorityQueueQuery (const TRI_qry_where_t*, TRI_doc_collection_t*); + TRI_query_t* TRI_CreateSkiplistQuery (const TRI_qry_where_t*, TRI_doc_collection_t*); TRI_query_t* TRI_CreateQuery (TRI_vocbase_t*, @@ -374,6 +376,12 @@ TRI_qry_where_t* TRI_CreateQueryWhereGeneral (char const*); TRI_qry_where_t* TRI_CreateQueryWhereHashConstant (TRI_idx_iid_t, TRI_json_t*); +//////////////////////////////////////////////////////////////////////////////// +/// @brief creates a query condition for a priority queue with constant parameters - DEPRECATED +//////////////////////////////////////////////////////////////////////////////// + +TRI_qry_where_t* TRI_CreateQueryWherePQConstant (TRI_idx_iid_t, TRI_json_t*); + //////////////////////////////////////////////////////////////////////////////// /// @brief creates a query condition for a hash with constant parameters - DEPRECATED //////////////////////////////////////////////////////////////////////////////// diff --git a/VocBase/simple-collection.c b/VocBase/simple-collection.c index 3e0afec876..2dccc0c5fc 100644 --- a/VocBase/simple-collection.c +++ b/VocBase/simple-collection.c @@ -92,6 +92,12 @@ static TRI_index_t* CreateHashIndexSimCollection (TRI_sim_collection_t* collecti bool unique, bool* created); +static TRI_index_t* CreatePriorityQueueIndexSimCollection (TRI_sim_collection_t* collection, + const TRI_vector_t* attributes, + TRI_idx_iid_t iid, + bool unique, + bool* created); + static TRI_index_t* CreateSkiplistIndexSimCollection (TRI_sim_collection_t* collection, const TRI_vector_t* attributes, TRI_idx_iid_t iid, @@ -1537,7 +1543,9 @@ static bool OpenIndexIterator (char const* filename, void* data) { // HASH INDEX OR SKIPLIST INDEX // ........................................................................... - else if (TRI_EqualString(typeStr, "hash") || TRI_EqualString(typeStr, "skiplist")) { + else if (TRI_EqualString(typeStr, "hash") || TRI_EqualString(typeStr, "skiplist") || + TRI_EqualString(typeStr, "priorityqueue") + ) { // Determine if the hash index is unique or non-unique gjs = TRI_LookupArrayJson(json, "unique"); @@ -1578,6 +1586,9 @@ static bool OpenIndexIterator (char const* filename, void* data) { if (TRI_EqualString(typeStr, "hash")) { idx = CreateHashIndexSimCollection(doc, &attributes, iid, uniqueIndex, NULL); } + else if (TRI_EqualString(typeStr, "priorityqueue")) { + idx = CreatePriorityQueueIndexSimCollection(doc, &attributes, iid, uniqueIndex, NULL); + } else if (TRI_EqualString(typeStr, "skiplist")) { idx = CreateSkiplistIndexSimCollection(doc, &attributes, iid, uniqueIndex, NULL); } @@ -1597,8 +1608,9 @@ static bool OpenIndexIterator (char const* filename, void* data) { return true; } + // ......................................................................... - // ups, unknown index type + // oops, unknown index type // ......................................................................... else { @@ -2840,6 +2852,104 @@ static TRI_index_t* CreateHashIndexSimCollection (TRI_sim_collection_t* collecti return idx; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief adds a priroity queue index to the collection +//////////////////////////////////////////////////////////////////////////////// + +static TRI_index_t* CreatePriorityQueueIndexSimCollection (TRI_sim_collection_t* collection, + const TRI_vector_t* attributes, + 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_vector_pointer_t fields; + bool ok; + size_t j; + + + TRI_InitVector(&paths, sizeof(TRI_shape_pid_t)); + TRI_InitVectorPointer(&fields); + + // ........................................................................... + // Determine the shape ids for the attributes + // ........................................................................... + + for (j = 0; j < attributes->_length; ++j) { + char* path = *((char**)(TRI_AtVector(attributes,j))); + TRI_shape_pid_t shape = shaper->findAttributePathByName(shaper, path); + TRI_PushBackVector(&paths, &shape); + TRI_PushBackVectorPointer(&fields, path); + } + + // ........................................................................... + // 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_LookupPriorityQueueIndexSimCollection(collection, &paths); + + if (idx != NULL) { + TRI_DestroyVector(&paths); + TRI_DestroyVectorPointer(&fields); + + LOG_TRACE("priority queue index already created"); + + if (created != NULL) { + *created = false; + } + + return idx; + } + + // ........................................................................... + // Create the priority queue index + // ........................................................................... + + idx = TRI_CreatePriorityQueueIndex(&collection->base, &fields, &paths, unique); + + // ........................................................................... + // If index id given, use it otherwise use the default. + // ........................................................................... + + if (iid) { + idx->_iid = iid; + } + + // ........................................................................... + // initialises the index with all existing documents + // ........................................................................... + + ok = FillIndex(collection, idx); + + if (! ok) { + TRI_FreeSkiplistIndex(idx); + return NULL; + } + + // ........................................................................... + // store index + // ........................................................................... + + TRI_PushBackVectorPointer(&collection->_indexes, idx); + + // ........................................................................... + // release memory allocated to vector + // ........................................................................... + + TRI_DestroyVector(&paths); + + if (created != NULL) { + *created = true; + } + + return idx; +} + + + //////////////////////////////////////////////////////////////////////////////// /// @brief adds a skiplist index to the collection //////////////////////////////////////////////////////////////////////////////// @@ -2934,6 +3044,7 @@ static TRI_index_t* CreateSkiplistIndexSimCollection (TRI_sim_collection_t* coll return idx; } + //////////////////////////////////////////////////////////////////////////////// /// @} @@ -3073,6 +3184,75 @@ TRI_index_t* TRI_LookupHashIndexSimCollection (TRI_sim_collection_t* collection, } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief finds a priority queue index (non-unique) +//////////////////////////////////////////////////////////////////////////////// + +TRI_index_t* TRI_LookupPriorityQueueIndexSimCollection (TRI_sim_collection_t* collection, + const TRI_vector_t* paths) { + TRI_index_t* matchedIndex = NULL; + size_t j, k; + + // ........................................................................... + // 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_priorityqueue_index_t* pqIndex = (TRI_priorityqueue_index_t*) idx; + bool found = true; + + // ......................................................................... + // check that the type of the index is in fact a skiplist index + // ......................................................................... + + if (idx->_type != TRI_IDX_TYPE_PRIORITY_QUEUE_INDEX) { + continue; + } + + // ......................................................................... + // check that the number of paths (fields) in the index matches that + // of the number of attributes + // ......................................................................... + + if (paths->_length != pqIndex->_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(&pqIndex->_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; + } + } + + return matchedIndex; +} + + + //////////////////////////////////////////////////////////////////////////////// /// @brief finds a skiplist index (unique or non-unique) //////////////////////////////////////////////////////////////////////////////// @@ -3249,6 +3429,47 @@ TRI_index_t* TRI_EnsureHashIndexSimCollection(TRI_sim_collection_t* sim, return res == TRI_ERROR_NO_ERROR ? idx : NULL; } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief ensures that a priority queue index exists +//////////////////////////////////////////////////////////////////////////////// + +TRI_index_t* TRI_EnsurePriorityQueueIndexSimCollection(TRI_sim_collection_t* sim, + const TRI_vector_t* attributes, + bool unique, + bool* created) { + TRI_index_t* idx; + int res; + + // ............................................................................. + // inside write-lock + // ............................................................................. + + TRI_WRITE_LOCK_DOCUMENTS_INDEXES_SIM_COLLECTION(sim); + + // ............................................................................. + // Given the list of attributes (as strings) + // ............................................................................. + + idx = CreatePriorityQueueIndexSimCollection(sim, attributes, 0, unique, created); + + if (idx == NULL) { + TRI_WRITE_UNLOCK_DOCUMENTS_INDEXES_SIM_COLLECTION(sim); + return NULL; + } + + TRI_WRITE_UNLOCK_DOCUMENTS_INDEXES_SIM_COLLECTION(sim); + + // ............................................................................. + // outside write-lock + // ............................................................................. + + res = TRI_SaveIndex(&sim->base, idx); + + return res == TRI_ERROR_NO_ERROR ? idx : NULL; +} + + //////////////////////////////////////////////////////////////////////////////// /// @brief ensures that a skiplist index exists //////////////////////////////////////////////////////////////////////////////// diff --git a/VocBase/simple-collection.h b/VocBase/simple-collection.h index e875d0b60b..3d1fb1db01 100644 --- a/VocBase/simple-collection.h +++ b/VocBase/simple-collection.h @@ -431,6 +431,16 @@ struct TRI_index_s* TRI_LookupHashIndexSimCollection (TRI_sim_collection_t*, TRI_vector_t const*); +//////////////////////////////////////////////////////////////////////////////// +/// @brief finds a priority queue index +/// +/// Note that the caller must hold at least a read-lock. +//////////////////////////////////////////////////////////////////////////////// + +struct TRI_index_s* TRI_LookupPriorityQueueIndexSimCollection (TRI_sim_collection_t*, + TRI_vector_t const*); + + //////////////////////////////////////////////////////////////////////////////// /// @brief finds a skiplist index /// @@ -467,8 +477,19 @@ struct TRI_index_s* TRI_EnsureHashIndexSimCollection (TRI_sim_collection_t* coll bool unique, bool* created); + //////////////////////////////////////////////////////////////////////////////// -/// @brief adds or returns an existing hash index to a collection +/// @brief adds or returns an existing priority queue index to a collection +//////////////////////////////////////////////////////////////////////////////// + +struct TRI_index_s* TRI_EnsurePriorityQueueIndexSimCollection (TRI_sim_collection_t* collection, + const TRI_vector_t* attributes, + bool unique, + bool* created); + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief adds or returns an existing skiplist index to a collection //////////////////////////////////////////////////////////////////////////////// struct TRI_index_s* TRI_EnsureSkiplistIndexSimCollection (TRI_sim_collection_t* collection, diff --git a/js/actions/system/api-collection.js b/js/actions/system/api-collection.js index c4cae6b1e5..857a05eba6 100644 --- a/js/actions/system/api-collection.js +++ b/js/actions/system/api-collection.js @@ -41,17 +41,17 @@ var API = "_api/collection"; /// @brief collection representation //////////////////////////////////////////////////////////////////////////////// -function CollectionRepresentation (collection, showParameter, showCount, showFigures) { +function CollectionRepresentation (collection, showProperties, showCount, showFigures) { var result = {}; result.id = collection._id; result.name = collection.name(); - if (showParameter) { - var parameter = collection.parameter(); + if (showProperties) { + var properties = collection.properties(); - result.waitForSync = parameter.waitForSync; - result.journalSize = parameter.journalSize; + result.waitForSync = properties.waitForSync; + result.journalSize = properties.journalSize; } if (showCount) { @@ -224,11 +224,12 @@ function GET_api_collections (req, res) { /// response will contain a field "Location" which contains the correct /// location. /// -/// @REST{GET /_api/collection/@FA{collection-identifier}/parameter} +/// @REST{GET /_api/collection/@FA{collection-identifier}/properties} +/// DEPRECATED: @REST{GET /_api/collection/@FA{collection-identifier}/parameter} //////////////////////////////////////////////////////////////////// /// /// In addition to the above, the result will always contain the -/// @LIT{waitForSync} and the @LIT{journalSize} parameters. This is +/// @LIT{waitForSync} and the @LIT{journalSize} properties. This is /// achieved by forcing a load of the underlying collection. /// /// @LIT{waitForSync}: If @LIT{true} then creating or changing a document will @@ -342,7 +343,18 @@ function GET_api_collection (req, res) { } // ............................................................................. - // /_api/collection//parameter + // /_api/collection//properties + // ............................................................................. + + else if (sub == "properties") { + var result = CollectionRepresentation(collection, true, false, false); + var headers = { location : "/" + API + "/" + collection._id + "/properties" }; + + actions.resultOk(req, res, actions.HTTP_OK, result, headers); + } + + // ............................................................................. + // /_api/collection//parameter (DEPRECATED) // ............................................................................. else if (sub == "parameter") { @@ -353,7 +365,7 @@ function GET_api_collection (req, res) { } else { - actions.resultNotFound(req, res, "expecting one of the resources 'count', 'figures', 'parameter'"); + actions.resultNotFound(req, res, "expecting one of the resources 'count', 'figures', 'properties', 'parameter'"); } } else { @@ -468,9 +480,10 @@ function PUT_api_collection_truncate (req, res, collection) { //////////////////////////////////////////////////////////////////////////////// /// @brief changes a collection /// -/// @REST{PUT /_api/collection/@FA{collection-identifier}/parameter} +/// @REST{PUT /_api/collection/@FA{collection-identifier}/properties} +/// DEPRECATED: @REST{PUT /_api/collection/@FA{collection-identifier}/parameter} /// -/// Changes the parameter of a collection. Expects an object with the +/// Changes the properties of a collection. Expects an object with the /// attribute(s) /// /// @LIT{waitForSync}: If @LIT{true} then creating or changing a document will @@ -486,10 +499,10 @@ function PUT_api_collection_truncate (req, res, collection) { /// /// @EXAMPLES /// -/// @verbinclude api-collection-identifier-parameter-sync +/// @verbinclude api-collection-identifier-properties-sync //////////////////////////////////////////////////////////////////////////////// -function PUT_api_collection_parameter (req, res, collection) { +function PUT_api_collection_properties (req, res, collection) { var body; try { @@ -501,7 +514,7 @@ function PUT_api_collection_parameter (req, res, collection) { } try { - collection.parameter(body); + collection.properties(body); var result = CollectionRepresentation(collection, true); @@ -595,14 +608,17 @@ function PUT_api_collection (req, res) { else if (sub == "truncate") { PUT_api_collection_truncate(req, res, collection); } - else if (sub == "parameter") { - PUT_api_collection_parameter(req, res, collection); + else if (sub == "properties") { + PUT_api_collection_properties(req, res, collection); + } + else if (sub == "parameter") { /* DEPRECATED */ + PUT_api_collection_properties(req, res, collection); } else if (sub == "rename") { PUT_api_collection_rename(req, res, collection); } else { - actions.resultNotFound(req, res, "expecting one of the actions 'load', 'unload', 'truncate', 'parameter', 'rename'"); + actions.resultNotFound(req, res, "expecting one of the actions 'load', 'unload', 'truncate', 'properties', 'parameter', 'rename'"); } } diff --git a/js/client/client.js b/js/client/client.js index 19ceae3e71..82c11a6a25 100644 --- a/js/client/client.js +++ b/js/client/client.js @@ -296,21 +296,25 @@ function AvocadoError (error) { //////////////////////////////////////////////////////////////////////////////// AvocadoError.prototype._PRINT = function() { + print(this.toString()); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief toString function +//////////////////////////////////////////////////////////////////////////////// + +AvocadoError.prototype.toString = function() { + var result = ""; if (typeof(COLOR_BRIGHT) != "undefined") { - internal.output(COLOR_BRIGHT); - internal.output("Error: "); - internal.output(COLOR_OUTPUT_RESET); + result = COLOR_BRIGHT + "Error: " + COLOR_OUTPUT_RESET; } else { - internal.output("Error: "); + result = "Error: "; } - internal.output("["); - internal.output(this.code); - internal.output(":"); - internal.output(this.errorNum); - internal.output("] "); - print(this.errorMessage); + result += "[" + this.code + ":" + this.errorNum + "] " + this.errorMessage; + + return result; } //////////////////////////////////////////////////////////////////////////////// @@ -1049,7 +1053,7 @@ try { print(HELP); } catch (err) { - print(COLOR_RED + "connection failure: " + err + COLOR_BLACK); + print(err); } //////////////////////////////////////////////////////////////////////////////// diff --git a/js/client/js-client.h b/js/client/js-client.h index 1f113ed92b..919cd8b57e 100644 --- a/js/client/js-client.h +++ b/js/client/js-client.h @@ -297,21 +297,25 @@ static string JS_client_client = "////////////////////////////////////////////////////////////////////////////////\n" "\n" "AvocadoError.prototype._PRINT = function() {\n" + " print(this.toString());\n" + "}\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "/// @brief toString function\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "AvocadoError.prototype.toString = function() {\n" + " var result = \"\";\n" " if (typeof(COLOR_BRIGHT) != \"undefined\") {\n" - " internal.output(COLOR_BRIGHT);\n" - " internal.output(\"Error: \");\n" - " internal.output(COLOR_OUTPUT_RESET);\n" + " result = COLOR_BRIGHT + \"Error: \" + COLOR_OUTPUT_RESET;\n" " }\n" " else {\n" - " internal.output(\"Error: \"); \n" + " result = \"Error: \";\n" " }\n" "\n" - " internal.output(\"[\"); \n" - " internal.output(this.code); \n" - " internal.output(\":\"); \n" - " internal.output(this.errorNum); \n" - " internal.output(\"] \"); \n" - " print(this.errorMessage);\n" + " result += \"[\" + this.code + \":\" + this.errorNum + \"] \" + this.errorMessage;\n" + " \n" + " return result;\n" "}\n" "\n" "////////////////////////////////////////////////////////////////////////////////\n" @@ -1050,7 +1054,7 @@ static string JS_client_client = " print(HELP);\n" "}\n" "catch (err) {\n" - " print(COLOR_RED + \"connection failure: \" + err + COLOR_BLACK);\n" + " print(err);\n" "}\n" "\n" "////////////////////////////////////////////////////////////////////////////////\n" diff --git a/js/common/bootstrap/errors.js b/js/common/bootstrap/errors.js index fe2aff0800..43e9553723 100644 --- a/js/common/bootstrap/errors.js +++ b/js/common/bootstrap/errors.js @@ -101,5 +101,7 @@ ModuleCache["/internal"].exports.errors = { "SIMPLE_CLIENT_COULD_NOT_WRITE" : { "code" : 2002, "message" : "could not write to server" }, "SIMPLE_CLIENT_COULD_NOT_READ" : { "code" : 2003, "message" : "could not read from server" }, "ERROR_AVOCADO_INDEX_PQ_INSERT_FAILED" : { "code" : 3100, "message" : "priority queue insert failure" }, + "ERROR_AVOCADO_INDEX_PQ_REMOVE_FAILED" : { "code" : 3110, "message" : "priority queue remove failure" }, + "ERROR_AVOCADO_INDEX_PQ_REMOVE_ITEM_MISSING" : { "code" : 3111, "message" : "priority queue remove failure - item missing in index" }, }; diff --git a/js/common/bootstrap/js-errors.h b/js/common/bootstrap/js-errors.h index 4ae8a53f7a..11b7eadb83 100644 --- a/js/common/bootstrap/js-errors.h +++ b/js/common/bootstrap/js-errors.h @@ -102,6 +102,8 @@ static string JS_common_bootstrap_errors = " \"SIMPLE_CLIENT_COULD_NOT_WRITE\" : { \"code\" : 2002, \"message\" : \"could not write to server\" }, \n" " \"SIMPLE_CLIENT_COULD_NOT_READ\" : { \"code\" : 2003, \"message\" : \"could not read from server\" }, \n" " \"ERROR_AVOCADO_INDEX_PQ_INSERT_FAILED\" : { \"code\" : 3100, \"message\" : \"priority queue insert failure\" }, \n" + " \"ERROR_AVOCADO_INDEX_PQ_REMOVE_FAILED\" : { \"code\" : 3110, \"message\" : \"priority queue remove failure\" }, \n" + " \"ERROR_AVOCADO_INDEX_PQ_REMOVE_ITEM_MISSING\" : { \"code\" : 3111, \"message\" : \"priority queue remove failure - item missing in index\" }, \n" "};\n" "\n" ;