1
0
Fork 0

Added proper truncation support for RocksDB indexes.

This commit is contained in:
Dan Larkin 2017-05-10 19:57:22 -04:00
parent ab815e6020
commit 52711a2b00
7 changed files with 96 additions and 47 deletions

View File

@ -644,52 +644,7 @@ void RocksDBCollection::truncate(transaction::Methods* trx,
// don't do anything beyond deleting their contents
for (std::shared_ptr<Index> const& index : _indexes) {
RocksDBIndex* rindex = static_cast<RocksDBIndex*>(index.get());
RocksDBKeyBounds indexBounds = RocksDBKeyBounds::Empty();
switch (rindex->type()) {
case RocksDBIndex::TRI_IDX_TYPE_PRIMARY_INDEX:
indexBounds = RocksDBKeyBounds::PrimaryIndex(rindex->objectId());
break;
case RocksDBIndex::TRI_IDX_TYPE_EDGE_INDEX:
indexBounds = RocksDBKeyBounds::EdgeIndex(rindex->objectId());
break;
case RocksDBIndex::TRI_IDX_TYPE_HASH_INDEX:
case RocksDBIndex::TRI_IDX_TYPE_SKIPLIST_INDEX:
case RocksDBIndex::TRI_IDX_TYPE_PERSISTENT_INDEX:
if (rindex->unique()) {
indexBounds = RocksDBKeyBounds::UniqueIndex(rindex->objectId());
} else {
indexBounds = RocksDBKeyBounds::IndexEntries(rindex->objectId());
}
break;
case RocksDBIndex::TRI_IDX_TYPE_FULLTEXT_INDEX:
indexBounds = RocksDBKeyBounds::FulltextIndex(rindex->objectId());
break;
case RocksDBIndex::TRI_IDX_TYPE_GEO1_INDEX:
case RocksDBIndex::TRI_IDX_TYPE_GEO2_INDEX:
indexBounds = RocksDBKeyBounds::GeoIndex(rindex->objectId());
break;
case RocksDBIndex::TRI_IDX_TYPE_UNKNOWN:
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
}
rocksdb::ReadOptions options = state->readOptions();
options.iterate_upper_bound = &(indexBounds.end());
iter.reset(rtrx->GetIterator(options));
iter->Seek(indexBounds.start());
rindex->disableCache(); // TODO: proper blacklisting of keys?
TRI_DEFER(rindex->createCache());
while (iter->Valid()) {
rocksdb::Status s = rtrx->Delete(iter->key());
if (!s.ok()) {
auto converted = convertStatus(s);
THROW_ARANGO_EXCEPTION(converted);
}
iter->Next();
}
rindex->truncate(trx);
}
}

View File

@ -27,13 +27,16 @@
#include "Cache/TransactionalCache.h"
#include "Cache/Common.h"
#include "Cache/Manager.h"
#include "RocksDBEngine/RocksDBCommon.h"
#include "RocksDBEngine/RocksDBComparator.h"
#include "RocksDBEngine/RocksDBEngine.h"
#include "RocksDBEngine/RocksDBTransactionState.h"
#include "StorageEngine/EngineSelectorFeature.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/ticks.h"
using namespace arangodb;
using namespace arangodb::rocksutils;
RocksDBIndex::RocksDBIndex(
TRI_idx_iid_t id, LogicalCollection* collection,
@ -153,6 +156,40 @@ int RocksDBIndex::drop() {
return TRI_ERROR_NO_ERROR;
}
void RocksDBIndex::truncate(transaction::Methods* trx) {
RocksDBTransactionState* state = rocksutils::toRocksTransactionState(trx);
rocksdb::Transaction* rtrx = state->rocksTransaction();
RocksDBKeyBounds indexBounds = getBounds();
rocksdb::ReadOptions options = state->readOptions();
options.iterate_upper_bound = &(indexBounds.end());
std::unique_ptr<rocksdb::Iterator> iter(rtrx->GetIterator(options));
iter->Seek(indexBounds.start());
while (iter->Valid()) {
rocksdb::Status s = rtrx->Delete(iter->key());
if (!s.ok()) {
auto converted = convertStatus(s);
THROW_ARANGO_EXCEPTION(converted);
}
Result r = postprocessRemove(trx, iter->key(), iter->value());
if (!r.ok()) {
THROW_ARANGO_EXCEPTION(r);
}
iter->Next();
}
}
Result RocksDBIndex::postprocessRemove(transaction::Methods* trx,
rocksdb::Slice const& key,
rocksdb::Slice const& value) {
return {TRI_ERROR_NO_ERROR};
}
// blacklist given key from transactional cache
void RocksDBIndex::blackListKey(char const* data, std::size_t len){
if (useCache()) {
@ -170,3 +207,27 @@ void RocksDBIndex::blackListKey(char const* data, std::size_t len){
}
}
}
RocksDBKeyBounds RocksDBIndex::getBounds() const {
switch (type()) {
case RocksDBIndex::TRI_IDX_TYPE_PRIMARY_INDEX:
return RocksDBKeyBounds::PrimaryIndex(objectId());
case RocksDBIndex::TRI_IDX_TYPE_EDGE_INDEX:
return RocksDBKeyBounds::EdgeIndex(objectId());
case RocksDBIndex::TRI_IDX_TYPE_HASH_INDEX:
case RocksDBIndex::TRI_IDX_TYPE_SKIPLIST_INDEX:
case RocksDBIndex::TRI_IDX_TYPE_PERSISTENT_INDEX:
if (unique()) {
return RocksDBKeyBounds::UniqueIndex(objectId());
}
return RocksDBKeyBounds::IndexEntries(objectId());
case RocksDBIndex::TRI_IDX_TYPE_FULLTEXT_INDEX:
return RocksDBKeyBounds::FulltextIndex(objectId());
case RocksDBIndex::TRI_IDX_TYPE_GEO1_INDEX:
case RocksDBIndex::TRI_IDX_TYPE_GEO2_INDEX:
return RocksDBKeyBounds::GeoIndex(objectId());
case RocksDBIndex::TRI_IDX_TYPE_UNKNOWN:
default:
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
}
}

View File

@ -41,7 +41,7 @@ class Cache;
}
class LogicalCollection;
class RocksDBComparator;
class RocksDBIndex : public Index {
protected:
RocksDBIndex(TRI_idx_iid_t, LogicalCollection*,
@ -68,6 +68,8 @@ class RocksDBIndex : public Index {
int unload() override;
virtual void truncate(transaction::Methods*);
/// @brief provides a size hint for the index
int sizeHint(transaction::Methods* /*trx*/, size_t /*size*/) override final {
// nothing to do here
@ -88,12 +90,19 @@ class RocksDBIndex : public Index {
void disableCache();
protected:
// Will be called during truncate to allow the index to update selectivity
// estimates, blacklist keys, etc.
virtual Result postprocessRemove(transaction::Methods* trx,
rocksdb::Slice const& key, rocksdb::Slice const& value);
inline bool useCache() const { return (_useCache && _cachePresent); }
void blackListKey(char const* data, std::size_t len);
void blackListKey(StringRef& ref){
blackListKey(ref.data(), ref.size());
};
RocksDBKeyBounds getBounds() const;
protected:
uint64_t _objectId;
RocksDBComparator* _cmp;

View File

@ -560,6 +560,13 @@ void RocksDBPrimaryIndex::invokeOnAllElements(
}
}
Result RocksDBPrimaryIndex::postprocessRemove(transaction::Methods* trx,
rocksdb::Slice const& key,
rocksdb::Slice const& value) {
blackListKey(key.data(), key.size());
return {TRI_ERROR_NO_ERROR};
}
/// @brief create the iterator, for a single attribute, IN operator
IndexIterator* RocksDBPrimaryIndex::createInIterator(
transaction::Methods* trx, ManagedDocumentResult* mmdr,

View File

@ -211,6 +211,10 @@ class RocksDBPrimaryIndex final : public RocksDBIndex {
int cleanup() override;
protected:
Result postprocessRemove(transaction::Methods* trx, rocksdb::Slice const& key,
rocksdb::Slice const& value) override;
private:
/// @brief create the iterator, for a single attribute, IN operator
IndexIterator* createInIterator(transaction::Methods*, ManagedDocumentResult*,

View File

@ -1412,3 +1412,12 @@ int RocksDBVPackIndex::cleanup() {
db->CompactRange(opts, &b, &e);
return TRI_ERROR_NO_ERROR;
}
Result RocksDBVPackIndex::postprocessRemove(transaction::Methods* trx,
rocksdb::Slice const& key,
rocksdb::Slice const& value) {
if (!unique()) {
// TODO: update selectivity estimate
}
return {TRI_ERROR_NO_ERROR};
}

View File

@ -179,6 +179,10 @@ class RocksDBVPackIndex : public RocksDBIndex {
int cleanup() override;
protected:
Result postprocessRemove(transaction::Methods* trx, rocksdb::Slice const& key,
rocksdb::Slice const& value) override;
private:
bool isDuplicateOperator(arangodb::aql::AstNode const*,
std::unordered_set<int> const&) const;