Compare commits
8 Commits
cpp23
...
v2.15.0-rc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1cdf9a0ba | ||
|
|
be8b755673 | ||
|
|
48db39a16a | ||
|
|
0f7d774fc5 | ||
|
|
dfb3a62cc4 | ||
|
|
307c2e0881 | ||
|
|
b9b221cfe2 | ||
|
|
6698d48a82 |
@@ -2,7 +2,7 @@
|
||||
BasedOnStyle: Google
|
||||
---
|
||||
Language: Cpp
|
||||
Standard: c++20
|
||||
Standard: "c++20"
|
||||
UseTab: Never
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Right
|
||||
|
||||
1
.github/ISSUE_TEMPLATE/bug_report.md
vendored
1
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -3,6 +3,7 @@ name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ""
|
||||
labels: bug
|
||||
assignees: gitbuda
|
||||
---
|
||||
|
||||
**Memgraph version**
|
||||
|
||||
@@ -17,10 +17,9 @@ repos:
|
||||
name: isort (python)
|
||||
args: ["--profile", "black"]
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: v17.0.6
|
||||
rev: v13.0.0
|
||||
hooks:
|
||||
- id: clang-format
|
||||
types_or: [c++, c]
|
||||
# - repo: local
|
||||
# hooks:
|
||||
# - id: clang-tidy
|
||||
|
||||
@@ -64,7 +64,7 @@ option(MG_ENTERPRISE "Build Memgraph Enterprise Edition" ON)
|
||||
# Set the current version here to override the automatic version detection. The
|
||||
# version must be specified as `X.Y.Z`. Primarily used when building new patch
|
||||
# versions.
|
||||
set(MEMGRAPH_OVERRIDE_VERSION "")
|
||||
set(MEMGRAPH_OVERRIDE_VERSION "2.15.0")
|
||||
|
||||
# Custom suffix that this version should have. The suffix can be any arbitrary
|
||||
# string. Primarily used when building a version for a specific customer.
|
||||
@@ -189,7 +189,7 @@ add_custom_target(clean_all
|
||||
# is easier debugging of compilation and linker flags.
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
# c99-designator is disabled because of required mixture of designated and
|
||||
# non-designated initializers in Python Query Module code (`py_module.cpp`).
|
||||
|
||||
2
init
2
init
@@ -120,7 +120,7 @@ fi
|
||||
# develop on them -> pre-commit hook not required -> we can use latest
|
||||
# packages.
|
||||
if [ "${DISTRO}" != "centos-7" ] && [ "$DISTRO" != "debian-10" ] && [ "${DISTRO}" != "ubuntu-18.04" ] && [ "${DISTRO}" != "amzn-2" ]; then
|
||||
python3 -m pip install pre-commit==3.5.*
|
||||
python3 -m pip install pre-commit
|
||||
python3 -m pre_commit install
|
||||
# Install py format tools for usage during the development.
|
||||
echo "Install black formatter"
|
||||
|
||||
@@ -36,7 +36,7 @@ ADDITIONAL USE GRANT: You may use the Licensed Work in accordance with the
|
||||
3. using the Licensed Work to create a work or solution
|
||||
which competes (or might reasonably be expected to
|
||||
compete) with the Licensed Work.
|
||||
CHANGE DATE: 2028-21-01
|
||||
CHANGE DATE: 2028-28-02
|
||||
CHANGE LICENSE: Apache License, Version 2.0
|
||||
|
||||
For information about alternative licensing arrangements, please visit: https://memgraph.com/legal.
|
||||
|
||||
@@ -54,10 +54,6 @@ class EdgeAccessor final {
|
||||
return impl_.GetProperty(key, view);
|
||||
}
|
||||
|
||||
storage::Result<uint64_t> GetPropertySize(storage::PropertyId key, storage::View view) const {
|
||||
return impl_.GetPropertySize(key, view);
|
||||
}
|
||||
|
||||
storage::Result<storage::PropertyValue> SetProperty(storage::PropertyId key, const storage::PropertyValue &value) {
|
||||
return impl_.SetProperty(key, value);
|
||||
}
|
||||
@@ -133,10 +129,6 @@ class VertexAccessor final {
|
||||
return impl_.GetProperty(key, view);
|
||||
}
|
||||
|
||||
storage::Result<uint64_t> GetPropertySize(storage::PropertyId key, storage::View view) const {
|
||||
return impl_.GetPropertySize(key, view);
|
||||
}
|
||||
|
||||
storage::Result<storage::PropertyValue> SetProperty(storage::PropertyId key, const storage::PropertyValue &value) {
|
||||
return impl_.SetProperty(key, value);
|
||||
}
|
||||
@@ -276,10 +268,6 @@ class SubgraphVertexAccessor final {
|
||||
return impl_.GetProperty(view, key);
|
||||
}
|
||||
|
||||
storage::Result<uint64_t> GetPropertySize(storage::PropertyId key, storage::View view) const {
|
||||
return impl_.GetPropertySize(key, view);
|
||||
}
|
||||
|
||||
storage::Gid Gid() const noexcept { return impl_.Gid(); }
|
||||
|
||||
storage::Result<size_t> InDegree(storage::View view) const { return impl_.InDegree(view); }
|
||||
@@ -541,10 +529,6 @@ class DbAccessor final {
|
||||
|
||||
storage::PropertyId NameToProperty(const std::string_view name) { return accessor_->NameToProperty(name); }
|
||||
|
||||
std::optional<storage::PropertyId> NameToPropertyIfExists(std::string_view name) const {
|
||||
return accessor_->NameToPropertyIfExists(name);
|
||||
}
|
||||
|
||||
storage::LabelId NameToLabel(const std::string_view name) { return accessor_->NameToLabel(name); }
|
||||
|
||||
storage::EdgeTypeId NameToEdgeType(const std::string_view name) { return accessor_->NameToEdgeType(name); }
|
||||
|
||||
@@ -442,29 +442,6 @@ TypedValue Size(const TypedValue *args, int64_t nargs, const FunctionContext &ct
|
||||
}
|
||||
}
|
||||
|
||||
TypedValue PropertySize(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) {
|
||||
FType<Or<Null, Vertex, Edge>, Or<String>>("propertySize", args, nargs);
|
||||
|
||||
auto *dba = ctx.db_accessor;
|
||||
|
||||
const auto &property_name = args[1].ValueString();
|
||||
const auto maybe_property_id = dba->NameToPropertyIfExists(property_name);
|
||||
|
||||
if (!maybe_property_id) {
|
||||
return TypedValue(0, ctx.memory);
|
||||
}
|
||||
|
||||
uint64_t property_size = 0;
|
||||
const auto &graph_entity = args[0];
|
||||
if (graph_entity.IsVertex()) {
|
||||
property_size = graph_entity.ValueVertex().GetPropertySize(*maybe_property_id, ctx.view).GetValue();
|
||||
} else if (graph_entity.IsEdge()) {
|
||||
property_size = graph_entity.ValueEdge().GetPropertySize(*maybe_property_id, ctx.view).GetValue();
|
||||
}
|
||||
|
||||
return TypedValue(static_cast<int64_t>(property_size), ctx.memory);
|
||||
}
|
||||
|
||||
TypedValue StartNode(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) {
|
||||
FType<Or<Null, Edge>>("startNode", args, nargs);
|
||||
if (args[0].IsNull()) return TypedValue(ctx.memory);
|
||||
@@ -1348,7 +1325,6 @@ std::function<TypedValue(const TypedValue *, int64_t, const FunctionContext &ctx
|
||||
if (function_name == "PROPERTIES") return Properties;
|
||||
if (function_name == "RANDOMUUID") return RandomUuid;
|
||||
if (function_name == "SIZE") return Size;
|
||||
if (function_name == "PROPERTYSIZE") return PropertySize;
|
||||
if (function_name == "STARTNODE") return StartNode;
|
||||
if (function_name == "TIMESTAMP") return Timestamp;
|
||||
if (function_name == "TOBOOLEAN") return ToBoolean;
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
#include "storage/v2/delta.hpp"
|
||||
#include "storage/v2/mvcc.hpp"
|
||||
#include "storage/v2/property_store.hpp"
|
||||
#include "storage/v2/property_value.hpp"
|
||||
#include "storage/v2/result.hpp"
|
||||
#include "storage/v2/storage.hpp"
|
||||
@@ -265,27 +264,6 @@ Result<PropertyValue> EdgeAccessor::GetProperty(PropertyId property, View view)
|
||||
return *std::move(value);
|
||||
}
|
||||
|
||||
Result<uint64_t> EdgeAccessor::GetPropertySize(PropertyId property, View view) const {
|
||||
if (!storage_->config_.salient.items.properties_on_edges) return 0;
|
||||
|
||||
auto guard = std::shared_lock{edge_.ptr->lock};
|
||||
Delta *delta = edge_.ptr->delta;
|
||||
if (!delta) {
|
||||
return edge_.ptr->properties.PropertySize(property);
|
||||
}
|
||||
|
||||
auto property_result = this->GetProperty(property, view);
|
||||
|
||||
if (property_result.HasError()) {
|
||||
return property_result.GetError();
|
||||
}
|
||||
|
||||
auto property_store = storage::PropertyStore();
|
||||
property_store.SetProperty(property, *property_result);
|
||||
|
||||
return property_store.PropertySize(property);
|
||||
};
|
||||
|
||||
Result<std::map<PropertyId, PropertyValue>> EdgeAccessor::Properties(View view) const {
|
||||
if (!storage_->config_.salient.items.properties_on_edges) return std::map<PropertyId, PropertyValue>{};
|
||||
bool exists = true;
|
||||
|
||||
@@ -82,9 +82,6 @@ class EdgeAccessor final {
|
||||
/// @throw std::bad_alloc
|
||||
Result<PropertyValue> GetProperty(PropertyId property, View view) const;
|
||||
|
||||
/// Returns the size of the encoded edge property in bytes.
|
||||
Result<uint64_t> GetPropertySize(PropertyId property, View view) const;
|
||||
|
||||
/// @throw std::bad_alloc
|
||||
Result<std::map<PropertyId, PropertyValue>> Properties(View view) const;
|
||||
|
||||
|
||||
@@ -83,18 +83,6 @@ class NameIdMapper {
|
||||
return id;
|
||||
}
|
||||
|
||||
/// This method unlike NameToId does not insert the new property id if not found
|
||||
/// but just returns either std::nullopt or the value of the property id if it
|
||||
/// finds it.
|
||||
virtual std::optional<uint64_t> NameToIdIfExists(const std::string_view name) {
|
||||
auto name_to_id_acc = name_to_id_.access();
|
||||
auto found = name_to_id_acc.find(name);
|
||||
if (found == name_to_id_acc.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return found->id;
|
||||
}
|
||||
|
||||
// NOTE: Currently this function returns a `const std::string &` instead of a
|
||||
// `std::string` to avoid making unnecessary copies of the string.
|
||||
// Usually, this wouldn't be correct because the accessor to the
|
||||
|
||||
@@ -93,19 +93,6 @@ enum class Size : uint8_t {
|
||||
INT64 = 0x03,
|
||||
};
|
||||
|
||||
uint64_t SizeToByteSize(Size size) {
|
||||
switch (size) {
|
||||
case Size::INT8:
|
||||
return 1;
|
||||
case Size::INT16:
|
||||
return 2;
|
||||
case Size::INT32:
|
||||
return 4;
|
||||
case Size::INT64:
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
|
||||
// All of these values must have the lowest 4 bits set to zero because they are
|
||||
// used to store two `Size` values as described in the comment above.
|
||||
enum class Type : uint8_t {
|
||||
@@ -499,27 +486,6 @@ std::optional<TemporalData> DecodeTemporalData(Reader &reader) {
|
||||
return TemporalData{static_cast<TemporalType>(*type_value), *microseconds_value};
|
||||
}
|
||||
|
||||
std::optional<uint64_t> DecodeTemporalDataSize(Reader &reader) {
|
||||
uint64_t temporal_data_size = 0;
|
||||
|
||||
auto metadata = reader.ReadMetadata();
|
||||
if (!metadata || metadata->type != Type::TEMPORAL_DATA) return std::nullopt;
|
||||
|
||||
temporal_data_size += 1;
|
||||
|
||||
auto type_value = reader.ReadUint(metadata->id_size);
|
||||
if (!type_value) return std::nullopt;
|
||||
|
||||
temporal_data_size += SizeToByteSize(metadata->id_size);
|
||||
|
||||
auto microseconds_value = reader.ReadInt(metadata->payload_size);
|
||||
if (!microseconds_value) return std::nullopt;
|
||||
|
||||
temporal_data_size += SizeToByteSize(metadata->payload_size);
|
||||
|
||||
return temporal_data_size;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Function used to decode a PropertyValue from a byte stream.
|
||||
@@ -606,92 +572,6 @@ std::optional<uint64_t> DecodeTemporalDataSize(Reader &reader) {
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] bool DecodePropertyValueSize(Reader *reader, Type type, Size payload_size, uint64_t &property_size) {
|
||||
switch (type) {
|
||||
case Type::EMPTY: {
|
||||
return false;
|
||||
}
|
||||
case Type::NONE:
|
||||
case Type::BOOL: {
|
||||
return true;
|
||||
}
|
||||
case Type::INT: {
|
||||
reader->ReadInt(payload_size);
|
||||
property_size += SizeToByteSize(payload_size);
|
||||
return true;
|
||||
}
|
||||
case Type::DOUBLE: {
|
||||
reader->ReadDouble(payload_size);
|
||||
property_size += SizeToByteSize(payload_size);
|
||||
return true;
|
||||
}
|
||||
case Type::STRING: {
|
||||
auto size = reader->ReadUint(payload_size);
|
||||
if (!size) return false;
|
||||
property_size += SizeToByteSize(payload_size);
|
||||
|
||||
std::string str_v(*size, '\0');
|
||||
if (!reader->SkipBytes(*size)) return false;
|
||||
property_size += *size;
|
||||
|
||||
return true;
|
||||
}
|
||||
case Type::LIST: {
|
||||
auto size = reader->ReadUint(payload_size);
|
||||
if (!size) return false;
|
||||
|
||||
uint64_t list_property_size = SizeToByteSize(payload_size);
|
||||
|
||||
for (uint64_t i = 0; i < *size; ++i) {
|
||||
auto metadata = reader->ReadMetadata();
|
||||
if (!metadata) return false;
|
||||
|
||||
list_property_size += 1;
|
||||
if (!DecodePropertyValueSize(reader, metadata->type, metadata->payload_size, list_property_size)) return false;
|
||||
}
|
||||
|
||||
property_size += list_property_size;
|
||||
return true;
|
||||
}
|
||||
case Type::MAP: {
|
||||
auto size = reader->ReadUint(payload_size);
|
||||
if (!size) return false;
|
||||
|
||||
uint64_t map_property_size = SizeToByteSize(payload_size);
|
||||
|
||||
for (uint64_t i = 0; i < *size; ++i) {
|
||||
auto metadata = reader->ReadMetadata();
|
||||
if (!metadata) return false;
|
||||
|
||||
map_property_size += 1;
|
||||
|
||||
auto key_size = reader->ReadUint(metadata->id_size);
|
||||
if (!key_size) return false;
|
||||
|
||||
map_property_size += SizeToByteSize(metadata->id_size);
|
||||
|
||||
std::string key(*key_size, '\0');
|
||||
if (!reader->ReadBytes(key.data(), *key_size)) return false;
|
||||
|
||||
map_property_size += *key_size;
|
||||
|
||||
if (!DecodePropertyValueSize(reader, metadata->type, metadata->payload_size, map_property_size)) return false;
|
||||
}
|
||||
|
||||
property_size += map_property_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
case Type::TEMPORAL_DATA: {
|
||||
const auto maybe_temporal_data_size = DecodeTemporalDataSize(*reader);
|
||||
if (!maybe_temporal_data_size) return false;
|
||||
|
||||
property_size += *maybe_temporal_data_size;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Function used to skip a PropertyValue from a byte stream.
|
||||
//
|
||||
// @sa ComparePropertyValue
|
||||
@@ -908,27 +788,6 @@ enum class ExpectedPropertyStatus {
|
||||
: ExpectedPropertyStatus::GREATER;
|
||||
}
|
||||
|
||||
[[nodiscard]] ExpectedPropertyStatus DecodeExpectedPropertySize(Reader *reader, PropertyId expected_property,
|
||||
uint64_t &size) {
|
||||
auto metadata = reader->ReadMetadata();
|
||||
if (!metadata) return ExpectedPropertyStatus::MISSING_DATA;
|
||||
|
||||
auto property_id = reader->ReadUint(metadata->id_size);
|
||||
if (!property_id) return ExpectedPropertyStatus::MISSING_DATA;
|
||||
|
||||
if (*property_id == expected_property.AsUint()) {
|
||||
// Add one byte for reading metadata + add the number of bytes for the property key
|
||||
size += (1 + SizeToByteSize(metadata->id_size));
|
||||
if (!DecodePropertyValueSize(reader, metadata->type, metadata->payload_size, size))
|
||||
return ExpectedPropertyStatus::MISSING_DATA;
|
||||
return ExpectedPropertyStatus::EQUAL;
|
||||
}
|
||||
// Don't load the value if this isn't the expected property.
|
||||
if (!SkipPropertyValue(reader, metadata->type, metadata->payload_size)) return ExpectedPropertyStatus::MISSING_DATA;
|
||||
return (*property_id < expected_property.AsUint()) ? ExpectedPropertyStatus::SMALLER
|
||||
: ExpectedPropertyStatus::GREATER;
|
||||
}
|
||||
|
||||
// Function used to check a property exists (PropertyId) from a byte stream.
|
||||
// It will skip the encoded PropertyValue.
|
||||
//
|
||||
@@ -1016,13 +875,6 @@ enum class ExpectedPropertyStatus {
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] ExpectedPropertyStatus FindSpecificPropertySize(Reader *reader, PropertyId property, uint64_t &size) {
|
||||
ExpectedPropertyStatus ret = ExpectedPropertyStatus::SMALLER;
|
||||
while ((ret = DecodeExpectedPropertySize(reader, property, size)) == ExpectedPropertyStatus::SMALLER) {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Function used to find if property is set. It relies on the fact that the properties
|
||||
// are sorted (by ID) in the buffer.
|
||||
//
|
||||
@@ -1131,31 +983,6 @@ std::pair<uint64_t, uint8_t *> GetSizeData(const uint8_t *buffer) {
|
||||
return {size, data};
|
||||
}
|
||||
|
||||
struct BufferInfo {
|
||||
uint64_t size;
|
||||
uint8_t *data{nullptr};
|
||||
bool in_local_buffer;
|
||||
};
|
||||
|
||||
template <size_t N>
|
||||
BufferInfo GetBufferInfo(const uint8_t (&buffer)[N]) {
|
||||
uint64_t size = 0;
|
||||
const uint8_t *data = nullptr;
|
||||
bool in_local_buffer = false;
|
||||
std::tie(size, data) = GetSizeData(buffer);
|
||||
if (size % 8 != 0) {
|
||||
// We are storing the data in the local buffer.
|
||||
size = sizeof(buffer) - 1;
|
||||
data = &buffer[1];
|
||||
in_local_buffer = true;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
||||
auto *non_const_data = const_cast<uint8_t *>(data);
|
||||
|
||||
return {size, non_const_data, in_local_buffer};
|
||||
}
|
||||
|
||||
void SetSizeData(uint8_t *buffer, uint64_t size, uint8_t *data) {
|
||||
memcpy(buffer, &size, sizeof(uint64_t));
|
||||
memcpy(buffer + sizeof(uint64_t), &data, sizeof(uint8_t *));
|
||||
@@ -1196,27 +1023,30 @@ PropertyStore::~PropertyStore() {
|
||||
}
|
||||
|
||||
PropertyValue PropertyStore::GetProperty(PropertyId property) const {
|
||||
BufferInfo buffer_info = GetBufferInfo(buffer_);
|
||||
Reader reader(buffer_info.data, buffer_info.size);
|
||||
|
||||
uint64_t size;
|
||||
const uint8_t *data;
|
||||
std::tie(size, data) = GetSizeData(buffer_);
|
||||
if (size % 8 != 0) {
|
||||
// We are storing the data in the local buffer.
|
||||
size = sizeof(buffer_) - 1;
|
||||
data = &buffer_[1];
|
||||
}
|
||||
Reader reader(data, size);
|
||||
PropertyValue value;
|
||||
if (FindSpecificProperty(&reader, property, value) != ExpectedPropertyStatus::EQUAL) return {};
|
||||
return value;
|
||||
}
|
||||
|
||||
uint64_t PropertyStore::PropertySize(PropertyId property) const {
|
||||
auto data_size_localbuffer = GetBufferInfo(buffer_);
|
||||
Reader reader(data_size_localbuffer.data, data_size_localbuffer.size);
|
||||
|
||||
uint64_t property_size = 0;
|
||||
if (FindSpecificPropertySize(&reader, property, property_size) != ExpectedPropertyStatus::EQUAL) return 0;
|
||||
return property_size;
|
||||
}
|
||||
|
||||
bool PropertyStore::HasProperty(PropertyId property) const {
|
||||
BufferInfo buffer_info = GetBufferInfo(buffer_);
|
||||
Reader reader(buffer_info.data, buffer_info.size);
|
||||
|
||||
uint64_t size;
|
||||
const uint8_t *data;
|
||||
std::tie(size, data) = GetSizeData(buffer_);
|
||||
if (size % 8 != 0) {
|
||||
// We are storing the data in the local buffer.
|
||||
size = sizeof(buffer_) - 1;
|
||||
data = &buffer_[1];
|
||||
}
|
||||
Reader reader(data, size);
|
||||
return ExistsSpecificProperty(&reader, property) == ExpectedPropertyStatus::EQUAL;
|
||||
}
|
||||
|
||||
@@ -1251,20 +1081,32 @@ std::optional<std::vector<PropertyValue>> PropertyStore::ExtractPropertyValues(
|
||||
}
|
||||
|
||||
bool PropertyStore::IsPropertyEqual(PropertyId property, const PropertyValue &value) const {
|
||||
BufferInfo buffer_info = GetBufferInfo(buffer_);
|
||||
Reader reader(buffer_info.data, buffer_info.size);
|
||||
|
||||
uint64_t size;
|
||||
const uint8_t *data;
|
||||
std::tie(size, data) = GetSizeData(buffer_);
|
||||
if (size % 8 != 0) {
|
||||
// We are storing the data in the local buffer.
|
||||
size = sizeof(buffer_) - 1;
|
||||
data = &buffer_[1];
|
||||
}
|
||||
Reader reader(data, size);
|
||||
auto info = FindSpecificPropertyAndBufferInfo(&reader, property);
|
||||
if (info.property_size == 0) return value.IsNull();
|
||||
Reader prop_reader(buffer_info.data + info.property_begin, info.property_size);
|
||||
Reader prop_reader(data + info.property_begin, info.property_size);
|
||||
if (!CompareExpectedProperty(&prop_reader, property, value)) return false;
|
||||
return prop_reader.GetPosition() == info.property_size;
|
||||
}
|
||||
|
||||
std::map<PropertyId, PropertyValue> PropertyStore::Properties() const {
|
||||
BufferInfo buffer_info = GetBufferInfo(buffer_);
|
||||
Reader reader(buffer_info.data, buffer_info.size);
|
||||
|
||||
uint64_t size;
|
||||
const uint8_t *data;
|
||||
std::tie(size, data) = GetSizeData(buffer_);
|
||||
if (size % 8 != 0) {
|
||||
// We are storing the data in the local buffer.
|
||||
size = sizeof(buffer_) - 1;
|
||||
data = &buffer_[1];
|
||||
}
|
||||
Reader reader(data, size);
|
||||
std::map<PropertyId, PropertyValue> props;
|
||||
while (true) {
|
||||
PropertyValue value;
|
||||
@@ -1498,20 +1340,33 @@ bool PropertyStore::InitProperties(std::vector<std::pair<storage::PropertyId, st
|
||||
}
|
||||
|
||||
bool PropertyStore::ClearProperties() {
|
||||
BufferInfo buffer_info = GetBufferInfo(buffer_);
|
||||
|
||||
if (!buffer_info.size) return false;
|
||||
if (!buffer_info.in_local_buffer) delete[] buffer_info.data;
|
||||
bool in_local_buffer = false;
|
||||
uint64_t size;
|
||||
uint8_t *data;
|
||||
std::tie(size, data) = GetSizeData(buffer_);
|
||||
if (size % 8 != 0) {
|
||||
// We are storing the data in the local buffer.
|
||||
size = sizeof(buffer_) - 1;
|
||||
data = &buffer_[1];
|
||||
in_local_buffer = true;
|
||||
}
|
||||
if (!size) return false;
|
||||
if (!in_local_buffer) delete[] data;
|
||||
SetSizeData(buffer_, 0, nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string PropertyStore::StringBuffer() const {
|
||||
BufferInfo buffer_info = GetBufferInfo(buffer_);
|
||||
|
||||
std::string arr(buffer_info.size, ' ');
|
||||
for (uint i = 0; i < buffer_info.size; ++i) {
|
||||
arr[i] = static_cast<char>(buffer_info.data[i]);
|
||||
uint64_t size = 0;
|
||||
const uint8_t *data = nullptr;
|
||||
std::tie(size, data) = GetSizeData(buffer_);
|
||||
if (size % 8 != 0) { // We are storing the data in the local buffer.
|
||||
size = sizeof(buffer_) - 1;
|
||||
data = &buffer_[1];
|
||||
}
|
||||
std::string arr(size, ' ');
|
||||
for (uint i = 0; i < size; ++i) {
|
||||
arr[i] = static_cast<char>(data[i]);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
@@ -45,11 +45,6 @@ class PropertyStore {
|
||||
/// @throw std::bad_alloc
|
||||
PropertyValue GetProperty(PropertyId property) const;
|
||||
|
||||
/// Returns the size of the encoded property in bytes.
|
||||
/// Returns 0 if the property does not exist.
|
||||
/// The time complexity of this function is O(n).
|
||||
uint64_t PropertySize(PropertyId property) const;
|
||||
|
||||
/// Checks whether the property `property` exists in the store. The time
|
||||
/// complexity of this function is O(n).
|
||||
bool HasProperty(PropertyId property) const;
|
||||
|
||||
@@ -250,10 +250,6 @@ class Storage {
|
||||
|
||||
PropertyId NameToProperty(std::string_view name) { return storage_->NameToProperty(name); }
|
||||
|
||||
std::optional<PropertyId> NameToPropertyIfExists(std::string_view name) const {
|
||||
return storage_->NameToPropertyIfExists(name);
|
||||
}
|
||||
|
||||
EdgeTypeId NameToEdgeType(std::string_view name) { return storage_->NameToEdgeType(name); }
|
||||
|
||||
StorageMode GetCreationStorageMode() const noexcept;
|
||||
@@ -322,14 +318,6 @@ class Storage {
|
||||
return PropertyId::FromUint(name_id_mapper_->NameToId(name));
|
||||
}
|
||||
|
||||
std::optional<PropertyId> NameToPropertyIfExists(std::string_view name) const {
|
||||
const auto id = name_id_mapper_->NameToIdIfExists(name);
|
||||
if (!id) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return PropertyId::FromUint(*id);
|
||||
}
|
||||
|
||||
EdgeTypeId NameToEdgeType(const std::string_view name) const {
|
||||
return EdgeTypeId::FromUint(name_id_mapper_->NameToId(name));
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2024 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -438,26 +438,6 @@ Result<PropertyValue> VertexAccessor::GetProperty(PropertyId property, View view
|
||||
return std::move(value);
|
||||
}
|
||||
|
||||
Result<uint64_t> VertexAccessor::GetPropertySize(PropertyId property, View view) const {
|
||||
{
|
||||
auto guard = std::shared_lock{vertex_->lock};
|
||||
Delta *delta = vertex_->delta;
|
||||
if (!delta) {
|
||||
return vertex_->properties.PropertySize(property);
|
||||
}
|
||||
}
|
||||
|
||||
auto property_result = this->GetProperty(property, view);
|
||||
if (property_result.HasError()) {
|
||||
return property_result.GetError();
|
||||
}
|
||||
|
||||
auto property_store = storage::PropertyStore();
|
||||
property_store.SetProperty(property, *property_result);
|
||||
|
||||
return property_store.PropertySize(property);
|
||||
};
|
||||
|
||||
Result<std::map<PropertyId, PropertyValue>> VertexAccessor::Properties(View view) const {
|
||||
bool exists = true;
|
||||
bool deleted = false;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2024 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -80,9 +80,6 @@ class VertexAccessor final {
|
||||
/// @throw std::bad_alloc
|
||||
Result<PropertyValue> GetProperty(PropertyId property, View view) const;
|
||||
|
||||
/// Returns the size of the encoded vertex property in bytes.
|
||||
Result<uint64_t> GetPropertySize(PropertyId property, View view) const;
|
||||
|
||||
/// @throw std::bad_alloc
|
||||
Result<std::map<PropertyId, PropertyValue>> Properties(View view) const;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2024 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -15,8 +15,6 @@
|
||||
|
||||
#include "utils/flag_validation.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_VALIDATED_uint64(delta_chain_cache_threshold, 128,
|
||||
"The threshold for when to cache long delta chains. This is used for heavy read + write "
|
||||
@@ -33,7 +31,6 @@ auto FetchHelper(VertexInfoCache const &caches, Func &&getCache, View view, Keys
|
||||
// check empty first, cheaper than the relative cost of doing an actual hash + find
|
||||
if (cache.empty()) return std::nullopt;
|
||||
|
||||
return std::nullopt;
|
||||
// defer building the key, maybe a cost at construction
|
||||
using key_type = typename std::remove_cvref_t<decltype(cache)>::key_type;
|
||||
auto const it = cache.find(key_type{std::forward<Keys>(keys)...});
|
||||
@@ -79,8 +76,8 @@ void VertexInfoCache::Invalidate(Vertex const *vertex) {
|
||||
new_.outDegreeCache_.erase(vertex);
|
||||
|
||||
// aggressive cache invalidation, TODO: be smarter
|
||||
// new_.hasLabelCache_.clear();
|
||||
// new_.propertyValueCache_.clear();
|
||||
new_.hasLabelCache_.clear();
|
||||
new_.propertyValueCache_.clear();
|
||||
new_.inEdgesCache_.clear();
|
||||
new_.outEdgesCache_.clear();
|
||||
}
|
||||
@@ -90,38 +87,36 @@ auto VertexInfoCache::GetLabels(View view, Vertex const *vertex) const
|
||||
return FetchHelper<std::vector<LabelId>>(*this, std::mem_fn(&VertexInfoCache::Caches::labelCache_), view, vertex);
|
||||
}
|
||||
void VertexInfoCache::StoreLabels(View view, Vertex const *vertex, const std::vector<LabelId> &res) {
|
||||
// Store(res, *this, std::mem_fn(&Caches::labelCache_), view, vertex);
|
||||
Store(res, *this, std::mem_fn(&Caches::labelCache_), view, vertex);
|
||||
}
|
||||
auto VertexInfoCache::GetHasLabel(View view, Vertex const *vertex, LabelId label) const -> std::optional<bool> {
|
||||
// return FetchHelper<bool>(*this, std::mem_fn(&Caches::hasLabelCache_), view, vertex, label);
|
||||
return std::nullopt;
|
||||
return FetchHelper<bool>(*this, std::mem_fn(&Caches::hasLabelCache_), view, vertex, label);
|
||||
}
|
||||
void VertexInfoCache::StoreHasLabel(View view, Vertex const *vertex, LabelId label, bool res) {
|
||||
// Store(res, *this, std::mem_fn(&Caches::hasLabelCache_), view, vertex, label);
|
||||
Store(res, *this, std::mem_fn(&Caches::hasLabelCache_), view, vertex, label);
|
||||
}
|
||||
void VertexInfoCache::Invalidate(Vertex const *vertex, LabelId label) {
|
||||
new_.labelCache_.erase(vertex);
|
||||
// new_.hasLabelCache_.erase(std::tuple{vertex, label});
|
||||
new_.hasLabelCache_.erase(std::tuple{vertex, label});
|
||||
}
|
||||
|
||||
auto VertexInfoCache::GetProperty(View view, Vertex const *vertex, PropertyId property) const
|
||||
-> std::optional<std::reference_wrapper<PropertyValue const>> {
|
||||
// return FetchHelper<PropertyValue>(*this, std::mem_fn(&Caches::propertyValueCache_), view, vertex, property);
|
||||
return std::nullopt;
|
||||
return FetchHelper<PropertyValue>(*this, std::mem_fn(&Caches::propertyValueCache_), view, vertex, property);
|
||||
}
|
||||
void VertexInfoCache::StoreProperty(View view, Vertex const *vertex, PropertyId property, PropertyValue value) {
|
||||
// Store(std::move(value), *this, std::mem_fn(&Caches::propertyValueCache_), view, vertex, property);
|
||||
Store(std::move(value), *this, std::mem_fn(&Caches::propertyValueCache_), view, vertex, property);
|
||||
}
|
||||
auto VertexInfoCache::GetProperties(View view, Vertex const *vertex) const
|
||||
-> std::optional<std::reference_wrapper<std::map<PropertyId, PropertyValue> const>> {
|
||||
return FetchHelper<std::map<PropertyId, PropertyValue>>(*this, std::mem_fn(&Caches::propertiesCache_), view, vertex);
|
||||
}
|
||||
void VertexInfoCache::StoreProperties(View view, Vertex const *vertex, std::map<PropertyId, PropertyValue> properties) {
|
||||
// Store(std::move(properties), *this, std::mem_fn(&Caches::propertiesCache_), view, vertex);
|
||||
Store(std::move(properties), *this, std::mem_fn(&Caches::propertiesCache_), view, vertex);
|
||||
}
|
||||
void VertexInfoCache::Invalidate(Vertex const *vertex, PropertyId property_key) {
|
||||
new_.propertiesCache_.erase(vertex);
|
||||
// new_.propertyValueCache_.erase(std::tuple{vertex, property_key});
|
||||
new_.propertyValueCache_.erase(std::tuple{vertex, property_key});
|
||||
}
|
||||
|
||||
auto VertexInfoCache::GetInEdges(View view, Vertex const *src_vertex, Vertex const *dst_vertex,
|
||||
@@ -131,8 +126,8 @@ auto VertexInfoCache::GetInEdges(View view, Vertex const *src_vertex, Vertex con
|
||||
}
|
||||
void VertexInfoCache::StoreInEdges(View view, Vertex const *src_vertex, Vertex const *dst_vertex,
|
||||
std::vector<EdgeTypeId> edge_types, EdgeStore in_edges) {
|
||||
// Store(std::move(in_edges), *this, std::mem_fn(&Caches::inEdgesCache_), view, src_vertex, dst_vertex,
|
||||
// std::move(edge_types));
|
||||
Store(std::move(in_edges), *this, std::mem_fn(&Caches::inEdgesCache_), view, src_vertex, dst_vertex,
|
||||
std::move(edge_types));
|
||||
}
|
||||
auto VertexInfoCache::GetOutEdges(View view, Vertex const *src_vertex, Vertex const *dst_vertex,
|
||||
const std::vector<EdgeTypeId> &edge_types) const
|
||||
@@ -141,8 +136,8 @@ auto VertexInfoCache::GetOutEdges(View view, Vertex const *src_vertex, Vertex co
|
||||
}
|
||||
void VertexInfoCache::StoreOutEdges(View view, Vertex const *src_vertex, Vertex const *dst_vertex,
|
||||
std::vector<EdgeTypeId> edge_types, EdgeStore out_edges) {
|
||||
// Store(std::move(out_edges), *this, std::mem_fn(&Caches::outEdgesCache_), view, src_vertex, dst_vertex,
|
||||
// std::move(edge_types));
|
||||
Store(std::move(out_edges), *this, std::mem_fn(&Caches::outEdgesCache_), view, src_vertex, dst_vertex,
|
||||
std::move(edge_types));
|
||||
}
|
||||
|
||||
auto VertexInfoCache::GetInDegree(View view, Vertex const *vertex) const -> std::optional<std::size_t> {
|
||||
@@ -150,7 +145,7 @@ auto VertexInfoCache::GetInDegree(View view, Vertex const *vertex) const -> std:
|
||||
}
|
||||
|
||||
void VertexInfoCache::StoreInDegree(View view, Vertex const *vertex, std::size_t in_degree) {
|
||||
// Store(in_degree, *this, std::mem_fn(&Caches::inDegreeCache_), view, vertex);
|
||||
Store(in_degree, *this, std::mem_fn(&Caches::inDegreeCache_), view, vertex);
|
||||
}
|
||||
|
||||
auto VertexInfoCache::GetOutDegree(View view, Vertex const *vertex) const -> std::optional<std::size_t> {
|
||||
@@ -158,7 +153,7 @@ auto VertexInfoCache::GetOutDegree(View view, Vertex const *vertex) const -> std
|
||||
}
|
||||
|
||||
void VertexInfoCache::StoreOutDegree(View view, Vertex const *vertex, std::size_t out_degree) {
|
||||
// Store(out_degree, *this, std::mem_fn(&Caches::outDegreeCache_), view, vertex);
|
||||
Store(out_degree, *this, std::mem_fn(&Caches::outDegreeCache_), view, vertex);
|
||||
}
|
||||
|
||||
void VertexInfoCache::Invalidate(Vertex const *vertex, EdgeTypeId /*unused*/, EdgeDirection direction) {
|
||||
@@ -180,8 +175,8 @@ void VertexInfoCache::Clear() {
|
||||
void VertexInfoCache::Caches::Clear() {
|
||||
existsCache_.clear();
|
||||
deletedCache_.clear();
|
||||
// hasLabelCache_.clear();
|
||||
// propertyValueCache_.clear();
|
||||
hasLabelCache_.clear();
|
||||
propertyValueCache_.clear();
|
||||
labelCache_.clear();
|
||||
propertiesCache_.clear();
|
||||
inEdgesCache_.clear();
|
||||
|
||||
@@ -76,7 +76,6 @@ add_subdirectory(queries)
|
||||
add_subdirectory(query_modules_storage_modes)
|
||||
add_subdirectory(garbage_collection)
|
||||
add_subdirectory(query_planning)
|
||||
add_subdirectory(awesome_functions)
|
||||
|
||||
if (MG_EXPERIMENTAL_HIGH_AVAILABILITY)
|
||||
add_subdirectory(high_availability_experimental)
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
function(copy_awesome_functions_e2e_python_files FILE_NAME)
|
||||
copy_e2e_python_files(awesome_functions ${FILE_NAME})
|
||||
endfunction()
|
||||
|
||||
copy_awesome_functions_e2e_python_files(common.py)
|
||||
copy_awesome_functions_e2e_python_files(awesome_functions.py)
|
||||
@@ -1,269 +0,0 @@
|
||||
# Copyright 2023 Memgraph Ltd.
|
||||
#
|
||||
# Use of this software is governed by the Business Source License
|
||||
# included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
# License, and you may not use this file except in compliance with the Business Source License.
|
||||
#
|
||||
# As of the Change Date specified in that file, in accordance with
|
||||
# the Business Source License, use of this software will be governed
|
||||
# by the Apache License, Version 2.0, included in the file
|
||||
# licenses/APL.txt.
|
||||
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
from common import get_bytes, memgraph
|
||||
|
||||
|
||||
def test_property_size_on_null_prop(memgraph):
|
||||
memgraph.execute(
|
||||
"""
|
||||
CREATE (n:Node)
|
||||
SET n.null_prop = null;
|
||||
"""
|
||||
)
|
||||
|
||||
null_bytes = get_bytes(memgraph, "null_prop")
|
||||
|
||||
# No property stored, no bytes allocated
|
||||
assert null_bytes == 0
|
||||
|
||||
|
||||
def test_property_size_on_bool_prop(memgraph):
|
||||
memgraph.execute(
|
||||
"""
|
||||
CREATE (n:Node)
|
||||
SET n.bool_prop = True;
|
||||
"""
|
||||
)
|
||||
|
||||
bool_bytes = get_bytes(memgraph, "bool_prop")
|
||||
|
||||
# 1 byte metadata, 1 byte prop id, but value is encoded in the metadata
|
||||
assert bool_bytes == 2
|
||||
|
||||
|
||||
def test_property_size_on_one_byte_int_prop(memgraph):
|
||||
memgraph.execute(
|
||||
"""
|
||||
CREATE (n:Node)
|
||||
SET n.S_int_prop = 4;
|
||||
"""
|
||||
)
|
||||
|
||||
s_int_bytes = get_bytes(memgraph, "S_int_prop")
|
||||
|
||||
# 1 byte metadata, 1 byte prop id + payload size 1 byte to store the int
|
||||
assert s_int_bytes == 3
|
||||
|
||||
|
||||
def test_property_size_on_two_byte_int_prop(memgraph):
|
||||
memgraph.execute(
|
||||
"""
|
||||
CREATE (n:Node)
|
||||
SET n.M_int_prop = 500;
|
||||
"""
|
||||
)
|
||||
|
||||
m_int_bytes = get_bytes(memgraph, "M_int_prop")
|
||||
|
||||
# 1 byte metadata, 1 byte prop id + payload size 2 bytes to store the int
|
||||
assert m_int_bytes == 4
|
||||
|
||||
|
||||
def test_property_size_on_four_byte_int_prop(memgraph):
|
||||
memgraph.execute(
|
||||
"""
|
||||
CREATE (n:Node)
|
||||
SET n.L_int_prop = 1000000000;
|
||||
"""
|
||||
)
|
||||
|
||||
l_int_bytes = get_bytes(memgraph, "L_int_prop")
|
||||
|
||||
# 1 byte metadata, 1 byte prop id + payload size 4 bytes to store the int
|
||||
assert l_int_bytes == 6
|
||||
|
||||
|
||||
def test_property_size_on_eight_byte_int_prop(memgraph):
|
||||
memgraph.execute(
|
||||
"""
|
||||
CREATE (n:Node)
|
||||
SET n.XL_int_prop = 1000000000000;
|
||||
"""
|
||||
)
|
||||
|
||||
xl_int_bytes = get_bytes(memgraph, "XL_int_prop")
|
||||
|
||||
# 1 byte metadata, 1 byte prop id + payload size 8 bytes to store the int
|
||||
assert xl_int_bytes == 10
|
||||
|
||||
|
||||
def test_property_size_on_float_prop(memgraph):
|
||||
memgraph.execute(
|
||||
"""
|
||||
CREATE (n:Node)
|
||||
SET n.float_prop = 4.0;
|
||||
"""
|
||||
)
|
||||
|
||||
float_bytes = get_bytes(memgraph, "float_prop")
|
||||
|
||||
# 1 byte metadata, 1 byte prop id + payload size 8 bytes to store the float
|
||||
assert float_bytes == 10
|
||||
|
||||
|
||||
def test_property_size_on_string_prop(memgraph):
|
||||
memgraph.execute(
|
||||
"""
|
||||
CREATE (n:Node)
|
||||
SET n.str_prop = 'str_value';
|
||||
"""
|
||||
)
|
||||
|
||||
str_bytes = get_bytes(memgraph, "str_prop")
|
||||
|
||||
# 1 byte metadata
|
||||
# 1 byte prop id
|
||||
# - the payload size contains the amount of bytes stored for the size in the next sequence
|
||||
# X bytes for the length of the string (1, 2, 4 or 8 bytes) -> "str_value" has 1 byte for the length of 9
|
||||
# Y bytes for the string content -> 9 bytes for "str_value"
|
||||
assert str_bytes == 12
|
||||
|
||||
|
||||
def test_property_size_on_list_prop(memgraph):
|
||||
memgraph.execute(
|
||||
"""
|
||||
CREATE (n:Node)
|
||||
SET n.list_prop = [1, 2, 3];
|
||||
"""
|
||||
)
|
||||
|
||||
list_bytes = get_bytes(memgraph, "list_prop")
|
||||
|
||||
# 1 byte metadata
|
||||
# 1 byte prop id
|
||||
# - the payload size contains the amount of bytes stored for the size of the list
|
||||
# X bytes for the size of the list (1, 2, 4 or 8 bytes)
|
||||
# for each list element:
|
||||
# - 1 byte for the metadata
|
||||
# - the amount of bytes for the payload of the type (a small int is 1 additional byte)
|
||||
# in this case 1 + 1 + 3 * (1 + 1)
|
||||
assert list_bytes == 9
|
||||
|
||||
|
||||
def test_property_size_on_map_prop(memgraph):
|
||||
memgraph.execute(
|
||||
"""
|
||||
CREATE (n:Node)
|
||||
SET n.map_prop = {key1: 'value', key2: 4};
|
||||
"""
|
||||
)
|
||||
|
||||
map_bytes = get_bytes(memgraph, "map_prop")
|
||||
|
||||
# 1 byte metadata
|
||||
# 1 byte prop id
|
||||
# - the payload size contains the amount of bytes stored for the size of the map
|
||||
# X bytes for the size of the map (1, 2, 4 or 8 bytes - in this case 1)
|
||||
# for every map element:
|
||||
# - 1 byte for metadata
|
||||
# - 1, 2, 4 or 8 bytes for the key length (read from the metadata payload) -> this case 1
|
||||
# - Y bytes for the key content -> this case 4
|
||||
# - Z amount of bytes for the type
|
||||
# - for 'value' -> 1 byte for size and 5 for length
|
||||
# - for 4 -> 1 byte for content read from payload
|
||||
# total: 1 + 1 + (1 + 1 + 4 + (1 + 5)) + (1 + 1 + 4 + (1))
|
||||
assert map_bytes == 22
|
||||
|
||||
|
||||
def test_property_size_on_date_prop(memgraph):
|
||||
memgraph.execute(
|
||||
"""
|
||||
CREATE (n:Node)
|
||||
SET n.date_prop = date('2023-01-01');
|
||||
"""
|
||||
)
|
||||
|
||||
date_bytes = get_bytes(memgraph, "date_prop")
|
||||
|
||||
# 1 byte metadata (to see that it's temporal data)
|
||||
# 1 byte prop id
|
||||
# 1 byte metadata
|
||||
# - type is again the same
|
||||
# - id field contains the length of the specific temporal type (1, 2, 4 or 8 bytes) -> probably always 1
|
||||
# - payload field contains the length of the microseconds (1, 2, 4, or 8 bytes) -> probably always 8
|
||||
assert date_bytes == 12
|
||||
|
||||
|
||||
def test_property_size_on_local_time_prop(memgraph):
|
||||
memgraph.execute(
|
||||
"""
|
||||
CREATE (n:Node)
|
||||
SET n.localtime_prop = localtime('23:00:00');
|
||||
"""
|
||||
)
|
||||
|
||||
local_time_bytes = get_bytes(memgraph, "localtime_prop")
|
||||
|
||||
# 1 byte metadata (to see that it's temporal data)
|
||||
# 1 byte prop id
|
||||
# 1 byte metadata
|
||||
# - type is again the same
|
||||
# - id field contains the length of the specific temporal type (1, 2, 4 or 8 bytes) -> probably always 1
|
||||
# - payload field contains the length of the microseconds (1, 2, 4, or 8 bytes) -> probably always 8
|
||||
assert local_time_bytes == 12
|
||||
|
||||
|
||||
def test_property_size_on_local_date_time_prop(memgraph):
|
||||
memgraph.execute(
|
||||
"""
|
||||
CREATE (n:Node)
|
||||
SET n.localdatetime_prop = localdatetime('2022-01-01T23:00:00');
|
||||
"""
|
||||
)
|
||||
|
||||
local_date_time_bytes = get_bytes(memgraph, "localdatetime_prop")
|
||||
|
||||
# 1 byte metadata (to see that it's temporal data)
|
||||
# 1 byte prop id
|
||||
# 1 byte metadata
|
||||
# - type is again the same
|
||||
# - id field contains the length of the specific temporal type (1, 2, 4 or 8 bytes) -> probably always 1
|
||||
# - payload field contains the length of the microseconds (1, 2, 4, or 8 bytes) -> probably always 8
|
||||
assert local_date_time_bytes == 12
|
||||
|
||||
|
||||
def test_property_size_on_duration_prop(memgraph):
|
||||
memgraph.execute(
|
||||
"""
|
||||
CREATE (n:Node)
|
||||
SET n.duration_prop = duration('P5DT2M2.33S');
|
||||
"""
|
||||
)
|
||||
|
||||
duration_bytes = get_bytes(memgraph, "duration_prop")
|
||||
|
||||
# 1 byte metadata (to see that it's temporal data)
|
||||
# 1 byte prop id
|
||||
# 1 byte metadata
|
||||
# - type is again the same
|
||||
# - id field contains the length of the specific temporal type (1, 2, 4 or 8 bytes) -> probably always 1
|
||||
# - payload field contains the length of the microseconds (1, 2, 4, or 8 bytes) -> probably always 8
|
||||
assert duration_bytes == 12
|
||||
|
||||
|
||||
def test_property_size_on_nonexistent_prop(memgraph):
|
||||
memgraph.execute(
|
||||
"""
|
||||
CREATE (n:Node);
|
||||
"""
|
||||
)
|
||||
|
||||
nonexistent_bytes = get_bytes(memgraph, "nonexistent_prop")
|
||||
|
||||
assert nonexistent_bytes == 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(pytest.main([__file__, "-rA"]))
|
||||
@@ -1,29 +0,0 @@
|
||||
# Copyright 2023 Memgraph Ltd.
|
||||
#
|
||||
# Use of this software is governed by the Business Source License
|
||||
# included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
# License, and you may not use this file except in compliance with the Business Source License.
|
||||
#
|
||||
# As of the Change Date specified in that file, in accordance with
|
||||
# the Business Source License, use of this software will be governed
|
||||
# by the Apache License, Version 2.0, included in the file
|
||||
# licenses/APL.txt.
|
||||
|
||||
import pytest
|
||||
from gqlalchemy import Memgraph
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def memgraph(**kwargs) -> Memgraph:
|
||||
memgraph = Memgraph()
|
||||
|
||||
yield memgraph
|
||||
|
||||
memgraph.drop_indexes()
|
||||
memgraph.ensure_constraints([])
|
||||
memgraph.drop_database()
|
||||
|
||||
|
||||
def get_bytes(memgraph, prop_name):
|
||||
res = list(memgraph.execute_and_fetch(f"MATCH (n) RETURN propertySize(n, '{prop_name}') AS size"))
|
||||
return res[0]["size"]
|
||||
@@ -1,14 +0,0 @@
|
||||
awesome_functions_cluster: &awesome_functions_cluster
|
||||
cluster:
|
||||
main:
|
||||
args: ["--bolt-port", "7687", "--log-level=TRACE"]
|
||||
log_file: "awesome_functions.log"
|
||||
setup_queries: []
|
||||
validation_queries: []
|
||||
|
||||
|
||||
workloads:
|
||||
- name: "Awesome Functions"
|
||||
binary: "tests/e2e/pytest_runner.sh"
|
||||
args: ["awesome_functions/awesome_functions.py"]
|
||||
<<: *awesome_functions_cluster
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2024 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -113,6 +113,7 @@ struct ConsumerTest : public ::testing::Test {
|
||||
void SeedTopicWithInt(const std::string &topic_name, int value) {
|
||||
std::array<char, sizeof(int)> int_as_char{};
|
||||
std::memcpy(int_as_char.data(), &value, int_as_char.size());
|
||||
|
||||
cluster.SeedTopic(topic_name, int_as_char);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2024 Memgraph Ltd.
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -78,6 +78,10 @@ void KafkaClusterMock::CreateTopic(const std::string &topic_name) {
|
||||
}
|
||||
}
|
||||
|
||||
void KafkaClusterMock::SeedTopic(const std::string &topic_name, std::string_view message) {
|
||||
SeedTopic(topic_name, std::span{message.data(), message.size()});
|
||||
}
|
||||
|
||||
void KafkaClusterMock::SeedTopic(const std::string &topic_name, std::span<const char> message) {
|
||||
char errstr[256] = {'\0'};
|
||||
std::string bootstraps_servers = Bootstraps();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2024 Memgraph Ltd.
|
||||
// Copyright 2021 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -41,6 +41,7 @@ class KafkaClusterMock {
|
||||
std::string Bootstraps() const;
|
||||
void CreateTopic(const std::string &topic_name);
|
||||
void SeedTopic(const std::string &topic_name, std::span<const char> message);
|
||||
void SeedTopic(const std::string &topic_name, std::string_view message);
|
||||
|
||||
private:
|
||||
RdKafkaUniquePtr rk_{nullptr};
|
||||
|
||||
Reference in New Issue
Block a user