1
0
Fork 0
arangodb/arangod/BitIndexes/bitarrayIndex.c

1269 lines
43 KiB
C
Executable File

////////////////////////////////////////////////////////////////////////////////
/// @brief bitarray 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 "bitarrayIndex.h"
#include "BasicsC/string-buffer.h"
#include "ShapedJson/json-shaper.h"
#include "ShapedJson/shaped-json.h"
#include "VocBase/document-collection.h"
#include "BasicsC/logging.h"
// .............................................................................
// forward declaration of static functions used for iterator callbacks
// .............................................................................
static void BitarrayIndexDestroyIterator (TRI_index_iterator_t*);
static bool BitarrayIndexHasNextIterationCallback (TRI_index_iterator_t*);
static void* BitarrayIndexNextIterationCallback (TRI_index_iterator_t*);
static void* BitarrayIndexNextsIterationCallback (TRI_index_iterator_t*, int64_t);
static bool BitarrayIndexHasPrevIterationCallback (TRI_index_iterator_t*);
static void* BitarrayIndexPrevIterationCallback (TRI_index_iterator_t*);
static void* BitarrayIndexPrevsIterationCallback (TRI_index_iterator_t*, int64_t);
static void BitarrayIndexResetIterator (TRI_index_iterator_t*, bool);
// .............................................................................
// forward declaration of static functions used for bit mask callbacks
// .............................................................................
static void BitarrayIndex_destroyMaskSet (TRI_bitarray_mask_set_t*);
static void BitarrayIndex_extendMaskSet (TRI_bitarray_mask_set_t*, const int, const double);
static int BitarrayIndex_findHelper (BitarrayIndex*, TRI_vector_t*, TRI_index_operator_t*, TRI_index_iterator_t*, TRI_bitarray_mask_set_t*);
static void BitarrayIndex_freeMaskSet (TRI_bitarray_mask_set_t*);
static int BitarrayIndex_generateInsertBitMask (BitarrayIndex*, const BitarrayIndexElement*, TRI_bitarray_mask_t*);
static int BitarrayIndex_generateEqualBitMask (BitarrayIndex*, const TRI_relation_index_operator_t*, TRI_bitarray_mask_t*);
static int BitarrayIndex_generateEqualBitMaskHelper (TRI_json_t*, TRI_json_t*, uint64_t*);
static void BitarrayIndex_insertMaskSet (TRI_bitarray_mask_set_t*, TRI_bitarray_mask_t*, bool);
// .............................................................................
// forward declaration of static functions used for debugging callbacks
// comment out to suppress compile warnings -- todo add preprocessor directives
// .............................................................................
/*
static void BitarrayIndex_debugPrintMaskFooter (const char*);
static void BitarrayIndex_debugPrintMaskHeader (const char*);
static void BitarrayIndex_debugPrintMask (BitarrayIndex*, uint64_t);
*/
// -----------------------------------------------------------------------------
// --SECTION-- bitarrayIndex common public methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup bitarrayIndex
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief destroys a bitarray index , but does not free the pointer
////////////////////////////////////////////////////////////////////////////////
void BitarrayIndex_destroy(BitarrayIndex* baIndex) {
size_t j;
if (baIndex == NULL) {
return;
}
for (j = 0; j < baIndex->_values._length; ++j) {
TRI_DestroyJson(TRI_UNKNOWN_MEM_ZONE, (TRI_json_t*)(TRI_AtVector(&(baIndex->_values),j)));
}
TRI_DestroyVector(&baIndex->_values);
TRI_FreeBitarray(baIndex->_bitarray);
baIndex->_bitarray = NULL;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief destroys a bitarray index and frees the pointer
////////////////////////////////////////////////////////////////////////////////
void BitarrayIndex_free(BitarrayIndex* baIndex) {
if (baIndex == NULL) {
return;
}
BitarrayIndex_destroy(baIndex);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, baIndex);
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
//------------------------------------------------------------------------------
// Public Methods
//------------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief Creates a new bitarray index. Failure will return an appropriate error code
////////////////////////////////////////////////////////////////////////////////
int BitarrayIndex_new(BitarrayIndex** baIndex,
TRI_memory_zone_t* memoryZone,
size_t cardinality,
TRI_vector_t* values,
bool supportUndef,
void* context) {
int result;
size_t numArrays;
int j;
// ...........................................................................
// Sime simple checks
// ...........................................................................
if (baIndex == NULL) {
assert(false);
return TRI_ERROR_INTERNAL;
}
// ...........................................................................
// If the bit array index has arealdy been created, return internal error
// ...........................................................................
if (*baIndex != NULL) {
return TRI_ERROR_INTERNAL;
}
// ...........................................................................
// If the memory zone is invalid, then return an internal error
// ...........................................................................
if (memoryZone == NULL) {
return TRI_ERROR_INTERNAL;
}
// ...........................................................................
// Create the bit array index structure
// ...........................................................................
*baIndex = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(BitarrayIndex), true);
if (*baIndex == NULL) {
return TRI_ERROR_OUT_OF_MEMORY;
}
// ...........................................................................
// Copy the values into this index
// ...........................................................................
TRI_InitVector(&((*baIndex)->_values), TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_json_t));
for (j = 0; j < values->_length; ++j) {
TRI_json_t value;
TRI_CopyToJson(TRI_UNKNOWN_MEM_ZONE, &value, (TRI_json_t*)(TRI_AtVector(values,j)));
TRI_PushBackVector(&((*baIndex)->_values), &value);
}
// ...........................................................................
// Store whether or not the index supports 'undefined' documents (that is
// documents with attributes which do not match those of the index
// ...........................................................................
(*baIndex)->_supportUndef = supportUndef;
// ...........................................................................
// Determine the number of bit columns which will comprise the bit array index.
// ...........................................................................
numArrays = cardinality;
// ...........................................................................
// Create the bit arrays
// ...........................................................................
result = TRI_InitBitarray(&((*baIndex)->_bitarray), memoryZone, numArrays, NULL);
// ...........................................................................
// return the result of creating the bit arrays
// ...........................................................................
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief adds (inserts) a data element into one or more bit arrays
////////////////////////////////////////////////////////////////////////////////
int BitarrayIndex_add(BitarrayIndex* baIndex, BitarrayIndexElement* element) {
int result;
TRI_bitarray_mask_t mask;
// ..........................................................................
// At the current time we have no way in which to store undefined documents
// need some sort of parameter passed here.
// ..........................................................................
// ..........................................................................
// generate bit mask -- initialise first
// ..........................................................................
mask._mask = 0;
mask._ignoreMask = 0;
result = BitarrayIndex_generateInsertBitMask(baIndex, element, &mask);
//debugPrintMask(baIndex, mask._mask);
// ..........................................................................
// It may happen that the values for one or more attributes are unsupported
// in this an error will be returned.
// ..........................................................................
if (result != TRI_ERROR_NO_ERROR) {
return result;
}
// ..........................................................................
// insert the bit mask into the bit array
// ..........................................................................
result = TRI_InsertBitMaskElementBitarray(baIndex->_bitarray, &mask, element->data);
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief attempts to locate one or more documents which match an index operator
////////////////////////////////////////////////////////////////////////////////
TRI_index_iterator_t* BitarrayIndex_find(BitarrayIndex* baIndex,
TRI_index_operator_t* indexOperator,
TRI_vector_t* shapeList,
void* collectionIndex,
bool (*filter) (TRI_index_iterator_t*) ) {
TRI_index_iterator_t* iterator;
TRI_bitarray_mask_set_t maskSet;
int result;
// ...........................................................................
// Attempt to allocate memory for the index iterator which stores the results
// if any of the lookup.
// ...........................................................................
iterator = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_index_iterator_t), true);
if (iterator == NULL) {
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
return NULL; // calling procedure needs to care when the iterator is null
}
// ...........................................................................
// We now initialise the index iterator with all the call back functions.
// ...........................................................................
TRI_InitVector(&(iterator->_intervals), TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_index_iterator_interval_t));
iterator->_index = collectionIndex;
iterator->_currentInterval = 0;
iterator->_cursor = NULL;
iterator->_filter = filter;
iterator->_hasNext = BitarrayIndexHasNextIterationCallback;
iterator->_next = BitarrayIndexNextIterationCallback;
iterator->_nexts = BitarrayIndexNextsIterationCallback;
iterator->_hasPrev = BitarrayIndexHasPrevIterationCallback;
iterator->_prev = BitarrayIndexPrevIterationCallback;
iterator->_prevs = BitarrayIndexPrevsIterationCallback;
iterator->_destroyIterator = BitarrayIndexDestroyIterator;
iterator->_reset = BitarrayIndexResetIterator;
// ...........................................................................
// We now initialise the mask set and set the array to some reasonable size
// ...........................................................................
maskSet._setSize = 0;
maskSet._arraySize = 0;
maskSet._maskArray = 0;
BitarrayIndex_extendMaskSet(&maskSet, 20, 0.0);
result = BitarrayIndex_findHelper(baIndex, shapeList, indexOperator, iterator, &maskSet);
if (result == TRI_ERROR_NO_ERROR) {
//BitarrayIndex_debugPrintMaskHeader("lookup");
//BitarrayIndex_debugPrintMask(baIndex,(maskSet._maskArray)->_mask);
//BitarrayIndex_debugPrintMask(baIndex,(maskSet._maskArray)->_ignoreMask);
//BitarrayIndex_debugPrintMaskFooter("");
result = TRI_LookupBitMaskSetBitarray(baIndex->_bitarray, &maskSet, iterator);
}
BitarrayIndex_destroyMaskSet(&maskSet);
if (result != TRI_ERROR_NO_ERROR) {
return NULL;
}
return iterator;
}
//////////////////////////////////////////////////////////////////////////////////
/// @brief alias for add Index item
//////////////////////////////////////////////////////////////////////////////////
int BitarrayIndex_insert(BitarrayIndex* baIndex, BitarrayIndexElement* element) {
return BitarrayIndex_add(baIndex,element);
}
//////////////////////////////////////////////////////////////////////////////////
/// @brief removes an entry from the bit arrays and master table
//////////////////////////////////////////////////////////////////////////////////
int BitarrayIndex_remove(BitarrayIndex* baIndex, BitarrayIndexElement* element) {
int result;
result = TRI_RemoveElementBitarray(baIndex->_bitarray, element->data);
return result;
}
//////////////////////////////////////////////////////////////////////////////////
/// @brief updates a bit array index entry
//////////////////////////////////////////////////////////////////////////////////
int BitarrayIndex_update(BitarrayIndex* baIndex,
const BitarrayIndexElement* oldElement,
const BitarrayIndexElement* newElement) {
assert(false);
return TRI_ERROR_INTERNAL;
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// Implementation of static functions forward declared above
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// .............................................................................
// forward declaration of static functions used for iterator callbacks
// .............................................................................
void BitarrayIndexDestroyIterator(TRI_index_iterator_t* iterator) {
TRI_DestroyVector(&(iterator->_intervals));
}
bool BitarrayIndexHasNextIterationCallback(TRI_index_iterator_t* iterator) {
if (iterator->_intervals._length == 0) {
return false;
}
if (iterator->_currentInterval >= iterator->_intervals._length) {
return false;
}
return true;
}
void* BitarrayIndexNextIterationCallback(TRI_index_iterator_t* iterator) {
TRI_index_iterator_interval_t* interval;
iterator->_currentDocument = NULL;
if (iterator->_cursor == NULL) {
iterator->_currentInterval = 0;
}
if (iterator->_intervals._length == 0) {
return NULL;
}
if (iterator->_currentInterval >= iterator->_intervals._length) {
return NULL;
}
interval = (TRI_index_iterator_interval_t*)(TRI_AtVector(&(iterator->_intervals),iterator->_currentInterval));
if (interval == NULL) { // should not occur -- something is wrong
LOG_WARNING("internal error in BitarrayIndexNextIterationCallback");
return NULL;
}
iterator->_cursor = interval->_leftEndPoint;
iterator->_currentDocument = interval->_leftEndPoint;
++iterator->_currentInterval;
return iterator->_currentDocument;
}
void* BitarrayIndexNextsIterationCallback(TRI_index_iterator_t* iterator, int64_t jumpSize) {
int64_t j;
void* result = NULL;
void* lastValidResult = NULL;
for (j = 0; j < jumpSize; ++j) {
result = BitarrayIndexNextIterationCallback(iterator);
if (result != NULL) {
lastValidResult = result;
}
if (result == NULL) {
break;
}
}
return lastValidResult;
}
bool BitarrayIndexHasPrevIterationCallback(TRI_index_iterator_t* iterator) {
if (iterator->_intervals._length == 0) {
return false;
}
if (iterator->_currentInterval >= iterator->_intervals._length) {
return false;
}
return true;
}
void* BitarrayIndexPrevIterationCallback(TRI_index_iterator_t* iterator) {
TRI_index_iterator_interval_t* interval;
iterator->_currentDocument = NULL;
if (iterator->_cursor == NULL) {
iterator->_currentInterval = iterator->_intervals._length - 1;
}
if (iterator->_currentInterval >= iterator->_intervals._length) {
return NULL;
}
if (iterator->_intervals._length == 0) {
return NULL;
}
interval = (TRI_index_iterator_interval_t*)(TRI_AtVector(&(iterator->_intervals),iterator->_currentInterval));
if (interval == NULL) { // should not occur -- something is wrong
LOG_WARNING("internal error in BitarrayIndexPrevIterationCallback");
return NULL;
}
iterator->_cursor = interval->_leftEndPoint;
iterator->_currentDocument = interval->_leftEndPoint;
if (iterator->_currentInterval == 0) {
iterator->_currentInterval = iterator->_intervals._length;
}
else {
--iterator->_currentInterval;
}
return iterator->_currentDocument;
}
void* BitarrayIndexPrevsIterationCallback(TRI_index_iterator_t* iterator, int64_t jumpSize) {
int64_t j;
void* result = NULL;
void* lastValidResult = NULL;
for (j = 0; j < jumpSize; ++j) {
result = BitarrayIndexPrevIterationCallback(iterator);
if (result != NULL) {
lastValidResult = result;
}
if (result == NULL) {
break;
}
}
return lastValidResult;
}
void BitarrayIndexResetIterator(TRI_index_iterator_t* iterator, bool beginning) {
if (beginning) {
iterator->_cursor = NULL;
iterator->_currentInterval = 0;
iterator->_currentDocument = NULL;
return;
}
iterator->_cursor = NULL;
iterator->_currentInterval = 0;
iterator->_currentDocument = NULL;
if (iterator->_intervals._length > 0) {
iterator->_currentInterval = iterator->_intervals._length - 1;
}
}
// .............................................................................
// forward declaration of static functions used internally here
// .............................................................................
int BitarrayIndex_findHelper(BitarrayIndex* baIndex,
TRI_vector_t* shapeList,
TRI_index_operator_t* indexOperator,
TRI_index_iterator_t* iterator,
TRI_bitarray_mask_set_t* maskSet) {
int result;
// ............................................................................
// Process the indexOperator recursively
// ............................................................................
switch (indexOperator->_type) {
case TRI_AND_INDEX_OPERATOR: {
int j;
TRI_bitarray_mask_set_t leftMaskSet;
TRI_bitarray_mask_set_t rightMaskSet;
TRI_logical_index_operator_t* logicalOperator = (TRI_logical_index_operator_t*)(indexOperator);
TRI_index_operator_t* leftOp = logicalOperator->_left;
TRI_index_operator_t* rightOp = logicalOperator->_right;
leftMaskSet._setSize = 0;
leftMaskSet._arraySize = 0;
leftMaskSet._maskArray = 0;
BitarrayIndex_extendMaskSet(&leftMaskSet, 20, 0.0);
rightMaskSet._setSize = 0;
rightMaskSet._arraySize = 0;
rightMaskSet._maskArray = 0;
BitarrayIndex_extendMaskSet(&rightMaskSet, 20, 0.0);
// ........................................................................
// For 'AND' operator, we simply take the intersection of the masks generated
// ........................................................................
result = BitarrayIndex_findHelper(baIndex, shapeList, leftOp, iterator, &leftMaskSet);
if (result != TRI_ERROR_NO_ERROR) {
BitarrayIndex_destroyMaskSet(&leftMaskSet);
return result;
}
result = BitarrayIndex_findHelper(baIndex, shapeList, rightOp, iterator, &rightMaskSet);
if (result != TRI_ERROR_NO_ERROR) {
BitarrayIndex_destroyMaskSet(&rightMaskSet);
return result;
}
for (j = 0; j < leftMaskSet._setSize; ++j) {
int k;
TRI_bitarray_mask_t* leftMask = leftMaskSet._maskArray + j;
TRI_bitarray_mask_t andMask;
leftMask->_mask = leftMask->_mask | leftMask->_ignoreMask;
for (k = 0; k < rightMaskSet._setSize; ++k) {
TRI_bitarray_mask_t* rightMask = rightMaskSet._maskArray + k;
rightMask->_mask = rightMask->_mask | rightMask->_ignoreMask;
andMask._mask = leftMask->_mask & rightMask->_mask;
andMask._ignoreMask = 0;
BitarrayIndex_insertMaskSet(maskSet,&andMask, true);
}
}
break;
}
case TRI_OR_INDEX_OPERATOR: {
TRI_logical_index_operator_t* logicalOperator = (TRI_logical_index_operator_t*)(indexOperator);
TRI_index_operator_t* leftOp = logicalOperator->_left;
TRI_index_operator_t* rightOp = logicalOperator->_right;
// ........................................................................
// For 'OR' operator, we simply take the union of the masks generated
// ........................................................................
result = BitarrayIndex_findHelper(baIndex, shapeList, leftOp, iterator, maskSet);
if (result != TRI_ERROR_NO_ERROR) {
return result;
}
result = BitarrayIndex_findHelper(baIndex, shapeList, rightOp, iterator, maskSet);
if (result != TRI_ERROR_NO_ERROR) {
return result;
}
break;
}
case TRI_EQ_INDEX_OPERATOR: {
TRI_bitarray_mask_t mask;
TRI_relation_index_operator_t* relationOperator = (TRI_relation_index_operator_t*)(indexOperator);
mask._mask = 0;
mask._ignoreMask = 0;
// ............................................................................
// for bitarray indexes, the number of attribute values ALWAYS matches the
// the number of parameters for a TRI_EQ_INDEX_OPERATOR. However, the client
// may wish some attributes to be ignored, so some values will be '{}'.
// ............................................................................
if (relationOperator->_numFields != shapeList->_length) {
assert(false);
}
// ............................................................................
// generate the bit mask
// ............................................................................
result = BitarrayIndex_generateEqualBitMask(baIndex, relationOperator, &mask);
//BitarrayIndex_debugPrintMask(baIndex, mask._mask);
//BitarrayIndex_debugPrintMask(baIndex, mask._ignoreMask);
// .......................................................................
// for now return this error
// .......................................................................
if (result == TRI_ERROR_ARANGO_INDEX_BITARRAY_INSERT_ITEM_UNSUPPORTED_VALUE) {
return result;
}
// .......................................................................
// Append the mask generated here to the mask set
// .......................................................................
BitarrayIndex_insertMaskSet(maskSet,&mask, true);
//BitarrayIndex_debugPrintMaskHeader("lookup");
//BitarrayIndex_debugPrintMask(baIndex,mask._mask);
//BitarrayIndex_debugPrintMask(baIndex,mask._ignoreMask);
//BitarrayIndex_debugPrintMaskFooter("");
break;
}
case TRI_NE_INDEX_OPERATOR: {
// todo
assert(false);
break;
}
case TRI_LE_INDEX_OPERATOR: {
// todo -- essentially (since finite number) take the union
assert(false);
break;
}
case TRI_LT_INDEX_OPERATOR: {
// todo
assert(false);
break;
}
case TRI_GE_INDEX_OPERATOR: {
// todo
assert(false);
break;
}
case TRI_GT_INDEX_OPERATOR: {
// todo
assert(false);
break;
}
default: {
assert(0);
}
} // end of switch statement
return result;
}
////////////////////////////////////////////////////////////////////////////////
// Given the index structure and the list of shaped json values which came from
// some document we generate a bit mask.
////////////////////////////////////////////////////////////////////////////////
static bool isEqualJson(TRI_json_t* left, TRI_json_t* right) {
if (left == NULL && right == NULL) {
return true;
}
if (left == NULL || right == NULL) {
return false;
}
if (left->_type != right->_type) {
return false;
}
switch (left->_type) {
case TRI_JSON_UNUSED: {
return true;
}
case TRI_JSON_NULL: {
return true;
}
case TRI_JSON_BOOLEAN: {
return (left->_value._boolean == right->_value._boolean);
}
case TRI_JSON_NUMBER: {
return (left->_value._number == right->_value._number);
}
case TRI_JSON_STRING: {
return (strcmp(left->_value._string.data, right->_value._string.data) == 0);
}
case TRI_JSON_ARRAY: {
int j;
if (left->_value._objects._length != right->_value._objects._length) {
return false;
}
for (j = 0; j < (left->_value._objects._length / 2); ++j) {
TRI_json_t* leftName;
TRI_json_t* leftValue;
TRI_json_t* rightValue;
leftName = (TRI_json_t*)(TRI_AtVector(&(left->_value._objects),2*j));
if (leftName == NULL) {
return false;
}
leftValue = (TRI_json_t*)(TRI_AtVector(&(left->_value._objects),(2*j) + 1));
rightValue = TRI_LookupArrayJson(right, leftName->_value._string.data);
if (isEqualJson(leftValue, rightValue)) {
continue;
}
return false;
}
return true;
}
case TRI_JSON_LIST: {
int j;
if (left->_value._objects._length != right->_value._objects._length) {
return false;
}
for (j = 0; j < left->_value._objects._length; ++j) {
TRI_json_t* subLeft;
TRI_json_t* subRight;
subLeft = (TRI_json_t*)(TRI_AtVector(&(left->_value._objects),j));
subRight = (TRI_json_t*)(TRI_AtVector(&(right->_value._objects),j));
if (isEqualJson(subLeft, subRight)) {
continue;
}
return false;
}
return true;
}
default: {
assert(false);
}
}
}
////////////////////////////////////////////////////////////////////////////////
// Implementation of static functions used for bit mask callbacks
////////////////////////////////////////////////////////////////////////////////
static void BitarrayIndex_destroyMaskSet(TRI_bitarray_mask_set_t* maskSet) {
if (maskSet != 0) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, maskSet->_maskArray);
}
}
static void BitarrayIndex_extendMaskSet(TRI_bitarray_mask_set_t* maskSet, const int nSize, const double increaseBy) {
size_t newSize;
TRI_bitarray_mask_t* newArray;
if (nSize <= 0) {
newSize = (increaseBy * maskSet->_arraySize) + 1;
}
else {
newSize = nSize;
}
newArray = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_bitarray_mask_t) * newSize, true);
if (newArray == NULL) {
// todo report memory failure
return;
}
if (maskSet->_maskArray == 0 || maskSet->_arraySize == 0) {
maskSet->_maskArray = newArray;
maskSet->_arraySize = newSize;
maskSet->_setSize = 0;
return;
}
memcpy(newArray, maskSet->_maskArray, sizeof(TRI_bitarray_mask_t) * maskSet->_setSize);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, maskSet->_maskArray);
maskSet->_maskArray = newArray;
maskSet->_arraySize = newSize;
}
static void BitarrayIndex_freeMaskSet(TRI_bitarray_mask_set_t* maskSet) {
BitarrayIndex_destroyMaskSet(maskSet);
if (maskSet != 0) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, maskSet);
}
}
static int BitarrayIndex_generateEqualBitMaskHelper(TRI_json_t* valueList, TRI_json_t* value, uint64_t* mask) {
int i;
uint64_t other = 0;
uint64_t tempMask = 0;
// .............................................................................
// valueList is a list of possible values for a given attribute.
// value is the attribute value to determine if it exists within the list of
// allowed values.
// .............................................................................
for (i = 0; i < valueList->_value._objects._length; ++i) {
int k;
TRI_json_t* listEntry = (TRI_json_t*)(TRI_AtVector(&(valueList->_value._objects), i));
// ...........................................................................
// if the ith possible set of values is not a list, do comparison
// ...........................................................................
if (listEntry->_type != TRI_JSON_LIST) {
if (isEqualJson(value, listEntry)) {
tempMask = tempMask | (1 << i);
}
continue; // there may be further matches!
}
// ...........................................................................
// ith entry in the set of possible values is a list
// ...........................................................................
// ...........................................................................
// Special case of an empty list -- this means all other values
// ...........................................................................
if (listEntry->_value._objects._length == 0) { // special case determine what the bit position of other is
other = (1 << i);
continue; // there may be further matches!
}
for (k = 0; k < listEntry->_value._objects._length; k++) {
TRI_json_t* subListEntry;
subListEntry = (TRI_json_t*)(TRI_AtVector(&(listEntry->_value._objects), k));
if (isEqualJson(value, subListEntry)) {
tempMask = tempMask | (1 << i);
break;
}
}
}
if (tempMask != 0) {
*mask = *mask | tempMask;
return TRI_ERROR_NO_ERROR;
}
if (other != 0) {
*mask = *mask | other;
return TRI_ERROR_NO_ERROR;
}
// ...........................................................................
// Allow this as an option when Bitarray index is created.
// ...........................................................................
return TRI_ERROR_ARANGO_INDEX_BITARRAY_INSERT_ITEM_UNSUPPORTED_VALUE;
}
int BitarrayIndex_generateInsertBitMask(BitarrayIndex* baIndex, const BitarrayIndexElement* element, TRI_bitarray_mask_t* mask) {
TRI_shaper_t* shaper;
int j;
int shiftLeft;
int result;
// ...........................................................................
// some safety checks first
// ...........................................................................
if (baIndex == NULL || element == NULL) {
return TRI_ERROR_INTERNAL;
}
if (element->collection == NULL) {
return TRI_ERROR_INTERNAL;
}
// ...........................................................................
// We could be trying to store an 'undefined' document into the bitarray
// We determine this implicitly. If element->numFields b == 0, then we
// assume that the document did not have any matching attributes, yet since
// we are here we wish to store this fact.
// ...........................................................................
if (!baIndex->_supportUndef && (element->numFields == 0 || element->fields == NULL)) {
return TRI_ERROR_INTERNAL;
}
if (baIndex->_supportUndef && element->numFields == 0) {
mask->_mask = 1;
mask->_ignoreMask = 0;
return TRI_ERROR_NO_ERROR;
}
// ...........................................................................
// attempt to convert the stored TRI_shaped_json_t into TRI_Json_t so that
// we can make a comparison between what values the bitarray index requires
// and what values the document has sent.
// ...........................................................................
shaper = ((TRI_doc_collection_t*)(element->collection))->_shaper;
mask->_mask = 0;
shiftLeft = 0;
for (j = 0; j < baIndex->_values._length; ++j) {
TRI_json_t* valueList;
TRI_json_t* value;
uint64_t other;
uint64_t tempMask;
value = TRI_JsonShapedJson(shaper, &(element->fields[j])); // from shaped json to simple json
valueList = (TRI_json_t*)(TRI_AtVector(&(baIndex->_values),j));
other = 0;
tempMask = 0;
// .........................................................................
// value is now the shaped json converted into plain json for comparison
// ........................................................................
result = BitarrayIndex_generateEqualBitMaskHelper(valueList, value, &tempMask);
// ............................................................................
// remove the json entry created from the shaped json
// ............................................................................
TRI_FreeJson(shaper->_memoryZone, value);
if (result != TRI_ERROR_NO_ERROR) {
return result;
}
mask->_mask = mask->_mask | (tempMask << shiftLeft);
shiftLeft += valueList->_value._objects._length;
}
return TRI_ERROR_NO_ERROR;
}
int BitarrayIndex_generateEqualBitMask(BitarrayIndex* baIndex, const TRI_relation_index_operator_t* relationOperator, TRI_bitarray_mask_t* mask) {
int j;
int shiftLeft;
int ignoreShiftLeft;
int result;
// ...........................................................................
// some safety checks first
// ...........................................................................
if (baIndex == NULL || relationOperator == NULL) {
return TRI_ERROR_INTERNAL;
}
// ...........................................................................
// supportUndef -- refers to where the document does not have 1 or more
// attributes which are defined in the index. (Not related to whether or
// not the attribute has a value defined in the set of supported values.)
// ...........................................................................
// ...........................................................................
// if the number of attributes is 0, then something must be wrong
// ...........................................................................
if (relationOperator->_numFields == 0) {
return TRI_ERROR_INTERNAL;
}
// ...........................................................................
// if an attribute which was defined in the index, was not sent by the client,
// then that bitarray column is ignored.
// ...........................................................................
mask->_mask = 0;
mask->_ignoreMask = 0;
shiftLeft = 0;
ignoreShiftLeft = 0;
for (j = 0; j < baIndex->_values._length; ++j) { // loop over the number of attributes defined in the index
TRI_json_t* valueList;
TRI_json_t* value;
uint64_t tempMask;
value = (TRI_json_t*)(TRI_AtVector(&(relationOperator->_parameters->_value._objects), j));
valueList = (TRI_json_t*)(TRI_AtVector(&(baIndex->_values),j));
ignoreShiftLeft += valueList->_value._objects._length;
// .........................................................................
// client did not send us this attribute (hence undefined value), therefore
// this particular column we ignore
// .........................................................................
if (value->_type == TRI_JSON_UNUSED) {
uint64_t tempInt;
tempMask = ~((~(uint64_t)(0)) << ignoreShiftLeft);
tempInt = (~(uint64_t)(0)) << (ignoreShiftLeft - valueList->_value._objects._length);
mask->_ignoreMask = mask->_ignoreMask | (tempMask & tempInt);
tempMask = 0;
}
// .........................................................................
// the client sent us one or more values for the attribute. If client sent
// us [a_1,a_2,...,a_n] as a value, then this is interpretated as turning
// on those bits. Note that if the value is itself a json list, then
// this must be sent as [[l_1,l_2,...,l_m]]
// .........................................................................
else {
tempMask = 0;
// ........................................................................
// the value (for this jth attribute) sent by the client is NOT a list
// ........................................................................
if (value->_type != TRI_JSON_LIST) {
result = BitarrayIndex_generateEqualBitMaskHelper(valueList, value, &tempMask);
// .......................................................................
// for now return this error
// .......................................................................
if (result == TRI_ERROR_ARANGO_INDEX_BITARRAY_INSERT_ITEM_UNSUPPORTED_VALUE) {
return result;
}
}
// ........................................................................
// the value (for this jth attribute) sent by the client IS a list
// we now have to loop through all the entries in this list
// ........................................................................
else {
int i;
for (i = 0; i < value->_value._objects._length; ++i) {
TRI_json_t* listEntry = (TRI_json_t*)(TRI_AtVector(&(value->_value._objects), i));
result = BitarrayIndex_generateEqualBitMaskHelper(valueList, listEntry, &tempMask);
if (result == TRI_ERROR_ARANGO_INDEX_BITARRAY_INSERT_ITEM_UNSUPPORTED_VALUE) {
return result;
}
}
}
}
// ............................................................................
// When we create a bitarray index, for example: ensureBitarray("x",[0,[],1,2,3])
// and we insert doc with {"x" : "hello world"}, then, since the value of "x"
// does not match 0,1,2 or 3 and [] appears as a valid list item, the doc is
// inserted with a mask of 01000
// This is what other means below
// ............................................................................
mask->_mask = mask->_mask | (tempMask << shiftLeft);
shiftLeft += valueList->_value._objects._length;
}
// ................................................................................
// check whether we actually ignore everything!
// ................................................................................
if (mask->_mask == 0 && !baIndex->_supportUndef) {
return TRI_ERROR_INTERNAL;
}
//debugPrintMaskHeader("lookup mask/ignore mask");
//debugPrintMask(baIndex,mask->_mask);
//debugPrintMask(baIndex,mask->_ignoreMask);
//debugPrintMaskFooter("");
return TRI_ERROR_NO_ERROR;
}
static void BitarrayIndex_insertMaskSet(TRI_bitarray_mask_set_t* maskSet, TRI_bitarray_mask_t* mask, bool checkForDuplicate) {
if (checkForDuplicate) {
int j;
for (j = 0; j < maskSet->_setSize; ++j) {
TRI_bitarray_mask_t* inMask = maskSet->_maskArray + j;
if (inMask->_mask == mask->_mask && inMask->_ignoreMask == mask->_ignoreMask) {
return;
}
}
}
if (maskSet->_setSize == maskSet->_arraySize) {
BitarrayIndex_extendMaskSet(maskSet, -1, 1.2);
}
memcpy((maskSet->_maskArray + maskSet->_setSize), mask, sizeof(TRI_bitarray_mask_t));
++maskSet->_setSize;
}
////////////////////////////////////////////////////////////////////////////////////////
// Implementation of forward declared debug functions
////////////////////////////////////////////////////////////////////////////////////////
/*
void BitarrayIndex_debugPrintMaskFooter(const char* footer) {
printf("%s\n\n",footer);
}
void BitarrayIndex_debugPrintMaskHeader(const char* header) {
printf("------------------- %s --------------------------\n",header);
}
void BitarrayIndex_debugPrintMask(BitarrayIndex* baIndex, uint64_t mask) {
int j;
for (j = 0; j < baIndex->_bitarray->_numColumns; ++j) {
if ((mask & ((uint64_t)(1) << j)) == 0) {
printf("0");
}
else {
printf("1");
}
}
printf("\n");
}
*/
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
// End: