Add functions for listing indices and constraints

Reviewers: teon.banek

Reviewed By: teon.banek

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D2371
This commit is contained in:
Matej Ferencevic 2019-09-11 13:22:11 +02:00
parent 6d9933373e
commit 73379bc57e
6 changed files with 80 additions and 9 deletions

View File

@ -72,4 +72,10 @@ ValidateExistenceConstraints(Vertex *vertex, Constraints *constraints) {
return std::nullopt;
}
/// Returns a list of all created existence constraints.
inline std::vector<std::pair<LabelId, PropertyId>> ListExistenceConstraints(
const Constraints &constraints) {
return constraints.existence_constraints;
}
} // namespace storage

View File

@ -298,6 +298,16 @@ void LabelIndex::UpdateOnAddLabel(LabelId label, Vertex *vertex,
GetOrCreateStorage(label)->access().insert(Entry{vertex, tx.start_timestamp});
}
std::vector<LabelId> LabelIndex::ListIndices() const {
std::vector<LabelId> ret;
ret.reserve(index_.size());
auto acc = index_.access();
for (const auto &item : acc) {
ret.push_back(item.label);
}
return ret;
}
void LabelIndex::RemoveObsoleteEntries(uint64_t oldest_active_start_timestamp) {
auto index_acc = index_.access();
for (auto &label_storage : index_acc) {
@ -463,6 +473,16 @@ bool LabelPropertyIndex::CreateIndex(
return true;
}
std::vector<std::pair<LabelId, PropertyId>> LabelPropertyIndex::ListIndices()
const {
std::vector<std::pair<LabelId, PropertyId>> ret;
ret.reserve(index_.size());
for (const auto &item : index_) {
ret.push_back(item.first);
}
return ret;
}
void LabelPropertyIndex::RemoveObsoleteEntries(
uint64_t oldest_active_start_timestamp) {
for (auto &[label_property, index] : index_) {

View File

@ -45,6 +45,8 @@ class LabelIndex {
/// @throw std::bad_alloc
void UpdateOnAddLabel(LabelId label, Vertex *vertex, const Transaction &tx);
std::vector<LabelId> ListIndices() const;
void RemoveObsoleteEntries(uint64_t oldest_active_start_timestamp);
class Iterable {
@ -142,6 +144,8 @@ class LabelPropertyIndex {
return index_.find({label, property}) != index_.end();
}
std::vector<std::pair<LabelId, PropertyId>> ListIndices() const;
/// @throw std::bad_alloc if unable to copy a PropertyValue
void RemoveObsoleteEntries(uint64_t oldest_active_start_timestamp);

View File

@ -152,6 +152,18 @@ class VerticesIterable final {
Iterator end();
};
/// Structure used to return information about existing indices in the storage.
struct IndicesInfo {
std::vector<LabelId> label;
std::vector<std::pair<LabelId, PropertyId>> label_property;
};
/// Structure used to return information about existing constraints in the
/// storage.
struct ConstraintsInfo {
std::vector<std::pair<LabelId, PropertyId>> existence;
};
class Storage final {
public:
/// @throw std::system_error
@ -321,6 +333,11 @@ class Storage final {
return indices_.label_property_index.IndexExists(label, property);
}
IndicesInfo ListAllIndices() const {
return {indices_.label_index.ListIndices(),
indices_.label_property_index.ListIndices()};
}
/// Creates a unique constraint`. Returns true if the constraint was
/// successfuly added, false if it already exists and an
/// `ExistenceConstraintViolation` if there is an existing vertex violating
@ -342,6 +359,10 @@ class Storage final {
return ::storage::DropExistenceConstraint(&constraints_, label, property);
}
ConstraintsInfo ListAllConstraints() const {
return {ListExistenceConstraints(constraints_)};
}
private:
/// @throw std::system_error
/// @throw std::bad_alloc

View File

@ -6,6 +6,8 @@
// NOLINTNEXTLINE(google-build-using-namespace)
using namespace storage;
using testing::UnorderedElementsAre;
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define ASSERT_NO_ERROR(result) ASSERT_FALSE((result).HasError())
@ -31,26 +33,39 @@ class ConstraintsTest : public testing::Test {
// NOLINTNEXTLINE(hicpp-special-member-functions)
TEST_F(ConstraintsTest, CreateAndDrop) {
EXPECT_EQ(storage.ListAllConstraints().existence.size(), 0);
{
auto res = storage.CreateExistenceConstraint(label1, prop1);
EXPECT_TRUE(res.HasValue() && res.GetValue());
}
EXPECT_THAT(storage.ListAllConstraints().existence,
UnorderedElementsAre(std::make_pair(label1, prop1)));
{
auto res = storage.CreateExistenceConstraint(label1, prop1);
EXPECT_TRUE(res.HasValue() && !res.GetValue());
}
EXPECT_THAT(storage.ListAllConstraints().existence,
UnorderedElementsAre(std::make_pair(label1, prop1)));
{
auto res = storage.CreateExistenceConstraint(label2, prop1);
EXPECT_TRUE(res.HasValue() && res.GetValue());
}
EXPECT_THAT(storage.ListAllConstraints().existence,
UnorderedElementsAre(std::make_pair(label1, prop1),
std::make_pair(label2, prop1)));
EXPECT_TRUE(storage.DropExistenceConstraint(label1, prop1));
EXPECT_FALSE(storage.DropExistenceConstraint(label1, prop1));
EXPECT_THAT(storage.ListAllConstraints().existence,
UnorderedElementsAre(std::make_pair(label2, prop1)));
EXPECT_TRUE(storage.DropExistenceConstraint(label2, prop1));
EXPECT_FALSE(storage.DropExistenceConstraint(label2, prop2));
EXPECT_EQ(storage.ListAllConstraints().existence.size(), 0);
{
auto res = storage.CreateExistenceConstraint(label2, prop1);
EXPECT_TRUE(res.HasValue() && res.GetValue());
}
EXPECT_THAT(storage.ListAllConstraints().existence,
UnorderedElementsAre(std::make_pair(label2, prop1)));
}
// NOLINTNEXTLINE(hicpp-special-member-functions)

View File

@ -6,9 +6,6 @@
// NOLINTNEXTLINE(google-build-using-namespace)
using namespace storage;
LabelId nil_label = LabelId::FromUint(0);
PropertyId nil_property = PropertyId::FromUint(0);
using testing::IsEmpty;
using testing::UnorderedElementsAre;
@ -17,12 +14,6 @@ using testing::UnorderedElementsAre;
class IndexTest : public testing::Test {
protected:
IndexTest()
: prop_id(nil_property),
prop_val(nil_property),
label1(nil_label),
label2(nil_label) {}
void SetUp() override {
auto acc = storage.Access();
prop_id = acc.NameToProperty("id");
@ -67,10 +58,13 @@ TEST_F(IndexTest, LabelIndexBasic) {
// vertices.
// 4. Delete even numbered vertices.
auto acc = storage.Access();
EXPECT_EQ(storage.ListAllIndices().label.size(), 0);
EXPECT_THAT(GetIds(acc.Vertices(label1, View::OLD), View::OLD), IsEmpty());
EXPECT_THAT(GetIds(acc.Vertices(label2, View::OLD), View::OLD), IsEmpty());
EXPECT_THAT(GetIds(acc.Vertices(label1, View::NEW), View::NEW), IsEmpty());
EXPECT_THAT(GetIds(acc.Vertices(label2, View::NEW), View::NEW), IsEmpty());
EXPECT_THAT(storage.ListAllIndices().label,
UnorderedElementsAre(label1, label2));
for (int i = 0; i < 10; ++i) {
auto vertex = CreateVertex(&acc);
@ -220,20 +214,31 @@ TEST_F(IndexTest, LabelIndexCountEstimate) {
// NOLINTNEXTLINE(hicpp-special-member-functions)
TEST_F(IndexTest, LabelPropertyIndexCreateAndDrop) {
EXPECT_EQ(storage.ListAllIndices().label_property.size(), 0);
EXPECT_TRUE(storage.CreateIndex(label1, prop_id));
EXPECT_TRUE(storage.LabelPropertyIndexExists(label1, prop_id));
EXPECT_THAT(storage.ListAllIndices().label_property,
UnorderedElementsAre(std::make_pair(label1, prop_id)));
EXPECT_FALSE(storage.LabelPropertyIndexExists(label2, prop_id));
EXPECT_FALSE(storage.CreateIndex(label1, prop_id));
EXPECT_THAT(storage.ListAllIndices().label_property,
UnorderedElementsAre(std::make_pair(label1, prop_id)));
EXPECT_TRUE(storage.CreateIndex(label2, prop_id));
EXPECT_TRUE(storage.LabelPropertyIndexExists(label2, prop_id));
EXPECT_THAT(storage.ListAllIndices().label_property,
UnorderedElementsAre(std::make_pair(label1, prop_id),
std::make_pair(label2, prop_id)));
EXPECT_TRUE(storage.DropIndex(label1, prop_id));
EXPECT_FALSE(storage.LabelPropertyIndexExists(label1, prop_id));
EXPECT_THAT(storage.ListAllIndices().label_property,
UnorderedElementsAre(std::make_pair(label2, prop_id)));
EXPECT_FALSE(storage.DropIndex(label1, prop_id));
EXPECT_TRUE(storage.DropIndex(label2, prop_id));
EXPECT_FALSE(storage.LabelPropertyIndexExists(label2, prop_id));
EXPECT_EQ(storage.ListAllIndices().label_property.size(), 0);
}
// The following three tests are almost an exact copy-paste of the corresponding