1
0
Fork 0
arangodb/arangod/HashIndex/hashindex.c

399 lines
15 KiB
C

////////////////////////////////////////////////////////////////////////////////
/// @brief geo 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 "hashindex.h"
// -----------------------------------------------------------------------------
// private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief free a hash index results list
////////////////////////////////////////////////////////////////////////////////
static void FreeResults (TRI_hash_index_elements_t* list) {
if (list->_elements) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, list->_elements);
}
TRI_Free(TRI_UNKNOWN_MEM_ZONE, list);
}
// -----------------------------------------------------------------------------
// destructors public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief destroys the hash index by calling the hash array's own Free function
////////////////////////////////////////////////////////////////////////////////
void HashIndex_destroy(HashIndex* hashIndex) {
if (hashIndex != NULL) {
TRI_FreeHashArray(hashIndex->hashArray);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief destroys the hash index and frees the memory associated with the index structure
////////////////////////////////////////////////////////////////////////////////
void HashIndex_free(HashIndex* hashIndex) {
if (hashIndex != NULL) {
HashIndex_destroy(hashIndex);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, hashIndex);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief free a result set allocated by HashIndex_find
////////////////////////////////////////////////////////////////////////////////
void HashIndex_freeResult(TRI_hash_index_elements_t* const list) {
FreeResults(list);
}
// -----------------------------------------------------------------------------
// constructors public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief Creates a new hash array used for storage of elements in the hash index
////////////////////////////////////////////////////////////////////////////////
HashIndex* HashIndex_new() {
HashIndex* hashIndex;
hashIndex = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(HashIndex), false);
if (hashIndex == NULL) {
return NULL;
}
hashIndex->unique = true;
hashIndex->hashArray = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_hasharray_t), false);
if (hashIndex->hashArray == NULL) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, hashIndex);
return NULL;
}
if (! TRI_InitHashArray(hashIndex->hashArray, sizeof(HashIndexElement), NULL, NULL, NULL, NULL, NULL, NULL) ) {
HashIndex_free(hashIndex);
return NULL;
}
return hashIndex;
}
// -----------------------------------------------------------------------------
// public functions : INSERT, REMOVE & LOOKUP
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief Adds (inserts) a data element into the hash array part of the hash index
////////////////////////////////////////////////////////////////////////////////
int HashIndex_add(HashIndex* hashIndex, HashIndexElement* element) {
bool result;
// .............................................................................
// Since we do not allow duplicates - we must compare using keys, rather than
// documents.
// .............................................................................
result = TRI_InsertKeyHashArray(hashIndex->hashArray, element, element, false);
return result ? TRI_ERROR_NO_ERROR : TRI_set_errno(TRI_ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief Locates an entry within the hash array part of the hash index
////////////////////////////////////////////////////////////////////////////////
TRI_hash_index_elements_t* HashIndex_find(HashIndex* hashIndex, HashIndexElement* element) {
HashIndexElement* result;
TRI_hash_index_elements_t* results;
// .............................................................................
// Create storage for the returned results if any. A return of NULL indicates
// some sort of error.
// .............................................................................
results = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_hash_index_elements_t), false);
if (results == NULL) {
return NULL;
}
// .............................................................................
// A find request means that a set of values for the "key" was sent. We need
// to locate the hash array entry by key.
// .............................................................................
result = (HashIndexElement*) (TRI_FindByKeyHashArray(hashIndex->hashArray, element));
if (result != NULL) {
results->_elements = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(HashIndexElement) * 1, false); // unique hash index maximum number is 1
if (results->_elements == NULL) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, results);
return NULL;
}
results->_elements[0] = *result;
results->_numElements = 1;
}
else {
results->_elements = NULL;
results->_numElements = 0;
}
return results;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief An alias for HashIndex_add
////////////////////////////////////////////////////////////////////////////////
int HashIndex_insert(HashIndex* hashIndex, HashIndexElement* element) {
return HashIndex_add(hashIndex,element);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief Removes an entry from the hash array part of the hash index
////////////////////////////////////////////////////////////////////////////////
int HashIndex_remove(HashIndex* hashIndex, HashIndexElement* element) {
bool result;
result = TRI_RemoveElementHashArray(hashIndex->hashArray, element);
return result ? TRI_ERROR_NO_ERROR : TRI_ERROR_INTERNAL;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief updates and entry from the associative array, first removes beforeElement,
/// @brief then adds the afterElement
////////////////////////////////////////////////////////////////////////////////
int HashIndex_update(HashIndex* hashIndex, const HashIndexElement* beforeElement,
const HashIndexElement* afterElement) {
// ...........................................................................
// This function is not currently implemented and must not be called.
// It's purpose would be to remove the existing beforeElement and replace it
// with the afterElement.
// ...........................................................................
assert(false);
return TRI_ERROR_INTERNAL;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Multi-hash non-unique hash indexes
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// destructors public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief destroys the hash index by calling the hash array's own Free function
////////////////////////////////////////////////////////////////////////////////
void MultiHashIndex_destroy(HashIndex* hashIndex) {
HashIndex_destroy(hashIndex);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief destroys the hash index and frees the memory associated with the index structure
////////////////////////////////////////////////////////////////////////////////
void MultiHashIndex_free(HashIndex* hashIndex) {
HashIndex_free(hashIndex);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief free a result set allocated by MultiHashIndex_find
////////////////////////////////////////////////////////////////////////////////
void MultiHashIndex_freeResult(TRI_hash_index_elements_t* const list) {
FreeResults(list);
}
// -----------------------------------------------------------------------------
// constructors public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief Creates a new multi (non-unique) hash index
////////////////////////////////////////////////////////////////////////////////
HashIndex* MultiHashIndex_new() {
HashIndex* hashIndex;
hashIndex = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(HashIndex), false);
if (hashIndex == NULL) {
return NULL;
}
hashIndex->unique = false;
hashIndex->hashArray = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_hasharray_t), false);
if (hashIndex->hashArray == NULL) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, hashIndex);
return NULL;
}
if (! TRI_InitHashArray(hashIndex->hashArray, sizeof(HashIndexElement), NULL, NULL, NULL, NULL, NULL, NULL) ) {
HashIndex_free(hashIndex);
return NULL;
}
return hashIndex;
}
// -----------------------------------------------------------------------------
// public functions : INSERT, REMOVE & LOOKUP
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief Adds (inserts) a data element into the hash array (hash index)
////////////////////////////////////////////////////////////////////////////////
int MultiHashIndex_add(HashIndex* hashIndex, HashIndexElement* element) {
bool result;
result = TRI_InsertElementHashArrayMulti(hashIndex->hashArray, element, false);
if (result) {
return 0;
}
return -1;
}
// ...............................................................................
// Locates an entry within the associative array
// ...............................................................................
TRI_hash_index_elements_t* MultiHashIndex_find(HashIndex* hashIndex, HashIndexElement* element) {
TRI_vector_pointer_t result;
TRI_hash_index_elements_t* results;
size_t j;
results = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_hash_index_elements_t), false);
if (results == NULL) {
return NULL;
}
// .............................................................................
// We can only use the LookupByKey method for non-unique hash indexes, since
// we want more than one result returned!
// .............................................................................
result = TRI_LookupByKeyHashArrayMulti (hashIndex->hashArray, element);
if (result._length == 0) {
results->_elements = NULL;
results->_numElements = 0;
}
else {
results->_numElements = result._length;
results->_elements = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(HashIndexElement) * result._length, false);
if (results->_elements == NULL) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, results);
return NULL;
}
for (j = 0; j < result._length; ++j) {
results->_elements[j] = *((HashIndexElement*)(result._buffer[j]));
}
}
TRI_DestroyVectorPointer(&result);
return results;
}
// ...............................................................................
// An alias for addIndex
// ...............................................................................
int MultiHashIndex_insert(HashIndex* hashIndex, HashIndexElement* element) {
return MultiHashIndex_add(hashIndex,element);
}
// ...............................................................................
// Removes an entry from the associative array
// ...............................................................................
int MultiHashIndex_remove(HashIndex* hashIndex, HashIndexElement* element) {
bool result;
result = TRI_RemoveElementHashArrayMulti(hashIndex->hashArray, element);
return result ? TRI_ERROR_NO_ERROR : TRI_ERROR_INTERNAL;
}
// ...............................................................................
// updates and entry from the associative array, first removes beforeElement,
// then adds the afterElement
// ...............................................................................
int MultiHashIndex_update(HashIndex* hashIndex, HashIndexElement* beforeElement,
HashIndexElement* afterElement) {
assert(false);
return TRI_ERROR_INTERNAL;
}