1
0
Fork 0

moved indexes to cxx

This commit is contained in:
Jan Steemann 2015-05-22 20:15:14 +02:00
parent 20f9be88e4
commit a5b6f00b7f
29 changed files with 4810 additions and 169 deletions

View File

@ -101,6 +101,14 @@ add_executable(
HashIndex/hash-array.cpp
HashIndex/hash-array-multi.cpp
HashIndex/hash-index.cpp
Indexes/CapConstraint.cpp
Indexes/EdgeIndex.cpp
Indexes/FulltextIndex.cpp
Indexes/GeoIndex2.cpp
Indexes/HashIndex.cpp
Indexes/Index.cpp
Indexes/PrimaryIndex.cpp
Indexes/SkiplistIndex2.cpp
IndexOperators/index-operator.cpp
Replication/ContinuousSyncer.cpp
Replication/InitialSyncer.cpp

View File

@ -774,7 +774,7 @@ int TRI_RemoveElementHashArrayMulti (TRI_hash_array_multi_t* array,
/// @brief returns a selectivity estimate for the index
////////////////////////////////////////////////////////////////////////////////
double TRI_SelectivityHashArrayMulti (TRI_hash_array_multi_t* array) {
double TRI_SelectivityHashArrayMulti (TRI_hash_array_multi_t const* array) {
size_t numTotal = static_cast<size_t>(array->_nrUsed + array->_nrOverflowUsed);
if (numTotal == 0) {

View File

@ -160,7 +160,7 @@ int TRI_RemoveElementHashArrayMulti (TRI_hash_array_multi_t*,
/// @brief returns a selectivity estimate for the index
////////////////////////////////////////////////////////////////////////////////
double TRI_SelectivityHashArrayMulti (TRI_hash_array_multi_t*);
double TRI_SelectivityHashArrayMulti (TRI_hash_array_multi_t const*);
#endif

View File

@ -362,7 +362,7 @@ int TRI_ResizeHashArray (TRI_hash_array_t* array,
/// @brief lookups an element given a key
////////////////////////////////////////////////////////////////////////////////
TRI_hash_index_element_t* TRI_LookupByKeyHashArray (TRI_hash_array_t* array,
TRI_hash_index_element_t* TRI_LookupByKeyHashArray (TRI_hash_array_t const* array,
TRI_index_search_value_t* key) {
uint64_t const n = array->_nrAlloc;
uint64_t i, k;
@ -387,7 +387,7 @@ TRI_hash_index_element_t* TRI_LookupByKeyHashArray (TRI_hash_array_t* array,
/// @brief finds an element given a key, return NULL if not found
////////////////////////////////////////////////////////////////////////////////
TRI_hash_index_element_t* TRI_FindByKeyHashArray (TRI_hash_array_t* array,
TRI_hash_index_element_t* TRI_FindByKeyHashArray (TRI_hash_array_t const* array,
TRI_index_search_value_t* key) {
TRI_hash_index_element_t* element = TRI_LookupByKeyHashArray(array, key);

View File

@ -108,14 +108,14 @@ int TRI_ResizeHashArray (TRI_hash_array_t*,
/// @brief lookups an element given a key
////////////////////////////////////////////////////////////////////////////////
struct TRI_hash_index_element_s* TRI_LookupByKeyHashArray (TRI_hash_array_t*,
struct TRI_hash_index_element_s* TRI_LookupByKeyHashArray (TRI_hash_array_t const*,
struct TRI_index_search_value_s* key);
////////////////////////////////////////////////////////////////////////////////
/// @brief finds an element given a key, returns NULL if not found
////////////////////////////////////////////////////////////////////////////////
struct TRI_hash_index_element_s* TRI_FindByKeyHashArray (TRI_hash_array_t*,
struct TRI_hash_index_element_s* TRI_FindByKeyHashArray (TRI_hash_array_t const*,
struct TRI_index_search_value_s* key);
////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,194 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief cap constraint
///
/// @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 Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "CapConstraint.h"
#include "Utils/transactions.h"
#include "VocBase/document-collection.h"
#include "VocBase/transaction.h"
using namespace triagens::arango;
// -----------------------------------------------------------------------------
// --SECTION-- class CapConstraint
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
CapConstraint::CapConstraint (TRI_idx_iid_t iid,
TRI_document_collection_t* collection,
size_t count,
int64_t size)
: Index(iid, std::vector<std::string>()),
_collection(collection),
_count(count),
_size(static_cast<int64_t>(size)) {
initialize();
}
CapConstraint::~CapConstraint () {
}
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
size_t CapConstraint::memory () const {
return 0;
}
triagens::basics::Json CapConstraint::toJson (TRI_memory_zone_t* zone) const {
auto json = Index::toJson(zone);
json("size", triagens::basics::Json(zone, static_cast<double>(_count)))
("byteSize", triagens::basics::Json(zone, static_cast<double>(_size)));
return json;
}
int CapConstraint::insert (TRI_doc_mptr_t const*,
bool) {
return TRI_ERROR_NO_ERROR;
}
int CapConstraint::remove (TRI_doc_mptr_t const*,
bool) {
return TRI_ERROR_NO_ERROR;
}
int CapConstraint::postInsert (TRI_transaction_collection_t* trxCollection,
TRI_doc_mptr_t const*) {
TRI_ASSERT(_count > 0 || _size > 0);
return apply(trxCollection->_collection->_collection, trxCollection);
}
// -----------------------------------------------------------------------------
// --SECTION-- private methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief initialize the cap constraint
////////////////////////////////////////////////////////////////////////////////
int CapConstraint::initialize () {
TRI_ASSERT(_count > 0 || _size > 0);
TRI_headers_t* headers = _collection->_headersPtr; // ONLY IN INDEX (CAP)
int64_t currentCount = static_cast<int64_t>(headers->count());
int64_t currentSize = headers->size();
if ((_count > 0 && currentCount <= _count) &&
(_size > 0 && currentSize <= _size)) {
// nothing to do
return TRI_ERROR_NO_ERROR;
}
else {
TRI_vocbase_t* vocbase = _collection->_vocbase;
TRI_voc_cid_t cid = _collection->_info._cid;
triagens::arango::SingleCollectionWriteTransaction<UINT64_MAX> trx(new triagens::arango::StandaloneTransactionContext(), vocbase, cid);
trx.addHint(TRI_TRANSACTION_HINT_LOCK_NEVER, false);
trx.addHint(TRI_TRANSACTION_HINT_NO_BEGIN_MARKER, false);
trx.addHint(TRI_TRANSACTION_HINT_NO_ABORT_MARKER, false);
trx.addHint(TRI_TRANSACTION_HINT_SINGLE_OPERATION, false); // this is actually not true, but necessary to create trx id 0
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
TRI_transaction_collection_t* trxCollection = trx.trxCollection();
res = apply(_collection, trxCollection);
res = trx.finish(res);
return res;
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief apply the cap constraint for the collection
////////////////////////////////////////////////////////////////////////////////
int CapConstraint::apply (TRI_document_collection_t* document,
TRI_transaction_collection_t* trxCollection) {
TRI_headers_t* headers = document->_headersPtr; // PROTECTED by trx in trxCollection
int64_t currentCount = static_cast<int64_t>(headers->count());
int64_t currentSize = headers->size();
int res = TRI_ERROR_NO_ERROR;
// delete while at least one of the constraints is still violated
while ((_count > 0 && currentCount > _count) ||
(_size > 0 && currentSize > _size)) {
TRI_doc_mptr_t* oldest = headers->front();
if (oldest != nullptr) {
TRI_ASSERT(oldest->getDataPtr() != nullptr); // ONLY IN INDEX, PROTECTED by RUNTIME
size_t oldSize = ((TRI_df_marker_t*) (oldest->getDataPtr()))->_size; // ONLY IN INDEX, PROTECTED by RUNTIME
TRI_ASSERT(oldSize > 0);
if (trxCollection != nullptr) {
res = TRI_DeleteDocumentDocumentCollection(trxCollection, nullptr, oldest);
if (res != TRI_ERROR_NO_ERROR) {
LOG_WARNING("cannot cap collection: %s", TRI_errno_string(res));
break;
}
}
else {
headers->unlink(oldest);
}
currentCount--;
currentSize -= (int64_t) oldSize;
}
else {
// we should not get here
LOG_WARNING("logic error in %s", __FUNCTION__);
break;
}
}
return res;
}
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

View File

@ -0,0 +1,145 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief cap constraint
///
/// @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 Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_INDEXES_CAP_CONSTRAINT_H
#define ARANGODB_INDEXES_CAP_CONSTRAINT_H 1
#include "Basics/Common.h"
#include "Indexes/Index.h"
#include "VocBase/vocbase.h"
#include "VocBase/voc-types.h"
// -----------------------------------------------------------------------------
// --SECTION-- class CapConstraint
// -----------------------------------------------------------------------------
namespace triagens {
namespace arango {
class CapConstraint : public Index {
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
public:
CapConstraint () = delete;
CapConstraint (TRI_idx_iid_t,
struct TRI_document_collection_t*,
size_t,
int64_t);
~CapConstraint ();
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
public:
IndexType type () const override final {
return Index::TRI_IDX_TYPE_CAP_CONSTRAINT;
}
bool hasSelectivityEstimate () const override final {
return false;
}
double selectivityEstimate () const override final;
size_t memory () const override final;
triagens::basics::Json toJson (TRI_memory_zone_t*) const override final;
int insert (struct TRI_doc_mptr_t const*, bool) override final;
int remove (struct TRI_doc_mptr_t const*, bool) override final;
int postInsert (struct TRI_transaction_collection_s*, struct TRI_doc_mptr_t const*) override final;
// -----------------------------------------------------------------------------
// --SECTION-- private methods
// -----------------------------------------------------------------------------
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief initialize the cap constraint
////////////////////////////////////////////////////////////////////////////////
int initialize ();
////////////////////////////////////////////////////////////////////////////////
/// @brief apply the cap constraint for the collection
////////////////////////////////////////////////////////////////////////////////
int apply (TRI_document_collection_t*,
struct TRI_transaction_collection_s*);
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief the underlying collection
////////////////////////////////////////////////////////////////////////////////
struct TRI_document_collection_t* _collection;
////////////////////////////////////////////////////////////////////////////////
/// @brief maximum number of documents in the collection
////////////////////////////////////////////////////////////////////////////////
int64_t const _count;
////////////////////////////////////////////////////////////////////////////////
/// @brief maximum size of documents in the collection
////////////////////////////////////////////////////////////////////////////////
int64_t const _size;
};
}
}
#endif
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

View File

@ -0,0 +1,440 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief edge index
///
/// @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 Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "EdgeIndex.h"
#include "Basics/Exceptions.h"
#include "Basics/fasthash.h"
#include "Basics/hashes.h"
#include "VocBase/document-collection.h"
#include "VocBase/edge-collection.h"
#include "VocBase/transaction.h"
using namespace triagens::arango;
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief hashes an edge key
////////////////////////////////////////////////////////////////////////////////
static uint64_t HashElementKey (void const* data) {
TRI_edge_header_t const* h = static_cast<TRI_edge_header_t const*>(data);
char const* key = h->_key;
uint64_t hash = h->_cid;
hash ^= (uint64_t) fasthash64(key, strlen(key), 0x87654321);
return fasthash64(&hash, sizeof(hash), 0x56781234);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief hashes an edge (_from case)
////////////////////////////////////////////////////////////////////////////////
static uint64_t HashElementEdgeFrom (void const* data,
bool byKey) {
uint64_t hash;
if (! byKey) {
hash = (uint64_t) data;
}
else {
TRI_doc_mptr_t const* mptr = static_cast<TRI_doc_mptr_t const*>(data);
TRI_df_marker_t const* marker = static_cast<TRI_df_marker_t const*>(mptr->getDataPtr()); // ONLY IN INDEX, PROTECTED by RUNTIME
if (marker->_type == TRI_DOC_MARKER_KEY_EDGE) {
TRI_doc_edge_key_marker_t const* edge = reinterpret_cast<TRI_doc_edge_key_marker_t const*>(marker); // ONLY IN INDEX, PROTECTED by RUNTIME
char const* key = (char const*) edge + edge->_offsetFromKey;
// LOG_TRACE("HASH FROM: COLLECTION: %llu, KEY: %s", (unsigned long long) edge->_fromCid, key);
hash = edge->_fromCid;
hash ^= (uint64_t) fasthash64(key, strlen(key), 0x87654321);
}
else if (marker->_type == TRI_WAL_MARKER_EDGE) {
triagens::wal::edge_marker_t const* edge = reinterpret_cast<triagens::wal::edge_marker_t const*>(marker); // ONLY IN INDEX, PROTECTED by RUNTIME
char const* key = (char const*) edge + edge->_offsetFromKey;
// LOG_TRACE("HASH FROM: COLLECTION: %llu, KEY: %s", (unsigned long long) edge->_fromCid, key);
hash = edge->_fromCid;
hash ^= (uint64_t) fasthash64(key, strlen(key), 0x87654321);
}
}
return fasthash64(&hash, sizeof(hash), 0x56781234);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief hashes an edge (_to case)
////////////////////////////////////////////////////////////////////////////////
static uint64_t HashElementEdgeTo (void const* data,
bool byKey) {
uint64_t hash;
if (! byKey) {
hash = (uint64_t) data;
}
else {
TRI_doc_mptr_t const* mptr = static_cast<TRI_doc_mptr_t const*>(data);
TRI_df_marker_t const* marker = static_cast<TRI_df_marker_t const*>(mptr->getDataPtr()); // ONLY IN INDEX, PROTECTED by RUNTIME
if (marker->_type == TRI_DOC_MARKER_KEY_EDGE) {
TRI_doc_edge_key_marker_t const* edge = reinterpret_cast<TRI_doc_edge_key_marker_t const*>(marker); // ONLY IN INDEX, PROTECTED by RUNTIME
char const* key = (char const*) edge + edge->_offsetToKey;
// LOG_TRACE("HASH TO: COLLECTION: %llu, KEY: %s", (unsigned long long) edge->_toCid, key);
hash = edge->_toCid;
hash ^= (uint64_t) fasthash64(key, strlen(key), 0x87654321);
}
else if (marker->_type == TRI_WAL_MARKER_EDGE) {
triagens::wal::edge_marker_t const* edge = reinterpret_cast<triagens::wal::edge_marker_t const*>(marker); // ONLY IN INDEX, PROTECTED by RUNTIME
char const* key = (char const*) edge + edge->_offsetToKey;
// LOG_TRACE("HASH TO: COLLECTION: %llu, KEY: %s", (unsigned long long) edge->_toCid, key);
hash = edge->_toCid;
hash ^= (uint64_t) fasthash64(key, strlen(key), 0x87654321);
}
}
return fasthash64(&hash, sizeof(hash), 0x56781234);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief checks if key and element match (_from case)
////////////////////////////////////////////////////////////////////////////////
static bool IsEqualKeyEdgeFrom (void const* left,
void const* right) {
// left is a key
// right is an element, that is a master pointer
TRI_edge_header_t const* l = static_cast<TRI_edge_header_t const*>(left);
char const* lKey = l->_key;
TRI_doc_mptr_t const* rMptr = static_cast<TRI_doc_mptr_t const*>(right);
TRI_df_marker_t const* marker = static_cast<TRI_df_marker_t const*>(rMptr->getDataPtr()); // ONLY IN INDEX, PROTECTED by RUNTIME
if (marker->_type == TRI_DOC_MARKER_KEY_EDGE) {
TRI_doc_edge_key_marker_t const* rEdge = reinterpret_cast<TRI_doc_edge_key_marker_t const*>(marker); // ONLY IN INDEX, PROTECTED by RUNTIME
char const* rKey = (char const*) rEdge + rEdge->_offsetFromKey;
// LOG_TRACE("ISEQUAL FROM: LCOLLECTION: %llu, LKEY: %s, RCOLLECTION: %llu, RKEY: %s", (unsigned long long) l->_cid, lKey, (unsigned long long) rEdge->_fromCid, rKey);
return (l->_cid == rEdge->_fromCid) && (strcmp(lKey, rKey) == 0);
}
else if (marker->_type == TRI_WAL_MARKER_EDGE) {
triagens::wal::edge_marker_t const* rEdge = reinterpret_cast<triagens::wal::edge_marker_t const*>(marker); // ONLY IN INDEX, PROTECTED by RUNTIME
char const* rKey = (char const*) rEdge + rEdge->_offsetFromKey;
// LOG_TRACE("ISEQUAL FROM: LCOLLECTION: %llu, LKEY: %s, RCOLLECTION: %llu, RKEY: %s", (unsigned long long) l->_cid, lKey, (unsigned long long) rEdge->_fromCid, rKey);
return (l->_cid == rEdge->_fromCid) && (strcmp(lKey, rKey) == 0);
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief checks if key and element match (_to case)
////////////////////////////////////////////////////////////////////////////////
static bool IsEqualKeyEdgeTo (void const* left,
void const* right) {
// left is a key
// right is an element, that is a master pointer
TRI_edge_header_t const* l = static_cast<TRI_edge_header_t const*>(left);
char const* lKey = l->_key;
TRI_doc_mptr_t const* rMptr = static_cast<TRI_doc_mptr_t const*>(right);
TRI_df_marker_t const* marker = static_cast<TRI_df_marker_t const*>(rMptr->getDataPtr()); // ONLY IN INDEX, PROTECTED by RUNTIME
if (marker->_type == TRI_DOC_MARKER_KEY_EDGE) {
TRI_doc_edge_key_marker_t const* rEdge = reinterpret_cast<TRI_doc_edge_key_marker_t const*>(marker); // ONLY IN INDEX, PROTECTED by RUNTIME
char const* rKey = (char const*) rEdge + rEdge->_offsetToKey;
// LOG_TRACE("ISEQUAL TO: LCOLLECTION: %llu, LKEY: %s, RCOLLECTION: %llu, RKEY: %s", (unsigned long long) l->_cid, lKey, (unsigned long long) rEdge->_toCid, rKey);
return (l->_cid == rEdge->_toCid) && (strcmp(lKey, rKey) == 0);
}
else if (marker->_type == TRI_WAL_MARKER_EDGE) {
triagens::wal::edge_marker_t const* rEdge = reinterpret_cast<triagens::wal::edge_marker_t const*>(marker); // ONLY IN INDEX, PROTECTED by RUNTIME
char const* rKey = (char const*) rEdge + rEdge->_offsetToKey;
// LOG_TRACE("ISEQUAL TO: LCOLLECTION: %llu, LKEY: %s, RCOLLECTION: %llu, RKEY: %s", (unsigned long long) l->_cid, lKey, (unsigned long long) rEdge->_toCid, rKey);
return (l->_cid == rEdge->_toCid) && (strcmp(lKey, rKey) == 0);
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief checks for elements are equal (_from and _to case)
////////////////////////////////////////////////////////////////////////////////
static bool IsEqualElementEdge (void const* left,
void const* right) {
return left == right;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief checks for elements are equal (_from case)
////////////////////////////////////////////////////////////////////////////////
static bool IsEqualElementEdgeFromByKey (void const* left,
void const* right) {
char const* lKey = nullptr;
char const* rKey = nullptr;
TRI_voc_cid_t lCid = 0;
TRI_voc_cid_t rCid = 0;
TRI_df_marker_t const* marker;
// left element
TRI_doc_mptr_t const* lMptr = static_cast<TRI_doc_mptr_t const*>(left);
marker = static_cast<TRI_df_marker_t const*>(lMptr->getDataPtr()); // ONLY IN INDEX, PROTECTED by RUNTIME
if (marker->_type == TRI_DOC_MARKER_KEY_EDGE) {
TRI_doc_edge_key_marker_t const* lEdge = reinterpret_cast<TRI_doc_edge_key_marker_t const*>(marker); // ONLY IN INDEX, PROTECTED by RUNTIME
lKey = (char const*) lEdge + lEdge->_offsetFromKey;
lCid = lEdge->_fromCid;
}
else if (marker->_type == TRI_WAL_MARKER_EDGE) {
triagens::wal::edge_marker_t const* lEdge = reinterpret_cast<triagens::wal::edge_marker_t const*>(marker); // ONLY IN INDEX, PROTECTED by RUNTIME
lKey = (char const*) lEdge + lEdge->_offsetFromKey;
lCid = lEdge->_fromCid;
}
// right element
TRI_doc_mptr_t const* rMptr = static_cast<TRI_doc_mptr_t const*>(right);
marker = static_cast<TRI_df_marker_t const*>(rMptr->getDataPtr()); // ONLY IN INDEX, PROTECTED by RUNTIME
if (marker->_type == TRI_DOC_MARKER_KEY_EDGE) {
TRI_doc_edge_key_marker_t const* rEdge = reinterpret_cast<TRI_doc_edge_key_marker_t const*>(marker); // ONLY IN INDEX, PROTECTED by RUNTIME
rKey = (char const*) rEdge + rEdge->_offsetFromKey;
rCid = rEdge->_fromCid;
}
else if (marker->_type == TRI_WAL_MARKER_EDGE) {
triagens::wal::edge_marker_t const* rEdge = reinterpret_cast<triagens::wal::edge_marker_t const*>(marker); // ONLY IN INDEX, PROTECTED by RUNTIME
rKey = (char const*) rEdge + rEdge->_offsetFromKey;
rCid = rEdge->_fromCid;
}
if (lKey == nullptr || rKey == nullptr) {
return false;
}
// LOG_TRACE("ISEQUALELEMENT FROM: LCOLLECTION: %llu, LKEY: %s, RCOLLECTION: %llu, RKEY: %s", (unsigned long long) lCid, lKey, (unsigned long long) rCid, rKey);
return ((lCid == rCid) && (strcmp(lKey, rKey) == 0));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief checks for elements are equal (_to case)
////////////////////////////////////////////////////////////////////////////////
static bool IsEqualElementEdgeToByKey (void const* left,
void const* right) {
char const* lKey = nullptr;
char const* rKey = nullptr;
TRI_voc_cid_t lCid = 0;
TRI_voc_cid_t rCid = 0;
TRI_df_marker_t const* marker;
// left element
TRI_doc_mptr_t const* lMptr = static_cast<TRI_doc_mptr_t const*>(left);
marker = static_cast<TRI_df_marker_t const*>(lMptr->getDataPtr()); // ONLY IN INDEX, PROTECTED by RUNTIME
if (marker->_type == TRI_DOC_MARKER_KEY_EDGE) {
TRI_doc_edge_key_marker_t const* lEdge = reinterpret_cast<TRI_doc_edge_key_marker_t const*>(marker); // ONLY IN INDEX, PROTECTED by RUNTIME
lKey = (char const*) lEdge + lEdge->_offsetToKey;
lCid = lEdge->_toCid;
}
else if (marker->_type == TRI_WAL_MARKER_EDGE) {
triagens::wal::edge_marker_t const* lEdge = reinterpret_cast<triagens::wal::edge_marker_t const*>(marker); // ONLY IN INDEX, PROTECTED by RUNTIME
lKey = (char const*) lEdge + lEdge->_offsetToKey;
lCid = lEdge->_toCid;
}
// right element
TRI_doc_mptr_t const* rMptr = static_cast<TRI_doc_mptr_t const*>(right);
marker = static_cast<TRI_df_marker_t const*>(rMptr->getDataPtr()); // ONLY IN INDEX, PROTECTED by RUNTIME
if (marker->_type == TRI_DOC_MARKER_KEY_EDGE) {
TRI_doc_edge_key_marker_t const* rEdge = reinterpret_cast<TRI_doc_edge_key_marker_t const*>(marker); // ONLY IN INDEX, PROTECTED by RUNTIME
rKey = (char const*) rEdge + rEdge->_offsetToKey;
rCid = rEdge->_toCid;
}
else if (marker->_type == TRI_WAL_MARKER_EDGE) {
triagens::wal::edge_marker_t const* rEdge = reinterpret_cast<triagens::wal::edge_marker_t const*>(marker); // ONLY IN INDEX, PROTECTED by RUNTIME
rKey = (char const*) rEdge + rEdge->_offsetToKey;
rCid = rEdge->_toCid;
}
if (lKey == nullptr || rKey == nullptr) {
return false;
}
// LOG_TRACE("ISEQUALELEMENT TO: LCOLLECTION: %llu, LKEY: %s, RCOLLECTION: %llu, RKEY: %s", (unsigned long long) lCid, lKey, (unsigned long long) rCid, rKey);
return ((lCid == rCid) && (strcmp(lKey, rKey) == 0));
}
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
EdgeIndex::EdgeIndex (TRI_idx_iid_t iid,
TRI_document_collection_t* collection)
: Index(iid, std::vector<std::string>({ TRI_VOC_ATTRIBUTE_FROM, TRI_VOC_ATTRIBUTE_TO })),
_collection(collection),
_edgesFrom(nullptr),
_edgesTo(nullptr) {
uint32_t indexBuckets = 1;
if (collection != nullptr) {
// document is a nullptr in the coordinator case
indexBuckets = collection->_info._indexBuckets;
}
_edgesFrom = new TRI_EdgeIndexHash_t(HashElementKey,
HashElementEdgeFrom,
IsEqualKeyEdgeFrom,
IsEqualElementEdge,
IsEqualElementEdgeFromByKey,
indexBuckets);
_edgesTo = new TRI_EdgeIndexHash_t(HashElementKey,
HashElementEdgeTo,
IsEqualKeyEdgeTo,
IsEqualElementEdge,
IsEqualElementEdgeToByKey,
indexBuckets);
}
EdgeIndex::~EdgeIndex () {
delete _edgesTo;
delete _edgesFrom;
}
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief return a selectivity esimtate for the index
////////////////////////////////////////////////////////////////////////////////
double EdgeIndex::selectivityEstimate () const {
// return average selectivity of the two index parts
return (_edgesFrom->selectivity() + _edgesTo->selectivity()) * 0.5;
}
size_t EdgeIndex::memory () const {
return _edgesFrom->memoryUsage() + _edgesTo->memoryUsage();
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return a JSON representation of the index
////////////////////////////////////////////////////////////////////////////////
triagens::basics::Json EdgeIndex::toJson (TRI_memory_zone_t* zone) const {
auto json = Index::toJson(zone);
triagens::basics::Json f(zone, triagens::basics::Json::Array, fields().size());
for (auto const& field : fields()) {
f.add(triagens::basics::Json(zone, field));
}
json("fields", f);
return json;
}
int EdgeIndex::insert (TRI_doc_mptr_t const* doc,
bool isRollback) {
_edgesFrom->insert(CONST_CAST(doc), true, isRollback);
try {
_edgesTo->insert(CONST_CAST(doc), true, isRollback);
}
catch (...) {
_edgesFrom->remove(doc);
throw;
}
return TRI_ERROR_NO_ERROR;
}
int EdgeIndex::remove (TRI_doc_mptr_t const* doc,
bool) {
_edgesFrom->remove(doc);
_edgesTo->remove(doc);
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief provides a size hint for the edge index
////////////////////////////////////////////////////////////////////////////////
int EdgeIndex::sizeHint (size_t size) {
// we assume this is called when setting up the index and the index
// is still empty
TRI_ASSERT(_edgesFrom->size() == 0);
// set an initial size for the index for some new nodes to be created
// without resizing
int err = _edgesFrom->resize(static_cast<uint32_t>(size + 2049));
if (err != TRI_ERROR_NO_ERROR) {
return err;
}
// we assume this is called when setting up the index and the index
// is still empty
TRI_ASSERT(_edgesTo->size() == 0);
// set an initial size for the index for some new nodes to be created
// without resizing
return _edgesTo->resize(static_cast<uint32_t>(size + 2049));
}
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

127
arangod/Indexes/EdgeIndex.h Normal file
View File

@ -0,0 +1,127 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief edge index
///
/// @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 Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_INDEXES_EDGE_INDEX_H
#define ARANGODB_INDEXES_EDGE_INDEX_H 1
#include "Basics/Common.h"
#include "Basics/AssocMulti.h"
#include "Indexes/Index.h"
#include "VocBase/vocbase.h"
#include "VocBase/voc-types.h"
// -----------------------------------------------------------------------------
// --SECTION-- class EdgeIndex
// -----------------------------------------------------------------------------
namespace triagens {
namespace arango {
class EdgeIndex : public Index {
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
public:
EdgeIndex () = delete;
EdgeIndex (TRI_idx_iid_t,
struct TRI_document_collection_t*);
~EdgeIndex ();
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
public:
IndexType type () const override final {
return Index::TRI_IDX_TYPE_EDGE_INDEX;
}
bool hasSelectivityEstimate () const override final {
return true;
}
double selectivityEstimate () const override final;
size_t memory () const override final;
triagens::basics::Json toJson (TRI_memory_zone_t*) const override final;
int insert (struct TRI_doc_mptr_t const*, bool) override final;
int remove (struct TRI_doc_mptr_t const*, bool) override final;
int sizeHint (size_t) override final;
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
private:
struct TRI_document_collection_t* _collection;
////////////////////////////////////////////////////////////////////////////////
/// @brief typedef for hash tables
////////////////////////////////////////////////////////////////////////////////
typedef triagens::basics::AssocMulti<void, void, uint32_t> TRI_EdgeIndexHash_t;
////////////////////////////////////////////////////////////////////////////////
/// @brief the hash table for _from
////////////////////////////////////////////////////////////////////////////////
TRI_EdgeIndexHash_t* _edgesFrom;
////////////////////////////////////////////////////////////////////////////////
/// @brief the hash table for _to
////////////////////////////////////////////////////////////////////////////////
TRI_EdgeIndexHash_t* _edgesTo;
};
}
}
#endif
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

View File

@ -0,0 +1,323 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief fulltext index
///
/// @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 Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "FulltextIndex.h"
#include "Basics/Utf8Helper.h"
#include "FulltextIndex/fulltext-index.h"
#include "FulltextIndex/fulltext-wordlist.h"
#include "VocBase/document-collection.h"
#include "VocBase/transaction.h"
#include "VocBase/voc-shaper.h"
using namespace triagens::arango;
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief extraction context
////////////////////////////////////////////////////////////////////////////////
struct TextExtractorContext {
std::vector<std::pair<char const*, size_t>>* _positions;
TRI_shaper_t* _shaper;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief walk over an array shape and extract the string values
////////////////////////////////////////////////////////////////////////////////
static bool ArrayTextExtractor (TRI_shaper_t* shaper,
TRI_shape_t const* shape,
char const*,
char const* shapedJson,
uint64_t length,
void* data) {
char* text;
size_t textLength;
bool ok = TRI_StringValueShapedJson(shape, shapedJson, &text, &textLength);
if (ok) {
// add string value found
try {
static_cast<TextExtractorContext*>(data)->_positions->emplace_back(text, textLength);
}
catch (...) {
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief walk over a list shape and extract the string values
////////////////////////////////////////////////////////////////////////////////
static bool ListTextExtractor (TRI_shaper_t* shaper,
TRI_shape_t const* shape,
char const* shapedJson,
uint64_t length,
void* data) {
if (shape->_type == TRI_SHAPE_ARRAY) {
// a sub-object
TRI_IterateShapeDataArray(static_cast<TextExtractorContext*>(data)->_shaper, shape, shapedJson, ArrayTextExtractor, data);
}
else if (shape->_type == TRI_SHAPE_SHORT_STRING ||
shape->_type == TRI_SHAPE_LONG_STRING) {
char* text;
size_t textLength;
bool ok = TRI_StringValueShapedJson(shape, shapedJson, &text, &textLength);
if (ok) {
// add string value found
try {
static_cast<TextExtractorContext*>(data)->_positions->emplace_back(text, textLength);
}
catch (...) {
}
}
}
return true;
}
// -----------------------------------------------------------------------------
// --SECTION-- class FulltextIndex
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
FulltextIndex::FulltextIndex (TRI_idx_iid_t iid,
TRI_document_collection_t* collection,
std::vector<std::string> const& fields,
int minWordLength)
: Index(iid, fields),
_collection(collection),
_attribute(0),
_fulltextIndex(nullptr),
_minWordLength(minWordLength > 0 ? minWordLength : 1) {
// look up the attribute
TRI_shaper_t* shaper = _collection->getShaper(); // ONLY IN INDEX, PROTECTED by RUNTIME
_attribute = shaper->findOrCreateAttributePathByName(shaper, fields[0].c_str());
if (_attribute == 0) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
_fulltextIndex = TRI_CreateFtsIndex(2048, 1, 1);
if (_fulltextIndex == nullptr) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
}
FulltextIndex::~FulltextIndex () {
if (_fulltextIndex != nullptr) {
LOG_TRACE("destroying fulltext index");
TRI_FreeFtsIndex(_fulltextIndex);
}
}
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
size_t FulltextIndex::memory () const {
return TRI_MemoryFulltextIndex(_fulltextIndex);
}
triagens::basics::Json FulltextIndex::toJson (TRI_memory_zone_t* zone) const {
auto json = Index::toJson(zone);
triagens::basics::Json f(zone, triagens::basics::Json::Array, fields().size());
for (auto const& field : fields()) {
f.add(triagens::basics::Json(zone, field));
}
json("fields", f)
("minLength", triagens::basics::Json(zone, static_cast<double>(_minWordLength)));
return json;
}
int FulltextIndex::insert (TRI_doc_mptr_t const* doc,
bool isRollback) {
int res = TRI_ERROR_NO_ERROR;
TRI_fulltext_wordlist_t* words = wordlist(doc);
if (words == nullptr) {
// TODO: distinguish the cases "empty wordlist" and "out of memory"
// LOG_WARNING("could not build wordlist");
return res;
}
if (words->_numWords > 0) {
// TODO: use status codes
if (! TRI_InsertWordsFulltextIndex(_fulltextIndex, (TRI_fulltext_doc_t) ((uintptr_t) doc), words)) {
LOG_ERROR("adding document to fulltext index failed");
res = TRI_ERROR_INTERNAL;
}
}
TRI_FreeWordlistFulltextIndex(words);
return res;
}
int FulltextIndex::remove (TRI_doc_mptr_t const* doc,
bool) {
TRI_DeleteDocumentFulltextIndex(_fulltextIndex, (TRI_fulltext_doc_t) ((uintptr_t) doc));
return TRI_ERROR_NO_ERROR;
}
int FulltextIndex::cleanup () {
LOG_TRACE("fulltext cleanup called");
int res = TRI_ERROR_NO_ERROR;
// check whether we should do a cleanup at all
if (! TRI_CompactFulltextIndex(_fulltextIndex)) {
res = TRI_ERROR_INTERNAL;
}
return res;
}
// -----------------------------------------------------------------------------
// --SECTION-- private methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief callback function called by the fulltext index to determine the
/// words to index for a specific document
////////////////////////////////////////////////////////////////////////////////
TRI_fulltext_wordlist_t* FulltextIndex::wordlist (TRI_doc_mptr_t const* document) {
TRI_shaped_json_t shaped;
TRI_shaped_json_t shapedJson;
TRI_shape_t const* shape;
// extract the shape
TRI_shaper_t* shaper = _collection->getShaper();
TRI_EXTRACT_SHAPED_JSON_MARKER(shaped, document->getDataPtr()); // ONLY IN INDEX, PROTECTED by RUNTIME
bool ok = TRI_ExtractShapedJsonVocShaper(shaper, &shaped, 0, _attribute, &shapedJson, &shape); // ONLY IN INDEX, PROTECTED by RUNTIME
if (! ok || shape == nullptr) {
return nullptr;
}
TRI_vector_string_t* words;
// extract the string value for the indexed attribute
if (shape->_type == TRI_SHAPE_SHORT_STRING || shape->_type == TRI_SHAPE_LONG_STRING) {
char* text;
size_t textLength;
ok = TRI_StringValueShapedJson(shape, shapedJson._data.data, &text, &textLength);
if (! ok) {
return nullptr;
}
// parse the document text
words = TRI_get_words(text, textLength, (size_t) _minWordLength, (size_t) TRI_FULLTEXT_MAX_WORD_LENGTH, true);
}
else if (shape->_type == TRI_SHAPE_ARRAY) {
std::vector<std::pair<char const*, size_t>> values;
TextExtractorContext context{ &values, shaper };
TRI_IterateShapeDataArray(shaper, shape, shapedJson._data.data, ArrayTextExtractor, &context);
words = nullptr;
for (auto const& it : values) {
if (! TRI_get_words(words, it.first, it.second, (size_t) _minWordLength, (size_t) TRI_FULLTEXT_MAX_WORD_LENGTH, true)) {
if (words != nullptr) {
TRI_FreeVectorString(TRI_UNKNOWN_MEM_ZONE, words);
}
return nullptr;
}
}
}
else if (shape->_type == TRI_SHAPE_LIST ||
shape->_type == TRI_SHAPE_HOMOGENEOUS_LIST ||
shape->_type == TRI_SHAPE_HOMOGENEOUS_SIZED_LIST) {
std::vector<std::pair<char const*, size_t>> values;
TextExtractorContext context{ &values, shaper };
TRI_IterateShapeDataList(shaper, shape, shapedJson._data.data, ListTextExtractor, &context);
words = nullptr;
for (auto const& it : values) {
if (! TRI_get_words(words, it.first, it.second, (size_t) _minWordLength, (size_t) TRI_FULLTEXT_MAX_WORD_LENGTH, true)) {
if (words != nullptr) {
TRI_FreeVectorString(TRI_UNKNOWN_MEM_ZONE, words);
}
return nullptr;
}
}
}
else {
words = nullptr;
}
if (words == nullptr) {
return nullptr;
}
TRI_fulltext_wordlist_t* wordlist = TRI_CreateWordlistFulltextIndex(words->_buffer, words->_length);
if (wordlist == nullptr) {
TRI_FreeVectorString(TRI_UNKNOWN_MEM_ZONE, words);
return nullptr;
}
// this really is a hack, but it works well:
// make the word list vector think it's empty and free it
// this does not free the word list, that we have already over the result
words->_length = 0;
words->_buffer = nullptr;
TRI_FreeVectorString(TRI_UNKNOWN_MEM_ZONE, words);
return wordlist;
}
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

View File

@ -0,0 +1,142 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief fulltext index
///
/// @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 Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_INDEXES_FULLTEXT_INDEX_H
#define ARANGODB_INDEXES_FULLTEXT_INDEX_H 1
#include "Basics/Common.h"
#include "FulltextIndex/fulltext-common.h"
#include "Indexes/Index.h"
#include "ShapedJson/shaped-json.h"
#include "VocBase/vocbase.h"
#include "VocBase/voc-types.h"
struct TRI_fulltext_wordlist_s;
// -----------------------------------------------------------------------------
// --SECTION-- class FulltextIndex
// -----------------------------------------------------------------------------
namespace triagens {
namespace arango {
class FulltextIndex : public Index {
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
public:
FulltextIndex () = delete;
FulltextIndex (TRI_idx_iid_t,
struct TRI_document_collection_t*,
std::vector<std::string> const&,
int);
~FulltextIndex ();
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
public:
IndexType type () const override final {
return Index::TRI_IDX_TYPE_FULLTEXT_INDEX;
}
bool hasSelectivityEstimate () const override final {
return false;
}
size_t memory () const override final;
triagens::basics::Json toJson (TRI_memory_zone_t*) const override final;
int insert (struct TRI_doc_mptr_t const*, bool) override final;
int remove (struct TRI_doc_mptr_t const*, bool) override final;
int cleanup () override final;
// -----------------------------------------------------------------------------
// --SECTION-- private methods
// -----------------------------------------------------------------------------
private:
struct TRI_fulltext_wordlist_s* wordlist (struct TRI_doc_mptr_t const*);
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief the underlying collection
////////////////////////////////////////////////////////////////////////////////
struct TRI_document_collection_t* _collection;
////////////////////////////////////////////////////////////////////////////////
/// @brief the indexed attribute (path)
////////////////////////////////////////////////////////////////////////////////
TRI_shape_pid_t _attribute;
////////////////////////////////////////////////////////////////////////////////
/// @brief the fulltext index
////////////////////////////////////////////////////////////////////////////////
TRI_fts_index_t* _fulltextIndex;
////////////////////////////////////////////////////////////////////////////////
/// @brief minimum word length
////////////////////////////////////////////////////////////////////////////////
int _minWordLength;
};
}
}
#endif
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

View File

@ -0,0 +1,439 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief geo index
///
/// @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 Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "GeoIndex2.h"
#include "VocBase/document-collection.h"
#include "VocBase/transaction.h"
#include "VocBase/voc-shaper.h"
using namespace triagens::arango;
// -----------------------------------------------------------------------------
// --SECTION-- class GeoIndex
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief create a new geo index, type "geo1"
////////////////////////////////////////////////////////////////////////////////
GeoIndex2::GeoIndex2 (TRI_idx_iid_t iid,
TRI_document_collection_t* collection,
std::vector<std::string> const& fields,
std::vector<TRI_shape_pid_t> const& paths,
bool geoJson)
: Index(iid, fields),
_collection(collection),
_paths(paths),
_location(paths[0]),
_latitude(0),
_longitude(0),
_variant(geoJson ? INDEX_GEO_COMBINED_LAT_LON : INDEX_GEO_COMBINED_LON_LAT),
_geoJson(geoJson),
_geoIndex(nullptr) {
_geoIndex = GeoIndex_new();
if (_geoIndex == nullptr) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create a new geo index, type "geo2"
////////////////////////////////////////////////////////////////////////////////
GeoIndex2::GeoIndex2 (TRI_idx_iid_t iid,
TRI_document_collection_t* collection,
std::vector<std::string> const& fields,
std::vector<TRI_shape_pid_t> const& paths)
: Index(iid, fields),
_collection(collection),
_paths(paths),
_location(0),
_latitude(paths[0]),
_longitude(paths[1]),
_variant(INDEX_GEO_INDIVIDUAL_LAT_LON),
_geoJson(false),
_geoIndex(nullptr) {
_geoIndex = GeoIndex_new();
if (_geoIndex == nullptr) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
}
GeoIndex2::~GeoIndex2 () {
if (_geoIndex != nullptr) {
GeoIndex_free(_geoIndex);
}
}
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
size_t GeoIndex2::memory () const {
return GeoIndex_MemoryUsage(_geoIndex);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return a JSON representation of the index
////////////////////////////////////////////////////////////////////////////////
triagens::basics::Json GeoIndex2::toJson (TRI_memory_zone_t* zone) const {
std::vector<std::string> f;
auto shaper = _collection->getShaper();
if (_variant == INDEX_GEO_COMBINED_LAT_LON ||
_variant == INDEX_GEO_COMBINED_LON_LAT) {
// index has one field
// convert location to string
char const* location = TRI_AttributeNameShapePid(shaper, _location);
if (location != nullptr) {
f.emplace_back(location);
}
}
else {
// index has two fields
char const* latitude = TRI_AttributeNameShapePid(shaper, _latitude);
if (latitude != nullptr) {
f.emplace_back(latitude);
}
char const* longitude = TRI_AttributeNameShapePid(shaper, _longitude);
if (longitude != nullptr) {
f.emplace_back(longitude);
}
}
if (f.empty()) {
return triagens::basics::Json();
}
// create json
auto json = Index::toJson(zone);
if (_variant == INDEX_GEO_COMBINED_LAT_LON ||
_variant == INDEX_GEO_COMBINED_LON_LAT) {
json("geoJson", triagens::basics::Json(zone, _geoJson));
}
// geo indexes are always non-unique
// geo indexes are always sparse.
// "ignoreNull" has the same meaning as "sparse" and is only returned for backwards compatibility
// the "constraint" attribute has no meaning since ArangoDB 2.5 and is only returned for backwards compatibility
json("constraint", triagens::basics::Json(zone, false))
("unique", triagens::basics::Json(zone, false))
("ignoreNull", triagens::basics::Json(zone, true))
("sparse", triagens::basics::Json(zone, true));
triagens::basics::Json fields(zone, triagens::basics::Json::Object, f.size());
for (auto const& field : f) {
fields.add(triagens::basics::Json(zone, field));
}
json("fields", fields);
return json;
}
int GeoIndex2::insert (TRI_doc_mptr_t const* doc,
bool) {
TRI_shaper_t* shaper = _collection->getShaper(); // ONLY IN INDEX, PROTECTED by RUNTIME
// lookup latitude and longitude
TRI_shaped_json_t shapedJson;
TRI_EXTRACT_SHAPED_JSON_MARKER(shapedJson, doc->getDataPtr()); // ONLY IN INDEX, PROTECTED by RUNTIME
bool ok;
double latitude;
double longitude;
if (_location != 0) {
if (_geoJson) {
ok = extractDoubleList(shaper, &shapedJson, &longitude, &latitude);
}
else {
ok = extractDoubleList(shaper, &shapedJson, &latitude, &longitude);
}
}
else {
ok = extractDoubleArray(shaper, &shapedJson, 0, &latitude);
ok = ok && extractDoubleArray(shaper, &shapedJson, 1, &longitude);
}
if (! ok) {
return TRI_ERROR_NO_ERROR;
}
// and insert into index
GeoCoordinate gc;
gc.latitude = latitude;
gc.longitude = longitude;
gc.data = CONST_CAST(doc);
int res = GeoIndex_insert(_geoIndex, &gc);
if (res == -1) {
LOG_WARNING("found duplicate entry in geo-index, should not happen");
return TRI_set_errno(TRI_ERROR_INTERNAL);
}
else if (res == -2) {
return TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
}
else if (res == -3) {
LOG_DEBUG("illegal geo-coordinates, ignoring entry");
return TRI_ERROR_NO_ERROR;
}
else if (res < 0) {
return TRI_set_errno(TRI_ERROR_INTERNAL);
}
return TRI_ERROR_NO_ERROR;
}
int GeoIndex2::remove (TRI_doc_mptr_t const* doc,
bool) {
TRI_shaped_json_t shapedJson;
TRI_shaper_t* shaper = _collection->getShaper(); // ONLY IN INDEX, PROTECTED by RUNTIME
TRI_EXTRACT_SHAPED_JSON_MARKER(shapedJson, doc->getDataPtr()); // ONLY IN INDEX, PROTECTED by RUNTIME
// lookup OLD latitude and longitude
bool ok;
double latitude;
double longitude;
if (_location != 0) {
ok = extractDoubleList(shaper, &shapedJson, &latitude, &longitude);
}
else {
ok = extractDoubleArray(shaper, &shapedJson, 0, &latitude);
ok = ok && extractDoubleArray(shaper, &shapedJson, 1, &longitude);
}
// and remove old entry
if (ok) {
GeoCoordinate gc;
gc.latitude = latitude;
gc.longitude = longitude;
gc.data = CONST_CAST(doc);
// ignore non-existing elements in geo-index
GeoIndex_remove(_geoIndex, &gc);
}
return TRI_ERROR_NO_ERROR;
}
// -----------------------------------------------------------------------------
// --SECTION-- private methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief extracts a double value from an array
////////////////////////////////////////////////////////////////////////////////
bool GeoIndex2::extractDoubleArray (TRI_shaper_t* shaper,
TRI_shaped_json_t const* document,
int which,
double* result) {
TRI_shape_pid_t const pid = (which == 0 ? _latitude : _longitude);
TRI_shape_t const* shape;
TRI_shaped_json_t json;
if (! TRI_ExtractShapedJsonVocShaper(shaper, document, 0, pid, &json, &shape)) {
return false;
}
if (shape == nullptr) {
return false;
}
else if (json._sid == BasicShapes::TRI_SHAPE_SID_NUMBER) {
*result = * (double*) json._data.data;
return true;
}
else if (json._sid == BasicShapes::TRI_SHAPE_SID_NULL) {
return false;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief extracts a double value from a list
////////////////////////////////////////////////////////////////////////////////
bool GeoIndex2::extractDoubleList (TRI_shaper_t* shaper,
TRI_shaped_json_t const* document,
double* latitude,
double* longitude) {
TRI_shape_t const* shape;
TRI_shaped_json_t list;
bool ok = TRI_ExtractShapedJsonVocShaper(shaper, document, 0, _location, &list, &shape);
if (! ok) {
return false;
}
if (shape == nullptr) {
return false;
}
// in-homogenous list
if (shape->_type == TRI_SHAPE_LIST) {
size_t len = TRI_LengthListShapedJson((const TRI_list_shape_t*) shape, &list);
if (len < 2) {
return false;
}
// latitude
TRI_shaped_json_t entry;
ok = TRI_AtListShapedJson((const TRI_list_shape_t*) shape, &list, 0, &entry);
if (! ok || entry._sid != BasicShapes::TRI_SHAPE_SID_NUMBER) {
return false;
}
*latitude = * (double*) entry._data.data;
// longitude
ok = TRI_AtListShapedJson((const TRI_list_shape_t*) shape, &list, 1, &entry);
if (! ok || entry._sid != BasicShapes::TRI_SHAPE_SID_NUMBER) {
return false;
}
*longitude = * (double*) entry._data.data;
return true;
}
// homogenous list
else if (shape->_type == TRI_SHAPE_HOMOGENEOUS_LIST) {
const TRI_homogeneous_list_shape_t* hom;
hom = (const TRI_homogeneous_list_shape_t*) shape;
if (hom->_sidEntry != BasicShapes::TRI_SHAPE_SID_NUMBER) {
return false;
}
size_t len = TRI_LengthHomogeneousListShapedJson((const TRI_homogeneous_list_shape_t*) shape, &list);
if (len < 2) {
return false;
}
// latitude
TRI_shaped_json_t entry;
ok = TRI_AtHomogeneousListShapedJson((const TRI_homogeneous_list_shape_t*) shape, &list, 0, &entry);
if (! ok) {
return false;
}
*latitude = * (double*) entry._data.data;
// longitude
ok = TRI_AtHomogeneousListShapedJson((const TRI_homogeneous_list_shape_t*) shape, &list, 1, &entry);
if (! ok) {
return false;
}
*longitude = * (double*) entry._data.data;
return true;
}
// homogeneous list
else if (shape->_type == TRI_SHAPE_HOMOGENEOUS_SIZED_LIST) {
const TRI_homogeneous_sized_list_shape_t* hom;
hom = (const TRI_homogeneous_sized_list_shape_t*) shape;
if (hom->_sidEntry != BasicShapes::TRI_SHAPE_SID_NUMBER) {
return false;
}
size_t len = TRI_LengthHomogeneousSizedListShapedJson((const TRI_homogeneous_sized_list_shape_t*) shape, &list);
if (len < 2) {
return false;
}
// latitude
TRI_shaped_json_t entry;
ok = TRI_AtHomogeneousSizedListShapedJson((const TRI_homogeneous_sized_list_shape_t*) shape, &list, 0, &entry);
if (! ok) {
return false;
}
*latitude = * (double*) entry._data.data;
// longitude
ok = TRI_AtHomogeneousSizedListShapedJson((const TRI_homogeneous_sized_list_shape_t*) shape, &list, 1, &entry);
if (! ok) {
return false;
}
*longitude = * (double*) entry._data.data;
return true;
}
return false;
}
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

184
arangod/Indexes/GeoIndex2.h Normal file
View File

@ -0,0 +1,184 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief geo index
///
/// @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 Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_INDEXES_GEO_INDEX_H
#define ARANGODB_INDEXES_GEO_INDEX_H 1
#include "Basics/Common.h"
#include "GeoIndex/GeoIndex.h"
#include "Indexes/Index.h"
#include "ShapedJson/shaped-json.h"
#include "VocBase/vocbase.h"
#include "VocBase/voc-types.h"
// -----------------------------------------------------------------------------
// --SECTION-- class GeoIndex
// -----------------------------------------------------------------------------
namespace triagens {
namespace arango {
class GeoIndex2 : public Index {
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
public:
GeoIndex2 () = delete;
GeoIndex2 (TRI_idx_iid_t,
struct TRI_document_collection_t*,
std::vector<std::string> const&,
std::vector<TRI_shape_pid_t> const&,
bool);
GeoIndex2 (TRI_idx_iid_t,
struct TRI_document_collection_t*,
std::vector<std::string> const&,
std::vector<TRI_shape_pid_t> const&);
~GeoIndex2 ();
// -----------------------------------------------------------------------------
// --SECTION-- public types
// -----------------------------------------------------------------------------
public:
////////////////////////////////////////////////////////////////////////////////
/// @brief geo index variants
////////////////////////////////////////////////////////////////////////////////
enum IndexVariant {
INDEX_GEO_NONE = 0,
INDEX_GEO_INDIVIDUAL_LAT_LON,
INDEX_GEO_COMBINED_LAT_LON,
INDEX_GEO_COMBINED_LON_LAT
};
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
public:
IndexType type () const override final;
bool hasSelectivityEstimate () const override final {
return false;
}
size_t memory () const override final;
triagens::basics::Json toJson (TRI_memory_zone_t*) const override final;
int insert (struct TRI_doc_mptr_t const*, bool) override final;
int remove (struct TRI_doc_mptr_t const*, bool) override final;
// -----------------------------------------------------------------------------
// --SECTION-- private methods
// -----------------------------------------------------------------------------
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief extracts a double value from an array
////////////////////////////////////////////////////////////////////////////////
bool extractDoubleArray (struct TRI_shaper_s*,
struct TRI_shaped_json_s const*,
int,
double*);
bool extractDoubleList (struct TRI_shaper_s*,
struct TRI_shaped_json_s const*,
double*,
double*);
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief the underlying collection
////////////////////////////////////////////////////////////////////////////////
struct TRI_document_collection_t* _collection;
////////////////////////////////////////////////////////////////////////////////
/// @brief the attribute paths
////////////////////////////////////////////////////////////////////////////////
std::vector<TRI_shape_pid_t> const _paths;
////////////////////////////////////////////////////////////////////////////////
/// @brief attribute paths
////////////////////////////////////////////////////////////////////////////////
TRI_shape_pid_t _location;
TRI_shape_pid_t _latitude;
TRI_shape_pid_t _longitude;
////////////////////////////////////////////////////////////////////////////////
/// @brief the geo index variant (geo1 or geo2)
////////////////////////////////////////////////////////////////////////////////
IndexVariant const _variant;
////////////////////////////////////////////////////////////////////////////////
/// @brief whether the index is a geoJson index (latitude / longitude reversed)
////////////////////////////////////////////////////////////////////////////////
bool _geoJson;
////////////////////////////////////////////////////////////////////////////////
/// @brief the actual geo index
////////////////////////////////////////////////////////////////////////////////
GeoIndex* _geoIndex;
};
}
}
#endif
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

View File

@ -0,0 +1,619 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief hash index
///
/// @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 Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "HashIndex.h"
#include "VocBase/document-collection.h"
#include "VocBase/transaction.h"
#include "VocBase/voc-shaper.h"
struct TRI_hash_index_element_multi_s;
using namespace triagens::arango;
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief fills the index search from hash index element
////////////////////////////////////////////////////////////////////////////////
template<typename T>
static int FillIndexSearchValueByHashIndexElement (HashIndex const* hashIndex,
TRI_index_search_value_t* key,
T const* element) {
key->_values = static_cast<TRI_shaped_json_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, hashIndex->keyEntrySize(), false));
if (key->_values == nullptr) {
return TRI_ERROR_OUT_OF_MEMORY;
}
char const* ptr = element->_document->getShapedJsonPtr(); // ONLY IN INDEX
size_t const n = hashIndex->paths().size();
for (size_t i = 0; i < n; ++i) {
auto sid = element->_subObjects[i]._sid;
key->_values[i]._sid = sid;
TRI_InspectShapedSub(&element->_subObjects[i], ptr, key->_values[i]);
}
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief frees space for sub-objects in the hash index element
////////////////////////////////////////////////////////////////////////////////
template<typename T>
static void FreeSubObjectsHashIndexElement (T* element) {
if (element->_subObjects != nullptr) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, element->_subObjects);
element->_subObjects = nullptr;
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief helper for hashing
///
/// This function takes a document master pointer and creates a corresponding
/// hash index element. The index element contains the document master pointer
/// and a lists of offsets and sizes describing the parts of the documents to be
/// hashed and the shape identifier of each part.
////////////////////////////////////////////////////////////////////////////////
template<typename T>
static int HashIndexHelper (HashIndex const* hashIndex,
T* hashElement,
TRI_doc_mptr_t const* document) {
TRI_shaped_json_t shapedJson; // the object behind document
TRI_shaper_t* shaper = hashIndex->collection()->getShaper(); // ONLY IN INDEX, PROTECTED by RUNTIME
bool const sparse = hashIndex->sparse();
// .............................................................................
// Assign the document to the TRI_hash_index_element_t structure - so that it
// can later be retreived.
// .............................................................................
TRI_EXTRACT_SHAPED_JSON_MARKER(shapedJson, document->getDataPtr()); // ONLY IN INDEX, PROTECTED by RUNTIME
hashElement->_document = const_cast<TRI_doc_mptr_t*>(document);
char const* ptr = document->getShapedJsonPtr(); // ONLY IN INDEX
// .............................................................................
// Extract the attribute values
// .............................................................................
int res = TRI_ERROR_NO_ERROR;
auto const& paths = hashIndex->paths();
size_t const n = paths.size();
for (size_t j = 0; j < n; ++j) {
TRI_shape_pid_t path = paths[j];
// determine if document has that particular shape
TRI_shape_access_t const* acc = TRI_FindAccessorVocShaper(shaper, shapedJson._sid, path);
// field not part of the object
if (acc == nullptr || acc->_resultSid == TRI_SHAPE_ILLEGAL) {
hashElement->_subObjects[j]._sid = BasicShapes::TRI_SHAPE_SID_NULL;
res = TRI_ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING;
if (sparse) {
// no need to continue
return res;
}
continue;
}
// extract the field
TRI_shaped_json_t shapedObject;
if (! TRI_ExecuteShapeAccessor(acc, &shapedJson, &shapedObject)) {
return TRI_ERROR_INTERNAL;
}
if (shapedObject._sid == BasicShapes::TRI_SHAPE_SID_NULL) {
res = TRI_ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING;
if (sparse) {
// no need to continue
return res;
}
}
TRI_FillShapedSub(&hashElement->_subObjects[j], &shapedObject, ptr);
}
return res;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief index helper for hashing with allocation
////////////////////////////////////////////////////////////////////////////////
template<typename T>
static int HashIndexHelperAllocate (HashIndex const* hashIndex,
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.
// .............................................................................
hashElement->_subObjects = static_cast<TRI_shaped_sub_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, hashIndex->keyEntrySize(), false));
if (hashElement->_subObjects == nullptr) {
return TRI_ERROR_OUT_OF_MEMORY;
}
int res = HashIndexHelper<T>(hashIndex, hashElement, document);
if (res == TRI_ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING) {
// if the document does not have the indexed attribute or has it, and it is null,
// then in case of a sparse index we don't index this document
if (! hashIndex->sparse()) {
// in case of a non-sparse index, we index this document
res = TRI_ERROR_NO_ERROR;
}
// and for a sparse index, we return TRI_ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING
}
return res;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief inserts a data element into the hash array
///
/// Since we do not allow duplicates - we must compare using keys, rather than
/// documents.
////////////////////////////////////////////////////////////////////////////////
static int HashIndex_insert (HashIndex* hashIndex,
TRI_hash_array_t* hashArray,
TRI_hash_index_element_t const* element,
bool isRollback) {
TRI_IF_FAILURE("InsertHashIndex") {
return TRI_ERROR_DEBUG;
}
TRI_index_search_value_t key;
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(hashArray, &key, element, isRollback);
if (key._values != nullptr) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, key._values);
}
return res;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief removes an entry from the hash array part of the hash index
////////////////////////////////////////////////////////////////////////////////
static int HashIndex_remove (TRI_hash_array_t* hashArray,
TRI_hash_index_element_t* element) {
TRI_IF_FAILURE("RemoveHashIndex") {
return TRI_ERROR_DEBUG;
}
int res = TRI_RemoveElementHashArray(hashArray, element);
// this might happen when rolling back
if (res == TRI_RESULT_ELEMENT_NOT_FOUND) {
return TRI_ERROR_NO_ERROR;
}
return res;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief inserts a data element into the hash array
///
/// Since we do allow duplicates - we must compare using documents, rather than
/// keys.
////////////////////////////////////////////////////////////////////////////////
static int MultiHashIndex_insert (HashIndex* hashIndex,
TRI_hash_array_multi_t* hashArrayMulti,
TRI_hash_index_element_multi_t* element,
bool isRollback) {
TRI_IF_FAILURE("InsertHashIndex") {
return TRI_ERROR_DEBUG;
}
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(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;
}
return res;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief removes an entry from the associative array
////////////////////////////////////////////////////////////////////////////////
static int MultiHashIndex_remove (HashIndex* hashIndex,
TRI_hash_array_multi_t* hashArrayMulti,
TRI_hash_index_element_multi_t* element) {
TRI_IF_FAILURE("RemoveHashIndex") {
return TRI_ERROR_DEBUG;
}
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(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;
}
return res;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief locates a key within the hash array part
/// it is the callers responsibility to destroy the result
////////////////////////////////////////////////////////////////////////////////
static TRI_vector_pointer_t HashIndex_find (TRI_hash_array_t const* hashArray,
TRI_index_search_value_t* key) {
TRI_vector_pointer_t results;
TRI_InitVectorPointer(&results, TRI_UNKNOWN_MEM_ZONE);
// .............................................................................
// A find request means that a set of values for the "key" was sent. We need
// to locate the hash array entry by key.
// .............................................................................
TRI_hash_index_element_t* result = TRI_FindByKeyHashArray(hashArray, key);
if (result != nullptr) {
// unique hash index: maximum number is 1
TRI_PushBackVectorPointer(&results, result->_document);
}
return results;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief locates a key within the hash array part
////////////////////////////////////////////////////////////////////////////////
static int HashIndex_find (TRI_hash_array_t const* hashArray,
TRI_index_search_value_t* key,
std::vector<TRI_doc_mptr_copy_t>& result) {
// .............................................................................
// A find request means that a set of values for the "key" was sent. We need
// to locate the hash array entry by key.
// .............................................................................
TRI_hash_index_element_t* found = TRI_FindByKeyHashArray(hashArray, key);
if (found != nullptr) {
// unique hash index: maximum number is 1
result.emplace_back(*(found->_document));
}
return TRI_ERROR_NO_ERROR;
}
// -----------------------------------------------------------------------------
// --SECTION-- class Index
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
HashIndex::HashIndex (TRI_idx_iid_t iid,
TRI_document_collection_t* collection,
std::vector<std::string> const& fields,
std::vector<TRI_shape_pid_t> const& paths,
bool unique,
bool sparse)
: Index(iid, fields),
_collection(collection),
_paths(paths),
_unique(unique),
_sparse(sparse) {
if (unique) {
_hashArray._table = nullptr;
_hashArray._tablePtr = nullptr;
if (TRI_InitHashArray(&_hashArray, paths.size()) != TRI_ERROR_NO_ERROR) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
}
else {
_hashArrayMulti._table = nullptr;
_hashArrayMulti._tablePtr = nullptr;
_hashArrayMulti._freelist = nullptr;
if (TRI_InitHashArrayMulti(&_hashArrayMulti, paths.size()) != TRI_ERROR_NO_ERROR) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
}
}
HashIndex::~HashIndex () {
if (_unique) {
TRI_DestroyHashArray(&_hashArray);
}
else {
TRI_DestroyHashArrayMulti(&_hashArrayMulti);
}
}
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief returns a selectivity estimate for the index
////////////////////////////////////////////////////////////////////////////////
double HashIndex::selectivityEstimate () const {
if (_unique) {
return 1.0;
}
return TRI_SelectivityHashArrayMulti(&_hashArrayMulti);
}
size_t HashIndex::memory () const {
if (_unique) {
return static_cast<size_t>(keyEntrySize() * _hashArray._nrUsed +
TRI_MemoryUsageHashArray(&_hashArray));
}
return static_cast<size_t>(keyEntrySize() * _hashArrayMulti._nrUsed +
TRI_MemoryUsageHashArrayMulti(&_hashArrayMulti));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return a JSON representation of the index
////////////////////////////////////////////////////////////////////////////////
triagens::basics::Json HashIndex::toJson (TRI_memory_zone_t* zone) const {
auto json = Index::toJson(zone);
triagens::basics::Json f(zone, triagens::basics::Json::Array, fields().size());
for (auto const& field : fields()) {
f.add(triagens::basics::Json(zone, field));
}
json("fields", f)
("unique", triagens::basics::Json(zone, _unique))
("sparse", triagens::basics::Json(zone, _sparse));
return json;
}
int HashIndex::insert (TRI_doc_mptr_t const* doc,
bool isRollback) {
int res;
if (_unique) {
TRI_hash_index_element_t hashElement;
res = HashIndexHelperAllocate<TRI_hash_index_element_t>(this, &hashElement, doc);
if (res == TRI_ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING) {
FreeSubObjectsHashIndexElement<TRI_hash_index_element_t>(&hashElement);
return TRI_ERROR_NO_ERROR;
}
if (res != TRI_ERROR_NO_ERROR) {
FreeSubObjectsHashIndexElement<TRI_hash_index_element_t>(&hashElement);
return res;
}
res = HashIndex_insert(this, &_hashArray, &hashElement, isRollback);
if (res != TRI_ERROR_NO_ERROR) {
FreeSubObjectsHashIndexElement<TRI_hash_index_element_t>(&hashElement);
}
}
else {
TRI_hash_index_element_multi_t hashElement;
res = HashIndexHelperAllocate<TRI_hash_index_element_multi_t>(this, &hashElement, doc);
if (res == TRI_ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING) {
FreeSubObjectsHashIndexElement<TRI_hash_index_element_multi_t>(&hashElement);
return TRI_ERROR_NO_ERROR;
}
if (res != TRI_ERROR_NO_ERROR) {
FreeSubObjectsHashIndexElement<TRI_hash_index_element_multi_t>(&hashElement);
return res;
}
res = MultiHashIndex_insert(this, &_hashArrayMulti, &hashElement, isRollback);
if (res != TRI_ERROR_NO_ERROR) {
FreeSubObjectsHashIndexElement<TRI_hash_index_element_multi_t>(&hashElement);
}
}
return res;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief removes an entry from the hash array part of the hash index
////////////////////////////////////////////////////////////////////////////////
int HashIndex::remove (TRI_doc_mptr_t const* doc,
bool) {
int res;
if (_unique) {
TRI_hash_index_element_t hashElement;
res = HashIndexHelperAllocate<TRI_hash_index_element_t>(this, &hashElement, doc);
if (res == TRI_ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING) {
FreeSubObjectsHashIndexElement<TRI_hash_index_element_t>(&hashElement);
return TRI_ERROR_NO_ERROR;
}
if (res != TRI_ERROR_NO_ERROR) {
FreeSubObjectsHashIndexElement<TRI_hash_index_element_t>(&hashElement);
return res;
}
res = HashIndex_remove(&_hashArray, &hashElement);
FreeSubObjectsHashIndexElement<TRI_hash_index_element_t>(&hashElement);
}
else {
TRI_hash_index_element_multi_t hashElement;
res = HashIndexHelperAllocate<TRI_hash_index_element_multi_t>(this, &hashElement, doc);
if (res == TRI_ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING) {
FreeSubObjectsHashIndexElement<TRI_hash_index_element_multi_t>(&hashElement);
return TRI_ERROR_NO_ERROR;
}
if (res != TRI_ERROR_NO_ERROR) {
FreeSubObjectsHashIndexElement<TRI_hash_index_element_multi_t>(&hashElement);
return res;
}
res = MultiHashIndex_remove(this, &_hashArrayMulti, &hashElement);
FreeSubObjectsHashIndexElement<TRI_hash_index_element_multi_t>(&hashElement);
}
return res;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief provides a size hint for the hash index
////////////////////////////////////////////////////////////////////////////////
int HashIndex::sizeHint (size_t size) {
if (_sparse) {
// for sparse indexes, we assume that we will have less index entries
// than if the index would be fully populated
size /= 5;
}
if (_unique) {
TRI_ResizeHashArray(&_hashArray, size);
}
else {
TRI_ResizeHashArrayMulti(&_hashArrayMulti, size);
}
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief locates entries in the hash index given shaped json objects
/// it is the callers responsibility to destroy the result
////////////////////////////////////////////////////////////////////////////////
TRI_vector_pointer_t HashIndex::lookup (TRI_index_search_value_t* searchValue) const {
if (_unique) {
return HashIndex_find(&_hashArray, searchValue);
}
return TRI_LookupByKeyHashArrayMulti(&_hashArrayMulti, searchValue);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief locates entries in the hash index given shaped json objects
////////////////////////////////////////////////////////////////////////////////
int HashIndex::lookup (TRI_index_search_value_t* searchValue,
std::vector<TRI_doc_mptr_copy_t>& documents) const {
if (_unique) {
return HashIndex_find(&_hashArray, searchValue, documents);
}
return TRI_LookupByKeyHashArrayMulti(&_hashArrayMulti, searchValue, documents);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief locates entries in the hash index given shaped json objects
////////////////////////////////////////////////////////////////////////////////
int HashIndex::lookup (TRI_index_search_value_t* searchValue,
std::vector<TRI_doc_mptr_copy_t>& documents,
struct TRI_hash_index_element_multi_s*& next,
size_t batchSize) const {
if (_unique) {
next = nullptr;
return HashIndex_find(&_hashArray, searchValue, documents);
}
return TRI_LookupByKeyHashArrayMulti(&_hashArrayMulti, searchValue, documents, next, batchSize);
}
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

190
arangod/Indexes/HashIndex.h Normal file
View File

@ -0,0 +1,190 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief hash index
///
/// @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 Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_INDEXES_HASH_INDEX_H
#define ARANGODB_INDEXES_HASH_INDEX_H 1
#include "Basics/Common.h"
#include "HashIndex/hash-array.h"
#include "HashIndex/hash-array-multi.h"
#include "HashIndex/hash-index.h"
#include "Indexes/Index.h"
#include "ShapedJson/shaped-json.h"
// TODO: remove the next include!
#include "VocBase/index.h"
#include "VocBase/vocbase.h"
#include "VocBase/voc-types.h"
// -----------------------------------------------------------------------------
// --SECTION-- class HashIndex
// -----------------------------------------------------------------------------
namespace triagens {
namespace arango {
class HashIndex : public Index {
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
public:
HashIndex () = delete;
HashIndex (TRI_idx_iid_t,
struct TRI_document_collection_t*,
std::vector<std::string> const&,
std::vector<TRI_shape_pid_t> const&,
bool,
bool);
~HashIndex ();
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
public:
IndexType type () const override final {
return Index::TRI_IDX_TYPE_HASH_INDEX;
}
bool hasSelectivityEstimate () const override final {
return true;
}
double selectivityEstimate () const override final;
size_t memory () const override final;
triagens::basics::Json toJson (TRI_memory_zone_t*) const override final;
int insert (struct TRI_doc_mptr_t const*, bool) override final;
int remove (struct TRI_doc_mptr_t const*, bool) override final;
int sizeHint (size_t) override final;
std::vector<TRI_shape_pid_t> const& paths () const {
return _paths;
}
struct TRI_document_collection_t* collection () const {
return _collection;
}
bool sparse () const {
return _sparse;
}
bool unique () const {
return _unique;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the memory needed for an index key entry
////////////////////////////////////////////////////////////////////////////////
size_t keyEntrySize () const {
return _paths.size() * sizeof(TRI_shaped_json_t);
}
TRI_vector_pointer_t lookup (TRI_index_search_value_t*) const;
////////////////////////////////////////////////////////////////////////////////
/// @brief locates entries in the hash index given shaped json objects
////////////////////////////////////////////////////////////////////////////////
int lookup (TRI_index_search_value_t*,
std::vector<TRI_doc_mptr_copy_t>&) const;
////////////////////////////////////////////////////////////////////////////////
/// @brief locates entries in the hash index given shaped json objects
////////////////////////////////////////////////////////////////////////////////
int lookup (TRI_index_search_value_t*,
std::vector<TRI_doc_mptr_copy_t>&,
struct TRI_hash_index_element_multi_s*&,
size_t batchSize) const;
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief the underlying collection
////////////////////////////////////////////////////////////////////////////////
struct TRI_document_collection_t* _collection;
////////////////////////////////////////////////////////////////////////////////
/// @brief the attribute paths
////////////////////////////////////////////////////////////////////////////////
std::vector<TRI_shape_pid_t> const _paths;
////////////////////////////////////////////////////////////////////////////////
/// @brief the actual hash index
////////////////////////////////////////////////////////////////////////////////
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
};
////////////////////////////////////////////////////////////////////////////////
/// @brief whether the index is unique
////////////////////////////////////////////////////////////////////////////////
bool const _unique;
////////////////////////////////////////////////////////////////////////////////
/// @brief whether the index is sparse
////////////////////////////////////////////////////////////////////////////////
bool const _sparse;
};
}
}
#endif
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

367
arangod/Indexes/Index.cpp Normal file
View File

@ -0,0 +1,367 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief index
///
/// @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 Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "Index.h"
#include "Basics/Exceptions.h"
#include "Basics/json-utilities.h"
#include "VocBase/server.h"
using namespace triagens::arango;
// -----------------------------------------------------------------------------
// --SECTION-- class Index
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
Index::Index (TRI_idx_iid_t iid,
std::vector<std::string> const& fields)
: _iid(iid),
_fields(fields) {
}
Index::~Index () {
}
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief return the index type based on a type name
////////////////////////////////////////////////////////////////////////////////
Index::IndexType Index::type (char const* type) {
if (::strcmp(type, "primary") == 0) {
return TRI_IDX_TYPE_PRIMARY_INDEX;
}
if (::strcmp(type, "edge") == 0) {
return TRI_IDX_TYPE_EDGE_INDEX;
}
if (::strcmp(type, "hash") == 0) {
return TRI_IDX_TYPE_HASH_INDEX;
}
if (::strcmp(type, "skiplist") == 0) {
return TRI_IDX_TYPE_SKIPLIST_INDEX;
}
if (::strcmp(type, "fulltext") == 0) {
return TRI_IDX_TYPE_FULLTEXT_INDEX;
}
if (::strcmp(type, "cap") == 0) {
return TRI_IDX_TYPE_CAP_CONSTRAINT;
}
if (::strcmp(type, "geo1") == 0) {
return TRI_IDX_TYPE_GEO1_INDEX;
}
if (::strcmp(type, "geo2") == 0) {
return TRI_IDX_TYPE_GEO2_INDEX;
}
return TRI_IDX_TYPE_UNKNOWN;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return the name of an index type
////////////////////////////////////////////////////////////////////////////////
char const* Index::typeName (Index::IndexType type) {
switch (type) {
case TRI_IDX_TYPE_PRIMARY_INDEX:
return "primary";
case TRI_IDX_TYPE_GEO1_INDEX:
return "geo1";
case TRI_IDX_TYPE_GEO2_INDEX:
return "geo2";
case TRI_IDX_TYPE_HASH_INDEX:
return "hash";
case TRI_IDX_TYPE_EDGE_INDEX:
return "edge";
case TRI_IDX_TYPE_FULLTEXT_INDEX:
return "fulltext";
case TRI_IDX_TYPE_SKIPLIST_INDEX:
return "skiplist";
case TRI_IDX_TYPE_CAP_CONSTRAINT:
return "cap";
case TRI_IDX_TYPE_PRIORITY_QUEUE_INDEX:
case TRI_IDX_TYPE_BITARRAY_INDEX:
case TRI_IDX_TYPE_UNKNOWN: {
}
}
return "";
}
////////////////////////////////////////////////////////////////////////////////
/// @brief validate an index id
////////////////////////////////////////////////////////////////////////////////
bool Index::validateId (char const* key) {
char const* p = key;
while (1) {
const char c = *p;
if (c == '\0') {
return (p - key) > 0;
}
if (c >= '0' && c <= '9') {
++p;
continue;
}
return false;
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief validate an index handle (collection name + / + index id)
////////////////////////////////////////////////////////////////////////////////
bool Index::validateHandle (char const* key,
size_t* split) {
char const* p = key;
char c = *p;
// extract collection name
if (! (c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) {
return false;
}
++p;
while (1) {
c = *p;
if ((c == '_') || (c == '-') || (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
++p;
continue;
}
if (c == '/') {
break;
}
return false;
}
if (p - key > TRI_COL_NAME_LENGTH) {
return false;
}
// store split position
*split = p - key;
++p;
// validate index id
return validateId(p);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generate a new index id
////////////////////////////////////////////////////////////////////////////////
TRI_idx_iid_t Index::generateId () {
return TRI_NewTickServer();
}
////////////////////////////////////////////////////////////////////////////////
/// @brief index comparator, used by the coordinator to detect if two index
/// contents are the same
////////////////////////////////////////////////////////////////////////////////
bool Index::Compare (TRI_json_t const* lhs,
TRI_json_t const* rhs) {
TRI_json_t* typeJson = TRI_LookupObjectJson(lhs, "type");
TRI_ASSERT(TRI_IsStringJson(typeJson));
// type must be identical
if (! TRI_CheckSameValueJson(typeJson, TRI_LookupObjectJson(rhs, "type"))) {
return false;
}
auto type = Index::type(typeJson->_value._string.data);
// unique must be identical if present
TRI_json_t* value = TRI_LookupObjectJson(lhs, "unique");
if (TRI_IsBooleanJson(value)) {
if (! TRI_CheckSameValueJson(value, TRI_LookupObjectJson(rhs, "unique"))) {
return false;
}
}
// sparse must be identical if present
value = TRI_LookupObjectJson(lhs, "sparse");
if (TRI_IsBooleanJson(value)) {
if (! TRI_CheckSameValueJson(value, TRI_LookupObjectJson(rhs, "sparse"))) {
return false;
}
}
if (type == IndexType::TRI_IDX_TYPE_GEO1_INDEX) {
// geoJson must be identical if present
value = TRI_LookupObjectJson(lhs, "geoJson");
if (TRI_IsBooleanJson(value)) {
if (! TRI_CheckSameValueJson(value, TRI_LookupObjectJson(rhs, "geoJson"))) {
return false;
}
}
}
else if (type == IndexType::TRI_IDX_TYPE_FULLTEXT_INDEX) {
// minLength
value = TRI_LookupObjectJson(lhs, "minLength");
if (TRI_IsNumberJson(value)) {
if (! TRI_CheckSameValueJson(value, TRI_LookupObjectJson(rhs, "minLength"))) {
return false;
}
}
}
else if (type == IndexType::TRI_IDX_TYPE_CAP_CONSTRAINT) {
// size, byteSize
value = TRI_LookupObjectJson(lhs, "size");
if (TRI_IsNumberJson(value)) {
if (! TRI_CheckSameValueJson(value, TRI_LookupObjectJson(rhs, "size"))) {
return false;
}
}
value = TRI_LookupObjectJson(lhs, "byteSize");
if (TRI_IsNumberJson(value)) {
if (! TRI_CheckSameValueJson(value, TRI_LookupObjectJson(rhs, "byteSize"))) {
return false;
}
}
}
// other index types: fields must be identical if present
value = TRI_LookupObjectJson(lhs, "fields");
if (TRI_IsArrayJson(value)) {
if (type == IndexType::TRI_IDX_TYPE_HASH_INDEX) {
size_t const nv = TRI_LengthArrayJson(value);
// compare fields in arbitrary order
TRI_json_t const* r = TRI_LookupObjectJson(rhs, "fields");
if (! TRI_IsArrayJson(r) ||
nv != TRI_LengthArrayJson(r)) {
return false;
}
size_t const nr = TRI_LengthArrayJson(r);
for (size_t i = 0; i < nv; ++i) {
TRI_json_t const* v = TRI_LookupArrayJson(value, i);
bool found = false;
for (size_t j = 0; j < nr; ++j) {
if (TRI_CheckSameValueJson(v, TRI_LookupArrayJson(r, j))) {
found = true;
break;
}
}
if (! found) {
return false;
}
}
}
else {
if (! TRI_CheckSameValueJson(value, TRI_LookupObjectJson(rhs, "fields"))) {
return false;
}
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create a JSON representation of the index
/// base functionality (called from derived classes)
////////////////////////////////////////////////////////////////////////////////
triagens::basics::Json Index::toJson (TRI_memory_zone_t* zone) const {
triagens::basics::Json json(zone, triagens::basics::Json::Object, 4);
json("id", triagens::basics::Json(zone, static_cast<double>(_iid)))
("type", triagens::basics::Json(zone, typeName()));
return json;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief default implementation for selectivityEstimate
////////////////////////////////////////////////////////////////////////////////
double Index::selectivityEstimate () const {
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief default implementation for postInsert
////////////////////////////////////////////////////////////////////////////////
int Index::postInsert (struct TRI_transaction_collection_s*,
struct TRI_doc_mptr_t const*) {
// do nothing
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief default implementation for cleanup
////////////////////////////////////////////////////////////////////////////////
int Index::cleanup () {
// do nothing
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief default implementation for sizeHint
////////////////////////////////////////////////////////////////////////////////
int Index::sizeHint (size_t) {
// do nothing
return TRI_ERROR_NO_ERROR;
}
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

199
arangod/Indexes/Index.h Normal file
View File

@ -0,0 +1,199 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief index base class
///
/// @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 Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_INDEXES_INDEX_H
#define ARANGODB_INDEXES_INDEX_H 1
#include "Basics/Common.h"
#include "Basics/JsonHelper.h"
#include "VocBase/vocbase.h"
#include "VocBase/voc-types.h"
// -----------------------------------------------------------------------------
// --SECTION-- forward declarations
// -----------------------------------------------------------------------------
struct TRI_doc_mptr_t;
struct TRI_transaction_collection_s;
// -----------------------------------------------------------------------------
// --SECTION-- class Index
// -----------------------------------------------------------------------------
namespace triagens {
namespace arango {
class Index {
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
public:
Index () = delete;
Index (Index const&) = delete;
Index& operator= (Index const&) = delete;
Index (TRI_idx_iid_t,
std::vector<std::string> const&);
virtual ~Index ();
public:
////////////////////////////////////////////////////////////////////////////////
/// @brief index types
////////////////////////////////////////////////////////////////////////////////
enum IndexType {
TRI_IDX_TYPE_UNKNOWN = 0,
TRI_IDX_TYPE_PRIMARY_INDEX,
TRI_IDX_TYPE_GEO1_INDEX,
TRI_IDX_TYPE_GEO2_INDEX,
TRI_IDX_TYPE_HASH_INDEX,
TRI_IDX_TYPE_EDGE_INDEX,
TRI_IDX_TYPE_FULLTEXT_INDEX,
TRI_IDX_TYPE_PRIORITY_QUEUE_INDEX, // DEPRECATED and not functional anymore
TRI_IDX_TYPE_SKIPLIST_INDEX,
TRI_IDX_TYPE_BITARRAY_INDEX, // DEPRECATED and not functional anymore
TRI_IDX_TYPE_CAP_CONSTRAINT
};
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
public:
////////////////////////////////////////////////////////////////////////////////
/// @brief return the index id
////////////////////////////////////////////////////////////////////////////////
inline TRI_idx_iid_t id () const {
return _iid;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return the index fields
////////////////////////////////////////////////////////////////////////////////
inline std::vector<std::string> const& fields () const {
return _fields;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return the name of the index
////////////////////////////////////////////////////////////////////////////////
char const* typeName () const {
return typeName(type());
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return the index type based on a type name
////////////////////////////////////////////////////////////////////////////////
static IndexType type (char const*);
////////////////////////////////////////////////////////////////////////////////
/// @brief return the name of an index type
////////////////////////////////////////////////////////////////////////////////
static char const* typeName (IndexType);
////////////////////////////////////////////////////////////////////////////////
/// @brief validate an index id
////////////////////////////////////////////////////////////////////////////////
static bool validateId (char const*);
////////////////////////////////////////////////////////////////////////////////
/// @brief validate an index handle (collection name + / + index id)
////////////////////////////////////////////////////////////////////////////////
static bool validateHandle (char const*,
size_t*);
////////////////////////////////////////////////////////////////////////////////
/// @brief generate a new index id
////////////////////////////////////////////////////////////////////////////////
static TRI_idx_iid_t generateId ();
////////////////////////////////////////////////////////////////////////////////
/// @brief index comparator, used by the coordinator to detect if two index
/// contents are the same
////////////////////////////////////////////////////////////////////////////////
static bool Compare (TRI_json_t const* lhs,
TRI_json_t const* rhs);
virtual IndexType type () const = 0;
virtual bool hasSelectivityEstimate () const;
virtual double selectivityEstimate () const;
virtual size_t memory () const = 0;
virtual triagens::basics::Json toJson (TRI_memory_zone_t*) const;
virtual int insert (struct TRI_doc_mptr_t const*, bool) = 0;
virtual int remove (struct TRI_doc_mptr_t const*, bool) = 0;
virtual int postInsert (struct TRI_transaction_collection_s*, struct TRI_doc_mptr_t const*);
// a garbage collection function for the index
virtual int cleanup ();
// give index a hint about the expected size
virtual int sizeHint (size_t);
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
private:
TRI_idx_iid_t const _iid;
std::vector<std::string> const _fields;
};
}
}
#endif
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

View File

@ -0,0 +1,403 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief primary index
///
/// @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 Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "PrimaryIndex.h"
#include "Basics/Exceptions.h"
#include "Basics/hashes.h"
#include "VocBase/document-collection.h"
#include "VocBase/transaction.h"
using namespace triagens::arango;
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief comparison function, compares a master pointer to another
////////////////////////////////////////////////////////////////////////////////
static inline bool IsDifferentKeyElement (TRI_doc_mptr_t const* header,
void const* element) {
TRI_doc_mptr_t const* e = static_cast<TRI_doc_mptr_t const*>(element);
// only after that compare actual keys
return (header->_hash != e->_hash || strcmp(TRI_EXTRACT_MARKER_KEY(header), TRI_EXTRACT_MARKER_KEY(e)) != 0); // ONLY IN INDEX, PROTECTED by RUNTIME
}
////////////////////////////////////////////////////////////////////////////////
/// @brief comparison function, compares a hash/key to a master pointer
////////////////////////////////////////////////////////////////////////////////
static inline bool IsDifferentHashElement (char const* key, uint64_t hash, void const* element) {
TRI_doc_mptr_t const* e = static_cast<TRI_doc_mptr_t const*>(element);
return (hash != e->_hash || strcmp(key, TRI_EXTRACT_MARKER_KEY(e)) != 0); // ONLY IN INDEX, PROTECTED by RUNTIME
}
// -----------------------------------------------------------------------------
// --SECTION-- class PrimaryIndex
// -----------------------------------------------------------------------------
uint64_t const PrimaryIndex::InitialSize = 251;
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
PrimaryIndex::PrimaryIndex (TRI_document_collection_t* collection)
: Index(0, std::vector<std::string>( { TRI_VOC_ATTRIBUTE_KEY } )),
_collection(collection) {
_primaryIndex._nrAlloc = 0;
_primaryIndex._nrUsed = 0;
_primaryIndex._table = static_cast<void**>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, static_cast<size_t>(InitialSize * sizeof(void*)), true));
if (_primaryIndex._table == nullptr) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
_primaryIndex._nrAlloc = InitialSize;
}
PrimaryIndex::~PrimaryIndex () {
if (_primaryIndex._table != nullptr) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, _primaryIndex._table);
}
}
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
size_t PrimaryIndex::memory () const {
return static_cast<size_t>(_primaryIndex._nrAlloc * sizeof(void*));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return a JSON representation of the index
////////////////////////////////////////////////////////////////////////////////
triagens::basics::Json PrimaryIndex::toJson (TRI_memory_zone_t* zone) const {
auto json = Index::toJson(zone);
triagens::basics::Json f(zone, triagens::basics::Json::Array, fields().size());
for (auto const& field : fields()) {
f.add(triagens::basics::Json(zone, field));
}
json("fields", f)
("unique", triagens::basics::Json(true))
("sparse", triagens::basics::Json(false));
return json;
}
int PrimaryIndex::insert (TRI_doc_mptr_t const*,
bool) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
}
int PrimaryIndex::remove (TRI_doc_mptr_t const*,
bool) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief looks up an element given a key
////////////////////////////////////////////////////////////////////////////////
void* PrimaryIndex::lookupKey (char const* key) const {
if (_primaryIndex._nrUsed == 0) {
return nullptr;
}
// compute the hash
uint64_t const hash = calculateHash(key);
uint64_t const n = _primaryIndex._nrAlloc;
uint64_t i, k;
i = k = hash % n;
TRI_ASSERT_EXPENSIVE(n > 0);
// search the table
for (; i < n && _primaryIndex._table[i] != nullptr && IsDifferentHashElement(key, hash, _primaryIndex._table[i]); ++i);
if (i == n) {
for (i = 0; i < k && _primaryIndex._table[i] != nullptr && IsDifferentHashElement(key, hash, _primaryIndex._table[i]); ++i);
}
TRI_ASSERT_EXPENSIVE(i < n);
// return whatever we found
return _primaryIndex._table[i];
}
////////////////////////////////////////////////////////////////////////////////
/// @brief adds a key/element to the index
/// returns a status code, and *found will contain a found element (if any)
////////////////////////////////////////////////////////////////////////////////
int PrimaryIndex::insertKey (TRI_doc_mptr_t const* header,
void const** found) {
*found = nullptr;
if (shouldResize()) {
// check for out-of-memory
if (! resize(static_cast<uint64_t>(2 * _primaryIndex._nrAlloc + 1), false)) {
return TRI_ERROR_OUT_OF_MEMORY;
}
}
uint64_t const n = _primaryIndex._nrAlloc;
uint64_t i, k;
TRI_ASSERT_EXPENSIVE(n > 0);
i = k = header->_hash % n;
for (; i < n && _primaryIndex._table[i] != nullptr && IsDifferentKeyElement(header, _primaryIndex._table[i]); ++i);
if (i == n) {
for (i = 0; i < k && _primaryIndex._table[i] != nullptr && IsDifferentKeyElement(header, _primaryIndex._table[i]); ++i);
}
TRI_ASSERT_EXPENSIVE(i < n);
void* old = _primaryIndex._table[i];
// if we found an element, return
if (old != nullptr) {
*found = old;
return TRI_ERROR_NO_ERROR;
}
// add a new element to the associative idx
_primaryIndex._table[i] = (void*) header;
++_primaryIndex._nrUsed;
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief adds a key/element to the index
/// this is a special, optimized (read: reduced) variant of the above insert
/// function
////////////////////////////////////////////////////////////////////////////////
void PrimaryIndex::insertKey (TRI_doc_mptr_t const* header) {
uint64_t const n = _primaryIndex._nrAlloc;
uint64_t i, k;
i = k = header->_hash % n;
for (; i < n && _primaryIndex._table[i] != nullptr && IsDifferentKeyElement(header, _primaryIndex._table[i]); ++i);
if (i == n) {
for (i = 0; i < k && _primaryIndex._table[i] != nullptr && IsDifferentKeyElement(header, _primaryIndex._table[i]); ++i);
}
TRI_ASSERT_EXPENSIVE(i < n);
TRI_ASSERT_EXPENSIVE(_primaryIndex._table[i] == nullptr);
_primaryIndex._table[i] = const_cast<void*>(static_cast<void const*>(header));
++_primaryIndex._nrUsed;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief removes an key/element from the index
////////////////////////////////////////////////////////////////////////////////
void* PrimaryIndex::removeKey (char const* key) {
uint64_t const hash = calculateHash(key);
uint64_t const n = _primaryIndex._nrAlloc;
uint64_t i, k;
i = k = hash % n;
// search the table
for (; i < n && _primaryIndex._table[i] != nullptr && IsDifferentHashElement(key, hash, _primaryIndex._table[i]); ++i);
if (i == n) {
for (i = 0; i < k && _primaryIndex._table[i] != nullptr && IsDifferentHashElement(key, hash, _primaryIndex._table[i]); ++i);
}
TRI_ASSERT_EXPENSIVE(i < n);
// if we did not find such an item return false
if (_primaryIndex._table[i] == nullptr) {
return nullptr;
}
// remove item
void* old = _primaryIndex._table[i];
_primaryIndex._table[i] = nullptr;
_primaryIndex._nrUsed--;
// and now check the following places for items to move here
k = TRI_IncModU64(i, n);
while (_primaryIndex._table[k] != nullptr) {
uint64_t j = (static_cast<TRI_doc_mptr_t const*>(_primaryIndex._table[k])->_hash) % n;
if ((i < k && ! (i < j && j <= k)) || (k < i && ! (i < j || j <= k))) {
_primaryIndex._table[i] = _primaryIndex._table[k];
_primaryIndex._table[k] = nullptr;
i = k;
}
k = TRI_IncModU64(k, n);
}
if (_primaryIndex._nrUsed == 0) {
resize(InitialSize, true);
}
// return success
return old;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief resizes the index
////////////////////////////////////////////////////////////////////////////////
int PrimaryIndex::resize (size_t targetSize) {
if (! resize(static_cast<uint64_t>(2 * targetSize + 1), false)) {
return TRI_ERROR_OUT_OF_MEMORY;
}
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief resize the index to a good size if too small
////////////////////////////////////////////////////////////////////////////////
int PrimaryIndex::resize () {
if (shouldResize() &&
! resize(static_cast<uint64_t>(2 * _primaryIndex._nrAlloc + 1), false)) {
return TRI_ERROR_OUT_OF_MEMORY;
}
return TRI_ERROR_NO_ERROR;
}
uint64_t PrimaryIndex::calculateHash (char const* key) {
return TRI_FnvHashString(key);
}
uint64_t PrimaryIndex::calculateHash (char const* key,
size_t length) {
return TRI_FnvHashPointer(static_cast<void const*>(key), length);
}
// -----------------------------------------------------------------------------
// --SECTION-- private methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not the index must be resized
////////////////////////////////////////////////////////////////////////////////
bool PrimaryIndex::shouldResize () const {
return _primaryIndex._nrAlloc < _primaryIndex._nrUsed + _primaryIndex._nrUsed;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief resizes the index
////////////////////////////////////////////////////////////////////////////////
bool PrimaryIndex::resize (uint64_t targetSize,
bool allowShrink) {
TRI_ASSERT(targetSize > 0);
if (_primaryIndex._nrAlloc >= targetSize && ! allowShrink) {
return true;
}
void** oldTable = _primaryIndex._table;
// only log performance infos for indexes with more than this number of entries
static uint64_t const NotificationSizeThreshold = 131072;
double start = TRI_microtime();
if (targetSize > NotificationSizeThreshold) {
LOG_ACTION("primary-index-resize, target size: %llu",
(unsigned long long) targetSize);
}
_primaryIndex._table = static_cast<void**>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, (size_t) (targetSize * sizeof(void*)), true));
if (_primaryIndex._table == nullptr) {
_primaryIndex._table = oldTable;
return false;
}
if (_primaryIndex._nrUsed > 0) {
uint64_t const oldAlloc = _primaryIndex._nrAlloc;
// table is already cleared by allocate, now copy old data
for (uint64_t j = 0; j < oldAlloc; j++) {
TRI_doc_mptr_t const* element = static_cast<TRI_doc_mptr_t const*>(oldTable[j]);
if (element != nullptr) {
uint64_t const hash = element->_hash;
uint64_t i, k;
i = k = hash % targetSize;
for (; i < targetSize && _primaryIndex._table[i] != nullptr; ++i);
if (i == targetSize) {
for (i = 0; i < k && _primaryIndex._table[i] != nullptr; ++i);
}
TRI_ASSERT_EXPENSIVE(i < targetSize);
_primaryIndex._table[i] = (void*) element;
}
}
}
TRI_Free(TRI_UNKNOWN_MEM_ZONE, oldTable);
_primaryIndex._nrAlloc = targetSize;
LOG_TIMER((TRI_microtime() - start),
"primary-index-resize, target size: %llu",
(unsigned long long) targetSize);
return true;
}
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

View File

@ -0,0 +1,141 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief primary index
///
/// @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 Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_INDEXES_PRIMARY_INDEX_H
#define ARANGODB_INDEXES_PRIMARY_INDEX_H 1
#include "Basics/Common.h"
#include "Indexes/Index.h"
#include "VocBase/vocbase.h"
#include "VocBase/voc-types.h"
// -----------------------------------------------------------------------------
// --SECTION-- class PrimaryIndex
// -----------------------------------------------------------------------------
namespace triagens {
namespace arango {
class PrimaryIndex : public Index {
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
public:
PrimaryIndex () = delete;
PrimaryIndex (struct TRI_document_collection_t*);
~PrimaryIndex ();
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
public:
IndexType type () const override final {
return Index::TRI_IDX_TYPE_PRIMARY_INDEX;
}
bool hasSelectivityEstimate () const override final {
return true;
}
double selectivityEstimate () const override final {
return 1.0;
}
size_t memory () const override final;
triagens::basics::Json toJson (TRI_memory_zone_t*) const override final;
int insert (struct TRI_doc_mptr_t const*, bool) override final;
int remove (struct TRI_doc_mptr_t const*, bool) override final;
void* lookupKey (char const*) const;
int insertKey (struct TRI_doc_mptr_t const*, void const**);
void insertKey (struct TRI_doc_mptr_t const*);
void* removeKey (char const*);
int resize (size_t);
int resize ();
static uint64_t calculateHash (char const*);
static uint64_t calculateHash (char const*, size_t);
// -----------------------------------------------------------------------------
// --SECTION-- private methods
// -----------------------------------------------------------------------------
private:
bool shouldResize () const;
bool resize (uint64_t, bool);
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
private:
struct TRI_document_collection_t* _collection;
////////////////////////////////////////////////////////////////////////////////
/// @brief associative array of pointers
////////////////////////////////////////////////////////////////////////////////
struct {
uint64_t _nrAlloc; // the size of the table
uint64_t _nrUsed; // the number of used entries
void** _table; // the table itself
}
_primaryIndex;
static uint64_t const InitialSize;
};
}
}
#endif
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

View File

@ -0,0 +1,392 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief skiplist index
///
/// @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 Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "SkiplistIndex2.h"
#include "VocBase/document-collection.h"
#include "VocBase/transaction.h"
#include "VocBase/voc-shaper.h"
using namespace triagens::arango;
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
static int FillLookupOperator (TRI_index_operator_t* slOperator,
TRI_document_collection_t* document) {
if (slOperator == nullptr) {
return TRI_ERROR_INTERNAL;
}
switch (slOperator->_type) {
case TRI_AND_INDEX_OPERATOR:
case TRI_NOT_INDEX_OPERATOR:
case TRI_OR_INDEX_OPERATOR: {
TRI_logical_index_operator_t* logicalOperator = (TRI_logical_index_operator_t*) slOperator;
int res = FillLookupOperator(logicalOperator->_left, document);
if (res == TRI_ERROR_NO_ERROR) {
res = FillLookupOperator(logicalOperator->_right, document);
}
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
break;
}
case TRI_EQ_INDEX_OPERATOR:
case TRI_GE_INDEX_OPERATOR:
case TRI_GT_INDEX_OPERATOR:
case TRI_NE_INDEX_OPERATOR:
case TRI_LE_INDEX_OPERATOR:
case TRI_LT_INDEX_OPERATOR: {
TRI_relation_index_operator_t* relationOperator = (TRI_relation_index_operator_t*) slOperator;
relationOperator->_numFields = TRI_LengthVector(&relationOperator->_parameters->_value._objects);
relationOperator->_fields = static_cast<TRI_shaped_json_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_shaped_json_t) * relationOperator->_numFields, false));
if (relationOperator->_fields != nullptr) {
for (size_t j = 0; j < relationOperator->_numFields; ++j) {
TRI_json_t const* jsonObject = static_cast<TRI_json_t* const>(TRI_AtVector(&(relationOperator->_parameters->_value._objects), j));
// find out if the search value is a list or an array
if ((TRI_IsArrayJson(jsonObject) || TRI_IsObjectJson(jsonObject)) &&
slOperator->_type != TRI_EQ_INDEX_OPERATOR) {
// non-equality operator used on list or array data type, this is disallowed
// because we need to shape these objects first. however, at this place (index lookup)
// we never want to create new shapes so we will have a problem if we cannot find an
// existing shape for the search value. in this case we would need to raise an error
// but then the query results would depend on the state of the shaper and if it had
// seen previous such objects
// we still allow looking for list or array values using equality. this is safe.
TRI_Free(TRI_UNKNOWN_MEM_ZONE, relationOperator->_fields);
relationOperator->_fields = nullptr;
return TRI_ERROR_BAD_PARAMETER;
}
// now shape the search object (but never create any new shapes)
TRI_shaped_json_t* shapedObject = TRI_ShapedJsonJson(document->getShaper(), jsonObject, false); // ONLY IN INDEX, PROTECTED by RUNTIME
if (shapedObject != nullptr) {
// found existing shape
relationOperator->_fields[j] = *shapedObject; // shallow copy here is ok
TRI_Free(TRI_UNKNOWN_MEM_ZONE, shapedObject); // don't require storage anymore
}
else {
// shape not found
TRI_Free(TRI_UNKNOWN_MEM_ZONE, relationOperator->_fields);
relationOperator->_fields = nullptr;
return TRI_RESULT_ELEMENT_NOT_FOUND;
}
}
}
else {
relationOperator->_numFields = 0; // out of memory?
}
break;
}
}
return TRI_ERROR_NO_ERROR;
}
// -----------------------------------------------------------------------------
// --SECTION-- class SkiplistIndex
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
SkiplistIndex2::SkiplistIndex2 (TRI_idx_iid_t iid,
TRI_document_collection_t* collection,
std::vector<std::string> const& fields,
std::vector<TRI_shape_pid_t> const& paths,
bool unique,
bool sparse)
: Index(iid, fields),
_collection(collection),
_paths(paths),
_skiplistIndex(nullptr),
_unique(unique),
_sparse(sparse) {
_skiplistIndex = SkiplistIndex_new(collection,
paths.size(),
unique);
}
SkiplistIndex2::~SkiplistIndex2 () {
if (_skiplistIndex != nullptr) {
SkiplistIndex_free(_skiplistIndex);
}
}
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
size_t SkiplistIndex2::memory () const {
return SkiplistIndex_memoryUsage(_skiplistIndex);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return a JSON representation of the index
////////////////////////////////////////////////////////////////////////////////
triagens::basics::Json SkiplistIndex2::toJson (TRI_memory_zone_t* zone) const {
auto json = Index::toJson(zone);
triagens::basics::Json f(zone, triagens::basics::Json::Array, fields().size());
for (auto const& field : fields()) {
f.add(triagens::basics::Json(zone, field));
}
json("fields", f)
("unique", triagens::basics::Json(zone, _unique))
("sparse", triagens::basics::Json(zone, _sparse));
return json;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief inserts a document into a skiplist index
////////////////////////////////////////////////////////////////////////////////
int SkiplistIndex2::insert (TRI_doc_mptr_t const* doc,
bool) {
auto skiplistElement = static_cast<TRI_skiplist_index_element_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, SkiplistIndex_ElementSize(_skiplistIndex), false));
if (skiplistElement == nullptr) {
return TRI_ERROR_OUT_OF_MEMORY;
}
int res = fillElement(skiplistElement, doc);
// ...........................................................................
// most likely the cause of this error is that the index is sparse
// and not all attributes the index needs are set -- so the document
// is ignored. So not really an error at all. Note that this does
// not happen in a non-sparse skiplist index, in which empty
// attributes are always treated as if they were bound to null, so
// TRI_ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING cannot happen at
// all.
// ...........................................................................
// .........................................................................
// It may happen that the document does not have the necessary
// attributes to be included within the hash index, in this case do
// not report back an error.
// .........................................................................
if (res == TRI_ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING) {
if (_sparse) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, skiplistElement);
return TRI_ERROR_NO_ERROR;
}
res = TRI_ERROR_NO_ERROR;
}
if (res != TRI_ERROR_NO_ERROR) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, skiplistElement);
return res;
}
// insert into the index. the memory for the element will be owned or freed
// by the index
return SkiplistIndex_insert(_skiplistIndex, skiplistElement);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief removes a document from a skiplist index
////////////////////////////////////////////////////////////////////////////////
int SkiplistIndex2::remove (TRI_doc_mptr_t const* doc,
bool) {
auto skiplistElement = static_cast<TRI_skiplist_index_element_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, SkiplistIndex_ElementSize(_skiplistIndex), false));
if (skiplistElement == nullptr) {
return TRI_ERROR_OUT_OF_MEMORY;
}
int res = fillElement(skiplistElement, doc);
// ..........................................................................
// Error returned generally implies that the document never was part of the
// skiplist index
// ..........................................................................
if (res == TRI_ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING) {
if (_sparse) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, skiplistElement);
return TRI_ERROR_NO_ERROR;
}
res = TRI_ERROR_NO_ERROR;
}
if (res != TRI_ERROR_NO_ERROR) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, skiplistElement);
return res;
}
// attempt the removal for skiplist indexes
// ownership for the index element is transferred to the index
return SkiplistIndex_remove(_skiplistIndex, skiplistElement);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief attempts to locate an entry in the skip list index
///
/// Note: this function will not destroy the passed slOperator before it returns
/// Warning: who ever calls this function is responsible for destroying
/// the TRI_index_operator_t* and the TRI_skiplist_iterator_t* results
////////////////////////////////////////////////////////////////////////////////
TRI_skiplist_iterator_t* SkiplistIndex2::lookup (TRI_index_operator_t* slOperator,
bool reverse) {
if (slOperator == nullptr) {
return nullptr;
}
// .........................................................................
// fill the relation operators which may be embedded in the slOperator with
// additional information. Recall the slOperator is what information was
// received from a user for query the skiplist.
// .........................................................................
int res = FillLookupOperator(slOperator, _collection);
if (res != TRI_ERROR_NO_ERROR) {
TRI_set_errno(res);
return nullptr;
}
return SkiplistIndex_find(_skiplistIndex,
slOperator,
reverse);
}
// -----------------------------------------------------------------------------
// --SECTION-- private methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief helper for skiplist methods
////////////////////////////////////////////////////////////////////////////////
int SkiplistIndex2::fillElement(TRI_skiplist_index_element_t* skiplistElement,
TRI_doc_mptr_t const* document) {
// ..........................................................................
// Assign the document to the SkiplistIndexElement structure so that it can
// be retrieved later.
// ..........................................................................
TRI_ASSERT(document != nullptr);
TRI_ASSERT_EXPENSIVE(document->getDataPtr() != nullptr); // ONLY IN INDEX, PROTECTED by RUNTIME
TRI_shaped_json_t shapedJson;
TRI_EXTRACT_SHAPED_JSON_MARKER(shapedJson, document->getDataPtr()); // ONLY IN INDEX, PROTECTED by RUNTIME
if (shapedJson._sid == TRI_SHAPE_ILLEGAL) {
LOG_WARNING("encountered invalid marker with shape id 0");
return TRI_ERROR_INTERNAL;
}
int res = TRI_ERROR_NO_ERROR;
skiplistElement->_document = const_cast<TRI_doc_mptr_t*>(document);
char const* ptr = skiplistElement->_document->getShapedJsonPtr(); // ONLY IN INDEX, PROTECTED by RUNTIME
auto subObjects = SkiplistIndex_Subobjects(skiplistElement);
size_t const n = _paths.size();
for (size_t j = 0; j < n; ++j) {
TRI_shape_pid_t shape = _paths[j];
// ..........................................................................
// Determine if document has that particular shape
// ..........................................................................
TRI_shape_access_t const* acc = TRI_FindAccessorVocShaper(_collection->getShaper(), shapedJson._sid, shape); // ONLY IN INDEX, PROTECTED by RUNTIME
if (acc == nullptr || acc->_resultSid == TRI_SHAPE_ILLEGAL) {
// OK, the document does not contain the attributed needed by
// the index, are we sparse?
subObjects[j]._sid = BasicShapes::TRI_SHAPE_SID_NULL;
res = TRI_ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING;
if (_sparse) {
// no need to continue
return res;
}
continue;
}
// ..........................................................................
// Extract the field
// ..........................................................................
TRI_shaped_json_t shapedObject;
if (! TRI_ExecuteShapeAccessor(acc, &shapedJson, &shapedObject)) {
return TRI_ERROR_INTERNAL;
}
if (shapedObject._sid == BasicShapes::TRI_SHAPE_SID_NULL) {
res = TRI_ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING;
if (_sparse) {
// no need to continue
return res;
}
}
// .........................................................................
// Store the field
// .........................................................................
TRI_FillShapedSub(&subObjects[j], &shapedObject, ptr);
}
return res;
}
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

View File

@ -0,0 +1,158 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief skiplist index
///
/// @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 Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_INDEXES_SKIPLIST_INDEX_H
#define ARANGODB_INDEXES_SKIPLIST_INDEX_H 1
#include "Basics/Common.h"
#include "Indexes/Index.h"
#include "IndexOperators/index-operator.h"
#include "SkipLists/skiplistIndex.h"
#include "ShapedJson/shaped-json.h"
#include "VocBase/vocbase.h"
#include "VocBase/voc-types.h"
// -----------------------------------------------------------------------------
// --SECTION-- class SkiplistIndex
// -----------------------------------------------------------------------------
namespace triagens {
namespace arango {
class SkiplistIndex2 : public Index {
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
public:
SkiplistIndex2 () = delete;
SkiplistIndex2 (TRI_idx_iid_t,
struct TRI_document_collection_t*,
std::vector<std::string> const&,
std::vector<TRI_shape_pid_t> const&,
bool,
bool);
~SkiplistIndex2 ();
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
public:
IndexType type () const override final {
return Index::TRI_IDX_TYPE_SKIPLIST_INDEX;
}
bool hasSelectivityEstimate () const override final {
return false;
}
size_t memory () const override final;
triagens::basics::Json toJson (TRI_memory_zone_t*) const override final;
int insert (struct TRI_doc_mptr_t const*, bool) override final;
int remove (struct TRI_doc_mptr_t const*, bool) override final;
////////////////////////////////////////////////////////////////////////////////
/// @brief attempts to locate an entry in the skip list index
///
/// Note: this function will not destroy the passed slOperator before it returns
/// Warning: who ever calls this function is responsible for destroying
/// the TRI_index_operator_t* and the TRI_skiplist_iterator_t* results
////////////////////////////////////////////////////////////////////////////////
TRI_skiplist_iterator_t* lookup (TRI_index_operator_t*,
bool);
// -----------------------------------------------------------------------------
// --SECTION-- private methods
// -----------------------------------------------------------------------------
private:
int fillElement(TRI_skiplist_index_element_t*,
struct TRI_doc_mptr_t const*);
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief the underlying collection
////////////////////////////////////////////////////////////////////////////////
struct TRI_document_collection_t* _collection;
////////////////////////////////////////////////////////////////////////////////
/// @brief the attribute paths
////////////////////////////////////////////////////////////////////////////////
std::vector<TRI_shape_pid_t> const _paths;
////////////////////////////////////////////////////////////////////////////////
/// @brief the actual skiplist index
////////////////////////////////////////////////////////////////////////////////
SkiplistIndex* _skiplistIndex;
////////////////////////////////////////////////////////////////////////////////
/// @brief whether the index is unique
////////////////////////////////////////////////////////////////////////////////
bool const _unique;
////////////////////////////////////////////////////////////////////////////////
/// @brief whether the index is sparse
////////////////////////////////////////////////////////////////////////////////
bool const _sparse;
};
}
}
#endif
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

View File

@ -74,6 +74,14 @@ arangod_libarangod_a_SOURCES = \
arangod/HashIndex/hash-array.cpp \
arangod/HashIndex/hash-array-multi.cpp \
arangod/HashIndex/hash-index.cpp \
arangod/Indexes/CapConstraint.cpp \
arangod/Indexes/EdgeIndex.cpp \
arangod/Indexes/FulltextIndex.cpp \
arangod/Indexes/GeoIndex2.cpp \
arangod/Indexes/HashIndex.cpp \
arangod/Indexes/Index.cpp \
arangod/Indexes/PrimaryIndex.cpp \
arangod/Indexes/SkiplistIndex2.cpp \
arangod/IndexOperators/index-operator.cpp \
arangod/Replication/ContinuousSyncer.cpp \
arangod/Replication/InitialSyncer.cpp \

View File

@ -627,8 +627,150 @@ static void SkiplistIndex_findHelper (SkiplistIndex* skiplistIndex,
switch (indexOperator->_type) {
case TRI_AND_INDEX_OPERATOR: {
SkiplistIndex_findHelper(skiplistIndex,shapeList, logicalOperator->_left, &leftResult);
SkiplistIndex_findHelper(skiplistIndex,shapeList, logicalOperator->_right, &rightResult);
SkiplistIndex_findHelper(skiplistIndex, shapeList, logicalOperator->_left, &leftResult);
SkiplistIndex_findHelper(skiplistIndex, shapeList, logicalOperator->_right, &rightResult);
size_t nl = TRI_LengthVector(&leftResult);
size_t nr = TRI_LengthVector(&rightResult);
for (size_t i = 0; i < nl; ++i) {
for (size_t j = 0; j < nr; ++j) {
auto tempLeftInterval = static_cast<TRI_skiplist_iterator_interval_t*>(TRI_AddressVector(&leftResult, i));
auto tempRightInterval = static_cast<TRI_skiplist_iterator_interval_t*>(TRI_AddressVector(&rightResult, j));
if (skiplistIndex_findHelperIntervalIntersectionValid(
skiplistIndex,
tempLeftInterval,
tempRightInterval,
&interval)) {
TRI_PushBackVector(resultIntervalList, &interval);
}
}
}
TRI_DestroyVector(&leftResult);
TRI_DestroyVector(&rightResult);
return;
}
case TRI_EQ_INDEX_OPERATOR: {
temp = skiplistIndex->skiplist->leftKeyLookup(&values);
TRI_ASSERT(nullptr != temp);
interval._leftEndPoint = temp;
bool const allAttributesCoveredByCondition = (values._numFields == skiplistIndex->_numFields);
if (skiplistIndex->unique && allAttributesCoveredByCondition) {
// At most one hit:
temp = temp->nextNode();
if (nullptr != temp) {
if (0 == CmpKeyElm(skiplistIndex, &values, temp->document())) {
interval._rightEndPoint = temp->nextNode();
if (skiplistIndex_findHelperIntervalValid(skiplistIndex,
&interval)) {
TRI_PushBackVector(resultIntervalList, &interval);
}
}
}
}
else {
temp = skiplistIndex->skiplist->rightKeyLookup(&values);
interval._rightEndPoint = temp->nextNode();
if (skiplistIndex_findHelperIntervalValid(skiplistIndex,
&interval)) {
TRI_PushBackVector(resultIntervalList, &interval);
}
}
return;
}
case TRI_LE_INDEX_OPERATOR: {
interval._leftEndPoint = skiplistIndex->skiplist->startNode();
temp = skiplistIndex->skiplist->rightKeyLookup(&values);
interval._rightEndPoint = temp->nextNode();
if (skiplistIndex_findHelperIntervalValid(skiplistIndex, &interval)) {
TRI_PushBackVector(resultIntervalList, &interval);
}
return;
}
case TRI_LT_INDEX_OPERATOR: {
interval._leftEndPoint = skiplistIndex->skiplist->startNode();
temp = skiplistIndex->skiplist->leftKeyLookup(&values);
interval._rightEndPoint = temp->nextNode();
if (skiplistIndex_findHelperIntervalValid(skiplistIndex, &interval)) {
TRI_PushBackVector(resultIntervalList, &interval);
}
return;
}
case TRI_GE_INDEX_OPERATOR: {
temp = skiplistIndex->skiplist->leftKeyLookup(&values);
interval._leftEndPoint = temp;
interval._rightEndPoint = skiplistIndex->skiplist->endNode();
if (skiplistIndex_findHelperIntervalValid(skiplistIndex, &interval)) {
TRI_PushBackVector(resultIntervalList, &interval);
}
return;
}
case TRI_GT_INDEX_OPERATOR: {
temp = skiplistIndex->skiplist->rightKeyLookup(&values);
interval._leftEndPoint = temp;
interval._rightEndPoint = skiplistIndex->skiplist->endNode();
if (skiplistIndex_findHelperIntervalValid(skiplistIndex, &interval)) {
TRI_PushBackVector(resultIntervalList, &interval);
}
return;
}
default: {
TRI_ASSERT(false);
}
} // end of switch statement
}
static void SkiplistIndex_findHelper (SkiplistIndex* skiplistIndex,
TRI_index_operator_t const* indexOperator,
TRI_vector_t* resultIntervalList) {
TRI_skiplist_index_key_t values;
TRI_vector_t leftResult;
TRI_vector_t rightResult;
TRI_skiplist_iterator_interval_t interval;
triagens::basics::SkipListNode* temp;
TRI_InitVector(&(leftResult), TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_skiplist_iterator_interval_t));
TRI_InitVector(&(rightResult), TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_skiplist_iterator_interval_t));
TRI_relation_index_operator_t* relationOperator = (TRI_relation_index_operator_t*) indexOperator;
TRI_logical_index_operator_t* logicalOperator = (TRI_logical_index_operator_t*) indexOperator;
switch (indexOperator->_type) {
case TRI_EQ_INDEX_OPERATOR:
case TRI_LE_INDEX_OPERATOR:
case TRI_LT_INDEX_OPERATOR:
case TRI_GE_INDEX_OPERATOR:
case TRI_GT_INDEX_OPERATOR:
values._fields = relationOperator->_fields;
values._numFields = relationOperator->_numFields;
break; // this is to silence a compiler warning
default: {
// must not access relationOperator->xxx if the operator is not a
// relational one otherwise we'll get invalid reads and the prog
// might crash
}
}
switch (indexOperator->_type) {
case TRI_AND_INDEX_OPERATOR: {
SkiplistIndex_findHelper(skiplistIndex, logicalOperator->_left, &leftResult);
SkiplistIndex_findHelper(skiplistIndex, logicalOperator->_right, &rightResult);
size_t nl = TRI_LengthVector(&leftResult);
size_t nr = TRI_LengthVector(&rightResult);
@ -739,7 +881,7 @@ TRI_skiplist_iterator_t* SkiplistIndex_find (
TRI_vector_t const* shapeList,
TRI_index_operator_t const* indexOperator,
bool reverse) {
TRI_skiplist_iterator_t* results = static_cast<TRI_skiplist_iterator_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_skiplist_iterator_t), true));
auto results = static_cast<TRI_skiplist_iterator_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_skiplist_iterator_t), true));
if (results == nullptr) {
return nullptr; // calling procedure needs to care when the iterator is null
@ -785,6 +927,55 @@ TRI_skiplist_iterator_t* SkiplistIndex_find (
return results;
}
TRI_skiplist_iterator_t* SkiplistIndex_find (SkiplistIndex* skiplistIndex,
TRI_index_operator_t const* indexOperator,
bool reverse) {
auto results = static_cast<TRI_skiplist_iterator_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_skiplist_iterator_t), true));
if (results == nullptr) {
return nullptr; // calling procedure needs to care when the iterator is null
}
results->_index = skiplistIndex;
TRI_InitVector(&(results->_intervals), TRI_UNKNOWN_MEM_ZONE,
sizeof(TRI_skiplist_iterator_interval_t));
results->_currentInterval = 0;
results->_cursor = nullptr;
if (reverse) {
// reverse iteration intentionally assigns the reverse traversal
// methods to hasNext() and next() so the interface remains the same
// for the caller!
results->hasNext = SkiplistHasPrevIterationCallback;
results->next = SkiplistPrevIterationCallback;
}
else {
results->hasNext = SkiplistHasNextIterationCallback;
results->next = SkiplistNextIterationCallback;
}
SkiplistIndex_findHelper(skiplistIndex, indexOperator, &(results->_intervals));
size_t const n = TRI_LengthVector(&results->_intervals);
// Finally initialise _cursor if the result is not empty:
if (0 < n) {
if (reverse) {
// start at last interval, right endpoint
results->_currentInterval = n - 1;
auto tmp = static_cast<TRI_skiplist_iterator_interval_t*>(TRI_AtVector(&results->_intervals, n - 1));
results->_cursor = tmp->_rightEndPoint;
}
else {
// start at first interval, left endpoint
auto tmp = static_cast<TRI_skiplist_iterator_interval_t*>(TRI_AtVector(&results->_intervals, 0));
results->_cursor = tmp->_leftEndPoint;
}
}
return results;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief inserts a data element into the skip list
/// ownership for the element is transferred to the index

View File

@ -147,6 +147,10 @@ TRI_skiplist_iterator_t* SkiplistIndex_find (SkiplistIndex*,
TRI_index_operator_t const*,
bool);
TRI_skiplist_iterator_t* SkiplistIndex_find (SkiplistIndex*,
TRI_index_operator_t const*,
bool);
int SkiplistIndex_insert (SkiplistIndex*, TRI_skiplist_index_element_t*);
int SkiplistIndex_remove (SkiplistIndex*, TRI_skiplist_index_element_t*);

View File

@ -1561,7 +1561,7 @@ TRI_index_t* TRI_LookupIndexByHandle (v8::Isolate* isolate,
}
}
TRI_index_t* idx = TRI_LookupIndex(collection->_collection, iid);
TRI_index_t* idx = collection->_collection->lookupIndex(iid);
if (idx == nullptr) {
if (! ignoreNotFound) {

View File

@ -488,6 +488,56 @@ static int CreateHeader (TRI_document_collection_t* document,
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief removes an index file
////////////////////////////////////////////////////////////////////////////////
static bool RemoveIndexFile (TRI_document_collection_t* collection,
TRI_idx_iid_t id) {
// construct filename
char* number = TRI_StringUInt64(id);
if (number == nullptr) {
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
LOG_ERROR("out of memory when creating index number");
return false;
}
char* name = TRI_Concatenate3String("index-", number, ".json");
if (name == nullptr) {
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
TRI_FreeString(TRI_CORE_MEM_ZONE, number);
LOG_ERROR("out of memory when creating index name");
return false;
}
char* filename = TRI_Concatenate2File(collection->_directory, name);
if (filename == nullptr) {
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
TRI_FreeString(TRI_CORE_MEM_ZONE, number);
TRI_FreeString(TRI_CORE_MEM_ZONE, name);
LOG_ERROR("out of memory when creating index filename");
return false;
}
TRI_FreeString(TRI_CORE_MEM_ZONE, name);
TRI_FreeString(TRI_CORE_MEM_ZONE, number);
int res = TRI_UnlinkFile(filename);
TRI_FreeString(TRI_CORE_MEM_ZONE, filename);
if (res != TRI_ERROR_NO_ERROR) {
LOG_ERROR("cannot remove index definition: %s", TRI_last_error());
return false;
}
return true;
}
// -----------------------------------------------------------------------------
// --SECTION-- DOCUMENT CRUD
// -----------------------------------------------------------------------------
@ -3505,6 +3555,73 @@ bool TRI_IsFullyCollectedDocumentCollection (TRI_document_collection_t* document
return (uncollected == 0);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief saves an index
////////////////////////////////////////////////////////////////////////////////
int TRI_SaveIndex (TRI_document_collection_t* document,
TRI_index_t* idx,
bool writeMarker) {
// convert into JSON
TRI_json_t* json = idx->json(idx);
if (json == nullptr) {
LOG_TRACE("cannot save index definition: index cannot be jsonified");
return TRI_set_errno(TRI_ERROR_INTERNAL);
}
// construct filename
char* number = TRI_StringUInt64(idx->_iid);
char* name = TRI_Concatenate3String("index-", number, ".json");
char* filename = TRI_Concatenate2File(document->_directory, name);
TRI_FreeString(TRI_CORE_MEM_ZONE, name);
TRI_FreeString(TRI_CORE_MEM_ZONE, number);
TRI_vocbase_t* vocbase = document->_vocbase;
// and save
bool ok = TRI_SaveJson(filename, json, document->_vocbase->_settings.forceSyncProperties);
TRI_FreeString(TRI_CORE_MEM_ZONE, filename);
if (! ok) {
LOG_ERROR("cannot save index definition: %s", TRI_last_error());
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
return TRI_errno();
}
if (! writeMarker) {
return TRI_ERROR_NO_ERROR;
}
int res = TRI_ERROR_NO_ERROR;
try {
triagens::wal::CreateIndexMarker marker(vocbase->_id, document->_info._cid, idx->_iid, triagens::basics::JsonHelper::toString(json));
triagens::wal::SlotInfoCopy slotInfo = triagens::wal::LogfileManager::instance()->allocateAndWrite(marker, false);
if (slotInfo.errorCode != TRI_ERROR_NO_ERROR) {
THROW_ARANGO_EXCEPTION(slotInfo.errorCode);
}
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
return TRI_ERROR_NO_ERROR;
}
catch (triagens::basics::Exception const& ex) {
res = ex.code();
}
catch (...) {
res = TRI_ERROR_INTERNAL;
}
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
// TODO: what to do here?
return res;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns a description of all indexes
///
@ -3568,7 +3685,7 @@ bool TRI_DropIndexDocumentCollection (TRI_document_collection_t* document,
// .............................................................................
if (found != nullptr) {
bool result = TRI_RemoveIndexFile(document, found);
bool result = RemoveIndexFile(document, found->_iid);
TRI_FreeIndex(found);

View File

@ -825,6 +825,14 @@ int TRI_CloseDocumentCollection (TRI_document_collection_t*,
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief saves an index
////////////////////////////////////////////////////////////////////////////////
int TRI_SaveIndex (TRI_document_collection_t*,
TRI_index_t*,
bool writeMarker);
////////////////////////////////////////////////////////////////////////////////
/// @brief returns a description of all indexes
///

View File

@ -282,139 +282,6 @@ void TRI_FreeIndex (TRI_index_t* idx) {
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief removes an index file
////////////////////////////////////////////////////////////////////////////////
bool TRI_RemoveIndexFile (TRI_document_collection_t* collection, TRI_index_t* idx) {
// construct filename
char* number = TRI_StringUInt64(idx->_iid);
if (number == nullptr) {
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
LOG_ERROR("out of memory when creating index number");
return false;
}
char* name = TRI_Concatenate3String("index-", number, ".json");
if (name == nullptr) {
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
TRI_FreeString(TRI_CORE_MEM_ZONE, number);
LOG_ERROR("out of memory when creating index name");
return false;
}
char* filename = TRI_Concatenate2File(collection->_directory, name);
if (filename == nullptr) {
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
TRI_FreeString(TRI_CORE_MEM_ZONE, number);
TRI_FreeString(TRI_CORE_MEM_ZONE, name);
LOG_ERROR("out of memory when creating index filename");
return false;
}
TRI_FreeString(TRI_CORE_MEM_ZONE, name);
TRI_FreeString(TRI_CORE_MEM_ZONE, number);
int res = TRI_UnlinkFile(filename);
TRI_FreeString(TRI_CORE_MEM_ZONE, filename);
if (res != TRI_ERROR_NO_ERROR) {
LOG_ERROR("cannot remove index definition: %s", TRI_last_error());
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief saves an index
////////////////////////////////////////////////////////////////////////////////
int TRI_SaveIndex (TRI_document_collection_t* document,
TRI_index_t* idx,
bool writeMarker) {
// convert into JSON
TRI_json_t* json = idx->json(idx);
if (json == nullptr) {
LOG_TRACE("cannot save index definition: index cannot be jsonified");
return TRI_set_errno(TRI_ERROR_INTERNAL);
}
// construct filename
char* number = TRI_StringUInt64(idx->_iid);
char* name = TRI_Concatenate3String("index-", number, ".json");
char* filename = TRI_Concatenate2File(document->_directory, name);
TRI_FreeString(TRI_CORE_MEM_ZONE, name);
TRI_FreeString(TRI_CORE_MEM_ZONE, number);
TRI_vocbase_t* vocbase = document->_vocbase;
// and save
bool ok = TRI_SaveJson(filename, json, document->_vocbase->_settings.forceSyncProperties);
TRI_FreeString(TRI_CORE_MEM_ZONE, filename);
if (! ok) {
LOG_ERROR("cannot save index definition: %s", TRI_last_error());
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
return TRI_errno();
}
if (! writeMarker) {
return TRI_ERROR_NO_ERROR;
}
int res = TRI_ERROR_NO_ERROR;
try {
triagens::wal::CreateIndexMarker marker(vocbase->_id, document->_info._cid, idx->_iid, triagens::basics::JsonHelper::toString(json));
triagens::wal::SlotInfoCopy slotInfo = triagens::wal::LogfileManager::instance()->allocateAndWrite(marker, false);
if (slotInfo.errorCode != TRI_ERROR_NO_ERROR) {
THROW_ARANGO_EXCEPTION(slotInfo.errorCode);
}
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
return TRI_ERROR_NO_ERROR;
}
catch (triagens::basics::Exception const& ex) {
res = ex.code();
}
catch (...) {
res = TRI_ERROR_INTERNAL;
}
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
// TODO: what to do here?
return res;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief looks up an index identifier
////////////////////////////////////////////////////////////////////////////////
TRI_index_t* TRI_LookupIndex (TRI_document_collection_t* document,
TRI_idx_iid_t iid) {
for (auto const& idx : document->allIndexes()) {
if (idx->_iid == iid) {
return idx;
}
}
TRI_set_errno(TRI_ERROR_ARANGO_NO_INDEX);
return nullptr;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a basic index description as JSON
/// this only contains the common index fields and needs to be extended by the

View File

@ -261,28 +261,6 @@ bool TRI_ValidateIndexIdIndex (char const*,
void TRI_FreeIndex (TRI_index_t*);
////////////////////////////////////////////////////////////////////////////////
/// @brief removes an index file
////////////////////////////////////////////////////////////////////////////////
bool TRI_RemoveIndexFile (struct TRI_document_collection_t*,
TRI_index_t*);
////////////////////////////////////////////////////////////////////////////////
/// @brief saves an index
////////////////////////////////////////////////////////////////////////////////
int TRI_SaveIndex (struct TRI_document_collection_t*,
TRI_index_t*,
bool);
////////////////////////////////////////////////////////////////////////////////
/// @brief looks up an index identifier
////////////////////////////////////////////////////////////////////////////////
TRI_index_t* TRI_LookupIndex (struct TRI_document_collection_t*,
TRI_idx_iid_t);
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a basic index description as JSON
/// this only contains the common index fields and needs to be extended by the
@ -381,9 +359,6 @@ void TRI_FreeSkiplistIndex (TRI_index_t* idx);
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
struct TRI_doc_mptr_t** TRI_LookupFulltextIndex (TRI_index_t*,
const char*);
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a fulltext index
////////////////////////////////////////////////////////////////////////////////