From def2b8bc4dcdbb9e6f953a3248b5f745e9a7eeaa Mon Sep 17 00:00:00 2001 From: blue Date: Sun, 6 Oct 2024 20:11:44 +0300 Subject: [PATCH 01/34] Some test fixes --- test/basic.cpp | 9 ++++--- test/duplicates.cpp | 57 ++++++++++++++++++++++++++++++++++----------- 2 files changed, 48 insertions(+), 18 deletions(-) diff --git a/test/basic.cpp b/test/basic.cpp index bf0bf39..fb6b0c5 100644 --- a/test/basic.cpp +++ b/test/basic.cpp @@ -113,10 +113,9 @@ TEST_F(BaseTest, AddingKeysToCache) { EXPECT_EQ(db->ready(), true); c1->addRecord(2, "blah balah"); c1->addRecord(-4, "testing goes brrr"); - c1->addRecord(140, "whatever"); + c1->addRecord(40, "whatever"); c1->addRecord(-37, "aaaaa tss tsss tsss tsss aaaaaaa"); - EXPECT_EQ(c1->getRecord(140), "whatever"); - EXPECT_EQ(c1->getRecord(-116), "whatever"); + EXPECT_EQ(c1->getRecord(40), "whatever"); } TEST_F(BaseTest, AddingKeysToVariableCache) { @@ -189,8 +188,8 @@ TEST_F(BaseTest, Persistence) { EXPECT_EQ(t2->count(), t2Size); EXPECT_EQ(c1->count(), c1Size); - EXPECT_EQ(c1->checkRecord(-116), true); - EXPECT_EQ(c1->getRecord(-116), "whatever"); + EXPECT_EQ(c1->checkRecord(40), true); + EXPECT_EQ(c1->getRecord(40), "whatever"); EXPECT_EQ(c1->checkRecord(-4), true); EXPECT_EQ(c1->getRecord(-4), "testing goes brrr"); EXPECT_EQ(c1->getRecord(-4), "testing goes brrr"); diff --git a/test/duplicates.cpp b/test/duplicates.cpp index 4fbe12a..0bc6b56 100644 --- a/test/duplicates.cpp +++ b/test/duplicates.cpp @@ -130,7 +130,10 @@ TEST_F(DuplicatesTest, Adding) { tu3->addRecord(7.20001, 4.00000001); //not sure how exactly, but it works EXPECT_EQ(tu3->count(), 7); - EXPECT_EQ(tu3->getRecord(7.2), -113); + + std::set res72({-113, -53.5478, 697, 4, 4.00000001}); + EXPECT_EQ(res72.count(tu3->getRecord(7.2)), 1); + float tu3dd = tu3->getRecord(5119); EXPECT_TRUE(tu3ds == tu3dd); EXPECT_EQ(tu3ds, tu3dd); @@ -144,8 +147,11 @@ TEST_F(DuplicatesTest, Adding) { EXPECT_THROW(tu4->addRecord(327, 79.624923), LMDBAL::Exist); EXPECT_EQ(tu4->count(), 4); - EXPECT_EQ(tu4->getRecord(172), 0.00000001); - EXPECT_EQ(tu4->getRecord(327), 463.28348); //since they are not int's they are compared sort of lexicographically + + std::set res327({463.28348, 79.624923}); + std::set res172({0.00001, 0.00000001}); + EXPECT_EQ(res172.count(tu4->getRecord(172)), 1); + EXPECT_EQ(res327.count(tu4->getRecord(327)), 1); tu5->addRecord(-84.7, 45656753); EXPECT_THROW(tu5->addRecord(-84.7, 45656753), LMDBAL::Exist); @@ -174,13 +180,19 @@ TEST_F(DuplicatesTest, Forcing) { tu1->addRecord(-56, 71); tu1->addRecord(-56, 274); tu1->addRecord(-56, 732); + + std::set res56({71, 274, 732}); EXPECT_EQ(tu1->count(), tu1Size += 3); EXPECT_TRUE(tu1->forceRecord(-56, 322)); + res56.insert(322); EXPECT_EQ(tu1->count(), tu1Size += 1); - EXPECT_EQ(tu1->getRecord(-56), 274); //like yeah, it's really counterintuitive, since it's compared byte by byte + EXPECT_EQ(res56.count(tu1->getRecord(-56)), 1); + + res56.insert(14); EXPECT_TRUE(tu1->forceRecord(-56, 14)); EXPECT_EQ(tu1->count(), tu1Size += 1); - EXPECT_EQ(tu1->getRecord(-56), 14); + EXPECT_EQ(res56.count(tu1->getRecord(-56)), 1); + EXPECT_FALSE(tu1->forceRecord(-56, 274)); EXPECT_EQ(tu1->count(), tu1Size); @@ -201,26 +213,38 @@ TEST_F(DuplicatesTest, Forcing) { tu3->addRecord(17.3, 93.21); tu3->addRecord(17.3, 6.6); tu3->addRecord(17.3, 105.1); + std::set res17({93.21, 6.6, 105.1}); + EXPECT_EQ(tu3->count(), tu3Size += 3); EXPECT_TRUE(tu3->forceRecord(17.3, 74.9)); + res17.insert(74.9); EXPECT_EQ(tu3->count(), tu3Size += 1); - EXPECT_EQ(tu3->getRecord(17.3), 105.1f); //here too, really one should not use this function with duplicates, - EXPECT_TRUE(tu3->forceRecord(17.3, 5.1)); //unless he wishes for kinda randomish result + EXPECT_EQ(res17.count(tu3->getRecord(17.3)), 1); + + EXPECT_TRUE(tu3->forceRecord(17.3, 5.1)); + res17.insert(5.1); EXPECT_EQ(tu3->count(), tu3Size += 1); - EXPECT_EQ(tu3->getRecord(17.3), 5.1f); + EXPECT_EQ(res17.count(tu3->getRecord(17.3)), 1); + EXPECT_FALSE(tu3->forceRecord(17.3, 93.21)); EXPECT_EQ(tu3->count(), tu3Size); LMDBAL::SizeType tu4Size = tu4->count(); tu4->addRecord(84, -359.109); tu4->addRecord(84, 2879.654); + std::set res84({-359.109, 2879.654}); + EXPECT_EQ(tu4->count(), tu4Size += 2); EXPECT_TRUE(tu4->forceRecord(84, 72.9)); + res84.insert(72.9); EXPECT_EQ(tu4->count(), tu4Size += 1); - EXPECT_EQ(tu4->getRecord(84), 2879.654); + EXPECT_EQ(res84.count(tu4->getRecord(84)), 1); + EXPECT_TRUE(tu4->forceRecord(84, 2679.5)); + res84.insert(2679.5); EXPECT_EQ(tu4->count(), tu4Size += 1); - EXPECT_EQ(tu4->getRecord(84), 2679.5); + EXPECT_EQ(res84.count(tu4->getRecord(84)), 1); + EXPECT_FALSE(tu4->forceRecord(84, -359.109)); EXPECT_EQ(tu4->count(), tu4Size); @@ -286,6 +310,7 @@ TEST_F(DuplicatesTest, Changing) { EXPECT_THROW(tu2->changeRecord("jeremy spins", -7), LMDBAL::Exist); LMDBAL::SizeType tu3Size = tu3->count(); + std::set res26; EXPECT_THROW(tu3->changeRecord(26.7, 68.22), LMDBAL::NotFound); EXPECT_EQ(tu3->count(), tu3Size); tu3->addRecord(26.7, 68.22); @@ -294,11 +319,13 @@ TEST_F(DuplicatesTest, Changing) { tu3->changeRecord(26.7, 68.22); //should just do nothing usefull, but work normally EXPECT_EQ(tu3->getRecord(26.7), 68.22f); tu3->changeRecord(26.7, 23.18); + res26.insert(23.18); EXPECT_EQ(tu3->count(), tu3Size); EXPECT_EQ(tu3->getRecord(26.7), 23.18f); tu3->addRecord(26.7, 22.16); + res26.insert(22.16); EXPECT_EQ(tu3->count(), tu3Size += 1); - EXPECT_EQ(tu3->getRecord(26.7), 23.18f); + EXPECT_EQ(res26.count(tu3->getRecord(26.7)), 1); tu3->changeRecord(26.7, 21.7); EXPECT_EQ(tu3->count(), tu3Size); EXPECT_EQ(tu3->getRecord(26.7), 21.7f); @@ -316,17 +343,21 @@ TEST_F(DuplicatesTest, Changing) { tu4->changeRecord(852, 6795.349); //should just do nothing usefull, but work normally EXPECT_EQ(tu4->getRecord(852), 6795.349); tu4->changeRecord(852, 13.54); + std::set res852({13.54}); EXPECT_EQ(tu4->count(), tu4Size); EXPECT_EQ(tu4->getRecord(852), 13.54); tu4->addRecord(852, 213.85); + res852.insert(213.85); EXPECT_EQ(tu4->count(), tu4Size += 1); - EXPECT_EQ(tu4->getRecord(852), 13.54); + EXPECT_EQ(res852.count(tu4->getRecord(852)), 1); tu4->changeRecord(852, 236.21); + res852.insert(236.21); EXPECT_EQ(tu4->count(), tu4Size); EXPECT_EQ(tu4->getRecord(852), 236.21); tu4->changeRecord(852, 46324.1135); + res852.insert(46324.1135); EXPECT_EQ(tu4->count(), tu4Size); - EXPECT_EQ(tu4->getRecord(852), 213.85); + EXPECT_EQ(res852.count(tu4->getRecord(852)), 1); EXPECT_THROW(tu4->changeRecord(852, 46324.1135), LMDBAL::Exist); } From 4fd3799c1912cd1c8cd87c5924728c5f5821707d Mon Sep 17 00:00:00 2001 From: blue Date: Mon, 28 Oct 2024 14:11:30 +0200 Subject: [PATCH 02/34] Playing with CI --- .gitea/workflows/aur.yml | 80 ++++++++++++++++++++++++++++++++++++ packaging/Archlinux/PKGBUILD | 6 +-- 2 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 .gitea/workflows/aur.yml diff --git a/.gitea/workflows/aur.yml b/.gitea/workflows/aur.yml new file mode 100644 index 0000000..bdd6e32 --- /dev/null +++ b/.gitea/workflows/aur.yml @@ -0,0 +1,80 @@ +name: Release to AUR +on: + workflow_call: + inputs: + package-name: + required: true + type: string + version: + required: true + type: string + description: + required: true + type: string + depends: + required: true + type: string + workflow_dispatch: + inputs: + package-name: + description: "The name under which the package is going to be packaged to AUR" + type: string + default: "lmdbal" + version: + description: "The version of the published package" + type: string + default: "1.0.0" + description: + description: "The description of the package" + type: string + default: "LMDB Abstraction Layer" + depends: + description: "Additional dependencies" + type: string + default: "" + +jobs: + aur: + name: Release ${{ inputs.package-name }} to AUR + runs-on: archlinux + steps: + - name: Download the release tarball + run: curl -sL ${{ gitea.server_url }}/${{ gitea.repository }}/archive/${{ gitea.event.release.tag_name }}.tar.gz --output tarball.tar.gz + + - name: Calculate SHA256 for the tarball + run: echo "tbSum=$(sha256sum tarball.tar.gz | cut -d ' ' -f 1)" >> $GITHUB_ENV + + - name: Unarchive tarball + run: tar -xvzf tarball.tar.gz + + - name: Clone the AUR repository + run: | + echo "${{ secrets.DEPLOY_TO_AUR_PRIVATE_KEY }}" > key + chmod 600 key + GIT_SSH_COMMAND="ssh -i key -o 'IdentitiesOnly yes' -o 'StrictHostKeyChecking no'" git clone ssh://aur@aur.archlinux.org/${{ inputs.package-name }}.git aur + chmod 777 -R aur + cd aur + git config user.name ${{ secrets.DEPLOY_TO_AUR_USER_NAME }} + git config user.email ${{ secrets.DEPLOY_TO_AUR_EMAIL }} + + + - name: Copy PKGBUILD to the directory + run: cp lmdbal/packaging/Archlinux/PKGBUILD aur/ + + - name: Patch PKGBUILD file, and generate .SRCINFO + working-directory: aur + run: | + sed -i "/sha256sums=/c\sha256sums=('${{ env.tbSum }}')" PKGBUILD + sed -i "/pkgname=lmdbal/c\pkgname=(${{ inputs.package-name }})" PKGBUILD + sed -i "/pkgver=1.0.0/c\pkgver=(${{ inputs.version }})" PKGBUILD + sed -i "/pkgdesc=\"LMDB Abstraction Layer\"/c\pkgdesc=(\"${{ inputs.description }}\")" PKGBUILD + sed -i "/depends=( 'lmdb' )/c\depends=( 'lmdb' ${{ inputs.depends }} ))" PKGBUILD +# sed -i "/pkgname=lmdbal/c\pkgname=('${{ gitea.event.release.tag_name }}')" PKGBUILD + sudo -u build makepkg --printsrcinfo > .SRCINFO + + - name: Commit package to aur + working-directory: aur + run: | + git add PKGBUILD .SRCINFO + git commit -m "${{ gitea.event.release.body }}" + GIT_SSH_COMMAND="ssh -i ../key -o 'IdentitiesOnly yes' -o 'StrictHostKeyChecking no'" git push diff --git a/packaging/Archlinux/PKGBUILD b/packaging/Archlinux/PKGBUILD index 0f4b0da..d8e2277 100644 --- a/packaging/Archlinux/PKGBUILD +++ b/packaging/Archlinux/PKGBUILD @@ -1,12 +1,12 @@ # Maintainer: Yury Gubich pkgname=lmdbal -pkgver=0.5.4 +pkgver=1.0.0 pkgrel=1 -pkgdesc="LMDB Abstraction Layer, qt5 version" +pkgdesc="LMDB Abstraction Layer" arch=('i686' 'x86_64') url="https://git.macaw.me/blue/lmdbal" license=('GPL3') -depends=( 'lmdb' 'qt5-base') +depends=( 'lmdb' ) makedepends=('cmake>=3.16' 'gcc') optdepends=() From 75aafd2750dcb2273566f94a196d87dfe5f3550f Mon Sep 17 00:00:00 2001 From: blue Date: Mon, 28 Oct 2024 14:14:39 +0200 Subject: [PATCH 03/34] A fix for CI hopefully --- .gitea/workflows/aur.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitea/workflows/aur.yml b/.gitea/workflows/aur.yml index bdd6e32..f0b1dc3 100644 --- a/.gitea/workflows/aur.yml +++ b/.gitea/workflows/aur.yml @@ -69,7 +69,6 @@ jobs: sed -i "/pkgver=1.0.0/c\pkgver=(${{ inputs.version }})" PKGBUILD sed -i "/pkgdesc=\"LMDB Abstraction Layer\"/c\pkgdesc=(\"${{ inputs.description }}\")" PKGBUILD sed -i "/depends=( 'lmdb' )/c\depends=( 'lmdb' ${{ inputs.depends }} ))" PKGBUILD -# sed -i "/pkgname=lmdbal/c\pkgname=('${{ gitea.event.release.tag_name }}')" PKGBUILD sudo -u build makepkg --printsrcinfo > .SRCINFO - name: Commit package to aur From 93ed15e1da1cc100c687becc318ffb68e655e9d4 Mon Sep 17 00:00:00 2001 From: blue Date: Sat, 30 Nov 2024 19:30:19 +0200 Subject: [PATCH 04/34] CI try 1 --- .gitea/workflows/aur.yml | 19 +++++++------ .gitea/workflows/release.yml | 53 +++++++++++------------------------- packaging/Archlinux/PKGBUILD | 2 +- 3 files changed, 27 insertions(+), 47 deletions(-) diff --git a/.gitea/workflows/aur.yml b/.gitea/workflows/aur.yml index f0b1dc3..a1d08cb 100644 --- a/.gitea/workflows/aur.yml +++ b/.gitea/workflows/aur.yml @@ -5,25 +5,21 @@ on: package-name: required: true type: string - version: - required: true - type: string description: required: true type: string depends: required: true type: string + flags: + required: true + type: string workflow_dispatch: inputs: package-name: description: "The name under which the package is going to be packaged to AUR" type: string default: "lmdbal" - version: - description: "The version of the published package" - type: string - default: "1.0.0" description: description: "The description of the package" type: string @@ -32,10 +28,14 @@ on: description: "Additional dependencies" type: string default: "" + flags: + description: "Additional CMake flags" + type: string + default: "" jobs: aur: - name: Release ${{ inputs.package-name }} to AUR + name: Releasing ${{ inputs.package-name }} to AUR runs-on: archlinux steps: - name: Download the release tarball @@ -66,9 +66,10 @@ jobs: run: | sed -i "/sha256sums=/c\sha256sums=('${{ env.tbSum }}')" PKGBUILD sed -i "/pkgname=lmdbal/c\pkgname=(${{ inputs.package-name }})" PKGBUILD - sed -i "/pkgver=1.0.0/c\pkgver=(${{ inputs.version }})" PKGBUILD + sed -i "/pkgver=1.0.0/c\pkgver=(${{ gitea.event.release.tag_name }})" PKGBUILD sed -i "/pkgdesc=\"LMDB Abstraction Layer\"/c\pkgdesc=(\"${{ inputs.description }}\")" PKGBUILD sed -i "/depends=( 'lmdb' )/c\depends=( 'lmdb' ${{ inputs.depends }} ))" PKGBUILD + sed -i '/cmake . -D/s/$/ ${{ input.flags }}/' PKGBUILD sudo -u build makepkg --printsrcinfo > .SRCINFO - name: Commit package to aur diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index e3772ff..21c263b 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -5,42 +5,21 @@ on: types: [published] jobs: - Archlinux: - runs-on: archlinux - steps: - - name: Download the release tarball - run: curl -sL ${{ gitea.server_url }}/${{ gitea.repository }}/archive/${{ gitea.event.release.tag_name }}.tar.gz --output tarball.tar.gz + qt5: + name: Release qt5 build to AUR + uses: ./.gitea/workflows/aur.yml + with: + package-name: lmdbal-qt5 + description: LMDB Abstraction Layer, qt5 version + depends: 'qt5-base' + flags: -D QT_VERSION_MAJOR=5 - - name: Calculate SHA256 for the tarball - run: echo "tbSum=$(sha256sum tarball.tar.gz | cut -d ' ' -f 1)" >> $GITHUB_ENV - - - name: Unarchive tarball - run: tar -xvzf tarball.tar.gz - - - name: Clone the AUR repository - run: | - echo "${{ secrets.DEPLOY_TO_AUR_PRIVATE_KEY }}" > key - chmod 600 key - GIT_SSH_COMMAND="ssh -i key -o 'IdentitiesOnly yes' -o 'StrictHostKeyChecking no'" git clone ssh://aur@aur.archlinux.org/lmdbal.git aur - chmod 777 -R aur - cd aur - git config user.name ${{ secrets.DEPLOY_TO_AUR_USER_NAME }} - git config user.email ${{ secrets.DEPLOY_TO_AUR_EMAIL }} - - - - name: Copy PKGBUILD to the directory - run: cp lmdbal/packaging/Archlinux/PKGBUILD aur/ - - - name: Put SHA256 sum to PKGBUILD file, and generate .SRCINFO - working-directory: aur - run: | - sed -i "/sha256sums=/c\sha256sums=('${{ env.tbSum }}')" PKGBUILD - sudo -u build makepkg --printsrcinfo > .SRCINFO - - - name: Commit package to aur - working-directory: aur - run: | - git add PKGBUILD .SRCINFO - git commit -m "${{ gitea.event.release.body }}" - GIT_SSH_COMMAND="ssh -i ../key -o 'IdentitiesOnly yes' -o 'StrictHostKeyChecking no'" git push + qt6: + name: Release qt6 build to AUR + uses: ./.gitea/workflows/aur.yml + with: + package-name: lmdbal-qt6 + description: LMDB Abstraction Layer, qt6 version + depends: 'qt6-base' + flags: -D QT_VERSION_MAJOR=6 diff --git a/packaging/Archlinux/PKGBUILD b/packaging/Archlinux/PKGBUILD index d8e2277..f1dba99 100644 --- a/packaging/Archlinux/PKGBUILD +++ b/packaging/Archlinux/PKGBUILD @@ -14,7 +14,7 @@ source=("$pkgname-$pkgver.tar.gz::https://git.macaw.me/blue/$pkgname/archive/$pk sha256sums=('SKIP') build() { cd "$srcdir/$pkgname" - cmake . -D CMAKE_INSTALL_PREFIX=/usr -D CMAKE_BUILD_TYPE=Release -D QT_VERSION_MAJOR=5 + cmake . -D CMAKE_INSTALL_PREFIX=/usr -D CMAKE_BUILD_TYPE=Release cmake --build . } package() { From 29b126c30ead7dd8f9fe2d3257e799a3e8d8fb89 Mon Sep 17 00:00:00 2001 From: blue Date: Sat, 30 Nov 2024 19:44:07 +0200 Subject: [PATCH 05/34] CI Try 2 --- .gitea/workflows/main.yml | 21 +++++++++++++++------ CHANGELOG.md | 4 ++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/.gitea/workflows/main.yml b/.gitea/workflows/main.yml index 8c29f65..82291cb 100644 --- a/.gitea/workflows/main.yml +++ b/.gitea/workflows/main.yml @@ -6,7 +6,20 @@ on: - master jobs: - Archlinux: + test-qt5: + name: Test LMDBAL with qt5 + uses: uses: ./.gitea/workflows/aur.yml + with: + flags: -D QT_VERSION_MAJOR=5 + + test-qt5: + name: Test LMDBAL with qt6 + uses: uses: ./.gitea/workflows/aur.yml + with: + flags: -D QT_VERSION_MAJOR=6 + + docs: + name: Release documentation runs-on: archlinux steps: - name: Check out repository code @@ -17,16 +30,12 @@ jobs: - name: Configure working-directory: ./build - run: cmake .. -D BUILD_TESTS=True -D BUILD_DOC_HTML=True -D BUILD_DOC_XML=True -D BUILD_DOC_MAN=True -D BUILD_DOXYGEN_AWESOME=True -D QT_VERSION_MAJOR=5 + run: cmake .. BUILD_DOC_HTML=True -D BUILD_DOC_XML=True -D BUILD_DOC_MAN=True -D BUILD_DOXYGEN_AWESOME=True - name: Build working-directory: ./build run: cmake --build . - - name: Run tests - working-directory: ./build/test - run: ./runUnitTests - - name: Copy docs via scp uses: appleboy/scp-action@master # working-directory: ./build/doc //doesn't work diff --git a/CHANGELOG.md b/CHANGELOG.md index a70560d..32ea9a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +# LMDBAL 0.5.4 (November 30, 2024) +### Improvements +- Technical release just to resolve build issues + # LMDBAL 0.5.3 (November 14, 2023) ### Improvements - Now you don't need to link agains lmdb, just linking against LMDBAL is enough From 7c26b09056aba7457dbc6a6af1b6d44b7a86be4e Mon Sep 17 00:00:00 2001 From: blue Date: Sat, 30 Nov 2024 19:45:27 +0200 Subject: [PATCH 06/34] CI try 3 --- .gitea/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/main.yml b/.gitea/workflows/main.yml index 82291cb..a4a6087 100644 --- a/.gitea/workflows/main.yml +++ b/.gitea/workflows/main.yml @@ -8,13 +8,13 @@ on: jobs: test-qt5: name: Test LMDBAL with qt5 - uses: uses: ./.gitea/workflows/aur.yml + uses: ./.gitea/workflows/aur.yml with: flags: -D QT_VERSION_MAJOR=5 test-qt5: name: Test LMDBAL with qt6 - uses: uses: ./.gitea/workflows/aur.yml + uses: ./.gitea/workflows/aur.yml with: flags: -D QT_VERSION_MAJOR=6 From 8b7d548df6317d8ab77526272d49a335eb010e7a Mon Sep 17 00:00:00 2001 From: blue Date: Sat, 30 Nov 2024 19:46:43 +0200 Subject: [PATCH 07/34] CI try 4 --- .gitea/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/main.yml b/.gitea/workflows/main.yml index a4a6087..bf54766 100644 --- a/.gitea/workflows/main.yml +++ b/.gitea/workflows/main.yml @@ -12,7 +12,7 @@ jobs: with: flags: -D QT_VERSION_MAJOR=5 - test-qt5: + test-qt6: name: Test LMDBAL with qt6 uses: ./.gitea/workflows/aur.yml with: From c3246fd2b59be3366c28c5689f8241e9ac0bd1ac Mon Sep 17 00:00:00 2001 From: blue Date: Sat, 30 Nov 2024 20:37:28 +0200 Subject: [PATCH 08/34] CI try 5 --- .gitea/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/main.yml b/.gitea/workflows/main.yml index bf54766..5cbf3af 100644 --- a/.gitea/workflows/main.yml +++ b/.gitea/workflows/main.yml @@ -8,13 +8,13 @@ on: jobs: test-qt5: name: Test LMDBAL with qt5 - uses: ./.gitea/workflows/aur.yml + uses: ./.gitea/workflows/test.yml with: flags: -D QT_VERSION_MAJOR=5 test-qt6: name: Test LMDBAL with qt6 - uses: ./.gitea/workflows/aur.yml + uses: ./.gitea/workflows/test.yml with: flags: -D QT_VERSION_MAJOR=6 From 551495843d60f3c9fe6f69da1df55d53aa8d225c Mon Sep 17 00:00:00 2001 From: blue Date: Sat, 30 Nov 2024 20:39:34 +0200 Subject: [PATCH 09/34] CI try 5 --- .gitea/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitea/workflows/main.yml b/.gitea/workflows/main.yml index 5cbf3af..066f206 100644 --- a/.gitea/workflows/main.yml +++ b/.gitea/workflows/main.yml @@ -21,6 +21,7 @@ jobs: docs: name: Release documentation runs-on: archlinux + needs: [test-qt5, test-qt6] steps: - name: Check out repository code uses: actions/checkout@v3 From 1083df36ee58505523960decf202838142851961 Mon Sep 17 00:00:00 2001 From: blue Date: Sat, 30 Nov 2024 20:59:49 +0200 Subject: [PATCH 10/34] CI try 6 --- .gitea/workflows/main.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.gitea/workflows/main.yml b/.gitea/workflows/main.yml index 066f206..558e28f 100644 --- a/.gitea/workflows/main.yml +++ b/.gitea/workflows/main.yml @@ -6,6 +6,18 @@ on: - master jobs: + debug-path: + name: Debug Repository State + runs-on: archlinux + steps: + - name: Check out repository code + uses: actions/checkout@v3 + + - name: List all files + run: | + echo "Listing files in $(pwd):" + ls -R + test-qt5: name: Test LMDBAL with qt5 uses: ./.gitea/workflows/test.yml From f5d6fb914105c8b1c9f79ef3dfc5ce30c22211d7 Mon Sep 17 00:00:00 2001 From: blue Date: Sat, 30 Nov 2024 21:11:30 +0200 Subject: [PATCH 11/34] CI try 7 --- .gitea/workflows/main.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/main.yml b/.gitea/workflows/main.yml index 558e28f..25650fe 100644 --- a/.gitea/workflows/main.yml +++ b/.gitea/workflows/main.yml @@ -12,11 +12,17 @@ jobs: steps: - name: Check out repository code uses: actions/checkout@v3 + with: + fetch-depth: 0 # Ensure all files and full history are fetched + path: . # Clone into the root workspace directory - - name: List all files + - name: List all files in the workspace run: | - echo "Listing files in $(pwd):" - ls -R + echo "Listing files in $(pwd):" + ls -la + echo "Checking .gitea contents:" + ls -la .gitea/workflows || echo ".gitea/workflows not found!" + test-qt5: name: Test LMDBAL with qt5 From 4c5e4bb6ac77043aa332a19a2da673d8d4869f08 Mon Sep 17 00:00:00 2001 From: blue Date: Sat, 30 Nov 2024 21:17:07 +0200 Subject: [PATCH 12/34] CI try 8 --- .gitea/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/main.yml b/.gitea/workflows/main.yml index 25650fe..4f52da0 100644 --- a/.gitea/workflows/main.yml +++ b/.gitea/workflows/main.yml @@ -26,13 +26,13 @@ jobs: test-qt5: name: Test LMDBAL with qt5 - uses: ./.gitea/workflows/test.yml + uses: ./.gitea/workflows/unit-test.yml with: flags: -D QT_VERSION_MAJOR=5 test-qt6: name: Test LMDBAL with qt6 - uses: ./.gitea/workflows/test.yml + uses: ./.gitea/workflows/unit-test.yml with: flags: -D QT_VERSION_MAJOR=6 From 75010c0bc6e75b5666efe31e5b2c1458821e4ac3 Mon Sep 17 00:00:00 2001 From: blue Date: Sat, 30 Nov 2024 21:19:50 +0200 Subject: [PATCH 13/34] CI try 9 --- .gitea/workflows/main.yml | 22 ++-------------------- .gitea/workflows/test.yml | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 20 deletions(-) create mode 100644 .gitea/workflows/test.yml diff --git a/.gitea/workflows/main.yml b/.gitea/workflows/main.yml index 4f52da0..066f206 100644 --- a/.gitea/workflows/main.yml +++ b/.gitea/workflows/main.yml @@ -6,33 +6,15 @@ on: - master jobs: - debug-path: - name: Debug Repository State - runs-on: archlinux - steps: - - name: Check out repository code - uses: actions/checkout@v3 - with: - fetch-depth: 0 # Ensure all files and full history are fetched - path: . # Clone into the root workspace directory - - - name: List all files in the workspace - run: | - echo "Listing files in $(pwd):" - ls -la - echo "Checking .gitea contents:" - ls -la .gitea/workflows || echo ".gitea/workflows not found!" - - test-qt5: name: Test LMDBAL with qt5 - uses: ./.gitea/workflows/unit-test.yml + uses: ./.gitea/workflows/test.yml with: flags: -D QT_VERSION_MAJOR=5 test-qt6: name: Test LMDBAL with qt6 - uses: ./.gitea/workflows/unit-test.yml + uses: ./.gitea/workflows/test.yml with: flags: -D QT_VERSION_MAJOR=6 diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml new file mode 100644 index 0000000..922e361 --- /dev/null +++ b/.gitea/workflows/test.yml @@ -0,0 +1,36 @@ +name: Build and run unit tests for LMDBAL +on: + workflow_call: + inputs: + flags: + required: true + type: string + workflow_dispatch: + inputs: + flags: + description: "Flags for CMake configure stage" + type: string + default: "lmdbal" + +jobs: + test: + name: Building and rinning unit tests + runs-on: archlinux + steps: + - name: Check out repository code + uses: actions/checkout@v3 + + - name: Make a build directory + run: mkdir build + + - name: Configure + working-directory: ./build + run: cmake .. -D BUILD_TESTS=True -D QT_VERSION_MAJOR= ${{ inputs.flags }} + + - name: Build + working-directory: ./build + run: cmake --build . + + - name: Run tests + working-directory: ./build/test + run: ./runUnitTests From 50a13d72908085b35c148e7d9a2371e0a6f63753 Mon Sep 17 00:00:00 2001 From: blue Date: Sat, 30 Nov 2024 22:28:15 +0200 Subject: [PATCH 14/34] CI try 10 --- .gitea/workflows/release.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 21c263b..d20a949 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -13,6 +13,10 @@ jobs: description: LMDB Abstraction Layer, qt5 version depends: 'qt5-base' flags: -D QT_VERSION_MAJOR=5 + secrets: + DEPLOY_TO_AUR_PRIVATE_KEY: ${{ secrets.DEPLOY_TO_AUR_PRIVATE_KEY }} + DEPLOY_TO_AUR_USER_NAME: ${{ secrets.DEPLOY_TO_AUR_USER_NAME }} + DEPLOY_TO_AUR_EMAIL: ${{ secrets.DEPLOY_TO_AUR_EMAIL }} qt6: name: Release qt6 build to AUR @@ -22,4 +26,8 @@ jobs: description: LMDB Abstraction Layer, qt6 version depends: 'qt6-base' flags: -D QT_VERSION_MAJOR=6 + secrets: + DEPLOY_TO_AUR_PRIVATE_KEY: ${{ secrets.DEPLOY_TO_AUR_PRIVATE_KEY }} + DEPLOY_TO_AUR_USER_NAME: ${{ secrets.DEPLOY_TO_AUR_USER_NAME }} + DEPLOY_TO_AUR_EMAIL: ${{ secrets.DEPLOY_TO_AUR_EMAIL }} From 2add0b1ae2c4d79e98b66308c24a8d4655b9b704 Mon Sep 17 00:00:00 2001 From: blue Date: Sat, 30 Nov 2024 22:46:09 +0200 Subject: [PATCH 15/34] CI try 11 --- .gitea/workflows/aur.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitea/workflows/aur.yml b/.gitea/workflows/aur.yml index a1d08cb..d4a8ec6 100644 --- a/.gitea/workflows/aur.yml +++ b/.gitea/workflows/aur.yml @@ -65,10 +65,10 @@ jobs: working-directory: aur run: | sed -i "/sha256sums=/c\sha256sums=('${{ env.tbSum }}')" PKGBUILD - sed -i "/pkgname=lmdbal/c\pkgname=(${{ inputs.package-name }})" PKGBUILD - sed -i "/pkgver=1.0.0/c\pkgver=(${{ gitea.event.release.tag_name }})" PKGBUILD - sed -i "/pkgdesc=\"LMDB Abstraction Layer\"/c\pkgdesc=(\"${{ inputs.description }}\")" PKGBUILD - sed -i "/depends=( 'lmdb' )/c\depends=( 'lmdb' ${{ inputs.depends }} ))" PKGBUILD + sed -i "/pkgname=lmdbal/c\pkgname=${{ inputs.package-name }}" PKGBUILD + sed -i "/pkgver=1.0.0/c\pkgver=${{ gitea.event.release.tag_name }}" PKGBUILD + sed -i "/pkgdesc=\"LMDB Abstraction Layer\"/c\pkgdesc=\"${{ inputs.description }}\"" PKGBUILD + sed -i "/depends=( 'lmdb' )/c\depends=( 'lmdb' ${{ inputs.depends }} )" PKGBUILD sed -i '/cmake . -D/s/$/ ${{ input.flags }}/' PKGBUILD sudo -u build makepkg --printsrcinfo > .SRCINFO From 567045331460f59a34597b5c7ead9b5eca7649e5 Mon Sep 17 00:00:00 2001 From: blue Date: Sat, 30 Nov 2024 23:07:49 +0200 Subject: [PATCH 16/34] CI try 12 --- .gitea/workflows/aur.yml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/aur.yml b/.gitea/workflows/aur.yml index d4a8ec6..df05943 100644 --- a/.gitea/workflows/aur.yml +++ b/.gitea/workflows/aur.yml @@ -69,7 +69,7 @@ jobs: sed -i "/pkgver=1.0.0/c\pkgver=${{ gitea.event.release.tag_name }}" PKGBUILD sed -i "/pkgdesc=\"LMDB Abstraction Layer\"/c\pkgdesc=\"${{ inputs.description }}\"" PKGBUILD sed -i "/depends=( 'lmdb' )/c\depends=( 'lmdb' ${{ inputs.depends }} )" PKGBUILD - sed -i '/cmake . -D/s/$/ ${{ input.flags }}/' PKGBUILD + sed -i '/cmake . -D/s/$/ ${{ inputs.flags }}/' PKGBUILD sudo -u build makepkg --printsrcinfo > .SRCINFO - name: Commit package to aur diff --git a/README.md b/README.md index 73302ef..36b620e 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ ### Prerequisites - a compiler (c++ would do) -- Qt 5 or higher (qt5-base would do) +- Qt 5 or 6 or higher (qt5-base or qt6-base would do) - lmdb - CMake 3.16 or higher - Doxygen (optional, for documentation) From 649d967963c7963a6296c49a65bd945873b9ecc1 Mon Sep 17 00:00:00 2001 From: blue Date: Sat, 30 Nov 2024 23:17:52 +0200 Subject: [PATCH 17/34] CI try 13 --- .gitea/workflows/aur.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/aur.yml b/.gitea/workflows/aur.yml index df05943..ef1df58 100644 --- a/.gitea/workflows/aur.yml +++ b/.gitea/workflows/aur.yml @@ -56,7 +56,7 @@ jobs: cd aur git config user.name ${{ secrets.DEPLOY_TO_AUR_USER_NAME }} git config user.email ${{ secrets.DEPLOY_TO_AUR_EMAIL }} - + git checkout -b master || git checkout master - name: Copy PKGBUILD to the directory run: cp lmdbal/packaging/Archlinux/PKGBUILD aur/ @@ -77,4 +77,4 @@ jobs: run: | git add PKGBUILD .SRCINFO git commit -m "${{ gitea.event.release.body }}" - GIT_SSH_COMMAND="ssh -i ../key -o 'IdentitiesOnly yes' -o 'StrictHostKeyChecking no'" git push + GIT_SSH_COMMAND="ssh -i ../key -o 'IdentitiesOnly yes' -o 'StrictHostKeyChecking no'" git push origin master From 7aaab5e80726b48e15c88c2788babe95f37d0278 Mon Sep 17 00:00:00 2001 From: blue Date: Tue, 3 Dec 2024 19:36:07 +0200 Subject: [PATCH 18/34] builds with different names to coexist --- .gitea/workflows/release.yml | 4 +-- CMakeLists.txt | 67 ++++++++++++++++++----------------- packaging/Archlinux/PKGBUILD | 8 ++--- src/CMakeLists.txt | 4 +-- src/serializer/CMakeLists.txt | 2 +- test/CMakeLists.txt | 2 +- 6 files changed, 45 insertions(+), 42 deletions(-) diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index d20a949..ad68d3f 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -12,7 +12,7 @@ jobs: package-name: lmdbal-qt5 description: LMDB Abstraction Layer, qt5 version depends: 'qt5-base' - flags: -D QT_VERSION_MAJOR=5 + flags: -D QT_VERSION_MAJOR=5 -D LMDBAL_NAME=LMDBAL-QT5 secrets: DEPLOY_TO_AUR_PRIVATE_KEY: ${{ secrets.DEPLOY_TO_AUR_PRIVATE_KEY }} DEPLOY_TO_AUR_USER_NAME: ${{ secrets.DEPLOY_TO_AUR_USER_NAME }} @@ -25,7 +25,7 @@ jobs: package-name: lmdbal-qt6 description: LMDB Abstraction Layer, qt6 version depends: 'qt6-base' - flags: -D QT_VERSION_MAJOR=6 + flags: -D QT_VERSION_MAJOR=6 -D LMDBAL_NAME=LMDBAL-QT5 secrets: DEPLOY_TO_AUR_PRIVATE_KEY: ${{ secrets.DEPLOY_TO_AUR_PRIVATE_KEY }} DEPLOY_TO_AUR_USER_NAME: ${{ secrets.DEPLOY_TO_AUR_USER_NAME }} diff --git a/CMakeLists.txt b/CMakeLists.txt index dcafaa1..a518d7f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,11 +5,12 @@ project(LMDBAL DESCRIPTION "LMDB (Lightning Memory-Mapped Database Manager) Abstraction Layer" LANGUAGES CXX ) -string(TOLOWER ${PROJECT_NAME} PROJECT_LOW) cmake_policy(SET CMP0076 NEW) cmake_policy(SET CMP0079 NEW) +set(LMDBAL_NAME ${PROJECT_NAME} CACHE STRING "Override for library name and install path") + option(BUILD_STATIC "Builds library as static library" OFF) option(BUILD_TESTS "Builds tests" OFF) option(BUILD_DOC_MAN "Builds man page documentation" OFF) @@ -25,6 +26,8 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +string(TOLOWER ${LMDBAL_NAME} LMDBAL_NAME_LOW) + if (NOT DEFINED QT_VERSION_MAJOR) find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core) endif() @@ -38,9 +41,9 @@ if (NOT CMAKE_BUILD_TYPE) endif () if (BUILD_STATIC) - add_library(${PROJECT_NAME} STATIC) + add_library(${LMDBAL_NAME} STATIC) else () - add_library(${PROJECT_NAME} SHARED) + add_library(${LMDBAL_NAME} SHARED) endif() if (CMAKE_BUILD_TYPE STREQUAL "Release") @@ -52,21 +55,21 @@ elseif (CMAKE_BUILD_TYPE STREQUAL "Debug") endif() message("Compilation options: " ${COMPILE_OPTIONS}) -target_compile_options(${PROJECT_NAME} PRIVATE ${COMPILE_OPTIONS}) +target_compile_options(${LMDBAL_NAME} PRIVATE ${COMPILE_OPTIONS}) -set_property(TARGET ${PROJECT_NAME} PROPERTY VERSION ${version}) -set_property(TARGET ${PROJECT_NAME} PROPERTY SOVERSION 1) -set_property(TARGET ${PROJECT_NAME} PROPERTY EXPORT_NAME ${PROJECT_NAME}) -set_property(TARGET ${PROJECT_NAME} PROPERTY INTERFACE_${PROJECT_NAME}_MAJOR_VERSION 1) -set_property(TARGET ${PROJECT_NAME} APPEND PROPERTY - COMPATIBLE_INTERFACE_STRING ${PROJECT_NAME}_MAJOR_VERSION +set_property(TARGET ${LMDBAL_NAME} PROPERTY VERSION ${version}) +set_property(TARGET ${LMDBAL_NAME} PROPERTY SOVERSION 1) +set_property(TARGET ${LMDBAL_NAME} PROPERTY EXPORT_NAME ${LMDBAL_NAME}) +set_property(TARGET ${LMDBAL_NAME} PROPERTY INTERFACE_${LMDBAL_NAME}_MAJOR_VERSION 1) +set_property(TARGET ${LMDBAL_NAME} APPEND PROPERTY + COMPATIBLE_INTERFACE_STRING ${LMDBAL_NAME}_MAJOR_VERSION ) if (UNIX) - set_property(TARGET ${PROJECT_NAME} PROPERTY INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/${PROJECT_LOW}") - set_property(TARGET ${PROJECT_NAME} PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) - set_property(TARGET ${PROJECT_NAME} PROPERTY SKIP_BUILD_RPATH FALSE) - set_property(TARGET ${PROJECT_NAME} PROPERTY BUILD_WITH_INSTALL_RPATH FALSE) + set_property(TARGET ${LMDBAL_NAME} PROPERTY INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/${LMDBAL_NAME_LOW}") + set_property(TARGET ${LMDBAL_NAME} PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) + set_property(TARGET ${LMDBAL_NAME} PROPERTY SKIP_BUILD_RPATH FALSE) + set_property(TARGET ${LMDBAL_NAME} PROPERTY BUILD_WITH_INSTALL_RPATH FALSE) endif() add_subdirectory(src) @@ -84,47 +87,47 @@ if (BUILD_TESTS) endif () target_include_directories( - ${PROJECT_NAME} + ${LMDBAL_NAME} PUBLIC - $ + $ $ $ ) -target_include_directories(${PROJECT_NAME} PRIVATE ${Qt${QT_VERSION_MAJOR}_INCLUDE_DIRS}) -target_include_directories(${PROJECT_NAME} PRIVATE ${Qt${QT_VERSION_MAJOR}Core_INCLUDE_DIRS}) +target_include_directories(${LMDBAL_NAME} PRIVATE ${Qt${QT_VERSION_MAJOR}_INCLUDE_DIRS}) +target_include_directories(${LMDBAL_NAME} PRIVATE ${Qt${QT_VERSION_MAJOR}Core_INCLUDE_DIRS}) target_link_libraries( - ${PROJECT_NAME} + ${LMDBAL_NAME} Qt${QT_VERSION_MAJOR}::Core lmdb ) configure_package_config_file( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.cmake.in - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_LOW}Config.cmake" - INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_LOW} + "${CMAKE_CURRENT_BINARY_DIR}/${LMDBAL_NAME_LOW}Config.cmake" + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${LMDBAL_NAME_LOW} ) write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_LOW}ConfigVersion.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${LMDBAL_NAME_LOW}ConfigVersion.cmake" VERSION "${version}" COMPATIBILITY AnyNewerVersion ) -install(TARGETS ${PROJECT_NAME} - EXPORT ${PROJECT_LOW}Targets +install(TARGETS ${LMDBAL_NAME} + EXPORT ${LMDBAL_NAME_LOW}Targets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_LOW} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${LMDBAL_NAME_LOW} ) -install(EXPORT ${PROJECT_LOW}Targets - FILE ${PROJECT_LOW}Targets.cmake - NAMESPACE ${PROJECT_NAME}:: - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_LOW} +install(EXPORT ${LMDBAL_NAME_LOW}Targets + FILE ${LMDBAL_NAME_LOW}Targets.cmake + NAMESPACE ${LMDBAL_NAME}:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${LMDBAL_NAME_LOW} ) install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_LOW}Config.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_LOW}ConfigVersion.cmake" - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_LOW} + "${CMAKE_CURRENT_BINARY_DIR}/${LMDBAL_NAME_LOW}Config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${LMDBAL_NAME_LOW}ConfigVersion.cmake" + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${LMDBAL_NAME_LOW} ) diff --git a/packaging/Archlinux/PKGBUILD b/packaging/Archlinux/PKGBUILD index f1dba99..28ef6d6 100644 --- a/packaging/Archlinux/PKGBUILD +++ b/packaging/Archlinux/PKGBUILD @@ -1,7 +1,7 @@ # Maintainer: Yury Gubich pkgname=lmdbal pkgver=1.0.0 -pkgrel=1 +pkgrel=2 pkgdesc="LMDB Abstraction Layer" arch=('i686' 'x86_64') url="https://git.macaw.me/blue/lmdbal" @@ -10,14 +10,14 @@ depends=( 'lmdb' ) makedepends=('cmake>=3.16' 'gcc') optdepends=() -source=("$pkgname-$pkgver.tar.gz::https://git.macaw.me/blue/$pkgname/archive/$pkgver.tar.gz") +source=("lmdbal-$pkgver.tar.gz::https://git.macaw.me/blue/lmdbal/archive/$pkgver.tar.gz") sha256sums=('SKIP') build() { - cd "$srcdir/$pkgname" + cd "$srcdir/lmdbal" cmake . -D CMAKE_INSTALL_PREFIX=/usr -D CMAKE_BUILD_TYPE=Release cmake --build . } package() { - cd "$srcdir/$pkgname" + cd "$srcdir/lmdbal" DESTDIR="$pkgdir/" cmake --install . } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 956e6b0..9332fd8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -18,8 +18,8 @@ set(HEADERS transaction.h ) -target_sources(${PROJECT_NAME} PRIVATE ${SOURCES}) +target_sources(${LMDBAL_NAME} PRIVATE ${SOURCES}) add_subdirectory(serializer) -install(FILES ${HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_LOW}) +install(FILES ${HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${LMDBAL_NAME_LOW}) diff --git a/src/serializer/CMakeLists.txt b/src/serializer/CMakeLists.txt index 0c0a633..2df8e47 100644 --- a/src/serializer/CMakeLists.txt +++ b/src/serializer/CMakeLists.txt @@ -16,4 +16,4 @@ set(HEADERS serializer_qbytearray.hpp ) -install(FILES ${HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_LOW}) +install(FILES ${HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${LMDBAL_NAME_LOW}) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 93d54e3..63e0701 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -20,7 +20,7 @@ target_include_directories(runUnitTests PRIVATE ${Qt${QT_VERSION_MAJOR}Core_INCL target_link_libraries( runUnitTests GTest::gtest_main - ${PROJECT_NAME} + ${LMDBAL_NAME} Qt${QT_VERSION_MAJOR}::Core ) include(GoogleTest) From 02946bbe984c98038f5581bb78be58d08ebb756f Mon Sep 17 00:00:00 2001 From: blue Date: Tue, 3 Dec 2024 19:45:15 +0200 Subject: [PATCH 19/34] Typo in the build CI --- .gitea/workflows/main.yml | 4 ++-- .gitea/workflows/release.yml | 2 +- CHANGELOG.md | 1 + packaging/Archlinux/PKGBUILD | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.gitea/workflows/main.yml b/.gitea/workflows/main.yml index 066f206..ed68bb0 100644 --- a/.gitea/workflows/main.yml +++ b/.gitea/workflows/main.yml @@ -10,13 +10,13 @@ jobs: name: Test LMDBAL with qt5 uses: ./.gitea/workflows/test.yml with: - flags: -D QT_VERSION_MAJOR=5 + flags: -D QT_VERSION_MAJOR=5 -D LMDBAL_NAME=LMDBAL-QT5 test-qt6: name: Test LMDBAL with qt6 uses: ./.gitea/workflows/test.yml with: - flags: -D QT_VERSION_MAJOR=6 + flags: -D QT_VERSION_MAJOR=6 -D LMDBAL_NAME=LMDBAL-QT6 docs: name: Release documentation diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index ad68d3f..8cdc744 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -25,7 +25,7 @@ jobs: package-name: lmdbal-qt6 description: LMDB Abstraction Layer, qt6 version depends: 'qt6-base' - flags: -D QT_VERSION_MAJOR=6 -D LMDBAL_NAME=LMDBAL-QT5 + flags: -D QT_VERSION_MAJOR=6 -D LMDBAL_NAME=LMDBAL-QT6 secrets: DEPLOY_TO_AUR_PRIVATE_KEY: ${{ secrets.DEPLOY_TO_AUR_PRIVATE_KEY }} DEPLOY_TO_AUR_USER_NAME: ${{ secrets.DEPLOY_TO_AUR_USER_NAME }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 32ea9a4..8194b28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ # LMDBAL 0.5.4 (November 30, 2024) ### Improvements - Technical release just to resolve build issues +- Now different flavours of the package can coexist in the system # LMDBAL 0.5.3 (November 14, 2023) ### Improvements diff --git a/packaging/Archlinux/PKGBUILD b/packaging/Archlinux/PKGBUILD index 28ef6d6..6c80d5a 100644 --- a/packaging/Archlinux/PKGBUILD +++ b/packaging/Archlinux/PKGBUILD @@ -1,7 +1,7 @@ # Maintainer: Yury Gubich pkgname=lmdbal pkgver=1.0.0 -pkgrel=2 +pkgrel=3 pkgdesc="LMDB Abstraction Layer" arch=('i686' 'x86_64') url="https://git.macaw.me/blue/lmdbal" From 43d490080952bfe3ad07611da48ee8d8d455eac3 Mon Sep 17 00:00:00 2001 From: blue Date: Fri, 13 Dec 2024 20:27:47 +0200 Subject: [PATCH 20/34] Some more build fixes --- .gitea/workflows/release.yml | 4 ++-- README.md | 1 + cmake/Config.cmake.in | 4 ++-- packaging/Archlinux/PKGBUILD | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 8cdc744..733957a 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -12,7 +12,7 @@ jobs: package-name: lmdbal-qt5 description: LMDB Abstraction Layer, qt5 version depends: 'qt5-base' - flags: -D QT_VERSION_MAJOR=5 -D LMDBAL_NAME=LMDBAL-QT5 + flags: -D QT_VERSION_MAJOR=5 -D LMDBAL_NAME=LMDBALQT5 secrets: DEPLOY_TO_AUR_PRIVATE_KEY: ${{ secrets.DEPLOY_TO_AUR_PRIVATE_KEY }} DEPLOY_TO_AUR_USER_NAME: ${{ secrets.DEPLOY_TO_AUR_USER_NAME }} @@ -25,7 +25,7 @@ jobs: package-name: lmdbal-qt6 description: LMDB Abstraction Layer, qt6 version depends: 'qt6-base' - flags: -D QT_VERSION_MAJOR=6 -D LMDBAL_NAME=LMDBAL-QT6 + flags: -D QT_VERSION_MAJOR=6 -D LMDBAL_NAME=LMDBALQT6 secrets: DEPLOY_TO_AUR_PRIVATE_KEY: ${{ secrets.DEPLOY_TO_AUR_PRIVATE_KEY }} DEPLOY_TO_AUR_USER_NAME: ${{ secrets.DEPLOY_TO_AUR_USER_NAME }} diff --git a/README.md b/README.md index 36b620e..9c6a152 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,7 @@ Here is the list of keys you can pass to configuration phase of `cmake ..`: - `BUILD_DOC` - `True` build doxygen documentation, `False` does not (default is `False`); - `BUILD_DOXYGEN_AWESOME` - `True` build doxygen awesome theme if `BUILD_DOC` is also `True` (default is `False`); - `QT_VERSION_MAJOR` - `5` links against Qt5, `6` links agains Qt6, there is no default, so, if you didn't specify it the project will chose automatically; +- `LMDBAL_NAME` - `LMDBAL` builds main target with this name, also install path witll be this name lowercase, usefull if you want to build `LMDBAL-QT6` not to conflict with `LMDBAL-QT5`; #### Running tests diff --git a/cmake/Config.cmake.in b/cmake/Config.cmake.in index 8fea032..f470d3d 100644 --- a/cmake/Config.cmake.in +++ b/cmake/Config.cmake.in @@ -1,5 +1,5 @@ @PACKAGE_INIT@ -include("${CMAKE_CURRENT_LIST_DIR}/lmdbalTargets.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/@LMDBAL_NAME_LOW@Targets.cmake") -check_required_components(lmdbal) +check_required_components(@LMDBAL_NAME_LOW@) diff --git a/packaging/Archlinux/PKGBUILD b/packaging/Archlinux/PKGBUILD index 6c80d5a..38b3e55 100644 --- a/packaging/Archlinux/PKGBUILD +++ b/packaging/Archlinux/PKGBUILD @@ -1,7 +1,7 @@ # Maintainer: Yury Gubich pkgname=lmdbal pkgver=1.0.0 -pkgrel=3 +pkgrel=4 pkgdesc="LMDB Abstraction Layer" arch=('i686' 'x86_64') url="https://git.macaw.me/blue/lmdbal" From 56d35d4832b0ddd1a48dea5e602eb87619252f8d Mon Sep 17 00:00:00 2001 From: blue Date: Tue, 17 Dec 2024 20:03:48 +0200 Subject: [PATCH 21/34] pragma once and minor change in transactions --- CHANGELOG.md | 4 ++++ packaging/Archlinux/PKGBUILD | 2 +- src/base.cpp | 24 +++++++++++------------- src/base.h | 7 ++----- src/cache.h | 5 +---- src/cache.hpp | 5 +---- src/cursor.h | 5 +---- src/cursor.hpp | 7 ++----- src/exceptions.h | 5 +---- src/operators.hpp | 5 +---- src/serializer/serializer.h | 6 ++---- src/serializer/serializer.hpp | 5 +---- src/serializer/serializer_double.hpp | 5 +---- src/serializer/serializer_float.hpp | 8 +------- src/serializer/serializer_int16.hpp | 5 +---- src/serializer/serializer_int32.hpp | 8 +------- src/serializer/serializer_int64.hpp | 8 +------- src/serializer/serializer_int8.hpp | 8 +------- src/serializer/serializer_qbytearray.hpp | 9 +-------- src/serializer/serializer_qstring.hpp | 10 +--------- src/serializer/serializer_stdstring.hpp | 9 +-------- src/serializer/serializer_uint16.hpp | 7 +------ src/serializer/serializer_uint32.hpp | 5 +---- src/serializer/serializer_uint64.hpp | 6 +----- src/serializer/serializer_uint8.hpp | 8 +------- src/storage.h | 5 +---- src/storage.hpp | 5 +---- src/transaction.cpp | 18 ++++++++++++++++++ src/transaction.h | 18 ++++++++++++++++++ 29 files changed, 79 insertions(+), 143 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8194b28..879f52d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +# LMDBAL 0.6.0 (UNRELEASED) +### Improvements +- Less dereferencing + # LMDBAL 0.5.4 (November 30, 2024) ### Improvements - Technical release just to resolve build issues diff --git a/packaging/Archlinux/PKGBUILD b/packaging/Archlinux/PKGBUILD index 38b3e55..c83a648 100644 --- a/packaging/Archlinux/PKGBUILD +++ b/packaging/Archlinux/PKGBUILD @@ -10,7 +10,7 @@ depends=( 'lmdb' ) makedepends=('cmake>=3.16' 'gcc') optdepends=() -source=("lmdbal-$pkgver.tar.gz::https://git.macaw.me/blue/lmdbal/archive/$pkgver.tar.gz") +source=("lmdbal-$pkgver-$pkgrel.tar.gz::https://git.macaw.me/blue/lmdbal/archive/$pkgver.tar.gz") sha256sums=('SKIP') build() { cd "$srcdir/lmdbal" diff --git a/src/base.cpp b/src/base.cpp index 149343b..ef932fd 100644 --- a/src/base.cpp +++ b/src/base.cpp @@ -43,7 +43,7 @@ LMDBAL::Base::Base(const QString& _name, uint16_t _mapSize): size(_mapSize), environment(), storages(), - transactions(new Transactions()) + transactions() {} /** @@ -52,8 +52,6 @@ LMDBAL::Base::Base(const QString& _name, uint16_t _mapSize): LMDBAL::Base::~Base() { close(); - delete transactions; - for (const std::pair& pair : storages) delete pair.second; } @@ -68,14 +66,14 @@ LMDBAL::Base::~Base() { */ void LMDBAL::Base::close() { if (opened) { - for (const LMDBAL::TransactionID id : *transactions) + for (const LMDBAL::TransactionID id : transactions) abortTransaction(id, emptyName); for (const std::pair& pair : storages) pair.second->close(); mdb_env_close(environment); - transactions->clear(); + transactions.clear(); opened = false; } } @@ -301,7 +299,7 @@ LMDBAL::TransactionID LMDBAL::Base::beginReadOnlyTransaction(const std::string& throw Closed("beginReadOnlyTransaction", name, storageName); TransactionID txn = beginPrivateReadOnlyTransaction(storageName); - transactions->emplace(txn); + transactions.emplace(txn); for (const std::pair& pair : storages) pair.second->transactionStarted(txn, true); @@ -325,7 +323,7 @@ LMDBAL::TransactionID LMDBAL::Base::beginTransaction(const std::string& storageN throw Closed("beginTransaction", name, storageName); TransactionID txn = beginPrivateTransaction(storageName); - transactions->emplace(txn); + transactions.emplace(txn); for (const std::pair& pair : storages) pair.second->transactionStarted(txn, false); @@ -349,15 +347,15 @@ void LMDBAL::Base::abortTransaction(LMDBAL::TransactionID id, const std::string& if (!opened) throw Closed("abortTransaction", name, storageName); - Transactions::iterator itr = transactions->find(id); - if (itr == transactions->end()) //TODO may be it's a good idea to make an exception class for this + Transactions::iterator itr = transactions.find(id); + if (itr == transactions.end()) //TODO may be it's a good idea to make an exception class for this throw Unknown(name, "unable to abort transaction: transaction was not found", storageName); abortPrivateTransaction(id, storageName); for (const std::pair& pair : storages) pair.second->transactionAborted(id); - transactions->erase(itr); + transactions.erase(itr); } /** @@ -376,15 +374,15 @@ void LMDBAL::Base::commitTransaction(LMDBAL::TransactionID id, const std::string if (!opened) throw Closed("abortTransaction", name, storageName); - Transactions::iterator itr = transactions->find(id); - if (itr == transactions->end()) //TODO may be it's a good idea to make an exception class for this + Transactions::iterator itr = transactions.find(id); + if (itr == transactions.end()) //TODO may be it's a good idea to make an exception class for this throw Unknown(name, "unable to commit transaction: transaction was not found", storageName); commitPrivateTransaction(id, storageName); for (const std::pair& pair : storages) pair.second->transactionCommited(id); - transactions->erase(itr); + transactions.erase(itr); } /** diff --git a/src/base.h b/src/base.h index c99bf21..749683f 100644 --- a/src/base.h +++ b/src/base.h @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -#ifndef LMDBAL_BASE_H -#define LMDBAL_BASE_H +#pragma once #include #include @@ -106,7 +105,7 @@ private: uint16_t size; /**<\brief lmdb map size in MiB*/ MDB_env* environment; /**<\brief lmdb environment handle*/ Storages storages; /**<\brief Registered storages and caches*/ - Transactions* transactions; /**<\brief Active public transactions*/ + mutable Transactions transactions; /**<\brief Active public transactions*/ inline static const std::string emptyName = ""; /**<\brief Empty string for general fallback purposes*/ }; @@ -215,5 +214,3 @@ template LMDBAL::Cache* LMDBAL::Base::getCache(const std::string& storageName) { return static_cast*>(storages.at(storageName)); } - -#endif //LMDBAL_BASE_H diff --git a/src/cache.h b/src/cache.h index 0883e65..0084984 100644 --- a/src/cache.h +++ b/src/cache.h @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -#ifndef LMDBAL_CACHE_H -#define LMDBAL_CACHE_H +#pragma once #include #include @@ -134,5 +133,3 @@ protected: } #include "cache.hpp" - -#endif // LMDBAL_CACHE_H diff --git a/src/cache.hpp b/src/cache.hpp index e3c6d60..29af6d0 100644 --- a/src/cache.hpp +++ b/src/cache.hpp @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -#ifndef LMDBAL_CACHE_HPP -#define LMDBAL_CACHE_HPP +#pragma once #include "cache.h" #include "exceptions.h" @@ -898,5 +897,3 @@ void LMDBAL::Cache::destroyTransactionEntry(const Entry& entry) const { break; } } - -#endif //LMDBAL_CACHE_HPP diff --git a/src/cursor.h b/src/cursor.h index c3ff362..c77d4e9 100644 --- a/src/cursor.h +++ b/src/cursor.h @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -#ifndef LMDBAL_CURSOR_H -#define LMDBAL_CURSOR_H +#pragma once #include @@ -105,5 +104,3 @@ private: #include "cursor.hpp" - -#endif //LMDBAL_CURSOR_H diff --git a/src/cursor.hpp b/src/cursor.hpp index 519bd41..0e0dc7b 100644 --- a/src/cursor.hpp +++ b/src/cursor.hpp @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -#ifndef LMDBAL_CURSOR_HPP -#define LMDBAL_CURSOR_HPP +#pragma once #include "cursor.h" #include @@ -482,7 +481,7 @@ void LMDBAL::Cursor::prev (K& key, V& value) { * \exception LMDBAL::Unknown thrown if there was some unexpected problem with lmdb */ template -void LMDBAL::Cursor::current (K& key, V& value) const { +void LMDBAL::Cursor::current (K& key, V& value) const { operateCursorRead(key, value, MDB_GET_CURRENT, currentMethodName, currentOperationName); } @@ -657,5 +656,3 @@ void LMDBAL::Cursor::operateCursorRead( else storage->discoveredRecord(key, value, storage->_mdbCursorTxn(cursor)); } - -#endif //LMDBAL_CURSOR_HPP diff --git a/src/exceptions.h b/src/exceptions.h index 58bbea4..6f03bd8 100644 --- a/src/exceptions.h +++ b/src/exceptions.h @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -#ifndef LMDBAL_EXCEPTIONS_H -#define LMDBAL_EXCEPTIONS_H +#pragma once #include #include @@ -237,5 +236,3 @@ private: }; } - -#endif //LMDBAL_EXCEPTIONS_H diff --git a/src/operators.hpp b/src/operators.hpp index 80353ac..9abb2d0 100644 --- a/src/operators.hpp +++ b/src/operators.hpp @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -#ifndef LMDBAL_OPERATORS_HPP -#define LMDBAL_OPERATORS_HPP +#pragma once #include #include @@ -209,5 +208,3 @@ QDataStream& operator >> (QDataStream &in, std::list& container) { return in; } - -#endif //LMDBAL_OPERATORS_HPP diff --git a/src/serializer/serializer.h b/src/serializer/serializer.h index 734ac51..bd7496a 100644 --- a/src/serializer/serializer.h +++ b/src/serializer/serializer.h @@ -16,8 +16,8 @@ * along with this program. If not, see . */ -#ifndef LMDBAL_SERIALIZER_H -#define LMDBAL_SERIALIZER_H +#pragma once + #include @@ -68,5 +68,3 @@ private: #include "serializer_stdstring.hpp" #include "serializer_qstring.hpp" #include "serializer_qbytearray.hpp" - -#endif // LMDBAL_SERIALIZER_H diff --git a/src/serializer/serializer.hpp b/src/serializer/serializer.hpp index 80f4d90..b3353f5 100644 --- a/src/serializer/serializer.hpp +++ b/src/serializer/serializer.hpp @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -#ifndef LMDBAL_SERIALIZER_HPP -#define LMDBAL_SERIALIZER_HPP +#pragma once #include "serializer.h" @@ -159,5 +158,3 @@ MDB_val LMDBAL::Serializer::getData() { return val; } - -#endif //LMDBAL_SERIALIZER_HPP diff --git a/src/serializer/serializer_double.hpp b/src/serializer/serializer_double.hpp index 4582459..be943b8 100644 --- a/src/serializer/serializer_double.hpp +++ b/src/serializer/serializer_double.hpp @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -#ifndef LMDBAL_SERIALIZER_DOUBLE_HPP -#define LMDBAL_SERIALIZER_DOUBLE_HPP +#pragma once namespace LMDBAL { @@ -53,7 +52,5 @@ private: } -#endif //LMDBAL_SERIALIZER_DOUBLE_HPP - diff --git a/src/serializer/serializer_float.hpp b/src/serializer/serializer_float.hpp index be2c72d..f4b84a9 100644 --- a/src/serializer/serializer_float.hpp +++ b/src/serializer/serializer_float.hpp @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -#ifndef LMDBAL_SERIALIZER_FLOAT_HPP -#define LMDBAL_SERIALIZER_FLOAT_HPP +#pragma once namespace LMDBAL { @@ -52,8 +51,3 @@ private: }; } - -#endif //LMDBAL_SERIALIZER_FLOAT_HPP - - - diff --git a/src/serializer/serializer_int16.hpp b/src/serializer/serializer_int16.hpp index 17e5ea2..0baaaad 100644 --- a/src/serializer/serializer_int16.hpp +++ b/src/serializer/serializer_int16.hpp @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -#ifndef LMDBAL_SERIALIZER_INT16_HPP -#define LMDBAL_SERIALIZER_INT16_HPP +#pragma once #include @@ -54,5 +53,3 @@ private: }; } - -#endif //LMDBAL_SERIALIZER_INT16_HPP diff --git a/src/serializer/serializer_int32.hpp b/src/serializer/serializer_int32.hpp index 78405c5..339dfea 100644 --- a/src/serializer/serializer_int32.hpp +++ b/src/serializer/serializer_int32.hpp @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -#ifndef LMDBAL_SERIALIZER_INT32_HPP -#define LMDBAL_SERIALIZER_INT32_HPP +#pragma once #include @@ -54,8 +53,3 @@ private: }; } - -#endif //LMDBAL_SERIALIZER_INT32_HPP - - - diff --git a/src/serializer/serializer_int64.hpp b/src/serializer/serializer_int64.hpp index 4992ae1..107d102 100644 --- a/src/serializer/serializer_int64.hpp +++ b/src/serializer/serializer_int64.hpp @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -#ifndef LMDBAL_SERIALIZER_INT64_HPP -#define LMDBAL_SERIALIZER_INT64_HPP +#pragma once #include @@ -54,8 +53,3 @@ private: }; } - -#endif //LMDBAL_SERIALIZER_INT64_HPP - - - diff --git a/src/serializer/serializer_int8.hpp b/src/serializer/serializer_int8.hpp index eafd5c6..6f68f18 100644 --- a/src/serializer/serializer_int8.hpp +++ b/src/serializer/serializer_int8.hpp @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -#ifndef LMDBAL_SERIALIZER_INT8_HPP -#define LMDBAL_SERIALIZER_INT8_HPP +#pragma once #include @@ -54,8 +53,3 @@ private: }; } - -#endif //LMDBAL_SERIALIZER_INT8_HPP - - - diff --git a/src/serializer/serializer_qbytearray.hpp b/src/serializer/serializer_qbytearray.hpp index 6f1c5d1..daf3027 100644 --- a/src/serializer/serializer_qbytearray.hpp +++ b/src/serializer/serializer_qbytearray.hpp @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -#ifndef LMDBAL_SERIALIZER_QBYTEARRAY_HPP -#define LMDBAL_SERIALIZER_QBYTEARRAY_HPP +#pragma once #include @@ -56,9 +55,3 @@ private: }; } - -#endif //LMDBAL_SERIALIZER_QBYTEARRAY_HPP - - - - diff --git a/src/serializer/serializer_qstring.hpp b/src/serializer/serializer_qstring.hpp index 1a36fcb..fb9310e 100644 --- a/src/serializer/serializer_qstring.hpp +++ b/src/serializer/serializer_qstring.hpp @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -#ifndef LMDBAL_SERIALIZER_QSTRING_HPP -#define LMDBAL_SERIALIZER_QSTRING_HPP +#pragma once #include #include @@ -56,10 +55,3 @@ private: }; } - -#endif //LMDBAL_SERIALIZER_QSTRING_HPP - - - - - diff --git a/src/serializer/serializer_stdstring.hpp b/src/serializer/serializer_stdstring.hpp index 416cfd6..1856e8c 100644 --- a/src/serializer/serializer_stdstring.hpp +++ b/src/serializer/serializer_stdstring.hpp @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -#ifndef LMDBAL_SERIALIZER_STDSTRING_HPP -#define LMDBAL_SERIALIZER_STDSTRING_HPP +#pragma once #include @@ -54,9 +53,3 @@ private: }; } - -#endif //LMDBAL_SERIALIZER_STDSTRING_HPP - - - - diff --git a/src/serializer/serializer_uint16.hpp b/src/serializer/serializer_uint16.hpp index d648695..8284f27 100644 --- a/src/serializer/serializer_uint16.hpp +++ b/src/serializer/serializer_uint16.hpp @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -#ifndef LMDBAL_SERIALIZER_UINT16_HPP -#define LMDBAL_SERIALIZER_UINT16_HPP +#pragma once #include @@ -54,7 +53,3 @@ private: }; } - -#endif //LMDBAL_SERIALIZER_UINT16_HPP - - diff --git a/src/serializer/serializer_uint32.hpp b/src/serializer/serializer_uint32.hpp index 211f151..83e9d35 100644 --- a/src/serializer/serializer_uint32.hpp +++ b/src/serializer/serializer_uint32.hpp @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -#ifndef LMDBAL_SERIALIZER_UINT32_HPP -#define LMDBAL_SERIALIZER_UINT32_HPP +#pragma once #include @@ -54,5 +53,3 @@ private: }; } - -#endif //LMDBAL_SERIALIZER_UINT32_HPP diff --git a/src/serializer/serializer_uint64.hpp b/src/serializer/serializer_uint64.hpp index 250ec03..f486082 100644 --- a/src/serializer/serializer_uint64.hpp +++ b/src/serializer/serializer_uint64.hpp @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -#ifndef LMDBAL_SERIALIZER_UINT64_HPP -#define LMDBAL_SERIALIZER_UINT64_HPP +#pragma once #include @@ -54,6 +53,3 @@ private: }; } - -#endif //LMDBAL_SERIALIZER_UINT64_HPP - diff --git a/src/serializer/serializer_uint8.hpp b/src/serializer/serializer_uint8.hpp index 31daca6..0bc73ab 100644 --- a/src/serializer/serializer_uint8.hpp +++ b/src/serializer/serializer_uint8.hpp @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -#ifndef LMDBAL_SERIALIZER_UINT8_HPP -#define LMDBAL_SERIALIZER_UINT8_HPP +#pragma once #include @@ -54,8 +53,3 @@ private: }; } - -#endif //LMDBAL_SERIALIZER_UINT8_HPP - - - diff --git a/src/storage.h b/src/storage.h index 82735a7..c077500 100644 --- a/src/storage.h +++ b/src/storage.h @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -#ifndef LMDBAL_STORAGE_H -#define LMDBAL_STORAGE_H +#pragma once #include #include @@ -199,5 +198,3 @@ protected: } #include "storage.hpp" - -#endif //LMDBAL_STORAGE_H diff --git a/src/storage.hpp b/src/storage.hpp index 91756b3..e56e91a 100644 --- a/src/storage.hpp +++ b/src/storage.hpp @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -#ifndef LMDBAL_STORAGE_HPP -#define LMDBAL_STORAGE_HPP +#pragma once #include "storage.h" #include "exceptions.h" @@ -1182,5 +1181,3 @@ template<> inline std::string LMDBAL::iStorage::toString(const std::string& value) { return value; } - -#endif //LMDBAL_STORAGE_HPP diff --git a/src/transaction.cpp b/src/transaction.cpp index 3632ad6..3d7e3c0 100644 --- a/src/transaction.cpp +++ b/src/transaction.cpp @@ -1,3 +1,21 @@ +/* + * LMDB Abstraction Layer. + * Copyright (C) 2023 Yury Gubich + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "transaction.h" /** diff --git a/src/transaction.h b/src/transaction.h index 43bb69e..59b6ae9 100644 --- a/src/transaction.h +++ b/src/transaction.h @@ -1,3 +1,21 @@ +/* + * LMDB Abstraction Layer. + * Copyright (C) 2023 Yury Gubich + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #pragma once #include "base.h" From 68ea7df6a9fc515487d1ee9a98165b3bbf1aa7e8 Mon Sep 17 00:00:00 2001 From: blue Date: Sun, 22 Dec 2024 19:39:35 +0200 Subject: [PATCH 22/34] Transactions now get closed with the database --- CHANGELOG.md | 4 +++ CMakeLists.txt | 2 +- src/base.cpp | 50 ++++++++++++++++++------------------- src/base.h | 2 +- src/exceptions.h | 2 +- src/transaction.cpp | 43 +++++++++++++++++++++++++++---- src/transaction.h | 2 ++ test/cachetransaction.cpp | 23 +++++++++++++++++ test/storagetransaction.cpp | 24 ++++++++++++++++++ 9 files changed, 118 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 879f52d..608c121 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ # LMDBAL 0.6.0 (UNRELEASED) ### Improvements - Less dereferencing +- Transactions are now closed with the database + +### Bug fixes +- SIGSEGV on closing database with opened transactions # LMDBAL 0.5.4 (November 30, 2024) ### Improvements diff --git a/CMakeLists.txt b/CMakeLists.txt index a518d7f..97b21ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.16) project(LMDBAL - VERSION 0.5.4 + VERSION 0.6.0 DESCRIPTION "LMDB (Lightning Memory-Mapped Database Manager) Abstraction Layer" LANGUAGES CXX ) diff --git a/src/base.cpp b/src/base.cpp index ef932fd..ce28975 100644 --- a/src/base.cpp +++ b/src/base.cpp @@ -66,8 +66,10 @@ LMDBAL::Base::~Base() { */ void LMDBAL::Base::close() { if (opened) { - for (const LMDBAL::TransactionID id : transactions) - abortTransaction(id, emptyName); + for (const std::pair pair : transactions) { + abortTransaction(pair.first, emptyName); + pair.second->reset(); + } for (const std::pair& pair : storages) pair.second->close(); @@ -259,12 +261,13 @@ LMDBAL::WriteTransaction LMDBAL::Base::beginTransaction() { * \brief Aborts transaction * * Terminates transaction cancelling changes. - * This is an optimal way to terminate read-only transactions + * Every storage receives notification about this transaction being aborted. + * This is an optimal way to abort public transactions * * \param[in] id - transaction ID you want to abort * * \exception LMDBAL::Closed - thrown if the database is closed - * \exception LMDBAL::Unknown - thrown if transaction with given ID was not found or if something unexpected happened + * \exception LMDBAL::Unknown - thrown if something unexpected happened */ void LMDBAL::Base::abortTransaction(LMDBAL::TransactionID id) const { return abortTransaction(id, emptyName);} @@ -273,11 +276,13 @@ void LMDBAL::Base::abortTransaction(LMDBAL::TransactionID id) const { * \brief Commits transaction * * Terminates transaction applying changes. + * Every storage receives notification about this transaction being committed. + * This is an optimal way to commit public transactions * * \param[in] id - transaction ID you want to commit * * \exception LMDBAL::Closed - thrown if the database is closed - * \exception LMDBAL::Unknown - thrown if transaction with given ID was not found or if something unexpected happened + * \exception LMDBAL::Unknown - thrown if something unexpected happened */ void LMDBAL::Base::commitTransaction(LMDBAL::TransactionID id) { return commitTransaction(id, emptyName);} @@ -285,7 +290,9 @@ void LMDBAL::Base::commitTransaction(LMDBAL::TransactionID id) { /** * \brief Begins read-only transaction * - * This function is intended to be called from subordinate storage or cache + * This function is intended to be called from subordinate storage, cache, transaction or cursor. + * Every storage receives notification about this transaction being started. + * This is an optimal way to begin read-only public transactions. * * \param[in] storageName - name of the storage/cache that you begin transaction from, needed just to inform if something went wrong * @@ -299,7 +306,6 @@ LMDBAL::TransactionID LMDBAL::Base::beginReadOnlyTransaction(const std::string& throw Closed("beginReadOnlyTransaction", name, storageName); TransactionID txn = beginPrivateReadOnlyTransaction(storageName); - transactions.emplace(txn); for (const std::pair& pair : storages) pair.second->transactionStarted(txn, true); @@ -309,7 +315,9 @@ LMDBAL::TransactionID LMDBAL::Base::beginReadOnlyTransaction(const std::string& /** * \brief Begins writable transaction * - * This function is intended to be called from subordinate storage or cache + * This function is intended to be called from subordinate storage, cache, transaction or cursor. + * Every storage receives notification about this transaction being started. + * This is an optimal way to begin public transactions. * * \param[in] storageName - name of the storage/cache that you begin transaction from, needed just to inform if something went wrong * @@ -323,7 +331,6 @@ LMDBAL::TransactionID LMDBAL::Base::beginTransaction(const std::string& storageN throw Closed("beginTransaction", name, storageName); TransactionID txn = beginPrivateTransaction(storageName); - transactions.emplace(txn); for (const std::pair& pair : storages) pair.second->transactionStarted(txn, false); @@ -334,55 +341,46 @@ LMDBAL::TransactionID LMDBAL::Base::beginTransaction(const std::string& storageN * \brief Aborts transaction * * Terminates transaction cancelling changes. - * This is an optimal way to terminate read-only transactions. - * This function is intended to be called from subordinate storage or cache + * Every storage receives notification about this transaction being aborted. + * This is an optimal way to abort public transactions. + * This function is intended to be called from subordinate storage, cache, transaction or cursor * * \param[in] id - transaction ID you want to abort * \param[in] storageName - name of the storage/cache that you begin transaction from, needed just to inform if something went wrong * * \exception LMDBAL::Closed - thrown if the database is closed - * \exception LMDBAL::Unknown - thrown if transaction with given ID was not found or if something unexpected happened + * \exception LMDBAL::Unknown - thrown if something unexpected happened */ void LMDBAL::Base::abortTransaction(LMDBAL::TransactionID id, const std::string& storageName) const { if (!opened) throw Closed("abortTransaction", name, storageName); - Transactions::iterator itr = transactions.find(id); - if (itr == transactions.end()) //TODO may be it's a good idea to make an exception class for this - throw Unknown(name, "unable to abort transaction: transaction was not found", storageName); - abortPrivateTransaction(id, storageName); for (const std::pair& pair : storages) pair.second->transactionAborted(id); - - transactions.erase(itr); } /** * \brief Commits transaction * * Terminates transaction applying changes. - * This function is intended to be called from subordinate storage or cache + * Every storage receives notification about this transaction being committed. + * This is an optimal way to commit public transactions + * This function is intended to be called from subordinate storage, cache, transaction or cursor * * \param[in] id - transaction ID you want to commit * \param[in] storageName - name of the storage/cache that you begin transaction from, needed just to inform if something went wrong * * \exception LMDBAL::Closed - thrown if the database is closed - * \exception LMDBAL::Unknown - thrown if transaction with given ID was not found or if something unexpected happened + * \exception LMDBAL::Unknown - thrown if something unexpected happened */ void LMDBAL::Base::commitTransaction(LMDBAL::TransactionID id, const std::string& storageName) { if (!opened) throw Closed("abortTransaction", name, storageName); - Transactions::iterator itr = transactions.find(id); - if (itr == transactions.end()) //TODO may be it's a good idea to make an exception class for this - throw Unknown(name, "unable to commit transaction: transaction was not found", storageName); - commitPrivateTransaction(id, storageName); for (const std::pair& pair : storages) pair.second->transactionCommited(id); - - transactions.erase(itr); } /** diff --git a/src/base.h b/src/base.h index 749683f..de61ad7 100644 --- a/src/base.h +++ b/src/base.h @@ -85,7 +85,7 @@ public: private: typedef std::map Storages; /**<\brief Storage and Cache pointers are saved in the std::map*/ - typedef std::set Transactions; /**<\brief Piblic transaction IDs are saved in the std::set*/ + typedef std::map Transactions; /**<\brief Piblic transaction IDs are saved in the std::set*/ void commitTransaction(TransactionID id); void abortTransaction(TransactionID id) const; diff --git a/src/exceptions.h b/src/exceptions.h index 6f03bd8..d5f252b 100644 --- a/src/exceptions.h +++ b/src/exceptions.h @@ -40,7 +40,7 @@ public: /** * \brief Thrown if LMDBAL had issues creating or opening database directory */ -class Directory: public Exception { +class Directory : public Exception { public: /** * \brief Creates exception diff --git a/src/transaction.cpp b/src/transaction.cpp index 3d7e3c0..52e3933 100644 --- a/src/transaction.cpp +++ b/src/transaction.cpp @@ -50,7 +50,9 @@ LMDBAL::Transaction::Transaction(TransactionID txn, const Base* parent) : txn(txn), active(true), parent(parent) -{} +{ + parent->transactions[txn] = this; +} /** * \brief Moves transaction to a new object @@ -60,7 +62,11 @@ LMDBAL::Transaction::Transaction(Transaction&& other): active(other.active), parent(other.parent) { - other.active = false; + if (active) { + parent->transactions[txn] = this; + + other.reset(); + } } /** @@ -74,13 +80,20 @@ LMDBAL::Transaction::~Transaction() { * \brief Move-assigns transaction to the new object */ LMDBAL::Transaction& LMDBAL::Transaction::operator=(Transaction&& other) { + if (this == &other) + return *this; + terminate(); txn = other.txn; active = other.active; parent = other.parent; - other.active = false; + if (active) { + parent->transactions[txn] = this; + + other.reset(); + } return *this; } @@ -93,10 +106,22 @@ LMDBAL::Transaction& LMDBAL::Transaction::operator=(Transaction&& other) { void LMDBAL::Transaction::terminate() { if (active) { parent->abortTransaction(txn); - active = false; + + parent->transactions.erase(txn); + reset(); } } +/** + * \brief Resets inner transaction properties to inactive state + */ +void LMDBAL::Transaction::reset() { + active = false; + txn = nullptr; + parent = nullptr; +} + + /** * \brief Returns transaction states * @@ -150,6 +175,12 @@ LMDBAL::WriteTransaction::WriteTransaction(WriteTransaction&& other): Transaction(std::move(other)) {} +LMDBAL::WriteTransaction& LMDBAL::WriteTransaction::operator=(WriteTransaction&& other) { + Transaction::operator=(std::move(other)); + + return *this; +} + /** * \brief Aborts transaction cancelling all changes * @@ -167,6 +198,8 @@ void LMDBAL::WriteTransaction::abort() { void LMDBAL::WriteTransaction::commit() { if (active) { const_cast(parent)->commitTransaction(txn); - active = false; + + parent->transactions.erase(txn); + reset(); } } diff --git a/src/transaction.h b/src/transaction.h index 59b6ae9..81acad6 100644 --- a/src/transaction.h +++ b/src/transaction.h @@ -39,6 +39,7 @@ public: protected: Transaction(TransactionID txn, const Base* parent); + void reset(); protected: TransactionID txn; /**<\brief Transaction inner handler*/ @@ -53,6 +54,7 @@ public: explicit WriteTransaction(WriteTransaction&& other); WriteTransaction(const WriteTransaction& other) = delete; WriteTransaction& operator = (const WriteTransaction& other) = delete; + WriteTransaction& operator = (WriteTransaction&& other); void commit(); void abort(); diff --git a/test/cachetransaction.cpp b/test/cachetransaction.cpp index e0bac76..0fc259d 100644 --- a/test/cachetransaction.cpp +++ b/test/cachetransaction.cpp @@ -279,3 +279,26 @@ TEST_F(CacheTransactionsTest, RAIIResourceFree) { EXPECT_EQ(c1->getRecord(221), 14); } +TEST_F(CacheTransactionsTest, TransactionTerminationOnClose) { + LMDBAL::WriteTransaction txn = db->beginTransaction(); + + c1->addRecord(578, 4552, txn); + + EXPECT_EQ(c1->getRecord(578, txn), 4552); + EXPECT_EQ(c1->checkRecord(578), false); + + db->close(); + db->open(); + + EXPECT_EQ(txn.isActive(), false); + EXPECT_THROW(c1->getRecord(578, txn), LMDBAL::TransactionTerminated); + EXPECT_NO_THROW(txn.commit()); + + EXPECT_EQ(c1->checkRecord(578), false); + + txn = db->beginTransaction(); + c1->addRecord(578, 4552, txn); + txn.commit(); + + EXPECT_EQ(c1->getRecord(578), 4552); +} diff --git a/test/storagetransaction.cpp b/test/storagetransaction.cpp index 4f04931..237a7c6 100644 --- a/test/storagetransaction.cpp +++ b/test/storagetransaction.cpp @@ -277,3 +277,27 @@ TEST_F(StorageTransactionsTest, RAIIResourceFree) { std::cout << "checking the final result" << std::endl; EXPECT_EQ(t1->getRecord(221), 14); } + +TEST_F(StorageTransactionsTest, TransactionTerminationOnClose) { + LMDBAL::WriteTransaction txn = db->beginTransaction(); + + t1->addRecord(543, 229, txn); + + EXPECT_EQ(t1->getRecord(543, txn), 229); + EXPECT_EQ(t1->checkRecord(543), false); + + db->close(); + db->open(); + + EXPECT_EQ(txn.isActive(), false); + EXPECT_THROW(t1->getRecord(543, txn), LMDBAL::TransactionTerminated); + EXPECT_NO_THROW(txn.commit()); + + EXPECT_EQ(t1->checkRecord(543), false); + + txn = db->beginTransaction(); + t1->addRecord(543, 229, txn); + txn.commit(); + + EXPECT_EQ(t1->getRecord(543), 229); +} From e88efb458ffd8ef035837bdb71113f71d52614a4 Mon Sep 17 00:00:00 2001 From: blue Date: Tue, 24 Dec 2024 14:59:58 +0200 Subject: [PATCH 23/34] Cursors get closed after transaction that open them --- CHANGELOG.md | 1 + README.md | 5 +-- src/CMakeLists.txt | 1 + src/cursor.h | 5 +-- src/cursor.hpp | 80 +++++++++++++++++++++++++++++------------- src/icursor.h | 32 +++++++++++++++++ src/storage.cpp | 69 +++++++++++++++++++++++++++++++++++- src/storage.h | 38 +++++++++++--------- src/transaction.cpp | 23 +++++++++--- src/transaction.h | 9 +++-- test/cachecursor.cpp | 2 +- test/storagecursor.cpp | 16 ++++++++- 12 files changed, 225 insertions(+), 56 deletions(-) create mode 100644 src/icursor.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 608c121..356decc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Improvements - Less dereferencing - Transactions are now closed with the database +- Cursors are now closed if the public transaction that opened them got closed ### Bug fixes - SIGSEGV on closing database with opened transactions diff --git a/README.md b/README.md index 9c6a152..6046d65 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,14 @@ # LMDBAL - Lightning Memory Data Base Abstraction Level [![AUR license](https://img.shields.io/aur/license/lmdbal?style=flat-square)](https://git.macaw.me/blue/lmdbal/raw/branch/master/LICENSE.md) -[![AUR version](https://img.shields.io/aur/version/lmdbal?style=flat-square)](https://aur.archlinux.org/packages/lmdbal/) +[![AUR qt5 version](https://img.shields.io/aur/version/lmdbal-qt5?style=flat-square)](https://aur.archlinux.org/packages/lmdbal-qt5/) +[![AUR qt6 version](https://img.shields.io/aur/version/lmdbal-qt6?style=flat-square)](https://aur.archlinux.org/packages/lmdbal-qt6/) [![Liberapay patrons](https://img.shields.io/liberapay/patrons/macaw.me?logo=liberapay&style=flat-square)](https://liberapay.com/macaw.me) [![Documentation](https://img.shields.io/badge/Documentation-HTML-green)](https://macaw.me/lmdbal/doc/html) ### Prerequisites -- a compiler (c++ would do) +- a c++ compiler (g++ would do) - Qt 5 or 6 or higher (qt5-base or qt6-base would do) - lmdb - CMake 3.16 or higher diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9332fd8..a717e80 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,6 +16,7 @@ set(HEADERS cache.hpp operators.hpp transaction.h + icursor.h ) target_sources(${LMDBAL_NAME} PRIVATE ${SOURCES}) diff --git a/src/cursor.h b/src/cursor.h index c77d4e9..65a947d 100644 --- a/src/cursor.h +++ b/src/cursor.h @@ -24,11 +24,12 @@ #include "base.h" #include "storage.h" #include "transaction.h" +#include "icursor.h" namespace LMDBAL { template -class Cursor { +class Cursor : public iCursor { friend class Storage; private: enum State { /** /** @@ -84,6 +85,10 @@ LMDBAL::Cursor::Cursor(Cursor&& other): if (id != 0) storage->cursors[id] = this; + if (state == openedPublic) + storage->attachCursorToTransaction(id, cursor, this); + + other.freed(); } @@ -110,6 +115,9 @@ LMDBAL::Cursor& LMDBAL::Cursor::operator = (Cursor&& other) { other.state = closed; storage->cursors[id] = this; + + if (state == openedPublic) + storage->attachCursorToTransaction(id, cursor, this); } return *this; @@ -184,7 +192,20 @@ bool LMDBAL::Cursor::empty () const { */ template void LMDBAL::Cursor::terminated () { - close(); //for now it's the same, but if I ever going to make writable cursor - here is where it's gonna be different + switch (state) { + case openedPublic: + storage->_mdbCursorClose(cursor); + + state = closed; + break; + case openedPrivate: + storage->closeCursorTransaction(cursor); + + state = closed; + break; + default: + break; + } } /** @@ -205,17 +226,11 @@ void LMDBAL::Cursor::open () { if (empty()) throw CursorEmpty(openCursorMethodName); - storage->ensureOpened(openCursorMethodName); switch (state) { - case closed: { - TransactionID txn = storage->beginReadOnlyTransaction(); - int result = storage->_mdbCursorOpen(txn, &cursor); - if (result != MDB_SUCCESS) - storage->throwUnknown(result, txn); - - storage->transactionStarted(txn, true); + case closed: + storage->openCursorTransaction(&cursor); state = openedPrivate; - } break; + break; default: break; } @@ -250,6 +265,7 @@ void LMDBAL::Cursor::open (const Transaction& transaction) { if (result != MDB_SUCCESS) storage->throwUnknown(result); + storage->attachCursorToTransaction(id, cursor, this); state = openedPublic; } break; default: @@ -285,15 +301,24 @@ void LMDBAL::Cursor::renew () { TransactionID txn = storage->_mdbCursorTxn(cursor); storage->abortTransaction(txn); storage->transactionAborted(txn); - [[fallthrough]]; + + txn = storage->beginReadOnlyTransaction(); + int result = storage->_mdbCursorRenew(txn, cursor); + if (result != MDB_SUCCESS) + storage->throwUnknown(result, txn); + + storage->transactionStarted(txn, true); + state = openedPrivate; } case openedPublic: { + storage->disconnectCursorFromTransaction(id, cursor); TransactionID txn = storage->beginReadOnlyTransaction(); int result = storage->_mdbCursorRenew(txn, cursor); if (result != MDB_SUCCESS) storage->throwUnknown(result, txn); storage->transactionStarted(txn, true); + storage->attachCursorToTransaction(id, cursor, this); state = openedPrivate; } break; default: @@ -330,17 +355,24 @@ void LMDBAL::Cursor::renew (const Transaction& transaction) { TransactionID txn = storage->extractTransactionId(transaction, renewCursorMethodName); switch (state) { case openedPrivate: { - TransactionID txn = storage->_mdbCursorTxn(cursor); - storage->abortTransaction(txn); - storage->transactionAborted(txn); - [[fallthrough]]; - } - case openedPublic: { + TransactionID txnOld = storage->_mdbCursorTxn(cursor); + storage->abortTransaction(txnOld); + storage->transactionAborted(txnOld); + int result = storage->_mdbCursorRenew(txn, cursor); if (result != MDB_SUCCESS) storage->throwUnknown(result); state = openedPublic; + } + case openedPublic: { + storage->disconnectCursorFromTransaction(id, cursor); + int result = storage->_mdbCursorRenew(txn, cursor); + if (result != MDB_SUCCESS) + storage->throwUnknown(result); + + storage->attachCursorToTransaction(id, cursor, this); + state = openedPublic; } break; default: break; @@ -360,19 +392,17 @@ void LMDBAL::Cursor::renew (const Transaction& transaction) { template void LMDBAL::Cursor::close () { switch (state) { - case openedPublic: { + case openedPublic: + storage->disconnectCursorFromTransaction(id, cursor); storage->_mdbCursorClose(cursor); state = closed; - } break; - case openedPrivate: { - TransactionID txn = storage->_mdbCursorTxn(cursor); - storage->_mdbCursorClose(cursor); - storage->abortTransaction(txn); - storage->transactionAborted(txn); + break; + case openedPrivate: + storage->closeCursorTransaction(cursor); state = closed; - } break; + break; default: break; } diff --git a/src/icursor.h b/src/icursor.h new file mode 100644 index 0000000..04bc811 --- /dev/null +++ b/src/icursor.h @@ -0,0 +1,32 @@ +/* + * LMDB Abstraction Layer. + * Copyright (C) 2023 Yury Gubich + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +namespace LMDBAL { + +class Transaction; + +class iCursor { + friend class Transaction; +protected: + virtual ~iCursor() {} + virtual void terminated() = 0; +}; + +} diff --git a/src/storage.cpp b/src/storage.cpp index cea474d..4847760 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -50,7 +50,7 @@ LMDBAL::iStorage::iStorage(Base* parent, const std::string& name, bool duplicate LMDBAL::iStorage::~iStorage() {} /** - * \brief A private virtual function I need to close each storage in the database + * \brief A private virtual function to close each storage in the database */ void LMDBAL::iStorage::close() { mdb_dbi_close(db->environment, dbi); @@ -159,6 +159,73 @@ LMDBAL::SizeType LMDBAL::iStorage::count() const { return amount; } +/** + * \brief Links cursor to the transaction it has been opened with + * + * This a service function is designed to be called by from LMDBAL::Cursor + * Cursor must be opened by a public transaction + * + * \exception std::out_of_range thrown if LMDBAL::Transaction pointer wasn't found in the LMDBAL::Base + */ + +void LMDBAL::iStorage::attachCursorToTransaction (uint32_t cursorId, MDB_cursor* cursorHandle, iCursor* pointer) const { + TransactionID txnID = _mdbCursorTxn(cursorHandle); + Transaction* txn = db->transactions.at(txnID); + txn->cursors[cursorId] = pointer; +} + + +/** + * \brief Opens a transaction that is ment to be private to LMDBAL::Cursor, but public to the LMDBAL::Storage + * + * This method is ment to be called from LMDBAL::Cursor + * + * \param[out] cursor - cursor handle + * + * \exception LMDBAL::Closed thrown if you try to open the cursor on a closed database + * \exception LMDBAL::Unknown thrown if there was a problem opening the cursor by the lmdb, or to begin a transaction + */ +void LMDBAL::iStorage::openCursorTransaction (MDB_cursor** cursor) const { + ensureOpened(openCursorTransactionMethodName); + + TransactionID txn = beginReadOnlyTransaction(); + int result = _mdbCursorOpen(txn, cursor); + if (result != MDB_SUCCESS) + throwUnknown(result, txn); + + transactionStarted(txn, true); +} + +/** + * \brief Closes transaction that is private to LMDBAL::Cursor, but public to the LMDBAL::Storage + * + * This method is ment to be called from LMDBAL::Cursor + * + * \param[in] cursor - cursor handle + */ +void LMDBAL::iStorage::closeCursorTransaction (MDB_cursor* cursor) const { + TransactionID txn = _mdbCursorTxn(cursor); + _mdbCursorClose(cursor); + abortTransaction(txn); + transactionAborted(txn); +} + +/** + * \brief Disconnects cursor from the transaction it has been opened with + * + * This a service function is designed to be called by from LMDBAL::Cursor + * Cursor must be still opened by a public transaction + * + * \exception std::out_of_range thrown if LMDBAL::Transaction pointer wasn't found in the LMDBAL::Base + */ + +void LMDBAL::iStorage::disconnectCursorFromTransaction (uint32_t cursorId, MDB_cursor* cursorHandle) const { + TransactionID txnID = _mdbCursorTxn(cursorHandle); + Transaction* txn = db->transactions.at(txnID); + txn->cursors.erase(cursorId); +} + + /** * \brief Storage size (private transaction variant) * diff --git a/src/storage.h b/src/storage.h index c077500..08c37ba 100644 --- a/src/storage.h +++ b/src/storage.h @@ -76,6 +76,11 @@ protected: virtual int drop(TransactionID transaction); virtual SizeType count(TransactionID txn) const; + void openCursorTransaction(MDB_cursor** cursor) const; + void closeCursorTransaction(MDB_cursor* cursor) const; + void attachCursorToTransaction(uint32_t cursorId, MDB_cursor* cursorHandle, iCursor* pointer) const; + void disconnectCursorFromTransaction(uint32_t cursorId, MDB_cursor* cursorHandle) const; + int _mdbOpen(MDB_txn* txn, unsigned int flags = 0); int _mdbPut(MDB_txn* txn, MDB_val& key, MDB_val& data, unsigned int flags = 0); @@ -103,24 +108,25 @@ public: virtual SizeType count(const Transaction& txn) const; protected: - MDB_dbi dbi; /**<\brief lmdb storage handle*/ - Base* db; /**<\brief parent database pointer (borrowed)*/ - const std::string name; /**<\brief this storage name*/ - const bool duplicates; /**<\brief true if storage supports duplicates*/ + MDB_dbi dbi; /**<\brief lmdb storage handle*/ + Base* db; /**<\brief parent database pointer (borrowed)*/ + const std::string name; /**<\brief this storage name*/ + const bool duplicates; /**<\brief true if storage supports duplicates*/ - inline static const std::string dropMethodName = "drop"; /**<\brief member function name, just for exceptions*/ - inline static const std::string countMethodName = "count"; /**<\brief member function name, just for exceptions*/ - inline static const std::string flagsMethodName = "flags"; /**<\brief member function name, just for exceptions*/ + inline static const std::string dropMethodName = "drop"; /**<\brief member function name, just for exceptions*/ + inline static const std::string countMethodName = "count"; /**<\brief member function name, just for exceptions*/ + inline static const std::string flagsMethodName = "flags"; /**<\brief member function name, just for exceptions*/ - inline static const std::string addRecordMethodName = "addRecord"; /**<\brief member function name, just for exceptions*/ - inline static const std::string forceRecordMethodName = "forceRecord"; /**<\brief member function name, just for exceptions*/ - inline static const std::string changeRecordMethodName = "changeRecord"; /**<\brief member function name, just for exceptions*/ - inline static const std::string removeRecordMethodName = "removeRecord"; /**<\brief member function name, just for exceptions*/ - inline static const std::string checkRecordMethodName = "checkRecord"; /**<\brief member function name, just for exceptions*/ - inline static const std::string getRecordMethodName = "getRecord"; /**<\brief member function name, just for exceptions*/ - inline static const std::string readAllMethodName = "readAllRecord"; /**<\brief member function name, just for exceptions*/ - inline static const std::string replaceAllMethodName = "replaceAll"; /**<\brief member function name, just for exceptions*/ - inline static const std::string addRecordsMethodName = "addRecords"; /**<\brief member function name, just for exceptions*/ + inline static const std::string addRecordMethodName = "addRecord"; /**<\brief member function name, just for exceptions*/ + inline static const std::string forceRecordMethodName = "forceRecord"; /**<\brief member function name, just for exceptions*/ + inline static const std::string changeRecordMethodName = "changeRecord"; /**<\brief member function name, just for exceptions*/ + inline static const std::string removeRecordMethodName = "removeRecord"; /**<\brief member function name, just for exceptions*/ + inline static const std::string checkRecordMethodName = "checkRecord"; /**<\brief member function name, just for exceptions*/ + inline static const std::string getRecordMethodName = "getRecord"; /**<\brief member function name, just for exceptions*/ + inline static const std::string readAllMethodName = "readAllRecord"; /**<\brief member function name, just for exceptions*/ + inline static const std::string replaceAllMethodName = "replaceAll"; /**<\brief member function name, just for exceptions*/ + inline static const std::string addRecordsMethodName = "addRecords"; /**<\brief member function name, just for exceptions*/ + inline static const std::string openCursorTransactionMethodName = "openCursorTransaction"; /**<\brief member function name, just for exceptions*/ protected: template diff --git a/src/transaction.cpp b/src/transaction.cpp index 52e3933..d2e6a05 100644 --- a/src/transaction.cpp +++ b/src/transaction.cpp @@ -40,7 +40,8 @@ LMDBAL::Transaction::Transaction(): txn(nullptr), active(false), - parent(nullptr) + parent(nullptr), + cursors() {} /** @@ -49,7 +50,8 @@ LMDBAL::Transaction::Transaction(): LMDBAL::Transaction::Transaction(TransactionID txn, const Base* parent) : txn(txn), active(true), - parent(parent) + parent(parent), + cursors() { parent->transactions[txn] = this; } @@ -60,7 +62,8 @@ LMDBAL::Transaction::Transaction(TransactionID txn, const Base* parent) : LMDBAL::Transaction::Transaction(Transaction&& other): txn(other.txn), active(other.active), - parent(other.parent) + parent(other.parent), + cursors(other.cursors) { if (active) { parent->transactions[txn] = this; @@ -88,6 +91,7 @@ LMDBAL::Transaction& LMDBAL::Transaction::operator=(Transaction&& other) { txn = other.txn; active = other.active; parent = other.parent; + cursors = other.cursors; if (active) { parent->transactions[txn] = this; @@ -105,13 +109,14 @@ LMDBAL::Transaction& LMDBAL::Transaction::operator=(Transaction&& other) { */ void LMDBAL::Transaction::terminate() { if (active) { + closeCursors(); parent->abortTransaction(txn); - parent->transactions.erase(txn); reset(); } } + /** * \brief Resets inner transaction properties to inactive state */ @@ -119,8 +124,16 @@ void LMDBAL::Transaction::reset() { active = false; txn = nullptr; parent = nullptr; + cursors.clear(); } +/** + * \brief Closes attached curors; + */ +void LMDBAL::Transaction::closeCursors () { + for (const std::pair& pair : cursors) + pair.second->terminated(); +} /** * \brief Returns transaction states @@ -197,8 +210,8 @@ void LMDBAL::WriteTransaction::abort() { */ void LMDBAL::WriteTransaction::commit() { if (active) { + closeCursors(); const_cast(parent)->commitTransaction(txn); - parent->transactions.erase(txn); reset(); } diff --git a/src/transaction.h b/src/transaction.h index 81acad6..f37dab0 100644 --- a/src/transaction.h +++ b/src/transaction.h @@ -19,6 +19,7 @@ #pragma once #include "base.h" +#include "icursor.h" namespace LMDBAL { class iStorage; @@ -40,11 +41,13 @@ public: protected: Transaction(TransactionID txn, const Base* parent); void reset(); + void closeCursors(); protected: - TransactionID txn; /**<\brief Transaction inner handler*/ - bool active; /**<\brief Transaction state*/ - const Base* parent; /**<\brief Pointer to the database this transaction belongs to*/ + TransactionID txn; /**<\brief Transaction inner handler*/ + bool active; /**<\brief Transaction state*/ + const Base* parent; /**<\brief Pointer to the database this transaction belongs to*/ + std::map cursors; /**<\brief a collection of cursors curently opened under this transaction*/ }; class WriteTransaction : public Transaction { diff --git a/test/cachecursor.cpp b/test/cachecursor.cpp index 7d9d440..ec15b46 100644 --- a/test/cachecursor.cpp +++ b/test/cachecursor.cpp @@ -402,7 +402,7 @@ TEST_F(CacheCursorTest, CursorRAIIBehaviour) { TEST_F(CacheCursorTest, CornerCases) { transaction.terminate(); - EXPECT_THROW(cursor.current(), LMDBAL::Unknown); + EXPECT_THROW(cursor.current(), LMDBAL::CursorNotReady); cursor.close(); LMDBAL::Cursor emptyCursor = emptyCache->createCursor(); diff --git a/test/storagecursor.cpp b/test/storagecursor.cpp index dde8d82..7e332fb 100644 --- a/test/storagecursor.cpp +++ b/test/storagecursor.cpp @@ -380,7 +380,7 @@ TEST_F(StorageCursorTest, CursorRAIIBehaviour) { TEST_F(StorageCursorTest, CornerCases) { EXPECT_EQ(getTableCursorsSize(), 1); transaction.terminate(); - EXPECT_THROW(cursor.current(), LMDBAL::Unknown); + EXPECT_THROW(cursor.current(), LMDBAL::CursorNotReady); cursor.close(); LMDBAL::Cursor emptyCursor = emptyTable->createCursor(); @@ -414,4 +414,18 @@ TEST_F(StorageCursorTest, CornerCases) { EXPECT_EQ(element.first, reference->first); EXPECT_EQ(element.second, reference->second); EXPECT_THROW(cursor.prev(), LMDBAL::NotFound); + + cursor.close(); +} + +TEST_F(StorageCursorTest, TerminatedTransaction) { + LMDBAL::Cursor emptyCursor = table->createCursor(); + + { + LMDBAL::Transaction txn = db->beginReadOnlyTransaction(); + cursor.open(txn); + EXPECT_NO_THROW(cursor.first()); + } + + EXPECT_FALSE(cursor.opened()); } From ef86d0adf97abc071f71106a187ca02a39a98e50 Mon Sep 17 00:00:00 2001 From: blue Date: Tue, 24 Dec 2024 18:35:56 +0200 Subject: [PATCH 24/34] Some reformation, test cases and first bugfixes --- src/cursor.hpp | 50 +++++++++++++----------------------------- src/storage.cpp | 21 +++++++++++++----- src/storage.h | 4 ++-- test/cachecursor.cpp | 35 +++++++++++++++++++++++++++++ test/storagecursor.cpp | 30 +++++++++++++++++++++---- 5 files changed, 93 insertions(+), 47 deletions(-) diff --git a/src/cursor.hpp b/src/cursor.hpp index 79fcff0..875b764 100644 --- a/src/cursor.hpp +++ b/src/cursor.hpp @@ -195,14 +195,12 @@ void LMDBAL::Cursor::terminated () { switch (state) { case openedPublic: storage->_mdbCursorClose(cursor); - state = closed; - break; + break; case openedPrivate: - storage->closeCursorTransaction(cursor); - + storage->closeCursorTransaction(cursor, true); state = closed; - break; + break; default: break; } @@ -228,7 +226,7 @@ void LMDBAL::Cursor::open () { switch (state) { case closed: - storage->openCursorTransaction(&cursor); + storage->openCursorTransaction(&cursor, false); state = openedPrivate; break; default: @@ -297,30 +295,15 @@ void LMDBAL::Cursor::renew () { storage->ensureOpened(renewCursorMethodName); switch (state) { - case openedPrivate: { - TransactionID txn = storage->_mdbCursorTxn(cursor); - storage->abortTransaction(txn); - storage->transactionAborted(txn); - - txn = storage->beginReadOnlyTransaction(); - int result = storage->_mdbCursorRenew(txn, cursor); - if (result != MDB_SUCCESS) - storage->throwUnknown(result, txn); - - storage->transactionStarted(txn, true); - state = openedPrivate; - } - case openedPublic: { + case openedPrivate: + storage->closeCursorTransaction(cursor, false); + storage->openCursorTransaction(&cursor, true); + break; + case openedPublic: storage->disconnectCursorFromTransaction(id, cursor); - TransactionID txn = storage->beginReadOnlyTransaction(); - int result = storage->_mdbCursorRenew(txn, cursor); - if (result != MDB_SUCCESS) - storage->throwUnknown(result, txn); - - storage->transactionStarted(txn, true); - storage->attachCursorToTransaction(id, cursor, this); + storage->openCursorTransaction(&cursor, true); state = openedPrivate; - } break; + break; default: break; } @@ -355,16 +338,14 @@ void LMDBAL::Cursor::renew (const Transaction& transaction) { TransactionID txn = storage->extractTransactionId(transaction, renewCursorMethodName); switch (state) { case openedPrivate: { - TransactionID txnOld = storage->_mdbCursorTxn(cursor); - storage->abortTransaction(txnOld); - storage->transactionAborted(txnOld); - + storage->closeCursorTransaction(cursor, false); int result = storage->_mdbCursorRenew(txn, cursor); if (result != MDB_SUCCESS) storage->throwUnknown(result); + storage->attachCursorToTransaction(id, cursor, this); state = openedPublic; - } + } break; case openedPublic: { storage->disconnectCursorFromTransaction(id, cursor); int result = storage->_mdbCursorRenew(txn, cursor); @@ -372,7 +353,6 @@ void LMDBAL::Cursor::renew (const Transaction& transaction) { storage->throwUnknown(result); storage->attachCursorToTransaction(id, cursor, this); - state = openedPublic; } break; default: break; @@ -399,7 +379,7 @@ void LMDBAL::Cursor::close () { state = closed; break; case openedPrivate: - storage->closeCursorTransaction(cursor); + storage->closeCursorTransaction(cursor, true); state = closed; break; diff --git a/src/storage.cpp b/src/storage.cpp index 4847760..4359987 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -180,16 +180,22 @@ void LMDBAL::iStorage::attachCursorToTransaction (uint32_t cursorId, MDB_cursor* * * This method is ment to be called from LMDBAL::Cursor * - * \param[out] cursor - cursor handle + * \param[out] cursor - cursor handle + * \param[in] renew - true if instead of opening cursor should be renewed * * \exception LMDBAL::Closed thrown if you try to open the cursor on a closed database * \exception LMDBAL::Unknown thrown if there was a problem opening the cursor by the lmdb, or to begin a transaction */ -void LMDBAL::iStorage::openCursorTransaction (MDB_cursor** cursor) const { +void LMDBAL::iStorage::openCursorTransaction (MDB_cursor** cursor, bool renew) const { ensureOpened(openCursorTransactionMethodName); TransactionID txn = beginReadOnlyTransaction(); - int result = _mdbCursorOpen(txn, cursor); + int result; + if (renew) + result = _mdbCursorRenew(txn, *cursor); + else + result = _mdbCursorOpen(txn, cursor); + if (result != MDB_SUCCESS) throwUnknown(result, txn); @@ -201,11 +207,14 @@ void LMDBAL::iStorage::openCursorTransaction (MDB_cursor** cursor) const { * * This method is ment to be called from LMDBAL::Cursor * - * \param[in] cursor - cursor handle + * \param[in] cursor - cursor handle + * \param[in] closeCursor - true if the cursor should also get closed, false if you wish to leave it open */ -void LMDBAL::iStorage::closeCursorTransaction (MDB_cursor* cursor) const { +void LMDBAL::iStorage::closeCursorTransaction (MDB_cursor* cursor, bool closeCursor) const { TransactionID txn = _mdbCursorTxn(cursor); - _mdbCursorClose(cursor); + if (closeCursor) + _mdbCursorClose(cursor); + abortTransaction(txn); transactionAborted(txn); } diff --git a/src/storage.h b/src/storage.h index 08c37ba..99141e0 100644 --- a/src/storage.h +++ b/src/storage.h @@ -76,8 +76,8 @@ protected: virtual int drop(TransactionID transaction); virtual SizeType count(TransactionID txn) const; - void openCursorTransaction(MDB_cursor** cursor) const; - void closeCursorTransaction(MDB_cursor* cursor) const; + void openCursorTransaction(MDB_cursor** cursor, bool renew = false) const; + void closeCursorTransaction(MDB_cursor* cursor, bool closeCursor = false) const; void attachCursorToTransaction(uint32_t cursorId, MDB_cursor* cursorHandle, iCursor* pointer) const; void disconnectCursorFromTransaction(uint32_t cursorId, MDB_cursor* cursorHandle) const; diff --git a/test/cachecursor.cpp b/test/cachecursor.cpp index ec15b46..b965c69 100644 --- a/test/cachecursor.cpp +++ b/test/cachecursor.cpp @@ -436,5 +436,40 @@ TEST_F(CacheCursorTest, CornerCases) { EXPECT_EQ(element.first, reference->first); EXPECT_EQ(element.second, reference->second); EXPECT_THROW(cursor.prev(), LMDBAL::NotFound); + + cursor.close(); } +TEST_F(CacheCursorTest, TerminatedTransaction) { + LMDBAL::Cursor cr = cache->createCursor(); + + { + LMDBAL::Transaction txn = db->beginReadOnlyTransaction(); + cr.open(txn); + EXPECT_NO_THROW(cr.first()); + } + + EXPECT_FALSE(cr.opened()); + + LMDBAL::Transaction txn2; + { + LMDBAL::Transaction txn = db->beginReadOnlyTransaction(); + EXPECT_TRUE(txn.isActive()); + EXPECT_FALSE(txn2.isActive()); + + cr.open(txn); + EXPECT_TRUE(cr.opened()); + + txn2 = std::move(txn); + EXPECT_FALSE(txn.isActive()); + EXPECT_TRUE(txn2.isActive()); + EXPECT_TRUE(cr.opened()); + } + + EXPECT_TRUE(txn2.isActive()); + EXPECT_TRUE(cr.opened()); + + txn2.terminate(); + EXPECT_FALSE(txn2.isActive()); + EXPECT_FALSE(cr.opened()); +} diff --git a/test/storagecursor.cpp b/test/storagecursor.cpp index 7e332fb..92279b1 100644 --- a/test/storagecursor.cpp +++ b/test/storagecursor.cpp @@ -419,13 +419,35 @@ TEST_F(StorageCursorTest, CornerCases) { } TEST_F(StorageCursorTest, TerminatedTransaction) { - LMDBAL::Cursor emptyCursor = table->createCursor(); + LMDBAL::Cursor cr = table->createCursor(); { LMDBAL::Transaction txn = db->beginReadOnlyTransaction(); - cursor.open(txn); - EXPECT_NO_THROW(cursor.first()); + cr.open(txn); + EXPECT_NO_THROW(cr.first()); } - EXPECT_FALSE(cursor.opened()); + EXPECT_FALSE(cr.opened()); + + LMDBAL::Transaction txn2; + { + LMDBAL::Transaction txn = db->beginReadOnlyTransaction(); + EXPECT_TRUE(txn.isActive()); + EXPECT_FALSE(txn2.isActive()); + + cr.open(txn); + EXPECT_TRUE(cr.opened()); + + txn2 = std::move(txn); + EXPECT_FALSE(txn.isActive()); + EXPECT_TRUE(txn2.isActive()); + EXPECT_TRUE(cr.opened()); + } + + EXPECT_TRUE(txn2.isActive()); + EXPECT_TRUE(cr.opened()); + + txn2.terminate(); + EXPECT_FALSE(txn2.isActive()); + EXPECT_FALSE(cr.opened()); } From bfb1d007ad8f07adbb4528fc564b9c62f0bc7ad3 Mon Sep 17 00:00:00 2001 From: blue Date: Wed, 25 Dec 2024 19:19:32 +0200 Subject: [PATCH 25/34] Cursors refactoring part one --- README.md | 4 +- src/CMakeLists.txt | 7 +- src/base.cpp | 20 +- src/base.h | 10 +- src/cache.hpp | 48 ++-- src/cursor.h | 45 +--- src/cursor.hpp | 333 ++---------------------- src/cursorcommon.cpp | 342 +++++++++++++++++++++++++ src/cursorcommon.h | 90 +++++++ src/icursor.h | 32 --- src/storage.h | 108 +------- src/storage.hpp | 84 +----- src/{storage.cpp => storagecommon.cpp} | 106 ++++---- src/storagecommon.h | 139 ++++++++++ src/storagecommon.hpp | 99 +++++++ src/transaction.cpp | 4 +- src/transaction.h | 14 +- test/cachetransaction.cpp | 8 +- test/storagetransaction.cpp | 8 +- 19 files changed, 824 insertions(+), 677 deletions(-) create mode 100644 src/cursorcommon.cpp create mode 100644 src/cursorcommon.h delete mode 100644 src/icursor.h rename src/{storage.cpp => storagecommon.cpp} (78%) create mode 100644 src/storagecommon.h create mode 100644 src/storagecommon.hpp diff --git a/README.md b/README.md index 6046d65..1226357 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # LMDBAL - Lightning Memory Data Base Abstraction Level [![AUR license](https://img.shields.io/aur/license/lmdbal?style=flat-square)](https://git.macaw.me/blue/lmdbal/raw/branch/master/LICENSE.md) -[![AUR qt5 version](https://img.shields.io/aur/version/lmdbal-qt5?style=flat-square)](https://aur.archlinux.org/packages/lmdbal-qt5/) -[![AUR qt6 version](https://img.shields.io/aur/version/lmdbal-qt6?style=flat-square)](https://aur.archlinux.org/packages/lmdbal-qt6/) +[![AUR qt5 version](https://img.shields.io/aur/version/lmdbal-qt5?style=flat-square&label=lmdbal-qt5)](https://aur.archlinux.org/packages/lmdbal-qt5/) +[![AUR qt6 version](https://img.shields.io/aur/version/lmdbal-qt6?style=flat-square&label=lmdbal-qt6)](https://aur.archlinux.org/packages/lmdbal-qt6/) [![Liberapay patrons](https://img.shields.io/liberapay/patrons/macaw.me?logo=liberapay&style=flat-square)](https://liberapay.com/macaw.me) [![Documentation](https://img.shields.io/badge/Documentation-HTML-green)](https://macaw.me/lmdbal/doc/html) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a717e80..9c53f6a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,8 +1,9 @@ set(SOURCES exceptions.cpp - storage.cpp + storagecommon.cpp base.cpp transaction.cpp + cursorcommon.cpp ) set(HEADERS @@ -10,13 +11,15 @@ set(HEADERS exceptions.h storage.h storage.hpp + storagecommon.h + storagecommon.hpp cursor.h cursor.hpp + cursorcommon.h cache.h cache.hpp operators.hpp transaction.h - icursor.h ) target_sources(${LMDBAL_NAME} PRIVATE ${SOURCES}) diff --git a/src/base.cpp b/src/base.cpp index ce28975..cac914b 100644 --- a/src/base.cpp +++ b/src/base.cpp @@ -52,7 +52,7 @@ LMDBAL::Base::Base(const QString& _name, uint16_t _mapSize): LMDBAL::Base::~Base() { close(); - for (const std::pair& pair : storages) + for (const std::pair& pair : storages) delete pair.second; } @@ -71,7 +71,7 @@ void LMDBAL::Base::close() { pair.second->reset(); } - for (const std::pair& pair : storages) + for (const std::pair& pair : storages) pair.second->close(); mdb_env_close(environment); @@ -99,8 +99,8 @@ void LMDBAL::Base::open() { mdb_env_open(environment, path.toStdString().c_str(), 0, 0664); TransactionID txn = beginPrivateTransaction(emptyName); - for (const std::pair& pair : storages) { - iStorage* storage = pair.second; + for (const std::pair& pair : storages) { + StorageCommon* storage = pair.second; int rc = storage->open(txn); if (rc) throw Unknown(name, mdb_strerror(rc)); @@ -200,7 +200,7 @@ void LMDBAL::Base::drop() { throw Closed("drop", name); TransactionID txn = beginPrivateTransaction(emptyName); - for (const std::pair& pair : storages) { + for (const std::pair& pair : storages) { int rc = pair.second->drop(txn); if (rc != MDB_SUCCESS) { abortPrivateTransaction(txn, emptyName); @@ -209,7 +209,7 @@ void LMDBAL::Base::drop() { } commitPrivateTransaction(txn, emptyName); - for (const std::pair& pair : storages) + for (const std::pair& pair : storages) pair.second->handleDrop(); } @@ -306,7 +306,7 @@ LMDBAL::TransactionID LMDBAL::Base::beginReadOnlyTransaction(const std::string& throw Closed("beginReadOnlyTransaction", name, storageName); TransactionID txn = beginPrivateReadOnlyTransaction(storageName); - for (const std::pair& pair : storages) + for (const std::pair& pair : storages) pair.second->transactionStarted(txn, true); return txn; @@ -331,7 +331,7 @@ LMDBAL::TransactionID LMDBAL::Base::beginTransaction(const std::string& storageN throw Closed("beginTransaction", name, storageName); TransactionID txn = beginPrivateTransaction(storageName); - for (const std::pair& pair : storages) + for (const std::pair& pair : storages) pair.second->transactionStarted(txn, false); return txn; @@ -356,7 +356,7 @@ void LMDBAL::Base::abortTransaction(LMDBAL::TransactionID id, const std::string& throw Closed("abortTransaction", name, storageName); abortPrivateTransaction(id, storageName); - for (const std::pair& pair : storages) + for (const std::pair& pair : storages) pair.second->transactionAborted(id); } @@ -379,7 +379,7 @@ void LMDBAL::Base::commitTransaction(LMDBAL::TransactionID id, const std::string throw Closed("abortTransaction", name, storageName); commitPrivateTransaction(id, storageName); - for (const std::pair& pair : storages) + for (const std::pair& pair : storages) pair.second->transactionCommited(id); } diff --git a/src/base.h b/src/base.h index de61ad7..a4b60a7 100644 --- a/src/base.h +++ b/src/base.h @@ -34,7 +34,7 @@ namespace LMDBAL { -class iStorage; +class StorageCommon; class Transaction; class WriteTransaction; @@ -51,7 +51,7 @@ typedef MDB_txn* TransactionID; /**<\brief I'm going to typedef uint32_t SizeType; /**<\brief All LMDBAL sizes are uint32_t*/ class Base { - friend class iStorage; + friend class StorageCommon; friend class Transaction; friend class WriteTransaction; public: @@ -84,7 +84,7 @@ public: LMDBAL::Cache* getCache(const std::string& storageName); private: - typedef std::map Storages; /**<\brief Storage and Cache pointers are saved in the std::map*/ + typedef std::map Storages; /**<\brief Storage and Cache pointers are saved in the std::map*/ typedef std::map Transactions; /**<\brief Piblic transaction IDs are saved in the std::set*/ void commitTransaction(TransactionID id); @@ -136,7 +136,7 @@ LMDBAL::Storage* LMDBAL::Base::addStorage(const std::string& storageName, throw Opened(name, "add storage " + storageName); Storage* storage = new Storage(this, storageName, duplicates); - std::pair pair = storages.insert(std::make_pair(storageName, (iStorage*)storage)); + std::pair pair = storages.insert(std::make_pair(storageName, (StorageCommon *)storage)); if (!pair.second) throw StorageDuplicate(name, storageName); @@ -164,7 +164,7 @@ LMDBAL::Cache * LMDBAL::Base::addCache(const std::string& storageName) { throw Opened(name, "add cache " + storageName); Cache* cache = new Cache(this, storageName, false); - std::pair pair = storages.insert(std::make_pair(storageName, (iStorage*)cache)); + std::pair pair = storages.insert(std::make_pair(storageName, (StorageCommon *)cache)); if (!pair.second) throw StorageDuplicate(name, storageName); diff --git a/src/cache.hpp b/src/cache.hpp index 29af6d0..6dd8c54 100644 --- a/src/cache.hpp +++ b/src/cache.hpp @@ -63,10 +63,10 @@ LMDBAL::Cache::~Cache() { template void LMDBAL::Cache::addRecord(const K& key, const V& value) { - iStorage::ensureOpened(iStorage::addRecordMethodName); + StorageCommon::ensureOpened(StorageCommon::addRecordMethodName); if (cache->count(key) > 0) - iStorage::throwDuplicate(iStorage::toString(key)); + StorageCommon::throwDuplicate(StorageCommon::toString(key)); Storage::addRecord(key, value); handleAddRecord(key, value); @@ -75,7 +75,7 @@ void LMDBAL::Cache::addRecord(const K& key, const V& value) { template void LMDBAL::Cache::addRecord(const K& key, const V& value, TransactionID txn) { if (cache->count(key) > 0) - iStorage::throwDuplicate(iStorage::toString(key)); + StorageCommon::throwDuplicate(StorageCommon::toString(key)); Storage::addRecord(key, value, txn); @@ -96,7 +96,7 @@ void LMDBAL::Cache::handleAddRecord(const K& key, const V& value) { template bool LMDBAL::Cache::forceRecord(const K& key, const V& value) { - iStorage::ensureOpened(iStorage::forceRecordMethodName); + StorageCommon::ensureOpened(StorageCommon::forceRecordMethodName); bool added = Storage::forceRecord(key, value); handleForceRecord(key, value, added); @@ -136,18 +136,18 @@ void LMDBAL::Cache::handleForceRecord(const K& key, const V& value, bool a template void LMDBAL::Cache::changeRecord(const K& key, const V& value) { - iStorage::ensureOpened(iStorage::changeRecordMethodName); + StorageCommon::ensureOpened(StorageCommon::changeRecordMethodName); if (mode == Mode::full) { typename std::map::iterator itr = cache->find(key); if (itr == cache->end()) - iStorage::throwNotFound(iStorage::toString(key)); + StorageCommon::throwNotFound(StorageCommon::toString(key)); Storage::changeRecord(key, value); itr->second = value; } else { if (abscent->count(key) > 0) - iStorage::throwNotFound(iStorage::toString(key)); + StorageCommon::throwNotFound(StorageCommon::toString(key)); try { Storage::changeRecord(key, value); @@ -169,12 +169,12 @@ void LMDBAL::Cache::changeRecord(const K& key, const V& value, Transaction if (mode == Mode::full) { typename std::map::iterator itr = cache->find(key); if (itr == cache->end()) - iStorage::throwNotFound(iStorage::toString(key)); + StorageCommon::throwNotFound(StorageCommon::toString(key)); Storage::changeRecord(key, value, txn); } else { if (abscent->count(key) > 0) - iStorage::throwNotFound(iStorage::toString(key)); + StorageCommon::throwNotFound(StorageCommon::toString(key)); try { Storage::changeRecord(key, value, txn); @@ -207,7 +207,7 @@ void LMDBAL::Cache::handleChangeRecord(const K& key, const V& value) { template V LMDBAL::Cache::getRecord(const K& key) const { - iStorage::ensureOpened(iStorage::getRecordMethodName); + StorageCommon::ensureOpened(StorageCommon::getRecordMethodName); V value; Cache::getRecord(key, value); @@ -216,7 +216,7 @@ V LMDBAL::Cache::getRecord(const K& key) const { template void LMDBAL::Cache::getRecord(const K& key, V& out) const { - iStorage::ensureOpened(iStorage::getRecordMethodName); + StorageCommon::ensureOpened(StorageCommon::getRecordMethodName); typename std::map::const_iterator itr = cache->find(key); if (itr != cache->end()) { @@ -225,7 +225,7 @@ void LMDBAL::Cache::getRecord(const K& key, V& out) const { } if (mode == Mode::full || abscent->count(key) != 0) - iStorage::throwNotFound(iStorage::toString(key)); + StorageCommon::throwNotFound(StorageCommon::toString(key)); try { Storage::getRecord(key, out); @@ -269,7 +269,7 @@ void LMDBAL::Cache::getRecord(const K& key, V& out, TransactionID txn) con } break; case Operation::remove: - iStorage::throwNotFound(iStorage::toString(key)); + StorageCommon::throwNotFound(StorageCommon::toString(key)); break; case Operation::change: if (static_cast*>(entry.second)->first == key) { @@ -285,7 +285,7 @@ void LMDBAL::Cache::getRecord(const K& key, V& out, TransactionID txn) con } break; case Operation::drop: - iStorage::throwNotFound(iStorage::toString(key)); + StorageCommon::throwNotFound(StorageCommon::toString(key)); break; case Operation::replace: { std::map* newMap = static_cast*>(entry.second); @@ -294,7 +294,7 @@ void LMDBAL::Cache::getRecord(const K& key, V& out, TransactionID txn) con out = vitr->second; return; } else { - iStorage::throwNotFound(iStorage::toString(key)); + StorageCommon::throwNotFound(StorageCommon::toString(key)); } } break; @@ -322,7 +322,7 @@ void LMDBAL::Cache::getRecord(const K& key, V& out, TransactionID txn) con } if (mode == Mode::full || abscent->count(key) != 0) - iStorage::throwNotFound(iStorage::toString(key)); + StorageCommon::throwNotFound(StorageCommon::toString(key)); try { Storage::getRecord(key, out, txn); @@ -352,7 +352,7 @@ void LMDBAL::Cache::discoveredRecord(const K& key, const V& value, Transac template bool LMDBAL::Cache::checkRecord(const K& key) const { - iStorage::ensureOpened(iStorage::checkRecordMethodName); + StorageCommon::ensureOpened(StorageCommon::checkRecordMethodName); typename std::map::const_iterator itr = cache->find(key); if (itr != cache->end()) @@ -457,7 +457,7 @@ void LMDBAL::Cache::appendToCache(const K& key, const V& value) const { template std::map LMDBAL::Cache::readAll() const { - iStorage::ensureOpened(iStorage::readAllMethodName); + StorageCommon::ensureOpened(StorageCommon::readAllMethodName); if (mode != Mode::full) { //there is a room for optimization mode = Mode::full; //I can read and deserialize only those values @@ -471,7 +471,7 @@ std::map LMDBAL::Cache::readAll() const { template void LMDBAL::Cache::readAll(std::map& out) const { - iStorage::ensureOpened(iStorage::readAllMethodName); + StorageCommon::ensureOpened(StorageCommon::readAllMethodName); if (mode != Mode::full) { //there is a room for optimization mode = Mode::full; //I can read and deserialize only those values @@ -642,7 +642,7 @@ void LMDBAL::Cache::handleAddRecords(const std::map& data, bool over template void LMDBAL::Cache::removeRecord(const K& key) { - iStorage::ensureOpened(iStorage::removeRecordMethodName); + StorageCommon::ensureOpened(StorageCommon::removeRecordMethodName); bool noKey = false; if (mode != Mode::full) @@ -651,7 +651,7 @@ void LMDBAL::Cache::removeRecord(const K& key) { noKey = abscent->count(key) > 0; if (noKey) - iStorage::throwNotFound(iStorage::toString(key)); + StorageCommon::throwNotFound(StorageCommon::toString(key)); Storage::removeRecord(key); handleRemoveRecord(key); @@ -666,7 +666,7 @@ void LMDBAL::Cache::removeRecord(const K& key, TransactionID txn) { noKey = abscent->count(key) > 0; if (noKey) - iStorage::throwNotFound(iStorage::toString(key)); + StorageCommon::throwNotFound(StorageCommon::toString(key)); Storage::removeRecord(key, txn); @@ -781,8 +781,8 @@ void LMDBAL::Cache::handleMode() const { template int LMDBAL::Cache::drop(const WriteTransaction& transaction) { - iStorage::ensureOpened(iStorage::dropMethodName); - TransactionID txn = iStorage::extractTransactionId(transaction, iStorage::dropMethodName); + StorageCommon::ensureOpened(StorageCommon::dropMethodName); + TransactionID txn = StorageCommon::extractTransactionId(transaction, StorageCommon::dropMethodName); int res = Storage::drop(txn); if (res != MDB_SUCCESS) diff --git a/src/cursor.h b/src/cursor.h index 65a947d..eef7cf1 100644 --- a/src/cursor.h +++ b/src/cursor.h @@ -24,20 +24,13 @@ #include "base.h" #include "storage.h" #include "transaction.h" -#include "icursor.h" +#include "cursorcommon.h" namespace LMDBAL { template -class Cursor : public iCursor { +class Cursor : public CursorCommon { friend class Storage; -private: - enum State { /*** parent); @@ -48,14 +41,6 @@ public: Cursor& operator = (const Cursor& other) = delete; Cursor& operator = (Cursor&& other); - void open(); - void open(const Transaction& transaction); - void renew(); - void renew(const Transaction& transaction); - void close(); - bool opened() const; - bool empty() const; - void drop(); std::pair first(); @@ -72,33 +57,7 @@ public: void current(K& key, V& value) const; private: - virtual void terminated() override; - void dropped(); - void freed(); void operateCursorRead(K& key, V& value, MDB_cursor_op operation, const std::string& methodName, const std::string& operationName) const; - -private: - Storage* storage; - MDB_cursor* cursor; - State state; - uint32_t id; - - inline static const std::string openCursorMethodName = "Cursor::open"; /**<\brief member function name, just for exceptions*/ - inline static const std::string closeCursorMethodName = "Cursor::close"; /**<\brief member function name, just for exceptions*/ - inline static const std::string renewCursorMethodName = "Cursor::renew"; /**<\brief member function name, just for exceptions*/ - - inline static const std::string firstMethodName = "first"; /**<\brief member function name, just for exceptions*/ - inline static const std::string lastMethodName = "last"; /**<\brief member function name, just for exceptions*/ - inline static const std::string nextMethodName = "next"; /**<\brief member function name, just for exceptions*/ - inline static const std::string prevMethodName = "prev"; /**<\brief member function name, just for exceptions*/ - inline static const std::string currentMethodName = "current"; /**<\brief member function name, just for exceptions*/ - inline static const std::string setMethodName = "set"; /**<\brief member function name, just for exceptions*/ - - inline static const std::string firstOperationName = "Cursor::first"; /**<\brief member function name, just for exceptions*/ - inline static const std::string lastOperationName = "Cursor::last"; /**<\brief member function name, just for exceptions*/ - inline static const std::string nextOperationName = "Cursor::next"; /**<\brief member function name, just for exceptions*/ - inline static const std::string prevOperationName = "Cursor::prev"; /**<\brief member function name, just for exceptions*/ - inline static const std::string currentOperationName = "Cursor::current"; /**<\brief member function name, just for exceptions*/ }; }; diff --git a/src/cursor.hpp b/src/cursor.hpp index 875b764..ed68e8f 100644 --- a/src/cursor.hpp +++ b/src/cursor.hpp @@ -41,8 +41,6 @@ * You are not supposed to instantiate or destory instances of this class yourself! */ -static uint32_t idCounter = 0; - /** * \brief Creates a cursor * @@ -50,12 +48,9 @@ static uint32_t idCounter = 0; */ template LMDBAL::Cursor::Cursor(Storage* parent): - storage(parent), - cursor(nullptr), - state(closed), - id(++idCounter) + CursorCommon(parent) { - storage->cursors[id] = this; + parent->cursors[id] = this; } /** @@ -65,10 +60,7 @@ LMDBAL::Cursor::Cursor(Storage* parent): */ template LMDBAL::Cursor::Cursor(): - storage(nullptr), - cursor(nullptr), - state(closed), - id(0) + CursorCommon() {} /** @@ -76,64 +68,39 @@ LMDBAL::Cursor::Cursor(): */ template LMDBAL::Cursor::Cursor(Cursor&& other): - storage(other.storage), - cursor(other.cursor), - state(other.state), - id(other.id) + CursorCommon(std::move(other)) { - other.terminated(); - if (id != 0) - storage->cursors[id] = this; - - if (state == openedPublic) - storage->attachCursorToTransaction(id, cursor, this); - - - other.freed(); + if (!empty()) + static_cast*>(storage)->cursors[id] = this; } /** - * \brief A private function that turns cursor into an empty one + * \brief Move assignment operator * - * This function is called from LMDBAL::Storage, when it gets destroyed, but still has some valid. - * Those cursors will become empty, and can't be used anymore + * Transfers other cursor into this one */ template LMDBAL::Cursor& LMDBAL::Cursor::operator = (Cursor&& other) { - terminated(); + if (!empty() && other.empty()) + static_cast*>(storage)->cursors.erase(id); - if (id != 0) - storage->cursors.erase(id); + CursorCommon::operator=(std::move(other)); - storage = other.storage; - cursor = other.cursor; - state = other.state; - id = other.id; - - if (id != 0) { - other.freed(); - other.state = closed; - - storage->cursors[id] = this; - - if (state == openedPublic) - storage->attachCursorToTransaction(id, cursor, this); - } + if (!empty()) + static_cast*>(storage)->cursors[id] = this; return *this; } /** - * \brief Destroys a cursor + * \brief Destroys this cursor * * If the cursor wasn't properly closed - it's going to be upon destruction */ template LMDBAL::Cursor::~Cursor () { - close(); - if (id != 0) - storage->cursors.erase(id); + static_cast*>(storage)->cursors.erase(id); } /** @@ -147,253 +114,9 @@ void LMDBAL::Cursor::drop () { close(); if (id != 0) - storage->cursors.erase(id); + static_cast*>(storage)->cursors.erase(id); - freed(); -} - -/** - * \brief A private method that turns cursor into an empty one - * - * This function is called from LMDBAL::Storage, when it gets destroyed, but still has some valid cursors. - * Those cursors will become empty, and can't be used anymore - */ -template -void LMDBAL::Cursor::dropped () { - terminated(); - freed(); -} - -/** - * \brief A private method that turns cursor into an empty one (submethod) - * - * This function is called from LMDBAL::Storage, when the cursor is getting destoryed. - * Those cursors will become empty, and can't be used anymore - */ -template -void LMDBAL::Cursor::freed () { - cursor = nullptr; - storage = nullptr; - id = 0; -} - -/** - * \brief Returns true if the cursor is empty - * - * Empty cursors can't be used, they can be only targets of move operations - */ -template -bool LMDBAL::Cursor::empty () const { - return id == 0; -} - -/** - * \brief A private function the storage owning this cursor will call to inform this cursor that the thansaction needs to be aborted - */ -template -void LMDBAL::Cursor::terminated () { - switch (state) { - case openedPublic: - storage->_mdbCursorClose(cursor); - state = closed; - break; - case openedPrivate: - storage->closeCursorTransaction(cursor, true); - state = closed; - break; - default: - break; - } -} - -/** - * \brief Opens the cursor for operations. - * - * This is a normal way to start the sequence of operations with the cursor. - * This variant of the function creates a read only transaction just for this cursor - * - * This function should be called when the LMDBAL::Storage is already opened and before any query with this cursor! - * It will do nothing to a cursor that was already opened (no matter what way). - * - * \exception LMDBAL::Closed thrown if you try to open the cursor on a closed database - * \exception LMDBAL::Unknown thrown if there was a problem opening the cursor by the lmdb, or to begin a transaction - * \exception LMDBAL::CursorEmpty thrown if the cursor was empty - */ -template -void LMDBAL::Cursor::open () { - if (empty()) - throw CursorEmpty(openCursorMethodName); - - switch (state) { - case closed: - storage->openCursorTransaction(&cursor, false); - state = openedPrivate; - break; - default: - break; - } -} - -/** - * \brief Opens the cursor for operations. - * - * This is a normal way to start the sequence of operations with the cursor. - * This variant of the function uses for queries a transaction you have obtained somewhere else. - * - * This function should be called when the LMDBAL::Storage is already opened and before any query with this cursor! - * It will do nothing to a cursor that was already opened (no matter what way). - * - * \param[in] transaction - a transaction, can be read only - * - * \exception LMDBAL::Closed thrown if you try to open the cursor on a closed database - * \exception LMDBAL::Unknown thrown if there was a problem opening the cursor by the lmdb - * \exception LMDBAL::TransactionTerminated thrown if the passed transaction not active, any action with it's inner ID is an error - * \exception LMDBAL::CursorEmpty thrown if the cursor was empty - */ -template -void LMDBAL::Cursor::open (const Transaction& transaction) { - if (empty()) - throw CursorEmpty(openCursorMethodName); - - storage->ensureOpened(openCursorMethodName); - TransactionID txn = storage->extractTransactionId(transaction, openCursorMethodName); - switch (state) { - case closed: { - int result = storage->_mdbCursorOpen(txn, &cursor); - if (result != MDB_SUCCESS) - storage->throwUnknown(result); - - storage->attachCursorToTransaction(id, cursor, this); - state = openedPublic; - } break; - default: - break; - } -} - -/** - * \brief Renews a cursor - * - * This function aborts current transaction if the cursor was opened with it's own transaction - * (does not mess up if the transaction was public), - * creates new private transaction and rebinds this cursor to it. - * - * Theoretically you could call this method if your public transaction was aborted (or commited) - * but you wish to continue to keep working with your cursor. - * Or if you just want to rebind your cursor to a new private transaction. - * - * This function does nothing if the cursor is closed - * - * \exception LMDBAL::Closed thrown if you try to renew the cursor on a closed database - * \exception LMDBAL::Unknown thrown if there was a problem beginning new transaction or if there was a problem renewing the cursor by lmdb - * \exception LMDBAL::CursorEmpty thrown if the cursor was empty - */ -template -void LMDBAL::Cursor::renew () { - if (empty()) - throw CursorEmpty(openCursorMethodName); - - storage->ensureOpened(renewCursorMethodName); - switch (state) { - case openedPrivate: - storage->closeCursorTransaction(cursor, false); - storage->openCursorTransaction(&cursor, true); - break; - case openedPublic: - storage->disconnectCursorFromTransaction(id, cursor); - storage->openCursorTransaction(&cursor, true); - state = openedPrivate; - break; - default: - break; - } -} - -/** - * \brief Renews a cursor - * - * This function aborts current transaction if the cursor was opened with it's own transaction - * (does not mess up if the transaction was public), - * and rebinds this cursor to a passed new transaction. - * - * Theoretically you could call this method if your previous public transaction was aborted (or commited) - * but you wish to continue to keep working with your cursor. - * Or if you just want to rebind your cursor to another public transaction. - * - * This function does nothing if the cursor is closed - * - * \param[in] transaction - a transaction you wish this cursor to be bound to - * - * \exception LMDBAL::Closed thrown if you try to renew the cursor on a closed database - * \exception LMDBAL::Unknown thrown if there was a problem renewing the cursor by lmdb - * \exception LMDBAL::TransactionTerminated thrown if the passed transaction not active, any action with it's inner ID is an error - * \exception LMDBAL::CursorEmpty thrown if the cursor was empty - */ -template -void LMDBAL::Cursor::renew (const Transaction& transaction) { - if (empty()) - throw CursorEmpty(openCursorMethodName); - - storage->ensureOpened(renewCursorMethodName); - TransactionID txn = storage->extractTransactionId(transaction, renewCursorMethodName); - switch (state) { - case openedPrivate: { - storage->closeCursorTransaction(cursor, false); - int result = storage->_mdbCursorRenew(txn, cursor); - if (result != MDB_SUCCESS) - storage->throwUnknown(result); - - storage->attachCursorToTransaction(id, cursor, this); - state = openedPublic; - } break; - case openedPublic: { - storage->disconnectCursorFromTransaction(id, cursor); - int result = storage->_mdbCursorRenew(txn, cursor); - if (result != MDB_SUCCESS) - storage->throwUnknown(result); - - storage->attachCursorToTransaction(id, cursor, this); - } break; - default: - break; - } -} - -/** - * \brief Termiates a sequence of operations with the cursor - * - * This is a normal way to tell that you're done with the cursor and don't want to continue the sequence of queries. - * The state of the cursor is lost after calling this method, some inner resorce is freed. - * - * If the cursor was opened with the private transaction - the owner storage will be notified of the aborted transaction. - * - * This function does nothing on a closed cursor. - */ -template -void LMDBAL::Cursor::close () { - switch (state) { - case openedPublic: - storage->disconnectCursorFromTransaction(id, cursor); - storage->_mdbCursorClose(cursor); - - state = closed; - break; - case openedPrivate: - storage->closeCursorTransaction(cursor, true); - - state = closed; - break; - default: - break; - } -} - -/** - * \brief Tells if the cursor is open - */ -template -bool LMDBAL::Cursor::opened () const { - return state != closed; + reset(); } /** @@ -614,16 +337,16 @@ std::pair LMDBAL::Cursor::current () const { template bool LMDBAL::Cursor::set (const K& key) { if (state == closed) - storage->throwCursorNotReady(setMethodName); + static_cast*>(storage)->throwCursorNotReady(setMethodName); - MDB_val mdbKey = storage->keySerializer.setData(key); - int result = storage->_mdbCursorSet(cursor, mdbKey); + MDB_val mdbKey = static_cast*>(storage)->keySerializer.setData(key); + int result = static_cast*>(storage)->_mdbCursorSet(handle, mdbKey); if (result == MDB_SUCCESS) return true; else if (result == MDB_NOTFOUND) return false; - storage->throwUnknown(result); + static_cast*>(storage)->throwUnknown(result); return false; //unreachable, just to suppress the warning } @@ -651,18 +374,18 @@ void LMDBAL::Cursor::operateCursorRead( const std::string& operationName ) const { if (state == closed) - storage->throwCursorNotReady(methodName); + static_cast*>(storage)->throwCursorNotReady(methodName); MDB_val mdbKey, mdbValue; - int result = storage->_mdbCursorGet(cursor, mdbKey, mdbValue, operation); + int result = static_cast*>(storage)->_mdbCursorGet(handle, mdbKey, mdbValue, operation); if (result != MDB_SUCCESS) - storage->throwNotFoundOrUnknown(result, operationName); + static_cast*>(storage)->throwNotFoundOrUnknown(result, operationName); - storage->keySerializer.deserialize(mdbKey, key); - storage->valueSerializer.deserialize(mdbValue, value); + static_cast*>(storage)->keySerializer.deserialize(mdbKey, key); + static_cast*>(storage)->valueSerializer.deserialize(mdbValue, value); if (state == openedPrivate) - storage->discoveredRecord(key, value); + static_cast*>(storage)->discoveredRecord(key, value); else - storage->discoveredRecord(key, value, storage->_mdbCursorTxn(cursor)); + static_cast*>(storage)->discoveredRecord(key, value, static_cast*>(storage)->_mdbCursorTxn(handle)); } diff --git a/src/cursorcommon.cpp b/src/cursorcommon.cpp new file mode 100644 index 0000000..bfa77f0 --- /dev/null +++ b/src/cursorcommon.cpp @@ -0,0 +1,342 @@ +/* + * LMDB Abstraction Layer. + * Copyright (C) 2023 Yury Gubich + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "cursorcommon.h" + +/** + * \class LMDBAL::CursorCommon + * \brief An object to manage cursor internals and state. + * + * Cursors are owned by the storage, they die with the storage. + * They also get closed if the storage is closed (if you close by the database for example) + * + * You can obtain an instance of this class calling LMDBAL::Storage::createCursor() + * and destory it calling LMDBAL::Storage::destoryCursor() at any time, LMDBAL::Base doesn't necessarily need to be opened. + * + * You are not supposed to instantiate or destory instances of this class yourself! + */ + +#include "storagecommon.h" + +static uint32_t idCounter = 0; + +/** + * \brief Creates a empty class + */ +LMDBAL::CursorCommon::CursorCommon (): + id(0), + state(closed), + handle(nullptr), + storage(nullptr) +{} + +/** + * \brief Creates a cursor + * + * \param[in] _storage a storage that created this cursor + */ +LMDBAL::CursorCommon::CursorCommon (StorageCommon* _storage): + id(++idCounter), + state(closed), + handle(nullptr), + storage(_storage) +{} + +/** + * \brief Moves other cursor into this class + * + * \param[in] other other instance that is being moved + */ +LMDBAL::CursorCommon::CursorCommon (CursorCommon&& other): + id(other.id), + state(other.state), + handle(other.handle), + storage(other.storage) +{ + other.dropped(); + + if (state == openedPublic) + storage->attachCursorToTransaction(id, handle, this); +} + +/** + * \brief Destroys this cursor + * + * If the cursor wasn't properly closed - it's going to be upon destruction + */ +LMDBAL::CursorCommon::~CursorCommon () noexcept { + close(); +} + +/** + * \brief Move assignment operator + * + * Transfers other cursor into this one + */ +LMDBAL::CursorCommon& LMDBAL::CursorCommon::operator = (CursorCommon&& other) { + terminated(); + + id = other.id; + state = other.state; + handle = other.handle; + storage = other.storage; + + other.reset(); + + if (state == openedPublic) + storage->attachCursorToTransaction(id, handle, this); + + return *this; +} + +/** + * \brief A private method that turns cursor into an empty one + * + * This method is called from LMDBAL::Storage, when the cursor is getting destoryed. + * After this method cursors will become empty, and can't be used anymore + */ +void LMDBAL::CursorCommon::reset () { + id = 0; + state = closed; + handle = nullptr; + storage = nullptr; +} + +/** + * \brief A private method that turns cursor into an empty one + * + * This function is called from LMDBAL::Storage, when it gets destroyed, but still has some valid cursors. + * Those cursors will become empty, and can't be used anymore + */ +void LMDBAL::CursorCommon::dropped () { + terminated(); + reset(); +} + +/** + * \brief A private function called to inform the cursor he has been terminated + * + * Is expected to be called from transaction, database, storage or move constructor + */ +void LMDBAL::CursorCommon::terminated () { + switch (state) { + case openedPublic: + storage->_mdbCursorClose(handle); + state = closed; + break; + case openedPrivate: + storage->closeCursorTransaction(handle, true); + state = closed; + break; + default: + break; + } +} + +/** + * \brief Termiates a sequence of operations with the cursor + * + * This is a normal way to tell that you're done with the cursor and don't want to continue the sequence of queries. + * The state of the cursor is lost after calling this method, some inner resorce is freed. + * + * If the cursor was opened with the private transaction - the owner storage will be notified of the aborted transaction. + * + * This function does nothing on a closed cursor. + */ +void LMDBAL::CursorCommon::close () { + switch (state) { + case openedPublic: + storage->disconnectCursorFromTransaction(id, handle); + storage->_mdbCursorClose(handle); + + state = closed; + break; + case openedPrivate: + storage->closeCursorTransaction(handle, true); + + state = closed; + break; + default: + break; + } +} + +/** + * \brief Opens the cursor for operations. + * + * This is a normal way to start the sequence of operations with the cursor. + * This variant of the function creates a read only transaction just for this cursor + * + * This function should be called when the LMDBAL::Storage is already opened and before any query with this cursor! + * It will do nothing to a cursor that was already opened (no matter what way). + * + * \exception LMDBAL::Closed thrown if you try to open the cursor on a closed database + * \exception LMDBAL::Unknown thrown if there was a problem opening the cursor by the lmdb, or to begin a transaction + * \exception LMDBAL::CursorEmpty thrown if the cursor was empty + */ +void LMDBAL::CursorCommon::open () { + if (empty()) + throw CursorEmpty(openCursorMethodName); + + switch (state) { + case closed: + storage->openCursorTransaction(&handle, false); + state = openedPrivate; + break; + default: + break; + } +} + +/** + * \brief Opens the cursor for operations. + * + * This is a normal way to start the sequence of operations with the cursor. + * This variant of the function uses for queries a transaction you have obtained somewhere else. + * + * This function should be called when the LMDBAL::Storage is already opened and before any query with this cursor! + * It will do nothing to a cursor that was already opened (no matter what way). + * + * \param[in] transaction - a transaction, can be read only + * + * \exception LMDBAL::Closed thrown if you try to open the cursor on a closed database + * \exception LMDBAL::Unknown thrown if there was a problem opening the cursor by the lmdb + * \exception LMDBAL::TransactionTerminated thrown if the passed transaction not active, any action with it's inner ID is an error + * \exception LMDBAL::CursorEmpty thrown if the cursor was empty + */ +void LMDBAL::CursorCommon::open (const Transaction& transaction) { + if (empty()) + throw CursorEmpty(openCursorMethodName); + + storage->ensureOpened(openCursorMethodName); + TransactionID txn = storage->extractTransactionId(transaction, openCursorMethodName); + switch (state) { + case closed: { + int result = storage->_mdbCursorOpen(txn, &handle); + if (result != MDB_SUCCESS) + storage->throwUnknown(result); + + storage->attachCursorToTransaction(id, handle, this); + state = openedPublic; + } break; + default: + break; + } +} + +/** + * \brief Renews a cursor + * + * This function aborts current transaction if the cursor was opened with it's own transaction + * (does not mess up if the transaction was public), + * creates new private transaction and rebinds this cursor to it. + * + * Theoretically you could call this method if your public transaction was aborted (or commited) + * but you wish to continue to keep working with your cursor. + * Or if you just want to rebind your cursor to a new private transaction. + * + * This function does nothing if the cursor is closed + * + * \exception LMDBAL::Closed thrown if you try to renew the cursor on a closed database + * \exception LMDBAL::Unknown thrown if there was a problem beginning new transaction or if there was a problem renewing the cursor by lmdb + * \exception LMDBAL::CursorEmpty thrown if the cursor was empty + */ +void LMDBAL::CursorCommon::renew () { + if (empty()) + throw CursorEmpty(openCursorMethodName); + + storage->ensureOpened(renewCursorMethodName); + switch (state) { + case openedPrivate: + storage->closeCursorTransaction(handle, false); + storage->openCursorTransaction(&handle, true); + break; + case openedPublic: + storage->disconnectCursorFromTransaction(id, handle); + storage->openCursorTransaction(&handle, true); + state = openedPrivate; + break; + default: + break; + } +} + +/** + * \brief Renews a cursor + * + * This function aborts current transaction if the cursor was opened with it's own transaction + * (does not mess up if the transaction was public), + * and rebinds this cursor to a passed new transaction. + * + * Theoretically you could call this method if your previous public transaction was aborted (or commited) + * but you wish to continue to keep working with your cursor. + * Or if you just want to rebind your cursor to another public transaction. + * + * This function does nothing if the cursor is closed + * + * \param[in] transaction - a transaction you wish this cursor to be bound to + * + * \exception LMDBAL::Closed thrown if you try to renew the cursor on a closed database + * \exception LMDBAL::Unknown thrown if there was a problem renewing the cursor by lmdb + * \exception LMDBAL::TransactionTerminated thrown if the passed transaction not active, any action with it's inner ID is an error + * \exception LMDBAL::CursorEmpty thrown if the cursor was empty + */ +void LMDBAL::CursorCommon::renew (const Transaction& transaction) { + if (empty()) + throw CursorEmpty(openCursorMethodName); + + storage->ensureOpened(renewCursorMethodName); + TransactionID txn = storage->extractTransactionId(transaction, renewCursorMethodName); + switch (state) { + case openedPrivate: { + storage->closeCursorTransaction(handle, false); + int result = storage->_mdbCursorRenew(txn, handle); + if (result != MDB_SUCCESS) + storage->throwUnknown(result); + + storage->attachCursorToTransaction(id, handle, this); + state = openedPublic; + } break; + case openedPublic: { + storage->disconnectCursorFromTransaction(id, handle); + int result = storage->_mdbCursorRenew(txn, handle); + if (result != MDB_SUCCESS) + storage->throwUnknown(result); + + storage->attachCursorToTransaction(id, handle, this); + } break; + default: + break; + } +} + +/** + * \brief Returns true if the cursor is empty + * + * Empty cursors can't be used, they can be only targets of move operations + */ +bool LMDBAL::CursorCommon::empty () const { + return id == 0; +} + +/** + * \brief Tells if the cursor is open + */ +bool LMDBAL::CursorCommon::opened () const { + return state != closed; +} diff --git a/src/cursorcommon.h b/src/cursorcommon.h new file mode 100644 index 0000000..fee4e8b --- /dev/null +++ b/src/cursorcommon.h @@ -0,0 +1,90 @@ +/* + * LMDB Abstraction Layer. + * Copyright (C) 2023 Yury Gubich + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include + +#include + +namespace LMDBAL { + +class Transaction; +class StorageCommon; + +class CursorCommon { + friend class Transaction; +protected: + enum State { /** - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -namespace LMDBAL { - -class Transaction; - -class iCursor { - friend class Transaction; -protected: - virtual ~iCursor() {} - virtual void terminated() = 0; -}; - -} diff --git a/src/storage.h b/src/storage.h index 99141e0..844beb2 100644 --- a/src/storage.h +++ b/src/storage.h @@ -25,6 +25,7 @@ #include "serializer.h" #include "cursor.h" #include "transaction.h" +#include "storagecommon.h" class BaseTest; class DuplicatesTest; @@ -33,111 +34,8 @@ class StorageCursorTest; namespace LMDBAL { -class iStorage { - friend class Base; -public: -protected: - iStorage(Base* parent, const std::string& name, bool duplicates = false); - virtual ~iStorage(); - - /** - * \brief A private virtual function I need to open each storage in the database - * - * \param[in] transaction - lmdb transaction to call mdb_dbi_open - * \returns MDB_SUCCESS if everything went smooth or MDB_ -like error code - */ - virtual int open(MDB_txn * transaction) = 0; - virtual void close(); - virtual void handleDrop(); - - bool isDBOpened() const; - const std::string& dbName() const; - - void ensureOpened(const std::string& methodName) const; - void throwDuplicateOrUnknown(int rc, const std::string& key) const; - void throwDuplicateOrUnknown(int rc, TransactionID txn, const std::string& key) const; - void throwNotFoundOrUnknown(int rc, const std::string& key) const; - void throwNotFoundOrUnknown(int rc, TransactionID txn, const std::string& key) const; - void throwUnknown(int rc, TransactionID txn) const; - void throwUnknown(int rc) const; - void throwUnknown(const std::string& message) const; - void throwDuplicate(const std::string& key) const; - void throwNotFound(const std::string& key) const; - void throwCursorNotReady(const std::string& method) const; - - TransactionID extractTransactionId(const Transaction& txn, const std::string& action = "") const; - TransactionID beginReadOnlyTransaction() const; - TransactionID beginTransaction() const; - void commitTransaction(TransactionID id); - void abortTransaction(TransactionID id) const; - virtual void transactionStarted(TransactionID txn, bool readOnly) const; - virtual void transactionCommited(TransactionID txn); - virtual void transactionAborted(TransactionID txn) const; - virtual int drop(TransactionID transaction); - virtual SizeType count(TransactionID txn) const; - - void openCursorTransaction(MDB_cursor** cursor, bool renew = false) const; - void closeCursorTransaction(MDB_cursor* cursor, bool closeCursor = false) const; - void attachCursorToTransaction(uint32_t cursorId, MDB_cursor* cursorHandle, iCursor* pointer) const; - void disconnectCursorFromTransaction(uint32_t cursorId, MDB_cursor* cursorHandle) const; - - int _mdbOpen(MDB_txn* txn, unsigned int flags = 0); - - int _mdbPut(MDB_txn* txn, MDB_val& key, MDB_val& data, unsigned int flags = 0); - int _mdbGet(MDB_txn* txn, MDB_val& key, MDB_val& data) const; - int _mdbDel(MDB_txn* txn, MDB_val& key); - int _mdbDel(MDB_txn* txn, MDB_val& key, MDB_val& data); - - int _mdbStat(MDB_txn* txn, MDB_stat& stat) const; - int _mdbFlags(MDB_txn* txn, uint32_t& flags) const; - - int _mdbCursorOpen(MDB_txn* txn, MDB_cursor** cursor) const; - void _mdbCursorClose(MDB_cursor* cursor) const; - int _mdbCursorGet(MDB_cursor* cursor, MDB_val& key, MDB_val& data, MDB_cursor_op operation) const; - int _mdbCursorSet(MDB_cursor* cursor, MDB_val& key) const; - int _mdbCursorDel(MDB_cursor* cursor, unsigned int flags = 0); - int _mdbCursorPut(MDB_cursor* cursor, MDB_val& key, MDB_val& data, unsigned int flags = 0); - - int _mdbCursorRenew(MDB_txn* txn, MDB_cursor* cursor) const; - MDB_txn* _mdbCursorTxn(MDB_cursor* cursor) const; - -public: - virtual void drop(); - virtual int drop(const WriteTransaction& txn); - virtual SizeType count() const; - virtual SizeType count(const Transaction& txn) const; - -protected: - MDB_dbi dbi; /**<\brief lmdb storage handle*/ - Base* db; /**<\brief parent database pointer (borrowed)*/ - const std::string name; /**<\brief this storage name*/ - const bool duplicates; /**<\brief true if storage supports duplicates*/ - - inline static const std::string dropMethodName = "drop"; /**<\brief member function name, just for exceptions*/ - inline static const std::string countMethodName = "count"; /**<\brief member function name, just for exceptions*/ - inline static const std::string flagsMethodName = "flags"; /**<\brief member function name, just for exceptions*/ - - inline static const std::string addRecordMethodName = "addRecord"; /**<\brief member function name, just for exceptions*/ - inline static const std::string forceRecordMethodName = "forceRecord"; /**<\brief member function name, just for exceptions*/ - inline static const std::string changeRecordMethodName = "changeRecord"; /**<\brief member function name, just for exceptions*/ - inline static const std::string removeRecordMethodName = "removeRecord"; /**<\brief member function name, just for exceptions*/ - inline static const std::string checkRecordMethodName = "checkRecord"; /**<\brief member function name, just for exceptions*/ - inline static const std::string getRecordMethodName = "getRecord"; /**<\brief member function name, just for exceptions*/ - inline static const std::string readAllMethodName = "readAllRecord"; /**<\brief member function name, just for exceptions*/ - inline static const std::string replaceAllMethodName = "replaceAll"; /**<\brief member function name, just for exceptions*/ - inline static const std::string addRecordsMethodName = "addRecords"; /**<\brief member function name, just for exceptions*/ - inline static const std::string openCursorTransactionMethodName = "openCursorTransaction"; /**<\brief member function name, just for exceptions*/ - -protected: - template - int makeStorage(MDB_txn* transaction, bool duplicates = false); - - template - static std::string toString(const T& value); -}; - template -class Storage : public iStorage { +class Storage : public StorageCommon { friend class ::BaseTest; friend class ::DuplicatesTest; friend class ::CacheCursorTest; @@ -165,7 +63,7 @@ protected: virtual uint32_t addRecords(const std::map& data, TransactionID txn, bool overwrite = false); public: - using iStorage::drop; + using StorageCommon::drop; virtual void addRecord(const K& key, const V& value); virtual void addRecord(const K& key, const V& value, const WriteTransaction& txn); virtual bool forceRecord(const K& key, const V& value); //returns true if there was addition, false if change diff --git a/src/storage.hpp b/src/storage.hpp index e56e91a..7f89fc2 100644 --- a/src/storage.hpp +++ b/src/storage.hpp @@ -46,7 +46,7 @@ */ template LMDBAL::Storage::Storage(Base* parent, const std::string& name, bool duplicates): - iStorage(parent, name, duplicates), + StorageCommon(parent, name, duplicates), keySerializer(), valueSerializer(), cursors() @@ -1015,7 +1015,7 @@ void LMDBAL::Storage::close() { for (const std::pair*>& pair : cursors) pair.second->terminated(); - iStorage::close(); + StorageCommon::close(); } /** @@ -1051,7 +1051,7 @@ void LMDBAL::Storage::destroyCursor(LMDBAL::Cursor& cursor) { cursor.close(); cursors.erase(itr); - cursor.freed(); + cursor.reset(); } /** @@ -1103,81 +1103,3 @@ void LMDBAL::Storage::discoveredRecord(const K& key, const V& value, Trans UNUSED(value); UNUSED(txn); } - -/** - * \brief A functiion to actually open MDB_dbi storage - * - * \tparam K type of keys in opening storage - * - * \param[in] transaction - lmdb transaction to call mdb_dbi_open, must be a writable transaction! - * \param[in] duplicates - true if key duplicates are allowed (false by default) - * - * \returns MDB_SUCCESS if everything went smooth or MDB_ -like error code - * - * This is a way to optimise database using MDB_INTEGERKEY flag, - * when the key is actually kind of an integer - * This infrastructure also allowes us to customize mdb_dbi_open call in the future - */ -template -inline int LMDBAL::iStorage::makeStorage(MDB_txn* transaction, bool duplicates) { - unsigned int flags = MDB_CREATE; - if constexpr (std::is_integral::value) - flags |= MDB_INTEGERKEY; - - if (duplicates) { - flags |= MDB_DUPSORT; - - if constexpr (std::is_scalar::value) - flags |= MDB_DUPFIXED; - - if constexpr ( - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value - ) //for some reason lmdb breaks if it's not one of these types in MDB_DUPFIXED mode - flags |= MDB_INTEGERDUP; - } - - return _mdbOpen(transaction, flags); -} - -/** - * \brief A method to cast a value (which can be a value or a key) to string. - * - * This function is mainly used in exceptions, to report which key was duplicated or not found. - * You can define your own specializations to this function in case std::to_string doesn't cover your case - * - * \param[in] value a value that should be converted to string - * \returns a string presentation of value - */ -template -inline std::string LMDBAL::iStorage::toString(const T& value) { - return std::to_string(value); -} - -/** - * \brief A method to cast a value (which can be a value or a key) to string. - * - * QString spectialization - * - * \param[in] value a value that should be converted to string - * \returns a string presentation of value - */ -template<> -inline std::string LMDBAL::iStorage::toString(const QString& value) { - return value.toStdString(); -} - -/** - * \brief A method to cast a value (which can be a value or a key) to string. - * - * std::string spectialization - * - * \param[in] value a value that should be converted to string - * \returns a string presentation of value - */ -template<> -inline std::string LMDBAL::iStorage::toString(const std::string& value) { - return value; -} diff --git a/src/storage.cpp b/src/storagecommon.cpp similarity index 78% rename from src/storage.cpp rename to src/storagecommon.cpp index 4359987..298f48d 100644 --- a/src/storage.cpp +++ b/src/storagecommon.cpp @@ -16,7 +16,9 @@ * along with this program. If not, see . */ -#include "storage.h" +#include "storagecommon.h" + +#include "cursorcommon.h" #define UNUSED(x) (void)(x) @@ -37,7 +39,7 @@ * \param[in] name - the name of the storage * \param[in] duplicates - true if key duplicates are allowed (false by default) */ -LMDBAL::iStorage::iStorage(Base* parent, const std::string& name, bool duplicates): +LMDBAL::StorageCommon::StorageCommon(Base* parent, const std::string& name, bool duplicates): dbi(), db(parent), name(name), @@ -47,12 +49,12 @@ LMDBAL::iStorage::iStorage(Base* parent, const std::string& name, bool duplicate /** * \brief Destroys a storage interface */ -LMDBAL::iStorage::~iStorage() {} +LMDBAL::StorageCommon::~StorageCommon () {} /** * \brief A private virtual function to close each storage in the database */ -void LMDBAL::iStorage::close() { +void LMDBAL::StorageCommon::close() { mdb_dbi_close(db->environment, dbi); } @@ -67,7 +69,7 @@ void LMDBAL::iStorage::close() { * * \exception LMDBAL::TransactionTerminated thrown if the passed transaction not active, any action with it's inner ID is an error */ -LMDBAL::TransactionID LMDBAL::iStorage::extractTransactionId(const Transaction& txn, const std::string& action) const { +LMDBAL::TransactionID LMDBAL::StorageCommon::extractTransactionId(const Transaction& txn, const std::string& action) const { if (!txn.isActive()) throw TransactionTerminated(db->name, name, action); @@ -82,11 +84,11 @@ LMDBAL::TransactionID LMDBAL::iStorage::extractTransactionId(const Transaction& * \exception LMDBAL::Closed thrown if the database was closed * \exception LMDBAL::Unknown thrown if something unexpected happened */ -void LMDBAL::iStorage::drop() { +void LMDBAL::StorageCommon::drop() { ensureOpened(dropMethodName); TransactionID txn = beginTransaction(); - int rc = iStorage::drop(txn); + int rc = StorageCommon::drop(txn); if (rc != MDB_SUCCESS) { abortTransaction(txn); throw Unknown(db->name, mdb_strerror(rc), name); @@ -104,7 +106,7 @@ void LMDBAL::iStorage::drop() { * \param[in] transaction - transaction ID, must be writable transaction! * \returns MDB_SUCCESS if everything went fine, MDB_ code otherwise */ -int LMDBAL::iStorage::drop(TransactionID transaction) { +int LMDBAL::StorageCommon::drop(TransactionID transaction) { return mdb_drop(transaction, dbi, 0); } @@ -118,7 +120,7 @@ int LMDBAL::iStorage::drop(TransactionID transaction) { * * \exception LMDBAL::TransactionTerminated thrown if the transaction was not active */ -int LMDBAL::iStorage::drop(const WriteTransaction& txn) { +int LMDBAL::StorageCommon::drop(const WriteTransaction& txn) { ensureOpened(dropMethodName); return drop(extractTransactionId(txn, dropMethodName)); } @@ -130,7 +132,7 @@ int LMDBAL::iStorage::drop(const WriteTransaction& txn) { * * \exception LMDBAL::Closed thrown if the database was closed */ -void LMDBAL::iStorage::ensureOpened(const std::string& methodName) const { +void LMDBAL::StorageCommon::ensureOpened(const std::string& methodName) const { if (!isDBOpened()) throw Closed(methodName, db->name, name); } @@ -143,7 +145,7 @@ void LMDBAL::iStorage::ensureOpened(const std::string& methodName) const { * \exception LMDBAL::Closed thrown if the database was closed * \exception LMDBAL::Unknown thrown if something unexpected happened */ -LMDBAL::SizeType LMDBAL::iStorage::count() const { +LMDBAL::SizeType LMDBAL::StorageCommon::count() const { ensureOpened(countMethodName); TransactionID txn = beginReadOnlyTransaction(); @@ -168,7 +170,7 @@ LMDBAL::SizeType LMDBAL::iStorage::count() const { * \exception std::out_of_range thrown if LMDBAL::Transaction pointer wasn't found in the LMDBAL::Base */ -void LMDBAL::iStorage::attachCursorToTransaction (uint32_t cursorId, MDB_cursor* cursorHandle, iCursor* pointer) const { +void LMDBAL::StorageCommon::attachCursorToTransaction (uint32_t cursorId, MDB_cursor* cursorHandle, CursorCommon* pointer) const { TransactionID txnID = _mdbCursorTxn(cursorHandle); Transaction* txn = db->transactions.at(txnID); txn->cursors[cursorId] = pointer; @@ -186,7 +188,7 @@ void LMDBAL::iStorage::attachCursorToTransaction (uint32_t cursorId, MDB_cursor* * \exception LMDBAL::Closed thrown if you try to open the cursor on a closed database * \exception LMDBAL::Unknown thrown if there was a problem opening the cursor by the lmdb, or to begin a transaction */ -void LMDBAL::iStorage::openCursorTransaction (MDB_cursor** cursor, bool renew) const { +void LMDBAL::StorageCommon::openCursorTransaction (MDB_cursor** cursor, bool renew) const { ensureOpened(openCursorTransactionMethodName); TransactionID txn = beginReadOnlyTransaction(); @@ -210,7 +212,7 @@ void LMDBAL::iStorage::openCursorTransaction (MDB_cursor** cursor, bool renew) c * \param[in] cursor - cursor handle * \param[in] closeCursor - true if the cursor should also get closed, false if you wish to leave it open */ -void LMDBAL::iStorage::closeCursorTransaction (MDB_cursor* cursor, bool closeCursor) const { +void LMDBAL::StorageCommon::closeCursorTransaction (MDB_cursor* cursor, bool closeCursor) const { TransactionID txn = _mdbCursorTxn(cursor); if (closeCursor) _mdbCursorClose(cursor); @@ -228,7 +230,7 @@ void LMDBAL::iStorage::closeCursorTransaction (MDB_cursor* cursor, bool closeCur * \exception std::out_of_range thrown if LMDBAL::Transaction pointer wasn't found in the LMDBAL::Base */ -void LMDBAL::iStorage::disconnectCursorFromTransaction (uint32_t cursorId, MDB_cursor* cursorHandle) const { +void LMDBAL::StorageCommon::disconnectCursorFromTransaction (uint32_t cursorId, MDB_cursor* cursorHandle) const { TransactionID txnID = _mdbCursorTxn(cursorHandle); Transaction* txn = db->transactions.at(txnID); txn->cursors.erase(cursorId); @@ -243,7 +245,7 @@ void LMDBAL::iStorage::disconnectCursorFromTransaction (uint32_t cursorId, MDB_c * * \exception LMDBAL::Unknown thrown if something unexpected happened */ -LMDBAL::SizeType LMDBAL::iStorage::count(TransactionID txn) const { +LMDBAL::SizeType LMDBAL::StorageCommon::count(TransactionID txn) const { MDB_stat stat; int rc = mdb_stat(txn, dbi, &stat); if (rc != MDB_SUCCESS) @@ -262,7 +264,7 @@ LMDBAL::SizeType LMDBAL::iStorage::count(TransactionID txn) const { * \exception LMDBAL::Unknown thrown if something unexpected happened * \exception LMDBAL::TransactionTerminated thrown if the passed transaction not active, any action with it's inner ID is an error */ -LMDBAL::SizeType LMDBAL::iStorage::count(const Transaction& txn) const { +LMDBAL::SizeType LMDBAL::StorageCommon::count(const Transaction& txn) const { ensureOpened(countMethodName); return count(extractTransactionId(txn, countMethodName)); } @@ -279,7 +281,7 @@ LMDBAL::SizeType LMDBAL::iStorage::count(const Transaction& txn) const { * \exception LMDBAL::Exist thrown if rc == MDB_KEYEXIST * \exception LMDBAL::Unknown thrown if rc != MDB_KEYEXIST */ -void LMDBAL::iStorage::throwDuplicateOrUnknown(int rc, TransactionID txn, const std::string& key) const { +void LMDBAL::StorageCommon::throwDuplicateOrUnknown(int rc, TransactionID txn, const std::string& key) const { abortTransaction(txn); throwDuplicateOrUnknown(rc, key); } @@ -296,7 +298,7 @@ void LMDBAL::iStorage::throwDuplicateOrUnknown(int rc, TransactionID txn, const * \exception LMDBAL::NotFound thrown if rc == MDB_NOTFOUND * \exception LMDBAL::Unknown thrown if rc != MDB_NOTFOUND */ -void LMDBAL::iStorage::throwNotFoundOrUnknown(int rc, LMDBAL::TransactionID txn, const std::string& key) const { +void LMDBAL::StorageCommon::throwNotFoundOrUnknown(int rc, LMDBAL::TransactionID txn, const std::string& key) const { abortTransaction(txn); throwNotFoundOrUnknown(rc, key); } @@ -312,7 +314,7 @@ void LMDBAL::iStorage::throwNotFoundOrUnknown(int rc, LMDBAL::TransactionID txn, * \exception LMDBAL::Exist thrown if rc == MDB_KEYEXIST * \exception LMDBAL::Unknown thrown if rc != MDB_KEYEXIST */ -void LMDBAL::iStorage::throwDuplicateOrUnknown(int rc, const std::string& key) const { +void LMDBAL::StorageCommon::throwDuplicateOrUnknown(int rc, const std::string& key) const { if (rc == MDB_KEYEXIST) throwDuplicate(key); else @@ -330,7 +332,7 @@ void LMDBAL::iStorage::throwDuplicateOrUnknown(int rc, const std::string& key) c * \exception LMDBAL::NotFound thrown if rc == MDB_NOTFOUND * \exception LMDBAL::Unknown thrown if rc != MDB_NOTFOUND */ -void LMDBAL::iStorage::throwNotFoundOrUnknown(int rc, const std::string& key) const { +void LMDBAL::StorageCommon::throwNotFoundOrUnknown(int rc, const std::string& key) const { if (rc == MDB_NOTFOUND) throwNotFound(key); else @@ -347,7 +349,7 @@ void LMDBAL::iStorage::throwNotFoundOrUnknown(int rc, const std::string& key) co * * \exception LMDBAL::Unknown thrown everytime */ -void LMDBAL::iStorage::throwUnknown(int rc, LMDBAL::TransactionID txn) const { +void LMDBAL::StorageCommon::throwUnknown(int rc, LMDBAL::TransactionID txn) const { abortTransaction(txn); throwUnknown(rc); } @@ -359,7 +361,7 @@ void LMDBAL::iStorage::throwUnknown(int rc, LMDBAL::TransactionID txn) const { * * \returns database name */ -const std::string & LMDBAL::iStorage::dbName() const { +const std::string & LMDBAL::StorageCommon::dbName() const { return db->name;} /** @@ -369,7 +371,7 @@ const std::string & LMDBAL::iStorage::dbName() const { * * \returns true if database is ipened, false otherwise */ -bool LMDBAL::iStorage::isDBOpened() const { +bool LMDBAL::StorageCommon::isDBOpened() const { return db->opened;} /** @@ -381,7 +383,7 @@ bool LMDBAL::iStorage::isDBOpened() const { * * \exception LMDBAL::Unknown thrown everytime */ -void LMDBAL::iStorage::throwUnknown(int rc) const { +void LMDBAL::StorageCommon::throwUnknown(int rc) const { throw Unknown(db->name, mdb_strerror(rc), name);} /** @@ -393,7 +395,7 @@ void LMDBAL::iStorage::throwUnknown(int rc) const { * * \exception LMDBAL::Unknown thrown everytime */ -void LMDBAL::iStorage::throwUnknown(const std::string& message) const { +void LMDBAL::StorageCommon::throwUnknown(const std::string& message) const { throw Unknown(db->name, message, name);} /** @@ -405,7 +407,7 @@ void LMDBAL::iStorage::throwUnknown(const std::string& message) const { * * \exception LMDBAL::Exist thrown everytime */ -void LMDBAL::iStorage::throwDuplicate(const std::string& key) const { +void LMDBAL::StorageCommon::throwDuplicate(const std::string& key) const { throw Exist(key, db->name, name);} /** @@ -417,7 +419,7 @@ void LMDBAL::iStorage::throwDuplicate(const std::string& key) const { * * \exception LMDBAL::NotFound thrown everytime */ -void LMDBAL::iStorage::throwNotFound(const std::string& key) const { +void LMDBAL::StorageCommon::throwNotFound(const std::string& key) const { throw NotFound(key, db->name, name);} /** @@ -429,7 +431,7 @@ void LMDBAL::iStorage::throwNotFound(const std::string& key) const { * * \exception LMDBAL::CursorNotReady thrown everytime */ -void LMDBAL::iStorage::throwCursorNotReady(const std::string& method) const { +void LMDBAL::StorageCommon::throwCursorNotReady(const std::string& method) const { throw CursorNotReady(method, db->name, name);} /** @@ -439,7 +441,7 @@ void LMDBAL::iStorage::throwCursorNotReady(const std::string& method) const { * * \returns read only transaction */ -LMDBAL::TransactionID LMDBAL::iStorage::beginReadOnlyTransaction() const { +LMDBAL::TransactionID LMDBAL::StorageCommon::beginReadOnlyTransaction() const { return db->beginPrivateReadOnlyTransaction(name);} /** @@ -449,7 +451,7 @@ LMDBAL::TransactionID LMDBAL::iStorage::beginReadOnlyTransaction() const { * * \returns read only transaction */ -LMDBAL::TransactionID LMDBAL::iStorage::beginTransaction() const { +LMDBAL::TransactionID LMDBAL::StorageCommon::beginTransaction() const { return db->beginPrivateTransaction(name);} /** @@ -457,7 +459,7 @@ LMDBAL::TransactionID LMDBAL::iStorage::beginTransaction() const { * * Ment to be called from heirs, name is reported to the database just to be displayed in std::exception::what() message */ -void LMDBAL::iStorage::abortTransaction(LMDBAL::TransactionID id) const { +void LMDBAL::StorageCommon::abortTransaction(LMDBAL::TransactionID id) const { db->abortPrivateTransaction(id, name);} /** @@ -467,7 +469,7 @@ void LMDBAL::iStorage::abortTransaction(LMDBAL::TransactionID id) const { * * \exception LMDBAL::Unknown thrown if something unexpected happened */ -void LMDBAL::iStorage::commitTransaction(LMDBAL::TransactionID id) { +void LMDBAL::StorageCommon::commitTransaction(LMDBAL::TransactionID id) { db->commitPrivateTransaction(id, name);} /** @@ -482,7 +484,7 @@ void LMDBAL::iStorage::commitTransaction(LMDBAL::TransactionID id) { * \param[in] txn - ID of started transaction * \param[in] readOnly - true if transaction is read-only, false otherwise */ -void LMDBAL::iStorage::transactionStarted(LMDBAL::TransactionID txn, bool readOnly) const { +void LMDBAL::StorageCommon::transactionStarted(LMDBAL::TransactionID txn, bool readOnly) const { UNUSED(txn); UNUSED(readOnly); } @@ -498,7 +500,7 @@ void LMDBAL::iStorage::transactionStarted(LMDBAL::TransactionID txn, bool readOn * * \param[in] txn - ID of started transaction */ -void LMDBAL::iStorage::transactionCommited(LMDBAL::TransactionID txn) { +void LMDBAL::StorageCommon::transactionCommited(LMDBAL::TransactionID txn) { UNUSED(txn);} /** @@ -512,7 +514,7 @@ void LMDBAL::iStorage::transactionCommited(LMDBAL::TransactionID txn) { * * \param[in] txn - ID of started transaction */ -void LMDBAL::iStorage::transactionAborted(LMDBAL::TransactionID txn) const { +void LMDBAL::StorageCommon::transactionAborted(LMDBAL::TransactionID txn) const { UNUSED(txn);} /** @@ -521,65 +523,65 @@ void LMDBAL::iStorage::transactionAborted(LMDBAL::TransactionID txn) const { * It's a protected method that is called to optimise drop process * after the transaction is commited. Used just for optimisations. */ -void LMDBAL::iStorage::handleDrop() {} +void LMDBAL::StorageCommon::handleDrop() {} -int LMDBAL::iStorage::_mdbOpen(MDB_txn *txn, unsigned int flags) { +int LMDBAL::StorageCommon::_mdbOpen(MDB_txn *txn, unsigned int flags) { return mdb_dbi_open(txn, name.c_str(), flags, &dbi); } -int LMDBAL::iStorage::_mdbPut(MDB_txn* txn, MDB_val& key, MDB_val& data, unsigned int flags) { +int LMDBAL::StorageCommon::_mdbPut(MDB_txn* txn, MDB_val& key, MDB_val& data, unsigned int flags) { return mdb_put(txn, dbi, &key, &data, flags); } -int LMDBAL::iStorage::_mdbGet(MDB_txn* txn, MDB_val& key, MDB_val& data) const { +int LMDBAL::StorageCommon::_mdbGet(MDB_txn* txn, MDB_val& key, MDB_val& data) const { return mdb_get(txn, dbi, &key, &data); } -int LMDBAL::iStorage::_mdbDel(MDB_txn* txn, MDB_val& key) { +int LMDBAL::StorageCommon::_mdbDel(MDB_txn* txn, MDB_val& key) { return mdb_del(txn, dbi, &key, NULL); } -int LMDBAL::iStorage::_mdbDel(MDB_txn* txn, MDB_val& key, MDB_val& data) { +int LMDBAL::StorageCommon::_mdbDel(MDB_txn* txn, MDB_val& key, MDB_val& data) { return mdb_del(txn, dbi, &key, &data); } -int LMDBAL::iStorage::_mdbStat(MDB_txn* txn, MDB_stat& stat) const { +int LMDBAL::StorageCommon::_mdbStat(MDB_txn* txn, MDB_stat& stat) const { return mdb_stat(txn, dbi, &stat); } -int LMDBAL::iStorage::_mdbFlags(MDB_txn* txn, uint32_t& flags) const { +int LMDBAL::StorageCommon::_mdbFlags(MDB_txn* txn, uint32_t& flags) const { return mdb_dbi_flags(txn, dbi, &flags); } -int LMDBAL::iStorage::_mdbCursorOpen(MDB_txn* txn, MDB_cursor** cursor) const { +int LMDBAL::StorageCommon::_mdbCursorOpen(MDB_txn* txn, MDB_cursor** cursor) const { return mdb_cursor_open(txn, dbi, cursor); } -void LMDBAL::iStorage::_mdbCursorClose(MDB_cursor *cursor) const { +void LMDBAL::StorageCommon::_mdbCursorClose(MDB_cursor *cursor) const { mdb_cursor_close(cursor); } -int LMDBAL::iStorage::_mdbCursorGet(MDB_cursor* cursor, MDB_val& key, MDB_val& data, MDB_cursor_op operation) const { +int LMDBAL::StorageCommon::_mdbCursorGet(MDB_cursor* cursor, MDB_val& key, MDB_val& data, MDB_cursor_op operation) const { return mdb_cursor_get(cursor, &key, &data, operation); } -int LMDBAL::iStorage::_mdbCursorSet(MDB_cursor* cursor, MDB_val& key) const { +int LMDBAL::StorageCommon::_mdbCursorSet(MDB_cursor* cursor, MDB_val& key) const { return mdb_cursor_get(cursor, &key, NULL, MDB_SET); } -int LMDBAL::iStorage::_mdbCursorDel(MDB_cursor* cursor, unsigned int flags) { +int LMDBAL::StorageCommon::_mdbCursorDel(MDB_cursor* cursor, unsigned int flags) { return mdb_cursor_del(cursor, flags); } -int LMDBAL::iStorage::_mdbCursorPut(MDB_cursor* cursor, MDB_val& key, MDB_val& data, unsigned int flags) { +int LMDBAL::StorageCommon::_mdbCursorPut(MDB_cursor* cursor, MDB_val& key, MDB_val& data, unsigned int flags) { return mdb_cursor_put(cursor, &key, &data, flags); } -int LMDBAL::iStorage::_mdbCursorRenew(MDB_txn* txn, MDB_cursor* cursor) const { +int LMDBAL::StorageCommon::_mdbCursorRenew(MDB_txn* txn, MDB_cursor* cursor) const { return mdb_cursor_renew(txn, cursor); } -MDB_txn* LMDBAL::iStorage::_mdbCursorTxn(MDB_cursor* cursor) const { +MDB_txn* LMDBAL::StorageCommon::_mdbCursorTxn(MDB_cursor* cursor) const { return mdb_cursor_txn(cursor); } diff --git a/src/storagecommon.h b/src/storagecommon.h new file mode 100644 index 0000000..367ef62 --- /dev/null +++ b/src/storagecommon.h @@ -0,0 +1,139 @@ +/* + * LMDB Abstraction Layer. + * Copyright (C) 2023 Yury Gubich + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include + +#include + +#include "base.h" +#include "transaction.h" + +namespace LMDBAL { + +class CursorCommon; + +class StorageCommon { + friend class Base; + friend class CursorCommon; +public: +protected: + StorageCommon(Base* parent, const std::string& name, bool duplicates = false); + virtual ~ StorageCommon(); + + /** + * \brief A private virtual function I need to open each storage in the database + * + * \param[in] transaction - lmdb transaction to call mdb_dbi_open + * \returns MDB_SUCCESS if everything went smooth or MDB_ -like error code + */ + virtual int open(MDB_txn * transaction) = 0; + virtual void close(); + virtual void handleDrop(); + + bool isDBOpened() const; + const std::string& dbName() const; + + void ensureOpened(const std::string& methodName) const; + void throwDuplicateOrUnknown(int rc, const std::string& key) const; + void throwDuplicateOrUnknown(int rc, TransactionID txn, const std::string& key) const; + void throwNotFoundOrUnknown(int rc, const std::string& key) const; + void throwNotFoundOrUnknown(int rc, TransactionID txn, const std::string& key) const; + void throwUnknown(int rc, TransactionID txn) const; + void throwUnknown(int rc) const; + void throwUnknown(const std::string& message) const; + void throwDuplicate(const std::string& key) const; + void throwNotFound(const std::string& key) const; + void throwCursorNotReady(const std::string& method) const; + + TransactionID extractTransactionId(const Transaction& txn, const std::string& action = "") const; + TransactionID beginReadOnlyTransaction() const; + TransactionID beginTransaction() const; + void commitTransaction(TransactionID id); + void abortTransaction(TransactionID id) const; + virtual void transactionStarted(TransactionID txn, bool readOnly) const; + virtual void transactionCommited(TransactionID txn); + virtual void transactionAborted(TransactionID txn) const; + virtual int drop(TransactionID transaction); + virtual SizeType count(TransactionID txn) const; + + void openCursorTransaction(MDB_cursor** cursor, bool renew = false) const; + void closeCursorTransaction(MDB_cursor* cursor, bool closeCursor = false) const; + void attachCursorToTransaction(uint32_t cursorId, MDB_cursor* cursorHandle, CursorCommon* pointer) const; + void disconnectCursorFromTransaction(uint32_t cursorId, MDB_cursor* cursorHandle) const; + + int _mdbOpen(MDB_txn* txn, unsigned int flags = 0); + + int _mdbPut(MDB_txn* txn, MDB_val& key, MDB_val& data, unsigned int flags = 0); + int _mdbGet(MDB_txn* txn, MDB_val& key, MDB_val& data) const; + int _mdbDel(MDB_txn* txn, MDB_val& key); + int _mdbDel(MDB_txn* txn, MDB_val& key, MDB_val& data); + + int _mdbStat(MDB_txn* txn, MDB_stat& stat) const; + int _mdbFlags(MDB_txn* txn, uint32_t& flags) const; + + int _mdbCursorOpen(MDB_txn* txn, MDB_cursor** cursor) const; + void _mdbCursorClose(MDB_cursor* cursor) const; + int _mdbCursorGet(MDB_cursor* cursor, MDB_val& key, MDB_val& data, MDB_cursor_op operation) const; + int _mdbCursorSet(MDB_cursor* cursor, MDB_val& key) const; + int _mdbCursorDel(MDB_cursor* cursor, unsigned int flags = 0); + int _mdbCursorPut(MDB_cursor* cursor, MDB_val& key, MDB_val& data, unsigned int flags = 0); + + int _mdbCursorRenew(MDB_txn* txn, MDB_cursor* cursor) const; + MDB_txn* _mdbCursorTxn(MDB_cursor* cursor) const; + +public: + virtual void drop(); + virtual int drop(const WriteTransaction& txn); + virtual SizeType count() const; + virtual SizeType count(const Transaction& txn) const; + +protected: + MDB_dbi dbi; /**<\brief lmdb storage handle*/ + Base* db; /**<\brief parent database pointer (borrowed)*/ + const std::string name; /**<\brief this storage name*/ + const bool duplicates; /**<\brief true if storage supports duplicates*/ + + inline static const std::string dropMethodName = "drop"; /**<\brief member function name, just for exceptions*/ + inline static const std::string countMethodName = "count"; /**<\brief member function name, just for exceptions*/ + inline static const std::string flagsMethodName = "flags"; /**<\brief member function name, just for exceptions*/ + + inline static const std::string addRecordMethodName = "addRecord"; /**<\brief member function name, just for exceptions*/ + inline static const std::string forceRecordMethodName = "forceRecord"; /**<\brief member function name, just for exceptions*/ + inline static const std::string changeRecordMethodName = "changeRecord"; /**<\brief member function name, just for exceptions*/ + inline static const std::string removeRecordMethodName = "removeRecord"; /**<\brief member function name, just for exceptions*/ + inline static const std::string checkRecordMethodName = "checkRecord"; /**<\brief member function name, just for exceptions*/ + inline static const std::string getRecordMethodName = "getRecord"; /**<\brief member function name, just for exceptions*/ + inline static const std::string readAllMethodName = "readAllRecord"; /**<\brief member function name, just for exceptions*/ + inline static const std::string replaceAllMethodName = "replaceAll"; /**<\brief member function name, just for exceptions*/ + inline static const std::string addRecordsMethodName = "addRecords"; /**<\brief member function name, just for exceptions*/ + inline static const std::string openCursorTransactionMethodName = "openCursorTransaction"; /**<\brief member function name, just for exceptions*/ + +protected: + template + int makeStorage(MDB_txn* transaction, bool duplicates = false); + + template + static std::string toString(const T& value); +}; + +} + +#include "storagecommon.hpp" diff --git a/src/storagecommon.hpp b/src/storagecommon.hpp new file mode 100644 index 0000000..c32ae6f --- /dev/null +++ b/src/storagecommon.hpp @@ -0,0 +1,99 @@ +/* + * LMDB Abstraction Layer. + * Copyright (C) 2023 Yury Gubich + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "storagecommon.h" + +/** + * \brief A functiion to actually open MDB_dbi storage + * + * \tparam K type of keys in opening storage + * + * \param[in] transaction - lmdb transaction to call mdb_dbi_open, must be a writable transaction! + * \param[in] duplicates - true if key duplicates are allowed (false by default) + * + * \returns MDB_SUCCESS if everything went smooth or MDB_ -like error code + * + * This is a way to optimise database using MDB_INTEGERKEY flag, + * when the key is actually kind of an integer + * This infrastructure also allowes us to customize mdb_dbi_open call in the future + */ +template +inline int LMDBAL::StorageCommon::makeStorage(MDB_txn* transaction, bool duplicates) { + unsigned int flags = MDB_CREATE; + if constexpr (std::is_integral::value) + flags |= MDB_INTEGERKEY; + + if (duplicates) { + flags |= MDB_DUPSORT; + + if constexpr (std::is_scalar::value) + flags |= MDB_DUPFIXED; + + if constexpr ( + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value + ) //for some reason lmdb breaks if it's not one of these types in MDB_DUPFIXED mode + flags |= MDB_INTEGERDUP; + } + + return _mdbOpen(transaction, flags); +} + +/** + * \brief A method to cast a value (which can be a value or a key) to string. + * + * This function is mainly used in exceptions, to report which key was duplicated or not found. + * You can define your own specializations to this function in case std::to_string doesn't cover your case + * + * \param[in] value a value that should be converted to string + * \returns a string presentation of value + */ +template +inline std::string LMDBAL::StorageCommon::toString(const T& value) { + return std::to_string(value); +} + +/** + * \brief A method to cast a value (which can be a value or a key) to string. + * + * QString spectialization + * + * \param[in] value a value that should be converted to string + * \returns a string presentation of value + */ +template<> +inline std::string LMDBAL::StorageCommon::toString(const QString& value) { + return value.toStdString(); +} + +/** + * \brief A method to cast a value (which can be a value or a key) to string. + * + * std::string spectialization + * + * \param[in] value a value that should be converted to string + * \returns a string presentation of value + */ +template<> +inline std::string LMDBAL::StorageCommon::toString(const std::string& value) { + return value; +} diff --git a/src/transaction.cpp b/src/transaction.cpp index d2e6a05..f92e7e8 100644 --- a/src/transaction.cpp +++ b/src/transaction.cpp @@ -18,6 +18,8 @@ #include "transaction.h" +#include "cursorcommon.h" + /** * \class LMDBAL::Transaction * \brief Public read only transaction @@ -131,7 +133,7 @@ void LMDBAL::Transaction::reset() { * \brief Closes attached curors; */ void LMDBAL::Transaction::closeCursors () { - for (const std::pair& pair : cursors) + for (const std::pair& pair : cursors) pair.second->terminated(); } diff --git a/src/transaction.h b/src/transaction.h index f37dab0..0fb28e3 100644 --- a/src/transaction.h +++ b/src/transaction.h @@ -19,14 +19,14 @@ #pragma once #include "base.h" -#include "icursor.h" namespace LMDBAL { -class iStorage; +class StorageCommon; +class CursorCommon; class Transaction { friend class Base; - friend class iStorage; + friend class StorageCommon; public: explicit Transaction(); explicit Transaction(Transaction&& other); @@ -44,10 +44,10 @@ protected: void closeCursors(); protected: - TransactionID txn; /**<\brief Transaction inner handler*/ - bool active; /**<\brief Transaction state*/ - const Base* parent; /**<\brief Pointer to the database this transaction belongs to*/ - std::map cursors; /**<\brief a collection of cursors curently opened under this transaction*/ + TransactionID txn; /**<\brief Transaction inner handler*/ + bool active; /**<\brief Transaction state*/ + const Base* parent; /**<\brief Pointer to the database this transaction belongs to*/ + std::map cursors; /**<\brief a collection of cursors curently opened under this transaction*/ }; class WriteTransaction : public Transaction { diff --git a/test/cachetransaction.cpp b/test/cachetransaction.cpp index 0fc259d..a2c0e42 100644 --- a/test/cachetransaction.cpp +++ b/test/cachetransaction.cpp @@ -182,7 +182,7 @@ TEST_F(CacheTransactionsTest, ConcurentModification) { int pid = fork(); if (pid == 0) { // I am the child - usleep(1); + usleep(5); std::cout << "beggining second transaction" << std::endl; LMDBAL::WriteTransaction txn2 = db->beginTransaction(); //<--- this is where the execution should pause //and wait for the first transaction to get finished @@ -208,7 +208,7 @@ TEST_F(CacheTransactionsTest, ConcurentModification) { LMDBAL::WriteTransaction txn1 = db->beginTransaction(); std::cout << "putting parent thread to sleep for 5 ms" << std::endl; - usleep(5); + usleep(10); std::cout << "adding first transaction value" << std::endl; c1->addRecord(5, 812, txn1); @@ -235,7 +235,7 @@ TEST_F(CacheTransactionsTest, RAIIResourceFree) { int pid = fork(); if (pid == 0) { // I am the child - usleep(1); + usleep(5); std::cout << "beggining child transaction" << std::endl; LMDBAL::WriteTransaction txn2 = db->beginTransaction(); //<--- this is where the execution should pause //and wait for the first transaction to get finished @@ -256,7 +256,7 @@ TEST_F(CacheTransactionsTest, RAIIResourceFree) { LMDBAL::WriteTransaction txn1 = db->beginTransaction(); std::cout << "putting parent thread to sleep for 5 ms" << std::endl; - usleep(5); + usleep(10); std::cout << "parent thread woke up" << std::endl; std::cout << "adding value from parent thread" << std::endl; diff --git a/test/storagetransaction.cpp b/test/storagetransaction.cpp index 237a7c6..d4b9089 100644 --- a/test/storagetransaction.cpp +++ b/test/storagetransaction.cpp @@ -181,7 +181,7 @@ TEST_F(StorageTransactionsTest, ConcurentModification) { int pid = fork(); if (pid == 0) { // I am the child - usleep(1); + usleep(5); std::cout << "beggining second transaction" << std::endl; LMDBAL::WriteTransaction txn2 = db->beginTransaction(); //<--- this is where the execution should pause //and wait for the first transaction to get finished @@ -207,7 +207,7 @@ TEST_F(StorageTransactionsTest, ConcurentModification) { LMDBAL::WriteTransaction txn1 = db->beginTransaction(); std::cout << "putting parent thread to sleep for 5 ms" << std::endl; - usleep(5); + usleep(10); std::cout << "adding first transaction value" << std::endl; t1->addRecord(5, 812, txn1); @@ -234,7 +234,7 @@ TEST_F(StorageTransactionsTest, RAIIResourceFree) { int pid = fork(); if (pid == 0) { // I am the child - usleep(1); + usleep(5); std::cout << "beggining child transaction" << std::endl; LMDBAL::WriteTransaction txn2 = db->beginTransaction(); //<--- this is where the execution should pause //and wait for the first transaction to get finished @@ -255,7 +255,7 @@ TEST_F(StorageTransactionsTest, RAIIResourceFree) { LMDBAL::WriteTransaction txn1 = db->beginTransaction(); std::cout << "putting parent thread to sleep for 5 ms" << std::endl; - usleep(5); + usleep(10); std::cout << "parent thread woke up" << std::endl; std::cout << "adding value from parent thread" << std::endl; From 3ae1fd15c0f4f753227d6fd5bafa4968c7310b92 Mon Sep 17 00:00:00 2001 From: blue Date: Sun, 5 Jan 2025 18:39:36 +0200 Subject: [PATCH 26/34] Some refactor --- src/cursorcommon.cpp | 40 ++++++++++++++++++++++++++++++++-------- src/cursorcommon.h | 4 ++++ src/storagecommon.cpp | 33 +++++++-------------------------- src/storagecommon.h | 4 ++-- src/transaction.h | 9 +++++---- 5 files changed, 50 insertions(+), 40 deletions(-) diff --git a/src/cursorcommon.cpp b/src/cursorcommon.cpp index bfa77f0..b8f1564 100644 --- a/src/cursorcommon.cpp +++ b/src/cursorcommon.cpp @@ -71,7 +71,7 @@ LMDBAL::CursorCommon::CursorCommon (CursorCommon&& other): other.dropped(); if (state == openedPublic) - storage->attachCursorToTransaction(id, handle, this); + attachToTransaction(); } /** @@ -99,7 +99,7 @@ LMDBAL::CursorCommon& LMDBAL::CursorCommon::operator = (CursorCommon&& other) { other.reset(); if (state == openedPublic) - storage->attachCursorToTransaction(id, handle, this); + attachToTransaction(); return *this; } @@ -161,7 +161,7 @@ void LMDBAL::CursorCommon::terminated () { void LMDBAL::CursorCommon::close () { switch (state) { case openedPublic: - storage->disconnectCursorFromTransaction(id, handle); + disconnectFromTransaction(); storage->_mdbCursorClose(handle); state = closed; @@ -231,7 +231,7 @@ void LMDBAL::CursorCommon::open (const Transaction& transaction) { if (result != MDB_SUCCESS) storage->throwUnknown(result); - storage->attachCursorToTransaction(id, handle, this); + transaction.cursors[id] = this; state = openedPublic; } break; default: @@ -267,7 +267,7 @@ void LMDBAL::CursorCommon::renew () { storage->openCursorTransaction(&handle, true); break; case openedPublic: - storage->disconnectCursorFromTransaction(id, handle); + disconnectFromTransaction(); storage->openCursorTransaction(&handle, true); state = openedPrivate; break; @@ -309,16 +309,16 @@ void LMDBAL::CursorCommon::renew (const Transaction& transaction) { if (result != MDB_SUCCESS) storage->throwUnknown(result); - storage->attachCursorToTransaction(id, handle, this); + transaction.cursors[id] = this; state = openedPublic; } break; case openedPublic: { - storage->disconnectCursorFromTransaction(id, handle); + disconnectFromTransaction(); int result = storage->_mdbCursorRenew(txn, handle); if (result != MDB_SUCCESS) storage->throwUnknown(result); - storage->attachCursorToTransaction(id, handle, this); + transaction.cursors[id] = this; } break; default: break; @@ -340,3 +340,27 @@ bool LMDBAL::CursorCommon::empty () const { bool LMDBAL::CursorCommon::opened () const { return state != closed; } + +/** + * \brief Links cursor to the transaction it has been opened with + * + * Cursor must be opened by a public transaction + * + * \exception std::out_of_range thrown if LMDBAL::Transaction pointer wasn't found in the LMDBAL::Base + */ +void LMDBAL::CursorCommon::attachToTransaction () { + Transaction* txn = storage->getTransactionForCursor(handle); + txn->cursors[id] = this; +} + +/** + * \brief Disconnects cursor from the transaction it has been opened with + * + * Cursor must be still opened by a public transaction + * + * \exception std::out_of_range thrown if LMDBAL::Transaction pointer wasn't found in the LMDBAL::Base + */ +void LMDBAL::CursorCommon::disconnectFromTransaction () { + Transaction* txn = storage->getTransactionForCursor(handle); + txn->cursors.erase(id); +} diff --git a/src/cursorcommon.h b/src/cursorcommon.h index fee4e8b..bf9b312 100644 --- a/src/cursorcommon.h +++ b/src/cursorcommon.h @@ -61,6 +61,10 @@ protected: void dropped(); void reset(); +private: + void attachToTransaction(); + void disconnectFromTransaction(); + protected: uint32_t id; State state; diff --git a/src/storagecommon.cpp b/src/storagecommon.cpp index 298f48d..3d7e92c 100644 --- a/src/storagecommon.cpp +++ b/src/storagecommon.cpp @@ -162,21 +162,19 @@ LMDBAL::SizeType LMDBAL::StorageCommon::count() const { } /** - * \brief Links cursor to the transaction it has been opened with + * \brief Retrieves public transaction object for a cursor handle * - * This a service function is designed to be called by from LMDBAL::Cursor - * Cursor must be opened by a public transaction + * Cursor must be still opened by a public transaction + * + * \param[out] cursor - cursor handle * * \exception std::out_of_range thrown if LMDBAL::Transaction pointer wasn't found in the LMDBAL::Base */ - -void LMDBAL::StorageCommon::attachCursorToTransaction (uint32_t cursorId, MDB_cursor* cursorHandle, CursorCommon* pointer) const { - TransactionID txnID = _mdbCursorTxn(cursorHandle); - Transaction* txn = db->transactions.at(txnID); - txn->cursors[cursorId] = pointer; +LMDBAL::Transaction* LMDBAL::StorageCommon::getTransactionForCursor (MDB_cursor* cursor) const { + TransactionID txnID = _mdbCursorTxn(cursor); + return db->transactions.at(txnID); } - /** * \brief Opens a transaction that is ment to be private to LMDBAL::Cursor, but public to the LMDBAL::Storage * @@ -221,22 +219,6 @@ void LMDBAL::StorageCommon::closeCursorTransaction (MDB_cursor* cursor, bool clo transactionAborted(txn); } -/** - * \brief Disconnects cursor from the transaction it has been opened with - * - * This a service function is designed to be called by from LMDBAL::Cursor - * Cursor must be still opened by a public transaction - * - * \exception std::out_of_range thrown if LMDBAL::Transaction pointer wasn't found in the LMDBAL::Base - */ - -void LMDBAL::StorageCommon::disconnectCursorFromTransaction (uint32_t cursorId, MDB_cursor* cursorHandle) const { - TransactionID txnID = _mdbCursorTxn(cursorHandle); - Transaction* txn = db->transactions.at(txnID); - txn->cursors.erase(cursorId); -} - - /** * \brief Storage size (private transaction variant) * @@ -553,7 +535,6 @@ int LMDBAL::StorageCommon::_mdbFlags(MDB_txn* txn, uint32_t& flags) const { return mdb_dbi_flags(txn, dbi, &flags); } - int LMDBAL::StorageCommon::_mdbCursorOpen(MDB_txn* txn, MDB_cursor** cursor) const { return mdb_cursor_open(txn, dbi, cursor); } diff --git a/src/storagecommon.h b/src/storagecommon.h index 367ef62..77a56d2 100644 --- a/src/storagecommon.h +++ b/src/storagecommon.h @@ -74,10 +74,10 @@ protected: virtual int drop(TransactionID transaction); virtual SizeType count(TransactionID txn) const; + Transaction* getTransactionForCursor(MDB_cursor* cursor) const; + void openCursorTransaction(MDB_cursor** cursor, bool renew = false) const; void closeCursorTransaction(MDB_cursor* cursor, bool closeCursor = false) const; - void attachCursorToTransaction(uint32_t cursorId, MDB_cursor* cursorHandle, CursorCommon* pointer) const; - void disconnectCursorFromTransaction(uint32_t cursorId, MDB_cursor* cursorHandle) const; int _mdbOpen(MDB_txn* txn, unsigned int flags = 0); diff --git a/src/transaction.h b/src/transaction.h index 0fb28e3..4866f17 100644 --- a/src/transaction.h +++ b/src/transaction.h @@ -27,6 +27,7 @@ class CursorCommon; class Transaction { friend class Base; friend class StorageCommon; + friend class CursorCommon; public: explicit Transaction(); explicit Transaction(Transaction&& other); @@ -44,10 +45,10 @@ protected: void closeCursors(); protected: - TransactionID txn; /**<\brief Transaction inner handler*/ - bool active; /**<\brief Transaction state*/ - const Base* parent; /**<\brief Pointer to the database this transaction belongs to*/ - std::map cursors; /**<\brief a collection of cursors curently opened under this transaction*/ + TransactionID txn; /**<\brief Transaction inner handler*/ + bool active; /**<\brief Transaction state*/ + const Base* parent; /**<\brief Pointer to the database this transaction belongs to*/ + mutable std::map cursors; /**<\brief a collection of cursors curently opened under this transaction*/ }; class WriteTransaction : public Transaction { From 1585b8e4f571fb3c29457e23aa006a8201802aea Mon Sep 17 00:00:00 2001 From: blue Date: Fri, 2 May 2025 18:19:06 +0300 Subject: [PATCH 27/34] Fix typos, fix some warnings, added more compile options, moved to forgejo CI --- {.gitea => .forgejo}/workflows/aur.yml | 0 {.gitea => .forgejo}/workflows/main.yml | 10 +- {.gitea => .forgejo}/workflows/release.yml | 4 +- {.gitea => .forgejo}/workflows/test.yml | 4 +- CMakeLists.txt | 132 ++++++++++++++------- README.md | 35 +++--- doc/CMakeLists.txt | 16 +-- src/base.cpp | 23 ++-- src/base.h | 10 +- src/serializer/serializer.hpp | 4 +- src/serializer/serializer_qbytearray.hpp | 14 ++- src/serializer/serializer_qstring.hpp | 30 ++++- src/serializer/serializer_stdstring.hpp | 4 +- src/storagecommon.cpp | 36 +++--- src/storagecommon.h | 2 +- 15 files changed, 204 insertions(+), 120 deletions(-) rename {.gitea => .forgejo}/workflows/aur.yml (100%) rename {.gitea => .forgejo}/workflows/main.yml (78%) rename {.gitea => .forgejo}/workflows/release.yml (93%) rename {.gitea => .forgejo}/workflows/test.yml (82%) diff --git a/.gitea/workflows/aur.yml b/.forgejo/workflows/aur.yml similarity index 100% rename from .gitea/workflows/aur.yml rename to .forgejo/workflows/aur.yml diff --git a/.gitea/workflows/main.yml b/.forgejo/workflows/main.yml similarity index 78% rename from .gitea/workflows/main.yml rename to .forgejo/workflows/main.yml index ed68bb0..44dba97 100644 --- a/.gitea/workflows/main.yml +++ b/.forgejo/workflows/main.yml @@ -1,4 +1,4 @@ -name: Main LMDBAL workfow +name: Main LMDBAL workflow run-name: ${{ gitea.actor }} is running LMDBAL main workflow on: push: @@ -8,13 +8,13 @@ on: jobs: test-qt5: name: Test LMDBAL with qt5 - uses: ./.gitea/workflows/test.yml + uses: ./.forgejo/workflows/test.yml with: flags: -D QT_VERSION_MAJOR=5 -D LMDBAL_NAME=LMDBAL-QT5 test-qt6: name: Test LMDBAL with qt6 - uses: ./.gitea/workflows/test.yml + uses: ./.forgejo/workflows/test.yml with: flags: -D QT_VERSION_MAJOR=6 -D LMDBAL_NAME=LMDBAL-QT6 @@ -31,7 +31,7 @@ jobs: - name: Configure working-directory: ./build - run: cmake .. BUILD_DOC_HTML=True -D BUILD_DOC_XML=True -D BUILD_DOC_MAN=True -D BUILD_DOXYGEN_AWESOME=True + run: cmake .. LMDBAL_BUILD_DOC_HTML=True -D LMDBAL_BUILD_DOC_XML=True -D LMDBAL_BUILD_DOC_MAN=True -D LMDBAL_BUILD_DOXYGEN_AWESOME=True - name: Build working-directory: ./build @@ -39,7 +39,7 @@ jobs: - name: Copy docs via scp uses: appleboy/scp-action@master - # working-directory: ./build/doc //doesn't work + # working-directory: ./build/doc //doesn't work with: host: ${{ secrets.DOMAIN_ROOT }} username: ${{ secrets.DEPLOY_USER_NAME }} diff --git a/.gitea/workflows/release.yml b/.forgejo/workflows/release.yml similarity index 93% rename from .gitea/workflows/release.yml rename to .forgejo/workflows/release.yml index 733957a..1af4d7c 100644 --- a/.gitea/workflows/release.yml +++ b/.forgejo/workflows/release.yml @@ -7,7 +7,7 @@ on: jobs: qt5: name: Release qt5 build to AUR - uses: ./.gitea/workflows/aur.yml + uses: ./.forgejo/workflows/aur.yml with: package-name: lmdbal-qt5 description: LMDB Abstraction Layer, qt5 version @@ -20,7 +20,7 @@ jobs: qt6: name: Release qt6 build to AUR - uses: ./.gitea/workflows/aur.yml + uses: ./.forgejo/workflows/aur.yml with: package-name: lmdbal-qt6 description: LMDB Abstraction Layer, qt6 version diff --git a/.gitea/workflows/test.yml b/.forgejo/workflows/test.yml similarity index 82% rename from .gitea/workflows/test.yml rename to .forgejo/workflows/test.yml index 922e361..a0f3867 100644 --- a/.gitea/workflows/test.yml +++ b/.forgejo/workflows/test.yml @@ -14,7 +14,7 @@ on: jobs: test: - name: Building and rinning unit tests + name: Building and running unit tests runs-on: archlinux steps: - name: Check out repository code @@ -25,7 +25,7 @@ jobs: - name: Configure working-directory: ./build - run: cmake .. -D BUILD_TESTS=True -D QT_VERSION_MAJOR= ${{ inputs.flags }} + run: cmake .. -D LMDBAL_STRICT=True -D LMDBAL_BUILD_TESTS=True -D QT_VERSION_MAJOR= ${{ inputs.flags }} - name: Build working-directory: ./build diff --git a/CMakeLists.txt b/CMakeLists.txt index 97b21ff..325901b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,9 @@ cmake_minimum_required(VERSION 3.16) project(LMDBAL - VERSION 0.6.0 - DESCRIPTION "LMDB (Lightning Memory-Mapped Database Manager) Abstraction Layer" - LANGUAGES CXX + VERSION 0.6.0 + DESCRIPTION "LMDB (Lightning Memory-Mapped Database Manager) Abstraction Layer" + LANGUAGES CXX ) cmake_policy(SET CMP0076 NEW) @@ -11,12 +11,16 @@ cmake_policy(SET CMP0079 NEW) set(LMDBAL_NAME ${PROJECT_NAME} CACHE STRING "Override for library name and install path") -option(BUILD_STATIC "Builds library as static library" OFF) -option(BUILD_TESTS "Builds tests" OFF) -option(BUILD_DOC_MAN "Builds man page documentation" OFF) -option(BUILD_DOC_HTML "Builds html documentation" OFF) -option(BUILD_DOC_XML "Builds xml documentation" OFF) -option(BUILD_DOXYGEN_AWESOME "Builds documentation alternative style" OFF) +option(LMDBAL_BUILD_STATIC "Builds library as static library" OFF) +option(LMDBAL_BUILD_TESTS "Builds tests" OFF) +option(LMDBAL_BUILD_DOC_MAN "Builds man page documentation" OFF) +option(LMDBAL_BUILD_DOC_HTML "Builds html documentation" OFF) +option(LMDBAL_BUILD_DOC_XML "Builds xml documentation" OFF) +option(LMDBAL_BUILD_DOXYGEN_AWESOME "Builds documentation alternative style" OFF) +option(LMDBAL_STRICT "Builds with extra compiler warnings" OFF) +option(LMDBAL_ASAN "Enables Address Sanitizer" OFF) +option(LMDBAL_UBSAN "Enables Undefined Behavior Sanitizer" OFF) +option(LMDBAL_TSAN "Enables Thread Sanitizer" OFF) include(GNUInstallDirs) include(CMakePackageConfigHelpers) @@ -29,40 +33,80 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") string(TOLOWER ${LMDBAL_NAME} LMDBAL_NAME_LOW) if (NOT DEFINED QT_VERSION_MAJOR) - find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core) -endif() + find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core) +endif () find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) find_package(LMDB REQUIRED) # Build type if (NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Debug) + set(CMAKE_BUILD_TYPE Debug) endif () -if (BUILD_STATIC) - add_library(${LMDBAL_NAME} STATIC) +if (LMDBAL_BUILD_STATIC) + add_library(${LMDBAL_NAME} STATIC) else () - add_library(${LMDBAL_NAME} SHARED) + add_library(${LMDBAL_NAME} SHARED) endif() -if (CMAKE_BUILD_TYPE STREQUAL "Release") - list(APPEND COMPILE_OPTIONS -O3) -elseif (CMAKE_BUILD_TYPE STREQUAL "Debug") - list(APPEND COMPILE_OPTIONS -g) - list(APPEND COMPILE_OPTIONS -Wall) - list(APPEND COMPILE_OPTIONS -Wextra) -endif() + +if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + list(APPEND COMPILE_OPTIONS -Wall) + list(APPEND COMPILE_OPTIONS -Wextra) + list(APPEND COMPILE_OPTIONS -Wpedantic) + + if (CMAKE_BUILD_TYPE STREQUAL "Release") + list(APPEND COMPILE_OPTIONS -O3) + list(APPEND COMPILE_OPTIONS -DNDEBUG) + elseif (CMAKE_BUILD_TYPE STREQUAL "Debug") + list(APPEND COMPILE_OPTIONS -O0) + list(APPEND COMPILE_OPTIONS -g3) + list(APPEND COMPILE_OPTIONS -ggdb) + endif () + + if (LMDBAL_STRICT) + list(APPEND COMPILE_OPTIONS -Wall) + list(APPEND COMPILE_OPTIONS -Werror) + list(APPEND COMPILE_OPTIONS -Wconversion) + list(APPEND COMPILE_OPTIONS -Wnon-virtual-dtor) + list(APPEND COMPILE_OPTIONS -Wold-style-cast) + list(APPEND COMPILE_OPTIONS -Wcast-align) + list(APPEND COMPILE_OPTIONS -Wunused) + list(APPEND COMPILE_OPTIONS -Woverloaded-virtual) + list(APPEND COMPILE_OPTIONS -Wsign-conversion) + list(APPEND COMPILE_OPTIONS -Wnull-dereference) + endif () + + if(JAY_ENABLE_ASAN) + list(APPEND COMPILE_OPTIONS -fsanitize=address) + list(APPEND COMPILE_OPTIONS -fno-omit-frame-pointer) + list(APPEND LINK_OPTIONS -fsanitize=address) + add_link_options() + endif() + + if(JAY_ENABLE_UBSAN) + list(APPEND COMPILE_OPTIONS -fsanitize=undefined) + list(APPEND LINK_OPTIONS -fsanitize=undefined) + endif() + + if(JAY_ENABLE_TSAN) + list(APPEND COMPILE_OPTIONS -fsanitize=thread) + list(APPEND LINK_OPTIONS -fsanitize=thread) + endif() +endif () message("Compilation options: " ${COMPILE_OPTIONS}) +message("Linking options: " ${LINK_OPTIONS}) target_compile_options(${LMDBAL_NAME} PRIVATE ${COMPILE_OPTIONS}) +target_link_options(${LMDBAL_NAME} PRIVATE ${LINK_OPTIONS}) set_property(TARGET ${LMDBAL_NAME} PROPERTY VERSION ${version}) set_property(TARGET ${LMDBAL_NAME} PROPERTY SOVERSION 1) set_property(TARGET ${LMDBAL_NAME} PROPERTY EXPORT_NAME ${LMDBAL_NAME}) set_property(TARGET ${LMDBAL_NAME} PROPERTY INTERFACE_${LMDBAL_NAME}_MAJOR_VERSION 1) set_property(TARGET ${LMDBAL_NAME} APPEND PROPERTY - COMPATIBLE_INTERFACE_STRING ${LMDBAL_NAME}_MAJOR_VERSION + COMPATIBLE_INTERFACE_STRING ${LMDBAL_NAME}_MAJOR_VERSION ) if (UNIX) @@ -70,36 +114,36 @@ if (UNIX) set_property(TARGET ${LMDBAL_NAME} PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) set_property(TARGET ${LMDBAL_NAME} PROPERTY SKIP_BUILD_RPATH FALSE) set_property(TARGET ${LMDBAL_NAME} PROPERTY BUILD_WITH_INSTALL_RPATH FALSE) -endif() +endif () add_subdirectory(src) -if (BUILD_DOC_MAN OR BUILD_DOC_HTML OR BUILD_DOC_XML) - find_package(Doxygen) - if (DOXYGEN_FOUND) - add_subdirectory(doc) - else() - message("Was trying to build documentation, but Doxygen was not found, skipping documentation") - endif() -endif() +if (LMDBAL_BUILD_DOC_MAN OR LMDBAL_BUILD_DOC_HTML OR LMDBAL_BUILD_DOC_XML) + find_package(Doxygen) + if (DOXYGEN_FOUND) + add_subdirectory(doc) + else () + message("Was trying to build documentation, but Doxygen was not found, skipping documentation") + endif () +endif () -if (BUILD_TESTS) - add_subdirectory(test) +if (LMDBAL_BUILD_TESTS) + add_subdirectory(test) endif () target_include_directories( - ${LMDBAL_NAME} - PUBLIC - $ - $ - $ + ${LMDBAL_NAME} + PUBLIC + $ + $ + $ ) target_include_directories(${LMDBAL_NAME} PRIVATE ${Qt${QT_VERSION_MAJOR}_INCLUDE_DIRS}) target_include_directories(${LMDBAL_NAME} PRIVATE ${Qt${QT_VERSION_MAJOR}Core_INCLUDE_DIRS}) target_link_libraries( - ${LMDBAL_NAME} - Qt${QT_VERSION_MAJOR}::Core - lmdb + ${LMDBAL_NAME} + Qt${QT_VERSION_MAJOR}::Core + lmdb ) configure_package_config_file( @@ -127,7 +171,7 @@ install(EXPORT ${LMDBAL_NAME_LOW}Targets ) install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/${LMDBAL_NAME_LOW}Config.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/${LMDBAL_NAME_LOW}ConfigVersion.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${LMDBAL_NAME_LOW}Config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${LMDBAL_NAME_LOW}ConfigVersion.cmake" DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${LMDBAL_NAME_LOW} ) diff --git a/README.md b/README.md index 1226357..3c5d671 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,8 @@ #### As a system library -If you're using LMDBAL as a system library you probably have no control over it's build options. The easiest way to include the project is to add following +If you're using LMDBAL as a system library, you probably have no control over its build options. +The easiest way to include the project is to add the following ``` find_package(lmdbal) @@ -29,14 +30,14 @@ if (LMDBAL_FOUND) endif() ``` -#### As an embeded subproject +#### As an embedded subproject -If you're using LMDBAL as a embeded library you might want to control it's build options, for example you can run +If you're using LMDBAL as a embedded library, you might want to control its build options, for example, you can run ``` -set(BUILD_STATIC ON) +set(LMDBAL_BUILD_STATIC ON) ``` -before including the library in your project. This will set the library to be build in a static mode. +... before including the library in your project. This will set the library to be build in a static mode. Then you want to run something like this ``` @@ -67,9 +68,11 @@ $ cmake --build . $ cmake --install . --prefix install ``` -This way will create you a `lmdbal/build` directory with temporary files, and `lmdbal/build/install` with all the export files for installation to the system. +This way will create you a `lmdbal/build` directory with temporary files, and `lmdbal/build/install` +with all the export files for installation to the system. -After `cmake ..` you can specify keys to alter the building process. In this context building keys are transfered like so +After `cmake ..` you can specify keys to alter the building process. +In this context building keys are transferred like so ``` cmake .. -D KEY1=VALUE1 -D KEY2=VALUE2 ... @@ -80,22 +83,26 @@ cmake .. -D KEY1=VALUE1 -D KEY2=VALUE2 ... Here is the list of keys you can pass to configuration phase of `cmake ..`: - `CMAKE_BUILD_TYPE` - `Debug` just builds showing all warnings, `Release` builds with no warnings and applies optimizations (default is `Debug`); -- `BUILD_STATIC` - `True` builds project as a static library, `False` builds as dynamic (default is `False`); -- `BUILD_TESTS` - `True` build unit tests, `False` does not (default is `False`); +- `LMDBAL_BUILD_STATIC` - `True` builds project as a static library, `False` builds as dynamic (default is `False`); +- `LMDBAL_BUILD_TESTS` - `True` build unit tests, `False` does not (default is `False`); - `BUILD_DOC` - `True` build doxygen documentation, `False` does not (default is `False`); -- `BUILD_DOXYGEN_AWESOME` - `True` build doxygen awesome theme if `BUILD_DOC` is also `True` (default is `False`); -- `QT_VERSION_MAJOR` - `5` links against Qt5, `6` links agains Qt6, there is no default, so, if you didn't specify it the project will chose automatically; -- `LMDBAL_NAME` - `LMDBAL` builds main target with this name, also install path witll be this name lowercase, usefull if you want to build `LMDBAL-QT6` not to conflict with `LMDBAL-QT5`; +- `LMDBAL_BUILD_DOXYGEN_AWESOME` - `True` build doxygen awesome theme if `BUILD_DOC` is also `True` (default is `False`); +- `QT_VERSION_MAJOR` - `5` links against Qt5, `6` links against Qt6, there is no default, so, if you didn't specify it, the project will choose automatically; +- `LMDBAL_NAME` - `LMDBAL` builds the main target with this name, also the installation path will be this name lowercase, useful if you want to build `LMDBAL-QT6` not to conflict with `LMDBAL-QT5`; +- `LMDBAL_STRICT` - `True` builds with extra warnings and considers them errors (default is `False`); +- `LMDBAL_ASAN` - `True` builds with address sanitizer (default is `False`); +- `LMDBAL_TSAN` - `True` builds with thread sanitizer (default is `False`); +- `LMDBAL_UBSAN` - `True` builds with undefined behavior sanitizer (default is `False`); #### Running tests -If you built the library with `-D BUILD_TESTS=True`, then there will be `lmdbal/build/tests/runUnitTests` executable file. You can simply run it as +If you built the library with `-D LMDBAL_BUILD_TESTS=True`, then there will be `lmdbal/build/tests/runUnitTests` executable file. You can run it as ``` ./runUnitTests ``` -if you're in the same directory with it +... if you're in the same directory with it ## License diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 0757340..66f3b76 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -1,14 +1,14 @@ -if (BUILD_DOC_HTML) +if (LMDBAL_BUILD_DOC_HTML) set(DOXYGEN_GENERATE_HTML YES) endif() -if (BUILD_DOC_MAN) +if (LMDBAL_BUILD_DOC_MAN) set(DOXYGEN_GENERATE_MAN YES) endif() -if (BUILD_DOC_XML) +if (LMDBAL_BUILD_DOC_XML) set(DOXYGEN_GENERATE_XML YES) endif() -if (BUILD_DOXYGEN_AWESOME) +if (LMDBAL_BUILD_DOXYGEN_AWESOME) include(ExternalProject) ExternalProject_Add(doxygen-awesome-css GIT_REPOSITORY https://github.com/jothepro/doxygen-awesome-css.git @@ -42,25 +42,25 @@ doxygen_add_docs( ALL COMMENT "Generate man and html pages" ) -if (BUILD_DOC_MAN) +if (LMDBAL_BUILD_DOC_MAN) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/man TYPE DOC ) endif() -if (BUILD_DOC_HTML) +if (LMDBAL_BUILD_DOC_HTML) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html TYPE DOC ) endif() -if (BUILD_DOC_XML) +if (LMDBAL_BUILD_DOC_XML) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/xml TYPE DOC ) endif() -if (BUILD_DOXYGEN_AWESOME) +if (LMDBAL_BUILD_DOXYGEN_AWESOME) add_dependencies(documentation doxygen-awesome-css) endif() \ No newline at end of file diff --git a/src/base.cpp b/src/base.cpp index cac914b..5100c83 100644 --- a/src/base.cpp +++ b/src/base.cpp @@ -28,13 +28,13 @@ * \brief Database abstraction * * This is a basic class that represents the database as a collection of storages. - * Storages is something key-value database has instead of tables in classic SQL databases. + * Storages are something that key-value databases have instead of tables in classic SQL databases. */ /** * \brief Creates the database * - * \param[in] _name - name of the database, it is going to affect folder name that is created to store data + * \param[in] _name - name of the database, it is going to affect the folder name that is created to store data * \param[in] _mapSize - LMDB map size (MiB), multiplied by 1024^2 and passed to mdb_env_set_mapsize during the call of LMDBAL::Base::open() */ LMDBAL::Base::Base(const QString& _name, uint16_t _mapSize): @@ -60,13 +60,13 @@ LMDBAL::Base::~Base() { * \brief Closes the database * * Closes all lmdb handles, aborts all public transactions. - * This function will do nothing on closed database + * This function will do nothing on a closed database * * \exception LMDBAL::Unknown - thrown if something went wrong aborting transactions */ void LMDBAL::Base::close() { if (opened) { - for (const std::pair pair : transactions) { + for (const std::pair pair : transactions) { abortTransaction(pair.first, emptyName); pair.second->reset(); } @@ -84,8 +84,8 @@ void LMDBAL::Base::close() { * \brief Opens the database * * Almost every LMDBAL::Base require it to be opened, this function does it. - * It laso creates the directory for the database if it was an initial launch. - * This function will do nothing on opened database + * It also creates the directory for the database if it was an initial launch. + * This function will do nothing on an opened database * * \exception LMDBAL::Unknown - thrown if something went wrong opening storages and caches */ @@ -94,15 +94,14 @@ void LMDBAL::Base::open() { mdb_env_create(&environment); QString path = createDirectory(); - mdb_env_set_maxdbs(environment, storages.size()); + mdb_env_set_maxdbs(environment, static_cast(storages.size())); mdb_env_set_mapsize(environment, size * 1024UL * 1024UL); mdb_env_open(environment, path.toStdString().c_str(), 0, 0664); TransactionID txn = beginPrivateTransaction(emptyName); for (const std::pair& pair : storages) { StorageCommon* storage = pair.second; - int rc = storage->open(txn); - if (rc) + if (const int rc = storage->open(txn)) throw Unknown(name, mdb_strerror(rc)); } commitPrivateTransaction(txn, emptyName); @@ -113,9 +112,9 @@ void LMDBAL::Base::open() { /** * \brief Removes database directory * - * \returns true if removal was successfull of if no directory was created where it's expected to be, false otherwise + * \returns true if removal was successful of if no directory was created where it's expected to be, false otherwise * - * \exception LMDBAL::Opened - thrown if this function was called on opened database + * \exception LMDBAL::Opened - thrown if this function was called on an opened database */ bool LMDBAL::Base::removeDirectory() { if (opened) @@ -141,7 +140,7 @@ bool LMDBAL::Base::removeDirectory() { * * \returns the path of the created directory * - * \exception LMDBAL::Opened - thrown if called on opened database + * \exception LMDBAL::Opened - thrown if called on an opened database * \exception LMDBAL::Directory - if the database couldn't create the folder */ QString LMDBAL::Base::createDirectory() { diff --git a/src/base.h b/src/base.h index a4b60a7..4ccf45d 100644 --- a/src/base.h +++ b/src/base.h @@ -48,7 +48,7 @@ template class Cache; typedef MDB_txn* TransactionID; /**<\brief I'm going to use transaction pointers as transaction IDs*/ -typedef uint32_t SizeType; /**<\brief All LMDBAL sizes are uint32_t*/ +typedef uint32_t SizeType; /**<\brief All LMDBAL sizes are uint32*/ class Base { friend class StorageCommon; @@ -135,8 +135,8 @@ LMDBAL::Storage* LMDBAL::Base::addStorage(const std::string& storageName, if (opened) throw Opened(name, "add storage " + storageName); - Storage* storage = new Storage(this, storageName, duplicates); - std::pair pair = storages.insert(std::make_pair(storageName, (StorageCommon *)storage)); + auto storage = new Storage(this, storageName, duplicates); + std::pair pair = storages.emplace(storageName, static_cast(storage)); if (!pair.second) throw StorageDuplicate(name, storageName); @@ -163,8 +163,8 @@ LMDBAL::Cache * LMDBAL::Base::addCache(const std::string& storageName) { if (opened) throw Opened(name, "add cache " + storageName); - Cache* cache = new Cache(this, storageName, false); - std::pair pair = storages.insert(std::make_pair(storageName, (StorageCommon *)cache)); + auto cache = new Cache(this, storageName, false); + std::pair pair = storages.emplace(storageName, static_cast(cache)); if (!pair.second) throw StorageDuplicate(name, storageName); diff --git a/src/serializer/serializer.hpp b/src/serializer/serializer.hpp index b3353f5..03bfaed 100644 --- a/src/serializer/serializer.hpp +++ b/src/serializer/serializer.hpp @@ -114,7 +114,7 @@ T LMDBAL::Serializer::deserialize(const MDB_val& value) { template void LMDBAL::Serializer::deserialize(const MDB_val& value, T& result) { clear(); - bytes.setRawData((char*)value.mv_data, value.mv_size); + bytes.setRawData(static_cast(value.mv_data), value.mv_size); stream >> result; } @@ -154,7 +154,7 @@ MDB_val LMDBAL::Serializer::getData() { MDB_val val; val.mv_size = buffer.pos(); - val.mv_data = (char*)bytes.data(); + val.mv_data = bytes.data(); return val; } diff --git a/src/serializer/serializer_qbytearray.hpp b/src/serializer/serializer_qbytearray.hpp index daf3027..2d3f494 100644 --- a/src/serializer/serializer_qbytearray.hpp +++ b/src/serializer/serializer_qbytearray.hpp @@ -34,7 +34,17 @@ public: return value; }; void deserialize(const MDB_val& data, QByteArray& result) { - result.setRawData((char*)data.mv_data, data.mv_size); +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + if (data.mv_size > static_cast(std::numeric_limits::max())) + throw std::runtime_error("Data size exceeds QByteArray capacity"); + + result.setRawData(static_cast(data.mv_data), static_cast(data.mv_size)); +#else + if (data.mv_size > static_cast(std::numeric_limits::max())) + throw std::runtime_error("Data size exceeds QByteArray capacity"); + + result.setRawData(static_cast(data.mv_data), static_cast(data.mv_size)); +#endif } MDB_val setData(const QByteArray& data) { value = data; @@ -43,7 +53,7 @@ public: MDB_val getData() { MDB_val result; result.mv_data = value.data(); - result.mv_size = value.size(); + result.mv_size = static_cast(value.size()); return result; }; void clear() { diff --git a/src/serializer/serializer_qstring.hpp b/src/serializer/serializer_qstring.hpp index fb9310e..a00aea5 100644 --- a/src/serializer/serializer_qstring.hpp +++ b/src/serializer/serializer_qstring.hpp @@ -31,11 +31,33 @@ public: ~Serializer() {}; QString deserialize(const MDB_val& data) { - value = QByteArray((char*)data.mv_data, data.mv_size); +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + if (data.mv_size > static_cast(std::numeric_limits::max())) + throw std::runtime_error("Data size exceeds QByteArray capacity"); + + value = QByteArray(static_cast(data.mv_data), static_cast(data.mv_size)); +#else + if (data.mv_size > static_cast(std::numeric_limits::max())) + throw std::runtime_error("Data size exceeds QByteArray capacity"); + + value = QByteArray(static_cast(data.mv_data), static_cast(data.mv_size)); +#endif + return QString::fromUtf8(value); }; void deserialize(const MDB_val& data, QString& result) { - value = QByteArray((char*)data.mv_data, data.mv_size); +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + if (data.mv_size > static_cast(std::numeric_limits::max())) + throw std::runtime_error("Data size exceeds QByteArray capacity"); + + value = QByteArray(static_cast(data.mv_data), static_cast(data.mv_size)); +#else + if (data.mv_size > static_cast(std::numeric_limits::max())) + throw std::runtime_error("Data size exceeds QByteArray capacity"); + + value = QByteArray(static_cast(data.mv_data), static_cast(data.mv_size)); +#endif + result = QString::fromUtf8(value); } MDB_val setData(const QString& data) { @@ -45,7 +67,7 @@ public: MDB_val getData() { MDB_val result; result.mv_data = value.data(); - result.mv_size = value.size(); + result.mv_size = static_cast(value.size()); return result; }; void clear() {}; //not possible; @@ -54,4 +76,4 @@ private: QByteArray value; }; -} +} \ No newline at end of file diff --git a/src/serializer/serializer_stdstring.hpp b/src/serializer/serializer_stdstring.hpp index 1856e8c..659cb89 100644 --- a/src/serializer/serializer_stdstring.hpp +++ b/src/serializer/serializer_stdstring.hpp @@ -34,7 +34,7 @@ public: return value; }; void deserialize(const MDB_val& data, std::string& result) { - result.assign((char*)data.mv_data, data.mv_size); + result.assign(static_cast(data.mv_data), data.mv_size); } MDB_val setData(const std::string& data) { value = data; @@ -42,7 +42,7 @@ public: }; MDB_val getData() { MDB_val result; - result.mv_data = (char*)value.c_str(); + result.mv_data = const_cast(value.c_str()); result.mv_size = value.size(); return result; }; diff --git a/src/storagecommon.cpp b/src/storagecommon.cpp index 3d7e92c..7202d23 100644 --- a/src/storagecommon.cpp +++ b/src/storagecommon.cpp @@ -23,13 +23,13 @@ #define UNUSED(x) (void)(x) /** - * \class LMDBAL::iStorage + * \class LMDBAL::StorageCommon * * \brief Storage interface * - * This is a interface-like class, it's designed to be an inner database interface to - * be used as a polymorphic entity, and provide protected interaction with the database - * from the heirs code + * This is an interface-like class, it's designed to be an inner database interface to + * be used as a polymorphic entity and provide protected interaction with the database + * from the heir code */ /** @@ -49,7 +49,7 @@ LMDBAL::StorageCommon::StorageCommon(Base* parent, const std::string& name, bool /** * \brief Destroys a storage interface */ -LMDBAL::StorageCommon::~StorageCommon () {} +LMDBAL::StorageCommon::~StorageCommon () = default; /** * \brief A private virtual function to close each storage in the database @@ -103,7 +103,7 @@ void LMDBAL::StorageCommon::drop() { * * Just performs content drop * - * \param[in] transaction - transaction ID, must be writable transaction! + * \param[in] transaction - transaction ID; must be writable transaction! * \returns MDB_SUCCESS if everything went fine, MDB_ code otherwise */ int LMDBAL::StorageCommon::drop(TransactionID transaction) { @@ -115,7 +115,7 @@ int LMDBAL::StorageCommon::drop(TransactionID transaction) { * * Just performs content drop * - * \param[in] txn - transaction ID, must be writable transaction! + * \param[in] txn - transaction ID; must be writable transaction! * \returns MDB_SUCCESS if everything went fine, MDB_ code otherwise * * \exception LMDBAL::TransactionTerminated thrown if the transaction was not active @@ -126,7 +126,7 @@ int LMDBAL::StorageCommon::drop(const WriteTransaction& txn) { } /** - * \brief Helper function, thows exception if the database is not opened + * \brief Helper function; throws an exception if the database is not opened * * \param[in] methodName - name of the method this function is called from, just for display in std::exception::what() message * @@ -140,7 +140,7 @@ void LMDBAL::StorageCommon::ensureOpened(const std::string& methodName) const { /** * \brief Storage size * - * \returns amount of records in the storage + * \returns number of records in the storage * * \exception LMDBAL::Closed thrown if the database was closed * \exception LMDBAL::Unknown thrown if something unexpected happened @@ -162,7 +162,7 @@ LMDBAL::SizeType LMDBAL::StorageCommon::count() const { } /** - * \brief Retrieves public transaction object for a cursor handle + * \brief Retrieves a public transaction object for a cursor handle * * Cursor must be still opened by a public transaction * @@ -222,25 +222,27 @@ void LMDBAL::StorageCommon::closeCursorTransaction (MDB_cursor* cursor, bool clo /** * \brief Storage size (private transaction variant) * - * \param[in] txn - transaction ID, can be read-only transaction - * \returns amount of records in the storage + * \param[in] txn - transaction ID; can be read-only transaction + * \returns number of records in the storage * * \exception LMDBAL::Unknown thrown if something unexpected happened */ LMDBAL::SizeType LMDBAL::StorageCommon::count(TransactionID txn) const { MDB_stat stat; - int rc = mdb_stat(txn, dbi, &stat); - if (rc != MDB_SUCCESS) + if (const int rc = mdb_stat(txn, dbi, &stat); rc != MDB_SUCCESS) throw Unknown(db->name, mdb_strerror(rc), name); - return stat.ms_entries; + if (stat.ms_entries > std::numeric_limits::max()) + throw Unknown(db->name, "Storage size exceeds it's limits", name); + + return static_cast(stat.ms_entries); } /** * \brief Storage size (public transaction variant) * - * \param[in] txn - transaction, can be read-only transaction - * \returns amount of records in the storage + * \param[in] txn - transaction; can be read-only transaction + * \returns number of records in the storage * * \exception LMDBAL::Closed thrown if the database was closed * \exception LMDBAL::Unknown thrown if something unexpected happened diff --git a/src/storagecommon.h b/src/storagecommon.h index 77a56d2..d54c8d2 100644 --- a/src/storagecommon.h +++ b/src/storagecommon.h @@ -19,7 +19,7 @@ #pragma once #include -#include +#include #include From a6ac974438c075ccb51ab5be1f3e83f8d42a1390 Mon Sep 17 00:00:00 2001 From: blue Date: Fri, 2 May 2025 20:44:23 +0300 Subject: [PATCH 28/34] CI 1 --- .forgejo/workflows/main.yml | 18 ++++++------------ .forgejo/workflows/test.yml | 4 ++-- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/.forgejo/workflows/main.yml b/.forgejo/workflows/main.yml index 44dba97..f99b54c 100644 --- a/.forgejo/workflows/main.yml +++ b/.forgejo/workflows/main.yml @@ -20,11 +20,11 @@ jobs: docs: name: Release documentation - runs-on: archlinux + runs-on: baremetall_peppersurprise needs: [test-qt5, test-qt6] steps: - name: Check out repository code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Make a build directory run: mkdir build @@ -37,13 +37,7 @@ jobs: working-directory: ./build run: cmake --build . - - name: Copy docs via scp - uses: appleboy/scp-action@master - # working-directory: ./build/doc //doesn't work - with: - host: ${{ secrets.DOMAIN_ROOT }} - username: ${{ secrets.DEPLOY_USER_NAME }} - key: ${{ secrets.DEPLOY_PRIVATE_KEY }} - source: "build/doc/html/*,build/doc/xml/*,build/doc/man/*" - target: "/srv/lmdbal/doc" - strip_components: 2 + - name: Deploy docs + run: | + rm -rf /srv/lmdbal/doc/* + cp -r build/doc/html/* /srv/lmdbal/doc/ diff --git a/.forgejo/workflows/test.yml b/.forgejo/workflows/test.yml index a0f3867..a3a8881 100644 --- a/.forgejo/workflows/test.yml +++ b/.forgejo/workflows/test.yml @@ -18,14 +18,14 @@ jobs: runs-on: archlinux steps: - name: Check out repository code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Make a build directory run: mkdir build - name: Configure working-directory: ./build - run: cmake .. -D LMDBAL_STRICT=True -D LMDBAL_BUILD_TESTS=True -D QT_VERSION_MAJOR= ${{ inputs.flags }} + run: cmake .. -D LMDBAL_STRICT=True -D LMDBAL_BUILD_TESTS=True ${{ inputs.flags }} - name: Build working-directory: ./build From 3e275265170b9634fab22b363320c3469b22dc4b Mon Sep 17 00:00:00 2001 From: blue Date: Fri, 2 May 2025 20:47:45 +0300 Subject: [PATCH 29/34] CI 2 --- .forgejo/workflows/main.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.forgejo/workflows/main.yml b/.forgejo/workflows/main.yml index f99b54c..a0aedbf 100644 --- a/.forgejo/workflows/main.yml +++ b/.forgejo/workflows/main.yml @@ -6,22 +6,22 @@ on: - master jobs: - test-qt5: - name: Test LMDBAL with qt5 - uses: ./.forgejo/workflows/test.yml - with: - flags: -D QT_VERSION_MAJOR=5 -D LMDBAL_NAME=LMDBAL-QT5 - - test-qt6: - name: Test LMDBAL with qt6 - uses: ./.forgejo/workflows/test.yml - with: - flags: -D QT_VERSION_MAJOR=6 -D LMDBAL_NAME=LMDBAL-QT6 +# test-qt5: +# name: Test LMDBAL with qt5 +# uses: ./.forgejo/workflows/test.yml +# with: +# flags: -D QT_VERSION_MAJOR=5 -D LMDBAL_NAME=LMDBAL-QT5 +# +# test-qt6: +# name: Test LMDBAL with qt6 +# uses: ./.forgejo/workflows/test.yml +# with: +# flags: -D QT_VERSION_MAJOR=6 -D LMDBAL_NAME=LMDBAL-QT6 docs: name: Release documentation runs-on: baremetall_peppersurprise - needs: [test-qt5, test-qt6] +# needs: [test-qt5, test-qt6] steps: - name: Check out repository code uses: actions/checkout@v4 From ad1a13c323faa22ae147678e359ab5015db39b6e Mon Sep 17 00:00:00 2001 From: blue Date: Fri, 2 May 2025 21:35:09 +0300 Subject: [PATCH 30/34] CI 3 --- .forgejo/workflows/main.yml | 24 +++++++++++++----------- .forgejo/workflows/test.yml | 3 +++ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/.forgejo/workflows/main.yml b/.forgejo/workflows/main.yml index a0aedbf..a69fd84 100644 --- a/.forgejo/workflows/main.yml +++ b/.forgejo/workflows/main.yml @@ -6,17 +6,19 @@ on: - master jobs: -# test-qt5: -# name: Test LMDBAL with qt5 -# uses: ./.forgejo/workflows/test.yml -# with: -# flags: -D QT_VERSION_MAJOR=5 -D LMDBAL_NAME=LMDBAL-QT5 -# -# test-qt6: -# name: Test LMDBAL with qt6 -# uses: ./.forgejo/workflows/test.yml -# with: -# flags: -D QT_VERSION_MAJOR=6 -D LMDBAL_NAME=LMDBAL-QT6 + test-qt5: + name: Test LMDBAL with qt5 + uses: ./.forgejo/workflows/test.yml + runs-on: archlinux + with: + flags: -D QT_VERSION_MAJOR=5 -D LMDBAL_NAME=LMDBAL-QT5 + + test-qt6: + name: Test LMDBAL with qt6 + uses: ./.forgejo/workflows/test.yml + runs-on: archlinux + with: + flags: -D QT_VERSION_MAJOR=6 -D LMDBAL_NAME=LMDBAL-QT6 docs: name: Release documentation diff --git a/.forgejo/workflows/test.yml b/.forgejo/workflows/test.yml index a3a8881..b8b3e07 100644 --- a/.forgejo/workflows/test.yml +++ b/.forgejo/workflows/test.yml @@ -5,6 +5,9 @@ on: flags: required: true type: string + + secrets: + workflow_dispatch: inputs: flags: From da9f935b148c961cd53c71856fcc563b365e981a Mon Sep 17 00:00:00 2001 From: blue Date: Fri, 2 May 2025 21:48:22 +0300 Subject: [PATCH 31/34] CI 4 --- .forgejo/workflows/main.yml | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/.forgejo/workflows/main.yml b/.forgejo/workflows/main.yml index a69fd84..c446a81 100644 --- a/.forgejo/workflows/main.yml +++ b/.forgejo/workflows/main.yml @@ -20,10 +20,10 @@ jobs: with: flags: -D QT_VERSION_MAJOR=6 -D LMDBAL_NAME=LMDBAL-QT6 - docs: - name: Release documentation - runs-on: baremetall_peppersurprise -# needs: [test-qt5, test-qt6] + build-documentation: + name: Builds documentation + runs-on: archlinux + needs: [test-qt5, test-qt6] steps: - name: Check out repository code uses: actions/checkout@v4 @@ -39,6 +39,24 @@ jobs: working-directory: ./build run: cmake --build . + - name: Upload docs + uses: actions/upload-artifact@v3 + with: + name: lmdbal-doc + path: build/doc + retention-days: 1 + + deploy-doc: + name: Deploys documentation + runs-on: archlinux + needs: [build-documentation] + steps: + - name: Download docs + uses: actions/download-artifact@v3 + with: + name: lmdbal-doc + path: build/doc + - name: Deploy docs run: | rm -rf /srv/lmdbal/doc/* From 3701fb92a1498bd737828d8d1df63d4c4d8f02c7 Mon Sep 17 00:00:00 2001 From: blue Date: Fri, 2 May 2025 22:08:08 +0300 Subject: [PATCH 32/34] CI 5 --- .forgejo/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/main.yml b/.forgejo/workflows/main.yml index c446a81..6d1cffb 100644 --- a/.forgejo/workflows/main.yml +++ b/.forgejo/workflows/main.yml @@ -48,7 +48,7 @@ jobs: deploy-doc: name: Deploys documentation - runs-on: archlinux + runs-on: baremetall_peppersurprise needs: [build-documentation] steps: - name: Download docs From f9902bc0b1e99434a711d490a80ef8594b45f085 Mon Sep 17 00:00:00 2001 From: blue Date: Tue, 6 May 2025 00:22:03 +0300 Subject: [PATCH 33/34] Sessions to manage db open state --- CHANGELOG.md | 3 + src/CMakeLists.txt | 2 + src/base.cpp | 193 ++++++++++++++++++++++++------------ src/base.h | 30 ++++-- src/session.cpp | 73 ++++++++++++++ src/session.h | 47 +++++++++ src/storagecommon.cpp | 2 +- test/basic.cpp | 49 ++++----- test/cachecursor.cpp | 7 +- test/cachetransaction.cpp | 23 +++-- test/duplicates.cpp | 7 +- test/storagecursor.cpp | 7 +- test/storagetransaction.cpp | 23 +++-- 13 files changed, 342 insertions(+), 124 deletions(-) create mode 100644 src/session.cpp create mode 100644 src/session.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 356decc..7987afe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ - Less dereferencing - Transactions are now closed with the database - Cursors are now closed if the public transaction that opened them got closed +- New primitive to manage database state - session +- Stricter warnings +- Sanitizer builds ### Bug fixes - SIGSEGV on closing database with opened transactions diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9c53f6a..9f9469e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,6 +4,7 @@ set(SOURCES base.cpp transaction.cpp cursorcommon.cpp + session.cpp ) set(HEADERS @@ -20,6 +21,7 @@ set(HEADERS cache.hpp operators.hpp transaction.h + session.h ) target_sources(${LMDBAL_NAME} PRIVATE ${SOURCES}) diff --git a/src/base.cpp b/src/base.cpp index 5100c83..ec4524c 100644 --- a/src/base.cpp +++ b/src/base.cpp @@ -18,8 +18,10 @@ #include "base.h" #include "exceptions.h" +#include "session.h" #include "storage.h" #include "transaction.h" +#include "session.h" #define UNUSED(x) (void)(x) @@ -39,75 +41,34 @@ */ LMDBAL::Base::Base(const QString& _name, uint16_t _mapSize): name(_name.toStdString()), - opened(false), + sessions(), size(_mapSize), environment(), storages(), - transactions() + transactions(), + mutex() {} /** * \brief Destroys the database */ LMDBAL::Base::~Base() { - close(); + std::lock_guard lock(mutex); + + for (Session* session : sessions) + session->terminate(); + + if (opened()) + deactivate(); for (const std::pair& pair : storages) delete pair.second; } -/** - * \brief Closes the database - * - * Closes all lmdb handles, aborts all public transactions. - * This function will do nothing on a closed database - * - * \exception LMDBAL::Unknown - thrown if something went wrong aborting transactions - */ -void LMDBAL::Base::close() { - if (opened) { - for (const std::pair pair : transactions) { - abortTransaction(pair.first, emptyName); - pair.second->reset(); - } - - for (const std::pair& pair : storages) - pair.second->close(); - - mdb_env_close(environment); - transactions.clear(); - opened = false; - } +LMDBAL::Session LMDBAL::Base::open() { + return {this}; } -/** - * \brief Opens the database - * - * Almost every LMDBAL::Base require it to be opened, this function does it. - * It also creates the directory for the database if it was an initial launch. - * This function will do nothing on an opened database - * - * \exception LMDBAL::Unknown - thrown if something went wrong opening storages and caches - */ -void LMDBAL::Base::open() { - if (!opened) { - mdb_env_create(&environment); - QString path = createDirectory(); - - mdb_env_set_maxdbs(environment, static_cast(storages.size())); - mdb_env_set_mapsize(environment, size * 1024UL * 1024UL); - mdb_env_open(environment, path.toStdString().c_str(), 0, 0664); - - TransactionID txn = beginPrivateTransaction(emptyName); - for (const std::pair& pair : storages) { - StorageCommon* storage = pair.second; - if (const int rc = storage->open(txn)) - throw Unknown(name, mdb_strerror(rc)); - } - commitPrivateTransaction(txn, emptyName); - opened = true; - } -} /** * \brief Removes database directory @@ -117,7 +78,7 @@ void LMDBAL::Base::open() { * \exception LMDBAL::Opened - thrown if this function was called on an opened database */ bool LMDBAL::Base::removeDirectory() { - if (opened) + if (opened()) throw Opened(name, "remove database directory"); QString path = getPath(); @@ -144,7 +105,7 @@ bool LMDBAL::Base::removeDirectory() { * \exception LMDBAL::Directory - if the database couldn't create the folder */ QString LMDBAL::Base::createDirectory() { - if (opened) + if (opened()) throw Opened(name, "create database directory"); QString path = getPath(); @@ -183,8 +144,9 @@ QString LMDBAL::Base::getPath() const { * * \returns true if the database is opened and ready for work, false otherwise */ -bool LMDBAL::Base::ready() const { - return opened;} +bool LMDBAL::Base::opened() const { + return !sessions.empty(); +} /** * \brief Drops the database @@ -195,7 +157,7 @@ bool LMDBAL::Base::ready() const { * \exception LMDBAL::Unknown - thrown if something unexpected happend */ void LMDBAL::Base::drop() { - if (!opened) + if (!opened()) throw Closed("drop", name); TransactionID txn = beginPrivateTransaction(emptyName); @@ -301,7 +263,7 @@ void LMDBAL::Base::commitTransaction(LMDBAL::TransactionID id) { * \exception LMDBAL::Unknown - thrown if something unexpected happened */ LMDBAL::TransactionID LMDBAL::Base::beginReadOnlyTransaction(const std::string& storageName) const { - if (!opened) + if (!opened()) throw Closed("beginReadOnlyTransaction", name, storageName); TransactionID txn = beginPrivateReadOnlyTransaction(storageName); @@ -326,7 +288,7 @@ LMDBAL::TransactionID LMDBAL::Base::beginReadOnlyTransaction(const std::string& * \exception LMDBAL::Unknown - thrown if something unexpected happened */ LMDBAL::TransactionID LMDBAL::Base::beginTransaction(const std::string& storageName) const { - if (!opened) + if (!opened()) throw Closed("beginTransaction", name, storageName); TransactionID txn = beginPrivateTransaction(storageName); @@ -351,7 +313,7 @@ LMDBAL::TransactionID LMDBAL::Base::beginTransaction(const std::string& storageN * \exception LMDBAL::Unknown - thrown if something unexpected happened */ void LMDBAL::Base::abortTransaction(LMDBAL::TransactionID id, const std::string& storageName) const { - if (!opened) + if (!opened()) throw Closed("abortTransaction", name, storageName); abortPrivateTransaction(id, storageName); @@ -374,7 +336,7 @@ void LMDBAL::Base::abortTransaction(LMDBAL::TransactionID id, const std::string& * \exception LMDBAL::Unknown - thrown if something unexpected happened */ void LMDBAL::Base::commitTransaction(LMDBAL::TransactionID id, const std::string& storageName) { - if (!opened) + if (!opened()) throw Closed("abortTransaction", name, storageName); commitPrivateTransaction(id, storageName); @@ -407,7 +369,7 @@ LMDBAL::TransactionID LMDBAL::Base::beginPrivateReadOnlyTransaction(const std::s * \brief Begins writable transaction * * This function is intended to be called from subordinate storage or cache, - * it's not accounted in transaction collection, other storages and caches are not notified about this kind of transaction + * it's not accounted in the transaction collection, other storages and caches are not notified about this kind of transaction * * \param[in] storageName - name of the storage/cache that you begin transaction from, needed just to inform if something went wrong * @@ -428,10 +390,10 @@ LMDBAL::TransactionID LMDBAL::Base::beginPrivateTransaction(const std::string& s /** * \brief Aborts transaction * - * Terminates transaction cancelling changes. + * Terminates transaction, cancelling changes. * This is an optimal way to terminate read-only transactions. * This function is intended to be called from subordinate storage or cache, - * it's not accounted in transaction collection, other storages and caches are not notified about this kind of transaction + * it's not accounted in the transaction collection, other storages and caches are not notified about this kind of transaction * * \param[in] id - transaction ID you want to abort * \param[in] storageName - name of the storage/cache that you begin transaction from, unused here @@ -458,3 +420,104 @@ void LMDBAL::Base::commitPrivateTransaction(LMDBAL::TransactionID id, const std: if (rc != MDB_SUCCESS) throw Unknown(name, mdb_strerror(rc), storageName); } + +/** + * \brief Registers session + * + * Registers the session in the session collection. + * If it was the first accounted session, it activates the database + * + * \exception LMDBAL::Unknown - thrown if this session was already registered + */ +void LMDBAL::Base::registerSession(Session* session) { + std::lock_guard lock(mutex); + + if (sessions.empty()) + activate(); + + if (!sessions.insert(session).second) + throw Unknown(name, "session already registered"); +} + +/** + * \brief Unregisters session + * + * Unregisters the session from the session collection. + * If it was the last accounted session, it deactivates the database + * + * \exception LMDBAL::Unknown - thrown if this session was not registered + */ +void LMDBAL::Base::unregisterSession(Session* session) { + std::lock_guard lock(mutex); + + if (sessions.size() == 1) + deactivate(); + + if (sessions.erase(session) != 1) + throw Unknown(name, "session was not registered"); +} + +/** + * \brief Swaps sessions + * + * Replaces one session by another in the session collection. + * + * \exception LMDBAL::Unknown - thrown if there is some unexpected state with sessions, it means the database is in the wrong state + */ +void LMDBAL::Base::replaceSession(Session* closing, Session* opening) { + std::lock_guard lock(mutex); + + if (sessions.erase(closing) != 1) + throw Unknown(name, "session was not registered"); + + if (!sessions.insert(opening).second) + throw Unknown(name, "session already registered"); +} + +/** + * \brief Deactivates the database, + * + * Closes all lmdb handles, aborts all public transactions. + * This function will emit SIGSEGV on a deactivated database + * + * \exception LMDBAL::Unknown - thrown if something went wrong aborting transactions + */ +void LMDBAL::Base::deactivate() { + for (const std::pair pair : transactions) { + abortTransaction(pair.first, emptyName); + pair.second->reset(); + } + + for (const std::pair& pair : storages) + pair.second->close(); + + mdb_env_close(environment); + transactions.clear(); +} + +/** + * \brief Activates the database + * + * Almost every LMDBAL::Base require it to be opened, this function does it. + * It also creates the directory for the database if it was an initial launch. + * This function will behave unpredictably on an activated database, possible data corruption. + * + * \exception LMDBAL::Unknown - thrown if something went wrong opening storages and caches + */ +void LMDBAL::Base::activate() { + mdb_env_create(&environment); + QString path = createDirectory(); + + mdb_env_set_maxdbs(environment, static_cast(storages.size())); + mdb_env_set_mapsize(environment, size * 1024UL * 1024UL); + mdb_env_open(environment, path.toStdString().c_str(), 0, 0664); + + TransactionID txn = beginPrivateTransaction(emptyName); + for (const std::pair& pair : storages) { + StorageCommon* storage = pair.second; + if (const int rc = storage->open(txn)) + throw Unknown(name, mdb_strerror(rc)); + } + + commitPrivateTransaction(txn, emptyName); +} \ No newline at end of file diff --git a/src/base.h b/src/base.h index 4ccf45d..230cf14 100644 --- a/src/base.h +++ b/src/base.h @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #include @@ -37,6 +39,7 @@ namespace LMDBAL { class StorageCommon; class Transaction; class WriteTransaction; +class Session; template class Serializer; @@ -54,14 +57,14 @@ class Base { friend class StorageCommon; friend class Transaction; friend class WriteTransaction; -public: + friend class Session; +public: Base(const QString& name, uint16_t mapSize = 10); ~Base(); - void open(); - void close(); - bool ready() const; + Session open(); + bool opened() const; bool removeDirectory(); QString createDirectory(); QString getName() const; @@ -84,8 +87,9 @@ public: LMDBAL::Cache* getCache(const std::string& storageName); private: - typedef std::map Storages; /**<\brief Storage and Cache pointers are saved in the std::map*/ - typedef std::map Transactions; /**<\brief Piblic transaction IDs are saved in the std::set*/ + typedef std::map Storages; /**<\brief Storage and Cache pointers are saved in the std::map*/ + typedef std::map Transactions; /**<\brief Public transaction IDs are saved in the std::map*/ + typedef std::set Sessions; /**<\brief Sessions are saved in the std::set*/ void commitTransaction(TransactionID id); void abortTransaction(TransactionID id) const; @@ -99,13 +103,21 @@ private: void commitPrivateTransaction(TransactionID id, const std::string& storageName); void abortPrivateTransaction(TransactionID id, const std::string& storageName) const; + void registerSession(Session* session); + void unregisterSession(Session* session); + void replaceSession(Session* closing, Session* opening); + + void activate(); + void deactivate(); + private: std::string name; /**<\brief Name of this database*/ - bool opened; /**<\brief State of this database*/ + Sessions sessions; /**<\brief Opened session pointers*/ uint16_t size; /**<\brief lmdb map size in MiB*/ MDB_env* environment; /**<\brief lmdb environment handle*/ Storages storages; /**<\brief Registered storages and caches*/ mutable Transactions transactions; /**<\brief Active public transactions*/ + std::mutex mutex; /**<\brief Mutex for thread safety*/ inline static const std::string emptyName = ""; /**<\brief Empty string for general fallback purposes*/ }; @@ -132,7 +144,7 @@ private: */ template LMDBAL::Storage* LMDBAL::Base::addStorage(const std::string& storageName, bool duplicates) { - if (opened) + if (opened()) throw Opened(name, "add storage " + storageName); auto storage = new Storage(this, storageName, duplicates); @@ -160,7 +172,7 @@ LMDBAL::Storage* LMDBAL::Base::addStorage(const std::string& storageName, */ template LMDBAL::Cache * LMDBAL::Base::addCache(const std::string& storageName) { - if (opened) + if (opened()) throw Opened(name, "add cache " + storageName); auto cache = new Cache(this, storageName, false); diff --git a/src/session.cpp b/src/session.cpp new file mode 100644 index 0000000..a02a745 --- /dev/null +++ b/src/session.cpp @@ -0,0 +1,73 @@ +/* +* LMDB Abstraction Layer. + * Copyright (C) 2023 Yury Gubich + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "session.h" + +LMDBAL::Session::Session(): + parent(nullptr) {} + +LMDBAL::Session::Session(Base* parent): + parent(parent) +{ + parent->registerSession(this); +} + +LMDBAL::Session::Session(Session&& other): + parent(other.parent) +{ + if (parent) + parent->replaceSession(&other, this); +} + +LMDBAL::Session::~Session() { + if (parent) + parent->unregisterSession(this); +} + +LMDBAL::Session& LMDBAL::Session::operator = (Session&& other) { + if (parent) + if (other.parent) + parent->unregisterSession(&other); + else + parent->unregisterSession(this); + else + if (other.parent) + other.parent->replaceSession(&other, this); + + parent = other.parent; + other.terminate(); + + return *this; +} + +void LMDBAL::Session::close() { + if (!parent) + return; + + parent->unregisterSession(this); + terminate(); +} + +bool LMDBAL::Session::opened() const { + return parent != nullptr; +} + +void LMDBAL::Session::terminate() { + parent = nullptr; +} + diff --git a/src/session.h b/src/session.h new file mode 100644 index 0000000..c0f8da8 --- /dev/null +++ b/src/session.h @@ -0,0 +1,47 @@ +/* +* LMDB Abstraction Layer. + * Copyright (C) 2023 Yury Gubich + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "base.h" + +namespace LMDBAL { + +class Session { + friend class Base; +public: + explicit Session(); + ~Session(); + Session(const Session&) = delete; + Session(Session&&); + + Session& operator = (const Session&) = delete; + Session& operator = (Session&&); + + void close(); + bool opened() const; + +private: + Base* parent; + +private: + Session(Base* parent); + void terminate(); +}; + +} diff --git a/src/storagecommon.cpp b/src/storagecommon.cpp index 7202d23..4feaaa7 100644 --- a/src/storagecommon.cpp +++ b/src/storagecommon.cpp @@ -356,7 +356,7 @@ const std::string & LMDBAL::StorageCommon::dbName() const { * \returns true if database is ipened, false otherwise */ bool LMDBAL::StorageCommon::isDBOpened() const { - return db->opened;} + return db->opened();} /** * \brief Throws LMDBAL::Unknown diff --git a/test/basic.cpp b/test/basic.cpp index fb6b0c5..36880b5 100644 --- a/test/basic.cpp +++ b/test/basic.cpp @@ -3,6 +3,7 @@ #include "base.h" #include "storage.h" #include "cache.h" +#include "session.h" #include #include @@ -34,13 +35,14 @@ protected: } static void TearDownTestSuite() { - db->close(); + session.close(); db->removeDirectory(); delete db; db = nullptr; } static LMDBAL::Base* db; + static LMDBAL::Session session; LMDBAL::Storage* t1; LMDBAL::Storage* t2; @@ -50,19 +52,20 @@ protected: LMDBAL::Base* BaseTest::db = nullptr; +LMDBAL::Session BaseTest::session; TEST_F(BaseTest, RemovingDirectory) { EXPECT_EQ(db->removeDirectory(), true); } TEST_F(BaseTest, OpeningClosingDatabase) { - EXPECT_EQ(db->ready(), false); - db->open(); - EXPECT_EQ(db->ready(), true); - db->close(); - EXPECT_EQ(db->ready(), false); - db->open(); - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), false); + session = db->open(); + EXPECT_EQ(db->opened(), true); + session.close(); + EXPECT_EQ(db->opened(), false); + session = db->open(); + EXPECT_EQ(db->opened(), true); } TEST_F(BaseTest, Flags) { @@ -93,7 +96,7 @@ TEST_F(BaseTest, Flags) { } TEST_F(BaseTest, AddingIntegerKey) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); t1->addRecord(1, 2); t1->addRecord(2, 2); t1->addRecord(3, 15); @@ -101,7 +104,7 @@ TEST_F(BaseTest, AddingIntegerKey) { } TEST_F(BaseTest, AddingQStringKey) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); t2->addRecord("hello", "world"); t2->addRecord("aaa", "gagdfsdf"); t2->addRecord("sdfhga", "DSFFDG"); @@ -110,7 +113,7 @@ TEST_F(BaseTest, AddingQStringKey) { } TEST_F(BaseTest, AddingKeysToCache) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); c1->addRecord(2, "blah balah"); c1->addRecord(-4, "testing goes brrr"); c1->addRecord(40, "whatever"); @@ -119,7 +122,7 @@ TEST_F(BaseTest, AddingKeysToCache) { } TEST_F(BaseTest, AddingKeysToVariableCache) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); c2->addRecord("regrets", "blah balah"); c2->addRecord("fossil fingers", 842); c2->addRecord("preloaded cut", 539.75); @@ -132,7 +135,7 @@ TEST_F(BaseTest, AddingKeysToVariableCache) { } TEST_F(BaseTest, AddingRepeatingKey) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); EXPECT_THROW(t1->addRecord(3, 24), LMDBAL::Exist); EXPECT_EQ(t1->getRecord(3), 15); @@ -148,7 +151,7 @@ TEST_F(BaseTest, AddingRepeatingKey) { } TEST_F(BaseTest, GettingNotExistingKeys) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); EXPECT_THROW(t2->getRecord("almonds"), LMDBAL::NotFound); EXPECT_THROW(t1->getRecord(64), LMDBAL::NotFound); @@ -157,21 +160,21 @@ TEST_F(BaseTest, GettingNotExistingKeys) { } TEST_F(BaseTest, Persistence) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); uint32_t t1Size = t1->count(); uint32_t t2Size = t2->count(); uint32_t c1Size = c1->count(); uint32_t c2Size = c2->count(); - db->close(); delete db; + EXPECT_EQ(session.opened(), false); db = new LMDBAL::Base("testBase"); t1 = db->addStorage("table1"); t2 = db->addStorage("table2"); c1 = db->addCache("cache1"); c2 = db->addCache("cache2"); - db->open(); + session = db->open(); EXPECT_EQ(t1->count(), t1Size); EXPECT_EQ(t1->getRecord(3), 15); @@ -212,7 +215,7 @@ TEST_F(BaseTest, Persistence) { } TEST_F(BaseTest, CountAndDrop) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); EXPECT_EQ(t1->count(), 3); EXPECT_EQ(t2->count(), 4); EXPECT_EQ(c1->count(), 4); @@ -237,7 +240,7 @@ TEST_F(BaseTest, CountAndDrop) { } TEST_F(BaseTest, Change) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); EXPECT_EQ(t1->count(), 1); EXPECT_EQ(t2->count(), 1); EXPECT_EQ(c1->count(), 2); @@ -283,7 +286,7 @@ TEST_F(BaseTest, Change) { } TEST_F(BaseTest, Force) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); EXPECT_EQ(t1->forceRecord(58, 35), false); //changing EXPECT_EQ(t1->forceRecord(68, 36), true); //adding @@ -318,7 +321,7 @@ TEST_F(BaseTest, Force) { } TEST_F(BaseTest, ReadAll) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); std::map m1 = t1->readAll(); std::map m2 = t2->readAll(); @@ -349,7 +352,7 @@ TEST_F(BaseTest, ReadAll) { } TEST_F(BaseTest, ReplaceAll) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); t1->replaceAll({ {7, 48}, @@ -417,7 +420,7 @@ TEST_F(BaseTest, ReplaceAll) { } TEST_F(BaseTest, AddRecords) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); LMDBAL::SizeType s1 = t1->addRecords({ {5, 3}, diff --git a/test/cachecursor.cpp b/test/cachecursor.cpp index b965c69..64b4f42 100644 --- a/test/cachecursor.cpp +++ b/test/cachecursor.cpp @@ -4,6 +4,7 @@ #include "storage.h" #include "cache.h" #include "cursor.h" +#include "session.h" class CacheCursorTest : public ::testing::Test { protected: @@ -19,7 +20,7 @@ protected: db = new LMDBAL::Base("testBase"); db->addCache("table1"); db->addCache("empty"); - db->open(); + session = db->open(); } } @@ -30,7 +31,7 @@ protected: static void TearDownTestSuite() { cursor.drop(); transaction.terminate(); - db->close(); + session.close(); db->removeDirectory(); delete db; db = nullptr; @@ -39,6 +40,7 @@ protected: static LMDBAL::Base* db; static LMDBAL::Cursor cursor; static LMDBAL::Transaction transaction; + static LMDBAL::Session session; LMDBAL::Cache* cache; LMDBAL::Cache* emptyCache; @@ -47,6 +49,7 @@ protected: LMDBAL::Base* CacheCursorTest::db = nullptr; LMDBAL::Cursor CacheCursorTest::cursor; LMDBAL::Transaction CacheCursorTest::transaction; +LMDBAL::Session CacheCursorTest::session; static const std::map data({ {245665783, "bothering nerds"}, diff --git a/test/cachetransaction.cpp b/test/cachetransaction.cpp index a2c0e42..5222852 100644 --- a/test/cachetransaction.cpp +++ b/test/cachetransaction.cpp @@ -4,6 +4,7 @@ #include "base.h" #include "cache.h" +#include "session.h" class CacheTransactionsTest : public testing::Test { protected: @@ -39,18 +40,19 @@ protected: db->addStorage("cache2"); } - db->open(); + session = db->open(); db->drop(); } static void TearDownTestSuite() { - db->close(); + session.close(); db->removeDirectory(); delete db; db = nullptr; } static LMDBAL::Base* db; + static LMDBAL::Session session; LMDBAL::Cache* c1; LMDBAL::Cache* c2; @@ -58,9 +60,10 @@ protected: LMDBAL::Base* CacheTransactionsTest::db = nullptr; +LMDBAL::Session CacheTransactionsTest::session; TEST_F(CacheTransactionsTest, Adding) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); EXPECT_EQ(c1->count(), 0); EXPECT_EQ(c2->count(), 0); @@ -90,7 +93,7 @@ TEST_F(CacheTransactionsTest, Adding) { } TEST_F(CacheTransactionsTest, Aborting) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); LMDBAL::SizeType s1 = c1->count(); LMDBAL::SizeType s2 = c2->count(); @@ -114,7 +117,7 @@ TEST_F(CacheTransactionsTest, Aborting) { } TEST_F(CacheTransactionsTest, Reading) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); LMDBAL::Transaction txn = db->beginReadOnlyTransaction(); @@ -132,7 +135,7 @@ TEST_F(CacheTransactionsTest, Reading) { } TEST_F(CacheTransactionsTest, ConcurentReading) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); LMDBAL::SizeType size = c1->count(); LMDBAL::WriteTransaction txn = db->beginTransaction(); @@ -168,7 +171,7 @@ TEST_F(CacheTransactionsTest, ConcurentReading) { TEST_F(CacheTransactionsTest, ConcurentModification) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); //if you start one writable transaction after another //in a single thread like so: @@ -231,7 +234,7 @@ TEST_F(CacheTransactionsTest, ConcurentModification) { } TEST_F(CacheTransactionsTest, RAIIResourceFree) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); int pid = fork(); if (pid == 0) { // I am the child @@ -287,8 +290,8 @@ TEST_F(CacheTransactionsTest, TransactionTerminationOnClose) { EXPECT_EQ(c1->getRecord(578, txn), 4552); EXPECT_EQ(c1->checkRecord(578), false); - db->close(); - db->open(); + session.close(); + session = db->open(); EXPECT_EQ(txn.isActive(), false); EXPECT_THROW(c1->getRecord(578, txn), LMDBAL::TransactionTerminated); diff --git a/test/duplicates.cpp b/test/duplicates.cpp index 0bc6b56..4bb77db 100644 --- a/test/duplicates.cpp +++ b/test/duplicates.cpp @@ -7,6 +7,7 @@ #include "base.h" #include "storage.h" #include "cursor.h" +#include "session.h" class DuplicatesTest : public ::testing::Test { protected: @@ -35,18 +36,19 @@ protected: db->addStorage("intDouble", true); db->addStorage("floatLong", true); - db->open(); + session = db->open(); } } static void TearDownTestSuite() { - db->close(); + session.close(); db->removeDirectory(); delete db; db = nullptr; } static LMDBAL::Base* db; + static LMDBAL::Session session; LMDBAL::Storage* tu1; LMDBAL::Storage* tu2; @@ -56,6 +58,7 @@ protected: }; LMDBAL::Base* DuplicatesTest::db = nullptr; +LMDBAL::Session DuplicatesTest::session; TEST_F(DuplicatesTest, Flags) { uint32_t tu1Flags = getTU1Flags(); diff --git a/test/storagecursor.cpp b/test/storagecursor.cpp index 92279b1..d44e657 100644 --- a/test/storagecursor.cpp +++ b/test/storagecursor.cpp @@ -3,6 +3,7 @@ #include "base.h" #include "storage.h" #include "cursor.h" +#include "session.h" class StorageCursorTest : public ::testing::Test { protected: @@ -18,7 +19,7 @@ protected: db = new LMDBAL::Base("testBase"); db->addStorage("table1"); db->addStorage("empty"); - db->open(); + session = db->open(); } } @@ -29,7 +30,7 @@ protected: static void TearDownTestSuite() { cursor.drop(); transaction.terminate(); - db->close(); + session.close(); db->removeDirectory(); delete db; db = nullptr; @@ -38,6 +39,7 @@ protected: static LMDBAL::Base* db; static LMDBAL::Cursor cursor; static LMDBAL::Transaction transaction; + static LMDBAL::Session session; LMDBAL::Storage* table; LMDBAL::Storage* emptyTable; @@ -46,6 +48,7 @@ protected: LMDBAL::Base* StorageCursorTest::db = nullptr; LMDBAL::Cursor StorageCursorTest::cursor; LMDBAL::Transaction StorageCursorTest::transaction = LMDBAL::Transaction(); +LMDBAL::Session StorageCursorTest::session = LMDBAL::Session(); static const std::map data({ {245665783, "bothering nerds"}, diff --git a/test/storagetransaction.cpp b/test/storagetransaction.cpp index d4b9089..be0fc1d 100644 --- a/test/storagetransaction.cpp +++ b/test/storagetransaction.cpp @@ -4,6 +4,7 @@ #include "base.h" #include "storage.h" +#include "session.h" class StorageTransactionsTest : public testing::Test { protected: @@ -39,18 +40,19 @@ protected: db->addStorage("table2"); } - db->open(); + session = db->open(); db->drop(); } static void TearDownTestSuite() { - db->close(); + session.close(); db->removeDirectory(); delete db; db = nullptr; } static LMDBAL::Base* db; + static LMDBAL::Session session; LMDBAL::Storage* t1; LMDBAL::Storage* t2; @@ -58,9 +60,10 @@ protected: LMDBAL::Base* StorageTransactionsTest::db = nullptr; +LMDBAL::Session StorageTransactionsTest::session; TEST_F(StorageTransactionsTest, Adding) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); EXPECT_EQ(t1->count(), 0); EXPECT_EQ(t2->count(), 0); @@ -90,7 +93,7 @@ TEST_F(StorageTransactionsTest, Adding) { } TEST_F(StorageTransactionsTest, Aborting) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); LMDBAL::SizeType s1 = t1->count(); LMDBAL::SizeType s2 = t2->count(); @@ -114,7 +117,7 @@ TEST_F(StorageTransactionsTest, Aborting) { } TEST_F(StorageTransactionsTest, Reading) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); LMDBAL::Transaction txn = db->beginReadOnlyTransaction(); @@ -132,7 +135,7 @@ TEST_F(StorageTransactionsTest, Reading) { } TEST_F(StorageTransactionsTest, ConcurentReading) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); LMDBAL::SizeType size = t1->count(); LMDBAL::WriteTransaction txn = db->beginTransaction(); @@ -167,7 +170,7 @@ TEST_F(StorageTransactionsTest, ConcurentReading) { } TEST_F(StorageTransactionsTest, ConcurentModification) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); //if you start one writable transaction after another //in a single thread like so: @@ -230,7 +233,7 @@ TEST_F(StorageTransactionsTest, ConcurentModification) { } TEST_F(StorageTransactionsTest, RAIIResourceFree) { - EXPECT_EQ(db->ready(), true); + EXPECT_EQ(db->opened(), true); int pid = fork(); if (pid == 0) { // I am the child @@ -286,8 +289,8 @@ TEST_F(StorageTransactionsTest, TransactionTerminationOnClose) { EXPECT_EQ(t1->getRecord(543, txn), 229); EXPECT_EQ(t1->checkRecord(543), false); - db->close(); - db->open(); + session.close(); + session = db->open(); EXPECT_EQ(txn.isActive(), false); EXPECT_THROW(t1->getRecord(543, txn), LMDBAL::TransactionTerminated); From 22902a64896339632543d09125ed54b50a61384b Mon Sep 17 00:00:00 2001 From: blue Date: Mon, 2 Jun 2025 20:34:32 +0300 Subject: [PATCH 34/34] Deploy to a different place --- .forgejo/workflows/main.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.forgejo/workflows/main.yml b/.forgejo/workflows/main.yml index 6d1cffb..f3f2fcf 100644 --- a/.forgejo/workflows/main.yml +++ b/.forgejo/workflows/main.yml @@ -48,7 +48,7 @@ jobs: deploy-doc: name: Deploys documentation - runs-on: baremetall_peppersurprise + runs-on: bm_site needs: [build-documentation] steps: - name: Download docs @@ -57,7 +57,10 @@ jobs: name: lmdbal-doc path: build/doc + - name: Make sure deploy folder exists + run: mkdir -p /srv/http/doc/lmdbal + - name: Deploy docs run: | - rm -rf /srv/lmdbal/doc/* - cp -r build/doc/html/* /srv/lmdbal/doc/ + rm -rf /srv/http/doc/lmdbal/* + cp -r build/doc/html/* /srv/http/doc/lmdbal/