diff --git a/arangod/VocBase/document-collection.c b/arangod/VocBase/document-collection.c index 4605b5d0f7..75dc060a06 100755 --- a/arangod/VocBase/document-collection.c +++ b/arangod/VocBase/document-collection.c @@ -1642,52 +1642,6 @@ static bool OpenIndexIterator (char const* filename, void* data) { } } - -////////////////////////////////////////////////////////////////////////////// -/// @brief hashes an edge header -//////////////////////////////////////////////////////////////////////////////// - -static uint64_t HashElementEdge (TRI_multi_pointer_t* array, void const* data) { - TRI_edge_header_t const* h; - uint64_t hash[3]; - - h = data; - - hash[0] = h->_direction; - hash[1] = h->_cid; - hash[2] = h->_did; - - return TRI_FnvHashPointer(hash, sizeof(hash)); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief checks if key and element match -//////////////////////////////////////////////////////////////////////////////// - -static bool IsEqualKeyEdge (TRI_multi_pointer_t* array, void const* left, void const* right) { - TRI_edge_header_t const* l; - TRI_edge_header_t const* r; - - l = left; - r = right; - - return l->_direction == r->_direction && l->_cid == r->_cid && l->_did == r->_did; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief checks for elements are equal -//////////////////////////////////////////////////////////////////////////////// - -static bool IsEqualElementEdge (TRI_multi_pointer_t* array, void const* left, void const* right) { - TRI_edge_header_t const* l; - TRI_edge_header_t const* r; - - l = left; - r = right; - - return l->_mptr == r->_mptr && l->_direction == r->_direction && l->_cid == r->_cid && l->_did == r->_did; -} - //////////////////////////////////////////////////////////////////////////////// /// @brief initialises a simple collection //////////////////////////////////////////////////////////////////////////////// @@ -1715,12 +1669,9 @@ static bool InitDocumentCollection (TRI_document_collection_t* collection, return false; } - TRI_InitMultiPointer(&collection->_edgesIndex, - TRI_UNKNOWN_MEM_ZONE, - HashElementEdge, - HashElementEdge, - IsEqualKeyEdge, - IsEqualElementEdge); + if (collection->base.base._type == TRI_COL_TYPE_EDGE) { + TRI_InitEdgesDocumentCollection(collection); + } TRI_InitCondition(&collection->_journalsCondition); @@ -1854,15 +1805,10 @@ void TRI_DestroyDocumentCollection (TRI_document_collection_t* collection) { TRI_DestroyCondition(&collection->_journalsCondition); - // free all elements in the edges index - n = collection->_edgesIndex._nrAlloc; - for (i = 0; i < n; ++i) { - void* element = collection->_edgesIndex._table[i]; - if (element) { - TRI_Free(TRI_UNKNOWN_MEM_ZONE, element); - } + // only required for edge collections + if (collection->base.base._type == TRI_COL_TYPE_EDGE) { + TRI_FreeEdgesDocumentCollection(collection); } - TRI_DestroyMultiPointer(&collection->_edgesIndex); TRI_FreeSimpleHeaders(collection->_headers); @@ -2234,79 +2180,22 @@ static int CreateImmediateIndexes (TRI_document_collection_t* sim, return TRI_ERROR_NO_ERROR; } + // check the document type + marker = header->_data; + // ............................................................................. // update edges index // ............................................................................. - // check the document type - marker = header->_data; - - // add edges if (marker->_type == TRI_DOC_MARKER_EDGE) { - TRI_edge_header_t* entry; - TRI_doc_edge_marker_t const* edge; - - edge = header->_data; - - // IN - entry = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_edge_header_t), true); - if (entry == NULL) { - // OOM - // TODO: do we have to release the header and remove the entry from the primaryIndex? - return TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); + if (sim->base.base._type != TRI_COL_TYPE_EDGE) { + // operation is only permitted for edge collections + return TRI_set_errno(TRI_ERROR_ARANGO_COLLECTION_TYPE_INVALID); } - entry->_mptr = header; - entry->_direction = TRI_EDGE_IN; - entry->_cid = edge->_toCid; - entry->_did = edge->_toDid; - - TRI_InsertElementMultiPointer(&sim->_edgesIndex, entry, true); - - // OUT - entry = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_edge_header_t), true); - if (entry == NULL) { - // OOM - // TODO: do we have to release the header and remove the entry from the primaryIndex? - return TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); - } - - entry->_mptr = header; - entry->_direction = TRI_EDGE_OUT; - entry->_cid = edge->_fromCid; - entry->_did = edge->_fromDid; - - TRI_InsertElementMultiPointer(&sim->_edgesIndex, entry, true); - - // ANY - entry = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_edge_header_t), true); - if (entry == NULL) { - // OOM - // TODO: do we have to release the header and remove the entry from the primaryIndex? - return TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); - } - - entry->_mptr = header; - entry->_direction = TRI_EDGE_ANY; - entry->_cid = edge->_toCid; - entry->_did = edge->_toDid; - - TRI_InsertElementMultiPointer(&sim->_edgesIndex, entry, true); - - if (edge->_toCid != edge->_fromCid || edge->_toDid != edge->_fromDid) { - entry = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_edge_header_t), true); - if (entry == NULL) { - // OOM - // TODO: do we have to release the header and remove the entry from the primaryIndex? - return TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); - } - - entry->_mptr = header; - entry->_direction = TRI_EDGE_ANY; - entry->_cid = edge->_fromCid; - entry->_did = edge->_fromDid; - - TRI_InsertElementMultiPointer(&sim->_edgesIndex, entry, true); + result = TRI_InsertEdgeDocumentCollection(sim, header); + if (result != TRI_ERROR_NO_ERROR) { + return result; } } @@ -2432,7 +2321,7 @@ static int DeleteImmediateIndexes (TRI_document_collection_t* collection, TRI_doc_mptr_t* found; size_t n; size_t i; - bool result; + int result; // set the deletion flag change.c = header; @@ -2450,64 +2339,21 @@ static int DeleteImmediateIndexes (TRI_document_collection_t* collection, return TRI_set_errno(TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND); } + // check the document type + marker = header->_data; + // ............................................................................. // update edges index // ............................................................................. - // check the document type - marker = header->_data; - - // add edges + // delete edges if (marker->_type == TRI_DOC_MARKER_EDGE) { - TRI_edge_header_t entry; - TRI_edge_header_t* old; - TRI_doc_edge_marker_t const* edge; - - edge = header->_data; - - memset(&entry, 0, sizeof(entry)); - entry._mptr = header; - - // IN - entry._direction = TRI_EDGE_IN; - entry._cid = edge->_toCid; - entry._did = edge->_toDid; - old = TRI_RemoveElementMultiPointer(&collection->_edgesIndex, &entry); - - if (old != NULL) { - TRI_Free(TRI_UNKNOWN_MEM_ZONE, old); + if (collection->base.base._type != TRI_COL_TYPE_EDGE) { + // operation is only permitted for edge collections + return TRI_set_errno(TRI_ERROR_ARANGO_COLLECTION_TYPE_INVALID); } - // OUT - entry._direction = TRI_EDGE_OUT; - entry._cid = edge->_fromCid; - entry._did = edge->_fromDid; - old = TRI_RemoveElementMultiPointer(&collection->_edgesIndex, &entry); - - if (old != NULL) { - TRI_Free(TRI_UNKNOWN_MEM_ZONE, old); - } - - // ANY - entry._direction = TRI_EDGE_ANY; - entry._cid = edge->_toCid; - entry._did = edge->_toDid; - old = TRI_RemoveElementMultiPointer(&collection->_edgesIndex, &entry); - - if (old != NULL) { - TRI_Free(TRI_UNKNOWN_MEM_ZONE, old); - } - - if (edge->_toCid != edge->_fromCid || edge->_toDid != edge->_fromDid) { - entry._direction = TRI_EDGE_ANY; - entry._cid = edge->_fromCid; - entry._did = edge->_fromDid; - old = TRI_RemoveElementMultiPointer(&collection->_edgesIndex, &entry); - - if (old != NULL) { - TRI_Free(TRI_UNKNOWN_MEM_ZONE, old); - } - } + TRI_DeleteEdgeDocumentCollection(collection, header); } // ............................................................................. diff --git a/arangod/VocBase/edge-collection.c b/arangod/VocBase/edge-collection.c index 8a965c3f11..062726e79b 100755 --- a/arangod/VocBase/edge-collection.c +++ b/arangod/VocBase/edge-collection.c @@ -31,6 +31,64 @@ // --SECTION-- EDGES INDEX // ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// --SECTION-- private functions +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup VocBase +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief hashes an edge header +//////////////////////////////////////////////////////////////////////////////// + +static uint64_t HashElementEdge (TRI_multi_pointer_t* array, void const* data) { + TRI_edge_header_t const* h; + uint64_t hash[3]; + + h = data; + + hash[0] = h->_direction; + hash[1] = h->_cid; + hash[2] = h->_did; + + return TRI_FnvHashPointer(hash, sizeof(hash)); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief checks if key and element match +//////////////////////////////////////////////////////////////////////////////// + +static bool IsEqualKeyEdge (TRI_multi_pointer_t* array, void const* left, void const* right) { + TRI_edge_header_t const* l; + TRI_edge_header_t const* r; + + l = left; + r = right; + + return l->_direction == r->_direction && l->_cid == r->_cid && l->_did == r->_did; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief checks for elements are equal +//////////////////////////////////////////////////////////////////////////////// + +static bool IsEqualElementEdge (TRI_multi_pointer_t* array, void const* left, void const* right) { + TRI_edge_header_t const* l; + TRI_edge_header_t const* r; + + l = left; + r = right; + + return l->_mptr == r->_mptr && l->_direction == r->_direction && l->_cid == r->_cid && l->_did == r->_did; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + // ----------------------------------------------------------------------------- // --SECTION-- public functions // ----------------------------------------------------------------------------- @@ -40,11 +98,196 @@ /// @{ //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// @brief initialise the edges index of a collection +//////////////////////////////////////////////////////////////////////////////// + +void TRI_InitEdgesDocumentCollection (TRI_document_collection_t* collection) { + TRI_InitMultiPointer(&collection->_edgesIndex, + TRI_UNKNOWN_MEM_ZONE, + HashElementEdge, + HashElementEdge, + IsEqualKeyEdge, + IsEqualElementEdge); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief free all edges in the collection's edges index +//////////////////////////////////////////////////////////////////////////////// + +void TRI_FreeEdgesDocumentCollection (TRI_document_collection_t* collection) { + size_t i, n; + + // free all elements in the edges index + n = collection->_edgesIndex._nrAlloc; + for (i = 0; i < n; ++i) { + void* element = collection->_edgesIndex._table[i]; + if (element) { + TRI_Free(TRI_UNKNOWN_MEM_ZONE, element); + } + } + TRI_DestroyMultiPointer(&collection->_edgesIndex); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief insert an edge into the edges index +//////////////////////////////////////////////////////////////////////////////// + +int TRI_InsertEdgeDocumentCollection (TRI_document_collection_t* collection, + TRI_doc_mptr_t const* header) { + TRI_edge_header_t* entryIn; + TRI_edge_header_t* entryOut; + TRI_edge_header_t* entryAny; + TRI_edge_header_t* entryAny2 = NULL; + TRI_doc_edge_marker_t const* edge; + bool needEntryAny2; + + edge = header->_data; + + // do we need one or two entries into for direction ANY? + needEntryAny2 = (edge->_toCid != edge->_fromCid || edge->_toDid != edge->_fromDid); + + // allocate 3 or 4 edge headers and return early if memory allocation fails + + // IN + entryIn = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_edge_header_t), true); + if (entryIn == NULL) { + return TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); + } + + // OUT + entryOut = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_edge_header_t), true); + if (entryOut == NULL) { + TRI_Free(TRI_UNKNOWN_MEM_ZONE, entryIn); + + return TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); + } + + // ANY + entryAny = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_edge_header_t), true); + if (entryAny == NULL) { + TRI_Free(TRI_UNKNOWN_MEM_ZONE, entryIn); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, entryOut); + + return TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); + } + + if (needEntryAny2) { + entryAny2 = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_edge_header_t), true); + if (entryAny2 == NULL) { + TRI_Free(TRI_UNKNOWN_MEM_ZONE, entryIn); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, entryOut); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, entryAny); + + return TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); + } + } + + // we have allocated all necessary memory by here + + // IN + assert(entryIn); + entryIn->_mptr = header; + entryIn->_direction = TRI_EDGE_IN; + entryIn->_cid = edge->_toCid; + entryIn->_did = edge->_toDid; + + TRI_InsertElementMultiPointer(&collection->_edgesIndex, entryIn, true); + + // OUT + assert(entryOut); + entryOut->_mptr = header; + entryOut->_direction = TRI_EDGE_OUT; + entryOut->_cid = edge->_fromCid; + entryOut->_did = edge->_fromDid; + + TRI_InsertElementMultiPointer(&collection->_edgesIndex, entryOut, true); + + // ANY + assert(entryAny); + entryAny->_mptr = header; + entryAny->_direction = TRI_EDGE_ANY; + entryAny->_cid = edge->_toCid; + entryAny->_did = edge->_toDid; + + TRI_InsertElementMultiPointer(&collection->_edgesIndex, entryAny, true); + + // ANY (reversed) + if (needEntryAny2) { + assert(entryAny2); + entryAny2->_mptr = header; + entryAny2->_direction = TRI_EDGE_ANY; + entryAny2->_cid = edge->_fromCid; + entryAny2->_did = edge->_fromDid; + + TRI_InsertElementMultiPointer(&collection->_edgesIndex, entryAny2, true); + } + + return TRI_ERROR_NO_ERROR; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief remove an edge from the edges index +//////////////////////////////////////////////////////////////////////////////// + +void TRI_DeleteEdgeDocumentCollection (TRI_document_collection_t* collection, + TRI_doc_mptr_t const* header) { + TRI_edge_header_t entry; + TRI_edge_header_t* old; + TRI_doc_edge_marker_t const* edge; + + edge = header->_data; + + memset(&entry, 0, sizeof(entry)); + entry._mptr = header; + + // IN + entry._direction = TRI_EDGE_IN; + entry._cid = edge->_toCid; + entry._did = edge->_toDid; + old = TRI_RemoveElementMultiPointer(&collection->_edgesIndex, &entry); + + if (old != NULL) { + TRI_Free(TRI_UNKNOWN_MEM_ZONE, old); + } + + // OUT + entry._direction = TRI_EDGE_OUT; + entry._cid = edge->_fromCid; + entry._did = edge->_fromDid; + old = TRI_RemoveElementMultiPointer(&collection->_edgesIndex, &entry); + + if (old != NULL) { + TRI_Free(TRI_UNKNOWN_MEM_ZONE, old); + } + + // ANY + entry._direction = TRI_EDGE_ANY; + entry._cid = edge->_toCid; + entry._did = edge->_toDid; + old = TRI_RemoveElementMultiPointer(&collection->_edgesIndex, &entry); + + if (old != NULL) { + TRI_Free(TRI_UNKNOWN_MEM_ZONE, old); + } + + if (edge->_toCid != edge->_fromCid || edge->_toDid != edge->_fromDid) { + entry._direction = TRI_EDGE_ANY; + entry._cid = edge->_fromCid; + entry._did = edge->_fromDid; + old = TRI_RemoveElementMultiPointer(&collection->_edgesIndex, &entry); + + if (old != NULL) { + TRI_Free(TRI_UNKNOWN_MEM_ZONE, old); + } + } +} + //////////////////////////////////////////////////////////////////////////////// /// @brief looks up edges //////////////////////////////////////////////////////////////////////////////// -TRI_vector_pointer_t TRI_LookupEdgesDocumentCollection (TRI_document_collection_t* edges, +TRI_vector_pointer_t TRI_LookupEdgesDocumentCollection (TRI_document_collection_t* collection, TRI_edge_direction_e direction, TRI_voc_cid_t cid, TRI_voc_did_t did) { @@ -60,7 +303,7 @@ TRI_vector_pointer_t TRI_LookupEdgesDocumentCollection (TRI_document_collection_ entry._cid = cid; entry._did = did; - found = TRI_LookupByKeyMultiPointer(TRI_UNKNOWN_MEM_ZONE, &edges->_edgesIndex, &entry); + found = TRI_LookupByKeyMultiPointer(TRI_UNKNOWN_MEM_ZONE, &collection->_edgesIndex, &entry); for (i = 0; i < found._length; ++i) { cnv.c = ((TRI_edge_header_t*) found._buffer[i])->_mptr; diff --git a/arangod/VocBase/edge-collection.h b/arangod/VocBase/edge-collection.h index 86dde90425..75403c988d 100755 --- a/arangod/VocBase/edge-collection.h +++ b/arangod/VocBase/edge-collection.h @@ -101,6 +101,32 @@ TRI_edge_header_t; /// @{ //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// @brief initialise the edges index of a collection +//////////////////////////////////////////////////////////////////////////////// + +void TRI_InitEdgesDocumentCollection (TRI_document_collection_t*); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief free all edges in the collection's edges index +//////////////////////////////////////////////////////////////////////////////// + +void TRI_FreeEdgesDocumentCollection (TRI_document_collection_t*); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief insert an edge into the edges index +//////////////////////////////////////////////////////////////////////////////// + +int TRI_InsertEdgeDocumentCollection (TRI_document_collection_t*, + TRI_doc_mptr_t const*); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief remove an edge from the edges index +//////////////////////////////////////////////////////////////////////////////// + +void TRI_DeleteEdgeDocumentCollection (TRI_document_collection_t*, + TRI_doc_mptr_t const*); + //////////////////////////////////////////////////////////////////////////////// /// @brief looks up edges ////////////////////////////////////////////////////////////////////////////////