1
0
Fork 0

Added view retrieval via HTTP with tests and initial work on view factory.

This commit is contained in:
Dan Larkin 2017-03-15 18:44:48 -04:00
parent 7e7fe8bc21
commit aa23074efd
8 changed files with 549 additions and 199 deletions

View File

@ -27,7 +27,9 @@ describe ArangoDB do
it "creating a view without name" do
cmd = api
body = "{ \"type\" : \"def\" }"
body = <<-END
{ "type": "def" }
END
doc = ArangoDB.log_post("#{prefix}-create-missing-name", cmd, :body => body)
doc.code.should eq(400)
@ -39,7 +41,9 @@ describe ArangoDB do
it "creating a view without type" do
cmd = api
body = "{ \"name\" : \"abc\" }"
body = <<-END
{ "name": "abc" }
END
doc = ArangoDB.log_post("#{prefix}-create-missing-type", cmd, :body => body)
doc.code.should eq(400)
@ -49,6 +53,117 @@ describe ArangoDB do
doc.parsed_response['errorNum'].should eq(400)
end
it "duplicate name" do
cmd1 = api
body1 = <<-END
{ "name": "dup",
"type": "type1" }
END
doc1 = ArangoDB.log_post("#{prefix}-create-duplicate", cmd1, :body => body1)
doc1.code.should eq(201)
doc1.headers['content-type'].should eq("application/json; charset=utf-8")
doc1.parsed_response['name'].should eq("dup")
doc1.parsed_response['type'].should eq("type1")
cmd2 = api
body2 = <<-END
{ "name": "dup",
"type": "type2" }
END
doc2 = ArangoDB.log_post("#{prefix}-create-duplicate", cmd1, :body => body2)
doc2.code.should eq(500)
doc2.headers['content-type'].should eq("application/json; charset=utf-8")
doc2.parsed_response['error'].should eq(true)
doc2.parsed_response['code'].should eq(500)
doc2.parsed_response['errorNum'].should eq(1207)
cmd3 = api + '/dup'
doc3 = ArangoDB.log_delete("#{prefix}-create-duplicate", cmd3)
doc3.code.should eq(204)
doc3.headers['content-type'].should eq("text/plain; charset=utf-8")
end
end
context "add/drop:" do
it "creating a view" do
cmd = api
body = <<-END
{ "name": "abc",
"type": "def" }
END
doc = ArangoDB.log_post("#{prefix}-create-a-view", cmd, :body => body)
doc.code.should eq(201)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
doc.parsed_response['name'].should eq("abc")
doc.parsed_response['type'].should eq("def")
end
it "dropping a view" do
cmd1 = api + "/abc"
doc1 = ArangoDB.log_delete("#{prefix}-drop-a-view", cmd1)
doc1.code.should eq(204)
doc1.headers['content-type'].should eq("text/plain; charset=utf-8")
cmd2 = api + "/abc"
doc2 = ArangoDB.log_get("#{prefix}-drop-a-view", cmd2)
doc2.code.should eq(404)
doc2.headers['content-type'].should eq("application/json; charset=utf-8")
doc2.parsed_response['error'].should eq(true)
doc2.parsed_response['code'].should eq(404)
end
end
context "retrieval:" do
it "empty list" do
cmd = api
doc = ArangoDB.log_get("#{prefix}-empty-list", cmd)
doc.code.should eq(200)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
doc.parsed_response.should eq([])
end
it "short list" do
cmd1 = api
body1 = <<-END
{"name": "abc",
"type": "type1"}
END
doc1 = ArangoDB.log_post("#{prefix}-short-list", cmd1, :body => body1)
doc1.code.should eq(201)
doc1.headers['content-type'].should eq("application/json; charset=utf-8")
doc1.parsed_response['name'].should eq("abc")
doc1.parsed_response['type'].should eq("type1")
cmd2 = api
body2 = <<-END
{"name": "def",
"type": "type2"}
END
doc2 = ArangoDB.log_post("#{prefix}-short-list", cmd2, :body => body2)
doc2.code.should eq(201)
doc2.headers['content-type'].should eq("application/json; charset=utf-8")
doc2.parsed_response['name'].should eq("def")
doc2.parsed_response['type'].should eq("type2")
cmd3 = api
doc3 = ArangoDB.log_get("#{prefix}-short-list", cmd3)
doc3.code.should eq(200)
puts doc3
doc3.headers['content-type'].should eq("application/json; charset=utf-8")
doc3.parsed_response.length.should eq(2)
doc3.parsed_response[0]['name'].should eq("abc")
doc3.parsed_response[1]['name'].should eq("def")
doc3.parsed_response[0]['type'].should eq("type1")
doc3.parsed_response[1]['type'].should eq("type2")
end
end
end

View File

@ -24,11 +24,14 @@
#include "RestViewHandler.h"
#include "Basics/Exceptions.h"
#include "Basics/StringUtils.h"
#include "Basics/VelocyPackHelper.h"
#include "VocBase/LogicalView.h"
#include <velocypack/velocypack-aliases.h>
using namespace arangodb;
using namespace arangodb::basics;
using namespace arangodb::rest;
RestViewHandler::RestViewHandler(GeneralRequest* request,
@ -54,6 +57,11 @@ RestStatus RestViewHandler::execute() {
return RestStatus::DONE;
}
if (type == rest::RequestType::GET) {
getViews();
return RestStatus::DONE;
}
generateError(rest::ResponseCode::METHOD_NOT_ALLOWED,
TRI_ERROR_HTTP_METHOD_NOT_ALLOWED);
return RestStatus::DONE;
@ -106,7 +114,11 @@ void RestViewHandler::createView() {
TRI_voc_cid_t id = 0;
std::shared_ptr<LogicalView> view = _vocbase->createView(body, id);
if (view != nullptr) {
generateOk(rest::ResponseCode::CREATED);
VPackBuilder props;
props.openObject();
view->toVelocyPack(props);
props.close();
generateResult(rest::ResponseCode::CREATED, props.slice());
} else {
generateError(rest::ResponseCode::SERVER_ERROR, TRI_ERROR_INTERNAL,
"problem creating view");
@ -181,10 +193,72 @@ void RestViewHandler::deleteView() {
if (res == TRI_ERROR_NO_ERROR) {
generateOk();
} else if (res == TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND) {
generateError(rest::ResponseCode::NOT_FOUND, TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND,
generateError(rest::ResponseCode::NOT_FOUND,
TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND,
"could not find view by that name");
} else {
generateError(rest::ResponseCode::SERVER_ERROR, TRI_ERROR_INTERNAL,
"problem dropping view");
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief was docuBlock JSF_post_api_cursor_delete
////////////////////////////////////////////////////////////////////////////////
void RestViewHandler::getViews() {
std::vector<std::string> const& suffixes = _request->suffixes();
if (suffixes.size() > 1) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting GET [/_api/view | /_api/view/<view-name>]");
return;
}
if (suffixes.size() == 0) {
getListOfViews();
return;
} else {
std::string const& name = suffixes[0];
getSingleView(name);
return;
}
}
void RestViewHandler::getListOfViews() {
std::vector<std::shared_ptr<LogicalView>> views = _vocbase->views();
std::sort(views.begin(), views.end(),
[](std::shared_ptr<LogicalView> const& lhs,
std::shared_ptr<LogicalView> const& rhs) -> bool {
return StringUtils::tolower(lhs->name()) <
StringUtils::tolower(rhs->name());
});
VPackBuilder props;
props.openArray();
for (std::shared_ptr<LogicalView> view : views) {
if (view.get() != nullptr) {
props.openObject();
view->toVelocyPack(props);
props.close();
}
}
props.close();
generateResult(rest::ResponseCode::OK, props.slice());
}
void RestViewHandler::getSingleView(std::string const& name) {
std::shared_ptr<LogicalView> view = _vocbase->lookupView(name);
if (view.get() != nullptr) {
VPackBuilder props;
props.openObject();
view->toVelocyPack(props);
props.close();
generateResult(rest::ResponseCode::OK, props.slice());
} else {
generateError(rest::ResponseCode::NOT_FOUND,
TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND,
"could not find view by that name");
}
}

View File

@ -46,6 +46,10 @@ class RestViewHandler : public RestVocbaseBaseHandler {
void createView();
void modifyView();
void deleteView();
void getViews();
void getSingleView(std::string const&);
void getListOfViews();
};
}

View File

@ -89,7 +89,6 @@ static std::string const ReadStringValue(VPackSlice info,
}
return Helper::getStringValue(info, name, def);
}
}
/// @brief This the "copy" constructor used in the cluster
@ -110,16 +109,14 @@ LogicalView::LogicalView(LogicalView const& other)
// @brief Constructor used in coordinator case.
// The Slice contains the part of the plan that
// is relevant for this view
LogicalView::LogicalView(TRI_vocbase_t* vocbase,
VPackSlice const& info)
LogicalView::LogicalView(TRI_vocbase_t* vocbase, VPackSlice const& info)
: _id(ReadId(info)),
_planId(ReadPlanId(info, _id)),
_type(ReadStringValue(info, "type", "")),
_name(ReadStringValue(info, "name", "")),
_isDeleted(Helper::readBooleanValue(info, "deleted", false)),
_vocbase(vocbase),
_physical(
EngineSelectorFeature::ENGINE->createPhysicalView(this, info)) {
_physical(EngineSelectorFeature::ENGINE->createPhysicalView(this, info)) {
TRI_ASSERT(_physical != nullptr);
if (!IsAllowedName(info)) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_ILLEGAL_NAME);
@ -208,7 +205,7 @@ void LogicalView::toVelocyPack(VPackBuilder& result) const {
// Cluster Specific
result.add("planId", VPackValue(std::to_string(_planId)));
TRI_ASSERT(result.isOpenObject());
// We leave the object open
}
@ -217,7 +214,7 @@ arangodb::Result LogicalView::updateProperties(VPackSlice const& slice,
bool doSync) {
WRITE_LOCKER(writeLocker, _infoLock);
// The physical may first reject illegal properties.
// The physical may first reject illegal properties.
// After this call it either has thrown or the properties are stored
getPhysical()->updateProperties(slice, doSync);
@ -240,3 +237,10 @@ void LogicalView::persistPhysicalView() {
engine->createView(_vocbase, _id, this);
}
void LogicalView::spawnImplementation(ViewCreator creator) {
VPackBuilder properties;
properties.openObject();
toVelocyPack(properties);
properties.close();
_implementation = creator(this, getPhysical(), properties.slice());
}

View File

@ -26,6 +26,7 @@
#include "Basics/Common.h"
#include "Basics/Result.h"
#include "VocBase/ViewImplementation.h"
#include "VocBase/voc-types.h"
#include "VocBase/vocbase.h"
@ -44,7 +45,7 @@ class LogicalView {
public:
LogicalView(TRI_vocbase_t*, velocypack::Slice const&);
~LogicalView();
~LogicalView();
protected: // If you need a copy outside the class, use clone below.
explicit LogicalView(LogicalView const&);
@ -61,7 +62,7 @@ class LogicalView {
}
inline TRI_voc_cid_t id() const { return _id; }
TRI_voc_cid_t planId() const;
std::string type() const { return _type; }
@ -72,7 +73,7 @@ class LogicalView {
void setDeleted(bool);
PhysicalView* getPhysical() const { return _physical.get(); }
void drop();
// SECTION: Serialization
@ -87,7 +88,10 @@ class LogicalView {
/// This should be called AFTER the view is successfully
/// created and only on Sinlge/DBServer
void persistPhysicalView();
/// @brief Create implementation object using factory method
void spawnImplementation(ViewCreator creator);
static bool IsAllowedName(velocypack::Slice parameters);
static bool IsAllowedName(std::string const& name);
@ -96,7 +100,7 @@ class LogicalView {
//
// @brief Local view id
TRI_voc_cid_t const _id;
// @brief Global view id
TRI_voc_cid_t const _planId;
@ -111,9 +115,10 @@ class LogicalView {
TRI_vocbase_t* _vocbase;
std::unique_ptr<PhysicalView> _physical;
std::unique_ptr<ViewImplementation> _implementation;
mutable basics::ReadWriteLock _lock; // lock protecting the status and name
mutable basics::ReadWriteLock _infoLock; // lock protecting the properties
mutable basics::ReadWriteLock _lock; // lock protecting the status and name
mutable basics::ReadWriteLock _infoLock; // lock protecting the properties
};
} // namespace arangodb

View File

@ -0,0 +1,70 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_VOCBASE_VIEW_IMPLEMENTATION_H
#define ARANGOD_VOCBASE_VIEW_IMPLEMENTATION_H 1
#include "Basics/Common.h"
#include "VocBase/voc-types.h"
#include <velocypack/Builder.h>
#include <velocypack/Slice.h>
namespace arangodb {
class LogicalView;
class PhysicalView;
class Result;
class ViewImplementation {
protected:
ViewImplementation(LogicalView* logical, PhysicalView* physical,
arangodb::velocypack::Slice const& info)
: _logicalView(logical), _physicalView(physical) {}
public:
virtual ~ViewImplementation() = default;
virtual arangodb::Result updateProperties(
arangodb::velocypack::Slice const& slice, bool doSync) = 0;
virtual arangodb::Result persistProperties() noexcept = 0;
/// @brief export properties
virtual void getPropertiesVPack(velocypack::Builder&) const = 0;
/// @brief opens an existing view
virtual void open(bool ignoreErrors) = 0;
virtual void drop() = 0;
protected:
LogicalView* _logicalView;
PhysicalView* _physicalView;
};
typedef std::function<std::unique_ptr<ViewImplementation>(
LogicalView*, PhysicalView*, arangodb::velocypack::Slice const&)>
ViewCreator;
} // namespace arangodb
#endif

View File

@ -29,9 +29,9 @@
#include <velocypack/velocypack-aliases.h>
#include "ApplicationFeatures/ApplicationServer.h"
#include "Aql/PlanCache.h"
#include "Aql/QueryCache.h"
#include "Aql/QueryList.h"
#include "Aql/PlanCache.h"
#include "Basics/ConditionLocker.h"
#include "Basics/Exceptions.h"
#include "Basics/FileUtils.h"
@ -62,6 +62,7 @@
#include "VocBase/LogicalView.h"
#include "VocBase/PhysicalCollection.h"
#include "VocBase/PhysicalView.h"
#include "VocBase/ViewImplementation.h"
#include "VocBase/replication-applier.h"
#include "VocBase/ticks.h"
@ -69,7 +70,7 @@
using namespace arangodb;
using namespace arangodb::basics;
/// @brief increase the reference counter for a database
bool TRI_vocbase_t::use() {
auto expected = _refCount.load(std::memory_order_relaxed);
@ -83,7 +84,9 @@ bool TRI_vocbase_t::use() {
// marked as deleted
auto updated = expected + 2;
TRI_ASSERT((updated & 1) == 0);
if (_refCount.compare_exchange_weak(expected, updated, std::memory_order_release, std::memory_order_relaxed)) {
if (_refCount.compare_exchange_weak(expected, updated,
std::memory_order_release,
std::memory_order_relaxed)) {
// compare-exchange worked. we're done
return true;
}
@ -92,9 +95,7 @@ bool TRI_vocbase_t::use() {
}
}
void TRI_vocbase_t::forceUse() {
_refCount += 2;
}
void TRI_vocbase_t::forceUse() { _refCount += 2; }
/// @brief decrease the reference counter for a database
void TRI_vocbase_t::release() {
@ -115,7 +116,7 @@ bool TRI_vocbase_t::isDangling() const {
// that noone else references the database but it has been marked as deleted
return (refCount == 1);
}
/// @brief whether or not the vocbase has been marked as deleted
bool TRI_vocbase_t::isDropped() const {
auto refCount = _refCount.load();
@ -151,12 +152,14 @@ void TRI_vocbase_t::registerCollection(
// check name
auto it = _collectionsByName.emplace(name, collection);
if (!it.second) {
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "duplicate entry for collection name '" << name << "'";
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "collection id " << cid
<< " has same name as already added collection "
<< _collectionsByName[name]->cid();
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< "duplicate entry for collection name '" << name << "'";
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< "collection id " << cid
<< " has same name as already added collection "
<< _collectionsByName[name]->cid();
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DUPLICATE_NAME);
}
@ -168,13 +171,13 @@ void TRI_vocbase_t::registerCollection(
if (!it2.second) {
_collectionsByName.erase(name);
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "duplicate collection identifier " << collection->cid()
<< " for name '" << name << "'";
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< "duplicate collection identifier " << collection->cid()
<< " for name '" << name << "'";
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DUPLICATE_IDENTIFIER);
}
}
catch (...) {
} catch (...) {
_collectionsByName.erase(name);
throw;
}
@ -183,14 +186,13 @@ void TRI_vocbase_t::registerCollection(
try {
_collections.emplace_back(collection);
}
catch (...) {
} catch (...) {
_collectionsByName.erase(name);
_collectionsById.erase(cid);
TRI_ASSERT(_collectionsByName.size() == _collectionsById.size());
throw;
}
collection->setStatus(TRI_VOC_COL_STATUS_UNLOADED);
TRI_ASSERT(_collectionsByName.size() == _collectionsById.size());
}
@ -199,10 +201,11 @@ void TRI_vocbase_t::registerCollection(
/// @brief removes a collection name from the global list of collections
/// This function is called when a collection is dropped.
/// NOTE: You need a writelock on _collectionsLock
bool TRI_vocbase_t::unregisterCollection(arangodb::LogicalCollection* collection) {
bool TRI_vocbase_t::unregisterCollection(
arangodb::LogicalCollection* collection) {
TRI_ASSERT(collection != nullptr);
std::string const colName(collection->name());
// pre-condition
TRI_ASSERT(_collectionsByName.size() == _collectionsById.size());
@ -211,8 +214,8 @@ bool TRI_vocbase_t::unregisterCollection(arangodb::LogicalCollection* collection
// this is because someone else might have created a new collection with the
// same name, but with a different id
_collectionsByName.erase(colName);
}
}
// post-condition
TRI_ASSERT(_collectionsByName.size() == _collectionsById.size());
@ -221,8 +224,8 @@ bool TRI_vocbase_t::unregisterCollection(arangodb::LogicalCollection* collection
/// @brief adds a new view
/// caller must hold _viewLock in write mode or set doLock
void TRI_vocbase_t::registerView(
bool doLock, std::shared_ptr<arangodb::LogicalView> view) {
void TRI_vocbase_t::registerView(bool doLock,
std::shared_ptr<arangodb::LogicalView> view) {
std::string const name = view->name();
TRI_voc_cid_t const id = view->id();
{
@ -230,12 +233,13 @@ void TRI_vocbase_t::registerView(
// check name
auto it = _viewsByName.emplace(name, view);
if (!it.second) {
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "duplicate entry for view name '" << name << "'";
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "view id " << id
<< " has same name as already added view "
<< _viewsByName[name]->id();
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< "duplicate entry for view name '" << name << "'";
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< "view id " << id << " has same name as already added view "
<< _viewsByName[name]->id();
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DUPLICATE_NAME);
}
@ -247,13 +251,13 @@ void TRI_vocbase_t::registerView(
if (!it2.second) {
_viewsByName.erase(name);
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "duplicate view identifier " << view->id()
<< " for name '" << name << "'";
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "duplicate view identifier "
<< view->id() << " for name '"
<< name << "'";
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DUPLICATE_IDENTIFIER);
}
}
catch (...) {
} catch (...) {
_viewsByName.erase(name);
throw;
}
@ -265,10 +269,11 @@ void TRI_vocbase_t::registerView(
/// @brief removes a views name from the global list of views
/// This function is called when a view is dropped.
/// NOTE: You need a writelock on _viewsLock
bool TRI_vocbase_t::unregisterView(std::shared_ptr<arangodb::LogicalView> view) {
bool TRI_vocbase_t::unregisterView(
std::shared_ptr<arangodb::LogicalView> view) {
TRI_ASSERT(view != nullptr);
std::string const name(view->name());
// pre-condition
TRI_ASSERT(_viewsByName.size() == _viewsById.size());
@ -277,8 +282,8 @@ bool TRI_vocbase_t::unregisterView(std::shared_ptr<arangodb::LogicalView> view)
// this is because someone else might have created a new view with the
// same name, but with a different id
_viewsByName.erase(name);
}
}
// post-condition
TRI_ASSERT(_viewsByName.size() == _viewsById.size());
@ -315,8 +320,9 @@ bool TRI_vocbase_t::UnloadCollectionCallback(LogicalCollection* collection) {
if (res != TRI_ERROR_NO_ERROR) {
std::string const colName(collection->name());
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "failed to close collection '" << colName
<< "': " << TRI_last_error();
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "failed to close collection '"
<< colName
<< "': " << TRI_last_error();
collection->setStatus(TRI_VOC_COL_STATUS_CORRUPTED);
return true;
@ -328,17 +334,19 @@ bool TRI_vocbase_t::UnloadCollectionCallback(LogicalCollection* collection) {
}
/// @brief drops a collection
bool TRI_vocbase_t::DropCollectionCallback(arangodb::LogicalCollection* collection) {
bool TRI_vocbase_t::DropCollectionCallback(
arangodb::LogicalCollection* collection) {
std::string const name(collection->name());
{
WRITE_LOCKER_EVENTUAL(statusLock, collection->_lock);
WRITE_LOCKER_EVENTUAL(statusLock, collection->_lock);
if (collection->status() != TRI_VOC_COL_STATUS_DELETED) {
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "someone resurrected the collection '" << name << "'";
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< "someone resurrected the collection '" << name << "'";
return false;
}
} // release status lock
} // release status lock
// remove from list of collections
TRI_vocbase_t* vocbase = collection->vocbase();
@ -367,9 +375,10 @@ bool TRI_vocbase_t::DropCollectionCallback(arangodb::LogicalCollection* collecti
/// @brief creates a new collection, worker function
arangodb::LogicalCollection* TRI_vocbase_t::createCollectionWorker(
VPackSlice parameters, TRI_voc_cid_t& cid) {
std::string name = arangodb::basics::VelocyPackHelper::getStringValue(parameters, "name" , "");
std::string name = arangodb::basics::VelocyPackHelper::getStringValue(
parameters, "name", "");
TRI_ASSERT(!name.empty());
// Try to create a new collection. This is not registered yet
std::unique_ptr<arangodb::LogicalCollection> collection =
@ -401,7 +410,7 @@ arangodb::LogicalCollection* TRI_vocbase_t::createCollectionWorker(
// Let's try to persist it.
collection->persistPhysicalCollection();
events::CreateCollection(name, TRI_ERROR_NO_ERROR);
return collection.release();
} catch (...) {
@ -505,7 +514,9 @@ int TRI_vocbase_t::loadCollection(arangodb::LogicalCollection* collection,
}
// only throw this particular error if the server is configured to do so
auto databaseFeature = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
auto databaseFeature =
application_features::ApplicationServer::getFeature<DatabaseFeature>(
"Database");
if (databaseFeature->throwCollectionNotLoadedError()) {
return TRI_ERROR_ARANGO_COLLECTION_NOT_LOADED;
}
@ -526,7 +537,7 @@ int TRI_vocbase_t::loadCollection(arangodb::LogicalCollection* collection,
// status while it is loading (loading may take a long time because of
// disk activity, index creation etc.)
locker.unlock();
bool ignoreDatafileErrors = false;
if (DatabaseFeature::DATABASE != nullptr) {
ignoreDatafileErrors = DatabaseFeature::DATABASE->ignoreDatafileErrors();
@ -535,15 +546,21 @@ int TRI_vocbase_t::loadCollection(arangodb::LogicalCollection* collection,
try {
collection->open(ignoreDatafileErrors);
} catch (arangodb::basics::Exception const& ex) {
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "caught exception while opening collection '" << collection->name() << "': " << ex.what();
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< "caught exception while opening collection '" << collection->name()
<< "': " << ex.what();
collection->setStatus(TRI_VOC_COL_STATUS_CORRUPTED);
return TRI_ERROR_ARANGO_CORRUPTED_COLLECTION;
} catch (std::exception const& ex) {
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "caught exception while opening collection '" << collection->name() << "': " << ex.what();
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< "caught exception while opening collection '" << collection->name()
<< "': " << ex.what();
collection->setStatus(TRI_VOC_COL_STATUS_CORRUPTED);
return TRI_ERROR_ARANGO_CORRUPTED_COLLECTION;
} catch (...) {
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "caught unknown exception while opening collection '" << collection->name() << "'";
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
<< "caught unknown exception while opening collection '"
<< collection->name() << "'";
collection->setStatus(TRI_VOC_COL_STATUS_CORRUPTED);
return TRI_ERROR_ARANGO_CORRUPTED_COLLECTION;
}
@ -563,8 +580,9 @@ int TRI_vocbase_t::loadCollection(arangodb::LogicalCollection* collection,
}
std::string const colName(collection->name());
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "unknown collection status " << collection->status() << " for '"
<< colName << "'";
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "unknown collection status "
<< collection->status() << " for '"
<< colName << "'";
return TRI_set_errno(TRI_ERROR_INTERNAL);
}
@ -574,10 +592,12 @@ int TRI_vocbase_t::dropCollectionWorker(arangodb::LogicalCollection* collection,
DropState& state) {
state = DROP_EXIT;
std::string const colName(collection->name());
// do not acquire these locks instantly
CONDITIONAL_WRITE_LOCKER(writeLocker, _collectionsLock, basics::ConditionalLocking::DoNotLock);
CONDITIONAL_WRITE_LOCKER(locker, collection->_lock, basics::ConditionalLocking::DoNotLock);
CONDITIONAL_WRITE_LOCKER(writeLocker, _collectionsLock,
basics::ConditionalLocking::DoNotLock);
CONDITIONAL_WRITE_LOCKER(locker, collection->_lock,
basics::ConditionalLocking::DoNotLock);
while (true) {
TRI_ASSERT(!writeLocker.isLocked());
@ -596,7 +616,7 @@ int TRI_vocbase_t::dropCollectionWorker(arangodb::LogicalCollection* collection,
// unlock the write locker so we don't block other operations
writeLocker.unlock();
TRI_ASSERT(!writeLocker.isLocked());
TRI_ASSERT(!locker.isLocked());
@ -634,8 +654,8 @@ int TRI_vocbase_t::dropCollectionWorker(arangodb::LogicalCollection* collection,
if (!collection->deleted()) {
collection->setDeleted(true);
try {
try {
StorageEngine* engine = EngineSelectorFeature::ENGINE;
engine->changeCollection(this, collection->cid(), collection, doSync);
} catch (arangodb::basics::Exception const& ex) {
@ -659,7 +679,7 @@ int TRI_vocbase_t::dropCollectionWorker(arangodb::LogicalCollection* collection,
StorageEngine* engine = EngineSelectorFeature::ENGINE;
TRI_ASSERT(engine != nullptr);
engine->dropCollection(this, collection);
DropCollectionCallback(collection);
break;
}
@ -668,13 +688,17 @@ int TRI_vocbase_t::dropCollectionWorker(arangodb::LogicalCollection* collection,
// collection is loaded
collection->setDeleted(true);
bool doSync = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database")->forceSyncProperties();
bool doSync =
application_features::ApplicationServer::getFeature<DatabaseFeature>(
"Database")
->forceSyncProperties();
doSync = (doSync && !MMFilesLogfileManager::instance()->isInRecovery());
VPackBuilder builder;
StorageEngine* engine = EngineSelectorFeature::ENGINE;
engine->getCollectionInfo(this, collection->cid(), builder, false, 0);
arangodb::Result res = collection->updateProperties(builder.slice().get("parameters"), doSync);
arangodb::Result res = collection->updateProperties(
builder.slice().get("parameters"), doSync);
if (!res.ok()) {
return res.errorNumber();
@ -733,7 +757,7 @@ void TRI_vocbase_t::shutdown() {
setState(TRI_vocbase_t::State::SHUTDOWN_COMPACTOR);
StorageEngine* engine = EngineSelectorFeature::ENGINE;
// shutdownDatabase() stops all threads
// shutdownDatabase() stops all threads
engine->shutdownDatabase(this);
// this will signal the cleanup thread to do one last iteration
@ -781,9 +805,12 @@ std::vector<std::string> TRI_vocbase_t::collectionNames() {
/// The list of collections will be sorted if sort function is given
////////////////////////////////////////////////////////////////////////////////
std::shared_ptr<VPackBuilder> TRI_vocbase_t::inventory(TRI_voc_tick_t maxTick,
bool (*filter)(arangodb::LogicalCollection*, void*), void* data, bool shouldSort,
std::function<bool(arangodb::LogicalCollection*, arangodb::LogicalCollection*)> sortCallback) {
std::shared_ptr<VPackBuilder> TRI_vocbase_t::inventory(
TRI_voc_tick_t maxTick, bool (*filter)(arangodb::LogicalCollection*, void*),
void* data, bool shouldSort,
std::function<bool(arangodb::LogicalCollection*,
arangodb::LogicalCollection*)>
sortCallback) {
std::vector<arangodb::LogicalCollection*> collections;
// cycle on write-lock
@ -874,7 +901,8 @@ LogicalCollection* TRI_vocbase_t::lookupCollection(std::string const& name) {
}
/// @brief looks up a collection by name
LogicalCollection* TRI_vocbase_t::lookupCollectionNoLock(std::string const& name) {
LogicalCollection* TRI_vocbase_t::lookupCollectionNoLock(
std::string const& name) {
if (name.empty()) {
return nullptr;
}
@ -904,7 +932,7 @@ LogicalCollection* TRI_vocbase_t::lookupCollectionNoLock(std::string const& name
/// @brief looks up a collection by identifier
LogicalCollection* TRI_vocbase_t::lookupCollection(TRI_voc_cid_t id) {
READ_LOCKER(readLocker, _collectionsLock);
auto it = _collectionsById.find(id);
if (it == _collectionsById.end()) {
@ -914,7 +942,8 @@ LogicalCollection* TRI_vocbase_t::lookupCollection(TRI_voc_cid_t id) {
}
/// @brief looks up a view by name
std::shared_ptr<LogicalView> TRI_vocbase_t::lookupView(std::string const& name) {
std::shared_ptr<LogicalView> TRI_vocbase_t::lookupView(
std::string const& name) {
if (name.empty()) {
return std::shared_ptr<LogicalView>();
}
@ -940,7 +969,7 @@ std::shared_ptr<LogicalView> TRI_vocbase_t::lookupView(std::string const& name)
/// @brief looks up a view by identifier
std::shared_ptr<LogicalView> TRI_vocbase_t::lookupView(TRI_voc_cid_t id) {
READ_LOCKER(readLocker, _viewsLock);
auto it = _viewsById.find(id);
if (it == _viewsById.end()) {
@ -955,19 +984,18 @@ std::shared_ptr<LogicalView> TRI_vocbase_t::lookupView(TRI_voc_cid_t id) {
/// using a cid of > 0 is supported to import dumps from other servers etc.
/// but the functionality is not advertised
arangodb::LogicalCollection* TRI_vocbase_t::createCollection(
VPackSlice parameters,
TRI_voc_cid_t cid) {
VPackSlice parameters, TRI_voc_cid_t cid) {
// check that the name does not contain any strange characters
if (!LogicalCollection::IsAllowedName(parameters)) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_ILLEGAL_NAME);
}
READ_LOCKER(readLocker, _inventoryLock);
// note: cid may be modified by this function call
arangodb::LogicalCollection* collection = createCollectionWorker(parameters, cid);
arangodb::LogicalCollection* collection =
createCollectionWorker(parameters, cid);
if (collection == nullptr) {
// something went wrong... must not continue
return nullptr;
@ -977,13 +1005,15 @@ arangodb::LogicalCollection* TRI_vocbase_t::createCollection(
TRI_ASSERT(engine != nullptr);
// TODO Review
arangodb::Result 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.
return collection;
}
/// @brief unloads a collection
int TRI_vocbase_t::unloadCollection(arangodb::LogicalCollection* collection, bool force) {
int TRI_vocbase_t::unloadCollection(arangodb::LogicalCollection* collection,
bool force) {
TRI_voc_cid_t cid = collection->cid();
{
WRITE_LOCKER_EVENTUAL(locker, collection->_lock);
@ -1043,9 +1073,9 @@ int TRI_vocbase_t::unloadCollection(arangodb::LogicalCollection* collection, boo
// add callback for unload
arangodb::MMFilesCollection::toMMFilesCollection(collection)
->ditches()
->createMMFilesUnloadCollectionDitch(collection, UnloadCollectionCallback,
__FILE__, __LINE__);
} // release locks
->createMMFilesUnloadCollectionDitch(
collection, UnloadCollectionCallback, __FILE__, __LINE__);
} // release locks
collection->unload();
@ -1057,11 +1087,11 @@ int TRI_vocbase_t::unloadCollection(arangodb::LogicalCollection* collection, boo
}
/// @brief drops a collection
int TRI_vocbase_t::dropCollection(arangodb::LogicalCollection* collection, bool allowDropSystem) {
int TRI_vocbase_t::dropCollection(arangodb::LogicalCollection* collection,
bool allowDropSystem) {
TRI_ASSERT(collection != nullptr);
if (!allowDropSystem &&
collection->isSystem() &&
if (!allowDropSystem && collection->isSystem() &&
!MMFilesLogfileManager::instance()->isInRecovery()) {
// prevent dropping of system collections
return TRI_set_errno(TRI_ERROR_FORBIDDEN);
@ -1083,8 +1113,8 @@ int TRI_vocbase_t::dropCollection(arangodb::LogicalCollection* collection, bool
// add callback for dropping
arangodb::MMFilesCollection::toMMFilesCollection(collection)
->ditches()
->createMMFilesDropCollectionDitch(collection, DropCollectionCallback,
__FILE__, __LINE__);
->createMMFilesDropCollectionDitch(
collection, DropCollectionCallback, __FILE__, __LINE__);
// wake up the cleanup thread
StorageEngine* engine = EngineSelectorFeature::ENGINE;
@ -1104,7 +1134,8 @@ int TRI_vocbase_t::dropCollection(arangodb::LogicalCollection* collection, bool
/// @brief renames a collection
int TRI_vocbase_t::renameCollection(arangodb::LogicalCollection* collection,
std::string const& newName, bool doOverride) {
std::string const& newName,
bool doOverride) {
if (collection->isSystem()) {
return TRI_set_errno(TRI_ERROR_FORBIDDEN);
}
@ -1139,10 +1170,10 @@ int TRI_vocbase_t::renameCollection(arangodb::LogicalCollection* collection,
}
READ_LOCKER(readLocker, _inventoryLock);
CONDITIONAL_WRITE_LOCKER(writeLocker, _collectionsLock, false);
CONDITIONAL_WRITE_LOCKER(locker, collection->_lock, false);
while (true) {
TRI_ASSERT(!writeLocker.isLocked());
TRI_ASSERT(!locker.isLocked());
@ -1160,17 +1191,17 @@ int TRI_vocbase_t::renameCollection(arangodb::LogicalCollection* collection,
// unlock the write locker so we don't block other operations
writeLocker.unlock();
TRI_ASSERT(!writeLocker.isLocked());
TRI_ASSERT(!locker.isLocked());
// sleep for a while
std::this_thread::yield();
}
TRI_ASSERT(writeLocker.isLocked());
TRI_ASSERT(locker.isLocked());
// Check for duplicate name
auto other = lookupCollectionNoLock(newName);
@ -1220,8 +1251,8 @@ int TRI_vocbase_t::useCollection(arangodb::LogicalCollection* collection,
}
/// @brief locks a (document) collection for usage by id
arangodb::LogicalCollection* TRI_vocbase_t::useCollection(TRI_voc_cid_t cid,
TRI_vocbase_col_status_e& status) {
arangodb::LogicalCollection* TRI_vocbase_t::useCollection(
TRI_voc_cid_t cid, TRI_vocbase_col_status_e& status) {
// check that we have an existing name
arangodb::LogicalCollection* collection = nullptr;
{
@ -1252,8 +1283,8 @@ arangodb::LogicalCollection* TRI_vocbase_t::useCollection(TRI_voc_cid_t cid,
}
/// @brief locks a collection for usage by name
arangodb::LogicalCollection* TRI_vocbase_t::useCollection(std::string const& name,
TRI_vocbase_col_status_e& status) {
arangodb::LogicalCollection* TRI_vocbase_t::useCollection(
std::string const& name, TRI_vocbase_col_status_e& status) {
// check that we have an existing name
arangodb::LogicalCollection* collection = nullptr;
@ -1288,12 +1319,22 @@ void TRI_vocbase_t::releaseCollection(arangodb::LogicalCollection* collection) {
collection->_lock.unlock();
}
void TRI_vocbase_t::registerViewImplementation(std::string const& type,
ViewCreator creator) {
_viewImplementations.emplace(type, creator);
}
bool TRI_vocbase_t::unregisterViewImplementation(std::string const& type) {
return (_viewImplementations.erase(type) > 0);
}
/// @brief creates a new view, worker function
std::shared_ptr<arangodb::LogicalView> TRI_vocbase_t::createViewWorker(
VPackSlice parameters, TRI_voc_cid_t& id) {
std::string name = arangodb::basics::VelocyPackHelper::getStringValue(parameters, "name" , "");
std::string name = arangodb::basics::VelocyPackHelper::getStringValue(
parameters, "name", "");
TRI_ASSERT(!name.empty());
// Try to create a new view. This is not registered yet
std::shared_ptr<arangodb::LogicalView> view =
@ -1317,7 +1358,16 @@ std::shared_ptr<arangodb::LogicalView> TRI_vocbase_t::createViewWorker(
// Let's try to persist it.
view->persistPhysicalView();
// now let's actually create the backing implementation
/* no implementations exist yet, need a dummy for testing
auto creator = _viewImplementations.find(view->type());
if (creator != _viewImplementations.end()) {
view->spawnImplementation(*creator);
} else {
throw; // no creator found for that type
}*/
events::CreateView(name, TRI_ERROR_NO_ERROR);
return view;
} catch (...) {
@ -1332,18 +1382,17 @@ std::shared_ptr<arangodb::LogicalView> TRI_vocbase_t::createViewWorker(
/// using a cid of > 0 is supported to import dumps from other servers etc.
/// but the functionality is not advertised
std::shared_ptr<arangodb::LogicalView> TRI_vocbase_t::createView(
VPackSlice parameters,
TRI_voc_cid_t id) {
VPackSlice parameters, TRI_voc_cid_t id) {
// check that the name does not contain any strange characters
if (!LogicalView::IsAllowedName(parameters)) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_ILLEGAL_NAME);
}
READ_LOCKER(readLocker, _inventoryLock);
// note: id may be modified by this function call
std::shared_ptr<LogicalView> view = createViewWorker(parameters, id);
if (view == nullptr) {
// something went wrong... must not continue
return nullptr;
@ -1360,7 +1409,7 @@ std::shared_ptr<arangodb::LogicalView> TRI_vocbase_t::createView(
int TRI_vocbase_t::dropView(std::string const& name) {
std::shared_ptr<LogicalView> view = lookupView(name);
if (view == nullptr) {
return TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND;
}
@ -1373,10 +1422,12 @@ int TRI_vocbase_t::dropView(std::shared_ptr<arangodb::LogicalView> view) {
TRI_ASSERT(view != nullptr);
READ_LOCKER(readLocker, _inventoryLock);
// do not acquire these locks instantly
CONDITIONAL_WRITE_LOCKER(writeLocker, _viewsLock, basics::ConditionalLocking::DoNotLock);
CONDITIONAL_WRITE_LOCKER(locker, view->_lock, basics::ConditionalLocking::DoNotLock);
CONDITIONAL_WRITE_LOCKER(writeLocker, _viewsLock,
basics::ConditionalLocking::DoNotLock);
CONDITIONAL_WRITE_LOCKER(locker, view->_lock,
basics::ConditionalLocking::DoNotLock);
while (true) {
TRI_ASSERT(!writeLocker.isLocked());
@ -1395,7 +1446,7 @@ int TRI_vocbase_t::dropView(std::shared_ptr<arangodb::LogicalView> view) {
// unlock the write locker so we don't block other operations
writeLocker.unlock();
TRI_ASSERT(!writeLocker.isLocked());
TRI_ASSERT(!locker.isLocked());
@ -1416,19 +1467,19 @@ int TRI_vocbase_t::dropView(std::shared_ptr<arangodb::LogicalView> view) {
b.close();
bool doSync =
application_features::ApplicationServer::getFeature<DatabaseFeature>(
application_features::ApplicationServer::getFeature<DatabaseFeature>(
"Database")
->forceSyncProperties();
view->updateProperties(b.slice(), doSync);
view->updateProperties(b.slice(), doSync);
unregisterView(view);
StorageEngine* engine = EngineSelectorFeature::ENGINE;
engine->dropView(this, view.get());
locker.unlock();
writeLocker.unlock();
events::DropView(view->name(), TRI_ERROR_NO_ERROR);
return TRI_ERROR_NO_ERROR;
@ -1445,7 +1496,6 @@ TRI_vocbase_t::TRI_vocbase_t(TRI_vocbase_type_e type, TRI_voc_tick_t id,
_isOwnAppsDirectory(true),
_deadlockDetector(false),
_userStructures(nullptr) {
_queries.reset(new arangodb::aql::QueryList(this));
_cursorRepository.reset(new arangodb::CursorRepository(this));
_collectionKeys.reset(new arangodb::CollectionKeysRepository());
@ -1471,7 +1521,7 @@ TRI_vocbase_t::~TRI_vocbase_t() {
delete it;
}
}
std::string TRI_vocbase_t::path() const {
StorageEngine* engine = EngineSelectorFeature::ENGINE;
return engine->databasePath(this);
@ -1512,7 +1562,7 @@ bool TRI_vocbase_t::IsAllowedName(bool allowSystem, std::string const& name) {
return true;
}
void TRI_vocbase_t::addReplicationApplier(TRI_replication_applier_t* applier) {
_replicationApplier.reset(applier);
}
@ -1567,7 +1617,8 @@ std::vector<std::shared_ptr<arangodb::LogicalView>> TRI_vocbase_t::views() {
return views;
}
std::vector<arangodb::LogicalCollection*> TRI_vocbase_t::collections(bool includeDeleted) {
std::vector<arangodb::LogicalCollection*> TRI_vocbase_t::collections(
bool includeDeleted) {
std::vector<arangodb::LogicalCollection*> collections;
{
@ -1604,7 +1655,7 @@ TRI_voc_rid_t TRI_ExtractRevisionId(VPackSlice slice) {
}
return 0;
}
/// @brief extract the _rev attribute from a slice as a slice
VPackSlice TRI_ExtractRevisionIdAsSlice(VPackSlice const slice) {
if (!slice.isObject()) {
@ -1623,9 +1674,8 @@ void TRI_SanitizeObject(VPackSlice const slice, VPackBuilder& builder) {
while (it.valid()) {
StringRef key(it.key());
if (key.empty() || key[0] != '_' ||
(key != StaticStrings::KeyString &&
key != StaticStrings::IdString &&
key != StaticStrings::RevString)) {
(key != StaticStrings::KeyString && key != StaticStrings::IdString &&
key != StaticStrings::RevString)) {
builder.add(key.data(), key.size(), it.value());
}
it.next();
@ -1634,17 +1684,16 @@ void TRI_SanitizeObject(VPackSlice const slice, VPackBuilder& builder) {
/// @brief sanitize an object, given as slice, builder must contain an
/// open object which will remain open. also excludes _from and _to
void TRI_SanitizeObjectWithEdges(VPackSlice const slice, VPackBuilder& builder) {
void TRI_SanitizeObjectWithEdges(VPackSlice const slice,
VPackBuilder& builder) {
TRI_ASSERT(slice.isObject());
VPackObjectIterator it(slice, true);
while (it.valid()) {
StringRef key(it.key());
if (key.empty() || key[0] != '_' ||
(key != StaticStrings::KeyString &&
key != StaticStrings::IdString &&
key != StaticStrings::RevString &&
key != StaticStrings::FromString &&
key != StaticStrings::ToString)) {
(key != StaticStrings::KeyString && key != StaticStrings::IdString &&
key != StaticStrings::RevString && key != StaticStrings::FromString &&
key != StaticStrings::ToString)) {
builder.add(key.data(), key.length(), it.value());
}
it.next();
@ -1652,8 +1701,9 @@ void TRI_SanitizeObjectWithEdges(VPackSlice const slice, VPackBuilder& builder)
}
/// @brief Convert a revision ID to a string
constexpr static TRI_voc_rid_t tickLimit
= static_cast<TRI_voc_rid_t>(2016ULL - 1970ULL) * 1000ULL * 60ULL * 60ULL * 24ULL * 365ULL;
constexpr static TRI_voc_rid_t tickLimit =
static_cast<TRI_voc_rid_t>(2016ULL - 1970ULL) * 1000ULL * 60ULL * 60ULL *
24ULL * 365ULL;
std::string TRI_RidToString(TRI_voc_rid_t rid) {
if (rid <= tickLimit) {
@ -1669,18 +1719,20 @@ TRI_voc_rid_t TRI_StringToRid(char const* p, size_t len, bool warn) {
}
/// @brief Convert a string into a revision ID, returns 0 if format invalid
TRI_voc_rid_t TRI_StringToRid(std::string const& ridStr, bool& isOld, bool warn) {
TRI_voc_rid_t TRI_StringToRid(std::string const& ridStr, bool& isOld,
bool warn) {
return TRI_StringToRid(ridStr.c_str(), ridStr.size(), isOld, warn);
}
/// @brief Convert a string into a revision ID, returns 0 if format invalid
TRI_voc_rid_t TRI_StringToRid(char const* p, size_t len, bool& isOld, bool warn) {
TRI_voc_rid_t TRI_StringToRid(char const* p, size_t len, bool& isOld,
bool warn) {
if (len > 0 && *p >= '1' && *p <= '9') {
TRI_voc_rid_t r = arangodb::basics::StringUtils::uint64_check(p, len);
if (warn && r > tickLimit) {
// An old tick value that could be confused with a time stamp
LOG_TOPIC(WARN, arangodb::Logger::FIXME)
<< "Saw old _rev value that could be confused with a time stamp!";
<< "Saw old _rev value that could be confused with a time stamp!";
}
isOld = true;
return r;
@ -1688,4 +1740,3 @@ TRI_voc_rid_t TRI_StringToRid(char const* p, size_t len, bool& isOld, bool warn)
isOld = false;
return HybridLogicalClock::decodeTimeStamp(p, len);
}

View File

@ -31,10 +31,11 @@
#include "Basics/ReadWriteLock.h"
#include "Basics/StringUtils.h"
#include "Basics/voc-errors.h"
#include "VocBase/ViewImplementation.h"
#include "VocBase/voc-types.h"
#include "velocypack/Slice.h"
#include "velocypack/Builder.h"
#include "velocypack/Slice.h"
#include "velocypack/velocypack-aliases.h"
class TRI_replication_applier_t;
@ -65,7 +66,7 @@ constexpr auto TRI_VOC_SYSTEM_DATABASE = "_system";
constexpr size_t TRI_COL_NAME_LENGTH = 64;
/// @brief default maximal collection journal size
constexpr size_t TRI_JOURNAL_DEFAULT_SIZE = 1024 * 1024 * 32; // 32 MB
constexpr size_t TRI_JOURNAL_DEFAULT_SIZE = 1024 * 1024 * 32; // 32 MB
////////////////////////////////////////////////////////////////////////////////
/// @brief minimal collection journal size (for testing, we allow very small
@ -74,11 +75,11 @@ constexpr size_t TRI_JOURNAL_DEFAULT_SIZE = 1024 * 1024 * 32; // 32 MB
#ifdef ARANGODB_ENABLE_MAINTAINER_MODE
constexpr size_t TRI_JOURNAL_MINIMAL_SIZE = 16 * 1024; // 16 KB
constexpr size_t TRI_JOURNAL_MINIMAL_SIZE = 16 * 1024; // 16 KB
#else
constexpr size_t TRI_JOURNAL_MINIMAL_SIZE = 1024 * 1024; // 1 MB
constexpr size_t TRI_JOURNAL_MINIMAL_SIZE = 1024 * 1024; // 1 MB
#endif
@ -96,7 +97,7 @@ constexpr auto TRI_INDEX_HANDLE_SEPARATOR_STR = "/";
/// @brief collection enum
enum TRI_col_type_e : uint32_t {
TRI_COL_TYPE_UNKNOWN = 0, // only used to signal an invalid collection type
TRI_COL_TYPE_UNKNOWN = 0, // only used to signal an invalid collection type
TRI_COL_TYPE_DOCUMENT = 2,
TRI_COL_TYPE_EDGE = 3
};
@ -124,7 +125,7 @@ enum TRI_vocbase_col_status_e : int {
struct TRI_vocbase_t {
friend class arangodb::CollectionNameResolver;
friend class arangodb::StorageEngine;
/// @brief database state
enum class State {
NORMAL = 0,
@ -133,51 +134,60 @@ struct TRI_vocbase_t {
FAILED_VERSION = 3
};
TRI_vocbase_t(TRI_vocbase_type_e type, TRI_voc_tick_t id, std::string const& name);
TRI_vocbase_t(TRI_vocbase_type_e type, TRI_voc_tick_t id,
std::string const& name);
~TRI_vocbase_t();
private:
/// @brief sleep interval used when polling for a loading collection's status
static constexpr unsigned collectionStatusPollInterval() { return 10 * 1000; }
static constexpr unsigned collectionStatusPollInterval() { return 10 * 1000; }
/// @brief states for dropping
enum DropState {
DROP_EXIT, // drop done, nothing else to do
DROP_AGAIN, // drop not done, must try again
DROP_PERFORM // drop done, must perform actual cleanup routine
DROP_EXIT, // drop done, nothing else to do
DROP_AGAIN, // drop not done, must try again
DROP_PERFORM // drop done, must perform actual cleanup routine
};
TRI_voc_tick_t const _id; // internal database id
TRI_voc_tick_t const _id; // internal database id
std::string _name; // database name
TRI_vocbase_type_e _type; // type (normal or coordinator)
std::atomic<uint64_t> _refCount;
State _state;
bool _isOwnAppsDirectory;
arangodb::basics::ReadWriteLock _collectionsLock; // collection iterator lock
std::vector<arangodb::LogicalCollection*> _collections; // pointers to ALL collections
std::vector<arangodb::LogicalCollection*> _deadCollections; // pointers to collections
// dropped that can be
// removed later
std::unordered_map<std::string, arangodb::LogicalCollection*> _collectionsByName; // collections by name
std::unordered_map<TRI_voc_cid_t, arangodb::LogicalCollection*> _collectionsById; // collections by id
std::vector<arangodb::LogicalCollection*>
_collections; // pointers to ALL collections
std::vector<arangodb::LogicalCollection*>
_deadCollections; // pointers to collections
// dropped that can be
// removed later
std::unordered_map<std::string, arangodb::LogicalCollection*>
_collectionsByName; // collections by name
std::unordered_map<TRI_voc_cid_t, arangodb::LogicalCollection*>
_collectionsById; // collections by id
arangodb::basics::ReadWriteLock _viewsLock; // views management lock
std::unordered_map<std::string, std::shared_ptr<arangodb::LogicalView>> _viewsByName; // views by name
std::unordered_map<TRI_voc_cid_t, std::shared_ptr<arangodb::LogicalView>> _viewsById; // views by id
std::unordered_map<std::string, std::shared_ptr<arangodb::LogicalView>>
_viewsByName; // views by name
std::unordered_map<TRI_voc_cid_t, std::shared_ptr<arangodb::LogicalView>>
_viewsById; // views by id
std::unique_ptr<arangodb::aql::QueryList> _queries;
std::unique_ptr<arangodb::CursorRepository> _cursorRepository;
std::unique_ptr<arangodb::CollectionKeysRepository> _collectionKeys;
std::unique_ptr<TRI_replication_applier_t> _replicationApplier;
arangodb::basics::ReadWriteLock _replicationClientsLock;
std::unordered_map<TRI_server_id_t, std::pair<double, TRI_voc_tick_t>>
_replicationClients;
// view factory
std::unordered_map<std::string, arangodb::ViewCreator> _viewImplementations;
public:
arangodb::basics::DeadlockDetector<arangodb::LogicalCollection>
_deadlockDetector;
@ -199,13 +209,20 @@ struct TRI_vocbase_t {
State state() const { return _state; }
void setState(State state) { _state = state; }
void updateReplicationClient(TRI_server_id_t, TRI_voc_tick_t);
std::vector<std::tuple<TRI_server_id_t, double, TRI_voc_tick_t>> getReplicationClients();
TRI_replication_applier_t* replicationApplier() const { return _replicationApplier.get(); }
std::vector<std::tuple<TRI_server_id_t, double, TRI_voc_tick_t>>
getReplicationClients();
TRI_replication_applier_t* replicationApplier() const {
return _replicationApplier.get();
}
void addReplicationApplier(TRI_replication_applier_t* applier);
arangodb::aql::QueryList* queryList() const { return _queries.get(); }
arangodb::CursorRepository* cursorRepository() const { return _cursorRepository.get(); }
arangodb::CollectionKeysRepository* collectionKeys() const { return _collectionKeys.get(); }
arangodb::CursorRepository* cursorRepository() const {
return _cursorRepository.get();
}
arangodb::CollectionKeysRepository* collectionKeys() const {
return _collectionKeys.get();
}
bool isOwnAppsDirectory() const { return _isOwnAppsDirectory; }
void setIsOwnAppsDirectory(bool value) { _isOwnAppsDirectory = value; }
@ -213,7 +230,7 @@ struct TRI_vocbase_t {
/// @brief signal the cleanup thread to wake up
void signalCleanup();
/// @brief increase the reference counter for a database.
/// @brief increase the reference counter for a database.
/// will return true if the refeence counter was increased, false otherwise
/// in case false is returned, the database must not be used
bool use();
@ -222,7 +239,7 @@ struct TRI_vocbase_t {
/// @brief decrease the reference counter for a database
void release();
/// @brief returns whether the database is dangling
bool isDangling() const;
@ -237,7 +254,7 @@ struct TRI_vocbase_t {
/// @brief closes a database and all collections
void shutdown();
/// @brief returns all known views
std::vector<std::shared_ptr<arangodb::LogicalView>> views();
@ -256,7 +273,7 @@ struct TRI_vocbase_t {
arangodb::LogicalCollection* lookupCollection(std::string const& name);
/// @brief looks up a collection by identifier
arangodb::LogicalCollection* lookupCollection(TRI_voc_cid_t id);
/// @brief looks up a view by name
std::shared_ptr<arangodb::LogicalView> lookupView(std::string const& name);
/// @brief looks up a view by identifier
@ -266,8 +283,9 @@ struct TRI_vocbase_t {
/// and optionally indexes
/// the result is sorted by type and name (vertices before edges)
std::shared_ptr<arangodb::velocypack::Builder> inventory(
TRI_voc_tick_t, bool (*)(arangodb::LogicalCollection*, void*), void*,
bool, std::function<bool(arangodb::LogicalCollection*, arangodb::LogicalCollection*)>);
TRI_voc_tick_t, bool (*)(arangodb::LogicalCollection*, void*), void*,
bool, std::function<bool(arangodb::LogicalCollection*,
arangodb::LogicalCollection*)>);
/// @brief renames a collection
int renameCollection(arangodb::LogicalCollection* collection,
@ -282,17 +300,25 @@ struct TRI_vocbase_t {
arangodb::velocypack::Slice parameters, TRI_voc_cid_t cid);
/// @brief drops a collection
int dropCollection(arangodb::LogicalCollection* collection, bool allowDropSystem);
int dropCollection(arangodb::LogicalCollection* collection,
bool allowDropSystem);
/// @brief callback for collection dropping
static bool DropCollectionCallback(arangodb::LogicalCollection* collection);
/// @brief unloads a collection
int unloadCollection(arangodb::LogicalCollection* collection, bool force);
/// @brief callback for unloading a collection
static bool UnloadCollectionCallback(arangodb::LogicalCollection* collection);
/// @brief adds a new view implementation
void registerViewImplementation(std::string const& type,
arangodb::ViewCreator creator);
/// @brief removes a view implementation
bool unregisterViewImplementation(std::string const& type);
/// @brief creates a new view from parameter set
/// view id is normally passed with a value of 0
/// this means that the system will assign a new id automatically
@ -308,19 +334,22 @@ struct TRI_vocbase_t {
/// @brief locks a collection for usage, loading or manifesting it
/// Note that this will READ lock the collection you have to release the
/// collection lock by yourself.
int useCollection(arangodb::LogicalCollection* collection, TRI_vocbase_col_status_e&);
int useCollection(arangodb::LogicalCollection* collection,
TRI_vocbase_col_status_e&);
/// @brief locks a collection for usage by id
/// Note that this will READ lock the collection you have to release the
/// collection lock by yourself and call @ref TRI_ReleaseCollectionVocBase
/// when you are done with the collection.
arangodb::LogicalCollection* useCollection(TRI_voc_cid_t cid, TRI_vocbase_col_status_e&);
arangodb::LogicalCollection* useCollection(TRI_voc_cid_t cid,
TRI_vocbase_col_status_e&);
/// @brief locks a collection for usage by name
/// Note that this will READ lock the collection you have to release the
/// collection lock by yourself and call @ref TRI_ReleaseCollectionVocBase
/// when you are done with the collection.
arangodb::LogicalCollection* useCollection(std::string const& name, TRI_vocbase_col_status_e&);
arangodb::LogicalCollection* useCollection(std::string const& name,
TRI_vocbase_col_status_e&);
/// @brief releases a collection from usage
void releaseCollection(arangodb::LogicalCollection* collection);
@ -330,8 +359,7 @@ struct TRI_vocbase_t {
arangodb::LogicalCollection* lookupCollectionNoLock(std::string const& name);
int loadCollection(arangodb::LogicalCollection* collection,
TRI_vocbase_col_status_e& status,
bool setStatus = true);
TRI_vocbase_col_status_e& status, bool setStatus = true);
/// @brief adds a new collection
/// caller must hold _collectionsLock in write mode or set doLock
@ -348,12 +376,11 @@ struct TRI_vocbase_t {
/// @brief drops a collection, worker function
int dropCollectionWorker(arangodb::LogicalCollection* collection,
DropState& state);
/// @brief creates a new view, worker function
std::shared_ptr<arangodb::LogicalView> createViewWorker(
arangodb::velocypack::Slice parameters, TRI_voc_cid_t& id);
/// @brief adds a new view
/// caller must hold _viewsLock in write mode or set doLock
void registerView(bool doLock, std::shared_ptr<arangodb::LogicalView> view);
@ -364,7 +391,7 @@ struct TRI_vocbase_t {
};
// scope guard for a database
// ensures that a database
// ensures that a database
class VocbaseGuard {
public:
VocbaseGuard() = delete;
@ -386,7 +413,7 @@ class VocbaseGuard {
/// @brief extract the _rev attribute from a slice
TRI_voc_rid_t TRI_ExtractRevisionId(VPackSlice const slice);
/// @brief extract the _rev attribute from a slice as a slice
VPackSlice TRI_ExtractRevisionIdAsSlice(VPackSlice const slice);