Add behaviour of no updates if vertex is updated with same value (#1791)
This commit is contained in:
@@ -77,6 +77,7 @@ add_subdirectory(garbage_collection)
|
||||
add_subdirectory(query_planning)
|
||||
add_subdirectory(awesome_functions)
|
||||
add_subdirectory(high_availability)
|
||||
add_subdirectory(concurrency)
|
||||
|
||||
add_subdirectory(replication_experimental)
|
||||
|
||||
|
||||
6
tests/e2e/concurrency/CMakeLists.txt
Normal file
6
tests/e2e/concurrency/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
function(copy_concurrency_e2e_python_files FILE_NAME)
|
||||
copy_e2e_python_files(concurrency ${FILE_NAME})
|
||||
endfunction()
|
||||
|
||||
copy_concurrency_e2e_python_files(common.py)
|
||||
copy_concurrency_e2e_python_files(concurrency.py)
|
||||
60
tests/e2e/concurrency/common.py
Normal file
60
tests/e2e/concurrency/common.py
Normal file
@@ -0,0 +1,60 @@
|
||||
# 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 typing
|
||||
|
||||
import mgclient
|
||||
import pytest
|
||||
|
||||
|
||||
def execute_and_fetch_all(cursor: mgclient.Cursor, query: str, params: dict = {}) -> typing.List[tuple]:
|
||||
cursor.execute(query, params)
|
||||
return cursor.fetchall()
|
||||
|
||||
|
||||
def execute_and_fetch_all_with_commit(
|
||||
connection: mgclient.Connection, query: str, params: dict = {}
|
||||
) -> typing.List[tuple]:
|
||||
cursor = connection.cursor()
|
||||
cursor.execute(query, params)
|
||||
results = cursor.fetchall()
|
||||
connection.commit()
|
||||
return results
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def first_connection(**kwargs) -> mgclient.Connection:
|
||||
connection = mgclient.connect(host="localhost", port=7687, **kwargs)
|
||||
connection.autocommit = True
|
||||
cursor = connection.cursor()
|
||||
execute_and_fetch_all(cursor, "USE DATABASE memgraph")
|
||||
try:
|
||||
execute_and_fetch_all(cursor, "DROP DATABASE clean")
|
||||
except:
|
||||
pass
|
||||
execute_and_fetch_all(cursor, "MATCH (n) DETACH DELETE n")
|
||||
connection.autocommit = False
|
||||
yield connection
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def second_connection(**kwargs) -> mgclient.Connection:
|
||||
connection = mgclient.connect(host="localhost", port=7687, **kwargs)
|
||||
connection.autocommit = True
|
||||
cursor = connection.cursor()
|
||||
execute_and_fetch_all(cursor, "USE DATABASE memgraph")
|
||||
try:
|
||||
execute_and_fetch_all(cursor, "DROP DATABASE clean")
|
||||
except:
|
||||
pass
|
||||
execute_and_fetch_all(cursor, "MATCH (n) DETACH DELETE n")
|
||||
connection.autocommit = False
|
||||
yield connection
|
||||
57
tests/e2e/concurrency/concurrency.py
Normal file
57
tests/e2e/concurrency/concurrency.py
Normal file
@@ -0,0 +1,57 @@
|
||||
# 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 execute_and_fetch_all, first_connection, second_connection
|
||||
|
||||
|
||||
def test_concurrency_if_no_delta_on_same_node_property_update(first_connection, second_connection):
|
||||
m1c = first_connection.cursor()
|
||||
m2c = second_connection.cursor()
|
||||
|
||||
execute_and_fetch_all(m1c, "CREATE (:Node {prop: 1})")
|
||||
first_connection.commit()
|
||||
|
||||
test_has_error = False
|
||||
try:
|
||||
m1c.execute("MATCH (n) SET n.prop = 1")
|
||||
m2c.execute("MATCH (n) SET n.prop = 1")
|
||||
first_connection.commit()
|
||||
second_connection.commit()
|
||||
except Exception as e:
|
||||
test_has_error = True
|
||||
|
||||
assert test_has_error is False
|
||||
|
||||
|
||||
def test_concurrency_if_no_delta_on_same_edge_property_update(first_connection, second_connection):
|
||||
m1c = first_connection.cursor()
|
||||
m2c = second_connection.cursor()
|
||||
|
||||
execute_and_fetch_all(m1c, "CREATE ()-[:TYPE {prop: 1}]->()")
|
||||
first_connection.commit()
|
||||
|
||||
test_has_error = False
|
||||
try:
|
||||
m1c.execute("MATCH (n)-[r]->(m) SET r.prop = 1")
|
||||
m2c.execute("MATCH (n)-[r]->(m) SET n.prop = 1")
|
||||
first_connection.commit()
|
||||
second_connection.commit()
|
||||
except Exception as e:
|
||||
test_has_error = True
|
||||
|
||||
assert test_has_error is False
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(pytest.main([__file__, "-rA"]))
|
||||
14
tests/e2e/concurrency/workloads.yaml
Normal file
14
tests/e2e/concurrency/workloads.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
concurrency_cluster: &concurrency_cluster
|
||||
cluster:
|
||||
main:
|
||||
args: ["--bolt-port", "7687", "--log-level=TRACE", "--storage-delta-on-identical-property-update=false"]
|
||||
log_file: "concurrency.log"
|
||||
setup_queries: []
|
||||
validation_queries: []
|
||||
|
||||
|
||||
workloads:
|
||||
- name: "Concurrency"
|
||||
binary: "tests/e2e/pytest_runner.sh"
|
||||
args: ["concurrency/concurrency.py"]
|
||||
<<: *concurrency_cluster
|
||||
@@ -141,6 +141,11 @@ startup_config_dict = {
|
||||
"1",
|
||||
"The time duration between two replica checks/pings. If < 1, replicas will NOT be checked at all. NOTE: The MAIN instance allocates a new thread for each REPLICA.",
|
||||
),
|
||||
"storage_delta_on_identical_property_update": (
|
||||
"true",
|
||||
"true",
|
||||
"Controls whether updating a property with the same value should create a delta object.",
|
||||
),
|
||||
"storage_gc_cycle_sec": ("30", "30", "Storage garbage collector interval (in seconds)."),
|
||||
"storage_python_gc_cycle_sec": ("180", "180", "Storage python full garbage collection interval (in seconds)."),
|
||||
"storage_items_per_batch": (
|
||||
|
||||
Reference in New Issue
Block a user