1
0
Fork 0

View Replication (#5915)

This commit is contained in:
Simon 2018-07-26 10:28:46 +02:00 committed by Jan
parent 939c4bc820
commit 2dd8593609
55 changed files with 1010 additions and 652 deletions

View File

@ -83,7 +83,7 @@ to the [naming conventions](../NamingConventions/README.md).
attribute and this can only be done efficiently if this is the
only shard key by delegating to the individual shards.
*cacheEnabled* (optional, default is *false*, **rocksdb-only**, from v. 3.4): Enable in-memory
*cacheEnabled* (optional, default is *false*, **rocksdb-only**, from v.3.4): Enable in-memory
caching for documents and primary index entries. This can potentially speed up point-lookups significantly,
especially if your collection has a subset of frequently accessed keys. Please test this feature
carefully to ensure that it does not adversely affect the performance of your system.

View File

@ -402,6 +402,7 @@ std::string auth::TokenCache::generateJwt(VPackSlice const& payload) const {
}
}
/// generate a JWT token for internal cluster communication
void auth::TokenCache::generateJwtToken() {
VPackBuilder body;
body.openObject();

View File

@ -519,6 +519,7 @@ void ClusterInfo::loadPlan() {
views.reserve(views.size() + 2);
views[viewId] = view;
views[view->name()] = view;
views[view->guid()] = view;
return true;
};

View File

@ -348,27 +348,10 @@ void ClusterEngine::unloadCollection(
collection.setStatus(TRI_VOC_COL_STATUS_UNLOADED);
}
void ClusterEngine::createView(
Result ClusterEngine::createView(
TRI_vocbase_t& vocbase,
TRI_voc_cid_t id,
arangodb::LogicalView const& /*view*/
) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
}
// asks the storage engine to persist renaming of a view
// This will write a renameMarker if not in recovery
Result ClusterEngine::renameView(
TRI_vocbase_t& vocbase,
arangodb::LogicalView const& view,
std::string const& /*oldName*/
) {
return persistView(vocbase, view);
}
arangodb::Result ClusterEngine::persistView(
TRI_vocbase_t& vocbase,
arangodb::LogicalView const& view
) {
return TRI_ERROR_NOT_IMPLEMENTED;
}
@ -387,25 +370,16 @@ void ClusterEngine::destroyView(
// nothing to do here
}
void ClusterEngine::changeView(
Result ClusterEngine::changeView(
TRI_vocbase_t& vocbase,
TRI_voc_cid_t /*id*/,
arangodb::LogicalView const& view,
bool /*doSync*/
) {
if (inRecovery()) {
// nothing to do
return;
}
auto const res = persistView(vocbase, view);
if (!res.ok()) {
THROW_ARANGO_EXCEPTION_MESSAGE(
res.errorNumber(),
"could not save view properties"
);
return {};
}
return TRI_ERROR_NOT_IMPLEMENTED;
}
void ClusterEngine::signalCleanup(TRI_vocbase_t&) {
@ -459,4 +433,4 @@ std::unique_ptr<TRI_vocbase_t> ClusterEngine::openExistingDatabase(
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -267,14 +267,13 @@ class ClusterEngine final : public StorageEngine {
LogicalCollection& collection
) override;
void changeView(
arangodb::Result changeView(
TRI_vocbase_t& vocbase,
TRI_voc_cid_t id,
arangodb::LogicalView const& view,
bool doSync
) override;
void createView(
arangodb::Result createView(
TRI_vocbase_t& vocbase,
TRI_voc_cid_t id,
arangodb::LogicalView const& view
@ -288,19 +287,6 @@ class ClusterEngine final : public StorageEngine {
// does nothing
}
arangodb::Result persistView(
TRI_vocbase_t& vocbase,
arangodb::LogicalView const& view
) override;
// asks the storage engine to persist renaming of a view
// This will write a renameMarker if not in recovery
arangodb::Result renameView(
TRI_vocbase_t& vocbase,
arangodb::LogicalView const& view,
std::string const& oldName
) override;
arangodb::Result dropView(
TRI_vocbase_t& vocbase,
LogicalView& view

View File

@ -72,9 +72,7 @@ GeneralCommTask::GeneralCommTask(Scheduler* scheduler, GeneralServer* server,
SocketTask(scheduler, std::move(socket), std::move(info),
keepAliveTimeout, skipSocketInit),
_server(server),
_auth(nullptr) {
_auth = application_features::ApplicationServer::getFeature<
AuthenticationFeature>("Authentication");
_auth(AuthenticationFeature::instance()) {
TRI_ASSERT(_auth != nullptr);
}

View File

@ -85,7 +85,7 @@ VstCommTask::VstCommTask(Scheduler* scheduler, GeneralServer* server,
: Task(scheduler, "VstCommTask"),
GeneralCommTask(scheduler, server, std::move(socket), std::move(info), timeout,
skipInit),
_authorized(false),
_authorized(!_auth->isActive()),
_authMethod(rest::AuthenticationMethod::NONE),
_authenticatedUser(),
_protocolVersion(protocolVersion) {

View File

@ -60,7 +60,7 @@ IResearchLink::IResearchLink(
TRI_idx_iid_t iid,
arangodb::LogicalCollection& collection
): _collection(collection),
_defaultId(0), // 0 is never a valid id
_defaultGuid(""), // "" is never a valid guid
_dropCollectionInDestructor(false),
_id(iid),
_view(nullptr) {
@ -141,13 +141,15 @@ int IResearchLink::drop() {
}
_dropCollectionInDestructor = false; // will do drop now
_defaultId = _view->id(); // remember view ID just in case (e.g. call to toVelocyPack(...) after unload())
_defaultGuid = _view->guid(); // remember view ID just in case (e.g. call to toVelocyPack(...) after unload())
TRI_voc_cid_t vid = _view->id();
_view = nullptr; // mark as unassociated
_viewLock.unlock(); // release read-lock on the IResearch View
// FIXME TODO this workaround should be in ClusterInfo when moving 'Plan' to 'Current', i.e. IResearchViewDBServer::drop
if (arangodb::ServerState::instance()->isDBServer()) {
return _collection.vocbase().dropView(_defaultId, true).errorNumber(); // cluster-view in ClusterInfo should already not have cid-view
return _collection.vocbase().dropView(vid, true).errorNumber(); // cluster-view in ClusterInfo should already not have cid-view
}
return TRI_ERROR_NO_ERROR;
@ -183,7 +185,8 @@ bool IResearchLink::init(arangodb::velocypack::Slice const& definition) {
}
if (!definition.isObject()
|| !definition.get(StaticStrings::ViewIdField).isNumber<uint64_t>()) {
|| !(definition.get(StaticStrings::ViewIdField).isString() ||
definition.get(StaticStrings::ViewIdField).isNumber<TRI_voc_cid_t>())) {
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
<< "error finding view for link '" << _id << "'";
TRI_set_errno(TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND);
@ -191,8 +194,9 @@ bool IResearchLink::init(arangodb::velocypack::Slice const& definition) {
return false;
}
auto identifier = definition.get(StaticStrings::ViewIdField);
auto viewId = identifier.getNumber<uint64_t>();
// we continue to support the old and new ID format
auto idSlice = definition.get(StaticStrings::ViewIdField);
std::string viewId = idSlice.isString() ? idSlice.copyString() : std::to_string(idSlice.getUInt());
auto& vocbase = _collection.vocbase();
auto logicalView = vocbase.lookupView(viewId); // will only contain IResearchView (even for a DBServer)
@ -208,7 +212,7 @@ bool IResearchLink::init(arangodb::velocypack::Slice const& definition) {
return false;
}
auto logicalWiew = ci->getView(vocbase.name(), std::to_string(viewId));
auto logicalWiew = ci->getView(vocbase.name(), viewId);
auto* wiew = LogicalView::cast<IResearchViewDBServer>(logicalWiew.get());
if (wiew) {
@ -288,7 +292,7 @@ bool IResearchLink::init(arangodb::velocypack::Slice const& definition) {
auto* engine = arangodb::EngineSelectorFeature::ENGINE;
if (engine && engine->inRecovery()) {
_defaultId = _view->id();
_defaultGuid = _view->guid();
}
}
@ -351,12 +355,11 @@ bool IResearchLink::json(
if (_view) {
builder.add(
StaticStrings::ViewIdField, arangodb::velocypack::Value(_view->id())
StaticStrings::ViewIdField, arangodb::velocypack::Value(_view->guid())
);
} else if (_defaultId) { // '0' _defaultId == no view name in source jSON
//if (_defaultId && forPersistence) { // MMFilesCollection::saveIndex(...) does not set 'forPersistence'
} else if (!_defaultGuid.empty()) { // _defaultGuid.empty() == no view name in source jSON
builder.add(
StaticStrings::ViewIdField, arangodb::velocypack::Value(_defaultId)
StaticStrings::ViewIdField, VPackValue(_defaultGuid)
);
}
@ -377,11 +380,9 @@ bool IResearchLink::matchesDefinition(VPackSlice const& slice) const {
}
auto identifier = slice.get(StaticStrings::ViewIdField);
if (!identifier.isNumber()
|| uint64_t(identifier.getInt()) != identifier.getUInt()
|| identifier.getUInt() != _view->id()) {
return false; // iResearch View names of current object and slice do not match
if (!((identifier.isString() && identifier.isEqualString(_view->guid())) ||
(identifier.isNumber<TRI_voc_cid_t>() && identifier.getUInt() != _view->id()))) {
return false; // iResearch View names of current object and slice do not match
}
} else if (_view) {
return false; // slice has no 'name' but the current object does
@ -493,7 +494,7 @@ int IResearchLink::unload() {
}
_dropCollectionInDestructor = false; // valid link (since unload(..) called), should not be dropped
_defaultId = _view->id(); // remember view ID just in case (e.g. call to toVelocyPack(...) after unload())
_defaultGuid = _view->guid(); // remember view ID just in case (e.g. call to toVelocyPack(...) after unload())
_view = nullptr; // mark as unassociated
_viewLock.unlock(); // release read-lock on the IResearch View
@ -533,4 +534,4 @@ NS_END // arangodb
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -190,7 +190,7 @@ class IResearchLink {
friend class IResearchView;
LogicalCollection& _collection; // the linked collection
TRI_voc_cid_t _defaultId; // the identifier of the desired view (iff _view == nullptr)
std::string _defaultGuid; // the identifier of the desired view (iff _view == nullptr)
bool _dropCollectionInDestructor; // collection should be dropped from view in the destructor (for the case where init(..) is called folowed by distructor)
TRI_idx_iid_t const _id; // the index identifier
IResearchLinkMeta _meta; // how this collection should be indexed
@ -202,4 +202,4 @@ class IResearchLink {
NS_END // iresearch
NS_END // arangodb
#endif
#endif

View File

@ -85,7 +85,8 @@ bool IResearchLinkCoordinator::init(VPackSlice definition) {
}
if (!definition.isObject()
|| !definition.get(StaticStrings::ViewIdField).isNumber<uint64_t>()) {
|| !(definition.get(StaticStrings::ViewIdField).isString() ||
definition.get(StaticStrings::ViewIdField).isNumber())) {
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
<< "error finding view for link '" << id() << "'";
TRI_set_errno(TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND);
@ -93,14 +94,12 @@ bool IResearchLinkCoordinator::init(VPackSlice definition) {
return false;
}
auto identifier = definition.get(StaticStrings::ViewIdField);
auto viewId = identifier.getNumber<uint64_t>();
auto idSlice = definition.get(StaticStrings::ViewIdField);
std::string viewId = idSlice.isString() ? idSlice.copyString() : std::to_string(idSlice.getUInt());
auto& vocbase = _collection.vocbase();
TRI_ASSERT(ClusterInfo::instance());
auto logicalView = ClusterInfo::instance()->getView(
vocbase.name(), basics::StringUtils::itoa(viewId)
);
auto logicalView = ClusterInfo::instance()->getView(vocbase.name(), viewId);
if (!logicalView
|| arangodb::iresearch::DATA_SOURCE_TYPE != logicalView->type()) {
@ -196,7 +195,7 @@ void IResearchLinkCoordinator::toVelocyPack(
);
builder.add(
StaticStrings::ViewIdField,
arangodb::velocypack::Value(_view->id())
arangodb::velocypack::Value(_view->guid())
);
if (withFigures) {
@ -220,4 +219,4 @@ char const* IResearchLinkCoordinator::typeName() const {
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -186,7 +186,7 @@ namespace iresearch {
);
namedJson.add(
StaticStrings::ViewIdField,
arangodb::velocypack::Value(view.id())
arangodb::velocypack::Value(view.guid())
);
if (!mergeSliceSkipKeys(namedJson, link, acceptor)) {

View File

@ -323,7 +323,7 @@ arangodb::Result persistProperties(
if (!engine->inRecovery()) {
// change view throws exception on error
try {
engine->changeView(view.vocbase(), view.id(), view, true);
engine->changeView(view.vocbase(), view, true);
} catch (arangodb::basics::Exception& e) {
IR_LOG_EXCEPTION();
@ -390,7 +390,7 @@ arangodb::Result persistProperties(
// change view throws exception on error
try {
engine->changeView(view.vocbase(), view.id(), view, true);
engine->changeView(view.vocbase(), view, true);
} catch (arangodb::basics::Exception& e) {
IR_LOG_EXCEPTION();
@ -2153,4 +2153,4 @@ NS_END // arangodb
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -81,7 +81,7 @@ arangodb::Result createLink(
arangodb::velocypack::Value(IResearchLinkHelper::type())
);
builder.add(
StaticStrings::ViewIdField, arangodb::velocypack::Value(view.id())
StaticStrings::ViewIdField, arangodb::velocypack::Value(view.guid())
);
if (!mergeSliceSkipKeys(builder, link, acceptor)) {
@ -599,4 +599,4 @@ Result IResearchViewCoordinator::drop() {
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -421,8 +421,6 @@ char const* TRI_NameMarkerDatafile(MMFilesMarkerType type) {
return "create view";
case TRI_DF_MARKER_VPACK_DROP_VIEW:
return "drop view";
case TRI_DF_MARKER_VPACK_RENAME_VIEW:
return "rename view";
case TRI_DF_MARKER_VPACK_CHANGE_VIEW:
return "change view";

View File

@ -71,7 +71,6 @@ enum MMFilesMarkerType : uint8_t {
TRI_DF_MARKER_VPACK_CREATE_VIEW = 80,
TRI_DF_MARKER_VPACK_DROP_VIEW = 81,
TRI_DF_MARKER_VPACK_CHANGE_VIEW = 82,
TRI_DF_MARKER_VPACK_RENAME_VIEW = 83,
TRI_DF_MARKER_MAX // again, this is not a real
// marker, but we use it for

View File

@ -84,7 +84,6 @@ static inline size_t VPackOffset(MMFilesMarkerType type) noexcept {
type == TRI_DF_MARKER_VPACK_DROP_INDEX ||
type == TRI_DF_MARKER_VPACK_CREATE_VIEW ||
type == TRI_DF_MARKER_VPACK_DROP_VIEW ||
type == TRI_DF_MARKER_VPACK_RENAME_VIEW ||
type == TRI_DF_MARKER_VPACK_CHANGE_VIEW) {
// VPack is located after database id and collection id
return sizeof(MMFilesMarker) + sizeof(TRI_voc_tick_t) + sizeof(TRI_voc_cid_t);
@ -121,7 +120,6 @@ static inline size_t DatabaseIdOffset(MMFilesMarkerType type) noexcept {
type == TRI_DF_MARKER_VPACK_DROP_INDEX ||
type == TRI_DF_MARKER_VPACK_CREATE_VIEW ||
type == TRI_DF_MARKER_VPACK_DROP_VIEW ||
type == TRI_DF_MARKER_VPACK_RENAME_VIEW ||
type == TRI_DF_MARKER_VPACK_CHANGE_VIEW ||
type == TRI_DF_MARKER_VPACK_CREATE_DATABASE ||
type == TRI_DF_MARKER_VPACK_DROP_DATABASE ||
@ -148,7 +146,6 @@ static inline TRI_voc_tick_t DatabaseId(MMFilesMarker const* marker) noexcept {
type == TRI_DF_MARKER_VPACK_DROP_INDEX ||
type == TRI_DF_MARKER_VPACK_CREATE_VIEW ||
type == TRI_DF_MARKER_VPACK_DROP_VIEW ||
type == TRI_DF_MARKER_VPACK_RENAME_VIEW ||
type == TRI_DF_MARKER_VPACK_CHANGE_VIEW ||
type == TRI_DF_MARKER_VPACK_CREATE_DATABASE ||
type == TRI_DF_MARKER_VPACK_DROP_DATABASE ||
@ -202,8 +199,7 @@ static inline TRI_voc_tick_t CollectionId(MMFilesMarker const* marker) noexcept
static inline size_t ViewIdOffset(MMFilesMarkerType type) noexcept {
if (type == TRI_DF_MARKER_VPACK_CREATE_VIEW ||
type == TRI_DF_MARKER_VPACK_DROP_VIEW ||
type == TRI_DF_MARKER_VPACK_CHANGE_VIEW ||
type == TRI_DF_MARKER_VPACK_RENAME_VIEW) {
type == TRI_DF_MARKER_VPACK_CHANGE_VIEW) {
return sizeof(MMFilesMarker) + sizeof(TRI_voc_tick_t);
}
return 0;
@ -217,8 +213,7 @@ static inline TRI_voc_tick_t ViewId(MMFilesMarker const* marker) noexcept {
MMFilesMarkerType type = marker->getType();
if (type == TRI_DF_MARKER_VPACK_CREATE_VIEW ||
type == TRI_DF_MARKER_VPACK_DROP_VIEW ||
type == TRI_DF_MARKER_VPACK_CHANGE_VIEW ||
type == TRI_DF_MARKER_VPACK_RENAME_VIEW) {
type == TRI_DF_MARKER_VPACK_CHANGE_VIEW) {
return encoding::readNumber<TRI_voc_cid_t>(reinterpret_cast<uint8_t const*>(marker) + ViewIdOffset(type), sizeof(TRI_voc_cid_t));
}
return 0;

View File

@ -1238,56 +1238,7 @@ Result MMFilesEngine::renameCollection(
return {res, TRI_errno_string(res)};
}
// asks the storage engine to persist renaming of a view
// This will write a renameMarker if not in recovery
Result MMFilesEngine::renameView(
TRI_vocbase_t& vocbase,
arangodb::LogicalView const& view,
std::string const& oldName
) {
if (inRecovery()) {
// Nothing todo. Marker already there
return {};
}
int res = TRI_ERROR_NO_ERROR;
try {
VPackBuilder builder;
builder.openObject();
builder.add("id", VPackValue(std::to_string(view.id())));
builder.add("oldName", VPackValue(oldName));
builder.add("name", VPackValue(view.name()));
builder.close();
MMFilesViewMarker marker(
TRI_DF_MARKER_VPACK_RENAME_VIEW, vocbase.id(), view.id(), builder.slice()
);
MMFilesWalSlotInfoCopy slotInfo =
MMFilesLogfileManager::instance()->allocateAndWrite(marker, false);
if (slotInfo.errorCode != TRI_ERROR_NO_ERROR) {
THROW_ARANGO_EXCEPTION(slotInfo.errorCode);
}
res = TRI_ERROR_NO_ERROR;
} catch (arangodb::basics::Exception const& ex) {
res = ex.code();
} catch (...) {
res = TRI_ERROR_INTERNAL;
}
if (res != TRI_ERROR_NO_ERROR) {
LOG_TOPIC(WARN, arangodb::Logger::FIXME)
<< "could not save view rename marker in log: "
<< TRI_errno_string(res);
}
return {res, TRI_errno_string(res)};
}
void MMFilesEngine::createView(
Result MMFilesEngine::createView(
TRI_vocbase_t& vocbase,
TRI_voc_cid_t id,
arangodb::LogicalView const& view
@ -1298,7 +1249,7 @@ void MMFilesEngine::createView(
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< "cannot create view '" << path
<< "', database path is not a directory";
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DATADIR_INVALID);
return TRI_ERROR_ARANGO_DATADIR_INVALID;
}
TRI_ASSERT(id != 0);
@ -1311,9 +1262,7 @@ void MMFilesEngine::createView(
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< "cannot create view '" << view.name() << "' in directory '"
<< dirname << "': directory already exists";
THROW_ARANGO_EXCEPTION(
TRI_ERROR_ARANGO_COLLECTION_DIRECTORY_ALREADY_EXISTS); // TODO: change
// error code
return TRI_ERROR_ARANGO_COLLECTION_DIRECTORY_ALREADY_EXISTS;
}
// use a temporary directory first. this saves us from leaving an empty
@ -1330,11 +1279,11 @@ void MMFilesEngine::createView(
<< "cannot create view '" << view.name() << "' in directory '"
<< path << "': " << TRI_errno_string(res) << " - " << systemError
<< " - " << errorMessage;
THROW_ARANGO_EXCEPTION(res);
return res;
}
TRI_IF_FAILURE("CreateView::tempDirectory") {
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
return TRI_ERROR_DEBUG;
}
// create a temporary file (.tmp)
@ -1347,7 +1296,7 @@ void MMFilesEngine::createView(
arangodb::basics::FileUtils::buildFilename(dirname, ".tmp"));
TRI_IF_FAILURE("CreateView::tempFile") {
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
return TRI_ERROR_DEBUG;
}
if (res != TRI_ERROR_NO_ERROR) {
@ -1356,11 +1305,11 @@ void MMFilesEngine::createView(
<< path << "': " << TRI_errno_string(res) << " - " << systemError
<< " - " << errorMessage;
TRI_RemoveDirectory(tmpname.c_str());
THROW_ARANGO_EXCEPTION(res);
return res;
}
TRI_IF_FAILURE("CreateView::renameDirectory") {
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
return TRI_ERROR_DEBUG;
}
res = TRI_RenameFile(tmpname.c_str(), dirname.c_str());
@ -1371,11 +1320,11 @@ void MMFilesEngine::createView(
<< path << "': " << TRI_errno_string(res) << " - " << systemError
<< " - " << errorMessage;
TRI_RemoveDirectory(tmpname.c_str());
THROW_ARANGO_EXCEPTION(res);
return res;
}
// now we have the directory in place with the correct name and a .tmp file in
// it
// now we have the directory in place with the correct name
// and a .tmp file in it
// delete .tmp file
TRI_UnlinkFile(tmpfile2.c_str());
@ -1386,7 +1335,44 @@ void MMFilesEngine::createView(
"Database")
->forceSyncProperties();
saveViewInfo(&vocbase, id, &view, doSync);
saveViewInfo(&vocbase, &view, doSync);
if (inRecovery()) {
// Nothing more do. In recovery we do not write markers.
return {};
}
VPackBuilder builder;
builder.openObject();
view.toVelocyPack(builder, true, true);
builder.close();
TRI_ASSERT(id != 0);
TRI_UpdateTickServer(static_cast<TRI_voc_tick_t>(id));
res = TRI_ERROR_NO_ERROR;
try {
MMFilesViewMarker marker(TRI_DF_MARKER_VPACK_CREATE_VIEW, vocbase.id(),
view.id(), builder.slice());
MMFilesWalSlotInfoCopy slotInfo =
MMFilesLogfileManager::instance()->allocateAndWrite(marker, false);
if (slotInfo.errorCode != TRI_ERROR_NO_ERROR) {
THROW_ARANGO_EXCEPTION(slotInfo.errorCode);
}
return {};
} catch (arangodb::basics::Exception const& ex) {
res = ex.code();
} catch (...) {
res = TRI_ERROR_INTERNAL;
}
LOG_TOPIC(WARN, arangodb::Logger::FIXME)
<< "could not save view create marker in log: " << TRI_errno_string(res);
return {res, TRI_errno_string(res)};
}
void MMFilesEngine::getViewProperties(
@ -1398,53 +1384,6 @@ void MMFilesEngine::getViewProperties(
result.add("path", velocypack::Value(viewDirectory(vocbase.id(), view.id())));
}
arangodb::Result MMFilesEngine::persistView(
TRI_vocbase_t& vocbase,
arangodb::LogicalView const& view
) {
if (inRecovery()) {
// Nothing to do. In recovery we do not write markers.
return {};
}
VPackBuilder builder;
builder.openObject();
view.toVelocyPack(builder, true, true);
builder.close();
VPackSlice const slice = builder.slice();
auto id = view.id();
TRI_ASSERT(id != 0);
TRI_UpdateTickServer(static_cast<TRI_voc_tick_t>(id));
int res = TRI_ERROR_NO_ERROR;
try {
MMFilesViewMarker marker(
TRI_DF_MARKER_VPACK_CREATE_VIEW, vocbase.id(), id, slice
);
MMFilesWalSlotInfoCopy slotInfo =
MMFilesLogfileManager::instance()->allocateAndWrite(marker, false);
if (slotInfo.errorCode != TRI_ERROR_NO_ERROR) {
THROW_ARANGO_EXCEPTION(slotInfo.errorCode);
}
return {};
} catch (arangodb::basics::Exception const& ex) {
res = ex.code();
} catch (...) {
res = TRI_ERROR_INTERNAL;
}
LOG_TOPIC(WARN, arangodb::Logger::FIXME)
<< "could not save view create marker in log: " << TRI_errno_string(res);
return {res, TRI_errno_string(res)};
}
arangodb::Result MMFilesEngine::dropView(
TRI_vocbase_t& vocbase,
LogicalView& view
@ -1452,7 +1391,7 @@ arangodb::Result MMFilesEngine::dropView(
auto* db = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
TRI_ASSERT(db);
saveViewInfo(&vocbase, view.id(), &view, db->forceSyncProperties());
saveViewInfo(&vocbase, &view, db->forceSyncProperties());
if (inRecovery()) {
// nothing to do here
@ -1463,10 +1402,9 @@ arangodb::Result MMFilesEngine::dropView(
try {
VPackBuilder builder;
builder.openObject();
builder.add("id", velocypack::Value(std::to_string(view.id())));
builder.add("name", velocypack::Value(view.name()));
builder.add(StaticStrings::DataSourceId, velocypack::Value(std::to_string(view.id())));
builder.add("cuid", velocypack::Value(view.guid()));
builder.close();
MMFilesViewMarker marker(
@ -1509,10 +1447,10 @@ void MMFilesEngine::destroyView(
}
}
void MMFilesEngine::saveViewInfo(TRI_vocbase_t* vocbase, TRI_voc_cid_t id,
void MMFilesEngine::saveViewInfo(TRI_vocbase_t* vocbase,
arangodb::LogicalView const* view,
bool forceSync) const {
std::string const filename = viewParametersFilename(vocbase->id(), id);
std::string const filename = viewParametersFilename(vocbase->id(), view->id());
VPackBuilder builder;
builder.openObject();
@ -1540,14 +1478,11 @@ void MMFilesEngine::saveViewInfo(TRI_vocbase_t* vocbase, TRI_voc_cid_t id,
// fail.
// the WAL entry for the propery change will be written *after* the call
// to "changeView" returns
void MMFilesEngine::changeView(
Result MMFilesEngine::changeView(
TRI_vocbase_t& vocbase,
TRI_voc_cid_t id,
arangodb::LogicalView const& view,
bool doSync
) {
// FIXME make noexcept and return Result???
if (!inRecovery()) {
VPackBuilder infoBuilder;
infoBuilder.openObject();
@ -1555,21 +1490,20 @@ void MMFilesEngine::changeView(
infoBuilder.close();
MMFilesViewMarker marker(
TRI_DF_MARKER_VPACK_CHANGE_VIEW, vocbase.id(), id, infoBuilder.slice()
TRI_DF_MARKER_VPACK_CHANGE_VIEW, vocbase.id(), view.id(), infoBuilder.slice()
);
MMFilesWalSlotInfoCopy slotInfo =
MMFilesLogfileManager::instance()->allocateAndWrite(marker, false);
if (slotInfo.errorCode != TRI_ERROR_NO_ERROR) {
THROW_ARANGO_EXCEPTION_MESSAGE(
slotInfo.errorCode,
"could not save view change marker in log"
);
return Result(slotInfo.errorCode,
"could not save view change marker in log");
}
}
saveViewInfo(&vocbase, id, &view, doSync);
saveViewInfo(&vocbase, &view, doSync);
return {};
}
// asks the storage engine to create an index as specified in the VPack

View File

@ -352,14 +352,13 @@ class MMFilesEngine final : public StorageEngine {
LogicalCollection& collection
) override;
void changeView(
arangodb::Result changeView(
TRI_vocbase_t& vocbase,
TRI_voc_cid_t id,
arangodb::LogicalView const&,
bool doSync
) override;
void createView(
arangodb::Result createView(
TRI_vocbase_t& vocbase,
TRI_voc_cid_t id,
arangodb::LogicalView const& view
@ -371,19 +370,6 @@ class MMFilesEngine final : public StorageEngine {
VPackBuilder& builder
) override;
arangodb::Result persistView(
TRI_vocbase_t& vocbase,
arangodb::LogicalView const& view
) override;
// asks the storage engine to persist renaming of a view
// This will write a renameMarker if not in recovery
arangodb::Result renameView(
TRI_vocbase_t& vocbase,
arangodb::LogicalView const& view,
std::string const& oldName
) override;
arangodb::Result dropView(
TRI_vocbase_t& vocbase,
LogicalView& view
@ -397,8 +383,7 @@ class MMFilesEngine final : public StorageEngine {
std::string createViewDirectoryName(std::string const& basePath,
TRI_voc_cid_t id);
void saveViewInfo(TRI_vocbase_t* vocbase, TRI_voc_cid_t id,
arangodb::LogicalView const*, bool forceSync) const;
void saveViewInfo(TRI_vocbase_t* vocbase, arangodb::LogicalView const*, bool sync) const;
void signalCleanup(TRI_vocbase_t& vocbase) override;

View File

@ -32,6 +32,7 @@
#include "MMFiles/MMFilesLogfileManager.h"
#include "MMFiles/mmfiles-replication-common.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/LogicalView.h"
#include "VocBase/vocbase.h"
#include <velocypack/Dumper.h>
@ -231,10 +232,18 @@ struct MMFilesWalAccessContext : WalAccessContext {
}
return true;
}
bool isViewWalMarker(MMFilesMarker const* marker) const {
MMFilesMarkerType t = marker->getType();
return t == TRI_DF_MARKER_VPACK_CREATE_VIEW ||
t == TRI_DF_MARKER_VPACK_DROP_VIEW ||
t == TRI_DF_MARKER_VPACK_CHANGE_VIEW;
}
/// @brief whether or not a marker is replicated
bool mustReplicateWalMarker(MMFilesMarker const* marker,
TRI_voc_tick_t databaseId, TRI_voc_cid_t cid) {
TRI_voc_tick_t databaseId,
TRI_voc_cid_t datasourceId) {
// first check the marker type
if (!MustReplicateWalMarkerType(marker, true)) {
return false;
@ -246,18 +255,20 @@ struct MMFilesWalAccessContext : WalAccessContext {
}
// finally check if the marker is for a collection that we want to ignore
if (cid != 0) {
if (datasourceId != 0) {
if (_filter.collection != 0 &&
(cid != _filter.collection && !isTransactionWalMarker(marker))) {
(datasourceId != _filter.collection && !isTransactionWalMarker(marker))) {
// restrict output to a single collection, but a different one
return false;
}
LogicalCollection* collection = loadCollection(databaseId, cid);
if (collection != nullptr) { // db may be already dropped
if (TRI_ExcludeCollectionReplication(collection->name(),
_filter.includeSystem)) {
return false;
if (!isViewWalMarker(marker)) {
// will not find anything for a view
LogicalCollection* collection = loadCollection(databaseId, datasourceId);
if (collection != nullptr) { // db may be already dropped
if (TRI_ExcludeCollectionReplication(collection->name(),
_filter.includeSystem)) {
return false;
}
}
}
}
@ -276,7 +287,7 @@ struct MMFilesWalAccessContext : WalAccessContext {
return true;
}
int sliceifyMarker(TRI_voc_tick_t databaseId, TRI_voc_cid_t collectionId,
int sliceifyMarker(TRI_voc_tick_t databaseId, TRI_voc_cid_t datasourceId,
MMFilesMarker const* marker) {
TRI_ASSERT(MustReplicateWalMarkerType(marker, true));
MMFilesMarkerType const type = marker->getType();
@ -308,20 +319,33 @@ struct MMFilesWalAccessContext : WalAccessContext {
MMFilesDatafileHelper::VPackOffset(type));
_builder.add("db", slice.get("name"));
} else if (type == TRI_DF_MARKER_VPACK_DROP_COLLECTION) {
} else if (type == TRI_DF_MARKER_VPACK_DROP_COLLECTION ||
type == TRI_DF_MARKER_VPACK_DROP_VIEW) {
TRI_ASSERT(databaseId != 0);
TRI_vocbase_t* vocbase = loadVocbase(databaseId);
if (vocbase == nullptr) {
// ignore markers from dropped dbs
return TRI_ERROR_NO_ERROR;
}
VPackSlice slice(reinterpret_cast<char const*>(marker) +
MMFilesDatafileHelper::VPackOffset(type));
_builder.add("db", VPackValue(vocbase->name()));
_builder.add("cuid", slice.get("cuid"));
} else if (type == TRI_DF_MARKER_VPACK_CREATE_VIEW ||
type == TRI_DF_MARKER_VPACK_CHANGE_VIEW) {
TRI_ASSERT(databaseId != 0);
TRI_vocbase_t* vocbase = loadVocbase(databaseId);
if (vocbase == nullptr) {
// ignore markers from dropped dbs
return TRI_ERROR_NO_ERROR;
}
auto view = vocbase->lookupView(datasourceId);
if (!view) {
return TRI_ERROR_NO_ERROR; // ignore marker
}
_builder.add("db", VPackValue(vocbase->name()));
_builder.add("cuid", VPackValue(view->guid()));
} else {
TRI_ASSERT(databaseId != 0);
TRI_vocbase_t* vocbase = loadVocbase(databaseId);
@ -332,13 +356,11 @@ struct MMFilesWalAccessContext : WalAccessContext {
_builder.add("db", VPackValue(vocbase->name()));
if (collectionId > 0) {
LogicalCollection* col = loadCollection(databaseId, collectionId);
if (datasourceId > 0) { // will not find anything for a view
LogicalCollection* col = loadCollection(databaseId, datasourceId);
if (col == nullptr) {
return TRI_ERROR_NO_ERROR; // ignore dropped collections
}
_builder.add("cuid", VPackValue(col->guid()));
}
}
@ -351,11 +373,9 @@ struct MMFilesWalAccessContext : WalAccessContext {
case TRI_DF_MARKER_VPACK_CREATE_INDEX:
case TRI_DF_MARKER_VPACK_CREATE_VIEW:
case TRI_DF_MARKER_VPACK_RENAME_COLLECTION:
case TRI_DF_MARKER_VPACK_RENAME_VIEW:
case TRI_DF_MARKER_VPACK_CHANGE_COLLECTION:
case TRI_DF_MARKER_VPACK_CHANGE_VIEW:
case TRI_DF_MARKER_VPACK_DROP_INDEX:
case TRI_DF_MARKER_VPACK_DROP_VIEW: {
case TRI_DF_MARKER_VPACK_DROP_INDEX: {
VPackSlice slice(reinterpret_cast<char const*>(marker) +
MMFilesDatafileHelper::VPackOffset(type));
_builder.add("data", slice);
@ -364,6 +384,7 @@ struct MMFilesWalAccessContext : WalAccessContext {
case TRI_DF_MARKER_VPACK_DROP_DATABASE:
case TRI_DF_MARKER_VPACK_DROP_COLLECTION:
case TRI_DF_MARKER_VPACK_DROP_VIEW:
case TRI_DF_MARKER_VPACK_BEGIN_TRANSACTION:
case TRI_DF_MARKER_VPACK_COMMIT_TRANSACTION:
case TRI_DF_MARKER_VPACK_ABORT_TRANSACTION: {
@ -480,25 +501,29 @@ struct MMFilesWalAccessContext : WalAccessContext {
}
TRI_voc_tick_t databaseId;
TRI_voc_cid_t collectionId;
TRI_voc_cid_t datasourceId;
if (type == TRI_DF_MARKER_VPACK_DOCUMENT ||
type == TRI_DF_MARKER_VPACK_REMOVE) {
databaseId = lastDatabaseId;
collectionId = lastCollectionId;
datasourceId = lastCollectionId;
} else {
databaseId = MMFilesDatafileHelper::DatabaseId(marker);
collectionId = MMFilesDatafileHelper::CollectionId(marker);
if (type == TRI_DF_MARKER_VPACK_CREATE_VIEW ||
type == TRI_DF_MARKER_VPACK_CHANGE_VIEW) {
datasourceId = MMFilesDatafileHelper::ViewId(marker);
} else {
datasourceId = MMFilesDatafileHelper::CollectionId(marker);
}
}
if (!mustReplicateWalMarker(marker, databaseId, collectionId)) {
if (!mustReplicateWalMarker(marker, databaseId, datasourceId)) {
continue;
}
// note the last tick we processed
lastFoundTick = foundTick;
res = sliceifyMarker(databaseId, collectionId, marker);
res = sliceifyMarker(databaseId, datasourceId, marker);
if (res != TRI_ERROR_NO_ERROR) {
THROW_ARANGO_EXCEPTION(res);
}

View File

@ -787,86 +787,6 @@ bool MMFilesWalRecoverState::ReplayMarker(MMFilesMarker const* marker,
break;
}
case TRI_DF_MARKER_VPACK_RENAME_VIEW: {
TRI_voc_tick_t const databaseId =
MMFilesDatafileHelper::DatabaseId(marker);
TRI_voc_cid_t const viewId = MMFilesDatafileHelper::ViewId(marker);
VPackSlice const payloadSlice(reinterpret_cast<char const*>(marker) +
MMFilesDatafileHelper::VPackOffset(type));
if (!payloadSlice.isObject()) {
LOG_TOPIC(WARN, arangodb::Logger::ENGINES)
<< "cannot rename view: invalid marker";
++state->errorCount;
return state->canContinue();
}
if (state->isDropped(databaseId)) {
return true;
}
LOG_TOPIC(TRACE, arangodb::Logger::ENGINES)
<< "found view rename marker. databaseId: " << databaseId
<< ", viewId: " << viewId;
TRI_vocbase_t* vocbase = state->useDatabase(databaseId);
if (vocbase == nullptr) {
// if the underlying database is gone, we can go on
LOG_TOPIC(TRACE, arangodb::Logger::ENGINES) << "cannot open database "
<< databaseId;
return true;
}
std::shared_ptr<arangodb::LogicalView> view =
vocbase->lookupView(viewId);
if (view == nullptr) {
// if the underlying collection is gone, we can go on
LOG_TOPIC(TRACE, arangodb::Logger::ENGINES)
<< "cannot rename view " << viewId << " in database " << databaseId << ": "
<< TRI_errno_string(TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND);
return true;
}
VPackSlice nameSlice = payloadSlice.get("name");
if (!nameSlice.isString()) {
LOG_TOPIC(WARN, arangodb::Logger::ENGINES)
<< "cannot rename view " << viewId << " in database "
<< databaseId << ": name attribute is no string";
++state->errorCount;
return state->canContinue();
}
std::string name = nameSlice.copyString();
// check if other view exists with target name
std::shared_ptr<arangodb::LogicalView> other = vocbase->lookupView(name);
if (other != nullptr) {
if (other->id() == view->id()) {
LOG_TOPIC(TRACE, arangodb::Logger::ENGINES)
<< "view " << viewId << " in database " << databaseId
<< " was already renamed; moving on";
break;
}
vocbase->dropView(other->id(), true);
}
int res = vocbase->renameView(view, name);
if (res != TRI_ERROR_NO_ERROR) {
LOG_TOPIC(WARN, arangodb::Logger::ENGINES)
<< "cannot rename view " << viewId << " in database "
<< databaseId << " to '" << name
<< "': " << TRI_errno_string(res);
++state->errorCount;
return state->canContinue();
}
break;
}
case TRI_DF_MARKER_VPACK_CHANGE_VIEW: {
TRI_voc_tick_t const databaseId =
MMFilesDatafileHelper::DatabaseId(marker);
@ -911,12 +831,35 @@ bool MMFilesWalRecoverState::ReplayMarker(MMFilesMarker const* marker,
}
// turn off sync temporarily if the database or collection are going to
// be
// dropped later
// be dropped later
bool const forceSync = state->willViewBeDropped(databaseId, viewId);
VPackSlice nameSlice = payloadSlice.get("name");
if (nameSlice.isString() && !nameSlice.isEqualString(view->name())) {
std::string name = nameSlice.copyString();
// check if other view exists with target name
std::shared_ptr<arangodb::LogicalView> other = vocbase->lookupView(name);
if (other != nullptr) {
if (other->id() == view->id()) {
LOG_TOPIC(TRACE, arangodb::Logger::ENGINES)
<< "view " << viewId << " in database " << databaseId
<< " was already renamed; moving on";
break;
}
vocbase->dropView(other->id(), true);
}
int res = vocbase->renameView(view, name);
if (res != TRI_ERROR_NO_ERROR) {
LOG_TOPIC(WARN, arangodb::Logger::ENGINES)
<< "cannot rename view " << viewId << " in database "
<< databaseId << " to '" << name
<< "': " << TRI_errno_string(res);
++state->errorCount;
return state->canContinue();
}
}
auto res = view->updateProperties(payloadSlice, false, forceSync);
if (!res.ok()) {
LOG_TOPIC(WARN, arangodb::Logger::ENGINES)
<< "cannot change properties for view " << viewId

View File

@ -45,7 +45,6 @@ bool MustReplicateWalMarkerType(MMFilesMarker const* marker, bool allowDBMarkers
type == TRI_DF_MARKER_VPACK_DROP_DATABASE)) ||
type == TRI_DF_MARKER_VPACK_CREATE_VIEW ||
type == TRI_DF_MARKER_VPACK_DROP_VIEW ||
type == TRI_DF_MARKER_VPACK_RENAME_VIEW ||
type == TRI_DF_MARKER_VPACK_CHANGE_VIEW);
}
@ -90,8 +89,6 @@ TRI_replication_operation_e TranslateType(MMFilesMarker const* marker) {
return REPLICATION_VIEW_CREATE;
case TRI_DF_MARKER_VPACK_DROP_VIEW:
return REPLICATION_VIEW_DROP;
case TRI_DF_MARKER_VPACK_RENAME_VIEW:
return REPLICATION_VIEW_RENAME;
case TRI_DF_MARKER_VPACK_CHANGE_VIEW:
return REPLICATION_VIEW_CHANGE;

View File

@ -169,7 +169,6 @@ static int StringifyMarker(MMFilesReplicationDumpContext* dump,
case TRI_DF_MARKER_VPACK_CREATE_VIEW:
case TRI_DF_MARKER_VPACK_RENAME_COLLECTION:
case TRI_DF_MARKER_VPACK_CHANGE_COLLECTION:
case TRI_DF_MARKER_VPACK_RENAME_VIEW:
case TRI_DF_MARKER_VPACK_CHANGE_VIEW:
case TRI_DF_MARKER_VPACK_DROP_DATABASE:
case TRI_DF_MARKER_VPACK_DROP_COLLECTION:
@ -262,7 +261,6 @@ static int SliceifyMarker(MMFilesReplicationDumpContext* dump,
case TRI_DF_MARKER_VPACK_CREATE_VIEW:
case TRI_DF_MARKER_VPACK_RENAME_COLLECTION:
case TRI_DF_MARKER_VPACK_CHANGE_COLLECTION:
case TRI_DF_MARKER_VPACK_RENAME_VIEW:
case TRI_DF_MARKER_VPACK_CHANGE_VIEW:
case TRI_DF_MARKER_VPACK_DROP_DATABASE:
case TRI_DF_MARKER_VPACK_DROP_COLLECTION:

View File

@ -49,6 +49,7 @@
#include "Utils/CollectionGuard.h"
#include "Utils/OperationOptions.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/LogicalView.h"
#include "VocBase/ManagedDocumentResult.h"
#include "VocBase/voc-types.h"
#include "VocBase/vocbase.h"
@ -129,7 +130,7 @@ DatabaseInitialSyncer::DatabaseInitialSyncer(
/// @brief run method, performs a full synchronization
Result DatabaseInitialSyncer::runWithInventory(bool incremental,
VPackSlice inventoryColls) {
VPackSlice dbInventory) {
if (!_config.connection.valid()) {
return Result(TRI_ERROR_INTERNAL, "invalid endpoint");
}
@ -196,23 +197,38 @@ Result DatabaseInitialSyncer::runWithInventory(bool incremental,
}
}
VPackBuilder inventoryResponse;
if (!inventoryColls.isArray()) {
VPackSlice collections, views;
if (dbInventory.isObject()) {
collections = dbInventory.get("collections"); // required
views = dbInventory.get("views"); // optional
}
VPackBuilder inventoryResponse; // hold response data
if (!collections.isArray()) {
// caller did not supply an inventory, we need to fetch it
Result res = fetchInventory(inventoryResponse);
if (!res.ok()) {
return res;
}
// we do not really care about the state response
inventoryColls = inventoryResponse.slice().get("collections");
if (!inventoryColls.isArray()) {
collections = inventoryResponse.slice().get("collections");
views = inventoryResponse.slice().get("views");
if (!collections.isArray()) {
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
"collections section is missing from response");
}
}
if (_config.applier._restrictCollections.empty()) {
r = handleViewCreation(views); // no requests to master
if (r.fail()) {
LOG_TOPIC(ERR, Logger::REPLICATION)
<< "Error during initial sync: " << r.errorMessage();
return r;
}
}
// strip eventual objectIDs and then dump the collections
auto pair = rocksutils::stripObjectIds(inventoryColls);
auto pair = rocksutils::stripObjectIds(collections);
r = handleLeaderCollections(pair.first, incremental);
// all done here, do not try to finish batch if master is unresponsive
@ -1475,5 +1491,16 @@ Result DatabaseInitialSyncer::iterateCollections(
// all ok
return Result();
}
/// @brief create non-existing views locally
Result DatabaseInitialSyncer::handleViewCreation(VPackSlice const& views) {
for (VPackSlice slice : VPackArrayIterator(views)) {
Result res = createView(vocbase(), slice);
if (res.fail()) {
return res;
}
}
return {};
}
} // namespace arangodb

View File

@ -227,6 +227,9 @@ class DatabaseInitialSyncer final : public InitialSyncer {
std::vector<std::pair<arangodb::velocypack::Slice,
arangodb::velocypack::Slice>> const&,
bool incremental, SyncPhase);
/// @brief create non-existing views locally
Result handleViewCreation(VPackSlice const& views);
private:
Configuration _config;

View File

@ -131,7 +131,7 @@ Result DatabaseTailingSyncer::syncCollectionFinalize(
"&from=" + StringUtils::itoa(fromTick) +
"&serverId=" + _state.localServerIdString +
"&collection=" + StringUtils::urlEncode(collectionName);
// send request
std::unique_ptr<SimpleHttpResult> response(
_state.connection.client->request(rest::RequestType::GET, url, nullptr,

View File

@ -164,23 +164,22 @@ Result GlobalInitialSyncer::runInternal(bool incremental) {
try {
// actually sync the database
for (auto const& database : VPackObjectIterator(databases)) {
for (auto const& dbEntry : VPackObjectIterator(databases)) {
if (application_features::ApplicationServer::isStopping()) {
return Result(TRI_ERROR_SHUTTING_DOWN);
} else if (isAborted()) {
return Result(TRI_ERROR_REPLICATION_APPLIER_STOPPED);
}
VPackSlice it = database.value;
if (!it.isObject()) {
VPackSlice dbInventory = dbEntry.value;
if (!dbInventory.isObject()) {
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
"database declaration is invalid in response");
}
VPackSlice const nameSlice = it.get("name");
VPackSlice const idSlice = it.get("id");
VPackSlice const collections = it.get("collections");
VPackSlice const nameSlice = dbInventory.get("name");
VPackSlice const idSlice = dbInventory.get("id");
VPackSlice const collections = dbInventory.get("collections");
if (!nameSlice.isString() || !idSlice.isString() ||
!collections.isArray()) {
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
@ -192,22 +191,20 @@ Result GlobalInitialSyncer::runInternal(bool incremental) {
if (vocbase == nullptr) {
return Result(TRI_ERROR_INTERNAL, "vocbase not found");
}
DatabaseGuard guard(nameSlice.copyString());
// change database name in place
auto configurationCopy = _state.applier;
configurationCopy._database = nameSlice.copyString();
auto syncer = std::make_shared<DatabaseInitialSyncer>(*vocbase, configurationCopy);
syncer->useAsChildSyncer(_state.master, _state.barrier.id,
_state.barrier.updateTime, _batch.id,
_batch.updateTime);
// run the syncer with the supplied inventory collections
Result r = syncer->runWithInventory(false, collections);
Result r = syncer->runWithInventory(false, dbInventory);
if (r.fail()) {
return r;
}
@ -228,8 +225,8 @@ Result GlobalInitialSyncer::runInternal(bool incremental) {
return TRI_ERROR_NO_ERROR;
}
/// @brief add or remove databases such that the local inventory mirrors the
/// masters
/// @brief add or remove databases such that the local inventory
/// mirrors the masters
Result GlobalInitialSyncer::updateServerInventory(
VPackSlice const& masterDatabases) {
std::set<std::string> existingDBs;

View File

@ -45,6 +45,7 @@
#include "Utils/OperationResult.h"
#include "Utils/SingleCollectionTransaction.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/LogicalView.h"
#include "VocBase/voc-types.h"
#include "VocBase/vocbase.h"
@ -442,8 +443,8 @@ std::shared_ptr<LogicalCollection> Syncer::resolveCollection(
}
if (cid == 0) {
LOG_TOPIC(ERR, Logger::REPLICATION)
<< TRI_errno_string(TRI_ERROR_REPLICATION_INVALID_RESPONSE);
LOG_TOPIC(ERR, Logger::REPLICATION) << "Invalid replication response: Was unable to resolve"
<< " collection from marker: " << slice.toJson();
return nullptr;
}
@ -525,7 +526,7 @@ Result Syncer::createCollection(TRI_vocbase_t& vocbase,
bool forceRemoveCid = false;
if (col != nullptr && _state.master.simulate32Client()) {
forceRemoveCid = true;
LOG_TOPIC(TRACE, Logger::REPLICATION)
LOG_TOPIC(INFO, Logger::REPLICATION)
<< "would have got a wrong collection!";
// go on now and truncate or drop/re-create the collection
}
@ -561,7 +562,7 @@ Result Syncer::createCollection(TRI_vocbase_t& vocbase,
}
}
VPackSlice uuid = slice.get("globallyUniqueId");
VPackSlice uuid = slice.get(StaticStrings::DataSourceGuid);
// merge in "isSystem" attribute, doesn't matter if name does not start with
// '_'
VPackBuilder s;
@ -574,7 +575,7 @@ Result Syncer::createCollection(TRI_vocbase_t& vocbase,
// if we received a globallyUniqueId from the remote, then we will always
// use this id so we can discard the "cid" and "id" values for the
// collection
s.add("id", VPackSlice::nullSlice());
s.add(StaticStrings::DataSourceId, VPackSlice::nullSlice());
s.add("cid", VPackSlice::nullSlice());
}
@ -751,6 +752,103 @@ Result Syncer::dropIndex(arangodb::velocypack::Slice const& slice) {
return r;
}
/// @brief creates a view, based on the VelocyPack provided
Result Syncer::createView(TRI_vocbase_t& vocbase,
arangodb::velocypack::Slice const& slice) {
if (!slice.isObject()) {
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
"collection slice is no object");
}
VPackSlice nameSlice = slice.get(StaticStrings::DataSourceName);
if (!nameSlice.isString() || nameSlice.getStringLength() == 0) {
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
"no name specified for view");
}
VPackSlice guidSlice = slice.get("globallyUniqueId");
if (!guidSlice.isString() || guidSlice.getStringLength() == 0) {
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
"no guid specified for view");
}
VPackSlice typeSlice = slice.get(StaticStrings::DataSourceType);
if (!typeSlice.isString() || typeSlice.getStringLength() == 0) {
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
"no type specified for view");
}
auto view = vocbase.lookupView(guidSlice.copyString());
if (view) { // identical view already exists
VPackSlice properties = slice.get("properties");
if (properties.isObject()) {
bool doSync = DatabaseFeature::DATABASE->forceSyncProperties();
return view->updateProperties(properties, false, doSync);
}
return {};
}
view = vocbase.lookupView(nameSlice.copyString());
if (view) { // resolve name conflict by deleting existing
Result res = vocbase.dropView(view->id(), /*dropSytem*/false);
if (res.fail()) {
return res;
}
}
VPackBuilder s;
s.openObject();
s.add("id", VPackSlice::nullSlice());
s.close();
VPackBuilder merged =
VPackCollection::merge(slice, s.slice(), /*mergeValues*/ true,
/*nullMeansRemove*/ true);
try {
vocbase.createView(merged.slice());
} catch (basics::Exception const& ex) {
return Result(ex.code(), ex.what());
} catch (std::exception const& ex) {
return Result(TRI_ERROR_INTERNAL, ex.what());
} catch (...) {
return Result(TRI_ERROR_INTERNAL);
}
return Result();
}
/// @brief drops a view, based on the VelocyPack provided
Result Syncer::dropView(arangodb::velocypack::Slice const& slice,
bool reportError) {
TRI_vocbase_t* vocbase = resolveVocbase(slice);
if (vocbase == nullptr) {
return Result(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
VPackSlice guidSlice = slice.get("globallyUniqueId");
if (guidSlice.isNone()) {
guidSlice = slice.get("cuid");
}
if (!guidSlice.isString() || guidSlice.getStringLength() == 0) {
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
"no guid specified for view");
}
try {
auto view = vocbase->lookupView(guidSlice.copyString());
if (view != nullptr) { // ignore non-existing
return vocbase->dropView(view->id(), false);
}
} catch (basics::Exception const& ex) {
return Result(ex.code(), ex.what());
} catch (std::exception const& ex) {
return Result(TRI_ERROR_INTERNAL, ex.what());
} catch (...) {
return Result(TRI_ERROR_INTERNAL);
}
return Result();
}
void Syncer::reloadUsers() {
AuthenticationFeature* af = AuthenticationFeature::instance();

View File

@ -195,6 +195,14 @@ class Syncer : public std::enable_shared_from_this<Syncer> {
/// @brief drops an index, based on the VelocyPack provided
Result dropIndex(arangodb::velocypack::Slice const&);
/// @brief creates a view, based on the VelocyPack provided
Result createView(TRI_vocbase_t& vocbase,
arangodb::velocypack::Slice const& slice);
/// @brief drops a view, based on the VelocyPack provided
Result dropView(arangodb::velocypack::Slice const&, bool reportError);
// TODO worker safety
virtual TRI_vocbase_t* resolveVocbase(velocypack::Slice const&);

View File

@ -45,6 +45,7 @@
#include "Utils/CollectionGuard.h"
#include "Utils/SingleCollectionTransaction.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/LogicalView.h"
#include "VocBase/Methods/Databases.h"
#include "VocBase/voc-types.h"
#include "VocBase/vocbase.h"
@ -621,8 +622,8 @@ Result TailingSyncer::renameCollection(VPackSlice const& slice) {
return Result(vocbase->renameCollection(col, name, true));
}
/// @brief changes the properties of a collection, based on the VelocyPack
/// provided
/// @brief changes the properties of a collection,
/// based on the VelocyPack provided
Result TailingSyncer::changeCollection(VPackSlice const& slice) {
if (!slice.isObject()) {
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
@ -672,6 +673,66 @@ Result TailingSyncer::changeCollection(VPackSlice const& slice) {
return guard.collection()->updateProperties(data, doSync);
}
/// @brief changes the properties of a view,
/// based on the VelocyPack provided
Result TailingSyncer::changeView(VPackSlice const& slice) {
if (!slice.isObject()) {
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
"view marker slice is no object");
}
VPackSlice data = slice.get("data");
if (!data.isObject()) {
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
"data slice is no object in view change marker");
}
VPackSlice d = data.get("deleted");
bool const isDeleted = (d.isBool() && d.getBool());
TRI_vocbase_t* vocbase = resolveVocbase(slice);
if (vocbase == nullptr) {
if (isDeleted) {
// not a problem if a view that is going to be deleted anyway
// does not exist on slave
return Result();
}
return Result(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
VPackSlice guidSlice = data.get(StaticStrings::DataSourceGuid);
if (!guidSlice.isString() || guidSlice.getStringLength() == 0) {
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
"no guid specified for view");
}
auto view = vocbase->lookupView(guidSlice.copyString());
if (view == nullptr) {
if (isDeleted) {
// not a problem if a collection that is going to be deleted anyway
// does not exist on slave
return Result();
}
return Result(TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND);
}
VPackSlice nameSlice = data.get(StaticStrings::DataSourceName);
if (nameSlice.isString() && !nameSlice.isEqualString(view->name())) {
int res = vocbase->renameView(view, nameSlice.copyString());
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
}
VPackSlice properties = data.get("properties");
if (properties.isObject()) {
bool doSync = DatabaseFeature::DATABASE->forceSyncProperties();
return view->updateProperties(properties, false, doSync);
}
return {};
}
/// @brief apply a single marker from the continuous log
Result TailingSyncer::applyLogMarker(VPackSlice const& slice,
TRI_voc_tick_t firstRegularTick) {
@ -764,16 +825,35 @@ Result TailingSyncer::applyLogMarker(VPackSlice const& slice,
return createIndex(slice);
} else if (type == REPLICATION_INDEX_DROP) {
return dropIndex(slice);
} else if (type == REPLICATION_VIEW_CREATE) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_NOT_IMPLEMENTED,
"view create not yet implemented");
}
else if (type == REPLICATION_VIEW_CREATE) {
if (_ignoreRenameCreateDrop) {
LOG_TOPIC(DEBUG, Logger::REPLICATION) << "Ignoring view create marker";
return TRI_ERROR_NO_ERROR;
}
TRI_vocbase_t* vocbase = resolveVocbase(slice);
if (vocbase == nullptr) {
LOG_TOPIC(WARN, Logger::REPLICATION)
<< "Did not find database for " << slice.toJson();
return Result(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
return createView(*vocbase, slice.get("data"));
} else if (type == REPLICATION_VIEW_DROP) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_NOT_IMPLEMENTED,
"view drop not yet implemented");
if (_ignoreRenameCreateDrop) {
LOG_TOPIC(DEBUG, Logger::REPLICATION) << "Ignoring view drop marker";
return TRI_ERROR_NO_ERROR;
}
return dropView(slice, false);
} else if (type == REPLICATION_VIEW_CHANGE) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_NOT_IMPLEMENTED,
"view change not yet implemented");
} else if (type == REPLICATION_DATABASE_CREATE ||
return changeView(slice);
}
else if (type == REPLICATION_DATABASE_CREATE ||
type == REPLICATION_DATABASE_DROP) {
if (_ignoreDatabaseMarkers) {
LOG_TOPIC(DEBUG, Logger::REPLICATION) << "Ignoring database marker";

View File

@ -97,9 +97,13 @@ class TailingSyncer : public Syncer {
/// @brief renames a collection, based on the VelocyPack provided
Result renameCollection(arangodb::velocypack::Slice const&);
/// @brief changes the properties of a collection, based on the VelocyPack
/// provided
/// @brief changes the properties of a collection,
/// based on the VelocyPack provided
Result changeCollection(arangodb::velocypack::Slice const&);
/// @brief changes the properties of a collection,
/// based on the VelocyPack provided
Result changeView(arangodb::velocypack::Slice const&);
/// @brief apply a single marker from the continuous log
Result applyLogMarker(arangodb::velocypack::Slice const&, TRI_voc_tick_t);

View File

@ -49,7 +49,6 @@ typedef enum {
REPLICATION_VIEW_CREATE = 2110,
REPLICATION_VIEW_DROP = 2111,
REPLICATION_VIEW_CHANGE = 2112,
REPLICATION_VIEW_RENAME = 2113,
REPLICATION_TRANSACTION_START = 2200,
REPLICATION_TRANSACTION_COMMIT = 2201,

View File

@ -1333,68 +1333,31 @@ void RocksDBEngine::unloadCollection(
collection.setStatus(TRI_VOC_COL_STATUS_UNLOADED);
}
void RocksDBEngine::createView(
Result RocksDBEngine::createView(
TRI_vocbase_t& vocbase,
TRI_voc_cid_t id,
arangodb::LogicalView const& /*view*/
arangodb::LogicalView const& view
) {
rocksdb::WriteBatch batch;
rocksdb::WriteOptions wo;
RocksDBLogValue logValue = RocksDBLogValue::ViewCreate(vocbase.id(), id);
RocksDBKey key;
key.constructView(vocbase.id(), id);
RocksDBLogValue logValue = RocksDBLogValue::ViewCreate(vocbase.id(), id);
auto value = RocksDBValue::View(VPackSlice::emptyObjectSlice());
VPackBuilder props;
props.openObject();
view.toVelocyPack(props, true, true);
props.close();
RocksDBValue const value = RocksDBValue::View(props.slice());
// Write marker + key into RocksDB inside one batch
batch.PutLogData(logValue.slice());
batch.Put(RocksDBColumnFamily::definitions(), key.string(), value.string());
auto res = _db->Write(wo, &batch);
auto status = rocksutils::convertStatus(res);
if (!status.ok()) {
THROW_ARANGO_EXCEPTION(status);
}
return rocksutils::convertStatus(res);
}
// asks the storage engine to persist renaming of a view
// This will write a renameMarker if not in recovery
Result RocksDBEngine::renameView(
TRI_vocbase_t& vocbase,
arangodb::LogicalView const& view,
std::string const& /*oldName*/
) {
return persistView(vocbase, view);
}
arangodb::Result RocksDBEngine::persistView(
TRI_vocbase_t& vocbase,
arangodb::LogicalView const& view
) {
auto db = rocksutils::globalRocksDB();
RocksDBKey key;
key.constructView(vocbase.id(), view.id());
VPackBuilder infoBuilder;
infoBuilder.openObject();
view.toVelocyPack(infoBuilder, true, true);
infoBuilder.close();
auto const value = RocksDBValue::View(infoBuilder.slice());
rocksdb::WriteOptions options; // TODO: check which options would make sense
rocksdb::Status const status = db->Put(
options, RocksDBColumnFamily::definitions(), key.string(), value.string()
);
return rocksutils::convertStatus(status);
}
arangodb::Result RocksDBEngine::dropView(
TRI_vocbase_t& vocbase,
LogicalView& view
@ -1406,9 +1369,9 @@ arangodb::Result RocksDBEngine::dropView(
builder.close();
auto logValue =
RocksDBLogValue::ViewDrop(vocbase.id(), view.id(), builder.slice());
RocksDBLogValue::ViewDrop(vocbase.id(), view.id(),
StringRef(view.guid()));
RocksDBKey key;
key.constructView(vocbase.id(), view.id());
rocksdb::WriteBatch batch;
@ -1428,25 +1391,41 @@ void RocksDBEngine::destroyView(
// nothing to do here
}
void RocksDBEngine::changeView(
Result RocksDBEngine::changeView(
TRI_vocbase_t& vocbase,
TRI_voc_cid_t /*id*/,
arangodb::LogicalView const& view,
bool /*doSync*/
) {
if (inRecovery()) {
// nothing to do
return;
return {};
}
auto const res = persistView(vocbase, view);
if (!res.ok()) {
THROW_ARANGO_EXCEPTION_MESSAGE(
res.errorNumber(),
"could not save view properties"
);
RocksDBKey key;
key.constructView(vocbase.id(), view.id());
VPackBuilder infoBuilder;
infoBuilder.openObject();
view.toVelocyPack(infoBuilder, true, true);
infoBuilder.close();
RocksDBLogValue log = RocksDBLogValue::ViewChange(vocbase.id(), view.id());
RocksDBValue const value = RocksDBValue::View(infoBuilder.slice());
rocksdb::WriteBatch batch;
rocksdb::WriteOptions wo; // TODO: check which options would make sense
rocksdb::Status s;
s = batch.PutLogData(log.slice());
if (!s.ok()) {
return rocksutils::convertStatus(s);
}
s = batch.Put(RocksDBColumnFamily::definitions(),
key.string(), value.string());
if (!s.ok()) {
return rocksutils::convertStatus(s);
}
auto db = rocksutils::globalRocksDB();
return rocksutils::convertStatus(db->Write(wo, &batch));
}
void RocksDBEngine::signalCleanup(TRI_vocbase_t& vocbase) {

View File

@ -269,14 +269,13 @@ class RocksDBEngine final : public StorageEngine {
LogicalCollection& collection
) override;
void changeView(
arangodb::Result changeView(
TRI_vocbase_t& vocbase,
TRI_voc_cid_t id,
arangodb::LogicalView const& view,
bool doSync
) override;
void createView(
arangodb::Result createView(
TRI_vocbase_t& vocbase,
TRI_voc_cid_t id,
arangodb::LogicalView const& view
@ -290,19 +289,6 @@ class RocksDBEngine final : public StorageEngine {
// does nothing
}
arangodb::Result persistView(
TRI_vocbase_t& vocbase,
arangodb::LogicalView const& view
) override;
// asks the storage engine to persist renaming of a view
// This will write a renameMarker if not in recovery
arangodb::Result renameView(
TRI_vocbase_t& vocbase,
arangodb::LogicalView const& view,
std::string const& oldName
) override;
arangodb::Result dropView(
TRI_vocbase_t& vocbase,
LogicalView& view

View File

@ -80,8 +80,8 @@ RocksDBLogValue RocksDBLogValue::ViewCreate(TRI_voc_tick_t dbid,
RocksDBLogValue RocksDBLogValue::ViewDrop(TRI_voc_tick_t dbid,
TRI_voc_cid_t vid,
VPackSlice const& viewInfo) {
return RocksDBLogValue(RocksDBLogType::ViewDrop, dbid, vid, viewInfo);
StringRef const& uuid) {
return RocksDBLogValue(RocksDBLogType::ViewDrop, dbid, vid, uuid);
}
RocksDBLogValue RocksDBLogValue::ViewChange(TRI_voc_tick_t dbid,
@ -89,11 +89,6 @@ RocksDBLogValue RocksDBLogValue::ViewChange(TRI_voc_tick_t dbid,
return RocksDBLogValue(RocksDBLogType::ViewChange, dbid, vid);
}
RocksDBLogValue RocksDBLogValue::ViewRename(TRI_voc_cid_t cid,
TRI_idx_iid_t iid) {
return RocksDBLogValue(RocksDBLogType::ViewRename, cid, iid);
}
#ifdef USE_IRESEARCH
RocksDBLogValue RocksDBLogValue::IResearchLinkDrop(TRI_voc_tick_t dbid,
TRI_voc_cid_t cid,
@ -153,8 +148,8 @@ RocksDBLogValue::RocksDBLogValue(RocksDBLogType type, uint64_t dbId,
switch (type) {
case RocksDBLogType::CollectionCreate:
case RocksDBLogType::CollectionChange:
case RocksDBLogType::CollectionDrop:
case RocksDBLogType::ViewCreate:
case RocksDBLogType::ViewChange:
case RocksDBLogType::BeginTransaction:
case RocksDBLogType::SinglePut:
case RocksDBLogType::CommitTransaction: {
@ -216,8 +211,7 @@ RocksDBLogValue::RocksDBLogValue(RocksDBLogType type, uint64_t dbId,
uint64_t cid, VPackSlice const& info)
: _buffer() {
switch (type) {
case RocksDBLogType::IndexCreate:
case RocksDBLogType::ViewDrop: {
case RocksDBLogType::IndexCreate: {
_buffer.reserve(sizeof(RocksDBLogType) + (sizeof(uint64_t) * 2) +
info.byteSize());
_buffer.push_back(static_cast<char>(type));
@ -238,14 +232,13 @@ RocksDBLogValue::RocksDBLogValue(RocksDBLogType type, uint64_t dbId,
: _buffer() {
switch (type) {
case RocksDBLogType::CollectionDrop:
case RocksDBLogType::CollectionRename: {
case RocksDBLogType::CollectionRename:
case RocksDBLogType::ViewDrop: {
_buffer.reserve(sizeof(RocksDBLogType) + sizeof(uint64_t) * 2 +
data.length());
_buffer.push_back(static_cast<char>(type));
uint64ToPersistent(_buffer, dbId);
uint64ToPersistent(_buffer, cid);
// append primary key for SingleRemove, or
// collection name for CollectionRename, or
// collection uuid for CollectionDrop
_buffer.append(data.data(), data.length());
break;
@ -356,18 +349,29 @@ VPackSlice RocksDBLogValue::viewSlice(rocksdb::Slice const& slice) {
sizeof(uint64_t) * 2);
}
namespace {
StringRef dropMarkerUUID(rocksdb::Slice const& slice) {
size_t off = sizeof(RocksDBLogType) + sizeof(uint64_t) * 2;
TRI_ASSERT(slice.size() >= off);
RocksDBLogType type = static_cast<RocksDBLogType>(slice.data()[0]);
TRI_ASSERT(type == RocksDBLogType::CollectionDrop ||
type == RocksDBLogType::ViewDrop);
if (slice.size() > off) {
// have a UUID
return StringRef(slice.data() + off, slice.size() - off);
}
// do not have a UUID
return StringRef();
}
}
StringRef RocksDBLogValue::collectionUUID(
rocksdb::Slice const& slice) {
size_t off = sizeof(RocksDBLogType) + sizeof(uint64_t) * 2;
TRI_ASSERT(slice.size() >= off);
RocksDBLogType type = static_cast<RocksDBLogType>(slice.data()[0]);
TRI_ASSERT(type == RocksDBLogType::CollectionDrop);
if (slice.size() > off) {
// have a UUID
return StringRef(slice.data() + off, slice.size() - off);
}
// do not have a UUID
return StringRef();
return ::dropMarkerUUID(slice);
}
StringRef RocksDBLogValue::viewUUID(rocksdb::Slice const& slice) {
return ::dropMarkerUUID(slice);
}
StringRef RocksDBLogValue::oldCollectionName(
@ -388,7 +392,6 @@ bool RocksDBLogValue::containsDatabaseId(RocksDBLogType type) {
type == RocksDBLogType::CollectionChange ||
type == RocksDBLogType::ViewCreate ||
type == RocksDBLogType::ViewDrop ||
type == RocksDBLogType::ViewRename ||
type == RocksDBLogType::ViewChange ||
#ifdef USE_IRESEARCH
type == RocksDBLogType::IResearchLinkDrop ||
@ -418,7 +421,6 @@ bool RocksDBLogValue::containsCollectionId(RocksDBLogType type) {
bool RocksDBLogValue::containsViewId(RocksDBLogType type) {
return type == RocksDBLogType::ViewCreate ||
type == RocksDBLogType::ViewDrop ||
type == RocksDBLogType::ViewRename ||
#ifdef USE_IRESEARCH
type == RocksDBLogType::IResearchLinkDrop ||
#endif

View File

@ -64,9 +64,8 @@ class RocksDBLogValue {
static RocksDBLogValue ViewCreate(TRI_voc_tick_t, TRI_voc_cid_t);
static RocksDBLogValue ViewDrop(TRI_voc_tick_t, TRI_voc_cid_t,
VPackSlice const& viewInfo);
StringRef const& uuid);
static RocksDBLogValue ViewChange(TRI_voc_tick_t, TRI_voc_cid_t);
static RocksDBLogValue ViewRename(TRI_voc_tick_t, TRI_voc_cid_t);
#ifdef USE_IRESEARCH
static RocksDBLogValue IResearchLinkDrop(TRI_voc_tick_t, TRI_voc_cid_t,
@ -91,11 +90,16 @@ class RocksDBLogValue {
static TRI_voc_cid_t collectionId(rocksdb::Slice const&);
static TRI_voc_cid_t viewId(rocksdb::Slice const&);
static TRI_idx_iid_t indexId(rocksdb::Slice const&);
/// For DocumentRemoveV2 and SingleRemoveV2
// ==== For DocumentRemoveV2 and SingleRemoveV2 ====
static TRI_voc_rid_t revisionId(rocksdb::Slice const&);
static velocypack::Slice indexSlice(rocksdb::Slice const&);
static velocypack::Slice viewSlice(rocksdb::Slice const&);
/// @brief get UUID from collection drop marker
static arangodb::StringRef collectionUUID(rocksdb::Slice const&);
/// @brief get UUID from view drop marker
static arangodb::StringRef viewUUID(rocksdb::Slice const&);
// deprecated method for old collection drop marker
static arangodb::StringRef oldCollectionName(rocksdb::Slice const&);
static bool containsDatabaseId(RocksDBLogType type);
@ -107,10 +111,6 @@ class RocksDBLogValue {
/// @brief Returns a reference to the underlying string buffer.
//////////////////////////////////////////////////////////////////////////////
std::string const& string() const { return _buffer; } // to be used with put
/*VPackSlice slice() const { return VPackSlice(
reinterpret_cast<uint8_t const*>(_buffer.data())
); }*/ // return a slice
RocksDBLogType type() const {
return static_cast<RocksDBLogType>(*(_buffer.data()));
}

View File

@ -238,10 +238,8 @@ class WALParser final : public rocksdb::WriteBatch::Handler {
}
case RocksDBLogType::ViewCreate:
case RocksDBLogType::ViewDrop:
case RocksDBLogType::ViewChange:
case RocksDBLogType::ViewRename: {
case RocksDBLogType::ViewChange: {
resetTransientState(); // finish ongoing trx
// TODO
break;
}
case RocksDBLogType::BeginTransaction: {

View File

@ -196,8 +196,6 @@ char const* arangodb::rocksDBLogTypeName(arangodb::RocksDBLogType type) {
return "ViewDrop";
case arangodb::RocksDBLogType::ViewChange:
return "ViewChange";
case arangodb::RocksDBLogType::ViewRename:
return "ViewRename";
#ifdef USE_IRESEARCH
case arangodb::RocksDBLogType::IResearchLinkDrop:
return "IResearchLinkDrop";

View File

@ -79,7 +79,6 @@ enum class RocksDBLogType : char {
SinglePut = '?',
SingleRemove = '@', // <- deprecated
DocumentRemoveAsPartOfUpdate = 'A', // <- deprecated
ViewRename = 'B',
#ifdef USE_IRESEARCH
IResearchLinkDrop = 'C',
#endif

View File

@ -31,6 +31,7 @@
#include "RocksDBEngine/RocksDBTypes.h"
#include "Utils/DatabaseGuard.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/LogicalView.h"
#include "Logger/Logger.h"
@ -88,15 +89,12 @@ class MyWALParser : public rocksdb::WriteBatch::Handler, public WalAccessContext
DB_CREATE,
DB_DROP,
COLLECTION_CREATE,
COLLECTION_DROP,
COLLECTION_RENAME,
COLLECTION_CHANGE,
INDEX_CREATE,
INDEX_DROP,
VIEW_CREATE,
VIEW_DROP,
VIEW_CHANGE,
VIEW_RENAME,
TRANSACTION,
SINGLE_PUT,
SINGLE_REMOVE
@ -165,7 +163,7 @@ class MyWALParser : public rocksdb::WriteBatch::Handler, public WalAccessContext
TRI_vocbase_t* vocbase = loadVocbase(dbid);
if (vocbase != nullptr) {
{ // tick number
StringRef uuid = RocksDBLogValue::collectionUUID(blob);
StringRef uuid = RocksDBLogValue::viewUUID(blob);
TRI_ASSERT(!uuid.empty());
uint64_t tick = _currentSequence + (_startOfBatch ? 0 : 1);
VPackObjectBuilder marker(&_builder, true);
@ -245,17 +243,53 @@ class MyWALParser : public rocksdb::WriteBatch::Handler, public WalAccessContext
_responseSize += _builder.size();
_builder.clear();
}
break;
}
case RocksDBLogType::ViewCreate:
case RocksDBLogType::ViewDrop:
case RocksDBLogType::ViewChange:
case RocksDBLogType::ViewRename: {
resetTransientState(); // finish ongoing trx
// TODO
if (shouldHandleView(RocksDBLogValue::databaseId(blob),
RocksDBLogValue::viewId(blob))) {
_state = VIEW_CREATE;
}
// wait for marker data in Put entry
break;
case RocksDBLogType::ViewDrop: {
resetTransientState(); // finish ongoing trx
TRI_voc_tick_t dbid = RocksDBLogValue::databaseId(blob);
TRI_voc_cid_t vid = RocksDBLogValue::viewId(blob);
if (shouldHandleView(dbid, vid)) {
TRI_vocbase_t* vocbase = loadVocbase(dbid);
if (vocbase != nullptr) {
{ // tick number
StringRef uuid = RocksDBLogValue::collectionUUID(blob);
TRI_ASSERT(!uuid.empty());
uint64_t tick = _currentSequence + (_startOfBatch ? 0 : 1);
VPackObjectBuilder marker(&_builder, true);
marker->add("tick", VPackValue(std::to_string(tick)));
marker->add("type", VPackValue(REPLICATION_VIEW_DROP));
marker->add("db", VPackValue(vocbase->name()));
marker->add("cuid", VPackValuePair(uuid.data(), uuid.size(),
VPackValueType::String));
}
_callback(vocbase, _builder.slice());
_responseSize += _builder.size();
_builder.clear();
}
}
// wait for marker data in Put entry
break;
}
case RocksDBLogType::ViewChange:
resetTransientState(); // finish ongoing trx
if (shouldHandleView(RocksDBLogValue::databaseId(blob),
RocksDBLogValue::viewId(blob))) {
_state = VIEW_CHANGE;
}
// wait for marker data in Put entry
break;
case RocksDBLogType::BeginTransaction: {
resetTransientState(); // finish ongoing trx
TRI_voc_tid_t tid = RocksDBLogValue::transactionId(blob);
@ -329,7 +363,8 @@ class MyWALParser : public rocksdb::WriteBatch::Handler, public WalAccessContext
}
break;
}
case RocksDBLogType::IResearchLinkDrop: // do nothing
case RocksDBLogType::DocumentOperationsPrologue:
case RocksDBLogType::DocumentRemove:
case RocksDBLogType::DocumentRemoveAsPartOfUpdate:
@ -428,7 +463,38 @@ class MyWALParser : public rocksdb::WriteBatch::Handler, public WalAccessContext
_responseSize += _builder.size();
_builder.clear();
}
} // if (RocksDBKey::type(key) == RocksDBEntryType::Collection)
} else if (RocksDBKey::type(key) == RocksDBEntryType::View) {
TRI_voc_tick_t dbid = RocksDBKey::databaseId(key);
TRI_voc_cid_t vid = RocksDBKey::viewId(key);
if (shouldHandleView(dbid, vid) && (_state == VIEW_CREATE ||
_state == VIEW_CHANGE)) {
TRI_vocbase_t* vocbase = loadVocbase(dbid);
TRI_ASSERT(vocbase != nullptr);
auto view = vocbase->lookupView(vid);
if (view != nullptr) { // ignore nonexisting views
VPackSlice viewDef = RocksDBValue::data(value);
{
VPackObjectBuilder marker(&_builder, true);
marker->add("tick", VPackValue(std::to_string(_currentSequence)));
marker->add("db", VPackValue(vocbase->name()));
marker->add("cuid", VPackValue(view->guid()));
marker->add("data", viewDef);
if (_state == VIEW_CREATE) {
marker->add("type", VPackValue(REPLICATION_VIEW_CREATE));
} else /*if (_state == VIEW_CHANGE)*/ {
marker->add("type", VPackValue(REPLICATION_VIEW_CHANGE));
}
}
_callback(vocbase, _builder.slice());
_responseSize += _builder.size();
_builder.clear();
}
}
}
// reset everything immediately after DDL operations
resetTransientState();

View File

@ -325,9 +325,8 @@ class StorageEngine : public application_features::ApplicationFeature {
// property changes and throw only then, so that subsequent operations will not fail.
// the WAL entry for the propery change will be written *after* the call
// to "changeView" returns
virtual void changeView(
virtual arangodb::Result changeView(
TRI_vocbase_t& vocbase,
TRI_voc_cid_t id,
arangodb::LogicalView const& view,
bool doSync
) = 0;
@ -341,7 +340,7 @@ class StorageEngine : public application_features::ApplicationFeature {
// and throw only then, so that subsequent view creation requests will not fail.
// the WAL entry for the view creation will be written *after* the call
// to "createCview" returns
virtual void createView(
virtual arangodb::Result createView(
TRI_vocbase_t& vocbase,
TRI_voc_cid_t id,
arangodb::LogicalView const& view
@ -355,20 +354,6 @@ class StorageEngine : public application_features::ApplicationFeature {
VPackBuilder& builder
) = 0;
// asks the storage engine to persist the view.
// After this call the view is persisted over recovery.
virtual arangodb::Result persistView(
TRI_vocbase_t& vocbase,
arangodb::LogicalView const& view
) = 0;
// asks the storage engine to persist renaming of a view
virtual arangodb::Result renameView(
TRI_vocbase_t& vocbase,
arangodb::LogicalView const& view,
std::string const& oldName
) = 0;
// asks the storage engine to drop the specified view and persist the
// deletion info. Note that physical deletion of the view data must not
// be carried out by this call, as there may

View File

@ -33,6 +33,20 @@ bool WalAccessContext::shouldHandleDB(TRI_voc_tick_t dbid) const {
return _filter.vocbase == 0 || _filter.vocbase == dbid;
}
/// @brief check if view should be handled, might already be deleted
bool WalAccessContext::shouldHandleView(TRI_voc_tick_t dbid,
TRI_voc_cid_t vid) const {
if (dbid == 0 || vid == 0 || !shouldHandleDB(dbid)) {
return false;
}
if (_filter.vocbase == 0 || (_filter.vocbase == dbid &&
(_filter.collection == 0 || _filter.collection == vid))) {
return true;
}
return false;
}
/// @brief Check if collection is in filter, will load collection
bool WalAccessContext::shouldHandleCollection(TRI_voc_tick_t dbid,
TRI_voc_cid_t cid) {

View File

@ -143,6 +143,10 @@ struct WalAccessContext {
/// @brief check if db should be handled, might already be deleted
bool shouldHandleDB(TRI_voc_tick_t dbid) const;
/// @brief check if view should be handled, might already be deleted
bool shouldHandleView(TRI_voc_tick_t dbid,
TRI_voc_cid_t vid) const;
/// @brief Check if collection is in filter, will load collection
/// and prevent deletion

View File

@ -23,6 +23,8 @@
#include <mutex>
#include "LogicalDataSource.h"
#include "Basics/conversions.h"
#include "Basics/VelocyPackHelper.h"
#include "Cluster/ClusterInfo.h"
@ -33,7 +35,8 @@
#include "VocBase/LogicalCollection.h"
#include "VocBase/ticks.h"
#include "LogicalDataSource.h"
//
#include "Logger/Logger.h"
namespace {
@ -50,25 +53,26 @@ std::string ensureGuid(
guid.reserve(64);
if (arangodb::ServerState::instance()->isCoordinator()) {
// view GUIDs are added to the ClusterInfo. To avoid conflicts
// with collection names we always put in a '/' which is an illegal
// character for collection names. Stringified collection or view
// id numbers can also not conflict, first character is always 'h'
if (arangodb::ServerState::instance()->isCoordinator() ||
arangodb::ServerState::instance()->isDBServer()) {
TRI_ASSERT(planId);
guid.append("c");
guid.append(std::to_string(planId));
} else if (arangodb::ServerState::instance()->isDBServer()) {
TRI_ASSERT(planId);
guid.append("c");
// we add the shard name to the collection. If we ever
// replicate shards, we can identify them cluster-wide
guid.append(std::to_string(planId));
guid.push_back('/');
guid.append(name);
if (arangodb::ServerState::instance()->isDBServer()) {
// we add the shard name to the collection. If we ever
// replicate shards, we can identify them cluster-wide
guid.append(name);
}
} else if (isSystem) {
guid.append(name);
} else {
char buf[sizeof(TRI_server_id_t) * 2 + 1];
auto len =
TRI_StringUInt64HexInPlace(arangodb::ServerIdFeature::getId(), buf);
auto len = TRI_StringUInt64HexInPlace(arangodb::ServerIdFeature::getId(), buf);
TRI_ASSERT(id);
guid.append("h");
guid.append(buf, len);

View File

@ -288,9 +288,7 @@ arangodb::Result LogicalViewStorageEngine::appendVelocyPack(
}
#endif
engine->createView(view.vocbase(), view.id(), view);
return engine->persistView(view.vocbase(), view);
return engine->createView(view.vocbase(), view.id(), view);
} catch (std::exception const& e) {
return arangodb::Result(
TRI_ERROR_INTERNAL,
@ -330,7 +328,8 @@ Result LogicalViewStorageEngine::rename(std::string&& newName, bool doSync) {
// store new view definition to disk
if (!engine->inRecovery()) {
engine->changeView(vocbase(), id(), *this, doSync);
// write WAL 'change' marker
return engine->changeView(vocbase(), *this, doSync);
}
} catch (basics::Exception const& ex) {
name(std::move(oldName));
@ -342,8 +341,7 @@ Result LogicalViewStorageEngine::rename(std::string&& newName, bool doSync) {
return TRI_ERROR_INTERNAL;
}
// write WAL 'rename' marker
return engine->renameView(vocbase(), *this, oldName);
return TRI_ERROR_NO_ERROR;
}
arangodb::Result LogicalViewStorageEngine::updateProperties(
@ -368,7 +366,7 @@ arangodb::Result LogicalViewStorageEngine::updateProperties(
}
try {
engine->changeView(vocbase(), id(), *this, doSync);
engine->changeView(vocbase(), *this, doSync);
} catch (arangodb::basics::Exception const& e) {
return { e.code() };
} catch (...) {
@ -382,4 +380,4 @@ arangodb::Result LogicalViewStorageEngine::updateProperties(
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -1207,8 +1207,8 @@ arangodb::LogicalCollection* TRI_vocbase_t::createCollection(
}
auto res2 = engine->persistCollection(*this, *collection);
// API compatibility, we always return the collection, even if creation
// failed.
// API compatibility, we always return the collection,
// even if creation failed.
if (DatabaseFeature::DATABASE != nullptr &&
DatabaseFeature::DATABASE->versionTracker() != nullptr) {

View File

@ -121,6 +121,7 @@ var compare = function(masterFunc, masterFunc2, slaveFuncOngoing, slaveFuncFinal
applierConfiguration.endpoint = masterEndpoint;
applierConfiguration.username = "root";
applierConfiguration.password = "";
applierConfiguration.force32mode = false;
if (!applierConfiguration.hasOwnProperty('chunkSize')) {
applierConfiguration.chunkSize = 16384;

View File

@ -82,6 +82,7 @@ const compare = function(masterFunc, masterFunc2, slaveFuncOngoing, slaveFuncFin
applierConfiguration.username = "root";
applierConfiguration.password = "";
applierConfiguration.includeSystem = false;
applierConfiguration.force32mode = false;
var syncResult = replication.syncGlobal({
endpoint: masterEndpoint,
@ -635,6 +636,124 @@ function BaseTestConfig() {
assertEqual(state.count, collectionCount(cn));
}
);
},
testViewBasic: function() {
connectToMaster();
compare(
function() {},
function(state) {
try {
db._create(cn);
let view = db._createView("UnitTestsSyncView", "arangosearch", {});
let links = {};
links[cn] = {
includeAllFields: true,
fields: {
text: { analyzers: [ "text_en" ] }
}
};
view.properties({"links": links});
state.arangoSearchEnabled = true;
} catch (err) { }
},
function() {},
function(state) {
if (!state.arangoSearchEnabled) {
return;
}
let view = db._view("UnitTestsSyncView");
assertTrue(view !== null);
let props = view.properties();
assertEqual(Object.keys(props.links).length, 1);
assertTrue(props.hasOwnProperty("links"));
assertTrue(props.links.hasOwnProperty(cn));
},
{}
);
},
testViewRename: function() {
connectToMaster();
compare(
function(state) {
try {
db._create(cn);
let view = db._createView("UnitTestsSyncView", "arangosearch", {});
let links = {};
links[cn] = {
includeAllFields: true,
fields: {
text: { analyzers: [ "text_en" ] }
}
};
view.properties({"links": links});
state.arangoSearchEnabled = true;
} catch (err) { }
},
function(state) {
if (!state.arangoSearchEnabled) {
return;
}
// rename view on master
let view = db._view("UnitTestsSyncView");
view.rename("UnitTestsSyncViewRenamed");
view = db._view("UnitTestsSyncViewRenamed");
assertTrue(view !== null);
let props = view.properties();
assertEqual(Object.keys(props.links).length, 1);
assertTrue(props.hasOwnProperty("links"));
assertTrue(props.links.hasOwnProperty(cn));
},
function(state) {},
function(state) {
if (!state.arangoSearchEnabled) {
return;
}
let view = db._view("UnitTestsSyncViewRenamed");
assertTrue(view !== null);
let props = view.properties();
assertEqual(Object.keys(props.links).length, 1);
assertTrue(props.hasOwnProperty("links"));
assertTrue(props.links.hasOwnProperty(cn));
},
{}
);
},
testViewDrop: function() {
connectToMaster();
compare(
function(state) {
try {
let view = db._createView("UnitTestsSyncView", "arangosearch", {});
state.arangoSearchEnabled = true;
} catch (err) { }
},
function(state) {
if (!state.arangoSearchEnabled) {
return;
}
// rename view on master
let view = db._view("UnitTestsSyncView");
view.drop();
},
function(state) {},
function(state) {
if (!state.arangoSearchEnabled) {
return;
}
let view = db._view("UnitTestsSyncView");
assertTrue(view === null);
},
{}
);
}
};
@ -675,6 +794,8 @@ function ReplicationSuite() {
suite.tearDown = function() {
connectToMaster();
db._dropView("UnitTestsSyncView");
db._dropView("UnitTestsSyncViewRenamed");
db._drop(cn);
db._drop(cn2);
@ -682,6 +803,8 @@ function ReplicationSuite() {
replication.globalApplier.stop();
replication.globalApplier.forget();
db._dropView("UnitTestsSyncView");
db._dropView("UnitTestsSyncViewRenamed");
db._drop(cn);
db._drop(cn2);
db._drop(cn + "Renamed");

View File

@ -97,6 +97,7 @@ const compare = function(masterFunc, masterFunc2, slaveFuncOngoing, slaveFuncFin
applierConfiguration.endpoint = masterEndpoint;
applierConfiguration.username = "root";
applierConfiguration.password = "";
applierConfiguration.force32mode = false;
if (!applierConfiguration.hasOwnProperty('chunkSize')) {
applierConfiguration.chunkSize = 16384;
@ -632,6 +633,124 @@ function BaseTestConfig() {
assertEqual(state.count, collectionCount(cn));
}
);
},
testViewBasic: function() {
connectToMaster();
compare(
function() {},
function(state) {
try {
db._create(cn);
let view = db._createView("UnitTestsSyncView", "arangosearch", {});
let links = {};
links[cn] = {
includeAllFields: true,
fields: {
text: { analyzers: [ "text_en" ] }
}
};
view.properties({"links": links});
state.arangoSearchEnabled = true;
} catch (err) { }
},
function() {},
function(state) {
if (!state.arangoSearchEnabled) {
return;
}
let view = db._view("UnitTestsSyncView");
assertTrue(view !== null);
let props = view.properties();
assertEqual(Object.keys(props.links).length, 1);
assertTrue(props.hasOwnProperty("links"));
assertTrue(props.links.hasOwnProperty(cn));
},
{}
);
},
testViewRename: function() {
connectToMaster();
compare(
function(state) {
try {
db._create(cn);
let view = db._createView("UnitTestsSyncView", "arangosearch", {});
let links = {};
links[cn] = {
includeAllFields: true,
fields: {
text: { analyzers: [ "text_en" ] }
}
};
view.properties({"links": links});
state.arangoSearchEnabled = true;
} catch (err) { }
},
function(state) {
if (!state.arangoSearchEnabled) {
return;
}
// rename view on master
let view = db._view("UnitTestsSyncView");
view.rename("UnitTestsSyncViewRenamed");
view = db._view("UnitTestsSyncViewRenamed");
assertTrue(view !== null);
let props = view.properties();
assertEqual(Object.keys(props.links).length, 1);
assertTrue(props.hasOwnProperty("links"));
assertTrue(props.links.hasOwnProperty(cn));
},
function(state) {},
function(state) {
if (!state.arangoSearchEnabled) {
return;
}
let view = db._view("UnitTestsSyncViewRenamed");
assertTrue(view !== null);
let props = view.properties();
assertEqual(Object.keys(props.links).length, 1);
assertTrue(props.hasOwnProperty("links"));
assertTrue(props.links.hasOwnProperty(cn));
},
{}
);
},
testViewDrop: function() {
connectToMaster();
compare(
function(state) {
try {
let view = db._createView("UnitTestsSyncView", "arangosearch", {});
state.arangoSearchEnabled = true;
} catch (err) { }
},
function(state) {
if (!state.arangoSearchEnabled) {
return;
}
// rename view on master
let view = db._view("UnitTestsSyncView");
view.drop();
},
function(state) {},
function(state) {
if (!state.arangoSearchEnabled) {
return;
}
let view = db._view("UnitTestsSyncView");
assertTrue(view === null);
},
{}
);
}
};
@ -672,6 +791,8 @@ function ReplicationSuite() {
suite.tearDown = function() {
connectToMaster();
db._dropView("UnitTestsSyncView");
db._dropView("UnitTestsSyncViewRenamed");
db._drop(cn);
db._drop(cn2);
@ -679,6 +800,8 @@ function ReplicationSuite() {
replication.applier.stop();
replication.applier.forget();
db._dropView("UnitTestsSyncView");
db._dropView("UnitTestsSyncViewRenamed");
db._drop(cn);
db._drop(cn2);
db._drop(cn + "Renamed");

View File

@ -2021,6 +2021,38 @@ function BaseTestConfig() {
restrictCollections: [cn2]
}
);
},
testViewBasic: function() {
compare(
function(state) {
try {
db._create(cn);
let view = db._createView("UnitTestsSyncView", "arangosearch", {});
let links = {};
links[cn] = {
includeAllFields: true,
fields: {
text: { analyzers: [ "text_en" ] }
}
};
view.properties({"links": links});
state.arangoSearchEnabled = true;
} catch (err) { }
},
function(state) {
if (!state.arangoSearchEnabled) {
return;
}
let view = db._view("UnitTestsSyncView");
assertTrue(view !== null);
let props = view.properties();
assertEqual(Object.keys(props.links).length, 1);
assertTrue(props.hasOwnProperty("links"));
assertTrue(props.links.hasOwnProperty(cn));
}
);
}
};
}

View File

@ -26,6 +26,8 @@
#define ARANGO_READ_WRITE_SPIN_LOCK_H 1
#include "Basics/Common.h"
#include "Basics/SharedAtomic.h"
#include "Basics/SharedCounter.h"
#include "Basics/cpu-relax.h"
#include <atomic>

View File

@ -229,8 +229,8 @@ SECTION("test_defaults") {
auto slice = builder->slice();
CHECK((
slice.hasKey("view")
&& slice.get("view").isNumber()
&& TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>()
&& slice.get("view").isString()
&& logicalView->guid() == slice.get("view").copyString()
&& slice.hasKey("figures")
&& slice.get("figures").isObject()
&& slice.get("figures").hasKey("memory")
@ -282,8 +282,8 @@ SECTION("test_defaults") {
auto slice = builder->slice();
CHECK((
slice.hasKey("view")
&& slice.get("view").isNumber()
&& TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>()
&& slice.get("view").isString()
&& logicalView->guid() == slice.get("view").copyString()
&& slice.hasKey("figures")
&& slice.get("figures").isObject()
&& slice.get("figures").hasKey("memory")
@ -299,8 +299,8 @@ SECTION("test_defaults") {
auto slice = builder->slice();
CHECK((
slice.hasKey("view")
&& slice.get("view").isNumber()
&& TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>()
&& slice.get("view").isString()
&& logicalView->guid() == slice.get("view").copyString()
&& slice.hasKey("figures")
&& slice.get("figures").isObject()
&& slice.get("figures").hasKey("memory")
@ -676,4 +676,4 @@ SECTION("test_write") {
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -367,8 +367,9 @@ SECTION("test_create_drop") {
CHECK(expectedMeta == actualMeta);
auto const slice = builder->slice();
CHECK(slice.hasKey("view"));
CHECK(slice.get("view").isNumber());
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
CHECK(slice.get("view").isString());
CHECK(logicalView->id() == 42);
CHECK(logicalView->guid() == slice.get("view").copyString());
CHECK(slice.hasKey("figures"));
CHECK(slice.get("figures").isObject());
CHECK(slice.get("figures").hasKey("memory"));
@ -405,8 +406,9 @@ SECTION("test_create_drop") {
CHECK(error.empty());
CHECK((
slice.hasKey("view")
&& slice.get("view").isNumber()
&& TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>()
&& slice.get("view").isString()
&& logicalView->id() == 42
&& logicalView->guid() == slice.get("view").copyString()
&& slice.hasKey("figures")
&& slice.get("figures").isObject()
&& slice.get("figures").hasKey("memory")
@ -473,8 +475,9 @@ SECTION("test_create_drop") {
auto slice = builder->slice();
CHECK((
slice.hasKey("view")
&& slice.get("view").isNumber()
&& TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>()
&& slice.get("view").isString()
&& logicalView->id() == 42
&& logicalView->guid() == slice.get("view").copyString()
&& slice.hasKey("figures")
&& slice.get("figures").isObject()
&& slice.get("figures").hasKey("memory")
@ -490,8 +493,9 @@ SECTION("test_create_drop") {
auto slice = builder->slice();
CHECK((
slice.hasKey("view")
&& slice.get("view").isNumber()
&& TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>()
&& slice.get("view").isString()
&& logicalView->id() == 42
&& logicalView->guid() == slice.get("view").copyString()
&& slice.hasKey("figures")
&& slice.get("figures").isObject()
&& slice.get("figures").hasKey("memory")

View File

@ -971,8 +971,8 @@ SECTION("test_update_links_partial_remove") {
CHECK(expectedMeta == actualMeta);
auto const slice = builder->slice();
CHECK(slice.hasKey("view"));
CHECK(slice.get("view").isNumber());
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
CHECK(slice.get("view").isString());
CHECK(view->guid() == slice.get("view").copyString());
CHECK(slice.hasKey("figures"));
CHECK(slice.get("figures").isObject());
CHECK(slice.get("figures").hasKey("memory"));
@ -1017,8 +1017,9 @@ SECTION("test_update_links_partial_remove") {
CHECK(expectedMeta == actualMeta);
auto const slice = builder->slice();
CHECK(slice.hasKey("view"));
CHECK(slice.get("view").isNumber());
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
CHECK(slice.get("view").isString());
CHECK(view->id() == 42);
CHECK(view->guid() == slice.get("view").copyString());
CHECK(slice.hasKey("figures"));
CHECK(slice.get("figures").isObject());
CHECK(slice.get("figures").hasKey("memory"));
@ -1061,8 +1062,9 @@ SECTION("test_update_links_partial_remove") {
CHECK(expectedMeta == actualMeta);
auto const slice = builder->slice();
CHECK(slice.hasKey("view"));
CHECK(slice.get("view").isNumber());
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
CHECK(slice.get("view").isString());
CHECK(view->id() == 42);
CHECK(view->guid() == slice.get("view").copyString());
CHECK(slice.hasKey("figures"));
CHECK(slice.get("figures").isObject());
CHECK(slice.get("figures").hasKey("memory"));
@ -1194,8 +1196,9 @@ SECTION("test_update_links_partial_remove") {
CHECK(expectedMeta == actualMeta);
auto const slice = builder->slice();
CHECK(slice.hasKey("view"));
CHECK(slice.get("view").isNumber());
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
CHECK(slice.get("view").isString());
CHECK(view->id() == 42);
CHECK(view->guid() == slice.get("view").copyString());
CHECK(slice.hasKey("figures"));
CHECK(slice.get("figures").isObject());
CHECK(slice.get("figures").hasKey("memory"));
@ -1239,8 +1242,9 @@ SECTION("test_update_links_partial_remove") {
CHECK(expectedMeta == actualMeta);
auto const slice = builder->slice();
CHECK(slice.hasKey("view"));
CHECK(slice.get("view").isNumber());
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
CHECK(slice.get("view").isString());
CHECK(view->id() == 42);
CHECK(view->guid() == slice.get("view").copyString());
CHECK(slice.hasKey("figures"));
CHECK(slice.get("figures").isObject());
CHECK(slice.get("figures").hasKey("memory"));
@ -1511,8 +1515,9 @@ SECTION("test_update_links_partial_add") {
CHECK(expectedMeta == actualMeta);
auto const slice = builder->slice();
CHECK(slice.hasKey("view"));
CHECK(slice.get("view").isNumber());
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
CHECK(slice.get("view").isString());
CHECK(view->id() == 42);
CHECK(view->guid() == slice.get("view").copyString());
CHECK(slice.hasKey("figures"));
CHECK(slice.get("figures").isObject());
CHECK(slice.get("figures").hasKey("memory"));
@ -1555,8 +1560,9 @@ SECTION("test_update_links_partial_add") {
CHECK(expectedMeta == actualMeta);
auto const slice = builder->slice();
CHECK(slice.hasKey("view"));
CHECK(slice.get("view").isNumber());
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
CHECK(slice.get("view").isString());
CHECK(view->id() == 42);
CHECK(view->guid() == slice.get("view").copyString());
CHECK(slice.hasKey("figures"));
CHECK(slice.get("figures").isObject());
CHECK(slice.get("figures").hasKey("memory"));
@ -1703,8 +1709,9 @@ SECTION("test_update_links_partial_add") {
CHECK(expectedMeta == actualMeta);
auto const slice = builder->slice();
CHECK(slice.hasKey("view"));
CHECK(slice.get("view").isNumber());
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
CHECK(slice.get("view").isString());
CHECK(view->id() == 42);
CHECK(view->guid() == slice.get("view").copyString());
CHECK(slice.hasKey("figures"));
CHECK(slice.get("figures").isObject());
CHECK(slice.get("figures").hasKey("memory"));
@ -1749,8 +1756,9 @@ SECTION("test_update_links_partial_add") {
CHECK(expectedMeta == actualMeta);
auto const slice = builder->slice();
CHECK(slice.hasKey("view"));
CHECK(slice.get("view").isNumber());
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
CHECK(slice.get("view").isString());
CHECK(view->id() == 42);
CHECK(view->guid() == slice.get("view").copyString());
CHECK(slice.hasKey("figures"));
CHECK(slice.get("figures").isObject());
CHECK(slice.get("figures").hasKey("memory"));
@ -1794,8 +1802,9 @@ SECTION("test_update_links_partial_add") {
CHECK(expectedMeta == actualMeta);
auto const slice = builder->slice();
CHECK(slice.hasKey("view"));
CHECK(slice.get("view").isNumber());
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
CHECK(slice.get("view").isString());
CHECK(view->id() == 42);
CHECK(view->guid() == slice.get("view").copyString());
CHECK(slice.hasKey("figures"));
CHECK(slice.get("figures").isObject());
CHECK(slice.get("figures").hasKey("memory"));
@ -2077,8 +2086,9 @@ SECTION("test_update_links_replace") {
CHECK(expectedMeta == actualMeta);
auto const slice = builder->slice();
CHECK(slice.hasKey("view"));
CHECK(slice.get("view").isNumber());
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
CHECK(slice.get("view").isString());
CHECK(view->id() == 42);
CHECK(view->guid() == slice.get("view").copyString());
CHECK(slice.hasKey("figures"));
CHECK(slice.get("figures").isObject());
CHECK(slice.get("figures").hasKey("memory"));
@ -2121,8 +2131,9 @@ SECTION("test_update_links_replace") {
CHECK(expectedMeta == actualMeta);
auto const slice = builder->slice();
CHECK(slice.hasKey("view"));
CHECK(slice.get("view").isNumber());
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
CHECK(slice.get("view").isString());
CHECK(view->id() == 42);
CHECK(view->guid() == slice.get("view").copyString());
CHECK(slice.hasKey("figures"));
CHECK(slice.get("figures").isObject());
CHECK(slice.get("figures").hasKey("memory"));
@ -2251,8 +2262,9 @@ SECTION("test_update_links_replace") {
CHECK(expectedMeta == actualMeta);
auto const slice = builder->slice();
CHECK(slice.hasKey("view"));
CHECK(slice.get("view").isNumber());
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
CHECK(slice.get("view").isString());
CHECK(view->id() == 42);
CHECK(view->guid() == slice.get("view").copyString());
CHECK(slice.hasKey("figures"));
CHECK(slice.get("figures").isObject());
CHECK(slice.get("figures").hasKey("memory"));
@ -2372,8 +2384,9 @@ SECTION("test_update_links_replace") {
CHECK(expectedMeta == actualMeta);
auto const slice = builder->slice();
CHECK(slice.hasKey("view"));
CHECK(slice.get("view").isNumber());
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
CHECK(slice.get("view").isString());
CHECK(view->id() == 42);
CHECK(view->guid() == slice.get("view").copyString());
CHECK(slice.hasKey("figures"));
CHECK(slice.get("figures").isObject());
CHECK(slice.get("figures").hasKey("memory"));
@ -2660,8 +2673,9 @@ SECTION("test_update_links_clear") {
CHECK(expectedMeta == actualMeta);
auto const slice = builder->slice();
CHECK(slice.hasKey("view"));
CHECK(slice.get("view").isNumber());
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
CHECK(slice.get("view").isString());
CHECK(view->id() == 42);
CHECK(view->guid() == slice.get("view").copyString());
CHECK(slice.hasKey("figures"));
CHECK(slice.get("figures").isObject());
CHECK(slice.get("figures").hasKey("memory"));
@ -2706,8 +2720,9 @@ SECTION("test_update_links_clear") {
CHECK(expectedMeta == actualMeta);
auto const slice = builder->slice();
CHECK(slice.hasKey("view"));
CHECK(slice.get("view").isNumber());
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
CHECK(slice.get("view").isString());
CHECK(view->id() == 42);
CHECK(view->guid() == slice.get("view").copyString());
CHECK(slice.hasKey("figures"));
CHECK(slice.get("figures").isObject());
CHECK(slice.get("figures").hasKey("memory"));
@ -2750,8 +2765,9 @@ SECTION("test_update_links_clear") {
CHECK(expectedMeta == actualMeta);
auto const slice = builder->slice();
CHECK(slice.hasKey("view"));
CHECK(slice.get("view").isNumber());
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
CHECK(slice.get("view").isString());
CHECK(view->id() == 42);
CHECK(view->guid() == slice.get("view").copyString());
CHECK(slice.hasKey("figures"));
CHECK(slice.get("figures").isObject());
CHECK(slice.get("figures").hasKey("memory"));
@ -3016,8 +3032,9 @@ SECTION("test_drop_link") {
CHECK(expectedMeta == actualMeta);
auto const slice = builder->slice();
CHECK(slice.hasKey("view"));
CHECK(slice.get("view").isNumber());
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
CHECK(slice.get("view").isString());
CHECK(view->id() == 42);
CHECK(view->guid() == slice.get("view").copyString());
CHECK(slice.hasKey("figures"));
CHECK(slice.get("figures").isObject());
CHECK(slice.get("figures").hasKey("memory"));

View File

@ -990,9 +990,8 @@ void StorageEngineMock::changeCollection(
// NOOP, assume physical collection changed OK
}
void StorageEngineMock::changeView(
arangodb::Result StorageEngineMock::changeView(
TRI_vocbase_t& vocbase,
TRI_voc_cid_t id,
arangodb::LogicalView const& view,
bool doSync
) {
@ -1004,6 +1003,7 @@ void StorageEngineMock::changeView(
view.toVelocyPack(builder, true, true);
builder.close();
views[std::make_pair(vocbase.id(), view.id())] = std::move(builder);
return {};
}
std::string StorageEngineMock::collectionPath(
@ -1092,13 +1092,21 @@ std::unique_ptr<arangodb::TransactionState> StorageEngineMock::createTransaction
);
}
void StorageEngineMock::createView(
arangodb::Result StorageEngineMock::createView(
TRI_vocbase_t& vocbase,
TRI_voc_cid_t id,
arangodb::LogicalView const& view
) {
before();
// NOOP, assume physical view created OK
TRI_ASSERT(views.find(std::make_pair(vocbase.id(), view.id())) == views.end()); // called after createView()
arangodb::velocypack::Builder builder;
builder.openObject();
view.toVelocyPack(builder, true, true);
builder.close();
views[std::make_pair(vocbase.id(), view.id())] = std::move(builder);
return arangodb::Result(TRI_ERROR_NO_ERROR); // assume mock view persisted OK
}
void StorageEngineMock::getViewProperties(
@ -1290,22 +1298,6 @@ arangodb::Result StorageEngineMock::persistCollection(
return arangodb::Result(TRI_ERROR_NO_ERROR); // assume mock collection persisted OK
}
arangodb::Result StorageEngineMock::persistView(
TRI_vocbase_t& vocbase,
arangodb::LogicalView const& view
) {
before();
TRI_ASSERT(views.find(std::make_pair(vocbase.id(), view.id())) == views.end()); // called after createView()
arangodb::velocypack::Builder builder;
builder.openObject();
view.toVelocyPack(builder, true, true);
builder.close();
views[std::make_pair(vocbase.id(), view.id())] = std::move(builder);
return arangodb::Result(TRI_ERROR_NO_ERROR); // assume mock view persisted OK
}
void StorageEngineMock::prepareDropDatabase(
TRI_vocbase_t& vocbase,
bool useWriteMarker,
@ -1345,23 +1337,6 @@ arangodb::Result StorageEngineMock::renameCollection(
return arangodb::Result(TRI_ERROR_INTERNAL);
}
arangodb::Result StorageEngineMock::renameView(
TRI_vocbase_t& vocbase,
arangodb::LogicalView const& view,
std::string const& newName
) {
before();
TRI_ASSERT(views.find(std::make_pair(vocbase.id(), view.id())) != views.end());
arangodb::velocypack::Builder builder;
builder.openObject();
view.toVelocyPack(builder, true, true);
builder.close();
views[std::make_pair(vocbase.id(), view.id())] = std::move(builder);
return arangodb::Result(TRI_ERROR_NO_ERROR); // assume mock view renames OK
}
int StorageEngineMock::saveReplicationApplierConfiguration(
TRI_vocbase_t& vocbase,
arangodb::velocypack::Slice slice,
@ -1554,4 +1529,4 @@ bool TransactionStateMock::hasFailedOperations() const {
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -147,7 +147,7 @@ class StorageEngineMock: public arangodb::StorageEngine {
virtual void addRestHandlers(arangodb::rest::RestHandlerFactory& handlerFactory) override;
virtual void addV8Functions() override;
virtual void changeCollection(TRI_vocbase_t& vocbase, TRI_voc_cid_t id, arangodb::LogicalCollection const& collection, bool doSync) override;
virtual void changeView(TRI_vocbase_t& vocbase, TRI_voc_cid_t id, arangodb::LogicalView const& view, bool doSync) override;
virtual arangodb::Result changeView(TRI_vocbase_t& vocbase, arangodb::LogicalView const& view, bool doSync) override;
virtual std::string collectionPath(TRI_vocbase_t const& vocbase, TRI_voc_cid_t id) const override;
virtual std::string createCollection(TRI_vocbase_t& vocbase, TRI_voc_cid_t id, arangodb::LogicalCollection const& collection) override;
virtual std::unique_ptr<TRI_vocbase_t> createDatabase(TRI_voc_tick_t id, arangodb::velocypack::Slice const& args, int& status) override;
@ -158,7 +158,7 @@ class StorageEngineMock: public arangodb::StorageEngine {
virtual std::unique_ptr<arangodb::transaction::ContextData> createTransactionContextData() override;
virtual std::unique_ptr<arangodb::TransactionManager> createTransactionManager() override;
virtual std::unique_ptr<arangodb::TransactionState> createTransactionState(TRI_vocbase_t& vocbase, arangodb::transaction::Options const& options) override;
virtual void createView(TRI_vocbase_t& vocbase, TRI_voc_cid_t id, arangodb::LogicalView const& view) override;
virtual arangodb::Result createView(TRI_vocbase_t& vocbase, TRI_voc_cid_t id, arangodb::LogicalView const& view) override;
virtual void getViewProperties(TRI_vocbase_t& vocbase, arangodb::LogicalView const& view, VPackBuilder& builder) override;
virtual TRI_voc_tick_t currentTick() const override;
virtual std::string databasePath(TRI_vocbase_t const* vocbase) const override;
@ -181,7 +181,6 @@ class StorageEngineMock: public arangodb::StorageEngine {
virtual double minimumSyncReplicationTimeout() const override { return 1.0; }
virtual std::unique_ptr<TRI_vocbase_t> openDatabase(arangodb::velocypack::Slice const& args, bool isUpgrade, int& status) override;
virtual arangodb::Result persistCollection(TRI_vocbase_t& vocbase, arangodb::LogicalCollection const& collection) override;
virtual arangodb::Result persistView(TRI_vocbase_t& vocbase, arangodb::LogicalView const& view) override;
virtual void prepareDropDatabase(TRI_vocbase_t& vocbase, bool useWriteMarker, int& status) override;
using StorageEngine::registerCollection;
using StorageEngine::registerView;
@ -190,7 +189,6 @@ class StorageEngineMock: public arangodb::StorageEngine {
virtual int removeReplicationApplierConfiguration(TRI_vocbase_t& vocbase) override;
virtual int removeReplicationApplierConfiguration() override;
virtual arangodb::Result renameCollection(TRI_vocbase_t& vocbase, arangodb::LogicalCollection const& collection, std::string const& oldName) override;
virtual arangodb::Result renameView(TRI_vocbase_t& vocbase, arangodb::LogicalView const& view, std::string const& oldName) override;
virtual int saveReplicationApplierConfiguration(TRI_vocbase_t& vocbase, arangodb::velocypack::Slice slice, bool doSync) override;
virtual int saveReplicationApplierConfiguration(arangodb::velocypack::Slice, bool) override;
virtual int shutdownDatabase(TRI_vocbase_t& vocbase) override;
@ -210,4 +208,4 @@ class StorageEngineMock: public arangodb::StorageEngine {
TRI_voc_tick_t _releasedTick;
};
#endif
#endif