Compare commits
138 Commits
replicate-
...
add-transf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e71b9a99ae | ||
|
|
2aa6b9ba8f | ||
|
|
6c9cdef944 | ||
|
|
5c10fb1d51 | ||
|
|
e73b3feea3 | ||
|
|
2ed40e9f16 | ||
|
|
ced34bc79c | ||
|
|
2b3540119f | ||
|
|
3936668e13 | ||
|
|
476080bace | ||
|
|
8528822af1 | ||
|
|
7ecf970dcd | ||
|
|
6ad5463d72 | ||
|
|
b1d560737e | ||
|
|
b719f0744f | ||
|
|
440838c0e9 | ||
|
|
79a3c5af8e | ||
|
|
bf03b38e39 | ||
|
|
fd63944493 | ||
|
|
6694de2dfa | ||
|
|
5e5f4ffc5d | ||
|
|
060b9d1c16 | ||
|
|
29a505cb38 | ||
|
|
d4fcd745d2 | ||
|
|
58546a9fe1 | ||
|
|
ab56abf4ca | ||
|
|
1bd47318cd | ||
|
|
0403b67073 | ||
|
|
9e4babcdbb | ||
|
|
b094fdbadc | ||
|
|
07dea328d8 | ||
|
|
bd1852f407 | ||
|
|
9c51dbbb01 | ||
|
|
c0d4f5e0bc | ||
|
|
974a6e3027 | ||
|
|
d9464c6ffd | ||
|
|
312d01bd0c | ||
|
|
b6b32bec03 | ||
|
|
93992a275b | ||
|
|
b5413c6f82 | ||
|
|
09fd5939da | ||
|
|
02eab6ab9c | ||
|
|
9661c52179 | ||
|
|
e928eed028 | ||
|
|
eb5167dfef | ||
|
|
b952139973 | ||
|
|
28dbcd1545 | ||
|
|
d516e40841 | ||
|
|
a6ec81b179 | ||
|
|
c526ff2a8f | ||
|
|
5f509532f2 | ||
|
|
4b3ba908c7 | ||
|
|
030b554ffd | ||
|
|
4bc5d749b2 | ||
|
|
a426ef9cc3 | ||
|
|
60e167d676 | ||
|
|
3f8befde79 | ||
|
|
9355e58e73 | ||
|
|
476968e2c8 | ||
|
|
97183fb9da | ||
|
|
adb65b2fff | ||
|
|
3bf2cf65ab | ||
|
|
8f3f693f20 | ||
|
|
2e51e703c3 | ||
|
|
adf7533751 | ||
|
|
509183e985 | ||
|
|
1fe2190747 | ||
|
|
762fe6a65d | ||
|
|
271b1a5ddb | ||
|
|
260660f1dd | ||
|
|
e5350a011c | ||
|
|
7bf827bb1e | ||
|
|
5d13c281fa | ||
|
|
020273f475 | ||
|
|
4a99625287 | ||
|
|
5bbed6ef9a | ||
|
|
f0bac53e7b | ||
|
|
514fed51c4 | ||
|
|
2877c343e8 | ||
|
|
50a1d1abb3 | ||
|
|
e8850549d2 | ||
|
|
fd819cd099 | ||
|
|
60f4ffc6a1 | ||
|
|
bd2ec6374a | ||
|
|
c501f59a09 | ||
|
|
210bea83d4 | ||
|
|
57fe3463f2 | ||
|
|
53fcd8ac4d | ||
|
|
259cba5d43 | ||
|
|
285b409927 | ||
|
|
8ebab84324 | ||
|
|
3fd9ce4a33 | ||
|
|
be4eb95a98 | ||
|
|
903a9f4636 | ||
|
|
18bd02423a | ||
|
|
58c0c4cebb | ||
|
|
110ca3968c | ||
|
|
9072fb7703 | ||
|
|
2b7707a2f1 | ||
|
|
76ca019f31 | ||
|
|
609b9a20f1 | ||
|
|
e489e4f3e7 | ||
|
|
ab4d1efe0b | ||
|
|
036da58d30 | ||
|
|
919f07fae1 | ||
|
|
ca1e98ad94 | ||
|
|
f0aca2d23b | ||
|
|
ec9840fff2 | ||
|
|
992e718a97 | ||
|
|
2ec6b7f40b | ||
|
|
05eca46267 | ||
|
|
fae039c215 | ||
|
|
3b9133fd5a | ||
|
|
9d056e7649 | ||
|
|
aa4f68a37d | ||
|
|
84721f7e0a | ||
|
|
261aa4f49b | ||
|
|
5ce1526995 | ||
|
|
cb843ee664 | ||
|
|
0f1ca745e5 | ||
|
|
3b781bf525 | ||
|
|
d573eda8bb | ||
|
|
00226dee24 | ||
|
|
546bfc0ede | ||
|
|
5b1ba10183 | ||
|
|
b25e9968ee | ||
|
|
bcd23fe3cb | ||
|
|
68e5610566 | ||
|
|
0ea96663ba | ||
|
|
da17fe92d6 | ||
|
|
e73eac77a9 | ||
|
|
d51a61fc5f | ||
|
|
b875649270 | ||
|
|
05cc35bf93 | ||
|
|
63f8298033 | ||
|
|
df95775222 | ||
|
|
eb22edfd35 | ||
|
|
1b85d77e9e |
20
.github/workflows/daily_benchmark.yaml
vendored
20
.github/workflows/daily_benchmark.yaml
vendored
@@ -67,7 +67,11 @@ jobs:
|
|||||||
- name: Run mgbench
|
- name: Run mgbench
|
||||||
run: |
|
run: |
|
||||||
cd tests/mgbench
|
cd tests/mgbench
|
||||||
./benchmark.py vendor-native --num-workers-for-benchmark 12 --export-results benchmark_result.json pokec/medium/*/*
|
./benchmark.py vendor-native --num-workers-for-benchmark 12 --export-results benchmark_pokec.json pokec/medium/*/*
|
||||||
|
|
||||||
|
./benchmark.py vendor-native --num-workers-for-benchmark 1 --export-results benchmark_supernode.json supernode
|
||||||
|
|
||||||
|
./benchmark.py vendor-native --num-workers-for-benchmark 1 --export-results benchmark_high_write_set_property.json high_write_set_property
|
||||||
|
|
||||||
- name: Upload mgbench results
|
- name: Upload mgbench results
|
||||||
run: |
|
run: |
|
||||||
@@ -76,7 +80,19 @@ jobs:
|
|||||||
source ve3/bin/activate
|
source ve3/bin/activate
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
./main.py --benchmark-name "mgbench" \
|
./main.py --benchmark-name "mgbench" \
|
||||||
--benchmark-results-path "../../tests/mgbench/benchmark_result.json" \
|
--benchmark-results-path "../../tests/mgbench/benchmark_pokec.json" \
|
||||||
|
--github-run-id "${{ github.run_id }}" \
|
||||||
|
--github-run-number "${{ github.run_number }}" \
|
||||||
|
--head-branch-name "${{ env.BRANCH_NAME }}"
|
||||||
|
|
||||||
|
./main.py --benchmark-name "supernode" \
|
||||||
|
--benchmark-results-path "../../tests/mgbench/benchmark_supernode.json" \
|
||||||
|
--github-run-id "${{ github.run_id }}" \
|
||||||
|
--github-run-number "${{ github.run_number }}" \
|
||||||
|
--head-branch-name "${{ env.BRANCH_NAME }}"
|
||||||
|
|
||||||
|
./main.py --benchmark-name "high_write_set_property" \
|
||||||
|
--benchmark-results-path "../../tests/mgbench/benchmark_high_write_set_property.json" \
|
||||||
--github-run-id "${{ github.run_id }}" \
|
--github-run-id "${{ github.run_id }}" \
|
||||||
--github-run-number "${{ github.run_number }}" \
|
--github-run-number "${{ github.run_number }}" \
|
||||||
--head-branch-name "${{ env.BRANCH_NAME }}"
|
--head-branch-name "${{ env.BRANCH_NAME }}"
|
||||||
|
|||||||
21
.github/workflows/diff.yaml
vendored
21
.github/workflows/diff.yaml
vendored
@@ -101,7 +101,7 @@ jobs:
|
|||||||
echo ${file}
|
echo ${file}
|
||||||
if [[ ${file} == *.py ]]; then
|
if [[ ${file} == *.py ]]; then
|
||||||
python3 -m black --check --diff ${file}
|
python3 -m black --check --diff ${file}
|
||||||
python3 -m isort --check-only --diff ${file}
|
python3 -m isort --profile black --check-only --diff ${file}
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -229,6 +229,11 @@ jobs:
|
|||||||
# branches and tags. (default: 1)
|
# branches and tags. (default: 1)
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Check e2e service dependencies
|
||||||
|
run: |
|
||||||
|
cd tests/e2e
|
||||||
|
./dependency_check.sh
|
||||||
|
|
||||||
- name: Build release binaries
|
- name: Build release binaries
|
||||||
run: |
|
run: |
|
||||||
# Activate toolchain.
|
# Activate toolchain.
|
||||||
@@ -266,21 +271,22 @@ jobs:
|
|||||||
|
|
||||||
- name: Run e2e tests
|
- name: Run e2e tests
|
||||||
run: |
|
run: |
|
||||||
# TODO(gitbuda): Setup mgclient and pymgclient properly.
|
|
||||||
cd tests
|
cd tests
|
||||||
./setup.sh
|
./setup.sh /opt/toolchain-v4/activate
|
||||||
source ve3/bin/activate
|
source ve3/bin/activate_e2e
|
||||||
cd e2e
|
cd e2e
|
||||||
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../../libs/mgclient/lib python runner.py --workloads-root-directory .
|
./run.sh
|
||||||
|
|
||||||
- name: Run stress test (plain)
|
- name: Run stress test (plain)
|
||||||
run: |
|
run: |
|
||||||
cd tests/stress
|
cd tests/stress
|
||||||
|
source ve3/bin/activate
|
||||||
./continuous_integration
|
./continuous_integration
|
||||||
|
|
||||||
- name: Run stress test (SSL)
|
- name: Run stress test (SSL)
|
||||||
run: |
|
run: |
|
||||||
cd tests/stress
|
cd tests/stress
|
||||||
|
source ve3/bin/activate
|
||||||
./continuous_integration --use-ssl
|
./continuous_integration --use-ssl
|
||||||
|
|
||||||
- name: Run durability test
|
- name: Run durability test
|
||||||
@@ -293,7 +299,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
# Activate toolchain.
|
# Activate toolchain.
|
||||||
source /opt/toolchain-v4/activate
|
source /opt/toolchain-v4/activate
|
||||||
|
|
||||||
cd build
|
cd build
|
||||||
|
|
||||||
# create mgconsole
|
# create mgconsole
|
||||||
@@ -340,10 +345,8 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
# Activate toolchain.
|
# Activate toolchain.
|
||||||
source /opt/toolchain-v4/activate
|
source /opt/toolchain-v4/activate
|
||||||
|
|
||||||
# Initialize dependencies.
|
# Initialize dependencies.
|
||||||
./init
|
./init
|
||||||
|
|
||||||
# Build only memgraph release binarie.
|
# Build only memgraph release binarie.
|
||||||
cd build
|
cd build
|
||||||
cmake -DCMAKE_BUILD_TYPE=release ..
|
cmake -DCMAKE_BUILD_TYPE=release ..
|
||||||
@@ -352,7 +355,7 @@ jobs:
|
|||||||
- name: Run Jepsen tests
|
- name: Run Jepsen tests
|
||||||
run: |
|
run: |
|
||||||
cd tests/jepsen
|
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
|
./run.sh test-all-individually --binary ../../build/memgraph --ignore-run-stdout-logs --ignore-run-stderr-logs
|
||||||
|
|
||||||
- name: Save Jepsen report
|
- name: Save Jepsen report
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
|
|||||||
8
.github/workflows/package_all.yaml
vendored
8
.github/workflows/package_all.yaml
vendored
@@ -6,7 +6,7 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
memgraph_version:
|
memgraph_version:
|
||||||
description: "Memgraph version to upload as. If empty upload is skipped. Format: 'vX.Y.Z'"
|
description: "Memgraph version to upload as. If empty upload is skipped. Format: 'X.Y.Z'"
|
||||||
required: false
|
required: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -201,7 +201,7 @@ jobs:
|
|||||||
|
|
||||||
debian-11-arm:
|
debian-11-arm:
|
||||||
runs-on: [self-hosted, DockerMgBuild, ARM64, strange]
|
runs-on: [self-hosted, DockerMgBuild, ARM64, strange]
|
||||||
timeout-minutes: 60
|
timeout-minutes: 120
|
||||||
steps:
|
steps:
|
||||||
- name: "Set up repository"
|
- name: "Set up repository"
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
@@ -218,7 +218,7 @@ jobs:
|
|||||||
|
|
||||||
ubuntu-2204-arm:
|
ubuntu-2204-arm:
|
||||||
runs-on: [self-hosted, DockerMgBuild, ARM64, strange]
|
runs-on: [self-hosted, DockerMgBuild, ARM64, strange]
|
||||||
timeout-minutes: 60
|
timeout-minutes: 120
|
||||||
steps:
|
steps:
|
||||||
- name: "Set up repository"
|
- name: "Set up repository"
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
@@ -253,4 +253,4 @@ jobs:
|
|||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_AWS_SECRET_ACCESS_KEY }}
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_AWS_SECRET_ACCESS_KEY }}
|
||||||
AWS_REGION: "eu-west-1"
|
AWS_REGION: "eu-west-1"
|
||||||
SOURCE_DIR: "build/output/release"
|
SOURCE_DIR: "build/output/release"
|
||||||
DEST_DIR: "memgraph/${{ github.event.inputs.memgraph_version }}/"
|
DEST_DIR: "memgraph/v${{ github.event.inputs.memgraph_version }}/"
|
||||||
|
|||||||
77
.github/workflows/performance_benchmarks.yaml
vendored
Normal file
77
.github/workflows/performance_benchmarks.yaml
vendored
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
name: Run performance benchmarks manually
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
performance_benchmarks:
|
||||||
|
name: "Performance benchmarks"
|
||||||
|
runs-on: [self-hosted, Linux, X64, Diff, Gen7]
|
||||||
|
env:
|
||||||
|
THREADS: 24
|
||||||
|
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
||||||
|
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Set up repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
# Number of commits to fetch. `0` indicates all history for all
|
||||||
|
# branches and tags. (default: 1)
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Build release binaries
|
||||||
|
run: |
|
||||||
|
# Activate toolchain.
|
||||||
|
source /opt/toolchain-v4/activate
|
||||||
|
|
||||||
|
# Initialize dependencies.
|
||||||
|
./init
|
||||||
|
|
||||||
|
# Build only memgraph release binaries.
|
||||||
|
cd build
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||||
|
make -j$THREADS
|
||||||
|
|
||||||
|
- name: 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: Run benchmarks
|
||||||
|
run: |
|
||||||
|
cd tests/mgbench
|
||||||
|
./benchmark.py vendor-native --num-workers-for-benchmark 12 --export-results benchmark_result.json pokec/medium/*/*
|
||||||
|
|
||||||
|
./benchmark.py vendor-native --num-workers-for-benchmark 1 --export-results benchmark_supernode.json supernode
|
||||||
|
|
||||||
|
./benchmark.py vendor-native --num-workers-for-benchmark 1 --export-results benchmark_high_write_set_property.json high_write_set_property
|
||||||
|
|
||||||
|
- name: Upload 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 "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 }}"
|
||||||
|
|
||||||
|
./main.py --benchmark-name "supernode" \
|
||||||
|
--benchmark-results-path "../../tests/mgbench/benchmark_supernode.json" \
|
||||||
|
--github-run-id "${{ github.run_id }}" \
|
||||||
|
--github-run-number "${{ github.run_number }}" \
|
||||||
|
--head-branch-name "${{ env.BRANCH_NAME }}"
|
||||||
|
|
||||||
|
./main.py --benchmark-name "high_write_set_property" \
|
||||||
|
--benchmark-results-path "../../tests/mgbench/benchmark_high_write_set_property.json" \
|
||||||
|
--github-run-id "${{ github.run_id }}" \
|
||||||
|
--github-run-number "${{ github.run_number }}" \
|
||||||
|
--head-branch-name "${{ env.BRANCH_NAME }}"
|
||||||
7
.github/workflows/release_centos8.yaml
vendored
7
.github/workflows/release_centos8.yaml
vendored
@@ -265,12 +265,11 @@ jobs:
|
|||||||
|
|
||||||
- name: Run e2e tests
|
- name: Run e2e tests
|
||||||
run: |
|
run: |
|
||||||
# TODO(gitbuda): Setup mgclient and pymgclient properly.
|
|
||||||
cd tests
|
cd tests
|
||||||
./setup.sh
|
./setup.sh /opt/toolchain-v4/activate
|
||||||
source ve3/bin/activate
|
source ve3/bin/activate_e2e
|
||||||
cd e2e
|
cd e2e
|
||||||
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../../libs/mgclient/lib python runner.py --workloads-root-directory .
|
./run.sh
|
||||||
|
|
||||||
- name: Run stress test (plain)
|
- name: Run stress test (plain)
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
11
.github/workflows/release_debian10.yaml
vendored
11
.github/workflows/release_debian10.yaml
vendored
@@ -264,12 +264,11 @@ jobs:
|
|||||||
|
|
||||||
- name: Run e2e tests
|
- name: Run e2e tests
|
||||||
run: |
|
run: |
|
||||||
# TODO(gitbuda): Setup mgclient and pymgclient properly.
|
|
||||||
cd tests
|
cd tests
|
||||||
./setup.sh
|
./setup.sh /opt/toolchain-v4/activate
|
||||||
source ve3/bin/activate
|
source ve3/bin/activate_e2e
|
||||||
cd e2e
|
cd e2e
|
||||||
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../../libs/mgclient/lib python runner.py --workloads-root-directory .
|
./run.sh
|
||||||
|
|
||||||
- name: Run stress test (plain)
|
- name: Run stress test (plain)
|
||||||
run: |
|
run: |
|
||||||
@@ -319,10 +318,8 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
# Activate toolchain.
|
# Activate toolchain.
|
||||||
source /opt/toolchain-v4/activate
|
source /opt/toolchain-v4/activate
|
||||||
|
|
||||||
# Initialize dependencies.
|
# Initialize dependencies.
|
||||||
./init
|
./init
|
||||||
|
|
||||||
# Build only memgraph release binary.
|
# Build only memgraph release binary.
|
||||||
cd build
|
cd build
|
||||||
cmake -DCMAKE_BUILD_TYPE=release ..
|
cmake -DCMAKE_BUILD_TYPE=release ..
|
||||||
@@ -331,7 +328,7 @@ jobs:
|
|||||||
- name: Run Jepsen tests
|
- name: Run Jepsen tests
|
||||||
run: |
|
run: |
|
||||||
cd tests/jepsen
|
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
|
./run.sh test-all-individually --binary ../../build/memgraph --ignore-run-stdout-logs --ignore-run-stderr-logs
|
||||||
|
|
||||||
- name: Save Jepsen report
|
- name: Save Jepsen report
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
|
|||||||
7
.github/workflows/release_ubuntu2004.yaml
vendored
7
.github/workflows/release_ubuntu2004.yaml
vendored
@@ -264,12 +264,11 @@ jobs:
|
|||||||
|
|
||||||
- name: Run e2e tests
|
- name: Run e2e tests
|
||||||
run: |
|
run: |
|
||||||
# TODO(gitbuda): Setup mgclient and pymgclient properly.
|
|
||||||
cd tests
|
cd tests
|
||||||
./setup.sh
|
./setup.sh /opt/toolchain-v4/activate
|
||||||
source ve3/bin/activate
|
source ve3/bin/activate_e2e
|
||||||
cd e2e
|
cd e2e
|
||||||
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../../libs/mgclient/lib python runner.py --workloads-root-directory .
|
./run.sh
|
||||||
|
|
||||||
- name: Run stress test (plain)
|
- name: Run stress test (plain)
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
32
.github/workflows/upload_to_s3.yaml
vendored
Normal file
32
.github/workflows/upload_to_s3.yaml
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: Upload Package All artifacts to S3
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
memgraph_version:
|
||||||
|
description: "Memgraph version to upload as. Format: 'X.Y.Z'"
|
||||||
|
required: true
|
||||||
|
run_number:
|
||||||
|
description: "# of the package_all workflow run to upload artifacts from. Format: '#XYZ'"
|
||||||
|
required: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
upload-to-s3:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Download artifacts
|
||||||
|
uses: dawidd6/action-download-artifact@v2
|
||||||
|
with:
|
||||||
|
workflow: package_all.yaml
|
||||||
|
workflow_conclusion: success
|
||||||
|
run_number: "${{ github.event.inputs.run_number }}"
|
||||||
|
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/v${{ github.event.inputs.memgraph_version }}/"
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -59,3 +59,5 @@ src/raft/storage_info_rpc_messages.hpp
|
|||||||
src/stats/stats_rpc_messages.hpp
|
src/stats/stats_rpc_messages.hpp
|
||||||
src/storage/distributed/rpc/concurrent_id_mapper_rpc_messages.hpp
|
src/storage/distributed/rpc/concurrent_id_mapper_rpc_messages.hpp
|
||||||
src/transactions/distributed/engine_rpc_messages.hpp
|
src/transactions/distributed/engine_rpc_messages.hpp
|
||||||
|
/tests/manual/js/transaction_timeout/package-lock.json
|
||||||
|
/tests/manual/js/transaction_timeout/node_modules/
|
||||||
|
|||||||
@@ -15,7 +15,21 @@ repos:
|
|||||||
hooks:
|
hooks:
|
||||||
- id: isort
|
- id: isort
|
||||||
name: isort (python)
|
name: isort (python)
|
||||||
|
args: ["--profile", "black"]
|
||||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||||
rev: v13.0.0
|
rev: v13.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: clang-format
|
- id: clang-format
|
||||||
|
# - repo: local
|
||||||
|
# hooks:
|
||||||
|
# - id: clang-tidy
|
||||||
|
# name: clang-tidy
|
||||||
|
# description: Runs clang-tidy and checks for errors
|
||||||
|
# entry: python ./tools/pre-commit/clang-tidy.py
|
||||||
|
# language: python
|
||||||
|
# files: ^src/
|
||||||
|
# types: [c++, text]
|
||||||
|
# fail_fast: true
|
||||||
|
# require_serial: true
|
||||||
|
# args: [--compile_commands_path=build]
|
||||||
|
# pass_filenames: false
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# MemGraph CMake configuration
|
# MemGraph CMake configuration
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.8)
|
cmake_minimum_required(VERSION 3.12)
|
||||||
|
cmake_policy(SET CMP0076 NEW)
|
||||||
|
|
||||||
# !! IMPORTANT !! run ./project_root/init.sh before cmake command
|
# !! IMPORTANT !! run ./project_root/init.sh before cmake command
|
||||||
# to download dependencies
|
# to download dependencies
|
||||||
@@ -18,10 +19,12 @@ set_directory_properties(PROPERTIES CLEAN_NO_CUSTOM TRUE)
|
|||||||
# during the code coverage process
|
# during the code coverage process
|
||||||
find_program(CCACHE_FOUND ccache)
|
find_program(CCACHE_FOUND ccache)
|
||||||
option(USE_CCACHE "ccache:" ON)
|
option(USE_CCACHE "ccache:" ON)
|
||||||
message(STATUS "CCache: ${USE_CCACHE}")
|
|
||||||
if(CCACHE_FOUND AND USE_CCACHE)
|
if(CCACHE_FOUND AND USE_CCACHE)
|
||||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
||||||
|
message(STATUS "CCache: Used")
|
||||||
|
else ()
|
||||||
|
message(STATUS "CCache: Not used")
|
||||||
endif(CCACHE_FOUND AND USE_CCACHE)
|
endif(CCACHE_FOUND AND USE_CCACHE)
|
||||||
|
|
||||||
# choose a compiler
|
# choose a compiler
|
||||||
@@ -37,7 +40,18 @@ endif()
|
|||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
project(memgraph)
|
project(memgraph LANGUAGES C CXX)
|
||||||
|
|
||||||
|
# NOTE: once in a while this needs to be toggled to check headers are
|
||||||
|
# correct and PCH isn't masking any include issues
|
||||||
|
set(CMAKE_DISABLE_PRECOMPILE_HEADERS OFF)
|
||||||
|
|
||||||
|
#TODO: upgrade to cmake 3.24 + CheckIPOSupported
|
||||||
|
#cmake_policy(SET CMP0138 NEW)
|
||||||
|
#include(CheckIPOSupported)
|
||||||
|
#check_ipo_supported()
|
||||||
|
#set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_Release TRUE)
|
||||||
|
#set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RelWithDebInfo TRUE)
|
||||||
|
|
||||||
# Install licenses.
|
# Install licenses.
|
||||||
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/licenses/
|
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/licenses/
|
||||||
@@ -143,7 +157,9 @@ endif()
|
|||||||
# files used can be seen here:
|
# files used can be seen here:
|
||||||
# https://git-scm.com/book/en/v2/Git-Internals-Git-References
|
# https://git-scm.com/book/en/v2/Git-Internals-Git-References
|
||||||
set(git_directory "${CMAKE_SOURCE_DIR}/.git")
|
set(git_directory "${CMAKE_SOURCE_DIR}/.git")
|
||||||
if (EXISTS "${git_directory}")
|
# Check for directory because if the repo is cloned as a git submodule, .git is
|
||||||
|
# a file and below code doesn't work.
|
||||||
|
if (IS_DIRECTORY "${git_directory}")
|
||||||
set_property(DIRECTORY APPEND PROPERTY
|
set_property(DIRECTORY APPEND PROPERTY
|
||||||
CMAKE_CONFIGURE_DEPENDS "${git_directory}/HEAD")
|
CMAKE_CONFIGURE_DEPENDS "${git_directory}/HEAD")
|
||||||
file(STRINGS "${git_directory}/HEAD" git_head_data)
|
file(STRINGS "${git_directory}/HEAD" git_head_data)
|
||||||
@@ -158,7 +174,7 @@ endif()
|
|||||||
|
|
||||||
# setup CMake module path, defines path for include() and find_package()
|
# setup CMake module path, defines path for include() and find_package()
|
||||||
# https://cmake.org/cmake/help/latest/variable/CMAKE_MODULE_PATH.html
|
# https://cmake.org/cmake/help/latest/variable/CMAKE_MODULE_PATH.html
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake)
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||||
# custom function definitions
|
# custom function definitions
|
||||||
include(functions)
|
include(functions)
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
@@ -184,7 +200,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall \
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall \
|
||||||
-Werror=switch -Werror=switch-bool -Werror=return-type \
|
-Werror=switch -Werror=switch-bool -Werror=return-type \
|
||||||
-Werror=return-stack-address \
|
-Werror=return-stack-address \
|
||||||
-Wno-c99-designator \
|
-Wno-c99-designator -Wmissing-field-initializers \
|
||||||
-DBOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT")
|
-DBOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT")
|
||||||
|
|
||||||
# Don't omit frame pointer in RelWithDebInfo, for additional callchain debug.
|
# Don't omit frame pointer in RelWithDebInfo, for additional callchain debug.
|
||||||
@@ -199,8 +215,8 @@ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO
|
|||||||
# ** Static linking is allowed only for executables! **
|
# ** Static linking is allowed only for executables! **
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++")
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++")
|
||||||
|
|
||||||
# Use gold linker to speedup build
|
# Use lld linker to speedup build
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold")
|
add_link_options(-fuse-ld=lld) # TODO: use mold linker
|
||||||
|
|
||||||
# release flags
|
# release flags
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
|
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
|
||||||
@@ -286,7 +302,7 @@ set(ENABLE_JEMALLOC ON)
|
|||||||
if (ASAN)
|
if (ASAN)
|
||||||
message(WARNING "Disabling jemalloc as it doesn't work well with ASAN")
|
message(WARNING "Disabling jemalloc as it doesn't work well with ASAN")
|
||||||
set(ENABLE_JEMALLOC OFF)
|
set(ENABLE_JEMALLOC OFF)
|
||||||
# Enable Addres sanitizer and get nicer stack traces in error messages.
|
# Enable Address sanitizer and get nicer stack traces in error messages.
|
||||||
# NOTE: AddressSanitizer uses llvm-symbolizer binary from the Clang
|
# NOTE: AddressSanitizer uses llvm-symbolizer binary from the Clang
|
||||||
# distribution to symbolize the stack traces (note that ideally the
|
# distribution to symbolize the stack traces (note that ideally the
|
||||||
# llvm-symbolizer version must match the version of ASan runtime library).
|
# llvm-symbolizer version must match the version of ASan runtime library).
|
||||||
|
|||||||
@@ -175,7 +175,6 @@ license](./licenses/BSL.txt).</br> Memgraph Enterprise is available under the
|
|||||||
|
|
||||||
- :purple_heart: [**Discord**](https://discord.gg/memgraph)
|
- :purple_heart: [**Discord**](https://discord.gg/memgraph)
|
||||||
- :ocean: [**Stack Overflow**](https://stackoverflow.com/questions/tagged/memgraphdb)
|
- :ocean: [**Stack Overflow**](https://stackoverflow.com/questions/tagged/memgraphdb)
|
||||||
- :busts_in_silhouette: [**Discourse forum**](https://discourse.memgraph.com/)
|
|
||||||
- :bird: [**Twitter**](https://twitter.com/memgraphdb)
|
- :bird: [**Twitter**](https://twitter.com/memgraphdb)
|
||||||
- :movie_camera:
|
- :movie_camera:
|
||||||
[**YouTube**](https://www.youtube.com/channel/UCZ3HOJvHGxtQ_JHxOselBYg)
|
[**YouTube**](https://www.youtube.com/channel/UCZ3HOJvHGxtQ_JHxOselBYg)
|
||||||
|
|||||||
@@ -107,6 +107,10 @@ modifications:
|
|||||||
value: "false"
|
value: "false"
|
||||||
override: true
|
override: true
|
||||||
|
|
||||||
|
- name: "query_callable_mappings_path"
|
||||||
|
value: "/etc/memgraph/apoc_compatibility_mappings.json"
|
||||||
|
override: true
|
||||||
|
|
||||||
undocumented:
|
undocumented:
|
||||||
- "flag_file"
|
- "flag_file"
|
||||||
- "also_log_to_stderr"
|
- "also_log_to_stderr"
|
||||||
|
|||||||
@@ -23,6 +23,14 @@ def wrap_text(s, initial_indent="# "):
|
|||||||
def extract_flags(binary_path):
|
def extract_flags(binary_path):
|
||||||
ret = {}
|
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")
|
||||||
|
# If something is printed out before the help output, it will break the the
|
||||||
|
# XML parsing -> filter out if something is not XML line because something
|
||||||
|
# can be logged before gflags output (e.g. during the global objects init).
|
||||||
|
# This gets called during memgraph build phase to generate default config
|
||||||
|
# file later installed under /etc/memgraph/memgraph.conf
|
||||||
|
# NOTE: Don't use \n in the gflags description strings.
|
||||||
|
# NOTE: Check here if gflags version changes because of the XML format.
|
||||||
|
data = "\n".join([line for line in data.split("\n") if line.startswith("<")])
|
||||||
root = ET.fromstring(data)
|
root = ET.fromstring(data)
|
||||||
for child in root:
|
for child in root:
|
||||||
if child.tag == "usage" and child.text.lower().count("warning"):
|
if child.tag == "usage" and child.text.lower().count("warning"):
|
||||||
|
|||||||
27
config/mappings.json
Normal file
27
config/mappings.json
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"dbms.components": "mgps.components",
|
||||||
|
"apoc.util.validate": "mgps.validate",
|
||||||
|
"db.schema.nodeTypeProperties":"schema.node_type_properties",
|
||||||
|
"db.schema.relTypeProperties":"schema.rel_type_properties",
|
||||||
|
"apoc.coll.contains": "collections.contains",
|
||||||
|
"apoc.coll.partition": "collections.partition",
|
||||||
|
"apoc.coll.toSet": "collections.to_set",
|
||||||
|
"apoc.coll.unionAll": "collections.unionAll",
|
||||||
|
"apoc.coll.removeAll": "collections.remove_all",
|
||||||
|
"apoc.coll.union": "collections.union",
|
||||||
|
"apoc.coll.sum": "collections.sum",
|
||||||
|
"apoc.coll.pairs": "collections.pairs",
|
||||||
|
"apoc.map.fromLists": "map.from_lists",
|
||||||
|
"apoc.map.removeKeys": "map.remove_keys",
|
||||||
|
"apoc.map.merge": "map.merge",
|
||||||
|
"apoc.create.nodes": "create.nodes",
|
||||||
|
"apoc.create.removeProperties": "create.remove_properties",
|
||||||
|
"apoc.create.node": "create.node",
|
||||||
|
"apoc.create.removeLabel": "create.remove_label",
|
||||||
|
"apoc.refactor.invert": "refactor.invert",
|
||||||
|
"apoc.refactor.cloneNode": "refactor.clone_node",
|
||||||
|
"apoc.refactor.cloneSubgraph": "refactor.clone_subgraph",
|
||||||
|
"apoc.refactor.cloneSubgraphFromPath": "refactor.clone_subgraph_from_path",
|
||||||
|
"apoc.label.exists": "label.exists"
|
||||||
|
|
||||||
|
}
|
||||||
@@ -202,3 +202,29 @@ for row in csv.reader(stream, delimiter=',', doublequote=True,
|
|||||||
For more information about the meaning of the above values, see:
|
For more information about the meaning of the above values, see:
|
||||||
https://docs.python.org/3/library/csv.html#csv.Dialect
|
https://docs.python.org/3/library/csv.html#csv.Dialect
|
||||||
|
|
||||||
|
## Errors
|
||||||
|
|
||||||
|
1. [Skipping duplicate node with ID '{}'. For more details, visit:
|
||||||
|
memgr.ph/csv-import-tool.](#error-1)
|
||||||
|
2. [Skipping bad relationship with START_ID '{}'. For more details, visit:
|
||||||
|
memgr.ph/csv-import-tool.](#error-2)
|
||||||
|
3. [Skipping bad relationship with END_ID '{}'. For more details, visit:
|
||||||
|
memgr.ph/csv-import-tool.](#error-3)
|
||||||
|
|
||||||
|
## Skipping duplicate node with ID {} {#error-1}
|
||||||
|
|
||||||
|
Duplicate nodes are nodes that have an ID that is the same as another node that
|
||||||
|
was already imported. You can instruct the importer to ignore all duplicate
|
||||||
|
nodes (instead of raising an error) by using the `--skip-duplicate-nodes` flag.
|
||||||
|
|
||||||
|
## Skipping bad relationship with START_ID {} {#error-2}
|
||||||
|
|
||||||
|
A node with the id `START_ID` doesn't exist. You can instruct the importer to
|
||||||
|
ignore all bad relationships (instead of raising an error) that refer to nodes
|
||||||
|
that don't exist in the node files by using the `--skip-bad-relationships` flag.
|
||||||
|
|
||||||
|
## Skipping bad relationship with END_ID {} {#error-3}
|
||||||
|
|
||||||
|
A node with the id `END_ID` doesn't exist. You can instruct the importer to
|
||||||
|
ignore all bad relationships (instead of raising an error) that refer to nodes
|
||||||
|
that don't exist in the node files by using the `--skip-bad-relationships` flag.
|
||||||
|
|||||||
10
environment/README.md
Normal file
10
environment/README.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Memgraph Operating Environments
|
||||||
|
|
||||||
|
## os
|
||||||
|
|
||||||
|
Under the `os` directory, you can find scripts to install all required system
|
||||||
|
dependencies on operating systems where Memgraph natively builds. The testing
|
||||||
|
script helps to see how to install all packages (in the case of a new package),
|
||||||
|
or make any adjustments in the overall system setup. Also, the testing script
|
||||||
|
helps check if Memgraph runs on a freshly installed operating system (with no
|
||||||
|
packages installed).
|
||||||
3
environment/os/.gitignore
vendored
3
environment/os/.gitignore
vendored
@@ -1,3 +1,6 @@
|
|||||||
*.deb
|
*.deb
|
||||||
|
*.deb.*
|
||||||
*.rpm
|
*.rpm
|
||||||
|
*.rpm.*
|
||||||
*.tar.gz
|
*.tar.gz
|
||||||
|
*.tar.gz.*
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ TOOLCHAIN_RUN_DEPS=(
|
|||||||
|
|
||||||
MEMGRAPH_BUILD_DEPS=(
|
MEMGRAPH_BUILD_DEPS=(
|
||||||
git # source code control
|
git # source code control
|
||||||
make # build system
|
make cmake # build system
|
||||||
wget # for downloading libs
|
wget # for downloading libs
|
||||||
libuuid-devel java-11-openjdk # required by antlr
|
libuuid-devel java-11-openjdk # required by antlr
|
||||||
readline-devel # for memgraph console
|
readline-devel # for memgraph console
|
||||||
@@ -57,9 +57,18 @@ MEMGRAPH_BUILD_DEPS=(
|
|||||||
libcurl-devel # mg-requests
|
libcurl-devel # mg-requests
|
||||||
rpm-build rpmlint # for RPM package building
|
rpm-build rpmlint # for RPM package building
|
||||||
doxygen graphviz # source documentation generators
|
doxygen graphviz # source documentation generators
|
||||||
which nodejs golang zip unzip java-11-openjdk-devel # for driver tests
|
which nodejs golang custom-golang1.18.9 zip unzip java-11-openjdk-devel jdk-17 custom-maven3.9.3 # for driver tests
|
||||||
autoconf # for jemalloc code generation
|
autoconf # for jemalloc code generation
|
||||||
libtool # for protobuf code generation
|
libtool # for protobuf code generation
|
||||||
|
cyrus-sasl-devel
|
||||||
|
)
|
||||||
|
|
||||||
|
MEMGRAPH_RUN_DEPS=(
|
||||||
|
logrotate openssl python3 libseccomp
|
||||||
|
)
|
||||||
|
|
||||||
|
NEW_DEPS=(
|
||||||
|
wget curl tar gzip
|
||||||
)
|
)
|
||||||
|
|
||||||
list() {
|
list() {
|
||||||
@@ -73,6 +82,18 @@ check() {
|
|||||||
local OLD_LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-""}
|
local OLD_LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-""}
|
||||||
LD_LIBRARY_PATH=""
|
LD_LIBRARY_PATH=""
|
||||||
for pkg in $1; do
|
for pkg in $1; do
|
||||||
|
if [ "$pkg" == custom-maven3.9.3 ]; then
|
||||||
|
if [ ! -f "/opt/apache-maven-3.9.3/bin/mvn" ]; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == custom-golang1.18.9 ]; then
|
||||||
|
if [ ! -f "/opt/go1.18.9/go/bin/go" ]; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
if [ "$pkg" == "PyYAML" ]; then
|
if [ "$pkg" == "PyYAML" ]; then
|
||||||
if ! python3 -c "import yaml" >/dev/null 2>/dev/null; then
|
if ! python3 -c "import yaml" >/dev/null 2>/dev/null; then
|
||||||
missing="$pkg $missing"
|
missing="$pkg $missing"
|
||||||
@@ -103,8 +124,27 @@ install() {
|
|||||||
else
|
else
|
||||||
echo "NOTE: export LANG=en_US.utf8"
|
echo "NOTE: export LANG=en_US.utf8"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
yum update -y
|
yum update -y
|
||||||
for pkg in $1; do
|
for pkg in $1; do
|
||||||
|
if [ "$pkg" == custom-maven3.9.3 ]; then
|
||||||
|
install_custom_maven "3.9.3"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == custom-golang1.18.9 ]; then
|
||||||
|
install_custom_golang "1.18.9"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == jdk-17 ]; then
|
||||||
|
if ! yum list installed jdk-17 >/dev/null 2>/dev/null; then
|
||||||
|
wget --no-check-certificate -c --header "Cookie: oraclelicense=accept-securebackup-cookie" https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.rpm
|
||||||
|
rpm -Uvh jdk-17_linux-x64_bin.rpm
|
||||||
|
# NOTE: Set Java 11 as default.
|
||||||
|
update-alternatives --set java java-11-openjdk.x86_64
|
||||||
|
update-alternatives --set javac java-11-openjdk.x86_64
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
if [ "$pkg" == libipt ]; then
|
if [ "$pkg" == libipt ]; then
|
||||||
if ! yum list installed libipt >/dev/null 2>/dev/null; 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
|
yum install -y http://repo.okay.com.mx/centos/8/x86_64/release/libipt-1.6.1-8.el8.x86_64.rpm
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ TOOLCHAIN_RUN_DEPS=(
|
|||||||
)
|
)
|
||||||
|
|
||||||
MEMGRAPH_BUILD_DEPS=(
|
MEMGRAPH_BUILD_DEPS=(
|
||||||
make pkgconfig # build system
|
make cmake pkgconfig # build system
|
||||||
curl wget # for downloading libs
|
curl wget # for downloading libs
|
||||||
libuuid-devel java-11-openjdk # required by antlr
|
libuuid-devel java-11-openjdk # required by antlr
|
||||||
readline-devel # for memgraph console
|
readline-devel # for memgraph console
|
||||||
@@ -56,9 +56,19 @@ MEMGRAPH_BUILD_DEPS=(
|
|||||||
sbcl # for custom Lisp C++ preprocessing
|
sbcl # for custom Lisp C++ preprocessing
|
||||||
rpm-build rpmlint # for RPM package building
|
rpm-build rpmlint # for RPM package building
|
||||||
doxygen graphviz # source documentation generators
|
doxygen graphviz # source documentation generators
|
||||||
which mono-complete dotnet-sdk-3.1 golang nodejs zip unzip java-11-openjdk-devel # for driver tests
|
which mono-complete dotnet-sdk-3.1 golang custom-golang1.18.9 # for driver tests
|
||||||
|
nodejs zip unzip java-11-openjdk-devel jdk-17 custom-maven3.9.3 # for driver tests
|
||||||
autoconf # for jemalloc code generation
|
autoconf # for jemalloc code generation
|
||||||
libtool # for protobuf code generation
|
libtool # for protobuf code generation
|
||||||
|
cyrus-sasl-devel
|
||||||
|
)
|
||||||
|
|
||||||
|
MEMGRAPH_RUN_DEPS=(
|
||||||
|
logrotate openssl python3 libseccomp
|
||||||
|
)
|
||||||
|
|
||||||
|
NEW_DEPS=(
|
||||||
|
wget curl tar gzip
|
||||||
)
|
)
|
||||||
|
|
||||||
list() {
|
list() {
|
||||||
@@ -68,6 +78,18 @@ list() {
|
|||||||
check() {
|
check() {
|
||||||
local missing=""
|
local missing=""
|
||||||
for pkg in $1; do
|
for pkg in $1; do
|
||||||
|
if [ "$pkg" == custom-maven3.9.3 ]; then
|
||||||
|
if [ ! -f "/opt/apache-maven-3.9.3/bin/mvn" ]; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == custom-golang1.18.9 ]; then
|
||||||
|
if [ ! -f "/opt/go1.18.9/go/bin/go" ]; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
if [ "$pkg" == git ]; then
|
if [ "$pkg" == git ]; then
|
||||||
if ! which "git" >/dev/null; then
|
if ! which "git" >/dev/null; then
|
||||||
missing="git $missing"
|
missing="git $missing"
|
||||||
@@ -110,7 +132,25 @@ install() {
|
|||||||
yum update -y
|
yum update -y
|
||||||
yum install -y wget python3 python3-pip
|
yum install -y wget python3 python3-pip
|
||||||
yum install -y git
|
yum install -y git
|
||||||
|
|
||||||
for pkg in $1; do
|
for pkg in $1; do
|
||||||
|
if [ "$pkg" == custom-maven3.9.3 ]; then
|
||||||
|
install_custom_maven "3.9.3"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == custom-golang1.18.9 ]; then
|
||||||
|
install_custom_golang "1.18.9"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == jdk-17 ]; then
|
||||||
|
if ! yum list installed jdk-17 >/dev/null 2>/dev/null; then
|
||||||
|
wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.rpm
|
||||||
|
rpm -ivh jdk-17_linux-x64_bin.rpm
|
||||||
|
update-alternatives --set java java-11-openjdk.x86_64
|
||||||
|
update-alternatives --set javac java-11-openjdk.x86_64
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
if [ "$pkg" == libipt ]; then
|
if [ "$pkg" == libipt ]; then
|
||||||
if ! yum list installed libipt >/dev/null 2>/dev/null; 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
|
yum install -y http://repo.okay.com.mx/centos/8/x86_64/release/libipt-1.6.1-8.el8.x86_64.rpm
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ TOOLCHAIN_RUN_DEPS=(
|
|||||||
|
|
||||||
MEMGRAPH_BUILD_DEPS=(
|
MEMGRAPH_BUILD_DEPS=(
|
||||||
git # source code control
|
git # source code control
|
||||||
make pkgconf-pkg-config # build system
|
make cmake pkgconf-pkg-config # build system
|
||||||
wget # for downloading libs
|
wget # for downloading libs
|
||||||
libuuid-devel java-11-openjdk # required by antlr
|
libuuid-devel java-11-openjdk # required by antlr
|
||||||
readline-devel # for memgraph console
|
readline-devel # for memgraph console
|
||||||
@@ -56,10 +56,20 @@ MEMGRAPH_BUILD_DEPS=(
|
|||||||
libcurl-devel # mg-requests
|
libcurl-devel # mg-requests
|
||||||
rpm-build rpmlint # for RPM package building
|
rpm-build rpmlint # for RPM package building
|
||||||
doxygen graphviz # source documentation generators
|
doxygen graphviz # source documentation generators
|
||||||
which nodejs golang zip unzip java-11-openjdk-devel # for driver tests
|
which nodejs golang custom-golang1.18.9 # for driver tests
|
||||||
|
zip unzip java-11-openjdk-devel java-17-openjdk java-17-openjdk-devel custom-maven3.9.3 # for driver tests
|
||||||
sbcl # for custom Lisp C++ preprocessing
|
sbcl # for custom Lisp C++ preprocessing
|
||||||
autoconf # for jemalloc code generation
|
autoconf # for jemalloc code generation
|
||||||
libtool # for protobuf code generation
|
libtool # for protobuf code generation
|
||||||
|
cyrus-sasl-devel
|
||||||
|
)
|
||||||
|
|
||||||
|
MEMGRAPH_RUN_DEPS=(
|
||||||
|
logrotate openssl python3 libseccomp
|
||||||
|
)
|
||||||
|
|
||||||
|
NEW_DEPS=(
|
||||||
|
wget curl tar gzip
|
||||||
)
|
)
|
||||||
|
|
||||||
list() {
|
list() {
|
||||||
@@ -69,6 +79,18 @@ list() {
|
|||||||
check() {
|
check() {
|
||||||
local missing=""
|
local missing=""
|
||||||
for pkg in $1; do
|
for pkg in $1; do
|
||||||
|
if [ "$pkg" == custom-maven3.9.3 ]; then
|
||||||
|
if [ ! -f "/opt/apache-maven-3.9.3/bin/mvn" ]; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == custom-golang1.18.9 ]; then
|
||||||
|
if [ ! -f "/opt/go1.18.9/go/bin/go" ]; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
if [ "$pkg" == "PyYAML" ]; then
|
if [ "$pkg" == "PyYAML" ]; then
|
||||||
if ! python3 -c "import yaml" >/dev/null 2>/dev/null; then
|
if ! python3 -c "import yaml" >/dev/null 2>/dev/null; then
|
||||||
missing="$pkg $missing"
|
missing="$pkg $missing"
|
||||||
@@ -103,7 +125,16 @@ install() {
|
|||||||
fi
|
fi
|
||||||
yum update -y
|
yum update -y
|
||||||
yum install -y wget git python3 python3-pip
|
yum install -y wget git python3 python3-pip
|
||||||
|
|
||||||
for pkg in $1; do
|
for pkg in $1; do
|
||||||
|
if [ "$pkg" == custom-maven3.9.3 ]; then
|
||||||
|
install_custom_maven "3.9.3"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == custom-golang1.18.9 ]; then
|
||||||
|
install_custom_golang "1.18.9"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
# Since there is no support for libipt-devel for CentOS 9 we install
|
# Since there is no support for libipt-devel for CentOS 9 we install
|
||||||
# Fedoras version of same libs, they are the same version but released
|
# Fedoras version of same libs, they are the same version but released
|
||||||
# for different OS
|
# for different OS
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ TOOLCHAIN_RUN_DEPS=(
|
|||||||
|
|
||||||
MEMGRAPH_BUILD_DEPS=(
|
MEMGRAPH_BUILD_DEPS=(
|
||||||
git # source code control
|
git # source code control
|
||||||
make pkg-config # build system
|
make cmake pkg-config # build system
|
||||||
curl wget # for downloading libs
|
curl wget # for downloading libs
|
||||||
uuid-dev default-jre-headless # required by antlr
|
uuid-dev default-jre-headless # required by antlr
|
||||||
libreadline-dev # for memgraph console
|
libreadline-dev # for memgraph console
|
||||||
@@ -53,10 +53,19 @@ MEMGRAPH_BUILD_DEPS=(
|
|||||||
libcurl4-openssl-dev # mg-requests
|
libcurl4-openssl-dev # mg-requests
|
||||||
sbcl # for custom Lisp C++ preprocessing
|
sbcl # for custom Lisp C++ preprocessing
|
||||||
doxygen graphviz # source documentation generators
|
doxygen graphviz # source documentation generators
|
||||||
mono-runtime mono-mcs zip unzip default-jdk-headless # for driver tests
|
mono-runtime mono-mcs zip unzip default-jdk-headless oracle-java17-installer custom-maven3.9.3 # for driver tests
|
||||||
dotnet-sdk-3.1 golang nodejs npm
|
dotnet-sdk-3.1 golang custom-golang1.18.9 nodejs npm # for driver tests
|
||||||
autoconf # for jemalloc code generation
|
autoconf # for jemalloc code generation
|
||||||
libtool # for protobuf code generation
|
libtool # for protobuf code generation
|
||||||
|
libsasl2-dev
|
||||||
|
)
|
||||||
|
|
||||||
|
MEMGRAPH_RUN_DEPS=(
|
||||||
|
logrotate openssl python3 libseccomp
|
||||||
|
)
|
||||||
|
|
||||||
|
NEW_DEPS=(
|
||||||
|
wget curl tar gzip
|
||||||
)
|
)
|
||||||
|
|
||||||
list() {
|
list() {
|
||||||
@@ -64,7 +73,28 @@ list() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
check() {
|
check() {
|
||||||
check_all_dpkg "$1"
|
local missing=""
|
||||||
|
for pkg in $1; do
|
||||||
|
if [ "$pkg" == custom-maven3.9.3 ]; then
|
||||||
|
if [ ! -f "/opt/apache-maven-3.9.3/bin/mvn" ]; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == custom-golang1.18.9 ]; then
|
||||||
|
if [ ! -f "/opt/go1.18.9/go/bin/go" ]; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if ! dpkg -s "$pkg" >/dev/null 2>/dev/null; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ "$missing" != "" ]; then
|
||||||
|
echo "MISSING PACKAGES: $missing"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
install() {
|
install() {
|
||||||
@@ -75,8 +105,15 @@ deb http://deb.debian.org/debian/ buster-updates main contrib non-free
|
|||||||
deb-src http://deb.debian.org/debian/ buster-updates main contrib non-free
|
deb-src http://deb.debian.org/debian/ buster-updates main contrib non-free
|
||||||
deb http://security.debian.org/debian-security buster/updates main contrib non-free
|
deb http://security.debian.org/debian-security buster/updates main contrib non-free
|
||||||
deb-src http://security.debian.org/debian-security buster/updates main contrib non-free
|
deb-src http://security.debian.org/debian-security buster/updates main contrib non-free
|
||||||
|
EOF
|
||||||
|
apt --allow-releaseinfo-change update
|
||||||
|
cat >/etc/apt/sources.list.d/java.list << EOF
|
||||||
|
deb http://ppa.launchpad.net/linuxuprising/java/ubuntu bionic main
|
||||||
|
deb-src http://ppa.launchpad.net/linuxuprising/java/ubuntu bionic main
|
||||||
EOF
|
EOF
|
||||||
cd "$DIR"
|
cd "$DIR"
|
||||||
|
apt install -y gnupg
|
||||||
|
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys EA8CACC073C3DB2A
|
||||||
apt --allow-releaseinfo-change update
|
apt --allow-releaseinfo-change update
|
||||||
# If GitHub Actions runner is installed, append LANG to the environment.
|
# If GitHub Actions runner is installed, append LANG to the environment.
|
||||||
# Python related tests doesn't work the LANG export.
|
# Python related tests doesn't work the LANG export.
|
||||||
@@ -85,8 +122,26 @@ EOF
|
|||||||
else
|
else
|
||||||
echo "NOTE: export LANG=en_US.utf8"
|
echo "NOTE: export LANG=en_US.utf8"
|
||||||
fi
|
fi
|
||||||
apt install -y wget
|
|
||||||
for pkg in $1; do
|
for pkg in $1; do
|
||||||
|
if [ "$pkg" == custom-maven3.9.3 ]; then
|
||||||
|
install_custom_maven "3.9.3"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == custom-golang1.18.9 ]; then
|
||||||
|
install_custom_golang "1.18.9"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == oracle-java17-installer ]; then
|
||||||
|
if ! dpkg -s "$pkg" 2>/dev/null >/dev/null; then
|
||||||
|
echo oracle-java17-installer shared/accepted-oracle-license-v1-3 select true | /usr/bin/debconf-set-selections
|
||||||
|
echo oracle-java17-installer shared/accepted-oracle-license-v1-3 seen true | /usr/bin/debconf-set-selections
|
||||||
|
apt install -y "$pkg"
|
||||||
|
update-alternatives --set java /usr/lib/jvm/java-11-openjdk-amd64/bin/java
|
||||||
|
update-alternatives --set javac /usr/lib/jvm/java-11-openjdk-amd64/bin/javac
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
if [ "$pkg" == dotnet-sdk-3.1 ]; then
|
if [ "$pkg" == dotnet-sdk-3.1 ]; then
|
||||||
if ! dpkg -s "$pkg" 2>/dev/null >/dev/null; then
|
if ! dpkg -s "$pkg" 2>/dev/null >/dev/null; then
|
||||||
wget -nv https://packages.microsoft.com/config/debian/10/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
|
wget -nv https://packages.microsoft.com/config/debian/10/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
|
||||||
|
|||||||
@@ -54,10 +54,19 @@ MEMGRAPH_BUILD_DEPS=(
|
|||||||
libcurl4-openssl-dev # mg-requests
|
libcurl4-openssl-dev # mg-requests
|
||||||
sbcl # for custom Lisp C++ preprocessing
|
sbcl # for custom Lisp C++ preprocessing
|
||||||
doxygen graphviz # source documentation generators
|
doxygen graphviz # source documentation generators
|
||||||
mono-runtime mono-mcs zip unzip default-jdk-headless # for driver tests
|
mono-runtime mono-mcs zip unzip default-jdk-headless openjdk-17-jdk custom-maven3.9.3 # for driver tests
|
||||||
golang nodejs npm
|
golang custom-golang1.18.9 nodejs npm
|
||||||
autoconf # for jemalloc code generation
|
autoconf # for jemalloc code generation
|
||||||
libtool # for protobuf code generation
|
libtool # for protobuf code generation
|
||||||
|
libsasl2-dev
|
||||||
|
)
|
||||||
|
|
||||||
|
MEMGRAPH_RUN_DEPS=(
|
||||||
|
logrotate openssl python3 libseccomp
|
||||||
|
)
|
||||||
|
|
||||||
|
NEW_DEPS=(
|
||||||
|
wget curl tar gzip
|
||||||
)
|
)
|
||||||
|
|
||||||
list() {
|
list() {
|
||||||
@@ -65,7 +74,28 @@ list() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
check() {
|
check() {
|
||||||
check_all_dpkg "$1"
|
local missing=""
|
||||||
|
for pkg in $1; do
|
||||||
|
if [ "$pkg" == custom-maven3.9.3 ]; then
|
||||||
|
if [ ! -f "/opt/apache-maven-3.9.3/bin/mvn" ]; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == custom-golang1.18.9 ]; then
|
||||||
|
if [ ! -f "/opt/go1.18.9/go/bin/go" ]; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if ! dpkg -s "$pkg" >/dev/null 2>/dev/null; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ "$missing" != "" ]; then
|
||||||
|
echo "MISSING PACKAGES: $missing"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
install() {
|
install() {
|
||||||
@@ -89,7 +119,25 @@ EOF
|
|||||||
echo "NOTE: export LANG=en_US.utf8"
|
echo "NOTE: export LANG=en_US.utf8"
|
||||||
fi
|
fi
|
||||||
apt install -y wget
|
apt install -y wget
|
||||||
|
|
||||||
for pkg in $1; do
|
for pkg in $1; do
|
||||||
|
if [ "$pkg" == custom-maven3.9.3 ]; then
|
||||||
|
install_custom_maven "3.9.3"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == custom-golang1.18.9 ]; then
|
||||||
|
install_custom_golang "1.18.9"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == openjdk-17-jdk ]; then
|
||||||
|
if ! dpkg -s "$pkg" 2>/dev/null >/dev/null; then
|
||||||
|
apt install -y "$pkg"
|
||||||
|
# The default Java version should be Java 11
|
||||||
|
update-alternatives --set java /usr/lib/jvm/java-11-openjdk-arm64/bin/java
|
||||||
|
update-alternatives --set javac /usr/lib/jvm/java-11-openjdk-arm64/bin/javac
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
apt install -y "$pkg"
|
apt install -y "$pkg"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ TOOLCHAIN_RUN_DEPS=(
|
|||||||
|
|
||||||
MEMGRAPH_BUILD_DEPS=(
|
MEMGRAPH_BUILD_DEPS=(
|
||||||
git # source code control
|
git # source code control
|
||||||
make pkg-config # build system
|
make cmake pkg-config # build system
|
||||||
curl wget # for downloading libs
|
curl wget # for downloading libs
|
||||||
uuid-dev default-jre-headless # required by antlr
|
uuid-dev default-jre-headless # required by antlr
|
||||||
libreadline-dev # for memgraph console
|
libreadline-dev # for memgraph console
|
||||||
@@ -54,10 +54,19 @@ MEMGRAPH_BUILD_DEPS=(
|
|||||||
libcurl4-openssl-dev # mg-requests
|
libcurl4-openssl-dev # mg-requests
|
||||||
sbcl # for custom Lisp C++ preprocessing
|
sbcl # for custom Lisp C++ preprocessing
|
||||||
doxygen graphviz # source documentation generators
|
doxygen graphviz # source documentation generators
|
||||||
mono-runtime mono-mcs zip unzip default-jdk-headless # for driver tests
|
mono-runtime mono-mcs zip unzip default-jdk-headless openjdk-17-jdk custom-maven3.9.3 # for driver tests
|
||||||
dotnet-sdk-3.1 golang nodejs npm
|
dotnet-sdk-3.1 golang custom-golang1.18.9 nodejs npm
|
||||||
autoconf # for jemalloc code generation
|
autoconf # for jemalloc code generation
|
||||||
libtool # for protobuf code generation
|
libtool # for protobuf code generation
|
||||||
|
libsasl2-dev
|
||||||
|
)
|
||||||
|
|
||||||
|
MEMGRAPH_RUN_DEPS=(
|
||||||
|
logrotate openssl python3 libseccomp
|
||||||
|
)
|
||||||
|
|
||||||
|
NEW_DEPS=(
|
||||||
|
wget curl tar gzip
|
||||||
)
|
)
|
||||||
|
|
||||||
list() {
|
list() {
|
||||||
@@ -65,7 +74,28 @@ list() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
check() {
|
check() {
|
||||||
check_all_dpkg "$1"
|
local missing=""
|
||||||
|
for pkg in $1; do
|
||||||
|
if [ "$pkg" == custom-maven3.9.3 ]; then
|
||||||
|
if [ ! -f "/opt/apache-maven-3.9.3/bin/mvn" ]; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == custom-golang1.18.9 ]; then
|
||||||
|
if [ ! -f "/opt/go1.18.9/go/bin/go" ]; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if ! dpkg -s "$pkg" >/dev/null 2>/dev/null; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ "$missing" != "" ]; then
|
||||||
|
echo "MISSING PACKAGES: $missing"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
install() {
|
install() {
|
||||||
@@ -89,7 +119,25 @@ EOF
|
|||||||
echo "NOTE: export LANG=en_US.utf8"
|
echo "NOTE: export LANG=en_US.utf8"
|
||||||
fi
|
fi
|
||||||
apt install -y wget
|
apt install -y wget
|
||||||
|
|
||||||
for pkg in $1; do
|
for pkg in $1; do
|
||||||
|
if [ "$pkg" == custom-maven3.9.3 ]; then
|
||||||
|
install_custom_maven "3.9.3"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == custom-golang1.18.9 ]; then
|
||||||
|
install_custom_golang "1.18.9"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == openjdk-17-jdk ]; then
|
||||||
|
if ! dpkg -s "$pkg" 2>/dev/null >/dev/null; then
|
||||||
|
apt install -y "$pkg"
|
||||||
|
# The default Java version should be Java 11
|
||||||
|
update-alternatives --set java /usr/lib/jvm/java-11-openjdk-amd64/bin/java
|
||||||
|
update-alternatives --set javac /usr/lib/jvm/java-11-openjdk-amd64/bin/javac
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
if [ "$pkg" == dotnet-sdk-3.1 ]; then
|
if [ "$pkg" == dotnet-sdk-3.1 ]; then
|
||||||
if ! dpkg -s "$pkg" 2>/dev/null >/dev/null; then
|
if ! dpkg -s "$pkg" 2>/dev/null >/dev/null; then
|
||||||
wget -nv https://packages.microsoft.com/config/debian/10/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
|
wget -nv https://packages.microsoft.com/config/debian/10/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ TOOLCHAIN_RUN_DEPS=(
|
|||||||
|
|
||||||
MEMGRAPH_BUILD_DEPS=(
|
MEMGRAPH_BUILD_DEPS=(
|
||||||
git # source code control
|
git # source code control
|
||||||
make pkgconf-pkg-config # build system
|
make cmake pkgconf-pkg-config # build system
|
||||||
wget # for downloading libs
|
wget # for downloading libs
|
||||||
libuuid-devel java-11-openjdk # required by antlr
|
libuuid-devel java-11-openjdk # required by antlr
|
||||||
readline-devel # for memgraph console
|
readline-devel # for memgraph console
|
||||||
@@ -52,10 +52,21 @@ MEMGRAPH_BUILD_DEPS=(
|
|||||||
libcurl-devel # mg-requests
|
libcurl-devel # mg-requests
|
||||||
rpm-build rpmlint # for RPM package building
|
rpm-build rpmlint # for RPM package building
|
||||||
doxygen graphviz # source documentation generators
|
doxygen graphviz # source documentation generators
|
||||||
which nodejs golang zip unzip java-11-openjdk-devel # for driver tests
|
java-11-openjdk-devel java-17-openjdk-devel custom-maven3.9.3 # for driver tests
|
||||||
|
which zip unzip
|
||||||
|
nodejs golang custom-golang1.18.9 # for driver tests
|
||||||
sbcl # for custom Lisp C++ preprocessing
|
sbcl # for custom Lisp C++ preprocessing
|
||||||
autoconf # for jemalloc code generation
|
autoconf # for jemalloc code generation
|
||||||
libtool # for protobuf code generation
|
libtool # for protobuf code generation
|
||||||
|
cyrus-sasl-devel
|
||||||
|
)
|
||||||
|
|
||||||
|
MEMGRAPH_RUN_DEPS=(
|
||||||
|
logrotate openssl python3 libseccomp
|
||||||
|
)
|
||||||
|
|
||||||
|
NEW_DEPS=(
|
||||||
|
wget curl tar gzip
|
||||||
)
|
)
|
||||||
|
|
||||||
list() {
|
list() {
|
||||||
@@ -64,11 +75,25 @@ list() {
|
|||||||
|
|
||||||
check() {
|
check() {
|
||||||
local missing=""
|
local missing=""
|
||||||
# On Fedora yum/dnf and python10 use newer glibc which is not compatible
|
if [ -v LD_LIBRARY_PATH ]; then
|
||||||
# with ours, so we need to momentarely disable env
|
# On Fedora yum/dnf and python10 use newer glibc which is not compatible
|
||||||
local OLD_LD_LIBRARY_PATH=${LD_LIBRARY_PATH}
|
# with ours, so we need to momentarely disable env
|
||||||
LD_LIBRARY_PATH=""
|
local OLD_LD_LIBRARY_PATH=${LD_LIBRARY_PATH}
|
||||||
|
LD_LIBRARY_PATH=""
|
||||||
|
fi
|
||||||
for pkg in $1; do
|
for pkg in $1; do
|
||||||
|
if [ "$pkg" == custom-maven3.9.3 ]; then
|
||||||
|
if [ ! -f "/opt/apache-maven-3.9.3/bin/mvn" ]; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == custom-golang1.18.9 ]; then
|
||||||
|
if [ ! -f "/opt/go1.18.9/go/bin/go" ]; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
if ! dnf list installed "$pkg" >/dev/null 2>/dev/null; then
|
if ! dnf list installed "$pkg" >/dev/null 2>/dev/null; then
|
||||||
missing="$pkg $missing"
|
missing="$pkg $missing"
|
||||||
fi
|
fi
|
||||||
@@ -77,7 +102,10 @@ check() {
|
|||||||
echo "MISSING PACKAGES: $missing"
|
echo "MISSING PACKAGES: $missing"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
LD_LIBRARY_PATH=${OLD_LD_LIBRARY_PATH}
|
if [ -v OLD_LD_LIBRARY_PATH ]; then
|
||||||
|
echo "Restoring LD_LIBRARY_PATH..."
|
||||||
|
LD_LIBRARY_PATH=${OLD_LD_LIBRARY_PATH}
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
install() {
|
install() {
|
||||||
@@ -94,7 +122,25 @@ install() {
|
|||||||
echo "NOTE: export LANG=en_US.utf8"
|
echo "NOTE: export LANG=en_US.utf8"
|
||||||
fi
|
fi
|
||||||
dnf update -y
|
dnf update -y
|
||||||
|
|
||||||
for pkg in $1; do
|
for pkg in $1; do
|
||||||
|
if [ "$pkg" == custom-maven3.9.3 ]; then
|
||||||
|
install_custom_maven "3.9.3"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == custom-golang1.18.9 ]; then
|
||||||
|
install_custom_golang "1.18.9"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == java-17-openjdk-devel ]; then
|
||||||
|
if ! dnf list installed "$pkg" >/dev/null 2>/dev/null; then
|
||||||
|
dnf install -y "$pkg"
|
||||||
|
# The default Java version should be Java 11
|
||||||
|
update-alternatives --set java java-11-openjdk.x86_64
|
||||||
|
update-alternatives --set javac java-11-openjdk.x86_64
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
dnf install -y "$pkg"
|
dnf install -y "$pkg"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|||||||
145
environment/os/run.sh
Executable file
145
environment/os/run.sh
Executable file
@@ -0,0 +1,145 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
|
IFS=' '
|
||||||
|
# NOTE: docker_image_name could be local image build based on release/package images.
|
||||||
|
# NOTE: each line has to be under quotes, docker_container_type, script_name and docker_image_name separate with a space.
|
||||||
|
# "docker_container_type script_name docker_image_name"
|
||||||
|
OPERATING_SYSTEMS=(
|
||||||
|
"mgrun amzn-2 amazonlinux:2"
|
||||||
|
"mgrun centos-7 centos:7"
|
||||||
|
"mgrun centos-9 dokken/centos-stream-9"
|
||||||
|
"mgrun debian-10 debian:10"
|
||||||
|
"mgrun debian-11 debian:11"
|
||||||
|
"mgrun fedora-36 fedora:36"
|
||||||
|
"mgrun ubuntu-18.04 ubuntu:18.04"
|
||||||
|
"mgrun ubuntu-20.04 ubuntu:20.04"
|
||||||
|
"mgrun ubuntu-22.04 ubuntu:22.04"
|
||||||
|
# "mgbuild centos-7 package-mgbuild_centos-7"
|
||||||
|
)
|
||||||
|
|
||||||
|
if [ ! "$(docker info)" ]; then
|
||||||
|
echo "ERROR: Docker is required"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
print_help () {
|
||||||
|
echo -e "$0 all\t\t\t\t => start + init all containers in the background"
|
||||||
|
echo -e "$0 check\t\t\t\t => check all containers"
|
||||||
|
echo -e "$0 delete\t\t\t\t => stop + remove all containers"
|
||||||
|
echo -e "$0 copy src_container dst_container => copy build package from src to dst container"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# NOTE: This is an idempotent operation!
|
||||||
|
# TODO(gitbuda): Consider making docker_run always delete + start a new container or add a new function.
|
||||||
|
docker_run () {
|
||||||
|
cnt_name="$1"
|
||||||
|
cnt_image="$2"
|
||||||
|
if [ ! "$(docker ps -q -f name=$cnt_name)" ]; then
|
||||||
|
if [ "$(docker ps -aq -f status=exited -f name=$cnt_name)" ]; then
|
||||||
|
echo "Cleanup of the old exited container..."
|
||||||
|
docker rm $cnt_name
|
||||||
|
fi
|
||||||
|
docker run -d --volume "$SCRIPT_DIR/../../:/memgraph" --network host --name "$cnt_name" "$cnt_image" sleep infinity
|
||||||
|
fi
|
||||||
|
echo "The $cnt_image container is active under $cnt_name name!"
|
||||||
|
}
|
||||||
|
|
||||||
|
docker_exec () {
|
||||||
|
cnt_name="$1"
|
||||||
|
cnt_cmd="$2"
|
||||||
|
docker exec -it "$cnt_name" bash -c "$cnt_cmd"
|
||||||
|
}
|
||||||
|
|
||||||
|
docker_stop_and_rm () {
|
||||||
|
cnt_name="$1"
|
||||||
|
if [ "$(docker ps -q -f name=$cnt_name)" ]; then
|
||||||
|
docker stop "$1"
|
||||||
|
if [ "$(docker ps -aq -f status=exited -f name=$cnt_name)" ]; then
|
||||||
|
docker rm "$1"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# TODO(gitbuda): Make the call to `install NEW_DEPS` configurable, the question what else is useful?
|
||||||
|
start_all () {
|
||||||
|
for script_docker_pair in "${OPERATING_SYSTEMS[@]}"; do
|
||||||
|
read -a script_docker <<< "$script_docker_pair"
|
||||||
|
docker_container_type="${script_docker[0]}"
|
||||||
|
script_name="${script_docker[1]}"
|
||||||
|
docker_image="${script_docker[2]}"
|
||||||
|
docker_name="${docker_container_type}_$script_name"
|
||||||
|
echo ""
|
||||||
|
echo "~~~~ OPERATING ON $docker_image as $docker_name..."
|
||||||
|
docker_run "$docker_name" "$docker_image"
|
||||||
|
docker_exec "$docker_name" "/memgraph/environment/os/$script_name.sh install NEW_DEPS"
|
||||||
|
echo "---- DONE EVERYHING FOR $docker_image as $docker_name..."
|
||||||
|
echo ""
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
check_all () {
|
||||||
|
for script_docker_pair in "${OPERATING_SYSTEMS[@]}"; do
|
||||||
|
read -a script_docker <<< "$script_docker_pair"
|
||||||
|
docker_container_type="${script_docker[0]}"
|
||||||
|
script_name="${script_docker[1]}"
|
||||||
|
docker_image="${script_docker[2]}"
|
||||||
|
docker_name="${docker_container_type}_$script_name"
|
||||||
|
echo ""
|
||||||
|
echo "~~~~ OPERATING ON $docker_image as $docker_name..."
|
||||||
|
docker_exec "$docker_name" "/memgraph/environment/os/$script_name.sh check NEW_DEPS"
|
||||||
|
echo "---- DONE EVERYHING FOR $docker_image as $docker_name..."
|
||||||
|
echo ""
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
delete_all () {
|
||||||
|
for script_docker_pair in "${OPERATING_SYSTEMS[@]}"; do
|
||||||
|
read -a script_docker <<< "$script_docker_pair"
|
||||||
|
docker_container_type="${script_docker[0]}"
|
||||||
|
script_name="${script_docker[1]}"
|
||||||
|
docker_image="${script_docker[2]}"
|
||||||
|
docker_name="${docker_container_type}_$script_name"
|
||||||
|
docker_stop_and_rm "$docker_name"
|
||||||
|
echo "~~~~ $docker_image as $docker_name DELETED"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# TODO(gitbuda): Copy file between containers is a useful util, also delete, + consider copying of a whole folder.
|
||||||
|
# TODO(gitbuda): Add args: src_cnt dst_cnt abs_path; both file and recursive folder, always delete + copy.
|
||||||
|
copy_build_package () {
|
||||||
|
src_container="$1"
|
||||||
|
dst_container="$2"
|
||||||
|
src="$src_container:/memgraph/build/output"
|
||||||
|
tmp_dst="$SCRIPT_DIR/../../build"
|
||||||
|
mkdir -p "$tmp_dst"
|
||||||
|
rm -rf "$tmp_dst/output"
|
||||||
|
dst="$dst_container:/"
|
||||||
|
docker cp "$src" "$tmp_dst"
|
||||||
|
docker cp "$tmp_dst/output" "$dst"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$#" -eq 0 ]; then
|
||||||
|
print_help
|
||||||
|
else
|
||||||
|
case $1 in
|
||||||
|
all)
|
||||||
|
start_all
|
||||||
|
;;
|
||||||
|
check)
|
||||||
|
check_all
|
||||||
|
;;
|
||||||
|
delete)
|
||||||
|
delete_all
|
||||||
|
;;
|
||||||
|
copy) # src_container dst_container
|
||||||
|
if [ "$#" -ne 3 ]; then
|
||||||
|
print_help
|
||||||
|
fi
|
||||||
|
copy_build_package "$2" "$3"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
print_help
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
@@ -6,6 +6,7 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
|||||||
source "$DIR/../util.sh"
|
source "$DIR/../util.sh"
|
||||||
|
|
||||||
check_operating_system "todo-os-name"
|
check_operating_system "todo-os-name"
|
||||||
|
check_architecture "todo-arch-name"
|
||||||
|
|
||||||
TOOLCHAIN_BUILD_DEPS=(
|
TOOLCHAIN_BUILD_DEPS=(
|
||||||
pkg
|
pkg
|
||||||
@@ -19,6 +20,16 @@ MEMGRAPH_BUILD_DEPS=(
|
|||||||
pkg
|
pkg
|
||||||
)
|
)
|
||||||
|
|
||||||
|
MEMGRAPH_RUN_DEPS=(
|
||||||
|
pkg
|
||||||
|
)
|
||||||
|
|
||||||
|
# NEW_DEPS is useful when you won't to test the installation of a new package.
|
||||||
|
# During the test you can put here packages like wget curl tar gzip
|
||||||
|
NEW_DEPS=(
|
||||||
|
pkg
|
||||||
|
)
|
||||||
|
|
||||||
list() {
|
list() {
|
||||||
echo "$1"
|
echo "$1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ TOOLCHAIN_RUN_DEPS=(
|
|||||||
|
|
||||||
MEMGRAPH_BUILD_DEPS=(
|
MEMGRAPH_BUILD_DEPS=(
|
||||||
git # source code control
|
git # source code control
|
||||||
make pkg-config # build system
|
make cmake pkg-config # build system
|
||||||
curl wget # downloading libs
|
curl wget # downloading libs
|
||||||
uuid-dev default-jre-headless # required by antlr
|
uuid-dev default-jre-headless # required by antlr
|
||||||
libreadline-dev # memgraph console
|
libreadline-dev # memgraph console
|
||||||
@@ -53,9 +53,19 @@ MEMGRAPH_BUILD_DEPS=(
|
|||||||
libcurl4-openssl-dev # mg-requests
|
libcurl4-openssl-dev # mg-requests
|
||||||
sbcl # custom Lisp C++ preprocessing
|
sbcl # custom Lisp C++ preprocessing
|
||||||
doxygen graphviz # source documentation generators
|
doxygen graphviz # source documentation generators
|
||||||
mono-runtime mono-mcs nodejs zip unzip default-jdk-headless # driver tests
|
mono-runtime mono-mcs nodejs zip unzip default-jdk-headless openjdk-17-jdk-headless custom-maven3.9.3 # driver tests
|
||||||
|
custom-golang1.18.9 # for driver tests
|
||||||
autoconf # for jemalloc code generation
|
autoconf # for jemalloc code generation
|
||||||
libtool # for protobuf code generation
|
libtool # for protobuf code generation
|
||||||
|
libsasl2-dev
|
||||||
|
)
|
||||||
|
|
||||||
|
MEMGRAPH_RUN_DEPS=(
|
||||||
|
logrotate openssl python3 libseccomp2
|
||||||
|
)
|
||||||
|
|
||||||
|
NEW_DEPS=(
|
||||||
|
wget curl tar gzip
|
||||||
)
|
)
|
||||||
|
|
||||||
list() {
|
list() {
|
||||||
@@ -63,11 +73,53 @@ list() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
check() {
|
check() {
|
||||||
check_all_dpkg "$1"
|
local missing=""
|
||||||
|
for pkg in $1; do
|
||||||
|
if [ "$pkg" == custom-maven3.9.3 ]; then
|
||||||
|
if [ ! -f "/opt/apache-maven-3.9.3/bin/mvn" ]; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == custom-golang1.18.9 ]; then
|
||||||
|
if [ ! -f "/opt/go1.18.9/go/bin/go" ]; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if ! dpkg -s "$pkg" >/dev/null 2>/dev/null; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ "$missing" != "" ]; then
|
||||||
|
echo "MISSING PACKAGES: $missing"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
install() {
|
install() {
|
||||||
apt install -y $1
|
apt update -y
|
||||||
|
|
||||||
|
for pkg in $1; do
|
||||||
|
if [ "$pkg" == custom-maven3.9.3 ]; then
|
||||||
|
install_custom_maven "3.9.3"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == custom-golang1.18.9 ]; then
|
||||||
|
install_custom_golang "1.18.9"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == openjdk-17-jdk-headless ]; then
|
||||||
|
if ! dpkg -s "$pkg" 2>/dev/null >/dev/null; then
|
||||||
|
apt install -y "$pkg"
|
||||||
|
# The default Java version should be Java 11
|
||||||
|
update-alternatives --set java /usr/lib/jvm/java-11-openjdk-amd64/bin/java
|
||||||
|
update-alternatives --set javac /usr/lib/jvm/java-11-openjdk-amd64/bin/javac
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
apt install -y "$pkg"
|
||||||
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
deps=$2"[*]"
|
deps=$2"[*]"
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ TOOLCHAIN_RUN_DEPS=(
|
|||||||
|
|
||||||
MEMGRAPH_BUILD_DEPS=(
|
MEMGRAPH_BUILD_DEPS=(
|
||||||
git # source code control
|
git # source code control
|
||||||
make pkg-config # build system
|
make cmake pkg-config # build system
|
||||||
curl wget # for downloading libs
|
curl wget # for downloading libs
|
||||||
uuid-dev default-jre-headless # required by antlr
|
uuid-dev default-jre-headless # required by antlr
|
||||||
libreadline-dev # for memgraph console
|
libreadline-dev # for memgraph console
|
||||||
@@ -53,10 +53,19 @@ MEMGRAPH_BUILD_DEPS=(
|
|||||||
libcurl4-openssl-dev # mg-requests
|
libcurl4-openssl-dev # mg-requests
|
||||||
sbcl # for custom Lisp C++ preprocessing
|
sbcl # for custom Lisp C++ preprocessing
|
||||||
doxygen graphviz # source documentation generators
|
doxygen graphviz # source documentation generators
|
||||||
mono-runtime mono-mcs zip unzip default-jdk-headless # for driver tests
|
mono-runtime mono-mcs zip unzip default-jdk-headless openjdk-17-jdk-headless custom-maven3.9.3 # for driver tests
|
||||||
dotnet-sdk-3.1 golang nodejs npm
|
dotnet-sdk-3.1 golang custom-golang1.18.9 nodejs npm # for driver tests
|
||||||
autoconf # for jemalloc code generation
|
autoconf # for jemalloc code generation
|
||||||
libtool # for protobuf code generation
|
libtool # for protobuf code generation
|
||||||
|
libsasl2-dev
|
||||||
|
)
|
||||||
|
|
||||||
|
MEMGRAPH_RUN_DEPS=(
|
||||||
|
logrotate openssl python3 libseccomp2
|
||||||
|
)
|
||||||
|
|
||||||
|
NEW_DEPS=(
|
||||||
|
wget curl tar gzip
|
||||||
)
|
)
|
||||||
|
|
||||||
list() {
|
list() {
|
||||||
@@ -64,12 +73,35 @@ list() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
check() {
|
check() {
|
||||||
check_all_dpkg "$1"
|
local missing=""
|
||||||
|
for pkg in $1; do
|
||||||
|
if [ "$pkg" == custom-maven3.9.3 ]; then
|
||||||
|
if [ ! -f "/opt/apache-maven-3.9.3/bin/mvn" ]; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == custom-golang1.18.9 ]; then
|
||||||
|
if [ ! -f "/opt/go1.18.9/go/bin/go" ]; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if ! dpkg -s "$pkg" >/dev/null 2>/dev/null; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ "$missing" != "" ]; then
|
||||||
|
echo "MISSING PACKAGES: $missing"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
install() {
|
install() {
|
||||||
cd "$DIR"
|
cd "$DIR"
|
||||||
apt update
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
apt update -y
|
||||||
|
apt install -y wget
|
||||||
# If GitHub Actions runner is installed, append LANG to the environment.
|
# If GitHub Actions runner is installed, append LANG to the environment.
|
||||||
# Python related tests doesn't work the LANG export.
|
# Python related tests doesn't work the LANG export.
|
||||||
if [ -d "/home/gh/actions-runner" ]; then
|
if [ -d "/home/gh/actions-runner" ]; then
|
||||||
@@ -77,8 +109,16 @@ install() {
|
|||||||
else
|
else
|
||||||
echo "NOTE: export LANG=en_US.utf8"
|
echo "NOTE: export LANG=en_US.utf8"
|
||||||
fi
|
fi
|
||||||
apt install -y wget
|
|
||||||
for pkg in $1; do
|
for pkg in $1; do
|
||||||
|
if [ "$pkg" == custom-maven3.9.3 ]; then
|
||||||
|
install_custom_maven "3.9.3"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == custom-golang1.18.9 ]; then
|
||||||
|
install_custom_golang "1.18.9"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
if [ "$pkg" == dotnet-sdk-3.1 ]; then
|
if [ "$pkg" == dotnet-sdk-3.1 ]; then
|
||||||
if ! dpkg -s dotnet-sdk-3.1 2>/dev/null >/dev/null; then
|
if ! dpkg -s dotnet-sdk-3.1 2>/dev/null >/dev/null; then
|
||||||
wget -nv https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
|
wget -nv https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
|
||||||
@@ -88,6 +128,15 @@ install() {
|
|||||||
fi
|
fi
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
if [ "$pkg" == openjdk-17-jdk-headless ]; then
|
||||||
|
if ! dpkg -s "$pkg" 2>/dev/null >/dev/null; then
|
||||||
|
apt install -y "$pkg"
|
||||||
|
# The default Java version should be Java 11
|
||||||
|
update-alternatives --set java /usr/lib/jvm/java-11-openjdk-amd64/bin/java
|
||||||
|
update-alternatives --set javac /usr/lib/jvm/java-11-openjdk-amd64/bin/javac
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
apt install -y "$pkg"
|
apt install -y "$pkg"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ TOOLCHAIN_RUN_DEPS=(
|
|||||||
|
|
||||||
MEMGRAPH_BUILD_DEPS=(
|
MEMGRAPH_BUILD_DEPS=(
|
||||||
git # source code control
|
git # source code control
|
||||||
make pkg-config # build system
|
make cmake pkg-config # build system
|
||||||
curl wget # for downloading libs
|
curl wget # for downloading libs
|
||||||
uuid-dev default-jre-headless # required by antlr
|
uuid-dev default-jre-headless # required by antlr
|
||||||
libreadline-dev # for memgraph console
|
libreadline-dev # for memgraph console
|
||||||
@@ -53,10 +53,19 @@ MEMGRAPH_BUILD_DEPS=(
|
|||||||
libcurl4-openssl-dev # mg-requests
|
libcurl4-openssl-dev # mg-requests
|
||||||
sbcl # for custom Lisp C++ preprocessing
|
sbcl # for custom Lisp C++ preprocessing
|
||||||
doxygen graphviz # source documentation generators
|
doxygen graphviz # source documentation generators
|
||||||
mono-runtime mono-mcs zip unzip default-jdk-headless # for driver tests
|
mono-runtime mono-mcs zip unzip default-jdk-headless openjdk-17-jdk-headless custom-maven3.9.3 # for driver tests
|
||||||
dotnet-sdk-6.0 golang nodejs npm
|
dotnet-sdk-6.0 golang custom-golang1.18.9 nodejs npm
|
||||||
autoconf # for jemalloc code generation
|
autoconf # for jemalloc code generation
|
||||||
libtool # for protobuf code generation
|
libtool # for protobuf code generation
|
||||||
|
libsasl2-dev
|
||||||
|
)
|
||||||
|
|
||||||
|
MEMGRAPH_RUN_DEPS=(
|
||||||
|
logrotate openssl python3 libseccomp2
|
||||||
|
)
|
||||||
|
|
||||||
|
NEW_DEPS=(
|
||||||
|
wget curl tar gzip
|
||||||
)
|
)
|
||||||
|
|
||||||
list() {
|
list() {
|
||||||
@@ -64,7 +73,28 @@ list() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
check() {
|
check() {
|
||||||
check_all_dpkg "$1"
|
local missing=""
|
||||||
|
for pkg in $1; do
|
||||||
|
if [ "$pkg" == custom-maven3.9.3 ]; then
|
||||||
|
if [ ! -f "/opt/apache-maven-3.9.3/bin/mvn" ]; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == custom-golang1.18.9 ]; then
|
||||||
|
if [ ! -f "/opt/go1.18.9/go/bin/go" ]; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if ! dpkg -s "$pkg" >/dev/null 2>/dev/null; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ "$missing" != "" ]; then
|
||||||
|
echo "MISSING PACKAGES: $missing"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
install() {
|
install() {
|
||||||
@@ -78,7 +108,16 @@ install() {
|
|||||||
echo "NOTE: export LANG=en_US.utf8"
|
echo "NOTE: export LANG=en_US.utf8"
|
||||||
fi
|
fi
|
||||||
apt install -y wget
|
apt install -y wget
|
||||||
|
|
||||||
for pkg in $1; do
|
for pkg in $1; do
|
||||||
|
if [ "$pkg" == custom-maven3.9.3 ]; then
|
||||||
|
install_custom_maven "3.9.3"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == custom-golang1.18.9 ]; then
|
||||||
|
install_custom_golang "1.18.9"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
if [ "$pkg" == dotnet-sdk-6.0 ]; then
|
if [ "$pkg" == dotnet-sdk-6.0 ]; then
|
||||||
if ! dpkg -s dotnet-sdk-6.0 2>/dev/null >/dev/null; 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
|
wget -nv https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
|
||||||
@@ -88,6 +127,15 @@ install() {
|
|||||||
fi
|
fi
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
if [ "$pkg" == openjdk-17-jdk-headless ]; then
|
||||||
|
if ! dpkg -s "$pkg" 2>/dev/null >/dev/null; then
|
||||||
|
apt install -y "$pkg"
|
||||||
|
# The default Java version should be Java 11
|
||||||
|
update-alternatives --set java /usr/lib/jvm/java-11-openjdk-arm64/bin/java
|
||||||
|
update-alternatives --set javac /usr/lib/jvm/java-11-openjdk-arm64/bin/javac
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
apt install -y "$pkg"
|
apt install -y "$pkg"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ TOOLCHAIN_RUN_DEPS=(
|
|||||||
|
|
||||||
MEMGRAPH_BUILD_DEPS=(
|
MEMGRAPH_BUILD_DEPS=(
|
||||||
git # source code control
|
git # source code control
|
||||||
make pkg-config # build system
|
make cmake pkg-config # build system
|
||||||
curl wget # for downloading libs
|
curl wget # for downloading libs
|
||||||
uuid-dev default-jre-headless # required by antlr
|
uuid-dev default-jre-headless # required by antlr
|
||||||
libreadline-dev # for memgraph console
|
libreadline-dev # for memgraph console
|
||||||
@@ -53,10 +53,19 @@ MEMGRAPH_BUILD_DEPS=(
|
|||||||
libcurl4-openssl-dev # mg-requests
|
libcurl4-openssl-dev # mg-requests
|
||||||
sbcl # for custom Lisp C++ preprocessing
|
sbcl # for custom Lisp C++ preprocessing
|
||||||
doxygen graphviz # source documentation generators
|
doxygen graphviz # source documentation generators
|
||||||
mono-runtime mono-mcs zip unzip default-jdk-headless # for driver tests
|
mono-runtime mono-mcs zip unzip default-jdk-headless openjdk-17-jdk-headless custom-maven3.9.3 # for driver tests
|
||||||
dotnet-sdk-6.0 golang nodejs npm
|
dotnet-sdk-6.0 golang custom-golang1.18.9 nodejs npm # for driver tests
|
||||||
autoconf # for jemalloc code generation
|
autoconf # for jemalloc code generation
|
||||||
libtool # for protobuf code generation
|
libtool # for protobuf code generation
|
||||||
|
libsasl2-dev
|
||||||
|
)
|
||||||
|
|
||||||
|
MEMGRAPH_RUN_DEPS=(
|
||||||
|
logrotate openssl python3 libseccomp2
|
||||||
|
)
|
||||||
|
|
||||||
|
NEW_DEPS=(
|
||||||
|
wget curl tar gzip
|
||||||
)
|
)
|
||||||
|
|
||||||
list() {
|
list() {
|
||||||
@@ -64,12 +73,34 @@ list() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
check() {
|
check() {
|
||||||
check_all_dpkg "$1"
|
local missing=""
|
||||||
|
for pkg in $1; do
|
||||||
|
if [ "$pkg" == custom-maven3.9.3 ]; then
|
||||||
|
if [ ! -f "/opt/apache-maven-3.9.3/bin/mvn" ]; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == custom-golang1.18.9 ]; then
|
||||||
|
if [ ! -f "/opt/go1.18.9/go/bin/go" ]; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if ! dpkg -s "$pkg" >/dev/null 2>/dev/null; then
|
||||||
|
missing="$pkg $missing"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ "$missing" != "" ]; then
|
||||||
|
echo "MISSING PACKAGES: $missing"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
install() {
|
install() {
|
||||||
cd "$DIR"
|
cd "$DIR"
|
||||||
apt update
|
apt update -y
|
||||||
|
apt install -y wget
|
||||||
# If GitHub Actions runner is installed, append LANG to the environment.
|
# If GitHub Actions runner is installed, append LANG to the environment.
|
||||||
# Python related tests doesn't work the LANG export.
|
# Python related tests doesn't work the LANG export.
|
||||||
if [ -d "/home/gh/actions-runner" ]; then
|
if [ -d "/home/gh/actions-runner" ]; then
|
||||||
@@ -77,8 +108,16 @@ install() {
|
|||||||
else
|
else
|
||||||
echo "NOTE: export LANG=en_US.utf8"
|
echo "NOTE: export LANG=en_US.utf8"
|
||||||
fi
|
fi
|
||||||
apt install -y wget
|
|
||||||
for pkg in $1; do
|
for pkg in $1; do
|
||||||
|
if [ "$pkg" == custom-maven3.9.3 ]; then
|
||||||
|
install_custom_maven "3.9.3"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$pkg" == custom-golang1.18.9 ]; then
|
||||||
|
install_custom_golang "1.18.9"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
if [ "$pkg" == dotnet-sdk-6.0 ]; then
|
if [ "$pkg" == dotnet-sdk-6.0 ]; then
|
||||||
if ! dpkg -s dotnet-sdk-6.0 2>/dev/null >/dev/null; 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
|
wget -nv https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
|
||||||
@@ -88,6 +127,15 @@ install() {
|
|||||||
fi
|
fi
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
if [ "$pkg" == openjdk-17-jdk-headless ]; then
|
||||||
|
if ! dpkg -s "$pkg" 2>/dev/null >/dev/null; then
|
||||||
|
apt install -y "$pkg"
|
||||||
|
# The default Java version should be Java 11
|
||||||
|
update-alternatives --set java /usr/lib/jvm/java-11-openjdk-amd64/bin/java
|
||||||
|
update-alternatives --set javac /usr/lib/jvm/java-11-openjdk-amd64/bin/javac
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
apt install -y "$pkg"
|
apt install -y "$pkg"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,15 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
function operating_system() {
|
function operating_system() {
|
||||||
grep -E '^(VERSION_)?ID=' /etc/os-release | \
|
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||||
sort | cut -d '=' -f 2- | sed 's/"//g' | paste -s -d '-'
|
grep -E '^(VERSION_)?ID=' /etc/os-release | \
|
||||||
|
sort | cut -d '=' -f 2- | sed 's/"//g' | paste -s -d '-'
|
||||||
|
elif [[ "$OSTYPE" == "darwin"* ]]; then
|
||||||
|
echo "$(sw_vers -productName)-$(sw_vers -productVersion | cut -d '.' -f 1)"
|
||||||
|
else
|
||||||
|
echo "operating_system called on an unknown OS"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
function check_operating_system() {
|
function check_operating_system() {
|
||||||
@@ -76,3 +83,28 @@ function install_all_apt() {
|
|||||||
apt install -y "$pkg"
|
apt install -y "$pkg"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function install_custom_golang() {
|
||||||
|
# NOTE: The official https://go.dev/doc/manage-install doesn't seem to be working.
|
||||||
|
GOVERSION="$1"
|
||||||
|
GOINSTALLDIR="/opt/go$GOVERSION"
|
||||||
|
GOROOT="$GOINSTALLDIR/go" # GOPATH=$HOME/go
|
||||||
|
if [ ! -f "$GOROOT/bin/go" ]; then
|
||||||
|
curl -LO https://go.dev/dl/go$GOVERSION.linux-amd64.tar.gz
|
||||||
|
mkdir -p "$GOINSTALLDIR"
|
||||||
|
tar -C "$GOINSTALLDIR" -xzf go$GOVERSION.linux-amd64.tar.gz
|
||||||
|
fi
|
||||||
|
echo "go $GOVERSION installed under $GOROOT"
|
||||||
|
}
|
||||||
|
|
||||||
|
function install_custom_maven() {
|
||||||
|
MVNVERSION="$1"
|
||||||
|
MVNINSTALLDIR="/opt/apache-maven-$MVNVERSION"
|
||||||
|
MVNURL="https://s3.eu-west-1.amazonaws.com/deps.memgraph.io/maven/apache-maven-$MVNVERSION-bin.tar.gz"
|
||||||
|
if [ ! -f "$MVNINSTALLDIR/bin/mvn" ]; then
|
||||||
|
echo "Downloading maven from $MVNURL"
|
||||||
|
curl -LO "$MVNURL"
|
||||||
|
tar -C "/opt" -xzf "apache-maven-$MVNVERSION-bin.tar.gz"
|
||||||
|
fi
|
||||||
|
echo "maven $MVNVERSION installed under $MVNINSTALLDIR"
|
||||||
|
}
|
||||||
|
|||||||
26
import/mglogs2cypherl.sh
Executable file
26
import/mglogs2cypherl.sh
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
#!/bin/bash -e
|
||||||
|
COLOR_ORANGE="\e[38;5;208m"
|
||||||
|
COLOR_GREEN="\e[38;5;35m"
|
||||||
|
COLOR_RED="\e[0;31m"
|
||||||
|
COLOR_NULL="\e[0m"
|
||||||
|
|
||||||
|
print_help() {
|
||||||
|
echo -e "${COLOR_ORANGE}HOW TO RUN:${COLOR_NULL} $0 memgraph_logs_file_path cypherl_output_path"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$#" -ne 2 ]; then
|
||||||
|
print_help
|
||||||
|
fi
|
||||||
|
INPUT="$1"
|
||||||
|
OUTPUT="$2"
|
||||||
|
if [ ! -f "$INPUT" ]; then
|
||||||
|
echo -e "${COLOR_RED}ERROR:${COLOR_NULL} memgraph_logs_file_path is not a file!"
|
||||||
|
print_help
|
||||||
|
fi
|
||||||
|
|
||||||
|
awk -v RS="Run] '" 'NR>1 { print $0 }' < "$INPUT" | sed -e "/^\[/d;" -e "s/'\([^']*\)$/;/g" > "$OUTPUT"
|
||||||
|
|
||||||
|
echo -e "${COLOR_GREEN}DONE!${COLOR_NULL} Please find Memgraph compatible cypherl file under $OUTPUT"
|
||||||
|
echo ""
|
||||||
|
echo "Import can be done by executing => \`cat $OUTPUT | mgconsole\`"
|
||||||
35
import/n2mg_cypherl.sh
Executable file
35
import/n2mg_cypherl.sh
Executable file
@@ -0,0 +1,35 @@
|
|||||||
|
#!/bin/bash -e
|
||||||
|
COLOR_ORANGE="\e[38;5;208m"
|
||||||
|
COLOR_GREEN="\e[38;5;35m"
|
||||||
|
COLOR_RED="\e[0;31m"
|
||||||
|
COLOR_NULL="\e[0m"
|
||||||
|
|
||||||
|
print_help() {
|
||||||
|
echo -e "${COLOR_ORANGE}HOW TO RUN:${COLOR_NULL} $0 input_file_path output_file_path"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$#" -ne 2 ]; then
|
||||||
|
print_help
|
||||||
|
fi
|
||||||
|
INPUT="$1"
|
||||||
|
OUTPUT="$2"
|
||||||
|
if [ ! -f "$INPUT" ]; then
|
||||||
|
echo -e "${COLOR_RED}ERROR:${COLOR_NULL} input_file_path is not a file!"
|
||||||
|
print_help
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${COLOR_ORANGE}NOTE:${COLOR_NULL} BEGIN and COMMIT are required because variables share the same name (e.g. row)"
|
||||||
|
echo -e "${COLOR_ORANGE}NOTE:${COLOR_NULL} CONSTRAINTS are just skipped -> ${COLOR_RED}please create consraints manually if needed${COLOR_NULL}"
|
||||||
|
|
||||||
|
sed -e 's/^:begin/BEGIN/g; s/^BEGIN$/BEGIN;/g;' \
|
||||||
|
-e 's/^:commit/COMMIT/g; s/^COMMIT$/COMMIT;/g;' \
|
||||||
|
-e '/^CALL/d; /^SCHEMA AWAIT/d;' \
|
||||||
|
-e 's/CREATE RANGE INDEX FOR (n:/CREATE INDEX ON :/g;' \
|
||||||
|
-e 's/) ON (n./(/g;' \
|
||||||
|
-e '/^CREATE CONSTRAINT/d; /^DROP CONSTRAINT/d;' "$INPUT" > "$OUTPUT"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${COLOR_GREEN}DONE!${COLOR_NULL} Please find Memgraph compatible cypherl|.cypher file under $OUTPUT"
|
||||||
|
echo ""
|
||||||
|
echo "Please import data by executing => \`cat $OUTPUT | mgconsole\`"
|
||||||
@@ -135,6 +135,13 @@ inline int64_t value_get_int(mgp_value *val) { return MgInvoke<int64_t>(mgp_valu
|
|||||||
|
|
||||||
inline 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); }
|
||||||
|
|
||||||
|
inline double value_get_numeric(mgp_value *val) {
|
||||||
|
if (MgInvoke<int>(mgp_value_is_int, val)) {
|
||||||
|
return static_cast<double>(value_get_int(val));
|
||||||
|
}
|
||||||
|
return value_get_double(val);
|
||||||
|
}
|
||||||
|
|
||||||
inline 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); }
|
||||||
|
|
||||||
inline 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); }
|
||||||
@@ -171,6 +178,8 @@ inline bool value_is_int(mgp_value *val) { return MgInvoke<int>(mgp_value_is_int
|
|||||||
|
|
||||||
inline 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); }
|
||||||
|
|
||||||
|
inline bool value_is_numeric(mgp_value *val) { return value_is_int(val) || value_is_double(val); }
|
||||||
|
|
||||||
inline 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); }
|
||||||
|
|
||||||
inline 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); }
|
||||||
@@ -246,6 +255,16 @@ inline mgp_edge *graph_create_edge(mgp_graph *graph, mgp_vertex *from, mgp_verte
|
|||||||
return MgInvoke<mgp_edge *>(mgp_graph_create_edge, graph, from, to, type, memory);
|
return MgInvoke<mgp_edge *>(mgp_graph_create_edge, graph, from, to, type, memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline mgp_edge *graph_edge_set_from(struct mgp_graph *graph, struct mgp_edge *e, struct mgp_vertex *new_from,
|
||||||
|
mgp_memory *memory) {
|
||||||
|
return MgInvoke<mgp_edge *>(mgp_graph_edge_set_from, graph, e, new_from, memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline mgp_edge *graph_edge_set_to(struct mgp_graph *graph, struct mgp_edge *e, struct mgp_vertex *new_to,
|
||||||
|
mgp_memory *memory) {
|
||||||
|
return MgInvoke<mgp_edge *>(mgp_graph_edge_set_to, graph, e, new_to, memory);
|
||||||
|
}
|
||||||
|
|
||||||
inline 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); }
|
||||||
|
|
||||||
inline 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) {
|
||||||
@@ -326,6 +345,12 @@ inline void map_insert(mgp_map *map, const char *key, mgp_value *value) {
|
|||||||
MgInvokeVoid(mgp_map_insert, map, key, value);
|
MgInvokeVoid(mgp_map_insert, map, key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void map_update(mgp_map *map, const char *key, mgp_value *value) {
|
||||||
|
MgInvokeVoid(mgp_map_update, map, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void map_erase(mgp_map *map, const char *key) { MgInvokeVoid(mgp_map_erase, map, key); }
|
||||||
|
|
||||||
inline 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); }
|
||||||
|
|
||||||
inline 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); }
|
||||||
@@ -352,6 +377,10 @@ inline mgp_map_item *map_items_iterator_next(mgp_map_items_iterator *it) {
|
|||||||
|
|
||||||
inline 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); }
|
||||||
|
|
||||||
|
inline size_t vertex_get_in_degree(mgp_vertex *v) { return MgInvoke<size_t>(mgp_vertex_get_in_degree, v); }
|
||||||
|
|
||||||
|
inline size_t vertex_get_out_degree(mgp_vertex *v) { return MgInvoke<size_t>(mgp_vertex_get_out_degree, v); }
|
||||||
|
|
||||||
inline 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);
|
return MgInvoke<mgp_vertex *>(mgp_vertex_copy, v, memory);
|
||||||
}
|
}
|
||||||
@@ -374,6 +403,10 @@ inline bool vertex_has_label_named(mgp_vertex *v, const char *label_name) {
|
|||||||
|
|
||||||
inline 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); }
|
||||||
|
|
||||||
|
inline void vertex_remove_label(mgp_vertex *vertex, mgp_label label) {
|
||||||
|
MgInvokeVoid(mgp_vertex_remove_label, vertex, label);
|
||||||
|
}
|
||||||
|
|
||||||
inline 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);
|
return MgInvoke<mgp_value *>(mgp_vertex_get_property, v, property_name, memory);
|
||||||
}
|
}
|
||||||
@@ -382,6 +415,10 @@ inline void vertex_set_property(mgp_vertex *v, const char *property_name, mgp_va
|
|||||||
MgInvokeVoid(mgp_vertex_set_property, v, property_name, property_value);
|
MgInvokeVoid(mgp_vertex_set_property, v, property_name, property_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void vertex_set_properties(mgp_vertex *v, struct mgp_map *properties) {
|
||||||
|
MgInvokeVoid(mgp_vertex_set_properties, v, properties);
|
||||||
|
}
|
||||||
|
|
||||||
inline mgp_properties_iterator *vertex_iter_properties(mgp_vertex *v, mgp_memory *memory) {
|
inline mgp_properties_iterator *vertex_iter_properties(mgp_vertex *v, mgp_memory *memory) {
|
||||||
return MgInvoke<mgp_properties_iterator *>(mgp_vertex_iter_properties, v, memory);
|
return MgInvoke<mgp_properties_iterator *>(mgp_vertex_iter_properties, v, memory);
|
||||||
}
|
}
|
||||||
@@ -418,6 +455,10 @@ inline void edge_set_property(mgp_edge *e, const char *property_name, mgp_value
|
|||||||
MgInvokeVoid(mgp_edge_set_property, e, property_name, property_value);
|
MgInvokeVoid(mgp_edge_set_property, e, property_name, property_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void edge_set_properties(mgp_edge *e, struct mgp_map *properties) {
|
||||||
|
MgInvokeVoid(mgp_edge_set_properties, e, properties);
|
||||||
|
}
|
||||||
|
|
||||||
inline mgp_properties_iterator *edge_iter_properties(mgp_edge *e, mgp_memory *memory) {
|
inline mgp_properties_iterator *edge_iter_properties(mgp_edge *e, mgp_memory *memory) {
|
||||||
return MgInvoke<mgp_properties_iterator *>(mgp_edge_iter_properties, e, memory);
|
return MgInvoke<mgp_properties_iterator *>(mgp_edge_iter_properties, e, memory);
|
||||||
}
|
}
|
||||||
@@ -677,6 +718,16 @@ inline mgp_proc *module_add_write_procedure(mgp_module *module, const char *name
|
|||||||
return MgInvoke<mgp_proc *>(mgp_module_add_write_procedure, module, name, cb);
|
return MgInvoke<mgp_proc *>(mgp_module_add_write_procedure, module, name, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline mgp_proc *module_add_batch_read_procedure(mgp_module *module, const char *name, mgp_proc_cb cb,
|
||||||
|
mgp_proc_initializer initializer, mgp_proc_cleanup cleanup) {
|
||||||
|
return MgInvoke<mgp_proc *>(mgp_module_add_batch_read_procedure, module, name, cb, initializer, cleanup);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline mgp_proc *module_add_batch_write_procedure(mgp_module *module, const char *name, mgp_proc_cb cb,
|
||||||
|
mgp_proc_initializer initializer, mgp_proc_cleanup cleanup) {
|
||||||
|
return MgInvoke<mgp_proc *>(mgp_module_add_batch_write_procedure, module, name, cb, initializer, cleanup);
|
||||||
|
}
|
||||||
|
|
||||||
inline 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);
|
MgInvokeVoid(mgp_proc_add_arg, proc, name, type);
|
||||||
}
|
}
|
||||||
@@ -693,7 +744,7 @@ inline void proc_add_deprecated_result(mgp_proc *proc, const char *name, mgp_typ
|
|||||||
MgInvokeVoid(mgp_proc_add_deprecated_result, proc, name, type);
|
MgInvokeVoid(mgp_proc_add_deprecated_result, proc, name, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool must_abort(mgp_graph *graph) { return mgp_must_abort(graph); }
|
inline int must_abort(mgp_graph *graph) { return mgp_must_abort(graph); }
|
||||||
|
|
||||||
// mgp_result
|
// mgp_result
|
||||||
|
|
||||||
@@ -731,4 +782,44 @@ inline void func_result_set_value(mgp_func_result *res, mgp_value *value, mgp_me
|
|||||||
MgInvokeVoid(mgp_func_result_set_value, res, value, memory);
|
MgInvokeVoid(mgp_func_result_set_value, res, value, memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Messages
|
||||||
|
|
||||||
|
inline mgp_source_type message_source_type(struct mgp_message *message) {
|
||||||
|
return MgInvoke<mgp_source_type>(mgp_message_source_type, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char *message_payload(struct mgp_message *message) {
|
||||||
|
return MgInvoke<const char *>(mgp_message_payload, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t message_payload_size(struct mgp_message *message) {
|
||||||
|
return MgInvoke<size_t>(mgp_message_payload_size, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char *message_topic_name(struct mgp_message *message) {
|
||||||
|
return MgInvoke<const char *>(mgp_message_topic_name, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char *message_key(struct mgp_message *message) { return MgInvoke<const char *>(mgp_message_key, message); }
|
||||||
|
|
||||||
|
inline size_t message_key_size(struct mgp_message *message) { return MgInvoke<size_t>(mgp_message_key_size, message); }
|
||||||
|
|
||||||
|
inline int64_t message_timestamp(struct mgp_message *message) {
|
||||||
|
return MgInvoke<int64_t>(mgp_message_timestamp, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int64_t message_offset(struct mgp_message *message) { return MgInvoke<int64_t>(mgp_message_offset, message); }
|
||||||
|
|
||||||
|
inline size_t messages_size(struct mgp_messages *message) { return MgInvoke<size_t>(mgp_messages_size, message); }
|
||||||
|
|
||||||
|
inline mgp_message *messages_at(struct mgp_messages *message, size_t index) {
|
||||||
|
return MgInvoke<mgp_message *>(mgp_messages_at, message, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transformation
|
||||||
|
|
||||||
|
inline void module_add_transformation(struct mgp_module *module, const char *name, mgp_trans_cb cb) {
|
||||||
|
return MgInvokeVoid(mgp_module_add_transformation, module, name, cb);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mgp
|
} // namespace mgp
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -13,45 +13,96 @@
|
|||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace mg_exception {
|
namespace mg_exception {
|
||||||
struct NotEnoughMemoryException : public std::exception {
|
|
||||||
const char *what() const throw() { return "Not enough memory!"; }
|
// Instead of writing this utility function, we could have used `fmt::format`, but that's not an ideal option here
|
||||||
};
|
// because that would introduce dependency that would be propagated to the client code (if exceptions here would be
|
||||||
|
// used). Since the functionality here is not complex + the code is not on a critical path, we opted for a pure C++
|
||||||
|
// solution.
|
||||||
|
template <typename FirstArg, typename... Args>
|
||||||
|
std::string StringSerialize(FirstArg &&firstArg, Args &&...args) {
|
||||||
|
std::stringstream stream;
|
||||||
|
stream << firstArg;
|
||||||
|
((stream << " " << args), ...);
|
||||||
|
return stream.str();
|
||||||
|
}
|
||||||
|
|
||||||
struct UnknownException : public std::exception {
|
struct UnknownException : public std::exception {
|
||||||
const char *what() const throw() { return "Unknown exception!"; }
|
const char *what() const noexcept override { return "Unknown exception!"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct NotEnoughMemoryException : public std::exception {
|
||||||
|
NotEnoughMemoryException()
|
||||||
|
: message_{
|
||||||
|
StringSerialize("Not enough memory! For more details please visit", "https://memgr.ph/memory-control")} {}
|
||||||
|
const char *what() const noexcept override { return message_.c_str(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string message_;
|
||||||
|
};
|
||||||
|
|
||||||
struct AllocationException : public std::exception {
|
struct AllocationException : public std::exception {
|
||||||
const char *what() const throw() { return "Could not allocate memory!"; }
|
AllocationException()
|
||||||
|
: message_{StringSerialize("Could not allocate memory. For more details please visit",
|
||||||
|
"https://memgr.ph/memory-control")} {}
|
||||||
|
const char *what() const noexcept override { return message_.c_str(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string message_;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct InsufficientBufferException : public std::exception {
|
struct InsufficientBufferException : public std::exception {
|
||||||
const char *what() const throw() { return "Buffer is not sufficient to process procedure!"; }
|
const char *what() const noexcept override { return "Buffer is not sufficient to process procedure!"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OutOfRangeException : public std::exception {
|
struct OutOfRangeException : public std::exception {
|
||||||
const char *what() const throw() { return "Index out of range!"; }
|
const char *what() const noexcept override { return "Index out of range!"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LogicException : public std::exception {
|
struct LogicException : public std::exception {
|
||||||
const char *what() const throw() { return "Logic exception, check the procedure signature!"; }
|
const char *what() const noexcept override { return "Logic exception, check the procedure signature!"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DeletedObjectException : public std::exception {
|
struct DeletedObjectException : public std::exception {
|
||||||
const char *what() const throw() { return "Object is deleted!"; }
|
const char *what() const noexcept override { return "Object is deleted!"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct InvalidArgumentException : public std::exception {
|
struct InvalidArgumentException : public std::exception {
|
||||||
const char *what() const throw() { return "Invalid argument!"; }
|
const char *what() const noexcept override { return "Invalid argument!"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct InvalidIDException : public std::exception {
|
struct InvalidIDException : public std::exception {
|
||||||
const char *what() const throw() { return "Invalid ID!"; }
|
InvalidIDException() : message_{"Invalid ID!"} {}
|
||||||
|
explicit InvalidIDException(std::uint64_t identifier) : message_{StringSerialize("Invalid ID =", identifier)} {}
|
||||||
|
const char *what() const noexcept override { return message_.c_str(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string message_;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct KeyAlreadyExistsException : public std::exception {
|
struct KeyAlreadyExistsException : public std::exception {
|
||||||
const char *what() const throw() { return "Key you are trying to set already exists!"; }
|
KeyAlreadyExistsException() : message_{"Key you are trying to set already exists!"} {}
|
||||||
|
explicit KeyAlreadyExistsException(const std::string &key)
|
||||||
|
: message_{StringSerialize("Key you are trying to set already exists! KEY = ", key)} {}
|
||||||
|
const char *what() const noexcept override { return message_.c_str(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string message_;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ImmutableObjectException : public std::exception {
|
struct ImmutableObjectException : public std::exception {
|
||||||
const char *what() const throw() { return "Object you are trying to change is immutable!"; }
|
const char *what() const noexcept override { return "Object you are trying to change is immutable!"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ValueConversionException : public std::exception {
|
struct ValueConversionException : public std::exception {
|
||||||
const char *what() const throw() { return "Error in value conversion!"; }
|
const char *what() const noexcept override { return "Error in value conversion!"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SerializationException : public std::exception {
|
struct SerializationException : public std::exception {
|
||||||
const char *what() const throw() { return "Error in serialization!"; }
|
const char *what() const noexcept override { return "Error in serialization!"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mg_exception
|
} // namespace mg_exception
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -462,6 +462,18 @@ void mgp_map_destroy(struct mgp_map *map);
|
|||||||
/// Return mgp_error::MGP_ERROR_KEY_ALREADY_EXISTS if a previous mapping already exists.
|
/// Return mgp_error::MGP_ERROR_KEY_ALREADY_EXISTS if a previous mapping already exists.
|
||||||
enum mgp_error mgp_map_insert(struct mgp_map *map, const char *key, struct mgp_value *value);
|
enum mgp_error mgp_map_insert(struct mgp_map *map, const char *key, struct mgp_value *value);
|
||||||
|
|
||||||
|
/// Insert a mapping from a NULL terminated character string to a value.
|
||||||
|
/// If a mapping with the same key already exists, it is replaced.
|
||||||
|
/// In case of update, both the string and the value are copied into the map.
|
||||||
|
/// Therefore, the map does not take ownership of the original key nor value, so
|
||||||
|
/// you still need to free their memory explicitly.
|
||||||
|
/// Return mgp_error::MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to allocate for insertion.
|
||||||
|
enum mgp_error mgp_map_update(struct mgp_map *map, const char *key, struct mgp_value *value);
|
||||||
|
|
||||||
|
// Erase a mapping by key.
|
||||||
|
// If the key doesn't exist in the map nothing happens
|
||||||
|
enum mgp_error mgp_map_erase(struct mgp_map *map, const char *key);
|
||||||
|
|
||||||
/// Get the number of items stored in mgp_map.
|
/// Get the number of items stored in mgp_map.
|
||||||
/// Current implementation always returns without errors.
|
/// Current implementation always returns without errors.
|
||||||
enum mgp_error mgp_map_size(struct mgp_map *map, size_t *result);
|
enum mgp_error mgp_map_size(struct mgp_map *map, size_t *result);
|
||||||
@@ -635,6 +647,12 @@ struct mgp_vertex_id {
|
|||||||
/// Get the ID of given vertex.
|
/// Get the ID of given vertex.
|
||||||
enum mgp_error mgp_vertex_get_id(struct mgp_vertex *v, struct mgp_vertex_id *result);
|
enum mgp_error mgp_vertex_get_id(struct mgp_vertex *v, struct mgp_vertex_id *result);
|
||||||
|
|
||||||
|
/// Get the in degree of given vertex.
|
||||||
|
enum mgp_error mgp_vertex_get_in_degree(struct mgp_vertex *v, size_t *result);
|
||||||
|
|
||||||
|
/// Get the out degree of given vertex.
|
||||||
|
enum mgp_error mgp_vertex_get_out_degree(struct mgp_vertex *v, size_t *result);
|
||||||
|
|
||||||
/// Result is non-zero if the vertex can be modified.
|
/// Result is non-zero if the vertex can be modified.
|
||||||
/// The mutability of the vertex is the same as the graph which it is part of. If a vertex is immutable, then edges
|
/// The mutability of the vertex is the same as the graph which it is part of. If a vertex is immutable, then edges
|
||||||
/// cannot be created or deleted, properties and labels cannot be set or removed and all of the returned edges will be
|
/// cannot be created or deleted, properties and labels cannot be set or removed and all of the returned edges will be
|
||||||
@@ -652,6 +670,15 @@ enum mgp_error mgp_vertex_underlying_graph_is_mutable(struct mgp_vertex *v, int
|
|||||||
enum mgp_error mgp_vertex_set_property(struct mgp_vertex *v, const char *property_name,
|
enum mgp_error mgp_vertex_set_property(struct mgp_vertex *v, const char *property_name,
|
||||||
struct mgp_value *property_value);
|
struct mgp_value *property_value);
|
||||||
|
|
||||||
|
/// Set the value of properties on a vertex.
|
||||||
|
/// When the value is `null`, then the property is removed from the vertex.
|
||||||
|
/// Return mgp_error::MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate memory for storing the property.
|
||||||
|
/// Return mgp_error::MGP_ERROR_IMMUTABLE_OBJECT if `v` is immutable.
|
||||||
|
/// Return mgp_error::MGP_ERROR_DELETED_OBJECT if `v` has been deleted.
|
||||||
|
/// Return mgp_error::MGP_ERROR_SERIALIZATION_ERROR if `v` has been modified by another transaction.
|
||||||
|
/// Return mgp_error::MGP_ERROR_VALUE_CONVERSION if `property_value` is vertex, edge or path.
|
||||||
|
enum mgp_error mgp_vertex_set_properties(struct mgp_vertex *v, struct mgp_map *properties);
|
||||||
|
|
||||||
/// Add the label to the vertex.
|
/// Add the label to the vertex.
|
||||||
/// If the vertex already has the label, this function does nothing.
|
/// If the vertex already has the label, this function does nothing.
|
||||||
/// Return mgp_error::MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate memory for storing the label.
|
/// Return mgp_error::MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate memory for storing the label.
|
||||||
@@ -802,6 +829,15 @@ enum mgp_error mgp_edge_get_property(struct mgp_edge *e, const char *property_na
|
|||||||
/// Return mgp_error::MGP_ERROR_VALUE_CONVERSION if `property_value` is vertex, edge or path.
|
/// Return mgp_error::MGP_ERROR_VALUE_CONVERSION if `property_value` is vertex, edge or path.
|
||||||
enum mgp_error mgp_edge_set_property(struct mgp_edge *e, const char *property_name, struct mgp_value *property_value);
|
enum mgp_error mgp_edge_set_property(struct mgp_edge *e, const char *property_name, struct mgp_value *property_value);
|
||||||
|
|
||||||
|
/// Set the value of properties on a vertex.
|
||||||
|
/// When the value is `null`, then the property is removed from the vertex.
|
||||||
|
/// Return mgp_error::MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate memory for storing the property.
|
||||||
|
/// Return mgp_error::MGP_ERROR_IMMUTABLE_OBJECT if `v` is immutable.
|
||||||
|
/// Return mgp_error::MGP_ERROR_DELETED_OBJECT if `v` has been deleted.
|
||||||
|
/// Return mgp_error::MGP_ERROR_SERIALIZATION_ERROR if `v` has been modified by another transaction.
|
||||||
|
/// Return mgp_error::MGP_ERROR_VALUE_CONVERSION if `property_value` is vertex, edge or path.
|
||||||
|
enum mgp_error mgp_edge_set_properties(struct mgp_edge *e, struct mgp_map *properties);
|
||||||
|
|
||||||
/// Start iterating over properties stored in the given edge.
|
/// Start iterating over properties stored in the given edge.
|
||||||
/// The properties of the edge are copied when the iterator is created, therefore later changes won't affect them.
|
/// The properties of the edge are copied when the iterator is created, therefore later changes won't affect them.
|
||||||
/// Resulting mgp_properties_iterator needs to be deallocated with
|
/// Resulting mgp_properties_iterator needs to be deallocated with
|
||||||
@@ -852,6 +888,22 @@ enum mgp_error mgp_graph_detach_delete_vertex(struct mgp_graph *graph, struct mg
|
|||||||
enum mgp_error mgp_graph_create_edge(struct mgp_graph *graph, struct mgp_vertex *from, struct mgp_vertex *to,
|
enum mgp_error mgp_graph_create_edge(struct mgp_graph *graph, struct mgp_vertex *from, struct mgp_vertex *to,
|
||||||
struct mgp_edge_type type, struct mgp_memory *memory, struct mgp_edge **result);
|
struct mgp_edge_type type, struct mgp_memory *memory, struct mgp_edge **result);
|
||||||
|
|
||||||
|
/// Change edge from vertex
|
||||||
|
/// Return mgp_error::MGP_ERROR_IMMUTABLE_OBJECT if `graph` is immutable.
|
||||||
|
/// Return mgp_error::MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_edge.
|
||||||
|
/// Return mgp_error::MGP_ERROR_DELETED_OBJECT if `from` or `to` has been deleted.
|
||||||
|
/// Return mgp_error::MGP_ERROR_SERIALIZATION_ERROR if `from` or `to` has been modified by another transaction.
|
||||||
|
enum mgp_error mgp_graph_edge_set_from(struct mgp_graph *graph, struct mgp_edge *e, struct mgp_vertex *new_from,
|
||||||
|
struct mgp_memory *memory, struct mgp_edge **result);
|
||||||
|
|
||||||
|
/// Change edge to vertex
|
||||||
|
/// Return mgp_error::MGP_ERROR_IMMUTABLE_OBJECT if `graph` is immutable.
|
||||||
|
/// Return mgp_error::MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_edge.
|
||||||
|
/// Return mgp_error::MGP_ERROR_DELETED_OBJECT if `from` or `to` has been deleted.
|
||||||
|
/// Return mgp_error::MGP_ERROR_SERIALIZATION_ERROR if `from` or `to` has been modified by another transaction.
|
||||||
|
enum mgp_error mgp_graph_edge_set_to(struct mgp_graph *graph, struct mgp_edge *e, struct mgp_vertex *new_to,
|
||||||
|
struct mgp_memory *memory, struct mgp_edge **result);
|
||||||
|
|
||||||
/// Delete an edge from the graph.
|
/// Delete an edge from the graph.
|
||||||
/// Return mgp_error::MGP_ERROR_IMMUTABLE_OBJECT if `graph` is immutable.
|
/// Return mgp_error::MGP_ERROR_IMMUTABLE_OBJECT if `graph` is immutable.
|
||||||
/// Return mgp_error::MGP_ERROR_SERIALIZATION_ERROR if `edge`, its source or destination vertex has been modified by
|
/// Return mgp_error::MGP_ERROR_SERIALIZATION_ERROR if `edge`, its source or destination vertex has been modified by
|
||||||
@@ -1318,6 +1370,13 @@ MGP_ENUM_CLASS mgp_log_level{
|
|||||||
/// to allocate global resources.
|
/// to allocate global resources.
|
||||||
typedef void (*mgp_proc_cb)(struct mgp_list *, struct mgp_graph *, struct mgp_result *, struct mgp_memory *);
|
typedef void (*mgp_proc_cb)(struct mgp_list *, struct mgp_graph *, struct mgp_result *, struct mgp_memory *);
|
||||||
|
|
||||||
|
/// Cleanup for a query module read procedure. Can't be invoked through OpenCypher. Cleans batched stream.
|
||||||
|
typedef void (*mgp_proc_cleanup)();
|
||||||
|
|
||||||
|
/// Initializer for a query module batched read procedure. Can't be invoked through OpenCypher. Initializes batched
|
||||||
|
/// stream.
|
||||||
|
typedef void (*mgp_proc_initializer)(struct mgp_list *, struct mgp_graph *, struct mgp_memory *);
|
||||||
|
|
||||||
/// Register a read-only procedure to a module.
|
/// Register a read-only procedure to a module.
|
||||||
///
|
///
|
||||||
/// The `name` must be a sequence of digits, underscores, lowercase and
|
/// The `name` must be a sequence of digits, underscores, lowercase and
|
||||||
@@ -1342,6 +1401,30 @@ enum mgp_error mgp_module_add_read_procedure(struct mgp_module *module, const ch
|
|||||||
enum mgp_error mgp_module_add_write_procedure(struct mgp_module *module, const char *name, mgp_proc_cb cb,
|
enum mgp_error mgp_module_add_write_procedure(struct mgp_module *module, const char *name, mgp_proc_cb cb,
|
||||||
struct mgp_proc **result);
|
struct mgp_proc **result);
|
||||||
|
|
||||||
|
/// Register a readable batched procedure to a module.
|
||||||
|
///
|
||||||
|
/// The `name` must be a valid identifier, following the same rules as the
|
||||||
|
/// procedure`name` in mgp_module_add_read_procedure.
|
||||||
|
///
|
||||||
|
/// Return mgp_error::MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate memory for mgp_proc.
|
||||||
|
/// Return mgp_error::MGP_ERROR_INVALID_ARGUMENT if `name` is not a valid procedure name.
|
||||||
|
/// RETURN mgp_error::MGP_ERROR_LOGIC_ERROR if a procedure with the same name was already registered.
|
||||||
|
enum mgp_error mgp_module_add_batch_read_procedure(struct mgp_module *module, const char *name, mgp_proc_cb cb,
|
||||||
|
mgp_proc_initializer initializer, mgp_proc_cleanup cleanup,
|
||||||
|
struct mgp_proc **result);
|
||||||
|
|
||||||
|
/// Register a writeable batched procedure to a module.
|
||||||
|
///
|
||||||
|
/// The `name` must be a valid identifier, following the same rules as the
|
||||||
|
/// procedure`name` in mgp_module_add_read_procedure.
|
||||||
|
///
|
||||||
|
/// Return mgp_error::MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate memory for mgp_proc.
|
||||||
|
/// Return mgp_error::MGP_ERROR_INVALID_ARGUMENT if `name` is not a valid procedure name.
|
||||||
|
/// RETURN mgp_error::MGP_ERROR_LOGIC_ERROR if a procedure with the same name was already registered.
|
||||||
|
enum mgp_error mgp_module_add_batch_write_procedure(struct mgp_module *module, const char *name, mgp_proc_cb cb,
|
||||||
|
mgp_proc_initializer initializer, mgp_proc_cleanup cleanup,
|
||||||
|
struct mgp_proc **result);
|
||||||
|
|
||||||
/// Add a required argument to a procedure.
|
/// Add a required argument to a procedure.
|
||||||
///
|
///
|
||||||
/// The order of adding arguments will correspond to the order the procedure
|
/// The order of adding arguments will correspond to the order the procedure
|
||||||
@@ -1417,7 +1500,10 @@ enum mgp_error mgp_log(enum mgp_log_level log_level, const char *output);
|
|||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
/// Return non-zero if the currently executing procedure should abort as soon as
|
/// Return non-zero if the currently executing procedure should abort as soon as
|
||||||
/// possible.
|
/// possible. If non-zero the reasons are:
|
||||||
|
/// (1) The transaction was requested to be terminated
|
||||||
|
/// (2) The server is gracefully shutting down
|
||||||
|
/// (3) The transaction has hit its timeout threshold
|
||||||
///
|
///
|
||||||
/// Procedures which perform heavyweight processing run the risk of running too
|
/// Procedures which perform heavyweight processing run the risk of running too
|
||||||
/// long and going over the query execution time limit. To prevent this, such
|
/// long and going over the query execution time limit. To prevent this, such
|
||||||
|
|||||||
1467
include/mgp.hpp
1467
include/mgp.hpp
File diff suppressed because it is too large
Load Diff
165
include/mgp.py
165
include/mgp.py
@@ -479,6 +479,12 @@ class Properties:
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def set_properties(self, properties: dict) -> None:
|
||||||
|
if not self._vertex_or_edge.is_valid():
|
||||||
|
raise InvalidContextError()
|
||||||
|
|
||||||
|
self._vertex_or_edge.set_properties(properties)
|
||||||
|
|
||||||
|
|
||||||
class EdgeType:
|
class EdgeType:
|
||||||
"""Type of an Edge."""
|
"""Type of an Edge."""
|
||||||
@@ -1402,6 +1408,13 @@ class UnsupportedTypingError(Exception):
|
|||||||
super().__init__("Unsupported typing annotation '{}'".format(type_))
|
super().__init__("Unsupported typing annotation '{}'".format(type_))
|
||||||
|
|
||||||
|
|
||||||
|
class UnequalTypesError(Exception):
|
||||||
|
"""Signals a typing annotation is not equal between types"""
|
||||||
|
|
||||||
|
def __init__(self, type1_: typing.Any, type2_: typing.Any):
|
||||||
|
super().__init__(f"Unequal typing annotation '{type1_}' and '{type2_}'")
|
||||||
|
|
||||||
|
|
||||||
def _typing_to_cypher_type(type_):
|
def _typing_to_cypher_type(type_):
|
||||||
"""Convert typing annotation to a _mgp.CypherType instance."""
|
"""Convert typing annotation to a _mgp.CypherType instance."""
|
||||||
simple_types = {
|
simple_types = {
|
||||||
@@ -1514,6 +1527,72 @@ def _typing_to_cypher_type(type_):
|
|||||||
return parse_typing(str(type_))
|
return parse_typing(str(type_))
|
||||||
|
|
||||||
|
|
||||||
|
def _is_typing_same(type1_, type2_):
|
||||||
|
"""Convert typing annotation to a _mgp.CypherType instance."""
|
||||||
|
simple_types = {
|
||||||
|
typing.Any: 1,
|
||||||
|
object: 2,
|
||||||
|
list: 3,
|
||||||
|
Any: 4,
|
||||||
|
bool: 5,
|
||||||
|
str: 6,
|
||||||
|
int: 7,
|
||||||
|
float: 8,
|
||||||
|
Number: 9,
|
||||||
|
Map: 10,
|
||||||
|
Vertex: 11,
|
||||||
|
Edge: 12,
|
||||||
|
Path: 13,
|
||||||
|
Date: 14,
|
||||||
|
LocalTime: 15,
|
||||||
|
LocalDateTime: 16,
|
||||||
|
Duration: 17,
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
return simple_types[type1_] == simple_types[type2_]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if sys.version_info < (3, 8):
|
||||||
|
# skip type checks
|
||||||
|
return True
|
||||||
|
|
||||||
|
complex_type1 = typing.get_origin(type1_)
|
||||||
|
type_args1 = typing.get_args(type2_)
|
||||||
|
|
||||||
|
complex_type2 = typing.get_origin(type1_)
|
||||||
|
type_args2 = typing.get_args(type2_)
|
||||||
|
|
||||||
|
if complex_type2 != complex_type1:
|
||||||
|
raise UnequalTypesError(type1_, type2_)
|
||||||
|
|
||||||
|
if complex_type1 == typing.Union:
|
||||||
|
contains_none_arg1 = type(None) in type_args1
|
||||||
|
contains_none_arg2 = type(None) in type_args2
|
||||||
|
|
||||||
|
if contains_none_arg1 != contains_none_arg2:
|
||||||
|
raise UnequalTypesError(type1_, type2_)
|
||||||
|
|
||||||
|
if contains_none_arg1:
|
||||||
|
types1 = tuple(t for t in type_args1 if t is not type(None)) # noqa E721
|
||||||
|
types2 = tuple(t for t in type_args2 if t is not type(None)) # noqa E721
|
||||||
|
if len(types1) != len(types2):
|
||||||
|
raise UnequalTypesError(types1, types2)
|
||||||
|
if len(types1) == 1:
|
||||||
|
(type_arg1,) = types1
|
||||||
|
(type_arg2,) = types2
|
||||||
|
else:
|
||||||
|
type_arg1 = typing.Union.__getitem__(types1)
|
||||||
|
type_arg2 = typing.Union.__getitem__(types2)
|
||||||
|
return _is_typing_same(type_arg1, type_arg2)
|
||||||
|
elif complex_type1 == list:
|
||||||
|
(type_arg1,) = type_args1
|
||||||
|
(type_arg2,) = type_args2
|
||||||
|
return _is_typing_same(type_arg1, type_arg2)
|
||||||
|
# skip type checks
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
# Procedure registration
|
# Procedure registration
|
||||||
|
|
||||||
|
|
||||||
@@ -1673,6 +1752,92 @@ def write_proc(func: typing.Callable[..., Record]):
|
|||||||
return _register_proc(func, True)
|
return _register_proc(func, True)
|
||||||
|
|
||||||
|
|
||||||
|
def _register_batch_proc(
|
||||||
|
func: typing.Callable[..., Record], initializer: typing.Callable, cleanup: typing.Callable, is_write: bool
|
||||||
|
):
|
||||||
|
raise_if_does_not_meet_requirements(func)
|
||||||
|
register_func = _mgp.Module.add_batch_write_procedure if is_write else _mgp.Module.add_batch_read_procedure
|
||||||
|
func_sig = inspect.signature(func)
|
||||||
|
func_params = tuple(func_sig.parameters.values())
|
||||||
|
|
||||||
|
initializer_sig = inspect.signature(initializer)
|
||||||
|
initializer_params = tuple(initializer_sig.parameters.values())
|
||||||
|
|
||||||
|
assert (
|
||||||
|
func_params and initializer_params or not func_params and not initializer_params
|
||||||
|
), "Both function params and initializer params must exist or not exist"
|
||||||
|
|
||||||
|
assert len(func_params) == len(initializer_params), "Number of params must be same"
|
||||||
|
|
||||||
|
assert initializer_sig.return_annotation is initializer_sig.empty, "Initializer can't return anything"
|
||||||
|
|
||||||
|
if func_params and func_params[0].annotation is ProcCtx:
|
||||||
|
assert (
|
||||||
|
initializer_params and initializer_params[0].annotation is ProcCtx
|
||||||
|
), "Initializer must have mgp.ProcCtx as first parameter"
|
||||||
|
|
||||||
|
@wraps(func)
|
||||||
|
def wrapper_func(graph, args):
|
||||||
|
return func(ProcCtx(graph), *args)
|
||||||
|
|
||||||
|
@wraps(initializer)
|
||||||
|
def wrapper_initializer(graph, args):
|
||||||
|
return initializer(ProcCtx(graph), *args)
|
||||||
|
|
||||||
|
func_params = func_params[1:]
|
||||||
|
initializer_params = initializer_params[1:]
|
||||||
|
mgp_proc = register_func(_mgp._MODULE, wrapper_func, wrapper_initializer, cleanup)
|
||||||
|
else:
|
||||||
|
|
||||||
|
@wraps(func)
|
||||||
|
def wrapper_func(graph, args):
|
||||||
|
return func(*args)
|
||||||
|
|
||||||
|
@wraps(initializer)
|
||||||
|
def wrapper_initializer(graph, args):
|
||||||
|
return initializer(*args)
|
||||||
|
|
||||||
|
mgp_proc = register_func(_mgp._MODULE, wrapper_func, wrapper_initializer, cleanup)
|
||||||
|
|
||||||
|
for func_param, initializer_param in zip(func_params, initializer_params):
|
||||||
|
func_param_name = func_param.name
|
||||||
|
func_param_type_ = func_param.annotation
|
||||||
|
if func_param_type_ is func_param.empty:
|
||||||
|
func_param_type_ = object
|
||||||
|
initializer_param_type_ = initializer_param.annotation
|
||||||
|
if initializer_param.annotation is initializer_param.empty:
|
||||||
|
initializer_param_type_ = object
|
||||||
|
|
||||||
|
assert _is_typing_same(
|
||||||
|
func_param_type_, initializer_param_type_
|
||||||
|
), "Types of initializer and function must be same"
|
||||||
|
|
||||||
|
func_cypher_type = _typing_to_cypher_type(func_param_type_)
|
||||||
|
if func_param.default is func_param.empty:
|
||||||
|
mgp_proc.add_arg(func_param_name, func_cypher_type)
|
||||||
|
else:
|
||||||
|
mgp_proc.add_opt_arg(func_param_name, func_cypher_type, func_param.default)
|
||||||
|
if func_sig.return_annotation is not func_sig.empty:
|
||||||
|
record = func_sig.return_annotation
|
||||||
|
if not isinstance(record, Record):
|
||||||
|
raise TypeError("Expected '{}' to return 'mgp.Record', got '{}'".format(func.__name__, type(record)))
|
||||||
|
for name, type_ in record.fields.items():
|
||||||
|
if isinstance(type_, Deprecated):
|
||||||
|
cypher_type = _typing_to_cypher_type(type_.field_type)
|
||||||
|
mgp_proc.add_deprecated_result(name, cypher_type)
|
||||||
|
else:
|
||||||
|
mgp_proc.add_result(name, _typing_to_cypher_type(type_))
|
||||||
|
return func
|
||||||
|
|
||||||
|
|
||||||
|
def add_batch_write_proc(func: typing.Callable[..., Record], initializer: typing.Callable, cleanup: typing.Callable):
|
||||||
|
return _register_batch_proc(func, initializer, cleanup, True)
|
||||||
|
|
||||||
|
|
||||||
|
def add_batch_read_proc(func: typing.Callable[..., Record], initializer: typing.Callable, cleanup: typing.Callable):
|
||||||
|
return _register_batch_proc(func, initializer, cleanup, False)
|
||||||
|
|
||||||
|
|
||||||
class InvalidMessageError(Exception):
|
class InvalidMessageError(Exception):
|
||||||
"""
|
"""
|
||||||
Signals using a message instance outside of the registered transformation.
|
Signals using a message instance outside of the registered transformation.
|
||||||
|
|||||||
22
init
22
init
@@ -77,7 +77,9 @@ fi
|
|||||||
|
|
||||||
# Fix for centos 7 during release
|
# Fix for centos 7 during release
|
||||||
if [ "${DISTRO}" = "centos-7" ] || [ "${DISTRO}" = "debian-11" ] || [ "${DISTRO}" = "amzn-2" ]; then
|
if [ "${DISTRO}" = "centos-7" ] || [ "${DISTRO}" = "debian-11" ] || [ "${DISTRO}" = "amzn-2" ]; then
|
||||||
python3 -m pip uninstall -y virtualenv
|
if python3 -m pip show virtualenv >/dev/null 2>/dev/null; then
|
||||||
|
python3 -m pip uninstall -y virtualenv
|
||||||
|
fi
|
||||||
python3 -m pip install virtualenv
|
python3 -m pip install virtualenv
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -91,6 +93,10 @@ setup_virtualenv tests/stress
|
|||||||
setup_virtualenv tests/integration/ldap
|
setup_virtualenv tests/integration/ldap
|
||||||
|
|
||||||
# Setup tests dependencies.
|
# Setup tests dependencies.
|
||||||
|
# NOTE: This is commented out because of the build order (at the time of
|
||||||
|
# execution mgclient is not built yet) which makes this setup to fail. mgclient
|
||||||
|
# is built during the make phase. The tests/setup.sh is called under GHA CI
|
||||||
|
# jobs.
|
||||||
# cd tests
|
# cd tests
|
||||||
# ./setup.sh
|
# ./setup.sh
|
||||||
# cd ..
|
# cd ..
|
||||||
@@ -100,11 +106,15 @@ setup_virtualenv tests/integration/ldap
|
|||||||
|
|
||||||
echo "Done installing dependencies for Memgraph"
|
echo "Done installing dependencies for Memgraph"
|
||||||
|
|
||||||
echo "Linking git hooks"
|
echo "Linking git hooks OR skip if .git folder is not there"
|
||||||
for hook in $(find $DIR/.githooks -type f -printf "%f\n"); do
|
if [ -d "$DIR/.git" ]; then
|
||||||
ln -s -f "$DIR/.githooks/$hook" "$DIR/.git/hooks/$hook"
|
for hook in $(find $DIR/.githooks -type f -printf "%f\n"); do
|
||||||
echo "Added $hook hook"
|
ln -s -f "$DIR/.githooks/$hook" "$DIR/.git/hooks/$hook"
|
||||||
done;
|
echo "Added $hook hook"
|
||||||
|
done;
|
||||||
|
else
|
||||||
|
echo "WARNING: .git folder not present, skip adding hooks"
|
||||||
|
fi
|
||||||
|
|
||||||
# Install precommit hook except on old operating systems because we don't
|
# Install precommit hook except on old operating systems because we don't
|
||||||
# develop on them -> pre-commit hook not required -> we can use latest
|
# develop on them -> pre-commit hook not required -> we can use latest
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ find_package(Boost 1.78 REQUIRED)
|
|||||||
find_package(BZip2 1.0.6 REQUIRED)
|
find_package(BZip2 1.0.6 REQUIRED)
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
set(GFLAGS_NOTHREADS OFF)
|
set(GFLAGS_NOTHREADS OFF)
|
||||||
|
# NOTE: config/generate.py depends on the gflags help XML format.
|
||||||
find_package(gflags REQUIRED)
|
find_package(gflags REQUIRED)
|
||||||
find_package(fmt 8.0.1)
|
find_package(fmt 8.0.1)
|
||||||
find_package(Jemalloc REQUIRED)
|
find_package(Jemalloc REQUIRED)
|
||||||
@@ -28,6 +29,7 @@ function(import_header_library name include_dir)
|
|||||||
set(${_upper_name}_INCLUDE_DIR ${include_dir} CACHE FILEPATH
|
set(${_upper_name}_INCLUDE_DIR ${include_dir} CACHE FILEPATH
|
||||||
"Path to ${name} include directory" FORCE)
|
"Path to ${name} include directory" FORCE)
|
||||||
mark_as_advanced(${_upper_name}_INCLUDE_DIR)
|
mark_as_advanced(${_upper_name}_INCLUDE_DIR)
|
||||||
|
add_library(lib::${name} ALIAS ${name})
|
||||||
endfunction(import_header_library)
|
endfunction(import_header_library)
|
||||||
|
|
||||||
function(import_library name type location include_dir)
|
function(import_library name type location include_dir)
|
||||||
@@ -256,3 +258,10 @@ import_external_library(librdtsc STATIC
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/librdtsc/include
|
${CMAKE_CURRENT_SOURCE_DIR}/librdtsc/include
|
||||||
CMAKE_ARGS ${MG_LIBRDTSC_CMAKE_ARGS}
|
CMAKE_ARGS ${MG_LIBRDTSC_CMAKE_ARGS}
|
||||||
BUILD_COMMAND $(MAKE) rdtsc)
|
BUILD_COMMAND $(MAKE) rdtsc)
|
||||||
|
|
||||||
|
# setup ctre
|
||||||
|
import_header_library(ctre ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
# setup absl (cmake sub_directory tolerant)
|
||||||
|
set(ABSL_PROPAGATE_CXX_STD ON)
|
||||||
|
add_subdirectory(absl EXCLUDE_FROM_ALL)
|
||||||
|
|||||||
@@ -71,8 +71,8 @@ file_get_try_double () {
|
|||||||
if [ -z "$primary_url" ]; then echo "Primary should not be empty." && exit 1; fi
|
if [ -z "$primary_url" ]; then echo "Primary should not be empty." && exit 1; fi
|
||||||
if [ -z "$secondary_url" ]; then echo "Secondary should not be empty." && exit 1; fi
|
if [ -z "$secondary_url" ]; then echo "Secondary should not be empty." && exit 1; fi
|
||||||
filename="$(basename "$secondary_url")"
|
filename="$(basename "$secondary_url")"
|
||||||
wget -nv "$primary_url" -O "$filename" || wget -nv "$secondary_url" -O "$filename" || exit 1
|
# Redirect primary/cache to /dev/null to make it less confusing for a new contributor because only CI has access to the cache.
|
||||||
echo ""
|
wget -nv "$primary_url" -O "$filename" >/dev/null 2>&1 || wget -nv "$secondary_url" -O "$filename" || exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
repo_clone_try_double () {
|
repo_clone_try_double () {
|
||||||
@@ -86,8 +86,8 @@ repo_clone_try_double () {
|
|||||||
if [ -z "$secondary_url" ]; then echo "Secondary should not be empty." && exit 1; fi
|
if [ -z "$secondary_url" ]; then echo "Secondary should not be empty." && exit 1; fi
|
||||||
if [ -z "$folder_name" ]; then echo "Clone folder should not be empty." && exit 1; fi
|
if [ -z "$folder_name" ]; then echo "Clone folder should not be empty." && exit 1; fi
|
||||||
if [ -z "$ref" ]; then echo "Git clone ref should not be empty." && exit 1; fi
|
if [ -z "$ref" ]; then echo "Git clone ref should not be empty." && exit 1; fi
|
||||||
clone "$primary_url" "$folder_name" "$ref" "$shallow" || clone "$secondary_url" "$folder_name" "$ref" "$shallow" || exit 1
|
# Redirect primary/cache to /dev/null to make it less confusing for a new contributor because only CI has access to the cache.
|
||||||
echo ""
|
clone "$primary_url" "$folder_name" "$ref" "$shallow" >/dev/null 2>&1 || clone "$secondary_url" "$folder_name" "$ref" "$shallow" || exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# List all dependencies.
|
# List all dependencies.
|
||||||
@@ -122,6 +122,8 @@ declare -A primary_urls=(
|
|||||||
["protobuf"]="http://$local_cache_host/git/protobuf.git"
|
["protobuf"]="http://$local_cache_host/git/protobuf.git"
|
||||||
["pulsar"]="http://$local_cache_host/git/pulsar.git"
|
["pulsar"]="http://$local_cache_host/git/pulsar.git"
|
||||||
["librdtsc"]="http://$local_cache_host/git/librdtsc.git"
|
["librdtsc"]="http://$local_cache_host/git/librdtsc.git"
|
||||||
|
["ctre"]="http://$local_cache_host/file/hanickadot/compile-time-regular-expressions/v3.7.2/single-header/ctre.hpp"
|
||||||
|
["absl"]="https://$local_cache_host/git/abseil-cpp.git"
|
||||||
)
|
)
|
||||||
|
|
||||||
# The goal of secondary urls is to have links to the "source of truth" of
|
# The goal of secondary urls is to have links to the "source of truth" of
|
||||||
@@ -139,7 +141,7 @@ declare -A secondary_urls=(
|
|||||||
["rocksdb"]="https://github.com/facebook/rocksdb.git"
|
["rocksdb"]="https://github.com/facebook/rocksdb.git"
|
||||||
["mgclient"]="https://github.com/memgraph/mgclient.git"
|
["mgclient"]="https://github.com/memgraph/mgclient.git"
|
||||||
["pymgclient"]="https://github.com/memgraph/pymgclient.git"
|
["pymgclient"]="https://github.com/memgraph/pymgclient.git"
|
||||||
["mgconsole"]="http://github.com/memgraph/mgconsole.git"
|
["mgconsole"]="https://github.com/memgraph/mgconsole.git"
|
||||||
["spdlog"]="https://github.com/gabime/spdlog"
|
["spdlog"]="https://github.com/gabime/spdlog"
|
||||||
["nlohmann"]="https://raw.githubusercontent.com/nlohmann/json/4f8fba14066156b73f1189a2b8bd568bde5284c5/single_include/nlohmann/json.hpp"
|
["nlohmann"]="https://raw.githubusercontent.com/nlohmann/json/4f8fba14066156b73f1189a2b8bd568bde5284c5/single_include/nlohmann/json.hpp"
|
||||||
["neo4j"]="https://dist.neo4j.org/neo4j-community-5.6.0-unix.tar.gz"
|
["neo4j"]="https://dist.neo4j.org/neo4j-community-5.6.0-unix.tar.gz"
|
||||||
@@ -147,6 +149,8 @@ declare -A secondary_urls=(
|
|||||||
["protobuf"]="https://github.com/protocolbuffers/protobuf.git"
|
["protobuf"]="https://github.com/protocolbuffers/protobuf.git"
|
||||||
["pulsar"]="https://github.com/apache/pulsar.git"
|
["pulsar"]="https://github.com/apache/pulsar.git"
|
||||||
["librdtsc"]="https://github.com/gabrieleara/librdtsc.git"
|
["librdtsc"]="https://github.com/gabrieleara/librdtsc.git"
|
||||||
|
["ctre"]="https://raw.githubusercontent.com/hanickadot/compile-time-regular-expressions/v3.7.2/single-header/ctre.hpp"
|
||||||
|
["absl"]="https://github.com/abseil/abseil-cpp.git"
|
||||||
)
|
)
|
||||||
|
|
||||||
# antlr
|
# antlr
|
||||||
@@ -208,7 +212,7 @@ pymgclient_tag="4f85c179e56302d46a1e3e2cf43509db65f062b3" # (2021-01-15)
|
|||||||
repo_clone_try_double "${primary_urls[pymgclient]}" "${secondary_urls[pymgclient]}" "pymgclient" "$pymgclient_tag"
|
repo_clone_try_double "${primary_urls[pymgclient]}" "${secondary_urls[pymgclient]}" "pymgclient" "$pymgclient_tag"
|
||||||
|
|
||||||
# mgconsole
|
# mgconsole
|
||||||
mgconsole_tag="v1.3.0" # (2022-11-20)
|
mgconsole_tag="v1.4.0" # (2023-05-21)
|
||||||
repo_clone_try_double "${primary_urls[mgconsole]}" "${secondary_urls[mgconsole]}" "mgconsole" "$mgconsole_tag" true
|
repo_clone_try_double "${primary_urls[mgconsole]}" "${secondary_urls[mgconsole]}" "mgconsole" "$mgconsole_tag" true
|
||||||
|
|
||||||
spdlog_tag="v1.9.2" # (2021-08-12)
|
spdlog_tag="v1.9.2" # (2021-08-12)
|
||||||
@@ -238,3 +242,13 @@ repo_clone_try_double "${primary_urls[librdtsc]}" "${secondary_urls[librdtsc]}"
|
|||||||
pushd librdtsc
|
pushd librdtsc
|
||||||
git apply ../librdtsc.patch
|
git apply ../librdtsc.patch
|
||||||
popd
|
popd
|
||||||
|
|
||||||
|
#ctre
|
||||||
|
mkdir -p ctre
|
||||||
|
cd ctre
|
||||||
|
file_get_try_double "${primary_urls[ctre]}" "${secondary_urls[ctre]}"
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# abseil 20230125.3
|
||||||
|
absl_ref="20230125.3"
|
||||||
|
repo_clone_try_double "${primary_urls[absl]}" "${secondary_urls[absl]}" "absl" "$absl_ref"
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ ADDITIONAL USE GRANT: You may use the Licensed Work in accordance with the
|
|||||||
3. using the Licensed Work to create a work or solution
|
3. using the Licensed Work to create a work or solution
|
||||||
which competes (or might reasonably be expected to
|
which competes (or might reasonably be expected to
|
||||||
compete) with the Licensed Work.
|
compete) with the Licensed Work.
|
||||||
CHANGE DATE: 2027-18-05
|
CHANGE DATE: 2027-13-09
|
||||||
CHANGE LICENSE: Apache License, Version 2.0
|
CHANGE LICENSE: Apache License, Version 2.0
|
||||||
|
|
||||||
For information about alternative licensing arrangements, please visit: https://memgraph.com/legal.
|
For information about alternative licensing arrangements, please visit: https://memgraph.com/legal.
|
||||||
|
|||||||
202
licenses/third-party/abseil-cpp/LICENSE
vendored
Normal file
202
licenses/third-party/abseil-cpp/LICENSE
vendored
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
https://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
|
||||||
|
|
||||||
|
https://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.
|
||||||
218
licenses/third-party/compile-time-regular-expressions/LICENSE
vendored
Normal file
218
licenses/third-party/compile-time-regular-expressions/LICENSE
vendored
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
--- LLVM Exceptions to the Apache 2.0 License ----
|
||||||
|
|
||||||
|
As an exception, if, as a result of your compiling your source code, portions
|
||||||
|
of this Software are embedded into an Object form of such source code, you
|
||||||
|
may redistribute such embedded portions in such Object form without complying
|
||||||
|
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
|
||||||
|
|
||||||
|
In addition, if you combine or link compiled forms of this Software with
|
||||||
|
software that is licensed under the GPLv2 ("Combined Software") and if a
|
||||||
|
court of competent jurisdiction determines that the patent provision (Section
|
||||||
|
3), the indemnity provision (Section 9) or other Section of the License
|
||||||
|
conflicts with the conditions of the GPLv2, you may retroactively and
|
||||||
|
prospectively choose to deem waived or otherwise exclude such Section(s) of
|
||||||
|
the License, but only in their entirety and only with respect to the Combined
|
||||||
|
Software.
|
||||||
@@ -6,6 +6,8 @@ project(memgraph_query_modules)
|
|||||||
|
|
||||||
disallow_in_source_build()
|
disallow_in_source_build()
|
||||||
|
|
||||||
|
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||||
|
|
||||||
# Everything that is installed here, should be under the "query_modules" component.
|
# Everything that is installed here, should be under the "query_modules" component.
|
||||||
set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME "query_modules")
|
set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME "query_modules")
|
||||||
string(TOLOWER ${CMAKE_BUILD_TYPE} lower_build_type)
|
string(TOLOWER ${CMAKE_BUILD_TYPE} lower_build_type)
|
||||||
@@ -37,9 +39,25 @@ endif()
|
|||||||
install(PROGRAMS $<TARGET_FILE:example_cpp>
|
install(PROGRAMS $<TARGET_FILE:example_cpp>
|
||||||
DESTINATION lib/memgraph/query_modules
|
DESTINATION lib/memgraph/query_modules
|
||||||
RENAME example_cpp.so)
|
RENAME example_cpp.so)
|
||||||
|
|
||||||
# Also install the source of the example, so user can read it.
|
# Also install the source of the example, so user can read it.
|
||||||
install(FILES example.cpp DESTINATION lib/memgraph/query_modules/src)
|
install(FILES example.cpp DESTINATION lib/memgraph/query_modules/src)
|
||||||
|
|
||||||
|
add_library(example_cpp_transformation SHARED example_transformation.cpp)
|
||||||
|
target_include_directories(example_cpp_transformation PRIVATE ${CMAKE_SOURCE_DIR}/include)
|
||||||
|
target_compile_options(example_cpp_transformation PRIVATE -Wall)
|
||||||
|
# Strip C++ transformation example in release build.
|
||||||
|
if (lower_build_type STREQUAL "release")
|
||||||
|
add_custom_command(TARGET example_cpp_transformation POST_BUILD
|
||||||
|
COMMAND strip -s $<TARGET_FILE:example_cpp_transformation>
|
||||||
|
COMMENT "Stripping symbols and sections from the C++ transformation example module")
|
||||||
|
endif()
|
||||||
|
install(PROGRAMS $<TARGET_FILE:example_cpp_transformation>
|
||||||
|
DESTINATION lib/memgraph/query_modules)
|
||||||
|
|
||||||
|
# Also install the source of the example, so user can read it.
|
||||||
|
install(FILES example_cpp_transformation.cpp DESTINATION lib/memgraph/query_modules/src)
|
||||||
|
|
||||||
# Install the Python example and modules
|
# Install the Python example and modules
|
||||||
install(FILES example.py DESTINATION lib/memgraph/query_modules RENAME py_example.py)
|
install(FILES example.py DESTINATION lib/memgraph/query_modules RENAME py_example.py)
|
||||||
install(FILES graph_analyzer.py DESTINATION lib/memgraph/query_modules)
|
install(FILES graph_analyzer.py DESTINATION lib/memgraph/query_modules)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -18,7 +18,11 @@ void ProcImpl(std::vector<mgp::Value> arguments, mgp::Graph graph, mgp::RecordFa
|
|||||||
|
|
||||||
void SampleReadProc(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) {
|
void SampleReadProc(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) {
|
||||||
try {
|
try {
|
||||||
mgp::memory = memory;
|
// The outcommented way of assigning the memory pointer is still
|
||||||
|
// working, but it is deprecated because of certain concurrency
|
||||||
|
// issues. Please use the guard instead.
|
||||||
|
// mgp::memory = memory;
|
||||||
|
mgp::MemoryDispatcherGuard guard(memory);
|
||||||
|
|
||||||
std::vector<mgp::Value> arguments;
|
std::vector<mgp::Value> arguments;
|
||||||
for (size_t i = 0; i < mgp::list_size(args); i++) {
|
for (size_t i = 0; i < mgp::list_size(args); i++) {
|
||||||
@@ -34,7 +38,11 @@ void SampleReadProc(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *resul
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AddXNodes(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) {
|
void AddXNodes(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) {
|
||||||
mgp::memory = memory;
|
// The outcommented way of assigning the memory pointer is still
|
||||||
|
// working, but it is deprecated because of certain concurrency
|
||||||
|
// issues. Please use the guard instead.
|
||||||
|
// mgp::memory = memory;
|
||||||
|
mgp::MemoryDispatcherGuard guard(memory);
|
||||||
auto graph = mgp::Graph(memgraph_graph);
|
auto graph = mgp::Graph(memgraph_graph);
|
||||||
|
|
||||||
std::vector<mgp::Value> arguments;
|
std::vector<mgp::Value> arguments;
|
||||||
@@ -49,7 +57,11 @@ void AddXNodes(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mg
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Multiply(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) {
|
void Multiply(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) {
|
||||||
mgp::memory = memory;
|
// The outcommented way of assigning the memory pointer is still
|
||||||
|
// working, but it is deprecated because of certain concurrency
|
||||||
|
// issues. Please use the guard instead.
|
||||||
|
// mgp::memory = memory;
|
||||||
|
mgp::MemoryDispatcherGuard guard(memory);
|
||||||
|
|
||||||
std::vector<mgp::Value> arguments;
|
std::vector<mgp::Value> arguments;
|
||||||
for (size_t i = 0; i < mgp::list_size(args); i++) {
|
for (size_t i = 0; i < mgp::list_size(args); i++) {
|
||||||
@@ -67,7 +79,11 @@ void Multiply(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_m
|
|||||||
|
|
||||||
extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) {
|
extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) {
|
||||||
try {
|
try {
|
||||||
mgp::memory = memory;
|
// The outcommented way of assigning the memory pointer is still
|
||||||
|
// working, but it is deprecated because of certain concurrency
|
||||||
|
// issues. Please use the guard instead.
|
||||||
|
// mgp::memory = memory;
|
||||||
|
mgp::MemoryDispatcherGuard guard(memory);
|
||||||
|
|
||||||
AddProcedure(SampleReadProc, "return_true", mgp::ProcedureType::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::Parameter("param_1", mgp::Type::Int), mgp::Parameter("param_2", mgp::Type::Double, 2.3)},
|
||||||
@@ -77,7 +93,11 @@ extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *mem
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mgp::memory = memory;
|
// The outcommented way of assigning the memory pointer is still
|
||||||
|
// working, but it is deprecated because of certain concurrency
|
||||||
|
// issues. Please use the guard instead.
|
||||||
|
// mgp::memory = memory;
|
||||||
|
mgp::MemoryDispatcherGuard guard(memory);
|
||||||
|
|
||||||
mgp::AddProcedure(AddXNodes, "add_x_nodes", mgp::ProcedureType::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);
|
{}, module, memory);
|
||||||
@@ -87,7 +107,11 @@ extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *mem
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mgp::memory = memory;
|
// The outcommented way of assigning the memory pointer is still
|
||||||
|
// working, but it is deprecated because of certain concurrency
|
||||||
|
// issues. Please use the guard instead.
|
||||||
|
// mgp::memory = memory;
|
||||||
|
mgp::MemoryDispatcherGuard guard(memory);
|
||||||
|
|
||||||
mgp::AddFunction(Multiply, "multiply",
|
mgp::AddFunction(Multiply, "multiply",
|
||||||
{mgp::Parameter("int", mgp::Type::Int), mgp::Parameter("int", mgp::Type::Int, (int64_t)3)}, module,
|
{mgp::Parameter("int", mgp::Type::Int), mgp::Parameter("int", mgp::Type::Int, (int64_t)3)}, module,
|
||||||
|
|||||||
64
query_modules/example_transformation.cpp
Normal file
64
query_modules/example_transformation.cpp
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
// 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 <exception>
|
||||||
|
#include <mgp.hpp>
|
||||||
|
|
||||||
|
static constexpr std::string_view kQuery = "query";
|
||||||
|
static constexpr std::string_view kParameters = "parameters";
|
||||||
|
|
||||||
|
std::string EscapeString(std::string s) {
|
||||||
|
std::string sign = "'";
|
||||||
|
std::string replace_sign;
|
||||||
|
|
||||||
|
size_t pos;
|
||||||
|
while ((pos = s.find(sign)) != std::string::npos) {
|
||||||
|
s.replace(pos, 1, replace_sign);
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transformation(struct mgp_messages *messages, mgp_graph *graph, mgp_result *result, mgp_memory *memory) {
|
||||||
|
mgp::MemoryDispatcherGuard guard(memory);
|
||||||
|
auto record_factory = mgp::RecordFactory(result);
|
||||||
|
try {
|
||||||
|
auto stream_messages = mgp::Messages(messages);
|
||||||
|
|
||||||
|
for (const mgp::Message &message : stream_messages) {
|
||||||
|
auto record = record_factory.NewRecord();
|
||||||
|
|
||||||
|
auto payload = EscapeString(message.Payload());
|
||||||
|
|
||||||
|
auto query = "CREATE (:Data {payload: '" + payload + "'});";
|
||||||
|
auto query_value = mgp::Value(query.data());
|
||||||
|
|
||||||
|
record.Insert(kQuery.data(), query_value);
|
||||||
|
record.Insert(kParameters.data(), mgp::Value());
|
||||||
|
}
|
||||||
|
} catch (std::exception &ex) {
|
||||||
|
record_factory.SetErrorMessage(ex.what());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int mgp_init_module(mgp_module *module, mgp_memory *memory) {
|
||||||
|
try {
|
||||||
|
mgp::MemoryDispatcherGuard guard(memory);
|
||||||
|
mgp::AddTransformation(Transformation, "transform", module);
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int mgp_shutdown_module() { return 0; }
|
||||||
@@ -14,7 +14,7 @@ set(CPACK_PACKAGE_VENDOR "Memgraph Ltd.")
|
|||||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY
|
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY
|
||||||
"High performance, in-memory, transactional graph database")
|
"High performance, in-memory, transactional graph database")
|
||||||
|
|
||||||
# Setting arhitecture extension for deb packages
|
# Setting architecture extension for deb packages
|
||||||
set(MG_ARCH_EXTENSION_DEB "all")
|
set(MG_ARCH_EXTENSION_DEB "all")
|
||||||
|
|
||||||
if(${MG_ARCH} STREQUAL "x86_64")
|
if(${MG_ARCH} STREQUAL "x86_64")
|
||||||
@@ -48,9 +48,9 @@ set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "${CPACK_PACKAGE_DESCRIPTION_SUMMARY}
|
|||||||
|
|
||||||
# Add `openssl` package to dependencies list. Used to generate SSL certificates.
|
# Add `openssl` package to dependencies list. Used to generate SSL certificates.
|
||||||
# We also depend on `python3` because we embed it in Memgraph.
|
# 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")
|
set(CPACK_DEBIAN_PACKAGE_DEPENDS "openssl (>= 1.1.0), python3 (>= 3.5.0)")
|
||||||
|
|
||||||
# Setting arhitecture extension for rpm packages
|
# Setting architecture extension for rpm packages
|
||||||
set(MG_ARCH_EXTENSION_RPM "noarch")
|
set(MG_ARCH_EXTENSION_RPM "noarch")
|
||||||
|
|
||||||
if(${MG_ARCH} STREQUAL "x86_64")
|
if(${MG_ARCH} STREQUAL "x86_64")
|
||||||
@@ -69,6 +69,12 @@ set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION
|
|||||||
set(CPACK_RPM_PACKAGE_REQUIRES_PRE "shadow-utils")
|
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_USER_BINARY_SPECFILE "${CMAKE_CURRENT_SOURCE_DIR}/rpm/memgraph.spec.in")
|
||||||
set(CPACK_RPM_PACKAGE_LICENSE "Memgraph License")
|
set(CPACK_RPM_PACKAGE_LICENSE "Memgraph License")
|
||||||
|
# CPACK deduces dependency to libstdc++ which:
|
||||||
|
# * can't be easily installed on Centos 7 (the one from the toolchain,
|
||||||
|
# only required to avoid printing issue within query modules)
|
||||||
|
# * it causes issues with glibcxx 2.4
|
||||||
|
# `if(DISTRO STREQUAL "Amazon Linux" AND DISTRO_VERSION STREQUAL "2")`
|
||||||
|
set(CPACK_RPM_PACKAGE_AUTOREQ " no")
|
||||||
|
|
||||||
# Description formatting is important, no line must be greater than 80 characters.
|
# Description formatting is important, no line must be greater than 80 characters.
|
||||||
set(CPACK_RPM_PACKAGE_DESCRIPTION "Contains Memgraph, the graph database.
|
set(CPACK_RPM_PACKAGE_DESCRIPTION "Contains Memgraph, the graph database.
|
||||||
@@ -77,13 +83,7 @@ the next generation of applications driver by real-time connected data.")
|
|||||||
|
|
||||||
# Add `openssl` package to dependencies list. Used to generate SSL certificates.
|
# Add `openssl` package to dependencies list. Used to generate SSL certificates.
|
||||||
# We also depend on `python3` because we embed it in Memgraph.
|
# 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++ >= 3.4.29, logrotate")
|
set(CPACK_RPM_PACKAGE_REQUIRES "openssl >= 1.0.0, curl >= 7.29.0, python3 >= 3.5.0, 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.
|
# All variables must be set before including.
|
||||||
include(CPack)
|
include(CPack)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
/etc/memgraph/memgraph.conf
|
/etc/memgraph/memgraph.conf
|
||||||
|
/etc/memgraph/apoc_compatibility_mappings.json
|
||||||
/etc/memgraph/auth_module/ldap.example.yaml
|
/etc/memgraph/auth_module/ldap.example.yaml
|
||||||
/etc/logrotate.d/memgraph
|
/etc/logrotate.d/memgraph
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ image_name="memgraph:${version}"
|
|||||||
image_package_name="memgraph-${version}-docker.tar.gz"
|
image_package_name="memgraph-${version}-docker.tar.gz"
|
||||||
|
|
||||||
# Build docker image.
|
# Build docker image.
|
||||||
docker build -t ${image_name} ${tag_latest} -f ${dockerfile_path} \
|
# NOTE: --pull is here to always pull that latest base image because of security patches.
|
||||||
|
docker build --pull -t ${image_name} ${tag_latest} -f ${dockerfile_path} \
|
||||||
--build-arg BINARY_NAME=${package_name} \
|
--build-arg BINARY_NAME=${package_name} \
|
||||||
--build-arg EXTENSION=${extension} \
|
--build-arg EXTENSION=${extension} \
|
||||||
--build-arg TARGETARCH="" .
|
--build-arg TARGETARCH="" .
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ RUN yum -y update \
|
|||||||
|
|
||||||
RUN wget -q https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/${TOOLCHAIN_VERSION}/${TOOLCHAIN_VERSION}-binaries-amzn-2-x86_64.tar.gz \
|
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 \
|
-O ${TOOLCHAIN_VERSION}-binaries-amzn-2-x86_64.tar.gz \
|
||||||
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-amzn-2-x86_64.tar.gz -C /opt
|
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-amzn-2-x86_64.tar.gz -C /opt \
|
||||||
|
&& rm ${TOOLCHAIN_VERSION}-binaries-amzn-2-x86_64.tar.gz
|
||||||
|
|
||||||
ENTRYPOINT ["sleep", "infinity"]
|
ENTRYPOINT ["sleep", "infinity"]
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ RUN yum -y update \
|
|||||||
|
|
||||||
RUN wget -q https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/${TOOLCHAIN_VERSION}/${TOOLCHAIN_VERSION}-binaries-centos-7-x86_64.tar.gz \
|
RUN wget -q https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/${TOOLCHAIN_VERSION}/${TOOLCHAIN_VERSION}-binaries-centos-7-x86_64.tar.gz \
|
||||||
-O ${TOOLCHAIN_VERSION}-binaries-centos-7-x86_64.tar.gz \
|
-O ${TOOLCHAIN_VERSION}-binaries-centos-7-x86_64.tar.gz \
|
||||||
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-centos-7-x86_64.tar.gz -C /opt
|
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-centos-7-x86_64.tar.gz -C /opt \
|
||||||
|
&& rm ${TOOLCHAIN_VERSION}-binaries-centos-7-x86_64.tar.gz
|
||||||
|
|
||||||
ENTRYPOINT ["sleep", "infinity"]
|
ENTRYPOINT ["sleep", "infinity"]
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ RUN yum -y update \
|
|||||||
|
|
||||||
RUN wget -q https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/${TOOLCHAIN_VERSION}/${TOOLCHAIN_VERSION}-binaries-centos-9-x86_64.tar.gz \
|
RUN wget -q https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/${TOOLCHAIN_VERSION}/${TOOLCHAIN_VERSION}-binaries-centos-9-x86_64.tar.gz \
|
||||||
-O ${TOOLCHAIN_VERSION}-binaries-centos-9-x86_64.tar.gz \
|
-O ${TOOLCHAIN_VERSION}-binaries-centos-9-x86_64.tar.gz \
|
||||||
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-centos-9-x86_64.tar.gz -C /opt
|
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-centos-9-x86_64.tar.gz -C /opt \
|
||||||
|
&& rm ${TOOLCHAIN_VERSION}-binaries-centos-9-x86_64.tar.gz
|
||||||
|
|
||||||
ENTRYPOINT ["sleep", "infinity"]
|
ENTRYPOINT ["sleep", "infinity"]
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ RUN apt update && apt install -y \
|
|||||||
|
|
||||||
RUN wget -q https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/${TOOLCHAIN_VERSION}/${TOOLCHAIN_VERSION}-binaries-debian-10-amd64.tar.gz \
|
RUN wget -q https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/${TOOLCHAIN_VERSION}/${TOOLCHAIN_VERSION}-binaries-debian-10-amd64.tar.gz \
|
||||||
-O ${TOOLCHAIN_VERSION}-binaries-debian-10-amd64.tar.gz \
|
-O ${TOOLCHAIN_VERSION}-binaries-debian-10-amd64.tar.gz \
|
||||||
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-debian-10-amd64.tar.gz -C /opt
|
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-debian-10-amd64.tar.gz -C /opt \
|
||||||
|
&& rm ${TOOLCHAIN_VERSION}-binaries-debian-10-amd64.tar.gz
|
||||||
|
|
||||||
ENTRYPOINT ["sleep", "infinity"]
|
ENTRYPOINT ["sleep", "infinity"]
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ RUN apt update && apt install -y \
|
|||||||
|
|
||||||
RUN wget -q https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/${TOOLCHAIN_VERSION}/${TOOLCHAIN_VERSION}-binaries-debian-11-arm64.tar.gz \
|
RUN wget -q https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/${TOOLCHAIN_VERSION}/${TOOLCHAIN_VERSION}-binaries-debian-11-arm64.tar.gz \
|
||||||
-O ${TOOLCHAIN_VERSION}-binaries-debian-11-arm64.tar.gz \
|
-O ${TOOLCHAIN_VERSION}-binaries-debian-11-arm64.tar.gz \
|
||||||
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-debian-11-arm64.tar.gz -C /opt
|
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-debian-11-arm64.tar.gz -C /opt \
|
||||||
|
&& rm ${TOOLCHAIN_VERSION}-binaries-debian-11-arm64.tar.gz
|
||||||
|
|
||||||
ENTRYPOINT ["sleep", "infinity"]
|
ENTRYPOINT ["sleep", "infinity"]
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ RUN apt update && apt install -y \
|
|||||||
|
|
||||||
RUN wget -q https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/${TOOLCHAIN_VERSION}/${TOOLCHAIN_VERSION}-binaries-debian-11-amd64.tar.gz \
|
RUN wget -q https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/${TOOLCHAIN_VERSION}/${TOOLCHAIN_VERSION}-binaries-debian-11-amd64.tar.gz \
|
||||||
-O ${TOOLCHAIN_VERSION}-binaries-debian-11-amd64.tar.gz \
|
-O ${TOOLCHAIN_VERSION}-binaries-debian-11-amd64.tar.gz \
|
||||||
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-debian-11-amd64.tar.gz -C /opt
|
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-debian-11-amd64.tar.gz -C /opt \
|
||||||
|
&& rm ${TOOLCHAIN_VERSION}-binaries-debian-11-amd64.tar.gz
|
||||||
|
|
||||||
ENTRYPOINT ["sleep", "infinity"]
|
ENTRYPOINT ["sleep", "infinity"]
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ RUN yum -y update \
|
|||||||
|
|
||||||
RUN wget -q https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/${TOOLCHAIN_VERSION}/${TOOLCHAIN_VERSION}-binaries-fedora-36-x86_64.tar.gz \
|
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 \
|
-O ${TOOLCHAIN_VERSION}-binaries-fedora-36-x86_64.tar.gz \
|
||||||
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-fedora-36-x86_64.tar.gz -C /opt
|
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-fedora-36-x86_64.tar.gz -C /opt \
|
||||||
|
&& rm ${TOOLCHAIN_VERSION}-binaries-fedora-36-x86_64.tar.gz
|
||||||
|
|
||||||
ENTRYPOINT ["sleep", "infinity"]
|
ENTRYPOINT ["sleep", "infinity"]
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ ACTIVATE_TOOLCHAIN="source /opt/${TOOLCHAIN_VERSION}/activate"
|
|||||||
HOST_OUTPUT_DIR="$PROJECT_ROOT/build/output"
|
HOST_OUTPUT_DIR="$PROJECT_ROOT/build/output"
|
||||||
|
|
||||||
print_help () {
|
print_help () {
|
||||||
echo "$0 init|package {os} [--for-docker|--for-platform]|docker|test"
|
# TODO(gitbuda): Update the release/package/run.sh help
|
||||||
|
echo "$0 init|package|docker|test {os} [--for-docker|--for-platform]"
|
||||||
echo ""
|
echo ""
|
||||||
echo " OSs: ${SUPPORTED_OS[*]}"
|
echo " OSs: ${SUPPORTED_OS[*]}"
|
||||||
exit 1
|
exit 1
|
||||||
@@ -35,7 +36,7 @@ make_package () {
|
|||||||
package_command=" cpack -G RPM --config ../CPackConfig.cmake && rpmlint --file='../../release/rpm/rpmlintrc' memgraph*.rpm "
|
package_command=" cpack -G RPM --config ../CPackConfig.cmake && rpmlint --file='../../release/rpm/rpmlintrc' memgraph*.rpm "
|
||||||
fi
|
fi
|
||||||
if [[ "$os" =~ ^"debian".* ]]; then
|
if [[ "$os" =~ ^"debian".* ]]; then
|
||||||
docker exec "$build_container" bash -c "apt update"
|
docker exec "$build_container" bash -c "apt --allow-releaseinfo-change -y update"
|
||||||
package_command=" cpack -G DEB --config ../CPackConfig.cmake "
|
package_command=" cpack -G DEB --config ../CPackConfig.cmake "
|
||||||
fi
|
fi
|
||||||
if [[ "$os" =~ ^"ubuntu".* ]]; then
|
if [[ "$os" =~ ^"ubuntu".* ]]; then
|
||||||
@@ -64,6 +65,7 @@ make_package () {
|
|||||||
git fetch origin master:master
|
git fetch origin master:master
|
||||||
fi
|
fi
|
||||||
docker exec "$build_container" mkdir -p /memgraph
|
docker exec "$build_container" mkdir -p /memgraph
|
||||||
|
# TODO(gitbuda): Revisit copying the whole repo -> makese sense under CI.
|
||||||
docker cp "$PROJECT_ROOT/." "$build_container:/memgraph/"
|
docker cp "$PROJECT_ROOT/." "$build_container:/memgraph/"
|
||||||
|
|
||||||
container_build_dir="/memgraph/build"
|
container_build_dir="/memgraph/build"
|
||||||
@@ -74,6 +76,8 @@ make_package () {
|
|||||||
# environment/os/{os}.sh does not come within the toolchain package. When
|
# environment/os/{os}.sh does not come within the toolchain package. When
|
||||||
# migrating to the next version of toolchain do that, and remove the
|
# migrating to the next version of toolchain do that, and remove the
|
||||||
# TOOLCHAIN_RUN_DEPS installation from here.
|
# TOOLCHAIN_RUN_DEPS installation from here.
|
||||||
|
# TODO(gitbuda): On the other side, having this here allows updating deps
|
||||||
|
# wihout reruning the build containers.
|
||||||
echo "Installing dependencies using '/memgraph/environment/os/$os.sh' script..."
|
echo "Installing dependencies using '/memgraph/environment/os/$os.sh' script..."
|
||||||
docker exec "$build_container" bash -c "/memgraph/environment/os/$os.sh install TOOLCHAIN_RUN_DEPS"
|
docker exec "$build_container" bash -c "/memgraph/environment/os/$os.sh install TOOLCHAIN_RUN_DEPS"
|
||||||
docker exec "$build_container" bash -c "/memgraph/environment/os/$os.sh install MEMGRAPH_BUILD_DEPS"
|
docker exec "$build_container" bash -c "/memgraph/environment/os/$os.sh install MEMGRAPH_BUILD_DEPS"
|
||||||
@@ -83,6 +87,7 @@ make_package () {
|
|||||||
docker exec "$build_container" bash -c "cd /memgraph && git config --global --add safe.directory '*'"
|
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 /memgraph && $ACTIVATE_TOOLCHAIN && ./init"
|
||||||
docker exec "$build_container" bash -c "cd $container_build_dir && rm -rf ./*"
|
docker exec "$build_container" bash -c "cd $container_build_dir && rm -rf ./*"
|
||||||
|
# TODO(gitbuda): cmake fails locally if remote is clone via ssh because of the key -> FIX
|
||||||
if [[ "$os" =~ "-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 .."
|
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
|
else
|
||||||
@@ -108,8 +113,13 @@ make_package () {
|
|||||||
case "$1" in
|
case "$1" in
|
||||||
init)
|
init)
|
||||||
cd "$SCRIPT_DIR"
|
cd "$SCRIPT_DIR"
|
||||||
docker-compose build --build-arg TOOLCHAIN_VERSION="${TOOLCHAIN_VERSION}"
|
if ! which "docker-compose" >/dev/null; then
|
||||||
docker-compose up -d
|
docker_compose_cmd="docker compose"
|
||||||
|
else
|
||||||
|
docker_compose_cmd="docker-compose"
|
||||||
|
fi
|
||||||
|
$docker_compose_cmd build --build-arg TOOLCHAIN_VERSION="${TOOLCHAIN_VERSION}"
|
||||||
|
$docker_compose_cmd up -d
|
||||||
;;
|
;;
|
||||||
|
|
||||||
docker)
|
docker)
|
||||||
@@ -149,6 +159,19 @@ case "$1" in
|
|||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
build)
|
||||||
|
shift 1
|
||||||
|
if [[ "$#" -ne 2 ]]; then
|
||||||
|
print_help
|
||||||
|
fi
|
||||||
|
# in the vX format, e.g. v5
|
||||||
|
toolchain_version="$1"
|
||||||
|
# a name of the os folder, e.g. ubuntu-22.04-arm
|
||||||
|
os="$2"
|
||||||
|
cd "$SCRIPT_DIR/$os"
|
||||||
|
docker build -f Dockerfile --build-arg TOOLCHAIN_VERSION="toolchain-$toolchain_version" -t "memgraph/memgraph-builder:${toolchain_version}_$os" .
|
||||||
|
;;
|
||||||
|
|
||||||
test)
|
test)
|
||||||
echo "TODO(gitbuda): Test all packages on mgtest containers."
|
echo "TODO(gitbuda): Test all packages on mgtest containers."
|
||||||
;;
|
;;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ RUN apt update && apt install -y \
|
|||||||
|
|
||||||
RUN wget -q https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/${TOOLCHAIN_VERSION}/${TOOLCHAIN_VERSION}-binaries-ubuntu-18.04-amd64.tar.gz \
|
RUN wget -q https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/${TOOLCHAIN_VERSION}/${TOOLCHAIN_VERSION}-binaries-ubuntu-18.04-amd64.tar.gz \
|
||||||
-O ${TOOLCHAIN_VERSION}-binaries-ubuntu-18.04-amd64.tar.gz \
|
-O ${TOOLCHAIN_VERSION}-binaries-ubuntu-18.04-amd64.tar.gz \
|
||||||
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-ubuntu-18.04-amd64.tar.gz -C /opt
|
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-ubuntu-18.04-amd64.tar.gz -C /opt \
|
||||||
|
&& rm ${TOOLCHAIN_VERSION}-binaries-ubuntu-18.04-amd64.tar.gz
|
||||||
|
|
||||||
ENTRYPOINT ["sleep", "infinity"]
|
ENTRYPOINT ["sleep", "infinity"]
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ RUN apt update && apt install -y \
|
|||||||
|
|
||||||
RUN wget -q https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/${TOOLCHAIN_VERSION}/${TOOLCHAIN_VERSION}-binaries-ubuntu-20.04-amd64.tar.gz \
|
RUN wget -q https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/${TOOLCHAIN_VERSION}/${TOOLCHAIN_VERSION}-binaries-ubuntu-20.04-amd64.tar.gz \
|
||||||
-O ${TOOLCHAIN_VERSION}-binaries-ubuntu-20.04-amd64.tar.gz \
|
-O ${TOOLCHAIN_VERSION}-binaries-ubuntu-20.04-amd64.tar.gz \
|
||||||
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-ubuntu-20.04-amd64.tar.gz -C /opt
|
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-ubuntu-20.04-amd64.tar.gz -C /opt \
|
||||||
|
&& rm ${TOOLCHAIN_VERSION}-binaries-ubuntu-20.04-amd64.tar.gz
|
||||||
|
|
||||||
ENTRYPOINT ["sleep", "infinity"]
|
ENTRYPOINT ["sleep", "infinity"]
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ RUN apt update && apt install -y \
|
|||||||
|
|
||||||
RUN wget -q https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/${TOOLCHAIN_VERSION}/${TOOLCHAIN_VERSION}-binaries-ubuntu-22.04-arm64.tar.gz \
|
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 \
|
-O ${TOOLCHAIN_VERSION}-binaries-ubuntu-22.04-arm64.tar.gz \
|
||||||
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-ubuntu-22.04-arm64.tar.gz -C /opt
|
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-ubuntu-22.04-arm64.tar.gz -C /opt \
|
||||||
|
&& rm ${TOOLCHAIN_VERSION}-binaries-ubuntu-22.04-arm64.tar.gz
|
||||||
|
|
||||||
ENTRYPOINT ["sleep", "infinity"]
|
ENTRYPOINT ["sleep", "infinity"]
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ RUN apt update && apt install -y \
|
|||||||
|
|
||||||
RUN wget -q https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/${TOOLCHAIN_VERSION}/${TOOLCHAIN_VERSION}-binaries-ubuntu-22.04-amd64.tar.gz \
|
RUN wget -q https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/${TOOLCHAIN_VERSION}/${TOOLCHAIN_VERSION}-binaries-ubuntu-22.04-amd64.tar.gz \
|
||||||
-O ${TOOLCHAIN_VERSION}-binaries-ubuntu-22.04-amd64.tar.gz \
|
-O ${TOOLCHAIN_VERSION}-binaries-ubuntu-22.04-amd64.tar.gz \
|
||||||
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-ubuntu-22.04-amd64.tar.gz -C /opt
|
&& tar xzvf ${TOOLCHAIN_VERSION}-binaries-ubuntu-22.04-amd64.tar.gz -C /opt \
|
||||||
|
&& rm ${TOOLCHAIN_VERSION}-binaries-ubuntu-22.04-amd64.tar.gz
|
||||||
|
|
||||||
ENTRYPOINT ["sleep", "infinity"]
|
ENTRYPOINT ["sleep", "infinity"]
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ echo "Don't forget to switch to the 'memgraph' user to use Memgraph" || exit 1
|
|||||||
# Override CPACK_RPM_ABSOLUTE_INSTALL_FILES with our %config(noreplace), cpack
|
# Override CPACK_RPM_ABSOLUTE_INSTALL_FILES with our %config(noreplace), cpack
|
||||||
# uses plain %config.
|
# uses plain %config.
|
||||||
%config(noreplace) "/etc/memgraph/memgraph.conf"
|
%config(noreplace) "/etc/memgraph/memgraph.conf"
|
||||||
|
%config(noreplace) "/etc/memgraph/apoc_compatibility_mappings.json"
|
||||||
%config(noreplace) "/etc/memgraph/auth_module/ldap.example.yaml"
|
%config(noreplace) "/etc/memgraph/auth_module/ldap.example.yaml"
|
||||||
%config(noreplace) "/etc/logrotate.d/memgraph"
|
%config(noreplace) "/etc/logrotate.d/memgraph"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# CMake configuration for the main memgraph library and executable
|
# CMake configuration for the main memgraph library and executable
|
||||||
|
|
||||||
# add memgraph sub libraries, ordered by dependency
|
# add memgraph sub libraries, ordered by dependency
|
||||||
|
add_subdirectory(csv)
|
||||||
add_subdirectory(utils)
|
add_subdirectory(utils)
|
||||||
add_subdirectory(requests)
|
add_subdirectory(requests)
|
||||||
add_subdirectory(io)
|
add_subdirectory(io)
|
||||||
@@ -16,10 +17,8 @@ add_subdirectory(slk)
|
|||||||
add_subdirectory(rpc)
|
add_subdirectory(rpc)
|
||||||
add_subdirectory(license)
|
add_subdirectory(license)
|
||||||
add_subdirectory(auth)
|
add_subdirectory(auth)
|
||||||
|
add_subdirectory(audit)
|
||||||
if(MG_ENTERPRISE)
|
add_subdirectory(flags)
|
||||||
add_subdirectory(audit)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
string(TOLOWER ${CMAKE_BUILD_TYPE} lower_build_type)
|
string(TOLOWER ${CMAKE_BUILD_TYPE} lower_build_type)
|
||||||
|
|
||||||
@@ -35,18 +34,11 @@ set(mg_single_node_v2_sources
|
|||||||
memgraph.cpp
|
memgraph.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(mg_single_node_v2_libs stdc++fs Threads::Threads
|
|
||||||
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
|
# memgraph main executable
|
||||||
add_executable(memgraph ${mg_single_node_v2_sources})
|
add_executable(memgraph ${mg_single_node_v2_sources})
|
||||||
target_include_directories(memgraph PUBLIC ${CMAKE_SOURCE_DIR}/include)
|
target_include_directories(memgraph PUBLIC ${CMAKE_SOURCE_DIR}/include)
|
||||||
target_link_libraries(memgraph ${mg_single_node_v2_libs})
|
target_link_libraries(memgraph stdc++fs Threads::Threads
|
||||||
|
mg-telemetry mg-communication mg-memory mg-utils mg-license mg-settings mg-glue mg-flags)
|
||||||
|
|
||||||
# NOTE: `include/mg_procedure.syms` describes a pattern match for symbols which
|
# NOTE: `include/mg_procedure.syms` describes a pattern match for symbols which
|
||||||
# should be dynamically exported, so that `dlopen` can correctly link the
|
# should be dynamically exported, so that `dlopen` can correctly link the
|
||||||
@@ -79,7 +71,7 @@ if(lower_build_type STREQUAL "release")
|
|||||||
COMMENT "Stripping symbols and sections from memgraph")
|
COMMENT "Stripping symbols and sections from memgraph")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Generate the configuration file.
|
# Generate the configuration file under the build directory.
|
||||||
add_custom_command(TARGET memgraph POST_BUILD
|
add_custom_command(TARGET memgraph POST_BUILD
|
||||||
COMMAND ${CMAKE_SOURCE_DIR}/config/generate.py
|
COMMAND ${CMAKE_SOURCE_DIR}/config/generate.py
|
||||||
${CMAKE_BINARY_DIR}/memgraph
|
${CMAKE_BINARY_DIR}/memgraph
|
||||||
@@ -88,6 +80,11 @@ add_custom_command(TARGET memgraph POST_BUILD
|
|||||||
${CMAKE_SOURCE_DIR}/config/flags.yaml
|
${CMAKE_SOURCE_DIR}/config/flags.yaml
|
||||||
BYPRODUCTS ${CMAKE_BINARY_DIR}/config/memgraph.conf
|
BYPRODUCTS ${CMAKE_BINARY_DIR}/config/memgraph.conf
|
||||||
COMMENT "Generating memgraph configuration file")
|
COMMENT "Generating memgraph configuration file")
|
||||||
|
# Copy the mappings file to the build directory.
|
||||||
|
add_custom_command(TARGET memgraph POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy
|
||||||
|
${CMAKE_SOURCE_DIR}/config/mappings.json
|
||||||
|
${CMAKE_BINARY_DIR}/config/apoc_compatibility_mappings.json)
|
||||||
|
|
||||||
# Everything here is under "memgraph" install component.
|
# Everything here is under "memgraph" install component.
|
||||||
set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME "memgraph")
|
set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME "memgraph")
|
||||||
@@ -123,6 +120,9 @@ install(FILES ${CMAKE_SOURCE_DIR}/include/mgp.hpp
|
|||||||
# Install the config file (must use absolute path).
|
# Install the config file (must use absolute path).
|
||||||
install(FILES ${CMAKE_BINARY_DIR}/config/memgraph.conf
|
install(FILES ${CMAKE_BINARY_DIR}/config/memgraph.conf
|
||||||
DESTINATION /etc/memgraph RENAME memgraph.conf)
|
DESTINATION /etc/memgraph RENAME memgraph.conf)
|
||||||
|
# Install the mappings file (must use absolute path).
|
||||||
|
install(FILES ${CMAKE_BINARY_DIR}/config/apoc_compatibility_mappings.json
|
||||||
|
DESTINATION /etc/memgraph RENAME apoc_compatibility_mappings.json)
|
||||||
|
|
||||||
# Install logrotate configuration (must use absolute path).
|
# Install logrotate configuration (must use absolute path).
|
||||||
install(FILES ${CMAKE_SOURCE_DIR}/release/logrotate.conf
|
install(FILES ${CMAKE_SOURCE_DIR}/release/logrotate.conf
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
|
// 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
|
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
|
||||||
@@ -116,12 +116,12 @@ Log::~Log() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Log::Record(const std::string &address, const std::string &username, const std::string &query,
|
void Log::Record(const std::string &address, const std::string &username, const std::string &query,
|
||||||
const storage::PropertyValue ¶ms) {
|
const storage::PropertyValue ¶ms, const std::string &db) {
|
||||||
if (!started_.load(std::memory_order_relaxed)) return;
|
if (!started_.load(std::memory_order_relaxed)) return;
|
||||||
auto timestamp =
|
auto timestamp =
|
||||||
std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch())
|
std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch())
|
||||||
.count();
|
.count();
|
||||||
buffer_->emplace(Item{timestamp, address, username, query, params});
|
buffer_->emplace(Item{timestamp, address, username, query, params, db});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Log::ReopenLog() {
|
void Log::ReopenLog() {
|
||||||
@@ -136,8 +136,8 @@ void Log::Flush() {
|
|||||||
for (uint64_t i = 0; i < buffer_size_; ++i) {
|
for (uint64_t i = 0; i < buffer_size_; ++i) {
|
||||||
auto item = buffer_->pop();
|
auto item = buffer_->pop();
|
||||||
if (!item) break;
|
if (!item) break;
|
||||||
log_.Write(fmt::format("{}.{:06d},{},{},{},{}\n", item->timestamp / 1000000, item->timestamp % 1000000,
|
log_.Write(fmt::format("{}.{:06d},{},{},{},{},{}\n", item->timestamp / 1000000, item->timestamp % 1000000,
|
||||||
item->address, item->username, utils::Escape(item->query),
|
item->address, item->username, item->db, utils::Escape(item->query),
|
||||||
utils::Escape(PropertyValueToJson(item->params).dump())));
|
utils::Escape(PropertyValueToJson(item->params).dump())));
|
||||||
}
|
}
|
||||||
log_.Sync();
|
log_.Sync();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
|
// 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
|
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
|
||||||
@@ -32,6 +32,7 @@ class Log {
|
|||||||
std::string username;
|
std::string username;
|
||||||
std::string query;
|
std::string query;
|
||||||
storage::PropertyValue params;
|
storage::PropertyValue params;
|
||||||
|
std::string db;
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -51,7 +52,7 @@ class Log {
|
|||||||
|
|
||||||
/// Adds an entry to the audit log. Thread-safe.
|
/// Adds an entry to the audit log. Thread-safe.
|
||||||
void Record(const std::string &address, const std::string &username, const std::string &query,
|
void Record(const std::string &address, const std::string &username, const std::string &query,
|
||||||
const storage::PropertyValue ¶ms);
|
const storage::PropertyValue ¶ms, const std::string &db);
|
||||||
|
|
||||||
/// Reopens the log file. Used for log file rotation. Thread-safe.
|
/// Reopens the log file. Used for log file rotation. Thread-safe.
|
||||||
void ReopenLog();
|
void ReopenLog();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
|
// 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
|
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
|
||||||
@@ -314,4 +314,57 @@ std::vector<auth::User> Auth::AllUsersForRole(const std::string &rolename_orig)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MG_ENTERPRISE
|
||||||
|
bool Auth::GrantDatabaseToUser(const std::string &db, const std::string &name) {
|
||||||
|
auto user = GetUser(name);
|
||||||
|
if (user) {
|
||||||
|
if (db == kAllDatabases) {
|
||||||
|
user->db_access().GrantAll();
|
||||||
|
} else {
|
||||||
|
user->db_access().Add(db);
|
||||||
|
}
|
||||||
|
SaveUser(*user);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Auth::RevokeDatabaseFromUser(const std::string &db, const std::string &name) {
|
||||||
|
auto user = GetUser(name);
|
||||||
|
if (user) {
|
||||||
|
if (db == kAllDatabases) {
|
||||||
|
user->db_access().DenyAll();
|
||||||
|
} else {
|
||||||
|
user->db_access().Remove(db);
|
||||||
|
}
|
||||||
|
SaveUser(*user);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Auth::DeleteDatabase(const std::string &db) {
|
||||||
|
for (auto it = storage_.begin(kUserPrefix); it != storage_.end(kUserPrefix); ++it) {
|
||||||
|
auto username = it->first.substr(kUserPrefix.size());
|
||||||
|
auto user = GetUser(username);
|
||||||
|
if (user) {
|
||||||
|
user->db_access().Delete(db);
|
||||||
|
SaveUser(*user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Auth::SetMainDatabase(const std::string &db, const std::string &name) {
|
||||||
|
auto user = GetUser(name);
|
||||||
|
if (user) {
|
||||||
|
if (!user->db_access().SetDefault(db)) {
|
||||||
|
throw AuthException("Couldn't set default database '{}' for user '{}'!", db, name);
|
||||||
|
}
|
||||||
|
SaveUser(*user);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace memgraph::auth
|
} // 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
|
// 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
|
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
|
||||||
@@ -19,6 +19,9 @@
|
|||||||
#include "utils/settings.hpp"
|
#include "utils/settings.hpp"
|
||||||
|
|
||||||
namespace memgraph::auth {
|
namespace memgraph::auth {
|
||||||
|
|
||||||
|
static const constexpr char *const kAllDatabases = "*";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class serves as the main Authentication/Authorization storage.
|
* This class serves as the main Authentication/Authorization storage.
|
||||||
* It provides functions for managing Users, Roles, Permissions and FineGrainedAccessPermissions.
|
* It provides functions for managing Users, Roles, Permissions and FineGrainedAccessPermissions.
|
||||||
@@ -155,6 +158,46 @@ class Auth final {
|
|||||||
*/
|
*/
|
||||||
std::vector<User> AllUsersForRole(const std::string &rolename) const;
|
std::vector<User> AllUsersForRole(const std::string &rolename) const;
|
||||||
|
|
||||||
|
#ifdef MG_ENTERPRISE
|
||||||
|
/**
|
||||||
|
* @brief Revoke access to individual database for a user.
|
||||||
|
*
|
||||||
|
* @param db name of the database to revoke
|
||||||
|
* @param name user's username
|
||||||
|
* @return true on success
|
||||||
|
* @throw AuthException if unable to find or update the user
|
||||||
|
*/
|
||||||
|
bool RevokeDatabaseFromUser(const std::string &db, const std::string &name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Grant access to individual database for a user.
|
||||||
|
*
|
||||||
|
* @param db name of the database to revoke
|
||||||
|
* @param name user's username
|
||||||
|
* @return true on success
|
||||||
|
* @throw AuthException if unable to find or update the user
|
||||||
|
*/
|
||||||
|
bool GrantDatabaseToUser(const std::string &db, const std::string &name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete a database from all users.
|
||||||
|
*
|
||||||
|
* @param db name of the database to delete
|
||||||
|
* @throw AuthException if unable to read data
|
||||||
|
*/
|
||||||
|
void DeleteDatabase(const std::string &db);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set main database for an individual user.
|
||||||
|
*
|
||||||
|
* @param db name of the database to revoke
|
||||||
|
* @param name user's username
|
||||||
|
* @return true on success
|
||||||
|
* @throw AuthException if unable to find or update the user
|
||||||
|
*/
|
||||||
|
bool SetMainDatabase(const std::string &db, const std::string &name);
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Even though the `kvstore::KVStore` class is guaranteed to be thread-safe,
|
// Even though the `kvstore::KVStore` class is guaranteed to be thread-safe,
|
||||||
// Auth is not thread-safe because modifying users and roles might require
|
// Auth is not thread-safe because modifying users and roles might require
|
||||||
|
|||||||
@@ -15,8 +15,10 @@
|
|||||||
|
|
||||||
#include "auth/crypto.hpp"
|
#include "auth/crypto.hpp"
|
||||||
#include "auth/exceptions.hpp"
|
#include "auth/exceptions.hpp"
|
||||||
|
#include "dbms/constants.hpp"
|
||||||
#include "license/license.hpp"
|
#include "license/license.hpp"
|
||||||
#include "query/constants.hpp"
|
#include "query/constants.hpp"
|
||||||
|
#include "spdlog/spdlog.h"
|
||||||
#include "utils/cast.hpp"
|
#include "utils/cast.hpp"
|
||||||
#include "utils/logging.hpp"
|
#include "utils/logging.hpp"
|
||||||
#include "utils/settings.hpp"
|
#include "utils/settings.hpp"
|
||||||
@@ -35,18 +37,31 @@ namespace memgraph::auth {
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Constant list of all available permissions.
|
// Constant list of all available permissions.
|
||||||
const std::vector<Permission> kPermissionsAll = {Permission::MATCH, Permission::CREATE,
|
const std::vector<Permission> kPermissionsAll = {Permission::MATCH,
|
||||||
Permission::MERGE, Permission::DELETE,
|
Permission::CREATE,
|
||||||
Permission::SET, Permission::REMOVE,
|
Permission::MERGE,
|
||||||
Permission::INDEX, Permission::STATS,
|
Permission::DELETE,
|
||||||
Permission::CONSTRAINT, Permission::DUMP,
|
Permission::SET,
|
||||||
Permission::AUTH, Permission::REPLICATION,
|
Permission::REMOVE,
|
||||||
Permission::DURABILITY, Permission::READ_FILE,
|
Permission::INDEX,
|
||||||
Permission::FREE_MEMORY, Permission::TRIGGER,
|
Permission::STATS,
|
||||||
Permission::CONFIG, Permission::STREAM,
|
Permission::CONSTRAINT,
|
||||||
Permission::MODULE_READ, Permission::MODULE_WRITE,
|
Permission::DUMP,
|
||||||
Permission::WEBSOCKET, Permission::TRANSACTION_MANAGEMENT,
|
Permission::AUTH,
|
||||||
Permission::STORAGE_MODE};
|
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,
|
||||||
|
Permission::MULTI_DATABASE_EDIT,
|
||||||
|
Permission::MULTI_DATABASE_USE};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -98,6 +113,10 @@ std::string PermissionToString(Permission permission) {
|
|||||||
return "TRANSACTION_MANAGEMENT";
|
return "TRANSACTION_MANAGEMENT";
|
||||||
case Permission::STORAGE_MODE:
|
case Permission::STORAGE_MODE:
|
||||||
return "STORAGE_MODE";
|
return "STORAGE_MODE";
|
||||||
|
case Permission::MULTI_DATABASE_EDIT:
|
||||||
|
return "MULTI_DATABASE_EDIT";
|
||||||
|
case Permission::MULTI_DATABASE_USE:
|
||||||
|
return "MULTI_DATABASE_USE";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -444,10 +463,11 @@ Role Role::Deserialize(const nlohmann::json &data) {
|
|||||||
auto permissions = Permissions::Deserialize(data["permissions"]);
|
auto permissions = Permissions::Deserialize(data["permissions"]);
|
||||||
#ifdef MG_ENTERPRISE
|
#ifdef MG_ENTERPRISE
|
||||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||||
if (!data["fine_grained_access_handler"].is_object()) {
|
FineGrainedAccessHandler fine_grained_access_handler;
|
||||||
throw AuthException("Couldn't load user data!");
|
// We can have an empty fine_grained if the user was created without a valid license
|
||||||
|
if (data["fine_grained_access_handler"].is_object()) {
|
||||||
|
fine_grained_access_handler = FineGrainedAccessHandler::Deserialize(data["fine_grained_access_handler"]);
|
||||||
}
|
}
|
||||||
auto fine_grained_access_handler = FineGrainedAccessHandler::Deserialize(data["fine_grained_access_handler"]);
|
|
||||||
return {data["rolename"], permissions, std::move(fine_grained_access_handler)};
|
return {data["rolename"], permissions, std::move(fine_grained_access_handler)};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -464,6 +484,82 @@ bool operator==(const Role &first, const Role &second) {
|
|||||||
return first.rolename_ == second.rolename_ && first.permissions_ == second.permissions_;
|
return first.rolename_ == second.rolename_ && first.permissions_ == second.permissions_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MG_ENTERPRISE
|
||||||
|
void Databases::Add(const std::string &db) {
|
||||||
|
if (allow_all_) {
|
||||||
|
grants_dbs_.clear();
|
||||||
|
allow_all_ = false;
|
||||||
|
}
|
||||||
|
grants_dbs_.emplace(db);
|
||||||
|
denies_dbs_.erase(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Databases::Remove(const std::string &db) {
|
||||||
|
denies_dbs_.emplace(db);
|
||||||
|
grants_dbs_.erase(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Databases::Delete(const std::string &db) {
|
||||||
|
denies_dbs_.erase(db);
|
||||||
|
if (!allow_all_) {
|
||||||
|
grants_dbs_.erase(db);
|
||||||
|
}
|
||||||
|
// Reset if default deleted
|
||||||
|
if (default_db_ == db) {
|
||||||
|
default_db_ = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Databases::GrantAll() {
|
||||||
|
allow_all_ = true;
|
||||||
|
grants_dbs_.clear();
|
||||||
|
denies_dbs_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Databases::DenyAll() {
|
||||||
|
allow_all_ = false;
|
||||||
|
grants_dbs_.clear();
|
||||||
|
denies_dbs_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Databases::SetDefault(const std::string &db) {
|
||||||
|
if (!Contains(db)) return false;
|
||||||
|
default_db_ = db;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool Databases::Contains(const std::string &db) const {
|
||||||
|
return !denies_dbs_.contains(db) && (allow_all_ || grants_dbs_.contains(db));
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &Databases::GetDefault() const {
|
||||||
|
if (!Contains(default_db_)) {
|
||||||
|
throw AuthException("No access to the set default database \"{}\".", default_db_);
|
||||||
|
}
|
||||||
|
return default_db_;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlohmann::json Databases::Serialize() const {
|
||||||
|
nlohmann::json data = nlohmann::json::object();
|
||||||
|
data["grants"] = grants_dbs_;
|
||||||
|
data["denies"] = denies_dbs_;
|
||||||
|
data["allow_all"] = allow_all_;
|
||||||
|
data["default"] = default_db_;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
Databases Databases::Deserialize(const nlohmann::json &data) {
|
||||||
|
if (!data.is_object()) {
|
||||||
|
throw AuthException("Couldn't load database data!");
|
||||||
|
}
|
||||||
|
if (!data["grants"].is_structured() || !data["denies"].is_structured() || !data["allow_all"].is_boolean() ||
|
||||||
|
!data["default"].is_string()) {
|
||||||
|
throw AuthException("Couldn't load database data!");
|
||||||
|
}
|
||||||
|
return {data["allow_all"], data["grants"], data["denies"], data["default"]};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
User::User() {}
|
User::User() {}
|
||||||
|
|
||||||
User::User(const std::string &username) : username_(utils::ToLowerCase(username)) {}
|
User::User(const std::string &username) : username_(utils::ToLowerCase(username)) {}
|
||||||
@@ -472,11 +568,12 @@ User::User(const std::string &username, const std::string &password_hash, const
|
|||||||
|
|
||||||
#ifdef MG_ENTERPRISE
|
#ifdef MG_ENTERPRISE
|
||||||
User::User(const std::string &username, const std::string &password_hash, const Permissions &permissions,
|
User::User(const std::string &username, const std::string &password_hash, const Permissions &permissions,
|
||||||
FineGrainedAccessHandler fine_grained_access_handler)
|
FineGrainedAccessHandler fine_grained_access_handler, Databases db_access)
|
||||||
: username_(utils::ToLowerCase(username)),
|
: username_(utils::ToLowerCase(username)),
|
||||||
password_hash_(password_hash),
|
password_hash_(password_hash),
|
||||||
permissions_(permissions),
|
permissions_(permissions),
|
||||||
fine_grained_access_handler_(std::move(fine_grained_access_handler)) {}
|
fine_grained_access_handler_(std::move(fine_grained_access_handler)),
|
||||||
|
database_access_(db_access) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool User::CheckPassword(const std::string &password) {
|
bool User::CheckPassword(const std::string &password) {
|
||||||
@@ -576,8 +673,10 @@ nlohmann::json User::Serialize() const {
|
|||||||
#ifdef MG_ENTERPRISE
|
#ifdef MG_ENTERPRISE
|
||||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||||
data["fine_grained_access_handler"] = fine_grained_access_handler_.Serialize();
|
data["fine_grained_access_handler"] = fine_grained_access_handler_.Serialize();
|
||||||
|
data["databases"] = database_access_.Serialize();
|
||||||
} else {
|
} else {
|
||||||
data["fine_grained_access_handler"] = {};
|
data["fine_grained_access_handler"] = {};
|
||||||
|
data["databases"] = {};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
// The role shouldn't be serialized here, it is stored as a foreign key.
|
// The role shouldn't be serialized here, it is stored as a foreign key.
|
||||||
@@ -594,11 +693,21 @@ User User::Deserialize(const nlohmann::json &data) {
|
|||||||
auto permissions = Permissions::Deserialize(data["permissions"]);
|
auto permissions = Permissions::Deserialize(data["permissions"]);
|
||||||
#ifdef MG_ENTERPRISE
|
#ifdef MG_ENTERPRISE
|
||||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||||
if (!data["fine_grained_access_handler"].is_object()) {
|
Databases db_access;
|
||||||
throw AuthException("Couldn't load user data!");
|
if (data["databases"].is_structured()) {
|
||||||
|
db_access = Databases::Deserialize(data["databases"]);
|
||||||
|
} else {
|
||||||
|
// Back-compatibility
|
||||||
|
spdlog::warn("User without specified database access. Given access to the default database.");
|
||||||
|
db_access.Add(dbms::kDefaultDB);
|
||||||
|
db_access.SetDefault(dbms::kDefaultDB);
|
||||||
}
|
}
|
||||||
auto fine_grained_access_handler = FineGrainedAccessHandler::Deserialize(data["fine_grained_access_handler"]);
|
FineGrainedAccessHandler fine_grained_access_handler;
|
||||||
return {data["username"], data["password_hash"], permissions, fine_grained_access_handler};
|
// We can have an empty fine_grained if the user was created without a valid license
|
||||||
|
if (data["fine_grained_access_handler"].is_object()) {
|
||||||
|
fine_grained_access_handler = FineGrainedAccessHandler::Deserialize(data["fine_grained_access_handler"]);
|
||||||
|
}
|
||||||
|
return {data["username"], data["password_hash"], permissions, std::move(fine_grained_access_handler), db_access};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return {data["username"], data["password_hash"], permissions};
|
return {data["username"], data["password_hash"], permissions};
|
||||||
|
|||||||
@@ -9,10 +9,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <json/json.hpp>
|
#include <json/json.hpp>
|
||||||
|
#include "dbms/constants.hpp"
|
||||||
|
#include "utils/logging.hpp"
|
||||||
|
|
||||||
namespace memgraph::auth {
|
namespace memgraph::auth {
|
||||||
// These permissions must have values that are applicable for usage in a
|
// These permissions must have values that are applicable for usage in a
|
||||||
@@ -41,7 +44,9 @@ enum class Permission : uint64_t {
|
|||||||
MODULE_WRITE = 1U << 19U,
|
MODULE_WRITE = 1U << 19U,
|
||||||
WEBSOCKET = 1U << 20U,
|
WEBSOCKET = 1U << 20U,
|
||||||
TRANSACTION_MANAGEMENT = 1U << 21U,
|
TRANSACTION_MANAGEMENT = 1U << 21U,
|
||||||
STORAGE_MODE = 1U << 22U
|
STORAGE_MODE = 1U << 22U,
|
||||||
|
MULTI_DATABASE_EDIT = 1U << 23U,
|
||||||
|
MULTI_DATABASE_USE = 1U << 24U,
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
@@ -237,6 +242,85 @@ class Role final {
|
|||||||
|
|
||||||
bool operator==(const Role &first, const Role &second);
|
bool operator==(const Role &first, const Role &second);
|
||||||
|
|
||||||
|
#ifdef MG_ENTERPRISE
|
||||||
|
class Databases final {
|
||||||
|
public:
|
||||||
|
Databases() : grants_dbs_({dbms::kDefaultDB}), allow_all_(false), default_db_(dbms::kDefaultDB) {}
|
||||||
|
|
||||||
|
Databases(const Databases &) = default;
|
||||||
|
Databases &operator=(const Databases &) = default;
|
||||||
|
Databases(Databases &&) noexcept = default;
|
||||||
|
Databases &operator=(Databases &&) noexcept = default;
|
||||||
|
~Databases() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add database to the list of granted access. @note allow_all_ will be false after execution
|
||||||
|
*
|
||||||
|
* @param db name of the database to grant access to
|
||||||
|
*/
|
||||||
|
void Add(const std::string &db);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Remove database to the list of granted access.
|
||||||
|
* @note if allow_all_ is set, the flag will remain set and the
|
||||||
|
* database will be added to the set of denied databases.
|
||||||
|
*
|
||||||
|
* @param db name of the database to grant access to
|
||||||
|
*/
|
||||||
|
void Remove(const std::string &db);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Called when database is dropped. Removes it from granted (if allow_all is false) and denied set.
|
||||||
|
* @note allow_all_ is not changed
|
||||||
|
*
|
||||||
|
* @param db name of the database to grant access to
|
||||||
|
*/
|
||||||
|
void Delete(const std::string &db);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set allow_all_ to true and clears grants and denied sets.
|
||||||
|
*/
|
||||||
|
void GrantAll();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set allow_all_ to false and clears grants and denied sets.
|
||||||
|
*/
|
||||||
|
void DenyAll();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the default database.
|
||||||
|
*/
|
||||||
|
bool SetDefault(const std::string &db);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if access is grated to the database.
|
||||||
|
*
|
||||||
|
* @param db name of the database
|
||||||
|
* @return true if allow_all and not denied or granted
|
||||||
|
*/
|
||||||
|
bool Contains(const std::string &db) const;
|
||||||
|
|
||||||
|
bool GetAllowAll() const { return allow_all_; }
|
||||||
|
const std::set<std::string> &GetGrants() const { return grants_dbs_; }
|
||||||
|
const std::set<std::string> &GetDenies() const { return denies_dbs_; }
|
||||||
|
const std::string &GetDefault() const;
|
||||||
|
|
||||||
|
nlohmann::json Serialize() const;
|
||||||
|
/// @throw AuthException if unable to deserialize.
|
||||||
|
static Databases Deserialize(const nlohmann::json &data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Databases(bool allow_all, std::set<std::string> grant, std::set<std::string> deny,
|
||||||
|
const std::string &default_db = dbms::kDefaultDB)
|
||||||
|
: grants_dbs_(grant), denies_dbs_(deny), allow_all_(allow_all), default_db_(default_db) {}
|
||||||
|
|
||||||
|
std::set<std::string> grants_dbs_; //!< set of databases with granted access
|
||||||
|
std::set<std::string> denies_dbs_; //!< set of databases with denied access
|
||||||
|
bool allow_all_; //!< flag to allow access to everything (denied overrides this)
|
||||||
|
std::string default_db_; //!< user's default database
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
// TODO (mferencevic): Implement password expiry.
|
// TODO (mferencevic): Implement password expiry.
|
||||||
class User final {
|
class User final {
|
||||||
public:
|
public:
|
||||||
@@ -246,7 +330,7 @@ class User final {
|
|||||||
User(const std::string &username, const std::string &password_hash, const Permissions &permissions);
|
User(const std::string &username, const std::string &password_hash, const Permissions &permissions);
|
||||||
#ifdef MG_ENTERPRISE
|
#ifdef MG_ENTERPRISE
|
||||||
User(const std::string &username, const std::string &password_hash, const Permissions &permissions,
|
User(const std::string &username, const std::string &password_hash, const Permissions &permissions,
|
||||||
FineGrainedAccessHandler fine_grained_access_handler);
|
FineGrainedAccessHandler fine_grained_access_handler, Databases db_access = {});
|
||||||
#endif
|
#endif
|
||||||
User(const User &) = default;
|
User(const User &) = default;
|
||||||
User &operator=(const User &) = default;
|
User &operator=(const User &) = default;
|
||||||
@@ -279,6 +363,11 @@ class User final {
|
|||||||
|
|
||||||
const Role *role() const;
|
const Role *role() const;
|
||||||
|
|
||||||
|
#ifdef MG_ENTERPRISE
|
||||||
|
Databases &db_access() { return database_access_; }
|
||||||
|
const Databases &db_access() const { return database_access_; }
|
||||||
|
#endif
|
||||||
|
|
||||||
nlohmann::json Serialize() const;
|
nlohmann::json Serialize() const;
|
||||||
|
|
||||||
/// @throw AuthException if unable to deserialize.
|
/// @throw AuthException if unable to deserialize.
|
||||||
@@ -292,6 +381,7 @@ class User final {
|
|||||||
Permissions permissions_;
|
Permissions permissions_;
|
||||||
#ifdef MG_ENTERPRISE
|
#ifdef MG_ENTERPRISE
|
||||||
FineGrainedAccessHandler fine_grained_access_handler_;
|
FineGrainedAccessHandler fine_grained_access_handler_;
|
||||||
|
Databases database_access_;
|
||||||
#endif
|
#endif
|
||||||
std::optional<Role> role_;
|
std::optional<Role> role_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,3 +22,4 @@ target_link_libraries(mg-communication Boost::headers Threads::Threads mg-utils
|
|||||||
find_package(OpenSSL REQUIRED)
|
find_package(OpenSSL REQUIRED)
|
||||||
target_link_libraries(mg-communication ${OPENSSL_LIBRARIES})
|
target_link_libraries(mg-communication ${OPENSSL_LIBRARIES})
|
||||||
target_include_directories(mg-communication SYSTEM PUBLIC ${OPENSSL_INCLUDE_DIR})
|
target_include_directories(mg-communication SYSTEM PUBLIC ${OPENSSL_INCLUDE_DIR})
|
||||||
|
target_precompile_headers(mg-communication INTERFACE http/server.hpp <boost/beast/websocket.hpp> bolt/v1/session.hpp)
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ inline constexpr uint8_t kPreamble[4] = {0x60, 0x60, 0xB0, 0x17};
|
|||||||
|
|
||||||
enum class Signature : uint8_t {
|
enum class Signature : uint8_t {
|
||||||
Noop = 0x00,
|
Noop = 0x00,
|
||||||
Init = 0x01,
|
Init = 0x01, // v3+ now HELLO
|
||||||
LogOn = 0x6A,
|
LogOn = 0x6A,
|
||||||
LogOff = 0x6B,
|
LogOff = 0x6B,
|
||||||
AckFailure = 0x0E, // only v1
|
AckFailure = 0x0E, // only v1
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <concepts>
|
||||||
|
#include <cstddef>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
@@ -24,8 +26,12 @@
|
|||||||
#include "communication/bolt/v1/states/executing.hpp"
|
#include "communication/bolt/v1/states/executing.hpp"
|
||||||
#include "communication/bolt/v1/states/handshake.hpp"
|
#include "communication/bolt/v1/states/handshake.hpp"
|
||||||
#include "communication/bolt/v1/states/init.hpp"
|
#include "communication/bolt/v1/states/init.hpp"
|
||||||
|
#include "communication/bolt/v1/value.hpp"
|
||||||
|
#include "dbms/constants.hpp"
|
||||||
|
#include "dbms/global.hpp"
|
||||||
#include "utils/exceptions.hpp"
|
#include "utils/exceptions.hpp"
|
||||||
#include "utils/logging.hpp"
|
#include "utils/logging.hpp"
|
||||||
|
#include "utils/uuid.hpp"
|
||||||
|
|
||||||
namespace memgraph::communication::bolt {
|
namespace memgraph::communication::bolt {
|
||||||
|
|
||||||
@@ -48,14 +54,26 @@ class SessionException : public utils::BasicException {
|
|||||||
* @tparam TOutputStream type of output stream that will be used
|
* @tparam TOutputStream type of output stream that will be used
|
||||||
*/
|
*/
|
||||||
template <typename TInputStream, typename TOutputStream>
|
template <typename TInputStream, typename TOutputStream>
|
||||||
class Session {
|
class Session : public dbms::SessionInterface {
|
||||||
public:
|
public:
|
||||||
using TEncoder = Encoder<ChunkedEncoderBuffer<TOutputStream>>;
|
using TEncoder = Encoder<ChunkedEncoderBuffer<TOutputStream>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Session object
|
||||||
|
*
|
||||||
|
* @param input_stream stream to read from
|
||||||
|
* @param output_stream stream to write to
|
||||||
|
* @param impl a default high-level implementation to use (has to be defined)
|
||||||
|
*/
|
||||||
Session(TInputStream *input_stream, TOutputStream *output_stream)
|
Session(TInputStream *input_stream, TOutputStream *output_stream)
|
||||||
: input_stream_(*input_stream), output_stream_(*output_stream) {}
|
: input_stream_(*input_stream), output_stream_(*output_stream), session_uuid_(utils::GenerateUUID()) {}
|
||||||
|
|
||||||
virtual ~Session() {}
|
virtual ~Session() = default;
|
||||||
|
|
||||||
|
Session(const Session &) = delete;
|
||||||
|
Session &operator=(const Session &) = delete;
|
||||||
|
Session(Session &&) noexcept = delete;
|
||||||
|
Session &operator=(Session &&) noexcept = delete;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process the given `query` with `params`.
|
* Process the given `query` with `params`.
|
||||||
@@ -64,7 +82,9 @@ class Session {
|
|||||||
*/
|
*/
|
||||||
virtual std::pair<std::vector<std::string>, std::optional<int>> Interpret(
|
virtual std::pair<std::vector<std::string>, std::optional<int>> Interpret(
|
||||||
const std::string &query, const std::map<std::string, Value> ¶ms,
|
const std::string &query, const std::map<std::string, Value> ¶ms,
|
||||||
const std::map<std::string, memgraph::communication::bolt::Value> &metadata) = 0;
|
const std::map<std::string, memgraph::communication::bolt::Value> &extra) = 0;
|
||||||
|
|
||||||
|
virtual void Configure(const std::map<std::string, memgraph::communication::bolt::Value> &run_time_info) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Put results of the processed query in the `encoder`.
|
* Put results of the processed query in the `encoder`.
|
||||||
@@ -86,7 +106,7 @@ class Session {
|
|||||||
*/
|
*/
|
||||||
virtual std::map<std::string, Value> Discard(std::optional<int> n, std::optional<int> qid) = 0;
|
virtual std::map<std::string, Value> Discard(std::optional<int> n, std::optional<int> qid) = 0;
|
||||||
|
|
||||||
virtual void BeginTransaction(const std::map<std::string, memgraph::communication::bolt::Value> &) = 0;
|
virtual void BeginTransaction(const std::map<std::string, memgraph::communication::bolt::Value> ¶ms) = 0;
|
||||||
virtual void CommitTransaction() = 0;
|
virtual void CommitTransaction() = 0;
|
||||||
virtual void RollbackTransaction() = 0;
|
virtual void RollbackTransaction() = 0;
|
||||||
|
|
||||||
@@ -99,7 +119,6 @@ class Session {
|
|||||||
/** Return the name of the server that should be used for the Bolt INIT
|
/** Return the name of the server that should be used for the Bolt INIT
|
||||||
* message. */
|
* message. */
|
||||||
virtual std::optional<std::string> GetServerNameForInit() = 0;
|
virtual std::optional<std::string> GetServerNameForInit() = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the session after data has been read into the buffer.
|
* Executes the session after data has been read into the buffer.
|
||||||
* Goes through the bolt states in order to execute commands from the client.
|
* Goes through the bolt states in order to execute commands from the client.
|
||||||
@@ -140,6 +159,7 @@ class Session {
|
|||||||
break;
|
break;
|
||||||
case State::Idle:
|
case State::Idle:
|
||||||
case State::Result:
|
case State::Result:
|
||||||
|
at_least_one_run_ = true;
|
||||||
state_ = StateExecutingRun(*this, state_);
|
state_ = StateExecutingRun(*this, state_);
|
||||||
break;
|
break;
|
||||||
case State::Error:
|
case State::Error:
|
||||||
@@ -161,8 +181,13 @@ class Session {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Rethink if there is a way to hide some members. At the momement all
|
void HandleError() {
|
||||||
// of them are public.
|
if (!at_least_one_run_) {
|
||||||
|
spdlog::info("Sudden connection loss. Make sure the client supports Memgraph.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Rethink if there is a way to hide some members. At the momement all of them are public.
|
||||||
TInputStream &input_stream_;
|
TInputStream &input_stream_;
|
||||||
TOutputStream &output_stream_;
|
TOutputStream &output_stream_;
|
||||||
|
|
||||||
@@ -174,6 +199,7 @@ class Session {
|
|||||||
|
|
||||||
bool handshake_done_{false};
|
bool handshake_done_{false};
|
||||||
State state_{State::Handshake};
|
State state_{State::Handshake};
|
||||||
|
bool at_least_one_run_{false};
|
||||||
|
|
||||||
struct Version {
|
struct Version {
|
||||||
uint8_t major;
|
uint8_t major;
|
||||||
@@ -182,6 +208,9 @@ class Session {
|
|||||||
|
|
||||||
Version version_;
|
Version version_;
|
||||||
|
|
||||||
|
std::string GetDatabaseName() const override = 0;
|
||||||
|
std::string UUID() const final { return session_uuid_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ClientFailureInvalidData() {
|
void ClientFailureInvalidData() {
|
||||||
// Set the state to Close.
|
// Set the state to Close.
|
||||||
@@ -197,6 +226,8 @@ class Session {
|
|||||||
// of the session to trigger session cleanup and socket close.
|
// of the session to trigger session cleanup and socket close.
|
||||||
throw SessionException("Something went wrong during session execution!");
|
throw SessionException("Something went wrong during session execution!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string session_uuid_; //!< unique identifier of the session (auto generated)
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace memgraph::communication::bolt
|
} // namespace memgraph::communication::bolt
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ State StateExecutingRun(TSession &session, State state) {
|
|||||||
return RunHandlerV4<TSession>(signature, session, state, marker);
|
return RunHandlerV4<TSession>(signature, session, state, marker);
|
||||||
}
|
}
|
||||||
case 5:
|
case 5:
|
||||||
|
memgraph::metrics::IncrementCounter(memgraph::metrics::BoltMessages);
|
||||||
return RunHandlerV5<TSession>(signature, session, state, marker);
|
return RunHandlerV5<TSession>(signature, session, state, marker);
|
||||||
default:
|
default:
|
||||||
spdlog::trace("Unsupported bolt version:{}.{})!", session.version_.major, session.version_.minor);
|
spdlog::trace("Unsupported bolt version:{}.{})!", session.version_.major, session.version_.minor);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -73,23 +74,6 @@ inline std::pair<std::string, std::string> ExceptionToErrorMessage(const std::ex
|
|||||||
"should be in database logs."};
|
"should be in database logs."};
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace helpers {
|
|
||||||
|
|
||||||
/** 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 {
|
namespace details {
|
||||||
|
|
||||||
template <bool is_pull, typename TSession>
|
template <bool is_pull, typename TSession>
|
||||||
@@ -224,7 +208,7 @@ State HandleRunV1(TSession &session, const State state, const Marker marker) {
|
|||||||
|
|
||||||
DMG_ASSERT(!session.encoder_buffer_.HasData(), "There should be no data to write in this state");
|
DMG_ASSERT(!session.encoder_buffer_.HasData(), "There should be no data to write in this state");
|
||||||
|
|
||||||
spdlog::debug("[Run] '{}'", query.ValueString());
|
spdlog::debug("[Run - {}] '{}'", session.GetDatabaseName(), query.ValueString());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Interpret can throw.
|
// Interpret can throw.
|
||||||
@@ -282,12 +266,17 @@ State HandleRunV4(TSession &session, const State state, const Marker marker) {
|
|||||||
|
|
||||||
DMG_ASSERT(!session.encoder_buffer_.HasData(), "There should be no data to write in this state");
|
DMG_ASSERT(!session.encoder_buffer_.HasData(), "There should be no data to write in this state");
|
||||||
|
|
||||||
spdlog::debug("[Run] '{}'", query.ValueString());
|
try {
|
||||||
|
session.Configure(extra.ValueMap());
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
return HandleFailure(session, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
spdlog::debug("[Run - {}] '{}'", session.GetDatabaseName(), query.ValueString());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Interpret can throw.
|
// Interpret can throw.
|
||||||
const auto [header, qid] =
|
const auto [header, qid] = session.Interpret(query.ValueString(), params.ValueMap(), extra.ValueMap());
|
||||||
session.Interpret(query.ValueString(), params.ValueMap(), helpers::ConsumeMetadata(extra));
|
|
||||||
// Convert std::string to Value
|
// Convert std::string to Value
|
||||||
std::vector<Value> vec;
|
std::vector<Value> vec;
|
||||||
std::map<std::string, Value> data;
|
std::map<std::string, Value> data;
|
||||||
@@ -399,7 +388,8 @@ State HandleBegin(TSession &session, const State state, const Marker marker) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
session.BeginTransaction(helpers::ConsumeMetadata(extra));
|
session.Configure(extra.ValueMap());
|
||||||
|
session.BeginTransaction(extra.ValueMap());
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
return HandleFailure(session, e);
|
return HandleFailure(session, e);
|
||||||
}
|
}
|
||||||
@@ -507,7 +497,7 @@ State HandleRoute(TSession &session, const Marker marker) {
|
|||||||
|
|
||||||
template <typename TSession>
|
template <typename TSession>
|
||||||
State HandleLogOff() {
|
State HandleLogOff() {
|
||||||
// Not arguments sent, the user just needs to reauthenticate
|
// No arguments sent, the user just needs to reauthenticate
|
||||||
return State::Init;
|
return State::Init;
|
||||||
}
|
}
|
||||||
} // namespace memgraph::communication::bolt
|
} // namespace memgraph::communication::bolt
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "communication/bolt/v1/state.hpp"
|
#include "communication/bolt/v1/state.hpp"
|
||||||
#include "communication/bolt/v1/value.hpp"
|
#include "communication/bolt/v1/value.hpp"
|
||||||
#include "communication/exceptions.hpp"
|
#include "communication/exceptions.hpp"
|
||||||
|
#include "spdlog/spdlog.h"
|
||||||
#include "utils/likely.hpp"
|
#include "utils/likely.hpp"
|
||||||
#include "utils/logging.hpp"
|
#include "utils/logging.hpp"
|
||||||
|
|
||||||
@@ -173,7 +174,7 @@ State SendSuccessMessage(TSession &session) {
|
|||||||
// we send a hardcoded value for now.
|
// we send a hardcoded value for now.
|
||||||
std::map<std::string, Value> metadata{{"connection_id", "bolt-1"}};
|
std::map<std::string, Value> metadata{{"connection_id", "bolt-1"}};
|
||||||
if (auto server_name = session.GetServerNameForInit(); server_name) {
|
if (auto server_name = session.GetServerNameForInit(); server_name) {
|
||||||
metadata.insert({"server", *server_name});
|
metadata.insert({"server", std::move(*server_name)});
|
||||||
}
|
}
|
||||||
bool success_sent = session.encoder_.MessageSuccess(metadata);
|
bool success_sent = session.encoder_.MessageSuccess(metadata);
|
||||||
if (!success_sent) {
|
if (!success_sent) {
|
||||||
@@ -248,8 +249,9 @@ State StateInitRunV5(TSession &session, Marker marker, Signature signature) {
|
|||||||
}
|
}
|
||||||
// Stay in Init
|
// Stay in Init
|
||||||
return State::Init;
|
return State::Init;
|
||||||
|
}
|
||||||
|
|
||||||
} else if (signature == Signature::LogOn) {
|
if (signature == Signature::LogOn) {
|
||||||
if (marker != Marker::TinyStruct1) [[unlikely]] {
|
if (marker != Marker::TinyStruct1) [[unlikely]] {
|
||||||
spdlog::trace("Expected TinyStruct1 marker, but received 0x{:02X}!", utils::UnderlyingCast(marker));
|
spdlog::trace("Expected TinyStruct1 marker, but received 0x{:02X}!", utils::UnderlyingCast(marker));
|
||||||
spdlog::trace(
|
spdlog::trace(
|
||||||
@@ -273,11 +275,10 @@ State StateInitRunV5(TSession &session, Marker marker, Signature signature) {
|
|||||||
return State::Close;
|
return State::Close;
|
||||||
}
|
}
|
||||||
return State::Idle;
|
return State::Idle;
|
||||||
|
|
||||||
} else [[unlikely]] {
|
|
||||||
spdlog::trace("Expected Init signature, but received 0x{:02X}!", utils::UnderlyingCast(signature));
|
|
||||||
return State::Close;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spdlog::trace("Expected Init signature, but received 0x{:02X}!", utils::UnderlyingCast(signature));
|
||||||
|
return State::Close;
|
||||||
}
|
}
|
||||||
} // namespace details
|
} // namespace details
|
||||||
|
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ struct Path {
|
|||||||
for (uint i = 0; i < edges.size(); i++) {
|
for (uint i = 0; i < edges.size(); i++) {
|
||||||
const auto &e = edges[i];
|
const auto &e = edges[i];
|
||||||
const auto &v = vertices[i + 1];
|
const auto &v = vertices[i + 1];
|
||||||
UnboundedEdge unbounded_edge{e.id, e.type, e.properties};
|
UnboundedEdge unbounded_edge{e.id, e.type, e.properties, e.element_id};
|
||||||
add_element(this->edges, unbounded_edge, e.to == v.id ? 1 : -1, 1);
|
add_element(this->edges, unbounded_edge, e.to == v.id ? 1 : -1, 1);
|
||||||
add_element(this->vertices, v, 1, 0);
|
add_element(this->vertices, v, 1, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -43,6 +43,7 @@ class Buffer final {
|
|||||||
Buffer(Buffer &&) = delete;
|
Buffer(Buffer &&) = delete;
|
||||||
Buffer &operator=(const Buffer &) = delete;
|
Buffer &operator=(const Buffer &) = delete;
|
||||||
Buffer &operator=(Buffer &&) = delete;
|
Buffer &operator=(Buffer &&) = delete;
|
||||||
|
~Buffer() = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides all functions from the buffer that are needed to allow
|
* This class provides all functions from the buffer that are needed to allow
|
||||||
@@ -50,12 +51,13 @@ class Buffer final {
|
|||||||
*/
|
*/
|
||||||
class ReadEnd {
|
class ReadEnd {
|
||||||
public:
|
public:
|
||||||
ReadEnd(Buffer *buffer);
|
explicit ReadEnd(Buffer *buffer);
|
||||||
|
|
||||||
ReadEnd(const ReadEnd &) = delete;
|
ReadEnd(const ReadEnd &) = delete;
|
||||||
ReadEnd(ReadEnd &&) = delete;
|
ReadEnd(ReadEnd &&) = delete;
|
||||||
ReadEnd &operator=(const ReadEnd &) = delete;
|
ReadEnd &operator=(const ReadEnd &) = delete;
|
||||||
ReadEnd &operator=(ReadEnd &&) = delete;
|
ReadEnd &operator=(ReadEnd &&) = delete;
|
||||||
|
~ReadEnd() = default;
|
||||||
|
|
||||||
uint8_t *data();
|
uint8_t *data();
|
||||||
|
|
||||||
@@ -77,12 +79,13 @@ class Buffer final {
|
|||||||
*/
|
*/
|
||||||
class WriteEnd {
|
class WriteEnd {
|
||||||
public:
|
public:
|
||||||
WriteEnd(Buffer *buffer);
|
explicit WriteEnd(Buffer *buffer);
|
||||||
|
|
||||||
WriteEnd(const WriteEnd &) = delete;
|
WriteEnd(const WriteEnd &) = delete;
|
||||||
WriteEnd(WriteEnd &&) = delete;
|
WriteEnd(WriteEnd &&) = delete;
|
||||||
WriteEnd &operator=(const WriteEnd &) = delete;
|
WriteEnd &operator=(const WriteEnd &) = delete;
|
||||||
WriteEnd &operator=(WriteEnd &&) = delete;
|
WriteEnd &operator=(WriteEnd &&) = delete;
|
||||||
|
~WriteEnd() = default;
|
||||||
|
|
||||||
io::network::StreamBuffer Allocate();
|
io::network::StreamBuffer Allocate();
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -15,6 +15,10 @@
|
|||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
|
|
||||||
|
// Centos 7 OpenSSL includes libkrb5 which has brings in macros TRUE and FALSE. undef to prevent issues.
|
||||||
|
#undef TRUE
|
||||||
|
#undef FALSE
|
||||||
|
|
||||||
#include "communication/buffer.hpp"
|
#include "communication/buffer.hpp"
|
||||||
#include "communication/context.hpp"
|
#include "communication/context.hpp"
|
||||||
#include "communication/init.hpp"
|
#include "communication/init.hpp"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -17,6 +17,10 @@
|
|||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#include <boost/asio/ssl/context.hpp>
|
#include <boost/asio/ssl/context.hpp>
|
||||||
|
|
||||||
|
// Centos 7 OpenSSL includes libkrb5 which has brings in macros TRUE and FALSE. undef to prevent issues.
|
||||||
|
#undef TRUE
|
||||||
|
#undef FALSE
|
||||||
|
|
||||||
namespace memgraph::communication {
|
namespace memgraph::communication {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -27,11 +27,11 @@
|
|||||||
|
|
||||||
namespace memgraph::communication::http {
|
namespace memgraph::communication::http {
|
||||||
|
|
||||||
template <class TRequestHandler, typename TSessionData>
|
template <class TRequestHandler, typename TSessionContext>
|
||||||
class Listener final : public std::enable_shared_from_this<Listener<TRequestHandler, TSessionData>> {
|
class Listener final : public std::enable_shared_from_this<Listener<TRequestHandler, TSessionContext>> {
|
||||||
using tcp = boost::asio::ip::tcp;
|
using tcp = boost::asio::ip::tcp;
|
||||||
using SessionHandler = Session<TRequestHandler, TSessionData>;
|
using SessionHandler = Session<TRequestHandler, TSessionContext>;
|
||||||
using std::enable_shared_from_this<Listener<TRequestHandler, TSessionData>>::shared_from_this;
|
using std::enable_shared_from_this<Listener<TRequestHandler, TSessionContext>>::shared_from_this;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Listener(const Listener &) = delete;
|
Listener(const Listener &) = delete;
|
||||||
@@ -50,8 +50,9 @@ class Listener final : public std::enable_shared_from_this<Listener<TRequestHand
|
|||||||
tcp::endpoint GetEndpoint() const { return acceptor_.local_endpoint(); }
|
tcp::endpoint GetEndpoint() const { return acceptor_.local_endpoint(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Listener(boost::asio::io_context &ioc, TSessionData *data, ServerContext *context, tcp::endpoint endpoint)
|
Listener(boost::asio::io_context &ioc, TSessionContext *session_context, ServerContext *context,
|
||||||
: ioc_(ioc), data_(data), context_(context), acceptor_(ioc) {
|
tcp::endpoint endpoint)
|
||||||
|
: ioc_(ioc), session_context_(session_context), context_(context), acceptor_(ioc) {
|
||||||
boost::beast::error_code ec;
|
boost::beast::error_code ec;
|
||||||
|
|
||||||
// Open the acceptor
|
// Open the acceptor
|
||||||
@@ -95,13 +96,13 @@ class Listener final : public std::enable_shared_from_this<Listener<TRequestHand
|
|||||||
return LogError(ec, "accept");
|
return LogError(ec, "accept");
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionHandler::Create(std::move(socket), data_, *context_)->Run();
|
SessionHandler::Create(std::move(socket), session_context_, *context_)->Run();
|
||||||
|
|
||||||
DoAccept();
|
DoAccept();
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::asio::io_context &ioc_;
|
boost::asio::io_context &ioc_;
|
||||||
TSessionData *data_;
|
TSessionContext *session_context_;
|
||||||
ServerContext *context_;
|
ServerContext *context_;
|
||||||
tcp::acceptor acceptor_;
|
tcp::acceptor acceptor_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,14 +21,12 @@
|
|||||||
|
|
||||||
namespace memgraph::communication::http {
|
namespace memgraph::communication::http {
|
||||||
|
|
||||||
template <class TRequestHandler, typename TSessionData>
|
template <class TRequestHandler, typename TSessionContext>
|
||||||
class Server final {
|
class Server final {
|
||||||
using tcp = boost::asio::ip::tcp;
|
using tcp = boost::asio::ip::tcp;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Server(io::network::Endpoint endpoint, TSessionData *data, ServerContext *context)
|
explicit Server(io::network::Endpoint endpoint, TSessionContext *session_context, 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(const Server &) = delete;
|
||||||
Server(Server &&) = delete;
|
Server(Server &&) = delete;
|
||||||
@@ -40,11 +38,7 @@ class Server final {
|
|||||||
"Server wasn't shutdown properly");
|
"Server wasn't shutdown properly");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Start() {
|
void Start();
|
||||||
MG_ASSERT(!background_thread_, "The server was already started!");
|
|
||||||
listener_->Run();
|
|
||||||
background_thread_.emplace([this] { ioc_.run(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void Shutdown() { ioc_.stop(); }
|
void Shutdown() { ioc_.stop(); }
|
||||||
|
|
||||||
@@ -54,12 +48,30 @@ class Server final {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool IsRunning() const { return background_thread_ && !ioc_.stopped(); }
|
bool IsRunning() const { return background_thread_ && !ioc_.stopped(); }
|
||||||
tcp::endpoint GetEndpoint() const { return listener_->GetEndpoint(); }
|
tcp::endpoint GetEndpoint() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
boost::asio::io_context ioc_;
|
boost::asio::io_context ioc_;
|
||||||
|
|
||||||
std::shared_ptr<Listener<TRequestHandler, TSessionData>> listener_;
|
std::shared_ptr<Listener<TRequestHandler, TSessionContext>> listener_;
|
||||||
std::optional<std::thread> background_thread_;
|
std::optional<std::thread> background_thread_;
|
||||||
};
|
};
|
||||||
|
template <class TRequestHandler, typename TSessionContext>
|
||||||
|
Server<TRequestHandler, TSessionContext>::Server(io::network::Endpoint endpoint, TSessionContext *session_context,
|
||||||
|
ServerContext *context)
|
||||||
|
: listener_{Listener<TRequestHandler, TSessionContext>::Create(
|
||||||
|
ioc_, session_context, context,
|
||||||
|
tcp::endpoint{boost::asio::ip::make_address(endpoint.address), endpoint.port})} {}
|
||||||
|
|
||||||
|
template <class TRequestHandler, typename TSessionContext>
|
||||||
|
void Server<TRequestHandler, TSessionContext>::Start() {
|
||||||
|
MG_ASSERT(!background_thread_, "The server was already started!");
|
||||||
|
listener_->Run();
|
||||||
|
background_thread_.emplace([this] { ioc_.run(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class TRequestHandler, typename TSessionContext>
|
||||||
|
boost::asio::ip::tcp::endpoint Server<TRequestHandler, TSessionContext>::GetEndpoint() const {
|
||||||
|
return listener_->GetEndpoint();
|
||||||
|
}
|
||||||
} // namespace memgraph::communication::http
|
} // namespace memgraph::communication::http
|
||||||
|
|||||||
@@ -42,10 +42,10 @@ inline void LogError(boost::beast::error_code ec, const std::string_view what) {
|
|||||||
spdlog::warn("HTTP session failed on {}: {}", what, ec.message());
|
spdlog::warn("HTTP session failed on {}: {}", what, ec.message());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class TRequestHandler, typename TSessionData>
|
template <class TRequestHandler, typename TSessionContext>
|
||||||
class Session : public std::enable_shared_from_this<Session<TRequestHandler, TSessionData>> {
|
class Session : public std::enable_shared_from_this<Session<TRequestHandler, TSessionContext>> {
|
||||||
using tcp = boost::asio::ip::tcp;
|
using tcp = boost::asio::ip::tcp;
|
||||||
using std::enable_shared_from_this<Session<TRequestHandler, TSessionData>>::shared_from_this;
|
using std::enable_shared_from_this<Session<TRequestHandler, TSessionContext>>::shared_from_this;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
@@ -72,7 +72,7 @@ class Session : public std::enable_shared_from_this<Session<TRequestHandler, TSe
|
|||||||
using PlainSocket = boost::beast::tcp_stream;
|
using PlainSocket = boost::beast::tcp_stream;
|
||||||
using SSLSocket = boost::beast::ssl_stream<boost::beast::tcp_stream>;
|
using SSLSocket = boost::beast::ssl_stream<boost::beast::tcp_stream>;
|
||||||
|
|
||||||
explicit Session(tcp::socket &&socket, TSessionData *data, ServerContext &context)
|
explicit Session(tcp::socket &&socket, TSessionContext *data, ServerContext &context)
|
||||||
: stream_(CreateSocket(std::move(socket), context)),
|
: stream_(CreateSocket(std::move(socket), context)),
|
||||||
handler_(data),
|
handler_(data),
|
||||||
strand_{boost::asio::make_strand(GetExecutor())} {}
|
strand_{boost::asio::make_strand(GetExecutor())} {}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -39,7 +39,7 @@ namespace memgraph::communication {
|
|||||||
* second, checks all sessions for expiration and shuts them down if they have
|
* second, checks all sessions for expiration and shuts them down if they have
|
||||||
* expired.
|
* expired.
|
||||||
*/
|
*/
|
||||||
template <class TSession, class TSessionData>
|
template <class TSession, class TSessionContext>
|
||||||
class Listener final {
|
class Listener final {
|
||||||
private:
|
private:
|
||||||
// The maximum number of events handled per execution thread is 1. This is
|
// The maximum number of events handled per execution thread is 1. This is
|
||||||
@@ -48,10 +48,10 @@ class Listener final {
|
|||||||
// can take a long time.
|
// can take a long time.
|
||||||
static const int kMaxEvents = 1;
|
static const int kMaxEvents = 1;
|
||||||
|
|
||||||
using SessionHandler = Session<TSession, TSessionData>;
|
using SessionHandler = Session<TSession, TSessionContext>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Listener(TSessionData *data, ServerContext *context, int inactivity_timeout_sec, const std::string &service_name,
|
Listener(TSessionContext *data, ServerContext *context, int inactivity_timeout_sec, const std::string &service_name,
|
||||||
size_t workers_count)
|
size_t workers_count)
|
||||||
: data_(data),
|
: data_(data),
|
||||||
alive_(false),
|
alive_(false),
|
||||||
@@ -259,7 +259,7 @@ class Listener final {
|
|||||||
|
|
||||||
io::network::Epoll epoll_;
|
io::network::Epoll epoll_;
|
||||||
|
|
||||||
TSessionData *data_;
|
TSessionContext *data_;
|
||||||
|
|
||||||
utils::SpinLock lock_;
|
utils::SpinLock lock_;
|
||||||
std::vector<std::unique_ptr<SessionHandler>> sessions_;
|
std::vector<std::unique_ptr<SessionHandler>> sessions_;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -46,10 +46,10 @@ namespace memgraph::communication {
|
|||||||
* @tparam TSession the server can handle different Sessions, each session
|
* @tparam TSession the server can handle different Sessions, each session
|
||||||
* represents a different protocol so the same network infrastructure
|
* represents a different protocol so the same network infrastructure
|
||||||
* can be used for handling different protocols
|
* can be used for handling different protocols
|
||||||
* @tparam TSessionData the class with objects that will be forwarded to the
|
* @tparam TSessionContext the class with objects that will be forwarded to the
|
||||||
* session
|
* session
|
||||||
*/
|
*/
|
||||||
template <typename TSession, typename TSessionData>
|
template <typename TSession, typename TSessionContext>
|
||||||
class Server final {
|
class Server final {
|
||||||
public:
|
public:
|
||||||
using Socket = io::network::Socket;
|
using Socket = io::network::Socket;
|
||||||
@@ -58,12 +58,12 @@ class Server final {
|
|||||||
* Constructs and binds server to endpoint, operates on session data and
|
* Constructs and binds server to endpoint, operates on session data and
|
||||||
* invokes workers_count workers
|
* invokes workers_count workers
|
||||||
*/
|
*/
|
||||||
Server(const io::network::Endpoint &endpoint, TSessionData *session_data, ServerContext *context,
|
Server(io::network::Endpoint endpoint, TSessionContext *session_context, ServerContext *context,
|
||||||
int inactivity_timeout_sec, const std::string &service_name,
|
int inactivity_timeout_sec, const std::string &service_name,
|
||||||
size_t workers_count = std::thread::hardware_concurrency())
|
size_t workers_count = std::thread::hardware_concurrency())
|
||||||
: alive_(false),
|
: alive_(false),
|
||||||
endpoint_(endpoint),
|
endpoint_(std::move(endpoint)),
|
||||||
listener_(session_data, context, inactivity_timeout_sec, service_name, workers_count),
|
listener_(session_context, context, inactivity_timeout_sec, service_name, workers_count),
|
||||||
service_name_(service_name) {}
|
service_name_(service_name) {}
|
||||||
|
|
||||||
~Server() {
|
~Server() {
|
||||||
@@ -156,7 +156,7 @@ class Server final {
|
|||||||
|
|
||||||
Socket socket_;
|
Socket socket_;
|
||||||
io::network::Endpoint endpoint_;
|
io::network::Endpoint endpoint_;
|
||||||
Listener<TSession, TSessionData> listener_;
|
Listener<TSession, TSessionContext> listener_;
|
||||||
|
|
||||||
const std::string service_name_;
|
const std::string service_name_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -22,6 +22,10 @@
|
|||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
|
|
||||||
|
// Centos 7 OpenSSL includes libkrb5 which has brings in macros TRUE and FALSE. undef to prevent issues.
|
||||||
|
#undef TRUE
|
||||||
|
#undef FALSE
|
||||||
|
|
||||||
#include "communication/buffer.hpp"
|
#include "communication/buffer.hpp"
|
||||||
#include "communication/context.hpp"
|
#include "communication/context.hpp"
|
||||||
#include "communication/exceptions.hpp"
|
#include "communication/exceptions.hpp"
|
||||||
@@ -69,10 +73,10 @@ class OutputStream final {
|
|||||||
* sessions. It handles socket ownership, inactivity timeout and protocol
|
* sessions. It handles socket ownership, inactivity timeout and protocol
|
||||||
* wrapping.
|
* wrapping.
|
||||||
*/
|
*/
|
||||||
template <class TSession, class TSessionData>
|
template <class TSession, class TSessionContext>
|
||||||
class Session final {
|
class Session final {
|
||||||
public:
|
public:
|
||||||
Session(io::network::Socket &&socket, TSessionData *data, ServerContext *context, int inactivity_timeout_sec)
|
Session(io::network::Socket &&socket, TSessionContext *data, ServerContext *context, int inactivity_timeout_sec)
|
||||||
: socket_(std::move(socket)),
|
: socket_(std::move(socket)),
|
||||||
output_stream_([this](const uint8_t *data, size_t len, bool have_more) { return Write(data, len, have_more); }),
|
output_stream_([this](const uint8_t *data, size_t len, bool have_more) { return Write(data, len, have_more); }),
|
||||||
session_(data, socket_.endpoint(), input_buffer_.read_end(), &output_stream_),
|
session_(data, socket_.endpoint(), input_buffer_.read_end(), &output_stream_),
|
||||||
|
|||||||
@@ -36,11 +36,11 @@
|
|||||||
|
|
||||||
namespace memgraph::communication::v2 {
|
namespace memgraph::communication::v2 {
|
||||||
|
|
||||||
template <class TSession, class TSessionData>
|
template <class TSession, class TSessionContext>
|
||||||
class Listener final : public std::enable_shared_from_this<Listener<TSession, TSessionData>> {
|
class Listener final : public std::enable_shared_from_this<Listener<TSession, TSessionContext>> {
|
||||||
using tcp = boost::asio::ip::tcp;
|
using tcp = boost::asio::ip::tcp;
|
||||||
using SessionHandler = Session<TSession, TSessionData>;
|
using SessionHandler = Session<TSession, TSessionContext>;
|
||||||
using std::enable_shared_from_this<Listener<TSession, TSessionData>>::shared_from_this;
|
using std::enable_shared_from_this<Listener<TSession, TSessionContext>>::shared_from_this;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Listener(const Listener &) = delete;
|
Listener(const Listener &) = delete;
|
||||||
@@ -59,10 +59,10 @@ class Listener final : public std::enable_shared_from_this<Listener<TSession, TS
|
|||||||
bool IsRunning() const noexcept { return alive_.load(std::memory_order_relaxed); }
|
bool IsRunning() const noexcept { return alive_.load(std::memory_order_relaxed); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Listener(boost::asio::io_context &io_context, TSessionData *data, ServerContext *server_context,
|
Listener(boost::asio::io_context &io_context, TSessionContext *session_context, ServerContext *server_context,
|
||||||
tcp::endpoint &endpoint, const std::string_view service_name, const uint64_t inactivity_timeout_sec)
|
tcp::endpoint &endpoint, const std::string_view service_name, const uint64_t inactivity_timeout_sec)
|
||||||
: io_context_(io_context),
|
: io_context_(io_context),
|
||||||
data_(data),
|
session_context_(session_context),
|
||||||
server_context_(server_context),
|
server_context_(server_context),
|
||||||
acceptor_(io_context_),
|
acceptor_(io_context_),
|
||||||
endpoint_{endpoint},
|
endpoint_{endpoint},
|
||||||
@@ -111,8 +111,8 @@ class Listener final : public std::enable_shared_from_this<Listener<TSession, TS
|
|||||||
return OnError(ec, "accept");
|
return OnError(ec, "accept");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto session = SessionHandler::Create(std::move(socket), data_, *server_context_, endpoint_, inactivity_timeout_,
|
auto session = SessionHandler::Create(std::move(socket), session_context_, *server_context_, endpoint_,
|
||||||
service_name_);
|
inactivity_timeout_, service_name_);
|
||||||
session->Start();
|
session->Start();
|
||||||
DoAccept();
|
DoAccept();
|
||||||
}
|
}
|
||||||
@@ -123,7 +123,7 @@ class Listener final : public std::enable_shared_from_this<Listener<TSession, TS
|
|||||||
}
|
}
|
||||||
|
|
||||||
boost::asio::io_context &io_context_;
|
boost::asio::io_context &io_context_;
|
||||||
TSessionData *data_;
|
TSessionContext *session_context_;
|
||||||
ServerContext *server_context_;
|
ServerContext *server_context_;
|
||||||
tcp::acceptor acceptor_;
|
tcp::acceptor acceptor_;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -60,53 +60,32 @@ using ServerEndpoint = boost::asio::ip::tcp::endpoint;
|
|||||||
* @tparam TSession the server can handle different Sessions, each session
|
* @tparam TSession the server can handle different Sessions, each session
|
||||||
* represents a different protocol so the same network infrastructure
|
* represents a different protocol so the same network infrastructure
|
||||||
* can be used for handling different protocols
|
* can be used for handling different protocols
|
||||||
* @tparam TSessionData the class with objects that will be forwarded to the
|
* @tparam TSessionContext the class with objects that will be forwarded to the
|
||||||
* session
|
* session
|
||||||
*/
|
*/
|
||||||
template <typename TSession, typename TSessionData>
|
template <typename TSession, typename TSessionContext>
|
||||||
class Server final {
|
class Server final {
|
||||||
using ServerHandler = Server<TSession, TSessionData>;
|
using ServerHandler = Server<TSession, TSessionContext>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Constructs and binds server to endpoint, operates on session data and
|
* Constructs and binds server to endpoint, operates on session data and
|
||||||
* invokes workers_count workers
|
* invokes workers_count workers
|
||||||
*/
|
*/
|
||||||
Server(ServerEndpoint &endpoint, TSessionData *session_data, ServerContext *server_context,
|
Server(ServerEndpoint &endpoint, TSessionContext *session_context, ServerContext *server_context,
|
||||||
const int inactivity_timeout_sec, const std::string_view service_name,
|
int inactivity_timeout_sec, std::string_view service_name,
|
||||||
size_t workers_count = std::thread::hardware_concurrency())
|
size_t workers_count = std::thread::hardware_concurrency());
|
||||||
: endpoint_{endpoint},
|
|
||||||
service_name_{service_name},
|
|
||||||
context_thread_pool_{workers_count},
|
|
||||||
listener_{Listener<TSession, TSessionData>::Create(context_thread_pool_.GetIOContext(), session_data,
|
|
||||||
server_context, endpoint_, service_name_,
|
|
||||||
inactivity_timeout_sec)} {}
|
|
||||||
|
|
||||||
~Server() { MG_ASSERT(!IsRunning(), "Server wasn't shutdown properly"); }
|
~Server();
|
||||||
|
|
||||||
Server(const Server &) = delete;
|
Server(const Server &) = delete;
|
||||||
Server(Server &&) = delete;
|
Server(Server &&) = delete;
|
||||||
Server &operator=(const Server &) = delete;
|
Server &operator=(const Server &) = delete;
|
||||||
Server &operator=(Server &&) = delete;
|
Server &operator=(Server &&) = delete;
|
||||||
|
|
||||||
const auto &Endpoint() const {
|
const auto &Endpoint() const;
|
||||||
MG_ASSERT(IsRunning(), "You can't get the server endpoint when it's not running!");
|
|
||||||
return endpoint_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Start() {
|
bool Start();
|
||||||
if (IsRunning()) {
|
|
||||||
spdlog::error("The server is already running");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
listener_->Start();
|
|
||||||
|
|
||||||
spdlog::info("{} server is fully armed and operational", service_name_);
|
|
||||||
spdlog::info("{} listening on {}", service_name_, endpoint_.address());
|
|
||||||
context_thread_pool_.Run();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Shutdown() {
|
void Shutdown() {
|
||||||
context_thread_pool_.Shutdown();
|
context_thread_pool_.Shutdown();
|
||||||
@@ -115,14 +94,56 @@ class Server final {
|
|||||||
|
|
||||||
void AwaitShutdown() { context_thread_pool_.AwaitShutdown(); }
|
void AwaitShutdown() { context_thread_pool_.AwaitShutdown(); }
|
||||||
|
|
||||||
bool IsRunning() const noexcept { return context_thread_pool_.IsRunning() && listener_->IsRunning(); }
|
bool IsRunning() const noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ServerEndpoint endpoint_;
|
ServerEndpoint endpoint_;
|
||||||
std::string service_name_;
|
std::string service_name_;
|
||||||
|
|
||||||
IOContextThreadPool context_thread_pool_;
|
IOContextThreadPool context_thread_pool_;
|
||||||
std::shared_ptr<Listener<TSession, TSessionData>> listener_;
|
std::shared_ptr<Listener<TSession, TSessionContext>> listener_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename TSession, typename TSessionContext>
|
||||||
|
Server<TSession, TSessionContext>::~Server() {
|
||||||
|
MG_ASSERT(!IsRunning(), "Server wasn't shutdown properly");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSession, typename TSessionContext>
|
||||||
|
Server<TSession, TSessionContext>::Server(ServerEndpoint &endpoint, TSessionContext *session_context,
|
||||||
|
ServerContext *server_context, const int inactivity_timeout_sec,
|
||||||
|
const std::string_view service_name, size_t workers_count)
|
||||||
|
: endpoint_{endpoint},
|
||||||
|
service_name_{service_name},
|
||||||
|
context_thread_pool_{workers_count},
|
||||||
|
listener_{Listener<TSession, TSessionContext>::Create(context_thread_pool_.GetIOContext(), session_context,
|
||||||
|
server_context, endpoint_, service_name_,
|
||||||
|
inactivity_timeout_sec)} {}
|
||||||
|
|
||||||
|
template <typename TSession, typename TSessionContext>
|
||||||
|
bool Server<TSession, TSessionContext>::Start() {
|
||||||
|
if (IsRunning()) {
|
||||||
|
spdlog::error("The server is already running");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
listener_->Start();
|
||||||
|
|
||||||
|
spdlog::info("{} server is fully armed and operational", service_name_);
|
||||||
|
spdlog::info("{} listening on {}", service_name_, endpoint_.address());
|
||||||
|
context_thread_pool_.Run();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSession, typename TSessionContext>
|
||||||
|
const auto &Server<TSession, TSessionContext>::Endpoint() const {
|
||||||
|
MG_ASSERT(IsRunning(), "You can't get the server endpoint when it's not running!");
|
||||||
|
return endpoint_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSession, typename TSessionContext>
|
||||||
|
bool Server<TSession, TSessionContext>::IsRunning() const noexcept {
|
||||||
|
return context_thread_pool_.IsRunning() && listener_->IsRunning();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace memgraph::communication::v2
|
} // namespace memgraph::communication::v2
|
||||||
|
|||||||
@@ -16,10 +16,12 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
#include <exception>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
@@ -41,9 +43,11 @@
|
|||||||
#include <boost/beast/websocket/rfc6455.hpp>
|
#include <boost/beast/websocket/rfc6455.hpp>
|
||||||
#include <boost/system/detail/error_code.hpp>
|
#include <boost/system/detail/error_code.hpp>
|
||||||
|
|
||||||
|
#include "communication/bolt/v1/session.hpp"
|
||||||
#include "communication/buffer.hpp"
|
#include "communication/buffer.hpp"
|
||||||
#include "communication/context.hpp"
|
#include "communication/context.hpp"
|
||||||
#include "communication/exceptions.hpp"
|
#include "communication/exceptions.hpp"
|
||||||
|
#include "dbms/global.hpp"
|
||||||
#include "utils/event_counter.hpp"
|
#include "utils/event_counter.hpp"
|
||||||
#include "utils/logging.hpp"
|
#include "utils/logging.hpp"
|
||||||
#include "utils/on_scope_exit.hpp"
|
#include "utils/on_scope_exit.hpp"
|
||||||
@@ -95,10 +99,10 @@ class OutputStream final {
|
|||||||
* Websocket Sessions. It handles socket ownership, inactivity timeout and protocol
|
* Websocket Sessions. It handles socket ownership, inactivity timeout and protocol
|
||||||
* wrapping.
|
* wrapping.
|
||||||
*/
|
*/
|
||||||
template <typename TSession, typename TSessionData>
|
template <typename TSession, typename TSessionContext>
|
||||||
class WebsocketSession : public std::enable_shared_from_this<WebsocketSession<TSession, TSessionData>> {
|
class WebsocketSession : public std::enable_shared_from_this<WebsocketSession<TSession, TSessionContext>> {
|
||||||
using WebSocket = boost::beast::websocket::stream<boost::beast::tcp_stream>;
|
using WebSocket = boost::beast::websocket::stream<boost::beast::tcp_stream>;
|
||||||
using std::enable_shared_from_this<WebsocketSession<TSession, TSessionData>>::shared_from_this;
|
using std::enable_shared_from_this<WebsocketSession<TSession, TSessionContext>>::shared_from_this;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
@@ -106,6 +110,17 @@ class WebsocketSession : public std::enable_shared_from_this<WebsocketSession<TS
|
|||||||
return std::shared_ptr<WebsocketSession>(new WebsocketSession(std::forward<Args>(args)...));
|
return std::shared_ptr<WebsocketSession>(new WebsocketSession(std::forward<Args>(args)...));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MG_ENTERPRISE
|
||||||
|
~WebsocketSession() { session_context_->Delete(session_); }
|
||||||
|
#else
|
||||||
|
~WebsocketSession() = default;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
WebsocketSession(const WebsocketSession &) = delete;
|
||||||
|
WebsocketSession &operator=(const WebsocketSession &) = delete;
|
||||||
|
WebsocketSession(WebsocketSession &&) noexcept = delete;
|
||||||
|
WebsocketSession &operator=(WebsocketSession &&) noexcept = delete;
|
||||||
|
|
||||||
// Start the asynchronous accept operation
|
// Start the asynchronous accept operation
|
||||||
template <class Body, class Allocator>
|
template <class Body, class Allocator>
|
||||||
void DoAccept(boost::beast::http::request<Body, boost::beast::http::basic_fields<Allocator>> req) {
|
void DoAccept(boost::beast::http::request<Body, boost::beast::http::basic_fields<Allocator>> req) {
|
||||||
@@ -151,15 +166,20 @@ class WebsocketSession : public std::enable_shared_from_this<WebsocketSession<TS
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// Take ownership of the socket
|
// Take ownership of the socket
|
||||||
explicit WebsocketSession(tcp::socket &&socket, TSessionData *data, tcp::endpoint endpoint,
|
explicit WebsocketSession(tcp::socket &&socket, TSessionContext *session_context, tcp::endpoint endpoint,
|
||||||
std::string_view service_name)
|
std::string_view service_name)
|
||||||
: ws_(std::move(socket)),
|
: ws_(std::move(socket)),
|
||||||
strand_{boost::asio::make_strand(ws_.get_executor())},
|
strand_{boost::asio::make_strand(ws_.get_executor())},
|
||||||
output_stream_([this](const uint8_t *data, size_t len, bool /*have_more*/) { return Write(data, len); }),
|
output_stream_([this](const uint8_t *data, size_t len, bool /*have_more*/) { return Write(data, len); }),
|
||||||
session_(data, endpoint, input_buffer_.read_end(), &output_stream_),
|
session_{*session_context, endpoint, input_buffer_.read_end(), &output_stream_},
|
||||||
|
session_context_{session_context},
|
||||||
endpoint_{endpoint},
|
endpoint_{endpoint},
|
||||||
remote_endpoint_{ws_.next_layer().socket().remote_endpoint()},
|
remote_endpoint_{ws_.next_layer().socket().remote_endpoint()},
|
||||||
service_name_{service_name} {}
|
service_name_{service_name} {
|
||||||
|
#ifdef MG_ENTERPRISE
|
||||||
|
session_context_->Register(session_);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void OnAccept(boost::beast::error_code ec) {
|
void OnAccept(boost::beast::error_code ec) {
|
||||||
if (ec) {
|
if (ec) {
|
||||||
@@ -242,6 +262,7 @@ class WebsocketSession : public std::enable_shared_from_this<WebsocketSession<TS
|
|||||||
communication::Buffer input_buffer_;
|
communication::Buffer input_buffer_;
|
||||||
OutputStream output_stream_;
|
OutputStream output_stream_;
|
||||||
TSession session_;
|
TSession session_;
|
||||||
|
TSessionContext *session_context_;
|
||||||
tcp::endpoint endpoint_;
|
tcp::endpoint endpoint_;
|
||||||
tcp::endpoint remote_endpoint_;
|
tcp::endpoint remote_endpoint_;
|
||||||
std::string_view service_name_;
|
std::string_view service_name_;
|
||||||
@@ -253,11 +274,11 @@ class WebsocketSession : public std::enable_shared_from_this<WebsocketSession<TS
|
|||||||
* Sessions. It handles socket ownership, inactivity timeout and protocol
|
* Sessions. It handles socket ownership, inactivity timeout and protocol
|
||||||
* wrapping.
|
* wrapping.
|
||||||
*/
|
*/
|
||||||
template <typename TSession, typename TSessionData>
|
template <typename TSession, typename TSessionContext>
|
||||||
class Session final : public std::enable_shared_from_this<Session<TSession, TSessionData>> {
|
class Session final : public std::enable_shared_from_this<Session<TSession, TSessionContext>> {
|
||||||
using TCPSocket = tcp::socket;
|
using TCPSocket = tcp::socket;
|
||||||
using SSLSocket = boost::asio::ssl::stream<TCPSocket>;
|
using SSLSocket = boost::asio::ssl::stream<TCPSocket>;
|
||||||
using std::enable_shared_from_this<Session<TSession, TSessionData>>::shared_from_this;
|
using std::enable_shared_from_this<Session<TSession, TSessionContext>>::shared_from_this;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
@@ -265,11 +286,16 @@ class Session final : public std::enable_shared_from_this<Session<TSession, TSes
|
|||||||
return std::shared_ptr<Session>(new Session(std::forward<Args>(args)...));
|
return std::shared_ptr<Session>(new Session(std::forward<Args>(args)...));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MG_ENTERPRISE
|
||||||
|
~Session() { session_context_->Delete(session_); }
|
||||||
|
#else
|
||||||
|
~Session() = default;
|
||||||
|
#endif
|
||||||
|
|
||||||
Session(const Session &) = delete;
|
Session(const Session &) = delete;
|
||||||
Session(Session &&) = delete;
|
Session(Session &&) = delete;
|
||||||
Session &operator=(const Session &) = delete;
|
Session &operator=(const Session &) = delete;
|
||||||
Session &operator=(Session &&) = delete;
|
Session &operator=(Session &&) = delete;
|
||||||
~Session() = default;
|
|
||||||
|
|
||||||
bool Start() {
|
bool Start() {
|
||||||
if (execution_active_) {
|
if (execution_active_) {
|
||||||
@@ -334,18 +360,23 @@ class Session final : public std::enable_shared_from_this<Session<TSession, TSes
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit Session(tcp::socket &&socket, TSessionData *data, ServerContext &server_context, tcp::endpoint endpoint,
|
explicit Session(tcp::socket &&socket, TSessionContext *session_context, ServerContext &server_context,
|
||||||
const std::chrono::seconds inactivity_timeout_sec, std::string_view service_name)
|
tcp::endpoint endpoint, const std::chrono::seconds inactivity_timeout_sec,
|
||||||
|
std::string_view service_name)
|
||||||
: socket_(CreateSocket(std::move(socket), server_context)),
|
: socket_(CreateSocket(std::move(socket), server_context)),
|
||||||
strand_{boost::asio::make_strand(GetExecutor())},
|
strand_{boost::asio::make_strand(GetExecutor())},
|
||||||
output_stream_([this](const uint8_t *data, size_t len, bool have_more) { return Write(data, len, have_more); }),
|
output_stream_([this](const uint8_t *data, size_t len, bool have_more) { return Write(data, len, have_more); }),
|
||||||
session_(data, endpoint, input_buffer_.read_end(), &output_stream_),
|
session_{*session_context, endpoint, input_buffer_.read_end(), &output_stream_},
|
||||||
data_{data},
|
session_context_{session_context},
|
||||||
endpoint_{endpoint},
|
endpoint_{endpoint},
|
||||||
remote_endpoint_{GetRemoteEndpoint()},
|
remote_endpoint_{GetRemoteEndpoint()},
|
||||||
service_name_{service_name},
|
service_name_{service_name},
|
||||||
timeout_seconds_(inactivity_timeout_sec),
|
timeout_seconds_(inactivity_timeout_sec),
|
||||||
timeout_timer_(GetExecutor()) {
|
timeout_timer_(GetExecutor()) {
|
||||||
|
#ifdef MG_ENTERPRISE
|
||||||
|
// TODO Try to remove Register (see comment at SessionInterface declaration)
|
||||||
|
session_context_->Register(session_);
|
||||||
|
#endif
|
||||||
ExecuteForSocket([](auto &&socket) {
|
ExecuteForSocket([](auto &&socket) {
|
||||||
socket.lowest_layer().set_option(tcp::no_delay(true)); // enable PSH
|
socket.lowest_layer().set_option(tcp::no_delay(true)); // enable PSH
|
||||||
socket.lowest_layer().set_option(boost::asio::socket_base::keep_alive(true)); // enable SO_KEEPALIVE
|
socket.lowest_layer().set_option(boost::asio::socket_base::keep_alive(true)); // enable SO_KEEPALIVE
|
||||||
@@ -382,6 +413,8 @@ class Session final : public std::enable_shared_from_this<Session<TSession, TSes
|
|||||||
|
|
||||||
void OnRead(const boost::system::error_code &ec, const size_t bytes_transferred) {
|
void OnRead(const boost::system::error_code &ec, const size_t bytes_transferred) {
|
||||||
if (ec) {
|
if (ec) {
|
||||||
|
// TODO Check if client disconnected
|
||||||
|
session_.HandleError();
|
||||||
return OnError(ec);
|
return OnError(ec);
|
||||||
}
|
}
|
||||||
input_buffer_.write_end()->Written(bytes_transferred);
|
input_buffer_.write_end()->Written(bytes_transferred);
|
||||||
@@ -396,7 +429,8 @@ class Session final : public std::enable_shared_from_this<Session<TSession, TSes
|
|||||||
spdlog::info("Switching {} to websocket connection", remote_endpoint_);
|
spdlog::info("Switching {} to websocket connection", remote_endpoint_);
|
||||||
if (std::holds_alternative<TCPSocket>(socket_)) {
|
if (std::holds_alternative<TCPSocket>(socket_)) {
|
||||||
auto sock = std::get<TCPSocket>(std::move(socket_));
|
auto sock = std::get<TCPSocket>(std::move(socket_));
|
||||||
WebsocketSession<TSession, TSessionData>::Create(std::move(sock), data_, endpoint_, service_name_)
|
WebsocketSession<TSession, TSessionContext>::Create(std::move(sock), session_context_, endpoint_,
|
||||||
|
service_name_)
|
||||||
->DoAccept(parser.release());
|
->DoAccept(parser.release());
|
||||||
execution_active_ = false;
|
execution_active_ = false;
|
||||||
return;
|
return;
|
||||||
@@ -535,7 +569,7 @@ class Session final : public std::enable_shared_from_this<Session<TSession, TSes
|
|||||||
communication::Buffer input_buffer_;
|
communication::Buffer input_buffer_;
|
||||||
OutputStream output_stream_;
|
OutputStream output_stream_;
|
||||||
TSession session_;
|
TSession session_;
|
||||||
TSessionData *data_;
|
TSessionContext *session_context_;
|
||||||
tcp::endpoint endpoint_;
|
tcp::endpoint endpoint_;
|
||||||
tcp::endpoint remote_endpoint_;
|
tcp::endpoint remote_endpoint_;
|
||||||
std::string_view service_name_;
|
std::string_view service_name_;
|
||||||
|
|||||||
18
src/csv/CMakeLists.txt
Normal file
18
src/csv/CMakeLists.txt
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
add_library(mg-csv STATIC)
|
||||||
|
add_library(mg::csv ALIAS mg-csv)
|
||||||
|
target_sources(mg-csv
|
||||||
|
PUBLIC
|
||||||
|
include/csv/parsing.hpp
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
|
parsing.cpp
|
||||||
|
)
|
||||||
|
target_include_directories(mg-csv PUBLIC include)
|
||||||
|
|
||||||
|
find_package(Boost REQUIRED COMPONENTS iostreams)
|
||||||
|
target_link_libraries(mg-csv
|
||||||
|
PUBLIC mg-utils
|
||||||
|
PRIVATE lib::ctre mg-requests Boost::iostreams
|
||||||
|
)
|
||||||
|
|
||||||
|
add_subdirectory(fuzz)
|
||||||
5
src/csv/fuzz/CMakeLists.txt
Normal file
5
src/csv/fuzz/CMakeLists.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
add_executable(fuzz_csv EXCLUDE_FROM_ALL)
|
||||||
|
target_sources(fuzz_csv PRIVATE fuzz_reader.cpp)
|
||||||
|
target_link_libraries(fuzz_csv PRIVATE mg::csv)
|
||||||
|
target_compile_options(fuzz_csv PRIVATE -fsanitize=fuzzer)
|
||||||
|
target_link_libraries(fuzz_csv PRIVATE -fsanitize=fuzzer)
|
||||||
78
src/csv/fuzz/fuzz_reader.cpp
Normal file
78
src/csv/fuzz/fuzz_reader.cpp
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
// 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 <cstdint>
|
||||||
|
#include <optional>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "csv/parsing.hpp"
|
||||||
|
#include "utils/string.hpp"
|
||||||
|
|
||||||
|
namespace mg = memgraph;
|
||||||
|
namespace csv = mg::csv;
|
||||||
|
|
||||||
|
using pmr_str = mg::utils::pmr::string;
|
||||||
|
|
||||||
|
extern "C" int LLVMFuzzerTestOneInput(std::uint8_t const *data, std::size_t size) {
|
||||||
|
// need to parse a config
|
||||||
|
if (size < 4) return 0;
|
||||||
|
auto const with_header = bool(data[0]);
|
||||||
|
auto const ignore_bad = bool(data[1]);
|
||||||
|
auto const delim_size = data[2];
|
||||||
|
auto const quote_size = data[3];
|
||||||
|
// 0 will be nullopt, everything else will be one smaller
|
||||||
|
// 0 , 1, 2, 3, 4
|
||||||
|
// nullopt, 0, 1, 2, 3
|
||||||
|
auto const delim_real_size = delim_size == 0 ? 0 : delim_size - 1;
|
||||||
|
auto const quote_real_size = quote_size == 0 ? 0 : quote_size - 1;
|
||||||
|
// not worth testing if too large
|
||||||
|
if (delim_real_size > 3 || quote_real_size > 3) return 0;
|
||||||
|
|
||||||
|
// is there enough space for them to exist
|
||||||
|
if (size < 4 + delim_real_size + quote_real_size) return 0;
|
||||||
|
auto const delim_start = 4;
|
||||||
|
auto const delim_end = delim_start + delim_real_size;
|
||||||
|
auto const quote_start = delim_end;
|
||||||
|
auto const quote_end = quote_start + quote_real_size;
|
||||||
|
|
||||||
|
auto *mem = mg::utils::NewDeleteResource();
|
||||||
|
auto delim = delim_size == 0 ? std::optional<pmr_str>{} : pmr_str(&data[delim_start], &data[delim_end], mem);
|
||||||
|
auto quote = quote_size == 0 ? std::optional<pmr_str>{} : pmr_str(&data[quote_start], &data[quote_end], mem);
|
||||||
|
|
||||||
|
auto const remaining = static_cast<int64_t>(size) - quote_end;
|
||||||
|
if (remaining < 0) __builtin_trap(); // if this hits, above parsing is wrong
|
||||||
|
|
||||||
|
// #############################################################################################################
|
||||||
|
|
||||||
|
// build Config
|
||||||
|
auto cfg = csv::Reader::Config{with_header, ignore_bad, std::move(delim), std::move(quote)};
|
||||||
|
|
||||||
|
// build CSV source
|
||||||
|
auto ss = std::stringstream{};
|
||||||
|
ss.write(reinterpret_cast<char const *>(&data[quote_end]), static_cast<std::streamsize>(remaining));
|
||||||
|
auto source = csv::StreamCsvSource{std::move(ss)};
|
||||||
|
|
||||||
|
// #############################################################################################################
|
||||||
|
try {
|
||||||
|
auto reader = memgraph::csv::Reader(std::move(source), std::move(cfg));
|
||||||
|
auto const header = reader.GetHeader();
|
||||||
|
asm volatile("" : : "g"(header) : "memory");
|
||||||
|
while (true) {
|
||||||
|
auto row = reader.GetNextRow(mem);
|
||||||
|
if (!row) break;
|
||||||
|
asm volatile("" : : "g"(row) : "memory");
|
||||||
|
}
|
||||||
|
} catch (csv::CsvReadException const &) {
|
||||||
|
// CsvReadException is ok
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "utils/exceptions.hpp"
|
#include "utils/exceptions.hpp"
|
||||||
@@ -36,13 +37,53 @@ class CsvReadException : public utils::BasicException {
|
|||||||
using utils::BasicException::BasicException;
|
using utils::BasicException::BasicException;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FileCsvSource {
|
||||||
|
public:
|
||||||
|
explicit FileCsvSource(std::filesystem::path path);
|
||||||
|
std::istream &GetStream();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::filesystem::path path_;
|
||||||
|
std::ifstream stream_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StreamCsvSource {
|
||||||
|
public:
|
||||||
|
StreamCsvSource(std::stringstream stream) : stream_{std::move(stream)} {}
|
||||||
|
std::istream &GetStream() { return stream_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::stringstream stream_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class UrlCsvSource : public StreamCsvSource {
|
||||||
|
public:
|
||||||
|
UrlCsvSource(char const *url);
|
||||||
|
};
|
||||||
|
|
||||||
|
class CsvSource {
|
||||||
|
public:
|
||||||
|
static auto Create(utils::pmr::string const &csv_location) -> CsvSource;
|
||||||
|
CsvSource(FileCsvSource source) : source_{std::move(source)} {}
|
||||||
|
CsvSource(StreamCsvSource source) : source_{std::move(source)} {}
|
||||||
|
CsvSource(UrlCsvSource source) : source_{std::move(source)} {}
|
||||||
|
std::istream &GetStream();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::variant<FileCsvSource, UrlCsvSource, StreamCsvSource> source_;
|
||||||
|
};
|
||||||
|
|
||||||
class Reader {
|
class Reader {
|
||||||
public:
|
public:
|
||||||
struct Config {
|
struct Config {
|
||||||
Config() = default;
|
Config() = default;
|
||||||
Config(const bool with_header, const bool ignore_bad, std::optional<utils::pmr::string> delim,
|
Config(const bool with_header, const bool ignore_bad, std::optional<utils::pmr::string> delim,
|
||||||
std::optional<utils::pmr::string> qt)
|
std::optional<utils::pmr::string> qt)
|
||||||
: with_header(with_header), ignore_bad(ignore_bad), delimiter(std::move(delim)), quote(std::move(qt)) {}
|
: with_header(with_header), ignore_bad(ignore_bad), delimiter(std::move(delim)), quote(std::move(qt)) {
|
||||||
|
// delimiter + quote can not be empty
|
||||||
|
if (delimiter && delimiter->empty()) delimiter.reset();
|
||||||
|
if (quote && quote->empty()) quote.reset();
|
||||||
|
}
|
||||||
|
|
||||||
bool with_header{false};
|
bool with_header{false};
|
||||||
bool ignore_bad{false};
|
bool ignore_bad{false};
|
||||||
@@ -53,16 +94,7 @@ class Reader {
|
|||||||
using Row = utils::pmr::vector<utils::pmr::string>;
|
using Row = utils::pmr::vector<utils::pmr::string>;
|
||||||
using Header = utils::pmr::vector<utils::pmr::string>;
|
using Header = utils::pmr::vector<utils::pmr::string>;
|
||||||
|
|
||||||
Reader() = default;
|
explicit Reader(CsvSource source, Config cfg, utils::MemoryResource *mem = utils::NewDeleteResource());
|
||||||
explicit Reader(std::filesystem::path path, Config cfg, utils::MemoryResource *mem = utils::NewDeleteResource())
|
|
||||||
: memory_(mem), path_(std::move(path)) {
|
|
||||||
read_config_.with_header = cfg.with_header;
|
|
||||||
read_config_.ignore_bad = cfg.ignore_bad;
|
|
||||||
read_config_.delimiter = cfg.delimiter ? std::move(*cfg.delimiter) : utils::pmr::string{",", memory_};
|
|
||||||
read_config_.quote = cfg.quote ? std::move(*cfg.quote) : utils::pmr::string{"\"", memory_};
|
|
||||||
InitializeStream();
|
|
||||||
TryInitializeHeader();
|
|
||||||
}
|
|
||||||
|
|
||||||
Reader(const Reader &) = delete;
|
Reader(const Reader &) = delete;
|
||||||
Reader &operator=(const Reader &) = delete;
|
Reader &operator=(const Reader &) = delete;
|
||||||
@@ -81,28 +113,18 @@ class Reader {
|
|||||||
};
|
};
|
||||||
|
|
||||||
using ParsingResult = utils::BasicResult<ParseError, Row>;
|
using ParsingResult = utils::BasicResult<ParseError, Row>;
|
||||||
[[nodiscard]] bool HasHeader() const;
|
|
||||||
const Header &GetHeader() const;
|
bool HasHeader() const;
|
||||||
std::optional<Row> GetNextRow(utils::MemoryResource *mem);
|
auto GetHeader() const -> Header const &;
|
||||||
|
auto GetNextRow(utils::MemoryResource *mem) -> std::optional<Row>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
utils::MemoryResource *memory_;
|
// Some implementation issues that need clearing up, but this is mainly because
|
||||||
std::filesystem::path path_;
|
// I don't want `boost/iostreams/filtering_stream.hpp` included in this header file
|
||||||
std::ifstream csv_stream_;
|
// Because it causes issues when combined with antlr headers
|
||||||
Config read_config_;
|
// When we have C++20 modules this can be fixed
|
||||||
uint64_t line_count_{1};
|
struct impl;
|
||||||
uint16_t number_of_columns_{0};
|
std::unique_ptr<impl, void (*)(impl *)> pimpl;
|
||||||
Header header_{memory_};
|
|
||||||
|
|
||||||
void InitializeStream();
|
|
||||||
|
|
||||||
void TryInitializeHeader();
|
|
||||||
|
|
||||||
std::optional<utils::pmr::string> GetNextLine(utils::MemoryResource *mem);
|
|
||||||
|
|
||||||
ParsingResult ParseHeader();
|
|
||||||
|
|
||||||
ParsingResult ParseRow(utils::MemoryResource *mem);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace memgraph::csv
|
} // namespace memgraph::csv
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -9,33 +9,132 @@
|
|||||||
// by the Apache License, Version 2.0, included in the file
|
// by the Apache License, Version 2.0, included in the file
|
||||||
// licenses/APL.txt.
|
// licenses/APL.txt.
|
||||||
|
|
||||||
#include "utils/csv_parsing.hpp"
|
#include "csv/parsing.hpp"
|
||||||
|
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
|
#include <boost/iostreams/filter/bzip2.hpp>
|
||||||
|
#include <boost/iostreams/filter/gzip.hpp>
|
||||||
|
#include <boost/iostreams/filtering_stream.hpp>
|
||||||
|
#include <ctre/ctre.hpp>
|
||||||
|
|
||||||
|
#include "requests/requests.hpp"
|
||||||
#include "utils/file.hpp"
|
#include "utils/file.hpp"
|
||||||
|
#include "utils/on_scope_exit.hpp"
|
||||||
#include "utils/string.hpp"
|
#include "utils/string.hpp"
|
||||||
|
|
||||||
|
using PlainStream = boost::iostreams::filtering_istream;
|
||||||
|
|
||||||
namespace memgraph::csv {
|
namespace memgraph::csv {
|
||||||
|
|
||||||
using ParseError = Reader::ParseError;
|
using ParseError = Reader::ParseError;
|
||||||
|
|
||||||
void Reader::InitializeStream() {
|
struct Reader::impl {
|
||||||
if (!std::filesystem::exists(path_)) {
|
impl(CsvSource source, Reader::Config cfg, utils::MemoryResource *mem);
|
||||||
throw CsvReadException("CSV file not found: {}", path_.string());
|
|
||||||
}
|
[[nodiscard]] bool HasHeader() const { return read_config_.with_header; }
|
||||||
csv_stream_.open(path_);
|
[[nodiscard]] auto Header() const -> Header const & { return header_; }
|
||||||
if (!csv_stream_.good()) {
|
|
||||||
throw CsvReadException("CSV file {} couldn't be opened!", path_.string());
|
auto GetNextRow(utils::MemoryResource *mem) -> std::optional<Reader::Row>;
|
||||||
}
|
|
||||||
|
private:
|
||||||
|
void InitializeStream();
|
||||||
|
|
||||||
|
void TryInitializeHeader();
|
||||||
|
|
||||||
|
std::optional<utils::pmr::string> GetNextLine(utils::MemoryResource *mem);
|
||||||
|
|
||||||
|
ParsingResult ParseHeader();
|
||||||
|
|
||||||
|
ParsingResult ParseRow(utils::MemoryResource *mem);
|
||||||
|
|
||||||
|
utils::MemoryResource *memory_;
|
||||||
|
std::filesystem::path path_;
|
||||||
|
CsvSource source_;
|
||||||
|
PlainStream csv_stream_;
|
||||||
|
Config read_config_;
|
||||||
|
uint64_t line_count_{1};
|
||||||
|
uint16_t number_of_columns_{0};
|
||||||
|
Reader::Header header_{memory_};
|
||||||
|
};
|
||||||
|
|
||||||
|
Reader::impl::impl(CsvSource source, Reader::Config cfg, utils::MemoryResource *mem)
|
||||||
|
: memory_(mem), source_(std::move(source)) {
|
||||||
|
read_config_.with_header = cfg.with_header;
|
||||||
|
read_config_.ignore_bad = cfg.ignore_bad;
|
||||||
|
read_config_.delimiter = cfg.delimiter ? std::move(*cfg.delimiter) : utils::pmr::string{",", memory_};
|
||||||
|
read_config_.quote = cfg.quote ? std::move(*cfg.quote) : utils::pmr::string{"\"", memory_};
|
||||||
|
InitializeStream();
|
||||||
|
TryInitializeHeader();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<utils::pmr::string> Reader::GetNextLine(utils::MemoryResource *mem) {
|
enum class CompressionMethod : uint8_t {
|
||||||
|
NONE,
|
||||||
|
GZip,
|
||||||
|
BZip2,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Detect compression based on magic sequences
|
||||||
|
auto DetectCompressionMethod(std::istream &is) -> CompressionMethod {
|
||||||
|
// Ensure stream is reset
|
||||||
|
auto const on_exit = utils::OnScopeExit{[&]() { is.seekg(std::ios::beg); }};
|
||||||
|
|
||||||
|
// Note we must use bytes for comparison, not char
|
||||||
|
//
|
||||||
|
std::byte c{}; // this gets reused
|
||||||
|
auto const next_byte = [&](std::byte &b) { return bool(is.get(reinterpret_cast<char &>(b))); };
|
||||||
|
if (!next_byte(c)) return CompressionMethod::NONE;
|
||||||
|
|
||||||
|
auto const as_bytes = []<typename... Args>(Args... args) {
|
||||||
|
return std::array<std::byte, sizeof...(Args)>{std::byte(args)...};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Gzip - 0x1F8B
|
||||||
|
constexpr static auto gzip_seq = as_bytes(0x1F, 0x8B);
|
||||||
|
if (c == gzip_seq[0]) {
|
||||||
|
if (!next_byte(c) || c != gzip_seq[1]) return CompressionMethod::NONE;
|
||||||
|
return CompressionMethod::GZip;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BZip2 - 0x425A68
|
||||||
|
constexpr static auto bzip_seq = as_bytes(0x42, 0x5A, 0x68);
|
||||||
|
if (c == bzip_seq[0]) {
|
||||||
|
if (!next_byte(c) || c != bzip_seq[1]) return CompressionMethod::NONE;
|
||||||
|
if (!next_byte(c) || c != bzip_seq[2]) return CompressionMethod::NONE;
|
||||||
|
return CompressionMethod::BZip2;
|
||||||
|
}
|
||||||
|
return CompressionMethod::NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Reader::Reader(CsvSource source, Reader::Config cfg, utils::MemoryResource *mem)
|
||||||
|
: pimpl{new impl{std::move(source), std::move(cfg), mem}, [](impl *p) { delete p; }} {}
|
||||||
|
|
||||||
|
void Reader::impl::InitializeStream() {
|
||||||
|
auto &source = source_.GetStream();
|
||||||
|
|
||||||
|
auto const method = DetectCompressionMethod(source);
|
||||||
|
switch (method) {
|
||||||
|
case CompressionMethod::GZip:
|
||||||
|
csv_stream_.push(boost::iostreams::gzip_decompressor{});
|
||||||
|
break;
|
||||||
|
case CompressionMethod::BZip2:
|
||||||
|
csv_stream_.push(boost::iostreams::bzip2_decompressor{});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
csv_stream_.push(source);
|
||||||
|
MG_ASSERT(csv_stream_.auto_close(), "Should be 'auto close' for correct operation");
|
||||||
|
MG_ASSERT(csv_stream_.is_complete(), "Should be 'complete' for correct operation");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::pmr::string> Reader::impl::GetNextLine(utils::MemoryResource *mem) {
|
||||||
utils::pmr::string line(mem);
|
utils::pmr::string line(mem);
|
||||||
if (!std::getline(csv_stream_, line)) {
|
if (!std::getline(csv_stream_, line)) {
|
||||||
// reached end of file or an I/0 error occurred
|
// reached end of file or an I/0 error occurred
|
||||||
if (!csv_stream_.good()) {
|
if (!csv_stream_.good()) {
|
||||||
csv_stream_.close();
|
csv_stream_.reset(); // this will close the file_stream_ and clear the chain
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
@@ -43,13 +142,13 @@ std::optional<utils::pmr::string> Reader::GetNextLine(utils::MemoryResource *mem
|
|||||||
return std::move(line);
|
return std::move(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
Reader::ParsingResult Reader::ParseHeader() {
|
Reader::ParsingResult Reader::impl::ParseHeader() {
|
||||||
// header must be the very first line in the file
|
// header must be the very first line in the file
|
||||||
MG_ASSERT(line_count_ == 1, "Invalid use of {}", __func__);
|
MG_ASSERT(line_count_ == 1, "Invalid use of {}", __func__);
|
||||||
return ParseRow(memory_);
|
return ParseRow(memory_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reader::TryInitializeHeader() {
|
void Reader::impl::TryInitializeHeader() {
|
||||||
if (!HasHeader()) {
|
if (!HasHeader()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -67,16 +166,16 @@ void Reader::TryInitializeHeader() {
|
|||||||
header_ = std::move(*header);
|
header_ = std::move(*header);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool Reader::HasHeader() const { return read_config_.with_header; }
|
[[nodiscard]] bool Reader::HasHeader() const { return pimpl->HasHeader(); }
|
||||||
|
|
||||||
const Reader::Header &Reader::GetHeader() const { return header_; }
|
const Reader::Header &Reader::GetHeader() const { return pimpl->Header(); }
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
enum class CsvParserState : uint8_t { INITIAL_FIELD, NEXT_FIELD, QUOTING, EXPECT_DELIMITER, DONE };
|
enum class CsvParserState : uint8_t { INITIAL_FIELD, NEXT_FIELD, QUOTING, EXPECT_DELIMITER, DONE };
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Reader::ParsingResult Reader::ParseRow(utils::MemoryResource *mem) {
|
Reader::ParsingResult Reader::impl::ParseRow(utils::MemoryResource *mem) {
|
||||||
utils::pmr::vector<utils::pmr::string> row(mem);
|
utils::pmr::vector<utils::pmr::string> row(mem);
|
||||||
if (number_of_columns_ != 0) {
|
if (number_of_columns_ != 0) {
|
||||||
row.reserve(number_of_columns_);
|
row.reserve(number_of_columns_);
|
||||||
@@ -140,9 +239,10 @@ Reader::ParsingResult Reader::ParseRow(utils::MemoryResource *mem) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CsvParserState::QUOTING: {
|
case CsvParserState::QUOTING: {
|
||||||
|
const auto quote_size = read_config_.quote->size();
|
||||||
const auto quote_now = utils::StartsWith(line_string_view, *read_config_.quote);
|
const auto quote_now = utils::StartsWith(line_string_view, *read_config_.quote);
|
||||||
const auto quote_next =
|
const auto quote_next = quote_size <= line_string_view.size() &&
|
||||||
utils::StartsWith(line_string_view.substr(read_config_.quote->size()), *read_config_.quote);
|
utils::StartsWith(line_string_view.substr(quote_size), *read_config_.quote);
|
||||||
if (quote_now && quote_next) {
|
if (quote_now && quote_next) {
|
||||||
// This is an escaped quote character.
|
// This is an escaped quote character.
|
||||||
column += *read_config_.quote;
|
column += *read_config_.quote;
|
||||||
@@ -216,12 +316,7 @@ Reader::ParsingResult Reader::ParseRow(utils::MemoryResource *mem) {
|
|||||||
return std::move(row);
|
return std::move(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns Reader::Row if the read row if valid;
|
std::optional<Reader::Row> Reader::impl::GetNextRow(utils::MemoryResource *mem) {
|
||||||
// Returns std::nullopt if end of file is reached or an error occurred
|
|
||||||
// making it unreadable;
|
|
||||||
// @throws CsvReadException if a bad row is encountered, and the ignore_bad is set
|
|
||||||
// to 'true' in the Reader::Config.
|
|
||||||
std::optional<Reader::Row> Reader::GetNextRow(utils::MemoryResource *mem) {
|
|
||||||
auto row = ParseRow(mem);
|
auto row = ParseRow(mem);
|
||||||
|
|
||||||
if (row.HasError()) {
|
if (row.HasError()) {
|
||||||
@@ -245,4 +340,44 @@ std::optional<Reader::Row> Reader::GetNextRow(utils::MemoryResource *mem) {
|
|||||||
return std::move(*row);
|
return std::move(*row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns Reader::Row if the read row if valid;
|
||||||
|
// Returns std::nullopt if end of file is reached or an error occurred
|
||||||
|
// making it unreadable;
|
||||||
|
// @throws CsvReadException if a bad row is encountered, and the ignore_bad is set
|
||||||
|
// to 'true' in the Reader::Config.
|
||||||
|
std::optional<Reader::Row> Reader::GetNextRow(utils::MemoryResource *mem) { return pimpl->GetNextRow(mem); }
|
||||||
|
|
||||||
|
FileCsvSource::FileCsvSource(std::filesystem::path path) : path_(std::move(path)) {
|
||||||
|
if (!std::filesystem::exists(path_)) {
|
||||||
|
throw CsvReadException("CSV file not found: {}", path_.string());
|
||||||
|
}
|
||||||
|
stream_.open(path_);
|
||||||
|
if (!stream_.good()) {
|
||||||
|
throw CsvReadException("CSV file {} couldn't be opened!", path_.string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::istream &FileCsvSource::GetStream() { return stream_; }
|
||||||
|
|
||||||
|
std::istream &CsvSource::GetStream() {
|
||||||
|
return *std::visit([](auto &&source) { return std::addressof(source.GetStream()); }, source_);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CsvSource::Create(const utils::pmr::string &csv_location) -> CsvSource {
|
||||||
|
constexpr auto protocol_matcher = ctre::starts_with<"(https?|ftp)://">;
|
||||||
|
if (protocol_matcher(csv_location)) {
|
||||||
|
return csv::UrlCsvSource{csv_location.c_str()};
|
||||||
|
}
|
||||||
|
return csv::FileCsvSource{csv_location};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper for UrlCsvSource
|
||||||
|
auto urlToStringStream(const char *url) -> std::stringstream {
|
||||||
|
auto ss = std::stringstream{};
|
||||||
|
if (!requests::DownloadToStream(url, ss)) {
|
||||||
|
throw CsvReadException("CSV was unable to be fetched from {}", url);
|
||||||
|
}
|
||||||
|
return ss;
|
||||||
|
};
|
||||||
|
|
||||||
|
UrlCsvSource::UrlCsvSource(const char *url) : StreamCsvSource{urlToStringStream(url)} {}
|
||||||
} // namespace memgraph::csv
|
} // namespace memgraph::csv
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
template <typename TElement>
|
template <typename TElement>
|
||||||
class RingBuffer {
|
class RingBuffer {
|
||||||
public:
|
public:
|
||||||
explicit RingBuffer(int capacity) : capacity_(capacity) { buffer_ = std::make_unique<TElement[]>(capacity_); }
|
explicit RingBuffer(int capacity) : capacity_(capacity), buffer_{std::make_unique<TElement[]>(capacity_)} {}
|
||||||
|
|
||||||
RingBuffer(const RingBuffer &) = delete;
|
RingBuffer(const RingBuffer &) = delete;
|
||||||
RingBuffer(RingBuffer &&) = delete;
|
RingBuffer(RingBuffer &&) = delete;
|
||||||
|
|||||||
18
src/dbms/constants.hpp
Normal file
18
src/dbms/constants.hpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
namespace memgraph::dbms {
|
||||||
|
|
||||||
|
constexpr static const char *kDefaultDB = "memgraph"; //!< Name of the default database
|
||||||
|
|
||||||
|
} // namespace memgraph::dbms
|
||||||
110
src/dbms/global.hpp
Normal file
110
src/dbms/global.hpp
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
// 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 <concepts>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "utils/exceptions.hpp"
|
||||||
|
|
||||||
|
namespace memgraph::dbms {
|
||||||
|
|
||||||
|
enum class DeleteError : uint8_t {
|
||||||
|
DEFAULT_DB,
|
||||||
|
USING,
|
||||||
|
NON_EXISTENT,
|
||||||
|
FAIL,
|
||||||
|
DISK_FAIL,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class NewError : uint8_t {
|
||||||
|
NO_CONFIGS,
|
||||||
|
EXISTS,
|
||||||
|
DEFUNCT,
|
||||||
|
GENERIC,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SetForResult : uint8_t {
|
||||||
|
SUCCESS,
|
||||||
|
ALREADY_SET,
|
||||||
|
FAIL,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UnknownSession Exception
|
||||||
|
*
|
||||||
|
* Used to indicate that an unknown session was used.
|
||||||
|
*/
|
||||||
|
class UnknownSessionException : public utils::BasicException {
|
||||||
|
public:
|
||||||
|
using utils::BasicException::BasicException;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UnknownDatabase Exception
|
||||||
|
*
|
||||||
|
* Used to indicate that an unknown database was used.
|
||||||
|
*/
|
||||||
|
class UnknownDatabaseException : public utils::BasicException {
|
||||||
|
public:
|
||||||
|
using utils::BasicException::BasicException;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Session interface used by the DBMS to handle the the active sessions.
|
||||||
|
* @todo Try to remove this dependency from SessionContextHandler. OnDelete could be removed, as it only does an assert.
|
||||||
|
* OnChange could be removed if SetFor returned the pointer and the called then handled the OnChange execution.
|
||||||
|
* However, the interface is very useful to decouple the interpreter's query execution and the sessions themselves.
|
||||||
|
*/
|
||||||
|
class SessionInterface {
|
||||||
|
public:
|
||||||
|
SessionInterface() = default;
|
||||||
|
virtual ~SessionInterface() = default;
|
||||||
|
|
||||||
|
SessionInterface(const SessionInterface &) = default;
|
||||||
|
SessionInterface &operator=(const SessionInterface &) = default;
|
||||||
|
SessionInterface(SessionInterface &&) noexcept = default;
|
||||||
|
SessionInterface &operator=(SessionInterface &&) noexcept = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the unique string identifying the session.
|
||||||
|
*
|
||||||
|
* @return std::string
|
||||||
|
*/
|
||||||
|
virtual std::string UUID() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the currently active database.
|
||||||
|
*
|
||||||
|
* @return std::string
|
||||||
|
*/
|
||||||
|
virtual std::string GetDatabaseName() const = 0;
|
||||||
|
|
||||||
|
#ifdef MG_ENTERPRISE
|
||||||
|
/**
|
||||||
|
* @brief Gets called on database change.
|
||||||
|
*
|
||||||
|
* @return SetForResult enum (SUCCESS, ALREADY_SET or FAIL)
|
||||||
|
*/
|
||||||
|
virtual dbms::SetForResult OnChange(const std::string &) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback that gets called on database delete (drop).
|
||||||
|
*
|
||||||
|
* @return true on success
|
||||||
|
*/
|
||||||
|
virtual bool OnDelete(const std::string &) = 0;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace memgraph::dbms
|
||||||
142
src/dbms/handler.hpp
Normal file
142
src/dbms/handler.hpp
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
// 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 <filesystem>
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
#include <string_view>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "global.hpp"
|
||||||
|
#include "utils/result.hpp"
|
||||||
|
#include "utils/sync_ptr.hpp"
|
||||||
|
|
||||||
|
namespace memgraph::dbms {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generic multi-database content handler.
|
||||||
|
*
|
||||||
|
* @tparam TContext
|
||||||
|
* @tparam TConfig
|
||||||
|
*/
|
||||||
|
template <typename TContext, typename TConfig>
|
||||||
|
class Handler {
|
||||||
|
public:
|
||||||
|
using NewResult = utils::BasicResult<NewError, std::shared_ptr<TContext>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Empty Handler constructor.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
Handler() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate a new context and corresponding configuration.
|
||||||
|
*
|
||||||
|
* @tparam T1 Variadic template of context constructor arguments
|
||||||
|
* @tparam T2 Variadic template of config constructor arguments
|
||||||
|
* @param name Name associated with the new context/config pair
|
||||||
|
* @param args1 Arguments passed (as a tuple) to the context constructor
|
||||||
|
* @param args2 Arguments passed (as a tuple) to the config constructor
|
||||||
|
* @return NewResult
|
||||||
|
*/
|
||||||
|
template <typename... T1, typename... T2>
|
||||||
|
NewResult New(std::string name, std::tuple<T1...> args1, std::tuple<T2...> args2) {
|
||||||
|
return New_(name, args1, args2, std::make_index_sequence<sizeof...(T1)>{},
|
||||||
|
std::make_index_sequence<sizeof...(T2)>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get pointer to context.
|
||||||
|
*
|
||||||
|
* @param name Name associated with the wanted context
|
||||||
|
* @return std::optional<std::shared_ptr<TContext>>
|
||||||
|
*/
|
||||||
|
std::optional<std::shared_ptr<TContext>> Get(const std::string &name) {
|
||||||
|
if (auto search = items_.find(name); search != items_.end()) {
|
||||||
|
return search->second.get();
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the config.
|
||||||
|
*
|
||||||
|
* @param name Name associated with the wanted config
|
||||||
|
* @return std::optional<TConfig>
|
||||||
|
*/
|
||||||
|
std::optional<TConfig> GetConfig(const std::string &name) const {
|
||||||
|
if (auto search = items_.find(name); search != items_.end()) {
|
||||||
|
return search->second.config();
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete the context/config pair associated with the name.
|
||||||
|
*
|
||||||
|
* @param name Name associated with the context/config pair to delete
|
||||||
|
* @return true on success
|
||||||
|
*/
|
||||||
|
bool Delete(const std::string &name) {
|
||||||
|
if (auto itr = items_.find(name); itr != items_.end()) {
|
||||||
|
itr->second.DestroyAndSync();
|
||||||
|
items_.erase(itr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if a name is already used.
|
||||||
|
*
|
||||||
|
* @param name Name to check
|
||||||
|
* @return true if a context/config pair is already associated with the name
|
||||||
|
*/
|
||||||
|
bool Has(const std::string &name) const { return items_.find(name) != items_.end(); }
|
||||||
|
|
||||||
|
auto begin() { return items_.begin(); }
|
||||||
|
auto end() { return items_.end(); }
|
||||||
|
auto begin() const { return items_.begin(); }
|
||||||
|
auto end() const { return items_.end(); }
|
||||||
|
auto cbegin() const { return items_.cbegin(); }
|
||||||
|
auto cend() const { return items_.cend(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief Lower level handler that hides some ugly code.
|
||||||
|
*
|
||||||
|
* @tparam T1 Variadic template of context constructor arguments
|
||||||
|
* @tparam T2 Variadic template of config constructor arguments
|
||||||
|
* @tparam I1 List of indexes associated with the first tuple
|
||||||
|
* @tparam I2 List of indexes associated with the second tuple
|
||||||
|
*/
|
||||||
|
template <typename... T1, typename... T2, std::size_t... I1, std::size_t... I2>
|
||||||
|
NewResult New_(std::string name, std::tuple<T1...> &args1, std::tuple<T2...> &args2,
|
||||||
|
std::integer_sequence<std::size_t, I1...> /*not-used*/,
|
||||||
|
std::integer_sequence<std::size_t, I2...> /*not-used*/) {
|
||||||
|
// Make sure the emplace will succeed, since we don't want to create temporary objects that could break something
|
||||||
|
if (!Has(name)) {
|
||||||
|
auto [itr, _] = items_.emplace(std::piecewise_construct, std::forward_as_tuple(name),
|
||||||
|
std::forward_as_tuple(TConfig{std::forward<T1>(std::get<I1>(args1))...},
|
||||||
|
std::forward<T2>(std::get<I2>(args2))...));
|
||||||
|
return itr->second.get();
|
||||||
|
}
|
||||||
|
spdlog::info("Item with name \"{}\" already exists.", name);
|
||||||
|
return NewError::EXISTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_map<std::string, utils::SyncPtr<TContext, TConfig>> items_; //!< map to all active items
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace memgraph::dbms
|
||||||
106
src/dbms/interp_handler.hpp
Normal file
106
src/dbms/interp_handler.hpp
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
#ifdef MG_ENTERPRISE
|
||||||
|
|
||||||
|
#include "global.hpp"
|
||||||
|
#include "query/auth_checker.hpp"
|
||||||
|
#include "query/config.hpp"
|
||||||
|
#include "query/interpreter.hpp"
|
||||||
|
#include "storage/v2/storage.hpp"
|
||||||
|
|
||||||
|
#include "handler.hpp"
|
||||||
|
|
||||||
|
namespace memgraph::dbms {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Simple class that adds useful information to the query's InterpreterContext
|
||||||
|
*
|
||||||
|
* @tparam T Multi-database handler type
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
class ExpandedInterpContext : public query::InterpreterContext {
|
||||||
|
public:
|
||||||
|
template <typename... TArgs>
|
||||||
|
explicit ExpandedInterpContext(T &ref, TArgs &&...args)
|
||||||
|
: query::InterpreterContext(std::forward<TArgs>(args)...), sc_handler_(ref) {}
|
||||||
|
|
||||||
|
T &sc_handler_; //!< Multi-database/SessionContext handler (used in some queries)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Simple structure that expands on the query's InterpreterConfig
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct ExpandedInterpConfig {
|
||||||
|
storage::Config storage_config; //!< Storage configuration
|
||||||
|
query::InterpreterConfig interp_config; //!< Interpreter configuration
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Multi-database interpreter context handler
|
||||||
|
*
|
||||||
|
* @tparam TSCHandler High-level multi-database/SessionContext handler type
|
||||||
|
*/
|
||||||
|
template <typename TSCHandler>
|
||||||
|
class InterpContextHandler : public Handler<ExpandedInterpContext<TSCHandler>, ExpandedInterpConfig> {
|
||||||
|
public:
|
||||||
|
using InterpContextT = ExpandedInterpContext<TSCHandler>;
|
||||||
|
using HandlerT = Handler<InterpContextT, ExpandedInterpConfig>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate a new interpreter context associated with the passed name.
|
||||||
|
*
|
||||||
|
* @param name Name associating the new interpreter context
|
||||||
|
* @param sc_handler Multi-database/SessionContext handler used (some queries might use it)
|
||||||
|
* @param db Storage associated with the interpreter context
|
||||||
|
* @param config Interpreter's configuration
|
||||||
|
* @param dir Directory used by the interpreter
|
||||||
|
* @param auth_handler AuthQueryHandler used
|
||||||
|
* @param auth_checker AuthChecker used
|
||||||
|
* @return HandlerT::NewResult
|
||||||
|
*/
|
||||||
|
typename HandlerT::NewResult New(const std::string &name, TSCHandler &sc_handler, storage::Config storage_config,
|
||||||
|
const query::InterpreterConfig &interpreter_config,
|
||||||
|
query::AuthQueryHandler &auth_handler, query::AuthChecker &auth_checker) {
|
||||||
|
// Check if compatible with the existing interpreters
|
||||||
|
if (std::any_of(HandlerT::cbegin(), HandlerT::cend(), [&](const auto &elem) {
|
||||||
|
const auto &config = elem.second.config().storage_config;
|
||||||
|
return config.durability.storage_directory == storage_config.durability.storage_directory;
|
||||||
|
})) {
|
||||||
|
spdlog::info("Tried to generate a new context using claimed directory and/or storage.");
|
||||||
|
return NewError::EXISTS;
|
||||||
|
}
|
||||||
|
const auto dir = storage_config.durability.storage_directory;
|
||||||
|
storage_config.name = name; // Set storage id via config
|
||||||
|
return HandlerT::New(
|
||||||
|
name, std::forward_as_tuple(storage_config, interpreter_config),
|
||||||
|
std::forward_as_tuple(sc_handler, storage_config, interpreter_config, dir, &auth_handler, &auth_checker));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief All currently active storage.
|
||||||
|
*
|
||||||
|
* @return std::vector<std::string>
|
||||||
|
*/
|
||||||
|
std::vector<std::string> All() const {
|
||||||
|
std::vector<std::string> res;
|
||||||
|
res.reserve(std::distance(HandlerT::cbegin(), HandlerT::cend()));
|
||||||
|
std::for_each(HandlerT::cbegin(), HandlerT::cend(), [&](const auto &elem) { res.push_back(elem.first); });
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace memgraph::dbms
|
||||||
|
|
||||||
|
#endif
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user