mirror of https://gitee.com/bigwinds/arangodb
View Replication (#5915)
This commit is contained in:
parent
939c4bc820
commit
2dd8593609
|
@ -83,7 +83,7 @@ to the [naming conventions](../NamingConventions/README.md).
|
|||
attribute and this can only be done efficiently if this is the
|
||||
only shard key by delegating to the individual shards.
|
||||
|
||||
*cacheEnabled* (optional, default is *false*, **rocksdb-only**, from v. 3.4): Enable in-memory
|
||||
*cacheEnabled* (optional, default is *false*, **rocksdb-only**, from v.3.4): Enable in-memory
|
||||
caching for documents and primary index entries. This can potentially speed up point-lookups significantly,
|
||||
especially if your collection has a subset of frequently accessed keys. Please test this feature
|
||||
carefully to ensure that it does not adversely affect the performance of your system.
|
||||
|
|
|
@ -402,6 +402,7 @@ std::string auth::TokenCache::generateJwt(VPackSlice const& payload) const {
|
|||
}
|
||||
}
|
||||
|
||||
/// generate a JWT token for internal cluster communication
|
||||
void auth::TokenCache::generateJwtToken() {
|
||||
VPackBuilder body;
|
||||
body.openObject();
|
||||
|
|
|
@ -519,6 +519,7 @@ void ClusterInfo::loadPlan() {
|
|||
views.reserve(views.size() + 2);
|
||||
views[viewId] = view;
|
||||
views[view->name()] = view;
|
||||
views[view->guid()] = view;
|
||||
return true;
|
||||
};
|
||||
|
||||
|
|
|
@ -348,27 +348,10 @@ void ClusterEngine::unloadCollection(
|
|||
collection.setStatus(TRI_VOC_COL_STATUS_UNLOADED);
|
||||
}
|
||||
|
||||
void ClusterEngine::createView(
|
||||
Result ClusterEngine::createView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
TRI_voc_cid_t id,
|
||||
arangodb::LogicalView const& /*view*/
|
||||
) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
// asks the storage engine to persist renaming of a view
|
||||
// This will write a renameMarker if not in recovery
|
||||
Result ClusterEngine::renameView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::LogicalView const& view,
|
||||
std::string const& /*oldName*/
|
||||
) {
|
||||
return persistView(vocbase, view);
|
||||
}
|
||||
|
||||
arangodb::Result ClusterEngine::persistView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::LogicalView const& view
|
||||
) {
|
||||
return TRI_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
@ -387,25 +370,16 @@ void ClusterEngine::destroyView(
|
|||
// nothing to do here
|
||||
}
|
||||
|
||||
void ClusterEngine::changeView(
|
||||
Result ClusterEngine::changeView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
TRI_voc_cid_t /*id*/,
|
||||
arangodb::LogicalView const& view,
|
||||
bool /*doSync*/
|
||||
) {
|
||||
if (inRecovery()) {
|
||||
// nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
auto const res = persistView(vocbase, view);
|
||||
|
||||
if (!res.ok()) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||
res.errorNumber(),
|
||||
"could not save view properties"
|
||||
);
|
||||
return {};
|
||||
}
|
||||
return TRI_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
void ClusterEngine::signalCleanup(TRI_vocbase_t&) {
|
||||
|
@ -459,4 +433,4 @@ std::unique_ptr<TRI_vocbase_t> ClusterEngine::openExistingDatabase(
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -267,14 +267,13 @@ class ClusterEngine final : public StorageEngine {
|
|||
LogicalCollection& collection
|
||||
) override;
|
||||
|
||||
void changeView(
|
||||
arangodb::Result changeView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
TRI_voc_cid_t id,
|
||||
arangodb::LogicalView const& view,
|
||||
bool doSync
|
||||
) override;
|
||||
|
||||
void createView(
|
||||
arangodb::Result createView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
TRI_voc_cid_t id,
|
||||
arangodb::LogicalView const& view
|
||||
|
@ -288,19 +287,6 @@ class ClusterEngine final : public StorageEngine {
|
|||
// does nothing
|
||||
}
|
||||
|
||||
arangodb::Result persistView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::LogicalView const& view
|
||||
) override;
|
||||
|
||||
// asks the storage engine to persist renaming of a view
|
||||
// This will write a renameMarker if not in recovery
|
||||
arangodb::Result renameView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::LogicalView const& view,
|
||||
std::string const& oldName
|
||||
) override;
|
||||
|
||||
arangodb::Result dropView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
LogicalView& view
|
||||
|
|
|
@ -72,9 +72,7 @@ GeneralCommTask::GeneralCommTask(Scheduler* scheduler, GeneralServer* server,
|
|||
SocketTask(scheduler, std::move(socket), std::move(info),
|
||||
keepAliveTimeout, skipSocketInit),
|
||||
_server(server),
|
||||
_auth(nullptr) {
|
||||
_auth = application_features::ApplicationServer::getFeature<
|
||||
AuthenticationFeature>("Authentication");
|
||||
_auth(AuthenticationFeature::instance()) {
|
||||
TRI_ASSERT(_auth != nullptr);
|
||||
}
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ VstCommTask::VstCommTask(Scheduler* scheduler, GeneralServer* server,
|
|||
: Task(scheduler, "VstCommTask"),
|
||||
GeneralCommTask(scheduler, server, std::move(socket), std::move(info), timeout,
|
||||
skipInit),
|
||||
_authorized(false),
|
||||
_authorized(!_auth->isActive()),
|
||||
_authMethod(rest::AuthenticationMethod::NONE),
|
||||
_authenticatedUser(),
|
||||
_protocolVersion(protocolVersion) {
|
||||
|
|
|
@ -60,7 +60,7 @@ IResearchLink::IResearchLink(
|
|||
TRI_idx_iid_t iid,
|
||||
arangodb::LogicalCollection& collection
|
||||
): _collection(collection),
|
||||
_defaultId(0), // 0 is never a valid id
|
||||
_defaultGuid(""), // "" is never a valid guid
|
||||
_dropCollectionInDestructor(false),
|
||||
_id(iid),
|
||||
_view(nullptr) {
|
||||
|
@ -141,13 +141,15 @@ int IResearchLink::drop() {
|
|||
}
|
||||
|
||||
_dropCollectionInDestructor = false; // will do drop now
|
||||
_defaultId = _view->id(); // remember view ID just in case (e.g. call to toVelocyPack(...) after unload())
|
||||
_defaultGuid = _view->guid(); // remember view ID just in case (e.g. call to toVelocyPack(...) after unload())
|
||||
|
||||
TRI_voc_cid_t vid = _view->id();
|
||||
_view = nullptr; // mark as unassociated
|
||||
_viewLock.unlock(); // release read-lock on the IResearch View
|
||||
|
||||
// FIXME TODO this workaround should be in ClusterInfo when moving 'Plan' to 'Current', i.e. IResearchViewDBServer::drop
|
||||
if (arangodb::ServerState::instance()->isDBServer()) {
|
||||
return _collection.vocbase().dropView(_defaultId, true).errorNumber(); // cluster-view in ClusterInfo should already not have cid-view
|
||||
return _collection.vocbase().dropView(vid, true).errorNumber(); // cluster-view in ClusterInfo should already not have cid-view
|
||||
}
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
|
@ -183,7 +185,8 @@ bool IResearchLink::init(arangodb::velocypack::Slice const& definition) {
|
|||
}
|
||||
|
||||
if (!definition.isObject()
|
||||
|| !definition.get(StaticStrings::ViewIdField).isNumber<uint64_t>()) {
|
||||
|| !(definition.get(StaticStrings::ViewIdField).isString() ||
|
||||
definition.get(StaticStrings::ViewIdField).isNumber<TRI_voc_cid_t>())) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "error finding view for link '" << _id << "'";
|
||||
TRI_set_errno(TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND);
|
||||
|
@ -191,8 +194,9 @@ bool IResearchLink::init(arangodb::velocypack::Slice const& definition) {
|
|||
return false;
|
||||
}
|
||||
|
||||
auto identifier = definition.get(StaticStrings::ViewIdField);
|
||||
auto viewId = identifier.getNumber<uint64_t>();
|
||||
// we continue to support the old and new ID format
|
||||
auto idSlice = definition.get(StaticStrings::ViewIdField);
|
||||
std::string viewId = idSlice.isString() ? idSlice.copyString() : std::to_string(idSlice.getUInt());
|
||||
auto& vocbase = _collection.vocbase();
|
||||
auto logicalView = vocbase.lookupView(viewId); // will only contain IResearchView (even for a DBServer)
|
||||
|
||||
|
@ -208,7 +212,7 @@ bool IResearchLink::init(arangodb::velocypack::Slice const& definition) {
|
|||
return false;
|
||||
}
|
||||
|
||||
auto logicalWiew = ci->getView(vocbase.name(), std::to_string(viewId));
|
||||
auto logicalWiew = ci->getView(vocbase.name(), viewId);
|
||||
auto* wiew = LogicalView::cast<IResearchViewDBServer>(logicalWiew.get());
|
||||
|
||||
if (wiew) {
|
||||
|
@ -288,7 +292,7 @@ bool IResearchLink::init(arangodb::velocypack::Slice const& definition) {
|
|||
auto* engine = arangodb::EngineSelectorFeature::ENGINE;
|
||||
|
||||
if (engine && engine->inRecovery()) {
|
||||
_defaultId = _view->id();
|
||||
_defaultGuid = _view->guid();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -351,12 +355,11 @@ bool IResearchLink::json(
|
|||
|
||||
if (_view) {
|
||||
builder.add(
|
||||
StaticStrings::ViewIdField, arangodb::velocypack::Value(_view->id())
|
||||
StaticStrings::ViewIdField, arangodb::velocypack::Value(_view->guid())
|
||||
);
|
||||
} else if (_defaultId) { // '0' _defaultId == no view name in source jSON
|
||||
//if (_defaultId && forPersistence) { // MMFilesCollection::saveIndex(...) does not set 'forPersistence'
|
||||
} else if (!_defaultGuid.empty()) { // _defaultGuid.empty() == no view name in source jSON
|
||||
builder.add(
|
||||
StaticStrings::ViewIdField, arangodb::velocypack::Value(_defaultId)
|
||||
StaticStrings::ViewIdField, VPackValue(_defaultGuid)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -377,11 +380,9 @@ bool IResearchLink::matchesDefinition(VPackSlice const& slice) const {
|
|||
}
|
||||
|
||||
auto identifier = slice.get(StaticStrings::ViewIdField);
|
||||
|
||||
if (!identifier.isNumber()
|
||||
|| uint64_t(identifier.getInt()) != identifier.getUInt()
|
||||
|| identifier.getUInt() != _view->id()) {
|
||||
return false; // iResearch View names of current object and slice do not match
|
||||
if (!((identifier.isString() && identifier.isEqualString(_view->guid())) ||
|
||||
(identifier.isNumber<TRI_voc_cid_t>() && identifier.getUInt() != _view->id()))) {
|
||||
return false; // iResearch View names of current object and slice do not match
|
||||
}
|
||||
} else if (_view) {
|
||||
return false; // slice has no 'name' but the current object does
|
||||
|
@ -493,7 +494,7 @@ int IResearchLink::unload() {
|
|||
}
|
||||
|
||||
_dropCollectionInDestructor = false; // valid link (since unload(..) called), should not be dropped
|
||||
_defaultId = _view->id(); // remember view ID just in case (e.g. call to toVelocyPack(...) after unload())
|
||||
_defaultGuid = _view->guid(); // remember view ID just in case (e.g. call to toVelocyPack(...) after unload())
|
||||
_view = nullptr; // mark as unassociated
|
||||
_viewLock.unlock(); // release read-lock on the IResearch View
|
||||
|
||||
|
@ -533,4 +534,4 @@ NS_END // arangodb
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -190,7 +190,7 @@ class IResearchLink {
|
|||
friend class IResearchView;
|
||||
|
||||
LogicalCollection& _collection; // the linked collection
|
||||
TRI_voc_cid_t _defaultId; // the identifier of the desired view (iff _view == nullptr)
|
||||
std::string _defaultGuid; // the identifier of the desired view (iff _view == nullptr)
|
||||
bool _dropCollectionInDestructor; // collection should be dropped from view in the destructor (for the case where init(..) is called folowed by distructor)
|
||||
TRI_idx_iid_t const _id; // the index identifier
|
||||
IResearchLinkMeta _meta; // how this collection should be indexed
|
||||
|
@ -202,4 +202,4 @@ class IResearchLink {
|
|||
NS_END // iresearch
|
||||
NS_END // arangodb
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -85,7 +85,8 @@ bool IResearchLinkCoordinator::init(VPackSlice definition) {
|
|||
}
|
||||
|
||||
if (!definition.isObject()
|
||||
|| !definition.get(StaticStrings::ViewIdField).isNumber<uint64_t>()) {
|
||||
|| !(definition.get(StaticStrings::ViewIdField).isString() ||
|
||||
definition.get(StaticStrings::ViewIdField).isNumber())) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "error finding view for link '" << id() << "'";
|
||||
TRI_set_errno(TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND);
|
||||
|
@ -93,14 +94,12 @@ bool IResearchLinkCoordinator::init(VPackSlice definition) {
|
|||
return false;
|
||||
}
|
||||
|
||||
auto identifier = definition.get(StaticStrings::ViewIdField);
|
||||
auto viewId = identifier.getNumber<uint64_t>();
|
||||
auto idSlice = definition.get(StaticStrings::ViewIdField);
|
||||
std::string viewId = idSlice.isString() ? idSlice.copyString() : std::to_string(idSlice.getUInt());
|
||||
auto& vocbase = _collection.vocbase();
|
||||
|
||||
TRI_ASSERT(ClusterInfo::instance());
|
||||
auto logicalView = ClusterInfo::instance()->getView(
|
||||
vocbase.name(), basics::StringUtils::itoa(viewId)
|
||||
);
|
||||
auto logicalView = ClusterInfo::instance()->getView(vocbase.name(), viewId);
|
||||
|
||||
if (!logicalView
|
||||
|| arangodb::iresearch::DATA_SOURCE_TYPE != logicalView->type()) {
|
||||
|
@ -196,7 +195,7 @@ void IResearchLinkCoordinator::toVelocyPack(
|
|||
);
|
||||
builder.add(
|
||||
StaticStrings::ViewIdField,
|
||||
arangodb::velocypack::Value(_view->id())
|
||||
arangodb::velocypack::Value(_view->guid())
|
||||
);
|
||||
|
||||
if (withFigures) {
|
||||
|
@ -220,4 +219,4 @@ char const* IResearchLinkCoordinator::typeName() const {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -186,7 +186,7 @@ namespace iresearch {
|
|||
);
|
||||
namedJson.add(
|
||||
StaticStrings::ViewIdField,
|
||||
arangodb::velocypack::Value(view.id())
|
||||
arangodb::velocypack::Value(view.guid())
|
||||
);
|
||||
|
||||
if (!mergeSliceSkipKeys(namedJson, link, acceptor)) {
|
||||
|
|
|
@ -323,7 +323,7 @@ arangodb::Result persistProperties(
|
|||
if (!engine->inRecovery()) {
|
||||
// change view throws exception on error
|
||||
try {
|
||||
engine->changeView(view.vocbase(), view.id(), view, true);
|
||||
engine->changeView(view.vocbase(), view, true);
|
||||
} catch (arangodb::basics::Exception& e) {
|
||||
IR_LOG_EXCEPTION();
|
||||
|
||||
|
@ -390,7 +390,7 @@ arangodb::Result persistProperties(
|
|||
|
||||
// change view throws exception on error
|
||||
try {
|
||||
engine->changeView(view.vocbase(), view.id(), view, true);
|
||||
engine->changeView(view.vocbase(), view, true);
|
||||
} catch (arangodb::basics::Exception& e) {
|
||||
IR_LOG_EXCEPTION();
|
||||
|
||||
|
@ -2153,4 +2153,4 @@ NS_END // arangodb
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -81,7 +81,7 @@ arangodb::Result createLink(
|
|||
arangodb::velocypack::Value(IResearchLinkHelper::type())
|
||||
);
|
||||
builder.add(
|
||||
StaticStrings::ViewIdField, arangodb::velocypack::Value(view.id())
|
||||
StaticStrings::ViewIdField, arangodb::velocypack::Value(view.guid())
|
||||
);
|
||||
|
||||
if (!mergeSliceSkipKeys(builder, link, acceptor)) {
|
||||
|
@ -599,4 +599,4 @@ Result IResearchViewCoordinator::drop() {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -421,8 +421,6 @@ char const* TRI_NameMarkerDatafile(MMFilesMarkerType type) {
|
|||
return "create view";
|
||||
case TRI_DF_MARKER_VPACK_DROP_VIEW:
|
||||
return "drop view";
|
||||
case TRI_DF_MARKER_VPACK_RENAME_VIEW:
|
||||
return "rename view";
|
||||
case TRI_DF_MARKER_VPACK_CHANGE_VIEW:
|
||||
return "change view";
|
||||
|
||||
|
|
|
@ -71,7 +71,6 @@ enum MMFilesMarkerType : uint8_t {
|
|||
TRI_DF_MARKER_VPACK_CREATE_VIEW = 80,
|
||||
TRI_DF_MARKER_VPACK_DROP_VIEW = 81,
|
||||
TRI_DF_MARKER_VPACK_CHANGE_VIEW = 82,
|
||||
TRI_DF_MARKER_VPACK_RENAME_VIEW = 83,
|
||||
|
||||
TRI_DF_MARKER_MAX // again, this is not a real
|
||||
// marker, but we use it for
|
||||
|
|
|
@ -84,7 +84,6 @@ static inline size_t VPackOffset(MMFilesMarkerType type) noexcept {
|
|||
type == TRI_DF_MARKER_VPACK_DROP_INDEX ||
|
||||
type == TRI_DF_MARKER_VPACK_CREATE_VIEW ||
|
||||
type == TRI_DF_MARKER_VPACK_DROP_VIEW ||
|
||||
type == TRI_DF_MARKER_VPACK_RENAME_VIEW ||
|
||||
type == TRI_DF_MARKER_VPACK_CHANGE_VIEW) {
|
||||
// VPack is located after database id and collection id
|
||||
return sizeof(MMFilesMarker) + sizeof(TRI_voc_tick_t) + sizeof(TRI_voc_cid_t);
|
||||
|
@ -121,7 +120,6 @@ static inline size_t DatabaseIdOffset(MMFilesMarkerType type) noexcept {
|
|||
type == TRI_DF_MARKER_VPACK_DROP_INDEX ||
|
||||
type == TRI_DF_MARKER_VPACK_CREATE_VIEW ||
|
||||
type == TRI_DF_MARKER_VPACK_DROP_VIEW ||
|
||||
type == TRI_DF_MARKER_VPACK_RENAME_VIEW ||
|
||||
type == TRI_DF_MARKER_VPACK_CHANGE_VIEW ||
|
||||
type == TRI_DF_MARKER_VPACK_CREATE_DATABASE ||
|
||||
type == TRI_DF_MARKER_VPACK_DROP_DATABASE ||
|
||||
|
@ -148,7 +146,6 @@ static inline TRI_voc_tick_t DatabaseId(MMFilesMarker const* marker) noexcept {
|
|||
type == TRI_DF_MARKER_VPACK_DROP_INDEX ||
|
||||
type == TRI_DF_MARKER_VPACK_CREATE_VIEW ||
|
||||
type == TRI_DF_MARKER_VPACK_DROP_VIEW ||
|
||||
type == TRI_DF_MARKER_VPACK_RENAME_VIEW ||
|
||||
type == TRI_DF_MARKER_VPACK_CHANGE_VIEW ||
|
||||
type == TRI_DF_MARKER_VPACK_CREATE_DATABASE ||
|
||||
type == TRI_DF_MARKER_VPACK_DROP_DATABASE ||
|
||||
|
@ -202,8 +199,7 @@ static inline TRI_voc_tick_t CollectionId(MMFilesMarker const* marker) noexcept
|
|||
static inline size_t ViewIdOffset(MMFilesMarkerType type) noexcept {
|
||||
if (type == TRI_DF_MARKER_VPACK_CREATE_VIEW ||
|
||||
type == TRI_DF_MARKER_VPACK_DROP_VIEW ||
|
||||
type == TRI_DF_MARKER_VPACK_CHANGE_VIEW ||
|
||||
type == TRI_DF_MARKER_VPACK_RENAME_VIEW) {
|
||||
type == TRI_DF_MARKER_VPACK_CHANGE_VIEW) {
|
||||
return sizeof(MMFilesMarker) + sizeof(TRI_voc_tick_t);
|
||||
}
|
||||
return 0;
|
||||
|
@ -217,8 +213,7 @@ static inline TRI_voc_tick_t ViewId(MMFilesMarker const* marker) noexcept {
|
|||
MMFilesMarkerType type = marker->getType();
|
||||
if (type == TRI_DF_MARKER_VPACK_CREATE_VIEW ||
|
||||
type == TRI_DF_MARKER_VPACK_DROP_VIEW ||
|
||||
type == TRI_DF_MARKER_VPACK_CHANGE_VIEW ||
|
||||
type == TRI_DF_MARKER_VPACK_RENAME_VIEW) {
|
||||
type == TRI_DF_MARKER_VPACK_CHANGE_VIEW) {
|
||||
return encoding::readNumber<TRI_voc_cid_t>(reinterpret_cast<uint8_t const*>(marker) + ViewIdOffset(type), sizeof(TRI_voc_cid_t));
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -1238,56 +1238,7 @@ Result MMFilesEngine::renameCollection(
|
|||
return {res, TRI_errno_string(res)};
|
||||
}
|
||||
|
||||
// asks the storage engine to persist renaming of a view
|
||||
// This will write a renameMarker if not in recovery
|
||||
Result MMFilesEngine::renameView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::LogicalView const& view,
|
||||
std::string const& oldName
|
||||
) {
|
||||
if (inRecovery()) {
|
||||
// Nothing todo. Marker already there
|
||||
return {};
|
||||
}
|
||||
|
||||
int res = TRI_ERROR_NO_ERROR;
|
||||
|
||||
try {
|
||||
VPackBuilder builder;
|
||||
|
||||
builder.openObject();
|
||||
builder.add("id", VPackValue(std::to_string(view.id())));
|
||||
builder.add("oldName", VPackValue(oldName));
|
||||
builder.add("name", VPackValue(view.name()));
|
||||
builder.close();
|
||||
|
||||
MMFilesViewMarker marker(
|
||||
TRI_DF_MARKER_VPACK_RENAME_VIEW, vocbase.id(), view.id(), builder.slice()
|
||||
);
|
||||
MMFilesWalSlotInfoCopy slotInfo =
|
||||
MMFilesLogfileManager::instance()->allocateAndWrite(marker, false);
|
||||
|
||||
if (slotInfo.errorCode != TRI_ERROR_NO_ERROR) {
|
||||
THROW_ARANGO_EXCEPTION(slotInfo.errorCode);
|
||||
}
|
||||
|
||||
res = TRI_ERROR_NO_ERROR;
|
||||
} catch (arangodb::basics::Exception const& ex) {
|
||||
res = ex.code();
|
||||
} catch (...) {
|
||||
res = TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
LOG_TOPIC(WARN, arangodb::Logger::FIXME)
|
||||
<< "could not save view rename marker in log: "
|
||||
<< TRI_errno_string(res);
|
||||
}
|
||||
|
||||
return {res, TRI_errno_string(res)};
|
||||
}
|
||||
|
||||
void MMFilesEngine::createView(
|
||||
Result MMFilesEngine::createView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
TRI_voc_cid_t id,
|
||||
arangodb::LogicalView const& view
|
||||
|
@ -1298,7 +1249,7 @@ void MMFilesEngine::createView(
|
|||
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
|
||||
<< "cannot create view '" << path
|
||||
<< "', database path is not a directory";
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DATADIR_INVALID);
|
||||
return TRI_ERROR_ARANGO_DATADIR_INVALID;
|
||||
}
|
||||
|
||||
TRI_ASSERT(id != 0);
|
||||
|
@ -1311,9 +1262,7 @@ void MMFilesEngine::createView(
|
|||
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
|
||||
<< "cannot create view '" << view.name() << "' in directory '"
|
||||
<< dirname << "': directory already exists";
|
||||
THROW_ARANGO_EXCEPTION(
|
||||
TRI_ERROR_ARANGO_COLLECTION_DIRECTORY_ALREADY_EXISTS); // TODO: change
|
||||
// error code
|
||||
return TRI_ERROR_ARANGO_COLLECTION_DIRECTORY_ALREADY_EXISTS;
|
||||
}
|
||||
|
||||
// use a temporary directory first. this saves us from leaving an empty
|
||||
|
@ -1330,11 +1279,11 @@ void MMFilesEngine::createView(
|
|||
<< "cannot create view '" << view.name() << "' in directory '"
|
||||
<< path << "': " << TRI_errno_string(res) << " - " << systemError
|
||||
<< " - " << errorMessage;
|
||||
THROW_ARANGO_EXCEPTION(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
TRI_IF_FAILURE("CreateView::tempDirectory") {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
|
||||
return TRI_ERROR_DEBUG;
|
||||
}
|
||||
|
||||
// create a temporary file (.tmp)
|
||||
|
@ -1347,7 +1296,7 @@ void MMFilesEngine::createView(
|
|||
arangodb::basics::FileUtils::buildFilename(dirname, ".tmp"));
|
||||
|
||||
TRI_IF_FAILURE("CreateView::tempFile") {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
|
||||
return TRI_ERROR_DEBUG;
|
||||
}
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
|
@ -1356,11 +1305,11 @@ void MMFilesEngine::createView(
|
|||
<< path << "': " << TRI_errno_string(res) << " - " << systemError
|
||||
<< " - " << errorMessage;
|
||||
TRI_RemoveDirectory(tmpname.c_str());
|
||||
THROW_ARANGO_EXCEPTION(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
TRI_IF_FAILURE("CreateView::renameDirectory") {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
|
||||
return TRI_ERROR_DEBUG;
|
||||
}
|
||||
|
||||
res = TRI_RenameFile(tmpname.c_str(), dirname.c_str());
|
||||
|
@ -1371,11 +1320,11 @@ void MMFilesEngine::createView(
|
|||
<< path << "': " << TRI_errno_string(res) << " - " << systemError
|
||||
<< " - " << errorMessage;
|
||||
TRI_RemoveDirectory(tmpname.c_str());
|
||||
THROW_ARANGO_EXCEPTION(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
// now we have the directory in place with the correct name and a .tmp file in
|
||||
// it
|
||||
// now we have the directory in place with the correct name
|
||||
// and a .tmp file in it
|
||||
|
||||
// delete .tmp file
|
||||
TRI_UnlinkFile(tmpfile2.c_str());
|
||||
|
@ -1386,7 +1335,44 @@ void MMFilesEngine::createView(
|
|||
"Database")
|
||||
->forceSyncProperties();
|
||||
|
||||
saveViewInfo(&vocbase, id, &view, doSync);
|
||||
saveViewInfo(&vocbase, &view, doSync);
|
||||
|
||||
|
||||
if (inRecovery()) {
|
||||
// Nothing more do. In recovery we do not write markers.
|
||||
return {};
|
||||
}
|
||||
|
||||
VPackBuilder builder;
|
||||
builder.openObject();
|
||||
view.toVelocyPack(builder, true, true);
|
||||
builder.close();
|
||||
|
||||
TRI_ASSERT(id != 0);
|
||||
TRI_UpdateTickServer(static_cast<TRI_voc_tick_t>(id));
|
||||
|
||||
res = TRI_ERROR_NO_ERROR;
|
||||
try {
|
||||
MMFilesViewMarker marker(TRI_DF_MARKER_VPACK_CREATE_VIEW, vocbase.id(),
|
||||
view.id(), builder.slice());
|
||||
MMFilesWalSlotInfoCopy slotInfo =
|
||||
MMFilesLogfileManager::instance()->allocateAndWrite(marker, false);
|
||||
|
||||
if (slotInfo.errorCode != TRI_ERROR_NO_ERROR) {
|
||||
THROW_ARANGO_EXCEPTION(slotInfo.errorCode);
|
||||
}
|
||||
|
||||
return {};
|
||||
} catch (arangodb::basics::Exception const& ex) {
|
||||
res = ex.code();
|
||||
} catch (...) {
|
||||
res = TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
LOG_TOPIC(WARN, arangodb::Logger::FIXME)
|
||||
<< "could not save view create marker in log: " << TRI_errno_string(res);
|
||||
|
||||
return {res, TRI_errno_string(res)};
|
||||
}
|
||||
|
||||
void MMFilesEngine::getViewProperties(
|
||||
|
@ -1398,53 +1384,6 @@ void MMFilesEngine::getViewProperties(
|
|||
result.add("path", velocypack::Value(viewDirectory(vocbase.id(), view.id())));
|
||||
}
|
||||
|
||||
arangodb::Result MMFilesEngine::persistView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::LogicalView const& view
|
||||
) {
|
||||
if (inRecovery()) {
|
||||
// Nothing to do. In recovery we do not write markers.
|
||||
return {};
|
||||
}
|
||||
|
||||
VPackBuilder builder;
|
||||
|
||||
builder.openObject();
|
||||
view.toVelocyPack(builder, true, true);
|
||||
builder.close();
|
||||
|
||||
VPackSlice const slice = builder.slice();
|
||||
auto id = view.id();
|
||||
|
||||
TRI_ASSERT(id != 0);
|
||||
TRI_UpdateTickServer(static_cast<TRI_voc_tick_t>(id));
|
||||
|
||||
int res = TRI_ERROR_NO_ERROR;
|
||||
|
||||
try {
|
||||
MMFilesViewMarker marker(
|
||||
TRI_DF_MARKER_VPACK_CREATE_VIEW, vocbase.id(), id, slice
|
||||
);
|
||||
MMFilesWalSlotInfoCopy slotInfo =
|
||||
MMFilesLogfileManager::instance()->allocateAndWrite(marker, false);
|
||||
|
||||
if (slotInfo.errorCode != TRI_ERROR_NO_ERROR) {
|
||||
THROW_ARANGO_EXCEPTION(slotInfo.errorCode);
|
||||
}
|
||||
|
||||
return {};
|
||||
} catch (arangodb::basics::Exception const& ex) {
|
||||
res = ex.code();
|
||||
} catch (...) {
|
||||
res = TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
LOG_TOPIC(WARN, arangodb::Logger::FIXME)
|
||||
<< "could not save view create marker in log: " << TRI_errno_string(res);
|
||||
|
||||
return {res, TRI_errno_string(res)};
|
||||
}
|
||||
|
||||
arangodb::Result MMFilesEngine::dropView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
LogicalView& view
|
||||
|
@ -1452,7 +1391,7 @@ arangodb::Result MMFilesEngine::dropView(
|
|||
auto* db = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
|
||||
TRI_ASSERT(db);
|
||||
saveViewInfo(&vocbase, view.id(), &view, db->forceSyncProperties());
|
||||
saveViewInfo(&vocbase, &view, db->forceSyncProperties());
|
||||
|
||||
if (inRecovery()) {
|
||||
// nothing to do here
|
||||
|
@ -1463,10 +1402,9 @@ arangodb::Result MMFilesEngine::dropView(
|
|||
|
||||
try {
|
||||
VPackBuilder builder;
|
||||
|
||||
builder.openObject();
|
||||
builder.add("id", velocypack::Value(std::to_string(view.id())));
|
||||
builder.add("name", velocypack::Value(view.name()));
|
||||
builder.add(StaticStrings::DataSourceId, velocypack::Value(std::to_string(view.id())));
|
||||
builder.add("cuid", velocypack::Value(view.guid()));
|
||||
builder.close();
|
||||
|
||||
MMFilesViewMarker marker(
|
||||
|
@ -1509,10 +1447,10 @@ void MMFilesEngine::destroyView(
|
|||
}
|
||||
}
|
||||
|
||||
void MMFilesEngine::saveViewInfo(TRI_vocbase_t* vocbase, TRI_voc_cid_t id,
|
||||
void MMFilesEngine::saveViewInfo(TRI_vocbase_t* vocbase,
|
||||
arangodb::LogicalView const* view,
|
||||
bool forceSync) const {
|
||||
std::string const filename = viewParametersFilename(vocbase->id(), id);
|
||||
std::string const filename = viewParametersFilename(vocbase->id(), view->id());
|
||||
|
||||
VPackBuilder builder;
|
||||
builder.openObject();
|
||||
|
@ -1540,14 +1478,11 @@ void MMFilesEngine::saveViewInfo(TRI_vocbase_t* vocbase, TRI_voc_cid_t id,
|
|||
// fail.
|
||||
// the WAL entry for the propery change will be written *after* the call
|
||||
// to "changeView" returns
|
||||
void MMFilesEngine::changeView(
|
||||
Result MMFilesEngine::changeView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
TRI_voc_cid_t id,
|
||||
arangodb::LogicalView const& view,
|
||||
bool doSync
|
||||
) {
|
||||
// FIXME make noexcept and return Result???
|
||||
|
||||
if (!inRecovery()) {
|
||||
VPackBuilder infoBuilder;
|
||||
infoBuilder.openObject();
|
||||
|
@ -1555,21 +1490,20 @@ void MMFilesEngine::changeView(
|
|||
infoBuilder.close();
|
||||
|
||||
MMFilesViewMarker marker(
|
||||
TRI_DF_MARKER_VPACK_CHANGE_VIEW, vocbase.id(), id, infoBuilder.slice()
|
||||
TRI_DF_MARKER_VPACK_CHANGE_VIEW, vocbase.id(), view.id(), infoBuilder.slice()
|
||||
);
|
||||
|
||||
MMFilesWalSlotInfoCopy slotInfo =
|
||||
MMFilesLogfileManager::instance()->allocateAndWrite(marker, false);
|
||||
|
||||
if (slotInfo.errorCode != TRI_ERROR_NO_ERROR) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||
slotInfo.errorCode,
|
||||
"could not save view change marker in log"
|
||||
);
|
||||
return Result(slotInfo.errorCode,
|
||||
"could not save view change marker in log");
|
||||
}
|
||||
}
|
||||
|
||||
saveViewInfo(&vocbase, id, &view, doSync);
|
||||
saveViewInfo(&vocbase, &view, doSync);
|
||||
return {};
|
||||
}
|
||||
|
||||
// asks the storage engine to create an index as specified in the VPack
|
||||
|
|
|
@ -352,14 +352,13 @@ class MMFilesEngine final : public StorageEngine {
|
|||
LogicalCollection& collection
|
||||
) override;
|
||||
|
||||
void changeView(
|
||||
arangodb::Result changeView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
TRI_voc_cid_t id,
|
||||
arangodb::LogicalView const&,
|
||||
bool doSync
|
||||
) override;
|
||||
|
||||
void createView(
|
||||
arangodb::Result createView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
TRI_voc_cid_t id,
|
||||
arangodb::LogicalView const& view
|
||||
|
@ -371,19 +370,6 @@ class MMFilesEngine final : public StorageEngine {
|
|||
VPackBuilder& builder
|
||||
) override;
|
||||
|
||||
arangodb::Result persistView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::LogicalView const& view
|
||||
) override;
|
||||
|
||||
// asks the storage engine to persist renaming of a view
|
||||
// This will write a renameMarker if not in recovery
|
||||
arangodb::Result renameView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::LogicalView const& view,
|
||||
std::string const& oldName
|
||||
) override;
|
||||
|
||||
arangodb::Result dropView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
LogicalView& view
|
||||
|
@ -397,8 +383,7 @@ class MMFilesEngine final : public StorageEngine {
|
|||
std::string createViewDirectoryName(std::string const& basePath,
|
||||
TRI_voc_cid_t id);
|
||||
|
||||
void saveViewInfo(TRI_vocbase_t* vocbase, TRI_voc_cid_t id,
|
||||
arangodb::LogicalView const*, bool forceSync) const;
|
||||
void saveViewInfo(TRI_vocbase_t* vocbase, arangodb::LogicalView const*, bool sync) const;
|
||||
|
||||
void signalCleanup(TRI_vocbase_t& vocbase) override;
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "MMFiles/MMFilesLogfileManager.h"
|
||||
#include "MMFiles/mmfiles-replication-common.h"
|
||||
#include "VocBase/LogicalCollection.h"
|
||||
#include "VocBase/LogicalView.h"
|
||||
#include "VocBase/vocbase.h"
|
||||
|
||||
#include <velocypack/Dumper.h>
|
||||
|
@ -231,10 +232,18 @@ struct MMFilesWalAccessContext : WalAccessContext {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isViewWalMarker(MMFilesMarker const* marker) const {
|
||||
MMFilesMarkerType t = marker->getType();
|
||||
return t == TRI_DF_MARKER_VPACK_CREATE_VIEW ||
|
||||
t == TRI_DF_MARKER_VPACK_DROP_VIEW ||
|
||||
t == TRI_DF_MARKER_VPACK_CHANGE_VIEW;
|
||||
}
|
||||
|
||||
/// @brief whether or not a marker is replicated
|
||||
bool mustReplicateWalMarker(MMFilesMarker const* marker,
|
||||
TRI_voc_tick_t databaseId, TRI_voc_cid_t cid) {
|
||||
TRI_voc_tick_t databaseId,
|
||||
TRI_voc_cid_t datasourceId) {
|
||||
// first check the marker type
|
||||
if (!MustReplicateWalMarkerType(marker, true)) {
|
||||
return false;
|
||||
|
@ -246,18 +255,20 @@ struct MMFilesWalAccessContext : WalAccessContext {
|
|||
}
|
||||
|
||||
// finally check if the marker is for a collection that we want to ignore
|
||||
if (cid != 0) {
|
||||
if (datasourceId != 0) {
|
||||
if (_filter.collection != 0 &&
|
||||
(cid != _filter.collection && !isTransactionWalMarker(marker))) {
|
||||
(datasourceId != _filter.collection && !isTransactionWalMarker(marker))) {
|
||||
// restrict output to a single collection, but a different one
|
||||
return false;
|
||||
}
|
||||
|
||||
LogicalCollection* collection = loadCollection(databaseId, cid);
|
||||
if (collection != nullptr) { // db may be already dropped
|
||||
if (TRI_ExcludeCollectionReplication(collection->name(),
|
||||
_filter.includeSystem)) {
|
||||
return false;
|
||||
if (!isViewWalMarker(marker)) {
|
||||
// will not find anything for a view
|
||||
LogicalCollection* collection = loadCollection(databaseId, datasourceId);
|
||||
if (collection != nullptr) { // db may be already dropped
|
||||
if (TRI_ExcludeCollectionReplication(collection->name(),
|
||||
_filter.includeSystem)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -276,7 +287,7 @@ struct MMFilesWalAccessContext : WalAccessContext {
|
|||
return true;
|
||||
}
|
||||
|
||||
int sliceifyMarker(TRI_voc_tick_t databaseId, TRI_voc_cid_t collectionId,
|
||||
int sliceifyMarker(TRI_voc_tick_t databaseId, TRI_voc_cid_t datasourceId,
|
||||
MMFilesMarker const* marker) {
|
||||
TRI_ASSERT(MustReplicateWalMarkerType(marker, true));
|
||||
MMFilesMarkerType const type = marker->getType();
|
||||
|
@ -308,20 +319,33 @@ struct MMFilesWalAccessContext : WalAccessContext {
|
|||
MMFilesDatafileHelper::VPackOffset(type));
|
||||
|
||||
_builder.add("db", slice.get("name"));
|
||||
} else if (type == TRI_DF_MARKER_VPACK_DROP_COLLECTION) {
|
||||
} else if (type == TRI_DF_MARKER_VPACK_DROP_COLLECTION ||
|
||||
type == TRI_DF_MARKER_VPACK_DROP_VIEW) {
|
||||
TRI_ASSERT(databaseId != 0);
|
||||
TRI_vocbase_t* vocbase = loadVocbase(databaseId);
|
||||
|
||||
if (vocbase == nullptr) {
|
||||
// ignore markers from dropped dbs
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
VPackSlice slice(reinterpret_cast<char const*>(marker) +
|
||||
MMFilesDatafileHelper::VPackOffset(type));
|
||||
|
||||
_builder.add("db", VPackValue(vocbase->name()));
|
||||
_builder.add("cuid", slice.get("cuid"));
|
||||
} else if (type == TRI_DF_MARKER_VPACK_CREATE_VIEW ||
|
||||
type == TRI_DF_MARKER_VPACK_CHANGE_VIEW) {
|
||||
TRI_ASSERT(databaseId != 0);
|
||||
TRI_vocbase_t* vocbase = loadVocbase(databaseId);
|
||||
if (vocbase == nullptr) {
|
||||
// ignore markers from dropped dbs
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
auto view = vocbase->lookupView(datasourceId);
|
||||
if (!view) {
|
||||
return TRI_ERROR_NO_ERROR; // ignore marker
|
||||
}
|
||||
_builder.add("db", VPackValue(vocbase->name()));
|
||||
_builder.add("cuid", VPackValue(view->guid()));
|
||||
|
||||
} else {
|
||||
TRI_ASSERT(databaseId != 0);
|
||||
TRI_vocbase_t* vocbase = loadVocbase(databaseId);
|
||||
|
@ -332,13 +356,11 @@ struct MMFilesWalAccessContext : WalAccessContext {
|
|||
|
||||
_builder.add("db", VPackValue(vocbase->name()));
|
||||
|
||||
if (collectionId > 0) {
|
||||
LogicalCollection* col = loadCollection(databaseId, collectionId);
|
||||
|
||||
if (datasourceId > 0) { // will not find anything for a view
|
||||
LogicalCollection* col = loadCollection(databaseId, datasourceId);
|
||||
if (col == nullptr) {
|
||||
return TRI_ERROR_NO_ERROR; // ignore dropped collections
|
||||
}
|
||||
|
||||
_builder.add("cuid", VPackValue(col->guid()));
|
||||
}
|
||||
}
|
||||
|
@ -351,11 +373,9 @@ struct MMFilesWalAccessContext : WalAccessContext {
|
|||
case TRI_DF_MARKER_VPACK_CREATE_INDEX:
|
||||
case TRI_DF_MARKER_VPACK_CREATE_VIEW:
|
||||
case TRI_DF_MARKER_VPACK_RENAME_COLLECTION:
|
||||
case TRI_DF_MARKER_VPACK_RENAME_VIEW:
|
||||
case TRI_DF_MARKER_VPACK_CHANGE_COLLECTION:
|
||||
case TRI_DF_MARKER_VPACK_CHANGE_VIEW:
|
||||
case TRI_DF_MARKER_VPACK_DROP_INDEX:
|
||||
case TRI_DF_MARKER_VPACK_DROP_VIEW: {
|
||||
case TRI_DF_MARKER_VPACK_DROP_INDEX: {
|
||||
VPackSlice slice(reinterpret_cast<char const*>(marker) +
|
||||
MMFilesDatafileHelper::VPackOffset(type));
|
||||
_builder.add("data", slice);
|
||||
|
@ -364,6 +384,7 @@ struct MMFilesWalAccessContext : WalAccessContext {
|
|||
|
||||
case TRI_DF_MARKER_VPACK_DROP_DATABASE:
|
||||
case TRI_DF_MARKER_VPACK_DROP_COLLECTION:
|
||||
case TRI_DF_MARKER_VPACK_DROP_VIEW:
|
||||
case TRI_DF_MARKER_VPACK_BEGIN_TRANSACTION:
|
||||
case TRI_DF_MARKER_VPACK_COMMIT_TRANSACTION:
|
||||
case TRI_DF_MARKER_VPACK_ABORT_TRANSACTION: {
|
||||
|
@ -480,25 +501,29 @@ struct MMFilesWalAccessContext : WalAccessContext {
|
|||
}
|
||||
|
||||
TRI_voc_tick_t databaseId;
|
||||
TRI_voc_cid_t collectionId;
|
||||
|
||||
TRI_voc_cid_t datasourceId;
|
||||
if (type == TRI_DF_MARKER_VPACK_DOCUMENT ||
|
||||
type == TRI_DF_MARKER_VPACK_REMOVE) {
|
||||
databaseId = lastDatabaseId;
|
||||
collectionId = lastCollectionId;
|
||||
datasourceId = lastCollectionId;
|
||||
} else {
|
||||
databaseId = MMFilesDatafileHelper::DatabaseId(marker);
|
||||
collectionId = MMFilesDatafileHelper::CollectionId(marker);
|
||||
if (type == TRI_DF_MARKER_VPACK_CREATE_VIEW ||
|
||||
type == TRI_DF_MARKER_VPACK_CHANGE_VIEW) {
|
||||
datasourceId = MMFilesDatafileHelper::ViewId(marker);
|
||||
} else {
|
||||
datasourceId = MMFilesDatafileHelper::CollectionId(marker);
|
||||
}
|
||||
}
|
||||
|
||||
if (!mustReplicateWalMarker(marker, databaseId, collectionId)) {
|
||||
if (!mustReplicateWalMarker(marker, databaseId, datasourceId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// note the last tick we processed
|
||||
lastFoundTick = foundTick;
|
||||
|
||||
res = sliceifyMarker(databaseId, collectionId, marker);
|
||||
res = sliceifyMarker(databaseId, datasourceId, marker);
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
THROW_ARANGO_EXCEPTION(res);
|
||||
}
|
||||
|
|
|
@ -787,86 +787,6 @@ bool MMFilesWalRecoverState::ReplayMarker(MMFilesMarker const* marker,
|
|||
break;
|
||||
}
|
||||
|
||||
case TRI_DF_MARKER_VPACK_RENAME_VIEW: {
|
||||
TRI_voc_tick_t const databaseId =
|
||||
MMFilesDatafileHelper::DatabaseId(marker);
|
||||
TRI_voc_cid_t const viewId = MMFilesDatafileHelper::ViewId(marker);
|
||||
|
||||
VPackSlice const payloadSlice(reinterpret_cast<char const*>(marker) +
|
||||
MMFilesDatafileHelper::VPackOffset(type));
|
||||
|
||||
if (!payloadSlice.isObject()) {
|
||||
LOG_TOPIC(WARN, arangodb::Logger::ENGINES)
|
||||
<< "cannot rename view: invalid marker";
|
||||
++state->errorCount;
|
||||
return state->canContinue();
|
||||
}
|
||||
|
||||
if (state->isDropped(databaseId)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG_TOPIC(TRACE, arangodb::Logger::ENGINES)
|
||||
<< "found view rename marker. databaseId: " << databaseId
|
||||
<< ", viewId: " << viewId;
|
||||
|
||||
TRI_vocbase_t* vocbase = state->useDatabase(databaseId);
|
||||
|
||||
if (vocbase == nullptr) {
|
||||
// if the underlying database is gone, we can go on
|
||||
LOG_TOPIC(TRACE, arangodb::Logger::ENGINES) << "cannot open database "
|
||||
<< databaseId;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<arangodb::LogicalView> view =
|
||||
vocbase->lookupView(viewId);
|
||||
|
||||
if (view == nullptr) {
|
||||
// if the underlying collection is gone, we can go on
|
||||
LOG_TOPIC(TRACE, arangodb::Logger::ENGINES)
|
||||
<< "cannot rename view " << viewId << " in database " << databaseId << ": "
|
||||
<< TRI_errno_string(TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND);
|
||||
return true;
|
||||
}
|
||||
|
||||
VPackSlice nameSlice = payloadSlice.get("name");
|
||||
if (!nameSlice.isString()) {
|
||||
LOG_TOPIC(WARN, arangodb::Logger::ENGINES)
|
||||
<< "cannot rename view " << viewId << " in database "
|
||||
<< databaseId << ": name attribute is no string";
|
||||
++state->errorCount;
|
||||
return state->canContinue();
|
||||
}
|
||||
std::string name = nameSlice.copyString();
|
||||
|
||||
// check if other view exists with target name
|
||||
std::shared_ptr<arangodb::LogicalView> other = vocbase->lookupView(name);
|
||||
|
||||
if (other != nullptr) {
|
||||
if (other->id() == view->id()) {
|
||||
LOG_TOPIC(TRACE, arangodb::Logger::ENGINES)
|
||||
<< "view " << viewId << " in database " << databaseId
|
||||
<< " was already renamed; moving on";
|
||||
break;
|
||||
}
|
||||
|
||||
vocbase->dropView(other->id(), true);
|
||||
}
|
||||
|
||||
int res = vocbase->renameView(view, name);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
LOG_TOPIC(WARN, arangodb::Logger::ENGINES)
|
||||
<< "cannot rename view " << viewId << " in database "
|
||||
<< databaseId << " to '" << name
|
||||
<< "': " << TRI_errno_string(res);
|
||||
++state->errorCount;
|
||||
return state->canContinue();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TRI_DF_MARKER_VPACK_CHANGE_VIEW: {
|
||||
TRI_voc_tick_t const databaseId =
|
||||
MMFilesDatafileHelper::DatabaseId(marker);
|
||||
|
@ -911,12 +831,35 @@ bool MMFilesWalRecoverState::ReplayMarker(MMFilesMarker const* marker,
|
|||
}
|
||||
|
||||
// turn off sync temporarily if the database or collection are going to
|
||||
// be
|
||||
// dropped later
|
||||
// be dropped later
|
||||
bool const forceSync = state->willViewBeDropped(databaseId, viewId);
|
||||
|
||||
VPackSlice nameSlice = payloadSlice.get("name");
|
||||
if (nameSlice.isString() && !nameSlice.isEqualString(view->name())) {
|
||||
std::string name = nameSlice.copyString();
|
||||
// check if other view exists with target name
|
||||
std::shared_ptr<arangodb::LogicalView> other = vocbase->lookupView(name);
|
||||
if (other != nullptr) {
|
||||
if (other->id() == view->id()) {
|
||||
LOG_TOPIC(TRACE, arangodb::Logger::ENGINES)
|
||||
<< "view " << viewId << " in database " << databaseId
|
||||
<< " was already renamed; moving on";
|
||||
break;
|
||||
}
|
||||
vocbase->dropView(other->id(), true);
|
||||
}
|
||||
int res = vocbase->renameView(view, name);
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
LOG_TOPIC(WARN, arangodb::Logger::ENGINES)
|
||||
<< "cannot rename view " << viewId << " in database "
|
||||
<< databaseId << " to '" << name
|
||||
<< "': " << TRI_errno_string(res);
|
||||
++state->errorCount;
|
||||
return state->canContinue();
|
||||
}
|
||||
}
|
||||
|
||||
auto res = view->updateProperties(payloadSlice, false, forceSync);
|
||||
|
||||
if (!res.ok()) {
|
||||
LOG_TOPIC(WARN, arangodb::Logger::ENGINES)
|
||||
<< "cannot change properties for view " << viewId
|
||||
|
|
|
@ -45,7 +45,6 @@ bool MustReplicateWalMarkerType(MMFilesMarker const* marker, bool allowDBMarkers
|
|||
type == TRI_DF_MARKER_VPACK_DROP_DATABASE)) ||
|
||||
type == TRI_DF_MARKER_VPACK_CREATE_VIEW ||
|
||||
type == TRI_DF_MARKER_VPACK_DROP_VIEW ||
|
||||
type == TRI_DF_MARKER_VPACK_RENAME_VIEW ||
|
||||
type == TRI_DF_MARKER_VPACK_CHANGE_VIEW);
|
||||
}
|
||||
|
||||
|
@ -90,8 +89,6 @@ TRI_replication_operation_e TranslateType(MMFilesMarker const* marker) {
|
|||
return REPLICATION_VIEW_CREATE;
|
||||
case TRI_DF_MARKER_VPACK_DROP_VIEW:
|
||||
return REPLICATION_VIEW_DROP;
|
||||
case TRI_DF_MARKER_VPACK_RENAME_VIEW:
|
||||
return REPLICATION_VIEW_RENAME;
|
||||
case TRI_DF_MARKER_VPACK_CHANGE_VIEW:
|
||||
return REPLICATION_VIEW_CHANGE;
|
||||
|
||||
|
|
|
@ -169,7 +169,6 @@ static int StringifyMarker(MMFilesReplicationDumpContext* dump,
|
|||
case TRI_DF_MARKER_VPACK_CREATE_VIEW:
|
||||
case TRI_DF_MARKER_VPACK_RENAME_COLLECTION:
|
||||
case TRI_DF_MARKER_VPACK_CHANGE_COLLECTION:
|
||||
case TRI_DF_MARKER_VPACK_RENAME_VIEW:
|
||||
case TRI_DF_MARKER_VPACK_CHANGE_VIEW:
|
||||
case TRI_DF_MARKER_VPACK_DROP_DATABASE:
|
||||
case TRI_DF_MARKER_VPACK_DROP_COLLECTION:
|
||||
|
@ -262,7 +261,6 @@ static int SliceifyMarker(MMFilesReplicationDumpContext* dump,
|
|||
case TRI_DF_MARKER_VPACK_CREATE_VIEW:
|
||||
case TRI_DF_MARKER_VPACK_RENAME_COLLECTION:
|
||||
case TRI_DF_MARKER_VPACK_CHANGE_COLLECTION:
|
||||
case TRI_DF_MARKER_VPACK_RENAME_VIEW:
|
||||
case TRI_DF_MARKER_VPACK_CHANGE_VIEW:
|
||||
case TRI_DF_MARKER_VPACK_DROP_DATABASE:
|
||||
case TRI_DF_MARKER_VPACK_DROP_COLLECTION:
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "Utils/CollectionGuard.h"
|
||||
#include "Utils/OperationOptions.h"
|
||||
#include "VocBase/LogicalCollection.h"
|
||||
#include "VocBase/LogicalView.h"
|
||||
#include "VocBase/ManagedDocumentResult.h"
|
||||
#include "VocBase/voc-types.h"
|
||||
#include "VocBase/vocbase.h"
|
||||
|
@ -129,7 +130,7 @@ DatabaseInitialSyncer::DatabaseInitialSyncer(
|
|||
|
||||
/// @brief run method, performs a full synchronization
|
||||
Result DatabaseInitialSyncer::runWithInventory(bool incremental,
|
||||
VPackSlice inventoryColls) {
|
||||
VPackSlice dbInventory) {
|
||||
if (!_config.connection.valid()) {
|
||||
return Result(TRI_ERROR_INTERNAL, "invalid endpoint");
|
||||
}
|
||||
|
@ -196,23 +197,38 @@ Result DatabaseInitialSyncer::runWithInventory(bool incremental,
|
|||
}
|
||||
}
|
||||
|
||||
VPackBuilder inventoryResponse;
|
||||
if (!inventoryColls.isArray()) {
|
||||
VPackSlice collections, views;
|
||||
if (dbInventory.isObject()) {
|
||||
collections = dbInventory.get("collections"); // required
|
||||
views = dbInventory.get("views"); // optional
|
||||
}
|
||||
VPackBuilder inventoryResponse; // hold response data
|
||||
if (!collections.isArray()) {
|
||||
// caller did not supply an inventory, we need to fetch it
|
||||
Result res = fetchInventory(inventoryResponse);
|
||||
if (!res.ok()) {
|
||||
return res;
|
||||
}
|
||||
// we do not really care about the state response
|
||||
inventoryColls = inventoryResponse.slice().get("collections");
|
||||
if (!inventoryColls.isArray()) {
|
||||
collections = inventoryResponse.slice().get("collections");
|
||||
views = inventoryResponse.slice().get("views");
|
||||
if (!collections.isArray()) {
|
||||
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
|
||||
"collections section is missing from response");
|
||||
}
|
||||
}
|
||||
|
||||
if (_config.applier._restrictCollections.empty()) {
|
||||
r = handleViewCreation(views); // no requests to master
|
||||
if (r.fail()) {
|
||||
LOG_TOPIC(ERR, Logger::REPLICATION)
|
||||
<< "Error during initial sync: " << r.errorMessage();
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
// strip eventual objectIDs and then dump the collections
|
||||
auto pair = rocksutils::stripObjectIds(inventoryColls);
|
||||
auto pair = rocksutils::stripObjectIds(collections);
|
||||
r = handleLeaderCollections(pair.first, incremental);
|
||||
|
||||
// all done here, do not try to finish batch if master is unresponsive
|
||||
|
@ -1475,5 +1491,16 @@ Result DatabaseInitialSyncer::iterateCollections(
|
|||
// all ok
|
||||
return Result();
|
||||
}
|
||||
|
||||
/// @brief create non-existing views locally
|
||||
Result DatabaseInitialSyncer::handleViewCreation(VPackSlice const& views) {
|
||||
for (VPackSlice slice : VPackArrayIterator(views)) {
|
||||
Result res = createView(vocbase(), slice);
|
||||
if (res.fail()) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace arangodb
|
||||
|
|
|
@ -227,6 +227,9 @@ class DatabaseInitialSyncer final : public InitialSyncer {
|
|||
std::vector<std::pair<arangodb::velocypack::Slice,
|
||||
arangodb::velocypack::Slice>> const&,
|
||||
bool incremental, SyncPhase);
|
||||
|
||||
/// @brief create non-existing views locally
|
||||
Result handleViewCreation(VPackSlice const& views);
|
||||
|
||||
private:
|
||||
Configuration _config;
|
||||
|
|
|
@ -131,7 +131,7 @@ Result DatabaseTailingSyncer::syncCollectionFinalize(
|
|||
"&from=" + StringUtils::itoa(fromTick) +
|
||||
"&serverId=" + _state.localServerIdString +
|
||||
"&collection=" + StringUtils::urlEncode(collectionName);
|
||||
|
||||
|
||||
// send request
|
||||
std::unique_ptr<SimpleHttpResult> response(
|
||||
_state.connection.client->request(rest::RequestType::GET, url, nullptr,
|
||||
|
|
|
@ -164,23 +164,22 @@ Result GlobalInitialSyncer::runInternal(bool incremental) {
|
|||
|
||||
try {
|
||||
// actually sync the database
|
||||
for (auto const& database : VPackObjectIterator(databases)) {
|
||||
for (auto const& dbEntry : VPackObjectIterator(databases)) {
|
||||
if (application_features::ApplicationServer::isStopping()) {
|
||||
return Result(TRI_ERROR_SHUTTING_DOWN);
|
||||
} else if (isAborted()) {
|
||||
return Result(TRI_ERROR_REPLICATION_APPLIER_STOPPED);
|
||||
}
|
||||
|
||||
VPackSlice it = database.value;
|
||||
if (!it.isObject()) {
|
||||
VPackSlice dbInventory = dbEntry.value;
|
||||
if (!dbInventory.isObject()) {
|
||||
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
|
||||
"database declaration is invalid in response");
|
||||
}
|
||||
|
||||
VPackSlice const nameSlice = it.get("name");
|
||||
VPackSlice const idSlice = it.get("id");
|
||||
VPackSlice const collections = it.get("collections");
|
||||
|
||||
VPackSlice const nameSlice = dbInventory.get("name");
|
||||
VPackSlice const idSlice = dbInventory.get("id");
|
||||
VPackSlice const collections = dbInventory.get("collections");
|
||||
if (!nameSlice.isString() || !idSlice.isString() ||
|
||||
!collections.isArray()) {
|
||||
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
|
||||
|
@ -192,22 +191,20 @@ Result GlobalInitialSyncer::runInternal(bool incremental) {
|
|||
if (vocbase == nullptr) {
|
||||
return Result(TRI_ERROR_INTERNAL, "vocbase not found");
|
||||
}
|
||||
|
||||
|
||||
DatabaseGuard guard(nameSlice.copyString());
|
||||
|
||||
// change database name in place
|
||||
auto configurationCopy = _state.applier;
|
||||
|
||||
configurationCopy._database = nameSlice.copyString();
|
||||
|
||||
auto syncer = std::make_shared<DatabaseInitialSyncer>(*vocbase, configurationCopy);
|
||||
|
||||
syncer->useAsChildSyncer(_state.master, _state.barrier.id,
|
||||
_state.barrier.updateTime, _batch.id,
|
||||
_batch.updateTime);
|
||||
|
||||
// run the syncer with the supplied inventory collections
|
||||
Result r = syncer->runWithInventory(false, collections);
|
||||
Result r = syncer->runWithInventory(false, dbInventory);
|
||||
if (r.fail()) {
|
||||
return r;
|
||||
}
|
||||
|
@ -228,8 +225,8 @@ Result GlobalInitialSyncer::runInternal(bool incremental) {
|
|||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
/// @brief add or remove databases such that the local inventory mirrors the
|
||||
/// masters
|
||||
/// @brief add or remove databases such that the local inventory
|
||||
/// mirrors the masters
|
||||
Result GlobalInitialSyncer::updateServerInventory(
|
||||
VPackSlice const& masterDatabases) {
|
||||
std::set<std::string> existingDBs;
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "Utils/OperationResult.h"
|
||||
#include "Utils/SingleCollectionTransaction.h"
|
||||
#include "VocBase/LogicalCollection.h"
|
||||
#include "VocBase/LogicalView.h"
|
||||
#include "VocBase/voc-types.h"
|
||||
#include "VocBase/vocbase.h"
|
||||
|
||||
|
@ -442,8 +443,8 @@ std::shared_ptr<LogicalCollection> Syncer::resolveCollection(
|
|||
}
|
||||
|
||||
if (cid == 0) {
|
||||
LOG_TOPIC(ERR, Logger::REPLICATION)
|
||||
<< TRI_errno_string(TRI_ERROR_REPLICATION_INVALID_RESPONSE);
|
||||
LOG_TOPIC(ERR, Logger::REPLICATION) << "Invalid replication response: Was unable to resolve"
|
||||
<< " collection from marker: " << slice.toJson();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -525,7 +526,7 @@ Result Syncer::createCollection(TRI_vocbase_t& vocbase,
|
|||
bool forceRemoveCid = false;
|
||||
if (col != nullptr && _state.master.simulate32Client()) {
|
||||
forceRemoveCid = true;
|
||||
LOG_TOPIC(TRACE, Logger::REPLICATION)
|
||||
LOG_TOPIC(INFO, Logger::REPLICATION)
|
||||
<< "would have got a wrong collection!";
|
||||
// go on now and truncate or drop/re-create the collection
|
||||
}
|
||||
|
@ -561,7 +562,7 @@ Result Syncer::createCollection(TRI_vocbase_t& vocbase,
|
|||
}
|
||||
}
|
||||
|
||||
VPackSlice uuid = slice.get("globallyUniqueId");
|
||||
VPackSlice uuid = slice.get(StaticStrings::DataSourceGuid);
|
||||
// merge in "isSystem" attribute, doesn't matter if name does not start with
|
||||
// '_'
|
||||
VPackBuilder s;
|
||||
|
@ -574,7 +575,7 @@ Result Syncer::createCollection(TRI_vocbase_t& vocbase,
|
|||
// if we received a globallyUniqueId from the remote, then we will always
|
||||
// use this id so we can discard the "cid" and "id" values for the
|
||||
// collection
|
||||
s.add("id", VPackSlice::nullSlice());
|
||||
s.add(StaticStrings::DataSourceId, VPackSlice::nullSlice());
|
||||
s.add("cid", VPackSlice::nullSlice());
|
||||
}
|
||||
|
||||
|
@ -751,6 +752,103 @@ Result Syncer::dropIndex(arangodb::velocypack::Slice const& slice) {
|
|||
|
||||
return r;
|
||||
}
|
||||
|
||||
/// @brief creates a view, based on the VelocyPack provided
|
||||
Result Syncer::createView(TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& slice) {
|
||||
if (!slice.isObject()) {
|
||||
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
|
||||
"collection slice is no object");
|
||||
}
|
||||
|
||||
VPackSlice nameSlice = slice.get(StaticStrings::DataSourceName);
|
||||
if (!nameSlice.isString() || nameSlice.getStringLength() == 0) {
|
||||
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
|
||||
"no name specified for view");
|
||||
}
|
||||
VPackSlice guidSlice = slice.get("globallyUniqueId");
|
||||
if (!guidSlice.isString() || guidSlice.getStringLength() == 0) {
|
||||
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
|
||||
"no guid specified for view");
|
||||
}
|
||||
VPackSlice typeSlice = slice.get(StaticStrings::DataSourceType);
|
||||
if (!typeSlice.isString() || typeSlice.getStringLength() == 0) {
|
||||
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
|
||||
"no type specified for view");
|
||||
}
|
||||
|
||||
auto view = vocbase.lookupView(guidSlice.copyString());
|
||||
if (view) { // identical view already exists
|
||||
VPackSlice properties = slice.get("properties");
|
||||
if (properties.isObject()) {
|
||||
bool doSync = DatabaseFeature::DATABASE->forceSyncProperties();
|
||||
return view->updateProperties(properties, false, doSync);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
view = vocbase.lookupView(nameSlice.copyString());
|
||||
if (view) { // resolve name conflict by deleting existing
|
||||
Result res = vocbase.dropView(view->id(), /*dropSytem*/false);
|
||||
if (res.fail()) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
VPackBuilder s;
|
||||
s.openObject();
|
||||
s.add("id", VPackSlice::nullSlice());
|
||||
s.close();
|
||||
|
||||
VPackBuilder merged =
|
||||
VPackCollection::merge(slice, s.slice(), /*mergeValues*/ true,
|
||||
/*nullMeansRemove*/ true);
|
||||
|
||||
try {
|
||||
vocbase.createView(merged.slice());
|
||||
} catch (basics::Exception const& ex) {
|
||||
return Result(ex.code(), ex.what());
|
||||
} catch (std::exception const& ex) {
|
||||
return Result(TRI_ERROR_INTERNAL, ex.what());
|
||||
} catch (...) {
|
||||
return Result(TRI_ERROR_INTERNAL);
|
||||
}
|
||||
|
||||
return Result();
|
||||
}
|
||||
|
||||
/// @brief drops a view, based on the VelocyPack provided
|
||||
Result Syncer::dropView(arangodb::velocypack::Slice const& slice,
|
||||
bool reportError) {
|
||||
TRI_vocbase_t* vocbase = resolveVocbase(slice);
|
||||
if (vocbase == nullptr) {
|
||||
return Result(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
VPackSlice guidSlice = slice.get("globallyUniqueId");
|
||||
if (guidSlice.isNone()) {
|
||||
guidSlice = slice.get("cuid");
|
||||
}
|
||||
if (!guidSlice.isString() || guidSlice.getStringLength() == 0) {
|
||||
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
|
||||
"no guid specified for view");
|
||||
}
|
||||
|
||||
try {
|
||||
auto view = vocbase->lookupView(guidSlice.copyString());
|
||||
if (view != nullptr) { // ignore non-existing
|
||||
return vocbase->dropView(view->id(), false);
|
||||
}
|
||||
} catch (basics::Exception const& ex) {
|
||||
return Result(ex.code(), ex.what());
|
||||
} catch (std::exception const& ex) {
|
||||
return Result(TRI_ERROR_INTERNAL, ex.what());
|
||||
} catch (...) {
|
||||
return Result(TRI_ERROR_INTERNAL);
|
||||
}
|
||||
|
||||
return Result();
|
||||
}
|
||||
|
||||
void Syncer::reloadUsers() {
|
||||
AuthenticationFeature* af = AuthenticationFeature::instance();
|
||||
|
|
|
@ -195,6 +195,14 @@ class Syncer : public std::enable_shared_from_this<Syncer> {
|
|||
|
||||
/// @brief drops an index, based on the VelocyPack provided
|
||||
Result dropIndex(arangodb::velocypack::Slice const&);
|
||||
|
||||
/// @brief creates a view, based on the VelocyPack provided
|
||||
Result createView(TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& slice);
|
||||
|
||||
/// @brief drops a view, based on the VelocyPack provided
|
||||
Result dropView(arangodb::velocypack::Slice const&, bool reportError);
|
||||
|
||||
|
||||
// TODO worker safety
|
||||
virtual TRI_vocbase_t* resolveVocbase(velocypack::Slice const&);
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "Utils/CollectionGuard.h"
|
||||
#include "Utils/SingleCollectionTransaction.h"
|
||||
#include "VocBase/LogicalCollection.h"
|
||||
#include "VocBase/LogicalView.h"
|
||||
#include "VocBase/Methods/Databases.h"
|
||||
#include "VocBase/voc-types.h"
|
||||
#include "VocBase/vocbase.h"
|
||||
|
@ -621,8 +622,8 @@ Result TailingSyncer::renameCollection(VPackSlice const& slice) {
|
|||
return Result(vocbase->renameCollection(col, name, true));
|
||||
}
|
||||
|
||||
/// @brief changes the properties of a collection, based on the VelocyPack
|
||||
/// provided
|
||||
/// @brief changes the properties of a collection,
|
||||
/// based on the VelocyPack provided
|
||||
Result TailingSyncer::changeCollection(VPackSlice const& slice) {
|
||||
if (!slice.isObject()) {
|
||||
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
|
||||
|
@ -672,6 +673,66 @@ Result TailingSyncer::changeCollection(VPackSlice const& slice) {
|
|||
return guard.collection()->updateProperties(data, doSync);
|
||||
}
|
||||
|
||||
|
||||
/// @brief changes the properties of a view,
|
||||
/// based on the VelocyPack provided
|
||||
Result TailingSyncer::changeView(VPackSlice const& slice) {
|
||||
if (!slice.isObject()) {
|
||||
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
|
||||
"view marker slice is no object");
|
||||
}
|
||||
|
||||
VPackSlice data = slice.get("data");
|
||||
if (!data.isObject()) {
|
||||
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
|
||||
"data slice is no object in view change marker");
|
||||
}
|
||||
|
||||
VPackSlice d = data.get("deleted");
|
||||
bool const isDeleted = (d.isBool() && d.getBool());
|
||||
|
||||
TRI_vocbase_t* vocbase = resolveVocbase(slice);
|
||||
if (vocbase == nullptr) {
|
||||
if (isDeleted) {
|
||||
// not a problem if a view that is going to be deleted anyway
|
||||
// does not exist on slave
|
||||
return Result();
|
||||
}
|
||||
return Result(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
VPackSlice guidSlice = data.get(StaticStrings::DataSourceGuid);
|
||||
if (!guidSlice.isString() || guidSlice.getStringLength() == 0) {
|
||||
return Result(TRI_ERROR_REPLICATION_INVALID_RESPONSE,
|
||||
"no guid specified for view");
|
||||
}
|
||||
auto view = vocbase->lookupView(guidSlice.copyString());
|
||||
if (view == nullptr) {
|
||||
if (isDeleted) {
|
||||
// not a problem if a collection that is going to be deleted anyway
|
||||
// does not exist on slave
|
||||
return Result();
|
||||
}
|
||||
return Result(TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
||||
VPackSlice nameSlice = data.get(StaticStrings::DataSourceName);
|
||||
if (nameSlice.isString() && !nameSlice.isEqualString(view->name())) {
|
||||
int res = vocbase->renameView(view, nameSlice.copyString());
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
VPackSlice properties = data.get("properties");
|
||||
if (properties.isObject()) {
|
||||
bool doSync = DatabaseFeature::DATABASE->forceSyncProperties();
|
||||
return view->updateProperties(properties, false, doSync);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
/// @brief apply a single marker from the continuous log
|
||||
Result TailingSyncer::applyLogMarker(VPackSlice const& slice,
|
||||
TRI_voc_tick_t firstRegularTick) {
|
||||
|
@ -764,16 +825,35 @@ Result TailingSyncer::applyLogMarker(VPackSlice const& slice,
|
|||
return createIndex(slice);
|
||||
} else if (type == REPLICATION_INDEX_DROP) {
|
||||
return dropIndex(slice);
|
||||
} else if (type == REPLICATION_VIEW_CREATE) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_NOT_IMPLEMENTED,
|
||||
"view create not yet implemented");
|
||||
}
|
||||
|
||||
else if (type == REPLICATION_VIEW_CREATE) {
|
||||
if (_ignoreRenameCreateDrop) {
|
||||
LOG_TOPIC(DEBUG, Logger::REPLICATION) << "Ignoring view create marker";
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
TRI_vocbase_t* vocbase = resolveVocbase(slice);
|
||||
|
||||
if (vocbase == nullptr) {
|
||||
LOG_TOPIC(WARN, Logger::REPLICATION)
|
||||
<< "Did not find database for " << slice.toJson();
|
||||
return Result(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
return createView(*vocbase, slice.get("data"));
|
||||
} else if (type == REPLICATION_VIEW_DROP) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_NOT_IMPLEMENTED,
|
||||
"view drop not yet implemented");
|
||||
if (_ignoreRenameCreateDrop) {
|
||||
LOG_TOPIC(DEBUG, Logger::REPLICATION) << "Ignoring view drop marker";
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
return dropView(slice, false);
|
||||
} else if (type == REPLICATION_VIEW_CHANGE) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_NOT_IMPLEMENTED,
|
||||
"view change not yet implemented");
|
||||
} else if (type == REPLICATION_DATABASE_CREATE ||
|
||||
return changeView(slice);
|
||||
}
|
||||
|
||||
else if (type == REPLICATION_DATABASE_CREATE ||
|
||||
type == REPLICATION_DATABASE_DROP) {
|
||||
if (_ignoreDatabaseMarkers) {
|
||||
LOG_TOPIC(DEBUG, Logger::REPLICATION) << "Ignoring database marker";
|
||||
|
|
|
@ -97,9 +97,13 @@ class TailingSyncer : public Syncer {
|
|||
/// @brief renames a collection, based on the VelocyPack provided
|
||||
Result renameCollection(arangodb::velocypack::Slice const&);
|
||||
|
||||
/// @brief changes the properties of a collection, based on the VelocyPack
|
||||
/// provided
|
||||
/// @brief changes the properties of a collection,
|
||||
/// based on the VelocyPack provided
|
||||
Result changeCollection(arangodb::velocypack::Slice const&);
|
||||
|
||||
/// @brief changes the properties of a collection,
|
||||
/// based on the VelocyPack provided
|
||||
Result changeView(arangodb::velocypack::Slice const&);
|
||||
|
||||
/// @brief apply a single marker from the continuous log
|
||||
Result applyLogMarker(arangodb::velocypack::Slice const&, TRI_voc_tick_t);
|
||||
|
|
|
@ -49,7 +49,6 @@ typedef enum {
|
|||
REPLICATION_VIEW_CREATE = 2110,
|
||||
REPLICATION_VIEW_DROP = 2111,
|
||||
REPLICATION_VIEW_CHANGE = 2112,
|
||||
REPLICATION_VIEW_RENAME = 2113,
|
||||
|
||||
REPLICATION_TRANSACTION_START = 2200,
|
||||
REPLICATION_TRANSACTION_COMMIT = 2201,
|
||||
|
|
|
@ -1333,68 +1333,31 @@ void RocksDBEngine::unloadCollection(
|
|||
collection.setStatus(TRI_VOC_COL_STATUS_UNLOADED);
|
||||
}
|
||||
|
||||
void RocksDBEngine::createView(
|
||||
Result RocksDBEngine::createView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
TRI_voc_cid_t id,
|
||||
arangodb::LogicalView const& /*view*/
|
||||
arangodb::LogicalView const& view
|
||||
) {
|
||||
rocksdb::WriteBatch batch;
|
||||
rocksdb::WriteOptions wo;
|
||||
|
||||
RocksDBLogValue logValue = RocksDBLogValue::ViewCreate(vocbase.id(), id);
|
||||
RocksDBKey key;
|
||||
|
||||
key.constructView(vocbase.id(), id);
|
||||
RocksDBLogValue logValue = RocksDBLogValue::ViewCreate(vocbase.id(), id);
|
||||
|
||||
auto value = RocksDBValue::View(VPackSlice::emptyObjectSlice());
|
||||
|
||||
VPackBuilder props;
|
||||
props.openObject();
|
||||
view.toVelocyPack(props, true, true);
|
||||
props.close();
|
||||
RocksDBValue const value = RocksDBValue::View(props.slice());
|
||||
|
||||
// Write marker + key into RocksDB inside one batch
|
||||
batch.PutLogData(logValue.slice());
|
||||
batch.Put(RocksDBColumnFamily::definitions(), key.string(), value.string());
|
||||
auto res = _db->Write(wo, &batch);
|
||||
auto status = rocksutils::convertStatus(res);
|
||||
|
||||
if (!status.ok()) {
|
||||
THROW_ARANGO_EXCEPTION(status);
|
||||
}
|
||||
return rocksutils::convertStatus(res);
|
||||
}
|
||||
|
||||
// asks the storage engine to persist renaming of a view
|
||||
// This will write a renameMarker if not in recovery
|
||||
Result RocksDBEngine::renameView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::LogicalView const& view,
|
||||
std::string const& /*oldName*/
|
||||
) {
|
||||
return persistView(vocbase, view);
|
||||
}
|
||||
|
||||
arangodb::Result RocksDBEngine::persistView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::LogicalView const& view
|
||||
) {
|
||||
auto db = rocksutils::globalRocksDB();
|
||||
RocksDBKey key;
|
||||
|
||||
key.constructView(vocbase.id(), view.id());
|
||||
|
||||
VPackBuilder infoBuilder;
|
||||
|
||||
infoBuilder.openObject();
|
||||
view.toVelocyPack(infoBuilder, true, true);
|
||||
infoBuilder.close();
|
||||
|
||||
auto const value = RocksDBValue::View(infoBuilder.slice());
|
||||
|
||||
rocksdb::WriteOptions options; // TODO: check which options would make sense
|
||||
|
||||
rocksdb::Status const status = db->Put(
|
||||
options, RocksDBColumnFamily::definitions(), key.string(), value.string()
|
||||
);
|
||||
|
||||
return rocksutils::convertStatus(status);
|
||||
}
|
||||
|
||||
|
||||
arangodb::Result RocksDBEngine::dropView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
LogicalView& view
|
||||
|
@ -1406,9 +1369,9 @@ arangodb::Result RocksDBEngine::dropView(
|
|||
builder.close();
|
||||
|
||||
auto logValue =
|
||||
RocksDBLogValue::ViewDrop(vocbase.id(), view.id(), builder.slice());
|
||||
RocksDBLogValue::ViewDrop(vocbase.id(), view.id(),
|
||||
StringRef(view.guid()));
|
||||
RocksDBKey key;
|
||||
|
||||
key.constructView(vocbase.id(), view.id());
|
||||
|
||||
rocksdb::WriteBatch batch;
|
||||
|
@ -1428,25 +1391,41 @@ void RocksDBEngine::destroyView(
|
|||
// nothing to do here
|
||||
}
|
||||
|
||||
void RocksDBEngine::changeView(
|
||||
Result RocksDBEngine::changeView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
TRI_voc_cid_t /*id*/,
|
||||
arangodb::LogicalView const& view,
|
||||
bool /*doSync*/
|
||||
) {
|
||||
if (inRecovery()) {
|
||||
// nothing to do
|
||||
return;
|
||||
return {};
|
||||
}
|
||||
|
||||
auto const res = persistView(vocbase, view);
|
||||
|
||||
if (!res.ok()) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||
res.errorNumber(),
|
||||
"could not save view properties"
|
||||
);
|
||||
RocksDBKey key;
|
||||
key.constructView(vocbase.id(), view.id());
|
||||
|
||||
VPackBuilder infoBuilder;
|
||||
infoBuilder.openObject();
|
||||
view.toVelocyPack(infoBuilder, true, true);
|
||||
infoBuilder.close();
|
||||
|
||||
RocksDBLogValue log = RocksDBLogValue::ViewChange(vocbase.id(), view.id());
|
||||
RocksDBValue const value = RocksDBValue::View(infoBuilder.slice());
|
||||
|
||||
rocksdb::WriteBatch batch;
|
||||
rocksdb::WriteOptions wo; // TODO: check which options would make sense
|
||||
rocksdb::Status s;
|
||||
s = batch.PutLogData(log.slice());
|
||||
if (!s.ok()) {
|
||||
return rocksutils::convertStatus(s);
|
||||
}
|
||||
s = batch.Put(RocksDBColumnFamily::definitions(),
|
||||
key.string(), value.string());
|
||||
if (!s.ok()) {
|
||||
return rocksutils::convertStatus(s);
|
||||
}
|
||||
auto db = rocksutils::globalRocksDB();
|
||||
return rocksutils::convertStatus(db->Write(wo, &batch));
|
||||
}
|
||||
|
||||
void RocksDBEngine::signalCleanup(TRI_vocbase_t& vocbase) {
|
||||
|
|
|
@ -269,14 +269,13 @@ class RocksDBEngine final : public StorageEngine {
|
|||
LogicalCollection& collection
|
||||
) override;
|
||||
|
||||
void changeView(
|
||||
arangodb::Result changeView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
TRI_voc_cid_t id,
|
||||
arangodb::LogicalView const& view,
|
||||
bool doSync
|
||||
) override;
|
||||
|
||||
void createView(
|
||||
arangodb::Result createView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
TRI_voc_cid_t id,
|
||||
arangodb::LogicalView const& view
|
||||
|
@ -290,19 +289,6 @@ class RocksDBEngine final : public StorageEngine {
|
|||
// does nothing
|
||||
}
|
||||
|
||||
arangodb::Result persistView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::LogicalView const& view
|
||||
) override;
|
||||
|
||||
// asks the storage engine to persist renaming of a view
|
||||
// This will write a renameMarker if not in recovery
|
||||
arangodb::Result renameView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::LogicalView const& view,
|
||||
std::string const& oldName
|
||||
) override;
|
||||
|
||||
arangodb::Result dropView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
LogicalView& view
|
||||
|
|
|
@ -80,8 +80,8 @@ RocksDBLogValue RocksDBLogValue::ViewCreate(TRI_voc_tick_t dbid,
|
|||
|
||||
RocksDBLogValue RocksDBLogValue::ViewDrop(TRI_voc_tick_t dbid,
|
||||
TRI_voc_cid_t vid,
|
||||
VPackSlice const& viewInfo) {
|
||||
return RocksDBLogValue(RocksDBLogType::ViewDrop, dbid, vid, viewInfo);
|
||||
StringRef const& uuid) {
|
||||
return RocksDBLogValue(RocksDBLogType::ViewDrop, dbid, vid, uuid);
|
||||
}
|
||||
|
||||
RocksDBLogValue RocksDBLogValue::ViewChange(TRI_voc_tick_t dbid,
|
||||
|
@ -89,11 +89,6 @@ RocksDBLogValue RocksDBLogValue::ViewChange(TRI_voc_tick_t dbid,
|
|||
return RocksDBLogValue(RocksDBLogType::ViewChange, dbid, vid);
|
||||
}
|
||||
|
||||
RocksDBLogValue RocksDBLogValue::ViewRename(TRI_voc_cid_t cid,
|
||||
TRI_idx_iid_t iid) {
|
||||
return RocksDBLogValue(RocksDBLogType::ViewRename, cid, iid);
|
||||
}
|
||||
|
||||
#ifdef USE_IRESEARCH
|
||||
RocksDBLogValue RocksDBLogValue::IResearchLinkDrop(TRI_voc_tick_t dbid,
|
||||
TRI_voc_cid_t cid,
|
||||
|
@ -153,8 +148,8 @@ RocksDBLogValue::RocksDBLogValue(RocksDBLogType type, uint64_t dbId,
|
|||
switch (type) {
|
||||
case RocksDBLogType::CollectionCreate:
|
||||
case RocksDBLogType::CollectionChange:
|
||||
case RocksDBLogType::CollectionDrop:
|
||||
case RocksDBLogType::ViewCreate:
|
||||
case RocksDBLogType::ViewChange:
|
||||
case RocksDBLogType::BeginTransaction:
|
||||
case RocksDBLogType::SinglePut:
|
||||
case RocksDBLogType::CommitTransaction: {
|
||||
|
@ -216,8 +211,7 @@ RocksDBLogValue::RocksDBLogValue(RocksDBLogType type, uint64_t dbId,
|
|||
uint64_t cid, VPackSlice const& info)
|
||||
: _buffer() {
|
||||
switch (type) {
|
||||
case RocksDBLogType::IndexCreate:
|
||||
case RocksDBLogType::ViewDrop: {
|
||||
case RocksDBLogType::IndexCreate: {
|
||||
_buffer.reserve(sizeof(RocksDBLogType) + (sizeof(uint64_t) * 2) +
|
||||
info.byteSize());
|
||||
_buffer.push_back(static_cast<char>(type));
|
||||
|
@ -238,14 +232,13 @@ RocksDBLogValue::RocksDBLogValue(RocksDBLogType type, uint64_t dbId,
|
|||
: _buffer() {
|
||||
switch (type) {
|
||||
case RocksDBLogType::CollectionDrop:
|
||||
case RocksDBLogType::CollectionRename: {
|
||||
case RocksDBLogType::CollectionRename:
|
||||
case RocksDBLogType::ViewDrop: {
|
||||
_buffer.reserve(sizeof(RocksDBLogType) + sizeof(uint64_t) * 2 +
|
||||
data.length());
|
||||
_buffer.push_back(static_cast<char>(type));
|
||||
uint64ToPersistent(_buffer, dbId);
|
||||
uint64ToPersistent(_buffer, cid);
|
||||
// append primary key for SingleRemove, or
|
||||
// collection name for CollectionRename, or
|
||||
// collection uuid for CollectionDrop
|
||||
_buffer.append(data.data(), data.length());
|
||||
break;
|
||||
|
@ -356,18 +349,29 @@ VPackSlice RocksDBLogValue::viewSlice(rocksdb::Slice const& slice) {
|
|||
sizeof(uint64_t) * 2);
|
||||
}
|
||||
|
||||
namespace {
|
||||
StringRef dropMarkerUUID(rocksdb::Slice const& slice) {
|
||||
size_t off = sizeof(RocksDBLogType) + sizeof(uint64_t) * 2;
|
||||
TRI_ASSERT(slice.size() >= off);
|
||||
RocksDBLogType type = static_cast<RocksDBLogType>(slice.data()[0]);
|
||||
TRI_ASSERT(type == RocksDBLogType::CollectionDrop ||
|
||||
type == RocksDBLogType::ViewDrop);
|
||||
if (slice.size() > off) {
|
||||
// have a UUID
|
||||
return StringRef(slice.data() + off, slice.size() - off);
|
||||
}
|
||||
// do not have a UUID
|
||||
return StringRef();
|
||||
}
|
||||
}
|
||||
|
||||
StringRef RocksDBLogValue::collectionUUID(
|
||||
rocksdb::Slice const& slice) {
|
||||
size_t off = sizeof(RocksDBLogType) + sizeof(uint64_t) * 2;
|
||||
TRI_ASSERT(slice.size() >= off);
|
||||
RocksDBLogType type = static_cast<RocksDBLogType>(slice.data()[0]);
|
||||
TRI_ASSERT(type == RocksDBLogType::CollectionDrop);
|
||||
if (slice.size() > off) {
|
||||
// have a UUID
|
||||
return StringRef(slice.data() + off, slice.size() - off);
|
||||
}
|
||||
// do not have a UUID
|
||||
return StringRef();
|
||||
return ::dropMarkerUUID(slice);
|
||||
}
|
||||
|
||||
StringRef RocksDBLogValue::viewUUID(rocksdb::Slice const& slice) {
|
||||
return ::dropMarkerUUID(slice);
|
||||
}
|
||||
|
||||
StringRef RocksDBLogValue::oldCollectionName(
|
||||
|
@ -388,7 +392,6 @@ bool RocksDBLogValue::containsDatabaseId(RocksDBLogType type) {
|
|||
type == RocksDBLogType::CollectionChange ||
|
||||
type == RocksDBLogType::ViewCreate ||
|
||||
type == RocksDBLogType::ViewDrop ||
|
||||
type == RocksDBLogType::ViewRename ||
|
||||
type == RocksDBLogType::ViewChange ||
|
||||
#ifdef USE_IRESEARCH
|
||||
type == RocksDBLogType::IResearchLinkDrop ||
|
||||
|
@ -418,7 +421,6 @@ bool RocksDBLogValue::containsCollectionId(RocksDBLogType type) {
|
|||
bool RocksDBLogValue::containsViewId(RocksDBLogType type) {
|
||||
return type == RocksDBLogType::ViewCreate ||
|
||||
type == RocksDBLogType::ViewDrop ||
|
||||
type == RocksDBLogType::ViewRename ||
|
||||
#ifdef USE_IRESEARCH
|
||||
type == RocksDBLogType::IResearchLinkDrop ||
|
||||
#endif
|
||||
|
|
|
@ -64,9 +64,8 @@ class RocksDBLogValue {
|
|||
|
||||
static RocksDBLogValue ViewCreate(TRI_voc_tick_t, TRI_voc_cid_t);
|
||||
static RocksDBLogValue ViewDrop(TRI_voc_tick_t, TRI_voc_cid_t,
|
||||
VPackSlice const& viewInfo);
|
||||
StringRef const& uuid);
|
||||
static RocksDBLogValue ViewChange(TRI_voc_tick_t, TRI_voc_cid_t);
|
||||
static RocksDBLogValue ViewRename(TRI_voc_tick_t, TRI_voc_cid_t);
|
||||
|
||||
#ifdef USE_IRESEARCH
|
||||
static RocksDBLogValue IResearchLinkDrop(TRI_voc_tick_t, TRI_voc_cid_t,
|
||||
|
@ -91,11 +90,16 @@ class RocksDBLogValue {
|
|||
static TRI_voc_cid_t collectionId(rocksdb::Slice const&);
|
||||
static TRI_voc_cid_t viewId(rocksdb::Slice const&);
|
||||
static TRI_idx_iid_t indexId(rocksdb::Slice const&);
|
||||
/// For DocumentRemoveV2 and SingleRemoveV2
|
||||
// ==== For DocumentRemoveV2 and SingleRemoveV2 ====
|
||||
static TRI_voc_rid_t revisionId(rocksdb::Slice const&);
|
||||
static velocypack::Slice indexSlice(rocksdb::Slice const&);
|
||||
static velocypack::Slice viewSlice(rocksdb::Slice const&);
|
||||
/// @brief get UUID from collection drop marker
|
||||
static arangodb::StringRef collectionUUID(rocksdb::Slice const&);
|
||||
/// @brief get UUID from view drop marker
|
||||
static arangodb::StringRef viewUUID(rocksdb::Slice const&);
|
||||
|
||||
// deprecated method for old collection drop marker
|
||||
static arangodb::StringRef oldCollectionName(rocksdb::Slice const&);
|
||||
|
||||
static bool containsDatabaseId(RocksDBLogType type);
|
||||
|
@ -107,10 +111,6 @@ class RocksDBLogValue {
|
|||
/// @brief Returns a reference to the underlying string buffer.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
std::string const& string() const { return _buffer; } // to be used with put
|
||||
/*VPackSlice slice() const { return VPackSlice(
|
||||
reinterpret_cast<uint8_t const*>(_buffer.data())
|
||||
); }*/ // return a slice
|
||||
|
||||
RocksDBLogType type() const {
|
||||
return static_cast<RocksDBLogType>(*(_buffer.data()));
|
||||
}
|
||||
|
|
|
@ -238,10 +238,8 @@ class WALParser final : public rocksdb::WriteBatch::Handler {
|
|||
}
|
||||
case RocksDBLogType::ViewCreate:
|
||||
case RocksDBLogType::ViewDrop:
|
||||
case RocksDBLogType::ViewChange:
|
||||
case RocksDBLogType::ViewRename: {
|
||||
case RocksDBLogType::ViewChange: {
|
||||
resetTransientState(); // finish ongoing trx
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
case RocksDBLogType::BeginTransaction: {
|
||||
|
|
|
@ -196,8 +196,6 @@ char const* arangodb::rocksDBLogTypeName(arangodb::RocksDBLogType type) {
|
|||
return "ViewDrop";
|
||||
case arangodb::RocksDBLogType::ViewChange:
|
||||
return "ViewChange";
|
||||
case arangodb::RocksDBLogType::ViewRename:
|
||||
return "ViewRename";
|
||||
#ifdef USE_IRESEARCH
|
||||
case arangodb::RocksDBLogType::IResearchLinkDrop:
|
||||
return "IResearchLinkDrop";
|
||||
|
|
|
@ -79,7 +79,6 @@ enum class RocksDBLogType : char {
|
|||
SinglePut = '?',
|
||||
SingleRemove = '@', // <- deprecated
|
||||
DocumentRemoveAsPartOfUpdate = 'A', // <- deprecated
|
||||
ViewRename = 'B',
|
||||
#ifdef USE_IRESEARCH
|
||||
IResearchLinkDrop = 'C',
|
||||
#endif
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "RocksDBEngine/RocksDBTypes.h"
|
||||
#include "Utils/DatabaseGuard.h"
|
||||
#include "VocBase/LogicalCollection.h"
|
||||
#include "VocBase/LogicalView.h"
|
||||
|
||||
#include "Logger/Logger.h"
|
||||
|
||||
|
@ -88,15 +89,12 @@ class MyWALParser : public rocksdb::WriteBatch::Handler, public WalAccessContext
|
|||
DB_CREATE,
|
||||
DB_DROP,
|
||||
COLLECTION_CREATE,
|
||||
COLLECTION_DROP,
|
||||
COLLECTION_RENAME,
|
||||
COLLECTION_CHANGE,
|
||||
INDEX_CREATE,
|
||||
INDEX_DROP,
|
||||
VIEW_CREATE,
|
||||
VIEW_DROP,
|
||||
VIEW_CHANGE,
|
||||
VIEW_RENAME,
|
||||
TRANSACTION,
|
||||
SINGLE_PUT,
|
||||
SINGLE_REMOVE
|
||||
|
@ -165,7 +163,7 @@ class MyWALParser : public rocksdb::WriteBatch::Handler, public WalAccessContext
|
|||
TRI_vocbase_t* vocbase = loadVocbase(dbid);
|
||||
if (vocbase != nullptr) {
|
||||
{ // tick number
|
||||
StringRef uuid = RocksDBLogValue::collectionUUID(blob);
|
||||
StringRef uuid = RocksDBLogValue::viewUUID(blob);
|
||||
TRI_ASSERT(!uuid.empty());
|
||||
uint64_t tick = _currentSequence + (_startOfBatch ? 0 : 1);
|
||||
VPackObjectBuilder marker(&_builder, true);
|
||||
|
@ -245,17 +243,53 @@ class MyWALParser : public rocksdb::WriteBatch::Handler, public WalAccessContext
|
|||
_responseSize += _builder.size();
|
||||
_builder.clear();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case RocksDBLogType::ViewCreate:
|
||||
case RocksDBLogType::ViewDrop:
|
||||
case RocksDBLogType::ViewChange:
|
||||
case RocksDBLogType::ViewRename: {
|
||||
resetTransientState(); // finish ongoing trx
|
||||
// TODO
|
||||
if (shouldHandleView(RocksDBLogValue::databaseId(blob),
|
||||
RocksDBLogValue::viewId(blob))) {
|
||||
_state = VIEW_CREATE;
|
||||
}
|
||||
// wait for marker data in Put entry
|
||||
break;
|
||||
|
||||
case RocksDBLogType::ViewDrop: {
|
||||
resetTransientState(); // finish ongoing trx
|
||||
TRI_voc_tick_t dbid = RocksDBLogValue::databaseId(blob);
|
||||
TRI_voc_cid_t vid = RocksDBLogValue::viewId(blob);
|
||||
if (shouldHandleView(dbid, vid)) {
|
||||
TRI_vocbase_t* vocbase = loadVocbase(dbid);
|
||||
if (vocbase != nullptr) {
|
||||
{ // tick number
|
||||
StringRef uuid = RocksDBLogValue::collectionUUID(blob);
|
||||
TRI_ASSERT(!uuid.empty());
|
||||
uint64_t tick = _currentSequence + (_startOfBatch ? 0 : 1);
|
||||
VPackObjectBuilder marker(&_builder, true);
|
||||
marker->add("tick", VPackValue(std::to_string(tick)));
|
||||
marker->add("type", VPackValue(REPLICATION_VIEW_DROP));
|
||||
marker->add("db", VPackValue(vocbase->name()));
|
||||
marker->add("cuid", VPackValuePair(uuid.data(), uuid.size(),
|
||||
VPackValueType::String));
|
||||
}
|
||||
_callback(vocbase, _builder.slice());
|
||||
_responseSize += _builder.size();
|
||||
_builder.clear();
|
||||
}
|
||||
}
|
||||
// wait for marker data in Put entry
|
||||
break;
|
||||
}
|
||||
|
||||
case RocksDBLogType::ViewChange:
|
||||
resetTransientState(); // finish ongoing trx
|
||||
if (shouldHandleView(RocksDBLogValue::databaseId(blob),
|
||||
RocksDBLogValue::viewId(blob))) {
|
||||
_state = VIEW_CHANGE;
|
||||
}
|
||||
// wait for marker data in Put entry
|
||||
break;
|
||||
|
||||
case RocksDBLogType::BeginTransaction: {
|
||||
resetTransientState(); // finish ongoing trx
|
||||
TRI_voc_tid_t tid = RocksDBLogValue::transactionId(blob);
|
||||
|
@ -329,7 +363,8 @@ class MyWALParser : public rocksdb::WriteBatch::Handler, public WalAccessContext
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case RocksDBLogType::IResearchLinkDrop: // do nothing
|
||||
case RocksDBLogType::DocumentOperationsPrologue:
|
||||
case RocksDBLogType::DocumentRemove:
|
||||
case RocksDBLogType::DocumentRemoveAsPartOfUpdate:
|
||||
|
@ -428,7 +463,38 @@ class MyWALParser : public rocksdb::WriteBatch::Handler, public WalAccessContext
|
|||
_responseSize += _builder.size();
|
||||
_builder.clear();
|
||||
}
|
||||
} // if (RocksDBKey::type(key) == RocksDBEntryType::Collection)
|
||||
} else if (RocksDBKey::type(key) == RocksDBEntryType::View) {
|
||||
|
||||
TRI_voc_tick_t dbid = RocksDBKey::databaseId(key);
|
||||
TRI_voc_cid_t vid = RocksDBKey::viewId(key);
|
||||
|
||||
if (shouldHandleView(dbid, vid) && (_state == VIEW_CREATE ||
|
||||
_state == VIEW_CHANGE)) {
|
||||
TRI_vocbase_t* vocbase = loadVocbase(dbid);
|
||||
TRI_ASSERT(vocbase != nullptr);
|
||||
auto view = vocbase->lookupView(vid);
|
||||
|
||||
if (view != nullptr) { // ignore nonexisting views
|
||||
VPackSlice viewDef = RocksDBValue::data(value);
|
||||
{
|
||||
VPackObjectBuilder marker(&_builder, true);
|
||||
marker->add("tick", VPackValue(std::to_string(_currentSequence)));
|
||||
marker->add("db", VPackValue(vocbase->name()));
|
||||
marker->add("cuid", VPackValue(view->guid()));
|
||||
marker->add("data", viewDef);
|
||||
if (_state == VIEW_CREATE) {
|
||||
marker->add("type", VPackValue(REPLICATION_VIEW_CREATE));
|
||||
} else /*if (_state == VIEW_CHANGE)*/ {
|
||||
marker->add("type", VPackValue(REPLICATION_VIEW_CHANGE));
|
||||
}
|
||||
}
|
||||
|
||||
_callback(vocbase, _builder.slice());
|
||||
_responseSize += _builder.size();
|
||||
_builder.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// reset everything immediately after DDL operations
|
||||
resetTransientState();
|
||||
|
|
|
@ -325,9 +325,8 @@ class StorageEngine : public application_features::ApplicationFeature {
|
|||
// property changes and throw only then, so that subsequent operations will not fail.
|
||||
// the WAL entry for the propery change will be written *after* the call
|
||||
// to "changeView" returns
|
||||
virtual void changeView(
|
||||
virtual arangodb::Result changeView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
TRI_voc_cid_t id,
|
||||
arangodb::LogicalView const& view,
|
||||
bool doSync
|
||||
) = 0;
|
||||
|
@ -341,7 +340,7 @@ class StorageEngine : public application_features::ApplicationFeature {
|
|||
// and throw only then, so that subsequent view creation requests will not fail.
|
||||
// the WAL entry for the view creation will be written *after* the call
|
||||
// to "createCview" returns
|
||||
virtual void createView(
|
||||
virtual arangodb::Result createView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
TRI_voc_cid_t id,
|
||||
arangodb::LogicalView const& view
|
||||
|
@ -355,20 +354,6 @@ class StorageEngine : public application_features::ApplicationFeature {
|
|||
VPackBuilder& builder
|
||||
) = 0;
|
||||
|
||||
// asks the storage engine to persist the view.
|
||||
// After this call the view is persisted over recovery.
|
||||
virtual arangodb::Result persistView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::LogicalView const& view
|
||||
) = 0;
|
||||
|
||||
// asks the storage engine to persist renaming of a view
|
||||
virtual arangodb::Result renameView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::LogicalView const& view,
|
||||
std::string const& oldName
|
||||
) = 0;
|
||||
|
||||
// asks the storage engine to drop the specified view and persist the
|
||||
// deletion info. Note that physical deletion of the view data must not
|
||||
// be carried out by this call, as there may
|
||||
|
|
|
@ -33,6 +33,20 @@ bool WalAccessContext::shouldHandleDB(TRI_voc_tick_t dbid) const {
|
|||
return _filter.vocbase == 0 || _filter.vocbase == dbid;
|
||||
}
|
||||
|
||||
/// @brief check if view should be handled, might already be deleted
|
||||
bool WalAccessContext::shouldHandleView(TRI_voc_tick_t dbid,
|
||||
TRI_voc_cid_t vid) const {
|
||||
if (dbid == 0 || vid == 0 || !shouldHandleDB(dbid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_filter.vocbase == 0 || (_filter.vocbase == dbid &&
|
||||
(_filter.collection == 0 || _filter.collection == vid))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @brief Check if collection is in filter, will load collection
|
||||
bool WalAccessContext::shouldHandleCollection(TRI_voc_tick_t dbid,
|
||||
TRI_voc_cid_t cid) {
|
||||
|
|
|
@ -143,6 +143,10 @@ struct WalAccessContext {
|
|||
|
||||
/// @brief check if db should be handled, might already be deleted
|
||||
bool shouldHandleDB(TRI_voc_tick_t dbid) const;
|
||||
|
||||
/// @brief check if view should be handled, might already be deleted
|
||||
bool shouldHandleView(TRI_voc_tick_t dbid,
|
||||
TRI_voc_cid_t vid) const;
|
||||
|
||||
/// @brief Check if collection is in filter, will load collection
|
||||
/// and prevent deletion
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
|
||||
#include <mutex>
|
||||
|
||||
#include "LogicalDataSource.h"
|
||||
|
||||
#include "Basics/conversions.h"
|
||||
#include "Basics/VelocyPackHelper.h"
|
||||
#include "Cluster/ClusterInfo.h"
|
||||
|
@ -33,7 +35,8 @@
|
|||
#include "VocBase/LogicalCollection.h"
|
||||
#include "VocBase/ticks.h"
|
||||
|
||||
#include "LogicalDataSource.h"
|
||||
//
|
||||
#include "Logger/Logger.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -50,25 +53,26 @@ std::string ensureGuid(
|
|||
|
||||
guid.reserve(64);
|
||||
|
||||
if (arangodb::ServerState::instance()->isCoordinator()) {
|
||||
// view GUIDs are added to the ClusterInfo. To avoid conflicts
|
||||
// with collection names we always put in a '/' which is an illegal
|
||||
// character for collection names. Stringified collection or view
|
||||
// id numbers can also not conflict, first character is always 'h'
|
||||
if (arangodb::ServerState::instance()->isCoordinator() ||
|
||||
arangodb::ServerState::instance()->isDBServer()) {
|
||||
TRI_ASSERT(planId);
|
||||
guid.append("c");
|
||||
guid.append(std::to_string(planId));
|
||||
} else if (arangodb::ServerState::instance()->isDBServer()) {
|
||||
TRI_ASSERT(planId);
|
||||
guid.append("c");
|
||||
// we add the shard name to the collection. If we ever
|
||||
// replicate shards, we can identify them cluster-wide
|
||||
guid.append(std::to_string(planId));
|
||||
guid.push_back('/');
|
||||
guid.append(name);
|
||||
if (arangodb::ServerState::instance()->isDBServer()) {
|
||||
// we add the shard name to the collection. If we ever
|
||||
// replicate shards, we can identify them cluster-wide
|
||||
guid.append(name);
|
||||
}
|
||||
} else if (isSystem) {
|
||||
guid.append(name);
|
||||
} else {
|
||||
char buf[sizeof(TRI_server_id_t) * 2 + 1];
|
||||
auto len =
|
||||
TRI_StringUInt64HexInPlace(arangodb::ServerIdFeature::getId(), buf);
|
||||
|
||||
auto len = TRI_StringUInt64HexInPlace(arangodb::ServerIdFeature::getId(), buf);
|
||||
TRI_ASSERT(id);
|
||||
guid.append("h");
|
||||
guid.append(buf, len);
|
||||
|
|
|
@ -288,9 +288,7 @@ arangodb::Result LogicalViewStorageEngine::appendVelocyPack(
|
|||
}
|
||||
#endif
|
||||
|
||||
engine->createView(view.vocbase(), view.id(), view);
|
||||
|
||||
return engine->persistView(view.vocbase(), view);
|
||||
return engine->createView(view.vocbase(), view.id(), view);
|
||||
} catch (std::exception const& e) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
|
@ -330,7 +328,8 @@ Result LogicalViewStorageEngine::rename(std::string&& newName, bool doSync) {
|
|||
|
||||
// store new view definition to disk
|
||||
if (!engine->inRecovery()) {
|
||||
engine->changeView(vocbase(), id(), *this, doSync);
|
||||
// write WAL 'change' marker
|
||||
return engine->changeView(vocbase(), *this, doSync);
|
||||
}
|
||||
} catch (basics::Exception const& ex) {
|
||||
name(std::move(oldName));
|
||||
|
@ -342,8 +341,7 @@ Result LogicalViewStorageEngine::rename(std::string&& newName, bool doSync) {
|
|||
return TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
// write WAL 'rename' marker
|
||||
return engine->renameView(vocbase(), *this, oldName);
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
arangodb::Result LogicalViewStorageEngine::updateProperties(
|
||||
|
@ -368,7 +366,7 @@ arangodb::Result LogicalViewStorageEngine::updateProperties(
|
|||
}
|
||||
|
||||
try {
|
||||
engine->changeView(vocbase(), id(), *this, doSync);
|
||||
engine->changeView(vocbase(), *this, doSync);
|
||||
} catch (arangodb::basics::Exception const& e) {
|
||||
return { e.code() };
|
||||
} catch (...) {
|
||||
|
@ -382,4 +380,4 @@ arangodb::Result LogicalViewStorageEngine::updateProperties(
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -1207,8 +1207,8 @@ arangodb::LogicalCollection* TRI_vocbase_t::createCollection(
|
|||
}
|
||||
|
||||
auto res2 = engine->persistCollection(*this, *collection);
|
||||
// API compatibility, we always return the collection, even if creation
|
||||
// failed.
|
||||
// API compatibility, we always return the collection,
|
||||
// even if creation failed.
|
||||
|
||||
if (DatabaseFeature::DATABASE != nullptr &&
|
||||
DatabaseFeature::DATABASE->versionTracker() != nullptr) {
|
||||
|
|
|
@ -121,6 +121,7 @@ var compare = function(masterFunc, masterFunc2, slaveFuncOngoing, slaveFuncFinal
|
|||
applierConfiguration.endpoint = masterEndpoint;
|
||||
applierConfiguration.username = "root";
|
||||
applierConfiguration.password = "";
|
||||
applierConfiguration.force32mode = false;
|
||||
|
||||
if (!applierConfiguration.hasOwnProperty('chunkSize')) {
|
||||
applierConfiguration.chunkSize = 16384;
|
||||
|
|
|
@ -82,6 +82,7 @@ const compare = function(masterFunc, masterFunc2, slaveFuncOngoing, slaveFuncFin
|
|||
applierConfiguration.username = "root";
|
||||
applierConfiguration.password = "";
|
||||
applierConfiguration.includeSystem = false;
|
||||
applierConfiguration.force32mode = false;
|
||||
|
||||
var syncResult = replication.syncGlobal({
|
||||
endpoint: masterEndpoint,
|
||||
|
@ -635,6 +636,124 @@ function BaseTestConfig() {
|
|||
assertEqual(state.count, collectionCount(cn));
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
testViewBasic: function() {
|
||||
connectToMaster();
|
||||
|
||||
compare(
|
||||
function() {},
|
||||
function(state) {
|
||||
try {
|
||||
db._create(cn);
|
||||
let view = db._createView("UnitTestsSyncView", "arangosearch", {});
|
||||
let links = {};
|
||||
links[cn] = {
|
||||
includeAllFields: true,
|
||||
fields: {
|
||||
text: { analyzers: [ "text_en" ] }
|
||||
}
|
||||
};
|
||||
view.properties({"links": links});
|
||||
state.arangoSearchEnabled = true;
|
||||
} catch (err) { }
|
||||
},
|
||||
function() {},
|
||||
function(state) {
|
||||
if (!state.arangoSearchEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
let view = db._view("UnitTestsSyncView");
|
||||
assertTrue(view !== null);
|
||||
let props = view.properties();
|
||||
assertEqual(Object.keys(props.links).length, 1);
|
||||
assertTrue(props.hasOwnProperty("links"));
|
||||
assertTrue(props.links.hasOwnProperty(cn));
|
||||
},
|
||||
{}
|
||||
);
|
||||
},
|
||||
|
||||
testViewRename: function() {
|
||||
connectToMaster();
|
||||
|
||||
compare(
|
||||
function(state) {
|
||||
try {
|
||||
db._create(cn);
|
||||
let view = db._createView("UnitTestsSyncView", "arangosearch", {});
|
||||
let links = {};
|
||||
links[cn] = {
|
||||
includeAllFields: true,
|
||||
fields: {
|
||||
text: { analyzers: [ "text_en" ] }
|
||||
}
|
||||
};
|
||||
view.properties({"links": links});
|
||||
state.arangoSearchEnabled = true;
|
||||
} catch (err) { }
|
||||
},
|
||||
function(state) {
|
||||
if (!state.arangoSearchEnabled) {
|
||||
return;
|
||||
}
|
||||
// rename view on master
|
||||
let view = db._view("UnitTestsSyncView");
|
||||
view.rename("UnitTestsSyncViewRenamed");
|
||||
view = db._view("UnitTestsSyncViewRenamed");
|
||||
assertTrue(view !== null);
|
||||
let props = view.properties();
|
||||
assertEqual(Object.keys(props.links).length, 1);
|
||||
assertTrue(props.hasOwnProperty("links"));
|
||||
assertTrue(props.links.hasOwnProperty(cn));
|
||||
},
|
||||
function(state) {},
|
||||
function(state) {
|
||||
if (!state.arangoSearchEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
let view = db._view("UnitTestsSyncViewRenamed");
|
||||
assertTrue(view !== null);
|
||||
let props = view.properties();
|
||||
assertEqual(Object.keys(props.links).length, 1);
|
||||
assertTrue(props.hasOwnProperty("links"));
|
||||
assertTrue(props.links.hasOwnProperty(cn));
|
||||
},
|
||||
{}
|
||||
);
|
||||
},
|
||||
|
||||
testViewDrop: function() {
|
||||
connectToMaster();
|
||||
|
||||
compare(
|
||||
function(state) {
|
||||
try {
|
||||
let view = db._createView("UnitTestsSyncView", "arangosearch", {});
|
||||
state.arangoSearchEnabled = true;
|
||||
} catch (err) { }
|
||||
},
|
||||
function(state) {
|
||||
if (!state.arangoSearchEnabled) {
|
||||
return;
|
||||
}
|
||||
// rename view on master
|
||||
let view = db._view("UnitTestsSyncView");
|
||||
view.drop();
|
||||
},
|
||||
function(state) {},
|
||||
function(state) {
|
||||
if (!state.arangoSearchEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
let view = db._view("UnitTestsSyncView");
|
||||
assertTrue(view === null);
|
||||
},
|
||||
{}
|
||||
);
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -675,6 +794,8 @@ function ReplicationSuite() {
|
|||
suite.tearDown = function() {
|
||||
connectToMaster();
|
||||
|
||||
db._dropView("UnitTestsSyncView");
|
||||
db._dropView("UnitTestsSyncViewRenamed");
|
||||
db._drop(cn);
|
||||
db._drop(cn2);
|
||||
|
||||
|
@ -682,6 +803,8 @@ function ReplicationSuite() {
|
|||
replication.globalApplier.stop();
|
||||
replication.globalApplier.forget();
|
||||
|
||||
db._dropView("UnitTestsSyncView");
|
||||
db._dropView("UnitTestsSyncViewRenamed");
|
||||
db._drop(cn);
|
||||
db._drop(cn2);
|
||||
db._drop(cn + "Renamed");
|
||||
|
|
|
@ -97,6 +97,7 @@ const compare = function(masterFunc, masterFunc2, slaveFuncOngoing, slaveFuncFin
|
|||
applierConfiguration.endpoint = masterEndpoint;
|
||||
applierConfiguration.username = "root";
|
||||
applierConfiguration.password = "";
|
||||
applierConfiguration.force32mode = false;
|
||||
|
||||
if (!applierConfiguration.hasOwnProperty('chunkSize')) {
|
||||
applierConfiguration.chunkSize = 16384;
|
||||
|
@ -632,6 +633,124 @@ function BaseTestConfig() {
|
|||
assertEqual(state.count, collectionCount(cn));
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
testViewBasic: function() {
|
||||
connectToMaster();
|
||||
|
||||
compare(
|
||||
function() {},
|
||||
function(state) {
|
||||
try {
|
||||
db._create(cn);
|
||||
let view = db._createView("UnitTestsSyncView", "arangosearch", {});
|
||||
let links = {};
|
||||
links[cn] = {
|
||||
includeAllFields: true,
|
||||
fields: {
|
||||
text: { analyzers: [ "text_en" ] }
|
||||
}
|
||||
};
|
||||
view.properties({"links": links});
|
||||
state.arangoSearchEnabled = true;
|
||||
} catch (err) { }
|
||||
},
|
||||
function() {},
|
||||
function(state) {
|
||||
if (!state.arangoSearchEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
let view = db._view("UnitTestsSyncView");
|
||||
assertTrue(view !== null);
|
||||
let props = view.properties();
|
||||
assertEqual(Object.keys(props.links).length, 1);
|
||||
assertTrue(props.hasOwnProperty("links"));
|
||||
assertTrue(props.links.hasOwnProperty(cn));
|
||||
},
|
||||
{}
|
||||
);
|
||||
},
|
||||
|
||||
testViewRename: function() {
|
||||
connectToMaster();
|
||||
|
||||
compare(
|
||||
function(state) {
|
||||
try {
|
||||
db._create(cn);
|
||||
let view = db._createView("UnitTestsSyncView", "arangosearch", {});
|
||||
let links = {};
|
||||
links[cn] = {
|
||||
includeAllFields: true,
|
||||
fields: {
|
||||
text: { analyzers: [ "text_en" ] }
|
||||
}
|
||||
};
|
||||
view.properties({"links": links});
|
||||
state.arangoSearchEnabled = true;
|
||||
} catch (err) { }
|
||||
},
|
||||
function(state) {
|
||||
if (!state.arangoSearchEnabled) {
|
||||
return;
|
||||
}
|
||||
// rename view on master
|
||||
let view = db._view("UnitTestsSyncView");
|
||||
view.rename("UnitTestsSyncViewRenamed");
|
||||
view = db._view("UnitTestsSyncViewRenamed");
|
||||
assertTrue(view !== null);
|
||||
let props = view.properties();
|
||||
assertEqual(Object.keys(props.links).length, 1);
|
||||
assertTrue(props.hasOwnProperty("links"));
|
||||
assertTrue(props.links.hasOwnProperty(cn));
|
||||
},
|
||||
function(state) {},
|
||||
function(state) {
|
||||
if (!state.arangoSearchEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
let view = db._view("UnitTestsSyncViewRenamed");
|
||||
assertTrue(view !== null);
|
||||
let props = view.properties();
|
||||
assertEqual(Object.keys(props.links).length, 1);
|
||||
assertTrue(props.hasOwnProperty("links"));
|
||||
assertTrue(props.links.hasOwnProperty(cn));
|
||||
},
|
||||
{}
|
||||
);
|
||||
},
|
||||
|
||||
testViewDrop: function() {
|
||||
connectToMaster();
|
||||
|
||||
compare(
|
||||
function(state) {
|
||||
try {
|
||||
let view = db._createView("UnitTestsSyncView", "arangosearch", {});
|
||||
state.arangoSearchEnabled = true;
|
||||
} catch (err) { }
|
||||
},
|
||||
function(state) {
|
||||
if (!state.arangoSearchEnabled) {
|
||||
return;
|
||||
}
|
||||
// rename view on master
|
||||
let view = db._view("UnitTestsSyncView");
|
||||
view.drop();
|
||||
},
|
||||
function(state) {},
|
||||
function(state) {
|
||||
if (!state.arangoSearchEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
let view = db._view("UnitTestsSyncView");
|
||||
assertTrue(view === null);
|
||||
},
|
||||
{}
|
||||
);
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -672,6 +791,8 @@ function ReplicationSuite() {
|
|||
suite.tearDown = function() {
|
||||
connectToMaster();
|
||||
|
||||
db._dropView("UnitTestsSyncView");
|
||||
db._dropView("UnitTestsSyncViewRenamed");
|
||||
db._drop(cn);
|
||||
db._drop(cn2);
|
||||
|
||||
|
@ -679,6 +800,8 @@ function ReplicationSuite() {
|
|||
replication.applier.stop();
|
||||
replication.applier.forget();
|
||||
|
||||
db._dropView("UnitTestsSyncView");
|
||||
db._dropView("UnitTestsSyncViewRenamed");
|
||||
db._drop(cn);
|
||||
db._drop(cn2);
|
||||
db._drop(cn + "Renamed");
|
||||
|
|
|
@ -2021,6 +2021,38 @@ function BaseTestConfig() {
|
|||
restrictCollections: [cn2]
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
testViewBasic: function() {
|
||||
compare(
|
||||
function(state) {
|
||||
try {
|
||||
db._create(cn);
|
||||
let view = db._createView("UnitTestsSyncView", "arangosearch", {});
|
||||
let links = {};
|
||||
links[cn] = {
|
||||
includeAllFields: true,
|
||||
fields: {
|
||||
text: { analyzers: [ "text_en" ] }
|
||||
}
|
||||
};
|
||||
view.properties({"links": links});
|
||||
state.arangoSearchEnabled = true;
|
||||
} catch (err) { }
|
||||
},
|
||||
function(state) {
|
||||
if (!state.arangoSearchEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
let view = db._view("UnitTestsSyncView");
|
||||
assertTrue(view !== null);
|
||||
let props = view.properties();
|
||||
assertEqual(Object.keys(props.links).length, 1);
|
||||
assertTrue(props.hasOwnProperty("links"));
|
||||
assertTrue(props.links.hasOwnProperty(cn));
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#define ARANGO_READ_WRITE_SPIN_LOCK_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "Basics/SharedAtomic.h"
|
||||
#include "Basics/SharedCounter.h"
|
||||
#include "Basics/cpu-relax.h"
|
||||
|
||||
#include <atomic>
|
||||
|
|
|
@ -229,8 +229,8 @@ SECTION("test_defaults") {
|
|||
auto slice = builder->slice();
|
||||
CHECK((
|
||||
slice.hasKey("view")
|
||||
&& slice.get("view").isNumber()
|
||||
&& TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>()
|
||||
&& slice.get("view").isString()
|
||||
&& logicalView->guid() == slice.get("view").copyString()
|
||||
&& slice.hasKey("figures")
|
||||
&& slice.get("figures").isObject()
|
||||
&& slice.get("figures").hasKey("memory")
|
||||
|
@ -282,8 +282,8 @@ SECTION("test_defaults") {
|
|||
auto slice = builder->slice();
|
||||
CHECK((
|
||||
slice.hasKey("view")
|
||||
&& slice.get("view").isNumber()
|
||||
&& TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>()
|
||||
&& slice.get("view").isString()
|
||||
&& logicalView->guid() == slice.get("view").copyString()
|
||||
&& slice.hasKey("figures")
|
||||
&& slice.get("figures").isObject()
|
||||
&& slice.get("figures").hasKey("memory")
|
||||
|
@ -299,8 +299,8 @@ SECTION("test_defaults") {
|
|||
auto slice = builder->slice();
|
||||
CHECK((
|
||||
slice.hasKey("view")
|
||||
&& slice.get("view").isNumber()
|
||||
&& TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>()
|
||||
&& slice.get("view").isString()
|
||||
&& logicalView->guid() == slice.get("view").copyString()
|
||||
&& slice.hasKey("figures")
|
||||
&& slice.get("figures").isObject()
|
||||
&& slice.get("figures").hasKey("memory")
|
||||
|
@ -676,4 +676,4 @@ SECTION("test_write") {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -367,8 +367,9 @@ SECTION("test_create_drop") {
|
|||
CHECK(expectedMeta == actualMeta);
|
||||
auto const slice = builder->slice();
|
||||
CHECK(slice.hasKey("view"));
|
||||
CHECK(slice.get("view").isNumber());
|
||||
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
|
||||
CHECK(slice.get("view").isString());
|
||||
CHECK(logicalView->id() == 42);
|
||||
CHECK(logicalView->guid() == slice.get("view").copyString());
|
||||
CHECK(slice.hasKey("figures"));
|
||||
CHECK(slice.get("figures").isObject());
|
||||
CHECK(slice.get("figures").hasKey("memory"));
|
||||
|
@ -405,8 +406,9 @@ SECTION("test_create_drop") {
|
|||
CHECK(error.empty());
|
||||
CHECK((
|
||||
slice.hasKey("view")
|
||||
&& slice.get("view").isNumber()
|
||||
&& TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>()
|
||||
&& slice.get("view").isString()
|
||||
&& logicalView->id() == 42
|
||||
&& logicalView->guid() == slice.get("view").copyString()
|
||||
&& slice.hasKey("figures")
|
||||
&& slice.get("figures").isObject()
|
||||
&& slice.get("figures").hasKey("memory")
|
||||
|
@ -473,8 +475,9 @@ SECTION("test_create_drop") {
|
|||
auto slice = builder->slice();
|
||||
CHECK((
|
||||
slice.hasKey("view")
|
||||
&& slice.get("view").isNumber()
|
||||
&& TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>()
|
||||
&& slice.get("view").isString()
|
||||
&& logicalView->id() == 42
|
||||
&& logicalView->guid() == slice.get("view").copyString()
|
||||
&& slice.hasKey("figures")
|
||||
&& slice.get("figures").isObject()
|
||||
&& slice.get("figures").hasKey("memory")
|
||||
|
@ -490,8 +493,9 @@ SECTION("test_create_drop") {
|
|||
auto slice = builder->slice();
|
||||
CHECK((
|
||||
slice.hasKey("view")
|
||||
&& slice.get("view").isNumber()
|
||||
&& TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>()
|
||||
&& slice.get("view").isString()
|
||||
&& logicalView->id() == 42
|
||||
&& logicalView->guid() == slice.get("view").copyString()
|
||||
&& slice.hasKey("figures")
|
||||
&& slice.get("figures").isObject()
|
||||
&& slice.get("figures").hasKey("memory")
|
||||
|
|
|
@ -971,8 +971,8 @@ SECTION("test_update_links_partial_remove") {
|
|||
CHECK(expectedMeta == actualMeta);
|
||||
auto const slice = builder->slice();
|
||||
CHECK(slice.hasKey("view"));
|
||||
CHECK(slice.get("view").isNumber());
|
||||
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
|
||||
CHECK(slice.get("view").isString());
|
||||
CHECK(view->guid() == slice.get("view").copyString());
|
||||
CHECK(slice.hasKey("figures"));
|
||||
CHECK(slice.get("figures").isObject());
|
||||
CHECK(slice.get("figures").hasKey("memory"));
|
||||
|
@ -1017,8 +1017,9 @@ SECTION("test_update_links_partial_remove") {
|
|||
CHECK(expectedMeta == actualMeta);
|
||||
auto const slice = builder->slice();
|
||||
CHECK(slice.hasKey("view"));
|
||||
CHECK(slice.get("view").isNumber());
|
||||
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
|
||||
CHECK(slice.get("view").isString());
|
||||
CHECK(view->id() == 42);
|
||||
CHECK(view->guid() == slice.get("view").copyString());
|
||||
CHECK(slice.hasKey("figures"));
|
||||
CHECK(slice.get("figures").isObject());
|
||||
CHECK(slice.get("figures").hasKey("memory"));
|
||||
|
@ -1061,8 +1062,9 @@ SECTION("test_update_links_partial_remove") {
|
|||
CHECK(expectedMeta == actualMeta);
|
||||
auto const slice = builder->slice();
|
||||
CHECK(slice.hasKey("view"));
|
||||
CHECK(slice.get("view").isNumber());
|
||||
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
|
||||
CHECK(slice.get("view").isString());
|
||||
CHECK(view->id() == 42);
|
||||
CHECK(view->guid() == slice.get("view").copyString());
|
||||
CHECK(slice.hasKey("figures"));
|
||||
CHECK(slice.get("figures").isObject());
|
||||
CHECK(slice.get("figures").hasKey("memory"));
|
||||
|
@ -1194,8 +1196,9 @@ SECTION("test_update_links_partial_remove") {
|
|||
CHECK(expectedMeta == actualMeta);
|
||||
auto const slice = builder->slice();
|
||||
CHECK(slice.hasKey("view"));
|
||||
CHECK(slice.get("view").isNumber());
|
||||
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
|
||||
CHECK(slice.get("view").isString());
|
||||
CHECK(view->id() == 42);
|
||||
CHECK(view->guid() == slice.get("view").copyString());
|
||||
CHECK(slice.hasKey("figures"));
|
||||
CHECK(slice.get("figures").isObject());
|
||||
CHECK(slice.get("figures").hasKey("memory"));
|
||||
|
@ -1239,8 +1242,9 @@ SECTION("test_update_links_partial_remove") {
|
|||
CHECK(expectedMeta == actualMeta);
|
||||
auto const slice = builder->slice();
|
||||
CHECK(slice.hasKey("view"));
|
||||
CHECK(slice.get("view").isNumber());
|
||||
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
|
||||
CHECK(slice.get("view").isString());
|
||||
CHECK(view->id() == 42);
|
||||
CHECK(view->guid() == slice.get("view").copyString());
|
||||
CHECK(slice.hasKey("figures"));
|
||||
CHECK(slice.get("figures").isObject());
|
||||
CHECK(slice.get("figures").hasKey("memory"));
|
||||
|
@ -1511,8 +1515,9 @@ SECTION("test_update_links_partial_add") {
|
|||
CHECK(expectedMeta == actualMeta);
|
||||
auto const slice = builder->slice();
|
||||
CHECK(slice.hasKey("view"));
|
||||
CHECK(slice.get("view").isNumber());
|
||||
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
|
||||
CHECK(slice.get("view").isString());
|
||||
CHECK(view->id() == 42);
|
||||
CHECK(view->guid() == slice.get("view").copyString());
|
||||
CHECK(slice.hasKey("figures"));
|
||||
CHECK(slice.get("figures").isObject());
|
||||
CHECK(slice.get("figures").hasKey("memory"));
|
||||
|
@ -1555,8 +1560,9 @@ SECTION("test_update_links_partial_add") {
|
|||
CHECK(expectedMeta == actualMeta);
|
||||
auto const slice = builder->slice();
|
||||
CHECK(slice.hasKey("view"));
|
||||
CHECK(slice.get("view").isNumber());
|
||||
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
|
||||
CHECK(slice.get("view").isString());
|
||||
CHECK(view->id() == 42);
|
||||
CHECK(view->guid() == slice.get("view").copyString());
|
||||
CHECK(slice.hasKey("figures"));
|
||||
CHECK(slice.get("figures").isObject());
|
||||
CHECK(slice.get("figures").hasKey("memory"));
|
||||
|
@ -1703,8 +1709,9 @@ SECTION("test_update_links_partial_add") {
|
|||
CHECK(expectedMeta == actualMeta);
|
||||
auto const slice = builder->slice();
|
||||
CHECK(slice.hasKey("view"));
|
||||
CHECK(slice.get("view").isNumber());
|
||||
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
|
||||
CHECK(slice.get("view").isString());
|
||||
CHECK(view->id() == 42);
|
||||
CHECK(view->guid() == slice.get("view").copyString());
|
||||
CHECK(slice.hasKey("figures"));
|
||||
CHECK(slice.get("figures").isObject());
|
||||
CHECK(slice.get("figures").hasKey("memory"));
|
||||
|
@ -1749,8 +1756,9 @@ SECTION("test_update_links_partial_add") {
|
|||
CHECK(expectedMeta == actualMeta);
|
||||
auto const slice = builder->slice();
|
||||
CHECK(slice.hasKey("view"));
|
||||
CHECK(slice.get("view").isNumber());
|
||||
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
|
||||
CHECK(slice.get("view").isString());
|
||||
CHECK(view->id() == 42);
|
||||
CHECK(view->guid() == slice.get("view").copyString());
|
||||
CHECK(slice.hasKey("figures"));
|
||||
CHECK(slice.get("figures").isObject());
|
||||
CHECK(slice.get("figures").hasKey("memory"));
|
||||
|
@ -1794,8 +1802,9 @@ SECTION("test_update_links_partial_add") {
|
|||
CHECK(expectedMeta == actualMeta);
|
||||
auto const slice = builder->slice();
|
||||
CHECK(slice.hasKey("view"));
|
||||
CHECK(slice.get("view").isNumber());
|
||||
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
|
||||
CHECK(slice.get("view").isString());
|
||||
CHECK(view->id() == 42);
|
||||
CHECK(view->guid() == slice.get("view").copyString());
|
||||
CHECK(slice.hasKey("figures"));
|
||||
CHECK(slice.get("figures").isObject());
|
||||
CHECK(slice.get("figures").hasKey("memory"));
|
||||
|
@ -2077,8 +2086,9 @@ SECTION("test_update_links_replace") {
|
|||
CHECK(expectedMeta == actualMeta);
|
||||
auto const slice = builder->slice();
|
||||
CHECK(slice.hasKey("view"));
|
||||
CHECK(slice.get("view").isNumber());
|
||||
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
|
||||
CHECK(slice.get("view").isString());
|
||||
CHECK(view->id() == 42);
|
||||
CHECK(view->guid() == slice.get("view").copyString());
|
||||
CHECK(slice.hasKey("figures"));
|
||||
CHECK(slice.get("figures").isObject());
|
||||
CHECK(slice.get("figures").hasKey("memory"));
|
||||
|
@ -2121,8 +2131,9 @@ SECTION("test_update_links_replace") {
|
|||
CHECK(expectedMeta == actualMeta);
|
||||
auto const slice = builder->slice();
|
||||
CHECK(slice.hasKey("view"));
|
||||
CHECK(slice.get("view").isNumber());
|
||||
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
|
||||
CHECK(slice.get("view").isString());
|
||||
CHECK(view->id() == 42);
|
||||
CHECK(view->guid() == slice.get("view").copyString());
|
||||
CHECK(slice.hasKey("figures"));
|
||||
CHECK(slice.get("figures").isObject());
|
||||
CHECK(slice.get("figures").hasKey("memory"));
|
||||
|
@ -2251,8 +2262,9 @@ SECTION("test_update_links_replace") {
|
|||
CHECK(expectedMeta == actualMeta);
|
||||
auto const slice = builder->slice();
|
||||
CHECK(slice.hasKey("view"));
|
||||
CHECK(slice.get("view").isNumber());
|
||||
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
|
||||
CHECK(slice.get("view").isString());
|
||||
CHECK(view->id() == 42);
|
||||
CHECK(view->guid() == slice.get("view").copyString());
|
||||
CHECK(slice.hasKey("figures"));
|
||||
CHECK(slice.get("figures").isObject());
|
||||
CHECK(slice.get("figures").hasKey("memory"));
|
||||
|
@ -2372,8 +2384,9 @@ SECTION("test_update_links_replace") {
|
|||
CHECK(expectedMeta == actualMeta);
|
||||
auto const slice = builder->slice();
|
||||
CHECK(slice.hasKey("view"));
|
||||
CHECK(slice.get("view").isNumber());
|
||||
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
|
||||
CHECK(slice.get("view").isString());
|
||||
CHECK(view->id() == 42);
|
||||
CHECK(view->guid() == slice.get("view").copyString());
|
||||
CHECK(slice.hasKey("figures"));
|
||||
CHECK(slice.get("figures").isObject());
|
||||
CHECK(slice.get("figures").hasKey("memory"));
|
||||
|
@ -2660,8 +2673,9 @@ SECTION("test_update_links_clear") {
|
|||
CHECK(expectedMeta == actualMeta);
|
||||
auto const slice = builder->slice();
|
||||
CHECK(slice.hasKey("view"));
|
||||
CHECK(slice.get("view").isNumber());
|
||||
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
|
||||
CHECK(slice.get("view").isString());
|
||||
CHECK(view->id() == 42);
|
||||
CHECK(view->guid() == slice.get("view").copyString());
|
||||
CHECK(slice.hasKey("figures"));
|
||||
CHECK(slice.get("figures").isObject());
|
||||
CHECK(slice.get("figures").hasKey("memory"));
|
||||
|
@ -2706,8 +2720,9 @@ SECTION("test_update_links_clear") {
|
|||
CHECK(expectedMeta == actualMeta);
|
||||
auto const slice = builder->slice();
|
||||
CHECK(slice.hasKey("view"));
|
||||
CHECK(slice.get("view").isNumber());
|
||||
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
|
||||
CHECK(slice.get("view").isString());
|
||||
CHECK(view->id() == 42);
|
||||
CHECK(view->guid() == slice.get("view").copyString());
|
||||
CHECK(slice.hasKey("figures"));
|
||||
CHECK(slice.get("figures").isObject());
|
||||
CHECK(slice.get("figures").hasKey("memory"));
|
||||
|
@ -2750,8 +2765,9 @@ SECTION("test_update_links_clear") {
|
|||
CHECK(expectedMeta == actualMeta);
|
||||
auto const slice = builder->slice();
|
||||
CHECK(slice.hasKey("view"));
|
||||
CHECK(slice.get("view").isNumber());
|
||||
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
|
||||
CHECK(slice.get("view").isString());
|
||||
CHECK(view->id() == 42);
|
||||
CHECK(view->guid() == slice.get("view").copyString());
|
||||
CHECK(slice.hasKey("figures"));
|
||||
CHECK(slice.get("figures").isObject());
|
||||
CHECK(slice.get("figures").hasKey("memory"));
|
||||
|
@ -3016,8 +3032,9 @@ SECTION("test_drop_link") {
|
|||
CHECK(expectedMeta == actualMeta);
|
||||
auto const slice = builder->slice();
|
||||
CHECK(slice.hasKey("view"));
|
||||
CHECK(slice.get("view").isNumber());
|
||||
CHECK(TRI_voc_cid_t(42) == slice.get("view").getNumber<TRI_voc_cid_t>());
|
||||
CHECK(slice.get("view").isString());
|
||||
CHECK(view->id() == 42);
|
||||
CHECK(view->guid() == slice.get("view").copyString());
|
||||
CHECK(slice.hasKey("figures"));
|
||||
CHECK(slice.get("figures").isObject());
|
||||
CHECK(slice.get("figures").hasKey("memory"));
|
||||
|
|
|
@ -990,9 +990,8 @@ void StorageEngineMock::changeCollection(
|
|||
// NOOP, assume physical collection changed OK
|
||||
}
|
||||
|
||||
void StorageEngineMock::changeView(
|
||||
arangodb::Result StorageEngineMock::changeView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
TRI_voc_cid_t id,
|
||||
arangodb::LogicalView const& view,
|
||||
bool doSync
|
||||
) {
|
||||
|
@ -1004,6 +1003,7 @@ void StorageEngineMock::changeView(
|
|||
view.toVelocyPack(builder, true, true);
|
||||
builder.close();
|
||||
views[std::make_pair(vocbase.id(), view.id())] = std::move(builder);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string StorageEngineMock::collectionPath(
|
||||
|
@ -1092,13 +1092,21 @@ std::unique_ptr<arangodb::TransactionState> StorageEngineMock::createTransaction
|
|||
);
|
||||
}
|
||||
|
||||
void StorageEngineMock::createView(
|
||||
arangodb::Result StorageEngineMock::createView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
TRI_voc_cid_t id,
|
||||
arangodb::LogicalView const& view
|
||||
) {
|
||||
before();
|
||||
// NOOP, assume physical view created OK
|
||||
TRI_ASSERT(views.find(std::make_pair(vocbase.id(), view.id())) == views.end()); // called after createView()
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
view.toVelocyPack(builder, true, true);
|
||||
builder.close();
|
||||
views[std::make_pair(vocbase.id(), view.id())] = std::move(builder);
|
||||
|
||||
return arangodb::Result(TRI_ERROR_NO_ERROR); // assume mock view persisted OK
|
||||
}
|
||||
|
||||
void StorageEngineMock::getViewProperties(
|
||||
|
@ -1290,22 +1298,6 @@ arangodb::Result StorageEngineMock::persistCollection(
|
|||
return arangodb::Result(TRI_ERROR_NO_ERROR); // assume mock collection persisted OK
|
||||
}
|
||||
|
||||
arangodb::Result StorageEngineMock::persistView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::LogicalView const& view
|
||||
) {
|
||||
before();
|
||||
TRI_ASSERT(views.find(std::make_pair(vocbase.id(), view.id())) == views.end()); // called after createView()
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
view.toVelocyPack(builder, true, true);
|
||||
builder.close();
|
||||
views[std::make_pair(vocbase.id(), view.id())] = std::move(builder);
|
||||
|
||||
return arangodb::Result(TRI_ERROR_NO_ERROR); // assume mock view persisted OK
|
||||
}
|
||||
|
||||
void StorageEngineMock::prepareDropDatabase(
|
||||
TRI_vocbase_t& vocbase,
|
||||
bool useWriteMarker,
|
||||
|
@ -1345,23 +1337,6 @@ arangodb::Result StorageEngineMock::renameCollection(
|
|||
return arangodb::Result(TRI_ERROR_INTERNAL);
|
||||
}
|
||||
|
||||
arangodb::Result StorageEngineMock::renameView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::LogicalView const& view,
|
||||
std::string const& newName
|
||||
) {
|
||||
before();
|
||||
TRI_ASSERT(views.find(std::make_pair(vocbase.id(), view.id())) != views.end());
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
view.toVelocyPack(builder, true, true);
|
||||
builder.close();
|
||||
views[std::make_pair(vocbase.id(), view.id())] = std::move(builder);
|
||||
|
||||
return arangodb::Result(TRI_ERROR_NO_ERROR); // assume mock view renames OK
|
||||
}
|
||||
|
||||
int StorageEngineMock::saveReplicationApplierConfiguration(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice slice,
|
||||
|
@ -1554,4 +1529,4 @@ bool TransactionStateMock::hasFailedOperations() const {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -147,7 +147,7 @@ class StorageEngineMock: public arangodb::StorageEngine {
|
|||
virtual void addRestHandlers(arangodb::rest::RestHandlerFactory& handlerFactory) override;
|
||||
virtual void addV8Functions() override;
|
||||
virtual void changeCollection(TRI_vocbase_t& vocbase, TRI_voc_cid_t id, arangodb::LogicalCollection const& collection, bool doSync) override;
|
||||
virtual void changeView(TRI_vocbase_t& vocbase, TRI_voc_cid_t id, arangodb::LogicalView const& view, bool doSync) override;
|
||||
virtual arangodb::Result changeView(TRI_vocbase_t& vocbase, arangodb::LogicalView const& view, bool doSync) override;
|
||||
virtual std::string collectionPath(TRI_vocbase_t const& vocbase, TRI_voc_cid_t id) const override;
|
||||
virtual std::string createCollection(TRI_vocbase_t& vocbase, TRI_voc_cid_t id, arangodb::LogicalCollection const& collection) override;
|
||||
virtual std::unique_ptr<TRI_vocbase_t> createDatabase(TRI_voc_tick_t id, arangodb::velocypack::Slice const& args, int& status) override;
|
||||
|
@ -158,7 +158,7 @@ class StorageEngineMock: public arangodb::StorageEngine {
|
|||
virtual std::unique_ptr<arangodb::transaction::ContextData> createTransactionContextData() override;
|
||||
virtual std::unique_ptr<arangodb::TransactionManager> createTransactionManager() override;
|
||||
virtual std::unique_ptr<arangodb::TransactionState> createTransactionState(TRI_vocbase_t& vocbase, arangodb::transaction::Options const& options) override;
|
||||
virtual void createView(TRI_vocbase_t& vocbase, TRI_voc_cid_t id, arangodb::LogicalView const& view) override;
|
||||
virtual arangodb::Result createView(TRI_vocbase_t& vocbase, TRI_voc_cid_t id, arangodb::LogicalView const& view) override;
|
||||
virtual void getViewProperties(TRI_vocbase_t& vocbase, arangodb::LogicalView const& view, VPackBuilder& builder) override;
|
||||
virtual TRI_voc_tick_t currentTick() const override;
|
||||
virtual std::string databasePath(TRI_vocbase_t const* vocbase) const override;
|
||||
|
@ -181,7 +181,6 @@ class StorageEngineMock: public arangodb::StorageEngine {
|
|||
virtual double minimumSyncReplicationTimeout() const override { return 1.0; }
|
||||
virtual std::unique_ptr<TRI_vocbase_t> openDatabase(arangodb::velocypack::Slice const& args, bool isUpgrade, int& status) override;
|
||||
virtual arangodb::Result persistCollection(TRI_vocbase_t& vocbase, arangodb::LogicalCollection const& collection) override;
|
||||
virtual arangodb::Result persistView(TRI_vocbase_t& vocbase, arangodb::LogicalView const& view) override;
|
||||
virtual void prepareDropDatabase(TRI_vocbase_t& vocbase, bool useWriteMarker, int& status) override;
|
||||
using StorageEngine::registerCollection;
|
||||
using StorageEngine::registerView;
|
||||
|
@ -190,7 +189,6 @@ class StorageEngineMock: public arangodb::StorageEngine {
|
|||
virtual int removeReplicationApplierConfiguration(TRI_vocbase_t& vocbase) override;
|
||||
virtual int removeReplicationApplierConfiguration() override;
|
||||
virtual arangodb::Result renameCollection(TRI_vocbase_t& vocbase, arangodb::LogicalCollection const& collection, std::string const& oldName) override;
|
||||
virtual arangodb::Result renameView(TRI_vocbase_t& vocbase, arangodb::LogicalView const& view, std::string const& oldName) override;
|
||||
virtual int saveReplicationApplierConfiguration(TRI_vocbase_t& vocbase, arangodb::velocypack::Slice slice, bool doSync) override;
|
||||
virtual int saveReplicationApplierConfiguration(arangodb::velocypack::Slice, bool) override;
|
||||
virtual int shutdownDatabase(TRI_vocbase_t& vocbase) override;
|
||||
|
@ -210,4 +208,4 @@ class StorageEngineMock: public arangodb::StorageEngine {
|
|||
TRI_voc_tick_t _releasedTick;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue