Compare commits
17 Commits
fix-pulsar
...
T1312-MG-C
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f560fe602 | ||
|
|
c3067d3640 | ||
|
|
a40b18b8aa | ||
|
|
422f9199bd | ||
|
|
89585fad1c | ||
|
|
8feefc20b7 | ||
|
|
646818a0b4 | ||
|
|
2f4156c2c9 | ||
|
|
61d301310a | ||
|
|
73a554a617 | ||
|
|
bc34a0add6 | ||
|
|
af4abd4db0 | ||
|
|
f806419b1d | ||
|
|
8e3be813ac | ||
|
|
b850a66afd | ||
|
|
96dcfae63e | ||
|
|
1b6a73a021 |
18
.github/ISSUE_TEMPLATE/bug_report.md
vendored
18
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,18 +1,19 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ""
|
||||
title: "[BUG] "
|
||||
labels: bug
|
||||
assignees: gitbuda
|
||||
assignees: gitbuda, antonio2368
|
||||
|
||||
---
|
||||
|
||||
|
||||
**Memgraph version**
|
||||
Which version did you use?
|
||||
|
||||
**Environment**
|
||||
Some information about the environment you are using Memgraph on: operating
|
||||
system, architecture (ARM, x86), how do you connect, with or without docker,
|
||||
which driver etc.
|
||||
system, how do you connect, with or without docker, which driver etc.
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
@@ -21,7 +22,6 @@ A clear and concise description of what the bug is.
|
||||
Steps to reproduce the behavior:
|
||||
1. Run the following query '...'
|
||||
2. Click on '....'
|
||||
3. ... IDEALLY: link to the workload info (DATASET & QUERIES) ...
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
@@ -32,11 +32,3 @@ your problem.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
|
||||
**Verification Environment**
|
||||
Once we fix it, what do you need to verify the fix?
|
||||
Do you need:
|
||||
* Plain memgraph package -> for which Linux?
|
||||
* Plain memgraph Docker image?
|
||||
* Which architecture do you use ARM | x86?
|
||||
* Full Memgraph platform?
|
||||
|
||||
16
.github/workflows/daily_benchmark.yaml
vendored
16
.github/workflows/daily_benchmark.yaml
vendored
@@ -59,7 +59,7 @@ jobs:
|
||||
source ve3/bin/activate
|
||||
pip install -r requirements.txt
|
||||
./main.py --benchmark-name "macro_benchmark" \
|
||||
--benchmark-results "../../tests/macro_benchmark/.harness_summary" \
|
||||
--benchmark-results-path "../../tests/macro_benchmark/.harness_summary" \
|
||||
--github-run-id "${{ github.run_id }}" \
|
||||
--github-run-number "${{ github.run_number }}" \
|
||||
--head-branch-name "${{ env.BRANCH_NAME }}"
|
||||
@@ -73,8 +73,6 @@ jobs:
|
||||
|
||||
./benchmark.py vendor-native --num-workers-for-benchmark 1 --export-results benchmark_high_write_set_property.json high_write_set_property
|
||||
|
||||
./benchmark.py vendor-native --num-workers-for-benchmark 12 --export-results cartesian.json cartesian
|
||||
|
||||
- name: Upload mgbench results
|
||||
run: |
|
||||
cd tools/bench-graph-client
|
||||
@@ -82,25 +80,19 @@ jobs:
|
||||
source ve3/bin/activate
|
||||
pip install -r requirements.txt
|
||||
./main.py --benchmark-name "mgbench" \
|
||||
--benchmark-results "../../tests/mgbench/benchmark_pokec.json" \
|
||||
--benchmark-results-path "../../tests/mgbench/benchmark_pokec.json" \
|
||||
--github-run-id "${{ github.run_id }}" \
|
||||
--github-run-number "${{ github.run_number }}" \
|
||||
--head-branch-name "${{ env.BRANCH_NAME }}"
|
||||
|
||||
./main.py --benchmark-name "supernode" \
|
||||
--benchmark-results "../../tests/mgbench/benchmark_supernode.json" \
|
||||
--benchmark-results-path "../../tests/mgbench/benchmark_supernode.json" \
|
||||
--github-run-id "${{ github.run_id }}" \
|
||||
--github-run-number "${{ github.run_number }}" \
|
||||
--head-branch-name "${{ env.BRANCH_NAME }}"
|
||||
|
||||
./main.py --benchmark-name "high_write_set_property" \
|
||||
--benchmark-results "../../tests/mgbench/benchmark_high_write_set_property.json" \
|
||||
--github-run-id "${{ github.run_id }}" \
|
||||
--github-run-number "${{ github.run_number }}" \
|
||||
--head-branch-name "${{ env.BRANCH_NAME }}"
|
||||
|
||||
./main.py --benchmark-name "cartesian" \
|
||||
--benchmark-results "../../tests/mgbench/cartesian.json" \
|
||||
--benchmark-results-path "../../tests/mgbench/benchmark_high_write_set_property.json" \
|
||||
--github-run-id "${{ github.run_id }}" \
|
||||
--github-run-number "${{ github.run_number }}" \
|
||||
--head-branch-name "${{ env.BRANCH_NAME }}"
|
||||
|
||||
316
.github/workflows/diff.yaml
vendored
316
.github/workflows/diff.yaml
vendored
@@ -17,9 +17,205 @@ on:
|
||||
- "licenses/*"
|
||||
|
||||
jobs:
|
||||
community_build:
|
||||
name: "Community build"
|
||||
runs-on: [self-hosted, Linux, X64, Diff]
|
||||
env:
|
||||
THREADS: 24
|
||||
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
||||
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
|
||||
|
||||
steps:
|
||||
- name: Set up repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# Number of commits to fetch. `0` indicates all history for all
|
||||
# branches and tags. (default: 1)
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Build community binaries
|
||||
run: |
|
||||
# Activate toolchain.
|
||||
source /opt/toolchain-v4/activate
|
||||
|
||||
# Initialize dependencies.
|
||||
./init
|
||||
|
||||
# Build community binaries.
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DMG_ENTERPRISE=OFF ..
|
||||
make -j$THREADS
|
||||
|
||||
- name: Run unit tests
|
||||
run: |
|
||||
# Activate toolchain.
|
||||
source /opt/toolchain-v4/activate
|
||||
|
||||
# Run unit tests.
|
||||
cd build
|
||||
ctest -R memgraph__unit --output-on-failure -j$THREADS
|
||||
|
||||
code_analysis:
|
||||
name: "Code analysis"
|
||||
runs-on: [self-hosted, Linux, X64, Diff]
|
||||
env:
|
||||
THREADS: 24
|
||||
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
||||
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
|
||||
|
||||
steps:
|
||||
- name: Set up repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# Number of commits to fetch. `0` indicates all history for all
|
||||
# branches and tags. (default: 1)
|
||||
fetch-depth: 0
|
||||
|
||||
# This is also needed if we want do to comparison against other branches
|
||||
# See https://github.community/t/checkout-code-fails-when-it-runs-lerna-run-test-since-master/17920
|
||||
- name: Fetch all history for all tags and branches
|
||||
run: git fetch
|
||||
|
||||
- name: Initialize deps
|
||||
run: |
|
||||
# Activate toolchain.
|
||||
source /opt/toolchain-v4/activate
|
||||
|
||||
# Initialize dependencies.
|
||||
./init
|
||||
|
||||
- name: Set base branch
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
run: |
|
||||
echo "BASE_BRANCH=origin/${{ github.base_ref }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Set base branch # if we manually dispatch or push to master
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
run: |
|
||||
echo "BASE_BRANCH=origin/master" >> $GITHUB_ENV
|
||||
|
||||
- name: Python code analysis
|
||||
run: |
|
||||
CHANGED_FILES=$(git diff -U0 ${{ env.BASE_BRANCH }}... --name-only)
|
||||
for file in ${CHANGED_FILES}; do
|
||||
echo ${file}
|
||||
if [[ ${file} == *.py ]]; then
|
||||
python3 -m black --check --diff ${file}
|
||||
python3 -m isort --profile black --check-only --diff ${file}
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Build combined ASAN, UBSAN and coverage binaries
|
||||
run: |
|
||||
# Activate toolchain.
|
||||
source /opt/toolchain-v4/activate
|
||||
|
||||
cd build
|
||||
cmake -DTEST_COVERAGE=ON -DASAN=ON -DUBSAN=ON ..
|
||||
make -j$THREADS memgraph__unit
|
||||
|
||||
- name: Run unit tests
|
||||
run: |
|
||||
# Activate toolchain.
|
||||
source /opt/toolchain-v4/activate
|
||||
|
||||
# Run unit tests. It is restricted to 2 threads intentionally, because higher concurrency makes the timing related tests unstable.
|
||||
cd build
|
||||
LSAN_OPTIONS=suppressions=$PWD/../tools/lsan.supp UBSAN_OPTIONS=halt_on_error=1 ctest -R memgraph__unit --output-on-failure -j2
|
||||
|
||||
- name: Compute code coverage
|
||||
run: |
|
||||
# Activate toolchain.
|
||||
source /opt/toolchain-v4/activate
|
||||
|
||||
# Compute code coverage.
|
||||
cd tools/github
|
||||
./coverage_convert
|
||||
|
||||
# Package code coverage.
|
||||
cd generated
|
||||
tar -czf code_coverage.tar.gz coverage.json html report.json summary.rmu
|
||||
|
||||
- name: Save code coverage
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: "Code coverage"
|
||||
path: tools/github/generated/code_coverage.tar.gz
|
||||
|
||||
- name: Run clang-tidy
|
||||
run: |
|
||||
source /opt/toolchain-v4/activate
|
||||
|
||||
# Restrict clang-tidy results only to the modified parts
|
||||
git diff -U0 ${{ env.BASE_BRANCH }}... -- src | ./tools/github/clang-tidy/clang-tidy-diff.py -p 1 -j $THREADS -path build -regex ".+\.cpp" | tee ./build/clang_tidy_output.txt
|
||||
|
||||
# Fail if any warning is reported
|
||||
! cat ./build/clang_tidy_output.txt | ./tools/github/clang-tidy/grep_error_lines.sh > /dev/null
|
||||
|
||||
debug_build:
|
||||
name: "Debug build"
|
||||
runs-on: [self-hosted, Linux, X64, Diff]
|
||||
env:
|
||||
THREADS: 24
|
||||
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
||||
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
|
||||
|
||||
steps:
|
||||
- name: Set up repository
|
||||
uses: actions/checkout@v3
|
||||
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 leftover CTest tests
|
||||
run: |
|
||||
# Activate toolchain.
|
||||
source /opt/toolchain-v4/activate
|
||||
|
||||
# Run leftover CTest tests (all except unit and benchmark tests).
|
||||
cd build
|
||||
ctest -E "(memgraph__unit|memgraph__benchmark)" --output-on-failure
|
||||
|
||||
- name: Run drivers tests
|
||||
run: |
|
||||
./tests/drivers/run.sh
|
||||
|
||||
- name: Run integration tests
|
||||
run: |
|
||||
tests/integration/run.sh
|
||||
|
||||
- name: Run cppcheck and clang-format
|
||||
run: |
|
||||
# Activate toolchain.
|
||||
source /opt/toolchain-v4/activate
|
||||
|
||||
# Run cppcheck and clang-format.
|
||||
cd tools/github
|
||||
./cppcheck_and_clang_format diff
|
||||
|
||||
- name: Save cppcheck and clang-format errors
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: "Code coverage"
|
||||
path: tools/github/cppcheck_and_clang_format.txt
|
||||
|
||||
release_build:
|
||||
name: "Release build"
|
||||
runs-on: [self-hosted, Linux, X64, gamora]
|
||||
runs-on: [self-hosted, Linux, X64, Diff]
|
||||
env:
|
||||
THREADS: 24
|
||||
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
||||
@@ -48,7 +244,7 @@ jobs:
|
||||
|
||||
# Build release binaries.
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
|
||||
make -j$THREADS
|
||||
|
||||
- name: Run GQL Behave tests
|
||||
@@ -129,3 +325,119 @@ jobs:
|
||||
path: |
|
||||
# multiple paths could be defined
|
||||
build/logs
|
||||
|
||||
release_jepsen_test:
|
||||
name: "Release Jepsen Test"
|
||||
runs-on: [self-hosted, Linux, X64, Debian10, JepsenControl]
|
||||
#continue-on-error: true
|
||||
env:
|
||||
THREADS: 24
|
||||
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
||||
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
|
||||
|
||||
steps:
|
||||
- name: Set up repository
|
||||
uses: actions/checkout@v3
|
||||
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 only memgraph release binarie.
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
|
||||
make -j$THREADS memgraph
|
||||
|
||||
- name: Run Jepsen tests
|
||||
run: |
|
||||
cd tests/jepsen
|
||||
./run.sh test-all-individually --binary ../../build/memgraph --ignore-run-stdout-logs --ignore-run-stderr-logs
|
||||
|
||||
- name: Save Jepsen report
|
||||
uses: actions/upload-artifact@v3
|
||||
if: ${{ always() }}
|
||||
with:
|
||||
name: "Jepsen Report"
|
||||
path: tests/jepsen/Jepsen.tar.gz
|
||||
|
||||
release_benchmarks:
|
||||
name: "Release benchmarks"
|
||||
runs-on: [self-hosted, Linux, X64, Diff, Gen7]
|
||||
env:
|
||||
THREADS: 24
|
||||
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
||||
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
|
||||
|
||||
steps:
|
||||
- name: Set up repository
|
||||
uses: actions/checkout@v3
|
||||
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 only memgraph release binaries.
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=release ..
|
||||
make -j$THREADS
|
||||
|
||||
- name: Run macro benchmarks
|
||||
run: |
|
||||
cd tests/macro_benchmark
|
||||
./harness QuerySuite MemgraphRunner \
|
||||
--groups aggregation 1000_create unwind_create dense_expand match \
|
||||
--no-strict
|
||||
|
||||
- name: Get branch name (merge)
|
||||
if: github.event_name != 'pull_request'
|
||||
shell: bash
|
||||
run: echo "BRANCH_NAME=$(echo ${GITHUB_REF#refs/heads/} | tr / -)" >> $GITHUB_ENV
|
||||
|
||||
- name: Get branch name (pull request)
|
||||
if: github.event_name == 'pull_request'
|
||||
shell: bash
|
||||
run: echo "BRANCH_NAME=$(echo ${GITHUB_HEAD_REF} | tr / -)" >> $GITHUB_ENV
|
||||
|
||||
- name: Upload macro benchmark results
|
||||
run: |
|
||||
cd tools/bench-graph-client
|
||||
virtualenv -p python3 ve3
|
||||
source ve3/bin/activate
|
||||
pip install -r requirements.txt
|
||||
./main.py --benchmark-name "macro_benchmark" \
|
||||
--benchmark-results "../../tests/macro_benchmark/.harness_summary" \
|
||||
--github-run-id "${{ github.run_id }}" \
|
||||
--github-run-number "${{ github.run_number }}" \
|
||||
--head-branch-name "${{ env.BRANCH_NAME }}"
|
||||
|
||||
# TODO (andi) No need for path flags and for --disk-storage and --in-memory-analytical
|
||||
- name: Run mgbench
|
||||
run: |
|
||||
cd tests/mgbench
|
||||
./benchmark.py vendor-native --num-workers-for-benchmark 12 --export-results benchmark_result.json pokec/medium/*/*
|
||||
|
||||
- name: Upload mgbench results
|
||||
run: |
|
||||
cd tools/bench-graph-client
|
||||
virtualenv -p python3 ve3
|
||||
source ve3/bin/activate
|
||||
pip install -r requirements.txt
|
||||
./main.py --benchmark-name "mgbench" \
|
||||
--benchmark-results "../../tests/mgbench/benchmark_result.json" \
|
||||
--github-run-id "${{ github.run_id }}" \
|
||||
--github-run-number "${{ github.run_number }}" \
|
||||
--head-branch-name "${{ env.BRANCH_NAME }}"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Package memgraph
|
||||
name: Package All
|
||||
|
||||
# TODO(gitbuda): Cleanup docker container if GHA job was canceled.
|
||||
|
||||
@@ -6,56 +6,18 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
memgraph_version:
|
||||
description: "Memgraph version to upload as. Leave this field empty if you don't want to upload binaries to S3. Format: 'X.Y.Z'"
|
||||
description: "Memgraph version to upload as. If empty upload is skipped. Format: 'X.Y.Z'"
|
||||
required: false
|
||||
build_type:
|
||||
type: choice
|
||||
description: "Memgraph Build type. Default value is Release"
|
||||
description: "Memgraph Build type. Default value is Release."
|
||||
default: 'Release'
|
||||
options:
|
||||
- Release
|
||||
- RelWithDebInfo
|
||||
target_os:
|
||||
type: choice
|
||||
description: "Target OS for which memgraph will be packaged. Select 'all' if you want to package for every listed OS. Default is Ubuntu 22.04"
|
||||
default: 'ubuntu-22_04'
|
||||
options:
|
||||
- all
|
||||
- amzn-2
|
||||
- centos-7
|
||||
- centos-9
|
||||
- debian-10
|
||||
- debian-11
|
||||
- debian-11-arm
|
||||
- debian-11-platform
|
||||
- docker
|
||||
- fedora-36
|
||||
- ubuntu-18_04
|
||||
- ubuntu-20_04
|
||||
- ubuntu-22_04
|
||||
- ubuntu-22_04-arm
|
||||
|
||||
jobs:
|
||||
amzn-2:
|
||||
if: ${{ github.event.inputs.target_os == 'amzn-2' || github.event.inputs.target_os == 'all' }}
|
||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- name: "Set up repository"
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # Required because of release/get_version.py
|
||||
- name: "Build package"
|
||||
run: |
|
||||
./release/package/run.sh package amzn-2 ${{ github.event.inputs.build_type }}
|
||||
- name: "Upload package"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: amzn-2
|
||||
path: build/output/amzn-2/memgraph*.rpm
|
||||
|
||||
centos-7:
|
||||
if: ${{ github.event.inputs.target_os == 'centos-7' || github.event.inputs.target_os == 'all' }}
|
||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
@@ -73,7 +35,6 @@ jobs:
|
||||
path: build/output/centos-7/memgraph*.rpm
|
||||
|
||||
centos-9:
|
||||
if: ${{ github.event.inputs.target_os == 'centos-9' || github.event.inputs.target_os == 'all' }}
|
||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
@@ -91,7 +52,6 @@ jobs:
|
||||
path: build/output/centos-9/memgraph*.rpm
|
||||
|
||||
debian-10:
|
||||
if: ${{ github.event.inputs.target_os == 'debian-10' || github.event.inputs.target_os == 'all' }}
|
||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
@@ -109,7 +69,6 @@ jobs:
|
||||
path: build/output/debian-10/memgraph*.deb
|
||||
|
||||
debian-11:
|
||||
if: ${{ github.event.inputs.target_os == 'debian-11' || github.event.inputs.target_os == 'all' }}
|
||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
@@ -126,44 +85,7 @@ jobs:
|
||||
name: debian-11
|
||||
path: build/output/debian-11/memgraph*.deb
|
||||
|
||||
debian-11-arm:
|
||||
if: ${{ github.event.inputs.target_os == 'debian-11-arm' || github.event.inputs.target_os == 'all' }}
|
||||
runs-on: [self-hosted, DockerMgBuild, ARM64, strange]
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
- name: "Set up repository"
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # Required because of release/get_version.py
|
||||
- name: "Build package"
|
||||
run: |
|
||||
./release/package/run.sh package debian-11-arm ${{ github.event.inputs.build_type }}
|
||||
- name: "Upload package"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: debian-11-aarch64
|
||||
path: build/output/debian-11-arm/memgraph*.deb
|
||||
|
||||
debian-11-platform:
|
||||
if: ${{ github.event.inputs.target_os == 'debian-11-platform' || github.event.inputs.target_os == 'all' }}
|
||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- name: "Set up repository"
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # Required because of release/get_version.py
|
||||
- name: "Build package"
|
||||
run: |
|
||||
./release/package/run.sh package debian-11 ${{ github.event.inputs.build_type }} --for-platform
|
||||
- name: "Upload package"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: debian-11-platform
|
||||
path: build/output/debian-11/memgraph*.deb
|
||||
|
||||
docker:
|
||||
if: ${{ github.event.inputs.target_os == 'docker' || github.event.inputs.target_os == 'all' }}
|
||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
@@ -182,26 +104,7 @@ jobs:
|
||||
name: docker
|
||||
path: build/output/docker/memgraph*.tar.gz
|
||||
|
||||
fedora-36:
|
||||
if: ${{ github.event.inputs.target_os == 'fedora-36' || github.event.inputs.target_os == 'all' }}
|
||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- name: "Set up repository"
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # Required because of release/get_version.py
|
||||
- name: "Build package"
|
||||
run: |
|
||||
./release/package/run.sh package fedora-36 ${{ github.event.inputs.build_type }}
|
||||
- name: "Upload package"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: fedora-36
|
||||
path: build/output/fedora-36/memgraph*.rpm
|
||||
|
||||
ubuntu-18_04:
|
||||
if: ${{ github.event.inputs.target_os == 'ubuntu-18_04' || github.event.inputs.target_os == 'all' }}
|
||||
ubuntu-1804:
|
||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
@@ -218,8 +121,7 @@ jobs:
|
||||
name: ubuntu-18.04
|
||||
path: build/output/ubuntu-18.04/memgraph*.deb
|
||||
|
||||
ubuntu-20_04:
|
||||
if: ${{ github.event.inputs.target_os == 'ubuntu-20_04' || github.event.inputs.target_os == 'all' }}
|
||||
ubuntu-2004:
|
||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
@@ -236,8 +138,7 @@ jobs:
|
||||
name: ubuntu-20.04
|
||||
path: build/output/ubuntu-20.04/memgraph*.deb
|
||||
|
||||
ubuntu-22_04:
|
||||
if: ${{ github.event.inputs.target_os == 'ubuntu-22_04' || github.event.inputs.target_os == 'all' }}
|
||||
ubuntu-2204:
|
||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
@@ -254,8 +155,75 @@ jobs:
|
||||
name: ubuntu-22.04
|
||||
path: build/output/ubuntu-22.04/memgraph*.deb
|
||||
|
||||
ubuntu-22_04-arm:
|
||||
if: ${{ github.event.inputs.target_os == 'ubuntu-22_04-arm' || github.event.inputs.target_os == 'all' }}
|
||||
debian-11-platform:
|
||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- name: "Set up repository"
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # Required because of release/get_version.py
|
||||
- name: "Build package"
|
||||
run: |
|
||||
./release/package/run.sh package debian-11 ${{ github.event.inputs.build_type }} --for-platform
|
||||
- name: "Upload package"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: debian-11-platform
|
||||
path: build/output/debian-11/memgraph*.deb
|
||||
|
||||
fedora-36:
|
||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- name: "Set up repository"
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # Required because of release/get_version.py
|
||||
- name: "Build package"
|
||||
run: |
|
||||
./release/package/run.sh package fedora-36 ${{ github.event.inputs.build_type }}
|
||||
- name: "Upload package"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: fedora-36
|
||||
path: build/output/fedora-36/memgraph*.rpm
|
||||
|
||||
amzn-2:
|
||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- name: "Set up repository"
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # Required because of release/get_version.py
|
||||
- name: "Build package"
|
||||
run: |
|
||||
./release/package/run.sh package amzn-2 ${{ github.event.inputs.build_type }}
|
||||
- name: "Upload package"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: amzn-2
|
||||
path: build/output/amzn-2/memgraph*.rpm
|
||||
|
||||
debian-11-arm:
|
||||
runs-on: [self-hosted, DockerMgBuild, ARM64, strange]
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
- name: "Set up repository"
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # Required because of release/get_version.py
|
||||
- name: "Build package"
|
||||
run: |
|
||||
./release/package/run.sh package debian-11-arm ${{ github.event.inputs.build_type }}
|
||||
- name: "Upload package"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: debian-11-aarch64
|
||||
path: build/output/debian-11-arm/memgraph*.deb
|
||||
|
||||
ubuntu-2204-arm:
|
||||
runs-on: [self-hosted, DockerMgBuild, ARM64, strange]
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
@@ -275,7 +243,7 @@ jobs:
|
||||
upload-to-s3:
|
||||
# only run upload if we specified version. Allows for runs without upload
|
||||
if: "${{ github.event.inputs.memgraph_version != '' }}"
|
||||
needs: [amzn-2, centos-7, centos-9, debian-10, debian-11, debian-11-arm, debian-11-platform, docker, fedora-36, ubuntu-18_04, ubuntu-20_04, ubuntu-22_04, ubuntu-22_04-arm]
|
||||
needs: [centos-7, centos-9, debian-10, debian-11, docker, ubuntu-1804, ubuntu-2004, ubuntu-2204, debian-11-platform, fedora-36, amzn-2, debian-11-arm, ubuntu-2204-arm]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
14
.github/workflows/performance_benchmarks.yaml
vendored
14
.github/workflows/performance_benchmarks.yaml
vendored
@@ -52,8 +52,6 @@ jobs:
|
||||
|
||||
./benchmark.py vendor-native --num-workers-for-benchmark 1 --export-results benchmark_high_write_set_property.json high_write_set_property
|
||||
|
||||
./benchmark.py vendor-native --num-workers-for-benchmark 12 --export-results benchmark_cartesian.json cartesian
|
||||
|
||||
- name: Upload benchmark results
|
||||
run: |
|
||||
cd tools/bench-graph-client
|
||||
@@ -61,25 +59,19 @@ jobs:
|
||||
source ve3/bin/activate
|
||||
pip install -r requirements.txt
|
||||
./main.py --benchmark-name "mgbench" \
|
||||
--benchmark-results "../../tests/mgbench/benchmark_result.json" \
|
||||
--benchmark-results-path "../../tests/mgbench/benchmark_result.json" \
|
||||
--github-run-id "${{ github.run_id }}" \
|
||||
--github-run-number "${{ github.run_number }}" \
|
||||
--head-branch-name "${{ env.BRANCH_NAME }}"
|
||||
|
||||
./main.py --benchmark-name "supernode" \
|
||||
--benchmark-results "../../tests/mgbench/benchmark_supernode.json" \
|
||||
--benchmark-results-path "../../tests/mgbench/benchmark_supernode.json" \
|
||||
--github-run-id "${{ github.run_id }}" \
|
||||
--github-run-number "${{ github.run_number }}" \
|
||||
--head-branch-name "${{ env.BRANCH_NAME }}"
|
||||
|
||||
./main.py --benchmark-name "high_write_set_property" \
|
||||
--benchmark-results "../../tests/mgbench/benchmark_high_write_set_property.json" \
|
||||
--github-run-id "${{ github.run_id }}" \
|
||||
--github-run-number "${{ github.run_number }}" \
|
||||
--head-branch-name "${{ env.BRANCH_NAME }}"
|
||||
|
||||
./main.py --benchmark-name "cartesian" \
|
||||
--benchmark-results "../../tests/mgbench/cartesian.json" \
|
||||
--benchmark-results-path "../../tests/mgbench/benchmark_high_write_set_property.json" \
|
||||
--github-run-id "${{ github.run_id }}" \
|
||||
--github-run-number "${{ github.run_number }}" \
|
||||
--head-branch-name "${{ env.BRANCH_NAME }}"
|
||||
|
||||
16
.github/workflows/release_centos8.yaml
vendored
16
.github/workflows/release_centos8.yaml
vendored
@@ -40,13 +40,9 @@ jobs:
|
||||
# Initialize dependencies.
|
||||
./init
|
||||
|
||||
# Set default build_type to Release
|
||||
INPUT_BUILD_TYPE=${{ github.event.inputs.build_type }}
|
||||
BUILD_TYPE=${INPUT_BUILD_TYPE:-"Release"}
|
||||
|
||||
# Build community binaries.
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DMG_ENTERPRISE=OFF ..
|
||||
cmake -DCMAKE_BUILD_TYPE=${{ github.event.inputs.build_type }} -DMG_ENTERPRISE=OFF ..
|
||||
make -j$THREADS
|
||||
|
||||
- name: Run unit tests
|
||||
@@ -201,13 +197,9 @@ jobs:
|
||||
# Initialize dependencies.
|
||||
./init
|
||||
|
||||
# Set default build_type to Release
|
||||
INPUT_BUILD_TYPE=${{ github.event.inputs.build_type }}
|
||||
BUILD_TYPE=${INPUT_BUILD_TYPE:-"Release"}
|
||||
|
||||
# Build release binaries.
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
|
||||
cmake -DCMAKE_BUILD_TYPE=${{ github.event.inputs.build_type }} ..
|
||||
make -j$THREADS
|
||||
|
||||
- name: Create enterprise RPM package
|
||||
@@ -260,9 +252,7 @@ jobs:
|
||||
|
||||
- name: Run GQL Behave tests
|
||||
run: |
|
||||
cd tests
|
||||
./setup.sh /opt/toolchain-v4/activate
|
||||
cd gql_behave
|
||||
cd tests/gql_behave
|
||||
./continuous_integration
|
||||
|
||||
- name: Save quality assurance status
|
||||
|
||||
25
.github/workflows/release_debian10.yaml
vendored
25
.github/workflows/release_debian10.yaml
vendored
@@ -40,13 +40,9 @@ jobs:
|
||||
# Initialize dependencies.
|
||||
./init
|
||||
|
||||
# Set default build_type to Release
|
||||
INPUT_BUILD_TYPE=${{ github.event.inputs.build_type }}
|
||||
BUILD_TYPE=${INPUT_BUILD_TYPE:-"Release"}
|
||||
|
||||
# Build community binaries.
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DMG_ENTERPRISE=OFF ..
|
||||
cmake -DCMAKE_BUILD_TYPE=${{ github.event.inputs.build_type }} -DMG_ENTERPRISE=OFF ..
|
||||
make -j$THREADS
|
||||
|
||||
- name: Run unit tests
|
||||
@@ -178,7 +174,7 @@ jobs:
|
||||
|
||||
release_build:
|
||||
name: "Release build"
|
||||
runs-on: [self-hosted, Linux, X64, Debian10, BigMemory]
|
||||
runs-on: [self-hosted, Linux, X64, Debian10]
|
||||
env:
|
||||
THREADS: 24
|
||||
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
||||
@@ -201,13 +197,9 @@ jobs:
|
||||
# Initialize dependencies.
|
||||
./init
|
||||
|
||||
# Set default build_type to Release
|
||||
INPUT_BUILD_TYPE=${{ github.event.inputs.build_type }}
|
||||
BUILD_TYPE=${INPUT_BUILD_TYPE:-"Release"}
|
||||
|
||||
# Build release binaries.
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
|
||||
cmake -DCMAKE_BUILD_TYPE=${{ github.event.inputs.build_type }} ..
|
||||
make -j$THREADS
|
||||
|
||||
- name: Create enterprise DEB package
|
||||
@@ -259,9 +251,7 @@ jobs:
|
||||
|
||||
- name: Run GQL Behave tests
|
||||
run: |
|
||||
cd tests
|
||||
./setup.sh /opt/toolchain-v4/activate
|
||||
cd gql_behave
|
||||
cd tests/gql_behave
|
||||
./continuous_integration
|
||||
|
||||
- name: Save quality assurance status
|
||||
@@ -339,14 +329,9 @@ jobs:
|
||||
source /opt/toolchain-v4/activate
|
||||
# Initialize dependencies.
|
||||
./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.
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
|
||||
cmake -DCMAKE_BUILD_TYPE=${{ github.event.inputs.build_type }} ..
|
||||
make -j$THREADS memgraph
|
||||
|
||||
- name: Run Jepsen tests
|
||||
|
||||
16
.github/workflows/release_ubuntu2004.yaml
vendored
16
.github/workflows/release_ubuntu2004.yaml
vendored
@@ -40,13 +40,9 @@ jobs:
|
||||
# Initialize dependencies.
|
||||
./init
|
||||
|
||||
# Set default build_type to Release
|
||||
INPUT_BUILD_TYPE=${{ github.event.inputs.build_type }}
|
||||
BUILD_TYPE=${INPUT_BUILD_TYPE:-"Release"}
|
||||
|
||||
# Build community binaries.
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DMG_ENTERPRISE=OFF ..
|
||||
cmake -DCMAKE_BUILD_TYPE=${{ github.event.inputs.build_type }} -DMG_ENTERPRISE=OFF ..
|
||||
make -j$THREADS
|
||||
|
||||
- name: Run unit tests
|
||||
@@ -201,13 +197,9 @@ jobs:
|
||||
# Initialize dependencies.
|
||||
./init
|
||||
|
||||
# Set default build_type to Release
|
||||
INPUT_BUILD_TYPE=${{ github.event.inputs.build_type }}
|
||||
BUILD_TYPE=${INPUT_BUILD_TYPE:-"Release"}
|
||||
|
||||
# Build release binaries.
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
|
||||
cmake -DCMAKE_BUILD_TYPE=${{ github.event.inputs.build_type }} ..
|
||||
make -j$THREADS
|
||||
|
||||
- name: Create enterprise DEB package
|
||||
@@ -259,9 +251,7 @@ jobs:
|
||||
|
||||
- name: Run GQL Behave tests
|
||||
run: |
|
||||
cd tests
|
||||
./setup.sh /opt/toolchain-v4/activate
|
||||
cd gql_behave
|
||||
cd tests/gql_behave
|
||||
./continuous_integration
|
||||
|
||||
- name: Save quality assurance status
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -60,5 +60,3 @@ src/storage/distributed/rpc/concurrent_id_mapper_rpc_messages.hpp
|
||||
src/transactions/distributed/engine_rpc_messages.hpp
|
||||
/tests/manual/js/transaction_timeout/package-lock.json
|
||||
/tests/manual/js/transaction_timeout/node_modules/
|
||||
.vscode/
|
||||
src/query/frontend/opencypher/grammar/.antlr/*
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
# Path to sources
|
||||
sonar.sources = .
|
||||
# sonar.exclusions=
|
||||
sonar.inclusions=src,include,query_modules
|
||||
|
||||
# Path to tests
|
||||
sonar.tests = tests/
|
||||
# sonar.test.exclusions=
|
||||
# sonar.test.inclusions=
|
||||
|
||||
# Source encoding
|
||||
# sonar.sourceEncoding=
|
||||
|
||||
# Exclusions for copy-paste detection
|
||||
# sonar.cpd.exclusions=
|
||||
|
||||
# Python version (for python projects only)
|
||||
# sonar.python.version=
|
||||
|
||||
# C++ standard version (for C++ projects only)
|
||||
# If not specified, it defaults to the latest supported standard
|
||||
# sonar.cfamily.reportingCppStandardOverride=c++98|c++11|c++14|c++17|c++20
|
||||
@@ -42,6 +42,10 @@ endif()
|
||||
|
||||
project(memgraph LANGUAGES C CXX)
|
||||
|
||||
# NOTE: once in a while this needs to be toggled to check headers are
|
||||
# correct and PCH isn't masking any include issues
|
||||
set(CMAKE_DISABLE_PRECOMPILE_HEADERS OFF)
|
||||
|
||||
#TODO: upgrade to cmake 3.24 + CheckIPOSupported
|
||||
#cmake_policy(SET CMP0138 NEW)
|
||||
#include(CheckIPOSupported)
|
||||
@@ -235,6 +239,7 @@ else()
|
||||
endif()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# default build type is debug
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Debug")
|
||||
@@ -292,7 +297,7 @@ if (MG_ENTERPRISE)
|
||||
add_definitions(-DMG_ENTERPRISE)
|
||||
endif()
|
||||
|
||||
option(ENABLE_JEMALLOC "Use jemalloc" ON)
|
||||
set(ENABLE_JEMALLOC ON)
|
||||
|
||||
if (ASAN)
|
||||
message(WARNING "Disabling jemalloc as it doesn't work well with ASAN")
|
||||
|
||||
29
README.md
29
README.md
@@ -141,20 +141,29 @@ guide](https://memgraph.com/docs/memgraph/reference-guide/configuration).
|
||||
|
||||
## :trophy: Contributing
|
||||
|
||||
Welcome to the heart of Memgraph development! We're on a mission to supercharge Memgraph, making it faster, more user-friendly, and even more powerful. We owe a big thanks to our fantastic community of contributors who help us fix bugs and bring incredible improvements to life. If you're passionate about databases and open source, here's your chance to make a difference!
|
||||
|
||||
### Explore Memgraph Internals
|
||||
|
||||
Interested in the nuts and bolts of Memgraph? Our [internals documentation](https://memgraph.notion.site/Memgraph-Internals-12b69132d67a417898972927d6870bd2) is where you can uncover the inner workings of Memgraph's architecture, learn how to build the project from scratch, and discover the secrets of effective contributions. Dive deep into the database!
|
||||
|
||||
### Dive into the Contributing Guide
|
||||
Ready to jump into the action? Explore our [contributing guide](CONTRIBUTING.md) to get the inside scoop on how we develop Memgraph. It's your roadmap for suggesting bug fixes and enhancements. Contribute your skills and ideas!
|
||||
The main purpose of this repository is to continue evolving Memgraph, making it
|
||||
faster and easier to use. Development of Memgraph happens in the open on GitHub,
|
||||
and we are grateful to the community for contributing bug fixes and
|
||||
improvements. Read below to learn how you can take part in improving Memgraph.
|
||||
|
||||
### Code of Conduct
|
||||
|
||||
Our commitment to a respectful and professional community is unwavering. Every participant in Memgraph is expected to adhere to a stringent Code of Conduct. Please carefully review [the complete text](CODE_OF_CONDUCT.md) to gain a comprehensive understanding of the behaviors that are both expected and explicitly prohibited.
|
||||
Memgraph has adopted a Code of Conduct that we expect project participants to
|
||||
adhere to. Please read [the full text](CODE_OF_CONDUCT.md) so that you can
|
||||
understand what actions will and will not be tolerated.
|
||||
|
||||
We maintain a zero-tolerance policy towards any violations. Our shared commitment to this Code of Conduct ensures that Memgraph remains a place where integrity and excellence are paramount.
|
||||
### Contributing Guide
|
||||
|
||||
Read our [contributing guide](CONTRIBUTING.md) to learn about our development
|
||||
process and how to propose bug fixes and improvements.
|
||||
|
||||
### Internals
|
||||
|
||||
Read our
|
||||
[internal](https://memgraph.notion.site/Memgraph-Internals-12b69132d67a417898972927d6870bd2)
|
||||
docs to learn more about Memgraph's architecture, how to build the project from
|
||||
source and how to start contributing. All information related to the database,
|
||||
can be found in the aforementioned docs.
|
||||
|
||||
### :scroll: License
|
||||
|
||||
|
||||
55
cmake/FindJemalloc.cmake
Normal file
55
cmake/FindJemalloc.cmake
Normal file
@@ -0,0 +1,55 @@
|
||||
# Try to find jemalloc library
|
||||
#
|
||||
# Use this module as:
|
||||
# find_package(Jemalloc)
|
||||
#
|
||||
# or:
|
||||
# find_package(Jemalloc REQUIRED)
|
||||
#
|
||||
# This will define the following variables:
|
||||
#
|
||||
# Jemalloc_FOUND True if the system has the jemalloc library.
|
||||
# Jemalloc_INCLUDE_DIRS Include directories needed to use jemalloc.
|
||||
# Jemalloc_LIBRARIES Libraries needed to link to jemalloc.
|
||||
#
|
||||
# The following cache variables may also be set:
|
||||
#
|
||||
# Jemalloc_INCLUDE_DIR The directory containing jemalloc/jemalloc.h.
|
||||
# Jemalloc_LIBRARY The path to the jemalloc static library.
|
||||
|
||||
find_path(Jemalloc_INCLUDE_DIR NAMES jemalloc/jemalloc.h PATH_SUFFIXES include)
|
||||
|
||||
find_library(Jemalloc_LIBRARY NAMES libjemalloc.a PATH_SUFFIXES lib)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Jemalloc
|
||||
FOUND_VAR Jemalloc_FOUND
|
||||
REQUIRED_VARS
|
||||
Jemalloc_LIBRARY
|
||||
Jemalloc_INCLUDE_DIR
|
||||
)
|
||||
|
||||
if(Jemalloc_FOUND)
|
||||
set(Jemalloc_LIBRARIES ${Jemalloc_LIBRARY})
|
||||
set(Jemalloc_INCLUDE_DIRS ${Jemalloc_INCLUDE_DIR})
|
||||
else()
|
||||
if(Jemalloc_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Cannot find jemalloc!")
|
||||
else()
|
||||
message(WARNING "jemalloc is not found!")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(Jemalloc_FOUND AND NOT TARGET Jemalloc::Jemalloc)
|
||||
add_library(Jemalloc::Jemalloc UNKNOWN IMPORTED)
|
||||
set_target_properties(Jemalloc::Jemalloc
|
||||
PROPERTIES
|
||||
IMPORTED_LOCATION "${Jemalloc_LIBRARY}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${Jemalloc_INCLUDE_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(
|
||||
Jemalloc_INCLUDE_DIR
|
||||
Jemalloc_LIBRARY
|
||||
)
|
||||
@@ -1,67 +0,0 @@
|
||||
# Try to find jemalloc library
|
||||
#
|
||||
# Use this module as:
|
||||
# find_package(jemalloc)
|
||||
#
|
||||
# or:
|
||||
# find_package(jemalloc REQUIRED)
|
||||
#
|
||||
# This will define the following variables:
|
||||
#
|
||||
# JEMALLOC_FOUND True if the system has the jemalloc library.
|
||||
# Jemalloc_INCLUDE_DIRS Include directories needed to use jemalloc.
|
||||
# Jemalloc_LIBRARIES Libraries needed to link to jemalloc.
|
||||
#
|
||||
# The following cache variables may also be set:
|
||||
#
|
||||
# Jemalloc_INCLUDE_DIR The directory containing jemalloc/jemalloc.h.
|
||||
# Jemalloc_LIBRARY The path to the jemalloc static library.
|
||||
|
||||
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(jemalloc
|
||||
FOUND_VAR JEMALLOC_FOUND
|
||||
REQUIRED_VARS
|
||||
JEMALLOC_LIBRARY
|
||||
JEMALLOC_INCLUDE_DIR
|
||||
)
|
||||
|
||||
if(JEMALLOC_INCLUDE_DIR)
|
||||
message(STATUS "Found jemalloc include dir: ${JEMALLOC_INCLUDE_DIR}")
|
||||
else()
|
||||
message(WARNING "jemalloc not found!")
|
||||
endif()
|
||||
|
||||
if(JEMALLOC_LIBRARY)
|
||||
message(STATUS "Found jemalloc library: ${JEMALLOC_LIBRARY}")
|
||||
else()
|
||||
message(WARNING "jemalloc library not found!")
|
||||
endif()
|
||||
|
||||
if(JEMALLOC_FOUND)
|
||||
set(Jemalloc_LIBRARIES ${JEMALLOC_LIBRARY})
|
||||
set(Jemalloc_INCLUDE_DIRS ${JEMALLOC_INCLUDE_DIR})
|
||||
else()
|
||||
if(Jemalloc_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Cannot find jemalloc!")
|
||||
else()
|
||||
message(WARNING "jemalloc is not found!")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(JEMALLOC_FOUND AND NOT TARGET Jemalloc::Jemalloc)
|
||||
message(STATUS "JEMALLOC NOT TARGET")
|
||||
|
||||
add_library(Jemalloc::Jemalloc UNKNOWN IMPORTED)
|
||||
set_target_properties(Jemalloc::Jemalloc
|
||||
PROPERTIES
|
||||
IMPORTED_LOCATION "${JEMALLOC_LIBRARY}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${JEMALLOC_INCLUDE_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(
|
||||
JEMALLOC_INCLUDE_DIR
|
||||
JEMALLOC_LIBRARY
|
||||
)
|
||||
@@ -111,14 +111,6 @@ modifications:
|
||||
value: "false"
|
||||
override: true
|
||||
|
||||
- name: "storage_parallel_schema_recovery"
|
||||
value: "false"
|
||||
override: true
|
||||
|
||||
- name: "storage_enable_schema_metadata"
|
||||
value: "false"
|
||||
override: true
|
||||
|
||||
- name: "query_callable_mappings_path"
|
||||
value: "/etc/memgraph/apoc_compatibility_mappings.json"
|
||||
override: true
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"dbms.components": "mgps.components",
|
||||
"apoc.util.validate": "mgps.validate",
|
||||
"db.schema.nodeTypeProperties": "schema.NodeTypeOroperties",
|
||||
"db.schema.relTypeProperties": "schema.RelTypeProperties",
|
||||
"db.schema.nodeTypeProperties":"schema.node_type_properties",
|
||||
"db.schema.relTypeProperties":"schema.rel_type_properties",
|
||||
"apoc.coll.contains": "collections.contains",
|
||||
"apoc.coll.partition": "collections.partition",
|
||||
"apoc.coll.toSet": "collections.to_set",
|
||||
@@ -23,4 +23,5 @@
|
||||
"apoc.refactor.cloneSubgraph": "refactor.clone_subgraph",
|
||||
"apoc.refactor.cloneSubgraphFromPath": "refactor.clone_subgraph_from_path",
|
||||
"apoc.label.exists": "label.exists"
|
||||
|
||||
}
|
||||
|
||||
@@ -158,9 +158,9 @@ install() {
|
||||
continue
|
||||
fi
|
||||
if [ "$pkg" == nodejs ]; then
|
||||
curl -sL https://rpm.nodesource.com/setup_16.x | bash -
|
||||
if ! yum list installed nodejs >/dev/null 2>/dev/null; then
|
||||
yum install https://rpm.nodesource.com/pub_16.x/nodistro/repo/nodesource-release-nodistro-1.noarch.rpm -y
|
||||
yum install nodejs -y --setopt=nodesource-nodejs.module_hotfixes=1
|
||||
yum install -y nodejs
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
@@ -172,6 +172,13 @@ install() {
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
if [ "$pkg" == nodejs ]; then
|
||||
curl -sL https://rpm.nodesource.com/setup_16.x | bash -
|
||||
if ! yum list installed nodejs >/dev/null 2>/dev/null; then
|
||||
yum install -y nodejs
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
if [ "$pkg" == java-11-openjdk ]; then
|
||||
amazon-linux-extras install -y java-openjdk11
|
||||
continue
|
||||
|
||||
@@ -234,57 +234,7 @@ inline mgp_type *type_duration() { return MgInvoke<mgp_type *>(mgp_type_duration
|
||||
|
||||
inline mgp_type *type_nullable(mgp_type *type) { return MgInvoke<mgp_type *>(mgp_type_nullable, type); }
|
||||
|
||||
inline bool create_label_index(mgp_graph *graph, const char *label) {
|
||||
return MgInvoke<int>(mgp_create_label_index, graph, label);
|
||||
}
|
||||
|
||||
inline bool drop_label_index(mgp_graph *graph, const char *label) {
|
||||
return MgInvoke<int>(mgp_drop_label_index, graph, label);
|
||||
}
|
||||
|
||||
inline mgp_list *list_all_label_indices(mgp_graph *graph, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_list *>(mgp_list_all_label_indices, graph, memory);
|
||||
}
|
||||
|
||||
inline bool create_label_property_index(mgp_graph *graph, const char *label, const char *property) {
|
||||
return MgInvoke<int>(mgp_create_label_property_index, graph, label, property);
|
||||
}
|
||||
|
||||
inline bool drop_label_property_index(mgp_graph *graph, const char *label, const char *property) {
|
||||
return MgInvoke<int>(mgp_drop_label_property_index, graph, label, property);
|
||||
}
|
||||
|
||||
inline mgp_list *list_all_label_property_indices(mgp_graph *graph, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_list *>(mgp_list_all_label_property_indices, graph, memory);
|
||||
}
|
||||
|
||||
inline bool create_existence_constraint(mgp_graph *graph, const char *label, const char *property) {
|
||||
return MgInvoke<int>(mgp_create_existence_constraint, graph, label, property);
|
||||
}
|
||||
|
||||
inline bool drop_existence_constraint(mgp_graph *graph, const char *label, const char *property) {
|
||||
return MgInvoke<int>(mgp_drop_existence_constraint, graph, label, property);
|
||||
}
|
||||
|
||||
inline mgp_list *list_all_existence_constraints(mgp_graph *graph, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_list *>(mgp_list_all_existence_constraints, graph, memory);
|
||||
}
|
||||
|
||||
inline bool create_unique_constraint(mgp_graph *memgraph_graph, const char *label, mgp_value *properties) {
|
||||
return MgInvoke<int>(mgp_create_unique_constraint, memgraph_graph, label, properties);
|
||||
}
|
||||
|
||||
inline bool drop_unique_constraint(mgp_graph *memgraph_graph, const char *label, mgp_value *properties) {
|
||||
return MgInvoke<int>(mgp_drop_unique_constraint, memgraph_graph, label, properties);
|
||||
}
|
||||
|
||||
inline mgp_list *list_all_unique_constraints(mgp_graph *graph, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_list *>(mgp_list_all_unique_constraints, graph, memory);
|
||||
}
|
||||
|
||||
// mgp_graph
|
||||
|
||||
inline bool graph_is_transactional(mgp_graph *graph) { return MgInvoke<int>(mgp_graph_is_transactional, graph); }
|
||||
|
||||
inline bool graph_is_mutable(mgp_graph *graph) { return MgInvoke<int>(mgp_graph_is_mutable, graph); }
|
||||
|
||||
@@ -315,11 +265,6 @@ inline mgp_edge *graph_edge_set_to(struct mgp_graph *graph, struct mgp_edge *e,
|
||||
return MgInvoke<mgp_edge *>(mgp_graph_edge_set_to, graph, e, new_to, memory);
|
||||
}
|
||||
|
||||
inline mgp_edge *graph_edge_change_type(struct mgp_graph *graph, struct mgp_edge *e, struct mgp_edge_type new_type,
|
||||
mgp_memory *memory) {
|
||||
return MgInvoke<mgp_edge *>(mgp_graph_edge_change_type, graph, e, new_type, memory);
|
||||
}
|
||||
|
||||
inline void graph_delete_edge(mgp_graph *graph, mgp_edge *edge) { MgInvokeVoid(mgp_graph_delete_edge, graph, edge); }
|
||||
|
||||
inline mgp_vertex *graph_get_vertex_by_id(mgp_graph *g, mgp_vertex_id id, mgp_memory *memory) {
|
||||
@@ -378,8 +323,6 @@ inline mgp_list *list_copy(mgp_list *list, mgp_memory *memory) {
|
||||
|
||||
inline void list_destroy(mgp_list *list) { mgp_list_destroy(list); }
|
||||
|
||||
inline bool list_contains_deleted(mgp_list *list) { return MgInvoke<int>(mgp_list_contains_deleted, list); }
|
||||
|
||||
inline void list_append(mgp_list *list, mgp_value *val) { MgInvokeVoid(mgp_list_append, list, val); }
|
||||
|
||||
inline void list_append_extend(mgp_list *list, mgp_value *val) { MgInvokeVoid(mgp_list_append_extend, list, val); }
|
||||
@@ -398,8 +341,6 @@ inline mgp_map *map_copy(mgp_map *map, mgp_memory *memory) { return MgInvoke<mgp
|
||||
|
||||
inline void map_destroy(mgp_map *map) { mgp_map_destroy(map); }
|
||||
|
||||
inline bool map_contains_deleted(mgp_map *map) { return MgInvoke<int>(mgp_map_contains_deleted, map); }
|
||||
|
||||
inline void map_insert(mgp_map *map, const char *key, mgp_value *value) {
|
||||
MgInvokeVoid(mgp_map_insert, map, key, value);
|
||||
}
|
||||
@@ -414,8 +355,6 @@ inline size_t map_size(mgp_map *map) { return MgInvoke<size_t>(mgp_map_size, map
|
||||
|
||||
inline mgp_value *map_at(mgp_map *map, const char *key) { return MgInvoke<mgp_value *>(mgp_map_at, map, key); }
|
||||
|
||||
inline bool key_exists(mgp_map *map, const char *key) { return MgInvoke<int>(mgp_key_exists, map, key); }
|
||||
|
||||
inline const char *map_item_key(mgp_map_item *item) { return MgInvoke<const char *>(mgp_map_item_key, item); }
|
||||
|
||||
inline mgp_value *map_item_value(mgp_map_item *item) { return MgInvoke<mgp_value *>(mgp_map_item_value, item); }
|
||||
@@ -448,8 +387,6 @@ inline mgp_vertex *vertex_copy(mgp_vertex *v, mgp_memory *memory) {
|
||||
|
||||
inline void vertex_destroy(mgp_vertex *v) { mgp_vertex_destroy(v); }
|
||||
|
||||
inline bool vertex_is_deleted(mgp_vertex *v) { return MgInvoke<int>(mgp_vertex_is_deleted, v); }
|
||||
|
||||
inline bool vertex_equal(mgp_vertex *v1, mgp_vertex *v2) { return MgInvoke<int>(mgp_vertex_equal, v1, v2); }
|
||||
|
||||
inline size_t vertex_labels_count(mgp_vertex *v) { return MgInvoke<size_t>(mgp_vertex_labels_count, v); }
|
||||
@@ -502,8 +439,6 @@ inline mgp_edge *edge_copy(mgp_edge *e, mgp_memory *memory) { return MgInvoke<mg
|
||||
|
||||
inline void edge_destroy(mgp_edge *e) { mgp_edge_destroy(e); }
|
||||
|
||||
inline bool edge_is_deleted(mgp_edge *e) { return MgInvoke<int>(mgp_edge_is_deleted, e); }
|
||||
|
||||
inline bool edge_equal(mgp_edge *e1, mgp_edge *e2) { return MgInvoke<int>(mgp_edge_equal, e1, e2); }
|
||||
|
||||
inline mgp_edge_type edge_get_type(mgp_edge *e) { return MgInvoke<mgp_edge_type>(mgp_edge_get_type, e); }
|
||||
@@ -540,8 +475,6 @@ inline mgp_path *path_copy(mgp_path *path, mgp_memory *memory) {
|
||||
|
||||
inline void path_destroy(mgp_path *path) { mgp_path_destroy(path); }
|
||||
|
||||
inline bool path_contains_deleted(mgp_path *path) { return MgInvoke<int>(mgp_path_contains_deleted, path); }
|
||||
|
||||
inline void path_expand(mgp_path *path, mgp_edge *edge) { MgInvokeVoid(mgp_path_expand, path, edge); }
|
||||
|
||||
inline void path_pop(mgp_path *path) { MgInvokeVoid(mgp_path_pop, path); }
|
||||
|
||||
@@ -111,22 +111,6 @@ enum mgp_error mgp_global_aligned_alloc(size_t size_in_bytes, size_t alignment,
|
||||
/// The behavior is undefined if `ptr` is not a value returned from a prior
|
||||
/// mgp_global_alloc() or mgp_global_aligned_alloc().
|
||||
void mgp_global_free(void *p);
|
||||
|
||||
/// State of the graph database.
|
||||
struct mgp_graph;
|
||||
|
||||
/// Allocations are tracked only for master thread. If new threads are spawned
|
||||
/// inside procedure, by calling following function
|
||||
/// you can start tracking allocations for current thread too. This
|
||||
/// is important if you need query memory limit to work
|
||||
/// for given procedure or per procedure memory limit.
|
||||
enum mgp_error mgp_track_current_thread_allocations(struct mgp_graph *graph);
|
||||
|
||||
/// Once allocations are tracked for current thread, you need to stop tracking allocations
|
||||
/// for given thread, before thread finishes with execution, or is detached.
|
||||
/// Otherwise it might result in slowdown of system due to unnecessary tracking of
|
||||
/// allocations.
|
||||
enum mgp_error mgp_untrack_current_thread_allocations(struct mgp_graph *graph);
|
||||
///@}
|
||||
|
||||
/// @name Operations on mgp_value
|
||||
@@ -429,9 +413,6 @@ enum mgp_error mgp_list_copy(struct mgp_list *list, struct mgp_memory *memory, s
|
||||
/// Free the memory used by the given mgp_list and contained elements.
|
||||
void mgp_list_destroy(struct mgp_list *list);
|
||||
|
||||
/// Return whether the given mgp_list contains any deleted values.
|
||||
enum mgp_error mgp_list_contains_deleted(struct mgp_list *list, int *result);
|
||||
|
||||
/// Append a copy of mgp_value to mgp_list if capacity allows.
|
||||
/// The list copies the given value and therefore does not take ownership of the
|
||||
/// original value. You still need to call mgp_value_destroy to free the
|
||||
@@ -472,9 +453,6 @@ enum mgp_error mgp_map_copy(struct mgp_map *map, struct mgp_memory *memory, stru
|
||||
/// Free the memory used by the given mgp_map and contained items.
|
||||
void mgp_map_destroy(struct mgp_map *map);
|
||||
|
||||
/// Return whether the given mgp_map contains any deleted values.
|
||||
enum mgp_error mgp_map_contains_deleted(struct mgp_map *map, int *result);
|
||||
|
||||
/// Insert a new mapping from a NULL terminated character string to a value.
|
||||
/// If a mapping with the same key already exists, it is *not* replaced.
|
||||
/// In case of insertion, both the string and the value are copied into the map.
|
||||
@@ -504,9 +482,6 @@ enum mgp_error mgp_map_size(struct mgp_map *map, size_t *result);
|
||||
/// Result is NULL if no mapping exists.
|
||||
enum mgp_error mgp_map_at(struct mgp_map *map, const char *key, struct mgp_value **result);
|
||||
|
||||
/// Returns true if key in map.
|
||||
enum mgp_error mgp_key_exists(struct mgp_map *map, const char *key, int *result);
|
||||
|
||||
/// An item in the mgp_map.
|
||||
struct mgp_map_item;
|
||||
|
||||
@@ -558,9 +533,6 @@ enum mgp_error mgp_path_copy(struct mgp_path *path, struct mgp_memory *memory, s
|
||||
/// Free the memory used by the given mgp_path and contained vertices and edges.
|
||||
void mgp_path_destroy(struct mgp_path *path);
|
||||
|
||||
/// Return whether the given mgp_path contains any deleted values.
|
||||
enum mgp_error mgp_path_contains_deleted(struct mgp_path *path, int *result);
|
||||
|
||||
/// Append an edge continuing from the last vertex on the path.
|
||||
/// The edge is copied into the path. Therefore, the path does not take
|
||||
/// ownership of the original edge, so you still need to free the edge memory
|
||||
@@ -734,9 +706,6 @@ enum mgp_error mgp_vertex_copy(struct mgp_vertex *v, struct mgp_memory *memory,
|
||||
/// Free the memory used by a mgp_vertex.
|
||||
void mgp_vertex_destroy(struct mgp_vertex *v);
|
||||
|
||||
/// Return whether the given mgp_vertex is deleted.
|
||||
enum mgp_error mgp_vertex_is_deleted(struct mgp_vertex *v, int *result);
|
||||
|
||||
/// Result is non-zero if given vertices are equal, otherwise 0.
|
||||
enum mgp_error mgp_vertex_equal(struct mgp_vertex *v1, struct mgp_vertex *v2, int *result);
|
||||
|
||||
@@ -831,9 +800,6 @@ enum mgp_error mgp_edge_copy(struct mgp_edge *e, struct mgp_memory *memory, stru
|
||||
/// Free the memory used by a mgp_edge.
|
||||
void mgp_edge_destroy(struct mgp_edge *e);
|
||||
|
||||
/// Return whether the given mgp_edge is deleted.
|
||||
enum mgp_error mgp_edge_is_deleted(struct mgp_edge *e, int *result);
|
||||
|
||||
/// Result is non-zero if given edges are equal, otherwise 0.
|
||||
enum mgp_error mgp_edge_equal(struct mgp_edge *e1, struct mgp_edge *e2, int *result);
|
||||
|
||||
@@ -885,83 +851,21 @@ enum mgp_error mgp_edge_set_properties(struct mgp_edge *e, struct mgp_map *prope
|
||||
enum mgp_error mgp_edge_iter_properties(struct mgp_edge *e, struct mgp_memory *memory,
|
||||
struct mgp_properties_iterator **result);
|
||||
|
||||
/// State of the graph database.
|
||||
struct mgp_graph;
|
||||
|
||||
/// Get the vertex corresponding to given ID, or NULL if no such vertex exists.
|
||||
/// Resulting vertex must be freed using mgp_vertex_destroy.
|
||||
/// Return mgp_error::MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate the vertex.
|
||||
enum mgp_error mgp_graph_get_vertex_by_id(struct mgp_graph *g, struct mgp_vertex_id id, struct mgp_memory *memory,
|
||||
struct mgp_vertex **result);
|
||||
|
||||
/// Creates label index for given label.
|
||||
/// mgp_error::MGP_ERROR_NO_ERROR is always returned.
|
||||
/// if label index already exists, result will be 0, otherwise 1.
|
||||
enum mgp_error mgp_create_label_index(struct mgp_graph *graph, const char *label, int *result);
|
||||
|
||||
/// Drop label index.
|
||||
enum mgp_error mgp_drop_label_index(struct mgp_graph *graph, const char *label, int *result);
|
||||
|
||||
/// List all label indices.
|
||||
enum mgp_error mgp_list_all_label_indices(struct mgp_graph *graph, struct mgp_memory *memory, struct mgp_list **result);
|
||||
|
||||
/// Creates label-property index for given label and propery.
|
||||
/// mgp_error::MGP_ERROR_NO_ERROR is always returned.
|
||||
/// if label property index already exists, result will be 0, otherwise 1.
|
||||
enum mgp_error mgp_create_label_property_index(struct mgp_graph *graph, const char *label, const char *property,
|
||||
int *result);
|
||||
|
||||
/// Drops label-property index for given label and propery.
|
||||
/// mgp_error::MGP_ERROR_NO_ERROR is always returned.
|
||||
/// if dropping label property index failed, result will be 0, otherwise 1.
|
||||
enum mgp_error mgp_drop_label_property_index(struct mgp_graph *graph, const char *label, const char *property,
|
||||
int *result);
|
||||
|
||||
/// List all label+property indices.
|
||||
enum mgp_error mgp_list_all_label_property_indices(struct mgp_graph *graph, struct mgp_memory *memory,
|
||||
struct mgp_list **result);
|
||||
|
||||
/// Creates existence constraint for given label and property.
|
||||
/// mgp_error::MGP_ERROR_NO_ERROR is always returned.
|
||||
/// if creating existence constraint failed, result will be 0, otherwise 1.
|
||||
enum mgp_error mgp_create_existence_constraint(struct mgp_graph *graph, const char *label, const char *property,
|
||||
int *result);
|
||||
|
||||
/// Drops existence constraint for given label and property.
|
||||
/// mgp_error::MGP_ERROR_NO_ERROR is always returned.
|
||||
/// if dropping existence constraint failed, result will be 0, otherwise 1.
|
||||
enum mgp_error mgp_drop_existence_constraint(struct mgp_graph *graph, const char *label, const char *property,
|
||||
int *result);
|
||||
|
||||
/// List all existence constraints.
|
||||
enum mgp_error mgp_list_all_existence_constraints(struct mgp_graph *graph, struct mgp_memory *memory,
|
||||
struct mgp_list **result);
|
||||
|
||||
/// Creates unique constraint for given label and properties.
|
||||
/// mgp_error::MGP_ERROR_NO_ERROR is always returned.
|
||||
/// if creating unique constraint failed, result will be 0, otherwise 1.
|
||||
enum mgp_error mgp_create_unique_constraint(struct mgp_graph *graph, const char *label, struct mgp_value *properties,
|
||||
int *result);
|
||||
|
||||
/// Drops unique constraint for given label and properties.
|
||||
/// mgp_error::MGP_ERROR_NO_ERROR is always returned.
|
||||
/// if dropping unique constraint failed, result will be 0, otherwise 1.
|
||||
enum mgp_error mgp_drop_unique_constraint(struct mgp_graph *graph, const char *label, struct mgp_value *properties,
|
||||
int *result);
|
||||
|
||||
/// List all unique constraints
|
||||
enum mgp_error mgp_list_all_unique_constraints(struct mgp_graph *graph, struct mgp_memory *memory,
|
||||
struct mgp_list **result);
|
||||
|
||||
/// Result is non-zero if the graph can be modified.
|
||||
/// If a graph is immutable, then vertices cannot be created or deleted, and all of the returned vertices will be
|
||||
/// immutable also. The same applies for edges.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_graph_is_mutable(struct mgp_graph *graph, int *result);
|
||||
|
||||
/// Result is non-zero if the graph is in transactional storage mode.
|
||||
/// If a graph is not in transactional mode (i.e. analytical mode), then vertices and edges can be missing
|
||||
/// because changes from other transactions are visible.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_graph_is_transactional(struct mgp_graph *graph, int *result);
|
||||
|
||||
/// Add a new vertex to the graph.
|
||||
/// Resulting vertex must be freed using mgp_vertex_destroy.
|
||||
/// Return mgp_error::MGP_ERROR_IMMUTABLE_OBJECT if `graph` is immutable.
|
||||
@@ -1004,13 +908,6 @@ enum mgp_error mgp_graph_edge_set_from(struct mgp_graph *graph, struct mgp_edge
|
||||
enum mgp_error mgp_graph_edge_set_to(struct mgp_graph *graph, struct mgp_edge *e, struct mgp_vertex *new_to,
|
||||
struct mgp_memory *memory, struct mgp_edge **result);
|
||||
|
||||
/// Change edge type
|
||||
/// Return mgp_error::MGP_ERROR_IMMUTABLE_OBJECT if `graph` is immutable.
|
||||
/// Return mgp_error::MGP_ERROR_SERIALIZATION_ERROR if `edge`, its source or destination vertex has been modified by
|
||||
/// another transaction.
|
||||
enum mgp_error mgp_graph_edge_change_type(struct mgp_graph *graph, struct mgp_edge *e, struct mgp_edge_type new_type,
|
||||
struct mgp_memory *memory, struct mgp_edge **result);
|
||||
|
||||
/// Delete an edge from the graph.
|
||||
/// Return mgp_error::MGP_ERROR_IMMUTABLE_OBJECT if `graph` is immutable.
|
||||
/// Return mgp_error::MGP_ERROR_SERIALIZATION_ERROR if `edge`, its source or destination vertex has been modified by
|
||||
|
||||
417
include/mgp.hpp
417
include/mgp.hpp
File diff suppressed because it is too large
Load Diff
@@ -4,8 +4,7 @@ include(GNUInstallDirs)
|
||||
|
||||
include(ProcessorCount)
|
||||
ProcessorCount(NPROC)
|
||||
|
||||
if(NPROC EQUAL 0)
|
||||
if (NPROC EQUAL 0)
|
||||
set(NPROC 1)
|
||||
endif()
|
||||
|
||||
@@ -13,10 +12,10 @@ find_package(Boost 1.78 REQUIRED)
|
||||
find_package(BZip2 1.0.6 REQUIRED)
|
||||
find_package(Threads REQUIRED)
|
||||
set(GFLAGS_NOTHREADS OFF)
|
||||
|
||||
# NOTE: config/generate.py depends on the gflags help XML format.
|
||||
find_package(gflags REQUIRED)
|
||||
find_package(fmt 8.0.1)
|
||||
find_package(Jemalloc REQUIRED)
|
||||
find_package(ZLIB 1.2.11 REQUIRED)
|
||||
|
||||
set(LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
@@ -25,27 +24,24 @@ set(LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
function(import_header_library name include_dir)
|
||||
add_library(${name} INTERFACE IMPORTED GLOBAL)
|
||||
set_property(TARGET ${name} PROPERTY
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${include_dir})
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${include_dir})
|
||||
string(TOUPPER ${name} _upper_name)
|
||||
set(${_upper_name}_INCLUDE_DIR ${include_dir} CACHE FILEPATH
|
||||
"Path to ${name} include directory" FORCE)
|
||||
"Path to ${name} include directory" FORCE)
|
||||
mark_as_advanced(${_upper_name}_INCLUDE_DIR)
|
||||
add_library(lib::${name} ALIAS ${name})
|
||||
endfunction(import_header_library)
|
||||
|
||||
function(import_library name type location include_dir)
|
||||
add_library(${name} ${type} IMPORTED GLOBAL)
|
||||
|
||||
if(${ARGN})
|
||||
if (${ARGN})
|
||||
# Optional argument is the name of the external project that we need to
|
||||
# depend on.
|
||||
add_dependencies(${name} ${ARGN0})
|
||||
else()
|
||||
add_dependencies(${name} ${name}-proj)
|
||||
endif()
|
||||
|
||||
set_property(TARGET ${name} PROPERTY IMPORTED_LOCATION ${location})
|
||||
|
||||
# We need to create the include directory first in order to be able to add it
|
||||
# as an include directory. The header files in the include directory will be
|
||||
# generated later during the build process.
|
||||
@@ -65,59 +61,43 @@ function(add_external_project name)
|
||||
set(options NO_C_COMPILER)
|
||||
set(one_value_kwargs SOURCE_DIR BUILD_IN_SOURCE)
|
||||
set(multi_value_kwargs CMAKE_ARGS DEPENDS INSTALL_COMMAND BUILD_COMMAND
|
||||
CONFIGURE_COMMAND)
|
||||
CONFIGURE_COMMAND)
|
||||
cmake_parse_arguments(KW "${options}" "${one_value_kwargs}" "${multi_value_kwargs}" ${ARGN})
|
||||
set(source_dir ${CMAKE_CURRENT_SOURCE_DIR}/${name})
|
||||
|
||||
if(KW_SOURCE_DIR)
|
||||
if (KW_SOURCE_DIR)
|
||||
set(source_dir ${KW_SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
set(build_in_source 0)
|
||||
|
||||
if(KW_BUILD_IN_SOURCE)
|
||||
if (KW_BUILD_IN_SOURCE)
|
||||
set(build_in_source ${KW_BUILD_IN_SOURCE})
|
||||
endif()
|
||||
|
||||
if(NOT KW_NO_C_COMPILER)
|
||||
if (NOT KW_NO_C_COMPILER)
|
||||
set(KW_CMAKE_ARGS -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} ${KW_CMAKE_ARGS})
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(${name}-proj DEPENDS ${KW_DEPENDS}
|
||||
PREFIX ${source_dir} SOURCE_DIR ${source_dir}
|
||||
BUILD_IN_SOURCE ${build_in_source}
|
||||
CONFIGURE_COMMAND ${KW_CONFIGURE_COMMAND}
|
||||
CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release
|
||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
||||
-DCMAKE_INSTALL_PREFIX=${source_dir}
|
||||
${KW_CMAKE_ARGS}
|
||||
INSTALL_COMMAND ${KW_INSTALL_COMMAND}
|
||||
BUILD_COMMAND ${KW_BUILD_COMMAND})
|
||||
PREFIX ${source_dir} SOURCE_DIR ${source_dir}
|
||||
BUILD_IN_SOURCE ${build_in_source}
|
||||
CONFIGURE_COMMAND ${KW_CONFIGURE_COMMAND}
|
||||
CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release
|
||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
||||
-DCMAKE_INSTALL_PREFIX=${source_dir}
|
||||
${KW_CMAKE_ARGS}
|
||||
INSTALL_COMMAND ${KW_INSTALL_COMMAND}
|
||||
BUILD_COMMAND ${KW_BUILD_COMMAND})
|
||||
endfunction(add_external_project)
|
||||
|
||||
# Calls `add_external_project`, sets NAME_LIBRARY, NAME_INCLUDE_DIR variables
|
||||
# and adds the library via `import_library`.
|
||||
macro(import_external_library name type library_location include_dir)
|
||||
add_external_project(${name} ${ARGN})
|
||||
string(TOUPPER ${name} _upper_name)
|
||||
set(${_upper_name}_LIBRARY ${library_location} CACHE FILEPATH
|
||||
"Path to ${name} library" FORCE)
|
||||
set(${_upper_name}_INCLUDE_DIR ${include_dir} CACHE FILEPATH
|
||||
"Path to ${name} include directory" FORCE)
|
||||
mark_as_advanced(${_upper_name}_LIBRARY ${_upper_name}_INCLUDE_DIR)
|
||||
import_library(${name} ${type} ${${_upper_name}_LIBRARY} ${${_upper_name}_INCLUDE_DIR})
|
||||
endmacro(import_external_library)
|
||||
|
||||
|
||||
macro(set_path_external_library name type library_location include_dir)
|
||||
string(TOUPPER ${name} _upper_name)
|
||||
set(${_upper_name}_LIBRARY ${library_location} CACHE FILEPATH
|
||||
"Path to ${name} library" FORCE)
|
||||
set(${_upper_name}_INCLUDE_DIR ${include_dir} CACHE FILEPATH
|
||||
"Path to ${name} include directory" FORCE)
|
||||
mark_as_advanced(${name}_LIBRARY ${name}_INCLUDE_DIR)
|
||||
endmacro(set_path_external_library)
|
||||
|
||||
mark_as_advanced(${_upper_name}_LIBRARY ${_upper_name}_INCLUDE_DIR)
|
||||
import_library(${name} ${type} ${${_upper_name}_LIBRARY} ${${_upper_name}_INCLUDE_DIR})
|
||||
endmacro(import_external_library)
|
||||
|
||||
# setup antlr
|
||||
import_external_library(antlr4 STATIC
|
||||
@@ -125,10 +105,10 @@ import_external_library(antlr4 STATIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/antlr4/runtime/Cpp/include/antlr4-runtime
|
||||
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/antlr4/runtime/Cpp
|
||||
CMAKE_ARGS # http://stackoverflow.com/questions/37096062/get-a-basic-c-program-to-compile-using-clang-on-ubuntu-16/38385967#38385967
|
||||
-DWITH_LIBCXX=OFF # because of debian bug
|
||||
-DCMAKE_SKIP_INSTALL_ALL_DEPENDENCY=true
|
||||
-DCMAKE_CXX_STANDARD=20
|
||||
-DANTLR_BUILD_CPP_TESTS=OFF
|
||||
-DWITH_LIBCXX=OFF # because of debian bug
|
||||
-DCMAKE_SKIP_INSTALL_ALL_DEPENDENCY=true
|
||||
-DCMAKE_CXX_STANDARD=20
|
||||
-DANTLR_BUILD_CPP_TESTS=OFF
|
||||
BUILD_COMMAND $(MAKE) antlr4_static
|
||||
INSTALL_COMMAND $(MAKE) install)
|
||||
|
||||
@@ -136,7 +116,6 @@ import_external_library(antlr4 STATIC
|
||||
import_external_library(benchmark STATIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/benchmark/${CMAKE_INSTALL_LIBDIR}/libbenchmark.a
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/benchmark/include
|
||||
|
||||
# Skip testing. The tests don't compile with Clang 8.
|
||||
CMAKE_ARGS -DBENCHMARK_ENABLE_TESTING=OFF)
|
||||
|
||||
@@ -152,15 +131,15 @@ add_subdirectory(rapidcheck EXCLUDE_FROM_ALL)
|
||||
# setup google test
|
||||
add_external_project(gtest SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/googletest)
|
||||
set(GTEST_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/googletest/include
|
||||
CACHE PATH "Path to gtest and gmock include directory" FORCE)
|
||||
CACHE PATH "Path to gtest and gmock include directory" FORCE)
|
||||
set(GMOCK_LIBRARY ${CMAKE_CURRENT_SOURCE_DIR}/googletest/lib/libgmock.a
|
||||
CACHE FILEPATH "Path to gmock library" FORCE)
|
||||
CACHE FILEPATH "Path to gmock library" FORCE)
|
||||
set(GMOCK_MAIN_LIBRARY ${CMAKE_CURRENT_SOURCE_DIR}/googletest/lib/libgmock_main.a
|
||||
CACHE FILEPATH "Path to gmock_main library" FORCE)
|
||||
CACHE FILEPATH "Path to gmock_main library" FORCE)
|
||||
set(GTEST_LIBRARY ${CMAKE_CURRENT_SOURCE_DIR}/googletest/lib/libgtest.a
|
||||
CACHE FILEPATH "Path to gtest library" FORCE)
|
||||
CACHE FILEPATH "Path to gtest library" FORCE)
|
||||
set(GTEST_MAIN_LIBRARY ${CMAKE_CURRENT_SOURCE_DIR}/googletest/lib/libgtest_main.a
|
||||
CACHE FILEPATH "Path to gtest_main library" FORCE)
|
||||
CACHE FILEPATH "Path to gtest_main library" FORCE)
|
||||
mark_as_advanced(GTEST_INCLUDE_DIR GMOCK_LIBRARY GMOCK_MAIN_LIBRARY GTEST_LIBRARY GTEST_MAIN_LIBRARY)
|
||||
import_library(gtest STATIC ${GTEST_LIBRARY} ${GTEST_INCLUDE_DIR} gtest-proj)
|
||||
import_library(gtest_main STATIC ${GTEST_MAIN_LIBRARY} ${GTEST_INCLUDE_DIR} gtest-proj)
|
||||
@@ -178,10 +157,10 @@ import_external_library(rocksdb STATIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rocksdb/lib/librocksdb.a
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rocksdb/include
|
||||
CMAKE_ARGS -DUSE_RTTI=ON
|
||||
-DWITH_TESTS=OFF
|
||||
-DGFLAGS_NOTHREADS=OFF
|
||||
-DCMAKE_INSTALL_LIBDIR=lib
|
||||
-DCMAKE_SKIP_INSTALL_ALL_DEPENDENCY=true
|
||||
-DWITH_TESTS=OFF
|
||||
-DGFLAGS_NOTHREADS=OFF
|
||||
-DCMAKE_INSTALL_LIBDIR=lib
|
||||
-DCMAKE_SKIP_INSTALL_ALL_DEPENDENCY=true
|
||||
BUILD_COMMAND $(MAKE) rocksdb)
|
||||
|
||||
# Setup libbcrypt
|
||||
@@ -190,8 +169,8 @@ import_external_library(libbcrypt STATIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/libbcrypt
|
||||
CONFIGURE_COMMAND sed s/-Wcast-align// -i ${CMAKE_CURRENT_SOURCE_DIR}/libbcrypt/crypt_blowfish/Makefile
|
||||
BUILD_COMMAND make -C ${CMAKE_CURRENT_SOURCE_DIR}/libbcrypt
|
||||
CC=${CMAKE_C_COMPILER}
|
||||
CXX=${CMAKE_CXX_COMPILER}
|
||||
CC=${CMAKE_C_COMPILER}
|
||||
CXX=${CMAKE_CXX_COMPILER}
|
||||
INSTALL_COMMAND true)
|
||||
|
||||
# Setup mgclient
|
||||
@@ -199,16 +178,16 @@ import_external_library(mgclient STATIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mgclient/lib/libmgclient.a
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mgclient/include
|
||||
CMAKE_ARGS -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
|
||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
||||
-DBUILD_TESTING=OFF
|
||||
-DBUILD_CPP_BINDINGS=ON)
|
||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
||||
-DBUILD_TESTING=OFF
|
||||
-DBUILD_CPP_BINDINGS=ON)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
target_link_libraries(mgclient INTERFACE ${OPENSSL_LIBRARIES})
|
||||
|
||||
add_external_project(mgconsole
|
||||
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/mgconsole
|
||||
CMAKE_ARGS
|
||||
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}
|
||||
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}
|
||||
BUILD_COMMAND $(MAKE) mgconsole)
|
||||
|
||||
add_custom_target(mgconsole DEPENDS mgconsole-proj)
|
||||
@@ -225,15 +204,14 @@ import_external_library(librdkafka STATIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/librdkafka/lib/librdkafka.a
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/librdkafka/include
|
||||
CMAKE_ARGS -DRDKAFKA_BUILD_STATIC=ON
|
||||
-DRDKAFKA_BUILD_EXAMPLES=OFF
|
||||
-DRDKAFKA_BUILD_TESTS=OFF
|
||||
-DWITH_ZSTD=OFF
|
||||
-DENABLE_LZ4_EXT=OFF
|
||||
-DCMAKE_INSTALL_LIBDIR=lib
|
||||
-DWITH_SSL=ON
|
||||
|
||||
# If we want SASL, we need to install it on build machines
|
||||
-DWITH_SASL=OFF)
|
||||
-DRDKAFKA_BUILD_EXAMPLES=OFF
|
||||
-DRDKAFKA_BUILD_TESTS=OFF
|
||||
-DWITH_ZSTD=OFF
|
||||
-DENABLE_LZ4_EXT=OFF
|
||||
-DCMAKE_INSTALL_LIBDIR=lib
|
||||
-DWITH_SSL=ON
|
||||
# If we want SASL, we need to install it on build machines
|
||||
-DWITH_SASL=OFF)
|
||||
target_link_libraries(librdkafka INTERFACE ${OPENSSL_LIBRARIES} ZLIB::ZLIB)
|
||||
|
||||
import_library(librdkafka++ STATIC
|
||||
@@ -254,24 +232,24 @@ import_external_library(pulsar STATIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/pulsar/install/include
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND cmake pulsar-client-cpp
|
||||
-DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_SOURCE_DIR}/pulsar/install
|
||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
||||
-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
|
||||
-DBUILD_DYNAMIC_LIB=OFF
|
||||
-DBUILD_STATIC_LIB=ON
|
||||
-DBUILD_TESTS=OFF
|
||||
-DLINK_STATIC=ON
|
||||
-DPROTOC_PATH=${PROTOBUF_ROOT}/bin/protoc
|
||||
-DBOOST_ROOT=${BOOST_ROOT}
|
||||
-DCMAKE_PREFIX_PATH=${PROTOBUF_ROOT}
|
||||
-DProtobuf_INCLUDE_DIRS=${PROTOBUF_ROOT}/include
|
||||
-DBUILD_PYTHON_WRAPPER=OFF
|
||||
-DBUILD_PERF_TOOLS=OFF
|
||||
-DUSE_LOG4CXX=OFF
|
||||
BUILD_COMMAND $(MAKE) pulsarStaticWithDeps)
|
||||
-DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_SOURCE_DIR}/pulsar/install
|
||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
||||
-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
|
||||
-DBUILD_DYNAMIC_LIB=OFF
|
||||
-DBUILD_STATIC_LIB=ON
|
||||
-DBUILD_TESTS=OFF
|
||||
-DLINK_STATIC=ON
|
||||
-DPROTOC_PATH=${PROTOBUF_ROOT}/bin/protoc
|
||||
-DBOOST_ROOT=${BOOST_ROOT}
|
||||
-DCMAKE_PREFIX_PATH=${PROTOBUF_ROOT}
|
||||
-DProtobuf_INCLUDE_DIRS=${PROTOBUF_ROOT}/include
|
||||
-DBUILD_PYTHON_WRAPPER=OFF
|
||||
-DBUILD_PERF_TOOLS=OFF
|
||||
-DUSE_LOG4CXX=OFF
|
||||
BUILD_COMMAND $(MAKE) pulsarStaticWithDeps)
|
||||
add_dependencies(pulsar-proj protobuf)
|
||||
|
||||
if(${MG_ARCH} STREQUAL "ARM64")
|
||||
if (${MG_ARCH} STREQUAL "ARM64")
|
||||
set(MG_LIBRDTSC_CMAKE_ARGS -DLIBRDTSC_ARCH_x86=OFF -DLIBRDTSC_ARCH_ARM64=ON)
|
||||
endif()
|
||||
|
||||
@@ -287,10 +265,3 @@ import_header_library(ctre ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
# setup absl (cmake sub_directory tolerant)
|
||||
set(ABSL_PROPAGATE_CXX_STD ON)
|
||||
add_subdirectory(absl EXCLUDE_FROM_ALL)
|
||||
|
||||
# set Jemalloc
|
||||
set_path_external_library(jemalloc STATIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/jemalloc/lib/libjemalloc.a
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/jemalloc/include/)
|
||||
|
||||
import_header_library(rangev3 ${CMAKE_CURRENT_SOURCE_DIR}/rangev3/include)
|
||||
|
||||
@@ -124,8 +124,6 @@ declare -A primary_urls=(
|
||||
["librdtsc"]="http://$local_cache_host/git/librdtsc.git"
|
||||
["ctre"]="http://$local_cache_host/file/hanickadot/compile-time-regular-expressions/v3.7.2/single-header/ctre.hpp"
|
||||
["absl"]="https://$local_cache_host/git/abseil-cpp.git"
|
||||
["jemalloc"]="https://$local_cache_host/git/jemalloc.git"
|
||||
["range-v3"]="https://$local_cache_host/git/ericniebler/range-v3.git"
|
||||
)
|
||||
|
||||
# The goal of secondary urls is to have links to the "source of truth" of
|
||||
@@ -153,8 +151,6 @@ declare -A secondary_urls=(
|
||||
["librdtsc"]="https://github.com/gabrieleara/librdtsc.git"
|
||||
["ctre"]="https://raw.githubusercontent.com/hanickadot/compile-time-regular-expressions/v3.7.2/single-header/ctre.hpp"
|
||||
["absl"]="https://github.com/abseil/abseil-cpp.git"
|
||||
["jemalloc"]="https://github.com/jemalloc/jemalloc.git"
|
||||
["range-v3"]="https://github.com/ericniebler/range-v3.git"
|
||||
)
|
||||
|
||||
# antlr
|
||||
@@ -256,24 +252,3 @@ cd ..
|
||||
# abseil 20230125.3
|
||||
absl_ref="20230125.3"
|
||||
repo_clone_try_double "${primary_urls[absl]}" "${secondary_urls[absl]}" "absl" "$absl_ref"
|
||||
|
||||
# jemalloc ea6b3e973b477b8061e0076bb257dbd7f3faa756
|
||||
JEMALLOC_COMMIT_VERSION="5.2.1"
|
||||
repo_clone_try_double "${secondary_urls[jemalloc]}" "${secondary_urls[jemalloc]}" "jemalloc" "$JEMALLOC_COMMIT_VERSION"
|
||||
|
||||
# this is hack for cmake in libs to set path, and for FindJemalloc to use Jemalloc_INCLUDE_DIR
|
||||
pushd jemalloc
|
||||
|
||||
./autogen.sh
|
||||
MALLOC_CONF="retain:false,percpu_arena:percpu,oversize_threshold:0,muzzy_decay_ms:5000,dirty_decay_ms:5000" \
|
||||
./configure \
|
||||
--disable-cxx \
|
||||
--enable-shared=no --prefix=$working_dir \
|
||||
--with-malloc-conf="retain:false,percpu_arena:percpu,oversize_threshold:0,muzzy_decay_ms:5000,dirty_decay_ms:5000"
|
||||
|
||||
make -j$CPUS install
|
||||
popd
|
||||
|
||||
#range-v3 release-0.12.0
|
||||
range_v3_ref="release-0.12.0"
|
||||
repo_clone_try_double "${primary_urls[range-v3]}" "${secondary_urls[range-v3]}" "rangev3" "$range_v3_ref"
|
||||
|
||||
@@ -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: 2027-08-12
|
||||
CHANGE DATE: 2027-13-09
|
||||
CHANGE LICENSE: Apache License, Version 2.0
|
||||
|
||||
For information about alternative licensing arrangements, please visit: https://memgraph.com/legal.
|
||||
|
||||
@@ -13,7 +13,6 @@ string(TOLOWER ${CMAKE_BUILD_TYPE} lower_build_type)
|
||||
add_library(example_c SHARED example.c)
|
||||
target_include_directories(example_c PRIVATE ${CMAKE_SOURCE_DIR}/include)
|
||||
target_compile_options(example_c PRIVATE -Wall)
|
||||
target_link_libraries(example_c PRIVATE -static-libgcc -static-libstdc++)
|
||||
# Strip C example in release build.
|
||||
if (lower_build_type STREQUAL "release")
|
||||
add_custom_command(TARGET example_c POST_BUILD
|
||||
@@ -29,7 +28,6 @@ install(FILES example.c DESTINATION lib/memgraph/query_modules/src)
|
||||
add_library(example_cpp SHARED example.cpp)
|
||||
target_include_directories(example_cpp PRIVATE ${CMAKE_SOURCE_DIR}/include)
|
||||
target_compile_options(example_cpp PRIVATE -Wall)
|
||||
target_link_libraries(example_cpp PRIVATE -static-libgcc -static-libstdc++)
|
||||
# Strip C++ example in release build.
|
||||
if (lower_build_type STREQUAL "release")
|
||||
add_custom_command(TARGET example_cpp POST_BUILD
|
||||
@@ -42,27 +40,9 @@ install(PROGRAMS $<TARGET_FILE:example_cpp>
|
||||
# Also install the source of the example, so user can read it.
|
||||
install(FILES example.cpp DESTINATION lib/memgraph/query_modules/src)
|
||||
|
||||
add_library(schema SHARED schema.cpp)
|
||||
target_include_directories(schema PRIVATE ${CMAKE_SOURCE_DIR}/include)
|
||||
target_compile_options(schema PRIVATE -Wall)
|
||||
target_link_libraries(schema PRIVATE -static-libgcc -static-libstdc++)
|
||||
# Strip C++ example in release build.
|
||||
if (lower_build_type STREQUAL "release")
|
||||
add_custom_command(TARGET schema POST_BUILD
|
||||
COMMAND strip -s $<TARGET_FILE:schema>
|
||||
COMMENT "Stripping symbols and sections from the C++ schema module")
|
||||
endif()
|
||||
install(PROGRAMS $<TARGET_FILE:schema>
|
||||
DESTINATION lib/memgraph/query_modules
|
||||
RENAME schema.so)
|
||||
# Also install the source of the example, so user can read it.
|
||||
install(FILES schema.cpp DESTINATION lib/memgraph/query_modules/src)
|
||||
|
||||
# Install the Python example and modules
|
||||
install(FILES example.py DESTINATION lib/memgraph/query_modules RENAME py_example.py)
|
||||
install(FILES graph_analyzer.py DESTINATION lib/memgraph/query_modules)
|
||||
install(FILES mgp_networkx.py DESTINATION lib/memgraph/query_modules)
|
||||
install(FILES nxalg.py DESTINATION lib/memgraph/query_modules)
|
||||
install(FILES wcc.py DESTINATION lib/memgraph/query_modules)
|
||||
install(FILES mgps.py DESTINATION lib/memgraph/query_modules)
|
||||
install(FILES convert.py DESTINATION lib/memgraph/query_modules)
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
from json import loads
|
||||
|
||||
import mgp
|
||||
|
||||
|
||||
@mgp.function
|
||||
def str2object(string: str) -> mgp.Any:
|
||||
if string:
|
||||
return loads(string)
|
||||
return None
|
||||
@@ -1,8 +0,0 @@
|
||||
import mgp
|
||||
|
||||
|
||||
@mgp.read_proc
|
||||
def components(
|
||||
context: mgp.ProcCtx,
|
||||
) -> mgp.Record(versions=list, edition=str, name=str):
|
||||
return mgp.Record(versions=["5.9.0"], edition="community", name="Memgraph")
|
||||
@@ -1,608 +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.
|
||||
|
||||
#include <mgp.hpp>
|
||||
#include "utils/string.hpp"
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace Schema {
|
||||
|
||||
constexpr std::string_view kStatusKept = "Kept";
|
||||
constexpr std::string_view kStatusCreated = "Created";
|
||||
constexpr std::string_view kStatusDropped = "Dropped";
|
||||
constexpr std::string_view kReturnNodeType = "nodeType";
|
||||
constexpr std::string_view kProcedureNodeType = "node_type_properties";
|
||||
constexpr std::string_view kProcedureRelType = "rel_type_properties";
|
||||
constexpr std::string_view kProcedureAssert = "assert";
|
||||
constexpr std::string_view kReturnLabels = "nodeLabels";
|
||||
constexpr std::string_view kReturnRelType = "relType";
|
||||
constexpr std::string_view kReturnPropertyName = "propertyName";
|
||||
constexpr std::string_view kReturnPropertyType = "propertyTypes";
|
||||
constexpr std::string_view kReturnMandatory = "mandatory";
|
||||
constexpr std::string_view kReturnLabel = "label";
|
||||
constexpr std::string_view kReturnKey = "key";
|
||||
constexpr std::string_view kReturnKeys = "keys";
|
||||
constexpr std::string_view kReturnUnique = "unique";
|
||||
constexpr std::string_view kReturnAction = "action";
|
||||
constexpr std::string_view kParameterIndices = "indices";
|
||||
constexpr std::string_view kParameterUniqueConstraints = "unique_constraints";
|
||||
constexpr std::string_view kParameterExistenceConstraints = "existence_constraints";
|
||||
constexpr std::string_view kParameterDropExisting = "drop_existing";
|
||||
|
||||
std::string TypeOf(const mgp::Type &type);
|
||||
|
||||
template <typename T>
|
||||
void ProcessPropertiesNode(mgp::Record &record, const std::string &type, const mgp::List &labels,
|
||||
const std::string &propertyName, const T &propertyType, const bool &mandatory);
|
||||
|
||||
template <typename T>
|
||||
void ProcessPropertiesRel(mgp::Record &record, const std::string_view &type, const std::string &propertyName,
|
||||
const T &propertyType, const bool &mandatory);
|
||||
|
||||
void NodeTypeProperties(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory);
|
||||
void RelTypeProperties(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory);
|
||||
void Assert(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory);
|
||||
} // namespace Schema
|
||||
|
||||
/*we have << operator for type in Cpp API, but in it we return somewhat different strings than I would like in this
|
||||
module, so I implemented a small function here*/
|
||||
std::string Schema::TypeOf(const mgp::Type &type) {
|
||||
switch (type) {
|
||||
case mgp::Type::Null:
|
||||
return "Null";
|
||||
case mgp::Type::Bool:
|
||||
return "Bool";
|
||||
case mgp::Type::Int:
|
||||
return "Int";
|
||||
case mgp::Type::Double:
|
||||
return "Double";
|
||||
case mgp::Type::String:
|
||||
return "String";
|
||||
case mgp::Type::List:
|
||||
return "List[Any]";
|
||||
case mgp::Type::Map:
|
||||
return "Map[Any]";
|
||||
case mgp::Type::Node:
|
||||
return "Vertex";
|
||||
case mgp::Type::Relationship:
|
||||
return "Edge";
|
||||
case mgp::Type::Path:
|
||||
return "Path";
|
||||
case mgp::Type::Date:
|
||||
return "Date";
|
||||
case mgp::Type::LocalTime:
|
||||
return "LocalTime";
|
||||
case mgp::Type::LocalDateTime:
|
||||
return "LocalDateTime";
|
||||
case mgp::Type::Duration:
|
||||
return "Duration";
|
||||
default:
|
||||
throw mgp::ValueException("Unsupported type");
|
||||
}
|
||||
}
|
||||
template <typename T>
|
||||
void Schema::ProcessPropertiesNode(mgp::Record &record, const std::string &type, const mgp::List &labels,
|
||||
const std::string &propertyName, const T &propertyType, const bool &mandatory) {
|
||||
record.Insert(std::string(kReturnNodeType).c_str(), type);
|
||||
record.Insert(std::string(kReturnLabels).c_str(), labels);
|
||||
record.Insert(std::string(kReturnPropertyName).c_str(), propertyName);
|
||||
record.Insert(std::string(kReturnPropertyType).c_str(), propertyType);
|
||||
record.Insert(std::string(kReturnMandatory).c_str(), mandatory);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Schema::ProcessPropertiesRel(mgp::Record &record, const std::string_view &type, const std::string &propertyName,
|
||||
const T &propertyType, const bool &mandatory) {
|
||||
record.Insert(std::string(kReturnRelType).c_str(), type);
|
||||
record.Insert(std::string(kReturnPropertyName).c_str(), propertyName);
|
||||
record.Insert(std::string(kReturnPropertyType).c_str(), propertyType);
|
||||
record.Insert(std::string(kReturnMandatory).c_str(), mandatory);
|
||||
}
|
||||
|
||||
void Schema::NodeTypeProperties(mgp_list * /*args*/, mgp_graph *memgraph_graph, mgp_result *result,
|
||||
mgp_memory *memory) {
|
||||
mgp::MemoryDispatcherGuard guard{memory};
|
||||
const auto record_factory = mgp::RecordFactory(result);
|
||||
try {
|
||||
const mgp::Graph graph = mgp::Graph(memgraph_graph);
|
||||
for (auto node : graph.Nodes()) {
|
||||
std::string type;
|
||||
mgp::List labels = mgp::List();
|
||||
for (auto label : node.Labels()) {
|
||||
labels.AppendExtend(mgp::Value(label));
|
||||
type += ":`" + std::string(label) + "`";
|
||||
}
|
||||
|
||||
if (node.Properties().empty()) {
|
||||
auto record = record_factory.NewRecord();
|
||||
ProcessPropertiesNode<std::string>(record, type, labels, "", "", false);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto &[key, prop] : node.Properties()) {
|
||||
auto property_type = mgp::List();
|
||||
auto record = record_factory.NewRecord();
|
||||
property_type.AppendExtend(mgp::Value(TypeOf(prop.Type())));
|
||||
ProcessPropertiesNode<mgp::List>(record, type, labels, key, property_type, true);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (const std::exception &e) {
|
||||
record_factory.SetErrorMessage(e.what());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Schema::RelTypeProperties(mgp_list * /*args*/, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) {
|
||||
mgp::MemoryDispatcherGuard guard{memory};
|
||||
const auto record_factory = mgp::RecordFactory(result);
|
||||
try {
|
||||
const mgp::Graph graph = mgp::Graph(memgraph_graph);
|
||||
|
||||
for (auto rel : graph.Relationships()) {
|
||||
std::string type = ":`" + std::string(rel.Type()) + "`";
|
||||
if (rel.Properties().empty()) {
|
||||
auto record = record_factory.NewRecord();
|
||||
ProcessPropertiesRel<std::string>(record, type, "", "", false);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto &[key, prop] : rel.Properties()) {
|
||||
auto property_type = mgp::List();
|
||||
auto record = record_factory.NewRecord();
|
||||
property_type.AppendExtend(mgp::Value(TypeOf(prop.Type())));
|
||||
ProcessPropertiesRel<mgp::List>(record, type, key, property_type, true);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (const std::exception &e) {
|
||||
record_factory.SetErrorMessage(e.what());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void InsertRecordForLabelIndex(const auto &record_factory, const std::string_view label,
|
||||
const std::string_view status) {
|
||||
auto record = record_factory.NewRecord();
|
||||
record.Insert(std::string(Schema::kReturnLabel).c_str(), label);
|
||||
record.Insert(std::string(Schema::kReturnKey).c_str(), "");
|
||||
record.Insert(std::string(Schema::kReturnKeys).c_str(), mgp::List());
|
||||
record.Insert(std::string(Schema::kReturnUnique).c_str(), false);
|
||||
record.Insert(std::string(Schema::kReturnAction).c_str(), status);
|
||||
}
|
||||
|
||||
void InsertRecordForUniqueConstraint(const auto &record_factory, const std::string_view label,
|
||||
const mgp::List &properties, const std::string_view status) {
|
||||
auto record = record_factory.NewRecord();
|
||||
record.Insert(std::string(Schema::kReturnLabel).c_str(), label);
|
||||
record.Insert(std::string(Schema::kReturnKey).c_str(), properties.ToString());
|
||||
record.Insert(std::string(Schema::kReturnKeys).c_str(), properties);
|
||||
record.Insert(std::string(Schema::kReturnUnique).c_str(), true);
|
||||
record.Insert(std::string(Schema::kReturnAction).c_str(), status);
|
||||
}
|
||||
|
||||
void InsertRecordForLabelPropertyIndexAndExistenceConstraint(const auto &record_factory, const std::string_view label,
|
||||
const std::string_view property,
|
||||
const std::string_view status) {
|
||||
auto record = record_factory.NewRecord();
|
||||
record.Insert(std::string(Schema::kReturnLabel).c_str(), label);
|
||||
record.Insert(std::string(Schema::kReturnKey).c_str(), property);
|
||||
record.Insert(std::string(Schema::kReturnKeys).c_str(), mgp::List({mgp::Value(property)}));
|
||||
record.Insert(std::string(Schema::kReturnUnique).c_str(), false);
|
||||
record.Insert(std::string(Schema::kReturnAction).c_str(), status);
|
||||
}
|
||||
|
||||
void ProcessCreatingLabelIndex(const std::string_view label, const std::set<std::string_view> &existing_label_indices,
|
||||
mgp_graph *memgraph_graph, const auto &record_factory) {
|
||||
if (existing_label_indices.contains(label)) {
|
||||
InsertRecordForLabelIndex(record_factory, label, Schema::kStatusKept);
|
||||
} else if (mgp::CreateLabelIndex(memgraph_graph, label)) {
|
||||
InsertRecordForLabelIndex(record_factory, label, Schema::kStatusCreated);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TFunc>
|
||||
void ProcessCreatingLabelPropertyIndexAndExistenceConstraint(const std::string_view label,
|
||||
const std::string_view property,
|
||||
const std::set<std::string_view> &existing_collection,
|
||||
const TFunc &func_creation, mgp_graph *memgraph_graph,
|
||||
const auto &record_factory) {
|
||||
const auto label_property_search_key = std::string(label) + ":" + std::string(property);
|
||||
if (existing_collection.contains(label_property_search_key)) {
|
||||
InsertRecordForLabelPropertyIndexAndExistenceConstraint(record_factory, label, property, Schema::kStatusKept);
|
||||
} else if (func_creation(memgraph_graph, label, property)) {
|
||||
InsertRecordForLabelPropertyIndexAndExistenceConstraint(record_factory, label, property, Schema::kStatusCreated);
|
||||
}
|
||||
}
|
||||
|
||||
/// We collect properties for which index was created.
|
||||
using AssertedIndices = std::set<std::string, std::less<>>;
|
||||
AssertedIndices CreateIndicesForLabel(const std::string_view label, const mgp::Value &properties_val,
|
||||
mgp_graph *memgraph_graph, const auto &record_factory,
|
||||
const std::set<std::string_view> &existing_label_indices,
|
||||
const std::set<std::string_view> &existing_label_property_indices) {
|
||||
AssertedIndices asserted_indices;
|
||||
if (!properties_val.IsList()) {
|
||||
return {};
|
||||
}
|
||||
if (const auto properties = properties_val.ValueList();
|
||||
properties.Empty() && mgp::CreateLabelIndex(memgraph_graph, label)) {
|
||||
InsertRecordForLabelIndex(record_factory, label, Schema::kStatusCreated);
|
||||
asserted_indices.emplace("");
|
||||
} else {
|
||||
std::for_each(properties.begin(), properties.end(),
|
||||
[&label, &existing_label_indices, &existing_label_property_indices, &memgraph_graph, &record_factory,
|
||||
&asserted_indices](const mgp::Value &property) {
|
||||
if (!property.IsString()) {
|
||||
return;
|
||||
}
|
||||
const auto property_str = property.ValueString();
|
||||
if (property_str.empty()) {
|
||||
ProcessCreatingLabelIndex(label, existing_label_indices, memgraph_graph, record_factory);
|
||||
asserted_indices.emplace("");
|
||||
} else {
|
||||
ProcessCreatingLabelPropertyIndexAndExistenceConstraint(
|
||||
label, property_str, existing_label_property_indices, mgp::CreateLabelPropertyIndex,
|
||||
memgraph_graph, record_factory);
|
||||
asserted_indices.emplace(property_str);
|
||||
}
|
||||
});
|
||||
}
|
||||
return asserted_indices;
|
||||
}
|
||||
|
||||
void ProcessIndices(const mgp::Map &indices_map, mgp_graph *memgraph_graph, const auto &record_factory,
|
||||
bool drop_existing) {
|
||||
auto mgp_existing_label_indices = mgp::ListAllLabelIndices(memgraph_graph);
|
||||
auto mgp_existing_label_property_indices = mgp::ListAllLabelPropertyIndices(memgraph_graph);
|
||||
|
||||
std::set<std::string_view> existing_label_indices;
|
||||
std::transform(mgp_existing_label_indices.begin(), mgp_existing_label_indices.end(),
|
||||
std::inserter(existing_label_indices, existing_label_indices.begin()),
|
||||
[](const mgp::Value &index) { return index.ValueString(); });
|
||||
|
||||
std::set<std::string_view> existing_label_property_indices;
|
||||
std::transform(mgp_existing_label_property_indices.begin(), mgp_existing_label_property_indices.end(),
|
||||
std::inserter(existing_label_property_indices, existing_label_property_indices.begin()),
|
||||
[](const mgp::Value &index) { return index.ValueString(); });
|
||||
|
||||
std::set<std::string> asserted_label_indices;
|
||||
std::set<std::string> asserted_label_property_indices;
|
||||
|
||||
auto merge_label_property = [](const std::string &label, const std::string &property) {
|
||||
return label + ":" + property;
|
||||
};
|
||||
|
||||
for (const auto &index : indices_map) {
|
||||
const std::string_view label = index.key;
|
||||
const mgp::Value &properties_val = index.value;
|
||||
|
||||
AssertedIndices asserted_indices_new = CreateIndicesForLabel(
|
||||
label, properties_val, memgraph_graph, record_factory, existing_label_indices, existing_label_property_indices);
|
||||
|
||||
if (!drop_existing) {
|
||||
continue;
|
||||
}
|
||||
std::ranges::for_each(asserted_indices_new, [&asserted_label_indices, &asserted_label_property_indices, label,
|
||||
&merge_label_property](const std::string &property) {
|
||||
if (property.empty()) {
|
||||
asserted_label_indices.emplace(label);
|
||||
} else {
|
||||
asserted_label_property_indices.emplace(merge_label_property(std::string(label), property));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!drop_existing) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::set<std::string_view> label_indices_to_drop;
|
||||
std::ranges::set_difference(existing_label_indices, asserted_label_indices,
|
||||
std::inserter(label_indices_to_drop, label_indices_to_drop.begin()));
|
||||
|
||||
std::ranges::for_each(label_indices_to_drop, [memgraph_graph, &record_factory](const std::string_view label) {
|
||||
if (mgp::DropLabelIndex(memgraph_graph, label)) {
|
||||
InsertRecordForLabelIndex(record_factory, label, Schema::kStatusDropped);
|
||||
}
|
||||
});
|
||||
|
||||
std::set<std::string_view> label_property_indices_to_drop;
|
||||
std::ranges::set_difference(existing_label_property_indices, asserted_label_property_indices,
|
||||
std::inserter(label_property_indices_to_drop, label_property_indices_to_drop.begin()));
|
||||
|
||||
auto decouple_label_property = [](const std::string_view label_property) {
|
||||
const auto label_size = label_property.find(':');
|
||||
const auto label = std::string(label_property.substr(0, label_size));
|
||||
const auto property = std::string(label_property.substr(label_size + 1));
|
||||
return std::make_pair(label, property);
|
||||
};
|
||||
|
||||
std::ranges::for_each(label_property_indices_to_drop, [memgraph_graph, &record_factory, decouple_label_property](
|
||||
const std::string_view label_property) {
|
||||
const auto [label, property] = decouple_label_property(label_property);
|
||||
if (mgp::DropLabelPropertyIndex(memgraph_graph, label, property)) {
|
||||
InsertRecordForLabelPropertyIndexAndExistenceConstraint(record_factory, label, property, Schema::kStatusDropped);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
using ExistenceConstraintsStorage = std::set<std::string_view>;
|
||||
|
||||
ExistenceConstraintsStorage CreateExistenceConstraintsForLabel(
|
||||
const std::string_view label, const mgp::Value &properties_val, mgp_graph *memgraph_graph,
|
||||
const auto &record_factory, const std::set<std::string_view> &existing_existence_constraints) {
|
||||
ExistenceConstraintsStorage asserted_existence_constraints;
|
||||
if (!properties_val.IsList()) {
|
||||
return asserted_existence_constraints;
|
||||
}
|
||||
|
||||
auto validate_property = [](const mgp::Value &property) -> bool {
|
||||
return property.IsString() && !property.ValueString().empty();
|
||||
};
|
||||
|
||||
const auto &properties = properties_val.ValueList();
|
||||
std::for_each(properties.begin(), properties.end(),
|
||||
[&label, &existing_existence_constraints, &asserted_existence_constraints, &memgraph_graph,
|
||||
&record_factory, &validate_property](const mgp::Value &property) {
|
||||
if (!validate_property(property)) {
|
||||
return;
|
||||
}
|
||||
const std::string_view property_str = property.ValueString();
|
||||
asserted_existence_constraints.emplace(property_str);
|
||||
ProcessCreatingLabelPropertyIndexAndExistenceConstraint(
|
||||
label, property_str, existing_existence_constraints, mgp::CreateExistenceConstraint,
|
||||
memgraph_graph, record_factory);
|
||||
});
|
||||
return asserted_existence_constraints;
|
||||
}
|
||||
|
||||
void ProcessExistenceConstraints(const mgp::Map &existence_constraints_map, mgp_graph *memgraph_graph,
|
||||
const auto &record_factory, bool drop_existing) {
|
||||
auto mgp_existing_existence_constraints = mgp::ListAllExistenceConstraints(memgraph_graph);
|
||||
std::set<std::string_view> existing_existence_constraints;
|
||||
std::transform(mgp_existing_existence_constraints.begin(), mgp_existing_existence_constraints.end(),
|
||||
std::inserter(existing_existence_constraints, existing_existence_constraints.begin()),
|
||||
[](const mgp::Value &constraint) { return constraint.ValueString(); });
|
||||
|
||||
auto merge_label_property = [](const std::string_view label, const std::string_view property) {
|
||||
auto str = std::string(label) + ":";
|
||||
str += property;
|
||||
return str;
|
||||
};
|
||||
|
||||
ExistenceConstraintsStorage asserted_existence_constraints;
|
||||
|
||||
for (const auto &existing_constraint : existence_constraints_map) {
|
||||
const std::string_view label = existing_constraint.key;
|
||||
const mgp::Value &properties_val = existing_constraint.value;
|
||||
auto asserted_existence_constraints_new = CreateExistenceConstraintsForLabel(
|
||||
label, properties_val, memgraph_graph, record_factory, existing_existence_constraints);
|
||||
if (!drop_existing) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::ranges::for_each(asserted_existence_constraints_new, [&asserted_existence_constraints, &merge_label_property,
|
||||
label](const std::string_view property) {
|
||||
asserted_existence_constraints.emplace(merge_label_property(label, property));
|
||||
});
|
||||
}
|
||||
|
||||
if (!drop_existing) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::set<std::string_view> existence_constraints_to_drop;
|
||||
std::ranges::set_difference(existing_existence_constraints, asserted_existence_constraints,
|
||||
std::inserter(existence_constraints_to_drop, existence_constraints_to_drop.begin()));
|
||||
|
||||
auto decouple_label_property = [](const std::string_view label_property) {
|
||||
const auto label_size = label_property.find(':');
|
||||
const auto label = std::string(label_property.substr(0, label_size));
|
||||
const auto property = std::string(label_property.substr(label_size + 1));
|
||||
return std::make_pair(label, property);
|
||||
};
|
||||
|
||||
std::ranges::for_each(existence_constraints_to_drop, [&](const std::string_view label_property) {
|
||||
const auto [label, property] = decouple_label_property(label_property);
|
||||
if (mgp::DropExistenceConstraint(memgraph_graph, label, property)) {
|
||||
InsertRecordForLabelPropertyIndexAndExistenceConstraint(record_factory, label, property, Schema::kStatusDropped);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
using AssertedUniqueConstraintsStorage = std::set<std::set<std::string_view>>;
|
||||
AssertedUniqueConstraintsStorage CreateUniqueConstraintsForLabel(
|
||||
const std::string_view label, const mgp::Value &unique_props_nested,
|
||||
const std::map<std::string_view, AssertedUniqueConstraintsStorage> &existing_unique_constraints,
|
||||
mgp_graph *memgraph_graph, const auto &record_factory) {
|
||||
AssertedUniqueConstraintsStorage asserted_unique_constraints;
|
||||
if (!unique_props_nested.IsList()) {
|
||||
return asserted_unique_constraints;
|
||||
}
|
||||
|
||||
auto validate_unique_constraint_props = [](const mgp::Value &properties) -> bool {
|
||||
if (!properties.IsList()) {
|
||||
return false;
|
||||
}
|
||||
const auto &properties_list = properties.ValueList();
|
||||
if (properties_list.Empty()) {
|
||||
return false;
|
||||
}
|
||||
return std::all_of(properties_list.begin(), properties_list.end(), [](const mgp::Value &property) {
|
||||
return property.IsString() && !property.ValueString().empty();
|
||||
});
|
||||
};
|
||||
|
||||
auto unique_constraint_exists =
|
||||
[](const std::string_view label, const std::set<std::string_view> &properties,
|
||||
const std::map<std::string_view, AssertedUniqueConstraintsStorage> &existing_unique_constraints) -> bool {
|
||||
auto iter = existing_unique_constraints.find(label);
|
||||
if (iter == existing_unique_constraints.end()) {
|
||||
return false;
|
||||
}
|
||||
return iter->second.find(properties) != iter->second.end();
|
||||
};
|
||||
|
||||
for (const auto unique_props_nested_list = unique_props_nested.ValueList();
|
||||
const auto &properties : unique_props_nested_list) {
|
||||
if (!validate_unique_constraint_props(properties)) {
|
||||
continue;
|
||||
}
|
||||
const auto properties_list = properties.ValueList();
|
||||
std::set<std::string_view> properties_coll;
|
||||
std::transform(properties_list.begin(), properties_list.end(),
|
||||
std::inserter(properties_coll, properties_coll.begin()),
|
||||
[](const mgp::Value &property) { return property.ValueString(); });
|
||||
|
||||
if (unique_constraint_exists(label, properties_coll, existing_unique_constraints)) {
|
||||
InsertRecordForUniqueConstraint(record_factory, label, properties_list, Schema::kStatusKept);
|
||||
} else if (mgp::CreateUniqueConstraint(memgraph_graph, label, properties.ptr())) {
|
||||
InsertRecordForUniqueConstraint(record_factory, label, properties_list, Schema::kStatusCreated);
|
||||
}
|
||||
asserted_unique_constraints.emplace(std::move(properties_coll));
|
||||
}
|
||||
return asserted_unique_constraints;
|
||||
}
|
||||
|
||||
void ProcessUniqueConstraints(const mgp::Map &unique_constraints_map, mgp_graph *memgraph_graph,
|
||||
const auto &record_factory, bool drop_existing) {
|
||||
auto mgp_existing_unique_constraints = mgp::ListAllUniqueConstraints(memgraph_graph);
|
||||
// label-unique_constraints pair
|
||||
std::map<std::string_view, AssertedUniqueConstraintsStorage> existing_unique_constraints;
|
||||
for (const auto &constraint : mgp_existing_unique_constraints) {
|
||||
auto constraint_list = constraint.ValueList();
|
||||
std::set<std::string_view> properties;
|
||||
for (int i = 1; i < constraint_list.Size(); i++) {
|
||||
properties.emplace(constraint_list[i].ValueString());
|
||||
}
|
||||
const std::string_view label = constraint_list[0].ValueString();
|
||||
auto [it, inserted] = existing_unique_constraints.try_emplace(label, AssertedUniqueConstraintsStorage{properties});
|
||||
if (!inserted) {
|
||||
it->second.emplace(std::move(properties));
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string_view, AssertedUniqueConstraintsStorage> asserted_unique_constraints;
|
||||
|
||||
for (const auto &[label, unique_props_nested] : unique_constraints_map) {
|
||||
auto asserted_unique_constraints_new = CreateUniqueConstraintsForLabel(
|
||||
label, unique_props_nested, existing_unique_constraints, memgraph_graph, record_factory);
|
||||
if (drop_existing) {
|
||||
asserted_unique_constraints.emplace(label, std::move(asserted_unique_constraints_new));
|
||||
}
|
||||
}
|
||||
|
||||
if (!drop_existing) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string_view, std::set<std::string_view>>> unique_constraints_to_drop;
|
||||
|
||||
// Check for each label for we found existing constraint in the DB whether it was asserted.
|
||||
// If no unique constraint was found with label, we can drop all unique constraints for this label. (if branch)
|
||||
// If some unique constraint was found with label, we can drop only those unique constraints that were not asserted.
|
||||
// (else branch.)
|
||||
std::ranges::for_each(existing_unique_constraints, [&asserted_unique_constraints, &unique_constraints_to_drop](
|
||||
const auto &existing_label_unique_constraints) {
|
||||
const auto &label = existing_label_unique_constraints.first;
|
||||
const auto &existing_unique_constraints_for_label = existing_label_unique_constraints.second;
|
||||
const auto &asserted_unique_constraints_for_label = asserted_unique_constraints.find(label);
|
||||
if (asserted_unique_constraints_for_label == asserted_unique_constraints.end()) {
|
||||
std::ranges::for_each(
|
||||
std::make_move_iterator(existing_unique_constraints_for_label.begin()),
|
||||
std::make_move_iterator(existing_unique_constraints_for_label.end()),
|
||||
[&unique_constraints_to_drop, &label](std::set<std::string_view> existing_unique_constraint_for_label) {
|
||||
unique_constraints_to_drop.emplace_back(label, std::move(existing_unique_constraint_for_label));
|
||||
});
|
||||
} else {
|
||||
const auto &asserted_unique_constraints_for_label_coll = asserted_unique_constraints_for_label->second;
|
||||
std::ranges::for_each(
|
||||
std::make_move_iterator(existing_unique_constraints_for_label.begin()),
|
||||
std::make_move_iterator(existing_unique_constraints_for_label.end()),
|
||||
[&unique_constraints_to_drop, &label, &asserted_unique_constraints_for_label_coll](
|
||||
std::set<std::string_view> existing_unique_constraint_for_label) {
|
||||
if (!asserted_unique_constraints_for_label_coll.contains(existing_unique_constraint_for_label)) {
|
||||
unique_constraints_to_drop.emplace_back(label, std::move(existing_unique_constraint_for_label));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
std::ranges::for_each(
|
||||
unique_constraints_to_drop, [memgraph_graph, &record_factory](const auto &label_unique_constraint) {
|
||||
const auto &[label, unique_constraint] = label_unique_constraint;
|
||||
|
||||
auto unique_constraint_list = mgp::List();
|
||||
std::ranges::for_each(unique_constraint, [&unique_constraint_list](const std::string_view &property) {
|
||||
unique_constraint_list.AppendExtend(mgp::Value(property));
|
||||
});
|
||||
|
||||
if (mgp::DropUniqueConstraint(memgraph_graph, label, mgp::Value(unique_constraint_list).ptr())) {
|
||||
InsertRecordForUniqueConstraint(record_factory, label, unique_constraint_list, Schema::kStatusDropped);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Schema::Assert(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) {
|
||||
mgp::MemoryDispatcherGuard guard{memory};
|
||||
const auto record_factory = mgp::RecordFactory(result);
|
||||
auto arguments = mgp::List(args);
|
||||
auto indices_map = arguments[0].ValueMap();
|
||||
auto unique_constraints_map = arguments[1].ValueMap();
|
||||
auto existence_constraints_map = arguments[2].ValueMap();
|
||||
auto drop_existing = arguments[3].ValueBool();
|
||||
|
||||
ProcessIndices(indices_map, memgraph_graph, record_factory, drop_existing);
|
||||
ProcessExistenceConstraints(existence_constraints_map, memgraph_graph, record_factory, drop_existing);
|
||||
ProcessUniqueConstraints(unique_constraints_map, memgraph_graph, record_factory, drop_existing);
|
||||
}
|
||||
|
||||
extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) {
|
||||
try {
|
||||
mgp::MemoryDispatcherGuard guard{memory};
|
||||
|
||||
AddProcedure(Schema::NodeTypeProperties, Schema::kProcedureNodeType, mgp::ProcedureType::Read, {},
|
||||
{mgp::Return(Schema::kReturnNodeType, mgp::Type::String),
|
||||
mgp::Return(Schema::kReturnLabels, {mgp::Type::List, mgp::Type::String}),
|
||||
mgp::Return(Schema::kReturnPropertyName, mgp::Type::String),
|
||||
mgp::Return(Schema::kReturnPropertyType, mgp::Type::Any),
|
||||
mgp::Return(Schema::kReturnMandatory, mgp::Type::Bool)},
|
||||
module, memory);
|
||||
|
||||
AddProcedure(Schema::RelTypeProperties, Schema::kProcedureRelType, mgp::ProcedureType::Read, {},
|
||||
{mgp::Return(Schema::kReturnRelType, mgp::Type::String),
|
||||
mgp::Return(Schema::kReturnPropertyName, mgp::Type::String),
|
||||
mgp::Return(Schema::kReturnPropertyType, mgp::Type::Any),
|
||||
mgp::Return(Schema::kReturnMandatory, mgp::Type::Bool)},
|
||||
module, memory);
|
||||
AddProcedure(
|
||||
Schema::Assert, Schema::kProcedureAssert, mgp::ProcedureType::Read,
|
||||
{
|
||||
mgp::Parameter(Schema::kParameterIndices, {mgp::Type::Map, mgp::Type::Any}),
|
||||
mgp::Parameter(Schema::kParameterUniqueConstraints, {mgp::Type::Map, mgp::Type::Any}),
|
||||
mgp::Parameter(Schema::kParameterExistenceConstraints, {mgp::Type::Map, mgp::Type::Any},
|
||||
mgp::Value(mgp::Map{})),
|
||||
mgp::Parameter(Schema::kParameterDropExisting, mgp::Type::Bool, mgp::Value(true)),
|
||||
},
|
||||
{mgp::Return(Schema::kReturnLabel, mgp::Type::String), mgp::Return(Schema::kReturnKey, mgp::Type::String),
|
||||
mgp::Return(Schema::kReturnKeys, {mgp::Type::List, mgp::Type::String}),
|
||||
mgp::Return(Schema::kReturnUnique, mgp::Type::Bool), mgp::Return(Schema::kReturnAction, mgp::Type::String)},
|
||||
module, memory);
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "Error while initializing query module: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int mgp_shutdown_module() { return 0; }
|
||||
@@ -104,9 +104,7 @@ def retry(retry_limit, timeout=100):
|
||||
except Exception:
|
||||
time.sleep(timeout)
|
||||
return func(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
return inner_func
|
||||
|
||||
|
||||
@@ -202,19 +200,19 @@ if args.version:
|
||||
try:
|
||||
current_branch = get_output("git", "rev-parse", "--abbrev-ref", "HEAD")
|
||||
if current_branch != "master":
|
||||
branches = get_output("git", "branch", "-r", "--list", "origin/master")
|
||||
if "origin/master" in branches:
|
||||
branches = get_output("git", "branch")
|
||||
if "master" in branches:
|
||||
# If master is present locally, the fetch is allowed to fail
|
||||
# because this script will still be able to compare against the
|
||||
# master branch.
|
||||
try:
|
||||
get_output("git", "fetch", "origin", "master")
|
||||
get_output("git", "fetch", "origin", "master:master")
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
# If master is not present locally, the fetch command has to
|
||||
# succeed because something else will fail otherwise.
|
||||
get_output("git", "fetch", "origin", "master")
|
||||
get_output("git", "fetch", "origin", "master:master")
|
||||
except Exception:
|
||||
print("Fatal error while ensuring local master branch.")
|
||||
sys.exit(1)
|
||||
@@ -234,7 +232,7 @@ for branch in branches:
|
||||
match = branch_regex.match(branch)
|
||||
if match is not None:
|
||||
version = tuple(map(int, match.group(1).split(".")))
|
||||
master_branch_merge = get_output("git", "merge-base", "origin/master", branch)
|
||||
master_branch_merge = get_output("git", "merge-base", "master", branch)
|
||||
versions.append((version, branch, master_branch_merge))
|
||||
versions.sort(reverse=True)
|
||||
|
||||
@@ -245,7 +243,7 @@ current_version = None
|
||||
for version in versions:
|
||||
version_tuple, branch, master_branch_merge = version
|
||||
current_branch_merge = get_output("git", "merge-base", current_hash, branch)
|
||||
master_current_merge = get_output("git", "merge-base", current_hash, "origin/master")
|
||||
master_current_merge = get_output("git", "merge-base", current_hash, "master")
|
||||
# The first check checks whether this commit is a child of `master` and
|
||||
# the version branch was created before us.
|
||||
# The second check checks whether this commit is a child of the version
|
||||
|
||||
@@ -1,27 +1,12 @@
|
||||
[Unit]
|
||||
Description=Memgraph: High performance, in-memory, transactional graph database
|
||||
|
||||
# Auto-restart config
|
||||
#StartLimitIntervalSec=300
|
||||
#StartLimitBurst=5
|
||||
|
||||
[Service]
|
||||
User=memgraph
|
||||
Group=memgraph
|
||||
ExecStart=/usr/lib/memgraph/memgraph
|
||||
|
||||
# Uncomment this if Memgraph needs more time to write the snapshot on exit.
|
||||
#TimeoutStopSec=5min
|
||||
|
||||
# Auto-restart config
|
||||
#Restart=on-failure
|
||||
#RestartSec=10s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
# Checks processes' memory usage and force kills it when it is taking up enough
|
||||
# memory to make the system unstable / about to crash, e.g. on Debian-based OS:
|
||||
# apt install systemd-oomd
|
||||
# systemctl enable systemd-oomd
|
||||
# systemctl start systemd-oomd
|
||||
|
||||
@@ -72,10 +72,6 @@ make_package () {
|
||||
if [[ "$(git rev-parse --abbrev-ref HEAD)" != "master" ]]; then
|
||||
git fetch origin master:master
|
||||
fi
|
||||
|
||||
# Ensure we have a clean build directory
|
||||
docker exec "$build_container" rm -rf /memgraph
|
||||
|
||||
docker exec "$build_container" mkdir -p /memgraph
|
||||
# TODO(gitbuda): Revisit copying the whole repo -> makese sense under CI.
|
||||
docker cp "$PROJECT_ROOT/." "$build_container:/memgraph/"
|
||||
|
||||
@@ -143,7 +143,7 @@ install(CODE "file(MAKE_DIRECTORY \$ENV{DESTDIR}/var/log/memgraph
|
||||
# Memgraph CSV Import Tool Executable
|
||||
# ----------------------------------------------------------------------------
|
||||
add_executable(mg_import_csv mg_import_csv.cpp)
|
||||
target_link_libraries(mg_import_csv mg-storage-v2 mg-dbms)
|
||||
target_link_libraries(mg_import_csv mg-storage-v2)
|
||||
|
||||
# Strip the executable in release build.
|
||||
if(lower_build_type STREQUAL "release")
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <json/json.hpp>
|
||||
#include <utility>
|
||||
|
||||
#include "storage/v2/temporal.hpp"
|
||||
#include "utils/logging.hpp"
|
||||
@@ -88,8 +87,8 @@ inline nlohmann::json PropertyValueToJson(const storage::PropertyValue &pv) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
Log::Log(std::filesystem::path storage_directory, int32_t buffer_size, int32_t buffer_flush_interval_millis)
|
||||
: storage_directory_(std::move(storage_directory)),
|
||||
Log::Log(const std::filesystem::path &storage_directory, int32_t buffer_size, int32_t buffer_flush_interval_millis)
|
||||
: storage_directory_(storage_directory),
|
||||
buffer_size_(buffer_size),
|
||||
buffer_flush_interval_millis_(buffer_flush_interval_millis),
|
||||
started_(false) {}
|
||||
|
||||
@@ -36,7 +36,7 @@ class Log {
|
||||
};
|
||||
|
||||
public:
|
||||
Log(std::filesystem::path storage_directory, int32_t buffer_size, int32_t buffer_flush_interval_millis);
|
||||
Log(const std::filesystem::path &storage_directory, int32_t buffer_size, int32_t buffer_flush_interval_millis);
|
||||
|
||||
~Log();
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <regex>
|
||||
#include <utility>
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
|
||||
@@ -561,20 +560,20 @@ Databases Databases::Deserialize(const nlohmann::json &data) {
|
||||
}
|
||||
#endif
|
||||
|
||||
User::User() = default;
|
||||
User::User() {}
|
||||
|
||||
User::User(const std::string &username) : username_(utils::ToLowerCase(username)) {}
|
||||
User::User(const std::string &username, std::string password_hash, const Permissions &permissions)
|
||||
: username_(utils::ToLowerCase(username)), password_hash_(std::move(password_hash)), permissions_(permissions) {}
|
||||
User::User(const std::string &username, const std::string &password_hash, const Permissions &permissions)
|
||||
: username_(utils::ToLowerCase(username)), password_hash_(password_hash), permissions_(permissions) {}
|
||||
|
||||
#ifdef MG_ENTERPRISE
|
||||
User::User(const std::string &username, std::string password_hash, const Permissions &permissions,
|
||||
User::User(const std::string &username, const std::string &password_hash, const Permissions &permissions,
|
||||
FineGrainedAccessHandler fine_grained_access_handler, Databases db_access)
|
||||
: username_(utils::ToLowerCase(username)),
|
||||
password_hash_(std::move(password_hash)),
|
||||
password_hash_(password_hash),
|
||||
permissions_(permissions),
|
||||
fine_grained_access_handler_(std::move(fine_grained_access_handler)),
|
||||
database_access_(std::move(db_access)) {}
|
||||
database_access_(db_access) {}
|
||||
#endif
|
||||
|
||||
bool User::CheckPassword(const std::string &password) {
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <unordered_map>
|
||||
|
||||
#include <json/json.hpp>
|
||||
#include <utility>
|
||||
#include "dbms/constants.hpp"
|
||||
#include "utils/logging.hpp"
|
||||
|
||||
@@ -302,8 +301,8 @@ class Databases final {
|
||||
bool Contains(const std::string &db) const;
|
||||
|
||||
bool GetAllowAll() const { return allow_all_; }
|
||||
const std::set<std::string, std::less<>> &GetGrants() const { return grants_dbs_; }
|
||||
const std::set<std::string, std::less<>> &GetDenies() const { return denies_dbs_; }
|
||||
const std::set<std::string> &GetGrants() const { return grants_dbs_; }
|
||||
const std::set<std::string> &GetDenies() const { return denies_dbs_; }
|
||||
const std::string &GetDefault() const;
|
||||
|
||||
nlohmann::json Serialize() const;
|
||||
@@ -311,17 +310,14 @@ class Databases final {
|
||||
static Databases Deserialize(const nlohmann::json &data);
|
||||
|
||||
private:
|
||||
Databases(bool allow_all, std::set<std::string, std::less<>> grant, std::set<std::string, std::less<>> deny,
|
||||
std::string default_db = dbms::kDefaultDB)
|
||||
: grants_dbs_(std::move(grant)),
|
||||
denies_dbs_(std::move(deny)),
|
||||
allow_all_(allow_all),
|
||||
default_db_(std::move(default_db)) {}
|
||||
Databases(bool allow_all, std::set<std::string> grant, std::set<std::string> deny,
|
||||
const std::string &default_db = dbms::kDefaultDB)
|
||||
: grants_dbs_(grant), denies_dbs_(deny), allow_all_(allow_all), default_db_(default_db) {}
|
||||
|
||||
std::set<std::string, std::less<>> grants_dbs_; //!< set of databases with granted access
|
||||
std::set<std::string, std::less<>> denies_dbs_; //!< set of databases with denied access
|
||||
bool allow_all_; //!< flag to allow access to everything (denied overrides this)
|
||||
std::string default_db_; //!< user's default database
|
||||
std::set<std::string> grants_dbs_; //!< set of databases with granted access
|
||||
std::set<std::string> denies_dbs_; //!< set of databases with denied access
|
||||
bool allow_all_; //!< flag to allow access to everything (denied overrides this)
|
||||
std::string default_db_; //!< user's default database
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -331,9 +327,9 @@ class User final {
|
||||
User();
|
||||
|
||||
explicit User(const std::string &username);
|
||||
User(const std::string &username, std::string password_hash, const Permissions &permissions);
|
||||
User(const std::string &username, const std::string &password_hash, const Permissions &permissions);
|
||||
#ifdef MG_ENTERPRISE
|
||||
User(const std::string &username, std::string password_hash, const Permissions &permissions,
|
||||
User(const std::string &username, const std::string &password_hash, const Permissions &permissions,
|
||||
FineGrainedAccessHandler fine_grained_access_handler, Databases db_access = {});
|
||||
#endif
|
||||
User(const User &) = default;
|
||||
|
||||
@@ -25,3 +25,4 @@ target_link_libraries(mg-communication Boost::headers Threads::Threads mg-utils
|
||||
find_package(OpenSSL REQUIRED)
|
||||
target_link_libraries(mg-communication ${OPENSSL_LIBRARIES})
|
||||
target_include_directories(mg-communication SYSTEM PUBLIC ${OPENSSL_INCLUDE_DIR})
|
||||
target_precompile_headers(mg-communication INTERFACE http/server.hpp <boost/beast/websocket.hpp> bolt/v1/session.hpp)
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "communication/bolt/v1/codes.hpp"
|
||||
@@ -35,8 +34,8 @@ class FailureResponseException : public utils::BasicException {
|
||||
|
||||
explicit FailureResponseException(const std::string &message) : utils::BasicException{message} {}
|
||||
|
||||
FailureResponseException(std::string code, const std::string &message)
|
||||
: utils::BasicException{message}, code_{std::move(code)} {}
|
||||
FailureResponseException(const std::string &code, const std::string &message)
|
||||
: utils::BasicException{message}, code_{code} {}
|
||||
|
||||
const std::string &code() const { return code_; }
|
||||
SPECIALIZE_GET_EXCEPTION_NAME(FailureResponseException)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2023 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
|
||||
@@ -51,7 +51,7 @@ enum class ChunkState : uint8_t {
|
||||
template <typename TBuffer>
|
||||
class ChunkedDecoderBuffer {
|
||||
public:
|
||||
explicit ChunkedDecoderBuffer(TBuffer &buffer) : buffer_(buffer) { data_.reserve(kChunkMaxDataSize); }
|
||||
ChunkedDecoderBuffer(TBuffer &buffer) : buffer_(buffer) { data_.reserve(kChunkMaxDataSize); }
|
||||
|
||||
/**
|
||||
* Reads data from the internal buffer.
|
||||
|
||||
@@ -401,11 +401,11 @@ class Decoder {
|
||||
}
|
||||
auto &labels = dv.ValueList();
|
||||
vertex.labels.reserve(labels.size());
|
||||
for (auto &label : labels) {
|
||||
if (label.type() != Value::Type::String) {
|
||||
for (size_t i = 0; i < labels.size(); ++i) {
|
||||
if (labels[i].type() != Value::Type::String) {
|
||||
return false;
|
||||
}
|
||||
vertex.labels.emplace_back(std::move(label.ValueString()));
|
||||
vertex.labels.emplace_back(std::move(labels[i].ValueString()));
|
||||
}
|
||||
|
||||
// read properties
|
||||
|
||||
@@ -111,12 +111,12 @@ class BaseEncoder {
|
||||
|
||||
void WriteList(const std::vector<Value> &value) {
|
||||
WriteTypeSize(value.size(), MarkerList);
|
||||
for (const auto &x : value) WriteValue(x);
|
||||
for (auto &x : value) WriteValue(x);
|
||||
}
|
||||
|
||||
void WriteMap(const std::map<std::string, Value> &value) {
|
||||
WriteTypeSize(value.size(), MarkerMap);
|
||||
for (const auto &x : value) {
|
||||
for (auto &x : value) {
|
||||
WriteString(x.first);
|
||||
WriteValue(x.second);
|
||||
}
|
||||
@@ -205,11 +205,11 @@ class BaseEncoder {
|
||||
WriteRAW(utils::UnderlyingCast(Marker::TinyStruct) + 3);
|
||||
WriteRAW(utils::UnderlyingCast(Signature::Path));
|
||||
WriteTypeSize(path.vertices.size(), MarkerList);
|
||||
for (const auto &v : path.vertices) WriteVertex(v);
|
||||
for (auto &v : path.vertices) WriteVertex(v);
|
||||
WriteTypeSize(path.edges.size(), MarkerList);
|
||||
for (const auto &e : path.edges) WriteEdge(e);
|
||||
for (auto &e : path.edges) WriteEdge(e);
|
||||
WriteTypeSize(path.indices.size(), MarkerList);
|
||||
for (const auto &i : path.indices) WriteInt(i);
|
||||
for (auto &i : path.indices) WriteInt(i);
|
||||
}
|
||||
|
||||
void WriteDate(const utils::Date &date) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2023 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
|
||||
@@ -48,7 +48,7 @@ namespace memgraph::communication::bolt {
|
||||
template <class TOutputStream>
|
||||
class ChunkedEncoderBuffer {
|
||||
public:
|
||||
explicit ChunkedEncoderBuffer(TOutputStream &output_stream) : output_stream_(output_stream) {}
|
||||
ChunkedEncoderBuffer(TOutputStream &output_stream) : output_stream_(output_stream) {}
|
||||
|
||||
/**
|
||||
* Writes n values into the buffer. If n is bigger than whole chunk size
|
||||
|
||||
@@ -39,7 +39,7 @@ class ClientEncoder : private BaseEncoder<Buffer> {
|
||||
using BaseEncoder<Buffer>::buffer_;
|
||||
|
||||
public:
|
||||
explicit ClientEncoder(Buffer &buffer) : BaseEncoder<Buffer>(buffer) {}
|
||||
ClientEncoder(Buffer &buffer) : BaseEncoder<Buffer>(buffer) {}
|
||||
|
||||
using BaseEncoder<Buffer>::UpdateVersion;
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ class Encoder : private BaseEncoder<Buffer> {
|
||||
using BaseEncoder<Buffer>::buffer_;
|
||||
|
||||
public:
|
||||
explicit Encoder(Buffer &buffer) : BaseEncoder<Buffer>(buffer) {}
|
||||
Encoder(Buffer &buffer) : BaseEncoder<Buffer>(buffer) {}
|
||||
|
||||
using BaseEncoder<Buffer>::UpdateVersion;
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ State HandlePullDiscard(TSession &session, std::optional<int> n, std::optional<i
|
||||
return State::Close;
|
||||
}
|
||||
|
||||
if (summary.contains("has_more") && summary.at("has_more").ValueBool()) {
|
||||
if (summary.count("has_more") && summary.at("has_more").ValueBool()) {
|
||||
return State::Result;
|
||||
}
|
||||
|
||||
@@ -148,13 +148,13 @@ State HandlePullDiscardV4(TSession &session, const State state, const Marker mar
|
||||
spdlog::trace("Couldn't read extra field!");
|
||||
}
|
||||
const auto &extra_map = extra.ValueMap();
|
||||
if (extra_map.contains("n")) {
|
||||
if (extra_map.count("n")) {
|
||||
if (const auto n_value = extra_map.at("n").ValueInt(); n_value != kPullAll) {
|
||||
n = n_value;
|
||||
}
|
||||
}
|
||||
|
||||
if (extra_map.contains("qid")) {
|
||||
if (extra_map.count("qid")) {
|
||||
if (const auto qid_value = extra_map.at("qid").ValueInt(); qid_value != kPullLast) {
|
||||
qid = qid_value;
|
||||
}
|
||||
@@ -209,11 +209,7 @@ State HandleRunV1(TSession &session, const State state, const Marker marker) {
|
||||
|
||||
DMG_ASSERT(!session.encoder_buffer_.HasData(), "There should be no data to write in this state");
|
||||
|
||||
#if MG_ENTERPRISE
|
||||
spdlog::debug("[Run - {}] '{}'", session.GetCurrentDB(), query.ValueString());
|
||||
#else
|
||||
spdlog::debug("[Run] '{}'", query.ValueString());
|
||||
#endif
|
||||
|
||||
// Increment number of queries in the metrics
|
||||
IncrementQueryMetrics(session);
|
||||
@@ -280,11 +276,7 @@ State HandleRunV4(TSession &session, const State state, const Marker marker) {
|
||||
return HandleFailure(session, e);
|
||||
}
|
||||
|
||||
#if MG_ENTERPRISE
|
||||
spdlog::debug("[Run - {}] '{}'", session.GetCurrentDB(), query.ValueString());
|
||||
#else
|
||||
spdlog::debug("[Run] '{}'", query.ValueString());
|
||||
#endif
|
||||
|
||||
// Increment number of queries in the metrics
|
||||
IncrementQueryMetrics(session);
|
||||
@@ -367,16 +359,14 @@ State HandleReset(TSession &session, const Marker marker) {
|
||||
return State::Close;
|
||||
}
|
||||
|
||||
try {
|
||||
session.Abort();
|
||||
if (!session.encoder_.MessageSuccess({})) {
|
||||
spdlog::trace("Couldn't send success message!");
|
||||
return State::Close;
|
||||
}
|
||||
return State::Idle;
|
||||
} catch (const std::exception &e) {
|
||||
return HandleFailure(session, e);
|
||||
if (!session.encoder_.MessageSuccess()) {
|
||||
spdlog::trace("Couldn't send success message!");
|
||||
return State::Close;
|
||||
}
|
||||
|
||||
session.Abort();
|
||||
|
||||
return State::Idle;
|
||||
}
|
||||
|
||||
template <typename TSession>
|
||||
@@ -399,17 +389,19 @@ State HandleBegin(TSession &session, const State state, const Marker marker) {
|
||||
|
||||
DMG_ASSERT(!session.encoder_buffer_.HasData(), "There should be no data to write in this state");
|
||||
|
||||
if (!session.encoder_.MessageSuccess({})) {
|
||||
spdlog::trace("Couldn't send success message!");
|
||||
return State::Close;
|
||||
}
|
||||
|
||||
try {
|
||||
session.Configure(extra.ValueMap());
|
||||
session.BeginTransaction(extra.ValueMap());
|
||||
if (!session.encoder_.MessageSuccess({})) {
|
||||
spdlog::trace("Couldn't send success message!");
|
||||
return State::Close;
|
||||
}
|
||||
return State::Idle;
|
||||
} catch (const std::exception &e) {
|
||||
return HandleFailure(session, e);
|
||||
}
|
||||
|
||||
return State::Idle;
|
||||
}
|
||||
|
||||
template <typename TSession>
|
||||
@@ -427,11 +419,11 @@ State HandleCommit(TSession &session, const State state, const Marker marker) {
|
||||
DMG_ASSERT(!session.encoder_buffer_.HasData(), "There should be no data to write in this state");
|
||||
|
||||
try {
|
||||
session.CommitTransaction();
|
||||
if (!session.encoder_.MessageSuccess({})) {
|
||||
spdlog::trace("Couldn't send success message!");
|
||||
return State::Close;
|
||||
}
|
||||
session.CommitTransaction();
|
||||
return State::Idle;
|
||||
} catch (const std::exception &e) {
|
||||
return HandleFailure(session, e);
|
||||
@@ -453,11 +445,11 @@ State HandleRollback(TSession &session, const State state, const Marker marker)
|
||||
DMG_ASSERT(!session.encoder_buffer_.HasData(), "There should be no data to write in this state");
|
||||
|
||||
try {
|
||||
session.RollbackTransaction();
|
||||
if (!session.encoder_.MessageSuccess({})) {
|
||||
spdlog::trace("Couldn't send success message!");
|
||||
return State::Close;
|
||||
}
|
||||
session.RollbackTransaction();
|
||||
return State::Idle;
|
||||
} catch (const std::exception &e) {
|
||||
return HandleFailure(session, e);
|
||||
|
||||
@@ -42,11 +42,11 @@ std::optional<State> AuthenticateUser(TSession &session, Value &metadata) {
|
||||
std::string username;
|
||||
std::string password;
|
||||
if (data["scheme"].ValueString() == "basic") {
|
||||
if (!data.contains("principal")) { // Special case principal = ""
|
||||
if (!data.count("principal")) { // Special case principal = ""
|
||||
spdlog::warn("The client didn't supply the principal field! Trying with \"\"...");
|
||||
data["principal"] = "";
|
||||
}
|
||||
if (!data.contains("credentials")) { // Special case credentials = ""
|
||||
if (!data.count("credentials")) { // Special case credentials = ""
|
||||
spdlog::warn("The client didn't supply the credentials field! Trying with \"\"...");
|
||||
data["credentials"] = "";
|
||||
}
|
||||
@@ -118,7 +118,7 @@ std::optional<Value> GetMetadataV4(TSession &session, const Marker marker) {
|
||||
}
|
||||
|
||||
auto &data = metadata.ValueMap();
|
||||
if (!data.contains("user_agent")) {
|
||||
if (!data.count("user_agent")) {
|
||||
spdlog::warn("The client didn't supply the user agent!");
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -142,7 +142,7 @@ std::optional<Value> GetInitDataV5(TSession &session, const Marker marker) {
|
||||
}
|
||||
|
||||
const auto &data = metadata.ValueMap();
|
||||
if (!data.contains("user_agent")) {
|
||||
if (!data.count("user_agent")) {
|
||||
spdlog::warn("The client didn't supply the user agent!");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ struct UnboundedEdge {
|
||||
* The decoder writes data into this structure.
|
||||
*/
|
||||
struct Path {
|
||||
Path() = default;
|
||||
Path() {}
|
||||
|
||||
Path(const std::vector<Vertex> &vertices, const std::vector<Edge> &edges) {
|
||||
// Helper function. Looks for the given element in the collection. If found,
|
||||
|
||||
@@ -132,7 +132,7 @@ class Client final {
|
||||
*/
|
||||
class ClientInputStream final {
|
||||
public:
|
||||
explicit ClientInputStream(Client &client);
|
||||
ClientInputStream(Client &client);
|
||||
|
||||
ClientInputStream(const ClientInputStream &) = delete;
|
||||
ClientInputStream(ClientInputStream &&) = delete;
|
||||
@@ -156,7 +156,7 @@ class ClientInputStream final {
|
||||
*/
|
||||
class ClientOutputStream final {
|
||||
public:
|
||||
explicit ClientOutputStream(Client &client);
|
||||
ClientOutputStream(Client &client);
|
||||
|
||||
ClientOutputStream(const ClientOutputStream &) = delete;
|
||||
ClientOutputStream(ClientOutputStream &&) = delete;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2023 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
|
||||
@@ -34,7 +34,7 @@ ClientContext::ClientContext(bool use_ssl) : use_ssl_(use_ssl), ctx_(nullptr) {
|
||||
}
|
||||
|
||||
ClientContext::ClientContext(const std::string &key_file, const std::string &cert_file) : ClientContext(true) {
|
||||
if (!key_file.empty() && !cert_file.empty()) {
|
||||
if (key_file != "" && cert_file != "") {
|
||||
MG_ASSERT(SSL_CTX_use_certificate_file(ctx_, cert_file.c_str(), SSL_FILETYPE_PEM) == 1,
|
||||
"Couldn't load client certificate from file: {}", cert_file);
|
||||
MG_ASSERT(SSL_CTX_use_PrivateKey_file(ctx_, key_file.c_str(), SSL_FILETYPE_PEM) == 1,
|
||||
@@ -124,7 +124,7 @@ ServerContext &ServerContext::operator=(ServerContext &&other) noexcept {
|
||||
return *this;
|
||||
}
|
||||
|
||||
ServerContext::~ServerContext() = default;
|
||||
ServerContext::~ServerContext() {}
|
||||
|
||||
SSL_CTX *ServerContext::context() {
|
||||
MG_ASSERT(ctx_);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2023 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
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
namespace memgraph::communication {
|
||||
|
||||
std::string SslGetLastError() {
|
||||
const std::string SslGetLastError() {
|
||||
char buff[2048];
|
||||
auto err = ERR_get_error();
|
||||
ERR_error_string_n(err, buff, sizeof(buff));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2023 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
|
||||
@@ -18,6 +18,6 @@ namespace memgraph::communication {
|
||||
/**
|
||||
* This function reads and returns a string describing the last OpenSSL error.
|
||||
*/
|
||||
std::string SslGetLastError();
|
||||
const std::string SslGetLastError();
|
||||
|
||||
} // namespace memgraph::communication
|
||||
|
||||
@@ -38,7 +38,7 @@ class Listener final : public std::enable_shared_from_this<Listener<TRequestHand
|
||||
Listener(Listener &&) = delete;
|
||||
Listener &operator=(const Listener &) = delete;
|
||||
Listener &operator=(Listener &&) = delete;
|
||||
~Listener() = default;
|
||||
~Listener() {}
|
||||
|
||||
template <typename... Args>
|
||||
static std::shared_ptr<Listener> Create(Args &&...args) {
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
|
||||
@@ -52,13 +51,13 @@ class Listener final {
|
||||
using SessionHandler = Session<TSession, TSessionContext>;
|
||||
|
||||
public:
|
||||
Listener(TSessionContext *data, ServerContext *context, int inactivity_timeout_sec, std::string service_name,
|
||||
Listener(TSessionContext *data, ServerContext *context, int inactivity_timeout_sec, const std::string &service_name,
|
||||
size_t workers_count)
|
||||
: data_(data),
|
||||
alive_(false),
|
||||
context_(context),
|
||||
inactivity_timeout_sec_(inactivity_timeout_sec),
|
||||
service_name_(std::move(service_name)),
|
||||
service_name_(service_name),
|
||||
workers_count_(workers_count) {}
|
||||
|
||||
~Listener() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2023 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
|
||||
@@ -80,7 +80,7 @@ class ResultStreamFaker {
|
||||
std::transform(header.begin(), header.end(), column_widths.begin(), [](const auto &s) { return s.size(); });
|
||||
|
||||
// convert all the results into strings, and track max column width
|
||||
const auto &results_data = results.GetResults();
|
||||
auto &results_data = results.GetResults();
|
||||
std::vector<std::vector<std::string>> result_strings(results_data.size(),
|
||||
std::vector<std::string>(column_widths.size()));
|
||||
for (int row_ind = 0; row_ind < static_cast<int>(results_data.size()); ++row_ind) {
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
@@ -52,8 +51,7 @@ using InputStream = Buffer::ReadEnd;
|
||||
*/
|
||||
class OutputStream final {
|
||||
public:
|
||||
explicit OutputStream(std::function<bool(const uint8_t *, size_t, bool)> write_function)
|
||||
: write_function_(std::move(write_function)) {}
|
||||
OutputStream(std::function<bool(const uint8_t *, size_t, bool)> write_function) : write_function_(write_function) {}
|
||||
|
||||
OutputStream(const OutputStream &) = delete;
|
||||
OutputStream(OutputStream &&) = delete;
|
||||
|
||||
@@ -47,7 +47,7 @@ class Listener final : public std::enable_shared_from_this<Listener<TSession, TS
|
||||
Listener(Listener &&) = delete;
|
||||
Listener &operator=(const Listener &) = delete;
|
||||
Listener &operator=(Listener &&) = delete;
|
||||
~Listener() = default;
|
||||
~Listener() {}
|
||||
|
||||
template <typename... Args>
|
||||
static std::shared_ptr<Listener> Create(Args &&...args) {
|
||||
|
||||
@@ -76,7 +76,7 @@ using tcp = boost::asio::ip::tcp;
|
||||
class OutputStream final {
|
||||
public:
|
||||
explicit OutputStream(std::function<bool(const uint8_t *, size_t, bool)> write_function)
|
||||
: write_function_(std::move(write_function)) {}
|
||||
: write_function_(write_function) {}
|
||||
|
||||
OutputStream(const OutputStream &) = delete;
|
||||
OutputStream(OutputStream &&) = delete;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2023 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
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <utility>
|
||||
|
||||
#include "communication/websocket/listener.hpp"
|
||||
#include "io/network/endpoint.hpp"
|
||||
@@ -46,7 +45,7 @@ class Server final {
|
||||
|
||||
class LoggingSink : public spdlog::sinks::base_sink<std::mutex> {
|
||||
public:
|
||||
explicit LoggingSink(std::weak_ptr<Listener> listener) : listener_(std::move(listener)) {}
|
||||
explicit LoggingSink(std::weak_ptr<Listener> listener) : listener_(listener) {}
|
||||
|
||||
private:
|
||||
void sink_it_(const spdlog::details::log_msg &msg) override;
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
|
||||
add_library(mg-dbms STATIC dbms_handler.cpp database.cpp replication_handler.cpp replication_client.cpp inmemory/replication_handlers.cpp)
|
||||
add_library(mg-dbms STATIC database.cpp)
|
||||
target_link_libraries(mg-dbms mg-utils mg-storage-v2 mg-query)
|
||||
|
||||
@@ -15,10 +15,4 @@ namespace memgraph::dbms {
|
||||
|
||||
constexpr static const char *kDefaultDB = "memgraph"; //!< Name of the default database
|
||||
|
||||
#ifdef MG_EXPERIMENTAL_REPLICATION_MULTITENANCY
|
||||
constexpr bool allow_mt_repl = true;
|
||||
#else
|
||||
constexpr bool allow_mt_repl = false;
|
||||
#endif
|
||||
|
||||
} // namespace memgraph::dbms
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
// licenses/APL.txt.
|
||||
|
||||
#include "dbms/database.hpp"
|
||||
#include "dbms/inmemory/storage_helper.hpp"
|
||||
#include "dbms/replication_handler.hpp"
|
||||
#include "flags/storage_mode.hpp"
|
||||
#include "storage/v2/disk/storage.hpp"
|
||||
#include "storage/v2/inmemory/storage.hpp"
|
||||
@@ -21,16 +19,14 @@ template struct memgraph::utils::Gatekeeper<memgraph::dbms::Database>;
|
||||
|
||||
namespace memgraph::dbms {
|
||||
|
||||
Database::Database(storage::Config config, replication::ReplicationState &repl_state)
|
||||
Database::Database(const storage::Config &config)
|
||||
: trigger_store_(config.durability.storage_directory / "triggers"),
|
||||
streams_{config.durability.storage_directory / "streams"},
|
||||
plan_cache_{FLAGS_query_plan_cache_max_size},
|
||||
repl_state_(&repl_state) {
|
||||
streams_{config.durability.storage_directory / "streams"} {
|
||||
if (config.storage_mode == memgraph::storage::StorageMode::ON_DISK_TRANSACTIONAL || config.force_on_disk ||
|
||||
utils::DirExists(config.disk.main_storage_directory)) {
|
||||
storage_ = std::make_unique<storage::DiskStorage>(std::move(config));
|
||||
storage_ = std::make_unique<storage::DiskStorage>(config);
|
||||
} else {
|
||||
storage_ = dbms::CreateInMemoryStorage(std::move(config), repl_state);
|
||||
storage_ = std::make_unique<storage::InMemoryStorage>(config, config.storage_mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
#include "query/trigger.hpp"
|
||||
#include "storage/v2/storage.hpp"
|
||||
#include "utils/gatekeeper.hpp"
|
||||
#include "utils/lru_cache.hpp"
|
||||
#include "utils/synchronized.hpp"
|
||||
|
||||
namespace memgraph::dbms {
|
||||
|
||||
@@ -48,7 +46,7 @@ class Database {
|
||||
*
|
||||
* @param config storage configuration
|
||||
*/
|
||||
explicit Database(storage::Config config, replication::ReplicationState &repl_state);
|
||||
explicit Database(const storage::Config &config);
|
||||
|
||||
/**
|
||||
* @brief Returns the raw storage pointer.
|
||||
@@ -58,7 +56,6 @@ class Database {
|
||||
* @return storage::Storage*
|
||||
*/
|
||||
storage::Storage *storage() { return storage_.get(); }
|
||||
storage::Storage const *storage() const { return storage_.get(); }
|
||||
|
||||
/**
|
||||
* @brief Storage's Accessor
|
||||
@@ -68,12 +65,12 @@ class Database {
|
||||
*/
|
||||
std::unique_ptr<storage::Storage::Accessor> Access(
|
||||
std::optional<storage::IsolationLevel> override_isolation_level = {}) {
|
||||
return storage_->Access(override_isolation_level, repl_state_->IsMain());
|
||||
return storage_->Access(override_isolation_level);
|
||||
}
|
||||
|
||||
std::unique_ptr<storage::Storage::Accessor> UniqueAccess(
|
||||
std::optional<storage::IsolationLevel> override_isolation_level = {}) {
|
||||
return storage_->UniqueAccess(override_isolation_level, repl_state_->IsMain());
|
||||
return storage_->UniqueAccess(override_isolation_level);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,7 +92,7 @@ class Database {
|
||||
*
|
||||
* @return storage::StorageMode
|
||||
*/
|
||||
storage::StorageMode GetStorageMode() const noexcept { return storage_->GetStorageMode(); }
|
||||
storage::StorageMode GetStorageMode() const { return storage_->GetStorageMode(); }
|
||||
|
||||
/**
|
||||
* @brief Get the storage info
|
||||
@@ -148,9 +145,9 @@ class Database {
|
||||
/**
|
||||
* @brief Returns the PlanCache vector raw pointer
|
||||
*
|
||||
* @return utils::Synchronized<utils::LRUCache<uint64_t, std::shared_ptr<PlanWrapper>>, utils::RWSpinLock>
|
||||
* @return utils::SkipList<query::PlanCacheEntry>*
|
||||
*/
|
||||
query::PlanCacheLRU *plan_cache() { return &plan_cache_; }
|
||||
utils::SkipList<query::PlanCacheEntry> *plan_cache() { return &plan_cache_; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<storage::Storage> storage_; //!< Underlying storage
|
||||
@@ -159,9 +156,7 @@ class Database {
|
||||
query::stream::Streams streams_; //!< Streams associated with the storage
|
||||
|
||||
// TODO: Move to a better place
|
||||
query::PlanCacheLRU plan_cache_; //!< Plan cache associated with the storage
|
||||
|
||||
const replication::ReplicationState *repl_state_;
|
||||
utils::SkipList<query::PlanCacheEntry> plan_cache_; //!< Plan cache associated with the storage
|
||||
};
|
||||
|
||||
} // namespace memgraph::dbms
|
||||
|
||||
@@ -51,7 +51,7 @@ class DatabaseHandler : public Handler<Database> {
|
||||
* @param config Storage configuration
|
||||
* @return HandlerT::NewResult
|
||||
*/
|
||||
HandlerT::NewResult New(std::string_view name, storage::Config config, replication::ReplicationState &repl_state) {
|
||||
HandlerT::NewResult New(std::string_view name, storage::Config config) {
|
||||
// Control that no one is using the same data directory
|
||||
if (std::any_of(begin(), end(), [&](auto &elem) {
|
||||
auto db_acc = elem.second.access();
|
||||
@@ -62,7 +62,7 @@ class DatabaseHandler : public Handler<Database> {
|
||||
return NewError::EXISTS;
|
||||
}
|
||||
config.name = name; // Set storage id via config
|
||||
return HandlerT::New(std::piecewise_construct, name, config, repl_state);
|
||||
return HandlerT::New(std::piecewise_construct, name, config);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,4 +93,5 @@ class DatabaseHandler : public Handler<Database> {
|
||||
};
|
||||
|
||||
} // namespace memgraph::dbms
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,75 +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.
|
||||
|
||||
#include "dbms/dbms_handler.hpp"
|
||||
|
||||
namespace memgraph::dbms {
|
||||
#ifdef MG_ENTERPRISE
|
||||
DbmsHandler::DbmsHandler(
|
||||
storage::Config config,
|
||||
memgraph::utils::Synchronized<memgraph::auth::Auth, memgraph::utils::WritePrioritizedRWLock> *auth,
|
||||
bool recovery_on_startup, bool delete_on_drop)
|
||||
: default_config_{std::move(config)},
|
||||
delete_on_drop_(delete_on_drop),
|
||||
repl_state_{ReplicationStateRootPath(default_config_)} {
|
||||
// TODO: Decouple storage config from dbms config
|
||||
// TODO: Save individual db configs inside the kvstore and restore from there
|
||||
storage::UpdatePaths(default_config_, default_config_.durability.storage_directory / "databases");
|
||||
const auto &db_dir = default_config_.durability.storage_directory;
|
||||
const auto durability_dir = db_dir / ".durability";
|
||||
utils::EnsureDirOrDie(db_dir);
|
||||
utils::EnsureDirOrDie(durability_dir);
|
||||
durability_ = std::make_unique<kvstore::KVStore>(durability_dir);
|
||||
|
||||
// Generate the default database
|
||||
MG_ASSERT(!NewDefault_().HasError(), "Failed while creating the default DB.");
|
||||
|
||||
// Recover previous databases
|
||||
if (recovery_on_startup) {
|
||||
for (const auto &[name, _] : *durability_) {
|
||||
if (name == kDefaultDB) continue; // Already set
|
||||
spdlog::info("Restoring database {}.", name);
|
||||
MG_ASSERT(!New_(name).HasError(), "Failed while creating database {}.", name);
|
||||
spdlog::info("Database {} restored.", name);
|
||||
}
|
||||
} else { // Clear databases from the durability list and auth
|
||||
auto locked_auth = auth->Lock();
|
||||
for (const auto &[name, _] : *durability_) {
|
||||
if (name == kDefaultDB) continue;
|
||||
locked_auth->DeleteDatabase(name);
|
||||
durability_->Delete(name);
|
||||
}
|
||||
}
|
||||
|
||||
// Startup replication state (if recovered at startup)
|
||||
auto replica = [this](replication::RoleReplicaData const &data) {
|
||||
// Register handlers
|
||||
InMemoryReplicationHandlers::Register(this, *data.server);
|
||||
if (!data.server->Start()) {
|
||||
spdlog::error("Unable to start the replication server.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
// Replication frequent check start
|
||||
auto main = [this](replication::RoleMainData &data) {
|
||||
for (auto &client : data.registered_replicas_) {
|
||||
StartReplicaClient(*this, client);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
// Startup proccess for main/replica
|
||||
MG_ASSERT(std::visit(memgraph::utils::Overloaded{replica, main}, repl_state_.ReplicationData()),
|
||||
"Replica recovery failure!");
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace memgraph::dbms
|
||||
@@ -26,11 +26,7 @@
|
||||
#include "auth/auth.hpp"
|
||||
#include "constants.hpp"
|
||||
#include "dbms/database.hpp"
|
||||
#include "dbms/inmemory/replication_handlers.hpp"
|
||||
#ifdef MG_ENTERPRISE
|
||||
#include "dbms/database_handler.hpp"
|
||||
#endif
|
||||
#include "dbms/replication_client.hpp"
|
||||
#include "global.hpp"
|
||||
#include "query/config.hpp"
|
||||
#include "query/interpreter_context.hpp"
|
||||
@@ -85,44 +81,58 @@ static inline nlohmann::json ToJson(const Statistics &stats) {
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifdef MG_ENTERPRISE
|
||||
|
||||
using DeleteResult = utils::BasicResult<DeleteError>;
|
||||
|
||||
/**
|
||||
* @brief Multi-database session contexts handler.
|
||||
*/
|
||||
class DbmsHandler {
|
||||
public:
|
||||
using LockT = utils::RWLock;
|
||||
#ifdef MG_ENTERPRISE
|
||||
|
||||
using NewResultT = utils::BasicResult<NewError, DatabaseAccess>;
|
||||
using DeleteResult = utils::BasicResult<DeleteError>;
|
||||
|
||||
/**
|
||||
* @brief Initialize the handler.
|
||||
*
|
||||
* @param configs storage configuration
|
||||
* @param configs storage and interpreter configurations
|
||||
* @param auth pointer to the global authenticator
|
||||
* @param recovery_on_startup restore databases (and its content) and authentication data
|
||||
* @param delete_on_drop when dropping delete any associated directories on disk
|
||||
*/
|
||||
DbmsHandler(storage::Config config,
|
||||
memgraph::utils::Synchronized<memgraph::auth::Auth, memgraph::utils::WritePrioritizedRWLock> *auth,
|
||||
bool recovery_on_startup, bool delete_on_drop); // TODO If more arguments are added use a config strut
|
||||
#else
|
||||
/**
|
||||
* @brief Initialize the handler. A single database is supported in community edition.
|
||||
*
|
||||
* @param configs storage configuration
|
||||
*/
|
||||
DbmsHandler(storage::Config config)
|
||||
: repl_state_{ReplicationStateRootPath(config)},
|
||||
db_gatekeeper_{[&] {
|
||||
config.name = kDefaultDB;
|
||||
return std::move(config);
|
||||
}(),
|
||||
repl_state_} {}
|
||||
#endif
|
||||
DbmsHandler(storage::Config config, auto *auth, bool recovery_on_startup, bool delete_on_drop)
|
||||
: lock_{utils::RWLock::Priority::READ}, default_config_{std::move(config)}, delete_on_drop_(delete_on_drop) {
|
||||
// TODO: Decouple storage config from dbms config
|
||||
// TODO: Save individual db configs inside the kvstore and restore from there
|
||||
storage::UpdatePaths(*default_config_, default_config_->durability.storage_directory / "databases");
|
||||
const auto &db_dir = default_config_->durability.storage_directory;
|
||||
const auto durability_dir = db_dir / ".durability";
|
||||
utils::EnsureDirOrDie(db_dir);
|
||||
utils::EnsureDirOrDie(durability_dir);
|
||||
durability_ = std::make_unique<kvstore::KVStore>(durability_dir);
|
||||
|
||||
// Generate the default database
|
||||
MG_ASSERT(!NewDefault_().HasError(), "Failed while creating the default DB.");
|
||||
|
||||
// Recover previous databases
|
||||
if (recovery_on_startup) {
|
||||
for (const auto &[name, _] : *durability_) {
|
||||
if (name == kDefaultDB) continue; // Already set
|
||||
spdlog::info("Restoring database {}.", name);
|
||||
MG_ASSERT(!New_(name).HasError(), "Failed while creating database {}.", name);
|
||||
spdlog::info("Database {} restored.", name);
|
||||
}
|
||||
} else { // Clear databases from the durability list and auth
|
||||
auto locked_auth = auth->Lock();
|
||||
for (const auto &[name, _] : *durability_) {
|
||||
if (name == kDefaultDB) continue;
|
||||
locked_auth->DeleteDatabase(name);
|
||||
durability_->Delete(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MG_ENTERPRISE
|
||||
/**
|
||||
* @brief Create a new Database associated with the "name" database
|
||||
*
|
||||
@@ -141,24 +151,11 @@ class DbmsHandler {
|
||||
* @return DatabaseAccess
|
||||
* @throw UnknownDatabaseException if database not found
|
||||
*/
|
||||
DatabaseAccess Get(std::string_view name = kDefaultDB) {
|
||||
DatabaseAccess Get(std::string_view name) {
|
||||
std::shared_lock<LockT> rd(lock_);
|
||||
return Get_(name);
|
||||
}
|
||||
#else
|
||||
/**
|
||||
* @brief Get the context associated with the default database
|
||||
*
|
||||
* @return DatabaseAccess
|
||||
*/
|
||||
DatabaseAccess Get() {
|
||||
auto acc = db_gatekeeper_.access();
|
||||
MG_ASSERT(acc, "Failed to get default database!");
|
||||
return *acc;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MG_ENTERPRISE
|
||||
/**
|
||||
* @brief Delete database.
|
||||
*
|
||||
@@ -204,7 +201,6 @@ class DbmsHandler {
|
||||
|
||||
return {}; // Success
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Return all active databases.
|
||||
@@ -212,20 +208,10 @@ class DbmsHandler {
|
||||
* @return std::vector<std::string>
|
||||
*/
|
||||
std::vector<std::string> All() const {
|
||||
#ifdef MG_ENTERPRISE
|
||||
std::shared_lock<LockT> rd(lock_);
|
||||
return db_handler_.All();
|
||||
#else
|
||||
return {db_gatekeeper_.access()->get()->id()};
|
||||
#endif
|
||||
}
|
||||
|
||||
replication::ReplicationState &ReplicationState() { return repl_state_; }
|
||||
replication::ReplicationState const &ReplicationState() const { return repl_state_; }
|
||||
|
||||
bool IsMain() const { return repl_state_.IsMain(); }
|
||||
bool IsReplica() const { return repl_state_.IsReplica(); }
|
||||
|
||||
/**
|
||||
* @brief Return the statistics all databases.
|
||||
*
|
||||
@@ -234,30 +220,24 @@ class DbmsHandler {
|
||||
Statistics Stats() {
|
||||
Statistics stats{};
|
||||
// TODO: Handle overflow?
|
||||
#ifdef MG_ENTERPRISE
|
||||
std::shared_lock<LockT> rd(lock_);
|
||||
for (auto &[_, db_gk] : db_handler_) {
|
||||
#else
|
||||
{
|
||||
auto &db_gk = db_gatekeeper_;
|
||||
#endif
|
||||
auto db_acc_opt = db_gk.access();
|
||||
if (db_acc_opt) {
|
||||
auto &db_acc = *db_acc_opt;
|
||||
const auto &info = db_acc->GetInfo();
|
||||
const auto &storage_info = info.storage_info;
|
||||
stats.num_vertex += storage_info.vertex_count;
|
||||
stats.num_edges += storage_info.edge_count;
|
||||
stats.triggers += info.triggers;
|
||||
stats.streams += info.streams;
|
||||
++stats.num_databases;
|
||||
stats.indices += storage_info.label_indices + storage_info.label_property_indices;
|
||||
stats.constraints += storage_info.existence_constraints + storage_info.unique_constraints;
|
||||
++stats.storage_modes[(int)storage_info.storage_mode];
|
||||
++stats.isolation_levels[(int)storage_info.isolation_level];
|
||||
stats.snapshot_enabled += storage_info.durability_snapshot_enabled;
|
||||
stats.wal_enabled += storage_info.durability_wal_enabled;
|
||||
}
|
||||
if (!db_acc_opt) continue;
|
||||
auto &db_acc = *db_acc_opt;
|
||||
const auto &info = db_acc->GetInfo();
|
||||
const auto &storage_info = info.storage_info;
|
||||
stats.num_vertex += storage_info.vertex_count;
|
||||
stats.num_edges += storage_info.edge_count;
|
||||
stats.triggers += info.triggers;
|
||||
stats.streams += info.streams;
|
||||
++stats.num_databases;
|
||||
stats.indices += storage_info.label_indices + storage_info.label_property_indices;
|
||||
stats.constraints += storage_info.existence_constraints + storage_info.unique_constraints;
|
||||
++stats.storage_modes[(int)storage_info.storage_mode];
|
||||
++stats.isolation_levels[(int)storage_info.isolation_level];
|
||||
stats.snapshot_enabled += storage_info.durability_snapshot_enabled;
|
||||
stats.wal_enabled += storage_info.durability_wal_enabled;
|
||||
}
|
||||
return stats;
|
||||
}
|
||||
@@ -269,19 +249,13 @@ class DbmsHandler {
|
||||
*/
|
||||
std::vector<DatabaseInfo> Info() {
|
||||
std::vector<DatabaseInfo> res;
|
||||
#ifdef MG_ENTERPRISE
|
||||
std::shared_lock<LockT> rd(lock_);
|
||||
res.reserve(std::distance(db_handler_.cbegin(), db_handler_.cend()));
|
||||
std::shared_lock<LockT> rd(lock_);
|
||||
for (auto &[_, db_gk] : db_handler_) {
|
||||
#else
|
||||
{
|
||||
auto &db_gk = db_gatekeeper_;
|
||||
#endif
|
||||
auto db_acc_opt = db_gk.access();
|
||||
if (db_acc_opt) {
|
||||
auto &db_acc = *db_acc_opt;
|
||||
res.push_back(db_acc->GetInfo());
|
||||
}
|
||||
if (!db_acc_opt) continue;
|
||||
auto &db_acc = *db_acc_opt;
|
||||
res.push_back(db_acc->GetInfo());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -293,21 +267,15 @@ class DbmsHandler {
|
||||
* @param ic global InterpreterContext
|
||||
*/
|
||||
void RestoreTriggers(query::InterpreterContext *ic) {
|
||||
#ifdef MG_ENTERPRISE
|
||||
std::lock_guard<LockT> wr(lock_);
|
||||
for (auto &[_, db_gk] : db_handler_) {
|
||||
#else
|
||||
{
|
||||
auto &db_gk = db_gatekeeper_;
|
||||
#endif
|
||||
auto db_acc_opt = db_gk.access();
|
||||
if (db_acc_opt) {
|
||||
auto &db_acc = *db_acc_opt;
|
||||
spdlog::debug("Restoring trigger for database \"{}\"", db_acc->id());
|
||||
auto storage_accessor = db_acc->Access();
|
||||
auto dba = memgraph::query::DbAccessor{storage_accessor.get()};
|
||||
db_acc->trigger_store()->RestoreTriggers(&ic->ast_cache, &dba, ic->config.query, ic->auth_checker);
|
||||
}
|
||||
if (!db_acc_opt) continue;
|
||||
auto &db_acc = *db_acc_opt;
|
||||
spdlog::debug("Restoring trigger for database \"{}\"", db_acc->id());
|
||||
auto storage_accessor = db_acc->Access();
|
||||
auto dba = memgraph::query::DbAccessor{storage_accessor.get()};
|
||||
db_acc->trigger_store()->RestoreTriggers(&ic->ast_cache, &dba, ic->config.query, ic->auth_checker);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,67 +286,17 @@ class DbmsHandler {
|
||||
* @param ic global InterpreterContext
|
||||
*/
|
||||
void RestoreStreams(query::InterpreterContext *ic) {
|
||||
#ifdef MG_ENTERPRISE
|
||||
std::lock_guard<LockT> wr(lock_);
|
||||
for (auto &[_, db_gk] : db_handler_) {
|
||||
#else
|
||||
{
|
||||
auto &db_gk = db_gatekeeper_;
|
||||
#endif
|
||||
auto db_acc = db_gk.access();
|
||||
if (db_acc) {
|
||||
auto *db = db_acc->get();
|
||||
spdlog::debug("Restoring streams for database \"{}\"", db->id());
|
||||
db->streams()->RestoreStreams(*db_acc, ic);
|
||||
}
|
||||
if (!db_acc) continue;
|
||||
auto *db = db_acc->get();
|
||||
spdlog::debug("Restoring streams for database \"{}\"", db->id());
|
||||
db->streams()->RestoreStreams(*db_acc, ic);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief todo
|
||||
*
|
||||
* @param f
|
||||
*/
|
||||
void ForEach(auto f) {
|
||||
#ifdef MG_ENTERPRISE
|
||||
std::shared_lock<LockT> rd(lock_);
|
||||
for (auto &[_, db_gk] : db_handler_) {
|
||||
#else
|
||||
{
|
||||
auto &db_gk = db_gatekeeper_;
|
||||
#endif
|
||||
auto db_acc = db_gk.access();
|
||||
if (db_acc) { // This isn't an error, just a defunct db
|
||||
f(db_acc->get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief todo
|
||||
*
|
||||
* @param f
|
||||
*/
|
||||
void ForOne(auto f) {
|
||||
#ifdef MG_ENTERPRISE
|
||||
std::shared_lock<LockT> rd(lock_);
|
||||
for (auto &[_, db_gk] : db_handler_) {
|
||||
auto db_acc = db_gk.access();
|
||||
if (db_acc) { // This isn't an error, just a defunct db
|
||||
if (f(db_acc->get())) break; // Run until the first successful one
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
auto db_acc = db_gatekeeper_.access();
|
||||
MG_ASSERT(db_acc, "Should always have the database");
|
||||
f(db_acc->get());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef MG_ENTERPRISE
|
||||
/**
|
||||
* @brief return the storage directory of the associated database
|
||||
*
|
||||
@@ -410,9 +328,13 @@ class DbmsHandler {
|
||||
* @return NewResultT context on success, error on failure
|
||||
*/
|
||||
NewResultT New_(const std::string &name, std::filesystem::path storage_subdir) {
|
||||
auto config_copy = default_config_;
|
||||
storage::UpdatePaths(config_copy, default_config_.durability.storage_directory / storage_subdir);
|
||||
return New_(name, config_copy);
|
||||
if (default_config_) {
|
||||
auto config_copy = *default_config_;
|
||||
storage::UpdatePaths(config_copy, default_config_->durability.storage_directory / storage_subdir);
|
||||
return New_(name, config_copy);
|
||||
}
|
||||
spdlog::info("Trying to generate session context without any configurations.");
|
||||
return NewError::NO_CONFIGS;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -429,7 +351,7 @@ class DbmsHandler {
|
||||
return NewError::DEFUNCT;
|
||||
}
|
||||
|
||||
auto new_db = db_handler_.New(name, storage_config, repl_state_);
|
||||
auto new_db = db_handler_.New(name, storage_config);
|
||||
if (new_db.HasValue()) {
|
||||
// Success
|
||||
if (durability_) durability_->Put(name, "ok"); // TODO: Serialize the configuration?
|
||||
@@ -514,17 +436,14 @@ class DbmsHandler {
|
||||
throw UnknownDatabaseException("Tried to retrieve an unknown database \"{}\".", name);
|
||||
}
|
||||
|
||||
mutable LockT lock_{utils::RWLock::Priority::READ}; //!< protective lock
|
||||
storage::Config default_config_; //!< Storage configuration used when creating new databases
|
||||
DatabaseHandler db_handler_; //!< multi-tenancy storage handler
|
||||
std::unique_ptr<kvstore::KVStore> durability_; //!< list of active dbs (pointer so we can postpone its creation)
|
||||
bool delete_on_drop_; //!< Flag defining if dropping storage also deletes its directory
|
||||
std::set<std::string> defunct_dbs_; //!< Databases that are in an unknown state due to various failures
|
||||
#endif
|
||||
replication::ReplicationState repl_state_; //!< Global replication state
|
||||
#ifndef MG_ENTERPRISE
|
||||
mutable utils::Gatekeeper<Database> db_gatekeeper_; //!< Single databases gatekeeper
|
||||
#endif
|
||||
// Should storage objects ever be deleted?
|
||||
mutable LockT lock_; //!< protective lock
|
||||
DatabaseHandler db_handler_; //!< multi-tenancy storage handler
|
||||
std::optional<storage::Config> default_config_; //!< Storage configuration used when creating new databases
|
||||
std::unique_ptr<kvstore::KVStore> durability_; //!< list of active dbs (pointer so we can postpone its creation)
|
||||
std::set<std::string> defunct_dbs_; //!< Databases that are in an unknown state due to various failures
|
||||
bool delete_on_drop_; //!< Flag defining if dropping storage also deletes its directory
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace memgraph::dbms
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
namespace memgraph::dbms {
|
||||
|
||||
#ifdef MG_ENTERPRISE
|
||||
enum class DeleteError : uint8_t {
|
||||
DEFAULT_DB,
|
||||
USING,
|
||||
@@ -35,7 +34,11 @@ enum class NewError : uint8_t {
|
||||
GENERIC,
|
||||
};
|
||||
|
||||
#endif
|
||||
enum class SetForResult : uint8_t {
|
||||
SUCCESS,
|
||||
ALREADY_SET,
|
||||
FAIL,
|
||||
};
|
||||
|
||||
/**
|
||||
* UnknownSession Exception
|
||||
|
||||
@@ -38,7 +38,7 @@ class Handler {
|
||||
* @brief Empty Handler constructor.
|
||||
*
|
||||
*/
|
||||
Handler() = default;
|
||||
Handler() {}
|
||||
|
||||
/**
|
||||
* @brief Generate a new context and corresponding configuration.
|
||||
@@ -49,7 +49,7 @@ class Handler {
|
||||
* @return NewResult
|
||||
*/
|
||||
template <typename... Args>
|
||||
NewResult New(std::piecewise_construct_t /* marker */, std::string_view name, Args &&...args) {
|
||||
NewResult New(std::piecewise_construct_t /* marker */, std::string_view name, Args... args) {
|
||||
// Make sure the emplace will succeed, since we don't want to create temporary objects that could break something
|
||||
if (!Has(name)) {
|
||||
auto [itr, _] = items_.emplace(std::piecewise_construct, std::forward_as_tuple(name),
|
||||
|
||||
@@ -1,49 +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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "replication/replication_server.hpp"
|
||||
#include "replication/state.hpp"
|
||||
#include "storage/v2/replication/serialization.hpp"
|
||||
|
||||
namespace memgraph::storage {
|
||||
class InMemoryStorage;
|
||||
}
|
||||
namespace memgraph::dbms {
|
||||
|
||||
class DbmsHandler;
|
||||
|
||||
class InMemoryReplicationHandlers {
|
||||
public:
|
||||
static void Register(dbms::DbmsHandler *dbms_handler, replication::ReplicationServer &server);
|
||||
|
||||
private:
|
||||
// RPC handlers
|
||||
static void HeartbeatHandler(dbms::DbmsHandler *dbms_handler, slk::Reader *req_reader, slk::Builder *res_builder);
|
||||
|
||||
static void AppendDeltasHandler(dbms::DbmsHandler *dbms_handler, slk::Reader *req_reader, slk::Builder *res_builder);
|
||||
|
||||
static void SnapshotHandler(dbms::DbmsHandler *dbms_handler, slk::Reader *req_reader, slk::Builder *res_builder);
|
||||
|
||||
static void WalFilesHandler(dbms::DbmsHandler *dbms_handler, slk::Reader *req_reader, slk::Builder *res_builder);
|
||||
|
||||
static void CurrentWalHandler(dbms::DbmsHandler *dbms_handler, slk::Reader *req_reader, slk::Builder *res_builder);
|
||||
|
||||
static void TimestampHandler(dbms::DbmsHandler *dbms_handler, slk::Reader *req_reader, slk::Builder *res_builder);
|
||||
|
||||
static void LoadWal(storage::InMemoryStorage *storage, storage::replication::Decoder *decoder);
|
||||
|
||||
static uint64_t ReadAndApplyDelta(storage::InMemoryStorage *storage, storage::durability::BaseDecoder *decoder,
|
||||
uint64_t version);
|
||||
};
|
||||
|
||||
} // namespace memgraph::dbms
|
||||
@@ -1,61 +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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <variant>
|
||||
|
||||
#include "dbms/constants.hpp"
|
||||
#include "dbms/replication_handler.hpp"
|
||||
#include "replication/state.hpp"
|
||||
#include "storage/v2/config.hpp"
|
||||
#include "storage/v2/inmemory/storage.hpp"
|
||||
#include "storage/v2/storage.hpp"
|
||||
|
||||
namespace memgraph::dbms {
|
||||
|
||||
inline std::unique_ptr<storage::Storage> CreateInMemoryStorage(storage::Config config,
|
||||
::memgraph::replication::ReplicationState &repl_state) {
|
||||
const auto wal_mode = config.durability.snapshot_wal_mode;
|
||||
const auto name = config.name;
|
||||
auto storage = std::make_unique<storage::InMemoryStorage>(std::move(config));
|
||||
|
||||
// Connect replication state and storage
|
||||
storage->CreateSnapshotHandler(
|
||||
[storage = storage.get(), &repl_state]() -> utils::BasicResult<storage::InMemoryStorage::CreateSnapshotError> {
|
||||
if (repl_state.IsReplica()) {
|
||||
return storage::InMemoryStorage::CreateSnapshotError::DisabledForReplica;
|
||||
}
|
||||
return storage->CreateSnapshot();
|
||||
});
|
||||
|
||||
if (allow_mt_repl || name == dbms::kDefaultDB) {
|
||||
// Handle global replication state
|
||||
spdlog::info("Replication configuration will be stored and will be automatically restored in case of a crash.");
|
||||
// RECOVER REPLICA CONNECTIONS
|
||||
memgraph::dbms::RestoreReplication(repl_state, *storage);
|
||||
} else if (const ::memgraph::replication::RoleMainData *data =
|
||||
std::get_if<::memgraph::replication::RoleMainData>(&repl_state.ReplicationData());
|
||||
data && !data->registered_replicas_.empty()) {
|
||||
spdlog::warn("Multi-tenant replication is currently not supported!");
|
||||
}
|
||||
|
||||
if (wal_mode == storage::Config::Durability::SnapshotWalMode::DISABLED && repl_state.IsMain()) {
|
||||
spdlog::warn(
|
||||
"The instance has the MAIN replication role, but durability logs and snapshots are disabled. Please consider "
|
||||
"enabling durability by using --storage-snapshot-interval-sec and --storage-wal-enabled flags because "
|
||||
"without write-ahead logs this instance is not replicating any data.");
|
||||
}
|
||||
|
||||
return std::move(storage);
|
||||
}
|
||||
|
||||
} // namespace memgraph::dbms
|
||||
@@ -1,34 +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.
|
||||
|
||||
#include "dbms/replication_client.hpp"
|
||||
|
||||
namespace memgraph::dbms {
|
||||
|
||||
void StartReplicaClient(DbmsHandler &dbms_handler, replication::ReplicationClient &client) {
|
||||
// No client error, start instance level client
|
||||
auto const &endpoint = client.rpc_client_.Endpoint();
|
||||
spdlog::trace("Replication client started at: {}:{}", endpoint.address, endpoint.port);
|
||||
client.StartFrequentCheck([&dbms_handler](std::string_view name) {
|
||||
// Working connection, check if any database has been left behind
|
||||
dbms_handler.ForEach([name](dbms::Database *db) {
|
||||
// Specific database <-> replica client
|
||||
db->storage()->repl_storage_state_.WithClient(name, [&](storage::ReplicationStorageClient *client) {
|
||||
if (client->State() == storage::replication::ReplicaState::MAYBE_BEHIND) {
|
||||
// Database <-> replica might be behind, check and recover
|
||||
client->TryCheckReplicaStateAsync(db->storage());
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace memgraph::dbms
|
||||
@@ -1,21 +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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "dbms/dbms_handler.hpp"
|
||||
#include "replication/replication_client.hpp"
|
||||
|
||||
namespace memgraph::dbms {
|
||||
|
||||
void StartReplicaClient(DbmsHandler &dbms_handler, replication::ReplicationClient &client);
|
||||
|
||||
} // namespace memgraph::dbms
|
||||
@@ -1,262 +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.
|
||||
|
||||
#include "dbms/replication_handler.hpp"
|
||||
|
||||
#include "dbms/constants.hpp"
|
||||
#include "dbms/dbms_handler.hpp"
|
||||
#include "dbms/inmemory/replication_handlers.hpp"
|
||||
#include "dbms/inmemory/storage_helper.hpp"
|
||||
#include "dbms/replication_client.hpp"
|
||||
#include "replication/state.hpp"
|
||||
|
||||
using memgraph::replication::ReplicationClientConfig;
|
||||
using memgraph::replication::ReplicationState;
|
||||
using memgraph::replication::RoleMainData;
|
||||
using memgraph::replication::RoleReplicaData;
|
||||
|
||||
namespace memgraph::dbms {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string RegisterReplicaErrorToString(RegisterReplicaError error) {
|
||||
switch (error) {
|
||||
using enum RegisterReplicaError;
|
||||
case NAME_EXISTS:
|
||||
return "NAME_EXISTS";
|
||||
case END_POINT_EXISTS:
|
||||
return "END_POINT_EXISTS";
|
||||
case CONNECTION_FAILED:
|
||||
return "CONNECTION_FAILED";
|
||||
case COULD_NOT_BE_PERSISTED:
|
||||
return "COULD_NOT_BE_PERSISTED";
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ReplicationHandler::ReplicationHandler(DbmsHandler &dbms_handler) : dbms_handler_(dbms_handler) {}
|
||||
|
||||
bool ReplicationHandler::SetReplicationRoleMain() {
|
||||
auto const main_handler = [](RoleMainData const &) {
|
||||
// If we are already MAIN, we don't want to change anything
|
||||
return false;
|
||||
};
|
||||
auto const replica_handler = [this](RoleReplicaData const &) {
|
||||
// STEP 1) bring down all REPLICA servers
|
||||
dbms_handler_.ForEach([](Database *db) {
|
||||
auto *storage = db->storage();
|
||||
// Remember old epoch + storage timestamp association
|
||||
storage->PrepareForNewEpoch();
|
||||
});
|
||||
|
||||
// STEP 2) Change to MAIN
|
||||
// TODO: restore replication servers if false?
|
||||
if (!dbms_handler_.ReplicationState().SetReplicationRoleMain()) {
|
||||
// TODO: Handle recovery on failure???
|
||||
return false;
|
||||
}
|
||||
|
||||
// STEP 3) We are now MAIN, update storage local epoch
|
||||
const auto &epoch =
|
||||
std::get<RoleMainData>(std::as_const(dbms_handler_.ReplicationState()).ReplicationData()).epoch_;
|
||||
dbms_handler_.ForEach([&](Database *db) {
|
||||
auto *storage = db->storage();
|
||||
storage->repl_storage_state_.epoch_ = epoch;
|
||||
});
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
// TODO: under lock
|
||||
return std::visit(utils::Overloaded{main_handler, replica_handler},
|
||||
dbms_handler_.ReplicationState().ReplicationData());
|
||||
}
|
||||
|
||||
bool ReplicationHandler::SetReplicationRoleReplica(const memgraph::replication::ReplicationServerConfig &config) {
|
||||
// We don't want to restart the server if we're already a REPLICA
|
||||
if (dbms_handler_.ReplicationState().IsReplica()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO StorageState needs to be synched. Could have a dangling reference if someone adds a database as we are
|
||||
// deleting the replica.
|
||||
// Remove database specific clients
|
||||
dbms_handler_.ForEach([&](Database *db) {
|
||||
auto *storage = db->storage();
|
||||
storage->repl_storage_state_.replication_clients_.WithLock([](auto &clients) { clients.clear(); });
|
||||
});
|
||||
// Remove instance level clients
|
||||
std::get<RoleMainData>(dbms_handler_.ReplicationState().ReplicationData()).registered_replicas_.clear();
|
||||
|
||||
// Creates the server
|
||||
dbms_handler_.ReplicationState().SetReplicationRoleReplica(config);
|
||||
|
||||
// Start
|
||||
const auto success =
|
||||
std::visit(utils::Overloaded{[](RoleMainData const &) {
|
||||
// ASSERT
|
||||
return false;
|
||||
},
|
||||
[this](RoleReplicaData const &data) {
|
||||
// Register handlers
|
||||
InMemoryReplicationHandlers::Register(&dbms_handler_, *data.server);
|
||||
if (!data.server->Start()) {
|
||||
spdlog::error("Unable to start the replication server.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}},
|
||||
dbms_handler_.ReplicationState().ReplicationData());
|
||||
// TODO Handle error (restore to main?)
|
||||
return success;
|
||||
}
|
||||
|
||||
auto ReplicationHandler::RegisterReplica(const memgraph::replication::ReplicationClientConfig &config)
|
||||
-> memgraph::utils::BasicResult<RegisterReplicaError> {
|
||||
MG_ASSERT(dbms_handler_.ReplicationState().IsMain(), "Only main instance can register a replica!");
|
||||
|
||||
auto instance_client = dbms_handler_.ReplicationState().RegisterReplica(config);
|
||||
if (instance_client.HasError()) switch (instance_client.GetError()) {
|
||||
case memgraph::replication::RegisterReplicaError::NOT_MAIN:
|
||||
MG_ASSERT(false, "Only main instance can register a replica!");
|
||||
return {};
|
||||
case memgraph::replication::RegisterReplicaError::NAME_EXISTS:
|
||||
return memgraph::dbms::RegisterReplicaError::NAME_EXISTS;
|
||||
case memgraph::replication::RegisterReplicaError::END_POINT_EXISTS:
|
||||
return memgraph::dbms::RegisterReplicaError::END_POINT_EXISTS;
|
||||
case memgraph::replication::RegisterReplicaError::COULD_NOT_BE_PERSISTED:
|
||||
return memgraph::dbms::RegisterReplicaError::COULD_NOT_BE_PERSISTED;
|
||||
case memgraph::replication::RegisterReplicaError::SUCCESS:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!allow_mt_repl && dbms_handler_.All().size() > 1) {
|
||||
spdlog::warn("Multi-tenant replication is currently not supported!");
|
||||
}
|
||||
|
||||
bool all_clients_good = true;
|
||||
|
||||
// Add database specific clients (NOTE Currently all databases are connected to each replica)
|
||||
dbms_handler_.ForEach([&](Database *db) {
|
||||
auto *storage = db->storage();
|
||||
if (!allow_mt_repl && storage->id() != kDefaultDB) {
|
||||
return;
|
||||
}
|
||||
// TODO: ATM only IN_MEMORY_TRANSACTIONAL, fix other modes
|
||||
if (storage->storage_mode_ != storage::StorageMode::IN_MEMORY_TRANSACTIONAL) return;
|
||||
|
||||
all_clients_good &=
|
||||
storage->repl_storage_state_.replication_clients_.WithLock([storage, &instance_client](auto &storage_clients) {
|
||||
auto client = std::make_unique<storage::ReplicationStorageClient>(*instance_client.GetValue());
|
||||
client->Start(storage);
|
||||
// After start the storage <-> replica state should be READY or RECOVERING (if correctly started)
|
||||
// MAYBE_BEHIND isn't a statement of the current state, this is the default value
|
||||
// Failed to start due to branching of MAIN and REPLICA
|
||||
if (client->State() == storage::replication::ReplicaState::MAYBE_BEHIND) {
|
||||
return false;
|
||||
}
|
||||
storage_clients.push_back(std::move(client));
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
// NOTE Currently if any databases fails, we revert back
|
||||
if (!all_clients_good) {
|
||||
spdlog::error("Failed to register all databases to the REPLICA \"{}\"", config.name);
|
||||
UnregisterReplica(config.name);
|
||||
return RegisterReplicaError::CONNECTION_FAILED;
|
||||
}
|
||||
|
||||
// No client error, start instance level client
|
||||
StartReplicaClient(dbms_handler_, *instance_client.GetValue());
|
||||
return {};
|
||||
}
|
||||
|
||||
auto ReplicationHandler::UnregisterReplica(std::string_view name) -> UnregisterReplicaResult {
|
||||
auto const replica_handler = [](RoleReplicaData const &) -> UnregisterReplicaResult {
|
||||
return UnregisterReplicaResult::NOT_MAIN;
|
||||
};
|
||||
auto const main_handler = [this, name](RoleMainData &mainData) -> UnregisterReplicaResult {
|
||||
if (!dbms_handler_.ReplicationState().TryPersistUnregisterReplica(name)) {
|
||||
return UnregisterReplicaResult::COULD_NOT_BE_PERSISTED;
|
||||
}
|
||||
// Remove database specific clients
|
||||
dbms_handler_.ForEach([name](Database *db) {
|
||||
db->storage()->repl_storage_state_.replication_clients_.WithLock([&name](auto &clients) {
|
||||
std::erase_if(clients, [name](const auto &client) { return client->Name() == name; });
|
||||
});
|
||||
});
|
||||
// Remove instance level clients
|
||||
auto const n_unregistered =
|
||||
std::erase_if(mainData.registered_replicas_, [name](auto const &client) { return client.name_ == name; });
|
||||
return n_unregistered != 0 ? UnregisterReplicaResult::SUCCESS : UnregisterReplicaResult::CAN_NOT_UNREGISTER;
|
||||
};
|
||||
|
||||
return std::visit(utils::Overloaded{main_handler, replica_handler},
|
||||
dbms_handler_.ReplicationState().ReplicationData());
|
||||
}
|
||||
|
||||
auto ReplicationHandler::GetRole() const -> memgraph::replication::ReplicationRole {
|
||||
return dbms_handler_.ReplicationState().GetRole();
|
||||
}
|
||||
|
||||
bool ReplicationHandler::IsMain() const { return dbms_handler_.ReplicationState().IsMain(); }
|
||||
|
||||
bool ReplicationHandler::IsReplica() const { return dbms_handler_.ReplicationState().IsReplica(); }
|
||||
|
||||
// Per storage
|
||||
// NOTE Storage will connect to all replicas. Future work might change this
|
||||
void RestoreReplication(replication::ReplicationState &repl_state, storage::Storage &storage) {
|
||||
spdlog::info("Restoring replication role.");
|
||||
|
||||
/// MAIN
|
||||
auto const recover_main = [&storage](RoleMainData &mainData) {
|
||||
// Each individual client has already been restored and started. Here we just go through each database and start its
|
||||
// client
|
||||
for (auto &instance_client : mainData.registered_replicas_) {
|
||||
spdlog::info("Replica {} restoration started for {}.", instance_client.name_, storage.id());
|
||||
|
||||
const auto &ret = storage.repl_storage_state_.replication_clients_.WithLock(
|
||||
[&](auto &storage_clients) -> utils::BasicResult<RegisterReplicaError> {
|
||||
auto client = std::make_unique<storage::ReplicationStorageClient>(instance_client);
|
||||
client->Start(&storage);
|
||||
// After start the storage <-> replica state should be READY or RECOVERING (if correctly started)
|
||||
// MAYBE_BEHIND isn't a statement of the current state, this is the default value
|
||||
// Failed to start due to branching of MAIN and REPLICA
|
||||
if (client->State() == storage::replication::ReplicaState::MAYBE_BEHIND) {
|
||||
spdlog::warn("Connection failed when registering replica {}. Replica will still be registered.",
|
||||
instance_client.name_);
|
||||
}
|
||||
storage_clients.push_back(std::move(client));
|
||||
return {};
|
||||
});
|
||||
|
||||
if (ret.HasError()) {
|
||||
MG_ASSERT(RegisterReplicaError::CONNECTION_FAILED != ret.GetError());
|
||||
LOG_FATAL("Failure when restoring replica {}: {}.", instance_client.name_,
|
||||
RegisterReplicaErrorToString(ret.GetError()));
|
||||
}
|
||||
spdlog::info("Replica {} restored for {}.", instance_client.name_, storage.id());
|
||||
}
|
||||
spdlog::info("Replication role restored to MAIN.");
|
||||
};
|
||||
|
||||
/// REPLICA
|
||||
auto const recover_replica = [](RoleReplicaData const &data) { /*nothing to do*/ };
|
||||
|
||||
std::visit(
|
||||
utils::Overloaded{
|
||||
recover_main,
|
||||
recover_replica,
|
||||
},
|
||||
repl_state.ReplicationData());
|
||||
}
|
||||
} // namespace memgraph::dbms
|
||||
@@ -5,7 +5,6 @@ add_library(mg-flags STATIC audit.cpp
|
||||
log_level.cpp
|
||||
memory_limit.cpp
|
||||
run_time_configurable.cpp
|
||||
storage_mode.cpp
|
||||
query.cpp)
|
||||
storage_mode.cpp)
|
||||
target_include_directories(mg-flags PUBLIC ${CMAKE_SOURCE_DIR}/include)
|
||||
target_link_libraries(mg-flags PUBLIC spdlog::spdlog mg-settings mg-utils)
|
||||
|
||||
@@ -16,6 +16,5 @@
|
||||
#include "flags/isolation_level.hpp"
|
||||
#include "flags/log_level.hpp"
|
||||
#include "flags/memory_limit.hpp"
|
||||
#include "flags/query.hpp"
|
||||
#include "flags/run_time_configurable.hpp"
|
||||
#include "flags/storage_mode.hpp"
|
||||
|
||||
@@ -36,3 +36,7 @@ DEFINE_VALIDATED_int32(bolt_session_inactivity_timeout, 1800,
|
||||
DEFINE_string(bolt_cert_file, "", "Certificate file which should be used for the Bolt server.");
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_string(bolt_key_file, "", "Key file which should be used for the Bolt server.");
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_string(bolt_server_name_for_init, "",
|
||||
"Server name which the database should send to the client in the "
|
||||
"Bolt INIT message.");
|
||||
|
||||
@@ -26,4 +26,4 @@ DECLARE_string(bolt_cert_file);
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DECLARE_string(bolt_key_file);
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
// DECLARE_string(bolt_server_name_for_init); Moved to run_time_configurable
|
||||
DECLARE_string(bolt_server_name_for_init);
|
||||
|
||||
@@ -65,7 +65,7 @@ DEFINE_bool(allow_load_csv, true, "Controls whether LOAD CSV clause is allowed i
|
||||
// Storage flags.
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_VALIDATED_uint64(storage_gc_cycle_sec, 30, "Storage garbage collector interval (in seconds).",
|
||||
FLAG_IN_RANGE(1, 24UL * 3600));
|
||||
FLAG_IN_RANGE(1, 24 * 3600));
|
||||
// NOTE: The `storage_properties_on_edges` flag must be the same here and in
|
||||
// `mg_import_csv`. If you change it, make sure to change it there as well.
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
@@ -104,19 +104,9 @@ DEFINE_bool(storage_snapshot_on_exit, false, "Controls whether the storage creat
|
||||
DEFINE_uint64(storage_items_per_batch, memgraph::storage::Config::Durability().items_per_batch,
|
||||
"The number of edges and vertices stored in a batch in a snapshot file.");
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables,misc-unused-parameters)
|
||||
DEFINE_VALIDATED_bool(
|
||||
storage_parallel_index_recovery, false,
|
||||
"Controls whether the index creation can be done in a multithreaded fashion.", {
|
||||
spdlog::warn(
|
||||
"storage_parallel_index_recovery flag is deprecated. Check storage_mode_parallel_schema_recovery for more "
|
||||
"details.");
|
||||
return true;
|
||||
});
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_bool(storage_parallel_schema_recovery, false,
|
||||
"Controls whether the indices and constraints creation can be done in a multithreaded fashion.");
|
||||
DEFINE_bool(storage_parallel_index_recovery, false,
|
||||
"Controls whether the index creation can be done in a multithreaded fashion.");
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_uint64(storage_recovery_thread_count,
|
||||
@@ -124,10 +114,6 @@ DEFINE_uint64(storage_recovery_thread_count,
|
||||
memgraph::storage::Config::Durability().recovery_thread_count),
|
||||
"The number of threads used to recover persisted data from disk.");
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_bool(storage_enable_schema_metadata, false,
|
||||
"Controls whether metadata should be collected about the resident labels and edge types.");
|
||||
|
||||
#ifdef MG_ENTERPRISE
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_bool(storage_delete_on_drop, true,
|
||||
@@ -159,6 +145,11 @@ DEFINE_string(pulsar_service_url, "", "Default URL used while connecting to Puls
|
||||
|
||||
// Query flags.
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_double(query_execution_timeout_sec, -1,
|
||||
"Maximum allowed query execution time. Queries exceeding this "
|
||||
"limit will be aborted. Value of 0 means no limit.");
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_uint64(replication_replica_check_frequency_sec, 1,
|
||||
"The time duration between two replica checks/pings. If < 1, replicas will NOT be checked at all. NOTE: "
|
||||
|
||||
@@ -73,15 +73,10 @@ DECLARE_uint64(storage_wal_file_flush_every_n_tx);
|
||||
DECLARE_bool(storage_snapshot_on_exit);
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DECLARE_uint64(storage_items_per_batch);
|
||||
// storage_parallel_index_recovery deprecated; use storage_parallel_schema_recovery instead
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DECLARE_bool(storage_parallel_index_recovery);
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DECLARE_bool(storage_parallel_schema_recovery);
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DECLARE_uint64(storage_recovery_thread_count);
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DECLARE_bool(storage_enable_schema_metadata);
|
||||
#ifdef MG_ENTERPRISE
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DECLARE_bool(storage_delete_on_drop);
|
||||
@@ -105,7 +100,7 @@ DECLARE_string(pulsar_service_url);
|
||||
// Query flags.
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
// DECLARE_double(query_execution_timeout_sec); Moved to run_time_configurable
|
||||
DECLARE_double(query_execution_timeout_sec);
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DECLARE_string(query_modules_directory);
|
||||
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
@@ -26,6 +26,7 @@ using namespace std::string_view_literals;
|
||||
|
||||
// Logging flags
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_HIDDEN_bool(also_log_to_stderr, false, "Log messages go to stderr in addition to logfiles");
|
||||
DEFINE_string(log_file, "", "Path to where the log should be stored.");
|
||||
|
||||
inline constexpr std::array log_level_mappings{
|
||||
@@ -33,8 +34,11 @@ inline constexpr std::array log_level_mappings{
|
||||
std::pair{"INFO"sv, spdlog::level::info}, std::pair{"WARNING"sv, spdlog::level::warn},
|
||||
std::pair{"ERROR"sv, spdlog::level::err}, std::pair{"CRITICAL"sv, spdlog::level::critical}};
|
||||
|
||||
const std::string memgraph::flags::log_level_help_string = fmt::format(
|
||||
"Minimum log level. Allowed values: {}", memgraph::utils::GetAllowedEnumValuesString(log_level_mappings));
|
||||
const std::string log_level_help_string = fmt::format("Minimum log level. Allowed values: {}",
|
||||
memgraph::utils::GetAllowedEnumValuesString(log_level_mappings));
|
||||
|
||||
DEFINE_VALIDATED_string(log_level, "WARNING", log_level_help_string.c_str(),
|
||||
{ return memgraph::flags::ValidLogLevel(value); });
|
||||
|
||||
bool memgraph::flags::ValidLogLevel(std::string_view value) {
|
||||
if (const auto result = memgraph::utils::IsValidEnumValueString(value, log_level_mappings); result.HasError()) {
|
||||
@@ -61,9 +65,7 @@ std::optional<spdlog::level::level_enum> memgraph::flags::LogLevelToEnum(std::st
|
||||
}
|
||||
|
||||
spdlog::level::level_enum ParseLogLevel() {
|
||||
std::string ll;
|
||||
gflags::GetCommandLineOption("log_level", &ll);
|
||||
const auto log_level = memgraph::flags::LogLevelToEnum(ll);
|
||||
const auto log_level = memgraph::flags::LogLevelToEnum(FLAGS_log_level);
|
||||
MG_ASSERT(log_level, "Invalid log level");
|
||||
return *log_level;
|
||||
}
|
||||
@@ -75,6 +77,10 @@ void CreateLoggerFromSink(const auto &sinks, const auto log_level) {
|
||||
logger->set_level(log_level);
|
||||
logger->flush_on(spdlog::level::trace);
|
||||
spdlog::set_default_logger(std::move(logger));
|
||||
// Enable stderr sink
|
||||
if (FLAGS_also_log_to_stderr) {
|
||||
memgraph::flags::LogToStderr(log_level);
|
||||
}
|
||||
}
|
||||
|
||||
void memgraph::flags::InitializeLogger() {
|
||||
@@ -111,14 +117,6 @@ void memgraph::flags::AddLoggerSink(spdlog::sink_ptr new_sink) {
|
||||
// NOTE: default_logger is not thread-safe and shouldn't be changed during application lifetime
|
||||
void memgraph::flags::LogToStderr(spdlog::level::level_enum log_level) {
|
||||
auto default_logger = spdlog::default_logger();
|
||||
auto stderr = default_logger->sinks().front();
|
||||
stderr->set_level(log_level);
|
||||
}
|
||||
|
||||
void memgraph::flags::UpdateStderr(spdlog::level::level_enum log_level) {
|
||||
auto default_logger = spdlog::default_logger();
|
||||
auto stderr = default_logger->sinks().front();
|
||||
if (stderr->level() != spdlog::level::off) {
|
||||
stderr->set_level(log_level);
|
||||
}
|
||||
auto sink = default_logger->sinks().front();
|
||||
sink->set_level(log_level);
|
||||
}
|
||||
|
||||
@@ -14,19 +14,16 @@
|
||||
#include <optional>
|
||||
#include "gflags/gflags.h"
|
||||
|
||||
// DECLARE_string(log_level); Moved to run_time_configurable
|
||||
// DECLARE_bool(also_log_to_stderr); Moved to run_time_configurable
|
||||
DECLARE_string(log_level);
|
||||
DECLARE_bool(also_log_to_stderr);
|
||||
|
||||
namespace memgraph::flags {
|
||||
|
||||
extern const std::string log_level_help_string;
|
||||
|
||||
bool ValidLogLevel(std::string_view value);
|
||||
std::optional<spdlog::level::level_enum> LogLevelToEnum(std::string_view value);
|
||||
|
||||
void InitializeLogger();
|
||||
void AddLoggerSink(spdlog::sink_ptr new_sink);
|
||||
void LogToStderr(spdlog::level::level_enum log_level);
|
||||
void UpdateStderr(spdlog::level::level_enum log_level);
|
||||
|
||||
} // namespace memgraph::flags
|
||||
|
||||
@@ -1,14 +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.
|
||||
#include "flags/query.hpp"
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
// DEFINE_bool(cartesian_product_enabled, true, "Enable cartesian product expansion."); Moved to run_time_configurable
|
||||
@@ -1,16 +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.
|
||||
#pragma once
|
||||
|
||||
#include "gflags/gflags.h"
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
// DECLARE_bool(cartesian_product_enabled); Moved to run_time_configurable
|
||||
@@ -10,193 +10,102 @@
|
||||
// licenses/APL.txt.
|
||||
|
||||
#include "flags/run_time_configurable.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
#include "gflags/gflags.h"
|
||||
|
||||
#include "flags/bolt.hpp"
|
||||
#include "flags/general.hpp"
|
||||
#include "flags/log_level.hpp"
|
||||
#include "flags/query.hpp"
|
||||
#include "spdlog/cfg/helpers-inl.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "utils/exceptions.hpp"
|
||||
#include "utils/flag_validation.hpp"
|
||||
#include "utils/settings.hpp"
|
||||
#include "utils/string.hpp"
|
||||
|
||||
/*
|
||||
* Setup GFlags
|
||||
*/
|
||||
|
||||
// Bolt server flags.
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_string(bolt_server_name_for_init, "Neo4j/v5.11.0 compatible graph database server - Memgraph",
|
||||
"Server name which the database should send to the client in the "
|
||||
"Bolt INIT message.");
|
||||
|
||||
// Logging flags
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_HIDDEN_bool(also_log_to_stderr, false, "Log messages go to stderr in addition to logfiles");
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables, misc-unused-parameters)
|
||||
DEFINE_VALIDATED_string(log_level, "WARNING", memgraph::flags::log_level_help_string.c_str(),
|
||||
{ return memgraph::flags::ValidLogLevel(value); });
|
||||
|
||||
// Query flags
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_double(query_execution_timeout_sec, 600,
|
||||
"Maximum allowed query execution time. Queries exceeding this "
|
||||
"limit will be aborted. Value of 0 means no limit.");
|
||||
|
||||
// Query plan flags
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_bool(cartesian_product_enabled, true, "Enable cartesian product expansion.");
|
||||
|
||||
namespace {
|
||||
// Bolt server name
|
||||
constexpr auto kServerNameSettingKey = "server.name";
|
||||
constexpr auto kServerNameGFlagsKey = "bolt_server_name_for_init";
|
||||
constexpr auto kDefaultServerName = "Neo4j/v5.11.0 compatible graph database server - Memgraph";
|
||||
// Query timeout
|
||||
constexpr auto kQueryTxSettingKey = "query.timeout";
|
||||
constexpr auto kQueryTxGFlagsKey = "query_execution_timeout_sec";
|
||||
constexpr auto kDefaultQueryTx = "600"; // seconds
|
||||
// Log level
|
||||
// No default value because it is not persistent
|
||||
constexpr auto kLogLevelSettingKey = "log.level";
|
||||
constexpr auto kLogLevelGFlagsKey = "log_level";
|
||||
// Log to stderr
|
||||
// No default value because it is not persistent
|
||||
constexpr auto kLogToStderrSettingKey = "log.to_stderr";
|
||||
constexpr auto kLogToStderrGFlagsKey = "also_log_to_stderr";
|
||||
|
||||
constexpr auto kCartesianProductEnabledSettingKey = "cartesian-product-enabled";
|
||||
constexpr auto kCartesianProductEnabledGFlagsKey = "cartesian-product-enabled";
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
std::atomic<double> execution_timeout_sec_; // Local cache-like thing
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
std::atomic<bool> cartesian_product_enabled_{true}; // Local cache-like thing
|
||||
|
||||
auto ToLLEnum(std::string_view val) {
|
||||
const auto ll_enum = memgraph::flags::LogLevelToEnum(val);
|
||||
if (!ll_enum) {
|
||||
throw memgraph::utils::BasicException("Unsupported log level {}", val);
|
||||
}
|
||||
return *ll_enum;
|
||||
}
|
||||
|
||||
bool ValidBoolStr(std::string_view in) {
|
||||
const auto lc = memgraph::utils::ToLowerCase(in);
|
||||
return lc == "false" || lc == "true";
|
||||
}
|
||||
|
||||
auto GenHandler(std::string flag, std::string key) {
|
||||
return [key = std::move(key), flag = std::move(flag)]() -> std::string {
|
||||
const auto &val = memgraph::utils::global_settings.GetValue(key);
|
||||
MG_ASSERT(val, "Failed to read value at '{}' from settings.", key);
|
||||
gflags::SetCommandLineOption(flag.c_str(), val->c_str());
|
||||
return *val;
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace memgraph::flags::run_time {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
memgraph::utils::Synchronized<std::string, memgraph::utils::SpinLock> bolt_server_name_;
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
std::atomic<double> execution_timeout_sec_;
|
||||
|
||||
void Initialize() {
|
||||
constexpr bool kRestore = true; //!< run-time flag is persistent between Memgraph restarts
|
||||
|
||||
/**
|
||||
* @brief Helper function that registers a run-time flag
|
||||
*
|
||||
* @param flag - GFlag name
|
||||
* @param key - Settings key used to store the flag
|
||||
* @param restore - true if the flag is persistent between restarts
|
||||
* @param post_update - user defined callback executed post flag update
|
||||
* @param validator - user defined value correctness checker
|
||||
*/
|
||||
auto register_flag = [&](
|
||||
const std::string &flag, const std::string &key, bool restore,
|
||||
std::function<void(const std::string &)> post_update = [](auto) {},
|
||||
std::function<bool(std::string_view)> validator = [](std::string_view) { return true; }) {
|
||||
// Get flag info
|
||||
gflags::CommandLineFlagInfo info;
|
||||
gflags::GetCommandLineFlagInfo(flag.c_str(), &info);
|
||||
// Register setting
|
||||
auto update = GenHandler(flag, key);
|
||||
memgraph::utils::global_settings.RegisterSetting(
|
||||
key, info.default_value,
|
||||
[update, post_update = std::move(post_update)] {
|
||||
const auto &val = update();
|
||||
post_update(val);
|
||||
},
|
||||
validator);
|
||||
|
||||
if (restore && info.is_default) {
|
||||
// No input from the user, restore persistent value from settings
|
||||
update();
|
||||
} else {
|
||||
// Override with current value - user defined a new value or the run-time flag is not persistent between starts
|
||||
memgraph::utils::global_settings.SetValue(key, info.current_value);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Register bolt server name settings
|
||||
*/
|
||||
register_flag(kServerNameGFlagsKey, kServerNameSettingKey, kRestore);
|
||||
|
||||
/*
|
||||
* Register query timeout
|
||||
*/
|
||||
register_flag(kQueryTxGFlagsKey, kQueryTxSettingKey, !kRestore, [&](const std::string &val) {
|
||||
execution_timeout_sec_ = std::stod(val); // Cache for faster reads
|
||||
// Register bolt server name settings
|
||||
memgraph::utils::global_settings.RegisterSetting(kServerNameSettingKey, kDefaultServerName, [&] {
|
||||
const auto server_name = memgraph::utils::global_settings.GetValue(kServerNameSettingKey);
|
||||
MG_ASSERT(server_name, "Bolt server name is missing from the settings");
|
||||
*(bolt_server_name_.Lock()) = *server_name;
|
||||
});
|
||||
// Update value from read settings
|
||||
const auto &name = memgraph::utils::global_settings.GetValue(kServerNameSettingKey);
|
||||
MG_ASSERT(name, "Failed to read server name from settings.");
|
||||
*(bolt_server_name_.Lock()) = *name;
|
||||
// Override server name if passed via command line argument
|
||||
if (!FLAGS_bolt_server_name_for_init.empty()) {
|
||||
memgraph::utils::global_settings.SetValue(kServerNameSettingKey, FLAGS_bolt_server_name_for_init);
|
||||
}
|
||||
|
||||
/*
|
||||
* Register log level
|
||||
*/
|
||||
register_flag(
|
||||
kLogLevelGFlagsKey, kLogLevelSettingKey, !kRestore,
|
||||
[](const std::string &val) {
|
||||
const auto ll_enum = ToLLEnum(val);
|
||||
spdlog::set_level(ll_enum);
|
||||
UpdateStderr(ll_enum); // Updates level if active
|
||||
},
|
||||
// Register query timeout
|
||||
memgraph::utils::global_settings.RegisterSetting(kQueryTxSettingKey, kDefaultQueryTx, [&] {
|
||||
const auto query_tx = memgraph::utils::global_settings.GetValue(kQueryTxSettingKey);
|
||||
MG_ASSERT(query_tx, "Query timeout is missing from the settings");
|
||||
execution_timeout_sec_ = std::stod(*query_tx);
|
||||
});
|
||||
// Update value from read settings
|
||||
const auto &tx = memgraph::utils::global_settings.GetValue(kQueryTxSettingKey);
|
||||
MG_ASSERT(tx, "Failed to read query timeout from settings.");
|
||||
execution_timeout_sec_ = std::stod(*tx);
|
||||
// Override query timeout if passed via command line argument
|
||||
if (FLAGS_query_execution_timeout_sec != -1) {
|
||||
memgraph::utils::global_settings.SetValue(kQueryTxSettingKey, std::to_string(FLAGS_query_execution_timeout_sec));
|
||||
}
|
||||
|
||||
// Register log level
|
||||
auto get_global_log_level = []() {
|
||||
const auto log_level = memgraph::utils::global_settings.GetValue(kLogLevelSettingKey);
|
||||
MG_ASSERT(log_level, "Log level is missing from the settings");
|
||||
const auto ll_enum = memgraph::flags::LogLevelToEnum(*log_level);
|
||||
if (!ll_enum) {
|
||||
throw utils::BasicException("Unsupported log level {}", *log_level);
|
||||
}
|
||||
return *ll_enum;
|
||||
};
|
||||
memgraph::utils::global_settings.RegisterSetting(
|
||||
kLogLevelSettingKey, FLAGS_log_level, [&] { spdlog::set_level(get_global_log_level()); },
|
||||
memgraph::flags::ValidLogLevel);
|
||||
// Always override log level with command line argument
|
||||
memgraph::utils::global_settings.SetValue(kLogLevelSettingKey, FLAGS_log_level);
|
||||
|
||||
/*
|
||||
* Register logging to stderr
|
||||
*/
|
||||
register_flag(
|
||||
kLogToStderrGFlagsKey, kLogToStderrSettingKey, !kRestore,
|
||||
[](const std::string &val) {
|
||||
if (val == "true") {
|
||||
// No need to check if ll_val exists, we got here, so the log_level must exist already
|
||||
const auto &ll_val = memgraph::utils::global_settings.GetValue(kLogLevelSettingKey);
|
||||
LogToStderr(ToLLEnum(*ll_val));
|
||||
// Register logging to stderr
|
||||
auto bool_to_str = [](bool in) { return in ? "true" : "false"; };
|
||||
const std::string log_to_stderr_s = bool_to_str(FLAGS_also_log_to_stderr);
|
||||
memgraph::utils::global_settings.RegisterSetting(
|
||||
kLogToStderrSettingKey, log_to_stderr_s,
|
||||
[&] {
|
||||
const auto enable = memgraph::utils::global_settings.GetValue(kLogToStderrSettingKey);
|
||||
if (enable == "true") {
|
||||
LogToStderr(get_global_log_level());
|
||||
} else {
|
||||
LogToStderr(spdlog::level::off);
|
||||
}
|
||||
},
|
||||
ValidBoolStr);
|
||||
|
||||
register_flag(
|
||||
kCartesianProductEnabledGFlagsKey, kCartesianProductEnabledSettingKey, !kRestore,
|
||||
[](const std::string &val) { cartesian_product_enabled_ = val == "true"; }, ValidBoolStr);
|
||||
[](std::string_view in) {
|
||||
const auto lc = memgraph::utils::ToLowerCase(in);
|
||||
return lc == "false" || lc == "true";
|
||||
});
|
||||
// Always override log to stderr with command line argument
|
||||
memgraph::utils::global_settings.SetValue(kLogToStderrSettingKey, log_to_stderr_s);
|
||||
}
|
||||
|
||||
std::string GetServerName() {
|
||||
std::string s;
|
||||
// Thread safe read of gflag
|
||||
gflags::GetCommandLineOption(kServerNameGFlagsKey, &s);
|
||||
return s;
|
||||
}
|
||||
|
||||
double GetExecutionTimeout() { return execution_timeout_sec_; }
|
||||
|
||||
bool GetCartesianProductEnabled() { return cartesian_product_enabled_; }
|
||||
|
||||
} // namespace memgraph::flags::run_time
|
||||
|
||||
@@ -15,31 +15,12 @@
|
||||
|
||||
namespace memgraph::flags::run_time {
|
||||
|
||||
/**
|
||||
* @brief Initialize the run-time flags (must be done before run-time flags are used).
|
||||
*
|
||||
*/
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
extern utils::Synchronized<std::string, utils::SpinLock> bolt_server_name_;
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
extern std::atomic<double> execution_timeout_sec_;
|
||||
|
||||
void Initialize();
|
||||
|
||||
/**
|
||||
* @brief Get the bolt server name value
|
||||
*
|
||||
* @return std::string
|
||||
*/
|
||||
std::string GetServerName();
|
||||
|
||||
/**
|
||||
* @brief Get the query execution timeout value
|
||||
*
|
||||
* @return double
|
||||
*/
|
||||
double GetExecutionTimeout();
|
||||
|
||||
/**
|
||||
* @brief Get the cartesian product enabled value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
bool GetCartesianProductEnabled();
|
||||
|
||||
} // namespace memgraph::flags::run_time
|
||||
|
||||
@@ -7,4 +7,5 @@ target_sources(mg-glue PRIVATE auth.cpp
|
||||
ServerT.cpp
|
||||
MonitoringServerT.cpp
|
||||
run_id.cpp)
|
||||
target_link_libraries(mg-glue mg-query mg-auth mg-audit mg-flags)
|
||||
target_link_libraries(mg-glue mg-query mg-auth mg-audit)
|
||||
target_precompile_headers(mg-glue INTERFACE auth_checker.hpp auth_handler.hpp)
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
// licenses/APL.txt.
|
||||
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
#include "gflags/gflags.h"
|
||||
|
||||
#include "audit/log.hpp"
|
||||
@@ -123,8 +122,8 @@ std::string SessionHL::GetCurrentDB() const {
|
||||
}
|
||||
|
||||
std::optional<std::string> SessionHL::GetServerNameForInit() {
|
||||
const auto &name = flags::run_time::GetServerName();
|
||||
return name.empty() ? std::nullopt : std::make_optional(name);
|
||||
auto locked_name = flags::run_time::bolt_server_name_.Lock();
|
||||
return locked_name->empty() ? std::nullopt : std::make_optional(*locked_name);
|
||||
}
|
||||
|
||||
bool SessionHL::Authenticate(const std::string &username, const std::string &password) {
|
||||
@@ -178,11 +177,6 @@ std::map<std::string, memgraph::communication::bolt::Value> SessionHL::Pull(Sess
|
||||
// Wrap QueryException into ClientError, because we want to allow the
|
||||
// client to fix their query.
|
||||
throw memgraph::communication::bolt::ClientError(e.what());
|
||||
} catch (const utils::BasicException &) {
|
||||
// Exceptions inheriting from BasicException will result in a TransientError
|
||||
// i. e. client will be encouraged to retry execution because it
|
||||
// could succeed if executed again.
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,55 +228,11 @@ std::pair<std::vector<std::string>, std::optional<int>> SessionHL::Interpret(
|
||||
throw memgraph::communication::bolt::ClientError(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void SessionHL::RollbackTransaction() {
|
||||
try {
|
||||
interpreter_.RollbackTransaction();
|
||||
} catch (const memgraph::query::QueryException &e) {
|
||||
// Count the number of specific exceptions thrown
|
||||
metrics::IncrementCounter(GetExceptionName(e));
|
||||
// Wrap QueryException into ClientError, because we want to allow the
|
||||
// client to fix their query.
|
||||
throw memgraph::communication::bolt::ClientError(e.what());
|
||||
} catch (const memgraph::query::ReplicationException &e) {
|
||||
// Count the number of specific exceptions thrown
|
||||
metrics::IncrementCounter(GetExceptionName(e));
|
||||
throw memgraph::communication::bolt::ClientError(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void SessionHL::CommitTransaction() {
|
||||
try {
|
||||
interpreter_.CommitTransaction();
|
||||
} catch (const memgraph::query::QueryException &e) {
|
||||
// Count the number of specific exceptions thrown
|
||||
metrics::IncrementCounter(GetExceptionName(e));
|
||||
// Wrap QueryException into ClientError, because we want to allow the
|
||||
// client to fix their query.
|
||||
throw memgraph::communication::bolt::ClientError(e.what());
|
||||
} catch (const memgraph::query::ReplicationException &e) {
|
||||
// Count the number of specific exceptions thrown
|
||||
metrics::IncrementCounter(GetExceptionName(e));
|
||||
throw memgraph::communication::bolt::ClientError(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void SessionHL::RollbackTransaction() { interpreter_.RollbackTransaction(); }
|
||||
void SessionHL::CommitTransaction() { interpreter_.CommitTransaction(); }
|
||||
void SessionHL::BeginTransaction(const std::map<std::string, memgraph::communication::bolt::Value> &extra) {
|
||||
try {
|
||||
interpreter_.BeginTransaction(ToQueryExtras(extra));
|
||||
} catch (const memgraph::query::QueryException &e) {
|
||||
// Count the number of specific exceptions thrown
|
||||
metrics::IncrementCounter(GetExceptionName(e));
|
||||
// Wrap QueryException into ClientError, because we want to allow the
|
||||
// client to fix their query.
|
||||
throw memgraph::communication::bolt::ClientError(e.what());
|
||||
} catch (const memgraph::query::ReplicationException &e) {
|
||||
// Count the number of specific exceptions thrown
|
||||
metrics::IncrementCounter(GetExceptionName(e));
|
||||
throw memgraph::communication::bolt::ClientError(e.what());
|
||||
}
|
||||
interpreter_.BeginTransaction(ToQueryExtras(extra));
|
||||
}
|
||||
|
||||
void SessionHL::Configure(const std::map<std::string, memgraph::communication::bolt::Value> &run_time_info) {
|
||||
#ifdef MG_ENTERPRISE
|
||||
std::string db;
|
||||
@@ -317,7 +267,7 @@ void SessionHL::Configure(const std::map<std::string, memgraph::communication::b
|
||||
#endif
|
||||
}
|
||||
SessionHL::SessionHL(memgraph::query::InterpreterContext *interpreter_context,
|
||||
memgraph::communication::v2::ServerEndpoint endpoint,
|
||||
const memgraph::communication::v2::ServerEndpoint &endpoint,
|
||||
memgraph::communication::v2::InputStream *input_stream,
|
||||
memgraph::communication::v2::OutputStream *output_stream,
|
||||
memgraph::utils::Synchronized<memgraph::auth::Auth, memgraph::utils::WritePrioritizedRWLock> *auth
|
||||
@@ -334,7 +284,7 @@ SessionHL::SessionHL(memgraph::query::InterpreterContext *interpreter_context,
|
||||
audit_log_(audit_log),
|
||||
#endif
|
||||
auth_(auth),
|
||||
endpoint_(std::move(endpoint)),
|
||||
endpoint_(endpoint),
|
||||
implicit_db_(dbms::kDefaultDB) {
|
||||
// Metrics update
|
||||
memgraph::metrics::IncrementCounter(memgraph::metrics::ActiveBoltSessions);
|
||||
|
||||
@@ -23,7 +23,7 @@ class SessionHL final : public memgraph::communication::bolt::Session<memgraph::
|
||||
memgraph::communication::v2::OutputStream> {
|
||||
public:
|
||||
SessionHL(memgraph::query::InterpreterContext *interpreter_context,
|
||||
memgraph::communication::v2::ServerEndpoint endpoint,
|
||||
const memgraph::communication::v2::ServerEndpoint &endpoint,
|
||||
memgraph::communication::v2::InputStream *input_stream,
|
||||
memgraph::communication::v2::OutputStream *output_stream,
|
||||
memgraph::utils::Synchronized<memgraph::auth::Auth, memgraph::utils::WritePrioritizedRWLock> *auth
|
||||
|
||||
@@ -127,8 +127,6 @@ storage::Result<Value> ToBoltValue(const query::TypedValue &value, const storage
|
||||
return Value(value.ValueLocalDateTime());
|
||||
case query::TypedValue::Type::Duration:
|
||||
return Value(value.ValueDuration());
|
||||
case query::TypedValue::Type::Function:
|
||||
throw communication::bolt::ValueException("Unsupported conversion from TypedValue::Function to Value");
|
||||
case query::TypedValue::Type::Graph:
|
||||
auto maybe_graph = ToBoltGraph(value.ValueGraph(), db, view);
|
||||
if (maybe_graph.HasError()) return maybe_graph.GetError();
|
||||
@@ -204,7 +202,7 @@ storage::Result<std::map<std::string, Value>> ToBoltGraph(const query::Graph &gr
|
||||
for (const auto &v : graph.vertices()) {
|
||||
auto maybe_vertex = ToBoltVertex(v, db, view);
|
||||
if (maybe_vertex.HasError()) return maybe_vertex.GetError();
|
||||
vertices.emplace_back(std::move(*maybe_vertex));
|
||||
vertices.emplace_back(Value(std::move(*maybe_vertex)));
|
||||
}
|
||||
map.emplace("nodes", Value(vertices));
|
||||
|
||||
@@ -213,7 +211,7 @@ storage::Result<std::map<std::string, Value>> ToBoltGraph(const query::Graph &gr
|
||||
for (const auto &e : graph.edges()) {
|
||||
auto maybe_edge = ToBoltEdge(e, db, view);
|
||||
if (maybe_edge.HasError()) return maybe_edge.GetError();
|
||||
edges.emplace_back(std::move(*maybe_edge));
|
||||
edges.emplace_back(Value(std::move(*maybe_edge)));
|
||||
}
|
||||
map.emplace("edges", Value(edges));
|
||||
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace memgraph::glue {
|
||||
extern const std::string run_id_;
|
||||
} // namespace memgraph::glue
|
||||
|
||||
@@ -31,7 +31,7 @@ inline void LoadConfig(const std::string &product_name) {
|
||||
std::vector<fs::path> configs = {fs::path("/etc/memgraph/memgraph.conf")};
|
||||
if (getenv("HOME") != nullptr) configs.emplace_back(fs::path(getenv("HOME")) / fs::path(".memgraph/config"));
|
||||
{
|
||||
auto *memgraph_config = getenv("MEMGRAPH_CONFIG");
|
||||
auto memgraph_config = getenv("MEMGRAPH_CONFIG");
|
||||
if (memgraph_config != nullptr) {
|
||||
auto path = fs::path(memgraph_config);
|
||||
MG_ASSERT(fs::exists(path), "MEMGRAPH_CONFIG environment variable set to nonexisting path: {}",
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <utils/event_counter.hpp>
|
||||
#include <utils/event_gauge.hpp>
|
||||
#include "storage/v2/storage.hpp"
|
||||
#include "utils/event_gauge.hpp"
|
||||
#include "utils/event_histogram.hpp"
|
||||
|
||||
namespace memgraph::http {
|
||||
@@ -64,7 +65,7 @@ class MetricsService {
|
||||
return MetricsResponse{.vertex_count = info.vertex_count,
|
||||
.edge_count = info.edge_count,
|
||||
.average_degree = info.average_degree,
|
||||
.memory_usage = info.memory_res,
|
||||
.memory_usage = info.memory_usage,
|
||||
.disk_usage = info.disk_usage,
|
||||
.event_counters = GetEventCounters(),
|
||||
.event_gauges = GetEventGauges(),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2023 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
|
||||
|
||||
@@ -171,10 +171,10 @@ class Consumer final : public RdKafka::EventCb {
|
||||
|
||||
class ConsumerRebalanceCb : public RdKafka::RebalanceCb {
|
||||
public:
|
||||
explicit ConsumerRebalanceCb(std::string consumer_name);
|
||||
ConsumerRebalanceCb(std::string consumer_name);
|
||||
|
||||
void rebalance_cb(RdKafka::KafkaConsumer *consumer, RdKafka::ErrorCode err,
|
||||
std::vector<RdKafka::TopicPartition *> &partitions) final;
|
||||
std::vector<RdKafka::TopicPartition *> &partitions) override final;
|
||||
|
||||
void set_offset(int64_t offset);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2023 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
|
||||
@@ -67,7 +67,7 @@ utils::BasicResult<std::string, std::vector<Message>> GetBatch(TConsumer &consum
|
||||
return std::move(batch);
|
||||
case pulsar_client::Result::ResultOk:
|
||||
if (message.getMessageId() != last_message_id) {
|
||||
batch.emplace_back(std::move(message));
|
||||
batch.emplace_back(Message{std::move(message)});
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2023 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
|
||||
@@ -10,7 +10,6 @@
|
||||
// licenses/APL.txt.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "endpoint.hpp"
|
||||
#include "io/network/endpoint.hpp"
|
||||
#include "io/network/network_error.hpp"
|
||||
#include "utils/logging.hpp"
|
||||
@@ -24,11 +23,11 @@
|
||||
|
||||
namespace memgraph::io::network {
|
||||
|
||||
Endpoint::IpFamily Endpoint::GetIpFamily(const std::string &address) {
|
||||
Endpoint::IpFamily Endpoint::GetIpFamily(const std::string &ip_address) {
|
||||
in_addr addr4;
|
||||
in6_addr addr6;
|
||||
int ipv4_result = inet_pton(AF_INET, address.c_str(), &addr4);
|
||||
int ipv6_result = inet_pton(AF_INET6, address.c_str(), &addr6);
|
||||
int ipv4_result = inet_pton(AF_INET, ip_address.c_str(), &addr4);
|
||||
int ipv6_result = inet_pton(AF_INET6, ip_address.c_str(), &addr6);
|
||||
if (ipv4_result == 1) {
|
||||
return IpFamily::IP4;
|
||||
} else if (ipv6_result == 1) {
|
||||
@@ -87,44 +86,6 @@ std::optional<std::pair<std::string, uint16_t>> Endpoint::ParseSocketOrIpAddress
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::pair<std::string, uint16_t>> Endpoint::ParseHostname(
|
||||
const std::string &address, const std::optional<uint16_t> default_port = {}) {
|
||||
const std::string delimiter = ":";
|
||||
std::string ip_address;
|
||||
std::vector<std::string> parts = utils::Split(address, delimiter);
|
||||
if (parts.size() == 1) {
|
||||
if (default_port) {
|
||||
if (!IsResolvableAddress(address, *default_port)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return std::pair{address, *default_port};
|
||||
}
|
||||
} else if (parts.size() == 2) {
|
||||
int64_t int_port{0};
|
||||
auto hostname = std::move(parts[0]);
|
||||
try {
|
||||
int_port = utils::ParseInt(parts[1]);
|
||||
} catch (utils::BasicException &e) {
|
||||
spdlog::error(utils::MessageWithLink("Invalid port number {}.", parts[1], "https://memgr.ph/ports"));
|
||||
return std::nullopt;
|
||||
}
|
||||
if (int_port < 0) {
|
||||
spdlog::error(utils::MessageWithLink("Invalid port number {}. The port number must be a positive integer.",
|
||||
int_port, "https://memgr.ph/ports"));
|
||||
return std::nullopt;
|
||||
}
|
||||
if (int_port > std::numeric_limits<uint16_t>::max()) {
|
||||
spdlog::error(utils::MessageWithLink("Invalid port number. The port number exceedes the maximum possible size.",
|
||||
"https://memgr.ph/ports"));
|
||||
return std::nullopt;
|
||||
}
|
||||
if (IsResolvableAddress(hostname, static_cast<uint16_t>(int_port))) {
|
||||
return std::pair{hostname, static_cast<u_int16_t>(int_port)};
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::string Endpoint::SocketAddress() const {
|
||||
auto ip_address = address.empty() ? "EMPTY" : address;
|
||||
return ip_address + ":" + std::to_string(port);
|
||||
@@ -138,16 +99,6 @@ Endpoint::Endpoint(std::string ip_address, uint16_t port) : address(std::move(ip
|
||||
family = ip_family;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE
|
||||
Endpoint::Endpoint(needs_resolving_t, std::string hostname, uint16_t port) : port(port) {
|
||||
address = ResolveHostnameIntoIpAddress(hostname, port);
|
||||
IpFamily ip_family = GetIpFamily(address);
|
||||
if (ip_family == IpFamily::NONE) {
|
||||
throw NetworkError("Not a valid IPv4 or IPv6 address: {}", address);
|
||||
}
|
||||
family = ip_family;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const Endpoint &endpoint) {
|
||||
// no need to cover the IpFamily::NONE case, as you can't even construct an
|
||||
// Endpoint object if the IpFamily is NONE (i.e. the IP address is invalid)
|
||||
@@ -158,65 +109,4 @@ std::ostream &operator<<(std::ostream &os, const Endpoint &endpoint) {
|
||||
return os << endpoint.address << ":" << endpoint.port;
|
||||
}
|
||||
|
||||
bool Endpoint::IsResolvableAddress(const std::string &address, uint16_t port) {
|
||||
addrinfo hints{
|
||||
.ai_flags = AI_PASSIVE,
|
||||
.ai_family = AF_UNSPEC, // IPv4 and IPv6
|
||||
.ai_socktype = SOCK_STREAM // TCP socket
|
||||
};
|
||||
addrinfo *info = nullptr;
|
||||
auto status = getaddrinfo(address.c_str(), std::to_string(port).c_str(), &hints, &info);
|
||||
freeaddrinfo(info);
|
||||
return status == 0;
|
||||
}
|
||||
|
||||
std::optional<std::pair<std::string, uint16_t>> Endpoint::ParseSocketOrAddress(
|
||||
const std::string &address, const std::optional<uint16_t> default_port = {}) {
|
||||
const std::string delimiter = ":";
|
||||
std::vector<std::string> parts = utils::Split(address, delimiter);
|
||||
if (parts.size() == 1) {
|
||||
if (GetIpFamily(address) == IpFamily::NONE) {
|
||||
return ParseHostname(address, default_port);
|
||||
}
|
||||
return ParseSocketOrIpAddress(address, default_port);
|
||||
}
|
||||
if (parts.size() == 2) {
|
||||
if (GetIpFamily(parts[0]) == IpFamily::NONE) {
|
||||
return ParseHostname(address, default_port);
|
||||
}
|
||||
return ParseSocketOrIpAddress(address, default_port);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::string Endpoint::ResolveHostnameIntoIpAddress(const std::string &address, uint16_t port) {
|
||||
addrinfo hints{
|
||||
.ai_flags = AI_PASSIVE,
|
||||
.ai_family = AF_UNSPEC, // IPv4 and IPv6
|
||||
.ai_socktype = SOCK_STREAM // TCP socket
|
||||
};
|
||||
addrinfo *info = nullptr;
|
||||
auto status = getaddrinfo(address.c_str(), std::to_string(port).c_str(), &hints, &info);
|
||||
if (status != 0) throw NetworkError(gai_strerror(status));
|
||||
|
||||
for (auto *result = info; result != nullptr; result = result->ai_next) {
|
||||
if (result->ai_family == AF_INET) {
|
||||
char ipstr[INET_ADDRSTRLEN];
|
||||
auto *ipv4 = reinterpret_cast<struct sockaddr_in *>(result->ai_addr);
|
||||
inet_ntop(AF_INET, &(ipv4->sin_addr), ipstr, sizeof(ipstr));
|
||||
freeaddrinfo(info);
|
||||
return ipstr;
|
||||
}
|
||||
if (result->ai_family == AF_INET6) {
|
||||
char ipstr[INET6_ADDRSTRLEN];
|
||||
auto *ipv6 = reinterpret_cast<struct sockaddr_in6 *>(result->ai_addr);
|
||||
inet_ntop(AF_INET6, &(ipv6->sin6_addr), ipstr, sizeof(ipstr));
|
||||
freeaddrinfo(info);
|
||||
return ipstr;
|
||||
}
|
||||
}
|
||||
freeaddrinfo(info);
|
||||
throw NetworkError("Not a valid address: {}", address);
|
||||
}
|
||||
|
||||
} // namespace memgraph::io::network
|
||||
|
||||
@@ -25,12 +25,8 @@ namespace memgraph::io::network {
|
||||
* connection address.
|
||||
*/
|
||||
struct Endpoint {
|
||||
static const struct needs_resolving_t {
|
||||
} needs_resolving;
|
||||
|
||||
Endpoint() = default;
|
||||
Endpoint(std::string ip_address, uint16_t port);
|
||||
Endpoint(needs_resolving_t, std::string hostname, uint16_t port);
|
||||
Endpoint(Endpoint const &) = default;
|
||||
Endpoint(Endpoint &&) noexcept = default;
|
||||
Endpoint &operator=(Endpoint const &) = default;
|
||||
@@ -48,9 +44,6 @@ struct Endpoint {
|
||||
uint16_t port{0};
|
||||
IpFamily family{IpFamily::NONE};
|
||||
|
||||
static std::optional<std::pair<std::string, uint16_t>> ParseSocketOrAddress(const std::string &address,
|
||||
std::optional<uint16_t> default_port);
|
||||
|
||||
/**
|
||||
* Tries to parse the given string as either a socket address or ip address.
|
||||
* Expected address format:
|
||||
@@ -61,29 +54,10 @@ struct Endpoint {
|
||||
* it into an ip address and a port number; even if a default port is given,
|
||||
* it won't be used, as we expect that it is given in the address string.
|
||||
*/
|
||||
static std::optional<std::pair<std::string, uint16_t>> ParseSocketOrIpAddress(const std::string &address,
|
||||
std::optional<uint16_t> default_port);
|
||||
static std::optional<std::pair<std::string, uint16_t>> ParseSocketOrIpAddress(
|
||||
const std::string &address, const std::optional<uint16_t> default_port);
|
||||
|
||||
/**
|
||||
* Tries to parse given string as either socket address or hostname.
|
||||
* Expected address format:
|
||||
* - "hostname:port_number"
|
||||
* - "hostname"
|
||||
* After we parse hostname and port we try to resolve the hostname into an ip_address.
|
||||
*/
|
||||
static std::optional<std::pair<std::string, uint16_t>> ParseHostname(const std::string &address,
|
||||
std::optional<uint16_t> default_port);
|
||||
|
||||
static IpFamily GetIpFamily(const std::string &address);
|
||||
|
||||
static bool IsResolvableAddress(const std::string &address, uint16_t port);
|
||||
|
||||
/**
|
||||
* Tries to resolve hostname to its corresponding IP address.
|
||||
* Given a DNS hostname, this function performs resolution and returns
|
||||
* the IP address associated with the hostname.
|
||||
*/
|
||||
static std::string ResolveHostnameIntoIpAddress(const std::string &address, uint16_t port);
|
||||
static IpFamily GetIpFamily(const std::string &ip_address);
|
||||
};
|
||||
|
||||
} // namespace memgraph::io::network
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2023 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
|
||||
@@ -32,7 +32,7 @@ class Epoll {
|
||||
public:
|
||||
using Event = struct epoll_event;
|
||||
|
||||
explicit Epoll(bool set_cloexec = false) : epoll_fd_(epoll_create1(set_cloexec ? EPOLL_CLOEXEC : 0)) {
|
||||
Epoll(bool set_cloexec = false) : epoll_fd_(epoll_create1(set_cloexec ? EPOLL_CLOEXEC : 0)) {
|
||||
// epoll_create1 returns an error if there is a logical error in our code
|
||||
// (for example invalid flags) or if there is irrecoverable error. In both
|
||||
// cases it is best to terminate.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2023 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
|
||||
@@ -216,7 +216,7 @@ bool Socket::Write(const uint8_t *data, size_t len, bool have_more) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Socket::Write(std::string_view s, bool have_more) {
|
||||
bool Socket::Write(const std::string &s, bool have_more) {
|
||||
return Write(reinterpret_cast<const uint8_t *>(s.data()), s.size(), have_more);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2023 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
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
#include "io/network/endpoint.hpp"
|
||||
|
||||
@@ -150,7 +149,7 @@ class Socket {
|
||||
* false if write failed
|
||||
*/
|
||||
bool Write(const uint8_t *data, size_t len, bool have_more = false);
|
||||
bool Write(std::string_view s, bool have_more = false);
|
||||
bool Write(const std::string &s, bool have_more = false);
|
||||
|
||||
/**
|
||||
* Read data from the socket.
|
||||
@@ -202,7 +201,7 @@ class Socket {
|
||||
bool WaitForReadyWrite();
|
||||
|
||||
private:
|
||||
Socket(int fd, Endpoint endpoint) : socket_(fd), endpoint_(std::move(endpoint)) {}
|
||||
Socket(int fd, const Endpoint &endpoint) : socket_(fd), endpoint_(endpoint) {}
|
||||
|
||||
int socket_ = -1;
|
||||
Endpoint endpoint_;
|
||||
|
||||
@@ -128,7 +128,7 @@ KVStore::iterator::iterator(const KVStore *kvstore, const std::string &prefix, b
|
||||
|
||||
KVStore::iterator::iterator(KVStore::iterator &&other) { pimpl_ = std::move(other.pimpl_); }
|
||||
|
||||
KVStore::iterator::~iterator() = default;
|
||||
KVStore::iterator::~iterator() {}
|
||||
|
||||
KVStore::iterator &KVStore::iterator::operator=(KVStore::iterator &&other) {
|
||||
pimpl_ = std::move(other.pimpl_);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user