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 attribute and this can only be done efficiently if this is the
only shard key by delegating to the individual shards. 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, 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 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. 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() { void auth::TokenCache::generateJwtToken() {
VPackBuilder body; VPackBuilder body;
body.openObject(); body.openObject();

View File

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

View File

@ -348,27 +348,10 @@ void ClusterEngine::unloadCollection(
collection.setStatus(TRI_VOC_COL_STATUS_UNLOADED); collection.setStatus(TRI_VOC_COL_STATUS_UNLOADED);
} }
void ClusterEngine::createView( Result ClusterEngine::createView(
TRI_vocbase_t& vocbase, TRI_vocbase_t& vocbase,
TRI_voc_cid_t id, TRI_voc_cid_t id,
arangodb::LogicalView const& /*view*/ 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; return TRI_ERROR_NOT_IMPLEMENTED;
} }
@ -387,25 +370,16 @@ void ClusterEngine::destroyView(
// nothing to do here // nothing to do here
} }
void ClusterEngine::changeView( Result ClusterEngine::changeView(
TRI_vocbase_t& vocbase, TRI_vocbase_t& vocbase,
TRI_voc_cid_t /*id*/,
arangodb::LogicalView const& view, arangodb::LogicalView const& view,
bool /*doSync*/ bool /*doSync*/
) { ) {
if (inRecovery()) { if (inRecovery()) {
// nothing to do // 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"
);
} }
return TRI_ERROR_NOT_IMPLEMENTED;
} }
void ClusterEngine::signalCleanup(TRI_vocbase_t&) { void ClusterEngine::signalCleanup(TRI_vocbase_t&) {
@ -459,4 +433,4 @@ std::unique_ptr<TRI_vocbase_t> ClusterEngine::openExistingDatabase(
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE // --SECTION-- END-OF-FILE
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -267,14 +267,13 @@ class ClusterEngine final : public StorageEngine {
LogicalCollection& collection LogicalCollection& collection
) override; ) override;
void changeView( arangodb::Result changeView(
TRI_vocbase_t& vocbase, TRI_vocbase_t& vocbase,
TRI_voc_cid_t id,
arangodb::LogicalView const& view, arangodb::LogicalView const& view,
bool doSync bool doSync
) override; ) override;
void createView( arangodb::Result createView(
TRI_vocbase_t& vocbase, TRI_vocbase_t& vocbase,
TRI_voc_cid_t id, TRI_voc_cid_t id,
arangodb::LogicalView const& view arangodb::LogicalView const& view
@ -288,19 +287,6 @@ class ClusterEngine final : public StorageEngine {
// does nothing // 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( arangodb::Result dropView(
TRI_vocbase_t& vocbase, TRI_vocbase_t& vocbase,
LogicalView& view LogicalView& view

View File

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

View File

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

View File

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

View File

@ -190,7 +190,7 @@ class IResearchLink {
friend class IResearchView; friend class IResearchView;
LogicalCollection& _collection; // the linked collection 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) 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 TRI_idx_iid_t const _id; // the index identifier
IResearchLinkMeta _meta; // how this collection should be indexed IResearchLinkMeta _meta; // how this collection should be indexed
@ -202,4 +202,4 @@ class IResearchLink {
NS_END // iresearch NS_END // iresearch
NS_END // arangodb NS_END // arangodb
#endif #endif

View File

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

View File

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

View File

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

View File

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

View File

@ -421,8 +421,6 @@ char const* TRI_NameMarkerDatafile(MMFilesMarkerType type) {
return "create view"; return "create view";
case TRI_DF_MARKER_VPACK_DROP_VIEW: case TRI_DF_MARKER_VPACK_DROP_VIEW:
return "drop view"; return "drop view";
case TRI_DF_MARKER_VPACK_RENAME_VIEW:
return "rename view";
case TRI_DF_MARKER_VPACK_CHANGE_VIEW: case TRI_DF_MARKER_VPACK_CHANGE_VIEW:
return "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_CREATE_VIEW = 80,
TRI_DF_MARKER_VPACK_DROP_VIEW = 81, TRI_DF_MARKER_VPACK_DROP_VIEW = 81,
TRI_DF_MARKER_VPACK_CHANGE_VIEW = 82, TRI_DF_MARKER_VPACK_CHANGE_VIEW = 82,
TRI_DF_MARKER_VPACK_RENAME_VIEW = 83,
TRI_DF_MARKER_MAX // again, this is not a real TRI_DF_MARKER_MAX // again, this is not a real
// marker, but we use it for // 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_DROP_INDEX ||
type == TRI_DF_MARKER_VPACK_CREATE_VIEW || type == TRI_DF_MARKER_VPACK_CREATE_VIEW ||
type == TRI_DF_MARKER_VPACK_DROP_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_CHANGE_VIEW) {
// VPack is located after database id and collection id // VPack is located after database id and collection id
return sizeof(MMFilesMarker) + sizeof(TRI_voc_tick_t) + sizeof(TRI_voc_cid_t); 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_DROP_INDEX ||
type == TRI_DF_MARKER_VPACK_CREATE_VIEW || type == TRI_DF_MARKER_VPACK_CREATE_VIEW ||
type == TRI_DF_MARKER_VPACK_DROP_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_CHANGE_VIEW ||
type == TRI_DF_MARKER_VPACK_CREATE_DATABASE || type == TRI_DF_MARKER_VPACK_CREATE_DATABASE ||
type == TRI_DF_MARKER_VPACK_DROP_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_DROP_INDEX ||
type == TRI_DF_MARKER_VPACK_CREATE_VIEW || type == TRI_DF_MARKER_VPACK_CREATE_VIEW ||
type == TRI_DF_MARKER_VPACK_DROP_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_CHANGE_VIEW ||
type == TRI_DF_MARKER_VPACK_CREATE_DATABASE || type == TRI_DF_MARKER_VPACK_CREATE_DATABASE ||
type == TRI_DF_MARKER_VPACK_DROP_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 { static inline size_t ViewIdOffset(MMFilesMarkerType type) noexcept {
if (type == TRI_DF_MARKER_VPACK_CREATE_VIEW || if (type == TRI_DF_MARKER_VPACK_CREATE_VIEW ||
type == TRI_DF_MARKER_VPACK_DROP_VIEW || type == TRI_DF_MARKER_VPACK_DROP_VIEW ||
type == TRI_DF_MARKER_VPACK_CHANGE_VIEW || type == TRI_DF_MARKER_VPACK_CHANGE_VIEW) {
type == TRI_DF_MARKER_VPACK_RENAME_VIEW) {
return sizeof(MMFilesMarker) + sizeof(TRI_voc_tick_t); return sizeof(MMFilesMarker) + sizeof(TRI_voc_tick_t);
} }
return 0; return 0;
@ -217,8 +213,7 @@ static inline TRI_voc_tick_t ViewId(MMFilesMarker const* marker) noexcept {
MMFilesMarkerType type = marker->getType(); MMFilesMarkerType type = marker->getType();
if (type == TRI_DF_MARKER_VPACK_CREATE_VIEW || if (type == TRI_DF_MARKER_VPACK_CREATE_VIEW ||
type == TRI_DF_MARKER_VPACK_DROP_VIEW || type == TRI_DF_MARKER_VPACK_DROP_VIEW ||
type == TRI_DF_MARKER_VPACK_CHANGE_VIEW || type == TRI_DF_MARKER_VPACK_CHANGE_VIEW) {
type == TRI_DF_MARKER_VPACK_RENAME_VIEW) {
return encoding::readNumber<TRI_voc_cid_t>(reinterpret_cast<uint8_t const*>(marker) + ViewIdOffset(type), sizeof(TRI_voc_cid_t)); return encoding::readNumber<TRI_voc_cid_t>(reinterpret_cast<uint8_t const*>(marker) + ViewIdOffset(type), sizeof(TRI_voc_cid_t));
} }
return 0; return 0;

View File

@ -1238,56 +1238,7 @@ Result MMFilesEngine::renameCollection(
return {res, TRI_errno_string(res)}; return {res, TRI_errno_string(res)};
} }
// asks the storage engine to persist renaming of a view Result MMFilesEngine::createView(
// 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(
TRI_vocbase_t& vocbase, TRI_vocbase_t& vocbase,
TRI_voc_cid_t id, TRI_voc_cid_t id,
arangodb::LogicalView const& view arangodb::LogicalView const& view
@ -1298,7 +1249,7 @@ void MMFilesEngine::createView(
LOG_TOPIC(ERR, arangodb::Logger::FIXME) LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< "cannot create view '" << path << "cannot create view '" << path
<< "', database path is not a directory"; << "', database path is not a directory";
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DATADIR_INVALID); return TRI_ERROR_ARANGO_DATADIR_INVALID;
} }
TRI_ASSERT(id != 0); TRI_ASSERT(id != 0);
@ -1311,9 +1262,7 @@ void MMFilesEngine::createView(
LOG_TOPIC(ERR, arangodb::Logger::FIXME) LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< "cannot create view '" << view.name() << "' in directory '" << "cannot create view '" << view.name() << "' in directory '"
<< dirname << "': directory already exists"; << dirname << "': directory already exists";
THROW_ARANGO_EXCEPTION( return TRI_ERROR_ARANGO_COLLECTION_DIRECTORY_ALREADY_EXISTS;
TRI_ERROR_ARANGO_COLLECTION_DIRECTORY_ALREADY_EXISTS); // TODO: change
// error code
} }
// use a temporary directory first. this saves us from leaving an empty // 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 '" << "cannot create view '" << view.name() << "' in directory '"
<< path << "': " << TRI_errno_string(res) << " - " << systemError << path << "': " << TRI_errno_string(res) << " - " << systemError
<< " - " << errorMessage; << " - " << errorMessage;
THROW_ARANGO_EXCEPTION(res); return res;
} }
TRI_IF_FAILURE("CreateView::tempDirectory") { TRI_IF_FAILURE("CreateView::tempDirectory") {
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG); return TRI_ERROR_DEBUG;
} }
// create a temporary file (.tmp) // create a temporary file (.tmp)
@ -1347,7 +1296,7 @@ void MMFilesEngine::createView(
arangodb::basics::FileUtils::buildFilename(dirname, ".tmp")); arangodb::basics::FileUtils::buildFilename(dirname, ".tmp"));
TRI_IF_FAILURE("CreateView::tempFile") { TRI_IF_FAILURE("CreateView::tempFile") {
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG); return TRI_ERROR_DEBUG;
} }
if (res != TRI_ERROR_NO_ERROR) { if (res != TRI_ERROR_NO_ERROR) {
@ -1356,11 +1305,11 @@ void MMFilesEngine::createView(
<< path << "': " << TRI_errno_string(res) << " - " << systemError << path << "': " << TRI_errno_string(res) << " - " << systemError
<< " - " << errorMessage; << " - " << errorMessage;
TRI_RemoveDirectory(tmpname.c_str()); TRI_RemoveDirectory(tmpname.c_str());
THROW_ARANGO_EXCEPTION(res); return res;
} }
TRI_IF_FAILURE("CreateView::renameDirectory") { TRI_IF_FAILURE("CreateView::renameDirectory") {
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG); return TRI_ERROR_DEBUG;
} }
res = TRI_RenameFile(tmpname.c_str(), dirname.c_str()); res = TRI_RenameFile(tmpname.c_str(), dirname.c_str());
@ -1371,11 +1320,11 @@ void MMFilesEngine::createView(
<< path << "': " << TRI_errno_string(res) << " - " << systemError << path << "': " << TRI_errno_string(res) << " - " << systemError
<< " - " << errorMessage; << " - " << errorMessage;
TRI_RemoveDirectory(tmpname.c_str()); 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 // now we have the directory in place with the correct name
// it // and a .tmp file in it
// delete .tmp file // delete .tmp file
TRI_UnlinkFile(tmpfile2.c_str()); TRI_UnlinkFile(tmpfile2.c_str());
@ -1386,7 +1335,44 @@ void MMFilesEngine::createView(
"Database") "Database")
->forceSyncProperties(); ->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( void MMFilesEngine::getViewProperties(
@ -1398,53 +1384,6 @@ void MMFilesEngine::getViewProperties(
result.add("path", velocypack::Value(viewDirectory(vocbase.id(), view.id()))); 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( arangodb::Result MMFilesEngine::dropView(
TRI_vocbase_t& vocbase, TRI_vocbase_t& vocbase,
LogicalView& view LogicalView& view
@ -1452,7 +1391,7 @@ arangodb::Result MMFilesEngine::dropView(
auto* db = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database"); auto* db = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
TRI_ASSERT(db); TRI_ASSERT(db);
saveViewInfo(&vocbase, view.id(), &view, db->forceSyncProperties()); saveViewInfo(&vocbase, &view, db->forceSyncProperties());
if (inRecovery()) { if (inRecovery()) {
// nothing to do here // nothing to do here
@ -1463,10 +1402,9 @@ arangodb::Result MMFilesEngine::dropView(
try { try {
VPackBuilder builder; VPackBuilder builder;
builder.openObject(); builder.openObject();
builder.add("id", velocypack::Value(std::to_string(view.id()))); builder.add(StaticStrings::DataSourceId, velocypack::Value(std::to_string(view.id())));
builder.add("name", velocypack::Value(view.name())); builder.add("cuid", velocypack::Value(view.guid()));
builder.close(); builder.close();
MMFilesViewMarker marker( 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, arangodb::LogicalView const* view,
bool forceSync) const { bool forceSync) const {
std::string const filename = viewParametersFilename(vocbase->id(), id); std::string const filename = viewParametersFilename(vocbase->id(), view->id());
VPackBuilder builder; VPackBuilder builder;
builder.openObject(); builder.openObject();
@ -1540,14 +1478,11 @@ void MMFilesEngine::saveViewInfo(TRI_vocbase_t* vocbase, TRI_voc_cid_t id,
// fail. // fail.
// the WAL entry for the propery change will be written *after* the call // the WAL entry for the propery change will be written *after* the call
// to "changeView" returns // to "changeView" returns
void MMFilesEngine::changeView( Result MMFilesEngine::changeView(
TRI_vocbase_t& vocbase, TRI_vocbase_t& vocbase,
TRI_voc_cid_t id,
arangodb::LogicalView const& view, arangodb::LogicalView const& view,
bool doSync bool doSync
) { ) {
// FIXME make noexcept and return Result???
if (!inRecovery()) { if (!inRecovery()) {
VPackBuilder infoBuilder; VPackBuilder infoBuilder;
infoBuilder.openObject(); infoBuilder.openObject();
@ -1555,21 +1490,20 @@ void MMFilesEngine::changeView(
infoBuilder.close(); infoBuilder.close();
MMFilesViewMarker marker( 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 = MMFilesWalSlotInfoCopy slotInfo =
MMFilesLogfileManager::instance()->allocateAndWrite(marker, false); MMFilesLogfileManager::instance()->allocateAndWrite(marker, false);
if (slotInfo.errorCode != TRI_ERROR_NO_ERROR) { if (slotInfo.errorCode != TRI_ERROR_NO_ERROR) {
THROW_ARANGO_EXCEPTION_MESSAGE( return Result(slotInfo.errorCode,
slotInfo.errorCode, "could not save view change marker in log");
"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 // 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 LogicalCollection& collection
) override; ) override;
void changeView( arangodb::Result changeView(
TRI_vocbase_t& vocbase, TRI_vocbase_t& vocbase,
TRI_voc_cid_t id,
arangodb::LogicalView const&, arangodb::LogicalView const&,
bool doSync bool doSync
) override; ) override;
void createView( arangodb::Result createView(
TRI_vocbase_t& vocbase, TRI_vocbase_t& vocbase,
TRI_voc_cid_t id, TRI_voc_cid_t id,
arangodb::LogicalView const& view arangodb::LogicalView const& view
@ -371,19 +370,6 @@ class MMFilesEngine final : public StorageEngine {
VPackBuilder& builder VPackBuilder& builder
) override; ) 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( arangodb::Result dropView(
TRI_vocbase_t& vocbase, TRI_vocbase_t& vocbase,
LogicalView& view LogicalView& view
@ -397,8 +383,7 @@ class MMFilesEngine final : public StorageEngine {
std::string createViewDirectoryName(std::string const& basePath, std::string createViewDirectoryName(std::string const& basePath,
TRI_voc_cid_t id); TRI_voc_cid_t id);
void saveViewInfo(TRI_vocbase_t* vocbase, TRI_voc_cid_t id, void saveViewInfo(TRI_vocbase_t* vocbase, arangodb::LogicalView const*, bool sync) const;
arangodb::LogicalView const*, bool forceSync) const;
void signalCleanup(TRI_vocbase_t& vocbase) override; void signalCleanup(TRI_vocbase_t& vocbase) override;

View File

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

View File

@ -787,86 +787,6 @@ bool MMFilesWalRecoverState::ReplayMarker(MMFilesMarker const* marker,
break; 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: { case TRI_DF_MARKER_VPACK_CHANGE_VIEW: {
TRI_voc_tick_t const databaseId = TRI_voc_tick_t const databaseId =
MMFilesDatafileHelper::DatabaseId(marker); 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 // turn off sync temporarily if the database or collection are going to
// be // be dropped later
// dropped later
bool const forceSync = state->willViewBeDropped(databaseId, viewId); 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); auto res = view->updateProperties(payloadSlice, false, forceSync);
if (!res.ok()) { if (!res.ok()) {
LOG_TOPIC(WARN, arangodb::Logger::ENGINES) LOG_TOPIC(WARN, arangodb::Logger::ENGINES)
<< "cannot change properties for view " << viewId << "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_DROP_DATABASE)) ||
type == TRI_DF_MARKER_VPACK_CREATE_VIEW || type == TRI_DF_MARKER_VPACK_CREATE_VIEW ||
type == TRI_DF_MARKER_VPACK_DROP_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_CHANGE_VIEW);
} }
@ -90,8 +89,6 @@ TRI_replication_operation_e TranslateType(MMFilesMarker const* marker) {
return REPLICATION_VIEW_CREATE; return REPLICATION_VIEW_CREATE;
case TRI_DF_MARKER_VPACK_DROP_VIEW: case TRI_DF_MARKER_VPACK_DROP_VIEW:
return REPLICATION_VIEW_DROP; return REPLICATION_VIEW_DROP;
case TRI_DF_MARKER_VPACK_RENAME_VIEW:
return REPLICATION_VIEW_RENAME;
case TRI_DF_MARKER_VPACK_CHANGE_VIEW: case TRI_DF_MARKER_VPACK_CHANGE_VIEW:
return REPLICATION_VIEW_CHANGE; 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_CREATE_VIEW:
case TRI_DF_MARKER_VPACK_RENAME_COLLECTION: case TRI_DF_MARKER_VPACK_RENAME_COLLECTION:
case TRI_DF_MARKER_VPACK_CHANGE_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_CHANGE_VIEW:
case TRI_DF_MARKER_VPACK_DROP_DATABASE: case TRI_DF_MARKER_VPACK_DROP_DATABASE:
case TRI_DF_MARKER_VPACK_DROP_COLLECTION: 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_CREATE_VIEW:
case TRI_DF_MARKER_VPACK_RENAME_COLLECTION: case TRI_DF_MARKER_VPACK_RENAME_COLLECTION:
case TRI_DF_MARKER_VPACK_CHANGE_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_CHANGE_VIEW:
case TRI_DF_MARKER_VPACK_DROP_DATABASE: case TRI_DF_MARKER_VPACK_DROP_DATABASE:
case TRI_DF_MARKER_VPACK_DROP_COLLECTION: case TRI_DF_MARKER_VPACK_DROP_COLLECTION:

View File

@ -49,6 +49,7 @@
#include "Utils/CollectionGuard.h" #include "Utils/CollectionGuard.h"
#include "Utils/OperationOptions.h" #include "Utils/OperationOptions.h"
#include "VocBase/LogicalCollection.h" #include "VocBase/LogicalCollection.h"
#include "VocBase/LogicalView.h"
#include "VocBase/ManagedDocumentResult.h" #include "VocBase/ManagedDocumentResult.h"
#include "VocBase/voc-types.h" #include "VocBase/voc-types.h"
#include "VocBase/vocbase.h" #include "VocBase/vocbase.h"
@ -129,7 +130,7 @@ DatabaseInitialSyncer::DatabaseInitialSyncer(
/// @brief run method, performs a full synchronization /// @brief run method, performs a full synchronization
Result DatabaseInitialSyncer::runWithInventory(bool incremental, Result DatabaseInitialSyncer::runWithInventory(bool incremental,
VPackSlice inventoryColls) { VPackSlice dbInventory) {
if (!_config.connection.valid()) { if (!_config.connection.valid()) {
return Result(TRI_ERROR_INTERNAL, "invalid endpoint"); return Result(TRI_ERROR_INTERNAL, "invalid endpoint");
} }
@ -196,23 +197,38 @@ Result DatabaseInitialSyncer::runWithInventory(bool incremental,
} }
} }
VPackBuilder inventoryResponse; VPackSlice collections, views;
if (!inventoryColls.isArray()) { 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 // caller did not supply an inventory, we need to fetch it
Result res = fetchInventory(inventoryResponse); Result res = fetchInventory(inventoryResponse);
if (!res.ok()) { if (!res.ok()) {
return res; return res;
} }
// we do not really care about the state response // we do not really care about the state response
inventoryColls = inventoryResponse.slice().get("collections"); collections = inventoryResponse.slice().get("collections");
if (!inventoryColls.isArray()) { views = inventoryResponse.slice().get("views");
if (!collections.isArray()) {
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE, return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
"collections section is missing from 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 // strip eventual objectIDs and then dump the collections
auto pair = rocksutils::stripObjectIds(inventoryColls); auto pair = rocksutils::stripObjectIds(collections);
r = handleLeaderCollections(pair.first, incremental); r = handleLeaderCollections(pair.first, incremental);
// all done here, do not try to finish batch if master is unresponsive // all done here, do not try to finish batch if master is unresponsive
@ -1475,5 +1491,16 @@ Result DatabaseInitialSyncer::iterateCollections(
// all ok // all ok
return Result(); 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 } // namespace arangodb

View File

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

View File

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

View File

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

View File

@ -45,6 +45,7 @@
#include "Utils/OperationResult.h" #include "Utils/OperationResult.h"
#include "Utils/SingleCollectionTransaction.h" #include "Utils/SingleCollectionTransaction.h"
#include "VocBase/LogicalCollection.h" #include "VocBase/LogicalCollection.h"
#include "VocBase/LogicalView.h"
#include "VocBase/voc-types.h" #include "VocBase/voc-types.h"
#include "VocBase/vocbase.h" #include "VocBase/vocbase.h"
@ -442,8 +443,8 @@ std::shared_ptr<LogicalCollection> Syncer::resolveCollection(
} }
if (cid == 0) { if (cid == 0) {
LOG_TOPIC(ERR, Logger::REPLICATION) LOG_TOPIC(ERR, Logger::REPLICATION) << "Invalid replication response: Was unable to resolve"
<< TRI_errno_string(TRI_ERROR_REPLICATION_INVALID_RESPONSE); << " collection from marker: " << slice.toJson();
return nullptr; return nullptr;
} }
@ -525,7 +526,7 @@ Result Syncer::createCollection(TRI_vocbase_t& vocbase,
bool forceRemoveCid = false; bool forceRemoveCid = false;
if (col != nullptr && _state.master.simulate32Client()) { if (col != nullptr && _state.master.simulate32Client()) {
forceRemoveCid = true; forceRemoveCid = true;
LOG_TOPIC(TRACE, Logger::REPLICATION) LOG_TOPIC(INFO, Logger::REPLICATION)
<< "would have got a wrong collection!"; << "would have got a wrong collection!";
// go on now and truncate or drop/re-create the 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 // merge in "isSystem" attribute, doesn't matter if name does not start with
// '_' // '_'
VPackBuilder s; 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 // 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 // use this id so we can discard the "cid" and "id" values for the
// collection // collection
s.add("id", VPackSlice::nullSlice()); s.add(StaticStrings::DataSourceId, VPackSlice::nullSlice());
s.add("cid", VPackSlice::nullSlice()); s.add("cid", VPackSlice::nullSlice());
} }
@ -751,6 +752,103 @@ Result Syncer::dropIndex(arangodb::velocypack::Slice const& slice) {
return r; 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() { void Syncer::reloadUsers() {
AuthenticationFeature* af = AuthenticationFeature::instance(); 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 /// @brief drops an index, based on the VelocyPack provided
Result dropIndex(arangodb::velocypack::Slice const&); 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 // TODO worker safety
virtual TRI_vocbase_t* resolveVocbase(velocypack::Slice const&); virtual TRI_vocbase_t* resolveVocbase(velocypack::Slice const&);

View File

@ -45,6 +45,7 @@
#include "Utils/CollectionGuard.h" #include "Utils/CollectionGuard.h"
#include "Utils/SingleCollectionTransaction.h" #include "Utils/SingleCollectionTransaction.h"
#include "VocBase/LogicalCollection.h" #include "VocBase/LogicalCollection.h"
#include "VocBase/LogicalView.h"
#include "VocBase/Methods/Databases.h" #include "VocBase/Methods/Databases.h"
#include "VocBase/voc-types.h" #include "VocBase/voc-types.h"
#include "VocBase/vocbase.h" #include "VocBase/vocbase.h"
@ -621,8 +622,8 @@ Result TailingSyncer::renameCollection(VPackSlice const& slice) {
return Result(vocbase->renameCollection(col, name, true)); return Result(vocbase->renameCollection(col, name, true));
} }
/// @brief changes the properties of a collection, based on the VelocyPack /// @brief changes the properties of a collection,
/// provided /// based on the VelocyPack provided
Result TailingSyncer::changeCollection(VPackSlice const& slice) { Result TailingSyncer::changeCollection(VPackSlice const& slice) {
if (!slice.isObject()) { if (!slice.isObject()) {
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE, return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
@ -672,6 +673,66 @@ Result TailingSyncer::changeCollection(VPackSlice const& slice) {
return guard.collection()->updateProperties(data, doSync); 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 /// @brief apply a single marker from the continuous log
Result TailingSyncer::applyLogMarker(VPackSlice const& slice, Result TailingSyncer::applyLogMarker(VPackSlice const& slice,
TRI_voc_tick_t firstRegularTick) { TRI_voc_tick_t firstRegularTick) {
@ -764,16 +825,35 @@ Result TailingSyncer::applyLogMarker(VPackSlice const& slice,
return createIndex(slice); return createIndex(slice);
} else if (type == REPLICATION_INDEX_DROP) { } else if (type == REPLICATION_INDEX_DROP) {
return dropIndex(slice); 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) { } else if (type == REPLICATION_VIEW_DROP) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_NOT_IMPLEMENTED, if (_ignoreRenameCreateDrop) {
"view drop not yet implemented"); LOG_TOPIC(DEBUG, Logger::REPLICATION) << "Ignoring view drop marker";
return TRI_ERROR_NO_ERROR;
}
return dropView(slice, false);
} else if (type == REPLICATION_VIEW_CHANGE) { } else if (type == REPLICATION_VIEW_CHANGE) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_NOT_IMPLEMENTED, return changeView(slice);
"view change not yet implemented"); }
} else if (type == REPLICATION_DATABASE_CREATE ||
else if (type == REPLICATION_DATABASE_CREATE ||
type == REPLICATION_DATABASE_DROP) { type == REPLICATION_DATABASE_DROP) {
if (_ignoreDatabaseMarkers) { if (_ignoreDatabaseMarkers) {
LOG_TOPIC(DEBUG, Logger::REPLICATION) << "Ignoring database marker"; 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 /// @brief renames a collection, based on the VelocyPack provided
Result renameCollection(arangodb::velocypack::Slice const&); Result renameCollection(arangodb::velocypack::Slice const&);
/// @brief changes the properties of a collection, based on the VelocyPack /// @brief changes the properties of a collection,
/// provided /// based on the VelocyPack provided
Result changeCollection(arangodb::velocypack::Slice const&); 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 /// @brief apply a single marker from the continuous log
Result applyLogMarker(arangodb::velocypack::Slice const&, TRI_voc_tick_t); Result applyLogMarker(arangodb::velocypack::Slice const&, TRI_voc_tick_t);

View File

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

View File

@ -1333,68 +1333,31 @@ void RocksDBEngine::unloadCollection(
collection.setStatus(TRI_VOC_COL_STATUS_UNLOADED); collection.setStatus(TRI_VOC_COL_STATUS_UNLOADED);
} }
void RocksDBEngine::createView( Result RocksDBEngine::createView(
TRI_vocbase_t& vocbase, TRI_vocbase_t& vocbase,
TRI_voc_cid_t id, TRI_voc_cid_t id,
arangodb::LogicalView const& /*view*/ arangodb::LogicalView const& view
) { ) {
rocksdb::WriteBatch batch; rocksdb::WriteBatch batch;
rocksdb::WriteOptions wo; rocksdb::WriteOptions wo;
RocksDBLogValue logValue = RocksDBLogValue::ViewCreate(vocbase.id(), id);
RocksDBKey key; RocksDBKey key;
key.constructView(vocbase.id(), id); 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 // Write marker + key into RocksDB inside one batch
batch.PutLogData(logValue.slice()); batch.PutLogData(logValue.slice());
batch.Put(RocksDBColumnFamily::definitions(), key.string(), value.string()); batch.Put(RocksDBColumnFamily::definitions(), key.string(), value.string());
auto res = _db->Write(wo, &batch); auto res = _db->Write(wo, &batch);
auto status = rocksutils::convertStatus(res); return rocksutils::convertStatus(res);
if (!status.ok()) {
THROW_ARANGO_EXCEPTION(status);
}
} }
// 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( arangodb::Result RocksDBEngine::dropView(
TRI_vocbase_t& vocbase, TRI_vocbase_t& vocbase,
LogicalView& view LogicalView& view
@ -1406,9 +1369,9 @@ arangodb::Result RocksDBEngine::dropView(
builder.close(); builder.close();
auto logValue = auto logValue =
RocksDBLogValue::ViewDrop(vocbase.id(), view.id(), builder.slice()); RocksDBLogValue::ViewDrop(vocbase.id(), view.id(),
StringRef(view.guid()));
RocksDBKey key; RocksDBKey key;
key.constructView(vocbase.id(), view.id()); key.constructView(vocbase.id(), view.id());
rocksdb::WriteBatch batch; rocksdb::WriteBatch batch;
@ -1428,25 +1391,41 @@ void RocksDBEngine::destroyView(
// nothing to do here // nothing to do here
} }
void RocksDBEngine::changeView( Result RocksDBEngine::changeView(
TRI_vocbase_t& vocbase, TRI_vocbase_t& vocbase,
TRI_voc_cid_t /*id*/,
arangodb::LogicalView const& view, arangodb::LogicalView const& view,
bool /*doSync*/ bool /*doSync*/
) { ) {
if (inRecovery()) { if (inRecovery()) {
// nothing to do // nothing to do
return; return {};
} }
auto const res = persistView(vocbase, view); RocksDBKey key;
key.constructView(vocbase.id(), view.id());
if (!res.ok()) {
THROW_ARANGO_EXCEPTION_MESSAGE( VPackBuilder infoBuilder;
res.errorNumber(), infoBuilder.openObject();
"could not save view properties" 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) { void RocksDBEngine::signalCleanup(TRI_vocbase_t& vocbase) {

View File

@ -269,14 +269,13 @@ class RocksDBEngine final : public StorageEngine {
LogicalCollection& collection LogicalCollection& collection
) override; ) override;
void changeView( arangodb::Result changeView(
TRI_vocbase_t& vocbase, TRI_vocbase_t& vocbase,
TRI_voc_cid_t id,
arangodb::LogicalView const& view, arangodb::LogicalView const& view,
bool doSync bool doSync
) override; ) override;
void createView( arangodb::Result createView(
TRI_vocbase_t& vocbase, TRI_vocbase_t& vocbase,
TRI_voc_cid_t id, TRI_voc_cid_t id,
arangodb::LogicalView const& view arangodb::LogicalView const& view
@ -290,19 +289,6 @@ class RocksDBEngine final : public StorageEngine {
// does nothing // 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( arangodb::Result dropView(
TRI_vocbase_t& vocbase, TRI_vocbase_t& vocbase,
LogicalView& view LogicalView& view

View File

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

View File

@ -64,9 +64,8 @@ class RocksDBLogValue {
static RocksDBLogValue ViewCreate(TRI_voc_tick_t, TRI_voc_cid_t); static RocksDBLogValue ViewCreate(TRI_voc_tick_t, TRI_voc_cid_t);
static RocksDBLogValue ViewDrop(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 ViewChange(TRI_voc_tick_t, TRI_voc_cid_t);
static RocksDBLogValue ViewRename(TRI_voc_tick_t, TRI_voc_cid_t);
#ifdef USE_IRESEARCH #ifdef USE_IRESEARCH
static RocksDBLogValue IResearchLinkDrop(TRI_voc_tick_t, TRI_voc_cid_t, 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 collectionId(rocksdb::Slice const&);
static TRI_voc_cid_t viewId(rocksdb::Slice const&); static TRI_voc_cid_t viewId(rocksdb::Slice const&);
static TRI_idx_iid_t indexId(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 TRI_voc_rid_t revisionId(rocksdb::Slice const&);
static velocypack::Slice indexSlice(rocksdb::Slice const&); static velocypack::Slice indexSlice(rocksdb::Slice const&);
static velocypack::Slice viewSlice(rocksdb::Slice const&); static velocypack::Slice viewSlice(rocksdb::Slice const&);
/// @brief get UUID from collection drop marker
static arangodb::StringRef collectionUUID(rocksdb::Slice const&); 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 arangodb::StringRef oldCollectionName(rocksdb::Slice const&);
static bool containsDatabaseId(RocksDBLogType type); static bool containsDatabaseId(RocksDBLogType type);
@ -107,10 +111,6 @@ class RocksDBLogValue {
/// @brief Returns a reference to the underlying string buffer. /// @brief Returns a reference to the underlying string buffer.
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
std::string const& string() const { return _buffer; } // to be used with put 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 { RocksDBLogType type() const {
return static_cast<RocksDBLogType>(*(_buffer.data())); return static_cast<RocksDBLogType>(*(_buffer.data()));
} }

View File

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

View File

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

View File

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

View File

@ -31,6 +31,7 @@
#include "RocksDBEngine/RocksDBTypes.h" #include "RocksDBEngine/RocksDBTypes.h"
#include "Utils/DatabaseGuard.h" #include "Utils/DatabaseGuard.h"
#include "VocBase/LogicalCollection.h" #include "VocBase/LogicalCollection.h"
#include "VocBase/LogicalView.h"
#include "Logger/Logger.h" #include "Logger/Logger.h"
@ -88,15 +89,12 @@ class MyWALParser : public rocksdb::WriteBatch::Handler, public WalAccessContext
DB_CREATE, DB_CREATE,
DB_DROP, DB_DROP,
COLLECTION_CREATE, COLLECTION_CREATE,
COLLECTION_DROP,
COLLECTION_RENAME, COLLECTION_RENAME,
COLLECTION_CHANGE, COLLECTION_CHANGE,
INDEX_CREATE, INDEX_CREATE,
INDEX_DROP, INDEX_DROP,
VIEW_CREATE, VIEW_CREATE,
VIEW_DROP,
VIEW_CHANGE, VIEW_CHANGE,
VIEW_RENAME,
TRANSACTION, TRANSACTION,
SINGLE_PUT, SINGLE_PUT,
SINGLE_REMOVE SINGLE_REMOVE
@ -165,7 +163,7 @@ class MyWALParser : public rocksdb::WriteBatch::Handler, public WalAccessContext
TRI_vocbase_t* vocbase = loadVocbase(dbid); TRI_vocbase_t* vocbase = loadVocbase(dbid);
if (vocbase != nullptr) { if (vocbase != nullptr) {
{ // tick number { // tick number
StringRef uuid = RocksDBLogValue::collectionUUID(blob); StringRef uuid = RocksDBLogValue::viewUUID(blob);
TRI_ASSERT(!uuid.empty()); TRI_ASSERT(!uuid.empty());
uint64_t tick = _currentSequence + (_startOfBatch ? 0 : 1); uint64_t tick = _currentSequence + (_startOfBatch ? 0 : 1);
VPackObjectBuilder marker(&_builder, true); VPackObjectBuilder marker(&_builder, true);
@ -245,17 +243,53 @@ class MyWALParser : public rocksdb::WriteBatch::Handler, public WalAccessContext
_responseSize += _builder.size(); _responseSize += _builder.size();
_builder.clear(); _builder.clear();
} }
break; break;
} }
case RocksDBLogType::ViewCreate: case RocksDBLogType::ViewCreate:
case RocksDBLogType::ViewDrop:
case RocksDBLogType::ViewChange:
case RocksDBLogType::ViewRename: {
resetTransientState(); // finish ongoing trx 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; 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: { case RocksDBLogType::BeginTransaction: {
resetTransientState(); // finish ongoing trx resetTransientState(); // finish ongoing trx
TRI_voc_tid_t tid = RocksDBLogValue::transactionId(blob); TRI_voc_tid_t tid = RocksDBLogValue::transactionId(blob);
@ -329,7 +363,8 @@ class MyWALParser : public rocksdb::WriteBatch::Handler, public WalAccessContext
} }
break; break;
} }
case RocksDBLogType::IResearchLinkDrop: // do nothing
case RocksDBLogType::DocumentOperationsPrologue: case RocksDBLogType::DocumentOperationsPrologue:
case RocksDBLogType::DocumentRemove: case RocksDBLogType::DocumentRemove:
case RocksDBLogType::DocumentRemoveAsPartOfUpdate: case RocksDBLogType::DocumentRemoveAsPartOfUpdate:
@ -428,7 +463,38 @@ class MyWALParser : public rocksdb::WriteBatch::Handler, public WalAccessContext
_responseSize += _builder.size(); _responseSize += _builder.size();
_builder.clear(); _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 // reset everything immediately after DDL operations
resetTransientState(); 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. // 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 // the WAL entry for the propery change will be written *after* the call
// to "changeView" returns // to "changeView" returns
virtual void changeView( virtual arangodb::Result changeView(
TRI_vocbase_t& vocbase, TRI_vocbase_t& vocbase,
TRI_voc_cid_t id,
arangodb::LogicalView const& view, arangodb::LogicalView const& view,
bool doSync bool doSync
) = 0; ) = 0;
@ -341,7 +340,7 @@ class StorageEngine : public application_features::ApplicationFeature {
// and throw only then, so that subsequent view creation requests will not fail. // 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 // the WAL entry for the view creation will be written *after* the call
// to "createCview" returns // to "createCview" returns
virtual void createView( virtual arangodb::Result createView(
TRI_vocbase_t& vocbase, TRI_vocbase_t& vocbase,
TRI_voc_cid_t id, TRI_voc_cid_t id,
arangodb::LogicalView const& view arangodb::LogicalView const& view
@ -355,20 +354,6 @@ class StorageEngine : public application_features::ApplicationFeature {
VPackBuilder& builder VPackBuilder& builder
) = 0; ) = 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 // asks the storage engine to drop the specified view and persist the
// deletion info. Note that physical deletion of the view data must not // deletion info. Note that physical deletion of the view data must not
// be carried out by this call, as there may // 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; 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 /// @brief Check if collection is in filter, will load collection
bool WalAccessContext::shouldHandleCollection(TRI_voc_tick_t dbid, bool WalAccessContext::shouldHandleCollection(TRI_voc_tick_t dbid,
TRI_voc_cid_t cid) { TRI_voc_cid_t cid) {

View File

@ -143,6 +143,10 @@ struct WalAccessContext {
/// @brief check if db should be handled, might already be deleted /// @brief check if db should be handled, might already be deleted
bool shouldHandleDB(TRI_voc_tick_t dbid) const; 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 /// @brief Check if collection is in filter, will load collection
/// and prevent deletion /// and prevent deletion

View File

@ -23,6 +23,8 @@
#include <mutex> #include <mutex>
#include "LogicalDataSource.h"
#include "Basics/conversions.h" #include "Basics/conversions.h"
#include "Basics/VelocyPackHelper.h" #include "Basics/VelocyPackHelper.h"
#include "Cluster/ClusterInfo.h" #include "Cluster/ClusterInfo.h"
@ -33,7 +35,8 @@
#include "VocBase/LogicalCollection.h" #include "VocBase/LogicalCollection.h"
#include "VocBase/ticks.h" #include "VocBase/ticks.h"
#include "LogicalDataSource.h" //
#include "Logger/Logger.h"
namespace { namespace {
@ -50,25 +53,26 @@ std::string ensureGuid(
guid.reserve(64); 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); TRI_ASSERT(planId);
guid.append("c"); guid.append("c");
guid.append(std::to_string(planId)); 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.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) { } else if (isSystem) {
guid.append(name); guid.append(name);
} else { } else {
char buf[sizeof(TRI_server_id_t) * 2 + 1]; char buf[sizeof(TRI_server_id_t) * 2 + 1];
auto len = auto len = TRI_StringUInt64HexInPlace(arangodb::ServerIdFeature::getId(), buf);
TRI_StringUInt64HexInPlace(arangodb::ServerIdFeature::getId(), buf);
TRI_ASSERT(id); TRI_ASSERT(id);
guid.append("h"); guid.append("h");
guid.append(buf, len); guid.append(buf, len);

View File

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

View File

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

View File

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

View File

@ -82,6 +82,7 @@ const compare = function(masterFunc, masterFunc2, slaveFuncOngoing, slaveFuncFin
applierConfiguration.username = "root"; applierConfiguration.username = "root";
applierConfiguration.password = ""; applierConfiguration.password = "";
applierConfiguration.includeSystem = false; applierConfiguration.includeSystem = false;
applierConfiguration.force32mode = false;
var syncResult = replication.syncGlobal({ var syncResult = replication.syncGlobal({
endpoint: masterEndpoint, endpoint: masterEndpoint,
@ -635,6 +636,124 @@ function BaseTestConfig() {
assertEqual(state.count, collectionCount(cn)); 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() { suite.tearDown = function() {
connectToMaster(); connectToMaster();
db._dropView("UnitTestsSyncView");
db._dropView("UnitTestsSyncViewRenamed");
db._drop(cn); db._drop(cn);
db._drop(cn2); db._drop(cn2);
@ -682,6 +803,8 @@ function ReplicationSuite() {
replication.globalApplier.stop(); replication.globalApplier.stop();
replication.globalApplier.forget(); replication.globalApplier.forget();
db._dropView("UnitTestsSyncView");
db._dropView("UnitTestsSyncViewRenamed");
db._drop(cn); db._drop(cn);
db._drop(cn2); db._drop(cn2);
db._drop(cn + "Renamed"); db._drop(cn + "Renamed");

View File

@ -97,6 +97,7 @@ const compare = function(masterFunc, masterFunc2, slaveFuncOngoing, slaveFuncFin
applierConfiguration.endpoint = masterEndpoint; applierConfiguration.endpoint = masterEndpoint;
applierConfiguration.username = "root"; applierConfiguration.username = "root";
applierConfiguration.password = ""; applierConfiguration.password = "";
applierConfiguration.force32mode = false;
if (!applierConfiguration.hasOwnProperty('chunkSize')) { if (!applierConfiguration.hasOwnProperty('chunkSize')) {
applierConfiguration.chunkSize = 16384; applierConfiguration.chunkSize = 16384;
@ -632,6 +633,124 @@ function BaseTestConfig() {
assertEqual(state.count, collectionCount(cn)); 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() { suite.tearDown = function() {
connectToMaster(); connectToMaster();
db._dropView("UnitTestsSyncView");
db._dropView("UnitTestsSyncViewRenamed");
db._drop(cn); db._drop(cn);
db._drop(cn2); db._drop(cn2);
@ -679,6 +800,8 @@ function ReplicationSuite() {
replication.applier.stop(); replication.applier.stop();
replication.applier.forget(); replication.applier.forget();
db._dropView("UnitTestsSyncView");
db._dropView("UnitTestsSyncViewRenamed");
db._drop(cn); db._drop(cn);
db._drop(cn2); db._drop(cn2);
db._drop(cn + "Renamed"); db._drop(cn + "Renamed");

View File

@ -2021,6 +2021,38 @@ function BaseTestConfig() {
restrictCollections: [cn2] 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 #define ARANGO_READ_WRITE_SPIN_LOCK_H 1
#include "Basics/Common.h" #include "Basics/Common.h"
#include "Basics/SharedAtomic.h"
#include "Basics/SharedCounter.h"
#include "Basics/cpu-relax.h" #include "Basics/cpu-relax.h"
#include <atomic> #include <atomic>

View File

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

View File

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

View File

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

View File

@ -990,9 +990,8 @@ void StorageEngineMock::changeCollection(
// NOOP, assume physical collection changed OK // NOOP, assume physical collection changed OK
} }
void StorageEngineMock::changeView( arangodb::Result StorageEngineMock::changeView(
TRI_vocbase_t& vocbase, TRI_vocbase_t& vocbase,
TRI_voc_cid_t id,
arangodb::LogicalView const& view, arangodb::LogicalView const& view,
bool doSync bool doSync
) { ) {
@ -1004,6 +1003,7 @@ void StorageEngineMock::changeView(
view.toVelocyPack(builder, true, true); view.toVelocyPack(builder, true, true);
builder.close(); builder.close();
views[std::make_pair(vocbase.id(), view.id())] = std::move(builder); views[std::make_pair(vocbase.id(), view.id())] = std::move(builder);
return {};
} }
std::string StorageEngineMock::collectionPath( 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_vocbase_t& vocbase,
TRI_voc_cid_t id, TRI_voc_cid_t id,
arangodb::LogicalView const& view arangodb::LogicalView const& view
) { ) {
before(); 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( void StorageEngineMock::getViewProperties(
@ -1290,22 +1298,6 @@ arangodb::Result StorageEngineMock::persistCollection(
return arangodb::Result(TRI_ERROR_NO_ERROR); // assume mock collection persisted OK 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( void StorageEngineMock::prepareDropDatabase(
TRI_vocbase_t& vocbase, TRI_vocbase_t& vocbase,
bool useWriteMarker, bool useWriteMarker,
@ -1345,23 +1337,6 @@ arangodb::Result StorageEngineMock::renameCollection(
return arangodb::Result(TRI_ERROR_INTERNAL); 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( int StorageEngineMock::saveReplicationApplierConfiguration(
TRI_vocbase_t& vocbase, TRI_vocbase_t& vocbase,
arangodb::velocypack::Slice slice, arangodb::velocypack::Slice slice,
@ -1554,4 +1529,4 @@ bool TransactionStateMock::hasFailedOperations() const {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE // --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 addRestHandlers(arangodb::rest::RestHandlerFactory& handlerFactory) override;
virtual void addV8Functions() 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 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 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::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; 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::transaction::ContextData> createTransactionContextData() override;
virtual std::unique_ptr<arangodb::TransactionManager> createTransactionManager() 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 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 void getViewProperties(TRI_vocbase_t& vocbase, arangodb::LogicalView const& view, VPackBuilder& builder) override;
virtual TRI_voc_tick_t currentTick() const override; virtual TRI_voc_tick_t currentTick() const override;
virtual std::string databasePath(TRI_vocbase_t const* vocbase) 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 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 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 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; virtual void prepareDropDatabase(TRI_vocbase_t& vocbase, bool useWriteMarker, int& status) override;
using StorageEngine::registerCollection; using StorageEngine::registerCollection;
using StorageEngine::registerView; using StorageEngine::registerView;
@ -190,7 +189,6 @@ class StorageEngineMock: public arangodb::StorageEngine {
virtual int removeReplicationApplierConfiguration(TRI_vocbase_t& vocbase) override; virtual int removeReplicationApplierConfiguration(TRI_vocbase_t& vocbase) override;
virtual int removeReplicationApplierConfiguration() 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 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(TRI_vocbase_t& vocbase, arangodb::velocypack::Slice slice, bool doSync) override;
virtual int saveReplicationApplierConfiguration(arangodb::velocypack::Slice, bool) override; virtual int saveReplicationApplierConfiguration(arangodb::velocypack::Slice, bool) override;
virtual int shutdownDatabase(TRI_vocbase_t& vocbase) override; virtual int shutdownDatabase(TRI_vocbase_t& vocbase) override;
@ -210,4 +208,4 @@ class StorageEngineMock: public arangodb::StorageEngine {
TRI_voc_tick_t _releasedTick; TRI_voc_tick_t _releasedTick;
}; };
#endif #endif