1
0
Fork 0

Merge branch 'devel' of https://github.com/triAGENS/ArangoDB into devel

This commit is contained in:
Jan Steemann 2014-10-10 18:58:07 +02:00
commit 77ff3642c9
14 changed files with 957 additions and 316 deletions

View File

@ -375,7 +375,7 @@ void ExecutionNode::CloneHelper (ExecutionNode* other,
other->_varsValid.insert(var);
}
if (_varOverview.get() != nullptr) {
auto othervarOverview = std::shared_ptr<VarOverview>(_varOverview->clone(plan));
auto othervarOverview = std::shared_ptr<VarOverview>(_varOverview->clone(plan, _plan));
other->_varOverview = othervarOverview;
}
}
@ -388,6 +388,7 @@ void ExecutionNode::CloneHelper (ExecutionNode* other,
other->_varsValid = _varsValid;
other->_varOverview = _varOverview;
}
plan->registerNode(other);
if (withDependencies) {
cloneDependencies(plan, other, withProperties);
@ -619,62 +620,63 @@ triagens::basics::Json ExecutionNode::toJsonHelperGeneric (triagens::basics::Jso
json("id", triagens::basics::Json(static_cast<double>(id())));
json("estimatedCost", triagens::basics::Json(_estimatedCost));
json("depth", triagens::basics::Json(static_cast<double>(_depth)));
if (verbose) {
json("depth", triagens::basics::Json(static_cast<double>(_depth)));
if (_varOverview) {
triagens::basics::Json jsonVarInfoList(triagens::basics::Json::List, _varOverview->varInfo.size());
for (auto oneVarInfo: _varOverview->varInfo) {
triagens::basics::Json jsonOneVarInfoArray(triagens::basics::Json::Array, 2);
jsonOneVarInfoArray(
"VariableId",
triagens::basics::Json(static_cast<double>(oneVarInfo.first)))
("depth", triagens::basics::Json(static_cast<double>(oneVarInfo.second.depth)))
("RegisterId", triagens::basics::Json(static_cast<double>(oneVarInfo.second.registerId)))
;
jsonVarInfoList(jsonOneVarInfoArray);
}
json("varInfoList", jsonVarInfoList);
if (_varOverview) {
triagens::basics::Json jsonVarInfoList(triagens::basics::Json::List, _varOverview->varInfo.size());
for (auto oneVarInfo: _varOverview->varInfo) {
triagens::basics::Json jsonOneVarInfoArray(triagens::basics::Json::Array, 2);
jsonOneVarInfoArray(
"VariableId",
triagens::basics::Json(static_cast<double>(oneVarInfo.first)))
("depth", triagens::basics::Json(static_cast<double>(oneVarInfo.second.depth)))
("RegisterId", triagens::basics::Json(static_cast<double>(oneVarInfo.second.registerId)))
;
jsonVarInfoList(jsonOneVarInfoArray);
}
json("varInfoList", jsonVarInfoList);
triagens::basics::Json jsonNRRegsList(triagens::basics::Json::List, _varOverview->nrRegs.size());
for (auto oneRegisterID: _varOverview->nrRegs) {
jsonNRRegsList(triagens::basics::Json(static_cast<double>(oneRegisterID)));
}
json("nrRegs", jsonNRRegsList);
triagens::basics::Json jsonNRRegsList(triagens::basics::Json::List, _varOverview->nrRegs.size());
for (auto oneRegisterID: _varOverview->nrRegs) {
jsonNRRegsList(triagens::basics::Json(static_cast<double>(oneRegisterID)));
}
json("nrRegs", jsonNRRegsList);
triagens::basics::Json jsonNRRegsHereList(triagens::basics::Json::List, _varOverview->nrRegsHere.size());
for (auto oneRegisterID: _varOverview->nrRegsHere) {
jsonNRRegsHereList(triagens::basics::Json(static_cast<double>(oneRegisterID)));
triagens::basics::Json jsonNRRegsHereList(triagens::basics::Json::List, _varOverview->nrRegsHere.size());
for (auto oneRegisterID: _varOverview->nrRegsHere) {
jsonNRRegsHereList(triagens::basics::Json(static_cast<double>(oneRegisterID)));
}
json("nrRegsHere", jsonNRRegsHereList);
json("totalNrRegs", triagens::basics::Json(static_cast<double>(_varOverview->totalNrRegs)));
}
json("nrRegsHere", jsonNRRegsHereList);
json("totalNrRegs", triagens::basics::Json(static_cast<double>(_varOverview->totalNrRegs)));
else {
json("varInfoList", triagens::basics::Json(triagens::basics::Json::List));
json("nrRegs", triagens::basics::Json(triagens::basics::Json::List));
json("nrRegsHere", triagens::basics::Json(triagens::basics::Json::List));
json("totalNrRegs", triagens::basics::Json(0.0));
}
triagens::basics::Json jsonRegsToClearList(triagens::basics::Json::List, _regsToClear.size());
for (auto oneRegisterID : _regsToClear) {
jsonRegsToClearList(triagens::basics::Json(static_cast<double>(oneRegisterID)));
}
json("regsToClear", jsonRegsToClearList);
triagens::basics::Json jsonVarsUsedLaterList(triagens::basics::Json::List, _varsUsedLater.size());
for (auto oneVarUsedLater: _varsUsedLater) {
jsonVarsUsedLaterList.add(oneVarUsedLater->toJson());
}
json("varsUsedLater", jsonVarsUsedLaterList);
triagens::basics::Json jsonvarsValidList(triagens::basics::Json::List, _varsValid.size());
for (auto oneVarUsedLater: _varsValid) {
jsonvarsValidList.add(oneVarUsedLater->toJson());
}
json("varsValid", jsonvarsValidList);
}
else {
json("varInfoList", triagens::basics::Json(triagens::basics::Json::List));
json("nrRegs", triagens::basics::Json(triagens::basics::Json::List));
json("nrRegsHere", triagens::basics::Json(triagens::basics::Json::List));
json("totalNrRegs", triagens::basics::Json(0.0));
}
triagens::basics::Json jsonRegsToClearList(triagens::basics::Json::List, _regsToClear.size());
for (auto oneRegisterID : _regsToClear) {
jsonRegsToClearList(triagens::basics::Json(static_cast<double>(oneRegisterID)));
}
json("regsToClear", jsonRegsToClearList);
triagens::basics::Json jsonVarsUsedLaterList(triagens::basics::Json::List, _varsUsedLater.size());
for (auto oneVarUsedLater: _varsUsedLater) {
jsonVarsUsedLaterList.add(oneVarUsedLater->toJson());
}
json("varsUsedLater", jsonVarsUsedLaterList);
triagens::basics::Json jsonvarsValidList(triagens::basics::Json::List, _varsValid.size());
for (auto oneVarUsedLater: _varsValid) {
jsonvarsValidList.add(oneVarUsedLater->toJson());
}
json("varsValid", jsonvarsValidList);
return json;
}
@ -782,7 +784,7 @@ void ExecutionNode::VarOverview::clear () {
totalNrRegs = 0;
}
ExecutionNode::VarOverview* ExecutionNode::VarOverview::clone (ExecutionPlan* plan) {
ExecutionNode::VarOverview* ExecutionNode::VarOverview::clone (ExecutionPlan* otherPlan, ExecutionPlan* plan) {
VarOverview* other = new VarOverview();
other->nrRegsHere = nrRegsHere;
@ -794,7 +796,7 @@ ExecutionNode::VarOverview* ExecutionNode::VarOverview::clone (ExecutionPlan* pl
for (auto en: subQueryNodes) {
auto otherId = en->id();
auto otherEN = plan->getNodeById(otherId);
auto otherEN = otherPlan->getNodeById(otherId);
other->subQueryNodes.push_back(otherEN);
}
return other;
@ -1564,6 +1566,11 @@ ExecutionNode* SubqueryNode::clone (ExecutionPlan* plan,
return static_cast<ExecutionNode*>(c);
}
void SubqueryNode::replaceOutVariable(Variable const* var) {
_outVariable = var;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief helper struct to find all (outer) variables used in a SubqueryNode
////////////////////////////////////////////////////////////////////////////////

View File

@ -561,7 +561,7 @@ namespace triagens {
virtual void after (ExecutionNode *eb);
VarOverview* clone(ExecutionPlan* plan);
VarOverview* clone(ExecutionPlan* otherPlan, ExecutionPlan* plan);
};
@ -1555,6 +1555,11 @@ namespace triagens {
return v;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief replace the out variable, so we can adjust the name.
////////////////////////////////////////////////////////////////////////////////
void replaceOutVariable(Variable const* var);
////////////////////////////////////////////////////////////////////////////////
/// @brief can the node throw? Note that this means that an exception can
/// *originate* from this node. That is, this method does not need to

View File

@ -58,6 +58,7 @@ ExecutionPlan::ExecutionPlan (Ast* ast)
_varUsageComputed(false),
_nextId(0),
_ast(ast) {
_lastSubqueryNodeId = (size_t)-1;
}
@ -426,8 +427,15 @@ ExecutionNode* ExecutionPlan::fromNodeLet (ExecutionNode* previous,
}
en = registerNode(new SubqueryNode(this, nextId(), subquery, v));
_lastSubqueryNodeId = en->id();
}
else {
if ((expression->type == NODE_TYPE_REFERENCE) &&
(_lastSubqueryNodeId == _nextId)) {
auto sn = static_cast<SubqueryNode*>(getNodeById(_lastSubqueryNodeId));
sn->replaceOutVariable(v);
return sn;
}
// operand is some misc expression, including references to other variables
auto expr = new Expression(_ast, const_cast<AstNode*>(expression));

View File

@ -456,6 +456,12 @@ namespace triagens {
size_t _nextId;
////////////////////////////////////////////////////////////////////////////////
/// @brief id of last Subquerynode.
////////////////////////////////////////////////////////////////////////////////
size_t _lastSubqueryNodeId;
////////////////////////////////////////////////////////////////////////////////
/// @brief the ast
////////////////////////////////////////////////////////////////////////////////

View File

@ -108,6 +108,7 @@ add_executable(
GeoIndex/GeoIndex.cpp
GeoIndex/geo-index.cpp
HashIndex/hash-array.cpp
HashIndex/hash-array-multi.cpp
HashIndex/hash-index.cpp
IndexOperators/index-operator.cpp
Replication/ContinuousSyncer.cpp

View File

@ -0,0 +1,577 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief multi-hash array implementation, using a linked-list for collisions
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Dr. Oreste Costa-Panaia
/// @author Martin Schoenert
/// @author Jan Steemann
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2004-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "hash-array-multi.h"
#include "Basics/fasthash.h"
#include "HashIndex/hash-index.h"
#include "VocBase/document-collection.h"
// -----------------------------------------------------------------------------
// --SECTION-- COMPARISON
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief destroys an element, removing any allocated memory
////////////////////////////////////////////////////////////////////////////////
static void DestroyElement (TRI_hash_array_multi_t* array,
TRI_hash_index_element_multi_t* element) {
TRI_ASSERT_EXPENSIVE(element != nullptr);
TRI_ASSERT_EXPENSIVE(element->_document != nullptr);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, element->_subObjects);
element->_document = nullptr;
element->_next = nullptr;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief determines if a key corresponds to an element
////////////////////////////////////////////////////////////////////////////////
static bool IsEqualKeyElement (TRI_hash_array_multi_t const* array,
TRI_index_search_value_t const* left,
TRI_hash_index_element_multi_t const* right) {
TRI_ASSERT_EXPENSIVE(right->_document != nullptr);
for (size_t j = 0; j < array->_numFields; ++j) {
TRI_shaped_json_t* leftJson = &left->_values[j];
TRI_shaped_sub_t* rightSub = &right->_subObjects[j];
if (leftJson->_sid != rightSub->_sid) {
return false;
}
auto length = leftJson->_data.length;
if (length != rightSub->_length) {
return false;
}
if (0 < length) {
char const* ptr = right->_document->getShapedJsonPtr() + rightSub->_offset; // ONLY IN INDEX
if (memcmp(leftJson->_data.data, ptr, length) != 0) {
return false;
}
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief given a key generates a hash integer
////////////////////////////////////////////////////////////////////////////////
static uint64_t HashKey (TRI_hash_array_multi_t const* array,
TRI_index_search_value_t const* key) {
uint64_t hash = 0x0123456789abcdef;
for (size_t j = 0; j < array->_numFields; ++j) {
// ignore the sid for hashing
hash = fasthash64(key->_values[j]._data.data, key->_values[j]._data.length, hash);
}
return hash;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief given an element generates a hash integer
////////////////////////////////////////////////////////////////////////////////
static uint64_t HashElement (TRI_hash_array_multi_t const* array,
TRI_hash_index_element_multi_t const* element) {
uint64_t hash = 0x0123456789abcdef;
char const* ptr = element->_document->getShapedJsonPtr(); // ONLY IN INDEX
for (size_t j = 0; j < array->_numFields; j++) {
// ignore the sid for hashing
// only hash the data block
hash = fasthash64(ptr + element->_subObjects[j]._offset, element->_subObjects[j]._length, hash);
}
return hash;
}
// -----------------------------------------------------------------------------
// --SECTION-- HASH ARRAY
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- private defines
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief initial preallocation size of the hash table when the table is
/// first created
/// setting this to a high value will waste memory but reduce the number of
/// reallocations/repositionings necessary when the table grows
////////////////////////////////////////////////////////////////////////////////
static inline uint64_t InitialSize () {
return 251;
}
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief return the size of a single entry
////////////////////////////////////////////////////////////////////////////////
static inline size_t TableEntrySize () {
return sizeof(TRI_hash_index_element_multi_t);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief allocate memory for the hash table
///
/// the hash table memory will be aligned on a cache line boundary
////////////////////////////////////////////////////////////////////////////////
static int AllocateTable (TRI_hash_array_multi_t* array,
uint64_t numElements) {
size_t const size = (size_t) (TableEntrySize() * numElements + 64);
TRI_hash_index_element_multi_t* table = static_cast<TRI_hash_index_element_multi_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, size, true));
if (table == nullptr) {
return TRI_ERROR_OUT_OF_MEMORY;
}
array->_tablePtr = table;
array->_table = static_cast<TRI_hash_index_element_multi_t*>(TRI_Align64(table));
array->_nrAlloc = numElements;
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief resizes the array
////////////////////////////////////////////////////////////////////////////////
static int ResizeHashArray (TRI_hash_array_multi_t* array,
uint64_t targetSize,
bool allowShrink) {
if (array->_nrAlloc >= targetSize && ! allowShrink) {
return TRI_ERROR_NO_ERROR;
}
TRI_hash_index_element_multi_t* oldTable = array->_table;
TRI_hash_index_element_multi_t* oldTablePtr = array->_tablePtr;
uint64_t oldAlloc = array->_nrAlloc;
TRI_ASSERT(targetSize > 0);
int res = AllocateTable(array, targetSize);
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
if (array->_nrUsed > 0) {
uint64_t const n = array->_nrAlloc;
for (uint64_t j = 0; j < oldAlloc; j++) {
TRI_hash_index_element_multi_t* element = &oldTable[j];
if (element->_document != nullptr) {
uint64_t i, k;
i = k = HashElement(array, element) % n;
for (; i < n && array->_table[i]._document != nullptr; ++i);
if (i == n) {
for (i = 0; i < k && array->_table[i]._document != nullptr; ++i);
}
TRI_ASSERT_EXPENSIVE(i < n);
// ...........................................................................
// add a new element to the associative array
// memcpy ok here since are simply moving array items internally
// ...........................................................................
memcpy(&array->_table[i], element, TableEntrySize());
}
}
}
TRI_Free(TRI_UNKNOWN_MEM_ZONE, oldTablePtr);
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief triggers a resize if necessary
////////////////////////////////////////////////////////////////////////////////
static bool CheckResize (TRI_hash_array_multi_t* array) {
if (array->_nrAlloc < 2 * array->_nrUsed) {
int res = ResizeHashArray(array, 2 * array->_nrAlloc + 1, false);
if (res != TRI_ERROR_NO_ERROR) {
return false;
}
}
return true;
}
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief initialises an array
////////////////////////////////////////////////////////////////////////////////
int TRI_InitHashArrayMulti (TRI_hash_array_multi_t* array,
size_t numFields) {
TRI_ASSERT(numFields > 0);
array->_numFields = numFields;
array->_tablePtr = nullptr;
array->_table = nullptr;
array->_nrUsed = 0;
array->_nrAlloc = 0;
array->_nrOverflow = 0;
return AllocateTable(array, InitialSize());
}
////////////////////////////////////////////////////////////////////////////////
/// @brief destroys an array, but does not free the pointer
////////////////////////////////////////////////////////////////////////////////
void TRI_DestroyHashArrayMulti (TRI_hash_array_multi_t* array) {
if (array == nullptr) {
return;
}
// ...........................................................................
// Go through each item in the array and remove any internal allocated memory
// ...........................................................................
// array->_table might be NULL if array initialisation fails
if (array->_table != nullptr) {
TRI_hash_index_element_multi_t* p;
TRI_hash_index_element_multi_t* e;
p = array->_table;
e = p + array->_nrAlloc;
for (; p < e; ++p) {
auto current = p;
while (current != nullptr && current->_document != nullptr) {
auto ptr = current->_next;
DestroyElement(array, current);
if (current != p) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, current);
}
current = ptr;
}
}
TRI_Free(TRI_UNKNOWN_MEM_ZONE, array->_tablePtr);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief destroys an array and frees the pointer
////////////////////////////////////////////////////////////////////////////////
void TRI_FreeHashArrayMulti (TRI_hash_array_multi_t* array) {
if (array != nullptr) {
TRI_DestroyHashArrayMulti(array);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, array);
}
}
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief get the hash array's memory usage
////////////////////////////////////////////////////////////////////////////////
size_t TRI_MemoryUsageHashArrayMulti (TRI_hash_array_multi_t const* array) {
if (array == nullptr) {
return 0;
}
size_t tableSize = (size_t) (array->_nrAlloc * TableEntrySize() + 64);
size_t memberSize = (size_t) (array->_nrUsed * array->_numFields * sizeof(TRI_shaped_sub_t));
size_t overflowSize = (size_t) (array->_nrOverflow * array->_numFields * sizeof(TRI_shaped_sub_t));
return (size_t) (tableSize + memberSize + overflowSize);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief resizes the hash table
////////////////////////////////////////////////////////////////////////////////
int TRI_ResizeHashArrayMulti (TRI_hash_array_multi_t* array,
size_t size) {
return ResizeHashArray(array, (uint64_t) (2 * size + 1), false);
}
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief lookups an element given a key
////////////////////////////////////////////////////////////////////////////////
TRI_vector_pointer_t TRI_LookupByKeyHashArrayMulti (TRI_hash_array_multi_t const* array,
TRI_index_search_value_t const* key) {
TRI_ASSERT_EXPENSIVE(array->_nrUsed < array->_nrAlloc);
// ...........................................................................
// initialise the vector which will hold the result if any
// ...........................................................................
TRI_vector_pointer_t result;
TRI_InitVectorPointer(&result, TRI_UNKNOWN_MEM_ZONE);
uint64_t const n = array->_nrAlloc;
uint64_t i, k;
i = k = HashKey(array, key) % n;
for (; i < n && array->_table[i]._document != nullptr && ! IsEqualKeyElement(array, key, &array->_table[i]); ++i);
if (i == n) {
for (i = 0; i < k && array->_table[i]._document != nullptr && ! IsEqualKeyElement(array, key, &array->_table[i]); ++i);
}
TRI_ASSERT_EXPENSIVE(i < n);
if (array->_table[i]._document != nullptr) {
auto current = &array->_table[i];
while (current != nullptr) {
if (IsEqualKeyElement(array, key, current)) {
TRI_PushBackVectorPointer(&result, current);
}
current = current->_next;
}
}
// ...........................................................................
// return whatever we found -- which could be an empty vector list if nothing
// matches.
// ...........................................................................
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief adds an element to the array
///
/// This function claims the owenship of the sub-objects in the inserted
/// element.
////////////////////////////////////////////////////////////////////////////////
int TRI_InsertElementHashArrayMulti (TRI_hash_array_multi_t* array,
TRI_index_search_value_t const* key,
TRI_hash_index_element_multi_t* element,
bool isRollback) {
if (! CheckResize(array)) {
return TRI_ERROR_OUT_OF_MEMORY;
}
element->_next = nullptr;
uint64_t const n = array->_nrAlloc;
uint64_t i, k;
i = k = HashKey(array, key) % n;
for (; i < n && array->_table[i]._document != nullptr && ! IsEqualKeyElement(array, key, &array->_table[i]); ++i);
if (i == n) {
for (i = 0; i < k && array->_table[i]._document != nullptr && ! IsEqualKeyElement(array, key, &array->_table[i]); ++i);
}
TRI_ASSERT_EXPENSIVE(i < n);
TRI_hash_index_element_multi_t* arrayElement = &array->_table[i];
// ...........................................................................
// If we found an element, return. While we allow duplicate entries in the
// hash table, we do not allow duplicate elements. Elements would refer to the
// (for example) an actual row in memory. This is different from the
// TRI_InsertElementMultiArray function below where we only have keys to
// differentiate between elements.
// ...........................................................................
bool found = (arrayElement->_document != nullptr);
if (found) {
if (isRollback) {
auto current = arrayElement;
while (current != nullptr) {
if (current->_document == element->_document) {
DestroyElement(array, element);
return TRI_RESULT_ELEMENT_EXISTS;
}
current = current->_next;
}
}
auto ptr = static_cast<TRI_hash_index_element_multi_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_hash_index_element_multi_t), true));
if (ptr == nullptr) {
return TRI_ERROR_OUT_OF_MEMORY;
}
element->_next = arrayElement->_next;
*ptr = *element;
arrayElement->_next = ptr;
array->_nrOverflow++;
return TRI_ERROR_NO_ERROR;
}
// ...........................................................................
// add a new element to the associative array
// ...........................................................................
*arrayElement = *element;
array->_nrUsed++;
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief removes an element from the array
////////////////////////////////////////////////////////////////////////////////
int TRI_RemoveElementHashArrayMulti (TRI_hash_array_multi_t* array,
TRI_index_search_value_t const* key,
TRI_hash_index_element_multi_t* element) {
uint64_t const n = array->_nrAlloc;
uint64_t i, k;
i = k = HashKey(array, key) % n;
for (; i < n && array->_table[i]._document != nullptr && ! IsEqualKeyElement(array, key, &array->_table[i]); ++i);
if (i == n) {
for (i = 0; i < k && array->_table[i]._document != nullptr && ! IsEqualKeyElement(array, key, &array->_table[i]); ++i);
}
TRI_ASSERT_EXPENSIVE(i < n);
TRI_hash_index_element_multi_t* arrayElement = &array->_table[i];
// ...........................................................................
// if we did not find such an item return false
// ...........................................................................
bool found = (arrayElement->_document != nullptr);
if (! found) {
return TRI_RESULT_ELEMENT_NOT_FOUND;
}
if (arrayElement->_document != element->_document) {
auto current = arrayElement;
while (current->_next != nullptr) {
if (current->_next->_document == element->_document) {
auto ptr = current->_next->_next;
DestroyElement(array, current->_next);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, current->_next);
current->_next = ptr;
array->_nrOverflow--;
return TRI_ERROR_NO_ERROR;
}
current = current->_next;
}
}
if (arrayElement->_next != nullptr) {
auto ptr = arrayElement->_next;
DestroyElement(array, arrayElement);
*arrayElement = *ptr;
TRI_Free(TRI_UNKNOWN_MEM_ZONE, ptr);
array->_nrOverflow--;
return TRI_ERROR_NO_ERROR;
}
// ...........................................................................
// remove item
// ...........................................................................
DestroyElement(array, arrayElement);
array->_nrUsed--;
// ...........................................................................
// and now check the following places for items to move here
// ...........................................................................
k = TRI_IncModU64(i, n);
while (array->_table[k]._document != nullptr) {
uint64_t j = HashElement(array, &array->_table[k]) % n;
if ((i < k && ! (i < j && j <= k)) || (k < i && ! (i < j || j <= k))) {
array->_table[i] = array->_table[k];
array->_table[k]._document = nullptr;
i = k;
}
k = TRI_IncModU64(k, n);
}
if (array->_nrUsed == 0) {
ResizeHashArray(array, InitialSize(), true);
}
return TRI_ERROR_NO_ERROR;
}
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

View File

@ -0,0 +1,143 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief multi-hash array implementation, using a linked-list for collisions
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Dr. Oreste Costa-Panaia
/// @author Martin Schoenert
/// @author Jan Steemann
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2006-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_HASH_INDEX_HASH__ARRAY_MULTI_H
#define ARANGODB_HASH_INDEX_HASH__ARRAY_MULTI_H 1
#include "Basics/Common.h"
#include "Basics/vector.h"
// -----------------------------------------------------------------------------
// --SECTION-- forward declarations
// -----------------------------------------------------------------------------
struct TRI_hash_index_element_multi_s;
struct TRI_index_search_value_s;
// -----------------------------------------------------------------------------
// --SECTION-- public types
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief associative array
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_hash_array_multi_s {
size_t _numFields; // the number of fields indexes
uint64_t _nrAlloc; // the size of the table
uint64_t _nrUsed; // the number of used entries
uint64_t _nrOverflow; // the number of overflow entries
struct TRI_hash_index_element_multi_s* _table; // the table itself, aligned to a cache line boundary
struct TRI_hash_index_element_multi_s* _tablePtr; // the table itself
}
TRI_hash_array_multi_t;
// -----------------------------------------------------------------------------
// --SECTION-- HASH ARRAY
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief initialises an array
////////////////////////////////////////////////////////////////////////////////
int TRI_InitHashArrayMulti (TRI_hash_array_multi_t*,
size_t);
////////////////////////////////////////////////////////////////////////////////
/// @brief destroys an array, but does not free the pointer
////////////////////////////////////////////////////////////////////////////////
void TRI_DestroyHashArrayMulti (TRI_hash_array_multi_t*);
////////////////////////////////////////////////////////////////////////////////
/// @brief destroys an array and frees the pointer
////////////////////////////////////////////////////////////////////////////////
void TRI_FreeHashArrayMulti (TRI_hash_array_multi_t*);
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief get the hash array's memory usage
////////////////////////////////////////////////////////////////////////////////
size_t TRI_MemoryUsageHashArrayMulti (TRI_hash_array_multi_t const*);
////////////////////////////////////////////////////////////////////////////////
/// @brief resizes the hash table
////////////////////////////////////////////////////////////////////////////////
int TRI_ResizeHashArrayMulti (TRI_hash_array_multi_t*,
size_t);
////////////////////////////////////////////////////////////////////////////////
/// @brief lookups an element given a key
////////////////////////////////////////////////////////////////////////////////
TRI_vector_pointer_t TRI_LookupByKeyHashArrayMulti (TRI_hash_array_multi_t const*,
struct TRI_index_search_value_s const*);
////////////////////////////////////////////////////////////////////////////////
/// @brief adds an element to the array
////////////////////////////////////////////////////////////////////////////////
int TRI_InsertElementHashArrayMulti (TRI_hash_array_multi_t*,
struct TRI_index_search_value_s const*,
struct TRI_hash_index_element_multi_s*,
bool);
////////////////////////////////////////////////////////////////////////////////
/// @brief removes an element from the array
////////////////////////////////////////////////////////////////////////////////
int TRI_RemoveElementHashArrayMulti (TRI_hash_array_multi_t*,
struct TRI_index_search_value_s const*,
struct TRI_hash_index_element_multi_s*);
#endif
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

View File

@ -390,7 +390,8 @@ TRI_hash_index_element_t* TRI_FindByKeyHashArray (TRI_hash_array_t* array,
int TRI_InsertKeyHashArray (TRI_hash_array_t* array,
TRI_index_search_value_t* key,
TRI_hash_index_element_t* element,
bool overwrite) {
bool overwrite,
bool isRollback) {
// ...........................................................................
// we are adding and the table is more than half full, extend it
@ -502,181 +503,6 @@ int TRI_RemoveElementHashArray (TRI_hash_array_t* array,
return TRI_ERROR_NO_ERROR;
}
// -----------------------------------------------------------------------------
// --SECTION-- HASH ARRAY MULTI
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief lookups an element given a key
////////////////////////////////////////////////////////////////////////////////
TRI_vector_pointer_t TRI_LookupByKeyHashArrayMulti (TRI_hash_array_t* array,
TRI_index_search_value_t* key) {
TRI_ASSERT_EXPENSIVE(array->_nrUsed < array->_nrAlloc);
// ...........................................................................
// initialise the vector which will hold the result if any
// ...........................................................................
TRI_vector_pointer_t result;
TRI_InitVectorPointer(&result, TRI_UNKNOWN_MEM_ZONE);
uint64_t const n = array->_nrAlloc;
uint64_t i, k;
i = k = HashKey(array, key) % n;
for (; i < n && array->_table[i]._document != nullptr; ++i) {
if (IsEqualKeyElement(array, key, &array->_table[i])) {
TRI_PushBackVectorPointer(&result, &array->_table[i]);
}
}
if (i == n) {
for (i = 0; i < k && array->_table[i]._document != nullptr; ++i) {
if (IsEqualKeyElement(array, key, &array->_table[i])) {
TRI_PushBackVectorPointer(&result, &array->_table[i]);
}
}
}
TRI_ASSERT_EXPENSIVE(i < n);
// ...........................................................................
// return whatever we found -- which could be an empty vector list if nothing
// matches.
// ...........................................................................
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief adds an element to the array
///
/// This function claims the owenship of the sub-objects in the inserted
/// element.
////////////////////////////////////////////////////////////////////////////////
int TRI_InsertElementHashArrayMulti (TRI_hash_array_t* array,
TRI_hash_index_element_t* element,
bool overwrite) {
if (! CheckResize(array)) {
return TRI_ERROR_OUT_OF_MEMORY;
}
uint64_t const n = array->_nrAlloc;
uint64_t i, k;
i = k = HashElement(array, element) % n;
for (; i < n && array->_table[i]._document != nullptr && element->_document != array->_table[i]._document; ++i);
if (i == n) {
for (i = 0; i < k && array->_table[i]._document != nullptr && element->_document != array->_table[i]._document; ++i);
}
TRI_ASSERT_EXPENSIVE(i < n);
TRI_hash_index_element_t* arrayElement = &array->_table[i];
// ...........................................................................
// If we found an element, return. While we allow duplicate entries in the
// hash table, we do not allow duplicate elements. Elements would refer to the
// (for example) an actual row in memory. This is different from the
// TRI_InsertElementMultiArray function below where we only have keys to
// differentiate between elements.
// ...........................................................................
bool found = (arrayElement->_document != nullptr);
if (found) {
if (overwrite) {
// destroy the underlying element since we are going to stomp on top if it
DestroyElement(array, arrayElement);
*arrayElement = *element;
}
else {
DestroyElement(array, element);
}
return TRI_RESULT_ELEMENT_EXISTS;
}
// ...........................................................................
// add a new element to the associative array
// ...........................................................................
*arrayElement = *element;
array->_nrUsed++;
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief removes an element from the array
////////////////////////////////////////////////////////////////////////////////
int TRI_RemoveElementHashArrayMulti (TRI_hash_array_t* array,
TRI_hash_index_element_t* element) {
uint64_t const n = array->_nrAlloc;
uint64_t i, k;
i = k = HashElement(array, element) % n;
for (; i < n && array->_table[i]._document != nullptr && element->_document != array->_table[i]._document; ++i);
if (i == n) {
for (i = 0; i < k && array->_table[i]._document != nullptr && element->_document != array->_table[i]._document; ++i);
}
TRI_ASSERT_EXPENSIVE(i < n);
TRI_hash_index_element_t* arrayElement = &array->_table[i];
// ...........................................................................
// if we did not find such an item return false
// ...........................................................................
bool found = (arrayElement->_document != nullptr);
if (! found) {
return TRI_RESULT_ELEMENT_NOT_FOUND;
}
// ...........................................................................
// remove item
// ...........................................................................
DestroyElement(array, arrayElement);
array->_nrUsed--;
// ...........................................................................
// and now check the following places for items to move here
// ...........................................................................
k = TRI_IncModU64(i, n);
while (array->_table[k]._document != nullptr) {
uint64_t j = HashElement(array, &array->_table[k]) % n;
if ((i < k && ! (i < j && j <= k)) || (k < i && ! (i < j || j <= k))) {
array->_table[i] = array->_table[k];
array->_table[k]._document = nullptr;
i = k;
}
k = TRI_IncModU64(k, n);
}
if (array->_nrUsed == 0) {
ResizeHashArray(array, InitialSize(), true);
}
return TRI_ERROR_NO_ERROR;
}
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------

View File

@ -125,7 +125,8 @@ struct TRI_hash_index_element_s* TRI_FindByKeyHashArray (TRI_hash_array_t*,
int TRI_InsertKeyHashArray (TRI_hash_array_t*,
struct TRI_index_search_value_s* key,
struct TRI_hash_index_element_s* element,
bool overwrite);
bool overwrite,
bool isRollback);
////////////////////////////////////////////////////////////////////////////////
/// @brief removes an element from the array
@ -134,36 +135,6 @@ int TRI_InsertKeyHashArray (TRI_hash_array_t*,
int TRI_RemoveElementHashArray (TRI_hash_array_t*,
struct TRI_hash_index_element_s* element);
// -----------------------------------------------------------------------------
// --SECTION-- MULTI HASH ARRAY
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief lookups an element given a key
////////////////////////////////////////////////////////////////////////////////
TRI_vector_pointer_t TRI_LookupByKeyHashArrayMulti (TRI_hash_array_t*,
struct TRI_index_search_value_s* key);
////////////////////////////////////////////////////////////////////////////////
/// @brief adds an element to the array
////////////////////////////////////////////////////////////////////////////////
int TRI_InsertElementHashArrayMulti (TRI_hash_array_t*,
struct TRI_hash_index_element_s* element,
bool overwrite);
////////////////////////////////////////////////////////////////////////////////
/// @brief removes an element from the array
////////////////////////////////////////////////////////////////////////////////
int TRI_RemoveElementHashArrayMulti (TRI_hash_array_t*,
struct TRI_hash_index_element_s* element);
#endif
// -----------------------------------------------------------------------------

View File

@ -60,9 +60,10 @@ static inline size_t KeyEntrySize (TRI_hash_index_t const* idx) {
/// @brief fills the index search from hash index element
////////////////////////////////////////////////////////////////////////////////
template<typename T>
static int FillIndexSearchValueByHashIndexElement (TRI_hash_index_t* hashIndex,
TRI_index_search_value_t* key,
TRI_hash_index_element_t* element) {
T* element) {
key->_values = static_cast<TRI_shaped_json_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, KeyEntrySize(hashIndex), false));
if (key->_values == nullptr) {
@ -85,8 +86,9 @@ static int FillIndexSearchValueByHashIndexElement (TRI_hash_index_t* hashIndex,
/// @brief creates space for sub-objects in the hash index element
////////////////////////////////////////////////////////////////////////////////
template<typename T>
static int AllocateSubObjectsHashIndexElement (TRI_hash_index_t const* idx,
TRI_hash_index_element_t* element) {
T* element) {
element->_subObjects = static_cast<TRI_shaped_sub_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, KeyEntrySize(idx), false));
@ -101,7 +103,8 @@ static int AllocateSubObjectsHashIndexElement (TRI_hash_index_t const* idx,
/// @brief frees space for sub-objects in the hash index element
////////////////////////////////////////////////////////////////////////////////
static void FreeSubObjectsHashIndexElement (TRI_hash_index_element_t* element) {
template<typename T>
static void FreeSubObjectsHashIndexElement (T* element) {
if (element->_subObjects != nullptr) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, element->_subObjects);
}
@ -116,8 +119,9 @@ static void FreeSubObjectsHashIndexElement (TRI_hash_index_element_t* element) {
/// hashed and the shape identifier of each part.
////////////////////////////////////////////////////////////////////////////////
template<typename T>
static int HashIndexHelper (TRI_hash_index_t const* hashIndex,
TRI_hash_index_element_t* hashElement,
T* hashElement,
TRI_doc_mptr_t const* document) {
TRI_shaper_t* shaper; // underlying shaper
TRI_shaped_json_t shapedObject; // the sub-object
@ -185,22 +189,23 @@ static int HashIndexHelper (TRI_hash_index_t const* hashIndex,
/// @brief index helper for hashing with allocation
////////////////////////////////////////////////////////////////////////////////
template<typename T>
static int HashIndexHelperAllocate (TRI_hash_index_t const* hashIndex,
TRI_hash_index_element_t* hashElement,
T* hashElement,
TRI_doc_mptr_t const* document) {
// .............................................................................
// Allocate storage to shaped json objects stored as a simple list. These
// will be used for hashing. Fill the json field list from the document.
// .............................................................................
int res = AllocateSubObjectsHashIndexElement(hashIndex, hashElement);
int res = AllocateSubObjectsHashIndexElement<T>(hashIndex, hashElement);
if (res != TRI_ERROR_NO_ERROR) {
// out of memory
return res;
}
res = HashIndexHelper(hashIndex, hashElement, document);
res = HashIndexHelper<T>(hashIndex, hashElement, document);
// .............................................................................
// It may happen that the document does not have the necessary attributes to
@ -213,7 +218,7 @@ static int HashIndexHelperAllocate (TRI_hash_index_t const* hashIndex,
res = TRI_ERROR_NO_ERROR;
}
else if (res != TRI_ERROR_NO_ERROR) {
FreeSubObjectsHashIndexElement(hashElement);
FreeSubObjectsHashIndexElement<T>(hashElement);
}
return res;
@ -235,16 +240,17 @@ static int HashIndexHelperAllocate (TRI_hash_index_t const* hashIndex,
////////////////////////////////////////////////////////////////////////////////
static int HashIndex_insert (TRI_hash_index_t* hashIndex,
TRI_hash_index_element_t* element) {
TRI_hash_index_element_t* element,
bool isRollback) {
TRI_index_search_value_t key;
int res = FillIndexSearchValueByHashIndexElement(hashIndex, &key, element);
int res = FillIndexSearchValueByHashIndexElement<TRI_hash_index_element_t>(hashIndex, &key, element);
if (res != TRI_ERROR_NO_ERROR) {
// out of memory
return res;
}
res = TRI_InsertKeyHashArray(&hashIndex->_hashArray, &key, element, false);
res = TRI_InsertKeyHashArray(&hashIndex->_hashArray, &key, element, false, isRollback);
if (key._values != nullptr) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, key._values);
@ -323,8 +329,21 @@ static TRI_index_result_t HashIndex_find (TRI_hash_index_t* hashIndex,
////////////////////////////////////////////////////////////////////////////////
static int MultiHashIndex_insert (TRI_hash_index_t* hashIndex,
TRI_hash_index_element_t* element) {
int res = TRI_InsertElementHashArrayMulti(&hashIndex->_hashArray, element, false);
TRI_hash_index_element_multi_t* element,
bool isRollback) {
TRI_index_search_value_t key;
int res = FillIndexSearchValueByHashIndexElement<TRI_hash_index_element_multi_t>(hashIndex, &key, element);
if (res != TRI_ERROR_NO_ERROR) {
// out of memory
return res;
}
res = TRI_InsertElementHashArrayMulti(&hashIndex->_hashArrayMulti, &key, element, isRollback);
if (key._values != nullptr) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, key._values);
}
if (res == TRI_RESULT_ELEMENT_EXISTS) {
return TRI_ERROR_INTERNAL;
@ -338,8 +357,20 @@ static int MultiHashIndex_insert (TRI_hash_index_t* hashIndex,
////////////////////////////////////////////////////////////////////////////////
int MultiHashIndex_remove (TRI_hash_index_t* hashIndex,
TRI_hash_index_element_t* element) {
int res = TRI_RemoveElementHashArrayMulti(&hashIndex->_hashArray, element);
TRI_hash_index_element_multi_t* element) {
TRI_index_search_value_t key;
int res = FillIndexSearchValueByHashIndexElement<TRI_hash_index_element_multi_t>(hashIndex, &key, element);
if (res != TRI_ERROR_NO_ERROR) {
// out of memory
return res;
}
res = TRI_RemoveElementHashArrayMulti(&hashIndex->_hashArrayMulti, &key, element);
if (key._values != nullptr) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, key._values);
}
if (res == TRI_RESULT_ELEMENT_NOT_FOUND) {
return TRI_ERROR_INTERNAL;
@ -361,7 +392,7 @@ static TRI_index_result_t MultiHashIndex_find (TRI_hash_index_t* hashIndex,
// we want more than one result returned!
// .............................................................................
TRI_vector_pointer_t result = TRI_LookupByKeyHashArrayMulti(&hashIndex->_hashArray, key);
TRI_vector_pointer_t result = TRI_LookupByKeyHashArrayMulti(&hashIndex->_hashArrayMulti, key);
if (result._length == 0) {
results._length = 0;
@ -369,7 +400,7 @@ static TRI_index_result_t MultiHashIndex_find (TRI_hash_index_t* hashIndex,
}
else {
results._length = result._length;
results._documents = static_cast<TRI_doc_mptr_t**>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, result._length* sizeof(TRI_doc_mptr_t*), false));
results._documents = static_cast<TRI_doc_mptr_t**>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, result._length * sizeof(TRI_doc_mptr_t*), false));
if (results._documents == nullptr) {
// no memory. prevent worst case by re-setting results length to 0
@ -380,7 +411,7 @@ static TRI_index_result_t MultiHashIndex_find (TRI_hash_index_t* hashIndex,
}
for (size_t j = 0; j < result._length; ++j) {
results._documents[j] = ((TRI_hash_index_element_t*)(result._buffer[j]))->_document;
results._documents[j] = ((TRI_hash_index_element_multi_t*)(result._buffer[j]))->_document;
}
}
@ -403,8 +434,14 @@ static TRI_index_result_t MultiHashIndex_find (TRI_hash_index_t* hashIndex,
size_t MemoryHashIndex (TRI_index_t const* idx) {
TRI_hash_index_t const* hashIndex = (TRI_hash_index_t const*) idx;
return static_cast<size_t>(KeyEntrySize(hashIndex) * hashIndex->_hashArray._nrUsed +
TRI_MemoryUsageHashArray(&hashIndex->_hashArray));
if (hashIndex->base._unique) {
return static_cast<size_t>(KeyEntrySize(hashIndex) * hashIndex->_hashArray._nrUsed +
TRI_MemoryUsageHashArray(&hashIndex->_hashArray));
}
else {
return static_cast<size_t>(KeyEntrySize(hashIndex) * hashIndex->_hashArrayMulti._nrUsed +
TRI_MemoryUsageHashArrayMulti(&hashIndex->_hashArrayMulti));
}
}
////////////////////////////////////////////////////////////////////////////////
@ -460,22 +497,34 @@ static int InsertHashIndex (TRI_index_t* idx,
bool isRollback) {
TRI_hash_index_t* hashIndex = (TRI_hash_index_t*) idx;
TRI_hash_index_element_t hashElement;
int res = HashIndexHelperAllocate(hashIndex, &hashElement, document);
if (res == TRI_ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING) {
return TRI_ERROR_NO_ERROR;
}
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
int res;
if (hashIndex->base._unique) {
res = HashIndex_insert(hashIndex, &hashElement);
TRI_hash_index_element_t hashElement;
res = HashIndexHelperAllocate<TRI_hash_index_element_t>(hashIndex, &hashElement, document);
if (res == TRI_ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING) {
return TRI_ERROR_NO_ERROR;
}
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
res = HashIndex_insert(hashIndex, &hashElement, isRollback);
}
else {
res = MultiHashIndex_insert(hashIndex, &hashElement);
TRI_hash_index_element_multi_t hashElement;
res = HashIndexHelperAllocate<TRI_hash_index_element_multi_t>(hashIndex, &hashElement, document);
if (res == TRI_ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING) {
return TRI_ERROR_NO_ERROR;
}
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
res = MultiHashIndex_insert(hashIndex, &hashElement, isRollback);
}
return res;
@ -489,26 +538,37 @@ static int RemoveHashIndex (TRI_index_t* idx,
TRI_doc_mptr_t const* document,
bool isRollback) {
TRI_hash_index_t* hashIndex = (TRI_hash_index_t*) idx;
TRI_hash_index_element_t hashElement;
int res = HashIndexHelperAllocate(hashIndex, &hashElement, document);
if (res == TRI_ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING) {
return TRI_ERROR_NO_ERROR;
}
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
int res;
if (hashIndex->base._unique) {
TRI_hash_index_element_t hashElement;
res = HashIndexHelperAllocate<TRI_hash_index_element_t>(hashIndex, &hashElement, document);
if (res == TRI_ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING) {
return TRI_ERROR_NO_ERROR;
}
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
res = HashIndex_remove(hashIndex, &hashElement);
FreeSubObjectsHashIndexElement<TRI_hash_index_element_t>(&hashElement);
}
else {
TRI_hash_index_element_multi_t hashElement;
res = HashIndexHelperAllocate<TRI_hash_index_element_multi_t>(hashIndex, &hashElement, document);
if (res == TRI_ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING) {
return TRI_ERROR_NO_ERROR;
}
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
res = MultiHashIndex_remove(hashIndex, &hashElement);
FreeSubObjectsHashIndexElement<TRI_hash_index_element_multi_t>(&hashElement);
}
FreeSubObjectsHashIndexElement(&hashElement);
return res;
}
@ -519,7 +579,13 @@ static int RemoveHashIndex (TRI_index_t* idx,
static int SizeHintHashIndex (TRI_index_t* idx,
size_t size) {
TRI_hash_index_t* hashIndex = (TRI_hash_index_t*) idx;
TRI_ResizeHashArray(&hashIndex->_hashArray, size);
if (hashIndex->base._unique) {
TRI_ResizeHashArray(&hashIndex->_hashArray, size);
}
else {
TRI_ResizeHashArrayMulti(&hashIndex->_hashArrayMulti, size);
}
return TRI_ERROR_NO_ERROR;
}
@ -561,9 +627,15 @@ TRI_index_t* TRI_CreateHashIndex (TRI_document_collection_t* document,
TRI_InitVectorString(&idx->_fields, TRI_CORE_MEM_ZONE);
TRI_CopyDataFromVectorPointerVectorString(TRI_CORE_MEM_ZONE, &idx->_fields, fields);
// create a index preallocated for the current number of documents
int res = TRI_InitHashArray(&hashIndex->_hashArray,
hashIndex->_paths._length);
int res;
if (unique) {
res = TRI_InitHashArray(&hashIndex->_hashArray,
hashIndex->_paths._length);
}
else {
res = TRI_InitHashArrayMulti(&hashIndex->_hashArrayMulti,
hashIndex->_paths._length);
}
// oops, out of memory?
if (res != TRI_ERROR_NO_ERROR) {
@ -583,12 +655,16 @@ TRI_index_t* TRI_CreateHashIndex (TRI_document_collection_t* document,
void TRI_DestroyHashIndex (TRI_index_t* idx) {
TRI_hash_index_t* hashIndex;
TRI_DestroyVectorString(&idx->_fields);
hashIndex = (TRI_hash_index_t*) idx;
if (hashIndex->base._unique) {
TRI_DestroyHashArray(&hashIndex->_hashArray);
}
else {
TRI_DestroyHashArrayMulti(&hashIndex->_hashArrayMulti);
}
TRI_DestroyVectorString(&idx->_fields);
TRI_DestroyVector(&hashIndex->_paths);
TRI_DestroyHashArray(&hashIndex->_hashArray);
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -34,6 +34,7 @@
#include "Basics/Common.h"
#include "HashIndex/hash-array.h"
#include "HashIndex/hash-array-multi.h"
#include "VocBase/index.h"
// -----------------------------------------------------------------------------
@ -63,6 +64,13 @@ typedef struct TRI_hash_index_element_s {
}
TRI_hash_index_element_t;
typedef struct TRI_hash_index_element_multi_s {
struct TRI_doc_mptr_t* _document;
struct TRI_shaped_sub_s* _subObjects;
struct TRI_hash_index_element_multi_s* _next;
}
TRI_hash_index_element_multi_t;
////////////////////////////////////////////////////////////////////////////////
/// @brief hash index
////////////////////////////////////////////////////////////////////////////////
@ -70,7 +78,10 @@ TRI_hash_index_element_t;
typedef struct TRI_hash_index_s {
TRI_index_t base;
TRI_hash_array_t _hashArray; // the hash array itself
union {
TRI_hash_array_t _hashArray; // the hash array itself, unique values
TRI_hash_array_multi_t _hashArrayMulti; // the hash array itself, non-unique values
};
TRI_vector_t _paths; // a list of shape pid which identifies the fields of the index
}
TRI_hash_index_t;

View File

@ -89,6 +89,7 @@ arangod_libarangod_a_SOURCES = \
arangod/GeoIndex/GeoIndex.cpp \
arangod/GeoIndex/geo-index.cpp \
arangod/HashIndex/hash-array.cpp \
arangod/HashIndex/hash-array-multi.cpp \
arangod/HashIndex/hash-index.cpp \
arangod/IndexOperators/index-operator.cpp \
arangod/Replication/ContinuousSyncer.cpp \

View File

@ -150,7 +150,6 @@ function EdgeShaper(parent, config, idfunc) {
bindEvent = function (type, func) {
if (type === "update") {
console.log("Overwriting");
addUpdate = func;
} else if (events[type] === undefined) {
throw "Sorry Unknown Event " + type + " cannot be bound.";

View File

@ -1,3 +1,4 @@
/*global require, assertTrue, assertEqual, AQL_EXECUTE, AQL_EXPLAIN */
////////////////////////////////////////////////////////////////////////////////
/// @brief tests for Ahuacatl, subqueries
///
@ -28,6 +29,7 @@
var jsunity = require("jsunity");
var helper = require("org/arangodb/aql-helper");
var getQueryResults = helper.getQueryResults2;
var findExecutionNodes = helper.findExecutionNodes;
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
@ -126,6 +128,14 @@ function ahuacatlSubqueryTestSuite () {
var actual = getQueryResults("LET a = (FOR i IN [ 1, 2, 3 ] LET s = (FOR j IN [ 1, 2 ] RETURN j) RETURN i * s[1]) RETURN a");
assertEqual(expected, actual);
},
testSubqueryOutVariableName : function () {
var XPResult = AQL_EXPLAIN('FOR u IN _users LET theLetVariable = (FOR j IN _users RETURN j) RETURN theLetVariable');
var SubqueryNode = findExecutionNodes(XPResult, "SubqueryNode")[0];
assertEqual(SubqueryNode.outVariable.name, "theLetVariable");
}
};