Compare commits
107 Commits
v2.4.0
...
fix-interp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a18b1c36a | ||
|
|
30ec570bb9 | ||
|
|
d917c3f0fd | ||
|
|
d842adbed3 | ||
|
|
cdfcbc106c | ||
|
|
651b6f3a5a | ||
|
|
0d9bd74a8a | ||
|
|
802f8aceda | ||
|
|
7ddce539fa | ||
|
|
c3e4f81026 | ||
|
|
208705f296 | ||
|
|
69634a5354 | ||
|
|
b8f282468d | ||
|
|
ab38161cd2 | ||
|
|
3a5f140c2b | ||
|
|
eead0f79fc | ||
|
|
91017b7f36 | ||
|
|
00f8d54249 | ||
|
|
4fcdd52f88 | ||
|
|
6c947947eb | ||
|
|
64fd281b2e | ||
|
|
97e250129e | ||
|
|
b02b201129 | ||
|
|
2c6a55775d | ||
|
|
940bf6722c | ||
|
|
49b5343238 | ||
|
|
26a0866938 | ||
|
|
6545283dac | ||
|
|
69c735934c | ||
|
|
64e837b355 | ||
|
|
a586f2f98d | ||
|
|
9fc51f74a0 | ||
|
|
128771a6ec | ||
|
|
f5a49ed29f | ||
|
|
398503da7a | ||
|
|
0819b40202 | ||
|
|
029be10f1d | ||
|
|
a9dc344b49 | ||
|
|
8b0dca9eab | ||
|
|
cb813c3070 | ||
|
|
6349fc9501 | ||
|
|
c4167bafdd | ||
|
|
6f51141148 | ||
|
|
97d45ab1d8 | ||
|
|
6abd356d01 | ||
|
|
99a6c72bba | ||
|
|
173f5430aa | ||
|
|
362dc95e27 | ||
|
|
eead24a562 | ||
|
|
d79dd69607 | ||
|
|
024bf0c578 | ||
|
|
d7443a5558 | ||
|
|
2df357b012 | ||
|
|
b2b5a6e2a0 | ||
|
|
5e2ee6c817 | ||
|
|
862a1afdf1 | ||
|
|
bbce21e78f | ||
|
|
15c8662023 | ||
|
|
beaba0fc16 | ||
|
|
8f70c5f2a5 | ||
|
|
14c651d3ba | ||
|
|
04efc7a4a6 | ||
|
|
19832b5838 | ||
|
|
e63fae2d5b | ||
|
|
34dd47ef07 | ||
|
|
d3f275b231 | ||
|
|
aad4bcb7a0 | ||
|
|
034b54cb72 | ||
|
|
8cf51d9f68 | ||
|
|
1cd1da84fd | ||
|
|
128a6cd522 | ||
|
|
d9eeedb9ee | ||
|
|
156e2cd095 | ||
|
|
8b834c702c | ||
|
|
eda5213d95 | ||
|
|
1f2a15e7c8 | ||
|
|
d72e7fa38d | ||
|
|
e5e37bc14a | ||
|
|
3ee068bbf9 | ||
|
|
68e846b182 | ||
|
|
310e305cfb | ||
|
|
9d6a23b6bd | ||
|
|
f2d5ab61c4 | ||
|
|
0f77c85824 | ||
|
|
d6d4153fb7 | ||
|
|
7d6a5e5b9c | ||
|
|
c529d52664 | ||
|
|
45451bae3b | ||
|
|
3e11f38548 | ||
|
|
6e4047a847 | ||
|
|
8febdc12fb | ||
|
|
3f23a10f44 | ||
|
|
11300960de | ||
|
|
1d5f387ddd | ||
|
|
c4c3a254bf | ||
|
|
b4beb0fc86 | ||
|
|
58e6097664 | ||
|
|
ff21c0705c | ||
|
|
2a2b99b02a | ||
|
|
3daab6ce97 | ||
|
|
fbd7274c95 | ||
|
|
6efc84f022 | ||
|
|
287c2e94d1 | ||
|
|
417cf4b30b | ||
|
|
68e7fd3d36 | ||
|
|
5261d82063 | ||
|
|
9eb87bcf3e |
@@ -1,6 +1,7 @@
|
||||
---
|
||||
BasedOnStyle: Google
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
Standard: "c++20"
|
||||
UseTab: Never
|
||||
DerivePointerAlignment: false
|
||||
|
||||
7
.github/pull_request_template.md
vendored
7
.github/pull_request_template.md
vendored
@@ -1,11 +1,14 @@
|
||||
[master < Epic] PR
|
||||
- [ ] Check, and update documentation if necessary
|
||||
- [ ] Update [changelog](https://docs.memgraph.com/memgraph/changelog)
|
||||
- [ ] Write E2E tests
|
||||
- [ ] Compare the [benchmarking results](https://bench-graph.memgraph.com/) between the master branch and the Epic branch
|
||||
- [ ] Provide the full content or a guide for the final git message
|
||||
|
||||
[master < Task] PR
|
||||
- [ ] Check, and update documentation if necessary
|
||||
- [ ] Update [changelog](https://docs.memgraph.com/memgraph/changelog)
|
||||
- [ ] Provide the full content or a guide for the final git message
|
||||
|
||||
|
||||
To keep docs changelog up to date, one more thing to do:
|
||||
- [ ] Write a release note here
|
||||
- [ ] Tag someone from docs team in the comments
|
||||
|
||||
6
.github/workflows/daily_benchmark.yaml
vendored
6
.github/workflows/daily_benchmark.yaml
vendored
@@ -3,7 +3,7 @@ name: Daily Benchmark
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 1 * * *"
|
||||
- cron: "0 22 * * *"
|
||||
|
||||
jobs:
|
||||
release_benchmarks:
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Set up repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# Number of commits to fetch. `0` indicates all history for all
|
||||
# branches and tags. (default: 1)
|
||||
@@ -67,7 +67,7 @@ jobs:
|
||||
- name: Run mgbench
|
||||
run: |
|
||||
cd tests/mgbench
|
||||
./benchmark.py --num-workers-for-benchmark 12 --export-results benchmark_result.json pokec/medium/*/*
|
||||
./benchmark.py vendor-native --num-workers-for-benchmark 12 --export-results benchmark_result.json pokec/medium/*/*
|
||||
|
||||
- name: Upload mgbench results
|
||||
run: |
|
||||
|
||||
382
.github/workflows/diff.yaml
vendored
382
.github/workflows/diff.yaml
vendored
@@ -14,46 +14,9 @@ on:
|
||||
- "**/*.md"
|
||||
- ".clang-format"
|
||||
- "CODEOWNERS"
|
||||
- "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@v2
|
||||
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=release -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]
|
||||
@@ -64,7 +27,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Set up repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# Number of commits to fetch. `0` indicates all history for all
|
||||
# branches and tags. (default: 1)
|
||||
@@ -75,7 +38,7 @@ jobs:
|
||||
- name: Fetch all history for all tags and branches
|
||||
run: git fetch
|
||||
|
||||
- name: Build combined ASAN, UBSAN and coverage binaries
|
||||
- name: Initialize deps
|
||||
run: |
|
||||
# Activate toolchain.
|
||||
source /opt/toolchain-v4/activate
|
||||
@@ -83,6 +46,32 @@ jobs:
|
||||
# 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 --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
|
||||
@@ -94,7 +83,7 @@ jobs:
|
||||
|
||||
# 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
|
||||
LSAN_OPTIONS=suppressions=$PWD/../tools/lsan.supp UBSAN_OPTIONS=halt_on_error=1 ctest -R memgraph__unit__interpreter --output-on-failure -j2
|
||||
|
||||
- name: Compute code coverage
|
||||
run: |
|
||||
@@ -110,21 +99,11 @@ jobs:
|
||||
tar -czf code_coverage.tar.gz coverage.json html report.json summary.rmu
|
||||
|
||||
- name: Save code coverage
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: "Code coverage"
|
||||
path: tools/github/generated/code_coverage.tar.gz
|
||||
|
||||
- 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: Run clang-tidy
|
||||
run: |
|
||||
source /opt/toolchain-v4/activate
|
||||
@@ -134,302 +113,3 @@ jobs:
|
||||
|
||||
# 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@v2
|
||||
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: |
|
||||
cd tests/integration
|
||||
for name in *; do
|
||||
if [ ! -d $name ]; then continue; fi
|
||||
pushd $name >/dev/null
|
||||
echo "Running: $name"
|
||||
if [ -x prepare.sh ]; then
|
||||
./prepare.sh
|
||||
fi
|
||||
if [ -x runner.py ]; then
|
||||
./runner.py
|
||||
elif [ -x runner.sh ]; then
|
||||
./runner.sh
|
||||
fi
|
||||
echo
|
||||
popd >/dev/null
|
||||
done
|
||||
|
||||
- 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@v2
|
||||
with:
|
||||
name: "Code coverage"
|
||||
path: tools/github/cppcheck_and_clang_format.txt
|
||||
|
||||
release_build:
|
||||
name: "Release 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@v2
|
||||
with:
|
||||
# Number of commits to fetch. `0` indicates all history for all
|
||||
# branches and tags. (default: 1)
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Build release binaries
|
||||
run: |
|
||||
# Activate toolchain.
|
||||
source /opt/toolchain-v4/activate
|
||||
|
||||
# Initialize dependencies.
|
||||
./init
|
||||
|
||||
# Build release binaries.
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=release ..
|
||||
make -j$THREADS
|
||||
|
||||
- name: Run GQL Behave tests
|
||||
run: |
|
||||
cd tests/gql_behave
|
||||
./continuous_integration
|
||||
|
||||
- name: Save quality assurance status
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: "GQL Behave Status"
|
||||
path: |
|
||||
tests/gql_behave/gql_behave_status.csv
|
||||
tests/gql_behave/gql_behave_status.html
|
||||
|
||||
- name: Run unit tests
|
||||
run: |
|
||||
# Activate toolchain.
|
||||
source /opt/toolchain-v4/activate
|
||||
|
||||
# Run unit tests.
|
||||
cd build
|
||||
ctest -R memgraph__unit --output-on-failure -j$THREADS
|
||||
|
||||
- name: Run e2e tests
|
||||
run: |
|
||||
# TODO(gitbuda): Setup mgclient and pymgclient properly.
|
||||
cd tests
|
||||
./setup.sh
|
||||
source ve3/bin/activate
|
||||
cd e2e
|
||||
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../../libs/mgclient/lib python runner.py --workloads-root-directory .
|
||||
|
||||
- name: Run stress test (plain)
|
||||
run: |
|
||||
cd tests/stress
|
||||
./continuous_integration
|
||||
|
||||
- name: Run stress test (SSL)
|
||||
run: |
|
||||
cd tests/stress
|
||||
./continuous_integration --use-ssl
|
||||
|
||||
- name: Run durability test
|
||||
run: |
|
||||
cd tests/stress
|
||||
source ve3/bin/activate
|
||||
python3 durability --num-steps 5
|
||||
|
||||
- name: Create enterprise DEB package
|
||||
run: |
|
||||
# Activate toolchain.
|
||||
source /opt/toolchain-v4/activate
|
||||
|
||||
cd build
|
||||
|
||||
# create mgconsole
|
||||
# we use the -B to force the build
|
||||
make -j$THREADS -B mgconsole
|
||||
|
||||
# Create enterprise DEB package.
|
||||
mkdir output && cd output
|
||||
cpack -G DEB --config ../CPackConfig.cmake
|
||||
|
||||
- name: Save enterprise DEB package
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: "Enterprise DEB package"
|
||||
path: build/output/memgraph*.deb
|
||||
|
||||
- name: Save test data
|
||||
uses: actions/upload-artifact@v2
|
||||
if: always()
|
||||
with:
|
||||
name: "Test data"
|
||||
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@v2
|
||||
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=release ..
|
||||
make -j$THREADS memgraph
|
||||
|
||||
- name: Run Jepsen tests
|
||||
run: |
|
||||
cd tests/jepsen
|
||||
./run.sh test --binary ../../build/memgraph --run-args "test-all --node-configs resources/node-config.edn" --ignore-run-stdout-logs --ignore-run-stderr-logs
|
||||
|
||||
- name: Save Jepsen report
|
||||
uses: actions/upload-artifact@v2
|
||||
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@v2
|
||||
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-path "../../tests/macro_benchmark/.harness_summary" \
|
||||
--github-run-id "${{ github.run_id }}" \
|
||||
--github-run-number "${{ github.run_number }}" \
|
||||
--head-branch-name "${{ env.BRANCH_NAME }}"
|
||||
|
||||
- name: Run mgbench
|
||||
run: |
|
||||
cd tests/mgbench
|
||||
./benchmark.py --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-path "../../tests/mgbench/benchmark_result.json" \
|
||||
--github-run-id "${{ github.run_id }}" \
|
||||
--github-run-number "${{ github.run_number }}" \
|
||||
--head-branch-name "${{ env.BRANCH_NAME }}"
|
||||
|
||||
2
.github/workflows/full_clang_tidy.yaml
vendored
2
.github/workflows/full_clang_tidy.yaml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Set up repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# Number of commits to fetch. `0` indicates all history for all
|
||||
# branches and tags. (default: 1)
|
||||
|
||||
108
.github/workflows/package_all.yaml
vendored
108
.github/workflows/package_all.yaml
vendored
@@ -2,7 +2,12 @@ name: Package All
|
||||
|
||||
# TODO(gitbuda): Cleanup docker container if GHA job was canceled.
|
||||
|
||||
on: workflow_dispatch
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
memgraph_version:
|
||||
description: "Memgraph version to upload as. If empty upload is skipped. Format: 'vX.Y.Z'"
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
centos-7:
|
||||
@@ -17,7 +22,7 @@ jobs:
|
||||
run: |
|
||||
./release/package/run.sh package centos-7
|
||||
- name: "Upload package"
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: centos-7
|
||||
path: build/output/centos-7/memgraph*.rpm
|
||||
@@ -34,7 +39,7 @@ jobs:
|
||||
run: |
|
||||
./release/package/run.sh package centos-9
|
||||
- name: "Upload package"
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: centos-9
|
||||
path: build/output/centos-9/memgraph*.rpm
|
||||
@@ -51,7 +56,7 @@ jobs:
|
||||
run: |
|
||||
./release/package/run.sh package debian-10
|
||||
- name: "Upload package"
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: debian-10
|
||||
path: build/output/debian-10/memgraph*.deb
|
||||
@@ -68,7 +73,7 @@ jobs:
|
||||
run: |
|
||||
./release/package/run.sh package debian-11
|
||||
- name: "Upload package"
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: debian-11
|
||||
path: build/output/debian-11/memgraph*.deb
|
||||
@@ -87,7 +92,7 @@ jobs:
|
||||
./run.sh package debian-11 --for-docker
|
||||
./run.sh docker
|
||||
- name: "Upload package"
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: docker
|
||||
path: build/output/docker/memgraph*.tar.gz
|
||||
@@ -104,9 +109,9 @@ jobs:
|
||||
run: |
|
||||
./release/package/run.sh package ubuntu-18.04
|
||||
- name: "Upload package"
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ubuntu-1804
|
||||
name: ubuntu-18.04
|
||||
path: build/output/ubuntu-18.04/memgraph*.deb
|
||||
|
||||
ubuntu-2004:
|
||||
@@ -121,9 +126,9 @@ jobs:
|
||||
run: |
|
||||
./release/package/run.sh package ubuntu-20.04
|
||||
- name: "Upload package"
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ubuntu-2004
|
||||
name: ubuntu-20.04
|
||||
path: build/output/ubuntu-20.04/memgraph*.deb
|
||||
|
||||
ubuntu-2204:
|
||||
@@ -138,9 +143,9 @@ jobs:
|
||||
run: |
|
||||
./release/package/run.sh package ubuntu-22.04
|
||||
- name: "Upload package"
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ubuntu-2204
|
||||
name: ubuntu-22.04
|
||||
path: build/output/ubuntu-22.04/memgraph*.deb
|
||||
|
||||
debian-11-platform:
|
||||
@@ -155,11 +160,45 @@ jobs:
|
||||
run: |
|
||||
./release/package/run.sh package debian-11 --for-platform
|
||||
- name: "Upload package"
|
||||
uses: actions/upload-artifact@v2
|
||||
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
|
||||
- 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
|
||||
- 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: 60
|
||||
@@ -172,7 +211,46 @@ jobs:
|
||||
run: |
|
||||
./release/package/run.sh package debian-11-arm
|
||||
- name: "Upload package"
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: debian-11-arm
|
||||
name: debian-11-aarch64
|
||||
path: build/output/debian-11-arm/memgraph*.deb
|
||||
|
||||
ubuntu-2204-arm:
|
||||
runs-on: [self-hosted, DockerMgBuild, ARM64, strange]
|
||||
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 ubuntu-22.04-arm
|
||||
- name: "Upload package"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ubuntu-22.04-aarch64
|
||||
path: build/output/ubuntu-22.04-arm/memgraph*.deb
|
||||
|
||||
upload-to-s3:
|
||||
# only run upload if we specified version. Allows for runs without upload
|
||||
if: "${{ github.event.inputs.memgraph_version != '' }}"
|
||||
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
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
# name: # if name input parameter is not provided, all artifacts are downloaded
|
||||
# and put in directories named after each one.
|
||||
path: build/output/release
|
||||
- name: Upload to S3
|
||||
uses: jakejarvis/s3-sync-action@v0.5.1
|
||||
env:
|
||||
AWS_S3_BUCKET: "download.memgraph.com"
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.S3_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_AWS_SECRET_ACCESS_KEY }}
|
||||
AWS_REGION: "eu-west-1"
|
||||
SOURCE_DIR: "build/output/release"
|
||||
DEST_DIR: "memgraph/${{ github.event.inputs.memgraph_version }}/"
|
||||
|
||||
18
.github/workflows/release_centos8.yaml
vendored
18
.github/workflows/release_centos8.yaml
vendored
@@ -3,7 +3,7 @@ name: Release CentOS 8
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 1 * * *"
|
||||
- cron: "0 22 * * *"
|
||||
|
||||
jobs:
|
||||
community_build:
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Set up repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# Number of commits to fetch. `0` indicates all history for all
|
||||
# branches and tags. (default: 1)
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Set up repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# Number of commits to fetch. `0` indicates all history for all
|
||||
# branches and tags. (default: 1)
|
||||
@@ -97,7 +97,7 @@ jobs:
|
||||
tar -czf code_coverage.tar.gz coverage.json html report.json summary.rmu
|
||||
|
||||
- name: Save code coverage
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: "Code coverage"
|
||||
path: tools/github/generated/code_coverage.tar.gz
|
||||
@@ -112,7 +112,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Set up repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# Number of commits to fetch. `0` indicates all history for all
|
||||
# branches and tags. (default: 1)
|
||||
@@ -173,7 +173,7 @@ jobs:
|
||||
./cppcheck_and_clang_format diff
|
||||
|
||||
- name: Save cppcheck and clang-format errors
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: "Code coverage"
|
||||
path: tools/github/cppcheck_and_clang_format.txt
|
||||
@@ -189,7 +189,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Set up repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# Number of commits to fetch. `0` indicates all history for all
|
||||
# branches and tags. (default: 1)
|
||||
@@ -225,7 +225,7 @@ jobs:
|
||||
rpmlint memgraph*.rpm
|
||||
|
||||
- name: Save enterprise RPM package
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: "Enterprise RPM package"
|
||||
path: build/output/memgraph*.rpm
|
||||
@@ -262,7 +262,7 @@ jobs:
|
||||
./continuous_integration
|
||||
|
||||
- name: Save quality assurance status
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: "GQL Behave Status"
|
||||
path: |
|
||||
|
||||
22
.github/workflows/release_debian10.yaml
vendored
22
.github/workflows/release_debian10.yaml
vendored
@@ -3,7 +3,7 @@ name: Release Debian 10
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 1 * * *"
|
||||
- cron: "0 22 * * *"
|
||||
|
||||
jobs:
|
||||
community_build:
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Set up repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# Number of commits to fetch. `0` indicates all history for all
|
||||
# branches and tags. (default: 1)
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Set up repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# Number of commits to fetch. `0` indicates all history for all
|
||||
# branches and tags. (default: 1)
|
||||
@@ -97,7 +97,7 @@ jobs:
|
||||
tar -czf code_coverage.tar.gz coverage.json html report.json summary.rmu
|
||||
|
||||
- name: Save code coverage
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: "Code coverage"
|
||||
path: tools/github/generated/code_coverage.tar.gz
|
||||
@@ -112,7 +112,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Set up repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# Number of commits to fetch. `0` indicates all history for all
|
||||
# branches and tags. (default: 1)
|
||||
@@ -173,7 +173,7 @@ jobs:
|
||||
./cppcheck_and_clang_format diff
|
||||
|
||||
- name: Save cppcheck and clang-format errors
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: "Code coverage"
|
||||
path: tools/github/cppcheck_and_clang_format.txt
|
||||
@@ -189,7 +189,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Set up repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# Number of commits to fetch. `0` indicates all history for all
|
||||
# branches and tags. (default: 1)
|
||||
@@ -224,7 +224,7 @@ jobs:
|
||||
cpack -G DEB --config ../CPackConfig.cmake
|
||||
|
||||
- name: Save enterprise DEB package
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: "Enterprise DEB package"
|
||||
path: build/output/memgraph*.deb
|
||||
@@ -261,7 +261,7 @@ jobs:
|
||||
./continuous_integration
|
||||
|
||||
- name: Save quality assurance status
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: "GQL Behave Status"
|
||||
path: |
|
||||
@@ -324,7 +324,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Set up repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# Number of commits to fetch. `0` indicates all history for all
|
||||
# branches and tags. (default: 1)
|
||||
@@ -349,7 +349,7 @@ jobs:
|
||||
./run.sh test --binary ../../build/memgraph --run-args "test-all --node-configs resources/node-config.edn" --ignore-run-stdout-logs --ignore-run-stderr-logs
|
||||
|
||||
- name: Save Jepsen report
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
if: ${{ always() }}
|
||||
with:
|
||||
name: "Jepsen Report"
|
||||
|
||||
12
.github/workflows/release_docker.yaml
vendored
12
.github/workflows/release_docker.yaml
vendored
@@ -19,20 +19,20 @@ jobs:
|
||||
DOCKER_REPOSITORY_NAME: memgraph
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Download memgraph binary
|
||||
run: |
|
||||
|
||||
63
.github/workflows/release_mgbench_client.yaml
vendored
Normal file
63
.github/workflows/release_mgbench_client.yaml
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
name: "Mgbench Bolt Client Publish Docker Image"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: "Mgbench bolt client version to publish on Dockerhub."
|
||||
required: true
|
||||
force_release:
|
||||
type: boolean
|
||||
required: false
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
mgbench_docker_publish:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKER_ORGANIZATION_NAME: memgraph
|
||||
DOCKER_REPOSITORY_NAME: mgbench-client
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Check if specified version is already pushed
|
||||
run: |
|
||||
EXISTS=$(docker manifest inspect $DOCKER_ORGANIZATION_NAME/$DOCKER_REPOSITORY_NAME:${{ github.event.inputs.version }} > /dev/null; echo $?)
|
||||
echo $EXISTS
|
||||
if [[ ${EXISTS} -eq 0 ]]; then
|
||||
echo 'The specified version has been already released to DockerHub.'
|
||||
if [[ ${{ github.event.inputs.force_release }} = true ]]; then
|
||||
echo 'Forcing the release!'
|
||||
else
|
||||
echo 'Stopping the release!'
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo 'All good the specified version has not been release to DockerHub.'
|
||||
fi
|
||||
|
||||
- name: Build & push docker images
|
||||
run: |
|
||||
cd tests/mgbench
|
||||
docker buildx build \
|
||||
--build-arg TOOLCHAIN_VERSION=toolchain-v4 \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
--tag $DOCKER_ORGANIZATION_NAME/$DOCKER_REPOSITORY_NAME:${{ github.event.inputs.version }} \
|
||||
--tag $DOCKER_ORGANIZATION_NAME/$DOCKER_REPOSITORY_NAME:latest \
|
||||
--file Dockerfile.mgbench_client \
|
||||
--push .
|
||||
18
.github/workflows/release_ubuntu2004.yaml
vendored
18
.github/workflows/release_ubuntu2004.yaml
vendored
@@ -3,7 +3,7 @@ name: Release Ubuntu 20.04
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 1 * * *"
|
||||
- cron: "0 22 * * *"
|
||||
|
||||
jobs:
|
||||
community_build:
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Set up repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# Number of commits to fetch. `0` indicates all history for all
|
||||
# branches and tags. (default: 1)
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Set up repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# Number of commits to fetch. `0` indicates all history for all
|
||||
# branches and tags. (default: 1)
|
||||
@@ -97,7 +97,7 @@ jobs:
|
||||
tar -czf code_coverage.tar.gz coverage.json html report.json summary.rmu
|
||||
|
||||
- name: Save code coverage
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: "Code coverage"
|
||||
path: tools/github/generated/code_coverage.tar.gz
|
||||
@@ -112,7 +112,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Set up repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# Number of commits to fetch. `0` indicates all history for all
|
||||
# branches and tags. (default: 1)
|
||||
@@ -173,7 +173,7 @@ jobs:
|
||||
./cppcheck_and_clang_format diff
|
||||
|
||||
- name: Save cppcheck and clang-format errors
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: "Code coverage"
|
||||
path: tools/github/cppcheck_and_clang_format.txt
|
||||
@@ -189,7 +189,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Set up repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# Number of commits to fetch. `0` indicates all history for all
|
||||
# branches and tags. (default: 1)
|
||||
@@ -224,7 +224,7 @@ jobs:
|
||||
cpack -G DEB --config ../CPackConfig.cmake
|
||||
|
||||
- name: Save enterprise DEB package
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: "Enterprise DEB package"
|
||||
path: build/output/memgraph*.deb
|
||||
@@ -261,7 +261,7 @@ jobs:
|
||||
./continuous_integration
|
||||
|
||||
- name: Save quality assurance status
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: "GQL Behave Status"
|
||||
path: |
|
||||
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -34,9 +34,6 @@ TAGS
|
||||
*.fas
|
||||
*.fasl
|
||||
|
||||
# LCP generated C++ files
|
||||
*.lcp.cpp
|
||||
|
||||
src/database/distributed/serialization.hpp
|
||||
src/database/single_node_ha/serialization.hpp
|
||||
src/distributed/bfs_rpc_messages.hpp
|
||||
@@ -50,15 +47,11 @@ src/distributed/pull_produce_rpc_messages.hpp
|
||||
src/distributed/storage_gc_rpc_messages.hpp
|
||||
src/distributed/token_sharing_rpc_messages.hpp
|
||||
src/distributed/updates_rpc_messages.hpp
|
||||
src/query/frontend/ast/ast.hpp
|
||||
src/query/distributed/frontend/ast/ast_serialization.hpp
|
||||
src/durability/distributed/state_delta.hpp
|
||||
src/durability/single_node/state_delta.hpp
|
||||
src/durability/single_node_ha/state_delta.hpp
|
||||
src/query/frontend/semantic/symbol.hpp
|
||||
src/query/distributed/frontend/semantic/symbol_serialization.hpp
|
||||
src/query/distributed/plan/ops.hpp
|
||||
src/query/plan/operator.hpp
|
||||
src/raft/log_entry.hpp
|
||||
src/raft/raft_rpc_messages.hpp
|
||||
src/raft/snapshot_metadata.hpp
|
||||
|
||||
@@ -1,23 +1,20 @@
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v2.3.0
|
||||
rev: v4.4.0
|
||||
hooks:
|
||||
- id: check-yaml
|
||||
args: [--allow-multiple-documents]
|
||||
- id: end-of-file-fixer
|
||||
- id: trailing-whitespace
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 22.3.0
|
||||
rev: 23.1.0
|
||||
hooks:
|
||||
- id: black
|
||||
args: # arguments to configure black
|
||||
- --line-length=120
|
||||
- --include='\.pyi?$'
|
||||
# these folders wont be formatted by black
|
||||
- --exclude="""\.git |
|
||||
\.__pycache__|
|
||||
build|
|
||||
libs|
|
||||
.cache"""
|
||||
- repo: https://github.com/pycqa/isort
|
||||
rev: 5.12.0
|
||||
hooks:
|
||||
- id: isort
|
||||
name: isort (python)
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: v13.0.0
|
||||
hooks:
|
||||
|
||||
@@ -231,7 +231,17 @@ endif()
|
||||
message(STATUS "CMake build type: ${CMAKE_BUILD_TYPE}")
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
set(MG_ARCH "x86_64" CACHE STRING "Host architecture to build Memgraph on. Supported values are x86_64 (default), ARM64.")
|
||||
add_definitions( -DCMAKE_BUILD_TYPE_NAME="${CMAKE_BUILD_TYPE}")
|
||||
|
||||
if (NOT MG_ARCH)
|
||||
set(MG_ARCH_DESCR "Host architecture to build Memgraph on. Supported values are x86_64, ARM64.")
|
||||
if (${CMAKE_HOST_SYSTEM_PROCESSOR} MATCHES "aarch64")
|
||||
set(MG_ARCH "ARM64" CACHE STRING ${MG_ARCH_DESCR})
|
||||
else()
|
||||
set(MG_ARCH "x86_64" CACHE STRING ${MG_ARCH_DESCR})
|
||||
endif()
|
||||
endif()
|
||||
message(STATUS "MG_ARCH: ${MG_ARCH}")
|
||||
|
||||
# setup external dependencies -------------------------------------------------
|
||||
|
||||
|
||||
81
README.md
81
README.md
@@ -4,10 +4,6 @@
|
||||
|
||||
---
|
||||
|
||||
<p align="center">
|
||||
Build modern, graph-based applications on top of your streaming data in minutes.
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/memgraph/memgraph/blob/master/licenses/APL.txt">
|
||||
<img src="https://img.shields.io/badge/license-APL-green" alt="license" title="license"/>
|
||||
@@ -22,7 +18,7 @@ Build modern, graph-based applications on top of your streaming data in minutes.
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/memgraph/memgraph">
|
||||
<img src="https://img.shields.io/github/workflow/status/memgraph/memgraph/Release%20Ubuntu%2020.04/master" alt="build" title="build"/>
|
||||
<img src="https://img.shields.io/github/actions/workflow/status/memgraph/memgraph/release_debian10.yaml?branch=master&label=build%20and%20test&logo=github"/>
|
||||
</a>
|
||||
<a href="https://memgraph.com/docs/" alt="Documentation">
|
||||
<img src="https://img.shields.io/badge/documentation-Memgraph-orange" />
|
||||
@@ -37,9 +33,10 @@ Build modern, graph-based applications on top of your streaming data in minutes.
|
||||
|
||||
## :clipboard: Description
|
||||
|
||||
Memgraph is a streaming graph application platform that helps you wrangle your
|
||||
streaming data, build sophisticated models that you can query in real-time, and
|
||||
develop graph applications.
|
||||
Memgraph is an open source graph database built for real-time streaming and
|
||||
compatible with Neo4j. Whether you're a developer or a data scientist with
|
||||
interconnected data, Memgraph will get you the immediate actionable insights
|
||||
fast.
|
||||
|
||||
Memgraph directly connects to your streaming infrastructure. You can ingest data
|
||||
from sources like Kafka, SQL, or plain CSV files. Memgraph provides a standard
|
||||
@@ -51,8 +48,20 @@ natural and effective way to model many real-world problems without relying on
|
||||
complex SQL schemas.
|
||||
|
||||
Memgraph is implemented in C/C++ and leverages an in-memory first architecture
|
||||
to ensure that you’re getting the best possible performance consistently and
|
||||
without surprises. It’s also ACID-compliant and highly available.
|
||||
to ensure that you’re getting the [best possible
|
||||
performance](http://memgraph.com/benchgraph) consistently and without surprises.
|
||||
It’s also ACID-compliant and highly available.
|
||||
|
||||
## :zap: Features
|
||||
|
||||
- Run Python, Rust, and C/C++ code natively, check out the
|
||||
[MAGE](https://github.com/memgraph/mage) graph algorithm library
|
||||
- Native support for machine learning
|
||||
- Streaming support
|
||||
- Replication
|
||||
- Authentication and authorization
|
||||
- ACID compliance
|
||||
|
||||
|
||||
## :video_game: Memgraph Playground
|
||||
|
||||
@@ -76,28 +85,49 @@ your browser.
|
||||
### macOS
|
||||
|
||||
[](https://memgraph.com/docs/memgraph/install-memgraph-on-macos-docker)
|
||||
[](https://memgraph.com/docs/memgraph/install-memgraph-on-ubuntu)
|
||||
|
||||
### Linux
|
||||
|
||||
[](https://memgraph.com/docs/memgraph/install-memgraph-on-linux-docker)
|
||||
[](https://memgraph.com/docs/memgraph/install-memgraph-on-debian)
|
||||
[](https://memgraph.com/docs/memgraph/install-memgraph-on-ubuntu)
|
||||
[](https://memgraph.com/docs/memgraph/install-memgraph-from-rpm)
|
||||
[](https://memgraph.com/docs/memgraph/install-memgraph-from-rpm)
|
||||
[](https://memgraph.com/docs/memgraph/install-memgraph-from-rpm)
|
||||
[](https://memgraph.com/docs/memgraph/install-memgraph-from-rpm)
|
||||
|
||||
You can find the binaries and Docker images on the [Download
|
||||
Hub](https://memgraph.com/download) and the installation instructions in the
|
||||
[official documentation](https://memgraph.com/docs/memgraph/installation).
|
||||
|
||||
## :zap: Features
|
||||
|
||||
- Run Python, Rust, and C/C++ code natively, check out the
|
||||
[MAGE](https://github.com/memgraph/mage) graph algorithm library
|
||||
- Native support for machine learning
|
||||
- Streaming support
|
||||
- Replication
|
||||
- Authentication and authorization
|
||||
- ACID compliance
|
||||
## :cloud: Memgraph Cloud
|
||||
|
||||
Check out [Memgraph Cloud](https://memgraph.com/docs/memgraph-cloud) - a cloud service fully managed on AWS and available in 6 geographic regions around the world. Memgraph Cloud allows you to create projects with Enterprise instances of MemgraphDB from your browser.
|
||||
|
||||
<p align="left">
|
||||
<a href="https://memgraph.com/docs/memgraph-cloud">
|
||||
<img width="450px" alt="Memgraph Cloud" src="https://public-assets.memgraph.com/memgraph-gifs%2Fcloud.gif">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## :link: Connect to Memgraph
|
||||
|
||||
[Connect to the database](https://memgraph.com/docs/memgraph/connect-to-memgraph) using Memgraph Lab, mgconsole, various drivers (Python, C/C++ and others) and WebSocket.
|
||||
|
||||
### :microscope: Memgraph Lab
|
||||
|
||||
Visualize graphs and play with queries to understand your data. [Memgraph Lab](https://memgraph.com/docs/memgraph-lab) is a user interface that helps you explore and manipulate the data stored in Memgraph. Visualize graphs, execute ad hoc queries, and optimize their performance.
|
||||
|
||||
<p align="left">
|
||||
<a href="https://memgraph.com/docs/memgraph-lab">
|
||||
<img width="450px" alt="Memgraph Cloud" src="https://public-assets.memgraph.com/memgraph-gifs%2Flab.gif">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## :file_folder: Import data
|
||||
|
||||
[Import data](https://memgraph.com/docs/memgraph/import-data) into Memgraph using Kafka, RedPanda or Pulsar streams, CSV and JSON files, or Cypher commands.
|
||||
|
||||
## :bookmark_tabs: Documentation
|
||||
|
||||
@@ -141,8 +171,17 @@ Memgraph Community is available under the [BSL
|
||||
license](./licenses/BSL.txt).</br> Memgraph Enterprise is available under the
|
||||
[MEL license](./licenses/MEL.txt).
|
||||
|
||||
## :busts_in_silhouette: Community
|
||||
|
||||
- :purple_heart: [**Discord**](https://discord.gg/memgraph)
|
||||
- :ocean: [**Stack Overflow**](https://stackoverflow.com/questions/tagged/memgraphdb)
|
||||
- :busts_in_silhouette: [**Discourse forum**](https://discourse.memgraph.com/)
|
||||
- :bird: [**Twitter**](https://twitter.com/memgraphdb)
|
||||
- :movie_camera:
|
||||
[**YouTube**](https://www.youtube.com/channel/UCZ3HOJvHGxtQ_JHxOselBYg)
|
||||
|
||||
<p align="center">
|
||||
<a href="#">
|
||||
<img src="https://img.shields.io/badge/⬆️back_to_top_⬆️-white" alt="Back to top" title="Back to top"/>
|
||||
<img src="https://img.shields.io/badge/⬆️ back_to_top_⬆️-white" alt="Back to top" title="Back to top"/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -103,6 +103,10 @@ modifications:
|
||||
value: "true"
|
||||
override: false
|
||||
|
||||
- name: "storage_parallel_index_recovery"
|
||||
value: "false"
|
||||
override: true
|
||||
|
||||
undocumented:
|
||||
- "flag_file"
|
||||
- "also_log_to_stderr"
|
||||
|
||||
@@ -5,12 +5,10 @@ import os
|
||||
import subprocess
|
||||
import sys
|
||||
import textwrap
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||
CONFIG_FILE = os.path.join(SCRIPT_DIR, "flags.yaml")
|
||||
WIDTH = 80
|
||||
@@ -18,14 +16,13 @@ WIDTH = 80
|
||||
|
||||
def wrap_text(s, initial_indent="# "):
|
||||
return "\n#\n".join(
|
||||
map(lambda x: textwrap.fill(x, WIDTH, initial_indent=initial_indent,
|
||||
subsequent_indent="# "), s.split("\n")))
|
||||
map(lambda x: textwrap.fill(x, WIDTH, initial_indent=initial_indent, subsequent_indent="# "), s.split("\n"))
|
||||
)
|
||||
|
||||
|
||||
def extract_flags(binary_path):
|
||||
ret = {}
|
||||
data = subprocess.run([binary_path, "--help-xml"],
|
||||
stdout=subprocess.PIPE).stdout.decode("utf-8")
|
||||
data = subprocess.run([binary_path, "--help-xml"], stdout=subprocess.PIPE).stdout.decode("utf-8")
|
||||
root = ET.fromstring(data)
|
||||
for child in root:
|
||||
if child.tag == "usage" and child.text.lower().count("warning"):
|
||||
@@ -46,8 +43,7 @@ def apply_config_to_flags(config, flags):
|
||||
for modification in config["modifications"]:
|
||||
name = modification["name"]
|
||||
if name not in flags:
|
||||
print("WARNING: Flag '" + name + "' missing from binary!",
|
||||
file=sys.stderr)
|
||||
print("WARNING: Flag '" + name + "' missing from binary!", file=sys.stderr)
|
||||
continue
|
||||
flags[name]["default"] = modification["value"]
|
||||
flags[name]["override"] = modification["override"]
|
||||
@@ -75,8 +71,9 @@ def extract_sections(flags):
|
||||
else:
|
||||
sections.append((current_section, current_flags))
|
||||
sections.append(("other", other))
|
||||
assert set(sum(map(lambda x: x[1], sections), [])) == set(flags.keys()), \
|
||||
"The section extraction algorithm lost some flags!"
|
||||
assert set(sum(map(lambda x: x[1], sections), [])) == set(
|
||||
flags.keys()
|
||||
), "The section extraction algorithm lost some flags!"
|
||||
return sections
|
||||
|
||||
|
||||
@@ -89,8 +86,7 @@ def generate_config_file(sections, flags):
|
||||
helpstr = flag["meaning"] + " [" + flag["type"] + "]"
|
||||
ret += wrap_text(helpstr) + "\n"
|
||||
prefix = "# " if not flag["override"] else ""
|
||||
ret += prefix + "--" + flag["name"].replace("_", "-") + \
|
||||
"=" + flag["default"] + "\n\n"
|
||||
ret += prefix + "--" + flag["name"].replace("_", "-") + "=" + flag["default"] + "\n\n"
|
||||
ret += "\n"
|
||||
ret += wrap_text(config["footer"])
|
||||
return ret.strip() + "\n"
|
||||
@@ -98,13 +94,9 @@ def generate_config_file(sections, flags):
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("memgraph_binary",
|
||||
help="path to Memgraph binary")
|
||||
parser.add_argument("output_file",
|
||||
help="path where to store the generated Memgraph "
|
||||
"configuration file")
|
||||
parser.add_argument("--config-file", default=CONFIG_FILE,
|
||||
help="path to generator configuration file")
|
||||
parser.add_argument("memgraph_binary", help="path to Memgraph binary")
|
||||
parser.add_argument("output_file", help="path where to store the generated Memgraph " "configuration file")
|
||||
parser.add_argument("--config-file", default=CONFIG_FILE, help="path to generator configuration file")
|
||||
|
||||
args = parser.parse_args()
|
||||
flags = extract_flags(args.memgraph_binary)
|
||||
|
||||
156
environment/os/amzn-2.sh
Executable file
156
environment/os/amzn-2.sh
Executable file
@@ -0,0 +1,156 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -Eeuo pipefail
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
source "$DIR/../util.sh"
|
||||
|
||||
check_operating_system "amzn-2"
|
||||
check_architecture "x86_64"
|
||||
|
||||
TOOLCHAIN_BUILD_DEPS=(
|
||||
gcc gcc-c++ make # generic build tools
|
||||
wget # used for archive download
|
||||
gnupg2 # used for archive signature verification
|
||||
tar gzip bzip2 xz unzip # used for archive unpacking
|
||||
zlib-devel # zlib library used for all builds
|
||||
expat-devel xz-devel python3-devel texinfo
|
||||
curl libcurl-devel # for cmake
|
||||
readline-devel # for cmake and llvm
|
||||
libffi-devel libxml2-devel # for llvm
|
||||
libedit-devel pcre-devel automake bison # for swig
|
||||
file
|
||||
openssl-devel
|
||||
gmp-devel
|
||||
gperf
|
||||
diffutils
|
||||
patch
|
||||
libipt libipt-devel # intel
|
||||
perl # for openssl
|
||||
)
|
||||
|
||||
TOOLCHAIN_RUN_DEPS=(
|
||||
make # generic build tools
|
||||
tar gzip bzip2 xz # used for archive unpacking
|
||||
zlib # zlib library used for all builds
|
||||
expat xz-libs python3 # for gdb
|
||||
readline # for cmake and llvm
|
||||
libffi libxml2 # for llvm
|
||||
openssl-devel
|
||||
)
|
||||
|
||||
MEMGRAPH_BUILD_DEPS=(
|
||||
git # source code control
|
||||
make # build system
|
||||
wget # for downloading libs
|
||||
libuuid-devel java-11-openjdk # required by antlr
|
||||
readline-devel # for memgraph console
|
||||
python3-devel # for query modules
|
||||
openssl-devel
|
||||
libseccomp-devel
|
||||
python3 python3-pip nmap-ncat # for tests
|
||||
#
|
||||
# IMPORTANT: python3-yaml does NOT exist on CentOS
|
||||
# Install it using `pip3 install PyYAML`
|
||||
#
|
||||
PyYAML # Package name here does not correspond to the yum package!
|
||||
libcurl-devel # mg-requests
|
||||
rpm-build rpmlint # for RPM package building
|
||||
doxygen graphviz # source documentation generators
|
||||
which nodejs golang zip unzip java-11-openjdk-devel # for driver tests
|
||||
autoconf # for jemalloc code generation
|
||||
libtool # for protobuf code generation
|
||||
)
|
||||
|
||||
list() {
|
||||
echo "$1"
|
||||
}
|
||||
|
||||
check() {
|
||||
local missing=""
|
||||
# On Fedora yum/dnf and python10 use newer glibc which is not compatible
|
||||
# with ours, so we need to momentarely disable env
|
||||
local OLD_LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-""}
|
||||
LD_LIBRARY_PATH=""
|
||||
for pkg in $1; do
|
||||
if [ "$pkg" == "PyYAML" ]; then
|
||||
if ! python3 -c "import yaml" >/dev/null 2>/dev/null; then
|
||||
missing="$pkg $missing"
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
if ! yum list installed "$pkg" >/dev/null 2>/dev/null; then
|
||||
missing="$pkg $missing"
|
||||
fi
|
||||
done
|
||||
if [ "$missing" != "" ]; then
|
||||
echo "MISSING PACKAGES: $missing"
|
||||
exit 1
|
||||
fi
|
||||
LD_LIBRARY_PATH=${OLD_LD_LIBRARY_PATH}
|
||||
}
|
||||
|
||||
install() {
|
||||
cd "$DIR"
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "Please run as root."
|
||||
exit 1
|
||||
fi
|
||||
# If GitHub Actions runner is installed, append LANG to the environment.
|
||||
# Python related tests don't work without the LANG export.
|
||||
if [ -d "/home/gh/actions-runner" ]; then
|
||||
echo "LANG=en_US.utf8" >> /home/gh/actions-runner/.env
|
||||
else
|
||||
echo "NOTE: export LANG=en_US.utf8"
|
||||
fi
|
||||
yum update -y
|
||||
for pkg in $1; do
|
||||
if [ "$pkg" == libipt ]; then
|
||||
if ! yum list installed libipt >/dev/null 2>/dev/null; then
|
||||
yum install -y http://repo.okay.com.mx/centos/8/x86_64/release/libipt-1.6.1-8.el8.x86_64.rpm
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
if [ "$pkg" == libipt-devel ]; then
|
||||
if ! yum list installed libipt-devel >/dev/null 2>/dev/null; then
|
||||
yum install -y http://repo.okay.com.mx/centos/8/x86_64/release/libipt-devel-1.6.1-8.el8.x86_64.rpm
|
||||
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" == PyYAML ]; then
|
||||
if [ -z ${SUDO_USER+x} ]; then # Running as root (e.g. Docker).
|
||||
pip3 install --user PyYAML
|
||||
else # Running using sudo.
|
||||
sudo -H -u "$SUDO_USER" bash -c "pip3 install --user PyYAML"
|
||||
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
|
||||
fi
|
||||
if [ "$pkg" == java-11-openjdk-devel ]; then
|
||||
amazon-linux-extras install -y java-openjdk11
|
||||
yum install -y java-11-openjdk-devel
|
||||
continue
|
||||
fi
|
||||
yum install -y "$pkg"
|
||||
done
|
||||
}
|
||||
|
||||
deps=$2"[*]"
|
||||
"$1" "${!deps}"
|
||||
@@ -6,7 +6,7 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
source "$DIR/../util.sh"
|
||||
|
||||
check_operating_system "debian-11"
|
||||
check_architecture "arm64"
|
||||
check_architecture "arm64" "aarch64"
|
||||
|
||||
TOOLCHAIN_BUILD_DEPS=(
|
||||
coreutils gcc g++ build-essential make # generic build tools
|
||||
|
||||
103
environment/os/fedora-36.sh
Executable file
103
environment/os/fedora-36.sh
Executable file
@@ -0,0 +1,103 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -Eeuo pipefail
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
source "$DIR/../util.sh"
|
||||
|
||||
check_operating_system "fedora-36"
|
||||
check_architecture "x86_64"
|
||||
|
||||
TOOLCHAIN_BUILD_DEPS=(
|
||||
coreutils-common gcc gcc-c++ make # generic build tools
|
||||
wget # used for archive download
|
||||
gnupg2 # used for archive signature verification
|
||||
tar gzip bzip2 xz unzip # used for archive unpacking
|
||||
zlib-devel # zlib library used for all builds
|
||||
expat-devel xz-devel python3-devel texinfo libbabeltrace-devel # for gdb
|
||||
curl libcurl-devel # for cmake
|
||||
readline-devel # for cmake and llvm
|
||||
libffi-devel libxml2-devel # for llvm
|
||||
libedit-devel pcre-devel automake bison # for swig
|
||||
file
|
||||
openssl-devel
|
||||
gmp-devel
|
||||
gperf
|
||||
diffutils
|
||||
libipt libipt-devel # intel
|
||||
patch
|
||||
perl # for openssl
|
||||
)
|
||||
|
||||
TOOLCHAIN_RUN_DEPS=(
|
||||
make # generic build tools
|
||||
tar gzip bzip2 xz # used for archive unpacking
|
||||
zlib # zlib library used for all builds
|
||||
expat xz-libs python3 # for gdb
|
||||
readline # for cmake and llvm
|
||||
libffi libxml2 # for llvm
|
||||
openssl-devel
|
||||
)
|
||||
|
||||
MEMGRAPH_BUILD_DEPS=(
|
||||
git # source code control
|
||||
make pkgconf-pkg-config # build system
|
||||
wget # for downloading libs
|
||||
libuuid-devel java-11-openjdk # required by antlr
|
||||
readline-devel # for memgraph console
|
||||
python3-devel # for query modules
|
||||
openssl-devel
|
||||
libseccomp-devel
|
||||
python3 python3-pip python3-virtualenv python3-virtualenvwrapper python3-pyyaml nmap-ncat # for tests
|
||||
libcurl-devel # mg-requests
|
||||
rpm-build rpmlint # for RPM package building
|
||||
doxygen graphviz # source documentation generators
|
||||
which nodejs golang zip unzip java-11-openjdk-devel # for driver tests
|
||||
sbcl # for custom Lisp C++ preprocessing
|
||||
autoconf # for jemalloc code generation
|
||||
libtool # for protobuf code generation
|
||||
)
|
||||
|
||||
list() {
|
||||
echo "$1"
|
||||
}
|
||||
|
||||
check() {
|
||||
local missing=""
|
||||
# On Fedora yum/dnf and python10 use newer glibc which is not compatible
|
||||
# with ours, so we need to momentarely disable env
|
||||
local OLD_LD_LIBRARY_PATH=${LD_LIBRARY_PATH}
|
||||
LD_LIBRARY_PATH=""
|
||||
for pkg in $1; do
|
||||
if ! dnf list installed "$pkg" >/dev/null 2>/dev/null; then
|
||||
missing="$pkg $missing"
|
||||
fi
|
||||
done
|
||||
if [ "$missing" != "" ]; then
|
||||
echo "MISSING PACKAGES: $missing"
|
||||
exit 1
|
||||
fi
|
||||
LD_LIBRARY_PATH=${OLD_LD_LIBRARY_PATH}
|
||||
}
|
||||
|
||||
install() {
|
||||
cd "$DIR"
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "Please run as root."
|
||||
exit 1
|
||||
fi
|
||||
# If GitHub Actions runner is installed, append LANG to the environment.
|
||||
# Python related tests don't work without the LANG export.
|
||||
if [ -d "/home/gh/actions-runner" ]; then
|
||||
echo "LANG=en_US.utf8" >> /home/gh/actions-runner/.env
|
||||
else
|
||||
echo "NOTE: export LANG=en_US.utf8"
|
||||
fi
|
||||
dnf update -y
|
||||
for pkg in $1; do
|
||||
dnf install -y "$pkg"
|
||||
done
|
||||
}
|
||||
|
||||
deps=$2"[*]"
|
||||
"$1" "${!deps}"
|
||||
96
environment/os/ubuntu-22.04-arm.sh
Executable file
96
environment/os/ubuntu-22.04-arm.sh
Executable file
@@ -0,0 +1,96 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -Eeuo pipefail
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
source "$DIR/../util.sh"
|
||||
|
||||
check_operating_system "ubuntu-22.04"
|
||||
check_architecture "arm64" "aarch64"
|
||||
|
||||
TOOLCHAIN_BUILD_DEPS=(
|
||||
coreutils gcc g++ build-essential make # generic build tools
|
||||
wget # used for archive download
|
||||
gnupg # used for archive signature verification
|
||||
tar gzip bzip2 xz-utils unzip # used for archive unpacking
|
||||
zlib1g-dev # zlib library used for all builds
|
||||
libexpat1-dev libbabeltrace-dev liblzma-dev python3-dev texinfo # for gdb
|
||||
libcurl4-openssl-dev # for cmake
|
||||
libreadline-dev # for cmake and llvm
|
||||
libffi-dev libxml2-dev # for llvm
|
||||
curl # snappy
|
||||
file
|
||||
git # for thrift
|
||||
libgmp-dev # for gdb
|
||||
gperf # for proxygen
|
||||
libssl-dev
|
||||
libedit-dev libpcre3-dev automake bison # for swig
|
||||
)
|
||||
|
||||
TOOLCHAIN_RUN_DEPS=(
|
||||
make # generic build tools
|
||||
tar gzip bzip2 xz-utils # used for archive unpacking
|
||||
zlib1g # zlib library used for all builds
|
||||
libexpat1 libbabeltrace1 liblzma5 python3 # for gdb
|
||||
libcurl4 # for cmake
|
||||
libreadline8 # for cmake and llvm
|
||||
libffi7 libxml2 # for llvm
|
||||
libssl-dev # for libevent
|
||||
)
|
||||
|
||||
MEMGRAPH_BUILD_DEPS=(
|
||||
git # source code control
|
||||
make pkg-config # build system
|
||||
curl wget # for downloading libs
|
||||
uuid-dev default-jre-headless # required by antlr
|
||||
libreadline-dev # for memgraph console
|
||||
libpython3-dev python3-dev # for query modules
|
||||
libssl-dev
|
||||
libseccomp-dev
|
||||
netcat # tests are using nc to wait for memgraph
|
||||
python3 python3-virtualenv python3-pip # for qa, macro_benchmark and stress tests
|
||||
python3-yaml # for the configuration generator
|
||||
libcurl4-openssl-dev # mg-requests
|
||||
sbcl # for custom Lisp C++ preprocessing
|
||||
doxygen graphviz # source documentation generators
|
||||
mono-runtime mono-mcs zip unzip default-jdk-headless # for driver tests
|
||||
dotnet-sdk-6.0 golang nodejs npm
|
||||
autoconf # for jemalloc code generation
|
||||
libtool # for protobuf code generation
|
||||
)
|
||||
|
||||
list() {
|
||||
echo "$1"
|
||||
}
|
||||
|
||||
check() {
|
||||
check_all_dpkg "$1"
|
||||
}
|
||||
|
||||
install() {
|
||||
cd "$DIR"
|
||||
apt update
|
||||
# If GitHub Actions runner is installed, append LANG to the environment.
|
||||
# Python related tests doesn't work the LANG export.
|
||||
if [ -d "/home/gh/actions-runner" ]; then
|
||||
echo "LANG=en_US.utf8" >> /home/gh/actions-runner/.env
|
||||
else
|
||||
echo "NOTE: export LANG=en_US.utf8"
|
||||
fi
|
||||
apt install -y wget
|
||||
for pkg in $1; do
|
||||
if [ "$pkg" == dotnet-sdk-6.0 ]; then
|
||||
if ! dpkg -s dotnet-sdk-6.0 2>/dev/null >/dev/null; then
|
||||
wget -nv https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
|
||||
dpkg -i packages-microsoft-prod.deb
|
||||
apt-get update
|
||||
apt-get install -y apt-transport-https dotnet-sdk-6.0
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
apt install -y "$pkg"
|
||||
done
|
||||
}
|
||||
|
||||
deps=$2"[*]"
|
||||
"$1" "${!deps}"
|
||||
1
environment/toolchain/.gitignore
vendored
Normal file
1
environment/toolchain/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.tar.gz
|
||||
@@ -10,6 +10,14 @@ cd "$DIR"
|
||||
source "$DIR/../util.sh"
|
||||
DISTRO="$(operating_system)"
|
||||
|
||||
function log_tool_name () {
|
||||
echo ""
|
||||
echo ""
|
||||
echo "#### $1 ####"
|
||||
echo ""
|
||||
echo ""
|
||||
}
|
||||
|
||||
for_arm=false
|
||||
if [[ "$#" -eq 1 ]]; then
|
||||
if [[ "$1" == "--for-arm" ]]; then
|
||||
@@ -20,9 +28,11 @@ if [[ "$#" -eq 1 ]]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
os="$1"
|
||||
|
||||
# toolchain version
|
||||
TOOLCHAIN_STDCXX="${TOOLCHAIN_STDCXX:-libstdc++}"
|
||||
if [[ "$TOOLCHAIN_STDCXX" != "libstdc++" && "$TOOLCHAIN_STDCXX" != "libc++" ]]; then
|
||||
echo "Only GCC (libstdc++) or LLVM (libc++) C++ standard library implementations are supported."
|
||||
exit 1
|
||||
fi
|
||||
TOOLCHAIN_VERSION=4
|
||||
|
||||
# package versions used
|
||||
@@ -41,11 +51,19 @@ CPPCHECK_VERSION=2.6
|
||||
LLVM_VERSION=13.0.0
|
||||
SWIG_VERSION=4.0.2 # used only for LLVM compilation
|
||||
|
||||
# Check for the dependencies.
|
||||
echo "ALL BUILD PACKAGES: $($DIR/../os/$DISTRO.sh list TOOLCHAIN_BUILD_DEPS)"
|
||||
$DIR/../os/$DISTRO.sh check TOOLCHAIN_BUILD_DEPS
|
||||
echo "ALL RUN PACKAGES: $($DIR/../os/$DISTRO.sh list TOOLCHAIN_RUN_DEPS)"
|
||||
$DIR/../os/$DISTRO.sh check TOOLCHAIN_RUN_DEPS
|
||||
# Set the right env script
|
||||
ENV_SCRIPT="$DIR/../os/$DISTRO.sh"
|
||||
if [[ "$for_arm" = true ]]; then
|
||||
ENV_SCRIPT="$DIR/../os/$DISTRO-arm.sh"
|
||||
fi
|
||||
|
||||
# Check for the toolchain build dependencies.
|
||||
echo "ALL BUILD PACKAGES: $(${ENV_SCRIPT} list TOOLCHAIN_BUILD_DEPS)"
|
||||
${ENV_SCRIPT} check TOOLCHAIN_BUILD_DEPS
|
||||
|
||||
# Check for the toolchain run dependencies.
|
||||
echo "ALL RUN PACKAGES: $(${ENV_SCRIPT} list TOOLCHAIN_RUN_DEPS)"
|
||||
${ENV_SCRIPT} check TOOLCHAIN_RUN_DEPS
|
||||
|
||||
# check installation directory
|
||||
NAME=toolchain-v$TOOLCHAIN_VERSION
|
||||
@@ -99,6 +117,8 @@ if [ ! -f llvm-$LLVM_VERSION.src.tar.xz ]; then
|
||||
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VERSION/clang-tools-extra-$LLVM_VERSION.src.tar.xz
|
||||
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VERSION/compiler-rt-$LLVM_VERSION.src.tar.xz
|
||||
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VERSION/libunwind-$LLVM_VERSION.src.tar.xz
|
||||
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VERSION/libcxx-$LLVM_VERSION.src.tar.xz
|
||||
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VERSION/libcxxabi-$LLVM_VERSION.src.tar.xz
|
||||
fi
|
||||
if [ ! -f pahole-gdb-master.zip ]; then
|
||||
wget https://github.com/PhilArmstrong/pahole-gdb/archive/master.zip -O pahole-gdb-master.zip
|
||||
@@ -156,6 +176,8 @@ if [ ! -f llvm-$LLVM_VERSION.src.tar.xz.sig ]; then
|
||||
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VERSION/clang-tools-extra-$LLVM_VERSION.src.tar.xz.sig
|
||||
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VERSION/compiler-rt-$LLVM_VERSION.src.tar.xz.sig
|
||||
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VERSION/libunwind-$LLVM_VERSION.src.tar.xz.sig
|
||||
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VERSION/libcxx-$LLVM_VERSION.src.tar.xz.sig
|
||||
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VERSION/libcxxabi-$LLVM_VERSION.src.tar.xz.sig
|
||||
fi
|
||||
# list of valid llvm gnupg keys: https://releases.llvm.org/download.html
|
||||
$GPG --keyserver $KEYSERVER --recv-keys 0x474E22316ABF4785A88C6E8EA2C794A986419D8A
|
||||
@@ -165,6 +187,8 @@ $GPG --verify lld-$LLVM_VERSION.src.tar.xz.sig lld-$LLVM_VERSION.src.tar.xz
|
||||
$GPG --verify clang-tools-extra-$LLVM_VERSION.src.tar.xz.sig clang-tools-extra-$LLVM_VERSION.src.tar.xz
|
||||
$GPG --verify compiler-rt-$LLVM_VERSION.src.tar.xz.sig compiler-rt-$LLVM_VERSION.src.tar.xz
|
||||
$GPG --verify libunwind-$LLVM_VERSION.src.tar.xz.sig libunwind-$LLVM_VERSION.src.tar.xz
|
||||
$GPG --verify libcxx-$LLVM_VERSION.src.tar.xz.sig libcxx-$LLVM_VERSION.src.tar.xz
|
||||
$GPG --verify libcxxabi-$LLVM_VERSION.src.tar.xz.sig libcxxabi-$LLVM_VERSION.src.tar.xz
|
||||
|
||||
popd
|
||||
|
||||
@@ -172,7 +196,7 @@ popd
|
||||
mkdir -p build
|
||||
pushd build
|
||||
|
||||
# compile gcc
|
||||
log_tool_name "GCC $GCC_VERSION"
|
||||
if [ ! -f $PREFIX/bin/gcc ]; then
|
||||
if [ -d gcc-$GCC_VERSION ]; then
|
||||
rm -rf gcc-$GCC_VERSION
|
||||
@@ -263,7 +287,7 @@ fi
|
||||
export PATH=$PREFIX/bin:$PATH
|
||||
export LD_LIBRARY_PATH=$PREFIX/lib64
|
||||
|
||||
# compile binutils
|
||||
log_tool_name "binutils $BINUTILS_VERSION"
|
||||
if [ ! -f $PREFIX/bin/ld.gold ]; then
|
||||
if [ -d binutils-$BINUTILS_VERSION ]; then
|
||||
rm -rf binutils-$BINUTILS_VERSION
|
||||
@@ -327,7 +351,7 @@ if [ ! -f $PREFIX/bin/ld.gold ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
# compile gdb
|
||||
log_tool_name "GDB $GDB_VERSION"
|
||||
if [ ! -f $PREFIX/bin/gdb ]; then
|
||||
if [ -d gdb-$GDB_VERSION ]; then
|
||||
rm -rf gdb-$GDB_VERSION
|
||||
@@ -363,6 +387,62 @@ if [ ! -f $PREFIX/bin/gdb ]; then
|
||||
--without-babeltrace \
|
||||
--enable-tui \
|
||||
--with-python=python3
|
||||
elif [[ "${DISTRO}" == fedora* ]]; then
|
||||
# Remove readline, gdb does not compile
|
||||
env \
|
||||
CC=gcc \
|
||||
CXX=g++ \
|
||||
CFLAGS="-g -O2 -fstack-protector-strong -Wformat -Werror=format-security" \
|
||||
CXXFLAGS="-g -O2 -fstack-protector-strong -Wformat -Werror=format-security" \
|
||||
CPPFLAGS="-Wdate-time -D_FORTIFY_SOURCE=2 -fPIC" \
|
||||
LDFLAGS="-Wl,-z,relro" \
|
||||
PYTHON="" \
|
||||
../configure \
|
||||
--build=x86_64-linux-gnu \
|
||||
--host=x86_64-linux-gnu \
|
||||
--prefix=$PREFIX \
|
||||
--disable-maintainer-mode \
|
||||
--disable-dependency-tracking \
|
||||
--disable-silent-rules \
|
||||
--disable-gdbtk \
|
||||
--disable-shared \
|
||||
--without-guile \
|
||||
--with-system-gdbinit=$PREFIX/etc/gdb/gdbinit \
|
||||
--with-expat \
|
||||
--with-system-zlib \
|
||||
--with-lzma \
|
||||
--with-babeltrace \
|
||||
--with-intel-pt \
|
||||
--enable-tui \
|
||||
--with-python=python3
|
||||
elif [[ "${DISTRO}" == "amzn-2" ]]; then
|
||||
# Remove readline, gdb does not compile
|
||||
env \
|
||||
CC=gcc \
|
||||
CXX=g++ \
|
||||
CFLAGS="-g -O2 -fstack-protector-strong -Wformat -Werror=format-security" \
|
||||
CXXFLAGS="-g -O2 -fstack-protector-strong -Wformat -Werror=format-security" \
|
||||
CPPFLAGS="-Wdate-time -D_FORTIFY_SOURCE=2 -fPIC" \
|
||||
LDFLAGS="-Wl,-z,relro" \
|
||||
PYTHON="" \
|
||||
../configure \
|
||||
--build=x86_64-linux-gnu \
|
||||
--host=x86_64-linux-gnu \
|
||||
--prefix=$PREFIX \
|
||||
--disable-maintainer-mode \
|
||||
--disable-dependency-tracking \
|
||||
--disable-silent-rules \
|
||||
--disable-gdbtk \
|
||||
--disable-shared \
|
||||
--without-guile \
|
||||
--with-system-gdbinit=$PREFIX/etc/gdb/gdbinit \
|
||||
--with-expat \
|
||||
--with-system-zlib \
|
||||
--with-lzma \
|
||||
--with-babeltrace \
|
||||
--with-intel-pt \
|
||||
--enable-tui \
|
||||
--with-python=python3
|
||||
else
|
||||
# https://buildd.debian.org/status/fetch.php?pkg=gdb&arch=amd64&ver=8.2.1-2&stamp=1550831554&raw=0
|
||||
env \
|
||||
@@ -398,13 +478,13 @@ if [ ! -f $PREFIX/bin/gdb ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
# install pahole
|
||||
log_tool_name "install pahole"
|
||||
if [ ! -d $PREFIX/share/pahole-gdb ]; then
|
||||
unzip ../archives/pahole-gdb-master.zip
|
||||
mv pahole-gdb-master $PREFIX/share/pahole-gdb
|
||||
fi
|
||||
|
||||
# setup system gdbinit
|
||||
log_tool_name "setup system gdbinit"
|
||||
if [ ! -f $PREFIX/etc/gdb/gdbinit ]; then
|
||||
mkdir -p $PREFIX/etc/gdb
|
||||
cat >$PREFIX/etc/gdb/gdbinit <<EOF
|
||||
@@ -430,7 +510,7 @@ end
|
||||
EOF
|
||||
fi
|
||||
|
||||
# compile cmake
|
||||
log_tool_name "cmake $CMAKE_VERSION"
|
||||
if [ ! -f $PREFIX/bin/cmake ]; then
|
||||
if [ -d cmake-$CMAKE_VERSION ]; then
|
||||
rm -rf cmake-$CMAKE_VERSION
|
||||
@@ -456,7 +536,7 @@ if [ ! -f $PREFIX/bin/cmake ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
# compile cppcheck
|
||||
log_tool_name "cppcheck $CPPCHECK_VERSION"
|
||||
if [ ! -f $PREFIX/bin/cppcheck ]; then
|
||||
if [ -d cppcheck-$CPPCHECK_VERSION ]; then
|
||||
rm -rf cppcheck-$CPPCHECK_VERSION
|
||||
@@ -480,7 +560,7 @@ if [ ! -f $PREFIX/bin/cppcheck ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
# compile swig
|
||||
log_tool_name "swig $SWIG_VERSION"
|
||||
if [ ! -d swig-$SWIG_VERSION/install ]; then
|
||||
if [ -d swig-$SWIG_VERSION ]; then
|
||||
rm -rf swig-$SWIG_VERSION
|
||||
@@ -496,7 +576,7 @@ if [ ! -d swig-$SWIG_VERSION/install ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
# compile llvm
|
||||
log_tool_name "LLVM $LLVM_VERSION"
|
||||
if [ ! -f $PREFIX/bin/clang ]; then
|
||||
if [ -d llvm-$LLVM_VERSION ]; then
|
||||
rm -rf llvm-$LLVM_VERSION
|
||||
@@ -513,8 +593,19 @@ if [ ! -f $PREFIX/bin/clang ]; then
|
||||
mv compiler-rt-$LLVM_VERSION.src/ llvm-$LLVM_VERSION/projects/compiler-rt
|
||||
tar -xvf ../archives/libunwind-$LLVM_VERSION.src.tar.xz
|
||||
mv libunwind-$LLVM_VERSION.src/include/mach-o llvm-$LLVM_VERSION/tools/lld/include
|
||||
|
||||
# The following is required because of libc++
|
||||
tar -xvf ../archives/libcxx-$LLVM_VERSION.src.tar.xz
|
||||
mv libcxx-$LLVM_VERSION.src llvm-$LLVM_VERSION/projects/libcxx
|
||||
tar -xvf ../archives/libcxxabi-$LLVM_VERSION.src.tar.xz
|
||||
mv libcxxabi-$LLVM_VERSION.src llvm-$LLVM_VERSION/projects/libcxxabi
|
||||
# NOTE: We moved part of the libunwind in one of the previous step.
|
||||
rm -r libunwind-$LLVM_VERSION.src
|
||||
tar -xvf ../archives/libunwind-$LLVM_VERSION.src.tar.xz
|
||||
mv libunwind-$LLVM_VERSION.src llvm-$LLVM_VERSION/projects/libunwind
|
||||
|
||||
pushd llvm-$LLVM_VERSION
|
||||
mkdir build && pushd build
|
||||
mkdir -p build && pushd build
|
||||
# activate swig
|
||||
export PATH=$DIR/build/swig-$SWIG_VERSION/install/bin:$PATH
|
||||
# influenced by: https://buildd.debian.org/status/fetch.php?pkg=llvm-toolchain-7&arch=amd64&ver=1%3A7.0.1%7E%2Brc2-1%7Eexp1&stamp=1541506173&raw=0
|
||||
@@ -567,7 +658,7 @@ In order to be able to run all of these tools you should install the following
|
||||
packages:
|
||||
|
||||
\`\`\`
|
||||
$($DIR/../os/$DISTRO.sh list TOOLCHAIN_RUN_DEPS)
|
||||
$($DIR/../os/$ENV_SCRIPT.sh list TOOLCHAIN_RUN_DEPS)
|
||||
\`\`\`
|
||||
|
||||
## Usage
|
||||
@@ -624,6 +715,7 @@ export PS1="($NAME) \$PS1"
|
||||
export LD_LIBRARY_PATH=$PREFIX/lib:$PREFIX/lib64
|
||||
export CXXFLAGS=-isystem\ $PREFIX/include\ \$CXXFLAGS
|
||||
export CFLAGS=-isystem\ $PREFIX/include\ \$CFLAGS
|
||||
export VENV=$PREFIX
|
||||
|
||||
# disable root
|
||||
function su () {
|
||||
@@ -675,7 +767,7 @@ PROXYGEN_SHA256=5360a8ccdfb2f5a6c7b3eed331ec7ab0e2c792d579c6fff499c85c516c11fe14
|
||||
SNAPPY_SHA256=75c1fbb3d618dd3a0483bff0e26d0a92b495bbe5059c8b4f1c962b478b6e06e7
|
||||
SNAPPY_VERSION=1.1.9
|
||||
XZ_VERSION=5.2.5 # for LZMA
|
||||
ZLIB_VERSION=1.2.12
|
||||
ZLIB_VERSION=1.2.13
|
||||
ZSTD_VERSION=1.5.0
|
||||
WANGLE_SHA256=1002e9c32b6f4837f6a760016e3b3e22f3509880ef3eaad191c80dc92655f23f
|
||||
|
||||
@@ -820,7 +912,11 @@ source $PREFIX/activate
|
||||
export CC=$PREFIX/bin/clang
|
||||
export CXX=$PREFIX/bin/clang++
|
||||
export CFLAGS="$CFLAGS -fPIC"
|
||||
export CXXFLAGS="$CXXFLAGS -fPIC"
|
||||
if [ "$TOOLCHAIN_STDCXX" = "libstdc++" ]; then
|
||||
export CXXFLAGS="$CXXFLAGS -fPIC"
|
||||
else
|
||||
export CXXFLAGS="$CXXFLAGS -fPIC -stdlib=libc++"
|
||||
fi
|
||||
COMMON_CMAKE_FLAGS="-DCMAKE_INSTALL_PREFIX=$PREFIX
|
||||
-DCMAKE_PREFIX_PATH=$PREFIX
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
@@ -834,7 +930,7 @@ COMMON_CMAKE_FLAGS="-DCMAKE_INSTALL_PREFIX=$PREFIX
|
||||
COMMON_CONFIGURE_FLAGS="--enable-shared=no --prefix=$PREFIX"
|
||||
COMMON_MAKE_INSTALL_FLAGS="-j$CPUS BUILD_SHARED=no PREFIX=$PREFIX install"
|
||||
|
||||
# install bzip2
|
||||
log_tool_name "bzip2 $BZIP2_VERSION"
|
||||
if [ ! -f $PREFIX/include/bzlib.h ]; then
|
||||
if [ -d bzip2-$BZIP2_VERSION ]; then
|
||||
rm -rf bzip2-$BZIP2_VERSION
|
||||
@@ -845,7 +941,7 @@ if [ ! -f $PREFIX/include/bzlib.h ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
# install fmt
|
||||
log_tool_name "fmt $FMT_VERSION"
|
||||
if [ ! -d $PREFIX/include/fmt ]; then
|
||||
if [ -d fmt-$FMT_VERSION ]; then
|
||||
rm -rf fmt-$FMT_VERSION
|
||||
@@ -858,7 +954,7 @@ if [ ! -d $PREFIX/include/fmt ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
# install lz4
|
||||
log_tool_name "lz4 $LZ4_VERSION"
|
||||
if [ ! -f $PREFIX/include/lz4.h ]; then
|
||||
if [ -d lz4-$LZ4_VERSION ]; then
|
||||
rm -rf lz4-$LZ4_VERSION
|
||||
@@ -869,7 +965,7 @@ if [ ! -f $PREFIX/include/lz4.h ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
# install xz
|
||||
log_tool_name "xz $XZ_VERSION"
|
||||
if [ ! -f $PREFIX/include/lzma.h ]; then
|
||||
if [ -d xz-$XZ_VERSION ]; then
|
||||
rm -rf xz-$XZ_VERSION
|
||||
@@ -881,7 +977,7 @@ if [ ! -f $PREFIX/include/lzma.h ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
# install zlib
|
||||
log_tool_name "zlib $ZLIB_VERSION"
|
||||
if [ ! -f $PREFIX/include/zlib.h ]; then
|
||||
if [ -d zlib-$ZLIB_VERSION ]; then
|
||||
rm -rf zlib-$ZLIB_VERSION
|
||||
@@ -895,7 +991,7 @@ if [ ! -f $PREFIX/include/zlib.h ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
# install zstd
|
||||
log_tool_name "zstd $ZSTD_VERSION"
|
||||
if [ ! -f $PREFIX/include/zstd.h ]; then
|
||||
if [ -d zstd-$ZSTD_VERSION ]; then
|
||||
rm -rf zstd-$ZSTD_VERSION
|
||||
@@ -910,7 +1006,8 @@ if [ ! -f $PREFIX/include/zstd.h ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
#install jemalloc
|
||||
# TODO(gitbuda): Freeze jmalloc version.
|
||||
log_tool_name "jmalloc"
|
||||
if [ ! -d $PREFIX/include/jemalloc ]; then
|
||||
if [ -d jemalloc ]; then
|
||||
rm -rf jemalloc
|
||||
@@ -927,7 +1024,7 @@ if [ ! -d $PREFIX/include/jemalloc ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
# install boost
|
||||
log_tool_name "BOOST $BOOST_VERSION"
|
||||
if [ ! -d $PREFIX/include/boost ]; then
|
||||
if [ -d boost_$BOOST_VERSION_UNDERSCORES ]; then
|
||||
rm -rf boost_$BOOST_VERSION_UNDERSCORES
|
||||
@@ -935,15 +1032,24 @@ if [ ! -d $PREFIX/include/boost ]; then
|
||||
tar -xzf ../archives/boost_$BOOST_VERSION_UNDERSCORES.tar.gz
|
||||
pushd boost_$BOOST_VERSION_UNDERSCORES
|
||||
./bootstrap.sh --prefix=$PREFIX --with-toolset=clang --with-python=python3 --without-icu
|
||||
./b2 toolset=clang -j$CPUS install variant=release link=static cxxstd=20 --disable-icu \
|
||||
-sZLIB_SOURCE="$PREFIX" -sZLIB_INCLUDE="$PREFIX/include" -sZLIB_LIBPATH="$PREFIX/lib" \
|
||||
-sBZIP2_SOURCE="$PREFIX" -sBZIP2_INCLUDE="$PREFIX/include" -sBZIP2_LIBPATH="$PREFIX/lib" \
|
||||
-sLZMA_SOURCE="$PREFIX" -sLZMA_INCLUDE="$PREFIX/include" -sLZMA_LIBPATH="$PREFIX/lib" \
|
||||
-sZSTD_SOURCE="$PREFIX" -sZSTD_INCLUDE="$PREFIX/include" -sZSTD_LIBPATH="$PREFIX/lib"
|
||||
if [ "$TOOLCHAIN_STDCXX" = "libstdc++" ]; then
|
||||
./b2 toolset=clang -j$CPUS install variant=release link=static cxxstd=20 --disable-icu \
|
||||
-sZLIB_SOURCE="$PREFIX" -sZLIB_INCLUDE="$PREFIX/include" -sZLIB_LIBPATH="$PREFIX/lib" \
|
||||
-sBZIP2_SOURCE="$PREFIX" -sBZIP2_INCLUDE="$PREFIX/include" -sBZIP2_LIBPATH="$PREFIX/lib" \
|
||||
-sLZMA_SOURCE="$PREFIX" -sLZMA_INCLUDE="$PREFIX/include" -sLZMA_LIBPATH="$PREFIX/lib" \
|
||||
-sZSTD_SOURCE="$PREFIX" -sZSTD_INCLUDE="$PREFIX/include" -sZSTD_LIBPATH="$PREFIX/lib"
|
||||
else
|
||||
./b2 toolset=clang -j$CPUS install variant=release link=static cxxstd=20 --disable-icu \
|
||||
cxxflags="-stdlib=libc++" linkflags="-stdlib=libc++" \
|
||||
-sZLIB_SOURCE="$PREFIX" -sZLIB_INCLUDE="$PREFIX/include" -sZLIB_LIBPATH="$PREFIX/lib" \
|
||||
-sBZIP2_SOURCE="$PREFIX" -sBZIP2_INCLUDE="$PREFIX/include" -sBZIP2_LIBPATH="$PREFIX/lib" \
|
||||
-sLZMA_SOURCE="$PREFIX" -sLZMA_INCLUDE="$PREFIX/include" -sLZMA_LIBPATH="$PREFIX/lib" \
|
||||
-sZSTD_SOURCE="$PREFIX" -sZSTD_INCLUDE="$PREFIX/include" -sZSTD_LIBPATH="$PREFIX/lib"
|
||||
fi
|
||||
popd
|
||||
fi
|
||||
|
||||
# install double-conversion
|
||||
log_tool_name "double-conversion $DOUBLE_CONVERSION_VERSION"
|
||||
if [ ! -d $PREFIX/include/double-conversion ]; then
|
||||
if [ -d double-conversion-$DOUBLE_CONVERSION_VERSION ]; then
|
||||
rm -rf double-conversion-$DOUBLE_CONVERSION_VERSION
|
||||
@@ -958,7 +1064,8 @@ if [ ! -d $PREFIX/include/double-conversion ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
# install gflags
|
||||
# TODO(gitbuda): Freeze gflags version.
|
||||
log_tool_name "gflags"
|
||||
if [ ! -d $PREFIX/include/gflags ]; then
|
||||
if [ -d gflags ]; then
|
||||
rm -rf gflags
|
||||
@@ -977,7 +1084,7 @@ if [ ! -d $PREFIX/include/gflags ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
# install libunwind
|
||||
log_tool_name "libunwind $LIBUNWIND_VERSION"
|
||||
if [ ! -f $PREFIX/include/libunwind.h ]; then
|
||||
if [ -d libunwind-$LIBUNWIND_VERSION ]; then
|
||||
rm -rf libunwind-$LIBUNWIND_VERSION
|
||||
@@ -990,7 +1097,7 @@ if [ ! -f $PREFIX/include/libunwind.h ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
# install glog
|
||||
log_tool_name "glog $GLOG_VERSION"
|
||||
if [ ! -d $PREFIX/include/glog ]; then
|
||||
if [ -d glog-$GLOG_VERSION ]; then
|
||||
rm -rf glog-$GLOG_VERSION
|
||||
@@ -1004,7 +1111,7 @@ if [ ! -d $PREFIX/include/glog ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
# install libevent
|
||||
log_tool_name "libevent $LIBEVENT_VERSION"
|
||||
if [ ! -d $PREFIX/include/event2 ]; then
|
||||
if [ -d libevent-$LIBEVENT_VERSION ]; then
|
||||
rm -rf libevent-$LIBEVENT_VERSION
|
||||
@@ -1023,7 +1130,7 @@ if [ ! -d $PREFIX/include/event2 ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
# install snappy
|
||||
log_tool_name "snappy $SNAPPY_VERSION"
|
||||
if [ ! -f $PREFIX/include/snappy.h ]; then
|
||||
if [ -d snappy-$SNAPPY_VERSION ]; then
|
||||
rm -rf snappy-$SNAPPY_VERSION
|
||||
@@ -1041,7 +1148,7 @@ if [ ! -f $PREFIX/include/snappy.h ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
# install libsodium
|
||||
log_tool_name "libsodium $LIBSODIUM_VERSION"
|
||||
if [ ! -f $PREFIX/include/sodium.h ]; then
|
||||
if [ -d libsodium-$LIBSODIUM_VERSION ]; then
|
||||
rm -rf libsodium-$LIBSODIUM_VERSION
|
||||
@@ -1053,7 +1160,7 @@ if [ ! -f $PREFIX/include/sodium.h ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
# install libaio
|
||||
log_tool_name "libaio $LIBAIO_VERSION"
|
||||
if [ ! -f $PREFIX/include/libaio.h ]; then
|
||||
if [ -d libaio-$LIBAIO_VERSION ]; then
|
||||
rm -rf libaio-$LIBAIO_VERSION
|
||||
@@ -1064,114 +1171,121 @@ if [ ! -f $PREFIX/include/libaio.h ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
# install folly
|
||||
if [ ! -d $PREFIX/include/folly ]; then
|
||||
if [ -d folly-$FBLIBS_VERSION ]; then
|
||||
rm -rf folly-$FBLIBS_VERSION
|
||||
if [[ "${DISTRO}" != "amzn-2" ]]; then
|
||||
log_tool_name "folly $FBLIBS_VERSION"
|
||||
if [ ! -d $PREFIX/include/folly ]; then
|
||||
if [ -d folly-$FBLIBS_VERSION ]; then
|
||||
rm -rf folly-$FBLIBS_VERSION
|
||||
fi
|
||||
mkdir folly-$FBLIBS_VERSION
|
||||
tar -xzf ../archives/folly-$FBLIBS_VERSION.tar.gz -C folly-$FBLIBS_VERSION
|
||||
pushd folly-$FBLIBS_VERSION
|
||||
patch -p1 < ../../folly.patch
|
||||
# build is used by facebook builder
|
||||
mkdir _build
|
||||
pushd _build
|
||||
cmake .. $COMMON_CMAKE_FLAGS \
|
||||
-DBOOST_LINK_STATIC=ON \
|
||||
-DBUILD_TESTS=OFF \
|
||||
-DGFLAGS_NOTHREADS=OFF \
|
||||
-DCXX_STD="c++20"
|
||||
make -j$CPUS install
|
||||
popd && popd
|
||||
fi
|
||||
mkdir folly-$FBLIBS_VERSION
|
||||
tar -xzf ../archives/folly-$FBLIBS_VERSION.tar.gz -C folly-$FBLIBS_VERSION
|
||||
pushd folly-$FBLIBS_VERSION
|
||||
patch -p1 < ../../folly.patch
|
||||
# build is used by facebook builder
|
||||
mkdir _build
|
||||
pushd _build
|
||||
cmake .. $COMMON_CMAKE_FLAGS \
|
||||
-DBOOST_LINK_STATIC=ON \
|
||||
-DBUILD_TESTS=OFF \
|
||||
-DGFLAGS_NOTHREADS=OFF \
|
||||
-DCXX_STD="c++20"
|
||||
make -j$CPUS install
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
# install fizz
|
||||
if [ ! -d $PREFIX/include/fizz ]; then
|
||||
if [ -d fizz-$FBLIBS_VERSION ]; then
|
||||
rm -rf fizz-$FBLIBS_VERSION
|
||||
log_tool_name "fizz $FBLIBS_VERSION"
|
||||
if [ ! -d $PREFIX/include/fizz ]; then
|
||||
if [ -d fizz-$FBLIBS_VERSION ]; then
|
||||
rm -rf fizz-$FBLIBS_VERSION
|
||||
fi
|
||||
mkdir fizz-$FBLIBS_VERSION
|
||||
tar -xzf ../archives/fizz-$FBLIBS_VERSION.tar.gz -C fizz-$FBLIBS_VERSION
|
||||
pushd fizz-$FBLIBS_VERSION
|
||||
# build is used by facebook builder
|
||||
mkdir _build
|
||||
pushd _build
|
||||
cmake ../fizz $COMMON_CMAKE_FLAGS \
|
||||
-DBUILD_TESTS=OFF \
|
||||
-DBUILD_EXAMPLES=OFF \
|
||||
-DGFLAGS_NOTHREADS=OFF
|
||||
make -j$CPUS install
|
||||
popd && popd
|
||||
fi
|
||||
mkdir fizz-$FBLIBS_VERSION
|
||||
tar -xzf ../archives/fizz-$FBLIBS_VERSION.tar.gz -C fizz-$FBLIBS_VERSION
|
||||
pushd fizz-$FBLIBS_VERSION
|
||||
# build is used by facebook builder
|
||||
mkdir _build
|
||||
pushd _build
|
||||
cmake ../fizz $COMMON_CMAKE_FLAGS \
|
||||
-DBUILD_TESTS=OFF \
|
||||
-DBUILD_EXAMPLES=OFF \
|
||||
-DGFLAGS_NOTHREADS=OFF
|
||||
make -j$CPUS install
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
# install wangle
|
||||
if [ ! -d $PREFIX/include/wangle ]; then
|
||||
if [ -d wangle-$FBLIBS_VERSION ]; then
|
||||
rm -rf wangle-$FBLIBS_VERSION
|
||||
log_tool_name "wangle FBLIBS_VERSION"
|
||||
if [ ! -d $PREFIX/include/wangle ]; then
|
||||
if [ -d wangle-$FBLIBS_VERSION ]; then
|
||||
rm -rf wangle-$FBLIBS_VERSION
|
||||
fi
|
||||
mkdir wangle-$FBLIBS_VERSION
|
||||
tar -xzf ../archives/wangle-$FBLIBS_VERSION.tar.gz -C wangle-$FBLIBS_VERSION
|
||||
pushd wangle-$FBLIBS_VERSION
|
||||
# build is used by facebook builder
|
||||
mkdir _build
|
||||
pushd _build
|
||||
cmake ../wangle $COMMON_CMAKE_FLAGS \
|
||||
-DBUILD_TESTS=OFF \
|
||||
-DBUILD_EXAMPLES=OFF \
|
||||
-DGFLAGS_NOTHREADS=OFF
|
||||
make -j$CPUS install
|
||||
popd && popd
|
||||
fi
|
||||
mkdir wangle-$FBLIBS_VERSION
|
||||
tar -xzf ../archives/wangle-$FBLIBS_VERSION.tar.gz -C wangle-$FBLIBS_VERSION
|
||||
pushd wangle-$FBLIBS_VERSION
|
||||
# build is used by facebook builder
|
||||
mkdir _build
|
||||
pushd _build
|
||||
cmake ../wangle $COMMON_CMAKE_FLAGS \
|
||||
-DBUILD_TESTS=OFF \
|
||||
-DBUILD_EXAMPLES=OFF \
|
||||
-DGFLAGS_NOTHREADS=OFF
|
||||
make -j$CPUS install
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
# install proxygen
|
||||
if [ ! -d $PREFIX/include/proxygen ]; then
|
||||
if [ -d proxygen-$FBLIBS_VERSION ]; then
|
||||
rm -rf proxygen-$FBLIBS_VERSION
|
||||
log_tool_name "proxygen $FBLIBS_VERSION"
|
||||
if [ ! -d $PREFIX/include/proxygen ]; then
|
||||
if [ -d proxygen-$FBLIBS_VERSION ]; then
|
||||
rm -rf proxygen-$FBLIBS_VERSION
|
||||
fi
|
||||
mkdir proxygen-$FBLIBS_VERSION
|
||||
tar -xzf ../archives/proxygen-$FBLIBS_VERSION.tar.gz -C proxygen-$FBLIBS_VERSION
|
||||
pushd proxygen-$FBLIBS_VERSION
|
||||
patch -p1 < ../../proxygen.patch
|
||||
# build is used by facebook builder
|
||||
mkdir _build
|
||||
pushd _build
|
||||
cmake .. $COMMON_CMAKE_FLAGS \
|
||||
-DBUILD_TESTS=OFF \
|
||||
-DBUILD_SAMPLES=OFF \
|
||||
-DGFLAGS_NOTHREADS=OFF \
|
||||
-DBUILD_QUIC=OFF
|
||||
make -j$CPUS install
|
||||
popd && popd
|
||||
fi
|
||||
mkdir proxygen-$FBLIBS_VERSION
|
||||
tar -xzf ../archives/proxygen-$FBLIBS_VERSION.tar.gz -C proxygen-$FBLIBS_VERSION
|
||||
pushd proxygen-$FBLIBS_VERSION
|
||||
patch -p1 < ../../proxygen.patch
|
||||
# build is used by facebook builder
|
||||
mkdir _build
|
||||
pushd _build
|
||||
cmake .. $COMMON_CMAKE_FLAGS \
|
||||
-DBUILD_TESTS=OFF \
|
||||
-DBUILD_SAMPLES=OFF \
|
||||
-DGFLAGS_NOTHREADS=OFF \
|
||||
-DBUILD_QUIC=OFF
|
||||
make -j$CPUS install
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
# install flex
|
||||
if [ ! -f $PREFIX/include/FlexLexer.h ]; then
|
||||
if [ -d flex-$FLEX_VERSION ]; then
|
||||
rm -rf flex-$FLEX_VERSION
|
||||
log_tool_name "flex $FBLIBS_VERSION"
|
||||
if [ ! -f $PREFIX/include/FlexLexer.h ]; then
|
||||
if [ -d flex-$FLEX_VERSION ]; then
|
||||
rm -rf flex-$FLEX_VERSION
|
||||
fi
|
||||
tar -xzf ../archives/flex-$FLEX_VERSION.tar.gz
|
||||
pushd flex-$FLEX_VERSION
|
||||
./configure $COMMON_CONFIGURE_FLAGS
|
||||
make -j$CPUS install
|
||||
popd
|
||||
fi
|
||||
tar -xzf ../archives/flex-$FLEX_VERSION.tar.gz
|
||||
pushd flex-$FLEX_VERSION
|
||||
./configure $COMMON_CONFIGURE_FLAGS
|
||||
make -j$CPUS install
|
||||
popd
|
||||
fi
|
||||
|
||||
# install fbthrift
|
||||
if [ ! -d $PREFIX/include/thrift ]; then
|
||||
if [ -d fbthrift-$FBLIBS_VERSION ]; then
|
||||
rm -rf fbthrift-$FBLIBS_VERSION
|
||||
log_tool_name "fbthrift $FBLIBS_VERSION"
|
||||
if [ ! -d $PREFIX/include/thrift ]; then
|
||||
if [ -d fbthrift-$FBLIBS_VERSION ]; then
|
||||
rm -rf fbthrift-$FBLIBS_VERSION
|
||||
fi
|
||||
git clone --depth 1 --branch v$FBLIBS_VERSION https://github.com/facebook/fbthrift.git fbthrift-$FBLIBS_VERSION
|
||||
pushd fbthrift-$FBLIBS_VERSION
|
||||
# build is used by facebook builder
|
||||
mkdir _build
|
||||
pushd _build
|
||||
if [ "$TOOLCHAIN_STDCXX" = "libstdc++" ]; then
|
||||
CMAKE_CXX_FLAGS="-fsized-deallocation"
|
||||
else
|
||||
CMAKE_CXX_FLAGS="-fsized-deallocation -stdlib=libc++"
|
||||
fi
|
||||
cmake .. $COMMON_CMAKE_FLAGS \
|
||||
-Denable_tests=OFF \
|
||||
-DGFLAGS_NOTHREADS=OFF \
|
||||
-DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS"
|
||||
make -j$CPUS install
|
||||
popd
|
||||
fi
|
||||
git clone --depth 1 --branch v$FBLIBS_VERSION https://github.com/facebook/fbthrift.git fbthrift-$FBLIBS_VERSION
|
||||
pushd fbthrift-$FBLIBS_VERSION
|
||||
# build is used by facebook builder
|
||||
mkdir _build
|
||||
pushd _build
|
||||
cmake .. $COMMON_CMAKE_FLAGS \
|
||||
-Denable_tests=OFF \
|
||||
-DGFLAGS_NOTHREADS=OFF \
|
||||
-DCMAKE_CXX_FLAGS=-fsized-deallocation
|
||||
make -j$CPUS install
|
||||
popd
|
||||
fi
|
||||
|
||||
popd
|
||||
@@ -1179,7 +1293,7 @@ popd
|
||||
# create toolchain archive
|
||||
if [ ! -f $NAME-binaries-$DISTRO.tar.gz ]; then
|
||||
DISTRO_FULL_NAME=${DISTRO}
|
||||
if [[ "${DISTRO}" == centos* ]]; then
|
||||
if [[ "${DISTRO}" == centos* ]] || [[ "${DISTRO}" == fedora* ]]; then
|
||||
if [[ "$for_arm" = "true" ]]; then
|
||||
DISTRO_FULL_NAME="$DISTRO_FULL_NAME-aarch64"
|
||||
else
|
||||
@@ -1192,7 +1306,12 @@ if [ ! -f $NAME-binaries-$DISTRO.tar.gz ]; then
|
||||
DISTRO_FULL_NAME="$DISTRO_FULL_NAME-amd64"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$TOOLCHAIN_STDCXX" = "libstdc++" ]; then
|
||||
# Pass because infra scripts assume there is not C++ standard lib in the name.
|
||||
echo "NOTE: Not adding anything to the archive name that GCC C++ standard lib is used."
|
||||
else
|
||||
DISTRO_FULL_NAME="$DISTRO_FULL_NAME-libc++"
|
||||
fi
|
||||
tar --owner=root --group=root -cpvzf $NAME-binaries-$DISTRO_FULL_NAME.tar.gz -C /opt $NAME
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
operating_system() {
|
||||
function operating_system() {
|
||||
grep -E '^(VERSION_)?ID=' /etc/os-release | \
|
||||
sort | cut -d '=' -f 2- | sed 's/"//g' | paste -s -d '-'
|
||||
}
|
||||
|
||||
check_operating_system() {
|
||||
function check_operating_system() {
|
||||
if [ "$(operating_system)" != "$1" ]; then
|
||||
echo "Not the right operating system!"
|
||||
exit 1
|
||||
@@ -14,20 +14,25 @@ check_operating_system() {
|
||||
fi
|
||||
}
|
||||
|
||||
architecture() {
|
||||
function architecture() {
|
||||
uname -m
|
||||
}
|
||||
|
||||
check_architecture() {
|
||||
if [ "$(architecture)" != "$1" ]; then
|
||||
echo "Not the right architecture!"
|
||||
exit 1
|
||||
else
|
||||
echo "The right architecture."
|
||||
fi
|
||||
local ARCH=$(architecture)
|
||||
for arch in "$@"; do
|
||||
if [ "${ARCH}" = "$arch" ]; then
|
||||
echo "The right architecture!"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
echo "Not the right architecture!"
|
||||
echo "Expected: $@"
|
||||
echo "Actual: ${ARCH}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
check_all_yum() {
|
||||
function check_all_yum() {
|
||||
local missing=""
|
||||
for pkg in $1; do
|
||||
if ! yum list installed "$pkg" >/dev/null 2>/dev/null; then
|
||||
@@ -40,7 +45,7 @@ check_all_yum() {
|
||||
fi
|
||||
}
|
||||
|
||||
check_all_dpkg() {
|
||||
function check_all_dpkg() {
|
||||
local missing=""
|
||||
for pkg in $1; do
|
||||
if ! dpkg -s "$pkg" >/dev/null 2>/dev/null; then
|
||||
@@ -53,7 +58,7 @@ check_all_dpkg() {
|
||||
fi
|
||||
}
|
||||
|
||||
check_all_dnf() {
|
||||
function check_all_dnf() {
|
||||
local missing=""
|
||||
for pkg in $1; do
|
||||
if ! dnf list installed "$pkg" >/dev/null 2>/dev/null; then
|
||||
@@ -65,7 +70,8 @@ check_all_dnf() {
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
install_all_apt() {
|
||||
|
||||
function install_all_apt() {
|
||||
for pkg in $1; do
|
||||
apt install -y "$pkg"
|
||||
done
|
||||
|
||||
449
include/_mgp.hpp
449
include/_mgp.hpp
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -22,7 +22,7 @@
|
||||
namespace mgp {
|
||||
|
||||
namespace {
|
||||
void MgExceptionHandle(mgp_error result_code) {
|
||||
inline void MgExceptionHandle(mgp_error result_code) {
|
||||
switch (result_code) {
|
||||
case mgp_error::MGP_ERROR_UNKNOWN_ERROR:
|
||||
throw mg_exception::UnknownException();
|
||||
@@ -62,7 +62,7 @@ TResult MgInvoke(TFunc func, TArgs... args) {
|
||||
}
|
||||
|
||||
template <typename TFunc, typename... TArgs>
|
||||
void MgInvokeVoid(TFunc func, TArgs... args) {
|
||||
inline void MgInvokeVoid(TFunc func, TArgs... args) {
|
||||
auto result_code = func(args...);
|
||||
MgExceptionHandle(result_code);
|
||||
}
|
||||
@@ -72,211 +72,221 @@ void MgInvokeVoid(TFunc func, TArgs... args) {
|
||||
|
||||
// Make value
|
||||
|
||||
mgp_value *value_make_null(mgp_memory *memory) { return MgInvoke<mgp_value *>(mgp_value_make_null, memory); }
|
||||
inline mgp_value *value_make_null(mgp_memory *memory) { return MgInvoke<mgp_value *>(mgp_value_make_null, memory); }
|
||||
|
||||
mgp_value *value_make_bool(int val, mgp_memory *memory) {
|
||||
inline mgp_value *value_make_bool(int val, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_value *>(mgp_value_make_bool, val, memory);
|
||||
}
|
||||
|
||||
mgp_value *value_make_int(int64_t val, mgp_memory *memory) {
|
||||
inline mgp_value *value_make_int(int64_t val, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_value *>(mgp_value_make_int, val, memory);
|
||||
}
|
||||
|
||||
mgp_value *value_make_double(double val, mgp_memory *memory) {
|
||||
inline mgp_value *value_make_double(double val, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_value *>(mgp_value_make_double, val, memory);
|
||||
}
|
||||
|
||||
mgp_value *value_make_string(const char *val, mgp_memory *memory) {
|
||||
inline mgp_value *value_make_string(const char *val, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_value *>(mgp_value_make_string, val, memory);
|
||||
}
|
||||
|
||||
mgp_value *value_make_list(mgp_list *val) { return MgInvoke<mgp_value *>(mgp_value_make_list, val); }
|
||||
inline mgp_value *value_make_list(mgp_list *val) { return MgInvoke<mgp_value *>(mgp_value_make_list, val); }
|
||||
|
||||
mgp_value *value_make_map(mgp_map *val) { return MgInvoke<mgp_value *>(mgp_value_make_map, val); }
|
||||
inline mgp_value *value_make_map(mgp_map *val) { return MgInvoke<mgp_value *>(mgp_value_make_map, val); }
|
||||
|
||||
mgp_value *value_make_vertex(mgp_vertex *val) { return MgInvoke<mgp_value *>(mgp_value_make_vertex, val); }
|
||||
inline mgp_value *value_make_vertex(mgp_vertex *val) { return MgInvoke<mgp_value *>(mgp_value_make_vertex, val); }
|
||||
|
||||
mgp_value *value_make_edge(mgp_edge *val) { return MgInvoke<mgp_value *>(mgp_value_make_edge, val); }
|
||||
inline mgp_value *value_make_edge(mgp_edge *val) { return MgInvoke<mgp_value *>(mgp_value_make_edge, val); }
|
||||
|
||||
mgp_value *value_make_path(mgp_path *val) { return MgInvoke<mgp_value *>(mgp_value_make_path, val); }
|
||||
inline mgp_value *value_make_path(mgp_path *val) { return MgInvoke<mgp_value *>(mgp_value_make_path, val); }
|
||||
|
||||
mgp_value *value_make_date(mgp_date *val) { return MgInvoke<mgp_value *>(mgp_value_make_date, val); }
|
||||
inline mgp_value *value_make_date(mgp_date *val) { return MgInvoke<mgp_value *>(mgp_value_make_date, val); }
|
||||
|
||||
mgp_value *value_make_local_time(mgp_local_time *val) { return MgInvoke<mgp_value *>(mgp_value_make_local_time, val); }
|
||||
inline mgp_value *value_make_local_time(mgp_local_time *val) {
|
||||
return MgInvoke<mgp_value *>(mgp_value_make_local_time, val);
|
||||
}
|
||||
|
||||
mgp_value *value_make_local_date_time(mgp_local_date_time *val) {
|
||||
inline mgp_value *value_make_local_date_time(mgp_local_date_time *val) {
|
||||
return MgInvoke<mgp_value *>(mgp_value_make_local_date_time, val);
|
||||
}
|
||||
|
||||
mgp_value *value_make_duration(mgp_duration *val) { return MgInvoke<mgp_value *>(mgp_value_make_duration, val); }
|
||||
inline mgp_value *value_make_duration(mgp_duration *val) { return MgInvoke<mgp_value *>(mgp_value_make_duration, val); }
|
||||
|
||||
// Copy value
|
||||
|
||||
// TODO: implement within MGP API
|
||||
// with primitive types ({bool, int, double, string}), create a new identical value
|
||||
// otherwise call mgp_##TYPE_copy and convert tpye
|
||||
mgp_value *value_copy(mgp_value *val, mgp_memory *memory) { return MgInvoke<mgp_value *>(mgp_value_copy, val, memory); }
|
||||
inline mgp_value *value_copy(mgp_value *val, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_value *>(mgp_value_copy, val, memory);
|
||||
}
|
||||
|
||||
// Destroy value
|
||||
|
||||
void value_destroy(mgp_value *val) { mgp_value_destroy(val); }
|
||||
inline void value_destroy(mgp_value *val) { mgp_value_destroy(val); }
|
||||
|
||||
// Get value of type
|
||||
|
||||
mgp_value_type value_get_type(mgp_value *val) { return MgInvoke<mgp_value_type>(mgp_value_get_type, val); }
|
||||
inline mgp_value_type value_get_type(mgp_value *val) { return MgInvoke<mgp_value_type>(mgp_value_get_type, val); }
|
||||
|
||||
bool value_get_bool(mgp_value *val) { return MgInvoke<int>(mgp_value_get_bool, val); }
|
||||
inline bool value_get_bool(mgp_value *val) { return MgInvoke<int>(mgp_value_get_bool, val); }
|
||||
|
||||
int64_t value_get_int(mgp_value *val) { return MgInvoke<int64_t>(mgp_value_get_int, val); }
|
||||
inline int64_t value_get_int(mgp_value *val) { return MgInvoke<int64_t>(mgp_value_get_int, val); }
|
||||
|
||||
double value_get_double(mgp_value *val) { return MgInvoke<double>(mgp_value_get_double, val); }
|
||||
inline double value_get_double(mgp_value *val) { return MgInvoke<double>(mgp_value_get_double, val); }
|
||||
|
||||
const char *value_get_string(mgp_value *val) { return MgInvoke<const char *>(mgp_value_get_string, val); }
|
||||
inline const char *value_get_string(mgp_value *val) { return MgInvoke<const char *>(mgp_value_get_string, val); }
|
||||
|
||||
mgp_list *value_get_list(mgp_value *val) { return MgInvoke<mgp_list *>(mgp_value_get_list, val); }
|
||||
inline mgp_list *value_get_list(mgp_value *val) { return MgInvoke<mgp_list *>(mgp_value_get_list, val); }
|
||||
|
||||
mgp_map *value_get_map(mgp_value *val) { return MgInvoke<mgp_map *>(mgp_value_get_map, val); }
|
||||
inline mgp_map *value_get_map(mgp_value *val) { return MgInvoke<mgp_map *>(mgp_value_get_map, val); }
|
||||
|
||||
mgp_vertex *value_get_vertex(mgp_value *val) { return MgInvoke<mgp_vertex *>(mgp_value_get_vertex, val); }
|
||||
inline mgp_vertex *value_get_vertex(mgp_value *val) { return MgInvoke<mgp_vertex *>(mgp_value_get_vertex, val); }
|
||||
|
||||
mgp_edge *value_get_edge(mgp_value *val) { return MgInvoke<mgp_edge *>(mgp_value_get_edge, val); }
|
||||
inline mgp_edge *value_get_edge(mgp_value *val) { return MgInvoke<mgp_edge *>(mgp_value_get_edge, val); }
|
||||
|
||||
mgp_path *value_get_path(mgp_value *val) { return MgInvoke<mgp_path *>(mgp_value_get_path, val); }
|
||||
inline mgp_path *value_get_path(mgp_value *val) { return MgInvoke<mgp_path *>(mgp_value_get_path, val); }
|
||||
|
||||
mgp_date *value_get_date(mgp_value *val) { return MgInvoke<mgp_date *>(mgp_value_get_date, val); }
|
||||
inline mgp_date *value_get_date(mgp_value *val) { return MgInvoke<mgp_date *>(mgp_value_get_date, val); }
|
||||
|
||||
mgp_local_time *value_get_local_time(mgp_value *val) {
|
||||
inline mgp_local_time *value_get_local_time(mgp_value *val) {
|
||||
return MgInvoke<mgp_local_time *>(mgp_value_get_local_time, val);
|
||||
}
|
||||
|
||||
mgp_local_date_time *value_get_local_date_time(mgp_value *val) {
|
||||
inline mgp_local_date_time *value_get_local_date_time(mgp_value *val) {
|
||||
return MgInvoke<mgp_local_date_time *>(mgp_value_get_local_date_time, val);
|
||||
}
|
||||
|
||||
mgp_duration *value_get_duration(mgp_value *val) { return MgInvoke<mgp_duration *>(mgp_value_get_duration, val); }
|
||||
inline mgp_duration *value_get_duration(mgp_value *val) {
|
||||
return MgInvoke<mgp_duration *>(mgp_value_get_duration, val);
|
||||
}
|
||||
|
||||
// Check type of value
|
||||
|
||||
bool value_is_null(mgp_value *val) { return MgInvoke<int>(mgp_value_is_null, val); }
|
||||
inline bool value_is_null(mgp_value *val) { return MgInvoke<int>(mgp_value_is_null, val); }
|
||||
|
||||
bool value_is_bool(mgp_value *val) { return MgInvoke<int>(mgp_value_is_bool, val); }
|
||||
inline bool value_is_bool(mgp_value *val) { return MgInvoke<int>(mgp_value_is_bool, val); }
|
||||
|
||||
bool value_is_int(mgp_value *val) { return MgInvoke<int>(mgp_value_is_int, val); }
|
||||
inline bool value_is_int(mgp_value *val) { return MgInvoke<int>(mgp_value_is_int, val); }
|
||||
|
||||
bool value_is_double(mgp_value *val) { return MgInvoke<int>(mgp_value_is_double, val); }
|
||||
inline bool value_is_double(mgp_value *val) { return MgInvoke<int>(mgp_value_is_double, val); }
|
||||
|
||||
bool value_is_string(mgp_value *val) { return MgInvoke<int>(mgp_value_is_string, val); }
|
||||
inline bool value_is_string(mgp_value *val) { return MgInvoke<int>(mgp_value_is_string, val); }
|
||||
|
||||
bool value_is_list(mgp_value *val) { return MgInvoke<int>(mgp_value_is_list, val); }
|
||||
inline bool value_is_list(mgp_value *val) { return MgInvoke<int>(mgp_value_is_list, val); }
|
||||
|
||||
bool value_is_map(mgp_value *val) { return MgInvoke<int>(mgp_value_is_map, val); }
|
||||
inline bool value_is_map(mgp_value *val) { return MgInvoke<int>(mgp_value_is_map, val); }
|
||||
|
||||
bool value_is_vertex(mgp_value *val) { return MgInvoke<int>(mgp_value_is_vertex, val); }
|
||||
inline bool value_is_vertex(mgp_value *val) { return MgInvoke<int>(mgp_value_is_vertex, val); }
|
||||
|
||||
bool value_is_edge(mgp_value *val) { return MgInvoke<int>(mgp_value_is_edge, val); }
|
||||
inline bool value_is_edge(mgp_value *val) { return MgInvoke<int>(mgp_value_is_edge, val); }
|
||||
|
||||
bool value_is_path(mgp_value *val) { return MgInvoke<int>(mgp_value_is_path, val); }
|
||||
inline bool value_is_path(mgp_value *val) { return MgInvoke<int>(mgp_value_is_path, val); }
|
||||
|
||||
bool value_is_date(mgp_value *val) { return MgInvoke<int>(mgp_value_is_date, val); }
|
||||
inline bool value_is_date(mgp_value *val) { return MgInvoke<int>(mgp_value_is_date, val); }
|
||||
|
||||
bool value_is_local_time(mgp_value *val) { return MgInvoke<int>(mgp_value_is_local_time, val); }
|
||||
inline bool value_is_local_time(mgp_value *val) { return MgInvoke<int>(mgp_value_is_local_time, val); }
|
||||
|
||||
bool value_is_local_date_time(mgp_value *val) { return MgInvoke<int>(mgp_value_is_local_date_time, val); }
|
||||
inline bool value_is_local_date_time(mgp_value *val) { return MgInvoke<int>(mgp_value_is_local_date_time, val); }
|
||||
|
||||
bool value_is_duration(mgp_value *val) { return MgInvoke<int>(mgp_value_is_duration, val); }
|
||||
inline bool value_is_duration(mgp_value *val) { return MgInvoke<int>(mgp_value_is_duration, val); }
|
||||
|
||||
// Get type
|
||||
|
||||
mgp_type *type_any() { return MgInvoke<mgp_type *>(mgp_type_any); }
|
||||
inline mgp_type *type_any() { return MgInvoke<mgp_type *>(mgp_type_any); }
|
||||
|
||||
mgp_type *type_bool() { return MgInvoke<mgp_type *>(mgp_type_bool); }
|
||||
inline mgp_type *type_bool() { return MgInvoke<mgp_type *>(mgp_type_bool); }
|
||||
|
||||
mgp_type *type_string() { return MgInvoke<mgp_type *>(mgp_type_string); }
|
||||
inline mgp_type *type_string() { return MgInvoke<mgp_type *>(mgp_type_string); }
|
||||
|
||||
mgp_type *type_int() { return MgInvoke<mgp_type *>(mgp_type_int); }
|
||||
inline mgp_type *type_int() { return MgInvoke<mgp_type *>(mgp_type_int); }
|
||||
|
||||
mgp_type *type_float() { return MgInvoke<mgp_type *>(mgp_type_float); }
|
||||
inline mgp_type *type_float() { return MgInvoke<mgp_type *>(mgp_type_float); }
|
||||
|
||||
mgp_type *type_number() { return MgInvoke<mgp_type *>(mgp_type_number); }
|
||||
inline mgp_type *type_number() { return MgInvoke<mgp_type *>(mgp_type_number); }
|
||||
|
||||
mgp_type *type_list(mgp_type *element_type) { return MgInvoke<mgp_type *>(mgp_type_list, element_type); }
|
||||
inline mgp_type *type_list(mgp_type *element_type) { return MgInvoke<mgp_type *>(mgp_type_list, element_type); }
|
||||
|
||||
mgp_type *type_map() { return MgInvoke<mgp_type *>(mgp_type_map); }
|
||||
inline mgp_type *type_map() { return MgInvoke<mgp_type *>(mgp_type_map); }
|
||||
|
||||
mgp_type *type_node() { return MgInvoke<mgp_type *>(mgp_type_node); }
|
||||
inline mgp_type *type_node() { return MgInvoke<mgp_type *>(mgp_type_node); }
|
||||
|
||||
mgp_type *type_relationship() { return MgInvoke<mgp_type *>(mgp_type_relationship); }
|
||||
inline mgp_type *type_relationship() { return MgInvoke<mgp_type *>(mgp_type_relationship); }
|
||||
|
||||
mgp_type *type_path() { return MgInvoke<mgp_type *>(mgp_type_path); }
|
||||
inline mgp_type *type_path() { return MgInvoke<mgp_type *>(mgp_type_path); }
|
||||
|
||||
mgp_type *type_date() { return MgInvoke<mgp_type *>(mgp_type_date); }
|
||||
inline mgp_type *type_date() { return MgInvoke<mgp_type *>(mgp_type_date); }
|
||||
|
||||
mgp_type *type_local_time() { return MgInvoke<mgp_type *>(mgp_type_local_time); }
|
||||
inline mgp_type *type_local_time() { return MgInvoke<mgp_type *>(mgp_type_local_time); }
|
||||
|
||||
mgp_type *type_local_date_time() { return MgInvoke<mgp_type *>(mgp_type_local_date_time); }
|
||||
inline mgp_type *type_local_date_time() { return MgInvoke<mgp_type *>(mgp_type_local_date_time); }
|
||||
|
||||
mgp_type *type_duration() { return MgInvoke<mgp_type *>(mgp_type_duration); }
|
||||
inline mgp_type *type_duration() { return MgInvoke<mgp_type *>(mgp_type_duration); }
|
||||
|
||||
mgp_type *type_nullable(mgp_type *type) { return MgInvoke<mgp_type *>(mgp_type_nullable, type); }
|
||||
inline mgp_type *type_nullable(mgp_type *type) { return MgInvoke<mgp_type *>(mgp_type_nullable, type); }
|
||||
|
||||
// mgp_graph
|
||||
|
||||
bool graph_is_mutable(mgp_graph *graph) { return MgInvoke<int>(mgp_graph_is_mutable, graph); }
|
||||
inline bool graph_is_mutable(mgp_graph *graph) { return MgInvoke<int>(mgp_graph_is_mutable, graph); }
|
||||
|
||||
mgp_vertex *graph_create_vertex(mgp_graph *graph, mgp_memory *memory) {
|
||||
inline mgp_vertex *graph_create_vertex(mgp_graph *graph, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_vertex *>(mgp_graph_create_vertex, graph, memory);
|
||||
}
|
||||
|
||||
void graph_delete_vertex(mgp_graph *graph, mgp_vertex *vertex) { MgInvokeVoid(mgp_graph_delete_vertex, graph, vertex); }
|
||||
inline void graph_delete_vertex(mgp_graph *graph, mgp_vertex *vertex) {
|
||||
MgInvokeVoid(mgp_graph_delete_vertex, graph, vertex);
|
||||
}
|
||||
|
||||
void graph_detach_delete_vertex(mgp_graph *graph, mgp_vertex *vertex) {
|
||||
inline void graph_detach_delete_vertex(mgp_graph *graph, mgp_vertex *vertex) {
|
||||
MgInvokeVoid(mgp_graph_detach_delete_vertex, graph, vertex);
|
||||
}
|
||||
|
||||
mgp_edge *graph_create_edge(mgp_graph *graph, mgp_vertex *from, mgp_vertex *to, mgp_edge_type type,
|
||||
mgp_memory *memory) {
|
||||
inline mgp_edge *graph_create_edge(mgp_graph *graph, mgp_vertex *from, mgp_vertex *to, mgp_edge_type type,
|
||||
mgp_memory *memory) {
|
||||
return MgInvoke<mgp_edge *>(mgp_graph_create_edge, graph, from, to, type, memory);
|
||||
}
|
||||
|
||||
void graph_delete_edge(mgp_graph *graph, mgp_edge *edge) { MgInvokeVoid(mgp_graph_delete_edge, graph, edge); }
|
||||
inline void graph_delete_edge(mgp_graph *graph, mgp_edge *edge) { MgInvokeVoid(mgp_graph_delete_edge, graph, edge); }
|
||||
|
||||
mgp_vertex *graph_get_vertex_by_id(mgp_graph *g, mgp_vertex_id id, mgp_memory *memory) {
|
||||
inline mgp_vertex *graph_get_vertex_by_id(mgp_graph *g, mgp_vertex_id id, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_vertex *>(mgp_graph_get_vertex_by_id, g, id, memory);
|
||||
}
|
||||
|
||||
mgp_vertices_iterator *graph_iter_vertices(mgp_graph *g, mgp_memory *memory) {
|
||||
inline mgp_vertices_iterator *graph_iter_vertices(mgp_graph *g, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_vertices_iterator *>(mgp_graph_iter_vertices, g, memory);
|
||||
}
|
||||
|
||||
// mgp_vertices_iterator
|
||||
|
||||
void vertices_iterator_destroy(mgp_vertices_iterator *it) { mgp_vertices_iterator_destroy(it); }
|
||||
inline void vertices_iterator_destroy(mgp_vertices_iterator *it) { mgp_vertices_iterator_destroy(it); }
|
||||
|
||||
mgp_vertex *vertices_iterator_get(mgp_vertices_iterator *it) {
|
||||
inline mgp_vertex *vertices_iterator_get(mgp_vertices_iterator *it) {
|
||||
return MgInvoke<mgp_vertex *>(mgp_vertices_iterator_get, it);
|
||||
}
|
||||
|
||||
mgp_vertex *vertices_iterator_next(mgp_vertices_iterator *it) {
|
||||
inline mgp_vertex *vertices_iterator_next(mgp_vertices_iterator *it) {
|
||||
return MgInvoke<mgp_vertex *>(mgp_vertices_iterator_next, it);
|
||||
}
|
||||
|
||||
// mgp_edges_iterator
|
||||
|
||||
void edges_iterator_destroy(mgp_edges_iterator *it) { mgp_edges_iterator_destroy(it); }
|
||||
inline void edges_iterator_destroy(mgp_edges_iterator *it) { mgp_edges_iterator_destroy(it); }
|
||||
|
||||
mgp_edge *edges_iterator_get(mgp_edges_iterator *it) { return MgInvoke<mgp_edge *>(mgp_edges_iterator_get, it); }
|
||||
inline mgp_edge *edges_iterator_get(mgp_edges_iterator *it) { return MgInvoke<mgp_edge *>(mgp_edges_iterator_get, it); }
|
||||
|
||||
mgp_edge *edges_iterator_next(mgp_edges_iterator *it) { return MgInvoke<mgp_edge *>(mgp_edges_iterator_next, it); }
|
||||
inline mgp_edge *edges_iterator_next(mgp_edges_iterator *it) {
|
||||
return MgInvoke<mgp_edge *>(mgp_edges_iterator_next, it);
|
||||
}
|
||||
|
||||
// mgp_properties_iterator
|
||||
|
||||
void properties_iterator_destroy(mgp_properties_iterator *it) { mgp_properties_iterator_destroy(it); }
|
||||
inline void properties_iterator_destroy(mgp_properties_iterator *it) { mgp_properties_iterator_destroy(it); }
|
||||
|
||||
mgp_property *properties_iterator_get(mgp_properties_iterator *it) {
|
||||
inline mgp_property *properties_iterator_get(mgp_properties_iterator *it) {
|
||||
return MgInvoke<mgp_property *>(mgp_properties_iterator_get, it);
|
||||
}
|
||||
|
||||
mgp_property *properties_iterator_next(mgp_properties_iterator *it) {
|
||||
inline mgp_property *properties_iterator_next(mgp_properties_iterator *it) {
|
||||
return MgInvoke<mgp_property *>(mgp_properties_iterator_next, it);
|
||||
}
|
||||
|
||||
@@ -284,409 +294,440 @@ mgp_property *properties_iterator_next(mgp_properties_iterator *it) {
|
||||
|
||||
// mgp_list
|
||||
|
||||
mgp_list *list_make_empty(size_t capacity, mgp_memory *memory) {
|
||||
inline mgp_list *list_make_empty(size_t capacity, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_list *>(mgp_list_make_empty, capacity, memory);
|
||||
}
|
||||
|
||||
mgp_list *list_copy(mgp_list *list, mgp_memory *memory) { return MgInvoke<mgp_list *>(mgp_list_copy, list, memory); }
|
||||
inline mgp_list *list_copy(mgp_list *list, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_list *>(mgp_list_copy, list, memory);
|
||||
}
|
||||
|
||||
void list_destroy(mgp_list *list) { mgp_list_destroy(list); }
|
||||
inline void list_destroy(mgp_list *list) { mgp_list_destroy(list); }
|
||||
|
||||
void list_append(mgp_list *list, mgp_value *val) { MgInvokeVoid(mgp_list_append, list, val); }
|
||||
inline void list_append(mgp_list *list, mgp_value *val) { MgInvokeVoid(mgp_list_append, list, val); }
|
||||
|
||||
void list_append_extend(mgp_list *list, mgp_value *val) { MgInvokeVoid(mgp_list_append_extend, list, val); }
|
||||
inline void list_append_extend(mgp_list *list, mgp_value *val) { MgInvokeVoid(mgp_list_append_extend, list, val); }
|
||||
|
||||
size_t list_size(mgp_list *list) { return MgInvoke<size_t>(mgp_list_size, list); }
|
||||
inline size_t list_size(mgp_list *list) { return MgInvoke<size_t>(mgp_list_size, list); }
|
||||
|
||||
size_t list_capacity(mgp_list *list) { return MgInvoke<size_t>(mgp_list_capacity, list); }
|
||||
inline size_t list_capacity(mgp_list *list) { return MgInvoke<size_t>(mgp_list_capacity, list); }
|
||||
|
||||
mgp_value *list_at(mgp_list *list, size_t index) { return MgInvoke<mgp_value *>(mgp_list_at, list, index); }
|
||||
inline mgp_value *list_at(mgp_list *list, size_t index) { return MgInvoke<mgp_value *>(mgp_list_at, list, index); }
|
||||
|
||||
// mgp_map
|
||||
|
||||
mgp_map *map_make_empty(mgp_memory *memory) { return MgInvoke<mgp_map *>(mgp_map_make_empty, memory); }
|
||||
inline mgp_map *map_make_empty(mgp_memory *memory) { return MgInvoke<mgp_map *>(mgp_map_make_empty, memory); }
|
||||
|
||||
mgp_map *map_copy(mgp_map *map, mgp_memory *memory) { return MgInvoke<mgp_map *>(mgp_map_copy, map, memory); }
|
||||
inline mgp_map *map_copy(mgp_map *map, mgp_memory *memory) { return MgInvoke<mgp_map *>(mgp_map_copy, map, memory); }
|
||||
|
||||
void map_destroy(mgp_map *map) { mgp_map_destroy(map); }
|
||||
inline void map_destroy(mgp_map *map) { mgp_map_destroy(map); }
|
||||
|
||||
void map_insert(mgp_map *map, const char *key, mgp_value *value) { MgInvokeVoid(mgp_map_insert, map, key, value); }
|
||||
inline void map_insert(mgp_map *map, const char *key, mgp_value *value) {
|
||||
MgInvokeVoid(mgp_map_insert, map, key, value);
|
||||
}
|
||||
|
||||
size_t map_size(mgp_map *map) { return MgInvoke<size_t>(mgp_map_size, map); }
|
||||
inline size_t map_size(mgp_map *map) { return MgInvoke<size_t>(mgp_map_size, map); }
|
||||
|
||||
mgp_value *map_at(mgp_map *map, const char *key) { return MgInvoke<mgp_value *>(mgp_map_at, map, key); }
|
||||
inline mgp_value *map_at(mgp_map *map, const char *key) { return MgInvoke<mgp_value *>(mgp_map_at, map, key); }
|
||||
|
||||
const char *map_item_key(mgp_map_item *item) { return MgInvoke<const char *>(mgp_map_item_key, item); }
|
||||
inline const char *map_item_key(mgp_map_item *item) { return MgInvoke<const char *>(mgp_map_item_key, item); }
|
||||
|
||||
mgp_value *map_item_value(mgp_map_item *item) { return MgInvoke<mgp_value *>(mgp_map_item_value, item); }
|
||||
inline mgp_value *map_item_value(mgp_map_item *item) { return MgInvoke<mgp_value *>(mgp_map_item_value, item); }
|
||||
|
||||
mgp_map_items_iterator *map_iter_items(mgp_map *map, mgp_memory *memory) {
|
||||
inline mgp_map_items_iterator *map_iter_items(mgp_map *map, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_map_items_iterator *>(mgp_map_iter_items, map, memory);
|
||||
}
|
||||
|
||||
void map_items_iterator_destroy(mgp_map_items_iterator *it) { mgp_map_items_iterator_destroy(it); }
|
||||
inline void map_items_iterator_destroy(mgp_map_items_iterator *it) { mgp_map_items_iterator_destroy(it); }
|
||||
|
||||
mgp_map_item *map_items_iterator_get(mgp_map_items_iterator *it) {
|
||||
inline mgp_map_item *map_items_iterator_get(mgp_map_items_iterator *it) {
|
||||
return MgInvoke<mgp_map_item *>(mgp_map_items_iterator_get, it);
|
||||
}
|
||||
|
||||
mgp_map_item *map_items_iterator_next(mgp_map_items_iterator *it) {
|
||||
inline mgp_map_item *map_items_iterator_next(mgp_map_items_iterator *it) {
|
||||
return MgInvoke<mgp_map_item *>(mgp_map_items_iterator_next, it);
|
||||
}
|
||||
|
||||
// mgp_vertex
|
||||
|
||||
mgp_vertex_id vertex_get_id(mgp_vertex *v) { return MgInvoke<mgp_vertex_id>(mgp_vertex_get_id, v); }
|
||||
inline mgp_vertex_id vertex_get_id(mgp_vertex *v) { return MgInvoke<mgp_vertex_id>(mgp_vertex_get_id, v); }
|
||||
|
||||
mgp_vertex *vertex_copy(mgp_vertex *v, mgp_memory *memory) {
|
||||
inline mgp_vertex *vertex_copy(mgp_vertex *v, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_vertex *>(mgp_vertex_copy, v, memory);
|
||||
}
|
||||
|
||||
void vertex_destroy(mgp_vertex *v) { mgp_vertex_destroy(v); }
|
||||
inline void vertex_destroy(mgp_vertex *v) { mgp_vertex_destroy(v); }
|
||||
|
||||
bool vertex_equal(mgp_vertex *v1, mgp_vertex *v2) { return MgInvoke<int>(mgp_vertex_equal, v1, v2); }
|
||||
inline bool vertex_equal(mgp_vertex *v1, mgp_vertex *v2) { return MgInvoke<int>(mgp_vertex_equal, v1, v2); }
|
||||
|
||||
size_t vertex_labels_count(mgp_vertex *v) { return MgInvoke<size_t>(mgp_vertex_labels_count, v); }
|
||||
inline size_t vertex_labels_count(mgp_vertex *v) { return MgInvoke<size_t>(mgp_vertex_labels_count, v); }
|
||||
|
||||
mgp_label vertex_label_at(mgp_vertex *v, size_t index) { return MgInvoke<mgp_label>(mgp_vertex_label_at, v, index); }
|
||||
inline mgp_label vertex_label_at(mgp_vertex *v, size_t index) {
|
||||
return MgInvoke<mgp_label>(mgp_vertex_label_at, v, index);
|
||||
}
|
||||
|
||||
bool vertex_has_label(mgp_vertex *v, mgp_label label) { return MgInvoke<int>(mgp_vertex_has_label, v, label); }
|
||||
inline bool vertex_has_label(mgp_vertex *v, mgp_label label) { return MgInvoke<int>(mgp_vertex_has_label, v, label); }
|
||||
|
||||
bool vertex_has_label_named(mgp_vertex *v, const char *label_name) {
|
||||
inline bool vertex_has_label_named(mgp_vertex *v, const char *label_name) {
|
||||
return MgInvoke<int>(mgp_vertex_has_label_named, v, label_name);
|
||||
}
|
||||
|
||||
void vertex_add_label(mgp_vertex *vertex, mgp_label label) { MgInvokeVoid(mgp_vertex_add_label, vertex, label); }
|
||||
inline void vertex_add_label(mgp_vertex *vertex, mgp_label label) { MgInvokeVoid(mgp_vertex_add_label, vertex, label); }
|
||||
|
||||
mgp_value *vertex_get_property(mgp_vertex *v, const char *property_name, mgp_memory *memory) {
|
||||
inline mgp_value *vertex_get_property(mgp_vertex *v, const char *property_name, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_value *>(mgp_vertex_get_property, v, property_name, memory);
|
||||
}
|
||||
|
||||
mgp_properties_iterator *vertex_iter_properties(mgp_vertex *v, mgp_memory *memory) {
|
||||
inline void vertex_set_property(mgp_vertex *v, const char *property_name, mgp_value *property_value) {
|
||||
MgInvokeVoid(mgp_vertex_set_property, v, property_name, property_value);
|
||||
}
|
||||
|
||||
inline mgp_properties_iterator *vertex_iter_properties(mgp_vertex *v, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_properties_iterator *>(mgp_vertex_iter_properties, v, memory);
|
||||
}
|
||||
|
||||
mgp_edges_iterator *vertex_iter_in_edges(mgp_vertex *v, mgp_memory *memory) {
|
||||
inline mgp_edges_iterator *vertex_iter_in_edges(mgp_vertex *v, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_edges_iterator *>(mgp_vertex_iter_in_edges, v, memory);
|
||||
}
|
||||
|
||||
mgp_edges_iterator *vertex_iter_out_edges(mgp_vertex *v, mgp_memory *memory) {
|
||||
inline mgp_edges_iterator *vertex_iter_out_edges(mgp_vertex *v, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_edges_iterator *>(mgp_vertex_iter_out_edges, v, memory);
|
||||
}
|
||||
|
||||
// mgp_edge
|
||||
|
||||
mgp_edge_id edge_get_id(mgp_edge *e) { return MgInvoke<mgp_edge_id>(mgp_edge_get_id, e); }
|
||||
inline mgp_edge_id edge_get_id(mgp_edge *e) { return MgInvoke<mgp_edge_id>(mgp_edge_get_id, e); }
|
||||
|
||||
mgp_edge *edge_copy(mgp_edge *e, mgp_memory *memory) { return MgInvoke<mgp_edge *>(mgp_edge_copy, e, memory); }
|
||||
inline mgp_edge *edge_copy(mgp_edge *e, mgp_memory *memory) { return MgInvoke<mgp_edge *>(mgp_edge_copy, e, memory); }
|
||||
|
||||
void edge_destroy(mgp_edge *e) { mgp_edge_destroy(e); }
|
||||
inline void edge_destroy(mgp_edge *e) { mgp_edge_destroy(e); }
|
||||
|
||||
bool edge_equal(mgp_edge *e1, mgp_edge *e2) { return MgInvoke<int>(mgp_edge_equal, e1, e2); }
|
||||
inline bool edge_equal(mgp_edge *e1, mgp_edge *e2) { return MgInvoke<int>(mgp_edge_equal, e1, e2); }
|
||||
|
||||
mgp_edge_type edge_get_type(mgp_edge *e) { return MgInvoke<mgp_edge_type>(mgp_edge_get_type, e); }
|
||||
inline mgp_edge_type edge_get_type(mgp_edge *e) { return MgInvoke<mgp_edge_type>(mgp_edge_get_type, e); }
|
||||
|
||||
mgp_vertex *edge_get_from(mgp_edge *e) { return MgInvoke<mgp_vertex *>(mgp_edge_get_from, e); }
|
||||
inline mgp_vertex *edge_get_from(mgp_edge *e) { return MgInvoke<mgp_vertex *>(mgp_edge_get_from, e); }
|
||||
|
||||
mgp_vertex *edge_get_to(mgp_edge *e) { return MgInvoke<mgp_vertex *>(mgp_edge_get_to, e); }
|
||||
inline mgp_vertex *edge_get_to(mgp_edge *e) { return MgInvoke<mgp_vertex *>(mgp_edge_get_to, e); }
|
||||
|
||||
mgp_value *edge_get_property(mgp_edge *e, const char *property_name, mgp_memory *memory) {
|
||||
inline mgp_value *edge_get_property(mgp_edge *e, const char *property_name, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_value *>(mgp_edge_get_property, e, property_name, memory);
|
||||
}
|
||||
|
||||
mgp_properties_iterator *edge_iter_properties(mgp_edge *e, mgp_memory *memory) {
|
||||
inline void edge_set_property(mgp_edge *e, const char *property_name, mgp_value *property_value) {
|
||||
MgInvokeVoid(mgp_edge_set_property, e, property_name, property_value);
|
||||
}
|
||||
|
||||
inline mgp_properties_iterator *edge_iter_properties(mgp_edge *e, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_properties_iterator *>(mgp_edge_iter_properties, e, memory);
|
||||
}
|
||||
|
||||
// mgp_path
|
||||
|
||||
mgp_path *path_make_with_start(mgp_vertex *vertex, mgp_memory *memory) {
|
||||
inline mgp_path *path_make_with_start(mgp_vertex *vertex, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_path *>(mgp_path_make_with_start, vertex, memory);
|
||||
}
|
||||
|
||||
mgp_path *path_copy(mgp_path *path, mgp_memory *memory) { return MgInvoke<mgp_path *>(mgp_path_copy, path, memory); }
|
||||
inline mgp_path *path_copy(mgp_path *path, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_path *>(mgp_path_copy, path, memory);
|
||||
}
|
||||
|
||||
void path_destroy(mgp_path *path) { mgp_path_destroy(path); }
|
||||
inline void path_destroy(mgp_path *path) { mgp_path_destroy(path); }
|
||||
|
||||
void path_expand(mgp_path *path, mgp_edge *edge) { MgInvokeVoid(mgp_path_expand, path, edge); }
|
||||
inline void path_expand(mgp_path *path, mgp_edge *edge) { MgInvokeVoid(mgp_path_expand, path, edge); }
|
||||
|
||||
size_t path_size(mgp_path *path) { return MgInvoke<size_t>(mgp_path_size, path); }
|
||||
inline size_t path_size(mgp_path *path) { return MgInvoke<size_t>(mgp_path_size, path); }
|
||||
|
||||
mgp_vertex *path_vertex_at(mgp_path *path, size_t index) {
|
||||
inline mgp_vertex *path_vertex_at(mgp_path *path, size_t index) {
|
||||
return MgInvoke<mgp_vertex *>(mgp_path_vertex_at, path, index);
|
||||
}
|
||||
|
||||
mgp_edge *path_edge_at(mgp_path *path, size_t index) { return MgInvoke<mgp_edge *>(mgp_path_edge_at, path, index); }
|
||||
inline mgp_edge *path_edge_at(mgp_path *path, size_t index) {
|
||||
return MgInvoke<mgp_edge *>(mgp_path_edge_at, path, index);
|
||||
}
|
||||
|
||||
bool path_equal(mgp_path *p1, mgp_path *p2) { return MgInvoke<int>(mgp_path_equal, p1, p2); }
|
||||
inline bool path_equal(mgp_path *p1, mgp_path *p2) { return MgInvoke<int>(mgp_path_equal, p1, p2); }
|
||||
|
||||
// Temporal type {mgp_date, mgp_local_time, mgp_local_date_time, mgp_duration} methods
|
||||
|
||||
// mgp_date
|
||||
|
||||
mgp_date *date_from_string(const char *string, mgp_memory *memory) {
|
||||
inline mgp_date *date_from_string(const char *string, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_date *>(mgp_date_from_string, string, memory);
|
||||
}
|
||||
|
||||
mgp_date *date_from_parameters(mgp_date_parameters *parameters, mgp_memory *memory) {
|
||||
inline mgp_date *date_from_parameters(mgp_date_parameters *parameters, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_date *>(mgp_date_from_parameters, parameters, memory);
|
||||
}
|
||||
|
||||
mgp_date *date_copy(mgp_date *date, mgp_memory *memory) { return MgInvoke<mgp_date *>(mgp_date_copy, date, memory); }
|
||||
inline mgp_date *date_copy(mgp_date *date, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_date *>(mgp_date_copy, date, memory);
|
||||
}
|
||||
|
||||
void date_destroy(mgp_date *date) { mgp_date_destroy(date); }
|
||||
inline void date_destroy(mgp_date *date) { mgp_date_destroy(date); }
|
||||
|
||||
bool date_equal(mgp_date *first, mgp_date *second) { return MgInvoke<int>(mgp_date_equal, first, second); }
|
||||
inline bool date_equal(mgp_date *first, mgp_date *second) { return MgInvoke<int>(mgp_date_equal, first, second); }
|
||||
|
||||
int date_get_year(mgp_date *date) { return MgInvoke<int>(mgp_date_get_year, date); }
|
||||
inline int date_get_year(mgp_date *date) { return MgInvoke<int>(mgp_date_get_year, date); }
|
||||
|
||||
int date_get_month(mgp_date *date) { return MgInvoke<int>(mgp_date_get_month, date); }
|
||||
inline int date_get_month(mgp_date *date) { return MgInvoke<int>(mgp_date_get_month, date); }
|
||||
|
||||
int date_get_day(mgp_date *date) { return MgInvoke<int>(mgp_date_get_day, date); }
|
||||
inline int date_get_day(mgp_date *date) { return MgInvoke<int>(mgp_date_get_day, date); }
|
||||
|
||||
int64_t date_timestamp(mgp_date *date) { return MgInvoke<int64_t>(mgp_date_timestamp, date); }
|
||||
inline int64_t date_timestamp(mgp_date *date) { return MgInvoke<int64_t>(mgp_date_timestamp, date); }
|
||||
|
||||
mgp_date *date_now(mgp_memory *memory) { return MgInvoke<mgp_date *>(mgp_date_now, memory); }
|
||||
inline mgp_date *date_now(mgp_memory *memory) { return MgInvoke<mgp_date *>(mgp_date_now, memory); }
|
||||
|
||||
mgp_date *date_add_duration(mgp_date *date, mgp_duration *dur, mgp_memory *memory) {
|
||||
inline mgp_date *date_add_duration(mgp_date *date, mgp_duration *dur, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_date *>(mgp_date_add_duration, date, dur, memory);
|
||||
}
|
||||
|
||||
mgp_date *date_sub_duration(mgp_date *date, mgp_duration *dur, mgp_memory *memory) {
|
||||
inline mgp_date *date_sub_duration(mgp_date *date, mgp_duration *dur, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_date *>(mgp_date_sub_duration, date, dur, memory);
|
||||
}
|
||||
|
||||
mgp_duration *date_diff(mgp_date *first, mgp_date *second, mgp_memory *memory) {
|
||||
inline mgp_duration *date_diff(mgp_date *first, mgp_date *second, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_duration *>(mgp_date_diff, first, second, memory);
|
||||
}
|
||||
|
||||
// mgp_local_time
|
||||
|
||||
mgp_local_time *local_time_from_string(const char *string, mgp_memory *memory) {
|
||||
inline mgp_local_time *local_time_from_string(const char *string, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_local_time *>(mgp_local_time_from_string, string, memory);
|
||||
}
|
||||
|
||||
mgp_local_time *local_time_from_parameters(mgp_local_time_parameters *parameters, mgp_memory *memory) {
|
||||
inline mgp_local_time *local_time_from_parameters(mgp_local_time_parameters *parameters, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_local_time *>(mgp_local_time_from_parameters, parameters, memory);
|
||||
}
|
||||
|
||||
mgp_local_time *local_time_copy(mgp_local_time *local_time, mgp_memory *memory) {
|
||||
inline mgp_local_time *local_time_copy(mgp_local_time *local_time, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_local_time *>(mgp_local_time_copy, local_time, memory);
|
||||
}
|
||||
|
||||
void local_time_destroy(mgp_local_time *local_time) { mgp_local_time_destroy(local_time); }
|
||||
inline void local_time_destroy(mgp_local_time *local_time) { mgp_local_time_destroy(local_time); }
|
||||
|
||||
bool local_time_equal(mgp_local_time *first, mgp_local_time *second) {
|
||||
inline bool local_time_equal(mgp_local_time *first, mgp_local_time *second) {
|
||||
return MgInvoke<int>(mgp_local_time_equal, first, second);
|
||||
}
|
||||
|
||||
int local_time_get_hour(mgp_local_time *local_time) { return MgInvoke<int>(mgp_local_time_get_hour, local_time); }
|
||||
inline int local_time_get_hour(mgp_local_time *local_time) {
|
||||
return MgInvoke<int>(mgp_local_time_get_hour, local_time);
|
||||
}
|
||||
|
||||
int local_time_get_minute(mgp_local_time *local_time) { return MgInvoke<int>(mgp_local_time_get_minute, local_time); }
|
||||
inline int local_time_get_minute(mgp_local_time *local_time) {
|
||||
return MgInvoke<int>(mgp_local_time_get_minute, local_time);
|
||||
}
|
||||
|
||||
int local_time_get_second(mgp_local_time *local_time) { return MgInvoke<int>(mgp_local_time_get_second, local_time); }
|
||||
inline int local_time_get_second(mgp_local_time *local_time) {
|
||||
return MgInvoke<int>(mgp_local_time_get_second, local_time);
|
||||
}
|
||||
|
||||
int local_time_get_millisecond(mgp_local_time *local_time) {
|
||||
inline int local_time_get_millisecond(mgp_local_time *local_time) {
|
||||
return MgInvoke<int>(mgp_local_time_get_millisecond, local_time);
|
||||
}
|
||||
|
||||
int local_time_get_microsecond(mgp_local_time *local_time) {
|
||||
inline int local_time_get_microsecond(mgp_local_time *local_time) {
|
||||
return MgInvoke<int>(mgp_local_time_get_microsecond, local_time);
|
||||
}
|
||||
|
||||
int64_t local_time_timestamp(mgp_local_time *local_time) {
|
||||
inline int64_t local_time_timestamp(mgp_local_time *local_time) {
|
||||
return MgInvoke<int64_t>(mgp_local_time_timestamp, local_time);
|
||||
}
|
||||
|
||||
mgp_local_time *local_time_now(mgp_memory *memory) { return MgInvoke<mgp_local_time *>(mgp_local_time_now, memory); }
|
||||
inline mgp_local_time *local_time_now(mgp_memory *memory) {
|
||||
return MgInvoke<mgp_local_time *>(mgp_local_time_now, memory);
|
||||
}
|
||||
|
||||
mgp_local_time *local_time_add_duration(mgp_local_time *local_time, mgp_duration *dur, mgp_memory *memory) {
|
||||
inline mgp_local_time *local_time_add_duration(mgp_local_time *local_time, mgp_duration *dur, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_local_time *>(mgp_local_time_add_duration, local_time, dur, memory);
|
||||
}
|
||||
|
||||
mgp_local_time *local_time_sub_duration(mgp_local_time *local_time, mgp_duration *dur, mgp_memory *memory) {
|
||||
inline mgp_local_time *local_time_sub_duration(mgp_local_time *local_time, mgp_duration *dur, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_local_time *>(mgp_local_time_sub_duration, local_time, dur, memory);
|
||||
}
|
||||
|
||||
mgp_duration *local_time_diff(mgp_local_time *first, mgp_local_time *second, mgp_memory *memory) {
|
||||
inline mgp_duration *local_time_diff(mgp_local_time *first, mgp_local_time *second, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_duration *>(mgp_local_time_diff, first, second, memory);
|
||||
}
|
||||
|
||||
// mgp_local_date_time
|
||||
|
||||
mgp_local_date_time *local_date_time_from_string(const char *string, mgp_memory *memory) {
|
||||
inline mgp_local_date_time *local_date_time_from_string(const char *string, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_local_date_time *>(mgp_local_date_time_from_string, string, memory);
|
||||
}
|
||||
|
||||
mgp_local_date_time *local_date_time_from_parameters(mgp_local_date_time_parameters *parameters, mgp_memory *memory) {
|
||||
inline mgp_local_date_time *local_date_time_from_parameters(mgp_local_date_time_parameters *parameters,
|
||||
mgp_memory *memory) {
|
||||
return MgInvoke<mgp_local_date_time *>(mgp_local_date_time_from_parameters, parameters, memory);
|
||||
}
|
||||
|
||||
mgp_local_date_time *local_date_time_copy(mgp_local_date_time *local_date_time, mgp_memory *memory) {
|
||||
inline mgp_local_date_time *local_date_time_copy(mgp_local_date_time *local_date_time, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_local_date_time *>(mgp_local_date_time_copy, local_date_time, memory);
|
||||
}
|
||||
|
||||
void local_date_time_destroy(mgp_local_date_time *local_date_time) { mgp_local_date_time_destroy(local_date_time); }
|
||||
inline void local_date_time_destroy(mgp_local_date_time *local_date_time) {
|
||||
mgp_local_date_time_destroy(local_date_time);
|
||||
}
|
||||
|
||||
bool local_date_time_equal(mgp_local_date_time *first, mgp_local_date_time *second) {
|
||||
inline bool local_date_time_equal(mgp_local_date_time *first, mgp_local_date_time *second) {
|
||||
return MgInvoke<int>(mgp_local_date_time_equal, first, second);
|
||||
}
|
||||
|
||||
int local_date_time_get_year(mgp_local_date_time *local_date_time) {
|
||||
inline int local_date_time_get_year(mgp_local_date_time *local_date_time) {
|
||||
return MgInvoke<int>(mgp_local_date_time_get_year, local_date_time);
|
||||
}
|
||||
|
||||
int local_date_time_get_month(mgp_local_date_time *local_date_time) {
|
||||
inline int local_date_time_get_month(mgp_local_date_time *local_date_time) {
|
||||
return MgInvoke<int>(mgp_local_date_time_get_month, local_date_time);
|
||||
}
|
||||
|
||||
int local_date_time_get_day(mgp_local_date_time *local_date_time) {
|
||||
inline int local_date_time_get_day(mgp_local_date_time *local_date_time) {
|
||||
return MgInvoke<int>(mgp_local_date_time_get_day, local_date_time);
|
||||
}
|
||||
|
||||
int local_date_time_get_hour(mgp_local_date_time *local_date_time) {
|
||||
inline int local_date_time_get_hour(mgp_local_date_time *local_date_time) {
|
||||
return MgInvoke<int>(mgp_local_date_time_get_hour, local_date_time);
|
||||
}
|
||||
|
||||
int local_date_time_get_minute(mgp_local_date_time *local_date_time) {
|
||||
inline int local_date_time_get_minute(mgp_local_date_time *local_date_time) {
|
||||
return MgInvoke<int>(mgp_local_date_time_get_minute, local_date_time);
|
||||
}
|
||||
|
||||
int local_date_time_get_second(mgp_local_date_time *local_date_time) {
|
||||
inline int local_date_time_get_second(mgp_local_date_time *local_date_time) {
|
||||
return MgInvoke<int>(mgp_local_date_time_get_second, local_date_time);
|
||||
}
|
||||
|
||||
int local_date_time_get_millisecond(mgp_local_date_time *local_date_time) {
|
||||
inline int local_date_time_get_millisecond(mgp_local_date_time *local_date_time) {
|
||||
return MgInvoke<int>(mgp_local_date_time_get_millisecond, local_date_time);
|
||||
}
|
||||
|
||||
int local_date_time_get_microsecond(mgp_local_date_time *local_date_time) {
|
||||
inline int local_date_time_get_microsecond(mgp_local_date_time *local_date_time) {
|
||||
return MgInvoke<int>(mgp_local_date_time_get_microsecond, local_date_time);
|
||||
}
|
||||
|
||||
int64_t local_date_time_timestamp(mgp_local_date_time *local_date_time) {
|
||||
inline int64_t local_date_time_timestamp(mgp_local_date_time *local_date_time) {
|
||||
return MgInvoke<int64_t>(mgp_local_date_time_timestamp, local_date_time);
|
||||
}
|
||||
|
||||
mgp_local_date_time *local_date_time_now(mgp_memory *memory) {
|
||||
inline mgp_local_date_time *local_date_time_now(mgp_memory *memory) {
|
||||
return MgInvoke<mgp_local_date_time *>(mgp_local_date_time_now, memory);
|
||||
}
|
||||
|
||||
mgp_local_date_time *local_date_time_add_duration(mgp_local_date_time *local_date_time, mgp_duration *dur,
|
||||
mgp_memory *memory) {
|
||||
inline mgp_local_date_time *local_date_time_add_duration(mgp_local_date_time *local_date_time, mgp_duration *dur,
|
||||
mgp_memory *memory) {
|
||||
return MgInvoke<mgp_local_date_time *>(mgp_local_date_time_add_duration, local_date_time, dur, memory);
|
||||
}
|
||||
|
||||
mgp_local_date_time *local_date_time_sub_duration(mgp_local_date_time *local_date_time, mgp_duration *dur,
|
||||
mgp_memory *memory) {
|
||||
inline mgp_local_date_time *local_date_time_sub_duration(mgp_local_date_time *local_date_time, mgp_duration *dur,
|
||||
mgp_memory *memory) {
|
||||
return MgInvoke<mgp_local_date_time *>(mgp_local_date_time_sub_duration, local_date_time, dur, memory);
|
||||
}
|
||||
|
||||
mgp_duration *local_date_time_diff(mgp_local_date_time *first, mgp_local_date_time *second, mgp_memory *memory) {
|
||||
inline mgp_duration *local_date_time_diff(mgp_local_date_time *first, mgp_local_date_time *second, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_duration *>(mgp_local_date_time_diff, first, second, memory);
|
||||
}
|
||||
|
||||
// mgp_duration
|
||||
|
||||
mgp_duration *duration_from_string(const char *string, mgp_memory *memory) {
|
||||
inline mgp_duration *duration_from_string(const char *string, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_duration *>(mgp_duration_from_string, string, memory);
|
||||
}
|
||||
|
||||
mgp_duration *duration_from_parameters(mgp_duration_parameters *parameters, mgp_memory *memory) {
|
||||
inline mgp_duration *duration_from_parameters(mgp_duration_parameters *parameters, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_duration *>(mgp_duration_from_parameters, parameters, memory);
|
||||
}
|
||||
|
||||
mgp_duration *duration_from_microseconds(int64_t microseconds, mgp_memory *memory) {
|
||||
inline mgp_duration *duration_from_microseconds(int64_t microseconds, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_duration *>(mgp_duration_from_microseconds, microseconds, memory);
|
||||
}
|
||||
|
||||
mgp_duration *duration_copy(mgp_duration *duration, mgp_memory *memory) {
|
||||
inline mgp_duration *duration_copy(mgp_duration *duration, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_duration *>(mgp_duration_copy, duration, memory);
|
||||
}
|
||||
|
||||
void duration_destroy(mgp_duration *duration) { mgp_duration_destroy(duration); }
|
||||
inline void duration_destroy(mgp_duration *duration) { mgp_duration_destroy(duration); }
|
||||
|
||||
int64_t duration_get_microseconds(mgp_duration *duration) {
|
||||
inline int64_t duration_get_microseconds(mgp_duration *duration) {
|
||||
return MgInvoke<int64_t>(mgp_duration_get_microseconds, duration);
|
||||
}
|
||||
|
||||
bool duration_equal(mgp_duration *first, mgp_duration *second) {
|
||||
inline bool duration_equal(mgp_duration *first, mgp_duration *second) {
|
||||
return MgInvoke<int>(mgp_duration_equal, first, second);
|
||||
}
|
||||
|
||||
mgp_duration *duration_neg(mgp_duration *duration, mgp_memory *memory) {
|
||||
inline mgp_duration *duration_neg(mgp_duration *duration, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_duration *>(mgp_duration_neg, duration, memory);
|
||||
}
|
||||
|
||||
mgp_duration *duration_add(mgp_duration *first, mgp_duration *second, mgp_memory *memory) {
|
||||
inline mgp_duration *duration_add(mgp_duration *first, mgp_duration *second, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_duration *>(mgp_duration_add, first, second, memory);
|
||||
}
|
||||
|
||||
mgp_duration *duration_sub(mgp_duration *first, mgp_duration *second, mgp_memory *memory) {
|
||||
inline mgp_duration *duration_sub(mgp_duration *first, mgp_duration *second, mgp_memory *memory) {
|
||||
return MgInvoke<mgp_duration *>(mgp_duration_sub, first, second, memory);
|
||||
}
|
||||
|
||||
// Procedure
|
||||
|
||||
mgp_proc *module_add_read_procedure(mgp_module *module, const char *name, mgp_proc_cb cb) {
|
||||
inline mgp_proc *module_add_read_procedure(mgp_module *module, const char *name, mgp_proc_cb cb) {
|
||||
return MgInvoke<mgp_proc *>(mgp_module_add_read_procedure, module, name, cb);
|
||||
}
|
||||
|
||||
mgp_proc *module_add_write_procedure(mgp_module *module, const char *name, mgp_proc_cb cb) {
|
||||
inline mgp_proc *module_add_write_procedure(mgp_module *module, const char *name, mgp_proc_cb cb) {
|
||||
return MgInvoke<mgp_proc *>(mgp_module_add_write_procedure, module, name, cb);
|
||||
}
|
||||
|
||||
void proc_add_arg(mgp_proc *proc, const char *name, mgp_type *type) {
|
||||
inline void proc_add_arg(mgp_proc *proc, const char *name, mgp_type *type) {
|
||||
MgInvokeVoid(mgp_proc_add_arg, proc, name, type);
|
||||
}
|
||||
|
||||
void proc_add_opt_arg(mgp_proc *proc, const char *name, mgp_type *type, mgp_value *default_value) {
|
||||
inline void proc_add_opt_arg(mgp_proc *proc, const char *name, mgp_type *type, mgp_value *default_value) {
|
||||
MgInvokeVoid(mgp_proc_add_opt_arg, proc, name, type, default_value);
|
||||
}
|
||||
|
||||
void proc_add_result(mgp_proc *proc, const char *name, mgp_type *type) {
|
||||
inline void proc_add_result(mgp_proc *proc, const char *name, mgp_type *type) {
|
||||
MgInvokeVoid(mgp_proc_add_result, proc, name, type);
|
||||
}
|
||||
|
||||
void proc_add_deprecated_result(mgp_proc *proc, const char *name, mgp_type *type) {
|
||||
inline void proc_add_deprecated_result(mgp_proc *proc, const char *name, mgp_type *type) {
|
||||
MgInvokeVoid(mgp_proc_add_deprecated_result, proc, name, type);
|
||||
}
|
||||
|
||||
bool must_abort(mgp_graph *graph) { return mgp_must_abort(graph); }
|
||||
inline bool must_abort(mgp_graph *graph) { return mgp_must_abort(graph); }
|
||||
|
||||
// mgp_result
|
||||
|
||||
void result_set_error_msg(mgp_result *res, const char *error_msg) {
|
||||
inline void result_set_error_msg(mgp_result *res, const char *error_msg) {
|
||||
MgInvokeVoid(mgp_result_set_error_msg, res, error_msg);
|
||||
}
|
||||
|
||||
mgp_result_record *result_new_record(mgp_result *res) {
|
||||
inline mgp_result_record *result_new_record(mgp_result *res) {
|
||||
return MgInvoke<mgp_result_record *>(mgp_result_new_record, res);
|
||||
}
|
||||
|
||||
void result_record_insert(mgp_result_record *record, const char *field_name, mgp_value *val) {
|
||||
inline void result_record_insert(mgp_result_record *record, const char *field_name, mgp_value *val) {
|
||||
MgInvokeVoid(mgp_result_record_insert, record, field_name, val);
|
||||
}
|
||||
|
||||
// Function
|
||||
|
||||
mgp_func *module_add_function(mgp_module *module, const char *name, mgp_func_cb cb) {
|
||||
inline mgp_func *module_add_function(mgp_module *module, const char *name, mgp_func_cb cb) {
|
||||
return MgInvoke<mgp_func *>(mgp_module_add_function, module, name, cb);
|
||||
}
|
||||
|
||||
void func_add_arg(mgp_func *func, const char *name, mgp_type *type) {
|
||||
inline void func_add_arg(mgp_func *func, const char *name, mgp_type *type) {
|
||||
MgInvokeVoid(mgp_func_add_arg, func, name, type);
|
||||
}
|
||||
|
||||
void func_add_opt_arg(mgp_func *func, const char *name, mgp_type *type, mgp_value *default_value) {
|
||||
inline void func_add_opt_arg(mgp_func *func, const char *name, mgp_type *type, mgp_value *default_value) {
|
||||
MgInvokeVoid(mgp_func_add_opt_arg, func, name, type, default_value);
|
||||
}
|
||||
|
||||
void func_result_set_error_msg(mgp_func_result *res, const char *msg, mgp_memory *memory) {
|
||||
inline void func_result_set_error_msg(mgp_func_result *res, const char *msg, mgp_memory *memory) {
|
||||
MgInvokeVoid(mgp_func_result_set_error_msg, res, msg, memory);
|
||||
}
|
||||
|
||||
void func_result_set_value(mgp_func_result *res, mgp_value *value, mgp_memory *memory) {
|
||||
inline void func_result_set_value(mgp_func_result *res, mgp_value *value, mgp_memory *memory) {
|
||||
MgInvokeVoid(mgp_func_result_set_value, res, value, memory);
|
||||
}
|
||||
|
||||
|
||||
343
include/_mgp_mock.py
Normal file
343
include/_mgp_mock.py
Normal file
@@ -0,0 +1,343 @@
|
||||
import typing
|
||||
from enum import Enum
|
||||
|
||||
import networkx as nx
|
||||
|
||||
NX_LABEL_ATTR = "labels"
|
||||
NX_TYPE_ATTR = "type"
|
||||
|
||||
SOURCE_TYPE_KAFKA = "SOURCE_TYPE_KAFKA"
|
||||
SOURCE_TYPE_PULSAR = "SOURCE_TYPE_PULSAR"
|
||||
|
||||
"""
|
||||
This module provides helpers for the mock Python API, much like _mgp.py does for mgp.py.
|
||||
"""
|
||||
|
||||
|
||||
class InvalidArgumentError(Exception):
|
||||
"""
|
||||
Signals that some of the arguments have invalid values.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class ImmutableObjectError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class LogicErrorError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class DeletedObjectError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class EdgeConstants(Enum):
|
||||
I_START = 0
|
||||
I_END = 1
|
||||
I_KEY = 2
|
||||
|
||||
|
||||
class Graph:
|
||||
"""Wrapper around a NetworkX MultiDiGraph instance."""
|
||||
|
||||
__slots__ = ("nx", "_highest_vertex_id", "_highest_edge_id", "_valid")
|
||||
|
||||
def __init__(self, graph: nx.MultiDiGraph) -> None:
|
||||
if not isinstance(graph, nx.MultiDiGraph):
|
||||
raise TypeError(f"Expected 'networkx.classes.multidigraph.MultiDiGraph', got '{type(graph)}'")
|
||||
|
||||
self.nx = graph
|
||||
self._highest_vertex_id = None
|
||||
self._highest_edge_id = None
|
||||
self._valid = True
|
||||
|
||||
@property
|
||||
def vertex_ids(self):
|
||||
return self.nx.nodes
|
||||
|
||||
def vertex_is_isolate(self, vertex_id: int) -> bool:
|
||||
return nx.is_isolate(self.nx, vertex_id)
|
||||
|
||||
@property
|
||||
def vertices(self):
|
||||
return (Vertex(node_id, self) for node_id in self.nx.nodes)
|
||||
|
||||
def has_node(self, node_id):
|
||||
return self.nx.has_node(node_id)
|
||||
|
||||
@property
|
||||
def edges(self):
|
||||
return self.nx.edges
|
||||
|
||||
def is_valid(self) -> bool:
|
||||
return self._valid
|
||||
|
||||
def get_vertex_by_id(self, vertex_id: int) -> "Vertex":
|
||||
return Vertex(vertex_id, self)
|
||||
|
||||
def invalidate(self):
|
||||
self._valid = False
|
||||
|
||||
def is_immutable(self) -> bool:
|
||||
return nx.is_frozen(self.nx)
|
||||
|
||||
def make_immutable(self):
|
||||
self.nx = nx.freeze(self.nx)
|
||||
|
||||
def _new_vertex_id(self):
|
||||
if self._highest_vertex_id is None:
|
||||
self._highest_vertex_id = max(vertex_id for vertex_id in self.nx.nodes)
|
||||
|
||||
return self._highest_vertex_id + 1
|
||||
|
||||
def _new_edge_id(self):
|
||||
if self._highest_edge_id is None:
|
||||
self._highest_edge_id = max(edge[EdgeConstants.I_KEY.value] for edge in self.nx.edges(keys=True))
|
||||
|
||||
return self._highest_edge_id + 1
|
||||
|
||||
def create_vertex(self) -> "Vertex":
|
||||
vertex_id = self._new_vertex_id()
|
||||
|
||||
self.nx.add_node(vertex_id)
|
||||
self._highest_vertex_id = vertex_id
|
||||
|
||||
return Vertex(vertex_id, self)
|
||||
|
||||
def create_edge(self, from_vertex: "Vertex", to_vertex: "Vertex", edge_type: str) -> "Edge":
|
||||
if from_vertex.is_deleted() or to_vertex.is_deleted():
|
||||
raise DeletedObjectError("Accessing deleted object.")
|
||||
|
||||
edge_id = self._new_edge_id()
|
||||
|
||||
from_id = from_vertex.id
|
||||
to_id = to_vertex.id
|
||||
|
||||
self.nx.add_edge(from_id, to_id, key=edge_id, type=edge_type)
|
||||
self._highest_edge_id = edge_id
|
||||
|
||||
return Edge((from_id, to_id, edge_id), self)
|
||||
|
||||
def delete_vertex(self, vertex_id: int):
|
||||
self.nx.remove_node(vertex_id)
|
||||
|
||||
def delete_edge(self, from_vertex_id: int, to_vertex_id: int, edge_id: int):
|
||||
self.nx.remove_edge(from_vertex_id, to_vertex_id, edge_id)
|
||||
|
||||
@property
|
||||
def highest_vertex_id(self) -> int:
|
||||
if self._highest_vertex_id is None:
|
||||
self._highest_vertex_id = max(vertex_id for vertex_id in self.nx.nodes) + 1
|
||||
|
||||
return self._highest_vertex_id
|
||||
|
||||
@property
|
||||
def highest_edge_id(self) -> int:
|
||||
if self._highest_edge_id is None:
|
||||
self._highest_edge_id = max(edge[EdgeConstants.I_KEY.value] for edge in self.nx.edges(keys=True))
|
||||
|
||||
return self._highest_edge_id + 1
|
||||
|
||||
|
||||
class Vertex:
|
||||
"""Represents a graph vertex."""
|
||||
|
||||
__slots__ = ("_id", "_graph")
|
||||
|
||||
def __init__(self, id: int, graph: Graph) -> None:
|
||||
if not isinstance(id, int):
|
||||
raise TypeError(f"Expected 'int', got '{type(id)}'")
|
||||
|
||||
if not isinstance(graph, Graph):
|
||||
raise TypeError(f"Expected '_mgp_mock.Graph', got '{type(graph)}'")
|
||||
|
||||
if not graph.nx.has_node(id):
|
||||
raise IndexError(f"Unable to find vertex with ID {id}.")
|
||||
|
||||
self._id = id
|
||||
self._graph = graph
|
||||
|
||||
def is_valid(self) -> bool:
|
||||
return self._graph.is_valid()
|
||||
|
||||
def is_deleted(self) -> bool:
|
||||
return not self._graph.nx.has_node(self._id) and self._id <= self._graph.highest_vertex_id
|
||||
|
||||
@property
|
||||
def underlying_graph(self) -> Graph:
|
||||
return self._graph
|
||||
|
||||
def underlying_graph_is_mutable(self) -> bool:
|
||||
return not nx.is_frozen(self._graph.nx)
|
||||
|
||||
@property
|
||||
def labels(self) -> typing.List[int]:
|
||||
return self._graph.nx.nodes[self._id][NX_LABEL_ATTR].split(":")
|
||||
|
||||
def add_label(self, label: str) -> None:
|
||||
if nx.is_frozen(self._graph.nx):
|
||||
raise ImmutableObjectError("Cannot modify immutable object.")
|
||||
|
||||
self._graph.nx.nodes[self._id][NX_LABEL_ATTR] += f":{label}"
|
||||
|
||||
def remove_label(self, label: str) -> None:
|
||||
if nx.is_frozen(self._graph.nx):
|
||||
raise ImmutableObjectError("Cannot modify immutable object.")
|
||||
|
||||
labels = self._graph.nx.nodes[self._id][NX_LABEL_ATTR]
|
||||
if labels.startswith(f"{label}:"):
|
||||
labels = "\n" + labels # pseudo-string starter
|
||||
self._graph.nx.nodes[self._id][NX_LABEL_ATTR] = labels.replace(f"\n{label}:", "")
|
||||
elif labels.endswith(f":{label}"):
|
||||
labels += "\n" # pseudo-string terminator
|
||||
self._graph.nx.nodes[self._id][NX_LABEL_ATTR] = labels.replace(f":{label}\n", "")
|
||||
else:
|
||||
self._graph.nx.nodes[self._id][NX_LABEL_ATTR] = labels.replace(f":{label}:", ":")
|
||||
|
||||
@property
|
||||
def id(self) -> int:
|
||||
return self._id
|
||||
|
||||
@property
|
||||
def properties(self):
|
||||
return (
|
||||
(key, value)
|
||||
for key, value in self._graph.nx.nodes[self._id].items()
|
||||
if key not in (NX_LABEL_ATTR, NX_TYPE_ATTR)
|
||||
)
|
||||
|
||||
def get_property(self, property_name: str):
|
||||
return self._graph.nx.nodes[self._id][property_name]
|
||||
|
||||
def set_property(self, property_name: str, value: object):
|
||||
self._graph.nx.nodes[self._id][property_name] = value
|
||||
|
||||
@property
|
||||
def in_edges(self) -> typing.Iterable["Edge"]:
|
||||
return [Edge(edge, self._graph) for edge in self._graph.nx.in_edges(self._id, keys=True)]
|
||||
|
||||
@property
|
||||
def out_edges(self) -> typing.Iterable["Edge"]:
|
||||
return [Edge(edge, self._graph) for edge in self._graph.nx.out_edges(self._id, keys=True)]
|
||||
|
||||
|
||||
class Edge:
|
||||
"""Represents a graph edge."""
|
||||
|
||||
__slots__ = ("_edge", "_graph")
|
||||
|
||||
def __init__(self, edge: typing.Tuple[int, int, int], graph: Graph) -> None:
|
||||
if not isinstance(edge, typing.Tuple):
|
||||
raise TypeError(f"Expected 'Tuple', got '{type(edge)}'")
|
||||
|
||||
if not isinstance(graph, Graph):
|
||||
raise TypeError(f"Expected '_mgp_mock.Graph', got '{type(graph)}'")
|
||||
|
||||
if not graph.nx.has_edge(*edge):
|
||||
raise IndexError(f"Unable to find edge with ID {edge[EdgeConstants.I_KEY.value]}.")
|
||||
|
||||
self._edge = edge
|
||||
self._graph = graph
|
||||
|
||||
def is_valid(self) -> bool:
|
||||
return self._graph.is_valid()
|
||||
|
||||
def is_deleted(self) -> bool:
|
||||
return (
|
||||
not self._graph.nx.has_edge(*self._edge)
|
||||
and self._edge[EdgeConstants.I_KEY.value] <= self._graph.highest_edge_id
|
||||
)
|
||||
|
||||
def underlying_graph_is_mutable(self) -> bool:
|
||||
return not nx.is_frozen(self._graph.nx)
|
||||
|
||||
@property
|
||||
def id(self) -> int:
|
||||
return self._edge[EdgeConstants.I_KEY.value]
|
||||
|
||||
@property
|
||||
def edge(self) -> typing.Tuple[int, int, int]:
|
||||
return self._edge
|
||||
|
||||
@property
|
||||
def start_id(self) -> int:
|
||||
return self._edge[EdgeConstants.I_START.value]
|
||||
|
||||
@property
|
||||
def end_id(self) -> int:
|
||||
return self._edge[EdgeConstants.I_END.value]
|
||||
|
||||
def get_type_name(self):
|
||||
return self._graph.nx.get_edge_data(*self._edge)[NX_TYPE_ATTR]
|
||||
|
||||
def from_vertex(self) -> Vertex:
|
||||
return Vertex(self.start_id, self._graph)
|
||||
|
||||
def to_vertex(self) -> Vertex:
|
||||
return Vertex(self.end_id, self._graph)
|
||||
|
||||
@property
|
||||
def properties(self):
|
||||
return (
|
||||
(key, value)
|
||||
for key, value in self._graph.nx.edges[self._edge].items()
|
||||
if key not in (NX_LABEL_ATTR, NX_TYPE_ATTR)
|
||||
)
|
||||
|
||||
def get_property(self, property_name: str):
|
||||
return self._graph.nx.edges[self._edge][property_name]
|
||||
|
||||
def set_property(self, property_name: str, value: object):
|
||||
self._graph.nx.edges[self._edge][property_name] = value
|
||||
|
||||
|
||||
class Path:
|
||||
"""Represents a path comprised of `Vertex` and `Edge` instances."""
|
||||
|
||||
__slots__ = ("_vertices", "_edges", "_graph")
|
||||
__create_key = object()
|
||||
|
||||
def __init__(self, create_key, vertex_id: int, graph: Graph) -> None:
|
||||
assert create_key == Path.__create_key, "Path objects must be created using Path.make_with_start"
|
||||
|
||||
self._vertices = [vertex_id]
|
||||
self._edges = []
|
||||
self._graph = graph
|
||||
|
||||
@classmethod
|
||||
def make_with_start(cls, vertex: Vertex) -> "Path":
|
||||
if not isinstance(vertex, Vertex):
|
||||
raise TypeError(f"Expected 'Vertex', got '{type(vertex)}'")
|
||||
|
||||
if not isinstance(vertex.underlying_graph, Graph):
|
||||
raise TypeError(f"Expected '_mgp_mock.Graph', got '{type(vertex.underlying_graph)}'")
|
||||
|
||||
if not vertex.underlying_graph.nx.has_node(vertex._id):
|
||||
raise IndexError(f"Unable to find vertex with ID {vertex._id}.")
|
||||
|
||||
return Path(cls.__create_key, vertex._id, vertex.underlying_graph)
|
||||
|
||||
def is_valid(self) -> bool:
|
||||
return self._graph.is_valid()
|
||||
|
||||
def underlying_graph_is_mutable(self) -> bool:
|
||||
return not nx.is_frozen(self._graph.nx)
|
||||
|
||||
def expand(self, edge: Edge):
|
||||
if edge.start_id != self._vertices[-1]:
|
||||
raise LogicErrorError("Logic error.")
|
||||
|
||||
self._vertices.append(edge.end_id)
|
||||
self._edges.append((edge.start_id, edge.end_id, edge.id))
|
||||
|
||||
def vertex_at(self, index: int) -> Vertex:
|
||||
return Vertex(self._vertices[index], self._graph)
|
||||
|
||||
def edge_at(self, index: int) -> Edge:
|
||||
return Edge(self._edges[index], self._graph)
|
||||
|
||||
def size(self) -> int:
|
||||
return len(self._edges)
|
||||
1911
include/mgp.hpp
1911
include/mgp.hpp
File diff suppressed because it is too large
Load Diff
@@ -1283,7 +1283,7 @@ class Graph:
|
||||
raise InvalidContextError()
|
||||
self._graph.detach_delete_vertex(vertex._vertex)
|
||||
|
||||
def create_edge(self, from_vertex: Vertex, to_vertex: Vertex, edge_type: EdgeType) -> None:
|
||||
def create_edge(self, from_vertex: Vertex, to_vertex: Vertex, edge_type: EdgeType) -> Edge:
|
||||
"""
|
||||
Create an edge.
|
||||
|
||||
@@ -1292,13 +1292,16 @@ class Graph:
|
||||
to_vertex: `Vertex' to where edge is directed.
|
||||
edge_type: `EdgeType` defines the type of edge.
|
||||
|
||||
Returns:
|
||||
Created `Edge`.
|
||||
|
||||
Raises:
|
||||
ImmutableObjectError: If `graph` is immutable.
|
||||
UnableToAllocateError: If unable to allocate an edge.
|
||||
DeletedObjectError: If `from_vertex` or `to_vertex` has been deleted.
|
||||
SerializationError: If `from_vertex` or `to_vertex` has been modified by another transaction.
|
||||
Examples:
|
||||
```graph.create_edge(from_vertex, vertex, edge_type)```
|
||||
```edge = graph.create_edge(from_vertex, vertex, edge_type)```
|
||||
"""
|
||||
if not self.is_valid():
|
||||
raise InvalidContextError()
|
||||
|
||||
1655
include/mgp_mock.py
Normal file
1655
include/mgp_mock.py
Normal file
File diff suppressed because it is too large
Load Diff
73
init
73
init
@@ -5,13 +5,15 @@ cd "$DIR"
|
||||
|
||||
source "$DIR/environment/util.sh"
|
||||
|
||||
DISTRO=$(operating_system)
|
||||
ARCHITECTURE=$(architecture)
|
||||
|
||||
function print_help () {
|
||||
echo "Usage: $0 [OPTION]"
|
||||
echo -e "Check for missing packages and setup the project.\n"
|
||||
echo "Optional arguments:"
|
||||
echo -e " -h\tdisplay this help and exit"
|
||||
echo -e " --without-libs-setup\tskip the step for setting up libs"
|
||||
echo -e " --wsl-quicklisp-proxy \"host:port\"\tquicklist HTTP proxy (this flag + HTTP proxy are required on WSL)"
|
||||
}
|
||||
|
||||
function setup_virtualenv () {
|
||||
@@ -32,7 +34,6 @@ function setup_virtualenv () {
|
||||
popd > /dev/null
|
||||
}
|
||||
|
||||
wsl_quicklisp_proxy=""
|
||||
setup_libs=true
|
||||
if [[ $# -eq 1 && "$1" == "-h" ]]; then
|
||||
print_help
|
||||
@@ -40,16 +41,6 @@ if [[ $# -eq 1 && "$1" == "-h" ]]; then
|
||||
else
|
||||
while(($#)); do
|
||||
case "$1" in
|
||||
--wsl-quicklisp-proxy)
|
||||
shift
|
||||
if [[ $# -eq 0 ]]; then
|
||||
echo "Missing proxy URL"
|
||||
print_help
|
||||
exit 1
|
||||
fi
|
||||
wsl_quicklisp_proxy=":proxy \"http://$1/\""
|
||||
shift
|
||||
;;
|
||||
--without-libs-setup)
|
||||
shift
|
||||
setup_libs=false
|
||||
@@ -64,8 +55,6 @@ else
|
||||
done
|
||||
fi
|
||||
|
||||
DISTRO=$(operating_system)
|
||||
ARCHITECTURE=$(architecture)
|
||||
if [ "${ARCHITECTURE}" = "arm64" ] || [ "${ARCHITECTURE}" = "aarch64" ]; then
|
||||
OS_SCRIPT=$DIR/environment/os/$DISTRO-arm.sh
|
||||
else
|
||||
@@ -78,37 +67,18 @@ echo "All packages are in-place..."
|
||||
# create a default build directory
|
||||
mkdir -p ./build
|
||||
|
||||
# quicklisp package manager for Common Lisp
|
||||
quicklisp_install_dir="$HOME/quicklisp"
|
||||
if [[ -v QUICKLISP_HOME ]]; then
|
||||
quicklisp_install_dir="${QUICKLISP_HOME}"
|
||||
fi
|
||||
|
||||
if [[ ! -f "${quicklisp_install_dir}/setup.lisp" ]]; then
|
||||
wget -nv https://beta.quicklisp.org/quicklisp.lisp -O quicklisp.lisp || exit 1
|
||||
echo \
|
||||
"
|
||||
(load \"${DIR}/quicklisp.lisp\")
|
||||
(quicklisp-quickstart:install $wsl_quicklisp_proxy :path \"${quicklisp_install_dir}\")
|
||||
" | sbcl --script || exit 1
|
||||
rm -rf quicklisp.lisp || exit 1
|
||||
fi
|
||||
ln -Tfs "$DIR/src/lisp" "${quicklisp_install_dir}/local-projects/lcp"
|
||||
# Install LCP dependencies
|
||||
# TODO: We should at some point cache or have a mirror of packages we use.
|
||||
# TODO: move the installation of LCP's dependencies into ./setup.sh
|
||||
echo \
|
||||
"
|
||||
(load \"${quicklisp_install_dir}/setup.lisp\")
|
||||
(ql:quickload '(:lcp :lcp/test) :silent t)
|
||||
" | sbcl --script
|
||||
|
||||
if [[ "$setup_libs" == "true" ]]; then
|
||||
# Setup libs (download).
|
||||
cd libs
|
||||
./cleanup.sh
|
||||
./setup.sh
|
||||
cd ..
|
||||
# Setup libs (download).
|
||||
cd libs
|
||||
./cleanup.sh
|
||||
./setup.sh
|
||||
cd ..
|
||||
fi
|
||||
|
||||
# Fix for centos 7 during release
|
||||
if [ "${DISTRO}" = "centos-7" ] || [ "${DISTRO}" = "debian-11" ] || [ "${DISTRO}" = "amzn-2" ]; then
|
||||
python3 -m pip uninstall -y virtualenv
|
||||
python3 -m pip install virtualenv
|
||||
fi
|
||||
|
||||
# setup gql_behave dependencies
|
||||
@@ -136,9 +106,18 @@ for hook in $(find $DIR/.githooks -type f -printf "%f\n"); do
|
||||
echo "Added $hook hook"
|
||||
done;
|
||||
|
||||
# Install precommit hook
|
||||
python3 -m pip install pre-commit
|
||||
python3 -m pre_commit install
|
||||
# Install precommit hook except on old operating systems because we don't
|
||||
# develop on them -> pre-commit hook not required -> we can use latest
|
||||
# packages.
|
||||
if [ "${DISTRO}" != "centos-7" ] && [ "$DISTRO" != "debian-10" ] && [ "${DISTRO}" != "ubuntu-18.04" ] && [ "${DISTRO}" != "amzn-2" ]; then
|
||||
python3 -m pip install pre-commit
|
||||
python3 -m pre_commit install
|
||||
# Install py format tools for usage during the development.
|
||||
echo "Install black formatter"
|
||||
python3 -m pip install black==23.1.*
|
||||
echo "Install isort"
|
||||
python3 -m pip install isort==5.12.*
|
||||
fi
|
||||
|
||||
# Link `include/mgp.py` with `release/mgp/mgp.py`
|
||||
ln -v -f include/mgp.py release/mgp/mgp.py
|
||||
|
||||
@@ -117,7 +117,7 @@ declare -A primary_urls=(
|
||||
["mgconsole"]="http://$local_cache_host/git/mgconsole.git"
|
||||
["spdlog"]="http://$local_cache_host/git/spdlog"
|
||||
["nlohmann"]="http://$local_cache_host/file/nlohmann/json/4f8fba14066156b73f1189a2b8bd568bde5284c5/single_include/nlohmann/json.hpp"
|
||||
["neo4j"]="http://$local_cache_host/file/neo4j-community-3.2.3-unix.tar.gz"
|
||||
["neo4j"]="http://$local_cache_host/file/neo4j-community-5.6.0-unix.tar.gz"
|
||||
["librdkafka"]="http://$local_cache_host/git/librdkafka.git"
|
||||
["protobuf"]="http://$local_cache_host/git/protobuf.git"
|
||||
["pulsar"]="http://$local_cache_host/git/pulsar.git"
|
||||
@@ -142,7 +142,7 @@ declare -A secondary_urls=(
|
||||
["mgconsole"]="http://github.com/memgraph/mgconsole.git"
|
||||
["spdlog"]="https://github.com/gabime/spdlog"
|
||||
["nlohmann"]="https://raw.githubusercontent.com/nlohmann/json/4f8fba14066156b73f1189a2b8bd568bde5284c5/single_include/nlohmann/json.hpp"
|
||||
["neo4j"]="https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/neo4j-community-3.2.3-unix.tar.gz"
|
||||
["neo4j"]="https://dist.neo4j.org/neo4j-community-5.6.0-unix.tar.gz"
|
||||
["librdkafka"]="https://github.com/edenhill/librdkafka.git"
|
||||
["protobuf"]="https://github.com/protocolbuffers/protobuf.git"
|
||||
["pulsar"]="https://github.com/apache/pulsar.git"
|
||||
@@ -180,9 +180,9 @@ repo_clone_try_double "${primary_urls[libbcrypt]}" "${secondary_urls[libbcrypt]}
|
||||
|
||||
# neo4j
|
||||
file_get_try_double "${primary_urls[neo4j]}" "${secondary_urls[neo4j]}"
|
||||
tar -xzf neo4j-community-3.2.3-unix.tar.gz
|
||||
mv neo4j-community-3.2.3 neo4j
|
||||
rm neo4j-community-3.2.3-unix.tar.gz
|
||||
tar -xzf neo4j-community-5.6.0-unix.tar.gz
|
||||
mv neo4j-community-5.6.0 neo4j
|
||||
rm neo4j-community-5.6.0-unix.tar.gz
|
||||
|
||||
# nlohmann json
|
||||
# We wget header instead of cloning repo since repo is huge (lots of test data).
|
||||
@@ -208,7 +208,7 @@ pymgclient_tag="4f85c179e56302d46a1e3e2cf43509db65f062b3" # (2021-01-15)
|
||||
repo_clone_try_double "${primary_urls[pymgclient]}" "${secondary_urls[pymgclient]}" "pymgclient" "$pymgclient_tag"
|
||||
|
||||
# mgconsole
|
||||
mgconsole_tag="v1.1.0" # (2021-10-07)
|
||||
mgconsole_tag="v1.3.0" # (2022-11-20)
|
||||
repo_clone_try_double "${primary_urls[mgconsole]}" "${secondary_urls[mgconsole]}" "mgconsole" "$mgconsole_tag" true
|
||||
|
||||
spdlog_tag="v1.9.2" # (2021-08-12)
|
||||
|
||||
@@ -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: 2026-20-09
|
||||
CHANGE DATE: 2027-18-05
|
||||
CHANGE LICENSE: Apache License, Version 2.0
|
||||
|
||||
For information about alternative licensing arrangements, please visit: https://memgraph.com/legal.
|
||||
|
||||
@@ -2,8 +2,8 @@ MEMGRAPH
|
||||
ENTERPRISE LICENCE AGREEMENT
|
||||
|
||||
|
||||
Memgraph Limited is registered in England under registration 10195084 and has its registered office at Suite 4,
|
||||
Ironstone House, Ironstone Way, Brixworth, Northampton, NN6 9UD (“Memgraph”).
|
||||
Memgraph Limited is registered in England under registration 10195084 and has its registered office at 90a High Street,
|
||||
Hertfordshire, Berkhamsted, HP4 2BL United Kingdom ("Memgraph").
|
||||
|
||||
|
||||
Memgraph agrees to license and/or grant you (the “Customer”) access to the Software ( as defined below) and provide
|
||||
|
||||
202
licenses/third-party/ldbc/LICENSE
vendored
Normal file
202
licenses/third-party/ldbc/LICENSE
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
12
pyproject.toml
Normal file
12
pyproject.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
[tool.black]
|
||||
line-length = 120
|
||||
include = '\.pyi?$'
|
||||
extend-exclude = '''
|
||||
/(
|
||||
| .git
|
||||
| .__pycache__
|
||||
| build
|
||||
| libs
|
||||
| .cache
|
||||
)/
|
||||
'''
|
||||
@@ -69,7 +69,7 @@ extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *mem
|
||||
try {
|
||||
mgp::memory = memory;
|
||||
|
||||
AddProcedure(SampleReadProc, "return_true", mgp::ProdecureType::Read,
|
||||
AddProcedure(SampleReadProc, "return_true", mgp::ProcedureType::Read,
|
||||
{mgp::Parameter("param_1", mgp::Type::Int), mgp::Parameter("param_2", mgp::Type::Double, 2.3)},
|
||||
{mgp::Return("out", mgp::Type::Bool)}, module, memory);
|
||||
} catch (const std::exception &e) {
|
||||
@@ -79,7 +79,7 @@ extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *mem
|
||||
try {
|
||||
mgp::memory = memory;
|
||||
|
||||
mgp::AddProcedure(AddXNodes, "add_x_nodes", mgp::ProdecureType::Write, {mgp::Parameter("param_1", mgp::Type::Int)},
|
||||
mgp::AddProcedure(AddXNodes, "add_x_nodes", mgp::ProcedureType::Write, {mgp::Parameter("param_1", mgp::Type::Int)},
|
||||
{}, module, memory);
|
||||
|
||||
} catch (const std::exception &e) {
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
# Install systemd service (must use absolute path).
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/memgraph.service
|
||||
DESTINATION /lib/systemd/system)
|
||||
DESTINATION /lib/systemd/system)
|
||||
|
||||
# Set parameters to recognize the host distro
|
||||
cmake_host_system_information(RESULT DISTRO QUERY DISTRIB_NAME)
|
||||
cmake_host_system_information(RESULT DISTRO_VERSION QUERY DISTRIB_VERSION)
|
||||
|
||||
# ---- Setup CPack --------
|
||||
|
||||
@@ -12,10 +16,11 @@ set(CPACK_PACKAGE_DESCRIPTION_SUMMARY
|
||||
|
||||
# Setting arhitecture extension for deb packages
|
||||
set(MG_ARCH_EXTENSION_DEB "all")
|
||||
if (${MG_ARCH} STREQUAL "x86_64")
|
||||
|
||||
if(${MG_ARCH} STREQUAL "x86_64")
|
||||
set(MG_ARCH_EXTENSION_DEB "amd64")
|
||||
elseif (${MG_ARCH} STREQUAL "ARM64")
|
||||
set(MG_ARCH_EXTENSION_DEB "arm64")
|
||||
elseif(${MG_ARCH} STREQUAL "ARM64")
|
||||
set(MG_ARCH_EXTENSION_DEB "arm64")
|
||||
endif()
|
||||
|
||||
# DEB specific
|
||||
@@ -34,21 +39,24 @@ set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/debian/postrm;"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/debian/postinst;")
|
||||
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
|
||||
|
||||
# Description formatting is important, summary must be followed with a newline and 1 space.
|
||||
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "${CPACK_PACKAGE_DESCRIPTION_SUMMARY}
|
||||
Contains Memgraph, the graph database. It aims to deliver developers the
|
||||
speed, simplicity and scale required to build the next generation of
|
||||
applications driver by real-time connected data.")
|
||||
|
||||
# Add `openssl` package to dependencies list. Used to generate SSL certificates.
|
||||
# We also depend on `python3` because we embed it in Memgraph.
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "openssl (>= 1.1.0), python3 (>= 3.5.0), libstdc++6")
|
||||
|
||||
# Setting arhitecture extension for rpm packages
|
||||
set(MG_ARCH_EXTENSION_RPM "noarch")
|
||||
if (${MG_ARCH} STREQUAL "x86_64")
|
||||
|
||||
if(${MG_ARCH} STREQUAL "x86_64")
|
||||
set(MG_ARCH_EXTENSION_RPM "x86_64")
|
||||
elseif (${MG_ARCH} STREQUAL "ARM64")
|
||||
set(MG_ARCH_EXTENSION_RPM "aarch64")
|
||||
elseif(${MG_ARCH} STREQUAL "ARM64")
|
||||
set(MG_ARCH_EXTENSION_RPM "aarch64")
|
||||
endif()
|
||||
|
||||
# RPM specific
|
||||
@@ -56,18 +64,26 @@ set(CPACK_RPM_PACKAGE_URL https://memgraph.com)
|
||||
set(CPACK_RPM_PACKAGE_VERSION "${MEMGRAPH_VERSION_RPM}")
|
||||
set(CPACK_RPM_FILE_NAME "memgraph-${MEMGRAPH_VERSION_RPM}-1.${MG_ARCH_EXTENSION_RPM}.rpm")
|
||||
set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION
|
||||
/var /var/lib /var/log /etc/logrotate.d
|
||||
/lib /lib/systemd /lib/systemd/system /lib/systemd/system/memgraph.service)
|
||||
/var /var/lib /var/log /etc/logrotate.d
|
||||
/lib /lib/systemd /lib/systemd/system /lib/systemd/system/memgraph.service)
|
||||
set(CPACK_RPM_PACKAGE_REQUIRES_PRE "shadow-utils")
|
||||
set(CPACK_RPM_USER_BINARY_SPECFILE "${CMAKE_CURRENT_SOURCE_DIR}/rpm/memgraph.spec.in")
|
||||
set(CPACK_RPM_PACKAGE_LICENSE "Memgraph License")
|
||||
|
||||
# Description formatting is important, no line must be greater than 80 characters.
|
||||
set(CPACK_RPM_PACKAGE_DESCRIPTION "Contains Memgraph, the graph database.
|
||||
It aims to deliver developers the speed, simplicity and scale required to build
|
||||
the next generation of applications driver by real-time connected data.")
|
||||
|
||||
# Add `openssl` package to dependencies list. Used to generate SSL certificates.
|
||||
# We also depend on `python3` because we embed it in Memgraph.
|
||||
set(CPACK_RPM_PACKAGE_REQUIRES "openssl >= 1.0.0, curl >= 7.29.0, python3 >= 3.5.0, libstdc >= 6, logrotate")
|
||||
set(CPACK_RPM_PACKAGE_REQUIRES "openssl >= 1.0.0, curl >= 7.29.0, python3 >= 3.5.0, libstdc++ >= 3.4.29, logrotate")
|
||||
|
||||
# If amzn-2
|
||||
if(DISTRO STREQUAL "Amazon Linux" AND DISTRO_VERSION STREQUAL "2")
|
||||
# It causes issues with glibcxx 2.4
|
||||
set(CPACK_RPM_PACKAGE_AUTOREQ " no")
|
||||
endif()
|
||||
|
||||
# All variables must be set before including.
|
||||
include(CPack)
|
||||
|
||||
1
release/mgp/.gitignore
vendored
1
release/mgp/.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
.venv
|
||||
dist
|
||||
mgp.py
|
||||
poetry.lock
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
# mgp
|
||||
|
||||
PyPi package used for type hinting when creating MAGE modules. The get started
|
||||
using MAGE repository checkout the repository here: https://github.com/memgraph/mage.
|
||||
PyPi package used for type hinting when creating query modules. Repository of already available query modules is called [MAGE](https://github.com/memgraph/mage).
|
||||
|
||||
## 🎬 Get started
|
||||
|
||||
To learn more, head over to the [docs for the query modules Python API](https://memgraph.com/docs/memgraph/reference-guide/query-modules/api/python-api). To get started with query modules, check out the [how-to guide](https://memgraph.com/docs/memgraph/how-to-guides/query-modules) on Memgraph docs.
|
||||
|
||||
## 🔢 Versioning
|
||||
|
||||
- mgp v1.1 is compatible with Memgraph >= 2.4.0
|
||||
|
||||
@@ -257,3 +257,11 @@ class _MODULE:
|
||||
@staticmethod
|
||||
def add_function(wrapper):
|
||||
pass
|
||||
|
||||
|
||||
class SOURCE_TYPE_KAFKA:
|
||||
pass
|
||||
|
||||
|
||||
class SOURCE_TYPE_PULSAR:
|
||||
pass
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
[tool.poetry]
|
||||
name = "mgp"
|
||||
version = "1.0.0"
|
||||
version = "1.1.1"
|
||||
description = "Memgraph's module for developing MAGE modules. Used only for type hinting!"
|
||||
authors = [
|
||||
"MasterMedo <mislav.vuletic@gmail.com>",
|
||||
"jbajic <jure.bajic@memgraph.io>",
|
||||
"katarinasupe <katarina.supe@memgraph.io>",
|
||||
"jbajic <jure.bajic@memgraph.io>",
|
||||
"antejavor <ante.javor@memgraph.io>",
|
||||
"antaljanosbenjamin <benjamin.antal@memgraph.io>",
|
||||
"MasterMedo <mislav.vuletic@gmail.com>",
|
||||
]
|
||||
license = "Apache-2.0"
|
||||
readme = "README.md"
|
||||
|
||||
14
release/package/amzn-2/Dockerfile
Normal file
14
release/package/amzn-2/Dockerfile
Normal file
@@ -0,0 +1,14 @@
|
||||
FROM amazonlinux:2
|
||||
|
||||
ARG TOOLCHAIN_VERSION
|
||||
|
||||
RUN yum -y update \
|
||||
&& yum install -y wget git tar
|
||||
# Do NOT be smart here and clean the cache because the container is used in the
|
||||
# stateful context.
|
||||
|
||||
RUN wget -q https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/${TOOLCHAIN_VERSION}/${TOOLCHAIN_VERSION}-binaries-amzn-2-x86_64.tar.gz \
|
||||
-O ${TOOLCHAIN_VERSION}-binaries-amzn-2-x86_64.tar.gz \
|
||||
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-amzn-2-x86_64.tar.gz -C /opt
|
||||
|
||||
ENTRYPOINT ["sleep", "infinity"]
|
||||
11
release/package/arm-builders.yml
Normal file
11
release/package/arm-builders.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
debian-11-arm:
|
||||
build:
|
||||
context: debian-11-arm
|
||||
container_name: "mgbuild_debian-11-arm"
|
||||
ubuntu-2204-arm:
|
||||
build:
|
||||
context: ubuntu-22.04-arm
|
||||
container_name: "mgbuild_ubuntu-22.04-arm"
|
||||
@@ -28,3 +28,11 @@ services:
|
||||
build:
|
||||
context: ubuntu-22.04
|
||||
container_name: "mgbuild_ubuntu-22.04"
|
||||
mgbuild_fedora-36:
|
||||
build:
|
||||
context: fedora-36
|
||||
container_name: "mgbuild_fedora-36"
|
||||
mgbuild_amzn-2:
|
||||
build:
|
||||
context: amzn-2
|
||||
container_name: "mgbuild_amzn-2"
|
||||
|
||||
15
release/package/fedora-36/Dockerfile
Normal file
15
release/package/fedora-36/Dockerfile
Normal file
@@ -0,0 +1,15 @@
|
||||
FROM fedora:36
|
||||
|
||||
ARG TOOLCHAIN_VERSION
|
||||
|
||||
# Stops tzdata interactive configuration.
|
||||
RUN yum -y update \
|
||||
&& yum install -y wget git
|
||||
# Do NOT be smart here and clean the cache because the container is used in the
|
||||
# stateful context.
|
||||
|
||||
RUN wget -q https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/${TOOLCHAIN_VERSION}/${TOOLCHAIN_VERSION}-binaries-fedora-36-x86_64.tar.gz \
|
||||
-O ${TOOLCHAIN_VERSION}-binaries-fedora-36-x86_64.tar.gz \
|
||||
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-fedora-36-x86_64.tar.gz -C /opt
|
||||
|
||||
ENTRYPOINT ["sleep", "infinity"]
|
||||
@@ -3,7 +3,14 @@
|
||||
set -Eeuo pipefail
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
SUPPORTED_OS=(centos-7 centos-9 debian-10 debian-11 ubuntu-18.04 ubuntu-20.04 ubuntu-22.04 debian-11-arm)
|
||||
SUPPORTED_OS=(
|
||||
centos-7 centos-9
|
||||
debian-10 debian-11 debian-11-arm
|
||||
ubuntu-18.04 ubuntu-20.04 ubuntu-22.04 ubuntu-22.04-arm
|
||||
fedora-36
|
||||
amzn-2
|
||||
)
|
||||
|
||||
PROJECT_ROOT="$SCRIPT_DIR/../.."
|
||||
TOOLCHAIN_VERSION="toolchain-v4"
|
||||
ACTIVATE_TOOLCHAIN="source /opt/${TOOLCHAIN_VERSION}/activate"
|
||||
@@ -23,9 +30,9 @@ make_package () {
|
||||
echo "Building Memgraph for $os on $build_container..."
|
||||
|
||||
package_command=""
|
||||
if [[ "$os" =~ ^"centos".* ]]; then
|
||||
if [[ "$os" =~ ^"centos".* ]] || [[ "$os" =~ ^"fedora".* ]] || [[ "$os" =~ ^"amzn".* ]]; then
|
||||
docker exec "$build_container" bash -c "yum -y update"
|
||||
package_command=" cpack -G RPM --config ../CPackConfig.cmake && rpmlint memgraph*.rpm "
|
||||
package_command=" cpack -G RPM --config ../CPackConfig.cmake && rpmlint --file='../../release/rpm/rpmlintrc' memgraph*.rpm "
|
||||
fi
|
||||
if [[ "$os" =~ ^"debian".* ]]; then
|
||||
docker exec "$build_container" bash -c "apt update"
|
||||
@@ -72,9 +79,11 @@ make_package () {
|
||||
docker exec "$build_container" bash -c "/memgraph/environment/os/$os.sh install MEMGRAPH_BUILD_DEPS"
|
||||
|
||||
echo "Building targeted package..."
|
||||
# Fix issue with git marking directory as not safe
|
||||
docker exec "$build_container" bash -c "cd /memgraph && git config --global --add safe.directory '*'"
|
||||
docker exec "$build_container" bash -c "cd /memgraph && $ACTIVATE_TOOLCHAIN && ./init"
|
||||
docker exec "$build_container" bash -c "cd $container_build_dir && rm -rf ./*"
|
||||
if [[ "$os" == "debian-11-arm" ]]; then
|
||||
if [[ "$os" =~ "-arm" ]]; then
|
||||
docker exec "$build_container" bash -c "cd $container_build_dir && $ACTIVATE_TOOLCHAIN && cmake -DCMAKE_BUILD_TYPE=release -DMG_ARCH="ARM64" $telemetry_id_override_flag .."
|
||||
else
|
||||
docker exec "$build_container" bash -c "cd $container_build_dir && $ACTIVATE_TOOLCHAIN && cmake -DCMAKE_BUILD_TYPE=release $telemetry_id_override_flag .."
|
||||
|
||||
17
release/package/ubuntu-22.04-arm/Dockerfile
Normal file
17
release/package/ubuntu-22.04-arm/Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
||||
FROM ubuntu:22.04
|
||||
|
||||
ARG TOOLCHAIN_VERSION
|
||||
|
||||
# Stops tzdata interactive configuration.
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN apt update && apt install -y \
|
||||
ca-certificates wget git
|
||||
# Do NOT be smart here and clean the cache because the container is used in the
|
||||
# stateful context.
|
||||
|
||||
RUN wget -q https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/${TOOLCHAIN_VERSION}/${TOOLCHAIN_VERSION}-binaries-ubuntu-22.04-arm64.tar.gz \
|
||||
-O ${TOOLCHAIN_VERSION}-binaries-ubuntu-22.04-arm64.tar.gz \
|
||||
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-ubuntu-22.04-arm64.tar.gz -C /opt
|
||||
|
||||
ENTRYPOINT ["sleep", "infinity"]
|
||||
@@ -30,7 +30,7 @@ BuildRequires: systemd
|
||||
# This is needed to prevent Python compilation errors when building the RPM
|
||||
# package
|
||||
# https://github.com/scylladb/scylla/issues/2235
|
||||
%if 0%{?rhel} < 8
|
||||
%if 0%{?rhel} && 0%{?rhel} < 8
|
||||
%global __os_install_post \
|
||||
/usr/lib/rpm/redhat/brp-compress \
|
||||
%{!?__debug_package:\
|
||||
@@ -40,7 +40,9 @@ BuildRequires: systemd
|
||||
/usr/lib/rpm/redhat/brp-strip-static-archive %{__strip} \
|
||||
%{!?__jar_repack:/usr/lib/rpm/redhat/brp-java-repack-jars} \
|
||||
%{nil}
|
||||
%else
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} && 0%{?fedora} < 35
|
||||
%global __os_install_post \
|
||||
/usr/lib/rpm/brp-compress \
|
||||
%{!?__debug_package:\
|
||||
|
||||
4
release/rpm/rpmlintrc
Normal file
4
release/rpm/rpmlintrc
Normal file
@@ -0,0 +1,4 @@
|
||||
# from https://github.com/google/earthenterprise/blob/master/earth_enterprise/rpmlintrc
|
||||
|
||||
# We are not packaging log dir
|
||||
addFilter("E: logrotate-log-dir-not-packaged")
|
||||
@@ -1,7 +1,6 @@
|
||||
# CMake configuration for the main memgraph library and executable
|
||||
|
||||
# add memgraph sub libraries, ordered by dependency
|
||||
add_subdirectory(lisp)
|
||||
add_subdirectory(utils)
|
||||
add_subdirectory(requests)
|
||||
add_subdirectory(io)
|
||||
@@ -15,10 +14,11 @@ add_subdirectory(query)
|
||||
add_subdirectory(glue)
|
||||
add_subdirectory(slk)
|
||||
add_subdirectory(rpc)
|
||||
add_subdirectory(license)
|
||||
add_subdirectory(auth)
|
||||
|
||||
if (MG_ENTERPRISE)
|
||||
add_subdirectory(audit)
|
||||
if(MG_ENTERPRISE)
|
||||
add_subdirectory(audit)
|
||||
endif()
|
||||
|
||||
string(TOLOWER ${CMAKE_BUILD_TYPE} lower_build_type)
|
||||
@@ -36,68 +36,80 @@ set(mg_single_node_v2_sources
|
||||
)
|
||||
|
||||
set(mg_single_node_v2_libs stdc++fs Threads::Threads
|
||||
telemetry_lib mg-query mg-communication mg-memory mg-utils mg-auth mg-license mg-settings mg-glue)
|
||||
if (MG_ENTERPRISE)
|
||||
# These are enterprise subsystems
|
||||
set(mg_single_node_v2_libs ${mg_single_node_v2_libs} mg-audit)
|
||||
mg-telemetry mg-query mg-communication mg-memory mg-utils mg-auth mg-license mg-settings mg-glue)
|
||||
|
||||
if(MG_ENTERPRISE)
|
||||
# These are enterprise subsystems
|
||||
set(mg_single_node_v2_libs ${mg_single_node_v2_libs} mg-audit)
|
||||
endif()
|
||||
|
||||
# memgraph main executable
|
||||
add_executable(memgraph ${mg_single_node_v2_sources})
|
||||
target_include_directories(memgraph PUBLIC ${CMAKE_SOURCE_DIR}/include)
|
||||
target_link_libraries(memgraph ${mg_single_node_v2_libs})
|
||||
|
||||
# NOTE: `include/mg_procedure.syms` describes a pattern match for symbols which
|
||||
# should be dynamically exported, so that `dlopen` can correctly link the
|
||||
# symbols in custom procedure module libraries.
|
||||
target_link_libraries(memgraph "-Wl,--dynamic-list=${CMAKE_SOURCE_DIR}/include/mg_procedure.syms")
|
||||
set_target_properties(memgraph PROPERTIES
|
||||
# Set the executable output name to include version information.
|
||||
OUTPUT_NAME "memgraph-${MEMGRAPH_VERSION}_${CMAKE_BUILD_TYPE}"
|
||||
# Output the executable in main binary dir.
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
# Set the executable output name to include version information.
|
||||
OUTPUT_NAME "memgraph-${MEMGRAPH_VERSION}_${CMAKE_BUILD_TYPE}"
|
||||
|
||||
# Output the executable in main binary dir.
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
# Create symlink to the built executable.
|
||||
add_custom_command(TARGET memgraph POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E create_symlink $<TARGET_FILE:memgraph> ${CMAKE_BINARY_DIR}/memgraph
|
||||
BYPRODUCTS ${CMAKE_BINARY_DIR}/memgraph
|
||||
COMMENT "Creating symlink to memgraph executable")
|
||||
COMMAND ${CMAKE_COMMAND} -E create_symlink $<TARGET_FILE:memgraph> ${CMAKE_BINARY_DIR}/memgraph
|
||||
BYPRODUCTS ${CMAKE_BINARY_DIR}/memgraph
|
||||
COMMENT "Creating symlink to memgraph executable")
|
||||
|
||||
# Emulate the installed python_support, by creating a symlink
|
||||
add_custom_command(TARGET memgraph POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_SOURCE_DIR}/include ${CMAKE_BINARY_DIR}/python_support
|
||||
BYPRODUCTS ${CMAKE_BINARY_DIR}/python_support
|
||||
COMMENT "Creating symlink for python_support")
|
||||
COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_SOURCE_DIR}/include ${CMAKE_BINARY_DIR}/python_support
|
||||
BYPRODUCTS ${CMAKE_BINARY_DIR}/python_support
|
||||
COMMENT "Creating symlink for python_support")
|
||||
|
||||
# Strip the executable in release build.
|
||||
if (lower_build_type STREQUAL "release")
|
||||
add_custom_command(TARGET memgraph POST_BUILD
|
||||
COMMAND strip -s $<TARGET_FILE:memgraph>
|
||||
COMMENT "Stripping symbols and sections from memgraph")
|
||||
if(lower_build_type STREQUAL "release")
|
||||
add_custom_command(TARGET memgraph POST_BUILD
|
||||
COMMAND strip -s $<TARGET_FILE:memgraph>
|
||||
COMMENT "Stripping symbols and sections from memgraph")
|
||||
endif()
|
||||
|
||||
# Generate the configuration file.
|
||||
add_custom_command(TARGET memgraph POST_BUILD
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/config/generate.py
|
||||
${CMAKE_BINARY_DIR}/memgraph
|
||||
${CMAKE_BINARY_DIR}/config/memgraph.conf
|
||||
DEPENDS ${CMAKE_SOURCE_DIR}/config/generate.py
|
||||
${CMAKE_SOURCE_DIR}/config/flags.yaml
|
||||
BYPRODUCTS ${CMAKE_BINARY_DIR}/config/memgraph.conf
|
||||
COMMENT "Generating memgraph configuration file")
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/config/generate.py
|
||||
${CMAKE_BINARY_DIR}/memgraph
|
||||
${CMAKE_BINARY_DIR}/config/memgraph.conf
|
||||
DEPENDS ${CMAKE_SOURCE_DIR}/config/generate.py
|
||||
${CMAKE_SOURCE_DIR}/config/flags.yaml
|
||||
BYPRODUCTS ${CMAKE_BINARY_DIR}/config/memgraph.conf
|
||||
COMMENT "Generating memgraph configuration file")
|
||||
|
||||
# Everything here is under "memgraph" install component.
|
||||
set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME "memgraph")
|
||||
|
||||
# TODO: Default directory permissions to 755
|
||||
# NOTE: This is added in CMake 3.11, so enable it then
|
||||
#set(CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS
|
||||
# OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ WORLD_READ)
|
||||
# set(CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS
|
||||
# OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ WORLD_READ)
|
||||
|
||||
# Install and rename executable to just 'memgraph' Since we have to rename,
|
||||
# we cannot use the recommended `install(TARGETS ...)`.
|
||||
install(PROGRAMS $<TARGET_FILE:memgraph>
|
||||
DESTINATION lib/memgraph RENAME memgraph)
|
||||
|
||||
# Install Python source for supporting our embedded Python.
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/include/mgp.py
|
||||
DESTINATION lib/memgraph/python_support)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/include/mgp_mock.py
|
||||
DESTINATION lib/memgraph/python_support)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/include/_mgp_mock.py
|
||||
DESTINATION lib/memgraph/python_support)
|
||||
|
||||
# Install the includes file for writing custom procedures in C and C++>
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/include/mg_procedure.h
|
||||
DESTINATION include/memgraph)
|
||||
@@ -107,9 +119,11 @@ install(FILES ${CMAKE_SOURCE_DIR}/include/mg_exceptions.hpp
|
||||
DESTINATION include/memgraph)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/include/mgp.hpp
|
||||
DESTINATION include/memgraph)
|
||||
|
||||
# Install the config file (must use absolute path).
|
||||
install(FILES ${CMAKE_BINARY_DIR}/config/memgraph.conf
|
||||
DESTINATION /etc/memgraph RENAME memgraph.conf)
|
||||
|
||||
# Install logrotate configuration (must use absolute path).
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/release/logrotate.conf
|
||||
DESTINATION /etc/logrotate.d RENAME memgraph)
|
||||
@@ -125,15 +139,14 @@ 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)
|
||||
|
||||
# Strip the executable in release build.
|
||||
if (lower_build_type STREQUAL "release")
|
||||
add_custom_command(TARGET mg_import_csv POST_BUILD
|
||||
COMMAND strip -s mg_import_csv
|
||||
COMMENT "Stripping symbols and sections from mg_import_csv")
|
||||
if(lower_build_type STREQUAL "release")
|
||||
add_custom_command(TARGET mg_import_csv POST_BUILD
|
||||
COMMAND strip -s mg_import_csv
|
||||
COMMENT "Stripping symbols and sections from mg_import_csv")
|
||||
endif()
|
||||
|
||||
install(TARGETS mg_import_csv RUNTIME DESTINATION bin)
|
||||
|
||||
@@ -16,6 +16,10 @@ target_link_libraries(mg-auth mg-utils mg-kvstore mg-license )
|
||||
target_link_libraries(mg-auth ${Seccomp_LIBRARIES})
|
||||
target_include_directories(mg-auth SYSTEM PRIVATE ${Seccomp_INCLUDE_DIRS})
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
target_link_libraries(mg-auth ${OPENSSL_LIBRARIES})
|
||||
target_include_directories(mg-auth SYSTEM PUBLIC ${OPENSSL_INCLUDE_DIR})
|
||||
|
||||
# Install reference auth modules and their configuration files.
|
||||
install(PROGRAMS ${CMAKE_CURRENT_SOURCE_DIR}/reference_modules/example.py
|
||||
DESTINATION lib/memgraph/auth_module)
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "auth/exceptions.hpp"
|
||||
#include "license/license.hpp"
|
||||
#include "utils/flag_validation.hpp"
|
||||
#include "utils/license.hpp"
|
||||
#include "utils/logging.hpp"
|
||||
#include "utils/message.hpp"
|
||||
#include "utils/settings.hpp"
|
||||
@@ -68,10 +68,9 @@ Auth::Auth(const std::string &storage_directory) : storage_(storage_directory),
|
||||
|
||||
std::optional<User> Auth::Authenticate(const std::string &username, const std::string &password) {
|
||||
if (module_.IsUsed()) {
|
||||
const auto license_check_result = utils::license::global_license_checker.IsValidLicense(utils::global_settings);
|
||||
const auto license_check_result = license::global_license_checker.IsEnterpriseValid(utils::global_settings);
|
||||
if (license_check_result.HasError()) {
|
||||
spdlog::warn(
|
||||
utils::license::LicenseCheckErrorToString(license_check_result.GetError(), "authentication modules"));
|
||||
spdlog::warn(license::LicenseCheckErrorToString(license_check_result.GetError(), "authentication modules"));
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,64 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
|
||||
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the License at https://memgraph.com/legal.
|
||||
//
|
||||
//
|
||||
|
||||
#include "auth/crypto.hpp"
|
||||
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
#include <libbcrypt/bcrypt.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include "auth/exceptions.hpp"
|
||||
#include "utils/enum.hpp"
|
||||
#include "utils/flag_validation.hpp"
|
||||
|
||||
namespace {
|
||||
using namespace std::literals;
|
||||
inline constexpr std::array password_encryption_mappings{
|
||||
std::pair{"bcrypt"sv, memgraph::auth::PasswordEncryptionAlgorithm::BCRYPT},
|
||||
std::pair{"sha256"sv, memgraph::auth::PasswordEncryptionAlgorithm::SHA256},
|
||||
std::pair{"sha256-multiple"sv, memgraph::auth::PasswordEncryptionAlgorithm::SHA256_MULTIPLE}};
|
||||
|
||||
inline constexpr uint64_t ONE_SHA_ITERATION = 1;
|
||||
inline constexpr uint64_t MULTIPLE_SHA_ITERATIONS = 1024;
|
||||
} // namespace
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables,misc-unused-parameters)
|
||||
DEFINE_VALIDATED_string(password_encryption_algorithm, "bcrypt",
|
||||
"The password encryption algorithm used for authentication.", {
|
||||
if (const auto result =
|
||||
memgraph::utils::IsValidEnumValueString(value, password_encryption_mappings);
|
||||
result.HasError()) {
|
||||
const auto error = result.GetError();
|
||||
switch (error) {
|
||||
case memgraph::utils::ValidationError::EmptyValue: {
|
||||
std::cout << "Password encryption algorithm cannot be empty." << std::endl;
|
||||
break;
|
||||
}
|
||||
case memgraph::utils::ValidationError::InvalidValue: {
|
||||
std::cout << "Invalid value for password encryption algorithm. Allowed values: "
|
||||
<< memgraph::utils::GetAllowedEnumValuesString(password_encryption_mappings)
|
||||
<< std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
namespace memgraph::auth {
|
||||
const std::string EncryptPassword(const std::string &password) {
|
||||
namespace BCrypt {
|
||||
std::string EncryptPassword(const std::string &password) {
|
||||
char salt[BCRYPT_HASHSIZE];
|
||||
char hash[BCRYPT_HASHSIZE];
|
||||
|
||||
@@ -28,7 +73,7 @@ const std::string EncryptPassword(const std::string &password) {
|
||||
throw AuthException("Couldn't hash password!");
|
||||
}
|
||||
|
||||
return std::string(hash);
|
||||
return {hash};
|
||||
}
|
||||
|
||||
bool VerifyPassword(const std::string &password, const std::string &hash) {
|
||||
@@ -38,5 +83,102 @@ bool VerifyPassword(const std::string &password, const std::string &hash) {
|
||||
}
|
||||
return ret == 0;
|
||||
}
|
||||
} // namespace BCrypt
|
||||
|
||||
namespace SHA {
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
std::string EncryptPasswordOpenSSL3(const std::string &password, const uint64_t number_of_iterations) {
|
||||
unsigned char hash[SHA256_DIGEST_LENGTH];
|
||||
|
||||
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
|
||||
EVP_MD *md = EVP_MD_fetch(nullptr, "SHA2-256", nullptr);
|
||||
|
||||
EVP_DigestInit_ex(ctx, md, nullptr);
|
||||
for (auto i = 0; i < number_of_iterations; i++) {
|
||||
EVP_DigestUpdate(ctx, password.c_str(), password.size());
|
||||
}
|
||||
EVP_DigestFinal_ex(ctx, hash, nullptr);
|
||||
|
||||
EVP_MD_free(md);
|
||||
EVP_MD_CTX_free(ctx);
|
||||
|
||||
std::stringstream result_stream;
|
||||
for (auto hash_char : hash) {
|
||||
result_stream << std::hex << std::setw(2) << std::setfill('0') << (int)hash_char;
|
||||
}
|
||||
|
||||
return result_stream.str();
|
||||
}
|
||||
#else
|
||||
std::string EncryptPasswordOpenSSL1_1(const std::string &password, const uint64_t number_of_iterations) {
|
||||
unsigned char hash[SHA256_DIGEST_LENGTH];
|
||||
|
||||
SHA256_CTX sha256;
|
||||
SHA256_Init(&sha256);
|
||||
for (auto i = 0; i < number_of_iterations; i++) {
|
||||
SHA256_Update(&sha256, password.c_str(), password.size());
|
||||
}
|
||||
SHA256_Final(hash, &sha256);
|
||||
|
||||
std::stringstream ss;
|
||||
for (auto hash_char : hash) {
|
||||
ss << std::hex << std::setw(2) << std::setfill('0') << (int)hash_char;
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string EncryptPassword(const std::string &password, const uint64_t number_of_iterations) {
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
return EncryptPasswordOpenSSL3(password, number_of_iterations);
|
||||
#else
|
||||
return EncryptPasswordOpenSSL1_1(password, number_of_iterations);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool VerifyPassword(const std::string &password, const std::string &hash, const uint64_t number_of_iterations) {
|
||||
auto password_hash = EncryptPassword(password, number_of_iterations);
|
||||
return password_hash == hash;
|
||||
}
|
||||
} // namespace SHA
|
||||
|
||||
bool VerifyPassword(const std::string &password, const std::string &hash) {
|
||||
const auto password_encryption_algorithm = utils::StringToEnum<PasswordEncryptionAlgorithm>(
|
||||
FLAGS_password_encryption_algorithm, password_encryption_mappings);
|
||||
|
||||
if (!password_encryption_algorithm.has_value()) {
|
||||
throw AuthException("Invalid password encryption flag '{}'!", FLAGS_password_encryption_algorithm);
|
||||
}
|
||||
|
||||
switch (password_encryption_algorithm.value()) {
|
||||
case PasswordEncryptionAlgorithm::BCRYPT:
|
||||
return BCrypt::VerifyPassword(password, hash);
|
||||
case PasswordEncryptionAlgorithm::SHA256:
|
||||
return SHA::VerifyPassword(password, hash, ONE_SHA_ITERATION);
|
||||
case PasswordEncryptionAlgorithm::SHA256_MULTIPLE:
|
||||
return SHA::VerifyPassword(password, hash, MULTIPLE_SHA_ITERATIONS);
|
||||
}
|
||||
|
||||
throw AuthException("Invalid password encryption flag '{}'!", FLAGS_password_encryption_algorithm);
|
||||
}
|
||||
|
||||
std::string EncryptPassword(const std::string &password) {
|
||||
const auto password_encryption_algorithm = utils::StringToEnum<PasswordEncryptionAlgorithm>(
|
||||
FLAGS_password_encryption_algorithm, password_encryption_mappings);
|
||||
|
||||
if (!password_encryption_algorithm.has_value()) {
|
||||
throw AuthException("Invalid password encryption flag '{}'!", FLAGS_password_encryption_algorithm);
|
||||
}
|
||||
|
||||
switch (password_encryption_algorithm.value()) {
|
||||
case PasswordEncryptionAlgorithm::BCRYPT:
|
||||
return BCrypt::EncryptPassword(password);
|
||||
case PasswordEncryptionAlgorithm::SHA256:
|
||||
return SHA::EncryptPassword(password, ONE_SHA_ITERATION);
|
||||
case PasswordEncryptionAlgorithm::SHA256_MULTIPLE:
|
||||
return SHA::EncryptPassword(password, MULTIPLE_SHA_ITERATIONS);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace memgraph::auth
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
|
||||
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
|
||||
@@ -11,10 +11,11 @@
|
||||
#include <string>
|
||||
|
||||
namespace memgraph::auth {
|
||||
enum class PasswordEncryptionAlgorithm : uint8_t { BCRYPT, SHA256, SHA256_MULTIPLE };
|
||||
|
||||
/// @throw AuthException if unable to encrypt the password.
|
||||
const std::string EncryptPassword(const std::string &password);
|
||||
std::string EncryptPassword(const std::string &password);
|
||||
|
||||
/// @throw AuthException if unable to verify the password.
|
||||
bool VerifyPassword(const std::string &password, const std::string &hash);
|
||||
|
||||
} // namespace memgraph::auth
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
|
||||
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
|
||||
@@ -15,8 +15,9 @@
|
||||
|
||||
#include "auth/crypto.hpp"
|
||||
#include "auth/exceptions.hpp"
|
||||
#include "license/license.hpp"
|
||||
#include "query/constants.hpp"
|
||||
#include "utils/cast.hpp"
|
||||
#include "utils/license.hpp"
|
||||
#include "utils/logging.hpp"
|
||||
#include "utils/settings.hpp"
|
||||
#include "utils/string.hpp"
|
||||
@@ -34,13 +35,19 @@ namespace memgraph::auth {
|
||||
namespace {
|
||||
|
||||
// Constant list of all available permissions.
|
||||
const std::vector<Permission> kPermissionsAll = {
|
||||
Permission::MATCH, Permission::CREATE, Permission::MERGE, Permission::DELETE,
|
||||
Permission::SET, Permission::REMOVE, Permission::INDEX, Permission::STATS,
|
||||
Permission::CONSTRAINT, Permission::DUMP, Permission::AUTH, Permission::REPLICATION,
|
||||
Permission::DURABILITY, Permission::READ_FILE, Permission::FREE_MEMORY, Permission::TRIGGER,
|
||||
Permission::CONFIG, Permission::STREAM, Permission::MODULE_READ, Permission::MODULE_WRITE,
|
||||
Permission::WEBSOCKET};
|
||||
const std::vector<Permission> kPermissionsAll = {Permission::MATCH, Permission::CREATE,
|
||||
Permission::MERGE, Permission::DELETE,
|
||||
Permission::SET, Permission::REMOVE,
|
||||
Permission::INDEX, Permission::STATS,
|
||||
Permission::CONSTRAINT, Permission::DUMP,
|
||||
Permission::AUTH, Permission::REPLICATION,
|
||||
Permission::DURABILITY, Permission::READ_FILE,
|
||||
Permission::FREE_MEMORY, Permission::TRIGGER,
|
||||
Permission::CONFIG, Permission::STREAM,
|
||||
Permission::MODULE_READ, Permission::MODULE_WRITE,
|
||||
Permission::WEBSOCKET, Permission::TRANSACTION_MANAGEMENT,
|
||||
Permission::STORAGE_MODE};
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string PermissionToString(Permission permission) {
|
||||
@@ -87,6 +94,10 @@ std::string PermissionToString(Permission permission) {
|
||||
return "MODULE_WRITE";
|
||||
case Permission::WEBSOCKET:
|
||||
return "WEBSOCKET";
|
||||
case Permission::TRANSACTION_MANAGEMENT:
|
||||
return "TRANSACTION_MANAGEMENT";
|
||||
case Permission::STORAGE_MODE:
|
||||
return "STORAGE_MODE";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,7 +253,7 @@ FineGrainedAccessPermissions::FineGrainedAccessPermissions(const std::unordered_
|
||||
|
||||
PermissionLevel FineGrainedAccessPermissions::Has(const std::string &permission,
|
||||
const FineGrainedPermission fine_grained_permission) const {
|
||||
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (!memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
return PermissionLevel::GRANT;
|
||||
}
|
||||
const auto concrete_permission = std::invoke([&]() -> uint64_t {
|
||||
@@ -264,7 +275,7 @@ PermissionLevel FineGrainedAccessPermissions::Has(const std::string &permission,
|
||||
|
||||
void FineGrainedAccessPermissions::Grant(const std::string &permission,
|
||||
const FineGrainedPermission fine_grained_permission) {
|
||||
if (permission == kAsterisk) {
|
||||
if (permission == query::kAsterisk) {
|
||||
global_permission_ = CalculateGrant(fine_grained_permission);
|
||||
} else {
|
||||
permissions_[permission] = CalculateGrant(fine_grained_permission);
|
||||
@@ -272,7 +283,7 @@ void FineGrainedAccessPermissions::Grant(const std::string &permission,
|
||||
}
|
||||
|
||||
void FineGrainedAccessPermissions::Revoke(const std::string &permission) {
|
||||
if (permission == kAsterisk) {
|
||||
if (permission == query::kAsterisk) {
|
||||
permissions_.clear();
|
||||
global_permission_ = std::nullopt;
|
||||
} else {
|
||||
@@ -281,7 +292,7 @@ void FineGrainedAccessPermissions::Revoke(const std::string &permission) {
|
||||
}
|
||||
|
||||
nlohmann::json FineGrainedAccessPermissions::Serialize() const {
|
||||
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (!memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
return {};
|
||||
}
|
||||
nlohmann::json data = nlohmann::json::object();
|
||||
@@ -294,7 +305,7 @@ FineGrainedAccessPermissions FineGrainedAccessPermissions::Deserialize(const nlo
|
||||
if (!data.is_object()) {
|
||||
throw AuthException("Couldn't load permissions data!");
|
||||
}
|
||||
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (!memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
return FineGrainedAccessPermissions{};
|
||||
}
|
||||
std::optional<uint64_t> global_permission;
|
||||
@@ -347,7 +358,7 @@ const FineGrainedAccessPermissions &FineGrainedAccessHandler::edge_type_permissi
|
||||
FineGrainedAccessPermissions &FineGrainedAccessHandler::edge_type_permissions() { return edge_type_permissions_; }
|
||||
|
||||
nlohmann::json FineGrainedAccessHandler::Serialize() const {
|
||||
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (!memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
return {};
|
||||
}
|
||||
nlohmann::json data = nlohmann::json::object();
|
||||
@@ -363,7 +374,7 @@ FineGrainedAccessHandler FineGrainedAccessHandler::Deserialize(const nlohmann::j
|
||||
if (!data["label_permissions"].is_object() || !data["edge_type_permissions"].is_object()) {
|
||||
throw AuthException("Couldn't load label_permissions or edge_type_permissions data!");
|
||||
}
|
||||
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (!memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
return FineGrainedAccessHandler{};
|
||||
}
|
||||
auto label_permissions = FineGrainedAccessPermissions::Deserialize(data["label_permissions"]);
|
||||
@@ -414,7 +425,7 @@ nlohmann::json Role::Serialize() const {
|
||||
data["rolename"] = rolename_;
|
||||
data["permissions"] = permissions_.Serialize();
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
data["fine_grained_access_handler"] = fine_grained_access_handler_.Serialize();
|
||||
} else {
|
||||
data["fine_grained_access_handler"] = {};
|
||||
@@ -432,7 +443,7 @@ Role Role::Deserialize(const nlohmann::json &data) {
|
||||
}
|
||||
auto permissions = Permissions::Deserialize(data["permissions"]);
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
if (!data["fine_grained_access_handler"].is_object()) {
|
||||
throw AuthException("Couldn't load user data!");
|
||||
}
|
||||
@@ -445,7 +456,7 @@ Role Role::Deserialize(const nlohmann::json &data) {
|
||||
|
||||
bool operator==(const Role &first, const Role &second) {
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
return first.rolename_ == second.rolename_ && first.permissions_ == second.permissions_ &&
|
||||
first.fine_grained_access_handler_ == second.fine_grained_access_handler_;
|
||||
}
|
||||
@@ -483,13 +494,13 @@ void User::UpdatePassword(const std::optional<std::string> &password) {
|
||||
}
|
||||
|
||||
if (FLAGS_auth_password_strength_regex != default_password_regex) {
|
||||
if (const auto license_check_result = utils::license::global_license_checker.IsValidLicense(utils::global_settings);
|
||||
if (const auto license_check_result = license::global_license_checker.IsEnterpriseValid(utils::global_settings);
|
||||
license_check_result.HasError()) {
|
||||
throw AuthException(
|
||||
"Custom password regex is a Memgraph Enterprise feature. Please set the config "
|
||||
"(\"--auth-password-strength-regex\") to its default value (\"{}\") or remove the flag.\n{}",
|
||||
default_password_regex,
|
||||
utils::license::LicenseCheckErrorToString(license_check_result.GetError(), "password regex"));
|
||||
license::LicenseCheckErrorToString(license_check_result.GetError(), "password regex"));
|
||||
}
|
||||
}
|
||||
std::regex re(FLAGS_auth_password_strength_regex);
|
||||
@@ -517,7 +528,7 @@ Permissions User::GetPermissions() const {
|
||||
|
||||
#ifdef MG_ENTERPRISE
|
||||
FineGrainedAccessPermissions User::GetFineGrainedAccessLabelPermissions() const {
|
||||
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (!memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
return FineGrainedAccessPermissions{};
|
||||
}
|
||||
|
||||
@@ -530,7 +541,7 @@ FineGrainedAccessPermissions User::GetFineGrainedAccessLabelPermissions() const
|
||||
}
|
||||
|
||||
FineGrainedAccessPermissions User::GetFineGrainedAccessEdgeTypePermissions() const {
|
||||
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (!memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
return FineGrainedAccessPermissions{};
|
||||
}
|
||||
if (role_) {
|
||||
@@ -563,7 +574,7 @@ nlohmann::json User::Serialize() const {
|
||||
data["password_hash"] = password_hash_;
|
||||
data["permissions"] = permissions_.Serialize();
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
data["fine_grained_access_handler"] = fine_grained_access_handler_.Serialize();
|
||||
} else {
|
||||
data["fine_grained_access_handler"] = {};
|
||||
@@ -582,7 +593,7 @@ User User::Deserialize(const nlohmann::json &data) {
|
||||
}
|
||||
auto permissions = Permissions::Deserialize(data["permissions"]);
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
if (!data["fine_grained_access_handler"].is_object()) {
|
||||
throw AuthException("Couldn't load user data!");
|
||||
}
|
||||
@@ -595,7 +606,7 @@ User User::Deserialize(const nlohmann::json &data) {
|
||||
|
||||
bool operator==(const User &first, const User &second) {
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
return first.username_ == second.username_ && first.password_hash_ == second.password_hash_ &&
|
||||
first.permissions_ == second.permissions_ && first.role_ == second.role_ &&
|
||||
first.fine_grained_access_handler_ == second.fine_grained_access_handler_;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
|
||||
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
|
||||
@@ -15,7 +15,6 @@
|
||||
#include <json/json.hpp>
|
||||
|
||||
namespace memgraph::auth {
|
||||
const std::string kAsterisk = "*";
|
||||
// These permissions must have values that are applicable for usage in a
|
||||
// bitmask.
|
||||
// clang-format off
|
||||
@@ -40,7 +39,9 @@ enum class Permission : uint64_t {
|
||||
STREAM = 1U << 17U,
|
||||
MODULE_READ = 1U << 18U,
|
||||
MODULE_WRITE = 1U << 19U,
|
||||
WEBSOCKET = 1U << 20U
|
||||
WEBSOCKET = 1U << 20U,
|
||||
TRANSACTION_MANAGEMENT = 1U << 21U,
|
||||
STORAGE_MODE = 1U << 22U
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ QueryData Client::Execute(const std::string &query, const std::map<std::string,
|
||||
// It is super critical from performance point of view to send the pull message right after the run message. Otherwise
|
||||
// the performance will degrade multiple magnitudes.
|
||||
encoder_.MessageRun(query, parameters, {});
|
||||
encoder_.MessagePull({});
|
||||
encoder_.MessagePull({{"n", Value(-1)}});
|
||||
|
||||
spdlog::debug("Reading run message response");
|
||||
Signature signature{};
|
||||
@@ -146,9 +146,10 @@ QueryData Client::Execute(const std::string &query, const std::map<std::string,
|
||||
throw ServerMalformedDataException();
|
||||
}
|
||||
|
||||
auto &header = fields.ValueMap();
|
||||
|
||||
QueryData ret{{}, std::move(records), std::move(metadata.ValueMap())};
|
||||
|
||||
auto &header = fields.ValueMap();
|
||||
if (header.find("fields") == header.end()) {
|
||||
throw ServerMalformedDataException();
|
||||
}
|
||||
@@ -164,6 +165,10 @@ QueryData Client::Execute(const std::string &query, const std::map<std::string,
|
||||
ret.fields.emplace_back(std::move(field_item.ValueString()));
|
||||
}
|
||||
|
||||
if (header.contains("qid")) {
|
||||
ret.metadata["qid"] = header["qid"];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -20,6 +20,8 @@ inline constexpr uint8_t kPreamble[4] = {0x60, 0x60, 0xB0, 0x17};
|
||||
enum class Signature : uint8_t {
|
||||
Noop = 0x00,
|
||||
Init = 0x01,
|
||||
LogOn = 0x6A,
|
||||
LogOff = 0x6B,
|
||||
AckFailure = 0x0E, // only v1
|
||||
Reset = 0x0F,
|
||||
Goodbye = 0x02,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -28,7 +28,7 @@ inline constexpr size_t kChunkWholeSize = kChunkHeaderSize + kChunkMaxDataSize;
|
||||
*/
|
||||
inline constexpr size_t kHandshakeSize = 20;
|
||||
|
||||
inline constexpr uint16_t kSupportedVersions[] = {0x0100, 0x0400, 0x0401, 0x0403};
|
||||
inline constexpr uint16_t kSupportedVersions[] = {0x0100, 0x0400, 0x0401, 0x0403, 0x0502};
|
||||
|
||||
inline constexpr int kPullAll = -1;
|
||||
inline constexpr int kPullLast = -1;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -33,7 +33,14 @@ namespace memgraph::communication::bolt {
|
||||
template <typename Buffer>
|
||||
class Decoder {
|
||||
public:
|
||||
explicit Decoder(Buffer &buffer) : buffer_(buffer) {}
|
||||
explicit Decoder(Buffer &buffer) : buffer_(buffer), major_v_(0) {}
|
||||
|
||||
/**
|
||||
* Lets the user update the version.
|
||||
* This is all single thread for now. TODO: Update if ever multithreaded.
|
||||
* @param major_v the major version of the Bolt protocol used.
|
||||
*/
|
||||
void UpdateVersion(int major_v) { major_v_ = major_v; }
|
||||
|
||||
/**
|
||||
* Reads a Value from the available data in the buffer.
|
||||
@@ -208,6 +215,10 @@ class Decoder {
|
||||
|
||||
protected:
|
||||
Buffer &buffer_;
|
||||
int major_v_; //!< Major version of the underlying Bolt protocol
|
||||
// TODO: when refactoring
|
||||
// Ideally the major_v would be a compile time constant. If the higher level (Bolt driver) ends up being separate
|
||||
// classes, this could be just a template and each version of the driver would use the appropriate decoder.
|
||||
|
||||
private:
|
||||
bool ReadNull(const Marker &marker, Value *data) {
|
||||
@@ -370,11 +381,7 @@ class Decoder {
|
||||
}
|
||||
ret.emplace(std::move(dv_key.ValueString()), std::move(dv_val));
|
||||
}
|
||||
if (ret.size() != size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return ret.size() == size;
|
||||
}
|
||||
|
||||
bool ReadVertex(Value *data) {
|
||||
@@ -407,6 +414,14 @@ class Decoder {
|
||||
}
|
||||
vertex.properties = std::move(dv.ValueMap());
|
||||
|
||||
if (major_v_ > 4) {
|
||||
// element_id introduced in v5.0
|
||||
if (!ReadValue(&dv, Value::Type::String)) {
|
||||
return false;
|
||||
}
|
||||
vertex.element_id = std::move(dv.ValueString());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -445,6 +460,23 @@ class Decoder {
|
||||
}
|
||||
edge.properties = std::move(dv.ValueMap());
|
||||
|
||||
if (major_v_ > 4) {
|
||||
// element_id introduced in v5.0
|
||||
if (!ReadValue(&dv, Value::Type::String)) {
|
||||
return false;
|
||||
}
|
||||
edge.element_id = std::move(dv.ValueString());
|
||||
// from_element_id introduced in v5.0
|
||||
if (!ReadValue(&dv, Value::Type::String)) {
|
||||
return false;
|
||||
}
|
||||
edge.from_element_id = std::move(dv.ValueString());
|
||||
// to_element_id introduced in v5.0
|
||||
if (!ReadValue(&dv, Value::Type::String)) {
|
||||
return false;
|
||||
}
|
||||
edge.to_element_id = std::move(dv.ValueString());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -471,6 +503,14 @@ class Decoder {
|
||||
}
|
||||
edge.properties = std::move(dv.ValueMap());
|
||||
|
||||
if (major_v_ > 4) {
|
||||
// element_id introduced in v5.0
|
||||
if (!ReadValue(&dv, Value::Type::String)) {
|
||||
return false;
|
||||
}
|
||||
edge.element_id = std::move(dv.ValueString());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -36,7 +36,14 @@ namespace memgraph::communication::bolt {
|
||||
template <typename Buffer>
|
||||
class BaseEncoder {
|
||||
public:
|
||||
explicit BaseEncoder(Buffer &buffer) : buffer_(buffer) {}
|
||||
explicit BaseEncoder(Buffer &buffer) : buffer_(buffer), major_v_(0) {}
|
||||
|
||||
/**
|
||||
* Lets the user update the version.
|
||||
* This is all single thread for now. TODO: Update if ever multithreaded.
|
||||
* @param major_v the major version of the Bolt protocol used.
|
||||
*/
|
||||
void UpdateVersion(int major_v) { major_v_ = major_v; }
|
||||
|
||||
void WriteRAW(const uint8_t *data, uint64_t len) { buffer_.Write(data, len); }
|
||||
|
||||
@@ -116,7 +123,8 @@ class BaseEncoder {
|
||||
}
|
||||
|
||||
void WriteVertex(const Vertex &vertex) {
|
||||
WriteRAW(utils::UnderlyingCast(Marker::TinyStruct) + 3);
|
||||
int struct_n = 3 + 1 * int(major_v_ > 4); // element_id introduced from v5
|
||||
WriteRAW(utils::UnderlyingCast(Marker::TinyStruct) + struct_n);
|
||||
WriteRAW(utils::UnderlyingCast(Signature::Node));
|
||||
WriteInt(vertex.id.AsInt());
|
||||
|
||||
@@ -132,10 +140,16 @@ class BaseEncoder {
|
||||
WriteString(prop.first);
|
||||
WriteValue(prop.second);
|
||||
}
|
||||
|
||||
if (major_v_ > 4) {
|
||||
// element_id introduced in v5.0
|
||||
WriteString(vertex.element_id);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteEdge(const Edge &edge, bool unbound = false) {
|
||||
WriteRAW(utils::UnderlyingCast(Marker::TinyStruct) + (unbound ? 3 : 5));
|
||||
int struct_n = (unbound ? 3 + 1 * int(major_v_ > 4) : 5 + 3 * int(major_v_ > 4)); // element_id introduced from v5
|
||||
WriteRAW(utils::UnderlyingCast(Marker::TinyStruct) + struct_n);
|
||||
WriteRAW(utils::UnderlyingCast(unbound ? Signature::UnboundRelationship : Signature::Relationship));
|
||||
|
||||
WriteInt(edge.id.AsInt());
|
||||
@@ -152,10 +166,22 @@ class BaseEncoder {
|
||||
WriteString(prop.first);
|
||||
WriteValue(prop.second);
|
||||
}
|
||||
|
||||
if (major_v_ > 4) {
|
||||
// element_id introduced in v5.0
|
||||
WriteString(edge.element_id);
|
||||
if (!unbound) {
|
||||
// from_element_id introduced in v5.0
|
||||
WriteString(edge.from_element_id);
|
||||
// to_element_id introduced in v5.0
|
||||
WriteString(edge.to_element_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WriteEdge(const UnboundedEdge &edge) {
|
||||
WriteRAW(utils::UnderlyingCast(Marker::TinyStruct) + 3);
|
||||
const int struct_n = 3 + 1 * int(major_v_ > 4); // element_id introduced from v5
|
||||
WriteRAW(utils::UnderlyingCast(Marker::TinyStruct) + struct_n);
|
||||
WriteRAW(utils::UnderlyingCast(Signature::UnboundRelationship));
|
||||
|
||||
WriteInt(edge.id.AsInt());
|
||||
@@ -168,6 +194,11 @@ class BaseEncoder {
|
||||
WriteString(prop.first);
|
||||
WriteValue(prop.second);
|
||||
}
|
||||
|
||||
if (major_v_ > 4) {
|
||||
// element_id introduced in v5.0
|
||||
WriteString(edge.element_id);
|
||||
}
|
||||
}
|
||||
|
||||
void WritePath(const Path &path) {
|
||||
@@ -264,6 +295,7 @@ class BaseEncoder {
|
||||
|
||||
protected:
|
||||
Buffer &buffer_;
|
||||
int major_v_; //!< Major version of the underlying Bolt protocol (TODO: Think about reimplementing the versioning)
|
||||
|
||||
private:
|
||||
template <class T>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -41,6 +41,8 @@ class ClientEncoder : private BaseEncoder<Buffer> {
|
||||
public:
|
||||
ClientEncoder(Buffer &buffer) : BaseEncoder<Buffer>(buffer) {}
|
||||
|
||||
using BaseEncoder<Buffer>::UpdateVersion;
|
||||
|
||||
/**
|
||||
* Writes a Init message.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -34,6 +34,8 @@ class Encoder : private BaseEncoder<Buffer> {
|
||||
public:
|
||||
Encoder(Buffer &buffer) : BaseEncoder<Buffer>(buffer) {}
|
||||
|
||||
using BaseEncoder<Buffer>::UpdateVersion;
|
||||
|
||||
/**
|
||||
* Sends a Record message.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -63,7 +63,8 @@ class Session {
|
||||
* if an explicit transaction was started.
|
||||
*/
|
||||
virtual std::pair<std::vector<std::string>, std::optional<int>> Interpret(
|
||||
const std::string &query, const std::map<std::string, Value> ¶ms) = 0;
|
||||
const std::string &query, const std::map<std::string, Value> ¶ms,
|
||||
const std::map<std::string, memgraph::communication::bolt::Value> &metadata) = 0;
|
||||
|
||||
/**
|
||||
* Put results of the processed query in the `encoder`.
|
||||
@@ -85,7 +86,7 @@ class Session {
|
||||
*/
|
||||
virtual std::map<std::string, Value> Discard(std::optional<int> n, std::optional<int> qid) = 0;
|
||||
|
||||
virtual void BeginTransaction() = 0;
|
||||
virtual void BeginTransaction(const std::map<std::string, memgraph::communication::bolt::Value> &) = 0;
|
||||
virtual void CommitTransaction() = 0;
|
||||
virtual void RollbackTransaction() = 0;
|
||||
|
||||
@@ -120,6 +121,9 @@ class Session {
|
||||
return;
|
||||
}
|
||||
handshake_done_ = true;
|
||||
// Update the decoder's Bolt version (v5 has changed the undelying structure)
|
||||
decoder_.UpdateVersion(version_.major);
|
||||
encoder_.UpdateVersion(version_.major);
|
||||
}
|
||||
|
||||
ChunkState chunk_state;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -22,10 +22,15 @@
|
||||
#include "communication/bolt/v1/state.hpp"
|
||||
#include "communication/bolt/v1/states/handlers.hpp"
|
||||
#include "communication/bolt/v1/value.hpp"
|
||||
#include "utils/event_counter.hpp"
|
||||
#include "utils/likely.hpp"
|
||||
#include "utils/logging.hpp"
|
||||
#include "utils/message.hpp"
|
||||
|
||||
namespace memgraph::metrics {
|
||||
extern const Event BoltMessages;
|
||||
} // namespace memgraph::metrics
|
||||
|
||||
namespace memgraph::communication::bolt {
|
||||
|
||||
template <typename TSession>
|
||||
@@ -86,6 +91,37 @@ State RunHandlerV4(Signature signature, TSession &session, State state, Marker m
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TSession>
|
||||
State RunHandlerV5(Signature signature, TSession &session, State state, Marker marker) {
|
||||
switch (signature) {
|
||||
case Signature::Run:
|
||||
return HandleRunV5<TSession>(session, state, marker);
|
||||
case Signature::Pull:
|
||||
return HandlePullV5<TSession>(session, state, marker);
|
||||
case Signature::Discard:
|
||||
return HandleDiscardV5<TSession>(session, state, marker);
|
||||
case Signature::Reset:
|
||||
return HandleReset<TSession>(session, marker);
|
||||
case Signature::Begin:
|
||||
return HandleBegin<TSession>(session, state, marker);
|
||||
case Signature::Commit:
|
||||
return HandleCommit<TSession>(session, state, marker);
|
||||
case Signature::Goodbye:
|
||||
return HandleGoodbye<TSession>();
|
||||
case Signature::Rollback:
|
||||
return HandleRollback<TSession>(session, state, marker);
|
||||
case Signature::Noop:
|
||||
return HandleNoop<TSession>(state);
|
||||
case Signature::Route:
|
||||
return HandleRoute<TSession>(session, marker);
|
||||
case Signature::LogOff:
|
||||
return HandleLogOff<TSession>();
|
||||
default:
|
||||
spdlog::trace("Unrecognized signature received (0x{:02X})!", utils::UnderlyingCast(signature));
|
||||
return State::Close;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executor state run function
|
||||
* This function executes an initialized Bolt session.
|
||||
@@ -103,8 +139,10 @@ State StateExecutingRun(TSession &session, State state) {
|
||||
|
||||
switch (session.version_.major) {
|
||||
case 1:
|
||||
memgraph::metrics::IncrementCounter(memgraph::metrics::BoltMessages);
|
||||
return RunHandlerV1(signature, session, state, marker);
|
||||
case 4: {
|
||||
memgraph::metrics::IncrementCounter(memgraph::metrics::BoltMessages);
|
||||
if (session.version_.minor >= 3) {
|
||||
return RunHandlerV4<TSession, 3>(signature, session, state, marker);
|
||||
}
|
||||
@@ -113,6 +151,8 @@ State StateExecutingRun(TSession &session, State state) {
|
||||
}
|
||||
return RunHandlerV4<TSession>(signature, session, state, marker);
|
||||
}
|
||||
case 5:
|
||||
return RunHandlerV5<TSession>(signature, session, state, marker);
|
||||
default:
|
||||
spdlog::trace("Unsupported bolt version:{}.{})!", session.version_.major, session.version_.minor);
|
||||
return State::Close;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -12,6 +12,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
@@ -22,6 +23,7 @@
|
||||
#include "communication/bolt/v1/state.hpp"
|
||||
#include "communication/bolt/v1/value.hpp"
|
||||
#include "communication/exceptions.hpp"
|
||||
#include "storage/v2/property_value.hpp"
|
||||
#include "utils/logging.hpp"
|
||||
#include "utils/message.hpp"
|
||||
|
||||
@@ -71,42 +73,25 @@ inline std::pair<std::string, std::string> ExceptionToErrorMessage(const std::ex
|
||||
"should be in database logs."};
|
||||
}
|
||||
|
||||
namespace details {
|
||||
namespace helpers {
|
||||
|
||||
template <typename TSession>
|
||||
State HandleRun(TSession &session, const State state, const Value &query, const Value ¶ms) {
|
||||
if (state != State::Idle) {
|
||||
// Client could potentially recover if we move to error state, but there is
|
||||
// no legitimate situation in which well working client would end up in this
|
||||
// situation.
|
||||
spdlog::trace("Unexpected RUN command!");
|
||||
return State::Close;
|
||||
}
|
||||
|
||||
DMG_ASSERT(!session.encoder_buffer_.HasData(), "There should be no data to write in this state");
|
||||
|
||||
spdlog::debug("[Run] '{}'", query.ValueString());
|
||||
|
||||
try {
|
||||
// Interpret can throw.
|
||||
const auto [header, qid] = session.Interpret(query.ValueString(), params.ValueMap());
|
||||
// Convert std::string to Value
|
||||
std::vector<Value> vec;
|
||||
std::map<std::string, Value> data;
|
||||
vec.reserve(header.size());
|
||||
for (auto &i : header) vec.emplace_back(std::move(i));
|
||||
data.emplace("fields", std::move(vec));
|
||||
// Send the header.
|
||||
if (!session.encoder_.MessageSuccess(data)) {
|
||||
spdlog::trace("Couldn't send query header!");
|
||||
return State::Close;
|
||||
}
|
||||
return State::Result;
|
||||
} catch (const std::exception &e) {
|
||||
return HandleFailure(session, e);
|
||||
/** Extracts metadata from the extras field.
|
||||
* NOTE: In order to avoid a copy, the metadata in moved.
|
||||
* TODO: Update if extra field is used for anything else.
|
||||
*/
|
||||
inline std::map<std::string, Value> ConsumeMetadata(Value &extra) {
|
||||
std::map<std::string, Value> md;
|
||||
auto &md_tv = extra.ValueMap()["tx_metadata"];
|
||||
if (md_tv.IsMap()) {
|
||||
md = std::move(md_tv.ValueMap());
|
||||
}
|
||||
return md;
|
||||
}
|
||||
|
||||
} // namespace helpers
|
||||
|
||||
namespace details {
|
||||
|
||||
template <bool is_pull, typename TSession>
|
||||
State HandlePullDiscard(TSession &session, std::optional<int> n, std::optional<int> qid) {
|
||||
try {
|
||||
@@ -229,7 +214,36 @@ State HandleRunV1(TSession &session, const State state, const Marker marker) {
|
||||
return State::Close;
|
||||
}
|
||||
|
||||
return details::HandleRun(session, state, query, params);
|
||||
if (state != State::Idle) {
|
||||
// Client could potentially recover if we move to error state, but there is
|
||||
// no legitimate situation in which well working client would end up in this
|
||||
// situation.
|
||||
spdlog::trace("Unexpected RUN command!");
|
||||
return State::Close;
|
||||
}
|
||||
|
||||
DMG_ASSERT(!session.encoder_buffer_.HasData(), "There should be no data to write in this state");
|
||||
|
||||
spdlog::debug("[Run] '{}'", query.ValueString());
|
||||
|
||||
try {
|
||||
// Interpret can throw.
|
||||
const auto [header, qid] = session.Interpret(query.ValueString(), params.ValueMap(), {});
|
||||
// Convert std::string to Value
|
||||
std::vector<Value> vec;
|
||||
std::map<std::string, Value> data;
|
||||
vec.reserve(header.size());
|
||||
for (auto &i : header) vec.emplace_back(std::move(i));
|
||||
data.emplace("fields", std::move(vec));
|
||||
// Send the header.
|
||||
if (!session.encoder_.MessageSuccess(data)) {
|
||||
spdlog::trace("Couldn't send query header!");
|
||||
return State::Close;
|
||||
}
|
||||
return State::Result;
|
||||
} catch (const std::exception &e) {
|
||||
return HandleFailure(session, e);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TSession>
|
||||
@@ -255,9 +269,50 @@ State HandleRunV4(TSession &session, const State state, const Marker marker) {
|
||||
// Even though this part seems unnecessary it is needed to move the buffer
|
||||
if (!session.decoder_.ReadValue(&extra, Value::Type::Map)) {
|
||||
spdlog::trace("Couldn't read extra field!");
|
||||
return State::Close;
|
||||
}
|
||||
|
||||
return details::HandleRun(session, state, query, params);
|
||||
if (state != State::Idle) {
|
||||
// Client could potentially recover if we move to error state, but there is
|
||||
// no legitimate situation in which well working client would end up in this
|
||||
// situation.
|
||||
spdlog::trace("Unexpected RUN command!");
|
||||
return State::Close;
|
||||
}
|
||||
|
||||
DMG_ASSERT(!session.encoder_buffer_.HasData(), "There should be no data to write in this state");
|
||||
|
||||
spdlog::debug("[Run] '{}'", query.ValueString());
|
||||
|
||||
try {
|
||||
// Interpret can throw.
|
||||
const auto [header, qid] =
|
||||
session.Interpret(query.ValueString(), params.ValueMap(), helpers::ConsumeMetadata(extra));
|
||||
// Convert std::string to Value
|
||||
std::vector<Value> vec;
|
||||
std::map<std::string, Value> data;
|
||||
vec.reserve(header.size());
|
||||
for (auto &i : header) vec.emplace_back(std::move(i));
|
||||
data.emplace("fields", std::move(vec));
|
||||
if (qid.has_value()) {
|
||||
data.emplace("qid", Value{*qid});
|
||||
}
|
||||
|
||||
// Send the header.
|
||||
if (!session.encoder_.MessageSuccess(data)) {
|
||||
spdlog::trace("Couldn't send query header!");
|
||||
return State::Close;
|
||||
}
|
||||
return State::Result;
|
||||
} catch (const std::exception &e) {
|
||||
return HandleFailure(session, e);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TSession>
|
||||
State HandleRunV5(TSession &session, const State state, const Marker marker) {
|
||||
// Using V4 on purpose
|
||||
return HandleRunV4<TSession>(session, state, marker);
|
||||
}
|
||||
|
||||
template <typename TSession>
|
||||
@@ -270,6 +325,12 @@ State HandlePullV4(TSession &session, const State state, const Marker marker) {
|
||||
return details::HandlePullDiscardV4<true>(session, state, marker);
|
||||
}
|
||||
|
||||
template <typename TSession>
|
||||
State HandlePullV5(TSession &session, const State state, const Marker marker) {
|
||||
// Using V4 on purpose
|
||||
return HandlePullV4<TSession>(session, state, marker);
|
||||
}
|
||||
|
||||
template <typename TSession>
|
||||
State HandleDiscardV1(TSession &session, const State state, const Marker marker) {
|
||||
return details::HandlePullDiscardV1<false>(session, state, marker);
|
||||
@@ -280,6 +341,12 @@ State HandleDiscardV4(TSession &session, const State state, const Marker marker)
|
||||
return details::HandlePullDiscardV4<false>(session, state, marker);
|
||||
}
|
||||
|
||||
template <typename TSession>
|
||||
State HandleDiscardV5(TSession &session, const State state, const Marker marker) {
|
||||
// Using V4 on purpose
|
||||
return HandleDiscardV4<TSession>(session, state, marker);
|
||||
}
|
||||
|
||||
template <typename TSession>
|
||||
State HandleReset(TSession &session, const Marker marker) {
|
||||
// IMPORTANT: This implementation of the Bolt RESET command isn't fully
|
||||
@@ -332,7 +399,7 @@ State HandleBegin(TSession &session, const State state, const Marker marker) {
|
||||
}
|
||||
|
||||
try {
|
||||
session.BeginTransaction();
|
||||
session.BeginTransaction(helpers::ConsumeMetadata(extra));
|
||||
} catch (const std::exception &e) {
|
||||
return HandleFailure(session, e);
|
||||
}
|
||||
@@ -437,4 +504,10 @@ State HandleRoute(TSession &session, const Marker marker) {
|
||||
}
|
||||
return State::Error;
|
||||
}
|
||||
|
||||
template <typename TSession>
|
||||
State HandleLogOff() {
|
||||
// Not arguments sent, the user just needs to reauthenticate
|
||||
return State::Init;
|
||||
}
|
||||
} // namespace memgraph::communication::bolt
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -27,17 +27,25 @@ namespace details {
|
||||
template <typename TSession>
|
||||
std::optional<State> AuthenticateUser(TSession &session, Value &metadata) {
|
||||
// Get authentication data.
|
||||
// From neo4j driver v4.4, fields that have a default value are not sent.
|
||||
// In order to have back-compatibility, the missing fields will be added.
|
||||
|
||||
auto &data = metadata.ValueMap();
|
||||
if (!data.count("scheme")) {
|
||||
spdlog::warn("The client didn't supply authentication information!");
|
||||
return State::Close;
|
||||
if (data.empty()) { // Special case auth=None
|
||||
spdlog::warn("The client didn't supply the authentication scheme! Trying with \"none\"...");
|
||||
data["scheme"] = "none";
|
||||
}
|
||||
|
||||
std::string username;
|
||||
std::string password;
|
||||
if (data["scheme"].ValueString() == "basic") {
|
||||
if (!data.count("principal") || !data.count("credentials")) {
|
||||
spdlog::warn("The client didn't supply authentication information!");
|
||||
return State::Close;
|
||||
if (!data.count("principal")) { // Special case principal = ""
|
||||
spdlog::warn("The client didn't supply the principal field! Trying with \"\"...");
|
||||
data["principal"] = "";
|
||||
}
|
||||
if (!data.count("credentials")) { // Special case credentials = ""
|
||||
spdlog::warn("The client didn't supply the credentials field! Trying with \"\"...");
|
||||
data["credentials"] = "";
|
||||
}
|
||||
username = data["principal"].ValueString();
|
||||
password = data["credentials"].ValueString();
|
||||
@@ -106,6 +114,30 @@ std::optional<Value> GetMetadataV4(TSession &session, const Marker marker) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto &data = metadata.ValueMap();
|
||||
if (!data.count("user_agent")) {
|
||||
spdlog::warn("The client didn't supply the user agent!");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
spdlog::info("Client connected '{}'", data.at("user_agent").ValueString());
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
template <typename TSession>
|
||||
std::optional<Value> GetInitDataV5(TSession &session, const Marker marker) {
|
||||
if (marker != Marker::TinyStruct1) [[unlikely]] {
|
||||
spdlog::trace("Expected TinyStruct1 marker, but received 0x{:02X}!", utils::UnderlyingCast(marker));
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
Value metadata;
|
||||
if (!session.decoder_.ReadValue(&metadata, Value::Type::Map)) {
|
||||
spdlog::trace("Couldn't read metadata!");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto &data = metadata.ValueMap();
|
||||
if (!data.count("user_agent")) {
|
||||
spdlog::warn("The client didn't supply the user agent!");
|
||||
@@ -117,6 +149,22 @@ std::optional<Value> GetMetadataV4(TSession &session, const Marker marker) {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
template <typename TSession>
|
||||
std::optional<Value> GetAuthDataV5(TSession &session, const Marker marker) {
|
||||
if (marker != Marker::TinyStruct1) [[unlikely]] {
|
||||
spdlog::trace("Expected TinyStruct1 marker, but received 0x{:02X}!", utils::UnderlyingCast(marker));
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
Value metadata;
|
||||
if (!session.decoder_.ReadValue(&metadata, Value::Type::Map)) {
|
||||
spdlog::trace("Couldn't read metadata!");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
template <typename TSession>
|
||||
State SendSuccessMessage(TSession &session) {
|
||||
// Neo4j's Java driver 4.1.1+ requires connection_id.
|
||||
@@ -180,6 +228,57 @@ State StateInitRunV4(TSession &session, Marker marker, Signature signature) {
|
||||
|
||||
return SendSuccessMessage(session);
|
||||
}
|
||||
|
||||
template <typename TSession>
|
||||
State StateInitRunV5(TSession &session, Marker marker, Signature signature) {
|
||||
if (signature == Signature::Noop) [[unlikely]] {
|
||||
SPDLOG_DEBUG("Received NOOP message");
|
||||
return State::Init;
|
||||
}
|
||||
|
||||
if (signature == Signature::Init) {
|
||||
auto maybeMetadata = GetInitDataV5(session, marker);
|
||||
|
||||
if (!maybeMetadata) {
|
||||
return State::Close;
|
||||
}
|
||||
|
||||
if (SendSuccessMessage(session) == State::Close) {
|
||||
return State::Close;
|
||||
}
|
||||
// Stay in Init
|
||||
return State::Init;
|
||||
|
||||
} else if (signature == Signature::LogOn) {
|
||||
if (marker != Marker::TinyStruct1) [[unlikely]] {
|
||||
spdlog::trace("Expected TinyStruct1 marker, but received 0x{:02X}!", utils::UnderlyingCast(marker));
|
||||
spdlog::trace(
|
||||
"The client sent malformed data, but we are continuing "
|
||||
"because the official Neo4j Java driver sends malformed "
|
||||
"data. D'oh!");
|
||||
return State::Close;
|
||||
}
|
||||
|
||||
auto maybeMetadata = GetAuthDataV5(session, marker);
|
||||
if (!maybeMetadata) {
|
||||
return State::Close;
|
||||
}
|
||||
auto result = AuthenticateUser(session, *maybeMetadata);
|
||||
if (result) {
|
||||
spdlog::trace("Failed to authenticate, closing connection...");
|
||||
return State::Close;
|
||||
}
|
||||
|
||||
if (SendSuccessMessage(session) == State::Close) {
|
||||
return State::Close;
|
||||
}
|
||||
return State::Idle;
|
||||
|
||||
} else [[unlikely]] {
|
||||
spdlog::trace("Expected Init signature, but received 0x{:02X}!", utils::UnderlyingCast(signature));
|
||||
return State::Close;
|
||||
}
|
||||
}
|
||||
} // namespace details
|
||||
|
||||
/**
|
||||
@@ -208,6 +307,9 @@ State StateInitRun(TSession &session) {
|
||||
}
|
||||
return details::StateInitRunV4<TSession>(session, marker, signature);
|
||||
}
|
||||
case 5: {
|
||||
return details::StateInitRunV5<TSession>(session, marker, signature);
|
||||
}
|
||||
}
|
||||
spdlog::trace("Unsupported bolt version:{}.{})!", session.version_.major, session.version_.minor);
|
||||
return State::Close;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -342,6 +342,9 @@ std::ostream &operator<<(std::ostream &os, const Vertex &vertex) {
|
||||
[&](auto &stream, const auto &pair) { stream << pair.first << ": " << pair.second; });
|
||||
os << "}";
|
||||
}
|
||||
if (!vertex.element_id.empty()) {
|
||||
os << " element_id: " << vertex.element_id;
|
||||
}
|
||||
return os << ")";
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -57,6 +57,7 @@ struct Vertex {
|
||||
Id id;
|
||||
std::vector<std::string> labels;
|
||||
std::map<std::string, Value> properties;
|
||||
std::string element_id;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -69,6 +70,9 @@ struct Edge {
|
||||
Id to;
|
||||
std::string type;
|
||||
std::map<std::string, Value> properties;
|
||||
std::string element_id;
|
||||
std::string from_element_id;
|
||||
std::string to_element_id;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -79,6 +83,7 @@ struct UnboundedEdge {
|
||||
Id id;
|
||||
std::string type;
|
||||
std::map<std::string, Value> properties;
|
||||
std::string element_id;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
108
src/communication/http/listener.hpp
Normal file
108
src/communication/http/listener.hpp
Normal file
@@ -0,0 +1,108 @@
|
||||
// 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 <list>
|
||||
#include <memory>
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/beast/core.hpp>
|
||||
|
||||
#include "communication/context.hpp"
|
||||
#include "communication/http/session.hpp"
|
||||
#include "utils/spin_lock.hpp"
|
||||
#include "utils/synchronized.hpp"
|
||||
|
||||
namespace memgraph::communication::http {
|
||||
|
||||
template <class TRequestHandler, typename TSessionData>
|
||||
class Listener final : public std::enable_shared_from_this<Listener<TRequestHandler, TSessionData>> {
|
||||
using tcp = boost::asio::ip::tcp;
|
||||
using SessionHandler = Session<TRequestHandler, TSessionData>;
|
||||
using std::enable_shared_from_this<Listener<TRequestHandler, TSessionData>>::shared_from_this;
|
||||
|
||||
public:
|
||||
Listener(const Listener &) = delete;
|
||||
Listener(Listener &&) = delete;
|
||||
Listener &operator=(const Listener &) = delete;
|
||||
Listener &operator=(Listener &&) = delete;
|
||||
~Listener() {}
|
||||
|
||||
template <typename... Args>
|
||||
static std::shared_ptr<Listener> Create(Args &&...args) {
|
||||
return std::shared_ptr<Listener>{new Listener(std::forward<Args>(args)...)};
|
||||
}
|
||||
|
||||
// Start accepting incoming connections
|
||||
void Run() { DoAccept(); }
|
||||
tcp::endpoint GetEndpoint() const { return acceptor_.local_endpoint(); }
|
||||
|
||||
private:
|
||||
Listener(boost::asio::io_context &ioc, TSessionData *data, ServerContext *context, tcp::endpoint endpoint)
|
||||
: ioc_(ioc), data_(data), context_(context), acceptor_(ioc) {
|
||||
boost::beast::error_code ec;
|
||||
|
||||
// Open the acceptor
|
||||
acceptor_.open(endpoint.protocol(), ec);
|
||||
if (ec) {
|
||||
LogError(ec, "open");
|
||||
return;
|
||||
}
|
||||
|
||||
// Allow address reuse
|
||||
acceptor_.set_option(boost::asio::socket_base::reuse_address(true), ec);
|
||||
if (ec) {
|
||||
LogError(ec, "set_option");
|
||||
return;
|
||||
}
|
||||
|
||||
// Bind to the server address
|
||||
acceptor_.bind(endpoint, ec);
|
||||
if (ec) {
|
||||
LogError(ec, "bind");
|
||||
return;
|
||||
}
|
||||
|
||||
acceptor_.listen(boost::asio::socket_base::max_listen_connections, ec);
|
||||
if (ec) {
|
||||
LogError(ec, "listen");
|
||||
return;
|
||||
}
|
||||
|
||||
spdlog::info("HTTP server is listening on {}:{}", endpoint.address(), endpoint.port());
|
||||
}
|
||||
|
||||
void DoAccept() {
|
||||
acceptor_.async_accept(ioc_, [shared_this = shared_from_this()](auto ec, auto socket) {
|
||||
shared_this->OnAccept(ec, std::move(socket));
|
||||
});
|
||||
}
|
||||
|
||||
void OnAccept(boost::beast::error_code ec, tcp::socket socket) {
|
||||
if (ec) {
|
||||
return LogError(ec, "accept");
|
||||
}
|
||||
|
||||
SessionHandler::Create(std::move(socket), data_, *context_)->Run();
|
||||
|
||||
DoAccept();
|
||||
}
|
||||
|
||||
boost::asio::io_context &ioc_;
|
||||
TSessionData *data_;
|
||||
ServerContext *context_;
|
||||
tcp::acceptor acceptor_;
|
||||
};
|
||||
} // namespace memgraph::communication::http
|
||||
65
src/communication/http/server.hpp
Normal file
65
src/communication/http/server.hpp
Normal file
@@ -0,0 +1,65 @@
|
||||
// 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 <thread>
|
||||
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
|
||||
#include "communication/http/listener.hpp"
|
||||
#include "io/network/endpoint.hpp"
|
||||
|
||||
namespace memgraph::communication::http {
|
||||
|
||||
template <class TRequestHandler, typename TSessionData>
|
||||
class Server final {
|
||||
using tcp = boost::asio::ip::tcp;
|
||||
|
||||
public:
|
||||
explicit Server(io::network::Endpoint endpoint, TSessionData *data, ServerContext *context)
|
||||
: listener_{Listener<TRequestHandler, TSessionData>::Create(
|
||||
ioc_, data, context, tcp::endpoint{boost::asio::ip::make_address(endpoint.address), endpoint.port})} {}
|
||||
|
||||
Server(const Server &) = delete;
|
||||
Server(Server &&) = delete;
|
||||
Server &operator=(const Server &) = delete;
|
||||
Server &operator=(Server &&) = delete;
|
||||
|
||||
~Server() {
|
||||
MG_ASSERT(!background_thread_ || (ioc_.stopped() && !background_thread_->joinable()),
|
||||
"Server wasn't shutdown properly");
|
||||
}
|
||||
|
||||
void Start() {
|
||||
MG_ASSERT(!background_thread_, "The server was already started!");
|
||||
listener_->Run();
|
||||
background_thread_.emplace([this] { ioc_.run(); });
|
||||
}
|
||||
|
||||
void Shutdown() { ioc_.stop(); }
|
||||
|
||||
void AwaitShutdown() {
|
||||
if (background_thread_ && background_thread_->joinable()) {
|
||||
background_thread_->join();
|
||||
}
|
||||
}
|
||||
bool IsRunning() const { return background_thread_ && !ioc_.stopped(); }
|
||||
tcp::endpoint GetEndpoint() const { return listener_->GetEndpoint(); }
|
||||
|
||||
private:
|
||||
boost::asio::io_context ioc_;
|
||||
|
||||
std::shared_ptr<Listener<TRequestHandler, TSessionData>> listener_;
|
||||
std::optional<std::thread> background_thread_;
|
||||
};
|
||||
} // namespace memgraph::communication::http
|
||||
193
src/communication/http/session.hpp
Normal file
193
src/communication/http/session.hpp
Normal file
@@ -0,0 +1,193 @@
|
||||
// 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 <deque>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/dispatch.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/beast/core/buffers_to_string.hpp>
|
||||
#include <boost/beast/core/stream_traits.hpp>
|
||||
#include <boost/beast/core/tcp_stream.hpp>
|
||||
#include <boost/beast/http.hpp>
|
||||
#include <boost/beast/ssl.hpp>
|
||||
#include <boost/beast/version.hpp>
|
||||
#include <json/json.hpp>
|
||||
|
||||
#include "communication/context.hpp"
|
||||
#include "utils/logging.hpp"
|
||||
#include "utils/variant_helpers.hpp"
|
||||
|
||||
namespace memgraph::communication::http {
|
||||
|
||||
inline constexpr uint16_t kSSLExpirySeconds = 30;
|
||||
inline void LogError(boost::beast::error_code ec, const std::string_view what) {
|
||||
spdlog::warn("HTTP session failed on {}: {}", what, ec.message());
|
||||
}
|
||||
|
||||
template <class TRequestHandler, typename TSessionData>
|
||||
class Session : public std::enable_shared_from_this<Session<TRequestHandler, TSessionData>> {
|
||||
using tcp = boost::asio::ip::tcp;
|
||||
using std::enable_shared_from_this<Session<TRequestHandler, TSessionData>>::shared_from_this;
|
||||
|
||||
public:
|
||||
template <typename... Args>
|
||||
static std::shared_ptr<Session> Create(Args &&...args) {
|
||||
return std::shared_ptr<Session>{new Session{std::forward<Args>(args)...}};
|
||||
}
|
||||
|
||||
void Run() {
|
||||
if (auto *ssl = std::get_if<SSLSocket>(&stream_); ssl != nullptr) {
|
||||
try {
|
||||
boost::beast::get_lowest_layer(*ssl).expires_after(std::chrono::seconds(kSSLExpirySeconds));
|
||||
ssl->handshake(boost::asio::ssl::stream_base::server);
|
||||
} catch (const boost::system::system_error &e) {
|
||||
spdlog::warn("Failed on SSL handshake: {}", e.what());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// run on the strand
|
||||
boost::asio::dispatch(strand_, [shared_this = shared_from_this()] { shared_this->DoRead(); });
|
||||
}
|
||||
|
||||
private:
|
||||
using PlainSocket = boost::beast::tcp_stream;
|
||||
using SSLSocket = boost::beast::ssl_stream<boost::beast::tcp_stream>;
|
||||
|
||||
explicit Session(tcp::socket &&socket, TSessionData *data, ServerContext &context)
|
||||
: stream_(CreateSocket(std::move(socket), context)),
|
||||
handler_(data),
|
||||
strand_{boost::asio::make_strand(GetExecutor())} {}
|
||||
|
||||
std::variant<PlainSocket, SSLSocket> CreateSocket(tcp::socket &&socket, ServerContext &context) {
|
||||
if (context.use_ssl()) {
|
||||
ssl_context_.emplace(context.context_clone());
|
||||
return Session::SSLSocket{std::move(socket), *ssl_context_};
|
||||
}
|
||||
|
||||
return Session::PlainSocket{std::move(socket)};
|
||||
}
|
||||
|
||||
void OnWrite(boost::beast::error_code ec, size_t bytes_transferred) {
|
||||
boost::ignore_unused(bytes_transferred);
|
||||
|
||||
if (ec) {
|
||||
close_ = true;
|
||||
return LogError(ec, "write");
|
||||
}
|
||||
|
||||
if (close_) {
|
||||
DoClose();
|
||||
return;
|
||||
}
|
||||
|
||||
res_ = nullptr;
|
||||
|
||||
DoRead();
|
||||
}
|
||||
|
||||
void DoRead() {
|
||||
req_ = {};
|
||||
|
||||
ExecuteForStream([this](auto &&stream) {
|
||||
boost::beast::get_lowest_layer(stream).expires_after(std::chrono::seconds(kSSLExpirySeconds));
|
||||
|
||||
boost::beast::http::async_read(
|
||||
stream, buffer_, req_,
|
||||
boost::asio::bind_executor(strand_, std::bind_front(&Session::OnRead, shared_from_this())));
|
||||
});
|
||||
}
|
||||
|
||||
void OnRead(boost::beast::error_code ec, size_t bytes_transferred) {
|
||||
boost::ignore_unused(bytes_transferred);
|
||||
|
||||
if (ec == boost::beast::http::error::end_of_stream) {
|
||||
DoClose();
|
||||
return;
|
||||
}
|
||||
|
||||
if (ec) {
|
||||
return LogError(ec, "read");
|
||||
}
|
||||
|
||||
auto async_write = [this](boost::beast::http::response<boost::beast::http::string_body> msg) {
|
||||
ExecuteForStream([this, &msg](auto &&stream) {
|
||||
// The lifetime of the message has to extend
|
||||
// for the duration of the async operation so
|
||||
// we use a shared_ptr to manage it.
|
||||
auto sp = std::make_shared<boost::beast::http::response<boost::beast::http::string_body>>(std::move(msg));
|
||||
|
||||
// Store a type-erased version of the shared
|
||||
// pointer in the class to keep it alive.
|
||||
res_ = sp;
|
||||
// Write the response
|
||||
boost::beast::http::async_write(
|
||||
stream, *sp, boost::asio::bind_executor(strand_, std::bind_front(&Session::OnWrite, shared_from_this())));
|
||||
});
|
||||
};
|
||||
|
||||
// handle request
|
||||
handler_.HandleRequest(std::move(req_), async_write);
|
||||
}
|
||||
|
||||
void DoClose() {
|
||||
std::visit(utils::Overloaded{[this](SSLSocket &stream) {
|
||||
boost::beast::get_lowest_layer(stream).expires_after(std::chrono::seconds(30));
|
||||
|
||||
// Perform the SSL shutdown
|
||||
stream.async_shutdown(
|
||||
boost::beast::bind_front_handler(&Session::OnClose, shared_from_this()));
|
||||
},
|
||||
[](PlainSocket &stream) {
|
||||
boost::beast::error_code ec;
|
||||
stream.socket().shutdown(tcp::socket::shutdown_send, ec);
|
||||
}},
|
||||
stream_);
|
||||
}
|
||||
void OnClose(boost::beast::error_code ec) {
|
||||
if (ec) {
|
||||
LogError(ec, "close");
|
||||
}
|
||||
|
||||
// At this point the connection is closed gracefully
|
||||
}
|
||||
|
||||
auto GetExecutor() {
|
||||
return std::visit(utils::Overloaded{[](auto &&stream) { return stream.get_executor(); }}, stream_);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
decltype(auto) ExecuteForStream(F &&fn) {
|
||||
return std::visit(utils::Overloaded{std::forward<F>(fn)}, stream_);
|
||||
}
|
||||
|
||||
std::optional<std::reference_wrapper<boost::asio::ssl::context>> ssl_context_;
|
||||
std::variant<PlainSocket, SSLSocket> stream_;
|
||||
boost::beast::flat_buffer buffer_;
|
||||
|
||||
TRequestHandler handler_;
|
||||
boost::beast::http::request<boost::beast::http::string_body> req_;
|
||||
std::shared_ptr<void> res_;
|
||||
|
||||
boost::asio::strand<boost::beast::tcp_stream::executor_type> strand_;
|
||||
bool close_{false};
|
||||
};
|
||||
} // namespace memgraph::communication::http
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "communication/context.hpp"
|
||||
#include "communication/v2/pool.hpp"
|
||||
#include "communication/v2/session.hpp"
|
||||
#include "utils/message.hpp"
|
||||
#include "utils/spin_lock.hpp"
|
||||
#include "utils/synchronized.hpp"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -41,11 +41,21 @@
|
||||
#include <boost/beast/websocket/rfc6455.hpp>
|
||||
#include <boost/system/detail/error_code.hpp>
|
||||
|
||||
#include "communication/buffer.hpp"
|
||||
#include "communication/context.hpp"
|
||||
#include "communication/exceptions.hpp"
|
||||
#include "utils/event_counter.hpp"
|
||||
#include "utils/logging.hpp"
|
||||
#include "utils/on_scope_exit.hpp"
|
||||
#include "utils/variant_helpers.hpp"
|
||||
|
||||
namespace memgraph::metrics {
|
||||
extern const Event ActiveSessions;
|
||||
extern const Event ActiveTCPSessions;
|
||||
extern const Event ActiveSSLSessions;
|
||||
extern const Event ActiveWebSocketSessions;
|
||||
} // namespace memgraph::metrics
|
||||
|
||||
namespace memgraph::communication::v2 {
|
||||
|
||||
/**
|
||||
@@ -99,6 +109,8 @@ class WebsocketSession : public std::enable_shared_from_this<WebsocketSession<TS
|
||||
// Start the asynchronous accept operation
|
||||
template <class Body, class Allocator>
|
||||
void DoAccept(boost::beast::http::request<Body, boost::beast::http::basic_fields<Allocator>> req) {
|
||||
memgraph::metrics::IncrementCounter(memgraph::metrics::ActiveWebSocketSessions);
|
||||
|
||||
execution_active_ = true;
|
||||
// Set suggested timeout settings for the websocket
|
||||
ws_.set_option(boost::beast::websocket::stream_base::timeout::suggested(boost::beast::role_type::server));
|
||||
@@ -213,6 +225,10 @@ class WebsocketSession : public std::enable_shared_from_this<WebsocketSession<TS
|
||||
if (!IsConnected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
memgraph::metrics::DecrementCounter(memgraph::metrics::ActiveSessions);
|
||||
memgraph::metrics::DecrementCounter(memgraph::metrics::ActiveWebSocketSessions);
|
||||
|
||||
if (ec) {
|
||||
return OnError(ec, "close");
|
||||
}
|
||||
@@ -259,12 +275,19 @@ class Session final : public std::enable_shared_from_this<Session<TSession, TSes
|
||||
if (execution_active_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memgraph::metrics::IncrementCounter(memgraph::metrics::ActiveSessions);
|
||||
|
||||
execution_active_ = true;
|
||||
timeout_timer_.async_wait(boost::asio::bind_executor(strand_, std::bind(&Session::OnTimeout, shared_from_this())));
|
||||
|
||||
if (std::holds_alternative<SSLSocket>(socket_)) {
|
||||
utils::OnScopeExit increment_counter(
|
||||
[] { memgraph::metrics::IncrementCounter(memgraph::metrics::ActiveSSLSessions); });
|
||||
boost::asio::dispatch(strand_, [shared_this = shared_from_this()] { shared_this->DoHandshake(); });
|
||||
} else {
|
||||
utils::OnScopeExit increment_counter(
|
||||
[] { memgraph::metrics::IncrementCounter(memgraph::metrics::ActiveTCPSessions); });
|
||||
boost::asio::dispatch(strand_, [shared_this = shared_from_this()] { shared_this->DoRead(); });
|
||||
}
|
||||
return true;
|
||||
@@ -450,6 +473,14 @@ class Session final : public std::enable_shared_from_this<Session<TSession, TSes
|
||||
}
|
||||
|
||||
void OnClose(const boost::system::error_code &ec) {
|
||||
if (ssl_context_.has_value()) {
|
||||
memgraph::metrics::DecrementCounter(memgraph::metrics::ActiveSSLSessions);
|
||||
} else {
|
||||
memgraph::metrics::DecrementCounter(memgraph::metrics::ActiveTCPSessions);
|
||||
}
|
||||
|
||||
memgraph::metrics::DecrementCounter(memgraph::metrics::ActiveSessions);
|
||||
|
||||
if (ec) {
|
||||
return OnError(ec);
|
||||
}
|
||||
@@ -465,7 +496,7 @@ class Session final : public std::enable_shared_from_this<Session<TSession, TSes
|
||||
if (timeout_timer_.expiry() <= boost::asio::steady_timer::clock_type::now()) {
|
||||
// The deadline has passed. Stop the session. The other actors will
|
||||
// terminate as soon as possible.
|
||||
spdlog::info("Shutting down session after {} of inactivity", timeout_seconds_);
|
||||
spdlog::info("Shutting down session after {} seconds of inactivity", timeout_seconds_.count());
|
||||
DoShutdown();
|
||||
} else {
|
||||
// Put the actor back to sleep.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -58,6 +58,10 @@ auth::Permission PrivilegeToPermission(query::AuthQuery::Privilege privilege) {
|
||||
return auth::Permission::MODULE_WRITE;
|
||||
case query::AuthQuery::Privilege::WEBSOCKET:
|
||||
return auth::Permission::WEBSOCKET;
|
||||
case query::AuthQuery::Privilege::STORAGE_MODE:
|
||||
return auth::Permission::STORAGE_MODE;
|
||||
case query::AuthQuery::Privilege::TRANSACTION_MANAGEMENT:
|
||||
return auth::Permission::TRANSACTION_MANAGEMENT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -14,8 +14,9 @@
|
||||
#include "auth/auth.hpp"
|
||||
#include "auth/models.hpp"
|
||||
#include "glue/auth.hpp"
|
||||
#include "license/license.hpp"
|
||||
#include "query/constants.hpp"
|
||||
#include "query/frontend/ast/ast.hpp"
|
||||
#include "utils/license.hpp"
|
||||
#include "utils/synchronized.hpp"
|
||||
|
||||
#ifdef MG_ENTERPRISE
|
||||
@@ -23,7 +24,7 @@ namespace {
|
||||
bool IsUserAuthorizedLabels(const memgraph::auth::User &user, const memgraph::query::DbAccessor *dba,
|
||||
const std::vector<memgraph::storage::LabelId> &labels,
|
||||
const memgraph::query::AuthQuery::FineGrainedPrivilege fine_grained_privilege) {
|
||||
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (!memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
return true;
|
||||
}
|
||||
return std::all_of(labels.begin(), labels.end(), [dba, &user, fine_grained_privilege](const auto &label) {
|
||||
@@ -35,26 +36,26 @@ bool IsUserAuthorizedLabels(const memgraph::auth::User &user, const memgraph::qu
|
||||
|
||||
bool IsUserAuthorizedGloballyLabels(const memgraph::auth::User &user,
|
||||
const memgraph::auth::FineGrainedPermission fine_grained_permission) {
|
||||
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (!memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
return true;
|
||||
}
|
||||
return user.GetFineGrainedAccessLabelPermissions().Has(memgraph::auth::kAsterisk, fine_grained_permission) ==
|
||||
return user.GetFineGrainedAccessLabelPermissions().Has(memgraph::query::kAsterisk, fine_grained_permission) ==
|
||||
memgraph::auth::PermissionLevel::GRANT;
|
||||
}
|
||||
|
||||
bool IsUserAuthorizedGloballyEdges(const memgraph::auth::User &user,
|
||||
const memgraph::auth::FineGrainedPermission fine_grained_permission) {
|
||||
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (!memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
return true;
|
||||
}
|
||||
return user.GetFineGrainedAccessEdgeTypePermissions().Has(memgraph::auth::kAsterisk, fine_grained_permission) ==
|
||||
return user.GetFineGrainedAccessEdgeTypePermissions().Has(memgraph::query::kAsterisk, fine_grained_permission) ==
|
||||
memgraph::auth::PermissionLevel::GRANT;
|
||||
}
|
||||
|
||||
bool IsUserAuthorizedEdgeType(const memgraph::auth::User &user, const memgraph::query::DbAccessor *dba,
|
||||
const memgraph::storage::EdgeTypeId &edgeType,
|
||||
const memgraph::query::AuthQuery::FineGrainedPrivilege fine_grained_privilege) {
|
||||
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (!memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
return true;
|
||||
}
|
||||
return user.GetFineGrainedAccessEdgeTypePermissions().Has(
|
||||
@@ -84,10 +85,11 @@ bool AuthChecker::IsUserAuthorized(const std::optional<std::string> &username,
|
||||
|
||||
return maybe_user.has_value() && IsUserAuthorized(*maybe_user, privileges);
|
||||
}
|
||||
|
||||
#ifdef MG_ENTERPRISE
|
||||
std::unique_ptr<memgraph::query::FineGrainedAuthChecker> AuthChecker::GetFineGrainedAuthChecker(
|
||||
const std::string &username, const memgraph::query::DbAccessor *dba) const {
|
||||
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (!memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
return {};
|
||||
}
|
||||
try {
|
||||
@@ -154,7 +156,7 @@ bool FineGrainedAuthChecker::Has(const memgraph::storage::EdgeTypeId &edge_type,
|
||||
|
||||
bool FineGrainedAuthChecker::HasGlobalPrivilegeOnVertices(
|
||||
const memgraph::query::AuthQuery::FineGrainedPrivilege fine_grained_privilege) const {
|
||||
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (!memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
return true;
|
||||
}
|
||||
return IsUserAuthorizedGloballyLabels(user_, FineGrainedPrivilegeToFineGrainedPermission(fine_grained_privilege));
|
||||
@@ -162,7 +164,7 @@ bool FineGrainedAuthChecker::HasGlobalPrivilegeOnVertices(
|
||||
|
||||
bool FineGrainedAuthChecker::HasGlobalPrivilegeOnEdges(
|
||||
const memgraph::query::AuthQuery::FineGrainedPrivilege fine_grained_privilege) const {
|
||||
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (!memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
return true;
|
||||
}
|
||||
return IsUserAuthorizedGloballyEdges(user_, FineGrainedPrivilegeToFineGrainedPermission(fine_grained_privilege));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -26,9 +26,11 @@ class AuthChecker : public query::AuthChecker {
|
||||
|
||||
bool IsUserAuthorized(const std::optional<std::string> &username,
|
||||
const std::vector<query::AuthQuery::Privilege> &privileges) const override;
|
||||
|
||||
#ifdef MG_ENTERPRISE
|
||||
std::unique_ptr<memgraph::query::FineGrainedAuthChecker> GetFineGrainedAuthChecker(
|
||||
const std::string &username, const memgraph::query::DbAccessor *dba) const override;
|
||||
|
||||
#endif
|
||||
[[nodiscard]] static bool IsUserAuthorized(const memgraph::auth::User &user,
|
||||
const std::vector<memgraph::query::AuthQuery::Privilege> &privileges);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -17,7 +17,8 @@
|
||||
|
||||
#include "auth/models.hpp"
|
||||
#include "glue/auth.hpp"
|
||||
#include "utils/license.hpp"
|
||||
#include "license/license.hpp"
|
||||
#include "query/constants.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -125,7 +126,7 @@ std::vector<FineGrainedPermissionForPrivilegeResult> GetFineGrainedPermissionFor
|
||||
const memgraph::auth::FineGrainedAccessPermissions &permissions, const std::string &permission_type,
|
||||
const std::string &user_or_role) {
|
||||
std::vector<FineGrainedPermissionForPrivilegeResult> fine_grained_permissions;
|
||||
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (!memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
return fine_grained_permissions;
|
||||
}
|
||||
const auto global_permission = permissions.GetGlobalPermission();
|
||||
@@ -166,7 +167,7 @@ std::vector<FineGrainedPermissionForPrivilegeResult> GetFineGrainedPermissionFor
|
||||
std::vector<std::vector<memgraph::query::TypedValue>> ConstructFineGrainedPrivilegesResult(
|
||||
const std::vector<FineGrainedPermissionForPrivilegeResult> &privileges) {
|
||||
std::vector<std::vector<memgraph::query::TypedValue>> grants;
|
||||
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (!memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
return {};
|
||||
}
|
||||
grants.reserve(privileges.size());
|
||||
@@ -182,7 +183,7 @@ std::vector<std::vector<memgraph::query::TypedValue>> ConstructFineGrainedPrivil
|
||||
|
||||
std::vector<std::vector<memgraph::query::TypedValue>> ShowFineGrainedUserPrivileges(
|
||||
const std::optional<memgraph::auth::User> &user) {
|
||||
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (!memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
return {};
|
||||
}
|
||||
const auto &label_permissions = user->GetFineGrainedAccessLabelPermissions();
|
||||
@@ -201,7 +202,7 @@ std::vector<std::vector<memgraph::query::TypedValue>> ShowFineGrainedUserPrivile
|
||||
|
||||
std::vector<std::vector<memgraph::query::TypedValue>> ShowFineGrainedRolePrivileges(
|
||||
const std::optional<memgraph::auth::Role> &role) {
|
||||
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (!memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
return {};
|
||||
}
|
||||
const auto &label_permissions = role->GetFineGrainedAccessLabelPermissions();
|
||||
@@ -231,13 +232,13 @@ AuthQueryHandler::AuthQueryHandler(
|
||||
bool AuthQueryHandler::CreateUser(const std::string &username, const std::optional<std::string> &password) {
|
||||
if (name_regex_string_ != kDefaultUserRoleRegex) {
|
||||
if (const auto license_check_result =
|
||||
memgraph::utils::license::global_license_checker.IsValidLicense(memgraph::utils::global_settings);
|
||||
memgraph::license::global_license_checker.IsEnterpriseValid(memgraph::utils::global_settings);
|
||||
license_check_result.HasError()) {
|
||||
throw memgraph::auth::AuthException(
|
||||
"Custom user/role regex is a Memgraph Enterprise feature. Please set the config "
|
||||
"(\"--auth-user-or-role-name-regex\") to its default value (\"{}\") or remove the flag.\n{}",
|
||||
kDefaultUserRoleRegex,
|
||||
memgraph::utils::license::LicenseCheckErrorToString(license_check_result.GetError(), "user/role regex"));
|
||||
memgraph::license::LicenseCheckErrorToString(license_check_result.GetError(), "user/role regex"));
|
||||
}
|
||||
}
|
||||
if (!std::regex_match(username, name_regex_)) {
|
||||
@@ -253,19 +254,18 @@ bool AuthQueryHandler::CreateUser(const std::string &username, const std::option
|
||||
|
||||
if (first_user) {
|
||||
spdlog::info("{} is first created user. Granting all privileges.", username);
|
||||
GrantPrivilege(username, memgraph::query::kPrivilegesAll
|
||||
GrantPrivilege(
|
||||
username, memgraph::query::kPrivilegesAll
|
||||
#ifdef MG_ENTERPRISE
|
||||
,
|
||||
{{{memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE, {memgraph::auth::kAsterisk}}}},
|
||||
{
|
||||
{
|
||||
{
|
||||
memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE, {
|
||||
memgraph::auth::kAsterisk
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
,
|
||||
{{{memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE, {memgraph::query::kAsterisk}}}},
|
||||
{
|
||||
{
|
||||
{
|
||||
memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE, { memgraph::query::kAsterisk }
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
);
|
||||
}
|
||||
@@ -473,20 +473,20 @@ std::vector<std::vector<memgraph::query::TypedValue>> AuthQueryHandler::GetPrivi
|
||||
if (user) {
|
||||
grants = ShowUserPrivileges(user);
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
fine_grained_grants = ShowFineGrainedUserPrivileges(user);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
grants = ShowRolePrivileges(role);
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
fine_grained_grants = ShowFineGrainedRolePrivileges(role);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
grants.insert(grants.end(), fine_grained_grants.begin(), fine_grained_grants.end());
|
||||
}
|
||||
#endif
|
||||
@@ -627,7 +627,7 @@ void AuthQueryHandler::EditPermissions(
|
||||
edit_permissions_fun(user->permissions(), permission);
|
||||
}
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
for (const auto &label_privilege_collection : label_privileges) {
|
||||
edit_fine_grained_permissions_fun(user->fine_grained_access_handler().label_permissions(),
|
||||
label_privilege_collection);
|
||||
@@ -644,9 +644,9 @@ void AuthQueryHandler::EditPermissions(
|
||||
edit_permissions_fun(role->permissions(), permission);
|
||||
}
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
for (const auto &label_privilege : label_privileges) {
|
||||
edit_fine_grained_permissions_fun(user->fine_grained_access_handler().label_permissions(), label_privilege);
|
||||
edit_fine_grained_permissions_fun(role->fine_grained_access_handler().label_permissions(), label_privilege);
|
||||
}
|
||||
for (const auto &edge_type_privilege : edge_type_privileges) {
|
||||
edit_fine_grained_permissions_fun(role->fine_grained_access_handler().edge_type_permissions(),
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
|
||||
#include "auth/auth.hpp"
|
||||
#include "glue/auth.hpp"
|
||||
#include "license/license.hpp"
|
||||
#include "query/interpreter.hpp"
|
||||
#include "utils/license.hpp"
|
||||
#include "utils/string.hpp"
|
||||
|
||||
namespace memgraph::glue {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -150,7 +150,9 @@ storage::Result<communication::bolt::Vertex> ToBoltVertex(const storage::VertexA
|
||||
for (const auto &prop : *maybe_properties) {
|
||||
properties[db.PropertyToName(prop.first)] = ToBoltValue(prop.second);
|
||||
}
|
||||
return communication::bolt::Vertex{id, labels, properties};
|
||||
// Introduced in Bolt v5 (for now just send the ID)
|
||||
const auto element_id = std::to_string(id.AsInt());
|
||||
return communication::bolt::Vertex{id, labels, properties, element_id};
|
||||
}
|
||||
|
||||
storage::Result<communication::bolt::Edge> ToBoltEdge(const storage::EdgeAccessor &edge, const storage::Storage &db,
|
||||
@@ -165,7 +167,11 @@ storage::Result<communication::bolt::Edge> ToBoltEdge(const storage::EdgeAccesso
|
||||
for (const auto &prop : *maybe_properties) {
|
||||
properties[db.PropertyToName(prop.first)] = ToBoltValue(prop.second);
|
||||
}
|
||||
return communication::bolt::Edge{id, from, to, type, properties};
|
||||
// Introduced in Bolt v5 (for now just send the ID)
|
||||
const auto element_id = std::to_string(id.AsInt());
|
||||
const auto from_element_id = std::to_string(from.AsInt());
|
||||
const auto to_element_id = std::to_string(to.AsInt());
|
||||
return communication::bolt::Edge{id, from, to, type, properties, element_id, from_element_id, to_element_id};
|
||||
}
|
||||
|
||||
storage::Result<communication::bolt::Path> ToBoltPath(const query::Path &path, const storage::Storage &db,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021 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
|
||||
@@ -12,6 +12,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -61,3 +62,42 @@ inline void LoadConfig(const std::string &product_name) {
|
||||
for (int i = 0; i < custom_argc; ++i) free(custom_argv[i]);
|
||||
delete[] custom_argv;
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> LoadUsernameAndPassword(const std::string &pass_file) {
|
||||
std::ifstream file(pass_file);
|
||||
if (file.fail()) {
|
||||
spdlog::warn("Problem with opening MG_PASSFILE, memgraph server will start without user");
|
||||
return {};
|
||||
}
|
||||
std::vector<std::string> result;
|
||||
|
||||
std::string line;
|
||||
std::getline(file, line);
|
||||
size_t pos = 0;
|
||||
std::string token;
|
||||
static constexpr std::string_view delimiter{":"};
|
||||
while ((pos = line.find(delimiter)) != std::string::npos) {
|
||||
if (line[pos - 1] == '\\') {
|
||||
line.erase(pos - 1, 1);
|
||||
token += line.substr(0, pos);
|
||||
line.erase(0, pos);
|
||||
|
||||
} else {
|
||||
token += line.substr(0, pos);
|
||||
result.push_back(token);
|
||||
line.erase(0, pos + delimiter.length());
|
||||
token = "";
|
||||
}
|
||||
}
|
||||
result.push_back(line);
|
||||
file.close();
|
||||
|
||||
if (result.size() != 2) {
|
||||
spdlog::warn(
|
||||
"Wrong data format. Data should be store in format: username:password, memgraph server will start without "
|
||||
"user");
|
||||
return {};
|
||||
}
|
||||
|
||||
return {result[0], result[1]};
|
||||
}
|
||||
|
||||
4
src/http_handlers/CMakeLists.txt
Normal file
4
src/http_handlers/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
set(mg_http_handlers_sources)
|
||||
|
||||
add_library(mg-http-handlers STATIC ${mg_http_handlers_sources})
|
||||
target_link_libraries(mg-http-handlers mg-query mg-storage-v2)
|
||||
211
src/http_handlers/metrics.hpp
Normal file
211
src/http_handlers/metrics.hpp
Normal file
@@ -0,0 +1,211 @@
|
||||
// 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 <atomic>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <boost/beast/http.hpp>
|
||||
#include <boost/beast/version.hpp>
|
||||
#include <json/json.hpp>
|
||||
|
||||
#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 {
|
||||
|
||||
struct MetricsResponse {
|
||||
uint64_t vertex_count;
|
||||
uint64_t edge_count;
|
||||
double average_degree;
|
||||
uint64_t memory_usage;
|
||||
uint64_t disk_usage;
|
||||
|
||||
// Storage of all the counter values throughout the system
|
||||
// e.g. number of active transactions
|
||||
std::vector<std::tuple<std::string, std::string, uint64_t>> event_counters{};
|
||||
|
||||
// Storage of all the current values throughout the system
|
||||
std::vector<std::tuple<std::string, std::string, uint64_t>> event_gauges{};
|
||||
|
||||
// Storage of all the percentile values across the histograms in the system
|
||||
// e.g. query latency percentiles, snapshot recovery duration percentiles, etc.
|
||||
std::vector<std::tuple<std::string, std::string, uint64_t>> event_histograms{};
|
||||
};
|
||||
|
||||
template <typename TSessionData>
|
||||
class MetricsService {
|
||||
public:
|
||||
explicit MetricsService(TSessionData *data) : db_(data->db) {}
|
||||
|
||||
nlohmann::json GetMetricsJSON() {
|
||||
auto response = GetMetrics();
|
||||
return AsJson(response);
|
||||
}
|
||||
|
||||
private:
|
||||
const storage::Storage *db_;
|
||||
|
||||
MetricsResponse GetMetrics() {
|
||||
auto info = db_->GetInfo();
|
||||
|
||||
return MetricsResponse{.vertex_count = info.vertex_count,
|
||||
.edge_count = info.edge_count,
|
||||
.average_degree = info.average_degree,
|
||||
.memory_usage = info.memory_usage,
|
||||
.disk_usage = info.disk_usage,
|
||||
.event_counters = GetEventCounters(),
|
||||
.event_gauges = GetEventGauges(),
|
||||
.event_histograms = GetEventHistograms()};
|
||||
}
|
||||
|
||||
nlohmann::json AsJson(MetricsResponse response) {
|
||||
auto metrics_response = nlohmann::json();
|
||||
const auto *general_type = "General";
|
||||
|
||||
metrics_response[general_type]["vertex_count"] = response.vertex_count;
|
||||
metrics_response[general_type]["edge_count"] = response.edge_count;
|
||||
metrics_response[general_type]["average_degree"] = response.average_degree;
|
||||
metrics_response[general_type]["memory_usage"] = response.memory_usage;
|
||||
metrics_response[general_type]["disk_usage"] = response.disk_usage;
|
||||
|
||||
for (const auto &[name, type, value] : response.event_counters) {
|
||||
metrics_response[type][name] = value;
|
||||
}
|
||||
|
||||
for (const auto &[name, type, value] : response.event_gauges) {
|
||||
metrics_response[type][name] = value;
|
||||
}
|
||||
|
||||
for (const auto &[name, type, value] : response.event_histograms) {
|
||||
metrics_response[type][name] = value;
|
||||
}
|
||||
|
||||
return metrics_response;
|
||||
}
|
||||
|
||||
auto GetEventCounters() {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
|
||||
std::vector<std::tuple<std::string, std::string, uint64_t>> event_counters{};
|
||||
|
||||
for (auto i = 0; i < memgraph::metrics::CounterEnd(); i++) {
|
||||
event_counters.emplace_back(memgraph::metrics::GetCounterName(i), memgraph::metrics::GetCounterType(i),
|
||||
memgraph::metrics::global_counters[i].load(std::memory_order_acquire));
|
||||
}
|
||||
|
||||
return event_counters;
|
||||
}
|
||||
|
||||
auto GetEventGauges() {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
|
||||
std::vector<std::tuple<std::string, std::string, uint64_t>> event_gauges{};
|
||||
|
||||
for (auto i = 0; i < memgraph::metrics::GaugeEnd(); i++) {
|
||||
event_gauges.emplace_back(memgraph::metrics::GetGaugeName(i), memgraph::metrics::GetGaugeType(i),
|
||||
memgraph::metrics::global_gauges[i].load(std::memory_order_acquire));
|
||||
}
|
||||
|
||||
return event_gauges;
|
||||
}
|
||||
|
||||
auto GetEventHistograms() {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
|
||||
std::vector<std::tuple<std::string, std::string, uint64_t>> event_histograms{};
|
||||
|
||||
for (auto i = 0; i < memgraph::metrics::HistogramEnd(); i++) {
|
||||
const auto *name = memgraph::metrics::GetHistogramName(i);
|
||||
auto &histogram = memgraph::metrics::global_histograms[i];
|
||||
|
||||
for (auto &[percentile, value] : histogram.YieldPercentiles()) {
|
||||
auto metric_name = std::string(name) + "_" + std::to_string(percentile) + "p";
|
||||
|
||||
event_histograms.emplace_back(metric_name, memgraph::metrics::GetHistogramType(i), value);
|
||||
}
|
||||
}
|
||||
|
||||
return event_histograms;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TSessionData>
|
||||
class MetricsRequestHandler final {
|
||||
public:
|
||||
explicit MetricsRequestHandler(TSessionData *data) : service_(data) {
|
||||
spdlog::info("Basic request handler started!");
|
||||
}
|
||||
|
||||
MetricsRequestHandler(const MetricsRequestHandler &) = delete;
|
||||
MetricsRequestHandler(MetricsRequestHandler &&) = delete;
|
||||
MetricsRequestHandler &operator=(const MetricsRequestHandler &) = delete;
|
||||
MetricsRequestHandler &operator=(MetricsRequestHandler &&) = delete;
|
||||
~MetricsRequestHandler() = default;
|
||||
|
||||
template <class Body, class Allocator>
|
||||
// NOLINTNEXTLINE(misc-unused-parameters)
|
||||
void HandleRequest(boost::beast::http::request<Body, boost::beast::http::basic_fields<Allocator>> &&req,
|
||||
std::function<void(boost::beast::http::response<boost::beast::http::string_body>)> &&send) {
|
||||
auto response_json = nlohmann::json();
|
||||
// Returns a bad request response
|
||||
auto const bad_request = [&req, &response_json](const auto why) {
|
||||
response_json["error"] = std::string(why);
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
|
||||
boost::beast::http::response<boost::beast::http::string_body> res{boost::beast::http::status::bad_request,
|
||||
req.version()};
|
||||
res.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING);
|
||||
res.set(boost::beast::http::field::content_type, "application/json");
|
||||
res.keep_alive(req.keep_alive());
|
||||
res.body() = response_json.dump();
|
||||
res.prepare_payload();
|
||||
return res;
|
||||
};
|
||||
|
||||
// Make sure we can handle the method
|
||||
if (req.method() != boost::beast::http::verb::get) {
|
||||
return send(bad_request("Unknown HTTP-method"));
|
||||
}
|
||||
|
||||
// Request path must be absolute and not contain "..".
|
||||
if (req.target().empty() || req.target()[0] != '/' || req.target().find("..") != boost::beast::string_view::npos) {
|
||||
return send(bad_request("Illegal request-target"));
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
|
||||
boost::beast::http::string_body::value_type body;
|
||||
|
||||
auto service_response = service_.GetMetricsJSON();
|
||||
body.append(service_response.dump());
|
||||
|
||||
// Cache the size since we need it after the move
|
||||
const auto size = body.size();
|
||||
|
||||
// Respond to GET request
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
|
||||
boost::beast::http::response<boost::beast::http::string_body> res{
|
||||
std::piecewise_construct, std::make_tuple(std::move(body)),
|
||||
std::make_tuple(boost::beast::http::status::ok, req.version())};
|
||||
res.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING);
|
||||
res.set(boost::beast::http::field::content_type, "application/json");
|
||||
res.content_length(size);
|
||||
res.keep_alive(req.keep_alive());
|
||||
return send(std::move(res));
|
||||
}
|
||||
|
||||
private:
|
||||
MetricsService<TSessionData> service_;
|
||||
};
|
||||
} // namespace memgraph::http
|
||||
6
src/license/CMakeLists.txt
Normal file
6
src/license/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
set(license_src_files
|
||||
license_sender.cpp
|
||||
license.cpp)
|
||||
add_library(mg-license STATIC ${license_src_files})
|
||||
|
||||
target_link_libraries(mg-license mg-settings mg-utils mg-requests spdlog::spdlog)
|
||||
@@ -9,17 +9,19 @@
|
||||
// by the Apache License, Version 2.0, included in the file
|
||||
// licenses/APL.txt.
|
||||
|
||||
#include "utils/license.hpp"
|
||||
#include "license/license.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <charconv>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "slk/serialization.hpp"
|
||||
#include "utils/base64.hpp"
|
||||
#include "utils/cast.hpp"
|
||||
#include "utils/exceptions.hpp"
|
||||
#include "utils/logging.hpp"
|
||||
#include "utils/memory_tracker.hpp"
|
||||
@@ -27,7 +29,7 @@
|
||||
#include "utils/spin_lock.hpp"
|
||||
#include "utils/synchronized.hpp"
|
||||
|
||||
namespace memgraph::utils::license {
|
||||
namespace memgraph::license {
|
||||
|
||||
namespace {
|
||||
inline constexpr std::string_view license_key_prefix = "mglk-";
|
||||
@@ -69,6 +71,17 @@ LicenseCheckResult IsValidLicenseInternal(const License &license, const std::str
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::string LicenseTypeToString(const LicenseType license_type) {
|
||||
switch (license_type) {
|
||||
case LicenseType::ENTERPRISE: {
|
||||
return "enterprise";
|
||||
}
|
||||
case LicenseType::OEM: {
|
||||
return "oem";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterLicenseSettings(LicenseChecker &license_checker, utils::Settings &settings) {
|
||||
settings.RegisterSetting(std::string{kEnterpriseLicenseSettingKey}, "",
|
||||
[&] { license_checker.RevalidateLicense(settings); });
|
||||
@@ -81,7 +94,7 @@ LicenseChecker global_license_checker;
|
||||
|
||||
LicenseChecker::~LicenseChecker() { scheduler_.Stop(); }
|
||||
|
||||
std::pair<std::string, std::string> LicenseChecker::GetLicenseInfo(const utils::Settings &settings) const {
|
||||
std::pair<std::string, std::string> LicenseChecker::ExtractLicenseInfo(const utils::Settings &settings) const {
|
||||
if (license_info_override_) {
|
||||
spdlog::warn("Ignoring license info stored in the settings because a different source was specified.");
|
||||
return *license_info_override_;
|
||||
@@ -96,7 +109,7 @@ std::pair<std::string, std::string> LicenseChecker::GetLicenseInfo(const utils::
|
||||
}
|
||||
|
||||
void LicenseChecker::RevalidateLicense(const utils::Settings &settings) {
|
||||
const auto license_info = GetLicenseInfo(settings);
|
||||
const auto license_info = ExtractLicenseInfo(settings);
|
||||
RevalidateLicense(license_info.first, license_info.second);
|
||||
}
|
||||
|
||||
@@ -117,18 +130,7 @@ void LicenseChecker::RevalidateLicense(const std::string &license_key, const std
|
||||
return;
|
||||
}
|
||||
|
||||
struct PreviousLicenseInfo {
|
||||
PreviousLicenseInfo(std::string license_key, std::string organization_name)
|
||||
: license_key(std::move(license_key)), organization_name(std::move(organization_name)) {}
|
||||
|
||||
std::string license_key;
|
||||
std::string organization_name;
|
||||
bool is_valid{false};
|
||||
};
|
||||
|
||||
static utils::Synchronized<std::optional<PreviousLicenseInfo>, utils::SpinLock> previous_license_info;
|
||||
|
||||
auto locked_previous_license_info_ptr = previous_license_info.Lock();
|
||||
auto locked_previous_license_info_ptr = previous_license_info_.Lock();
|
||||
auto &locked_previous_license_info = *locked_previous_license_info_ptr;
|
||||
const bool same_license_info = locked_previous_license_info &&
|
||||
locked_previous_license_info->license_key == license_key &&
|
||||
@@ -140,7 +142,7 @@ void LicenseChecker::RevalidateLicense(const std::string &license_key, const std
|
||||
|
||||
locked_previous_license_info.emplace(license_key, organization_name);
|
||||
|
||||
const auto maybe_license = GetLicense(locked_previous_license_info->license_key);
|
||||
auto maybe_license = GetLicense(locked_previous_license_info->license_key);
|
||||
if (!maybe_license) {
|
||||
spdlog::warn(LicenseCheckErrorToString(LicenseCheckError::INVALID_LICENSE_KEY_STRING, "Enterprise features"));
|
||||
is_valid_.store(false, std::memory_order_relaxed);
|
||||
@@ -156,22 +158,30 @@ void LicenseChecker::RevalidateLicense(const std::string &license_key, const std
|
||||
spdlog::warn(LicenseCheckErrorToString(license_check_result.GetError(), "Enterprise features"));
|
||||
is_valid_.store(false, std::memory_order_relaxed);
|
||||
locked_previous_license_info->is_valid = false;
|
||||
license_type_ = maybe_license->type;
|
||||
set_memory_limit(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!same_license_info) {
|
||||
spdlog::info("All Enterprise features are active.");
|
||||
license_type_ = maybe_license->type;
|
||||
if (license_type_ == LicenseType::ENTERPRISE) {
|
||||
spdlog::info("Enterprise license is active.");
|
||||
} else {
|
||||
spdlog::info("OEM license is active.");
|
||||
}
|
||||
is_valid_.store(true, std::memory_order_relaxed);
|
||||
locked_previous_license_info->is_valid = true;
|
||||
set_memory_limit(maybe_license->memory_limit);
|
||||
locked_previous_license_info->license = std::move(*maybe_license);
|
||||
}
|
||||
}
|
||||
|
||||
void LicenseChecker::EnableTesting() {
|
||||
void LicenseChecker::EnableTesting(const LicenseType license_type) {
|
||||
enterprise_enabled_ = true;
|
||||
is_valid_.store(true, std::memory_order_relaxed);
|
||||
spdlog::info("All Enterprise features are activated for testing.");
|
||||
license_type_ = license_type;
|
||||
spdlog::info("The license type {} is set for testing.", LicenseTypeToString(license_type));
|
||||
}
|
||||
|
||||
void LicenseChecker::CheckEnvLicense() {
|
||||
@@ -216,20 +226,26 @@ std::string LicenseCheckErrorToString(LicenseCheckError error, const std::string
|
||||
"following query:\n"
|
||||
"SET DATABASE SETTING \"enterprise.license\" TO \"your-license-key\"",
|
||||
feature);
|
||||
case LicenseCheckError::NOT_ENTERPRISE_LICENSE:
|
||||
return fmt::format("Your license has an invalid type. To use {} you need to have an enterprise license. \n",
|
||||
feature);
|
||||
}
|
||||
}
|
||||
|
||||
LicenseCheckResult LicenseChecker::IsValidLicense(const utils::Settings &settings) const {
|
||||
LicenseCheckResult LicenseChecker::IsEnterpriseValid(const utils::Settings &settings) const {
|
||||
if (enterprise_enabled_) [[unlikely]] {
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto license_info = GetLicenseInfo(settings);
|
||||
const auto license_info = ExtractLicenseInfo(settings);
|
||||
|
||||
const auto maybe_license = GetLicense(license_info.first);
|
||||
if (!maybe_license) {
|
||||
return LicenseCheckError::INVALID_LICENSE_KEY_STRING;
|
||||
}
|
||||
if (maybe_license->type != LicenseType::ENTERPRISE) {
|
||||
return LicenseCheckError::NOT_ENTERPRISE_LICENSE;
|
||||
}
|
||||
|
||||
return IsValidLicenseInternal(*maybe_license, license_info.second);
|
||||
}
|
||||
@@ -239,7 +255,13 @@ void LicenseChecker::StartBackgroundLicenseChecker(const utils::Settings &settin
|
||||
scheduler_.Run("licensechecker", std::chrono::minutes{5}, [&, this] { RevalidateLicense(settings); });
|
||||
}
|
||||
|
||||
bool LicenseChecker::IsValidLicenseFast() const { return is_valid_.load(std::memory_order_relaxed); }
|
||||
utils::Synchronized<std::optional<LicenseInfo>, utils::SpinLock> &LicenseChecker::GetLicenseInfo() {
|
||||
return previous_license_info_;
|
||||
}
|
||||
|
||||
bool LicenseChecker::IsEnterpriseValidFast() const {
|
||||
return license_type_ == LicenseType::ENTERPRISE && is_valid_.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
std::string Encode(const License &license) {
|
||||
std::vector<uint8_t> buffer;
|
||||
@@ -252,9 +274,10 @@ std::string Encode(const License &license) {
|
||||
slk::Save(license.organization_name, &builder);
|
||||
slk::Save(license.valid_until, &builder);
|
||||
slk::Save(license.memory_limit, &builder);
|
||||
slk::Save(utils::UnderlyingCast(license.type), &builder);
|
||||
builder.Finalize();
|
||||
|
||||
return std::string{license_key_prefix} + base64_encode(buffer.data(), buffer.size());
|
||||
return std::string{license_key_prefix} + utils::base64_encode(buffer.data(), buffer.size());
|
||||
}
|
||||
|
||||
std::optional<License> Decode(std::string_view license_key) {
|
||||
@@ -266,7 +289,7 @@ std::optional<License> Decode(std::string_view license_key) {
|
||||
|
||||
const auto decoded = std::invoke([license_key]() -> std::optional<std::string> {
|
||||
try {
|
||||
return base64_decode(license_key);
|
||||
return utils::base64_decode(license_key);
|
||||
} catch (const std::runtime_error & /*exception*/) {
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -284,10 +307,12 @@ std::optional<License> Decode(std::string_view license_key) {
|
||||
slk::Load(&valid_until, &reader);
|
||||
int64_t memory_limit{0};
|
||||
slk::Load(&memory_limit, &reader);
|
||||
return License{.organization_name = organization_name, .valid_until = valid_until, .memory_limit = memory_limit};
|
||||
std::underlying_type_t<LicenseType> license_type{0};
|
||||
slk::Load(&license_type, &reader);
|
||||
return {License{organization_name, valid_until, memory_limit, LicenseType(license_type)}};
|
||||
} catch (const slk::SlkReaderException &e) {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace memgraph::utils::license
|
||||
} // namespace memgraph::license
|
||||
@@ -12,26 +12,57 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "utils/result.hpp"
|
||||
#include "utils/scheduler.hpp"
|
||||
#include "utils/settings.hpp"
|
||||
#include "utils/spin_lock.hpp"
|
||||
#include "utils/synchronized.hpp"
|
||||
|
||||
namespace memgraph::utils::license {
|
||||
namespace memgraph::license {
|
||||
|
||||
enum class LicenseType : uint8_t { ENTERPRISE, OEM };
|
||||
|
||||
std::string LicenseTypeToString(LicenseType license_type);
|
||||
|
||||
struct License {
|
||||
License() = default;
|
||||
|
||||
License(std::string organization_name, int64_t valid_until, int64_t memory_limit, LicenseType license_type)
|
||||
: organization_name{std::move(organization_name)},
|
||||
valid_until{valid_until},
|
||||
memory_limit{memory_limit},
|
||||
type{license_type} {}
|
||||
|
||||
std::string organization_name;
|
||||
int64_t valid_until;
|
||||
int64_t memory_limit;
|
||||
LicenseType type;
|
||||
|
||||
bool operator==(const License &) const = default;
|
||||
};
|
||||
|
||||
struct LicenseInfo {
|
||||
LicenseInfo(std::string license_key, std::string organization_name)
|
||||
: license_key(std::move(license_key)), organization_name{std::move(organization_name)} {}
|
||||
|
||||
std::string license_key;
|
||||
std::string organization_name;
|
||||
bool is_valid{false};
|
||||
License license;
|
||||
};
|
||||
|
||||
inline constexpr std::string_view kEnterpriseLicenseSettingKey = "enterprise.license";
|
||||
inline constexpr std::string_view kOrganizationNameSettingKey = "organization.name";
|
||||
|
||||
enum class LicenseCheckError : uint8_t { INVALID_LICENSE_KEY_STRING, INVALID_ORGANIZATION_NAME, EXPIRED_LICENSE };
|
||||
enum class LicenseCheckError : uint8_t {
|
||||
INVALID_LICENSE_KEY_STRING,
|
||||
INVALID_ORGANIZATION_NAME,
|
||||
EXPIRED_LICENSE,
|
||||
NOT_ENTERPRISE_LICENSE
|
||||
};
|
||||
|
||||
std::string LicenseCheckErrorToString(LicenseCheckError error, std::string_view feature);
|
||||
|
||||
@@ -49,19 +80,25 @@ struct LicenseChecker {
|
||||
|
||||
void CheckEnvLicense();
|
||||
void SetLicenseInfoOverride(std::string license_key, std::string organization_name);
|
||||
void EnableTesting();
|
||||
LicenseCheckResult IsValidLicense(const utils::Settings &settings) const;
|
||||
bool IsValidLicenseFast() const;
|
||||
void EnableTesting(LicenseType license_type = LicenseType::ENTERPRISE);
|
||||
// Checks if license is valid and if enterprise is enabled
|
||||
LicenseCheckResult IsEnterpriseValid(const utils::Settings &settings) const;
|
||||
bool IsEnterpriseValidFast() const;
|
||||
|
||||
void StartBackgroundLicenseChecker(const utils::Settings &settings);
|
||||
|
||||
utils::Synchronized<std::optional<LicenseInfo>, utils::SpinLock> &GetLicenseInfo();
|
||||
|
||||
private:
|
||||
std::pair<std::string, std::string> GetLicenseInfo(const utils::Settings &settings) const;
|
||||
std::pair<std::string, std::string> ExtractLicenseInfo(const utils::Settings &settings) const;
|
||||
void RevalidateLicense(const utils::Settings &settings);
|
||||
void RevalidateLicense(const std::string &license_key, const std::string &organization_name);
|
||||
|
||||
std::optional<std::pair<std::string, std::string>> license_info_override_;
|
||||
utils::Synchronized<std::optional<LicenseInfo>, utils::SpinLock> previous_license_info_{std::nullopt};
|
||||
bool enterprise_enabled_{false};
|
||||
std::atomic<bool> is_valid_{false};
|
||||
LicenseType license_type_;
|
||||
utils::Scheduler scheduler_;
|
||||
|
||||
friend void RegisterLicenseSettings(LicenseChecker &license_checker, utils::Settings &settings);
|
||||
@@ -74,4 +111,4 @@ std::string Encode(const License &license);
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
extern LicenseChecker global_license_checker;
|
||||
} // namespace memgraph::utils::license
|
||||
} // namespace memgraph::license
|
||||
71
src/license/license_sender.cpp
Normal file
71
src/license/license_sender.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
// 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
|
||||
// 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 "license/license_sender.hpp"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <cstdint>
|
||||
|
||||
#include "requests/requests.hpp"
|
||||
#include "utils/memory_tracker.hpp"
|
||||
#include "utils/stat.hpp"
|
||||
#include "utils/synchronized.hpp"
|
||||
#include "utils/system_info.hpp"
|
||||
#include "utils/timestamp.hpp"
|
||||
|
||||
namespace memgraph::license {
|
||||
|
||||
LicenseInfoSender::LicenseInfoSender(std::string url, std::string uuid, std::string machine_id, int64_t memory_limit,
|
||||
utils::Synchronized<std::optional<LicenseInfo>, utils::SpinLock> &license_info,
|
||||
std::chrono::seconds request_frequency)
|
||||
: url_{std::move(url)},
|
||||
uuid_{std::move(uuid)},
|
||||
machine_id_{std::move(machine_id)},
|
||||
memory_limit_{memory_limit},
|
||||
license_info_{license_info} {
|
||||
scheduler_.Run("LicenseCheck", request_frequency, [&] { SendData(); });
|
||||
}
|
||||
|
||||
LicenseInfoSender::~LicenseInfoSender() { scheduler_.Stop(); }
|
||||
|
||||
void LicenseInfoSender::SendData() {
|
||||
nlohmann::json data = nlohmann::json::object();
|
||||
|
||||
license_info_.WithLock([&data, this](const auto &license_info) mutable {
|
||||
if (license_info && !license_info->organization_name.empty()) {
|
||||
const auto memory_info = utils::GetMemoryInfo();
|
||||
const auto memory_usage = utils::GetMemoryUsage();
|
||||
data = {{"run_id", uuid_},
|
||||
{"machine_id", machine_id_},
|
||||
{"type", "license-check"},
|
||||
{"license_type", LicenseTypeToString(license_info->license.type)},
|
||||
{"license_key", license_info->license_key},
|
||||
{"organization", license_info->organization_name},
|
||||
{"valid", license_info->is_valid},
|
||||
{"physical_memory_size", memory_info.memory},
|
||||
{"swap_memory_size", memory_info.swap},
|
||||
{"memory_used", memory_usage},
|
||||
{"runtime_memory_limit", memory_limit_},
|
||||
{"license_memory_limit", license_info->license.memory_limit},
|
||||
{"timestamp", utils::Timestamp::Now().SecWithNsecSinceTheEpoch()}};
|
||||
}
|
||||
});
|
||||
|
||||
if (data.empty()) {
|
||||
return;
|
||||
}
|
||||
if (!requests::RequestPostJson(url_, data,
|
||||
/* timeout_in_seconds = */ 2 * 60)) {
|
||||
spdlog::trace("Cannot send license information, enable {} availability!", url_);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace memgraph::license
|
||||
50
src/license/license_sender.hpp
Normal file
50
src/license/license_sender.hpp
Normal file
@@ -0,0 +1,50 @@
|
||||
// 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
|
||||
// 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 <chrono>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include <json/json.hpp>
|
||||
|
||||
#include "license/license.hpp"
|
||||
#include "utils/scheduler.hpp"
|
||||
#include "utils/timer.hpp"
|
||||
|
||||
namespace memgraph::license {
|
||||
|
||||
class LicenseInfoSender final {
|
||||
public:
|
||||
LicenseInfoSender(std::string url, std::string uuid, std::string machine_id, int64_t memory_limit,
|
||||
utils::Synchronized<std::optional<LicenseInfo>, utils::SpinLock> &license_info,
|
||||
std::chrono::seconds request_frequency = std::chrono::seconds(8 * 60 * 60));
|
||||
|
||||
LicenseInfoSender(const LicenseInfoSender &) = delete;
|
||||
LicenseInfoSender(LicenseInfoSender &&) noexcept = delete;
|
||||
LicenseInfoSender &operator=(const LicenseInfoSender &) = delete;
|
||||
LicenseInfoSender &operator=(LicenseInfoSender &&) noexcept = delete;
|
||||
~LicenseInfoSender();
|
||||
|
||||
private:
|
||||
void SendData();
|
||||
|
||||
const std::string url_;
|
||||
const std::string uuid_;
|
||||
const std::string machine_id_;
|
||||
const int64_t memory_limit_;
|
||||
|
||||
utils::Synchronized<std::optional<LicenseInfo>, utils::SpinLock> &license_info_;
|
||||
utils::Scheduler scheduler_;
|
||||
};
|
||||
|
||||
} // namespace memgraph::license
|
||||
288
src/memgraph.cpp
288
src/memgraph.cpp
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <fmt/format.h>
|
||||
#include <gflags/gflags.h>
|
||||
#include <spdlog/common.h>
|
||||
@@ -35,11 +36,15 @@
|
||||
|
||||
#include "auth/models.hpp"
|
||||
#include "communication/bolt/v1/constants.hpp"
|
||||
#include "communication/http/server.hpp"
|
||||
#include "communication/websocket/auth.hpp"
|
||||
#include "communication/websocket/server.hpp"
|
||||
#include "glue/auth_checker.hpp"
|
||||
#include "glue/auth_handler.hpp"
|
||||
#include "helpers.hpp"
|
||||
#include "http_handlers/metrics.hpp"
|
||||
#include "license/license.hpp"
|
||||
#include "license/license_sender.hpp"
|
||||
#include "py/py.hpp"
|
||||
#include "query/auth_checker.hpp"
|
||||
#include "query/discard_value_stream.hpp"
|
||||
@@ -54,10 +59,10 @@
|
||||
#include "storage/v2/storage.hpp"
|
||||
#include "storage/v2/view.hpp"
|
||||
#include "telemetry/telemetry.hpp"
|
||||
#include "utils/enum.hpp"
|
||||
#include "utils/event_counter.hpp"
|
||||
#include "utils/file.hpp"
|
||||
#include "utils/flag_validation.hpp"
|
||||
#include "utils/license.hpp"
|
||||
#include "utils/logging.hpp"
|
||||
#include "utils/memory_tracker.hpp"
|
||||
#include "utils/message.hpp"
|
||||
@@ -68,6 +73,7 @@
|
||||
#include "utils/string.hpp"
|
||||
#include "utils/synchronized.hpp"
|
||||
#include "utils/sysinfo/memory.hpp"
|
||||
#include "utils/system_info.hpp"
|
||||
#include "utils/terminate_handler.hpp"
|
||||
#include "version.hpp"
|
||||
|
||||
@@ -96,47 +102,22 @@
|
||||
#include "audit/log.hpp"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
std::string GetAllowedEnumValuesString(const auto &mappings) {
|
||||
std::vector<std::string> allowed_values;
|
||||
allowed_values.reserve(mappings.size());
|
||||
std::transform(mappings.begin(), mappings.end(), std::back_inserter(allowed_values),
|
||||
[](const auto &mapping) { return std::string(mapping.first); });
|
||||
return memgraph::utils::Join(allowed_values, ", ");
|
||||
}
|
||||
constexpr const char *kMgUser = "MEMGRAPH_USER";
|
||||
constexpr const char *kMgPassword = "MEMGRAPH_PASSWORD";
|
||||
constexpr const char *kMgPassfile = "MEMGRAPH_PASSFILE";
|
||||
|
||||
enum class ValidationError : uint8_t { EmptyValue, InvalidValue };
|
||||
|
||||
memgraph::utils::BasicResult<ValidationError> IsValidEnumValueString(const auto &value, const auto &mappings) {
|
||||
if (value.empty()) {
|
||||
return ValidationError::EmptyValue;
|
||||
}
|
||||
|
||||
if (std::find_if(mappings.begin(), mappings.end(), [&](const auto &mapping) { return mapping.first == value; }) ==
|
||||
mappings.cend()) {
|
||||
return ValidationError::InvalidValue;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename Enum>
|
||||
std::optional<Enum> StringToEnum(const auto &value, const auto &mappings) {
|
||||
const auto mapping_iter =
|
||||
std::find_if(mappings.begin(), mappings.end(), [&](const auto &mapping) { return mapping.first == value; });
|
||||
if (mapping_iter == mappings.cend()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return mapping_iter->second;
|
||||
}
|
||||
} // namespace
|
||||
// Short help flag.
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_HIDDEN_bool(h, false, "Print usage and exit.");
|
||||
|
||||
// Bolt server flags.
|
||||
DEFINE_string(bolt_address, "0.0.0.0", "IP address on which the Bolt server should listen.");
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_string(monitoring_address, "0.0.0.0",
|
||||
"IP address on which the websocket server for Memgraph monitoring should listen.");
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_string(metrics_address, "0.0.0.0",
|
||||
"IP address on which the Memgraph server for exposing metrics should listen.");
|
||||
DEFINE_VALIDATED_int32(bolt_port, 7687, "Port on which the Bolt server should listen.",
|
||||
FLAG_IN_RANGE(0, std::numeric_limits<uint16_t>::max()));
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
@@ -144,6 +125,9 @@ DEFINE_VALIDATED_int32(monitoring_port, 7444,
|
||||
"Port on which the websocket server for Memgraph monitoring should listen.",
|
||||
FLAG_IN_RANGE(0, std::numeric_limits<uint16_t>::max()));
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_VALIDATED_int32(metrics_port, 9091, "Port on which the Memgraph server for exposing metrics should listen.",
|
||||
FLAG_IN_RANGE(0, std::numeric_limits<uint16_t>::max()));
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_VALIDATED_int32(bolt_num_workers, std::max(std::thread::hardware_concurrency(), 1U),
|
||||
"Number of workers used by the Bolt server. By default, this will be the "
|
||||
"number of processing units available on the machine.",
|
||||
@@ -161,6 +145,11 @@ DEFINE_string(bolt_key_file, "", "Key file which should be used for the Bolt ser
|
||||
DEFINE_string(bolt_server_name_for_init, "",
|
||||
"Server name which the database should send to the client in the "
|
||||
"Bolt INIT message.");
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_string(init_file, "",
|
||||
"Path to cypherl file that is used for configuring users and database schema before server starts.");
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_string(init_data_file, "", "Path to cypherl file that is used for creating data after server starts.");
|
||||
|
||||
// General purpose flags.
|
||||
// NOTE: The `data_directory` flag must be the same here and in
|
||||
@@ -211,6 +200,20 @@ DEFINE_VALIDATED_uint64(storage_wal_file_flush_every_n_tx,
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_bool(storage_snapshot_on_exit, false, "Controls whether the storage creates another snapshot on exit.");
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
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)
|
||||
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,
|
||||
std::max(static_cast<uint64_t>(std::thread::hardware_concurrency()),
|
||||
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(telemetry_enabled, false,
|
||||
"Set to true to enable telemetry. We collect information about the "
|
||||
@@ -274,21 +277,21 @@ inline constexpr std::array isolation_level_mappings{
|
||||
|
||||
const std::string isolation_level_help_string =
|
||||
fmt::format("Default isolation level used for the transactions. Allowed values: {}",
|
||||
GetAllowedEnumValuesString(isolation_level_mappings));
|
||||
memgraph::utils::GetAllowedEnumValuesString(isolation_level_mappings));
|
||||
} // namespace
|
||||
|
||||
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_VALIDATED_string(isolation_level, "SNAPSHOT_ISOLATION", isolation_level_help_string.c_str(), {
|
||||
if (const auto result = IsValidEnumValueString(value, isolation_level_mappings); result.HasError()) {
|
||||
if (const auto result = memgraph::utils::IsValidEnumValueString(value, isolation_level_mappings); result.HasError()) {
|
||||
const auto error = result.GetError();
|
||||
switch (error) {
|
||||
case ValidationError::EmptyValue: {
|
||||
case memgraph::utils::ValidationError::EmptyValue: {
|
||||
std::cout << "Isolation level cannot be empty." << std::endl;
|
||||
break;
|
||||
}
|
||||
case ValidationError::InvalidValue: {
|
||||
case memgraph::utils::ValidationError::InvalidValue: {
|
||||
std::cout << "Invalid value for isolation level. Allowed values: "
|
||||
<< GetAllowedEnumValuesString(isolation_level_mappings) << std::endl;
|
||||
<< memgraph::utils::GetAllowedEnumValuesString(isolation_level_mappings) << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -301,7 +304,7 @@ DEFINE_VALIDATED_string(isolation_level, "SNAPSHOT_ISOLATION", isolation_level_h
|
||||
namespace {
|
||||
memgraph::storage::IsolationLevel ParseIsolationLevel() {
|
||||
const auto isolation_level =
|
||||
StringToEnum<memgraph::storage::IsolationLevel>(FLAGS_isolation_level, isolation_level_mappings);
|
||||
memgraph::utils::StringToEnum<memgraph::storage::IsolationLevel>(FLAGS_isolation_level, isolation_level_mappings);
|
||||
MG_ASSERT(isolation_level, "Invalid isolation level");
|
||||
return *isolation_level;
|
||||
}
|
||||
@@ -361,21 +364,21 @@ 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 log_level_help_string =
|
||||
fmt::format("Minimum log level. Allowed values: {}", GetAllowedEnumValuesString(log_level_mappings));
|
||||
const std::string log_level_help_string = fmt::format("Minimum log level. Allowed values: {}",
|
||||
memgraph::utils::GetAllowedEnumValuesString(log_level_mappings));
|
||||
} // namespace
|
||||
|
||||
DEFINE_VALIDATED_string(log_level, "WARNING", log_level_help_string.c_str(), {
|
||||
if (const auto result = IsValidEnumValueString(value, log_level_mappings); result.HasError()) {
|
||||
if (const auto result = memgraph::utils::IsValidEnumValueString(value, log_level_mappings); result.HasError()) {
|
||||
const auto error = result.GetError();
|
||||
switch (error) {
|
||||
case ValidationError::EmptyValue: {
|
||||
case memgraph::utils::ValidationError::EmptyValue: {
|
||||
std::cout << "Log level cannot be empty." << std::endl;
|
||||
break;
|
||||
}
|
||||
case ValidationError::InvalidValue: {
|
||||
std::cout << "Invalid value for log level. Allowed values: " << GetAllowedEnumValuesString(log_level_mappings)
|
||||
<< std::endl;
|
||||
case memgraph::utils::ValidationError::InvalidValue: {
|
||||
std::cout << "Invalid value for log level. Allowed values: "
|
||||
<< memgraph::utils::GetAllowedEnumValuesString(log_level_mappings) << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -387,7 +390,7 @@ DEFINE_VALIDATED_string(log_level, "WARNING", log_level_help_string.c_str(), {
|
||||
|
||||
namespace {
|
||||
spdlog::level::level_enum ParseLogLevel() {
|
||||
const auto log_level = StringToEnum<spdlog::level::level_enum>(FLAGS_log_level, log_level_mappings);
|
||||
const auto log_level = memgraph::utils::StringToEnum<spdlog::level::level_enum>(FLAGS_log_level, log_level_mappings);
|
||||
MG_ASSERT(log_level, "Invalid log level");
|
||||
return *log_level;
|
||||
}
|
||||
@@ -470,6 +473,37 @@ struct SessionData {
|
||||
DEFINE_string(auth_user_or_role_name_regex, memgraph::glue::kDefaultUserRoleRegex.data(),
|
||||
"Set to the regular expression that each user or role name must fulfill.");
|
||||
|
||||
void InitFromCypherlFile(memgraph::query::InterpreterContext &ctx, std::string cypherl_file_path
|
||||
#ifdef MG_ENTERPRISE
|
||||
,
|
||||
memgraph::audit::Log *audit_log
|
||||
#endif
|
||||
) {
|
||||
memgraph::query::Interpreter interpreter(&ctx);
|
||||
std::ifstream file(cypherl_file_path);
|
||||
if (file.is_open()) {
|
||||
std::string line;
|
||||
while (std::getline(file, line)) {
|
||||
if (!line.empty()) {
|
||||
auto results = interpreter.Prepare(line, {}, {});
|
||||
memgraph::query::DiscardValueResultStream stream;
|
||||
interpreter.Pull(&stream, {}, results.qid);
|
||||
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
audit_log->Record("", "", line, {});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
namespace memgraph::metrics {
|
||||
extern const Event ActiveBoltSessions;
|
||||
} // namespace memgraph::metrics
|
||||
|
||||
class BoltSession final : public memgraph::communication::bolt::Session<memgraph::communication::v2::InputStream,
|
||||
memgraph::communication::v2::OutputStream> {
|
||||
public:
|
||||
@@ -479,6 +513,7 @@ class BoltSession final : public memgraph::communication::bolt::Session<memgraph
|
||||
: memgraph::communication::bolt::Session<memgraph::communication::v2::InputStream,
|
||||
memgraph::communication::v2::OutputStream>(input_stream, output_stream),
|
||||
db_(data->db),
|
||||
interpreter_context_(data->interpreter_context),
|
||||
interpreter_(data->interpreter_context),
|
||||
auth_(data->auth),
|
||||
#if MG_ENTERPRISE
|
||||
@@ -486,33 +521,53 @@ class BoltSession final : public memgraph::communication::bolt::Session<memgraph
|
||||
#endif
|
||||
endpoint_(endpoint),
|
||||
run_id_(data->run_id) {
|
||||
memgraph::metrics::IncrementCounter(memgraph::metrics::ActiveBoltSessions);
|
||||
interpreter_context_->interpreters.WithLock([this](auto &interpreters) { interpreters.insert(&interpreter_); });
|
||||
}
|
||||
|
||||
~BoltSession() override {
|
||||
memgraph::metrics::DecrementCounter(memgraph::metrics::ActiveBoltSessions);
|
||||
interpreter_context_->interpreters.WithLock([this](auto &interpreters) { interpreters.erase(&interpreter_); });
|
||||
}
|
||||
|
||||
using memgraph::communication::bolt::Session<memgraph::communication::v2::InputStream,
|
||||
memgraph::communication::v2::OutputStream>::TEncoder;
|
||||
|
||||
void BeginTransaction() override { interpreter_.BeginTransaction(); }
|
||||
void BeginTransaction(const std::map<std::string, memgraph::communication::bolt::Value> &metadata) override {
|
||||
std::map<std::string, memgraph::storage::PropertyValue> metadata_pv;
|
||||
for (const auto &[key, bolt_value] : metadata) {
|
||||
metadata_pv.emplace(key, memgraph::glue::ToPropertyValue(bolt_value));
|
||||
}
|
||||
interpreter_.BeginTransaction(metadata_pv);
|
||||
}
|
||||
|
||||
void CommitTransaction() override { interpreter_.CommitTransaction(); }
|
||||
|
||||
void RollbackTransaction() override { interpreter_.RollbackTransaction(); }
|
||||
|
||||
std::pair<std::vector<std::string>, std::optional<int>> Interpret(
|
||||
const std::string &query, const std::map<std::string, memgraph::communication::bolt::Value> ¶ms) override {
|
||||
const std::string &query, const std::map<std::string, memgraph::communication::bolt::Value> ¶ms,
|
||||
const std::map<std::string, memgraph::communication::bolt::Value> &metadata) override {
|
||||
std::map<std::string, memgraph::storage::PropertyValue> params_pv;
|
||||
for (const auto &kv : params) params_pv.emplace(kv.first, memgraph::glue::ToPropertyValue(kv.second));
|
||||
std::map<std::string, memgraph::storage::PropertyValue> metadata_pv;
|
||||
for (const auto &[key, bolt_param] : params) {
|
||||
params_pv.emplace(key, memgraph::glue::ToPropertyValue(bolt_param));
|
||||
}
|
||||
for (const auto &[key, bolt_md] : metadata) {
|
||||
metadata_pv.emplace(key, memgraph::glue::ToPropertyValue(bolt_md));
|
||||
}
|
||||
const std::string *username{nullptr};
|
||||
if (user_) {
|
||||
username = &user_->username();
|
||||
}
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
audit_log_->Record(endpoint_.address().to_string(), user_ ? *username : "", query,
|
||||
memgraph::storage::PropertyValue(params_pv));
|
||||
}
|
||||
#endif
|
||||
try {
|
||||
auto result = interpreter_.Prepare(query, params_pv, username);
|
||||
auto result = interpreter_.Prepare(query, params_pv, username, metadata_pv);
|
||||
if (user_ && !memgraph::glue::AuthChecker::IsUserAuthorized(*user_, result.privileges)) {
|
||||
interpreter_.Abort();
|
||||
throw memgraph::communication::bolt::ClientError(
|
||||
@@ -631,6 +686,7 @@ class BoltSession final : public memgraph::communication::bolt::Session<memgraph
|
||||
|
||||
// NOTE: Needed only for ToBoltValue conversions
|
||||
const memgraph::storage::Storage *db_;
|
||||
memgraph::query::InterpreterContext *interpreter_context_;
|
||||
memgraph::query::Interpreter interpreter_;
|
||||
memgraph::utils::Synchronized<memgraph::auth::Auth, memgraph::utils::WritePrioritizedRWLock> *auth_;
|
||||
std::optional<memgraph::auth::User> user_;
|
||||
@@ -643,6 +699,8 @@ class BoltSession final : public memgraph::communication::bolt::Session<memgraph
|
||||
};
|
||||
|
||||
using ServerT = memgraph::communication::v2::Server<BoltSession, SessionData>;
|
||||
using MonitoringServerT =
|
||||
memgraph::communication::http::Server<memgraph::http::MetricsRequestHandler<SessionData>, SessionData>;
|
||||
using memgraph::communication::ServerContext;
|
||||
|
||||
// Needed to correctly handle memgraph destruction from a signal handler.
|
||||
@@ -685,6 +743,11 @@ int main(int argc, char **argv) {
|
||||
LoadConfig("memgraph");
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
if (FLAGS_h) {
|
||||
gflags::ShowUsageWithFlags(argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
InitializeLogger();
|
||||
|
||||
// Unhandled exception handler init.
|
||||
@@ -779,15 +842,15 @@ int main(int argc, char **argv) {
|
||||
memgraph::utils::OnScopeExit settings_finalizer([&] { memgraph::utils::global_settings.Finalize(); });
|
||||
|
||||
// register all runtime settings
|
||||
memgraph::utils::license::RegisterLicenseSettings(memgraph::utils::license::global_license_checker,
|
||||
memgraph::utils::global_settings);
|
||||
memgraph::license::RegisterLicenseSettings(memgraph::license::global_license_checker,
|
||||
memgraph::utils::global_settings);
|
||||
|
||||
memgraph::utils::license::global_license_checker.CheckEnvLicense();
|
||||
memgraph::license::global_license_checker.CheckEnvLicense();
|
||||
if (!FLAGS_organization_name.empty() && !FLAGS_license_key.empty()) {
|
||||
memgraph::utils::license::global_license_checker.SetLicenseInfoOverride(FLAGS_license_key, FLAGS_organization_name);
|
||||
memgraph::license::global_license_checker.SetLicenseInfoOverride(FLAGS_license_key, FLAGS_organization_name);
|
||||
}
|
||||
|
||||
memgraph::utils::license::global_license_checker.StartBackgroundLicenseChecker(memgraph::utils::global_settings);
|
||||
memgraph::license::global_license_checker.StartBackgroundLicenseChecker(memgraph::utils::global_settings);
|
||||
|
||||
// All enterprise features should be constructed before the main database
|
||||
// storage. This will cause them to be destructed *after* the main database
|
||||
@@ -832,7 +895,10 @@ int main(int argc, char **argv) {
|
||||
.wal_file_size_kibibytes = FLAGS_storage_wal_file_size_kib,
|
||||
.wal_file_flush_every_n_tx = FLAGS_storage_wal_file_flush_every_n_tx,
|
||||
.snapshot_on_exit = FLAGS_storage_snapshot_on_exit,
|
||||
.restore_replicas_on_startup = true},
|
||||
.restore_replicas_on_startup = true,
|
||||
.items_per_batch = FLAGS_storage_items_per_batch,
|
||||
.recovery_thread_count = FLAGS_storage_recovery_thread_count,
|
||||
.allow_parallel_index_creation = FLAGS_storage_parallel_index_recovery},
|
||||
.transaction = {.isolation_level = ParseIsolationLevel()}};
|
||||
if (FLAGS_storage_snapshot_interval_sec == 0) {
|
||||
if (FLAGS_storage_wal_enabled) {
|
||||
@@ -878,6 +944,29 @@ int main(int argc, char **argv) {
|
||||
interpreter_context.auth = &auth_handler;
|
||||
interpreter_context.auth_checker = &auth_checker;
|
||||
|
||||
if (!FLAGS_init_file.empty()) {
|
||||
spdlog::info("Running init file.");
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
InitFromCypherlFile(interpreter_context, FLAGS_init_file, &audit_log);
|
||||
}
|
||||
#else
|
||||
InitFromCypherlFile(interpreter_context, FLAGS_init_file);
|
||||
#endif
|
||||
}
|
||||
|
||||
auto *maybe_username = std::getenv(kMgUser);
|
||||
auto *maybe_password = std::getenv(kMgPassword);
|
||||
auto *maybe_pass_file = std::getenv(kMgPassfile);
|
||||
if (maybe_username && maybe_password) {
|
||||
auth_handler.CreateUser(maybe_username, maybe_password);
|
||||
} else if (maybe_pass_file) {
|
||||
const auto [username, password] = LoadUsernameAndPassword(maybe_pass_file);
|
||||
if (!username.empty() && !password.empty()) {
|
||||
auth_handler.CreateUser(username, password);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Triggers can execute query procedures, so we need to reload the modules first and then
|
||||
// the triggers
|
||||
@@ -906,20 +995,24 @@ int main(int argc, char **argv) {
|
||||
ServerT server(server_endpoint, &session_data, &context, FLAGS_bolt_session_inactivity_timeout, service_name,
|
||||
FLAGS_bolt_num_workers);
|
||||
|
||||
const auto run_id = memgraph::utils::GenerateUUID();
|
||||
const auto machine_id = memgraph::utils::GetMachineId();
|
||||
session_data.run_id = run_id;
|
||||
|
||||
// Setup telemetry
|
||||
static constexpr auto telemetry_server{"https://telemetry.memgraph.com/88b5e7e8-746a-11e8-9f85-538a9e9690cc/"};
|
||||
std::optional<memgraph::telemetry::Telemetry> telemetry;
|
||||
if (FLAGS_telemetry_enabled) {
|
||||
telemetry.emplace("https://telemetry.memgraph.com/88b5e7e8-746a-11e8-9f85-538a9e9690cc/",
|
||||
data_directory / "telemetry", std::chrono::minutes(10));
|
||||
session_data.run_id = telemetry->GetRunId();
|
||||
telemetry.emplace(telemetry_server, data_directory / "telemetry", run_id, machine_id, std::chrono::minutes(10));
|
||||
telemetry->AddCollector("storage", [&db]() -> nlohmann::json {
|
||||
auto info = db.GetInfo();
|
||||
return {{"vertices", info.vertex_count}, {"edges", info.edge_count}};
|
||||
});
|
||||
telemetry->AddCollector("event_counters", []() -> nlohmann::json {
|
||||
nlohmann::json ret;
|
||||
for (size_t i = 0; i < EventCounter::End(); ++i) {
|
||||
ret[EventCounter::GetName(i)] = EventCounter::global_counters[i].load(std::memory_order_relaxed);
|
||||
for (size_t i = 0; i < memgraph::metrics::CounterEnd(); ++i) {
|
||||
ret[memgraph::metrics::GetCounterName(i)] =
|
||||
memgraph::metrics::global_counters[i].load(std::memory_order_relaxed);
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
@@ -927,12 +1020,51 @@ int main(int argc, char **argv) {
|
||||
return memgraph::query::plan::CallProcedure::GetAndResetCounters();
|
||||
});
|
||||
}
|
||||
memgraph::license::LicenseInfoSender license_info_sender(telemetry_server, run_id, machine_id, memory_limit,
|
||||
memgraph::license::global_license_checker.GetLicenseInfo());
|
||||
|
||||
memgraph::communication::websocket::SafeAuth websocket_auth{&auth};
|
||||
memgraph::communication::websocket::Server websocket_server{
|
||||
{FLAGS_monitoring_address, static_cast<uint16_t>(FLAGS_monitoring_port)}, &context, websocket_auth};
|
||||
AddLoggerSink(websocket_server.GetLoggingSink());
|
||||
|
||||
MonitoringServerT metrics_server{
|
||||
{FLAGS_metrics_address, static_cast<uint16_t>(FLAGS_metrics_port)}, &session_data, &context};
|
||||
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
// Handler for regular termination signals
|
||||
auto shutdown = [&metrics_server, &websocket_server, &server, &interpreter_context] {
|
||||
// Server needs to be shutdown first and then the database. This prevents
|
||||
// a race condition when a transaction is accepted during server shutdown.
|
||||
server.Shutdown();
|
||||
// After the server is notified to stop accepting and processing
|
||||
// connections we tell the execution engine to stop processing all pending
|
||||
// queries.
|
||||
memgraph::query::Shutdown(&interpreter_context);
|
||||
|
||||
websocket_server.Shutdown();
|
||||
metrics_server.Shutdown();
|
||||
};
|
||||
|
||||
InitSignalHandlers(shutdown);
|
||||
} else {
|
||||
// Handler for regular termination signals
|
||||
auto shutdown = [&websocket_server, &server, &interpreter_context] {
|
||||
// Server needs to be shutdown first and then the database. This prevents
|
||||
// a race condition when a transaction is accepted during server shutdown.
|
||||
server.Shutdown();
|
||||
// After the server is notified to stop accepting and processing
|
||||
// connections we tell the execution engine to stop processing all pending
|
||||
// queries.
|
||||
memgraph::query::Shutdown(&interpreter_context);
|
||||
|
||||
websocket_server.Shutdown();
|
||||
};
|
||||
|
||||
InitSignalHandlers(shutdown);
|
||||
}
|
||||
#else
|
||||
// Handler for regular termination signals
|
||||
auto shutdown = [&websocket_server, &server, &interpreter_context] {
|
||||
// Server needs to be shutdown first and then the database. This prevents
|
||||
@@ -942,16 +1074,40 @@ int main(int argc, char **argv) {
|
||||
// connections we tell the execution engine to stop processing all pending
|
||||
// queries.
|
||||
memgraph::query::Shutdown(&interpreter_context);
|
||||
|
||||
websocket_server.Shutdown();
|
||||
};
|
||||
|
||||
InitSignalHandlers(shutdown);
|
||||
#endif
|
||||
|
||||
MG_ASSERT(server.Start(), "Couldn't start the Bolt server!");
|
||||
websocket_server.Start();
|
||||
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
metrics_server.Start();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!FLAGS_init_data_file.empty()) {
|
||||
spdlog::info("Running init data file.");
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
InitFromCypherlFile(interpreter_context, FLAGS_init_data_file, &audit_log);
|
||||
}
|
||||
#else
|
||||
InitFromCypherlFile(interpreter_context, FLAGS_init_data_file);
|
||||
#endif
|
||||
}
|
||||
|
||||
server.AwaitShutdown();
|
||||
websocket_server.AwaitShutdown();
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||
metrics_server.AwaitShutdown();
|
||||
}
|
||||
#endif
|
||||
|
||||
memgraph::query::procedure::gModuleRegistry.UnloadAllModules();
|
||||
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
define_add_lcp(add_lcp_query lcp_query_cpp_files generated_lcp_query_files)
|
||||
|
||||
add_lcp_query(frontend/ast/ast.lcp)
|
||||
add_lcp_query(frontend/semantic/symbol.lcp)
|
||||
add_lcp_query(plan/operator.lcp)
|
||||
|
||||
add_custom_target(generate_lcp_query DEPENDS ${generated_lcp_query_files})
|
||||
|
||||
set(mg_query_sources
|
||||
${lcp_query_cpp_files}
|
||||
frontend/ast/ast.cpp
|
||||
frontend/semantic/symbol.cpp
|
||||
plan/operator_type_info.cpp
|
||||
common.cpp
|
||||
cypher_query_interpreter.cpp
|
||||
dump.cpp
|
||||
@@ -46,7 +40,6 @@ set(mg_query_sources
|
||||
find_package(Boost REQUIRED)
|
||||
|
||||
add_library(mg-query STATIC ${mg_query_sources})
|
||||
add_dependencies(mg-query generate_lcp_query)
|
||||
target_include_directories(mg-query PUBLIC ${CMAKE_SOURCE_DIR}/include)
|
||||
target_link_libraries(mg-query dl cppitertools Boost::headers)
|
||||
target_link_libraries(mg-query mg-integrations-pulsar mg-integrations-kafka mg-storage-v2 mg-license mg-utils mg-kvstore mg-memory)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -107,5 +107,37 @@ storage::PropertyValue PropsSetChecked(T *record, const storage::PropertyId &key
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
concept AccessorWithInitProperties = requires(T accessor,
|
||||
const std::map<storage::PropertyId, storage::PropertyValue> &properties) {
|
||||
{ accessor.InitProperties(properties) } -> std::same_as<storage::Result<bool>>;
|
||||
};
|
||||
|
||||
/// Set property `values` mapped with given `key` on a `record`.
|
||||
///
|
||||
/// @throw QueryRuntimeException if value cannot be set as a property value
|
||||
template <AccessorWithInitProperties T>
|
||||
bool MultiPropsInitChecked(T *record, std::map<storage::PropertyId, storage::PropertyValue> &properties) {
|
||||
try {
|
||||
auto maybe_values = record->InitProperties(properties);
|
||||
if (maybe_values.HasError()) {
|
||||
switch (maybe_values.GetError()) {
|
||||
case storage::Error::SERIALIZATION_ERROR:
|
||||
throw TransactionSerializationException();
|
||||
case storage::Error::DELETED_OBJECT:
|
||||
throw QueryRuntimeException("Trying to set properties on a deleted object.");
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw QueryRuntimeException("Can't set property because properties on edges are disabled.");
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
case storage::Error::NONEXISTENT_OBJECT:
|
||||
throw QueryRuntimeException("Unexpected error when setting a property.");
|
||||
}
|
||||
}
|
||||
return std::move(*maybe_values);
|
||||
} catch (const TypedValueException &) {
|
||||
throw QueryRuntimeException("Cannot set properties.");
|
||||
}
|
||||
}
|
||||
|
||||
int64_t QueryTimestamp();
|
||||
} // namespace memgraph::query
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -16,4 +16,6 @@
|
||||
namespace memgraph::query {
|
||||
inline constexpr uint16_t kDefaultReplicationPort = 10000;
|
||||
inline constexpr auto *kDefaultReplicationServerIp = "0.0.0.0";
|
||||
inline const std::string kAsterisk = "*";
|
||||
inline constexpr uint16_t kDeleteStatisticsNumResults = 6;
|
||||
} // namespace memgraph::query
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -22,8 +22,19 @@
|
||||
#include "query/trigger.hpp"
|
||||
#include "utils/async_timer.hpp"
|
||||
|
||||
#include "query/frame_change.hpp"
|
||||
|
||||
namespace memgraph::query {
|
||||
|
||||
enum class TransactionStatus {
|
||||
IDLE,
|
||||
ACTIVE,
|
||||
VERIFYING,
|
||||
TERMINATED,
|
||||
STARTED_COMMITTING,
|
||||
STARTED_ROLLBACK,
|
||||
};
|
||||
|
||||
struct EvaluationContext {
|
||||
/// Memory for allocations during evaluation of a *single* Pull call.
|
||||
///
|
||||
@@ -66,12 +77,14 @@ struct ExecutionContext {
|
||||
SymbolTable symbol_table;
|
||||
EvaluationContext evaluation_context;
|
||||
std::atomic<bool> *is_shutting_down{nullptr};
|
||||
std::atomic<TransactionStatus> *transaction_status{nullptr};
|
||||
bool is_profile_query{false};
|
||||
std::chrono::duration<double> profile_execution_time;
|
||||
plan::ProfilingStats stats;
|
||||
plan::ProfilingStats *stats_root{nullptr};
|
||||
ExecutionStats execution_stats;
|
||||
TriggerContextCollector *trigger_context_collector{nullptr};
|
||||
FrameChangeCollector *frame_change_collector{nullptr};
|
||||
utils::AsyncTimer timer;
|
||||
#ifdef MG_ENTERPRISE
|
||||
std::unique_ptr<FineGrainedAuthChecker> auth_checker{nullptr};
|
||||
@@ -82,7 +95,9 @@ static_assert(std::is_move_assignable_v<ExecutionContext>, "ExecutionContext mus
|
||||
static_assert(std::is_move_constructible_v<ExecutionContext>, "ExecutionContext must be move constructible!");
|
||||
|
||||
inline bool MustAbort(const ExecutionContext &context) noexcept {
|
||||
return (context.is_shutting_down != nullptr && context.is_shutting_down->load(std::memory_order_acquire)) ||
|
||||
return (context.transaction_status != nullptr &&
|
||||
context.transaction_status->load(std::memory_order_acquire) == TransactionStatus::TERMINATED) ||
|
||||
(context.is_shutting_down != nullptr && context.is_shutting_down->load(std::memory_order_acquire)) ||
|
||||
context.timer.IsExpired();
|
||||
}
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ auto SubgraphVertexAccessor::OutEdges(storage::View view) const -> decltype(impl
|
||||
auto maybe_edges = impl_.impl_.OutEdges(view, {});
|
||||
if (maybe_edges.HasError()) return maybe_edges.GetError();
|
||||
auto edges = std::move(*maybe_edges);
|
||||
auto graph_edges = graph_->edges();
|
||||
const auto &graph_edges = graph_->edges();
|
||||
|
||||
std::vector<storage::EdgeAccessor> filteredOutEdges;
|
||||
for (auto &edge : edges) {
|
||||
@@ -132,7 +132,7 @@ auto SubgraphVertexAccessor::InEdges(storage::View view) const -> decltype(impl_
|
||||
auto maybe_edges = impl_.impl_.InEdges(view, {});
|
||||
if (maybe_edges.HasError()) return maybe_edges.GetError();
|
||||
auto edges = std::move(*maybe_edges);
|
||||
auto graph_edges = graph_->edges();
|
||||
const auto &graph_edges = graph_->edges();
|
||||
|
||||
std::vector<storage::EdgeAccessor> filteredOutEdges;
|
||||
for (auto &edge : edges) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -71,6 +71,10 @@ class EdgeAccessor final {
|
||||
return impl_.SetProperty(key, value);
|
||||
}
|
||||
|
||||
storage::Result<bool> InitProperties(const std::map<storage::PropertyId, storage::PropertyValue> &properties) {
|
||||
return impl_.InitProperties(properties);
|
||||
}
|
||||
|
||||
storage::Result<storage::PropertyValue> RemoveProperty(storage::PropertyId key) {
|
||||
return SetProperty(key, storage::PropertyValue());
|
||||
}
|
||||
@@ -125,6 +129,10 @@ class VertexAccessor final {
|
||||
return impl_.SetProperty(key, value);
|
||||
}
|
||||
|
||||
storage::Result<bool> InitProperties(const std::map<storage::PropertyId, storage::PropertyValue> &properties) {
|
||||
return impl_.InitProperties(properties);
|
||||
}
|
||||
|
||||
storage::Result<storage::PropertyValue> RemoveProperty(storage::PropertyId key) {
|
||||
return SetProperty(key, storage::PropertyValue());
|
||||
}
|
||||
@@ -200,7 +208,7 @@ class SubgraphVertexAccessor final {
|
||||
return impl_ == v.impl_;
|
||||
}
|
||||
|
||||
auto InEdges(storage::View view) const -> decltype(impl_.OutEdges(view));
|
||||
auto InEdges(storage::View view) const -> decltype(impl_.InEdges(view));
|
||||
|
||||
auto OutEdges(storage::View view) const -> decltype(impl_.OutEdges(view));
|
||||
|
||||
@@ -422,6 +430,25 @@ class DbAccessor final {
|
||||
return accessor_->LabelPropertyIndexExists(label, prop);
|
||||
}
|
||||
|
||||
std::optional<storage::IndexStats> GetIndexStats(const storage::LabelId &label,
|
||||
const storage::PropertyId &property) const {
|
||||
return accessor_->GetIndexStats(label, property);
|
||||
}
|
||||
|
||||
std::vector<std::pair<storage::LabelId, storage::PropertyId>> ClearIndexStats() {
|
||||
return accessor_->ClearIndexStats();
|
||||
}
|
||||
|
||||
std::vector<std::pair<storage::LabelId, storage::PropertyId>> DeleteIndexStatsForLabels(
|
||||
const std::span<std::string> labels) {
|
||||
return accessor_->DeleteIndexStatsForLabels(labels);
|
||||
}
|
||||
|
||||
void SetIndexStats(const storage::LabelId &label, const storage::PropertyId &property,
|
||||
const storage::IndexStats &stats) {
|
||||
accessor_->SetIndexStats(label, property, stats);
|
||||
}
|
||||
|
||||
int64_t VerticesCount() const { return accessor_->ApproximateVertexCount(); }
|
||||
|
||||
int64_t VerticesCount(storage::LabelId label) const { return accessor_->ApproximateVertexCount(label); }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -120,9 +120,8 @@ class HintedAbortError : public utils::BasicException {
|
||||
using utils::BasicException::BasicException;
|
||||
HintedAbortError()
|
||||
: utils::BasicException(
|
||||
"Transaction was asked to abort, most likely because it was "
|
||||
"executing longer than time specified by "
|
||||
"--query-execution-timeout-sec flag.") {}
|
||||
"Transaction was asked to abort either because it was executing longer than time specified or another user "
|
||||
"asked it to abort.") {}
|
||||
};
|
||||
|
||||
class ExplicitTransactionUsageException : public QueryRuntimeException {
|
||||
@@ -212,6 +211,21 @@ class IsolationLevelModificationInMulticommandTxException : public QueryExceptio
|
||||
: QueryException("Isolation level cannot be modified in multicommand transactions.") {}
|
||||
};
|
||||
|
||||
class IsolationLevelModificationInAnalyticsException : public QueryException {
|
||||
public:
|
||||
IsolationLevelModificationInAnalyticsException()
|
||||
: QueryException(
|
||||
"Isolation level cannot be modified when storage mode is set to IN_MEMORY_ANALYTICAL."
|
||||
"IN_MEMORY_ANALYTICAL mode doesn't provide any isolation guarantees, "
|
||||
"you can think about it as an equivalent to READ_UNCOMMITED.") {}
|
||||
};
|
||||
|
||||
class StorageModeModificationInMulticommandTxException : public QueryException {
|
||||
public:
|
||||
StorageModeModificationInMulticommandTxException()
|
||||
: QueryException("Storage mode cannot be modified in multicommand transactions.") {}
|
||||
};
|
||||
|
||||
class CreateSnapshotInMulticommandTxException final : public QueryException {
|
||||
public:
|
||||
CreateSnapshotInMulticommandTxException()
|
||||
@@ -230,6 +244,12 @@ class VersionInfoInMulticommandTxException : public QueryException {
|
||||
: QueryException("Version info query not allowed in multicommand transactions.") {}
|
||||
};
|
||||
|
||||
class AnalyzeGraphInMulticommandTxException : public QueryException {
|
||||
public:
|
||||
AnalyzeGraphInMulticommandTxException()
|
||||
: QueryException("Analyze graph query not allowed in multicommand transactions.") {}
|
||||
};
|
||||
|
||||
class ReplicationException : public utils::BasicException {
|
||||
public:
|
||||
using utils::BasicException::BasicException;
|
||||
@@ -237,4 +257,11 @@ class ReplicationException : public utils::BasicException {
|
||||
: utils::BasicException("Replication Exception: {} Check the status of the replicas using 'SHOW REPLICA' query.",
|
||||
message) {}
|
||||
};
|
||||
|
||||
class TransactionQueueInMulticommandTxException : public QueryException {
|
||||
public:
|
||||
TransactionQueueInMulticommandTxException()
|
||||
: QueryException("Transaction queue queries not allowed in multicommand transactions.") {}
|
||||
};
|
||||
|
||||
} // namespace memgraph::query
|
||||
|
||||
122
src/query/frame_change.hpp
Normal file
122
src/query/frame_change.hpp
Normal file
@@ -0,0 +1,122 @@
|
||||
// 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 "query/typed_value.hpp"
|
||||
#include "utils/memory.hpp"
|
||||
#include "utils/pmr/unordered_map.hpp"
|
||||
#include "utils/pmr/vector.hpp"
|
||||
namespace memgraph::query {
|
||||
|
||||
// Key is hash output, value is vector of unique elements
|
||||
using CachedType = utils::pmr::unordered_map<size_t, std::vector<TypedValue>>;
|
||||
|
||||
struct CachedValue {
|
||||
// Cached value, this can be probably templateized
|
||||
CachedType cache_;
|
||||
|
||||
explicit CachedValue(utils::MemoryResource *mem) : cache_(mem) {}
|
||||
|
||||
CachedValue(CachedType &&cache, memgraph::utils::MemoryResource *memory) : cache_(std::move(cache), memory) {}
|
||||
|
||||
CachedValue(const CachedValue &other, memgraph::utils::MemoryResource *memory) : cache_(other.cache_, memory) {}
|
||||
|
||||
CachedValue(CachedValue &&other, memgraph::utils::MemoryResource *memory) : cache_(std::move(other.cache_), memory) {}
|
||||
|
||||
CachedValue(CachedValue &&other) noexcept = delete;
|
||||
|
||||
/// Copy construction without memgraph::utils::MemoryResource is not allowed.
|
||||
CachedValue(const CachedValue &) = delete;
|
||||
|
||||
CachedValue &operator=(const CachedValue &) = delete;
|
||||
CachedValue &operator=(CachedValue &&) = delete;
|
||||
|
||||
~CachedValue() = default;
|
||||
|
||||
memgraph::utils::MemoryResource *GetMemoryResource() const noexcept {
|
||||
return cache_.get_allocator().GetMemoryResource();
|
||||
}
|
||||
|
||||
// Func to check if cache_ contains value
|
||||
bool CacheValue(const TypedValue &value) {
|
||||
if (!value.IsList()) {
|
||||
return false;
|
||||
}
|
||||
const auto &list = value.ValueList();
|
||||
TypedValue::Hash hash{};
|
||||
for (const TypedValue &element : list) {
|
||||
const auto key = hash(element);
|
||||
auto &vector_values = cache_[key];
|
||||
if (!IsValueInVec(vector_values, element)) {
|
||||
vector_values.push_back(element);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Func to cache_value inside cache_
|
||||
bool ContainsValue(const TypedValue &value) const {
|
||||
TypedValue::Hash hash{};
|
||||
const auto key = hash(value);
|
||||
if (cache_.contains(key)) {
|
||||
return IsValueInVec(cache_.at(key), value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
bool IsValueInVec(const std::vector<TypedValue> &vec_values, const TypedValue &value) const {
|
||||
return std::any_of(vec_values.begin(), vec_values.end(), [&value](auto &vec_value) {
|
||||
const auto is_value_equal = vec_value == value;
|
||||
if (is_value_equal.IsNull()) return false;
|
||||
return is_value_equal.ValueBool();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Class tracks keys for which user can cache values which help with faster search or faster retrieval
|
||||
// in the future.
|
||||
class FrameChangeCollector {
|
||||
public:
|
||||
explicit FrameChangeCollector(utils::MemoryResource *mem) : tracked_values_(mem){};
|
||||
|
||||
// Add tracking key to cache later value
|
||||
CachedValue &AddTrackingKey(const std::string &key) {
|
||||
const auto &[it, _] = tracked_values_.emplace(key, tracked_values_.get_allocator().GetMemoryResource());
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Is key tracked
|
||||
bool IsKeyTracked(const std::string &key) const { return tracked_values_.contains(key); }
|
||||
|
||||
// Is value for given key cached
|
||||
bool IsKeyValueCached(const std::string &key) const {
|
||||
return tracked_values_.contains(key) && !tracked_values_.at(key).cache_.empty();
|
||||
}
|
||||
|
||||
// Reset value for tracking key
|
||||
bool ResetTrackingValue(const std::string &key) {
|
||||
if (tracked_values_.contains(key)) {
|
||||
tracked_values_.erase(key);
|
||||
AddTrackingKey(key);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get value cached for tracking key, throws if key is not in tracked
|
||||
CachedValue &GetCachedValue(const std::string &key) { return tracked_values_.at(key); }
|
||||
|
||||
// Checks for keys tracked
|
||||
bool IsTrackingValues() const { return !tracked_values_.empty(); }
|
||||
|
||||
private:
|
||||
// Key is output of utils::GetFrameChangeId, value is utils::pmr::unordered_map
|
||||
memgraph::utils::pmr::unordered_map<std::string, CachedValue> tracked_values_;
|
||||
};
|
||||
} // namespace memgraph::query
|
||||
282
src/query/frontend/ast/ast.cpp
Normal file
282
src/query/frontend/ast/ast.cpp
Normal file
@@ -0,0 +1,282 @@
|
||||
// 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 "query/frontend/ast/ast.hpp"
|
||||
#include "query/frontend/ast/ast_visitor.hpp"
|
||||
#include "utils/typeinfo.hpp"
|
||||
|
||||
namespace memgraph {
|
||||
|
||||
constexpr utils::TypeInfo query::LabelIx::kType{utils::TypeId::AST_LABELIX, "LabelIx", nullptr};
|
||||
|
||||
constexpr utils::TypeInfo query::PropertyIx::kType{utils::TypeId::AST_PROPERTYIX, "PropertyIx", nullptr};
|
||||
|
||||
constexpr utils::TypeInfo query::EdgeTypeIx::kType{utils::TypeId::AST_EDGETYPEIX, "EdgeTypeIx", nullptr};
|
||||
|
||||
constexpr utils::TypeInfo query::Tree::kType{utils::TypeId::AST_TREE, "Tree", nullptr};
|
||||
|
||||
constexpr utils::TypeInfo query::Expression::kType{utils::TypeId::AST_EXPRESSION, "Expression", &query::Tree::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::Where::kType{utils::TypeId::AST_WHERE, "Where", &query::Tree::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::BinaryOperator::kType{utils::TypeId::AST_BINARY_OPERATOR, "BinaryOperator",
|
||||
&query::Expression::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::UnaryOperator::kType{utils::TypeId::AST_UNARY_OPERATOR, "UnaryOperator",
|
||||
&query::Expression::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::OrOperator::kType{utils::TypeId::AST_OR_OPERATOR, "OrOperator",
|
||||
&query::BinaryOperator::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::XorOperator::kType{utils::TypeId::AST_XOR_OPERATOR, "XorOperator",
|
||||
&query::BinaryOperator::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::AndOperator::kType{utils::TypeId::AST_AND_OPERATOR, "AndOperator",
|
||||
&query::BinaryOperator::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::AdditionOperator::kType{utils::TypeId::AST_ADDITION_OPERATOR, "AdditionOperator",
|
||||
&query::BinaryOperator::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::SubtractionOperator::kType{utils::TypeId::AST_SUBTRACTION_OPERATOR,
|
||||
"SubtractionOperator", &query::BinaryOperator::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::MultiplicationOperator::kType{utils::TypeId::AST_MULTIPLICATION_OPERATOR,
|
||||
"MultiplicationOperator", &query::BinaryOperator::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::DivisionOperator::kType{utils::TypeId::AST_DIVISION_OPERATOR, "DivisionOperator",
|
||||
&query::BinaryOperator::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::ModOperator::kType{utils::TypeId::AST_MOD_OPERATOR, "ModOperator",
|
||||
&query::BinaryOperator::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::NotEqualOperator::kType{utils::TypeId::AST_NOT_EQUAL_OPERATOR, "NotEqualOperator",
|
||||
&query::BinaryOperator::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::EqualOperator::kType{utils::TypeId::AST_EQUAL_OPERATOR, "EqualOperator",
|
||||
&query::BinaryOperator::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::LessOperator::kType{utils::TypeId::AST_LESS_OPERATOR, "LessOperator",
|
||||
&query::BinaryOperator::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::GreaterOperator::kType{utils::TypeId::AST_GREATER_OPERATOR, "GreaterOperator",
|
||||
&query::BinaryOperator::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::LessEqualOperator::kType{utils::TypeId::AST_LESS_EQUAL_OPERATOR, "LessEqualOperator",
|
||||
&query::BinaryOperator::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::GreaterEqualOperator::kType{utils::TypeId::AST_GREATER_EQUAL_OPERATOR,
|
||||
"GreaterEqualOperator", &query::BinaryOperator::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::InListOperator::kType{utils::TypeId::AST_IN_LIST_OPERATOR, "InListOperator",
|
||||
&query::BinaryOperator::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::SubscriptOperator::kType{utils::TypeId::AST_SUBSCRIPT_OPERATOR, "SubscriptOperator",
|
||||
&query::BinaryOperator::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::NotOperator::kType{utils::TypeId::AST_NOT_OPERATOR, "NotOperator",
|
||||
&query::UnaryOperator::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::UnaryPlusOperator::kType{utils::TypeId::AST_UNARY_PLUS_OPERATOR, "UnaryPlusOperator",
|
||||
&query::UnaryOperator::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::UnaryMinusOperator::kType{utils::TypeId::AST_UNARY_MINUS_OPERATOR,
|
||||
"UnaryMinusOperator", &query::UnaryOperator::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::IsNullOperator::kType{utils::TypeId::AST_IS_NULL_OPERATOR, "IsNullOperator",
|
||||
&query::UnaryOperator::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::Aggregation::kType{utils::TypeId::AST_AGGREGATION, "Aggregation",
|
||||
&query::BinaryOperator::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::ListSlicingOperator::kType{utils::TypeId::AST_LIST_SLICING_OPERATOR,
|
||||
"ListSlicingOperator", &query::Expression::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::IfOperator::kType{utils::TypeId::AST_IF_OPERATOR, "IfOperator",
|
||||
&query::Expression::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::BaseLiteral::kType{utils::TypeId::AST_BASE_LITERAL, "BaseLiteral",
|
||||
&query::Expression::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::PrimitiveLiteral::kType{utils::TypeId::AST_PRIMITIVE_LITERAL, "PrimitiveLiteral",
|
||||
&query::BaseLiteral::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::ListLiteral::kType{utils::TypeId::AST_LIST_LITERAL, "ListLiteral",
|
||||
&query::BaseLiteral::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::MapLiteral::kType{utils::TypeId::AST_MAP_LITERAL, "MapLiteral",
|
||||
&query::BaseLiteral::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::MapProjectionLiteral::kType{utils::TypeId::AST_MAP_PROJECTION_LITERAL,
|
||||
"MapProjectionLiteral", &query::BaseLiteral::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::Identifier::kType{utils::TypeId::AST_IDENTIFIER, "Identifier",
|
||||
&query::Expression::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::PropertyLookup::kType{utils::TypeId::AST_PROPERTY_LOOKUP, "PropertyLookup",
|
||||
&query::Expression::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::AllPropertiesLookup::kType{utils::TypeId::AST_ALL_PROPERTIES_LOOKUP,
|
||||
"AllPropertiesLookup", &query::Expression::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::LabelsTest::kType{utils::TypeId::AST_LABELS_TEST, "LabelsTest",
|
||||
&query::Expression::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::Function::kType{utils::TypeId::AST_FUNCTION, "Function", &query::Expression::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::Reduce::kType{utils::TypeId::AST_REDUCE, "Reduce", &query::Expression::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::Coalesce::kType{utils::TypeId::AST_COALESCE, "Coalesce", &query::Expression::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::Extract::kType{utils::TypeId::AST_EXTRACT, "Extract", &query::Expression::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::All::kType{utils::TypeId::AST_ALL, "All", &query::Expression::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::Single::kType{utils::TypeId::AST_SINGLE, "Single", &query::Expression::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::Any::kType{utils::TypeId::AST_ANY, "Any", &query::Expression::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::None::kType{utils::TypeId::AST_NONE, "None", &query::Expression::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::ParameterLookup::kType{utils::TypeId::AST_PARAMETER_LOOKUP, "ParameterLookup",
|
||||
&query::Expression::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::RegexMatch::kType{utils::TypeId::AST_REGEX_MATCH, "RegexMatch",
|
||||
&query::Expression::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::NamedExpression::kType{utils::TypeId::AST_NAMED_EXPRESSION, "NamedExpression",
|
||||
&query::Tree::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::PatternAtom::kType{utils::TypeId::AST_PATTERN_ATOM, "PatternAtom",
|
||||
&query::Tree::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::NodeAtom::kType{utils::TypeId::AST_NODE_ATOM, "NodeAtom", &query::PatternAtom::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::EdgeAtom::Lambda::kType{utils::TypeId::AST_EDGE_ATOM_LAMBDA, "Lambda", nullptr};
|
||||
|
||||
constexpr utils::TypeInfo query::EdgeAtom::kType{utils::TypeId::AST_EDGE_ATOM, "EdgeAtom", &query::PatternAtom::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::Pattern::kType{utils::TypeId::AST_PATTERN, "Pattern", &query::Tree::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::Clause::kType{utils::TypeId::AST_CLAUSE, "Clause", &query::Tree::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::SingleQuery::kType{utils::TypeId::AST_SINGLE_QUERY, "SingleQuery",
|
||||
&query::Tree::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::CypherUnion::kType{utils::TypeId::AST_CYPHER_UNION, "CypherUnion",
|
||||
&query::Tree::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::Query::kType{utils::TypeId::AST_QUERY, "Query", &query::Tree::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::CypherQuery::kType{utils::TypeId::AST_CYPHER_QUERY, "CypherQuery",
|
||||
&query::Query::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::ExplainQuery::kType{utils::TypeId::AST_EXPLAIN_QUERY, "ExplainQuery",
|
||||
&query::Query::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::ProfileQuery::kType{utils::TypeId::AST_PROFILE_QUERY, "ProfileQuery",
|
||||
&query::Query::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::IndexQuery::kType{utils::TypeId::AST_INDEX_QUERY, "IndexQuery", &query::Query::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::Create::kType{utils::TypeId::AST_CREATE, "Create", &query::Clause::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::CallProcedure::kType{utils::TypeId::AST_CALL_PROCEDURE, "CallProcedure",
|
||||
&query::Clause::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::Match::kType{utils::TypeId::AST_MATCH, "Match", &query::Clause::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::SortItem::kType{utils::TypeId::AST_SORT_ITEM, "SortItem", nullptr};
|
||||
|
||||
constexpr utils::TypeInfo query::ReturnBody::kType{utils::TypeId::AST_RETURN_BODY, "ReturnBody", nullptr};
|
||||
|
||||
constexpr utils::TypeInfo query::Return::kType{utils::TypeId::AST_RETURN, "Return", &query::Clause::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::With::kType{utils::TypeId::AST_WITH, "With", &query::Clause::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::Delete::kType{utils::TypeId::AST_DELETE, "Delete", &query::Clause::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::SetProperty::kType{utils::TypeId::AST_SET_PROPERTY, "SetProperty",
|
||||
&query::Clause::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::SetProperties::kType{utils::TypeId::AST_SET_PROPERTIES, "SetProperties",
|
||||
&query::Clause::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::SetLabels::kType{utils::TypeId::AST_SET_LABELS, "SetLabels", &query::Clause::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::RemoveProperty::kType{utils::TypeId::AST_REMOVE_PROPERTY, "RemoveProperty",
|
||||
&query::Clause::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::RemoveLabels::kType{utils::TypeId::AST_REMOVE_LABELS, "RemoveLabels",
|
||||
&query::Clause::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::Merge::kType{utils::TypeId::AST_MERGE, "Merge", &query::Clause::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::Unwind::kType{utils::TypeId::AST_UNWIND, "Unwind", &query::Clause::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::AuthQuery::kType{utils::TypeId::AST_AUTH_QUERY, "AuthQuery", &query::Query::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::InfoQuery::kType{utils::TypeId::AST_INFO_QUERY, "InfoQuery", &query::Query::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::Constraint::kType{utils::TypeId::AST_CONSTRAINT, "Constraint", nullptr};
|
||||
|
||||
constexpr utils::TypeInfo query::ConstraintQuery::kType{utils::TypeId::AST_CONSTRAINT_QUERY, "ConstraintQuery",
|
||||
&query::Query::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::DumpQuery::kType{utils::TypeId::AST_DUMP_QUERY, "DumpQuery", &query::Query::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::ReplicationQuery::kType{utils::TypeId::AST_REPLICATION_QUERY, "ReplicationQuery",
|
||||
&query::Query::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::LockPathQuery::kType{utils::TypeId::AST_LOCK_PATH_QUERY, "LockPathQuery",
|
||||
&query::Query::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::LoadCsv::kType{utils::TypeId::AST_LOAD_CSV, "LoadCsv", &query::Clause::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::FreeMemoryQuery::kType{utils::TypeId::AST_FREE_MEMORY_QUERY, "FreeMemoryQuery",
|
||||
&query::Query::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::TriggerQuery::kType{utils::TypeId::AST_TRIGGER_QUERY, "TriggerQuery",
|
||||
&query::Query::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::IsolationLevelQuery::kType{utils::TypeId::AST_ISOLATION_LEVEL_QUERY,
|
||||
"IsolationLevelQuery", &query::Query::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::StorageModeQuery::kType{utils::TypeId::AST_STORAGE_MODE_QUERY, "StorageModeQuery",
|
||||
&query::Query::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::CreateSnapshotQuery::kType{utils::TypeId::AST_CREATE_SNAPSHOT_QUERY,
|
||||
"CreateSnapshotQuery", &query::Query::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::StreamQuery::kType{utils::TypeId::AST_STREAM_QUERY, "StreamQuery",
|
||||
&query::Query::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::SettingQuery::kType{utils::TypeId::AST_SETTING_QUERY, "SettingQuery",
|
||||
&query::Query::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::VersionQuery::kType{utils::TypeId::AST_VERSION_QUERY, "VersionQuery",
|
||||
&query::Query::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::Foreach::kType{utils::TypeId::AST_FOREACH, "Foreach", &query::Clause::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::ShowConfigQuery::kType{utils::TypeId::AST_SHOW_CONFIG_QUERY, "ShowConfigQuery",
|
||||
&query::Query::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::AnalyzeGraphQuery::kType{utils::TypeId::AST_ANALYZE_GRAPH_QUERY, "AnalyzeGraphQuery",
|
||||
&query::Query::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::TransactionQueueQuery::kType{utils::TypeId::AST_TRANSACTION_QUEUE_QUERY,
|
||||
"TransactionQueueQuery", &query::Query::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::Exists::kType{utils::TypeId::AST_EXISTS, "Exists", &query::Expression::kType};
|
||||
|
||||
constexpr utils::TypeInfo query::CallSubquery::kType{utils::TypeId::AST_CALL_SUBQUERY, "CallSubquery",
|
||||
&query::Clause::kType};
|
||||
} // namespace memgraph
|
||||
3445
src/query/frontend/ast/ast.hpp
Normal file
3445
src/query/frontend/ast/ast.hpp
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user