mirror of https://gitee.com/bigwinds/arangodb
moved indexes to cxx
This commit is contained in:
parent
20f9be88e4
commit
a5b6f00b7f
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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:
|
|
@ -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:
|
|
@ -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:
|
|
@ -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:
|
|
@ -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:
|
|
@ -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:
|
|
@ -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:
|
|
@ -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:
|
|
@ -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:
|
|
@ -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:
|
|
@ -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:
|
|
@ -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:
|
|
@ -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:
|
|
@ -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:
|
|
@ -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:
|
|
@ -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:
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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*);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
///
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
Loading…
Reference in New Issue