1
0
Fork 0

move collection keys into engine

This commit is contained in:
jsteemann 2017-03-21 14:23:29 +01:00
parent 36ff459cfb
commit 63868b4378
7 changed files with 328 additions and 213 deletions

View File

@ -383,6 +383,7 @@ set(ARANGOD_SOURCES
MMFiles/MMFilesCleanupThread.cpp
MMFiles/MMFilesCollection.cpp
MMFiles/MMFilesCollectionExport.cpp
MMFiles/MMFilesCollectionKeys.cpp
MMFiles/MMFilesCollectorThread.cpp
MMFiles/MMFilesCompactorThread.cpp
MMFiles/MMFilesDatafile.cpp

View File

@ -0,0 +1,215 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 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 Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#include "MMFilesCollectionKeys.h"
#include "Basics/StaticStrings.h"
#include "Basics/StringRef.h"
#include "MMFiles/MMFilesCollection.h"
#include "MMFiles/MMFilesDitch.h"
#include "MMFiles/MMFilesLogfileManager.h"
#include "StorageEngine/EngineSelectorFeature.h"
#include "StorageEngine/StorageEngine.h"
#include "Transaction/Helpers.h"
#include "Utils/CollectionGuard.h"
#include "Utils/SingleCollectionTransaction.h"
#include "Transaction/StandaloneContext.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/vocbase.h"
#include <velocypack/Builder.h>
#include <velocypack/Iterator.h>
#include <velocypack/velocypack-aliases.h>
using namespace arangodb;
MMFilesCollectionKeys::MMFilesCollectionKeys(TRI_vocbase_t* vocbase, std::string const& name,
TRI_voc_tick_t blockerId, double ttl)
: CollectionKeys(vocbase, name, ttl),
_ditch(nullptr),
_resolver(vocbase),
_blockerId(blockerId) {
TRI_ASSERT(_blockerId > 0);
// prevent the collection from being unloaded while the export is ongoing
// this may throw
_guard.reset(new arangodb::CollectionGuard(vocbase, _name.c_str(), false));
_collection = _guard->collection();
TRI_ASSERT(_collection != nullptr);
}
MMFilesCollectionKeys::~MMFilesCollectionKeys() {
// remove compaction blocker
StorageEngine* engine = EngineSelectorFeature::ENGINE;
engine->removeCompactionBlocker(_vocbase, _blockerId);
if (_ditch != nullptr) {
_ditch->ditches()->freeMMFilesDocumentDitch(_ditch, false);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief initially creates the list of keys
////////////////////////////////////////////////////////////////////////////////
void MMFilesCollectionKeys::create(TRI_voc_tick_t maxTick) {
MMFilesLogfileManager::instance()->waitForCollectorQueue(
_collection->cid(), 30.0);
StorageEngine* engine = EngineSelectorFeature::ENGINE;
engine->preventCompaction(_collection->vocbase(), [this](TRI_vocbase_t* vocbase) {
// create a ditch under the compaction lock
_ditch = arangodb::MMFilesCollection::toMMFilesCollection(_collection)
->ditches()
->createMMFilesDocumentDitch(false, __FILE__, __LINE__);
});
// now we either have a ditch or not
if (_ditch == nullptr) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
_vpack.reserve(16384);
// copy all document tokens into the result under the read-lock
{
SingleCollectionTransaction trx(
transaction::StandaloneContext::Create(_collection->vocbase()), _name,
AccessMode::Type::READ);
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
THROW_ARANGO_EXCEPTION(res);
}
ManagedDocumentResult mmdr;
trx.invokeOnAllElements(
_collection->name(), [this, &trx, &maxTick, &mmdr](DocumentIdentifierToken const& token) {
if (_collection->readDocumentConditional(&trx, token, maxTick, mmdr)) {
_vpack.emplace_back(mmdr.vpack());
}
return true;
});
trx.finish(res);
}
// now sort all document tokens without the read-lock
std::sort(_vpack.begin(), _vpack.end(),
[](uint8_t const* lhs, uint8_t const* rhs) -> bool {
return (StringRef(transaction::helpers::extractKeyFromDocument(VPackSlice(lhs))) < StringRef(transaction::helpers::extractKeyFromDocument(VPackSlice(rhs))));
});
}
////////////////////////////////////////////////////////////////////////////////
/// @brief hashes a chunk of keys
////////////////////////////////////////////////////////////////////////////////
std::tuple<std::string, std::string, uint64_t> MMFilesCollectionKeys::hashChunk(
size_t from, size_t to) const {
if (from >= _vpack.size() || to > _vpack.size() || from >= to ||
to == 0) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
}
VPackSlice first(_vpack.at(from));
VPackSlice last(_vpack.at(to - 1));
TRI_ASSERT(first.isObject());
TRI_ASSERT(last.isObject());
uint64_t hash = 0x012345678;
for (size_t i = from; i < to; ++i) {
VPackSlice current(_vpack.at(i));
TRI_ASSERT(current.isObject());
// we can get away with the fast hash function here, as key values are
// restricted to strings
hash ^= transaction::helpers::extractKeyFromDocument(current).hashString();
hash ^= transaction::helpers::extractRevSliceFromDocument(current).hash();
}
return std::make_tuple(
transaction::helpers::extractKeyFromDocument(first).copyString(),
transaction::helpers::extractKeyFromDocument(last).copyString(),
hash);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief dumps keys into the result
////////////////////////////////////////////////////////////////////////////////
void MMFilesCollectionKeys::dumpKeys(VPackBuilder& result, size_t chunk,
size_t chunkSize) const {
size_t from = chunk * chunkSize;
size_t to = (chunk + 1) * chunkSize;
if (to > _vpack.size()) {
to = _vpack.size();
}
if (from >= _vpack.size() || from >= to || to == 0) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
}
for (size_t i = from; i < to; ++i) {
VPackSlice current(_vpack.at(i));
TRI_ASSERT(current.isObject());
result.openArray();
result.add(current.get(StaticStrings::KeyString));
result.add(current.get(StaticStrings::RevString));
result.close();
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief dumps documents into the result
////////////////////////////////////////////////////////////////////////////////
void MMFilesCollectionKeys::dumpDocs(arangodb::velocypack::Builder& result, size_t chunk,
size_t chunkSize, VPackSlice const& ids) const {
if (!ids.isArray()) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
}
for (auto const& it : VPackArrayIterator(ids)) {
if (!it.isNumber()) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
}
size_t position = chunk * chunkSize + it.getNumber<size_t>();
if (position >= _vpack.size()) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
}
VPackSlice current(_vpack.at(position));
TRI_ASSERT(current.isObject());
result.add(current);
}
}

View File

@ -0,0 +1,94 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 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 Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_MMFILES_MMFILES_COLLECTION_KEYS_H
#define ARANGOD_MMFILES_MMFILES_COLLECTION_KEYS_H 1
#include "Basics/Common.h"
#include "Utils/CollectionKeys.h"
#include "Utils/CollectionNameResolver.h"
#include "VocBase/voc-types.h"
#include <velocypack/Builder.h>
#include <velocypack/Slice.h>
#include <velocypack/velocypack-aliases.h>
struct TRI_vocbase_t;
namespace arangodb {
class CollectionGuard;
class MMFilesDocumentDitch;
typedef TRI_voc_tick_t CollectionKeysId;
class MMFilesCollectionKeys final : public CollectionKeys {
public:
MMFilesCollectionKeys(MMFilesCollectionKeys const&) = delete;
MMFilesCollectionKeys& operator=(MMFilesCollectionKeys const&) = delete;
MMFilesCollectionKeys(TRI_vocbase_t*, std::string const& name,
TRI_voc_tick_t blockerId, double ttl);
~MMFilesCollectionKeys();
public:
size_t count() const override {
return _vpack.size();
}
//////////////////////////////////////////////////////////////////////////////
/// @brief initially creates the list of keys
//////////////////////////////////////////////////////////////////////////////
void create(TRI_voc_tick_t) override;
//////////////////////////////////////////////////////////////////////////////
/// @brief hashes a chunk of keys
//////////////////////////////////////////////////////////////////////////////
std::tuple<std::string, std::string, uint64_t> hashChunk(size_t,
size_t) const override;
//////////////////////////////////////////////////////////////////////////////
/// @brief dumps keys into the result
//////////////////////////////////////////////////////////////////////////////
void dumpKeys(arangodb::velocypack::Builder&, size_t, size_t) const override;
//////////////////////////////////////////////////////////////////////////////
/// @brief dumps documents into the result
//////////////////////////////////////////////////////////////////////////////
void dumpDocs(arangodb::velocypack::Builder&, size_t, size_t,
arangodb::velocypack::Slice const&) const override;
private:
std::unique_ptr<arangodb::CollectionGuard> _guard;
arangodb::MMFilesDocumentDitch* _ditch;
arangodb::CollectionNameResolver _resolver;
TRI_voc_tick_t _blockerId;
std::vector<uint8_t const*> _vpack;
};
}
#endif

View File

@ -34,6 +34,7 @@
#include "GeneralServer/GeneralServer.h"
#include "Indexes/Index.h"
#include "Logger/Logger.h"
#include "MMFiles/MMFilesCollectionKeys.h"
#include "MMFiles/MMFilesLogfileManager.h"
#include "MMFiles/mmfiles-replication-dump.h"
#include "Replication/InitialSyncer.h"
@ -44,7 +45,6 @@
#include "StorageEngine/EngineSelectorFeature.h"
#include "StorageEngine/StorageEngine.h"
#include "Utils/CollectionGuard.h"
#include "Utils/CollectionKeys.h"
#include "Utils/CollectionKeysRepository.h"
#include "Utils/CollectionNameResolver.h"
#include "Utils/OperationOptions.h"
@ -2348,7 +2348,7 @@ void RestReplicationHandler::handleCommandCreateKeys() {
// initialize a container with the keys
auto keys =
std::make_unique<CollectionKeys>(_vocbase, col->name(), id, 300.0);
std::make_unique<MMFilesCollectionKeys>(_vocbase, col->name(), id, 300.0);
std::string const idString(std::to_string(keys->id()));
@ -2402,7 +2402,7 @@ void RestReplicationHandler::handleCommandGetKeys() {
auto keysRepository = _vocbase->collectionKeys();
TRI_ASSERT(keysRepository != nullptr);
auto collectionKeysId = static_cast<arangodb::CollectionKeysId>(
auto collectionKeysId = static_cast<CollectionKeysId>(
arangodb::basics::StringUtils::uint64(id));
auto collectionKeys = keysRepository->find(collectionKeysId);
@ -2501,7 +2501,7 @@ void RestReplicationHandler::handleCommandFetchKeys() {
auto keysRepository = _vocbase->collectionKeys();
TRI_ASSERT(keysRepository != nullptr);
auto collectionKeysId = static_cast<arangodb::CollectionKeysId>(
auto collectionKeysId = static_cast<CollectionKeysId>(
arangodb::basics::StringUtils::uint64(id));
auto collectionKeys = keysRepository->find(collectionKeysId);
@ -2563,7 +2563,7 @@ void RestReplicationHandler::handleCommandRemoveKeys() {
auto keys = _vocbase->collectionKeys();
TRI_ASSERT(keys != nullptr);
auto collectionKeysId = static_cast<arangodb::CollectionKeysId>(
auto collectionKeysId = static_cast<CollectionKeysId>(
arangodb::basics::StringUtils::uint64(id));
bool found = keys->remove(collectionKeysId);

View File

@ -22,35 +22,14 @@
////////////////////////////////////////////////////////////////////////////////
#include "CollectionKeys.h"
#include "Basics/StaticStrings.h"
#include "Basics/StringRef.h"
#include "MMFiles/MMFilesLogfileManager.h" //TODO -- REMOVE
#include "MMFiles/MMFilesCollection.h"
#include "MMFiles/MMFilesDitch.h"
#include "StorageEngine/EngineSelectorFeature.h"
#include "StorageEngine/StorageEngine.h"
#include "Transaction/Helpers.h"
#include "Utils/CollectionGuard.h"
#include "Utils/SingleCollectionTransaction.h"
#include "Transaction/StandaloneContext.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/ticks.h"
#include "VocBase/vocbase.h"
#include <velocypack/Builder.h>
#include <velocypack/Iterator.h>
#include <velocypack/velocypack-aliases.h>
using namespace arangodb;
CollectionKeys::CollectionKeys(TRI_vocbase_t* vocbase, std::string const& name,
TRI_voc_tick_t blockerId, double ttl)
CollectionKeys::CollectionKeys(TRI_vocbase_t* vocbase, std::string const& name, double ttl)
: _vocbase(vocbase),
_collection(nullptr),
_ditch(nullptr),
_name(name),
_resolver(vocbase),
_blockerId(blockerId),
_id(0),
_ttl(ttl),
_expires(0.0),
@ -58,168 +37,4 @@ CollectionKeys::CollectionKeys(TRI_vocbase_t* vocbase, std::string const& name,
_isUsed(false) {
_id = TRI_NewTickServer();
_expires = TRI_microtime() + _ttl;
TRI_ASSERT(_blockerId > 0);
// prevent the collection from being unloaded while the export is ongoing
// this may throw
_guard.reset(new arangodb::CollectionGuard(vocbase, _name.c_str(), false));
_collection = _guard->collection();
TRI_ASSERT(_collection != nullptr);
}
CollectionKeys::~CollectionKeys() {
// remove compaction blocker
StorageEngine* engine = EngineSelectorFeature::ENGINE;
engine->removeCompactionBlocker(_vocbase, _blockerId);
if (_ditch != nullptr) {
_ditch->ditches()->freeMMFilesDocumentDitch(_ditch, false);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief initially creates the list of keys
////////////////////////////////////////////////////////////////////////////////
void CollectionKeys::create(TRI_voc_tick_t maxTick) {
MMFilesLogfileManager::instance()->waitForCollectorQueue(
_collection->cid(), 30.0);
StorageEngine* engine = EngineSelectorFeature::ENGINE;
engine->preventCompaction(_collection->vocbase(), [this](TRI_vocbase_t* vocbase) {
// create a ditch under the compaction lock
_ditch = arangodb::MMFilesCollection::toMMFilesCollection(_collection)
->ditches()
->createMMFilesDocumentDitch(false, __FILE__, __LINE__);
});
// now we either have a ditch or not
if (_ditch == nullptr) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
_vpack.reserve(16384);
// copy all document tokens into the result under the read-lock
{
SingleCollectionTransaction trx(
transaction::StandaloneContext::Create(_collection->vocbase()), _name,
AccessMode::Type::READ);
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
THROW_ARANGO_EXCEPTION(res);
}
ManagedDocumentResult mmdr;
trx.invokeOnAllElements(
_collection->name(), [this, &trx, &maxTick, &mmdr](DocumentIdentifierToken const& token) {
if (_collection->readDocumentConditional(&trx, token, maxTick, mmdr)) {
_vpack.emplace_back(mmdr.vpack());
}
return true;
});
trx.finish(res);
}
// now sort all document tokens without the read-lock
std::sort(_vpack.begin(), _vpack.end(),
[](uint8_t const* lhs, uint8_t const* rhs) -> bool {
return (StringRef(transaction::helpers::extractKeyFromDocument(VPackSlice(lhs))) < StringRef(transaction::helpers::extractKeyFromDocument(VPackSlice(rhs))));
});
}
////////////////////////////////////////////////////////////////////////////////
/// @brief hashes a chunk of keys
////////////////////////////////////////////////////////////////////////////////
std::tuple<std::string, std::string, uint64_t> CollectionKeys::hashChunk(
size_t from, size_t to) const {
if (from >= _vpack.size() || to > _vpack.size() || from >= to ||
to == 0) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
}
VPackSlice first(_vpack.at(from));
VPackSlice last(_vpack.at(to - 1));
TRI_ASSERT(first.isObject());
TRI_ASSERT(last.isObject());
uint64_t hash = 0x012345678;
for (size_t i = from; i < to; ++i) {
VPackSlice current(_vpack.at(i));
TRI_ASSERT(current.isObject());
// we can get away with the fast hash function here, as key values are
// restricted to strings
hash ^= transaction::helpers::extractKeyFromDocument(current).hashString();
hash ^= transaction::helpers::extractRevSliceFromDocument(current).hash();
}
return std::make_tuple(
transaction::helpers::extractKeyFromDocument(first).copyString(),
transaction::helpers::extractKeyFromDocument(last).copyString(),
hash);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief dumps keys into the result
////////////////////////////////////////////////////////////////////////////////
void CollectionKeys::dumpKeys(VPackBuilder& result, size_t chunk,
size_t chunkSize) const {
size_t from = chunk * chunkSize;
size_t to = (chunk + 1) * chunkSize;
if (to > _vpack.size()) {
to = _vpack.size();
}
if (from >= _vpack.size() || from >= to || to == 0) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
}
for (size_t i = from; i < to; ++i) {
VPackSlice current(_vpack.at(i));
TRI_ASSERT(current.isObject());
result.openArray();
result.add(current.get(StaticStrings::KeyString));
result.add(current.get(StaticStrings::RevString));
result.close();
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief dumps documents into the result
////////////////////////////////////////////////////////////////////////////////
void CollectionKeys::dumpDocs(arangodb::velocypack::Builder& result, size_t chunk,
size_t chunkSize, VPackSlice const& ids) const {
if (!ids.isArray()) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
}
for (auto const& it : VPackArrayIterator(ids)) {
if (!it.isNumber()) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
}
size_t position = chunk * chunkSize + it.getNumber<size_t>();
if (position >= _vpack.size()) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
}
VPackSlice current(_vpack.at(position));
TRI_ASSERT(current.isObject());
result.add(current);
}
}

View File

@ -25,8 +25,6 @@
#define ARANGOD_UTILS_COLLECTION_KEYS_H 1
#include "Basics/Common.h"
#include "Utils/CollectionNameResolver.h"
#include "VocBase/ManagedDocumentResult.h"
#include "VocBase/voc-types.h"
#include <velocypack/Builder.h>
@ -40,8 +38,7 @@ namespace velocypack {
class Slice;
}
class CollectionGuard;
class MMFilesDocumentDitch;
class LogicalCollection;
typedef TRI_voc_tick_t CollectionKeysId;
@ -50,10 +47,10 @@ class CollectionKeys {
CollectionKeys(CollectionKeys const&) = delete;
CollectionKeys& operator=(CollectionKeys const&) = delete;
CollectionKeys(TRI_vocbase_t*, std::string const&, TRI_voc_tick_t,
CollectionKeys(TRI_vocbase_t*, std::string const& name,
double ttl);
~CollectionKeys();
virtual ~CollectionKeys() = default;
public:
CollectionKeysId id() const { return _id; }
@ -81,50 +78,43 @@ class CollectionKeys {
_isUsed = false;
}
size_t count() const {
return _vpack.size();
}
virtual size_t count() const = 0;
//////////////////////////////////////////////////////////////////////////////
/// @brief initially creates the list of keys
//////////////////////////////////////////////////////////////////////////////
void create(TRI_voc_tick_t);
virtual void create(TRI_voc_tick_t) = 0;
//////////////////////////////////////////////////////////////////////////////
/// @brief hashes a chunk of keys
//////////////////////////////////////////////////////////////////////////////
std::tuple<std::string, std::string, uint64_t> hashChunk(size_t,
size_t) const;
virtual std::tuple<std::string, std::string, uint64_t> hashChunk(size_t,
size_t) const = 0;
//////////////////////////////////////////////////////////////////////////////
/// @brief dumps keys into the result
//////////////////////////////////////////////////////////////////////////////
void dumpKeys(arangodb::velocypack::Builder&, size_t, size_t) const;
virtual void dumpKeys(arangodb::velocypack::Builder&, size_t, size_t) const = 0;
//////////////////////////////////////////////////////////////////////////////
/// @brief dumps documents into the result
//////////////////////////////////////////////////////////////////////////////
void dumpDocs(arangodb::velocypack::Builder&, size_t, size_t,
arangodb::velocypack::Slice const&) const;
virtual void dumpDocs(arangodb::velocypack::Builder&, size_t, size_t,
arangodb::velocypack::Slice const&) const = 0;
private:
protected:
TRI_vocbase_t* _vocbase;
std::unique_ptr<arangodb::CollectionGuard> _guard;
arangodb::LogicalCollection* _collection;
arangodb::MMFilesDocumentDitch* _ditch;
std::string const _name;
arangodb::CollectionNameResolver _resolver;
TRI_voc_tick_t _blockerId;
CollectionKeysId _id;
double _ttl;
double _expires;
bool _isDeleted;
bool _isUsed;
std::vector<uint8_t const*> _vpack;
};
}

View File

@ -22,8 +22,8 @@
////////////////////////////////////////////////////////////////////////////////
#include "CollectionKeysRepository.h"
#include "Logger/Logger.h"
#include "Basics/MutexLocker.h"
#include "Logger/Logger.h"
#include "VocBase/vocbase.h"
using namespace arangodb;