Compare commits

...

11 Commits

Author SHA1 Message Date
Deda
a2a863b009 Override memgraph version to 2.14.1 2024-02-16 08:45:14 +01:00
Deda
5bf5dee730 Add concurrency rules for release tests 2024-02-15 15:07:39 +01:00
Deda
8d5fef3ba8 Make release builds run on push to release branch 2024-02-14 15:59:47 +01:00
Aidar Samerkhanov
6074edb6eb Fix accumulated path evaluation in builtin algorithms. (#1642)
Fix accumulated path evaluation in DFS, BFS, WeghtedShortestPath and AllShortestPath algorithm.
2024-02-14 15:54:37 +01:00
Deda
3d606d1f06 Turn e2e tests on 2024-02-14 15:48:45 +01:00
Deda
4905ae298f Update deprecated github actions 2024-02-14 15:46:06 +01:00
Marko Barišić
7817f9ddc0 Update release CI job timeouts (#1683)
* Set timeout for jobs in release CI to 60 minutes

* Set timout for stress test large to 12 hours
2024-02-14 15:03:04 +01:00
Marko Barišić
fe0b292e57 Make release CI predictable (#1658)
* Move stress test large to a separate workflow
* Combine Debian10 and Ubuntu20.04 stress tests into one workflow
* Remove BigMemory tag from release_debian10
* Move e2e tests to a separate job
* Move debug interation tests to a separate job
* Move release durability and stress tests to a separate job
* Move release benchamarks to separate job
* Add 90 min timeout restriction to all jobs
* Move env variables to workflow level
* Move BUILD_TYPE env var to workflow level
---------

Co-authored-by: Aidar Samerkhanov <aidar.samerkhanov@memgraph.io>
2024-02-14 14:52:38 +01:00
Marko Barišić
1919afa850 Add step to refresh jepsen cluster before test (#1667)
refresh jepsen during diff workflow
2024-02-14 14:52:19 +01:00
Deda
474fd43f37 Override version to 2.14.0 2024-01-22 14:28:15 +01:00
Gareth Lloyd
639d43c3ef Bugfix don't use _Py_IsFinalizing
This is an unstable function and would bump our dependency to python 3.7
2024-01-22 14:27:15 +01:00
14 changed files with 633 additions and 204 deletions

View File

@@ -365,6 +365,11 @@ jobs:
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo .. cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
make -j$THREADS memgraph make -j$THREADS memgraph
- name: Refresh Jepsen Cluster
run: |
cd tests/jepsen
./run.sh cluster-refresh
- name: Run Jepsen tests - name: Run Jepsen tests
run: | run: |
cd tests/jepsen cd tests/jepsen

View File

@@ -1,4 +1,7 @@
name: Release Debian 10 name: Release Debian 10
concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}
cancel-in-progress: true
on: on:
workflow_dispatch: workflow_dispatch:
@@ -10,23 +13,30 @@ on:
options: options:
- Release - Release
- RelWithDebInfo - RelWithDebInfo
push:
branches:
- "release/**"
tags:
- "v*.*.*-rc*"
- "v*.*-rc*"
schedule: schedule:
- cron: "0 22 * * *" - cron: "0 22 * * *"
env:
THREADS: 24
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
BUILD_TYPE: ${{ github.event.inputs.build_type || 'Release' }}
jobs: jobs:
community_build: community_build:
name: "Community build" name: "Community build"
runs-on: [self-hosted, Linux, X64, Debian10] runs-on: [self-hosted, Linux, X64, Debian10]
env: timeout-minutes: 60
THREADS: 24
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
timeout-minutes: 960
steps: steps:
- name: Set up repository - name: Set up repository
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
# Number of commits to fetch. `0` indicates all history for all # Number of commits to fetch. `0` indicates all history for all
# branches and tags. (default: 1) # branches and tags. (default: 1)
@@ -40,10 +50,6 @@ jobs:
# Initialize dependencies. # Initialize dependencies.
./init ./init
# Set default build_type to Release
INPUT_BUILD_TYPE=${{ github.event.inputs.build_type }}
BUILD_TYPE=${INPUT_BUILD_TYPE:-"Release"}
# Build community binaries. # Build community binaries.
cd build cd build
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DMG_ENTERPRISE=OFF .. cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DMG_ENTERPRISE=OFF ..
@@ -65,10 +71,11 @@ jobs:
THREADS: 24 THREADS: 24
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }} MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }} MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
timeout-minutes: 60
steps: steps:
- name: Set up repository - name: Set up repository
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
# Number of commits to fetch. `0` indicates all history for all # Number of commits to fetch. `0` indicates all history for all
# branches and tags. (default: 1) # branches and tags. (default: 1)
@@ -110,22 +117,19 @@ jobs:
tar -czf code_coverage.tar.gz coverage.json html report.json summary.rmu tar -czf code_coverage.tar.gz coverage.json html report.json summary.rmu
- name: Save code coverage - name: Save code coverage
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: "Code coverage" name: "Code coverage(Coverage build)"
path: tools/github/generated/code_coverage.tar.gz path: tools/github/generated/code_coverage.tar.gz
debug_build: debug_build:
name: "Debug build" name: "Debug build"
runs-on: [self-hosted, Linux, X64, Debian10] runs-on: [self-hosted, Linux, X64, Debian10]
env: timeout-minutes: 60
THREADS: 24
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
steps: steps:
- name: Set up repository - name: Set up repository
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
# Number of commits to fetch. `0` indicates all history for all # Number of commits to fetch. `0` indicates all history for all
# branches and tags. (default: 1) # branches and tags. (default: 1)
@@ -157,10 +161,6 @@ jobs:
run: | run: |
./tests/drivers/run.sh ./tests/drivers/run.sh
- name: Run integration tests
run: |
tests/integration/run.sh
- name: Run cppcheck and clang-format - name: Run cppcheck and clang-format
run: | run: |
# Activate toolchain. # Activate toolchain.
@@ -171,23 +171,49 @@ jobs:
./cppcheck_and_clang_format diff ./cppcheck_and_clang_format diff
- name: Save cppcheck and clang-format errors - name: Save cppcheck and clang-format errors
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: "Code coverage" name: "Code coverage(Debug build)"
path: tools/github/cppcheck_and_clang_format.txt path: tools/github/cppcheck_and_clang_format.txt
release_build: debug_integration_test:
name: "Release build" name: "Debug integration tests"
runs-on: [self-hosted, Linux, X64, Debian10, BigMemory] runs-on: [self-hosted, Linux, X64, Debian10]
env: timeout-minutes: 60
THREADS: 24
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
timeout-minutes: 960
steps: steps:
- name: Set up repository - name: Set up repository
uses: actions/checkout@v3 uses: actions/checkout@v4
with:
# Number of commits to fetch. `0` indicates all history for all
# branches and tags. (default: 1)
fetch-depth: 0
- name: Build debug binaries
run: |
# Activate toolchain.
source /opt/toolchain-v4/activate
# Initialize dependencies.
./init
# Build debug binaries.
cd build
cmake ..
make -j$THREADS
- name: Run integration tests
run: |
tests/integration/run.sh
release_build:
name: "Release build"
runs-on: [self-hosted, Linux, X64, Debian10]
timeout-minutes: 60
steps:
- name: Set up repository
uses: actions/checkout@v4
with: with:
# Number of commits to fetch. `0` indicates all history for all # Number of commits to fetch. `0` indicates all history for all
# branches and tags. (default: 1) # branches and tags. (default: 1)
@@ -201,10 +227,6 @@ jobs:
# Initialize dependencies. # Initialize dependencies.
./init ./init
# Set default build_type to Release
INPUT_BUILD_TYPE=${{ github.event.inputs.build_type }}
BUILD_TYPE=${INPUT_BUILD_TYPE:-"Release"}
# Build release binaries. # Build release binaries.
cd build cd build
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE .. cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
@@ -226,11 +248,60 @@ jobs:
cpack -G DEB --config ../CPackConfig.cmake cpack -G DEB --config ../CPackConfig.cmake
- name: Save enterprise DEB package - name: Save enterprise DEB package
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: "Enterprise DEB package" name: "Enterprise DEB package"
path: build/output/memgraph*.deb path: build/output/memgraph*.deb
- name: Run GQL Behave tests
run: |
cd tests
./setup.sh /opt/toolchain-v4/activate
cd gql_behave
./continuous_integration
- name: Save quality assurance status
uses: actions/upload-artifact@v4
with:
name: "GQL Behave Status"
path: |
tests/gql_behave/gql_behave_status.csv
tests/gql_behave/gql_behave_status.html
- name: Run unit tests
run: |
# Activate toolchain.
source /opt/toolchain-v4/activate
# Run unit tests.
cd build
ctest -R memgraph__unit --output-on-failure
release_benchmark_tests:
name: "Release Benchmark Tests"
runs-on: [self-hosted, Linux, X64, Debian10]
timeout-minutes: 60
steps:
- name: Set up repository
uses: actions/checkout@v4
with:
# Number of commits to fetch. `0` indicates all history for all
# branches and tags. (default: 1)
fetch-depth: 0
- name: Build release binaries
run: |
# Activate toolchain.
source /opt/toolchain-v4/activate
# Initialize dependencies.
./init
# Build release binaries
cd build
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
make -j$THREADS
- name: Run micro benchmark tests - name: Run micro benchmark tests
run: | run: |
# Activate toolchain. # Activate toolchain.
@@ -257,29 +328,30 @@ jobs:
--num-database-workers 9 --num-clients-workers 30 \ --num-database-workers 9 --num-clients-workers 30 \
--no-strict --no-strict
- name: Run GQL Behave tests release_e2e_test:
run: | name: "Release End-to-end Test"
cd tests runs-on: [self-hosted, Linux, X64, Debian10]
./setup.sh /opt/toolchain-v4/activate timeout-minutes: 60
cd gql_behave
./continuous_integration
- name: Save quality assurance status steps:
uses: actions/upload-artifact@v3 - name: Set up repository
uses: actions/checkout@v4
with: with:
name: "GQL Behave Status" # Number of commits to fetch. `0` indicates all history for all
path: | # branches and tags. (default: 1)
tests/gql_behave/gql_behave_status.csv fetch-depth: 0
tests/gql_behave/gql_behave_status.html
- name: Run unit tests - name: Build release binaries
run: | run: |
# Activate toolchain. # Activate toolchain.
source /opt/toolchain-v4/activate source /opt/toolchain-v4/activate
# Initialize dependencies.
./init
# Run unit tests. # Build release binaries
cd build cd build
ctest -R memgraph__unit --output-on-failure cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
make -j$THREADS
- name: Ensure Kafka and Pulsar are up - name: Ensure Kafka and Pulsar are up
run: | run: |
@@ -304,6 +376,32 @@ jobs:
cd ../pulsar cd ../pulsar
docker-compose down docker-compose down
release_durability_stress_tests:
name: "Release durability and stress tests"
runs-on: [self-hosted, Linux, X64, Debian10]
timeout-minutes: 60
steps:
- name: Set up repository
uses: actions/checkout@v4
with:
# Number of commits to fetch. `0` indicates all history for all
# branches and tags. (default: 1)
fetch-depth: 0
- name: Build release binaries
run: |
# Activate toolchain.
source /opt/toolchain-v4/activate
# Initialize dependencies.
./init
# Build release binaries.
cd build
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
make -j$THREADS
- name: Run stress test (plain) - name: Run stress test (plain)
run: | run: |
cd tests/stress cd tests/stress
@@ -314,11 +412,6 @@ jobs:
cd tests/stress cd tests/stress
./continuous_integration --use-ssl ./continuous_integration --use-ssl
- name: Run stress test (large)
run: |
cd tests/stress
./continuous_integration --large-dataset
- name: Run durability test (plain) - name: Run durability test (plain)
run: | run: |
cd tests/stress cd tests/stress
@@ -334,15 +427,11 @@ jobs:
release_jepsen_test: release_jepsen_test:
name: "Release Jepsen Test" name: "Release Jepsen Test"
runs-on: [self-hosted, Linux, X64, Debian10, JepsenControl] runs-on: [self-hosted, Linux, X64, Debian10, JepsenControl]
env:
THREADS: 24
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
timeout-minutes: 60 timeout-minutes: 60
steps: steps:
- name: Set up repository - name: Set up repository
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
# Number of commits to fetch. `0` indicates all history for all # Number of commits to fetch. `0` indicates all history for all
# branches and tags. (default: 1) # branches and tags. (default: 1)
@@ -355,22 +444,23 @@ jobs:
# Initialize dependencies. # Initialize dependencies.
./init ./init
# Set default build_type to Release
INPUT_BUILD_TYPE=${{ github.event.inputs.build_type }}
BUILD_TYPE=${INPUT_BUILD_TYPE:-"Release"}
# Build only memgraph release binary. # Build only memgraph release binary.
cd build cd build
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE .. cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
make -j$THREADS memgraph make -j$THREADS memgraph
- name: Refresh Jepsen Cluster
run: |
cd tests/jepsen
./run.sh cluster-refresh
- name: Run Jepsen tests - name: Run Jepsen tests
run: | run: |
cd tests/jepsen cd tests/jepsen
./run.sh test-all-individually --binary ../../build/memgraph --ignore-run-stdout-logs --ignore-run-stderr-logs ./run.sh test-all-individually --binary ../../build/memgraph --ignore-run-stdout-logs --ignore-run-stderr-logs
- name: Save Jepsen report - name: Save Jepsen report
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
if: ${{ always() }} if: ${{ always() }}
with: with:
name: "Jepsen Report" name: "Jepsen Report"

View File

@@ -1,4 +1,7 @@
name: Release Ubuntu 20.04 name: Release Ubuntu 20.04
concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}
cancel-in-progress: true
on: on:
workflow_dispatch: workflow_dispatch:
@@ -10,23 +13,30 @@ on:
options: options:
- Release - Release
- RelWithDebInfo - RelWithDebInfo
push:
branches:
- "release/**"
tags:
- "v*.*.*-rc*"
- "v*.*-rc*"
schedule: schedule:
- cron: "0 22 * * *" - cron: "0 22 * * *"
env:
THREADS: 24
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
BUILD_TYPE: ${{ github.event.inputs.build_type || 'Release' }}
jobs: jobs:
community_build: community_build:
name: "Community build" name: "Community build"
runs-on: [self-hosted, Linux, X64, Ubuntu20.04] runs-on: [self-hosted, Linux, X64, Ubuntu20.04]
env: timeout-minutes: 60
THREADS: 24
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
timeout-minutes: 960
steps: steps:
- name: Set up repository - name: Set up repository
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
# Number of commits to fetch. `0` indicates all history for all # Number of commits to fetch. `0` indicates all history for all
# branches and tags. (default: 1) # branches and tags. (default: 1)
@@ -40,10 +50,6 @@ jobs:
# Initialize dependencies. # Initialize dependencies.
./init ./init
# Set default build_type to Release
INPUT_BUILD_TYPE=${{ github.event.inputs.build_type }}
BUILD_TYPE=${INPUT_BUILD_TYPE:-"Release"}
# Build community binaries. # Build community binaries.
cd build cd build
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DMG_ENTERPRISE=OFF .. cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DMG_ENTERPRISE=OFF ..
@@ -61,14 +67,11 @@ jobs:
coverage_build: coverage_build:
name: "Coverage build" name: "Coverage build"
runs-on: [self-hosted, Linux, X64, Ubuntu20.04] runs-on: [self-hosted, Linux, X64, Ubuntu20.04]
env: timeout-minutes: 60
THREADS: 24
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
steps: steps:
- name: Set up repository - name: Set up repository
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
# Number of commits to fetch. `0` indicates all history for all # Number of commits to fetch. `0` indicates all history for all
# branches and tags. (default: 1) # branches and tags. (default: 1)
@@ -110,22 +113,19 @@ jobs:
tar -czf code_coverage.tar.gz coverage.json html report.json summary.rmu tar -czf code_coverage.tar.gz coverage.json html report.json summary.rmu
- name: Save code coverage - name: Save code coverage
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: "Code coverage" name: "Code coverage(Coverage build)"
path: tools/github/generated/code_coverage.tar.gz path: tools/github/generated/code_coverage.tar.gz
debug_build: debug_build:
name: "Debug build" name: "Debug build"
runs-on: [self-hosted, Linux, X64, Ubuntu20.04] runs-on: [self-hosted, Linux, X64, Ubuntu20.04]
env: timeout-minutes: 60
THREADS: 24
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
steps: steps:
- name: Set up repository - name: Set up repository
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
# Number of commits to fetch. `0` indicates all history for all # Number of commits to fetch. `0` indicates all history for all
# branches and tags. (default: 1) # branches and tags. (default: 1)
@@ -157,10 +157,6 @@ jobs:
run: | run: |
./tests/drivers/run.sh ./tests/drivers/run.sh
- name: Run integration tests
run: |
tests/integration/run.sh
- name: Run cppcheck and clang-format - name: Run cppcheck and clang-format
run: | run: |
# Activate toolchain. # Activate toolchain.
@@ -171,23 +167,49 @@ jobs:
./cppcheck_and_clang_format diff ./cppcheck_and_clang_format diff
- name: Save cppcheck and clang-format errors - name: Save cppcheck and clang-format errors
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: "Code coverage" name: "Code coverage(Debug build)"
path: tools/github/cppcheck_and_clang_format.txt path: tools/github/cppcheck_and_clang_format.txt
debug_integration_test:
name: "Debug integration tests"
runs-on: [self-hosted, Linux, X64, Ubuntu20.04]
timeout-minutes: 60
steps:
- name: Set up repository
uses: actions/checkout@v4
with:
# Number of commits to fetch. `0` indicates all history for all
# branches and tags. (default: 1)
fetch-depth: 0
- name: Build debug binaries
run: |
# Activate toolchain.
source /opt/toolchain-v4/activate
# Initialize dependencies.
./init
# Build debug binaries.
cd build
cmake ..
make -j$THREADS
- name: Run integration tests
run: |
tests/integration/run.sh
release_build: release_build:
name: "Release build" name: "Release build"
runs-on: [self-hosted, Linux, X64, Ubuntu20.04] runs-on: [self-hosted, Linux, X64, Ubuntu20.04]
env: timeout-minutes: 60
THREADS: 24
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
timeout-minutes: 960
steps: steps:
- name: Set up repository - name: Set up repository
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
# Number of commits to fetch. `0` indicates all history for all # Number of commits to fetch. `0` indicates all history for all
# branches and tags. (default: 1) # branches and tags. (default: 1)
@@ -201,10 +223,6 @@ jobs:
# Initialize dependencies. # Initialize dependencies.
./init ./init
# Set default build_type to Release
INPUT_BUILD_TYPE=${{ github.event.inputs.build_type }}
BUILD_TYPE=${INPUT_BUILD_TYPE:-"Release"}
# Build release binaries. # Build release binaries.
cd build cd build
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE .. cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
@@ -226,11 +244,60 @@ jobs:
cpack -G DEB --config ../CPackConfig.cmake cpack -G DEB --config ../CPackConfig.cmake
- name: Save enterprise DEB package - name: Save enterprise DEB package
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: "Enterprise DEB package" name: "Enterprise DEB package"
path: build/output/memgraph*.deb path: build/output/memgraph*.deb
- name: Run GQL Behave tests
run: |
cd tests
./setup.sh /opt/toolchain-v4/activate
cd gql_behave
./continuous_integration
- name: Save quality assurance status
uses: actions/upload-artifact@v4
with:
name: "GQL Behave Status"
path: |
tests/gql_behave/gql_behave_status.csv
tests/gql_behave/gql_behave_status.html
- name: Run unit tests
run: |
# Activate toolchain.
source /opt/toolchain-v4/activate
# Run unit tests.
cd build
ctest -R memgraph__unit --output-on-failure
release_benchmark_tests:
name: "Release Benchmark Tests"
runs-on: [self-hosted, Linux, X64, Ubuntu20.04]
timeout-minutes: 60
steps:
- name: Set up repository
uses: actions/checkout@v4
with:
# Number of commits to fetch. `0` indicates all history for all
# branches and tags. (default: 1)
fetch-depth: 0
- name: Build release binaries
run: |
# Activate toolchain.
source /opt/toolchain-v4/activate
# Initialize dependencies.
./init
# Build release binaries
cd build
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
make -j$THREADS
- name: Run micro benchmark tests - name: Run micro benchmark tests
run: | run: |
# Activate toolchain. # Activate toolchain.
@@ -257,29 +324,30 @@ jobs:
--num-database-workers 9 --num-clients-workers 30 \ --num-database-workers 9 --num-clients-workers 30 \
--no-strict --no-strict
- name: Run GQL Behave tests release_e2e_test:
run: | name: "Release End-to-end Test"
cd tests runs-on: [self-hosted, Linux, X64, Ubuntu20.04]
./setup.sh /opt/toolchain-v4/activate timeout-minutes: 60
cd gql_behave
./continuous_integration
- name: Save quality assurance status steps:
uses: actions/upload-artifact@v3 - name: Set up repository
uses: actions/checkout@v4
with: with:
name: "GQL Behave Status" # Number of commits to fetch. `0` indicates all history for all
path: | # branches and tags. (default: 1)
tests/gql_behave/gql_behave_status.csv fetch-depth: 0
tests/gql_behave/gql_behave_status.html
- name: Run unit tests - name: Build release binaries
run: | run: |
# Activate toolchain. # Activate toolchain.
source /opt/toolchain-v4/activate source /opt/toolchain-v4/activate
# Initialize dependencies.
./init
# Run unit tests. # Build release binaries
cd build cd build
ctest -R memgraph__unit --output-on-failure cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
make -j$THREADS
- name: Ensure Kafka and Pulsar are up - name: Ensure Kafka and Pulsar are up
run: | run: |
@@ -304,6 +372,32 @@ jobs:
cd ../pulsar cd ../pulsar
docker-compose down docker-compose down
release_durability_stress_tests:
name: "Release durability and stress tests"
runs-on: [self-hosted, Linux, X64, Ubuntu20.04]
timeout-minutes: 60
steps:
- name: Set up repository
uses: actions/checkout@v4
with:
# Number of commits to fetch. `0` indicates all history for all
# branches and tags. (default: 1)
fetch-depth: 0
- name: Build release binaries
run: |
# Activate toolchain.
source /opt/toolchain-v4/activate
# Initialize dependencies.
./init
# Build release binaries.
cd build
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
make -j$THREADS
- name: Run stress test (plain) - name: Run stress test (plain)
run: | run: |
cd tests/stress cd tests/stress
@@ -314,11 +408,6 @@ jobs:
cd tests/stress cd tests/stress
./continuous_integration --use-ssl ./continuous_integration --use-ssl
- name: Run stress test (large)
run: |
cd tests/stress
./continuous_integration --large-dataset
- name: Run durability test (plain) - name: Run durability test (plain)
run: | run: |
cd tests/stress cd tests/stress

View File

@@ -0,0 +1,68 @@
name: Stress test large
concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}
cancel-in-progress: true
on:
workflow_dispatch:
inputs:
build_type:
type: choice
description: "Memgraph Build type. Default value is Release."
default: 'Release'
options:
- Release
- RelWithDebInfo
push:
tags:
- "v*.*.*-rc*"
- "v*.*-rc*"
schedule:
- cron: "0 22 * * *"
env:
THREADS: 24
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
BUILD_TYPE: ${{ github.event.inputs.build_type || 'Release' }}
jobs:
stress_test_large:
name: "Stress test large"
timeout-minutes: 720
strategy:
matrix:
os: [Debian10, Ubuntu20.04]
extra: [BigMemory, Gen8]
exclude:
- os: Debian10
extra: Gen8
- os: Ubuntu20.04
extra: BigMemory
runs-on: [self-hosted, Linux, X64, "${{ matrix.os }}", "${{ matrix.extra }}"]
steps:
- name: Set up repository
uses: actions/checkout@v4
with:
# Number of commits to fetch. `0` indicates all history for all
# branches and tags. (default: 1)
fetch-depth: 0
- name: Build release binaries
run: |
# Activate toolchain.
source /opt/toolchain-v4/activate
# Initialize dependencies.
./init
# Build release binaries.
cd build
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
make -j$THREADS
- name: Run stress test (large)
run: |
cd tests/stress
./continuous_integration --large-dataset

View File

@@ -64,7 +64,7 @@ option(MG_ENTERPRISE "Build Memgraph Enterprise Edition" ON)
# Set the current version here to override the automatic version detection. The # 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 # version must be specified as `X.Y.Z`. Primarily used when building new patch
# versions. # versions.
set(MEMGRAPH_OVERRIDE_VERSION "") set(MEMGRAPH_OVERRIDE_VERSION "2.14.1")
# Custom suffix that this version should have. The suffix can be any arbitrary # Custom suffix that this version should have. The suffix can be any arbitrary
# string. Primarily used when building a version for a specific customer. # string. Primarily used when building a version for a specific customer.

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd. // Copyright 2024 Memgraph Ltd.
// //
// Use of this software is governed by the Business Source License // 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 // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -114,12 +114,17 @@ class Path {
/** Expands the path with the given vertex. */ /** Expands the path with the given vertex. */
void Expand(const VertexAccessor &vertex) { void Expand(const VertexAccessor &vertex) {
DMG_ASSERT(vertices_.size() == edges_.size(), "Illegal path construction order"); DMG_ASSERT(vertices_.size() == edges_.size(), "Illegal path construction order");
DMG_ASSERT(edges_.empty() || (!edges_.empty() && (edges_.back().To().Gid() == vertex.Gid() ||
edges_.back().From().Gid() == vertex.Gid())),
"Illegal path construction order");
vertices_.emplace_back(vertex); vertices_.emplace_back(vertex);
} }
/** Expands the path with the given edge. */ /** Expands the path with the given edge. */
void Expand(const EdgeAccessor &edge) { void Expand(const EdgeAccessor &edge) {
DMG_ASSERT(vertices_.size() - 1 == edges_.size(), "Illegal path construction order"); DMG_ASSERT(vertices_.size() - 1 == edges_.size(), "Illegal path construction order");
DMG_ASSERT(vertices_.back().Gid() == edge.From().Gid() || vertices_.back().Gid() == edge.To().Gid(),
"Illegal path construction order");
edges_.emplace_back(edge); edges_.emplace_back(edge);
} }
@@ -130,6 +135,14 @@ class Path {
Expand(others...); Expand(others...);
} }
void Shrink() {
DMG_ASSERT(!vertices_.empty(), "Vertices should not be empty in the path before shrink.");
vertices_.pop_back();
if (!edges_.empty()) {
edges_.pop_back();
}
}
/** Returns the number of expansions (edges) in this path. */ /** Returns the number of expansions (edges) in this path. */
auto size() const { return edges_.size(); } auto size() const { return edges_.size(); }

View File

@@ -1,4 +1,4 @@
// Copyright 2023 Memgraph Ltd. // Copyright 2024 Memgraph Ltd.
// //
// Use of this software is governed by the Business Source License // 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 // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -1057,7 +1057,8 @@ class ExpandVariableCursor : public Cursor {
if (!self_.common_.existing_node) { if (!self_.common_.existing_node) {
frame[self_.common_.node_symbol] = start_vertex; frame[self_.common_.node_symbol] = start_vertex;
return true; return true;
} else if (CheckExistingNode(start_vertex, self_.common_.node_symbol, frame)) { }
if (CheckExistingNode(start_vertex, self_.common_.node_symbol, frame)) {
return true; return true;
} }
} }
@@ -1243,6 +1244,10 @@ class ExpandVariableCursor : public Cursor {
MG_ASSERT(frame[self_.filter_lambda_.accumulated_path_symbol.value()].IsPath(), MG_ASSERT(frame[self_.filter_lambda_.accumulated_path_symbol.value()].IsPath(),
"Accumulated path must be path"); "Accumulated path must be path");
Path &accumulated_path = frame[self_.filter_lambda_.accumulated_path_symbol.value()].ValuePath(); Path &accumulated_path = frame[self_.filter_lambda_.accumulated_path_symbol.value()].ValuePath();
// Shrink the accumulated path including current level if necessary
while (accumulated_path.size() >= edges_on_frame.size()) {
accumulated_path.Shrink();
}
accumulated_path.Expand(current_edge.first); accumulated_path.Expand(current_edge.first);
accumulated_path.Expand(current_vertex); accumulated_path.Expand(current_vertex);
} }
@@ -1260,10 +1265,9 @@ class ExpandVariableCursor : public Cursor {
if (self_.common_.existing_node && !CheckExistingNode(current_vertex, self_.common_.node_symbol, frame)) continue; if (self_.common_.existing_node && !CheckExistingNode(current_vertex, self_.common_.node_symbol, frame)) continue;
// We only yield true if we satisfy the lower bound. // We only yield true if we satisfy the lower bound.
if (static_cast<int64_t>(edges_on_frame.size()) >= lower_bound_) if (static_cast<int64_t>(edges_on_frame.size()) >= lower_bound_) {
return true; return true;
else }
continue;
} }
} }
}; };
@@ -1527,8 +1531,8 @@ class SingleSourceShortestPathCursor : public query::plan::Cursor {
: self_(self), : self_(self),
input_cursor_(self_.input()->MakeCursor(mem)), input_cursor_(self_.input()->MakeCursor(mem)),
processed_(mem), processed_(mem),
to_visit_current_(mem), to_visit_next_(mem),
to_visit_next_(mem) { to_visit_current_(mem) {
MG_ASSERT(!self_.common_.existing_node, MG_ASSERT(!self_.common_.existing_node,
"Single source shortest path algorithm " "Single source shortest path algorithm "
"should not be used when `existing_node` " "should not be used when `existing_node` "
@@ -1558,12 +1562,14 @@ class SingleSourceShortestPathCursor : public query::plan::Cursor {
#endif #endif
frame[self_.filter_lambda_.inner_edge_symbol] = edge; frame[self_.filter_lambda_.inner_edge_symbol] = edge;
frame[self_.filter_lambda_.inner_node_symbol] = vertex; frame[self_.filter_lambda_.inner_node_symbol] = vertex;
std::optional<Path> curr_acc_path = std::nullopt;
if (self_.filter_lambda_.accumulated_path_symbol) { if (self_.filter_lambda_.accumulated_path_symbol) {
MG_ASSERT(frame[self_.filter_lambda_.accumulated_path_symbol.value()].IsPath(), MG_ASSERT(frame[self_.filter_lambda_.accumulated_path_symbol.value()].IsPath(),
"Accumulated path must have Path type"); "Accumulated path must have Path type");
Path &accumulated_path = frame[self_.filter_lambda_.accumulated_path_symbol.value()].ValuePath(); Path &accumulated_path = frame[self_.filter_lambda_.accumulated_path_symbol.value()].ValuePath();
accumulated_path.Expand(edge); accumulated_path.Expand(edge);
accumulated_path.Expand(vertex); accumulated_path.Expand(vertex);
curr_acc_path = accumulated_path;
} }
if (self_.filter_lambda_.expression) { if (self_.filter_lambda_.expression) {
@@ -1578,21 +1584,33 @@ class SingleSourceShortestPathCursor : public query::plan::Cursor {
throw QueryRuntimeException("Expansion condition must evaluate to boolean or null."); throw QueryRuntimeException("Expansion condition must evaluate to boolean or null.");
} }
} }
to_visit_next_.emplace_back(edge, vertex); to_visit_next_.emplace_back(edge, vertex, std::move(curr_acc_path));
processed_.emplace(vertex, edge); processed_.emplace(vertex, edge);
}; };
auto restore_frame_state_after_expansion = [this, &frame]() {
if (self_.filter_lambda_.accumulated_path_symbol) {
frame[self_.filter_lambda_.accumulated_path_symbol.value()].ValuePath().Shrink();
}
};
// populates the to_visit_next_ structure with expansions // populates the to_visit_next_ structure with expansions
// from the given vertex. skips expansions that don't satisfy // from the given vertex. skips expansions that don't satisfy
// the "where" condition. // the "where" condition.
auto expand_from_vertex = [this, &expand_pair](const auto &vertex) { auto expand_from_vertex = [this, &expand_pair, &restore_frame_state_after_expansion](const auto &vertex) {
if (self_.common_.direction != EdgeAtom::Direction::IN) { if (self_.common_.direction != EdgeAtom::Direction::IN) {
auto out_edges = UnwrapEdgesResult(vertex.OutEdges(storage::View::OLD, self_.common_.edge_types)).edges; auto out_edges = UnwrapEdgesResult(vertex.OutEdges(storage::View::OLD, self_.common_.edge_types)).edges;
for (const auto &edge : out_edges) expand_pair(edge, edge.To()); for (const auto &edge : out_edges) {
expand_pair(edge, edge.To());
restore_frame_state_after_expansion();
}
} }
if (self_.common_.direction != EdgeAtom::Direction::OUT) { if (self_.common_.direction != EdgeAtom::Direction::OUT) {
auto in_edges = UnwrapEdgesResult(vertex.InEdges(storage::View::OLD, self_.common_.edge_types)).edges; auto in_edges = UnwrapEdgesResult(vertex.InEdges(storage::View::OLD, self_.common_.edge_types)).edges;
for (const auto &edge : in_edges) expand_pair(edge, edge.From()); for (const auto &edge : in_edges) {
expand_pair(edge, edge.From());
restore_frame_state_after_expansion();
}
} }
}; };
@@ -1638,14 +1656,14 @@ class SingleSourceShortestPathCursor : public query::plan::Cursor {
} }
// take the next expansion from the queue // take the next expansion from the queue
auto expansion = to_visit_current_.back(); auto [curr_edge, curr_vertex, curr_acc_path] = to_visit_current_.back();
to_visit_current_.pop_back(); to_visit_current_.pop_back();
// create the frame value for the edges // create the frame value for the edges
auto *pull_memory = context.evaluation_context.memory; auto *pull_memory = context.evaluation_context.memory;
utils::pmr::vector<TypedValue> edge_list(pull_memory); utils::pmr::vector<TypedValue> edge_list(pull_memory);
edge_list.emplace_back(expansion.first); edge_list.emplace_back(curr_edge);
auto last_vertex = expansion.second; auto last_vertex = curr_vertex;
while (true) { while (true) {
const EdgeAccessor &last_edge = edge_list.back().ValueEdge(); const EdgeAccessor &last_edge = edge_list.back().ValueEdge();
last_vertex = last_edge.From() == last_vertex ? last_edge.To() : last_edge.From(); last_vertex = last_edge.From() == last_vertex ? last_edge.To() : last_edge.From();
@@ -1657,11 +1675,17 @@ class SingleSourceShortestPathCursor : public query::plan::Cursor {
} }
// expand only if what we've just expanded is less then max depth // expand only if what we've just expanded is less then max depth
if (static_cast<int64_t>(edge_list.size()) < upper_bound_) expand_from_vertex(expansion.second); if (static_cast<int64_t>(edge_list.size()) < upper_bound_) {
if (self_.filter_lambda_.accumulated_path_symbol) {
MG_ASSERT(curr_acc_path.has_value(), "Expected non-null accumulated path");
frame[self_.filter_lambda_.accumulated_path_symbol.value()] = std::move(curr_acc_path.value());
}
expand_from_vertex(curr_vertex);
}
if (static_cast<int64_t>(edge_list.size()) < lower_bound_) continue; if (static_cast<int64_t>(edge_list.size()) < lower_bound_) continue;
frame[self_.common_.node_symbol] = expansion.second; frame[self_.common_.node_symbol] = curr_vertex;
// place edges on the frame in the correct order // place edges on the frame in the correct order
std::reverse(edge_list.begin(), edge_list.end()); std::reverse(edge_list.begin(), edge_list.end());
@@ -1693,9 +1717,9 @@ class SingleSourceShortestPathCursor : public query::plan::Cursor {
// edge because the root does not get expanded from anything. // edge because the root does not get expanded from anything.
// contains visited vertices as well as those scheduled to be visited. // contains visited vertices as well as those scheduled to be visited.
utils::pmr::unordered_map<VertexAccessor, std::optional<EdgeAccessor>> processed_; utils::pmr::unordered_map<VertexAccessor, std::optional<EdgeAccessor>> processed_;
// edge/vertex pairs we have yet to visit, for current and next depth // edge, vertex we have yet to visit, for current and next depth and their accumulated paths
utils::pmr::vector<std::pair<EdgeAccessor, VertexAccessor>> to_visit_current_; utils::pmr::vector<std::tuple<EdgeAccessor, VertexAccessor, std::optional<Path>>> to_visit_next_;
utils::pmr::vector<std::pair<EdgeAccessor, VertexAccessor>> to_visit_next_; utils::pmr::vector<std::tuple<EdgeAccessor, VertexAccessor, std::optional<Path>>> to_visit_current_;
}; };
namespace { namespace {
@@ -1768,6 +1792,7 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor {
ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, context.db_accessor, ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, context.db_accessor,
storage::View::OLD); storage::View::OLD);
auto create_state = [this](const VertexAccessor &vertex, int64_t depth) { auto create_state = [this](const VertexAccessor &vertex, int64_t depth) {
return std::make_pair(vertex, upper_bound_set_ ? depth : 0); return std::make_pair(vertex, upper_bound_set_ ? depth : 0);
}; };
@@ -1791,6 +1816,7 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor {
frame[self_.weight_lambda_->inner_node_symbol] = vertex; frame[self_.weight_lambda_->inner_node_symbol] = vertex;
TypedValue next_weight = CalculateNextWeight(self_.weight_lambda_, total_weight, evaluator); TypedValue next_weight = CalculateNextWeight(self_.weight_lambda_, total_weight, evaluator);
std::optional<Path> curr_acc_path = std::nullopt;
if (self_.filter_lambda_.expression) { if (self_.filter_lambda_.expression) {
frame[self_.filter_lambda_.inner_edge_symbol] = edge; frame[self_.filter_lambda_.inner_edge_symbol] = edge;
frame[self_.filter_lambda_.inner_node_symbol] = vertex; frame[self_.filter_lambda_.inner_node_symbol] = vertex;
@@ -1800,6 +1826,7 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor {
Path &accumulated_path = frame[self_.filter_lambda_.accumulated_path_symbol.value()].ValuePath(); Path &accumulated_path = frame[self_.filter_lambda_.accumulated_path_symbol.value()].ValuePath();
accumulated_path.Expand(edge); accumulated_path.Expand(edge);
accumulated_path.Expand(vertex); accumulated_path.Expand(vertex);
curr_acc_path = accumulated_path;
if (self_.filter_lambda_.accumulated_weight_symbol) { if (self_.filter_lambda_.accumulated_weight_symbol) {
frame[self_.filter_lambda_.accumulated_weight_symbol.value()] = next_weight; frame[self_.filter_lambda_.accumulated_weight_symbol.value()] = next_weight;
@@ -1815,24 +1842,32 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor {
if (found_it != total_cost_.end() && (found_it->second.IsNull() || (found_it->second <= next_weight).ValueBool())) if (found_it != total_cost_.end() && (found_it->second.IsNull() || (found_it->second <= next_weight).ValueBool()))
return; return;
pq_.emplace(next_weight, depth + 1, vertex, edge); pq_.emplace(next_weight, depth + 1, vertex, edge, curr_acc_path);
};
auto restore_frame_state_after_expansion = [this, &frame]() {
if (self_.filter_lambda_.accumulated_path_symbol) {
frame[self_.filter_lambda_.accumulated_path_symbol.value()].ValuePath().Shrink();
}
}; };
// Populates the priority queue structure with expansions // Populates the priority queue structure with expansions
// from the given vertex. skips expansions that don't satisfy // from the given vertex. skips expansions that don't satisfy
// the "where" condition. // the "where" condition.
auto expand_from_vertex = [this, &expand_pair](const VertexAccessor &vertex, const TypedValue &weight, auto expand_from_vertex = [this, &expand_pair, &restore_frame_state_after_expansion](
int64_t depth) { const VertexAccessor &vertex, const TypedValue &weight, int64_t depth) {
if (self_.common_.direction != EdgeAtom::Direction::IN) { if (self_.common_.direction != EdgeAtom::Direction::IN) {
auto out_edges = UnwrapEdgesResult(vertex.OutEdges(storage::View::OLD, self_.common_.edge_types)).edges; auto out_edges = UnwrapEdgesResult(vertex.OutEdges(storage::View::OLD, self_.common_.edge_types)).edges;
for (const auto &edge : out_edges) { for (const auto &edge : out_edges) {
expand_pair(edge, edge.To(), weight, depth); expand_pair(edge, edge.To(), weight, depth);
restore_frame_state_after_expansion();
} }
} }
if (self_.common_.direction != EdgeAtom::Direction::OUT) { if (self_.common_.direction != EdgeAtom::Direction::OUT) {
auto in_edges = UnwrapEdgesResult(vertex.InEdges(storage::View::OLD, self_.common_.edge_types)).edges; auto in_edges = UnwrapEdgesResult(vertex.InEdges(storage::View::OLD, self_.common_.edge_types)).edges;
for (const auto &edge : in_edges) { for (const auto &edge : in_edges) {
expand_pair(edge, edge.From(), weight, depth); expand_pair(edge, edge.From(), weight, depth);
restore_frame_state_after_expansion();
} }
} }
}; };
@@ -1850,9 +1885,12 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor {
// Skip expansion for such nodes. // Skip expansion for such nodes.
if (node.IsNull()) continue; if (node.IsNull()) continue;
} }
std::optional<Path> curr_acc_path;
if (self_.filter_lambda_.accumulated_path_symbol) { if (self_.filter_lambda_.accumulated_path_symbol) {
// Add initial vertex of path to the accumulated path // Add initial vertex of path to the accumulated path
frame[self_.filter_lambda_.accumulated_path_symbol.value()] = Path(vertex); curr_acc_path = Path(vertex);
frame[self_.filter_lambda_.accumulated_path_symbol.value()] = curr_acc_path.value();
} }
if (self_.upper_bound_) { if (self_.upper_bound_) {
upper_bound_ = EvaluateInt(&evaluator, self_.upper_bound_, "Max depth in weighted shortest path expansion"); upper_bound_ = EvaluateInt(&evaluator, self_.upper_bound_, "Max depth in weighted shortest path expansion");
@@ -1876,7 +1914,7 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor {
total_cost_.clear(); total_cost_.clear();
yielded_vertices_.clear(); yielded_vertices_.clear();
pq_.emplace(current_weight, 0, vertex, std::nullopt); pq_.emplace(current_weight, 0, vertex, std::nullopt, curr_acc_path);
// We are adding the starting vertex to the set of yielded vertices // We are adding the starting vertex to the set of yielded vertices
// because we don't want to yield paths that end with the starting // because we don't want to yield paths that end with the starting
// vertex. // vertex.
@@ -1885,7 +1923,7 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor {
while (!pq_.empty()) { while (!pq_.empty()) {
AbortCheck(context); AbortCheck(context);
auto [current_weight, current_depth, current_vertex, current_edge] = pq_.top(); auto [current_weight, current_depth, current_vertex, current_edge, curr_acc_path] = pq_.top();
pq_.pop(); pq_.pop();
auto current_state = create_state(current_vertex, current_depth); auto current_state = create_state(current_vertex, current_depth);
@@ -1898,7 +1936,12 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor {
total_cost_.emplace(current_state, current_weight); total_cost_.emplace(current_state, current_weight);
// Expand only if what we've just expanded is less than max depth. // Expand only if what we've just expanded is less than max depth.
if (current_depth < upper_bound_) expand_from_vertex(current_vertex, current_weight, current_depth); if (current_depth < upper_bound_) {
if (self_.filter_lambda_.accumulated_path_symbol) {
frame[self_.filter_lambda_.accumulated_path_symbol.value()] = std::move(curr_acc_path.value());
}
expand_from_vertex(current_vertex, current_weight, current_depth);
}
// If we yielded a path for a vertex already, make the expansion but // If we yielded a path for a vertex already, make the expansion but
// don't return the path again. // don't return the path again.
@@ -1921,9 +1964,9 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor {
// Place destination node on the frame, handle existence flag. // Place destination node on the frame, handle existence flag.
if (self_.common_.existing_node) { if (self_.common_.existing_node) {
const auto &node = frame[self_.common_.node_symbol]; const auto &node = frame[self_.common_.node_symbol];
if ((node != TypedValue(current_vertex, pull_memory)).ValueBool()) if ((node != TypedValue(current_vertex, pull_memory)).ValueBool()) {
continue; continue;
else }
// Prevent expanding other paths, because we found the // Prevent expanding other paths, because we found the
// shortest to existing node. // shortest to existing node.
ClearQueue(); ClearQueue();
@@ -1979,8 +2022,9 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor {
// Priority queue comparator. Keep lowest weight on top of the queue. // Priority queue comparator. Keep lowest weight on top of the queue.
class PriorityQueueComparator { class PriorityQueueComparator {
public: public:
bool operator()(const std::tuple<TypedValue, int64_t, VertexAccessor, std::optional<EdgeAccessor>> &lhs, bool operator()(
const std::tuple<TypedValue, int64_t, VertexAccessor, std::optional<EdgeAccessor>> &rhs) { const std::tuple<TypedValue, int64_t, VertexAccessor, std::optional<EdgeAccessor>, std::optional<Path>> &lhs,
const std::tuple<TypedValue, int64_t, VertexAccessor, std::optional<EdgeAccessor>, std::optional<Path>> &rhs) {
const auto &lhs_weight = std::get<0>(lhs); const auto &lhs_weight = std::get<0>(lhs);
const auto &rhs_weight = std::get<0>(rhs); const auto &rhs_weight = std::get<0>(rhs);
// Null defines minimum value for all types // Null defines minimum value for all types
@@ -1997,8 +2041,9 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor {
} }
}; };
std::priority_queue<std::tuple<TypedValue, int64_t, VertexAccessor, std::optional<EdgeAccessor>>, std::priority_queue<std::tuple<TypedValue, int64_t, VertexAccessor, std::optional<EdgeAccessor>, std::optional<Path>>,
utils::pmr::vector<std::tuple<TypedValue, int64_t, VertexAccessor, std::optional<EdgeAccessor>>>, utils::pmr::vector<std::tuple<TypedValue, int64_t, VertexAccessor, std::optional<EdgeAccessor>,
std::optional<Path>>>,
PriorityQueueComparator> PriorityQueueComparator>
pq_; pq_;
@@ -2024,6 +2069,9 @@ class ExpandAllShortestPathsCursor : public query::plan::Cursor {
ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, context.db_accessor, ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, context.db_accessor,
storage::View::OLD); storage::View::OLD);
auto *memory = context.evaluation_context.memory;
auto create_state = [this](const VertexAccessor &vertex, int64_t depth) { auto create_state = [this](const VertexAccessor &vertex, int64_t depth) {
return std::make_pair(vertex, upper_bound_set_ ? depth : 0); return std::make_pair(vertex, upper_bound_set_ ? depth : 0);
}; };
@@ -2041,6 +2089,7 @@ class ExpandAllShortestPathsCursor : public query::plan::Cursor {
TypedValue next_weight = CalculateNextWeight(self_.weight_lambda_, total_weight, evaluator); TypedValue next_weight = CalculateNextWeight(self_.weight_lambda_, total_weight, evaluator);
// If filter expression exists, evaluate filter // If filter expression exists, evaluate filter
std::optional<Path> curr_acc_path = std::nullopt;
if (self_.filter_lambda_.expression) { if (self_.filter_lambda_.expression) {
frame[self_.filter_lambda_.inner_edge_symbol] = edge; frame[self_.filter_lambda_.inner_edge_symbol] = edge;
frame[self_.filter_lambda_.inner_node_symbol] = next_vertex; frame[self_.filter_lambda_.inner_node_symbol] = next_vertex;
@@ -2050,6 +2099,7 @@ class ExpandAllShortestPathsCursor : public query::plan::Cursor {
Path &accumulated_path = frame[self_.filter_lambda_.accumulated_path_symbol.value()].ValuePath(); Path &accumulated_path = frame[self_.filter_lambda_.accumulated_path_symbol.value()].ValuePath();
accumulated_path.Expand(edge); accumulated_path.Expand(edge);
accumulated_path.Expand(next_vertex); accumulated_path.Expand(next_vertex);
curr_acc_path = accumulated_path;
if (self_.filter_lambda_.accumulated_weight_symbol) { if (self_.filter_lambda_.accumulated_weight_symbol) {
frame[self_.filter_lambda_.accumulated_weight_symbol.value()] = next_weight; frame[self_.filter_lambda_.accumulated_weight_symbol.value()] = next_weight;
@@ -2076,14 +2126,20 @@ class ExpandAllShortestPathsCursor : public query::plan::Cursor {
} }
DirectedEdge directed_edge = {edge, direction, next_weight}; DirectedEdge directed_edge = {edge, direction, next_weight};
pq_.emplace(next_weight, depth + 1, next_vertex, directed_edge); pq_.emplace(next_weight, depth + 1, next_vertex, directed_edge, curr_acc_path);
};
auto restore_frame_state_after_expansion = [this, &frame]() {
if (self_.filter_lambda_.accumulated_path_symbol) {
frame[self_.filter_lambda_.accumulated_path_symbol.value()].ValuePath().Shrink();
}
}; };
// Populates the priority queue structure with expansions // Populates the priority queue structure with expansions
// from the given vertex. skips expansions that don't satisfy // from the given vertex. skips expansions that don't satisfy
// the "where" condition. // the "where" condition.
auto expand_from_vertex = [this, &expand_vertex, &context](const VertexAccessor &vertex, const TypedValue &weight, auto expand_from_vertex = [this, &expand_vertex, &context, &restore_frame_state_after_expansion](
int64_t depth) { const VertexAccessor &vertex, const TypedValue &weight, int64_t depth) {
if (self_.common_.direction != EdgeAtom::Direction::IN) { if (self_.common_.direction != EdgeAtom::Direction::IN) {
auto out_edges = UnwrapEdgesResult(vertex.OutEdges(storage::View::OLD, self_.common_.edge_types)).edges; auto out_edges = UnwrapEdgesResult(vertex.OutEdges(storage::View::OLD, self_.common_.edge_types)).edges;
for (const auto &edge : out_edges) { for (const auto &edge : out_edges) {
@@ -2096,6 +2152,7 @@ class ExpandAllShortestPathsCursor : public query::plan::Cursor {
} }
#endif #endif
expand_vertex(edge, EdgeAtom::Direction::OUT, weight, depth); expand_vertex(edge, EdgeAtom::Direction::OUT, weight, depth);
restore_frame_state_after_expansion();
} }
} }
if (self_.common_.direction != EdgeAtom::Direction::OUT) { if (self_.common_.direction != EdgeAtom::Direction::OUT) {
@@ -2110,12 +2167,12 @@ class ExpandAllShortestPathsCursor : public query::plan::Cursor {
} }
#endif #endif
expand_vertex(edge, EdgeAtom::Direction::IN, weight, depth); expand_vertex(edge, EdgeAtom::Direction::IN, weight, depth);
restore_frame_state_after_expansion();
} }
} }
}; };
std::optional<VertexAccessor> start_vertex; std::optional<VertexAccessor> start_vertex;
auto *memory = context.evaluation_context.memory;
auto create_path = [this, &frame, &memory]() { auto create_path = [this, &frame, &memory]() {
auto &current_level = traversal_stack_.back(); auto &current_level = traversal_stack_.back();
@@ -2167,11 +2224,11 @@ class ExpandAllShortestPathsCursor : public query::plan::Cursor {
return true; return true;
}; };
auto create_DFS_traversal_tree = [this, &context, &memory, &create_state, &expand_from_vertex]() { auto create_DFS_traversal_tree = [this, &context, &memory, &frame, &create_state, &expand_from_vertex]() {
while (!pq_.empty()) { while (!pq_.empty()) {
AbortCheck(context); AbortCheck(context);
const auto [current_weight, current_depth, current_vertex, directed_edge] = pq_.top(); auto [current_weight, current_depth, current_vertex, directed_edge, acc_path] = pq_.top();
pq_.pop(); pq_.pop();
const auto &[current_edge, direction, weight] = directed_edge; const auto &[current_edge, direction, weight] = directed_edge;
@@ -2183,6 +2240,10 @@ class ExpandAllShortestPathsCursor : public query::plan::Cursor {
} else { } else {
total_cost_.emplace(current_state, current_weight); total_cost_.emplace(current_state, current_weight);
if (current_depth < upper_bound_) { if (current_depth < upper_bound_) {
if (self_.filter_lambda_.accumulated_path_symbol) {
DMG_ASSERT(acc_path.has_value(), "Path must be already filled in AllShortestPath DFS traversals");
frame[self_.filter_lambda_.accumulated_path_symbol.value()] = std::move(acc_path.value());
}
expand_from_vertex(current_vertex, current_weight, current_depth); expand_from_vertex(current_vertex, current_weight, current_depth);
} }
} }
@@ -2315,8 +2376,8 @@ class ExpandAllShortestPathsCursor : public query::plan::Cursor {
// Priority queue comparator. Keep lowest weight on top of the queue. // Priority queue comparator. Keep lowest weight on top of the queue.
class PriorityQueueComparator { class PriorityQueueComparator {
public: public:
bool operator()(const std::tuple<TypedValue, int64_t, VertexAccessor, DirectedEdge> &lhs, bool operator()(const std::tuple<TypedValue, int64_t, VertexAccessor, DirectedEdge, std::optional<Path>> &lhs,
const std::tuple<TypedValue, int64_t, VertexAccessor, DirectedEdge> &rhs) { const std::tuple<TypedValue, int64_t, VertexAccessor, DirectedEdge, std::optional<Path>> &rhs) {
const auto &lhs_weight = std::get<0>(lhs); const auto &lhs_weight = std::get<0>(lhs);
const auto &rhs_weight = std::get<0>(rhs); const auto &rhs_weight = std::get<0>(rhs);
// Null defines minimum value for all types // Null defines minimum value for all types
@@ -2335,8 +2396,9 @@ class ExpandAllShortestPathsCursor : public query::plan::Cursor {
// Priority queue - core element of the algorithm. // Priority queue - core element of the algorithm.
// Stores: {weight, depth, next vertex, edge and direction} // Stores: {weight, depth, next vertex, edge and direction}
std::priority_queue<std::tuple<TypedValue, int64_t, VertexAccessor, DirectedEdge>, std::priority_queue<
utils::pmr::vector<std::tuple<TypedValue, int64_t, VertexAccessor, DirectedEdge>>, std::tuple<TypedValue, int64_t, VertexAccessor, DirectedEdge, std::optional<Path>>,
utils::pmr::vector<std::tuple<TypedValue, int64_t, VertexAccessor, DirectedEdge, std::optional<Path>>>,
PriorityQueueComparator> PriorityQueueComparator>
pq_; pq_;

View File

@@ -1,4 +1,4 @@
// Copyright 2023 Memgraph Ltd. // Copyright 2024 Memgraph Ltd.
// //
// Use of this software is governed by the Business Source License // 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 // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -868,7 +868,10 @@ py::Object MgpListToPyTuple(mgp_list *list, PyObject *py_graph) {
} }
void PyCollectGarbage() { void PyCollectGarbage() {
if (!Py_IsInitialized() || _Py_IsFinalizing()) { // NOTE: No need to call _Py_IsFinalizing(), we ensure
// Python GC thread is stopped before Py_Finalize() is called
// in memgraph.cpp
if (!Py_IsInitialized()) {
// Calling EnsureGIL will crash the program if this is true. // Calling EnsureGIL will crash the program if this is true.
return; return;
} }

View File

@@ -762,6 +762,16 @@ Feature: Match
| path | | path |
| <(:label1 {id: 1})-[:type2 {id: 10}]->(:label3 {id: 3})> | | <(:label1 {id: 1})-[:type2 {id: 10}]->(:label3 {id: 3})> |
Scenario: Test DFS variable expand using IN edges with filter by edge type1
Given graph "graph_edges"
When executing query:
"""
MATCH path=(:label3)<-[* (e, n, p | NOT(type(e)='type1' AND type(last(relationships(p))) = 'type1'))]-(:label1) RETURN path;
"""
Then the result should be:
| path |
| <(:label3 {id: 3})<-[:type2 {id: 10}]-(:label1 {id: 1})> |
Scenario: Test DFS variable expand with filter by edge type2 Scenario: Test DFS variable expand with filter by edge type2
Given graph "graph_edges" Given graph "graph_edges"
When executing query: When executing query:
@@ -772,6 +782,16 @@ Feature: Match
| path | | path |
| <(:label1 {id: 1})-[:type1 {id: 1}]->(:label2 {id: 2})-[:type1 {id: 2}]->(:label3 {id: 3})> | | <(:label1 {id: 1})-[:type1 {id: 1}]->(:label2 {id: 2})-[:type1 {id: 2}]->(:label3 {id: 3})> |
Scenario: Test DFS variable expand using IN edges with filter by edge type2
Given graph "graph_edges"
When executing query:
"""
MATCH path=(:label3)<-[* (e, n, p | NOT(type(e)='type2' AND type(last(relationships(p))) = 'type2'))]-(:label1) RETURN path;
"""
Then the result should be:
| path |
| <(:label3 {id: 3})<-[:type1 {id: 2}]-(:label2 {id: 2})<-[:type1 {id: 1}]-(:label1 {id: 1})> |
Scenario: Using path indentifier from CREATE in MERGE Scenario: Using path indentifier from CREATE in MERGE
Given an empty graph Given an empty graph
And having executed: And having executed:

View File

@@ -205,11 +205,7 @@ Feature: All Shortest Path
| 20.3 | | 20.3 |
Scenario: Test match AllShortest with accumulated path filtered by order of ids Scenario: Test match AllShortest with accumulated path filtered by order of ids
Given an empty graph Given graph "graph_edges"
And having executed:
"""
CREATE (:label1 {id: 1})-[:type1 {id:1}]->(:label2 {id: 2})-[:type1 {id: 2}]->(:label3 {id: 3})-[:type1 {id: 3}]->(:label4 {id: 4});
"""
When executing query: When executing query:
""" """
MATCH pth=(:label1)-[*ALLSHORTEST (r, n | r.id) total_weight (e,n,p | e.id > 0 and (nodes(p)[-1]).id > (nodes(p)[-2]).id)]->(:label4) RETURN pth, total_weight; MATCH pth=(:label1)-[*ALLSHORTEST (r, n | r.id) total_weight (e,n,p | e.id > 0 and (nodes(p)[-1]).id > (nodes(p)[-2]).id)]->(:label4) RETURN pth, total_weight;
@@ -218,6 +214,16 @@ Feature: All Shortest Path
| pth | total_weight | | pth | total_weight |
| <(:label1{id:1})-[:type1{id:1}]->(:label2{id:2})-[:type1{id:2}]->(:label3{id:3})-[:type1{id:3}]->(:label4{id:4})> | 6 | | <(:label1{id:1})-[:type1{id:1}]->(:label2{id:2})-[:type1{id:2}]->(:label3{id:3})-[:type1{id:3}]->(:label4{id:4})> | 6 |
Scenario: Test match AllShortest using IN edges with accumulated path filtered by order of ids
Given graph "graph_edges"
When executing query:
"""
MATCH pth=(:label4)<-[*ALLSHORTEST (r, n | r.id) total_weight (e,n,p | e.id > 0 and (nodes(p)[-1]).id < (nodes(p)[-2]).id)]-(:label1) RETURN pth, total_weight;
"""
Then the result should be:
| pth | total_weight |
| <(:label4{id:4})<-[:type1{id:3}]-(:label3{id:3})<-[:type1{id:2}]-(:label2{id:2})<-[:type1{id:1}]-(:label1{id:1})> | 6 |
Scenario: Test match AllShortest with accumulated path filtered by edge type1 Scenario: Test match AllShortest with accumulated path filtered by edge type1
Given graph "graph_edges" Given graph "graph_edges"
When executing query: When executing query:

View File

@@ -136,6 +136,42 @@ Feature: Bfs
| pth | | pth |
| <(:label1{id:1})-[:type1{id:1}]->(:label2{id:2})-[:type1{id:2}]->(:label3{id:3})> | | <(:label1{id:1})-[:type1{id:1}]->(:label2{id:2})-[:type1{id:2}]->(:label3{id:3})> |
Scenario: Test BFS variable expand using IN edges with filter by last edge type of accumulated path
Given graph "graph_edges"
When executing query:
"""
MATCH pth=(:label3)<-[*BFS (e,n,p | type(relationships(p)[-1]) = 'type1')]-(:label1) return pth;
"""
Then the result should be:
| pth |
| <(:label3 {id: 3})<-[:type1 {id: 2}]-(:label2 {id: 2})<-[:type1 {id: 1}]-(:label1 {id: 1})> |
Scenario: Test BFS variable expand using IN edges with filter by number of vertices in the accumulated path
Given graph "graph_edges"
When executing query:
"""
MATCH p=(n)<-[*BFS (r, n, p | size(nodes(p)) > 0)]-(m {id:1}) return p;
"""
Then the result should be:
| p |
| <(:label2 {id: 2})<-[:type1 {id: 1}]-(:label1 {id: 1})> |
| <(:label3 {id: 3})<-[:type2 {id: 10}]-(:label1 {id: 1})> |
| <(:label4 {id: 4})<-[:type1 {id: 3}]-(:label3 {id: 3})<-[:type2 {id: 10}]-(:label1 {id: 1})> |
| <(:label5 {id: 5})<-[:type3 {id: 20}]-(:label1 {id: 1})> |
Scenario: Test BFS variable expand using IN edges with filter by id of vertices but accumulated path is not used
Given graph "graph_edges"
When executing query:
"""
MATCH p=(n)<-[*BFS (r, n, p | r.id > 0)]-(m {id:1}) return p;
"""
Then the result should be:
| p |
| <(:label2 {id: 2})<-[:type1 {id: 1}]-(:label1 {id: 1})> |
| <(:label3 {id: 3})<-[:type2 {id: 10}]-(:label1 {id: 1})> |
| <(:label4 {id: 4})<-[:type1 {id: 3}]-(:label3 {id: 3})<-[:type2 {id: 10}]-(:label1 {id: 1})> |
| <(:label5 {id: 5})<-[:type3 {id: 20}]-(:label1 {id: 1})> |
Scenario: Test BFS variable expand with restict filter by last edge type of accumulated path Scenario: Test BFS variable expand with restict filter by last edge type of accumulated path
Given an empty graph Given an empty graph
And having executed: And having executed:

View File

@@ -170,6 +170,20 @@ Feature: Weighted Shortest Path
| pth | total_weight | | pth | total_weight |
| <(:label1{id:1})-[:type1{id:1}]->(:label2{id:2})-[:type1{id:2}]->(:label3{id:3})-[:type1{id:3}]->(:label4{id:4})> | 6 | | <(:label1{id:1})-[:type1{id:1}]->(:label2{id:2})-[:type1{id:2}]->(:label3{id:3})-[:type1{id:3}]->(:label4{id:4})> | 6 |
Scenario: Test match wShortest using IN edges with accumulated path filtered by order of ids
Given an empty graph
And having executed:
"""
CREATE (:label1 {id: 1})-[:type1 {id:1}]->(:label2 {id: 2})-[:type1 {id: 2}]->(:label3 {id: 3})-[:type1 {id: 3}]->(:label4 {id: 4});
"""
When executing query:
"""
MATCH pth=(:label4)<-[*WSHORTEST (r, n | r.id) total_weight (e,n,p | e.id > 0 and (nodes(p)[-1]).id < (nodes(p)[-2]).id)]-(:label1) RETURN pth, total_weight;
"""
Then the result should be:
| pth | total_weight |
| <(:label4{id:4})<-[:type1{id:3}]-(:label3{id:3})<-[:type1{id:2}]-(:label2{id:2})<-[:type1{id:1}]-(:label1{id:1})> | 6 |
Scenario: Test match wShortest with accumulated path filtered by edge type1 Scenario: Test match wShortest with accumulated path filtered by edge type1
Given graph "graph_edges" Given graph "graph_edges"
When executing query: When executing query:

View File

@@ -1,2 +1,3 @@
CREATE (:label1 {id: 1})-[:type1 {id:1}]->(:label2 {id: 2})-[:type1 {id: 2}]->(:label3 {id: 3})-[:type1 {id: 3}]->(:label4 {id: 4}); CREATE (:label1 {id: 1})-[:type1 {id:1}]->(:label2 {id: 2})-[:type1 {id: 2}]->(:label3 {id: 3})-[:type1 {id: 3}]->(:label4 {id: 4});
MATCH (n :label1), (m :label3) CREATE (n)-[:type2 {id: 10}]->(m); MATCH (n :label1), (m :label3) CREATE (n)-[:type2 {id: 10}]->(m);
MATCH (n :label1) CREATE (n)-[:type3 {id: 20}]->(:label5 { id: 5 });

View File

@@ -24,7 +24,7 @@ PRINT_CONTEXT() {
HELP_EXIT() { HELP_EXIT() {
echo "" echo ""
echo "HELP: $0 help|cluster-up|cluster-cleanup|cluster-dealloc|mgbuild|test|test-all-individually [args]" echo "HELP: $0 help|cluster-up|cluster-refresh|cluster-cleanup|cluster-dealloc|mgbuild|test|test-all-individually [args]"
echo "" echo ""
echo " test args --binary MEMGRAPH_BINARY_PATH" echo " test args --binary MEMGRAPH_BINARY_PATH"
echo " --ignore-run-stdout-logs Ignore lein run stdout logs." echo " --ignore-run-stdout-logs Ignore lein run stdout logs."
@@ -184,35 +184,21 @@ PROCESS_RESULTS() {
INFO "Result processing (printing and packing) DONE." INFO "Result processing (printing and packing) DONE."
} }
# Initialize testing context by copying source/binary files. Inside CI, CLUSTER_UP() {
# Memgraph is tested on a single machine cluster based on Docker containers.
# Once these tests will be part of the official Jepsen repo, the majority of
# functionalities inside this script won't be needed because each node clones
# the public repo.
case $1 in
# Start Jepsen Docker cluster of 5 nodes. To configure the cluster please
# take a look under jepsen/docker/docker-compose.yml.
# NOTE: If you delete the jepsen folder where docker config is located,
# the current cluster is broken because it relies on the folder. That can
# happen easiliy because the jepsen folder is git ignored.
cluster-up)
PRINT_CONTEXT PRINT_CONTEXT
"$script_dir/jepsen/docker/bin/up" --daemon "$script_dir/jepsen/docker/bin/up" --daemon
;; sleep 10
# Ensure all SSH connections between Jepsen containers work
cluster-cleanup) for node in $(docker ps --filter name=jepsen* --filter status=running --format "{{.Names}}"); do
jepsen_control_exec="docker exec jepsen-control bash -c" if [ "$node" == "jepsen-control" ]; then
INFO "Deleting /jepsen/memgraph/store/* on jepsen-control" continue
$jepsen_control_exec "rm -rf /jepsen/memgraph/store/*" fi
for iter in $(seq 1 "$JEPSEN_ACTIVE_NODES_NO"); do node_hostname="${node##jepsen-}"
jepsen_node_name="jepsen-n$iter" docker exec jepsen-control bash -c "ssh -oStrictHostKeyChecking=no -t $node_hostname exit"
jepsen_node_exec="docker exec $jepsen_node_name bash -c"
INFO "Deleting /opt/memgraph/* on $jepsen_node_name"
$jepsen_node_exec "rm -rf /opt/memgraph/*"
done done
;; }
cluster-dealloc) CLUSTER_DEALLOC() {
ps=$(docker ps --filter name=jepsen* --filter status=running -q) ps=$(docker ps --filter name=jepsen* --filter status=running -q)
if [[ ! -z ${ps} ]]; then if [[ ! -z ${ps} ]]; then
echo "Killing ${ps}" echo "Killing ${ps}"
@@ -227,6 +213,42 @@ case $1 in
else else
echo "No Jepsen containers detected!" echo "No Jepsen containers detected!"
fi fi
}
# Initialize testing context by copying source/binary files. Inside CI,
# Memgraph is tested on a single machine cluster based on Docker containers.
# Once these tests will be part of the official Jepsen repo, the majority of
# functionalities inside this script won't be needed because each node clones
# the public repo.
case $1 in
# Start Jepsen Docker cluster of 5 nodes. To configure the cluster please
# take a look under jepsen/docker/docker-compose.yml.
# NOTE: If you delete the jepsen folder where docker config is located,
# the current cluster is broken because it relies on the folder. That can
# happen easiliy because the jepsen folder is git ignored.
cluster-up)
CLUSTER_UP
;;
cluster-refresh)
CLUSTER_DEALLOC
CLUSTER_UP
;;
cluster-dealloc)
CLUSTER_DEALLOC
;;
cluster-cleanup)
jepsen_control_exec="docker exec jepsen-control bash -c"
INFO "Deleting /jepsen/memgraph/store/* on jepsen-control"
$jepsen_control_exec "rm -rf /jepsen/memgraph/store/*"
for iter in $(seq 1 "$JEPSEN_ACTIVE_NODES_NO"); do
jepsen_node_name="jepsen-n$iter"
jepsen_node_exec="docker exec $jepsen_node_name bash -c"
INFO "Deleting /opt/memgraph/* on $jepsen_node_name"
$jepsen_node_exec "rm -rf /opt/memgraph/*"
done
;; ;;
mgbuild) mgbuild)