├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature.md │ └── question.md └── workflows │ ├── gha.yml │ └── maven.yml ├── .gitignore ├── CONTRIBUTING.md ├── ChangeLog ├── DEBUGGING.md ├── LICENSE ├── NOTICES.md ├── README.md ├── RELEASE_STEPS.md ├── examples ├── ByteBufferExample │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── ByteBufferExample.java ├── IteratorExample │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── IteratorExample.java ├── MixedTypesExample │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── MixedTypesExample.java ├── PicturesExample │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── PicturesExample.java ├── README.md ├── StringExample │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── StringExample.java └── pom.xml ├── jni-binding ├── common.cpp ├── common.h ├── io_pmem_pmemkv_Database.cpp ├── io_pmem_pmemkv_Database_Builder.cpp ├── io_pmem_pmemkv_Database_ReadIterator.cpp ├── libpmemkv_jni.map └── pom.xml ├── pmemkv-binding ├── pom.xml └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── pmem │ │ │ └── pmemkv │ │ │ ├── BuilderException.java │ │ │ ├── ByteBufferConverter.java │ │ │ ├── Converter.java │ │ │ ├── Database.java │ │ │ ├── DatabaseException.java │ │ │ ├── InvalidArgumentException.java │ │ │ ├── KeyCallback.java │ │ │ ├── KeyValueCallback.java │ │ │ ├── NotFoundException.java │ │ │ ├── NotSupportedException.java │ │ │ ├── OutOfMemoryException.java │ │ │ ├── StoppedByCallbackException.java │ │ │ ├── TransactionScopeException.java │ │ │ ├── ValueCallback.java │ │ │ └── WrongEngineNameException.java │ └── resources │ │ └── version.properties │ └── test │ └── java │ └── io │ └── pmem │ └── pmemkv │ ├── CmapTest.java │ ├── DatabaseIteratorTest.java │ ├── DatabaseTest.java │ ├── ExceptionTest.java │ └── TestUtils.java ├── pom.xml └── utils ├── docker ├── build.sh ├── images │ ├── Dockerfile.fedora-33 │ ├── Dockerfile.fedora-34 │ ├── Dockerfile.ubuntu-20.04 │ ├── Dockerfile.ubuntu-21.04_clean │ ├── README.md │ ├── build-image.sh │ ├── install-dependencies.sh │ ├── install-libpmemobj-cpp.sh │ ├── install-pmdk.sh │ ├── prepare-pmemkv.sh │ ├── push-image.sh │ └── setup-maven-settings.sh ├── prepare-for-build.sh ├── pull-or-rebuild-image.sh ├── run-build.sh ├── run-doc-update.sh ├── run-maven-example.sh └── set-ci-vars.sh └── eclipse-formatter-config.xml /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | *.jpg binary 3 | *.png binary 4 | *.gif binary 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Did you find a bug in pmemkv's java binding? Please let us know. 4 | labels: "Type: Bug" 5 | --- 6 | 13 | 14 | # ISSUE: 15 | 16 | ## Environment Information 17 | 18 | - pmemkv-java version(s): 19 | - pmemkv version(s): 20 | - libpmemobj-cpp version(s): 21 | - PMDK (libpmem/libpmemobj) package version(s): 22 | - OS(es) version(s): 23 | - java/JDK versions: 24 | - kernel version(s): 25 | - compiler, libraries, packaging and other related tools version(s): 26 | 27 | 28 | 29 | ## Please provide a reproduction of the bug: 30 | 31 | 32 | 33 | ## How often bug is revealed: 34 | 35 | (always, often, rare) 36 | 37 | 38 | ## Actual behavior: 39 | 40 | 41 | 42 | ## Expected behavior: 43 | 44 | 45 | 46 | ## Details 47 | 48 | 49 | 50 | ## Additional information about Priority and Help Requested: 51 | 52 | Are you willing to submit a pull request with a proposed change? (Yes, No) 53 | 54 | Requested priority: (Showstopper, High, Medium, Low) 55 | 56 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature 3 | about: Feature your request 4 | labels: "Type: Feature" 5 | --- 6 | # FEAT: 7 | 8 | ## Rationale 9 | 10 | 11 | 12 | ## Description 13 | 14 | 15 | 16 | ## API Changes 17 | 18 | 19 | 20 | ## Implementation details 21 | 22 | 23 | 24 | ## Meta 25 | 26 | 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: Do you have question regarding pmemkv's java binding? Don't hesitate to ask. 4 | labels: "Type: Question" 5 | --- 6 | # QUESTION: 7 | 8 | ## Details 9 | 10 | 11 | 12 | 16 | -------------------------------------------------------------------------------- /.github/workflows/gha.yml: -------------------------------------------------------------------------------- 1 | 2 | name: pmemkv-java 3 | on: 4 | push: 5 | pull_request: 6 | release: 7 | types: 8 | - created 9 | 10 | env: 11 | REPO: pmemkv-java 12 | GITHUB_REPO: pmem/pmemkv-java 13 | CONTAINER_REG: ghcr.io/pmem/pmemkv-java 14 | HOST_WORKDIR: ${{ github.workspace }} 15 | WORKDIR: utils/docker 16 | IMG_VER: latest 17 | 18 | jobs: 19 | linux: 20 | name: Linux 21 | runs-on: ubuntu-latest 22 | env: 23 | # use org's Private Access Token to log in to GitHub Container Registry 24 | CONTAINER_REG_USER: ${{ secrets.GH_CR_USER }} 25 | CONTAINER_REG_PASS: ${{ secrets.GH_CR_PAT }} 26 | FORCE_IMAGE_ACTION: ${{ secrets.FORCE_IMAGE_ACTION }} 27 | TYPE: normal 28 | strategy: 29 | matrix: 30 | CONFIG: ["OS=ubuntu OS_VER=20.04 PMEMKV=master PUSH_IMAGE=1", 31 | "OS=ubuntu OS_VER=20.04 PMEMKV=stable-1.4", 32 | "OS=ubuntu OS_VER=20.04 PMEMKV=stable-1.5", 33 | "OS=fedora OS_VER=34 PMEMKV=master PUSH_IMAGE=1", 34 | "OS=fedora OS_VER=34 PMEMKV=stable-1.4", 35 | "OS=fedora OS_VER=34 PMEMKV=stable-1.5", 36 | "OS=fedora OS_VER=33 PMEMKV=master PUSH_IMAGE=1"] 37 | steps: 38 | - name: Set image version and force image action for stable branch 39 | # we want to set IMG_VER to e.g. '1.x' for stable branches and PRs against them 40 | # for PRs we have to use 'base_ref' - this is the target branch (and we have to check that instead) 41 | if: 42 | startsWith(github.ref, 'refs/heads/stable-') || startsWith(github.base_ref, 'stable-') 43 | # we now know we're on (or against) stable branches, so we just need to pick the version (e.g. the mentioned '1.x') 44 | run: | 45 | IMG_VER=$(echo ${GITHUB_BASE_REF} | cut -d - -f 2) 46 | [ -z "${IMG_VER}" ] \ 47 | && echo "IMG_VER=$(echo ${GITHUB_REF#refs/heads/} | cut -d - -f 2)" >> $GITHUB_ENV \ 48 | || echo "IMG_VER=${IMG_VER}" >> $GITHUB_ENV 49 | echo "FORCE_IMAGE_ACTION=rebuild" >> $GITHUB_ENV 50 | 51 | - name: Clone the git repo 52 | uses: actions/checkout@v2 53 | with: 54 | fetch-depth: 0 55 | 56 | # "pull" or "rebuild" can be passed to a secret FORCE_IMAGE_ACTION to override default action 57 | - name: Pull the image or rebuild and push it 58 | run: cd $WORKDIR && ${{ matrix.CONFIG }} ./pull-or-rebuild-image.sh $FORCE_IMAGE_ACTION 59 | 60 | - name: Run the build 61 | run: cd $WORKDIR && ${{ matrix.CONFIG }} ./build.sh 62 | doc: 63 | name: build and publish docs 64 | runs-on: ubuntu-latest 65 | needs: linux 66 | env: 67 | DOC_UPDATE_GITHUB_TOKEN: ${{ secrets.DOC_UPDATE_GITHUB_TOKEN }} 68 | DOC_UPDATE_BOT_NAME: ${{ secrets.DOC_UPDATE_BOT_NAME }} 69 | DOC_REPO_OWNER: ${{ secrets.DOC_REPO_OWNER }} 70 | if: 71 | github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/stable-') 72 | strategy: 73 | matrix: 74 | CONFIG: ["TYPE=doc OS=fedora OS_VER=34"] 75 | steps: 76 | - name: Set image version for stable branch 77 | if: startsWith(github.ref, 'refs/heads/stable-') 78 | run: | 79 | echo "IMG_VER=$(echo ${GITHUB_REF#refs/heads/} | cut -d - -f 2)" >> $GITHUB_ENV 80 | 81 | - name: Clone the git repo 82 | uses: actions/checkout@v2 83 | 84 | - name: Pull the image 85 | run: cd $WORKDIR && ${{ matrix.CONFIG }} ./pull-or-rebuild-image.sh pull 86 | 87 | - name: Run the build 88 | run: cd $WORKDIR && ${{ matrix.CONFIG }} ./build.sh 89 | -------------------------------------------------------------------------------- /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | 2 | name: pmemkv-java-maven 3 | # this job downloads pmemkv from maven and tries to run example with it 4 | on: 5 | schedule: 6 | # run this job at 00:00 UTC every Monday 7 | - cron: '0 0 * * 1' 8 | 9 | env: 10 | REPO: pmemkv-java 11 | GITHUB_REPO: pmem/pmemkv-java 12 | CONTAINER_REG: ghcr.io/pmem/pmemkv-java 13 | HOST_WORKDIR: ${{ github.workspace }} 14 | WORKDIR: utils/docker 15 | IMG_VER: latest 16 | # use org's Private Access Token to log in to GitHub Container Registry 17 | CONTAINER_REG_USER: ${{ secrets.GH_CR_USER }} 18 | CONTAINER_REG_PASS: ${{ secrets.GH_CR_PAT }} 19 | 20 | jobs: 21 | linux: 22 | name: Linux-maven 23 | runs-on: ubuntu-latest 24 | strategy: 25 | matrix: 26 | CONFIG: ["TYPE=maven OS=ubuntu OS_VER=21.04_clean PUSH_IMAGE=1"] 27 | steps: 28 | - name: Clone the git repo 29 | uses: actions/checkout@v2 30 | 31 | # maven workflow should always rebuild the image 32 | - name: Rebuild the image 33 | run: cd $WORKDIR && ${{ matrix.CONFIG }} ./pull-or-rebuild-image.sh rebuild 34 | 35 | - name: Run the build 36 | run: cd $WORKDIR && ${{ matrix.CONFIG }} ./build.sh 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | !.gitignore 3 | !.gitattributes 4 | !.github/ 5 | *.iml 6 | *.log 7 | target/ 8 | *.d 9 | *.class 10 | *~ 11 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to pmemkv-java 2 | 3 | - [Opening New Issues](#opening-new-issues) 4 | - [Code Style](#code-style) 5 | - [Submitting Pull Requests](#submitting-pull-requests) 6 | - [Configuring GitHub fork](#configuring-github-fork) 7 | 8 | ## Opening New Issues 9 | 10 | Please log bugs or suggestions as [GitHub issues](https://github.com/pmem/pmemkv-java/issues). 11 | Details such as OS and pmemkv version are always appreciated. 12 | 13 | ## Code Style 14 | 15 | We use code style as defined in the Eclipse formatter settings. 16 | 17 | Code is validated on `mvn validate` phase (executed automatically before `mvn compile` phase). 18 | 19 | If you want to format your code you can run adequate target: 20 | ```sh 21 | mvn formatter:format 22 | ``` 23 | 24 | ## Submitting Pull Requests 25 | 26 | We take outside code contributions to `pmemkv-java` through GitHub pull requests. 27 | 28 | **NOTE: If you do decide to implement code changes and contribute them, 29 | please make sure you agree your contribution can be made available 30 | under the [BSD-style License used for pmemkv-java](https://github.com/pmem/pmemkv-java/blob/master/LICENSE).** 31 | 32 | **NOTE: Submitting your changes also means that you certify the following:** 33 | 34 | ``` 35 | Developer's Certificate of Origin 1.1 36 | 37 | By making a contribution to this project, I certify that: 38 | 39 | (a) The contribution was created in whole or in part by me and I 40 | have the right to submit it under the open source license 41 | indicated in the file; or 42 | 43 | (b) The contribution is based upon previous work that, to the best 44 | of my knowledge, is covered under an appropriate open source 45 | license and I have the right under that license to submit that 46 | work with modifications, whether created in whole or in part 47 | by me, under the same open source license (unless I am 48 | permitted to submit under a different license), as indicated 49 | in the file; or 50 | 51 | (c) The contribution was provided directly to me by some other 52 | person who certified (a), (b) or (c) and I have not modified 53 | it. 54 | 55 | (d) I understand and agree that this project and the contribution 56 | are public and that a record of the contribution (including all 57 | personal information I submit with it, including my sign-off) is 58 | maintained indefinitely and may be redistributed consistent with 59 | this project or the open source license(s) involved. 60 | ``` 61 | 62 | In case of any doubt, the gatekeeper may ask you to certify the above in writing, 63 | i.e. via email or by including a `Signed-off-by:` line at the bottom 64 | of your commit comments. 65 | 66 | To improve tracking of who is the author of a contribution, we kindly ask you 67 | to use your real name (not an alias) when committing your changes to pmemkv-java: 68 | ``` 69 | Author: Random J Developer 70 | ``` 71 | 72 | ## Configuring GitHub fork 73 | 74 | To build and submit documentation as an automatically generated pull request, 75 | the repository has to be properly configured. 76 | 77 | * [Personal access token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) for GitHub account has to be generated. 78 | * Such personal access token has to be set in in GitHub repository's 79 | [secrets](https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets) 80 | as `DOC_UPDATE_GITHUB_TOKEN` variable. 81 | 82 | * `DOC_UPDATE_BOT_NAME` secret variable has to be set. In most cases it will be 83 | the same as GitHub account name. 84 | 85 | * `DOC_REPO_OWNER` secret variable has to be set. Name of GitHub account, 86 | which will be target to make an automatic pull request with documentation. 87 | In most cases it will be the same as GitHub account name. 88 | 89 | To enable automatic images pushing to GitHub Container Registry, following variables: 90 | 91 | * `CONTAINER_REG` existing environment variable (defined in workflow files, in .github/ directory) 92 | has to be updated to contain proper GitHub Container Registry address (to forking user's container registry), 93 | 94 | * `GH_CR_USER` secret variable has to be set up - an account (with proper permissions) to publish 95 | images to the Container Registry (tab **Packages** in your GH profile/organization). 96 | 97 | * `GH_CR_PAT` secret variable also has to be set up - Personal Access Token 98 | (with only read & write packages permissions), to be generated as described 99 | [here](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token#creating-a-token) 100 | for selected account (user defined in above variable). 101 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | Fri Jul 02 2021 Łukasz Stolarczuk 2 | 3 | * Version 1.2.0 4 | 5 | Improvements: 6 | - add ReadIterator experimental API - it allows iterating through 7 | records and read (currently only entire) value 8 | - add new Builder methods to read config params from JSON objects 9 | 10 | Requirement notice: 11 | - since this release, pmemkv is required in version at least 1.4 12 | 13 | Tue Jun 08 2021 Igor Chorążewicz 14 | 15 | * Version 1.1.0 16 | 17 | Improvements: 18 | - improve performance over 2 times by caching direct buffers and 19 | optimizing JNI calls (of callbacks) 20 | - add new Builder methods to adjust direct buffers' sizes 21 | - use pmemkv C++ API (instead of C) in JNI layer 22 | 23 | Minor changes: 24 | - set up configurable test path 25 | - update documentation 26 | 27 | Other: 28 | - rethrow user exception in get_above/all/below/between instead of 29 | StoppedByCallbackException 30 | - adjust versioning scheme to match Semantic Versioning (always provide 31 | patch version) 32 | 33 | Fri Mar 12 2021 Krzysztof Filipek 34 | 35 | * Version 1.0.1 36 | 37 | Improvements: 38 | - simplify compilation 39 | - generated JAR files include dependencies 40 | - every example is compiled to runnable JAR 41 | - remove oleaster-matcher dependency 42 | - change Maven modules paths 43 | - disable javadoc generation for examples 44 | - add throws clauses to Database methods 45 | 46 | Bug fixes: 47 | - fix occasional crash in finalize method 48 | - add error handling for count* methods 49 | - remove unnecessary dependency to libpmemkv_json_config 50 | 51 | Tue Jun 30 2020 Szymon Romik 52 | 53 | * Version 1.0 54 | 55 | This is the first pmemkv-java release which is fully compatible with 56 | pmmekv 1.0 and guarantees backward compatibility. 57 | 58 | Major changes: 59 | - API redesign (support for an arbitrary type with converter to ByteBuffer) 60 | - config API redesign with builder pattern 61 | - extended exception list 62 | - extended documentation 63 | - build system refactor to start using mvn only 64 | - project merge with pmemkv-jni 65 | 66 | Fri Oct 04 2019 Szymon Romik 67 | 68 | * Version 0.9 69 | 70 | This release adjusts pmemkv-java to work with pmemkv 1.0 71 | 72 | Fri Jun 28 2019 Szymon Romik 73 | 74 | * Version 0.8 75 | 76 | This is the first official release of pmemkv-java project. 77 | 78 | It provides Java bindings to libpmemkv 0.8 with simplified API and not 79 | functionally equal to its native C/C++ counterpart. 80 | -------------------------------------------------------------------------------- /DEBUGGING.md: -------------------------------------------------------------------------------- 1 | # Debugging JNI with gdb 2 | 3 | As a starting point, we recommend good description of [how to debug JNI code using gdb](https://medium.com/@pirogov.alexey/gdb-debug-native-part-of-java-application-c-c-libraries-and-jdk-6593af3b4f3f). 4 | 5 | To build our JNI code with debug symbols - add extra debug compilation 6 | flag in `jni-binding/pom.xml`, in `compilerEndOptions` section: 7 | 8 | ```xml 9 | 10 | 11 | -g 12 | ... 13 | 14 | ``` 15 | 16 | It may be needed to disable [ptrace security options](https://www.kernel.org/doc/Documentation/security/Yama.txt): 17 | 18 | ```sh 19 | echo 0 > /proc/sys/kernel/yama/ptrace_scope 20 | ``` 21 | 22 | Now let's debug basic example: 23 | 24 | ```sh 25 | cd examples 26 | gdb --args java -ea -Xms1G -jar MixedTypesExample/target/MixedTypesExample-*-jar-with-dependencies.jar 27 | (gdb) handle SIGSEGV nostop noprint pass <- JVM is handling segfault on its own, so need to disable it in gdb 28 | (gdb) break jni_function_to_debug 29 | ``` 30 | 31 | # Debugging with jdb 32 | 33 | Build example with debug information 34 | 35 | ```sh 36 | cd MixedTypesExample/target 37 | javac -g -cp MixedTypesExample-*-jar-with-dependencies.jar ../src/main/java/MixedTypesExample.java 38 | jdb -classpath MixedTypesExample-*-jar-with-dependencies.jar MixedTypesExample 39 | ``` 40 | 41 | # Generating JNI header(s) 42 | 43 | To generate JNI header e.g. for Database class, run: 44 | 45 | ```sh 46 | javac -h jni-binding/ -cp pmemkv-binding/target/pmemkv-*.jar pmemkv-binding/src/main/java/io/pmem/pmemkv/Database.java 47 | ``` 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2017-2019, Intel Corporation 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the 13 | distribution. 14 | 15 | * Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived 17 | from this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /NOTICES.md: -------------------------------------------------------------------------------- 1 | # Legal notices 2 | 3 | We rely on the following open source projects. You can find links to the 4 | source code for these open source projects along with license information below. 5 | 6 | ### Apache 7 | 8 | https://maven.apache.org - Apache Maven 9 | 10 | Used under Apache License, Version 2 11 | 12 | Copyright © 2016 The Apache Software Foundation 13 | 14 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 15 | this software except in compliance with the License. You may obtain a copy of 16 | the License here: https://www.apache.org/licenses/LICENSE-2.0 17 | 18 | Unless required by applicable law or agreed to in writing, software distributed 19 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 20 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 21 | specific language governing permissions and limitations under the License. 22 | 23 | ### JUnit 24 | 25 | https://junit.org 26 | 27 | Used under Eclipse Public License 28 | 29 | Copyright © 2002-2016 JUnit 30 | 31 | All rights reserved. This program and the accompanying materials are made 32 | available under the terms of the Eclipse Public License v1.0 which accompanies 33 | this distribution, and is available at: 34 | https://www.eclipse.org/legal/epl-v10.html 35 | 36 | ### OpenJDK 37 | 38 | https://openjdk.java.net 39 | 40 | Used under GPLv2 with Classpath Exception 41 | 42 | Copyright © 2016 Oracle Corporation and/or its affiliates 43 | 44 | This program is free software; you can redistribute it and/or modify it under 45 | the terms of the GNU General Public License as published by the Free Software 46 | Foundation; either version 2 of the License, or (at your option) any later 47 | version. 48 | 49 | This program is distributed in the hope that it will be useful, but WITHOUT ANY 50 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 51 | PARTICULAR PURPOSE. See https://openjdk.java.net/legal/gplv2+ce.html for more 52 | details. 53 | 54 | As a special exception, the copyright holders of this library give you 55 | permission to link this library with independent modules to produce an 56 | executable, regardless of the license terms of these independent modules, and 57 | to copy and distribute the resulting executable under terms of your choice, 58 | provided that you also meet, for each linked independent module, the terms and 59 | conditions of the license of that module. An independent module is a module 60 | which is not derived from or based on this library. If you modify this library, 61 | you may extend this exception to your version of the library, but you are not 62 | obligated to do so. If you do not wish to do so, delete this exception 63 | statement from your version. 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pmemkv-java 2 | [![GHA build status](https://github.com/pmem/pmemkv-java/workflows/pmemkv-java/badge.svg?branch=master)](https://github.com/pmem/pmemkv-java/actions) 3 | [![PMEMKV-JAVA version](https://img.shields.io/github/tag/pmem/pmemkv-java.svg)](https://github.com/pmem/pmemkv-java/releases/latest) 4 | [![pmemkv-root maven central](https://maven-badges.herokuapp.com/maven-central/io.pmem/pmemkv-root/badge.svg?style=flat-for-the-badge)](https://search.maven.org/artifact/io.pmem/pmemkv-root) 5 | 6 | ## ⚠️ Discontinuation of the project 7 | The **pmemkv-java** project will no longer be maintained by Intel. 8 | - Intel has ceased development and contributions including, but not limited to, maintenance, bug fixes, new releases, 9 | or updates, to this project. 10 | - Intel no longer accepts patches to this project. 11 | - If you have an ongoing need to use this project, are interested in independently developing it, or would like to 12 | maintain patches for the open source software community, please create your own fork of this project. 13 | - You will find more information [here](https://pmem.io/blog/2022/11/update-on-pmdk-and-our-long-term-support-strategy/). 14 | 15 | ## Introduction 16 | 17 | Java bindings for pmemkv, using Java Native Interface. It's mostly functionally equal to pmemkv 18 | in version 1.0, but some of the new functionalities (e.g. from pmemkv 1.4) are already available. 19 | 20 | All known issues and limitations are logged as GitHub issues or are described 21 | in pmemkv's man pages. 22 | 23 | Java API is documented with javadocs and can be found as html on https://pmem.io/pmemkv-java 24 | for every branch/release. For most recent always see [master](https://pmem.io/pmemkv-java/master/html/index.html) docs. 25 | 26 | Latest releases can be found on the ["releases" tab](https://github.com/pmem/pmemkv-java/releases). 27 | Up-to-date support/maintenance status of branches/releases is available on [pmem.io](https://pmem.io/pmemkv-java). 28 | 29 | ## Dependencies 30 | 31 | * [pmemkv 1.4](https://github.com/pmem/pmemkv) - Key-Value Datastore for Persistent Memory 32 | * pmemkv source package (pmemkv-devel or libpmemkv-dev) 33 | * Java Development Kit 8 34 | * gcc-c++ compiler 35 | * [Apache Maven 3](https://maven.apache.org) - build system 36 | 37 | ## Usage 38 | 39 | ### Maven repository 40 | 41 | This pmemkv binding is accessible from maven repository: 42 | 43 | [io.pmem namespace @ maven.org](https://repo1.maven.org/maven2/io/pmem/pmemkv-root) 44 | 45 | You can add our project as a dependency and use it freely. Make sure to use it e.g. like this: 46 | 47 | ``` 48 | 49 | io.pmem 50 | pmemkv-root 51 | [1.2.0,) 52 | 53 | ``` 54 | 55 | ### Installation 56 | 57 | Start by installing [pmemkv](https://github.com/pmem/pmemkv/blob/master/INSTALLING.md) 58 | (currently at least in version **1.4**) in your system. Make sure our helper library `pmemkv_json_config` 59 | is enabled by specifying extra cmake parameter - `cmake .. -DBUILD_JSON_CONFIG=ON ...`. 60 | 61 | It may be necessary to [configure a proxy](https://maven.apache.org/guides/mini/guide-proxies.html) 62 | and set `JAVA_HOME` environment variable. Set `JAVA_HOME` variable with directory containing 63 | JDK 8 installed typically in `/usr/lib/jvm/`, command below will set first directory matching to 64 | 1.8.0, but path can differ in some exotic distros: 65 | 66 | ```sh 67 | export JAVA_HOME=`ls -d1 /usr/lib/jvm/* | grep "1.8.0" | head -n 1` 68 | echo $JAVA_HOME 69 | ``` 70 | 71 | Clone the pmemkv-java tree: 72 | 73 | ```sh 74 | git clone https://github.com/pmem/pmemkv-java.git 75 | cd pmemkv-java 76 | ``` 77 | 78 | Build and install Java Native Interface (JNI) and java bindings: 79 | 80 | ```sh 81 | mvn install 82 | ``` 83 | 84 | If dependencies (pmemkv, libpmemobj-cpp, pmdk, etc.) are installed in non-standard 85 | location(s) it may be also necessary to set up: 86 | **CPLUS_INCLUDE_PATH** and **LIBRARY_PATH** for compiling and linking JNI code (gcc env. variables), 87 | **LD_LIBRARY_PATH** for examples and tests build/execution. 88 | 89 | ```sh 90 | CPLUS_INCLUDE_PATH= \ 91 | LIBRARY_PATH= \ 92 | LD_LIBRARY_PATH= mvn install 93 | ``` 94 | 95 | ## Testing 96 | 97 | This library includes a set of automated tests that exercise all functionality. 98 | 99 | ```sh 100 | LD_LIBRARY_PATH= mvn test 101 | ``` 102 | 103 | to execute tests on non-default path (`/dev/shm`), setup desired directory, e.g.: 104 | 105 | ```sh 106 | LD_LIBRARY_PATH= mvn test -Dtest.db.dir=/my/test/dir 107 | ``` 108 | 109 | ## Examples 110 | 111 | We use `/dev/shm` with [emulated persistent memory](https://pmem.io/2016/02/22/pm-emulation.html) 112 | in examples. 113 | 114 | Examples can be found within this repository in [examples directory](https://github.com/pmem/pmemkv-java/tree/master/examples). 115 | To execute them, run e.g.: 116 | 117 | ```sh 118 | cd examples 119 | mvn package 120 | PMEM_IS_PMEM_FORCE=1 java -ea -Xms1G -jar StringExample/target/StringExample-*-jar-with-dependencies.jar 121 | ``` 122 | 123 | If you want to use our examples with pmemkv from maven repository, you can take a look at our 124 | [testing script](./utils/docker/run-maven-example.sh) executed in our [dedicated CI workflow](./.github/workflows/maven.yml). 125 | It boils down to changing build command (`mvn package`) to e.g.: 126 | 127 | ```sh 128 | mvn package -Dpmemkv.packageName=pmemkv-root -Dpmemkv.packageVersion=1.2.0 129 | ``` 130 | 131 | ## Contributing 132 | 133 | Any contributions are welcome. Process, hints and good practices 134 | are described in [CONTRIBUTING.md](./CONTRIBUTING.md). 135 | 136 | ### Debugging 137 | 138 | Debugging process is described in [DEBUGGING.md](./DEBUGGING.md). 139 | 140 | ### Documentation 141 | 142 | Docs can be generated using mvn by executing commands: 143 | 144 | ```sh 145 | mvn javadoc:javadoc 146 | ``` 147 | 148 | ## Contact us 149 | 150 | If you read the [blog post](https://pmem.io/blog/2022/11/update-on-pmdk-and-our-long-term-support-strategy/) and still have some questions (especially about discontinuation of the project), please contact us using the dedicated e-mail: pmdk_support@intel.com. 151 | -------------------------------------------------------------------------------- /RELEASE_STEPS.md: -------------------------------------------------------------------------------- 1 | # pmemkv-java release steps 2 | 3 | This document contains all the steps required to make a new release of pmemkv-java. 4 | 5 | \#define $VERSION = current full version (e.g. 1.0.2); $VER = major+minor only version (e.g. 1.0) 6 | 7 | Make a release locally: 8 | - add an entry to ChangeLog, remember to change the day of the week in the release date 9 | - for major/minor releases mention compatibility with the previous release 10 | - update "pmemkv-java" project's version in all pom.xml files 11 | - update version tested in the `run-maven-example.sh` script 12 | - git commit -a -S -m "common: $VERSION release" 13 | - git tag -a -s -m "pmemkv-java version $VERSION" $VERSION 14 | 15 | Make a package: 16 | - mvn package 17 | - verify created packages: 18 | - .jar's (with java code and docs) and 19 | - .so (JNI, C++ code) 20 | 21 | Publish changes: 22 | - for major/minor release: 23 | - git push upstream HEAD:master $VERSION 24 | - create and push to upstream stable-$VERSION branch: 25 | - git checkout -b stable-$VER 26 | - git push upstream HEAD:stable-$VER 27 | - for patch release: 28 | - git push upstream HEAD:stable-$VER $VERSION 29 | - create PR from stable-$VER to next stable (or master, if release is from most recent stable branch) 30 | 31 | Publish package and make it official: 32 | - go to [GitHub's releases tab](https://github.com/pmem/pmemkv-java/releases/new): 33 | - tag version: $VERSION, release title: pmemkv-java version $VERSION, description: copy entry from ChangeLog and format it with no tabs and no characters limit in line 34 | - announce the release on pmem group 35 | - publish package to mvn central repository 36 | 37 | Later, for major/minor release: 38 | - once 'docs' branch contains new documentation, move its content to pmem.io and add $VER entry in docs links 39 | and in "Releases' support status" table (and update any status if needed) 40 | -------------------------------------------------------------------------------- /examples/ByteBufferExample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | io.pmem 9 | examples 10 | 1.2.0 11 | 12 | 13 | ByteBufferExample 14 | ByteBufferExample 15 | jar 16 | 17 | -------------------------------------------------------------------------------- /examples/ByteBufferExample/src/main/java/ByteBufferExample.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2020-2021, Intel Corporation */ 3 | 4 | import io.pmem.pmemkv.Database; 5 | import io.pmem.pmemkv.ByteBufferConverter; 6 | 7 | import java.nio.ByteBuffer; 8 | 9 | public class ByteBufferExample { 10 | public static void main(String[] args) { 11 | String ENGINE = "vsmap"; 12 | 13 | /* 14 | * Keys and values are ByteBuffer; ByteBufferConverter is already delivered in 15 | * io.pmem.pmemkv package 16 | */ 17 | Database db = new Database.Builder(ENGINE) 18 | .setSize(1073741824) 19 | .setPath("/dev/shm") 20 | .setKeyConverter(new ByteBufferConverter()) 21 | .setValueConverter(new ByteBufferConverter()) 22 | .build(); 23 | 24 | /* Direct ByteBuffer */ 25 | for (int i = 0; i < 0xFF; i++) { 26 | ByteBuffer key = ByteBuffer.allocateDirect(4); 27 | key.putInt(i); 28 | db.put(key, key); 29 | } 30 | /* Simply read all data using getAll() with a lambda callback */ 31 | db.getAll((ByteBuffer k, ByteBuffer v) -> { 32 | System.out.println("Key: " + String.format("0x%02X", k.getInt()) + 33 | " Value: " + String.format("0x%02X", v.getInt())); 34 | }); 35 | 36 | db.stop(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /examples/IteratorExample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | io.pmem 9 | examples 10 | 1.2.0 11 | 12 | 13 | IteratorExample 14 | IteratorExample 15 | jar 16 | 17 | -------------------------------------------------------------------------------- /examples/IteratorExample/src/main/java/IteratorExample.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2021, Intel Corporation */ 3 | 4 | import io.pmem.pmemkv.Converter; 5 | import io.pmem.pmemkv.Database; 6 | 7 | import java.nio.ByteBuffer; 8 | 9 | /* Implementation of Converter interface to allow 10 | * storing (in Database) keys and values as Strings. 11 | */ 12 | class StringConverter implements Converter { 13 | public ByteBuffer toByteBuffer(String entry) { 14 | return ByteBuffer.wrap(entry.getBytes()); 15 | } 16 | 17 | public String fromByteBuffer(ByteBuffer entry) { 18 | byte[] bytes; 19 | bytes = new byte[entry.capacity()]; 20 | entry.get(bytes); 21 | return new String(bytes); 22 | } 23 | } 24 | 25 | public class IteratorExample { 26 | public static void main(String[] args) { 27 | /* 28 | * We pick sorted engine in this example to show the usage of seekHigherEq 29 | * method. Unsorted engines do not support seekLower[Eq]/Higher[Eq] methods. 30 | */ 31 | String ENGINE = "vsmap"; 32 | 33 | System.out.println("Starting engine"); 34 | Database db = new Database.Builder(ENGINE) 35 | .setSize(1073741824) 36 | .setPath("/dev/shm") 37 | .setKeyConverter(new StringConverter()) 38 | .setValueConverter(new StringConverter()) 39 | .build(); 40 | 41 | System.out.println("Putting only odd keys"); 42 | for (int i = 0; i <= 10; i++) { 43 | if (i % 2 == 0) 44 | continue; 45 | db.put("key" + i, "value" + i); 46 | } 47 | 48 | /* Create iterator using try-with-resources statement */ 49 | try (Database.ReadIterator it = db.readIterator()) { 50 | assert it != null; 51 | 52 | System.out.println("Seek first record and read it"); 53 | boolean succeeded = it.seekToFirst(); 54 | assert succeeded; 55 | 56 | /* Can't manipulate data in DB using key() or value() ! */ 57 | String key = it.key(); 58 | String value = it.value(); 59 | System.out.println("Key: " + key + " and its value: " + value); 60 | assert key.equals("key1"); 61 | assert value.equals("value1"); 62 | 63 | System.out.println("Skip to record higher or equal to 'key2'"); 64 | it.seekHigherEq("key2"); 65 | key = it.key(); 66 | value = it.value(); 67 | System.out.println("Key: " + key + " and its value: " + value); 68 | 69 | System.out.println("Iterate until the end"); 70 | while (it.isNext()) { 71 | it.next(); 72 | key = it.key(); 73 | value = it.value(); 74 | System.out.println("Key: " + key + " and its value: " + value); 75 | } 76 | 77 | /* No need to close the iterator manually, it implements AutoCloseable */ 78 | } 79 | 80 | System.out.println("Stopping engine"); 81 | db.stop(); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /examples/MixedTypesExample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | io.pmem 9 | examples 10 | 1.2.0 11 | 12 | 13 | MixedTypesExample 14 | MixedTypesExample 15 | jar 16 | 17 | -------------------------------------------------------------------------------- /examples/MixedTypesExample/src/main/java/MixedTypesExample.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2020-2021, Intel Corporation */ 3 | 4 | import io.pmem.pmemkv.Database; 5 | import io.pmem.pmemkv.Converter; 6 | import io.pmem.pmemkv.ByteBufferConverter; 7 | 8 | import java.nio.ByteBuffer; 9 | 10 | class StringConverter implements Converter { 11 | public ByteBuffer toByteBuffer(String entry) { 12 | return ByteBuffer.wrap(entry.getBytes()); 13 | } 14 | 15 | public String fromByteBuffer(ByteBuffer entry) { 16 | byte[] bytes; 17 | bytes = new byte[entry.capacity()]; 18 | entry.get(bytes); 19 | return new String(bytes); 20 | } 21 | } 22 | 23 | public class MixedTypesExample { 24 | public static void main(String[] args) { 25 | String ENGINE = "vsmap"; 26 | 27 | /* 28 | * Keys are String - Converter is implemented above; Values are ByteBuffer - 29 | * ByteBufferConverter is already delivered in io.pmem.pmemkv package 30 | */ 31 | Database db = new Database.Builder(ENGINE) 32 | .setSize(1073741824) 33 | .setPath("/dev/shm") 34 | .setKeyConverter(new StringConverter()) 35 | .setValueConverter(new ByteBufferConverter()) 36 | .build(); 37 | 38 | for (int i = 0; i < 0xFF; i++) { 39 | ByteBuffer value = ByteBuffer.allocateDirect(4); 40 | value.putInt(i); 41 | String key = "str" + i; 42 | db.put(key, value); 43 | } 44 | /* Simply read all data using getAll() with a lambda callback */ 45 | db.getAll((k, v) -> { 46 | System.out.println("Key: " + k + 47 | " Value: " + String.format("0x%02X", v.getInt())); 48 | }); 49 | 50 | db.stop(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /examples/PicturesExample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | io.pmem 9 | examples 10 | 1.2.0 11 | 12 | 13 | PicturesExample 14 | PicturesExample 15 | jar 16 | 17 | -------------------------------------------------------------------------------- /examples/PicturesExample/src/main/java/PicturesExample.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2020-2021, Intel Corporation */ 3 | 4 | import io.pmem.pmemkv.Database; 5 | import io.pmem.pmemkv.Converter; 6 | 7 | import java.awt.*; 8 | import java.awt.image.BufferedImage; 9 | import java.io.ByteArrayOutputStream; 10 | import java.io.File; 11 | import java.io.InputStream; 12 | import java.io.IOException; 13 | import java.nio.ByteBuffer; 14 | import java.util.concurrent.atomic.AtomicInteger; 15 | import javax.imageio.ImageIO; 16 | import javax.swing.JFrame; 17 | 18 | /* Helper implementation, extending InputStream. 19 | * We'll use it to store images as ByteBuffer. 20 | */ 21 | class ByteBufferBackedInputStream extends InputStream { 22 | ByteBuffer buff; 23 | 24 | public ByteBufferBackedInputStream(ByteBuffer buff) { 25 | this.buff = buff; 26 | this.buff.rewind(); 27 | } 28 | 29 | @Override 30 | public int read() { 31 | throw new UnsupportedOperationException(); 32 | } 33 | 34 | @Override 35 | public int read(byte[] bytes, int off, int len) 36 | throws IOException { 37 | if (!buff.hasRemaining()) { 38 | return -1; 39 | } 40 | len = Math.min(len, buff.remaining()); 41 | buff.get(bytes, off, len); 42 | return len; 43 | } 44 | } 45 | 46 | /* 47 | * We want to use String as keys, so we need to show how to convert it into/from 48 | * ByteBuffer. 49 | */ 50 | class StringConverter implements Converter { 51 | public ByteBuffer toByteBuffer(String entry) { 52 | return ByteBuffer.wrap(entry.getBytes()); 53 | } 54 | 55 | public String fromByteBuffer(ByteBuffer entry) { 56 | byte[] bytes; 57 | bytes = new byte[entry.capacity()]; 58 | entry.get(bytes); 59 | return new String(bytes); 60 | } 61 | } 62 | 63 | /* And BufferedImage will be our values. */ 64 | class ImageConverter implements Converter { 65 | public ByteBuffer toByteBuffer(BufferedImage entry) { 66 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 67 | try { 68 | ImageIO.write(entry, "png", out); 69 | } catch (IOException e) { 70 | return null; 71 | } 72 | return ByteBuffer.wrap(out.toByteArray()); 73 | } 74 | 75 | public BufferedImage fromByteBuffer(ByteBuffer entry) { 76 | BufferedImage out = null; 77 | try { 78 | out = ImageIO.read(new ByteBufferBackedInputStream(entry)); 79 | } catch (IOException e) { 80 | return null; 81 | } 82 | return out; 83 | } 84 | } 85 | 86 | /* Add pmemkv's superpowers to the Canvas class */ 87 | class PmemkvPicture extends Canvas { 88 | private static final long serialVersionUID = 705612541135496879L; 89 | 90 | /* Use Strings as keys and BufferedImages as values */ 91 | private Database db; 92 | private String engine = "cmap"; 93 | 94 | public PmemkvPicture(String path, int size) { 95 | System.out.println("Creating new database in path: " + path + " with size: " + size); 96 | db = new Database.Builder(engine) 97 | .setSize(size) 98 | .setPath(path) 99 | .setKeyConverter(new StringConverter()) 100 | .setValueConverter(new ImageConverter()) 101 | .setForceCreate(true) 102 | .build(); 103 | } 104 | 105 | public PmemkvPicture(String path) { 106 | System.out.println("Using already existing database: " + path); 107 | db = new Database.Builder(engine) 108 | .setPath(path) 109 | .setKeyConverter(new StringConverter()) 110 | .setValueConverter(new ImageConverter()) 111 | .build(); 112 | } 113 | 114 | /* Simply read all images from a directory and put them into Database. */ 115 | public void putAllPicturesFromDirectory(String dirPath) { 116 | File[] images = new File(dirPath).listFiles((dir, name) -> name.endsWith(".png")); 117 | for (File image : images) { 118 | System.out.println(image.getAbsolutePath()); 119 | 120 | BufferedImage image_buffer = null; 121 | try { 122 | image_buffer = ImageIO.read(image); 123 | } catch (IOException e) { 124 | System.exit(1); 125 | } 126 | db.put(image.getName(), image_buffer); 127 | } 128 | } 129 | 130 | @Override 131 | public void paint(Graphics g) { 132 | System.out.println("Draw images from pmemkv database"); 133 | AtomicInteger yPosition = new AtomicInteger(0); 134 | db.getAll((k, v) -> { 135 | System.out.println("\tDraw " + k); 136 | g.drawImage(v, 0, yPosition.getAndAdd(v.getHeight()), null); 137 | }); 138 | } 139 | } 140 | 141 | /* 142 | * Main example's class. 143 | * 144 | * Reads parameters from environment, open/create database, optionally load 145 | * pictures from directory, paint them all in JFrame. 146 | */ 147 | public class PicturesExample { 148 | public static void main(String[] args) { 149 | String inputDirEnv = System.getenv("InputDir"); 150 | String pmemkvPathEnv = System.getenv("PmemkvPath"); 151 | String pmemkvSizeEnv = System.getenv("PmemkvSize"); 152 | int pmemkvSize = 0; 153 | 154 | /* PmemkvPath is obligatory for this example */ 155 | if (pmemkvPathEnv == null) { 156 | System.out.println("Provide at least PmemkvPath parameter. See examples' README for usage."); 157 | System.exit(0); 158 | } 159 | 160 | try { 161 | pmemkvSize = Integer.parseInt(pmemkvSizeEnv); 162 | } catch (NumberFormatException e) { 163 | System.out.println("Wrong size: " + e); 164 | System.exit(1); 165 | } 166 | 167 | System.out.println("Parameters:"); 168 | System.out.println("InputDir: " + inputDirEnv); 169 | System.out.println("Path: " + pmemkvPathEnv); 170 | System.out.println("Size: " + pmemkvSizeEnv); 171 | 172 | PmemkvPicture m = null; 173 | if (pmemkvSize != 0) { 174 | /* if size is given we create new database */ 175 | m = new PmemkvPicture(pmemkvPathEnv, pmemkvSize); 176 | } else { 177 | /* only path was given, we open existing database with pictures */ 178 | m = new PmemkvPicture(pmemkvPathEnv); 179 | } 180 | /* input dir was set - we're loading all .png pictures into database */ 181 | if (inputDirEnv != null) { 182 | System.out.println("Loading files from " + inputDirEnv + " to pmemkv database."); 183 | m.putAllPicturesFromDirectory(inputDirEnv); 184 | } 185 | 186 | JFrame f = new JFrame(); 187 | f.add(m); 188 | f.setSize(512, 512); 189 | f.setVisible(true); 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | ## Pmemkv-examples 2 | 3 | This directory contains examples for pmemkv-java. Examples use various 4 | pmemkv engines (e.g. vsmap or cmap) - if example does not work, 5 | please verify if engine is enabled in pmemkv. 6 | 7 | Examples can be built and executed, e.g.: 8 | ```sh 9 | mvn package 10 | PMEM_IS_PMEM_FORCE=1 java -ea -Xms1G -jar StringExample/target/StringExample-*-jar-with-dependencies.jar 11 | ``` 12 | 13 | ### StringExample 14 | 15 | It's a basic example, where both (key and value) are String objects. 16 | 17 | ### ByteBufferExample 18 | 19 | It's an example, where key and values are a binary data. 20 | 21 | ### MixedTypesExample 22 | 23 | As in the name - it has mixed types: keys are String objects and values are binary data. 24 | 25 | ### PicturesExample 26 | 27 | It's more complex one - it uses persistent engine (cmap) to store pictures in pmemkv. Keys are String, values are BufferedImage. 28 | 29 | Load pictures in the png format from the directory specified by the InputDir environment variable to new pmemkv datastore of size (in bytes) specified by PmemkvSize and display all pictures stored in this datastore. 30 | ```sh 31 | PmemkvPath=/dev/shm/file PmemkvSize=10000000 InputDir=/path/to/directory/with/png/files PMEM_IS_PMEM_FORCE=1 java -ea -Xms1G -jar PicturesExample/target/PicturesExample-*-jar-with-dependencies.jar 32 | ``` 33 | 34 | Display pictures already stored in the pmemkv datastore: 35 | ```sh 36 | PmemkvPath=/dev/shm/file PMEM_IS_PMEM_FORCE=1 java -ea -Xms1G -jar PicturesExample/target/PicturesExample-*-jar-with-dependencies.jar 37 | ``` 38 | 39 | Add new pictures to already existing pmemkv datastore and display all pictures stored in this datastore. 40 | ```sh 41 | PmemkvPath=/dev/shm/file InputDir=/path/to/directory/with/png/files PMEM_IS_PMEM_FORCE=1 java -ea -Xms1G -jar PicturesExample/target/PicturesExample-*-jar-with-dependencies.jar 42 | ``` 43 | -------------------------------------------------------------------------------- /examples/StringExample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | io.pmem 9 | examples 10 | 1.2.0 11 | 12 | 13 | StringExample 14 | StringExample 15 | jar 16 | 17 | -------------------------------------------------------------------------------- /examples/StringExample/src/main/java/StringExample.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2020-2021, Intel Corporation */ 3 | 4 | import io.pmem.pmemkv.Database; 5 | import io.pmem.pmemkv.Converter; 6 | 7 | import java.nio.ByteBuffer; 8 | 9 | /* Implementation of Converter interface to allow 10 | * storing (in Database) keys and values as Strings. 11 | */ 12 | class StringConverter implements Converter { 13 | public ByteBuffer toByteBuffer(String entry) { 14 | return ByteBuffer.wrap(entry.getBytes()); 15 | } 16 | 17 | public String fromByteBuffer(ByteBuffer entry) { 18 | byte[] bytes; 19 | bytes = new byte[entry.capacity()]; 20 | entry.get(bytes); 21 | return new String(bytes); 22 | } 23 | } 24 | 25 | public class StringExample { 26 | public static void main(String[] args) { 27 | String ENGINE = "vsmap"; 28 | 29 | System.out.println("Starting engine"); 30 | Database db = new Database.Builder(ENGINE) 31 | .setSize(1073741824) 32 | .setPath("/dev/shm") 33 | .setKeyConverter(new StringConverter()) 34 | .setValueConverter(new StringConverter()) 35 | .build(); 36 | 37 | System.out.println("Putting new key"); 38 | db.put("key1", "value1"); 39 | assert db.countAll() == 1; 40 | 41 | System.out.println("Reading key back"); 42 | String value = db.getCopy("key1"); 43 | assert value.equals("value1"); 44 | 45 | System.out.println("Reading key back using callback"); 46 | db.get("key1", (String v) -> { 47 | assert v.equals("value1"); 48 | }); 49 | 50 | System.out.println("Putting more keys"); 51 | db.put("key2", "value2"); 52 | db.put("key3", "value3"); 53 | 54 | System.out.println("Iterating existing keys"); 55 | db.getKeys((k) -> System.out.println(" visited: " + k)); 56 | 57 | System.out.println("Removing existing key"); 58 | db.remove("key1"); 59 | assert !db.exists("key1"); 60 | 61 | System.out.println("Stopping engine"); 62 | db.stop(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /examples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | io.pmem 9 | pmemkv-root 10 | 1.2.0 11 | 12 | 13 | examples 14 | Examples for pmemkv Java binding 15 | pom 16 | 17 | 18 | true 19 | 20 | ${project.parent.basedir}/.. 21 | 22 | pmemkv 23 | ${project.version} 24 | 25 | 26 | 27 | ByteBufferExample 28 | PicturesExample 29 | StringExample 30 | MixedTypesExample 31 | IteratorExample 32 | 33 | 34 | 35 | 36 | 37 | org.apache.maven.plugins 38 | maven-compiler-plugin 39 | 3.8.1 40 | 41 | true 42 | false 43 | 44 | -Xlint:all 45 | 46 | 47 | 48 | 49 | org.apache.maven.plugins 50 | maven-jar-plugin 51 | 3.2.0 52 | 53 | 54 | 55 | true 56 | ${project.artifactId} 57 | 58 | 59 | 60 | 61 | 62 | maven-assembly-plugin 63 | 64 | 65 | package 66 | 67 | single 68 | 69 | 70 | 71 | 72 | 73 | jar-with-dependencies 74 | 75 | 76 | 77 | ${project.artifactId} 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | io.pmem 88 | ${pmemkv.packageName} 89 | ${pmemkv.packageVersion} 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /jni-binding/common.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2017-2021, Intel Corporation */ 3 | 4 | #include 5 | 6 | std::unordered_map PmemkvJavaException::PmemkvStatusDispatcher = { 7 | { pmem::kv::status::UNKNOWN_ERROR, "io/pmem/pmemkv/DatabaseException" }, 8 | { pmem::kv::status::NOT_FOUND, "io/pmem/pmemkv/NotFoundException"}, 9 | { pmem::kv::status::NOT_SUPPORTED, "io/pmem/pmemkv/NotSupportedException"}, 10 | { pmem::kv::status::INVALID_ARGUMENT, "io/pmem/pmemkv/InvalidArgumentException"}, 11 | { pmem::kv::status::CONFIG_PARSING_ERROR, "io/pmem/pmemkv/BuilderException"}, 12 | { pmem::kv::status::CONFIG_TYPE_ERROR, "io/pmem/pmemkv/BuilderException"}, 13 | { pmem::kv::status::STOPPED_BY_CB, "io/pmem/pmemkv/StoppedByCallbackException"}, 14 | { pmem::kv::status::OUT_OF_MEMORY, "io/pmem/pmemkv/OutOfMemoryException"}, 15 | { pmem::kv::status::WRONG_ENGINE_NAME, "io/pmem/pmemkv/WrongEngineNameException"}, 16 | { pmem::kv::status::TRANSACTION_SCOPE_ERROR, "io/pmem/pmemkv/TransactionScopeException"} 17 | }; 18 | -------------------------------------------------------------------------------- /jni-binding/common.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2017-2021, Intel Corporation */ 3 | 4 | #ifndef HEADER_COMMON_H 5 | #define HEADER_COMMON_H 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | class PmemkvJavaException { 12 | private: 13 | static std::unordered_map PmemkvStatusDispatcher; 14 | JNIEnv* env; 15 | 16 | public: 17 | constexpr static const char* DatabaseException = "io/pmem/pmemkv/DatabaseException"; 18 | constexpr static const char* GeneralException = "java/lang/Error"; 19 | 20 | PmemkvJavaException(JNIEnv* env_) { 21 | env = env_; 22 | } 23 | 24 | void ThrowException(pmem::kv::status status, const char* msg = pmemkv_errormsg()){ 25 | jclass exception_class; 26 | exception_class = env->FindClass(PmemkvStatusDispatcher[status]); 27 | if(exception_class == NULL) { 28 | exception_class = env->FindClass(DatabaseException); 29 | } 30 | if(exception_class == NULL) { 31 | exception_class = env->FindClass(GeneralException); 32 | } 33 | env->ThrowNew(exception_class, msg); 34 | } 35 | 36 | void ThrowException(const char* signature, const char* msg=""){ 37 | jclass exception_class; 38 | exception_class = env->FindClass(signature); 39 | if(exception_class == NULL) { 40 | exception_class = env->FindClass(GeneralException); 41 | } 42 | env->ThrowNew(exception_class, msg); 43 | } 44 | }; 45 | 46 | #endif // HEADER_COMMON_H 47 | -------------------------------------------------------------------------------- /jni-binding/io_pmem_pmemkv_Database.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2017-2022, Intel Corporation */ 3 | 4 | #include 5 | 6 | #define KEY_CALLBACK_NAME "keyCallbackWrapper" 7 | #define VALUE_CALLBACK_NAME "valueCallbackWrapper" 8 | #define KEY_VALUE_CALLBACK_NAME "keyValueCallbackWrapper" 9 | #define KEY_CALLBACK_SIG "(Lio/pmem/pmemkv/Database;Lio/pmem/pmemkv/KeyCallback;ILjava/nio/ByteBuffer;)V" 10 | #define VALUE_CALLBACK_SIG "(Lio/pmem/pmemkv/Database;Lio/pmem/pmemkv/ValueCallback;ILjava/nio/ByteBuffer;)V" 11 | #define KEY_VALUE_CALLBACK_SIG "(Lio/pmem/pmemkv/Database;Lio/pmem/pmemkv/KeyValueCallback;ILjava/nio/ByteBuffer;ILjava/nio/ByteBuffer;)V" 12 | 13 | jmethodID keyCallbackID = NULL; 14 | jmethodID valueCallbackID = NULL; 15 | jmethodID keyValueCallbackID = NULL; 16 | 17 | struct Context { 18 | JNIEnv* env; 19 | jobject db; 20 | jobject callback; 21 | jmethodID mid; 22 | 23 | Context(JNIEnv* env_, jobject db_, jobject callback_, jmethodID mid_) { 24 | env = env_; 25 | db = db_; 26 | callback = callback_; 27 | mid = mid_; 28 | } 29 | }; 30 | 31 | struct ContextGetByteArray { 32 | JNIEnv* env; 33 | jbyteArray result; 34 | 35 | ContextGetByteArray(JNIEnv* env_, jbyteArray result_ = NULL){ 36 | env = env_; 37 | result = result_; 38 | } 39 | }; 40 | 41 | void callback_get_byte_array(const char* v, size_t vb, void *arg) { 42 | const auto c = reinterpret_cast(arg); 43 | if ((c->result = c->env->NewByteArray(vb))) { 44 | c->env->SetByteArrayRegion(c->result, 0, vb, reinterpret_cast(v)); 45 | } else { 46 | PmemkvJavaException ex = PmemkvJavaException(c->env); 47 | ex.ThrowException(PmemkvJavaException::DatabaseException, "Cannot allocate output buffer"); 48 | } 49 | } 50 | 51 | int Callback_get_all_buffer(const char* k, size_t kb, const char* v, size_t vb, void *arg) { 52 | const auto c = static_cast(arg); 53 | 54 | jobject keybuf = c->env->NewDirectByteBuffer(const_cast(k), kb); 55 | jobject valuebuf = c->env->NewDirectByteBuffer(const_cast(v), vb); 56 | if (keybuf && valuebuf) { 57 | c->env->CallStaticVoidMethod(c->env->GetObjectClass(c->db), c->mid, 58 | c->db, c->callback, kb, keybuf, vb, valuebuf); 59 | c->env->DeleteLocalRef(keybuf); 60 | c->env->DeleteLocalRef(valuebuf); 61 | } 62 | if (c->env->ExceptionOccurred()) { 63 | return 1; 64 | } 65 | return 0; 66 | } 67 | 68 | extern "C" JNIEXPORT jlong JNICALL Java_io_pmem_pmemkv_Database_database_1start 69 | (JNIEnv* env, jobject obj, jstring engine, jlong config) { 70 | const char* cengine = env->GetStringUTFChars(engine, NULL); 71 | 72 | keyCallbackID = env->GetStaticMethodID(env->GetObjectClass(obj), KEY_CALLBACK_NAME, KEY_CALLBACK_SIG); 73 | valueCallbackID = env->GetStaticMethodID(env->GetObjectClass(obj), VALUE_CALLBACK_NAME, VALUE_CALLBACK_SIG); 74 | keyValueCallbackID = env->GetStaticMethodID(env->GetObjectClass(obj), 75 | KEY_VALUE_CALLBACK_NAME, KEY_VALUE_CALLBACK_SIG); 76 | 77 | pmem::kv::db *db = new pmem::kv::db(); 78 | auto cfg = reinterpret_cast(config); 79 | pmem::kv::status status = db->open(cengine, pmem::kv::config(cfg)); 80 | env->ReleaseStringUTFChars(engine, cengine); 81 | 82 | if (status != pmem::kv::status::OK) { 83 | PmemkvJavaException(env).ThrowException(status); 84 | } 85 | return (jlong) db; 86 | } 87 | 88 | extern "C" JNIEXPORT void JNICALL Java_io_pmem_pmemkv_Database_database_1stop 89 | (JNIEnv* env, jobject obj, jlong pointer) { 90 | auto engine = reinterpret_cast(pointer); 91 | engine->close(); 92 | } 93 | 94 | void Callback_get_value_buffer(const char* v, size_t vb, void *arg) { 95 | const auto c = static_cast(arg); 96 | // OutOfMemoryError may occur 97 | if (jobject valuebuf = c->env->NewDirectByteBuffer(const_cast(v), vb)) { 98 | c->env->CallStaticVoidMethod(c->env->GetObjectClass(c->db), c->mid, c->db, c->callback, vb, valuebuf); 99 | c->env->DeleteLocalRef(valuebuf); 100 | } 101 | } 102 | 103 | int Callback_get_keys_buffer(const char* k, size_t kb, const char* v, size_t vb, void *arg) { 104 | const auto c = static_cast(arg); 105 | Callback_get_value_buffer(k, kb, arg); 106 | if (c->env->ExceptionCheck() == JNI_TRUE) { 107 | return 1; 108 | } 109 | return 0; 110 | } 111 | 112 | extern "C" JNIEXPORT void JNICALL Java_io_pmem_pmemkv_Database_database_1get_1keys_1buffer 113 | (JNIEnv* env, jobject obj, jlong pointer, jobject callback) { 114 | auto engine = reinterpret_cast(pointer); 115 | auto ctx = Context(env, obj, callback, keyCallbackID); 116 | auto status = engine->get_all(Callback_get_keys_buffer, &ctx); 117 | if (env->ExceptionCheck() == JNI_TRUE) return; 118 | if (status != pmem::kv::status::OK) PmemkvJavaException(env).ThrowException(status); 119 | } 120 | 121 | extern "C" JNIEXPORT void JNICALL Java_io_pmem_pmemkv_Database_database_1get_1keys_1above_1buffer 122 | (JNIEnv* env, jobject obj, jlong pointer, jint keybytes, jobject key, jobject callback) { 123 | auto engine = reinterpret_cast(pointer); 124 | const char* ckey = reinterpret_cast(env->GetDirectBufferAddress(key)); 125 | pmem::kv::string_view cppkey(ckey, keybytes); 126 | auto cxt = Context(env, obj, callback, keyCallbackID); 127 | auto status = engine->get_above(cppkey, Callback_get_keys_buffer, &cxt); 128 | if (env->ExceptionCheck() == JNI_TRUE) return; 129 | if (status != pmem::kv::status::OK) PmemkvJavaException(env).ThrowException(status); 130 | } 131 | 132 | extern "C" JNIEXPORT void JNICALL Java_io_pmem_pmemkv_Database_database_1get_1keys_1below_1buffer 133 | (JNIEnv* env, jobject obj, jlong pointer, jint keybytes, jobject key, jobject callback) { 134 | auto engine = reinterpret_cast(pointer); 135 | const char* ckey = reinterpret_cast(env->GetDirectBufferAddress(key)); 136 | pmem::kv::string_view cppkey(ckey, keybytes); 137 | auto cxt = Context(env, obj, callback, keyCallbackID); 138 | auto status = engine->get_below(cppkey, Callback_get_keys_buffer, &cxt); 139 | if (env->ExceptionCheck() == JNI_TRUE) return; 140 | if (status != pmem::kv::status::OK) PmemkvJavaException(env).ThrowException(status); 141 | } 142 | 143 | extern "C" JNIEXPORT void JNICALL Java_io_pmem_pmemkv_Database_database_1get_1keys_1between_1buffer 144 | (JNIEnv* env, jobject obj, jlong pointer, jint keybytes1, jobject key1, jint keybytes2, 145 | jobject key2, jobject callback) { 146 | auto engine = reinterpret_cast(pointer); 147 | const char* ckey1 = reinterpret_cast(env->GetDirectBufferAddress(key1)); 148 | const char* ckey2 = reinterpret_cast(env->GetDirectBufferAddress(key2)); 149 | pmem::kv::string_view cppkey1(ckey1, keybytes1); 150 | pmem::kv::string_view cppkey2(ckey2, keybytes2); 151 | auto cxt = Context(env, obj, callback, keyCallbackID); 152 | auto status = engine->get_between(cppkey1, cppkey2, Callback_get_keys_buffer, &cxt); 153 | if (env->ExceptionCheck() == JNI_TRUE) return; 154 | if (status != pmem::kv::status::OK) PmemkvJavaException(env).ThrowException(status); 155 | } 156 | 157 | extern "C" JNIEXPORT jlong JNICALL Java_io_pmem_pmemkv_Database_database_1count_1all 158 | (JNIEnv* env, jobject obj, jlong pointer) { 159 | auto engine = reinterpret_cast(pointer); 160 | size_t count; 161 | auto status = engine->count_all(count); 162 | if (status != pmem::kv::status::OK) PmemkvJavaException(env).ThrowException(status); 163 | return count; 164 | } 165 | 166 | extern "C" JNIEXPORT jlong JNICALL Java_io_pmem_pmemkv_Database_database_1count_1above_1buffer 167 | (JNIEnv* env, jobject obj, jlong pointer, jint keybytes, jobject key) { 168 | auto engine = reinterpret_cast(pointer); 169 | const char* ckey = reinterpret_cast(env->GetDirectBufferAddress(key)); 170 | pmem::kv::string_view cppkey(ckey, keybytes); 171 | size_t count; 172 | auto status = engine->count_above(cppkey, count); 173 | if (status != pmem::kv::status::OK) PmemkvJavaException(env).ThrowException(status); 174 | return count; 175 | } 176 | 177 | extern "C" JNIEXPORT jlong JNICALL Java_io_pmem_pmemkv_Database_database_1count_1below_1buffer 178 | (JNIEnv* env, jobject obj, jlong pointer, jint keybytes, jobject key) { 179 | auto engine = reinterpret_cast(pointer); 180 | const char* ckey = reinterpret_cast(env->GetDirectBufferAddress(key)); 181 | pmem::kv::string_view cppkey(ckey, keybytes); 182 | size_t count; 183 | auto status = engine->count_below(cppkey, count); 184 | if (status != pmem::kv::status::OK) PmemkvJavaException(env).ThrowException(status); 185 | 186 | return count; 187 | } 188 | 189 | extern "C" JNIEXPORT jlong JNICALL Java_io_pmem_pmemkv_Database_database_1count_1between_1buffer 190 | (JNIEnv* env, jobject obj, jlong pointer, jint keybytes1, jobject key1, jint keybytes2, jobject key2) { 191 | auto engine = reinterpret_cast(pointer); 192 | const char* ckey1 = reinterpret_cast(env->GetDirectBufferAddress(key1)); 193 | const char* ckey2 = reinterpret_cast(env->GetDirectBufferAddress(key2)); 194 | pmem::kv::string_view cppkey1(ckey1, keybytes1); 195 | pmem::kv::string_view cppkey2(ckey2, keybytes2); 196 | size_t count; 197 | auto status = engine->count_between(cppkey1, cppkey2, count); 198 | if (status != pmem::kv::status::OK) PmemkvJavaException(env).ThrowException(status); 199 | 200 | return count; 201 | } 202 | 203 | extern "C" JNIEXPORT void JNICALL Java_io_pmem_pmemkv_Database_database_1get_1all_1buffer 204 | (JNIEnv* env, jobject obj, jlong pointer, jobject callback) { 205 | auto engine = reinterpret_cast(pointer); 206 | auto cxt = Context(env, obj, callback, keyValueCallbackID); 207 | auto status = engine->get_all(Callback_get_all_buffer, &cxt); 208 | if (env->ExceptionCheck() == JNI_TRUE) 209 | return; // Propagate exception 210 | if (status != pmem::kv::status::OK) PmemkvJavaException(env).ThrowException(status); 211 | } 212 | 213 | extern "C" JNIEXPORT void JNICALL Java_io_pmem_pmemkv_Database_database_1get_1above_1buffer 214 | (JNIEnv* env, jobject obj, jlong pointer, jint keybytes, jobject key, jobject callback) { 215 | auto engine = reinterpret_cast(pointer); 216 | const char* ckey = reinterpret_cast(env->GetDirectBufferAddress(key)); 217 | pmem::kv::string_view cppkey(ckey, keybytes); 218 | auto cxt = Context(env, obj, callback, keyValueCallbackID); 219 | auto status = engine->get_above(cppkey, Callback_get_all_buffer, &cxt); 220 | if (env->ExceptionCheck() == JNI_TRUE) 221 | return; // Propagate exception 222 | if (status != pmem::kv::status::OK) PmemkvJavaException(env).ThrowException(status); 223 | } 224 | 225 | extern "C" JNIEXPORT void JNICALL Java_io_pmem_pmemkv_Database_database_1get_1below_1buffer 226 | (JNIEnv* env, jobject obj, jlong pointer, jint keybytes, jobject key, jobject callback) { 227 | auto engine = reinterpret_cast(pointer); 228 | const char* ckey = reinterpret_cast(env->GetDirectBufferAddress(key)); 229 | pmem::kv::string_view cppkey(ckey, keybytes); 230 | auto cxt = Context(env, obj, callback, keyValueCallbackID); 231 | auto status = engine->get_below(cppkey, Callback_get_all_buffer, &cxt); 232 | if (env->ExceptionCheck() == JNI_TRUE) 233 | return; // Propagate exception 234 | if (status != pmem::kv::status::OK) PmemkvJavaException(env).ThrowException(status); 235 | } 236 | 237 | extern "C" JNIEXPORT void JNICALL Java_io_pmem_pmemkv_Database_database_1get_1between_1buffer 238 | (JNIEnv* env, jobject obj, jlong pointer, jint keybytes1, jobject key1, jint keybytes2, 239 | jobject key2, jobject callback) { 240 | auto engine = reinterpret_cast(pointer); 241 | const char* ckey1 = reinterpret_cast(env->GetDirectBufferAddress(key1)); 242 | const char* ckey2 = reinterpret_cast(env->GetDirectBufferAddress(key2)); 243 | pmem::kv::string_view cppkey1(ckey1, keybytes1); 244 | pmem::kv::string_view cppkey2(ckey2, keybytes2); 245 | auto cxt = Context(env, obj, callback, keyValueCallbackID); 246 | auto status = engine->get_between(cppkey1, cppkey2, Callback_get_all_buffer, &cxt); 247 | if (env->ExceptionCheck() == JNI_TRUE) 248 | return; // Propagate exception 249 | if (status != pmem::kv::status::OK) PmemkvJavaException(env).ThrowException(status); 250 | } 251 | 252 | extern "C" JNIEXPORT jboolean JNICALL Java_io_pmem_pmemkv_Database_database_1exists_1buffer 253 | (JNIEnv* env, jobject obj, jlong pointer, jint keybytes, jobject key) { 254 | auto engine = reinterpret_cast(pointer); 255 | const char* ckey = reinterpret_cast(env->GetDirectBufferAddress(key)); 256 | pmem::kv::string_view cppkey(ckey, keybytes); 257 | auto status = engine->exists(cppkey); 258 | if (status != pmem::kv::status::OK && status != pmem::kv::status::NOT_FOUND) 259 | PmemkvJavaException(env).ThrowException(status); 260 | return status == pmem::kv::status::OK; 261 | } 262 | 263 | extern "C" JNIEXPORT void JNICALL Java_io_pmem_pmemkv_Database_database_1get_1buffer_1with_1callback 264 | (JNIEnv* env, jobject obj, jlong pointer, jint keybytes, jobject key, jobject callback) { 265 | auto engine = reinterpret_cast(pointer); 266 | const char* ckey = reinterpret_cast(env->GetDirectBufferAddress(key)); 267 | pmem::kv::string_view cppkey(ckey, keybytes); 268 | auto cxt = Context(env, obj, callback, valueCallbackID); 269 | auto status = engine->get(cppkey, Callback_get_value_buffer, &cxt); 270 | if (env->ExceptionCheck() == JNI_TRUE) return; // Propagate exception 271 | if (status != pmem::kv::status::OK) PmemkvJavaException(env).ThrowException(status); 272 | } 273 | 274 | extern "C" JNIEXPORT jbyteArray JNICALL Java_io_pmem_pmemkv_Database_database_1get_1bytes 275 | (JNIEnv* env, jobject obj, jlong pointer, jint keybytes, jobject key) { 276 | auto engine = reinterpret_cast(pointer); 277 | const char* ckey = reinterpret_cast(env->GetDirectBufferAddress(key)); 278 | pmem::kv::string_view cppkey(ckey, keybytes); 279 | ContextGetByteArray cxt = ContextGetByteArray(env); 280 | auto status = engine->get(cppkey, callback_get_byte_array, &cxt); 281 | if (env->ExceptionCheck() == JNI_TRUE) return nullptr; // Propagate exception 282 | if (status != pmem::kv::status::OK) 283 | PmemkvJavaException(env).ThrowException(status); 284 | return cxt.result; 285 | } 286 | 287 | extern "C" JNIEXPORT void JNICALL Java_io_pmem_pmemkv_Database_database_1put_1buffer 288 | (JNIEnv* env, jobject obj, jlong pointer, jint keybytes, jobject key, jint valuebytes, jobject value) { 289 | auto engine = reinterpret_cast(pointer); 290 | const char* ckey = reinterpret_cast(env->GetDirectBufferAddress(key)); 291 | const char* cvalue = reinterpret_cast(env->GetDirectBufferAddress(value)); 292 | pmem::kv::string_view cppkey(ckey, keybytes); 293 | pmem::kv::string_view cppvalue(cvalue, valuebytes); 294 | const auto result = engine->put(cppkey, cppvalue); 295 | if (result != pmem::kv::status::OK) 296 | PmemkvJavaException(env).ThrowException(result); 297 | } 298 | 299 | extern "C" JNIEXPORT jboolean JNICALL Java_io_pmem_pmemkv_Database_database_1remove_1buffer 300 | (JNIEnv* env, jobject obj, jlong pointer, jint keybytes, jobject key) { 301 | auto engine = reinterpret_cast(pointer); 302 | const char* ckey = reinterpret_cast(env->GetDirectBufferAddress(key)); 303 | pmem::kv::string_view cppkey(ckey, keybytes); 304 | const auto result = engine->remove(cppkey); 305 | if (result != pmem::kv::status::OK && result != pmem::kv::status::NOT_FOUND) 306 | PmemkvJavaException(env).ThrowException(result); 307 | return result == pmem::kv::status::OK; 308 | } 309 | -------------------------------------------------------------------------------- /jni-binding/io_pmem_pmemkv_Database_Builder.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2021, Intel Corporation */ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define EXCEPTION_CLASS "io/pmem/pmemkv/BuilderException" 9 | 10 | extern "C" JNIEXPORT jlong JNICALL Java_io_pmem_pmemkv_Database_00024Builder_config_1new 11 | (JNIEnv *env, jobject) { 12 | auto cfg = pmemkv_config_new(); 13 | if (cfg == nullptr) { 14 | env->ThrowNew(env->FindClass(EXCEPTION_CLASS), pmemkv_errormsg()); 15 | return 0; 16 | } 17 | return reinterpret_cast(cfg); 18 | } 19 | 20 | extern "C" JNIEXPORT void JNICALL Java_io_pmem_pmemkv_Database_00024Builder_config_1delete 21 | (JNIEnv *, jobject, jlong cfg) { 22 | pmemkv_config_delete(reinterpret_cast(cfg)); 23 | } 24 | 25 | extern "C" JNIEXPORT void JNICALL Java_io_pmem_pmemkv_Database_00024Builder_config_1put_1int 26 | (JNIEnv *env, jobject, jlong cfg, jstring jkey, jlong value) { 27 | const char* key = env->GetStringUTFChars(jkey, NULL); 28 | auto status = pmemkv_config_put_int64(reinterpret_cast(cfg), key, (int64_t) value); 29 | if (status != PMEMKV_STATUS_OK) 30 | env->ThrowNew(env->FindClass(EXCEPTION_CLASS), pmemkv_errormsg()); 31 | 32 | env->ReleaseStringUTFChars(jkey, key); 33 | } 34 | 35 | extern "C" JNIEXPORT void JNICALL Java_io_pmem_pmemkv_Database_00024Builder_config_1put_1string 36 | (JNIEnv *env, jobject, jlong cfg, jstring jkey, jstring jvalue) { 37 | const char* key = env->GetStringUTFChars(jkey, NULL); 38 | const char* value = env->GetStringUTFChars(jvalue, NULL); 39 | 40 | auto status = pmemkv_config_put_string(reinterpret_cast(cfg), key, value); 41 | if (status != PMEMKV_STATUS_OK) 42 | env->ThrowNew(env->FindClass(EXCEPTION_CLASS), pmemkv_errormsg()); 43 | 44 | env->ReleaseStringUTFChars(jkey, key); 45 | env->ReleaseStringUTFChars(jvalue, value); 46 | } 47 | 48 | extern "C" JNIEXPORT void JNICALL Java_io_pmem_pmemkv_Database_00024Builder_config_1from_1json 49 | (JNIEnv *env, jobject, jlong cfg, jstring jjson) { 50 | jboolean copySucceeded; 51 | const char* cjson = env->GetStringUTFChars(jjson, ©Succeeded); 52 | if (copySucceeded == JNI_FALSE || !cjson) { 53 | env->ThrowNew(env->FindClass(EXCEPTION_CLASS), "json string must be UTF-8 and cannot be null"); 54 | } else { 55 | auto status = pmemkv_config_from_json(reinterpret_cast(cfg), cjson); 56 | if (status != PMEMKV_STATUS_OK) 57 | env->ThrowNew(env->FindClass(EXCEPTION_CLASS), pmemkv_config_from_json_errormsg()); 58 | } 59 | env->ReleaseStringUTFChars(jjson, cjson); 60 | } 61 | -------------------------------------------------------------------------------- /jni-binding/io_pmem_pmemkv_Database_ReadIterator.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2021, Intel Corporation */ 3 | 4 | #include 5 | 6 | /* Helper function for seek methods */ 7 | template 8 | jboolean boilerplate_seek(JNIEnv *env, jlong ptr, Function &&func, jobject key = nullptr) { 9 | auto r_it = reinterpret_cast(ptr); 10 | const char* ckey = (key ? reinterpret_cast(env->GetDirectBufferAddress(key)) : nullptr); 11 | pmem::kv::status status = func(r_it, ckey); 12 | 13 | if (status == pmem::kv::status::OK || status == pmem::kv::status::NOT_FOUND) { 14 | return status == pmem::kv::status::OK; 15 | } 16 | PmemkvJavaException(env).ThrowException(status); 17 | return false; 18 | } 19 | 20 | /* Helper function for key() and value() methods */ 21 | template 22 | jobject boilerplate_access(JNIEnv *env, jlong ptr, Function &&func) { 23 | auto r_it = reinterpret_cast(ptr); 24 | pmem::kv::result res = func(r_it); 25 | 26 | if (res.is_ok()) { 27 | auto &key = res.get_value(); 28 | auto key_jbuffer = env->NewDirectByteBuffer(const_cast(key.data()), key.size()); 29 | if (env->ExceptionCheck() == JNI_TRUE) 30 | return nullptr; // Propagate exception 31 | return key_jbuffer; 32 | } 33 | 34 | PmemkvJavaException(env).ThrowException(res.get_status()); 35 | return nullptr; 36 | } 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | /* 42 | * Class: io_pmem_pmemkv_Database_ReadIterator 43 | * Method: iterator_new_read_iterator 44 | * Signature: (J)J 45 | */ 46 | JNIEXPORT jlong JNICALL 47 | Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1new_1read_1iterator(JNIEnv *env, jobject, jlong db_pointer) { 48 | auto engine = reinterpret_cast(db_pointer); 49 | pmem::kv::result res = engine->new_read_iterator(); 50 | 51 | if (res.is_ok()) { 52 | pmem::kv::db::read_iterator &r_it = res.get_value(); 53 | pmem::kv::db::read_iterator *ptr = new pmem::kv::db::read_iterator(std::move(r_it)); 54 | return reinterpret_cast(ptr); 55 | } else { 56 | PmemkvJavaException(env).ThrowException(res.get_status()); 57 | } 58 | return 0; 59 | } 60 | 61 | /* 62 | * Class: io_pmem_pmemkv_Database_ReadIterator 63 | * Method: iterator_seek 64 | * Signature: (JLjava/nio/ByteBuffer;)Z 65 | */ 66 | JNIEXPORT jboolean JNICALL Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1seek 67 | (JNIEnv *env, jobject, jlong ptr, jobject key) { 68 | return boilerplate_seek(env, ptr, [](pmem::kv::db::read_iterator *r_it, const char* ckey) { 69 | return r_it->seek(ckey); 70 | }, key); 71 | } 72 | 73 | /* 74 | * Class: io_pmem_pmemkv_Database_ReadIterator 75 | * Method: iterator_seek_lower 76 | * Signature: (JLjava/nio/ByteBuffer;)Z 77 | */ 78 | JNIEXPORT jboolean JNICALL Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1seek_1lower 79 | (JNIEnv *env, jobject, jlong ptr, jobject key) { 80 | return boilerplate_seek(env, ptr, [](pmem::kv::db::read_iterator *r_it, const char* ckey) { 81 | return r_it->seek_lower(ckey); 82 | }, key); 83 | } 84 | 85 | /* 86 | * Class: io_pmem_pmemkv_Database_ReadIterator 87 | * Method: iterator_seek_lower_eq 88 | * Signature: (JLjava/nio/ByteBuffer;)Z 89 | */ 90 | JNIEXPORT jboolean JNICALL Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1seek_1lower_1eq 91 | (JNIEnv *env, jobject, jlong ptr, jobject key) { 92 | return boilerplate_seek(env, ptr, [](pmem::kv::db::read_iterator *r_it, const char* ckey) { 93 | return r_it->seek_lower_eq(ckey); 94 | }, key); 95 | } 96 | 97 | /* 98 | * Class: io_pmem_pmemkv_Database_ReadIterator 99 | * Method: iterator_seek_higher 100 | * Signature: (JLjava/nio/ByteBuffer;)Z 101 | */ 102 | JNIEXPORT jboolean JNICALL Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1seek_1higher 103 | (JNIEnv *env, jobject, jlong ptr, jobject key) { 104 | return boilerplate_seek(env, ptr, [](pmem::kv::db::read_iterator *r_it, const char* ckey) { 105 | return r_it->seek_higher(ckey); 106 | }, key); 107 | } 108 | 109 | /* 110 | * Class: io_pmem_pmemkv_Database_ReadIterator 111 | * Method: iterator_seek_higher_eq 112 | * Signature: (JLjava/nio/ByteBuffer;)Z 113 | */ 114 | JNIEXPORT jboolean JNICALL Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1seek_1higher_1eq 115 | (JNIEnv *env, jobject, jlong ptr, jobject key) { 116 | return boilerplate_seek(env, ptr, [](pmem::kv::db::read_iterator *r_it, const char* ckey) { 117 | return r_it->seek_higher_eq(ckey); 118 | }, key); 119 | } 120 | 121 | /* 122 | * Class: io_pmem_pmemkv_Database_ReadIterator 123 | * Method: iterator_seek_to_first 124 | * Signature: (J)Z 125 | */ 126 | JNIEXPORT jboolean JNICALL Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1seek_1to_1first 127 | (JNIEnv *env, jobject, jlong ptr) { 128 | return boilerplate_seek(env, ptr, [](pmem::kv::db::read_iterator *r_it, const char* ckey) { 129 | return r_it->seek_to_first(); 130 | }); 131 | } 132 | 133 | /* 134 | * Class: io_pmem_pmemkv_Database_ReadIterator 135 | * Method: iterator_seek_to_last 136 | * Signature: (J)Z 137 | */ 138 | JNIEXPORT jboolean JNICALL Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1seek_1to_1last 139 | (JNIEnv *env, jobject, jlong ptr) { 140 | return boilerplate_seek(env, ptr, [](pmem::kv::db::read_iterator *r_it, const char* ckey) { 141 | return r_it->seek_to_last(); 142 | }); 143 | } 144 | 145 | /* 146 | * Class: io_pmem_pmemkv_Database_ReadIterator 147 | * Method: iterator_is_next 148 | * Signature: (J)Z 149 | */ 150 | JNIEXPORT jboolean JNICALL Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1is_1next 151 | (JNIEnv *env, jobject, jlong ptr) { 152 | return boilerplate_seek(env, ptr, [](pmem::kv::db::read_iterator *r_it, const char* ckey) { 153 | return r_it->is_next(); 154 | }); 155 | } 156 | 157 | /* 158 | * Class: io_pmem_pmemkv_Database_ReadIterator 159 | * Method: iterator_next 160 | * Signature: (J)Z 161 | */ 162 | JNIEXPORT jboolean JNICALL Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1next 163 | (JNIEnv *env, jobject, jlong ptr) { 164 | return boilerplate_seek(env, ptr, [](pmem::kv::db::read_iterator *r_it, const char* ckey) { 165 | return r_it->next(); 166 | }); 167 | } 168 | 169 | /* 170 | * Class: io_pmem_pmemkv_Database_ReadIterator 171 | * Method: iterator_prev 172 | * Signature: (J)Z 173 | */ 174 | JNIEXPORT jboolean JNICALL Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1prev 175 | (JNIEnv *env, jobject, jlong ptr) { 176 | return boilerplate_seek(env, ptr, [](pmem::kv::db::read_iterator *r_it, const char* ckey) { 177 | return r_it->prev(); 178 | }); 179 | } 180 | 181 | /* 182 | * Class: io_pmem_pmemkv_Database_ReadIterator 183 | * Method: iterator_key 184 | * Signature: (J)Ljava/nio/ByteBuffer; 185 | */ 186 | JNIEXPORT jobject JNICALL Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1key 187 | (JNIEnv *env, jobject, jlong ptr) { 188 | return boilerplate_access(env, ptr, [](pmem::kv::db::read_iterator *r_it) { 189 | return r_it->key(); 190 | }); 191 | } 192 | 193 | /* 194 | * Class: io_pmem_pmemkv_Database_ReadIterator 195 | * Method: iterator_value 196 | * Signature: (J)Ljava/nio/ByteBuffer; 197 | */ 198 | JNIEXPORT jobject JNICALL Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1value 199 | (JNIEnv *env, jobject, jlong ptr) { 200 | return boilerplate_access(env, ptr, [](pmem::kv::db::read_iterator *r_it) { 201 | return r_it->read_range(); 202 | }); 203 | } 204 | 205 | /* 206 | * Class: io_pmem_pmemkv_Database_ReadIterator 207 | * Method: iterator_close 208 | * Signature: (J)V 209 | */ 210 | JNIEXPORT void JNICALL Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1close 211 | (JNIEnv *, jobject, jlong ptr) { 212 | auto r_it = reinterpret_cast(ptr); 213 | delete r_it; 214 | } 215 | 216 | #ifdef __cplusplus 217 | } 218 | #endif 219 | -------------------------------------------------------------------------------- /jni-binding/libpmemkv_jni.map: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright 2020-2021, Intel Corporation 3 | # 4 | # 5 | # libpmemkv-jni.map -- linker map file for libpmemkv-jni 6 | # 7 | LIBPMEMKV_JNI_1.0 { 8 | global: 9 | Java_io_pmem_pmemkv_Database_database_1start; 10 | Java_io_pmem_pmemkv_Database_database_1stop; 11 | Java_io_pmem_pmemkv_Database_database_1get_1keys_1buffer; 12 | Java_io_pmem_pmemkv_Database_database_1get_1keys_1above_1buffer; 13 | Java_io_pmem_pmemkv_Database_database_1get_1keys_1below_1buffer; 14 | Java_io_pmem_pmemkv_Database_database_1get_1keys_1between_1buffer; 15 | Java_io_pmem_pmemkv_Database_database_1count_1all; 16 | Java_io_pmem_pmemkv_Database_database_1count_1above_1buffer; 17 | Java_io_pmem_pmemkv_Database_database_1count_1below_1buffer; 18 | Java_io_pmem_pmemkv_Database_database_1count_1between_1buffer; 19 | Java_io_pmem_pmemkv_Database_database_1get_1all_1buffer; 20 | Java_io_pmem_pmemkv_Database_database_1get_1above_1buffer; 21 | Java_io_pmem_pmemkv_Database_database_1get_1below_1buffer; 22 | Java_io_pmem_pmemkv_Database_database_1get_1between_1buffer; 23 | Java_io_pmem_pmemkv_Database_database_1exists_1buffer; 24 | Java_io_pmem_pmemkv_Database_database_1get_1buffer_1with_1callback; 25 | Java_io_pmem_pmemkv_Database_database_1get_1bytes; 26 | Java_io_pmem_pmemkv_Database_database_1put_1buffer; 27 | Java_io_pmem_pmemkv_Database_database_1remove_1buffer; 28 | Java_io_pmem_pmemkv_Database_00024Builder_config_1new; 29 | Java_io_pmem_pmemkv_Database_00024Builder_config_1delete; 30 | Java_io_pmem_pmemkv_Database_00024Builder_config_1from_1json; 31 | Java_io_pmem_pmemkv_Database_00024Builder_config_1put_1int; 32 | Java_io_pmem_pmemkv_Database_00024Builder_config_1put_1string; 33 | Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1new_1read_1iterator; 34 | Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1seek_1to_1first; 35 | Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1seek_1to_1last; 36 | Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1seek; 37 | Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1seek_1lower; 38 | Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1seek_1lower_1eq; 39 | Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1seek_1higher; 40 | Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1seek_1higher_1eq; 41 | Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1is_1next; 42 | Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1next; 43 | Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1prev; 44 | Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1key; 45 | Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1value; 46 | Java_io_pmem_pmemkv_Database_00024ReadIterator_iterator_1close; 47 | local: 48 | *; 49 | }; 50 | -------------------------------------------------------------------------------- /jni-binding/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | io.pmem 9 | pmemkv-root 10 | 1.2.0 11 | 12 | 13 | libpmemkv-jni 14 | JNI layer for pmemkv Java binding 15 | pmemkv-jni 16 | so 17 | 18 | 19 | 1 20 | ${project.parent.basedir} 21 | 22 | 23 | 24 | 25 | 26 | org.codehaus.mojo 27 | native-maven-plugin 28 | 1.0-alpha-11 29 | true 30 | 31 | ${project.packaging}.${soversion} 32 | ${project.packaging} 33 | ${basedir} 34 | 35 | 36 | . 37 | 38 | common.cpp 39 | io_pmem_pmemkv_Database.cpp 40 | io_pmem_pmemkv_Database_Builder.cpp 41 | io_pmem_pmemkv_Database_ReadIterator.cpp 42 | 43 | 44 | 45 | 46 | -I ${JAVA_HOME}/include/ 47 | -I ${JAVA_HOME}/include/linux/ 48 | 49 | 50 | -Wall 51 | -Werror 52 | -O3 53 | -fPIC 54 | -shared 55 | -std=gnu++11 56 | 57 | 58 | -shared 59 | -Wl,-soname,${project.artifactId}.${project.packaging}.${soversion} 60 | -Wl,--version-script,${basedir}/libpmemkv_jni.map 61 | -fPIC 62 | -O3 63 | 64 | 65 | -lpmemkv -lpmemkv_json_config 66 | 67 | 68 | 69 | 70 | org.apache.maven.plugins 71 | maven-antrun-plugin 72 | 1.8 73 | 74 | 75 | package 76 | 77 | 78 | 81 | 82 | 83 | 84 | run 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /pmemkv-binding/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | io.pmem 9 | pmemkv-root 10 | 1.2.0 11 | 12 | 13 | pmemkv 14 | Java code and main package for pmemkv Java binding 15 | pmemkv-binding 16 | jar 17 | 18 | 19 | ${project.parent.basedir} 20 | 21 | 22 | 23 | 24 | 25 | ../jni-binding/target/ 26 | 27 | libpmemkv-jni.so.1 28 | 29 | 30 | 31 | 32 | 33 | org.apache.maven.plugins 34 | maven-compiler-plugin 35 | 3.8.1 36 | 37 | true 38 | true 39 | 40 | -Xlint:all 41 | 42 | 43 | 44 | 45 | org.apache.maven.plugins 46 | maven-surefire-plugin 47 | 2.22.1 48 | 49 | false 50 | -Djava.library.path=../jni-binding/target/ -Dfile.encoding=UTF-8 51 | 52 | 53 | 54 | org.apache.maven.plugins 55 | maven-source-plugin 56 | 3.2.1 57 | 58 | 59 | attach-sources 60 | 61 | jar 62 | 63 | 64 | 65 | 66 | 67 | org.apache.maven.plugins 68 | maven-enforcer-plugin 69 | 3.0.0-M2 70 | 71 | 72 | enforce-property 73 | 74 | enforce 75 | 76 | 77 | 78 | 79 | test.db.dir 80 | Property test.db.dir was not set! Default test path "/dev/shm" will be used! 81 | 82 | 83 | false 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | junit 94 | junit 95 | [4.12,) 96 | test 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /pmemkv-binding/src/main/java/io/pmem/pmemkv/BuilderException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2020, Intel Corporation */ 3 | 4 | package io.pmem.pmemkv; 5 | 6 | /** 7 | * Pmemkv database configuration failed. 8 | *

9 | * It's not an equivalent to any of pmemkv's statuses per se, but it's a close 10 | * friend to CONFIG_* errors (it varies due to usage of Builder pattern). 11 | * 12 | * @see io.pmem.pmemkv.Database.Builder 13 | * @see Pmemkv 15 | * errors 16 | */ 17 | @SuppressWarnings("serial") 18 | public class BuilderException extends DatabaseException { 19 | 20 | public BuilderException(String message) { 21 | super(message); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /pmemkv-binding/src/main/java/io/pmem/pmemkv/ByteBufferConverter.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2020-2022, Intel Corporation */ 3 | 4 | package io.pmem.pmemkv; 5 | 6 | import java.nio.ByteBuffer; 7 | 8 | /** 9 | * Implementation of Converter interface for ByteBuffer type 10 | */ 11 | public class ByteBufferConverter implements Converter { 12 | public ByteBuffer toByteBuffer(ByteBuffer entry) { 13 | return entry; 14 | } 15 | 16 | public ByteBuffer fromByteBuffer(ByteBuffer entry) { 17 | return entry; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /pmemkv-binding/src/main/java/io/pmem/pmemkv/Converter.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2020-2021, Intel Corporation */ 3 | 4 | package io.pmem.pmemkv; 5 | 6 | import java.nio.ByteBuffer; 7 | 8 | /** 9 | * Helper interface, which provides functionality of storing objects of any type 10 | * as ByteBuffer inside the pmemkv datastore. 11 | * 12 | * This interface is mostly implemented for {@link io.pmem.pmemkv.Database 13 | * Database} class to use any, arbitrary type as a key and value. 14 | * 15 | * @param 16 | * the type of an object, which will be converted to ByteBuffer and 17 | * stored in the pmemkv datastore. 18 | */ 19 | public interface Converter { 20 | /** 21 | * Defines how object of type T will be converted to ByteBuffer and stored in 22 | * the pmemkv datastore. 23 | * 24 | * @param entry 25 | * Object of type T, which will be stored in the pmemkv datastore. 26 | * @return ByteBuffer representation of passed objects. 27 | */ 28 | public ByteBuffer toByteBuffer(T entry); 29 | 30 | /** 31 | * Defines how object stored in pmemkv will be converted from ByteBuffer back to 32 | * type T to be passed to the callback functions. 33 | * 34 | * @param entry 35 | * ByteBuffer stored in pmemkv. 36 | * @return Object of type T, which will be passed to the callback functions. 37 | */ 38 | public T fromByteBuffer(ByteBuffer entry); 39 | } 40 | -------------------------------------------------------------------------------- /pmemkv-binding/src/main/java/io/pmem/pmemkv/DatabaseException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2017-2020, Intel Corporation */ 3 | 4 | package io.pmem.pmemkv; 5 | 6 | /** 7 | * DatabaseException is the superclass of all exceptions that can be thrown when 8 | * handling pmemkv errors. 9 | * 10 | * @see Pmemkv 12 | * errors 13 | */ 14 | @SuppressWarnings("serial") 15 | public class DatabaseException extends RuntimeException { 16 | 17 | public DatabaseException(String message) { 18 | super(message); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /pmemkv-binding/src/main/java/io/pmem/pmemkv/InvalidArgumentException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2020, Intel Corporation */ 3 | 4 | package io.pmem.pmemkv; 5 | 6 | /** 7 | * Argument passed to the function has a wrong value. 8 | * 9 | * @see Pmemkv 11 | * errors 12 | */ 13 | @SuppressWarnings("serial") 14 | public class InvalidArgumentException extends DatabaseException { 15 | 16 | public InvalidArgumentException(String message) { 17 | super(message); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /pmemkv-binding/src/main/java/io/pmem/pmemkv/KeyCallback.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2017-2021, Intel Corporation */ 3 | 4 | package io.pmem.pmemkv; 5 | 6 | /** 7 | * Represents callback function, which handle key-only use cases. Such 8 | * expression may be passed to getKeys*() methods in 9 | * {@link io.pmem.pmemkv.Database Database} class. 10 | * 11 | * @param 12 | * the type of a key stored in the pmemkv database 13 | */ 14 | @FunctionalInterface 15 | public interface KeyCallback { 16 | /** 17 | * It's internally used as a middle layer to run callback function 18 | * 19 | * @param key 20 | * the key returned by pmemkv engine to callback function 21 | */ 22 | void process(KeyT key); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /pmemkv-binding/src/main/java/io/pmem/pmemkv/KeyValueCallback.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2017-2021, Intel Corporation */ 3 | 4 | package io.pmem.pmemkv; 5 | 6 | /** 7 | * Represents callback function, which handle key/value use cases. Such 8 | * expression may be passed to get*() methods in {@link io.pmem.pmemkv.Database 9 | * Database} class. 10 | * 11 | * @param 12 | * the type of a key stored in the pmemkv database 13 | * @param 14 | * the type of a value stored in the pmemkv database 15 | */ 16 | @FunctionalInterface 17 | public interface KeyValueCallback { 18 | /** 19 | * It's internally used as a middle layer to run callback function 20 | * 21 | * @param key 22 | * the key returned by pmemkv engine to the callback function 23 | * @param value 24 | * the value returned by pmemkv engine to the callback function 25 | */ 26 | void process(KeyT key, ValueT value); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /pmemkv-binding/src/main/java/io/pmem/pmemkv/NotFoundException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2020, Intel Corporation */ 3 | 4 | package io.pmem.pmemkv; 5 | 6 | /** 7 | * Database entry or config item not found. 8 | * 9 | * @see Pmemkv 11 | * errors 12 | */ 13 | @SuppressWarnings("serial") 14 | public class NotFoundException extends DatabaseException { 15 | 16 | public NotFoundException(String message) { 17 | super(message); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /pmemkv-binding/src/main/java/io/pmem/pmemkv/NotSupportedException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2020, Intel Corporation */ 3 | 4 | package io.pmem.pmemkv; 5 | 6 | /** 7 | * Function is not implemented by the current engine. 8 | * 9 | * @see Pmemkv 11 | * errors 12 | */ 13 | @SuppressWarnings("serial") 14 | public class NotSupportedException extends DatabaseException { 15 | 16 | public NotSupportedException(String message) { 17 | super(message); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /pmemkv-binding/src/main/java/io/pmem/pmemkv/OutOfMemoryException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2020, Intel Corporation */ 3 | 4 | package io.pmem.pmemkv; 5 | 6 | /** 7 | * Operation failed because there is not enough memory (or space on the device). 8 | * 9 | * @see Pmemkv 11 | * errors 12 | */ 13 | @SuppressWarnings("serial") 14 | public class OutOfMemoryException extends DatabaseException { 15 | 16 | public OutOfMemoryException(String message) { 17 | super(message); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /pmemkv-binding/src/main/java/io/pmem/pmemkv/StoppedByCallbackException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2020, Intel Corporation */ 3 | 4 | package io.pmem.pmemkv; 5 | 6 | /** 7 | * Callback function aborted. 8 | * 9 | * @see Pmemkv 11 | * errors 12 | */ 13 | @SuppressWarnings("serial") 14 | public class StoppedByCallbackException extends DatabaseException { 15 | 16 | public StoppedByCallbackException(String message) { 17 | super(message); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /pmemkv-binding/src/main/java/io/pmem/pmemkv/TransactionScopeException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2020, Intel Corporation */ 3 | 4 | package io.pmem.pmemkv; 5 | 6 | /** 7 | * An error with the scope of the libpmemobj transaction. 8 | *

9 | * This exception is defined for compatibility with pmemkv API and most probably 10 | * never occurs. 11 | * 12 | * @see Pmemkv 14 | * errors 15 | */ 16 | @SuppressWarnings("serial") 17 | public class TransactionScopeException extends DatabaseException { 18 | 19 | public TransactionScopeException(String message) { 20 | super(message); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /pmemkv-binding/src/main/java/io/pmem/pmemkv/ValueCallback.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2017-2021, Intel Corporation */ 3 | 4 | package io.pmem.pmemkv; 5 | 6 | /** 7 | * Represents callback function, which handle value-only use cases. Such 8 | * expression may be passed to get() method in {@link io.pmem.pmemkv.Database 9 | * Database} class. 10 | * 11 | * @param 12 | * the type of a key stored in the pmemkv database 13 | */ 14 | @FunctionalInterface 15 | public interface ValueCallback { 16 | /** 17 | * It's internally used as a middle layer to run callback function 18 | * 19 | * @param value 20 | * the value returned by pmemkv engine to the callback function 21 | */ 22 | void process(ValueT value); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /pmemkv-binding/src/main/java/io/pmem/pmemkv/WrongEngineNameException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2020-2022, Intel Corporation */ 3 | 4 | package io.pmem.pmemkv; 5 | 6 | /** 7 | * Engine name does not match any available engine. 8 | * 9 | * @see Pmemkv 11 | * errors 12 | * @see Currently 13 | * available pmemkv engines 14 | */ 15 | @SuppressWarnings("serial") 16 | public class WrongEngineNameException extends DatabaseException { 17 | 18 | public WrongEngineNameException(String message) { 19 | super(message); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /pmemkv-binding/src/main/resources/version.properties: -------------------------------------------------------------------------------- 1 | version=${project.version} 2 | -------------------------------------------------------------------------------- /pmemkv-binding/src/test/java/io/pmem/pmemkv/CmapTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2020-2021, Intel Corporation */ 3 | 4 | package io.pmem.pmemkv; 5 | 6 | import java.util.Map; 7 | import java.util.TreeMap; 8 | import org.junit.Assert; 9 | import org.junit.Before; 10 | import org.junit.Rule; 11 | import org.junit.Test; 12 | import org.junit.rules.TemporaryFolder; 13 | import static org.junit.Assert.*; 14 | 15 | import java.io.File; 16 | import java.nio.ByteBuffer; 17 | 18 | import static io.pmem.pmemkv.TestUtils.*; 19 | 20 | public class CmapTest { 21 | 22 | private final String ENGINE = "cmap"; 23 | private String DB_PATH = ""; 24 | 25 | @Rule 26 | public TemporaryFolder testDir = new TemporaryFolder(DEFAULT_DB_DIR); 27 | 28 | @Before 29 | public void init() { 30 | DB_PATH = testDir.getRoot() + File.separator + "testfile"; 31 | assertTrue(DB_PATH != null && !DB_PATH.isEmpty()); 32 | } 33 | 34 | @Test 35 | public void testCreateAndOpen() { 36 | Database db = createDB(ENGINE, DB_PATH, new ByteBufferConverter()); 37 | assertNotNull(db); 38 | assertFalse(db.stopped()); 39 | 40 | assertFalse(db.exists(stringToByteBuffer("key1"))); 41 | db.put(stringToByteBuffer("key1"), stringToByteBuffer("value1")); 42 | assertTrue(db.exists(stringToByteBuffer("key1"))); 43 | ByteBuffer resBuff = db.getCopy(stringToByteBuffer("key1")); 44 | assertEquals(byteBufferToString(resBuff), "value1"); 45 | 46 | db.stop(); 47 | assertTrue(db.stopped()); 48 | 49 | db = openDB(ENGINE, DB_PATH, new ByteBufferConverter()); 50 | assertNotNull(db); 51 | assertFalse(db.stopped()); 52 | assertTrue(db.exists(stringToByteBuffer("key1"))); 53 | resBuff = db.getCopy(stringToByteBuffer("key1")); 54 | assertEquals(byteBufferToString(resBuff), "value1"); 55 | } 56 | 57 | @Test 58 | public void throwsExceptionOnStartWhenOpeningNonExistentFile() { 59 | Database db = null; 60 | 61 | try { 62 | db = openDB(ENGINE, DB_PATH, new ByteBufferConverter()); 63 | Assert.fail(); 64 | } catch (DatabaseException e) { 65 | /* file doesn't exist, open should throw */ 66 | } 67 | 68 | assertNull(db); 69 | } 70 | 71 | @Test 72 | public void createDBFromJson() { 73 | String json = "{\"path\":\"" + DB_PATH + "\", \"size\":" + DEFAULT_DB_SIZE + ", \"force_create\":1}"; 74 | Database db = openDBFromJson(ENGINE, json, new ByteBufferConverter()); 75 | assertNotNull(db); 76 | assertFalse(db.stopped()); 77 | db.stop(); 78 | } 79 | 80 | @Test 81 | public void throwsOnStartWhenOpeningFromJsonNonExistentFile() { 82 | Exception exception = assertThrows(DatabaseException.class, () -> { 83 | /* force_create set to 0 */ 84 | String json = "{\"path\":\"" + DB_PATH + "\", \"size\":" + DEFAULT_DB_SIZE + ", \"force_create\":0}"; 85 | Database db = openDBFromJson(ENGINE, json, new ByteBufferConverter()); 86 | 87 | /* 88 | * It's not a valid path (it's not created), so it should be 89 | * InvalidArgumentException, but: https://github.com/pmem/pmemkv/issues/565 90 | */ 91 | }); 92 | assertTrue(exception.getMessage().length() > 0); 93 | } 94 | 95 | @Test 96 | public void throwsExceptionOnSortedCountFuncs() { 97 | Database db = createDB(ENGINE, DB_PATH, new ByteBufferConverter()); 98 | ByteBuffer key1 = stringToByteBuffer("key1"); 99 | ByteBuffer key2 = stringToByteBuffer("key2"); 100 | 101 | try { 102 | db.countAbove(key1); 103 | Assert.fail(); 104 | } catch (DatabaseException e) { 105 | /* countAbove for unsorted engines should throw NotSupported */ 106 | } 107 | 108 | try { 109 | db.countBelow(key1); 110 | Assert.fail(); 111 | } catch (DatabaseException e) { 112 | /* countBelow for unsorted engines should throw NotSupported */ 113 | } 114 | 115 | try { 116 | db.countBetween(key1, key2); 117 | Assert.fail(); 118 | } catch (DatabaseException e) { 119 | /* countBetween for unsorted engines should throw NotSupported */ 120 | } 121 | 122 | db.stop(); 123 | } 124 | 125 | /* Test the DB on multiple threads */ 126 | @Test 127 | public void multipleThreadsDBTest() { 128 | final int threadsNumber = 8; 129 | final int numberOfElements = 100; 130 | 131 | final Database db = createDB(ENGINE, DB_PATH, new ByteBufferConverter()); 132 | 133 | runParallel(threadsNumber, () -> { 134 | for (int j = 0; j < numberOfElements; ++j) { 135 | final int x = j; 136 | db.put(stringToByteBuffer(Integer.toString(x)), 137 | stringToByteBuffer(Integer.toString(x + 1))); 138 | } 139 | }); 140 | 141 | runParallel(threadsNumber, () -> { 142 | for (int j = 0; j < numberOfElements; ++j) { 143 | final int x = j; 144 | assertTrue(db.exists(stringToByteBuffer(Integer.toString(x)))); 145 | } 146 | }); 147 | 148 | runParallel(threadsNumber, () -> { 149 | for (int j = numberOfElements - 1; j >= 0; --j) { 150 | final int x = j; 151 | db.get(stringToByteBuffer(Integer.toString(x)), (ByteBuffer v) -> { 152 | assertEquals(byteBufferToString(v), Integer.toString(x + 1)); 153 | }); 154 | } 155 | }); 156 | 157 | db.stop(); 158 | } 159 | 160 | /* Use 2 different DBs simultaneously. */ 161 | @Test 162 | public void multipleDBTypesTest() { 163 | final int threadsNumber = 8; 164 | final int numberOfElements = 200; 165 | 166 | String file1 = DB_PATH + "1"; 167 | final Database dbString = createDB(ENGINE, file1, new StringConverter(), 190, 190); 168 | final StringBuilder sb = new StringBuilder(numberOfElements + 1); 169 | sb.append('x'); 170 | for (int i = 0; i < numberOfElements; ++i) { 171 | sb.append('x'); 172 | dbString.put(sb.substring(0, i), sb.substring(0, i + 1)); 173 | } 174 | 175 | String file2 = DB_PATH + "2"; 176 | final Database dbByteBuffer = createDB(ENGINE, file2, new ByteBufferConverter(), 180, 177 | 180); 178 | for (int i = 0; i < numberOfElements; ++i) { 179 | dbByteBuffer.put(stringToByteBuffer(sb.substring(0, i)), stringToByteBuffer(sb.substring(0, i + 1))); 180 | } 181 | 182 | runParallel(threadsNumber, () -> { 183 | for (int j = 0; j < numberOfElements; ++j) { 184 | final int x = j; 185 | dbString.get(sb.substring(0, x), (String v) -> { 186 | assertEquals(v, sb.substring(0, x + 1)); 187 | }); 188 | } 189 | }, () -> { 190 | for (int j = 0; j < numberOfElements; ++j) { 191 | final int x = j; 192 | dbByteBuffer.get(stringToByteBuffer(sb.substring(0, x)), (ByteBuffer v) -> { 193 | assertEquals(byteBufferToString(v), sb.substring(0, x + 1)); 194 | }); 195 | } 196 | }); 197 | dbByteBuffer.stop(); 198 | dbString.stop(); 199 | } 200 | 201 | /* unsorted engine should not implement lower/higher methods */ 202 | @Test 203 | public void testIteratorExceptionWithCmap() { 204 | Database db = createDB(ENGINE, DB_PATH, new ByteBufferConverter()); 205 | 206 | Database.ReadIterator it = db.readIterator(); 207 | assertThrows(NotSupportedException.class, () -> { 208 | it.seekHigher(stringToByteBuffer("key")); 209 | assertTrue(false); 210 | }); 211 | assertThrows(NotSupportedException.class, () -> { 212 | it.seekLower(stringToByteBuffer("key")); 213 | assertTrue(false); 214 | }); 215 | assertThrows(NotSupportedException.class, () -> { 216 | it.seekLowerEq(stringToByteBuffer("key")); 217 | assertTrue(false); 218 | }); 219 | assertThrows(NotSupportedException.class, () -> { 220 | it.seekHigherEq(stringToByteBuffer("key")); 221 | assertTrue(false); 222 | }); 223 | it.close(); 224 | db.stop(); 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /pmemkv-binding/src/test/java/io/pmem/pmemkv/DatabaseIteratorTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2021, Intel Corporation */ 3 | 4 | package io.pmem.pmemkv; 5 | 6 | import java.nio.ByteBuffer; 7 | import java.util.Map; 8 | import java.util.TreeMap; 9 | import org.junit.Before; 10 | import org.junit.Rule; 11 | import org.junit.Test; 12 | import org.junit.rules.TemporaryFolder; 13 | 14 | import static org.junit.Assert.*; 15 | 16 | public class DatabaseIteratorTest { 17 | 18 | private final String ENGINE = "vsmap"; 19 | private String DB_DIR = ""; 20 | 21 | /* Helper methods, used in most of the tests in this file */ 22 | private Database buildDB(String engine) { 23 | Database db = TestUtils.openDB(engine, DB_DIR, new ByteBufferConverter()); 24 | assertNotNull(db); 25 | assertFalse(db.stopped()); 26 | return db; 27 | } 28 | 29 | private TreeMap buildHashMapWithGaps(int size) { 30 | TreeMap hs = new TreeMap(); 31 | int seed = 4; 32 | for (int i = 0; i < size; i++) { 33 | if (i % seed == 0) 34 | continue; 35 | hs.put("key" + i, "value" + i); 36 | } 37 | return hs; 38 | } 39 | 40 | @Rule 41 | public TemporaryFolder testDir = new TemporaryFolder(TestUtils.DEFAULT_DB_DIR); 42 | 43 | @Before 44 | public void init() { 45 | DB_DIR = testDir.getRoot().toString(); 46 | assertTrue(DB_DIR != null && !DB_DIR.isEmpty()); 47 | } 48 | 49 | /* 50 | * XXX: change ByteBufferConverter to StringConverter to avoid conversion 51 | * outside converter 52 | */ 53 | @Test 54 | public void readFirstEntryTest() { 55 | Database db = buildDB(ENGINE); 56 | assertFalse(db.exists(TestUtils.stringToByteBuffer("key1"))); 57 | 58 | db.put(TestUtils.stringToByteBuffer("key1"), TestUtils.stringToByteBuffer("value1")); 59 | assertTrue(db.exists(TestUtils.stringToByteBuffer("key1"))); 60 | try (Database.ReadIterator it = db.readIterator()) { 61 | assertNotNull(it); 62 | assertTrue(it.seekToFirst()); 63 | assertTrue(TestUtils.byteBufferToString(it.key()).equals("key1")); 64 | assertTrue(TestUtils.byteBufferToString(it.value()).equals("value1")); 65 | assertFalse(it.isNext()); 66 | } 67 | db.stop(); 68 | assertTrue(db.stopped()); 69 | } 70 | @Test 71 | public void readAllEntriesTest() { 72 | TreeMap hs = buildHashMapWithGaps(1024); 73 | Database db = buildDB(ENGINE); 74 | assertFalse(db.exists(TestUtils.stringToByteBuffer("key1"))); 75 | 76 | for (Map.Entry entry : hs.entrySet()) { 77 | db.put(TestUtils.stringToByteBuffer(entry.getKey()), TestUtils.stringToByteBuffer(entry.getValue())); 78 | } 79 | 80 | try (Database.ReadIterator it = db.readIterator()) { 81 | assertNotNull(it); 82 | assertTrue(it.seekToFirst()); 83 | assertTrue(it.isNext()); 84 | int counter = 1; 85 | while (it.isNext()) { 86 | counter++; 87 | String key = TestUtils.byteBufferToString(it.key()); 88 | String value = TestUtils.byteBufferToString(it.value()); 89 | /* key and value should have the same last character */ 90 | assertTrue(key.substring(key.length() - 1).equals(value.substring(value.length() - 1))); 91 | assertTrue(it.next()); 92 | } 93 | assertTrue(counter == hs.size()); 94 | } 95 | db.stop(); 96 | } 97 | 98 | @Test 99 | public void seekAndReadKeyTest() { 100 | TreeMap hs = buildHashMapWithGaps(10); 101 | Database db = buildDB(ENGINE); 102 | 103 | for (Map.Entry entry : hs.entrySet()) { 104 | db.put(TestUtils.stringToByteBuffer(entry.getKey()), TestUtils.stringToByteBuffer(entry.getValue())); 105 | } 106 | 107 | try (Database.ReadIterator it = db.readIterator()) { 108 | assertTrue(it.seek(TestUtils.stringToByteBuffer("key3"))); 109 | assertTrue(TestUtils.byteBufferToString(it.key()).equals("key3")); 110 | assertTrue(TestUtils.byteBufferToString(it.value()).equals("value3")); 111 | while (it.isNext()) { 112 | assertTrue(it.next()); 113 | assertTrue(hs.containsKey(TestUtils.byteBufferToString(it.key()))); 114 | } 115 | } 116 | db.stop(); 117 | } 118 | 119 | @Test 120 | public void seekFailTest() { 121 | TreeMap hs = buildHashMapWithGaps(10); 122 | Database db = buildDB(ENGINE); 123 | 124 | for (Map.Entry entry : hs.entrySet()) { 125 | db.put(TestUtils.stringToByteBuffer(entry.getKey()), TestUtils.stringToByteBuffer(entry.getValue())); 126 | } 127 | 128 | try (Database.ReadIterator it = db.readIterator()) { 129 | assertFalse(it.seek(TestUtils.stringToByteBuffer("nope"))); 130 | } 131 | db.stop(); 132 | } 133 | 134 | @Test 135 | public void seekLowerAndReadKeyTest() { 136 | TreeMap hs = buildHashMapWithGaps(10); 137 | Database db = buildDB(ENGINE); 138 | 139 | for (Map.Entry entry : hs.entrySet()) { 140 | db.put(TestUtils.stringToByteBuffer(entry.getKey()), TestUtils.stringToByteBuffer(entry.getValue())); 141 | } 142 | 143 | try (Database.ReadIterator it = db.readIterator()) { 144 | assertTrue(it.seekLower(TestUtils.stringToByteBuffer("key3"))); 145 | assertTrue(TestUtils.byteBufferToString(it.key()).equals("key2")); 146 | assertTrue(TestUtils.byteBufferToString(it.value()).equals("value2")); 147 | while (it.isNext()) { 148 | assertTrue(it.next()); 149 | assertTrue(hs.containsKey(TestUtils.byteBufferToString(it.key()))); 150 | } 151 | } 152 | db.stop(); 153 | } 154 | 155 | @Test 156 | public void seekLowerFailTest() { 157 | TreeMap hs = buildHashMapWithGaps(10); 158 | Database db = buildDB(ENGINE); 159 | 160 | for (Map.Entry entry : hs.entrySet()) { 161 | db.put(TestUtils.stringToByteBuffer(entry.getKey()), TestUtils.stringToByteBuffer(entry.getValue())); 162 | } 163 | 164 | try (Database.ReadIterator it = db.readIterator()) { 165 | assertFalse(it.seekLower(TestUtils.stringToByteBuffer("key0"))); 166 | } 167 | db.stop(); 168 | } 169 | 170 | @Test 171 | public void seekLowerEqAndReadKeyTest() { 172 | TreeMap hs = buildHashMapWithGaps(10); 173 | Database db = buildDB(ENGINE); 174 | 175 | for (Map.Entry entry : hs.entrySet()) { 176 | db.put(TestUtils.stringToByteBuffer(entry.getKey()), TestUtils.stringToByteBuffer(entry.getValue())); 177 | } 178 | 179 | try (Database.ReadIterator it = db.readIterator()) { 180 | assertTrue(it.seekLowerEq(TestUtils.stringToByteBuffer("key4"))); 181 | assertTrue(TestUtils.byteBufferToString(it.key()).equals("key3")); 182 | assertTrue(TestUtils.byteBufferToString(it.value()).equals("value3")); 183 | while (it.isNext()) { 184 | assertTrue(it.next()); 185 | assertTrue(hs.containsKey(TestUtils.byteBufferToString(it.key()))); 186 | } 187 | } 188 | db.stop(); 189 | } 190 | 191 | @Test 192 | public void seekLowerEqWhenExistsAndReadKeyTest() { 193 | TreeMap hs = buildHashMapWithGaps(10); 194 | Database db = buildDB(ENGINE); 195 | 196 | for (Map.Entry entry : hs.entrySet()) { 197 | db.put(TestUtils.stringToByteBuffer(entry.getKey()), TestUtils.stringToByteBuffer(entry.getValue())); 198 | } 199 | 200 | try (Database.ReadIterator it = db.readIterator()) { 201 | assertTrue(it.seekLowerEq(TestUtils.stringToByteBuffer("key3"))); 202 | assertTrue(TestUtils.byteBufferToString(it.key()).equals("key3")); 203 | assertTrue(TestUtils.byteBufferToString(it.value()).equals("value3")); 204 | while (it.isNext()) { 205 | assertTrue(it.next()); 206 | assertTrue(hs.containsKey(TestUtils.byteBufferToString(it.key()))); 207 | } 208 | } 209 | db.stop(); 210 | } 211 | 212 | @Test 213 | public void seekHigherAndReadKeyTest() { 214 | TreeMap hs = buildHashMapWithGaps(10); 215 | Database db = buildDB(ENGINE); 216 | 217 | for (Map.Entry entry : hs.entrySet()) { 218 | db.put(TestUtils.stringToByteBuffer(entry.getKey()), TestUtils.stringToByteBuffer(entry.getValue())); 219 | } 220 | 221 | try (Database.ReadIterator it = db.readIterator()) { 222 | assertTrue(it.seekHigher(TestUtils.stringToByteBuffer("key3"))); 223 | assertTrue(TestUtils.byteBufferToString(it.key()).equals("key5")); 224 | assertTrue(TestUtils.byteBufferToString(it.value()).equals("value5")); 225 | while (it.isNext()) { 226 | assertTrue(it.next()); 227 | assertTrue(hs.containsKey(TestUtils.byteBufferToString(it.key()))); 228 | } 229 | } 230 | db.stop(); 231 | } 232 | 233 | @Test 234 | public void seekHigherFailTest() { 235 | TreeMap hs = buildHashMapWithGaps(10); 236 | Database db = buildDB(ENGINE); 237 | 238 | for (Map.Entry entry : hs.entrySet()) { 239 | db.put(TestUtils.stringToByteBuffer(entry.getKey()), TestUtils.stringToByteBuffer(entry.getValue())); 240 | } 241 | 242 | try (Database.ReadIterator it = db.readIterator()) { 243 | assertFalse(it.seekHigher(TestUtils.stringToByteBuffer("key9"))); 244 | } 245 | db.stop(); 246 | } 247 | 248 | @Test 249 | public void seekHigherEqAndReadKeyTest() { 250 | TreeMap hs = buildHashMapWithGaps(10); 251 | Database db = buildDB(ENGINE); 252 | 253 | for (Map.Entry entry : hs.entrySet()) { 254 | db.put(TestUtils.stringToByteBuffer(entry.getKey()), TestUtils.stringToByteBuffer(entry.getValue())); 255 | } 256 | 257 | try (Database.ReadIterator it = db.readIterator()) { 258 | assertTrue(it.seekHigherEq(TestUtils.stringToByteBuffer("key4"))); 259 | assertTrue(TestUtils.byteBufferToString(it.key()).equals("key5")); 260 | assertTrue(TestUtils.byteBufferToString(it.value()).equals("value5")); 261 | while (it.isNext()) { 262 | assertTrue(it.next()); 263 | assertTrue(hs.containsKey(TestUtils.byteBufferToString(it.key()))); 264 | } 265 | } 266 | db.stop(); 267 | } 268 | 269 | @Test 270 | public void seekHigherEqWhenExistsAndReadKeyTest() { 271 | TreeMap hs = buildHashMapWithGaps(10); 272 | Database db = buildDB(ENGINE); 273 | 274 | for (Map.Entry entry : hs.entrySet()) { 275 | db.put(TestUtils.stringToByteBuffer(entry.getKey()), TestUtils.stringToByteBuffer(entry.getValue())); 276 | } 277 | 278 | try (Database.ReadIterator it = db.readIterator()) { 279 | assertTrue(it.seekHigherEq(TestUtils.stringToByteBuffer("key3"))); 280 | assertTrue(TestUtils.byteBufferToString(it.key()).equals("key3")); 281 | assertTrue(TestUtils.byteBufferToString(it.value()).equals("value3")); 282 | while (it.isNext()) { 283 | assertTrue(it.next()); 284 | assertTrue(hs.containsKey(TestUtils.byteBufferToString(it.key()))); 285 | } 286 | } 287 | db.stop(); 288 | } 289 | 290 | @Test 291 | public void variousSeekTest() { 292 | TreeMap hs = buildHashMapWithGaps(10); 293 | Database db = buildDB(ENGINE); 294 | 295 | for (Map.Entry entry : hs.entrySet()) { 296 | db.put(TestUtils.stringToByteBuffer(entry.getKey()), TestUtils.stringToByteBuffer(entry.getValue())); 297 | } 298 | 299 | try (Database.ReadIterator it = db.readIterator()) { 300 | assertTrue(it.seekToLast()); 301 | assertTrue(TestUtils.byteBufferToString(it.key()).equals("key9")); 302 | assertTrue(TestUtils.byteBufferToString(it.value()).equals("value9")); 303 | assertFalse(it.isNext()); 304 | 305 | assertTrue(it.seekToFirst()); 306 | assertTrue(TestUtils.byteBufferToString(it.key()).equals("key1")); 307 | assertTrue(TestUtils.byteBufferToString(it.value()).equals("value1")); 308 | 309 | assertTrue(it.seekHigherEq(TestUtils.stringToByteBuffer("key3"))); 310 | assertTrue(TestUtils.byteBufferToString(it.key()).equals("key3")); 311 | assertTrue(TestUtils.byteBufferToString(it.value()).equals("value3")); 312 | 313 | assertTrue(it.seekHigherEq(TestUtils.stringToByteBuffer("key4"))); 314 | assertTrue(TestUtils.byteBufferToString(it.key()).equals("key5")); 315 | assertTrue(TestUtils.byteBufferToString(it.value()).equals("value5")); 316 | 317 | assertTrue(it.seekLowerEq(TestUtils.stringToByteBuffer("key8"))); 318 | assertTrue(TestUtils.byteBufferToString(it.key()).equals("key7")); 319 | assertTrue(TestUtils.byteBufferToString(it.value()).equals("value7")); 320 | 321 | assertTrue(it.seekHigher(TestUtils.stringToByteBuffer("key0"))); 322 | assertTrue(TestUtils.byteBufferToString(it.key()).equals("key1")); 323 | assertTrue(TestUtils.byteBufferToString(it.value()).equals("value1")); 324 | 325 | assertTrue(it.seekLower(TestUtils.stringToByteBuffer("key99"))); 326 | assertTrue(TestUtils.byteBufferToString(it.key()).equals("key9")); 327 | assertTrue(TestUtils.byteBufferToString(it.value()).equals("value9")); 328 | 329 | assertTrue(it.seekLowerEq(TestUtils.stringToByteBuffer("key10"))); 330 | assertTrue(TestUtils.byteBufferToString(it.key()).equals("key1")); 331 | assertTrue(TestUtils.byteBufferToString(it.value()).equals("value1")); 332 | 333 | assertTrue(it.seekToFirst()); 334 | assertTrue(TestUtils.byteBufferToString(it.key()).equals("key1")); 335 | assertTrue(TestUtils.byteBufferToString(it.value()).equals("value1")); 336 | assertTrue(it.isNext()); 337 | } 338 | db.stop(); 339 | } 340 | } 341 | -------------------------------------------------------------------------------- /pmemkv-binding/src/test/java/io/pmem/pmemkv/DatabaseTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2017-2021, Intel Corporation */ 3 | 4 | package io.pmem.pmemkv; 5 | 6 | import java.nio.ByteBuffer; 7 | import java.util.concurrent.atomic.AtomicInteger; 8 | import org.junit.Before; 9 | import org.junit.Rule; 10 | import org.junit.Test; 11 | import org.junit.rules.TemporaryFolder; 12 | 13 | import static io.pmem.pmemkv.TestUtils.*; 14 | import static java.nio.charset.StandardCharsets.UTF_8; 15 | import static org.junit.Assert.*; 16 | 17 | public class DatabaseTest { 18 | 19 | private final String ENGINE = "vsmap"; 20 | private String DB_DIR = ""; 21 | 22 | /* Helper method, used in most of the tests in this file */ 23 | private Database buildDB(String engine) { 24 | return openDB(engine, DB_DIR, new ByteBufferConverter()); 25 | } 26 | 27 | @Rule 28 | public TemporaryFolder testDir = new TemporaryFolder(DEFAULT_DB_DIR); 29 | 30 | @Before 31 | public void init() { 32 | DB_DIR = testDir.getRoot().toString(); 33 | assertTrue(DB_DIR != null && !DB_DIR.isEmpty()); 34 | } 35 | 36 | @Test 37 | public void blackholeTest() { 38 | Database db = buildDB("blackhole"); 39 | assertEquals(db.countAll(), 0); 40 | assertFalse(db.exists(stringToByteBuffer("key1"))); 41 | assertNull(db.getCopy(stringToByteBuffer("key1"))); 42 | db.put(stringToByteBuffer("key1"), stringToByteBuffer("value1")); 43 | assertEquals(db.countAll(), 0); 44 | assertFalse(db.exists(stringToByteBuffer("key1"))); 45 | assertNull(db.getCopy(stringToByteBuffer("key1"))); 46 | assertTrue(db.remove(stringToByteBuffer("key1"))); 47 | assertFalse(db.exists(stringToByteBuffer("key1"))); 48 | assertNull(db.getCopy(stringToByteBuffer("key1"))); 49 | db.stop(); 50 | } 51 | 52 | @Test 53 | public void startEngineTest() { 54 | Database db = buildDB(ENGINE); 55 | assertNotNull(db); 56 | assertFalse(db.stopped()); 57 | db.stop(); 58 | assertTrue(db.stopped()); 59 | } 60 | 61 | @Test 62 | public void stopsEngineMultipleTimesTest() { 63 | Database db = buildDB(ENGINE); 64 | assertFalse(db.stopped()); 65 | db.stop(); 66 | assertTrue(db.stopped()); 67 | db.stop(); 68 | assertTrue(db.stopped()); 69 | db.stop(); 70 | assertTrue(db.stopped()); 71 | } 72 | 73 | @Test 74 | public void openDBFromJsonTest() { 75 | String json = "{\"path\":\"" + DB_DIR + "\", \"size\":" + DEFAULT_DB_SIZE + "}"; 76 | Database db = openDBFromJson(ENGINE, json, new ByteBufferConverter()); 77 | db.stop(); 78 | } 79 | 80 | @Test 81 | public void openDBFromJsonAndSetTest() { 82 | String json = "{\"path\":\"" + DB_DIR + "\", \"my_bool_param\":" + true + "}"; 83 | Database db = new Database.Builder(ENGINE) 84 | .fromJson(json) 85 | .setSize(DEFAULT_DB_SIZE) 86 | .setKeyConverter(new ByteBufferConverter()) 87 | .setValueConverter(new ByteBufferConverter()) 88 | .build(); 89 | db.stop(); 90 | } 91 | 92 | @Test 93 | public void getsMissingKeyTest() { 94 | Database db = buildDB(ENGINE); 95 | assertFalse(db.exists(stringToByteBuffer("key1"))); 96 | assertNull(db.getCopy(stringToByteBuffer("key1"))); 97 | db.stop(); 98 | } 99 | 100 | @Test 101 | public void putsBasicValueTest() { 102 | Database db = buildDB(ENGINE); 103 | assertFalse(db.exists(stringToByteBuffer("key1"))); 104 | db.put(stringToByteBuffer("key1"), stringToByteBuffer("value1")); 105 | assertTrue(db.exists(stringToByteBuffer("key1"))); 106 | ByteBuffer resBuff = db.getCopy(stringToByteBuffer("key1")); 107 | assertEquals(byteBufferToString(resBuff), "value1"); 108 | db.stop(); 109 | } 110 | 111 | @Test 112 | public void putsEmptyKeyTest() { 113 | Database db = buildDB(ENGINE); 114 | db.put(stringToByteBuffer(""), stringToByteBuffer("empty")); 115 | db.put(stringToByteBuffer(" "), stringToByteBuffer("single-space")); 116 | db.put(stringToByteBuffer("\t\t"), stringToByteBuffer("two-tab")); 117 | assertTrue(db.exists(stringToByteBuffer(""))); 118 | assertEquals(byteBufferToString(db.getCopy(stringToByteBuffer(""))), "empty"); 119 | assertTrue(db.exists(stringToByteBuffer(" "))); 120 | assertEquals(byteBufferToString(db.getCopy(stringToByteBuffer(" "))), "single-space"); 121 | assertTrue(db.exists(stringToByteBuffer("\t\t"))); 122 | assertEquals(byteBufferToString(db.getCopy(stringToByteBuffer("\t\t"))), "two-tab"); 123 | db.stop(); 124 | } 125 | 126 | @Test 127 | public void putsEmptyValueTest() { 128 | Database db = buildDB(ENGINE); 129 | db.put(stringToByteBuffer("empty"), stringToByteBuffer("")); 130 | db.put(stringToByteBuffer("single-space"), stringToByteBuffer(" ")); 131 | db.put(stringToByteBuffer("two-tab"), stringToByteBuffer("\t\t")); 132 | assertEquals(byteBufferToString(db.getCopy(stringToByteBuffer("empty"))), ""); 133 | assertEquals(byteBufferToString(db.getCopy(stringToByteBuffer("single-space"))), " "); 134 | assertEquals(byteBufferToString(db.getCopy(stringToByteBuffer("two-tab"))), "\t\t"); 135 | db.stop(); 136 | } 137 | 138 | @Test 139 | public void putsMultipleValuesTest() { 140 | Database db = buildDB(ENGINE); 141 | db.put(stringToByteBuffer("key1"), stringToByteBuffer("value1")); 142 | db.put(stringToByteBuffer("key2"), stringToByteBuffer("value2")); 143 | db.put(stringToByteBuffer("key3"), stringToByteBuffer("value3")); 144 | assertTrue(db.exists(stringToByteBuffer("key1"))); 145 | assertEquals(byteBufferToString(db.getCopy(stringToByteBuffer("key1"))), "value1"); 146 | assertTrue(db.exists(stringToByteBuffer("key2"))); 147 | assertEquals(byteBufferToString(db.getCopy(stringToByteBuffer("key2"))), "value2"); 148 | assertTrue(db.exists(stringToByteBuffer("key3"))); 149 | assertEquals(byteBufferToString(db.getCopy(stringToByteBuffer("key3"))), "value3"); 150 | assertEquals(db.countAll(), 3); 151 | db.stop(); 152 | } 153 | 154 | @Test 155 | public void putsOverwritingExistingValueTest() { 156 | Database db = buildDB(ENGINE); 157 | db.put(stringToByteBuffer("key1"), stringToByteBuffer("value1")); 158 | assertEquals(byteBufferToString(db.getCopy(stringToByteBuffer("key1"))), "value1"); 159 | db.put(stringToByteBuffer("key1"), stringToByteBuffer("value123")); 160 | assertEquals(byteBufferToString(db.getCopy(stringToByteBuffer("key1"))), "value123"); 161 | db.put(stringToByteBuffer("key1"), stringToByteBuffer("asdf")); 162 | assertEquals(byteBufferToString(db.getCopy(stringToByteBuffer("key1"))), "asdf"); 163 | db.stop(); 164 | } 165 | 166 | @Test 167 | public void removesKeyandValueTest() { 168 | Database db = buildDB(ENGINE); 169 | 170 | db.put(stringToByteBuffer("key1"), stringToByteBuffer("value1")); 171 | assertTrue(db.exists(stringToByteBuffer("key1"))); 172 | db.get(stringToByteBuffer("key1"), (ByteBuffer v) -> { 173 | assertEquals(byteBufferToString(v), "value1"); 174 | }); 175 | assertTrue(db.remove(stringToByteBuffer("key1"))); 176 | assertFalse(db.remove(stringToByteBuffer("key1"))); 177 | assertFalse(db.exists(stringToByteBuffer("key1"))); 178 | assertNull(db.getCopy(stringToByteBuffer("key1"))); 179 | 180 | db.stop(); 181 | } 182 | 183 | @Test 184 | public void usesGetKeysTest() { 185 | Database db = buildDB(ENGINE); 186 | db.put(stringToByteBuffer("1"), stringToByteBuffer("one")); 187 | db.put(stringToByteBuffer("2"), stringToByteBuffer("two")); 188 | db.put(stringToByteBuffer("记!"), stringToByteBuffer("RR")); 189 | 190 | assertEquals(db.countAll(), 3); 191 | StringBuilder x3 = new StringBuilder(); 192 | db.getKeys((ByteBuffer k) -> x3.append("<").append(UTF_8.decode(k).toString()).append(">,")); 193 | assertEquals(x3.toString(), "<1>,<2>,<记!>,"); 194 | 195 | db.stop(); 196 | } 197 | 198 | @Test 199 | public void usesGetKeysAboveTest() { 200 | Database db = buildDB(ENGINE); 201 | db.put(stringToByteBuffer("A"), stringToByteBuffer("1")); 202 | db.put(stringToByteBuffer("AB"), stringToByteBuffer("2")); 203 | db.put(stringToByteBuffer("AC"), stringToByteBuffer("3")); 204 | db.put(stringToByteBuffer("B"), stringToByteBuffer("4")); 205 | db.put(stringToByteBuffer("BB"), stringToByteBuffer("5")); 206 | db.put(stringToByteBuffer("BC"), stringToByteBuffer("6")); 207 | db.put(stringToByteBuffer("记!"), stringToByteBuffer("RR")); 208 | 209 | StringBuilder x3 = new StringBuilder(); 210 | ByteBuffer keyb = ByteBuffer.allocateDirect(1000); 211 | keyb.put("B".getBytes()); 212 | db.getKeysAbove(keyb, (ByteBuffer k) -> x3.append(UTF_8.decode(k).toString()).append(",")); 213 | assertEquals(x3.toString(), "BB,BC,记!,"); 214 | 215 | db.stop(); 216 | } 217 | 218 | @Test 219 | public void usesGetKeysBelowTest() { 220 | Database db = buildDB(ENGINE); 221 | db.put(stringToByteBuffer("A"), stringToByteBuffer("1")); 222 | db.put(stringToByteBuffer("AB"), stringToByteBuffer("2")); 223 | db.put(stringToByteBuffer("AC"), stringToByteBuffer("3")); 224 | db.put(stringToByteBuffer("B"), stringToByteBuffer("4")); 225 | db.put(stringToByteBuffer("BB"), stringToByteBuffer("5")); 226 | db.put(stringToByteBuffer("BC"), stringToByteBuffer("6")); 227 | db.put(stringToByteBuffer("记!"), stringToByteBuffer("RR")); 228 | 229 | StringBuilder x3 = new StringBuilder(); 230 | ByteBuffer keyb = ByteBuffer.allocateDirect(1000); 231 | keyb.put("\uFFFF".getBytes()); 232 | db.getKeysBelow(keyb, (ByteBuffer k) -> x3.append(UTF_8.decode(k).toString()).append(",")); 233 | assertEquals(x3.toString(), "A,AB,AC,B,BB,BC,记!,"); 234 | 235 | db.stop(); 236 | } 237 | 238 | @Test 239 | public void usesGetKeysBetweenTest() { 240 | Database db = buildDB(ENGINE); 241 | db.put(stringToByteBuffer("A"), stringToByteBuffer("1")); 242 | db.put(stringToByteBuffer("AB"), stringToByteBuffer("2")); 243 | db.put(stringToByteBuffer("AC"), stringToByteBuffer("3")); 244 | db.put(stringToByteBuffer("B"), stringToByteBuffer("4")); 245 | db.put(stringToByteBuffer("BB"), stringToByteBuffer("5")); 246 | db.put(stringToByteBuffer("BC"), stringToByteBuffer("6")); 247 | db.put(stringToByteBuffer("记!"), stringToByteBuffer("RR")); 248 | 249 | StringBuilder x3 = new StringBuilder(); 250 | ByteBuffer key1b = ByteBuffer.allocateDirect(1000); 251 | key1b.put("B".getBytes()); 252 | ByteBuffer key2b = ByteBuffer.allocateDirect(1000); 253 | key2b.put("\uFFFF".getBytes()); 254 | db.getKeysBetween(key1b, key2b, (ByteBuffer k) -> x3.append(UTF_8.decode(k).toString()).append(",")); 255 | assertEquals(x3.toString(), "BB,BC,记!,"); 256 | 257 | StringBuilder x4 = new StringBuilder(); 258 | db.getKeysBetween(stringToByteBuffer(""), stringToByteBuffer(""), (ByteBuffer k) -> x4.append(k).append(",")); 259 | db.getKeysBetween(stringToByteBuffer("A"), stringToByteBuffer("A"), (ByteBuffer k) -> x4.append(k).append(",")); 260 | db.getKeysBetween(stringToByteBuffer("B"), stringToByteBuffer("A"), (ByteBuffer k) -> x4.append(k).append(",")); 261 | assertEquals(x4.toString(), ""); 262 | 263 | db.stop(); 264 | } 265 | 266 | @Test 267 | public void usesCountTest() { 268 | Database db = buildDB(ENGINE); 269 | db.put(stringToByteBuffer("A"), stringToByteBuffer("1")); 270 | db.put(stringToByteBuffer("AB"), stringToByteBuffer("2")); 271 | db.put(stringToByteBuffer("AC"), stringToByteBuffer("3")); 272 | db.put(stringToByteBuffer("B"), stringToByteBuffer("4")); 273 | db.put(stringToByteBuffer("BB"), stringToByteBuffer("5")); 274 | db.put(stringToByteBuffer("BC"), stringToByteBuffer("6")); 275 | db.put(stringToByteBuffer("BD"), stringToByteBuffer("7")); 276 | assertEquals(db.countAll(), 7); 277 | 278 | assertEquals(db.countAbove(stringToByteBuffer("")), 7); 279 | assertEquals(db.countAbove(stringToByteBuffer("A")), 6); 280 | assertEquals(db.countAbove(stringToByteBuffer("B")), 3); 281 | assertEquals(db.countAbove(stringToByteBuffer("BC")), 1); 282 | assertEquals(db.countAbove(stringToByteBuffer("BD")), 0); 283 | assertEquals(db.countAbove(stringToByteBuffer("Z")), 0); 284 | 285 | assertEquals(db.countBelow(stringToByteBuffer("")), 0); 286 | assertEquals(db.countBelow(stringToByteBuffer("A")), 0); 287 | assertEquals(db.countBelow(stringToByteBuffer("B")), 3); 288 | assertEquals(db.countBelow(stringToByteBuffer("BD")), 6); 289 | assertEquals(db.countBelow(stringToByteBuffer("ZZZZZ")), 7); 290 | 291 | assertEquals(db.countBetween(stringToByteBuffer(""), stringToByteBuffer("ZZZZ")), 7); 292 | assertEquals(db.countBetween(stringToByteBuffer(""), stringToByteBuffer("A")), 0); 293 | assertEquals(db.countBetween(stringToByteBuffer(""), stringToByteBuffer("B")), 3); 294 | assertEquals(db.countBetween(stringToByteBuffer("A"), stringToByteBuffer("B")), 2); 295 | assertEquals(db.countBetween(stringToByteBuffer("B"), stringToByteBuffer("ZZZZ")), 3); 296 | 297 | assertEquals(db.countBetween(stringToByteBuffer(""), stringToByteBuffer("")), 0); 298 | assertEquals(db.countBetween(stringToByteBuffer("A"), stringToByteBuffer("A")), 0); 299 | assertEquals(db.countBetween(stringToByteBuffer("AC"), stringToByteBuffer("A")), 0); 300 | assertEquals(db.countBetween(stringToByteBuffer("B"), stringToByteBuffer("A")), 0); 301 | assertEquals(db.countBetween(stringToByteBuffer("BD"), stringToByteBuffer("A")), 0); 302 | assertEquals(db.countBetween(stringToByteBuffer("ZZZ"), stringToByteBuffer("B")), 0); 303 | 304 | ByteBuffer key1b = ByteBuffer.allocateDirect(1000); 305 | key1b.put("B".getBytes()); 306 | ByteBuffer key2b = ByteBuffer.allocateDirect(1000); 307 | key2b.put("BD".getBytes()); 308 | assertEquals(db.countAbove(key1b), 3); 309 | assertEquals(db.countBelow(key2b), 6); 310 | assertEquals(db.countBetween(key1b, key2b), 2); 311 | 312 | db.stop(); 313 | } 314 | 315 | @Test 316 | public void usesGetAllTest() { 317 | Database db = buildDB(ENGINE); 318 | db.put(stringToByteBuffer("1"), stringToByteBuffer("one")); 319 | db.put(stringToByteBuffer("2"), stringToByteBuffer("two")); 320 | db.put(stringToByteBuffer("记!"), stringToByteBuffer("RR")); 321 | 322 | StringBuilder x3 = new StringBuilder(); 323 | db.getAll((ByteBuffer k, ByteBuffer v) -> x3.append("<").append(UTF_8.decode(k).toString()).append(">,<") 324 | .append(UTF_8.decode(v).toString()).append(">|")); 325 | assertEquals(x3.toString(), "<1>,|<2>,|<记!>,|"); 326 | 327 | db.stop(); 328 | } 329 | 330 | @Test 331 | public void usesGetAllAboveTest() { 332 | Database db = buildDB(ENGINE); 333 | db.put(stringToByteBuffer("A"), stringToByteBuffer("1")); 334 | db.put(stringToByteBuffer("AB"), stringToByteBuffer("2")); 335 | db.put(stringToByteBuffer("AC"), stringToByteBuffer("3")); 336 | db.put(stringToByteBuffer("B"), stringToByteBuffer("4")); 337 | db.put(stringToByteBuffer("BB"), stringToByteBuffer("5")); 338 | db.put(stringToByteBuffer("BC"), stringToByteBuffer("6")); 339 | db.put(stringToByteBuffer("记!"), stringToByteBuffer("RR")); 340 | 341 | StringBuilder x = new StringBuilder(); 342 | db.getAbove(stringToByteBuffer("B"), (ByteBuffer k, ByteBuffer v) -> x.append(UTF_8.decode(k).toString()) 343 | .append(",").append(UTF_8.decode(v).toString()).append("|")); 344 | 345 | assertEquals(x.toString(), "BB,5|BC,6|记!,RR|"); 346 | 347 | StringBuilder x3 = new StringBuilder(); 348 | ByteBuffer keyb = ByteBuffer.allocateDirect(1000); 349 | keyb.put("B".getBytes()); 350 | db.getAbove(keyb, (ByteBuffer k, ByteBuffer v) -> x3.append(UTF_8.decode(k).toString()).append(",") 351 | .append(UTF_8.decode(v).toString()).append("|")); 352 | assertEquals(x3.toString(), "BB,5|BC,6|记!,RR|"); 353 | 354 | db.stop(); 355 | } 356 | 357 | @Test 358 | public void usesGetBelowTest() { 359 | Database db = buildDB(ENGINE); 360 | db.put(stringToByteBuffer("A"), stringToByteBuffer("1")); 361 | db.put(stringToByteBuffer("AB"), stringToByteBuffer("2")); 362 | db.put(stringToByteBuffer("AC"), stringToByteBuffer("3")); 363 | db.put(stringToByteBuffer("B"), stringToByteBuffer("4")); 364 | db.put(stringToByteBuffer("BB"), stringToByteBuffer("5")); 365 | db.put(stringToByteBuffer("BC"), stringToByteBuffer("6")); 366 | db.put(stringToByteBuffer("记!"), stringToByteBuffer("RR")); 367 | 368 | StringBuilder x = new StringBuilder(); 369 | db.getBelow(stringToByteBuffer("AC"), (ByteBuffer k, ByteBuffer v) -> x.append(UTF_8.decode(k).toString()) 370 | .append(",").append(UTF_8.decode(v).toString()).append("|")); 371 | 372 | assertEquals(x.toString(), "A,1|AB,2|"); 373 | 374 | StringBuilder x3 = new StringBuilder(); 375 | ByteBuffer keyb = ByteBuffer.allocateDirect(1000); 376 | keyb.put("\uFFFF".getBytes()); 377 | db.getBelow(keyb, (ByteBuffer k, ByteBuffer v) -> x3.append(UTF_8.decode(k).toString()).append(",") 378 | .append(UTF_8.decode(v).toString()).append("|")); 379 | assertEquals(x3.toString(), "A,1|AB,2|AC,3|B,4|BB,5|BC,6|记!,RR|"); 380 | 381 | db.stop(); 382 | } 383 | 384 | @Test 385 | public void usesGetBetweenTest() { 386 | Database db = buildDB(ENGINE); 387 | db.put(stringToByteBuffer("A"), stringToByteBuffer("1")); 388 | db.put(stringToByteBuffer("AB"), stringToByteBuffer("2")); 389 | db.put(stringToByteBuffer("AC"), stringToByteBuffer("3")); 390 | db.put(stringToByteBuffer("B"), stringToByteBuffer("4")); 391 | db.put(stringToByteBuffer("BB"), stringToByteBuffer("5")); 392 | db.put(stringToByteBuffer("BC"), stringToByteBuffer("6")); 393 | db.put(stringToByteBuffer("记!"), stringToByteBuffer("RR")); 394 | 395 | StringBuilder x = new StringBuilder(); 396 | 397 | db.getBetween(stringToByteBuffer("A"), stringToByteBuffer("B"), (ByteBuffer k, ByteBuffer v) -> { 398 | x.append(UTF_8.decode(k).toString()).append(",").append(UTF_8.decode(v).toString()).append("|"); 399 | }); 400 | assertEquals(x.toString(), "AB,2|AC,3|"); 401 | 402 | StringBuilder x3 = new StringBuilder(); 403 | ByteBuffer key1b = ByteBuffer.allocateDirect(1000); 404 | key1b.put("B".getBytes()); 405 | ByteBuffer key2b = ByteBuffer.allocateDirect(1000); 406 | key2b.put("\uFFFF".getBytes()); 407 | db.getBetween(key1b, key2b, (ByteBuffer k, ByteBuffer v) -> { 408 | x3.append(UTF_8.decode(k).toString()).append(",").append(UTF_8.decode(v).toString()).append("|"); 409 | }); 410 | assertEquals(x3.toString(), "BB,5|BC,6|记!,RR|"); 411 | 412 | StringBuilder x4 = new StringBuilder(); 413 | db.getBetween(stringToByteBuffer(""), stringToByteBuffer(""), 414 | (ByteBuffer k, ByteBuffer v) -> x4.append(k).append(",")); 415 | db.getBetween(stringToByteBuffer("A"), stringToByteBuffer("A"), 416 | (ByteBuffer k, ByteBuffer v) -> x4.append(k).append(",")); 417 | db.getBetween(stringToByteBuffer("B"), stringToByteBuffer("A"), 418 | (ByteBuffer k, ByteBuffer v) -> x4.append(k).append(",")); 419 | assertEquals(x4.toString(), ""); 420 | 421 | db.stop(); 422 | } 423 | 424 | @Test 425 | public void usesBuffersTest() { 426 | Database db = buildDB(ENGINE); 427 | 428 | ByteBuffer keyb = ByteBuffer.allocateDirect(1000); 429 | ByteBuffer valb = ByteBuffer.allocateDirect(1000); 430 | keyb.putInt(123); 431 | valb.putInt(234); 432 | assertFalse(db.exists(keyb)); 433 | db.put(keyb, valb); 434 | assertTrue(db.exists(keyb)); 435 | assertEquals(db.countAll(), 1); 436 | 437 | keyb.clear(); 438 | keyb.putInt(5678); 439 | valb.clear(); 440 | valb.putInt(6789); 441 | assertFalse(db.exists(keyb)); 442 | db.put(keyb, valb); 443 | assertTrue(db.exists(keyb)); 444 | assertEquals(db.countAll(), 2); 445 | 446 | AtomicInteger count = new AtomicInteger(0); 447 | db.getAll((ByteBuffer kb, ByteBuffer vb) -> { 448 | count.addAndGet(kb.getInt()); 449 | count.addAndGet(vb.getInt()); 450 | }); 451 | assertEquals(count.intValue(), 12824); 452 | 453 | assertTrue(db.exists(keyb)); 454 | assertTrue(db.remove(keyb)); 455 | assertFalse(db.exists(keyb)); 456 | assertFalse(db.remove(keyb)); 457 | 458 | db.stop(); 459 | } 460 | 461 | @Test 462 | public void usesGetBufferIsDirectBufferTest() { 463 | Database db = buildDB(ENGINE); 464 | // Direct ByteBuffer 465 | ByteBuffer keybb = ByteBuffer.allocateDirect(16); 466 | ByteBuffer valbb = ByteBuffer.allocateDirect(16); 467 | keybb.putInt(42); 468 | valbb.putInt(42); 469 | 470 | db.put(keybb, valbb); 471 | db.get(keybb, (ByteBuffer v) -> assertTrue(v.isDirect())); 472 | // Indirect ByteBuffer 473 | byte[] keyb = {41}; 474 | byte[] valb = {41}; 475 | 476 | db.put(ByteBuffer.wrap(keyb), ByteBuffer.wrap(valb)); 477 | db.get(ByteBuffer.wrap(keyb), (ByteBuffer v) -> assertTrue(v.isDirect())); 478 | } 479 | 480 | /* Test get method on a multiple threads */ 481 | @Test 482 | public void usesGetMultiThreadedTest() { 483 | final int threadsNumber = 16; 484 | final int numberOfElements = 100; 485 | 486 | Database db = buildDB(ENGINE); 487 | 488 | for (int i = 0; i < numberOfElements; ++i) { 489 | db.put(stringToByteBuffer(Integer.toString(i)), stringToByteBuffer(Integer.toString(i + 1))); 490 | } 491 | 492 | runParallel(threadsNumber, () -> { 493 | for (int j = 0; j < numberOfElements; ++j) { 494 | final int x = j; 495 | db.get(stringToByteBuffer(Integer.toString(x)), (ByteBuffer v) -> { 496 | assertEquals(byteBufferToString(v), Integer.toString(x + 1)); 497 | }); 498 | } 499 | }, () -> { 500 | for (int j = numberOfElements - 1; j >= 0; --j) { 501 | final int x = j; 502 | db.get(stringToByteBuffer(Integer.toString(x)), (ByteBuffer v) -> { 503 | assertEquals(byteBufferToString(v), Integer.toString(x + 1)); 504 | }); 505 | } 506 | }); 507 | 508 | db.stop(); 509 | } 510 | 511 | /* Test getAll method on a multiple threads */ 512 | @Test 513 | public void usesGetAllMultiThreadedTest() { 514 | final int threadsNumber = 16; 515 | final int numberOfElements = 100; 516 | 517 | Database db = buildDB(ENGINE); 518 | 519 | for (int i = 0; i < numberOfElements; ++i) { 520 | db.put(stringToByteBuffer(Integer.toString(i)), stringToByteBuffer(Integer.toString(i + 1))); 521 | } 522 | 523 | final AtomicInteger cnt = new AtomicInteger(0); 524 | 525 | runParallel(threadsNumber, () -> { 526 | db.getAll((ByteBuffer k, ByteBuffer v) -> { 527 | assertEquals(Integer.parseInt(byteBufferToString(k)) + 1, 528 | Integer.parseInt(byteBufferToString(v))); 529 | }); 530 | }, () -> { 531 | db.getAll((ByteBuffer k, ByteBuffer v) -> { 532 | cnt.getAndIncrement(); 533 | }); 534 | }); 535 | 536 | assertEquals(cnt.get(), threadsNumber / 2 * numberOfElements); 537 | 538 | db.stop(); 539 | } 540 | 541 | /* Test DB with non default cache buffers */ 542 | @Test 543 | public void usesNotDefaultCacheBuffersTest() { 544 | Database db = createDB(ENGINE, DB_DIR, new ByteBufferConverter(), 5, 5); 545 | 546 | /* cache buffers should be used */ 547 | db.put(stringToByteBuffer("A"), stringToByteBuffer("A")); 548 | db.get(stringToByteBuffer("A"), (ByteBuffer v) -> { 549 | assertEquals(byteBufferToString(v), "A"); 550 | }); 551 | 552 | /* key size > key cache buffer size */ 553 | db.put(stringToByteBuffer("AAAAAAAAAAAAAAAAA"), stringToByteBuffer("A")); 554 | db.get(stringToByteBuffer("AAAAAAAAAAAAAAAAA"), (ByteBuffer v) -> { 555 | assertEquals(byteBufferToString(v), "A"); 556 | }); 557 | 558 | /* value size > value cache buffer size */ 559 | db.put(stringToByteBuffer("B"), stringToByteBuffer("AAAAAAAAAAAAAAAAA")); 560 | db.get(stringToByteBuffer("B"), (ByteBuffer v) -> { 561 | assertEquals(byteBufferToString(v), "AAAAAAAAAAAAAAAAA"); 562 | }); 563 | 564 | /* both sizes are bigger than their cache buffers */ 565 | db.put(stringToByteBuffer("BBBBBBBBBBBBBBBBB"), stringToByteBuffer("BBBBBBBBBBBBBBBBB")); 566 | db.get(stringToByteBuffer("BBBBBBBBBBBBBBBBB"), (ByteBuffer v) -> { 567 | assertEquals(byteBufferToString(v), "BBBBBBBBBBBBBBBBB"); 568 | }); 569 | 570 | db.stop(); 571 | } 572 | 573 | /* Test creating DB with various cache buffers sizes */ 574 | @Test 575 | public void usesVariousCacheBuffersSizeTest() { 576 | boolean exception_caught = false; 577 | try { 578 | Database db = createDB(ENGINE, DB_DIR, new ByteBufferConverter(), -5, 5); 579 | } catch (IllegalArgumentException e) { 580 | exception_caught = true; 581 | } 582 | assertTrue(exception_caught); 583 | 584 | exception_caught = false; 585 | try { 586 | Database db = createDB(ENGINE, DB_DIR, new ByteBufferConverter(), 5, -5); 587 | } catch (IllegalArgumentException e) { 588 | exception_caught = true; 589 | } 590 | assertTrue(exception_caught); 591 | 592 | exception_caught = false; 593 | try { 594 | Database db = createDB(ENGINE, DB_DIR, new ByteBufferConverter(), 0, 0); 595 | } catch (IllegalArgumentException e) { 596 | exception_caught = true; 597 | } 598 | assertTrue(exception_caught); 599 | 600 | exception_caught = false; 601 | try { 602 | Database db = createDB(ENGINE, DB_DIR, new ByteBufferConverter(), 603 | Integer.MAX_VALUE, Integer.MAX_VALUE); 604 | } catch (IllegalArgumentException e) { 605 | exception_caught = true; 606 | } 607 | assertFalse(exception_caught); 608 | } 609 | } 610 | -------------------------------------------------------------------------------- /pmemkv-binding/src/test/java/io/pmem/pmemkv/ExceptionTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2020-2021, Intel Corporation */ 3 | 4 | package io.pmem.pmemkv; 5 | 6 | import org.junit.After; 7 | import org.junit.Assert; 8 | import org.junit.Before; 9 | import org.junit.Rule; 10 | import org.junit.rules.TemporaryFolder; 11 | import org.junit.Test; 12 | import static org.junit.Assert.*; 13 | 14 | import java.nio.ByteBuffer; 15 | import java.util.Arrays; 16 | import java.util.concurrent.atomic.AtomicInteger; 17 | import java.util.List; 18 | 19 | import static io.pmem.pmemkv.TestUtils.*; 20 | 21 | @SuppressWarnings("serial") 22 | class CustomException extends RuntimeException { 23 | public CustomException(String message) { 24 | super(message); 25 | } 26 | } 27 | 28 | public class ExceptionTest { 29 | 30 | private final String ENGINE = "vsmap"; 31 | private String DB_DIR = ""; 32 | private Database db; 33 | 34 | /* Helper method, used in most of the tests in this file */ 35 | private Database buildDB(String engine) { 36 | return new Database.Builder(engine) 37 | .setSize(DEFAULT_DB_SIZE) 38 | .setPath(DB_DIR) 39 | .setKeyConverter(new ByteBufferConverter()) 40 | .setValueConverter(new ByteBufferConverter()) 41 | .build(); 42 | } 43 | 44 | @Rule 45 | public TemporaryFolder testDir = new TemporaryFolder(DEFAULT_DB_DIR); 46 | 47 | @Before 48 | public void init() { 49 | DB_DIR = testDir.getRoot().toString(); 50 | assertTrue(DB_DIR != null && !DB_DIR.isEmpty()); 51 | 52 | db = buildDB(ENGINE); 53 | // Direct ByteBuffer 54 | for (int i = 0; i < 0xFF; i++) { 55 | ByteBuffer key = ByteBuffer.allocateDirect(256); 56 | key.putInt(i); 57 | db.put(key, key); 58 | } 59 | assertEquals(db.countAll(), 0xFF); 60 | } 61 | 62 | @After 63 | public void finalize() { 64 | db.stop(); 65 | } 66 | 67 | /* Exceptions related to config and in Open method */ 68 | 69 | @Test 70 | public void throwsExceptionOnStartWhenPathIsMissing() { 71 | Exception exception = assertThrows(InvalidArgumentException.class, () -> { 72 | Database db = new Database.Builder(ENGINE) 73 | .setSize(DEFAULT_DB_SIZE) 74 | .build(); 75 | }); 76 | assertTrue(exception.getMessage().length() > 0); 77 | } 78 | 79 | @Test 80 | public void throwsExceptionOnStartWhenSizeIsMissing() { 81 | Exception exception = assertThrows(InvalidArgumentException.class, () -> { 82 | Database db = new Database.Builder(ENGINE) 83 | .setPath(DB_DIR) 84 | .build(); 85 | }); 86 | assertTrue(exception.getMessage().length() > 0); 87 | } 88 | 89 | @Test 90 | public void throwsExceptionOnStartWhenEngineIsInvalidTest() { 91 | Exception exception = assertThrows(WrongEngineNameException.class, () -> { 92 | Database db = buildDB("nope.nope"); 93 | }); 94 | assertTrue(exception.getMessage().length() > 0); 95 | } 96 | 97 | @Test 98 | public void throwsExceptionOnStartWhenPathIsInvalidTest() { 99 | Exception exception = assertThrows(DatabaseException.class, () -> { 100 | Database db = new Database.Builder(ENGINE) 101 | .setSize(DEFAULT_DB_SIZE) 102 | .setPath("/tmp/123/234/345/456/567/678/nope.nope") 103 | .build(); 104 | /* 105 | * It should be InvalidArgumentException, but: 106 | * https://github.com/pmem/pmemkv/issues/565 107 | */ 108 | }); 109 | assertTrue(exception.getMessage().length() > 0); 110 | } 111 | 112 | @Test 113 | public void throwsExceptionOnStartWhenPathIsWrongTypeTest() { 114 | Exception exception = assertThrows(DatabaseException.class, () -> { 115 | Database db = new Database.Builder(ENGINE) 116 | .setSize(DEFAULT_DB_SIZE) 117 | .setPath("1234") 118 | .build(); 119 | /* 120 | * It's not a valid path, so it should be InvalidArgumentException, but: 121 | * https://github.com/pmem/pmemkv/issues/565 122 | */ 123 | }); 124 | assertTrue(exception.getMessage().length() > 0); 125 | } 126 | 127 | @Test 128 | public void throwsExceptionOnStartWhenPathIsWrongInJsonTest() { 129 | Exception exception = assertThrows(InvalidArgumentException.class, () -> { 130 | String wrongPathJson = "{\"path\":\"/non-existing/dir\"}"; 131 | Database db = openDBFromJson(ENGINE, wrongPathJson, new ByteBufferConverter()); 132 | }); 133 | assertTrue(exception.getMessage().length() > 0); 134 | } 135 | 136 | @Test 137 | public void throwsExceptionOnStartWhenJsonIsIncorrectTest() { 138 | Exception exception = assertThrows(BuilderException.class, () -> { 139 | String wrongJson = "{{{{\":"; 140 | Database db = openDBFromJson(ENGINE, wrongJson, new ByteBufferConverter()); 141 | }); 142 | assertTrue(exception.getMessage().length() > 0); 143 | } 144 | 145 | /* 146 | * XXX: this test fails because of: https://github.com/pmem/pmemkv/issues/568 147 | */ 148 | /* 149 | * @Test public void throwsExceptionOnStartWhenJsonIsIncorrect2Test() { 150 | * Exception exception = assertThrows(BuilderException.class, () -> { // 151 | * malformed config json with additional escape slashes and quote characters 152 | * String wrongJson = 153 | * "\"{\\\"path\\\":\\\"/dev/shm\\\",\\\"size\\\":1073741824}\""; 154 | * Database db = openDBFromJson(ENGINE, wrongJson, new 155 | * ByteBufferConverter()); }); assertTrue(exception.getMessage().length() > 0); 156 | * } 157 | */ 158 | 159 | @Test 160 | public void throwsExceptionOnStartWhenParamIsDefinedTwiceTest() { 161 | Exception exception = assertThrows(BuilderException.class, () -> { 162 | String json = "{\"path\":\"" + DB_DIR + "\", \"size\":" + DEFAULT_DB_SIZE + "}"; 163 | Database db = new Database.Builder(ENGINE) 164 | .fromJson(json) 165 | .setSize(DEFAULT_DB_SIZE) 166 | .setPath("1234") 167 | .build(); 168 | }); 169 | assertTrue(exception.getMessage().length() > 0); 170 | } 171 | 172 | /* Exceptions in Gets methods */ 173 | 174 | @Test 175 | public void exceptionInGetAllTest() { 176 | String exception_message = "Inner exception"; 177 | Exception exception = assertThrows(CustomException.class, () -> { 178 | db.getAll((k, v) -> { 179 | throw new CustomException(exception_message); 180 | }); 181 | }); 182 | assertEquals(exception_message, exception.getMessage()); 183 | } 184 | 185 | @Test 186 | public void exceptionInGetKeysTest() { 187 | String exception_message = "Inner exception"; 188 | AtomicInteger loop_counter = new AtomicInteger(0); 189 | Exception exception = assertThrows(CustomException.class, () -> { 190 | db.getKeys((k) -> { 191 | loop_counter.getAndIncrement(); 192 | throw new CustomException(exception_message); 193 | }); 194 | }); 195 | assertEquals(exception_message, exception.getMessage()); 196 | assertEquals(loop_counter.intValue(), 1); 197 | } 198 | 199 | @Test 200 | public void exceptionInTheMiddleOfGetKeysTest() { 201 | String exception_message = "Inner exception"; 202 | AtomicInteger loop_counter = new AtomicInteger(0); 203 | Exception exception = assertThrows(CustomException.class, () -> { 204 | db.getKeys((k) -> { 205 | loop_counter.getAndIncrement(); 206 | if (k.getInt() == 15) { 207 | throw new CustomException(exception_message); 208 | } 209 | }); 210 | }); 211 | assertEquals(exception_message, exception.getMessage()); 212 | assertEquals(loop_counter.intValue(), 16); 213 | } 214 | 215 | @Test 216 | public void exceptionInGet() { 217 | ByteBuffer key = ByteBuffer.allocateDirect(256); 218 | String exception_message = "Lorem ipsum"; 219 | key.putInt(1); 220 | Exception exception = assertThrows(CustomException.class, () -> { 221 | db.get(key, (ByteBuffer k) -> { 222 | throw new CustomException(exception_message); 223 | }); 224 | }); 225 | assertEquals(exception.getMessage(), exception_message); 226 | } 227 | 228 | /* Other exceptions */ 229 | 230 | @Test(expected = RuntimeException.class) 231 | public void exceptionsHierarchy() { 232 | /* All engines should derive from DatabaseException class */ 233 | List exceptions = Arrays.asList(new DatabaseException(""), new NotFoundException(""), 234 | new NotSupportedException(""), new InvalidArgumentException(""), new BuilderException(""), 235 | new StoppedByCallbackException(""), new OutOfMemoryException(""), new WrongEngineNameException(""), 236 | new TransactionScopeException("")); 237 | 238 | /* We just make sure DBException is of RuntimeException class */ 239 | throw new DatabaseException(""); 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /pmemkv-binding/src/test/java/io/pmem/pmemkv/TestUtils.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* Copyright 2021-2022, Intel Corporation */ 3 | 4 | package io.pmem.pmemkv; 5 | 6 | import static org.junit.Assert.assertTrue; 7 | 8 | import java.io.File; 9 | import java.nio.ByteBuffer; 10 | import java.util.ArrayList; 11 | 12 | interface Callback { 13 | void call(); 14 | } 15 | 16 | class TestUtils { 17 | public static final long DEFAULT_DB_SIZE = 1073741824; 18 | 19 | /* Get test dir from command line or use default */ 20 | public static final File DEFAULT_DB_DIR = new File(System.getProperty("test.db.dir", "/dev/shm")); 21 | 22 | public static class StringConverter implements Converter { 23 | public ByteBuffer toByteBuffer(String entry) { 24 | return ByteBuffer.wrap(entry.getBytes()); 25 | } 26 | 27 | public String fromByteBuffer(ByteBuffer entry) { 28 | byte[] bytes; 29 | bytes = new byte[entry.capacity()]; 30 | entry.get(bytes); 31 | return new String(bytes); 32 | } 33 | } 34 | 35 | public static ByteBuffer stringToByteBuffer(String msg) { 36 | return ByteBuffer.wrap(msg.getBytes()); 37 | } 38 | 39 | public static String byteBufferToString(ByteBuffer buffer) { 40 | byte[] bytes; 41 | bytes = new byte[buffer.capacity()]; 42 | buffer.get(bytes); 43 | return new String(bytes); 44 | } 45 | 46 | /* 47 | * This method executes passed functions in parallel. Each function will be 48 | * executed on numberOfThreads / functions.length threads. 49 | */ 50 | public static void runParallel(int numberOfThreads, Callback... functions) { 51 | ArrayList threads = new ArrayList<>(); 52 | for (int i = 0; i < functions.length; i++) { 53 | for (int j = 0; j < numberOfThreads / functions.length; j++) { 54 | final Callback function = functions[i]; 55 | threads.add(new Thread() { 56 | public void run() { 57 | function.call(); 58 | } 59 | }); 60 | } 61 | } 62 | for (Thread t : threads) { 63 | t.run(); 64 | } 65 | for (Thread t : threads) { 66 | try { 67 | t.join(); 68 | } catch (Exception e) { 69 | assertTrue(false); 70 | } 71 | } 72 | } 73 | 74 | public static Database createDB(String engine, String path, Converter kvConverter) { 75 | return new Database.Builder(engine) 76 | .setSize(DEFAULT_DB_SIZE) 77 | .setForceCreate(true) 78 | .setPath(path) 79 | .setKeyConverter(kvConverter) 80 | .setValueConverter(kvConverter) 81 | .build(); 82 | } 83 | 84 | public static Database createDB(String engine, String path, Converter kvConverter, 85 | int keyBufferSize, int valBufferSize) { 86 | return new Database.Builder(engine) 87 | .setSize(DEFAULT_DB_SIZE) 88 | .setForceCreate(true) 89 | .setPath(path) 90 | .setKeyConverter(kvConverter) 91 | .setValueConverter(kvConverter) 92 | .setKeyBufferSize(keyBufferSize) 93 | .setValueBufferSize(valBufferSize) 94 | .build(); 95 | } 96 | 97 | public static Database openDB(String engine, String path, Converter kvConverter) { 98 | return new Database.Builder(engine) 99 | .setSize(DEFAULT_DB_SIZE) 100 | .setForceCreate(false) 101 | .setPath(path) 102 | .setKeyConverter(kvConverter) 103 | .setValueConverter(kvConverter) 104 | .build(); 105 | } 106 | 107 | public static Database openDB(String engine, String path, Converter kvConverter, int keyBufferSize, 108 | int valBufferSize) { 109 | return new Database.Builder(engine) 110 | .setForceCreate(false) 111 | .setPath(path) 112 | .setKeyConverter(kvConverter) 113 | .setValueConverter(kvConverter) 114 | .setKeyBufferSize(keyBufferSize) 115 | .setValueBufferSize(valBufferSize) 116 | .build(); 117 | } 118 | 119 | public static Database openDBFromJson(String engine, String json, Converter kvConverter) { 120 | return new Database.Builder(engine) 121 | .fromJson(json) 122 | .setKeyConverter(kvConverter) 123 | .setValueConverter(kvConverter) 124 | .build(); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | io.pmem 8 | pmemkv-root 9 | 1.2.0 10 | pmemkv-root 11 | Java binding for pmemkv (top-level, parent artifact) 12 | https://github.com/pmem/pmemkv-java 13 | pom 14 | 15 | 16 | 17 | 1.8 18 | 1.8 19 | UTF-8 20 | UTF-8 21 | ${project.basedir} 22 | 23 | 24 | 25 | jni-binding 26 | pmemkv-binding 27 | examples 28 | 29 | 30 | 31 | 32 | 33 | net.revelc.code.formatter 34 | formatter-maven-plugin 35 | 2.11.0 36 | 37 | ${main.utilsParent}/utils/eclipse-formatter-config.xml 38 | LF 39 | 40 | 41 | 42 | 43 | validate 44 | 45 | 46 | 47 | 48 | 49 | org.apache.maven.plugins 50 | maven-javadoc-plugin 51 | 3.2.0 52 | 53 | 54 | attach-javadocs 55 | 56 | jar 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 3-Clause BSD License 67 | https://github.com/pmem/pmemkv-java/blob/master/LICENSE 68 | repo 69 | 70 | 71 | 72 | 73 | 74 | igchor 75 | Igor Chorążewicz 76 | igor.chorazewicz@intel.com 77 | https://github.com/igchor 78 | Intel 79 | https://pmem.io 80 | 81 | architect 82 | developer 83 | 84 | 85 | 86 | karczex 87 | Paweł Karczewski 88 | pawel.karczewski@intel.com 89 | https://github.com/karczex 90 | Intel 91 | https://pmem.io 92 | 93 | developer 94 | 95 | 96 | 97 | kfilipek 98 | Krzysztof Filipek 99 | krzysztof.filipek@intel.com 100 | https://github.com/kfilipek 101 | Intel 102 | https://pmem.io 103 | 104 | developer 105 | 106 | 107 | 108 | lukaszstolarczuk 109 | Łukasz Stolarczuk 110 | lukasz.stolarczuk@intel.com 111 | https://github.com/lukaszstolarczuk 112 | Intel 113 | https://pmem.io 114 | 115 | developer 116 | 117 | 118 | 119 | 120 | 121 | Intel 122 | https://pmem.io 123 | 124 | 125 | 126 | scm:git:git@github.com:pmem/pmemkv-java.git 127 | scm:git:git@github.com:pmem/pmemkv-java.git 128 | https://github.com/pmem/pmemkv-java 129 | 130 | 131 | 132 | GitHub 133 | https://github.com/pmem/pmemkv-java/issues 134 | 135 | 136 | -------------------------------------------------------------------------------- /utils/docker/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | # Copyright 2017-2021, Intel Corporation 4 | 5 | # 6 | # build.sh - runs a Docker container from a Docker image with environment 7 | # prepared for running pmemkv-java builds and tests. It uses Docker image 8 | # tagged as described in ./images/build-image.sh. 9 | # 10 | # Notes: 11 | # - set env var 'HOST_WORKDIR' to where the root of this project is on the host machine, 12 | # - set env var 'OS' and 'OS_VER' properly to a system/Docker you want to build this 13 | # repo on (for proper values take a look at the list of Dockerfiles at the 14 | # utils/docker/images directory in this repo), e.g. OS=ubuntu, OS_VER=20.04, 15 | # - set env var 'CONTAINER_REG' to container registry address 16 | # [and possibly user/org name, and package name], e.g. "/pmem/pmemkv-java", 17 | # - set env var 'DNS_SERVER' if you use one, 18 | # - set env var 'COMMAND' to execute specific command within Docker container or 19 | # env var 'TYPE' to pick command based on one of the predefined types of build (see below). 20 | # - set env var 'PMEMKV' to a pmemkv's branch (e.g. 'master') with which java tests 21 | # should be run. Directory '/opt/pmemkv-${PMEMKV}' with libpmemkv packages has to exist. 22 | # 23 | 24 | set -e 25 | 26 | source $(dirname $0)/set-ci-vars.sh 27 | IMG_VER=${IMG_VER:-devel} 28 | TAG="${OS}-${OS_VER}-${IMG_VER}" 29 | IMAGE_NAME=${CONTAINER_REG}:${TAG} 30 | CONTAINER_NAME=pmemkv-java-${OS}-${OS_VER} 31 | WORKDIR=/pmemkv-java # working dir within Docker container 32 | SCRIPTSDIR=${WORKDIR}/utils/docker 33 | 34 | if [[ -z "${OS}" || -z "${OS_VER}" ]]; then 35 | echo "ERROR: The variables OS and OS_VER have to be set " \ 36 | "(e.g. OS=fedora, OS_VER=32)." 37 | exit 1 38 | fi 39 | 40 | if [[ -z "${HOST_WORKDIR}" ]]; then 41 | echo "ERROR: The variable HOST_WORKDIR has to contain a path to " \ 42 | "the root of this project on the host machine." 43 | exit 1 44 | fi 45 | 46 | if [[ -z "${CONTAINER_REG}" ]]; then 47 | echo "ERROR: CONTAINER_REG environment variable is not set " \ 48 | "(e.g. \"//\")." 49 | exit 1 50 | fi 51 | 52 | # Set command to execute in the Docker container 53 | if [[ -z "$COMMAND" ]]; then 54 | echo "COMMAND will be based on the type of build: ${TYPE}" 55 | case ${TYPE} in 56 | normal) 57 | COMMAND="./run-build.sh ${PMEMKV}"; 58 | ;; 59 | doc) 60 | COMMAND="./run-doc-update.sh"; 61 | ;; 62 | maven) 63 | COMMAND="./run-maven-example.sh"; 64 | ;; 65 | *) 66 | echo "ERROR: wrong build TYPE" 67 | exit 1 68 | ;; 69 | esac 70 | fi 71 | echo "COMMAND to execute within Docker container: ${COMMAND}" 72 | 73 | if [ "${COVERAGE}" == "1" ]; then 74 | DOCKER_OPTS="${DOCKER_OPTS} $(bash <(curl -s https://codecov.io/env))"; 75 | fi 76 | 77 | if [ -n "${DNS_SERVER}" ]; then DOCKER_OPTS="${DOCKER_OPTS} --dns=${DNS_SERVER} "; fi 78 | 79 | # Check if we are running on a CI (Travis or GitHub Actions) 80 | [ -n "${GITHUB_ACTIONS}" -o -n "${TRAVIS}" ] && CI_RUN="YES" || CI_RUN="NO" 81 | 82 | # Do not allocate a pseudo-TTY if we are running on GitHub Actions 83 | [ ! "${GITHUB_ACTIONS}" ] && DOCKER_OPTS="${DOCKER_OPTS} --tty=true" 84 | 85 | 86 | echo "Running build using Docker image: ${IMAGE_NAME}" 87 | 88 | # Run a container with 89 | # - environment variables set (--env) 90 | # - host directory containing source mounted (-v) 91 | # - working directory set (-w) 92 | docker run --privileged=true --name=${CONTAINER_NAME} -i \ 93 | ${DOCKER_OPTS} \ 94 | --env http_proxy=${http_proxy} \ 95 | --env https_proxy=${https_proxy} \ 96 | --env TERM=xterm-256color \ 97 | --env WORKDIR=${WORKDIR} \ 98 | --env SCRIPTSDIR=${SCRIPTSDIR} \ 99 | --env GITHUB_REPO=${GITHUB_REPO} \ 100 | --env CI_RUN=${CI_RUN} \ 101 | --env TRAVIS=${TRAVIS} \ 102 | --env GITHUB_ACTIONS=${GITHUB_ACTIONS} \ 103 | --env CI_COMMIT=${CI_COMMIT} \ 104 | --env CI_COMMIT_RANGE=${CI_COMMIT_RANGE} \ 105 | --env CI_BRANCH=${CI_BRANCH} \ 106 | --env CI_EVENT_TYPE=${CI_EVENT_TYPE} \ 107 | --env CI_REPO_SLUG=${CI_REPO_SLUG} \ 108 | --env DOC_UPDATE_GITHUB_TOKEN=${DOC_UPDATE_GITHUB_TOKEN} \ 109 | --env DOC_UPDATE_BOT_NAME=${DOC_UPDATE_BOT_NAME} \ 110 | --env DOC_REPO_OWNER=${DOC_REPO_OWNER} \ 111 | --env COVERITY_SCAN_TOKEN=${COVERITY_SCAN_TOKEN} \ 112 | --env COVERITY_SCAN_NOTIFICATION_EMAIL=${COVERITY_SCAN_NOTIFICATION_EMAIL} \ 113 | --env COVERAGE=${COVERAGE} \ 114 | --env TZ='Europe/Warsaw' \ 115 | --shm-size=4G \ 116 | -v ${HOST_WORKDIR}:${WORKDIR} \ 117 | -v /etc/localtime:/etc/localtime \ 118 | -w ${SCRIPTSDIR} \ 119 | ${IMAGE_NAME} ${COMMAND} 120 | -------------------------------------------------------------------------------- /utils/docker/images/Dockerfile.fedora-33: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright 2016-2021, Intel Corporation 3 | 4 | # 5 | # Dockerfile - a 'recipe' for Docker to build an image of fedora-based 6 | # environment prepared for running pmemkv-java build and tests. 7 | # 8 | 9 | # Pull base image 10 | FROM registry.fedoraproject.org/fedora:33 11 | MAINTAINER igor.chorazewicz@intel.com 12 | 13 | # Set required environment variables 14 | ENV OS fedora 15 | ENV OS_VER 33 16 | ENV PACKAGE_MANAGER rpm 17 | ENV NOTTY 1 18 | ENV JAVA_HOME /usr/lib/jvm/java-1.8.0-openjdk/ 19 | 20 | # Additional parameters to build docker without building components 21 | ARG SKIP_PMDK_BUILD 22 | ARG SKIP_LIBPMEMOBJ_CPP_BUILD 23 | ARG SKIP_PMEMKV_BUILD 24 | ARG SKIP_DEPENDENCIES_BUILD 25 | ARG SKIP_MAVEN_RUNTIME_SETUP 26 | 27 | # Base development packages 28 | ARG BASE_DEPS="\ 29 | cmake \ 30 | gcc \ 31 | gcc-c++ \ 32 | git \ 33 | make" 34 | 35 | # Dependencies for compiling pmemkv-java project 36 | ARG PMEMKV_JAVA_DEPS="\ 37 | maven \ 38 | java-1.8.0-openjdk-devel" 39 | 40 | # PMDK's dependencies (optional; libpmemobj-devel package may be used instead) 41 | ARG PMDK_DEPS="\ 42 | autoconf \ 43 | automake \ 44 | daxctl-devel \ 45 | gdb \ 46 | man \ 47 | ndctl-devel \ 48 | pandoc \ 49 | python3 \ 50 | rpm-build \ 51 | rpm-build-libs \ 52 | rpmdevtools \ 53 | which" 54 | 55 | # Dependencies for compiling libpmemobj-cpp project (optional; libpmemobj++-devel package may be used instead) 56 | ARG LIBPMEMOBJ_CPP_DEPS="\ 57 | libatomic \ 58 | tbb-devel" 59 | 60 | # Dependencies for compiling pmemkv project (optional; pmemkv-devel package may be used instead) 61 | ARG PMEMKV_DEPS="\ 62 | memkind-devel \ 63 | rapidjson-devel \ 64 | tbb-devel" 65 | 66 | # Misc for our builds/CI (optional) 67 | ARG MISC_DEPS="\ 68 | clang \ 69 | hub \ 70 | perl-Text-Diff \ 71 | pkgconf \ 72 | sudo" 73 | 74 | # Update packages and install basic tools 75 | RUN dnf update -y \ 76 | && dnf install -y \ 77 | ${BASE_DEPS} \ 78 | ${PMEMKV_JAVA_DEPS} \ 79 | ${PMDK_DEPS} \ 80 | ${LIBPMEMOBJ_CPP_DEPS} \ 81 | ${PMEMKV_DEPS} \ 82 | ${MISC_DEPS} \ 83 | && dnf clean all 84 | 85 | # Install pmdk 86 | COPY install-pmdk.sh install-pmdk.sh 87 | RUN ./install-pmdk.sh rpm 88 | 89 | # Install pmdk c++ bindings 90 | COPY install-libpmemobj-cpp.sh install-libpmemobj-cpp.sh 91 | RUN ./install-libpmemobj-cpp.sh RPM 92 | 93 | # Prepare pmemkv 94 | COPY prepare-pmemkv.sh prepare-pmemkv.sh 95 | RUN ./prepare-pmemkv.sh RPM 96 | 97 | # Prepare extra maven params 98 | # It's executed and its result is exported within 'install-dependencies.sh' 99 | # To avoid setting this script up also in users' .bashrc, 100 | # for a container runtime, set 'SKIP_MAVEN_RUNTIME_SETUP' 101 | COPY setup-maven-settings.sh /opt/setup-maven-settings.sh 102 | 103 | # Install dependencies for the java binding so it can be built offline 104 | COPY install-dependencies.sh install-dependencies.sh 105 | RUN ./install-dependencies.sh RPM 106 | 107 | # Add user 108 | ENV USER user 109 | ENV USERPASS pass 110 | RUN useradd -m $USER \ 111 | && echo "$USER:$USERPASS" | chpasswd \ 112 | && gpasswd wheel -a $USER 113 | USER $USER 114 | -------------------------------------------------------------------------------- /utils/docker/images/Dockerfile.fedora-34: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright 2016-2021, Intel Corporation 3 | 4 | # 5 | # Dockerfile - a 'recipe' for Docker to build an image of fedora-based 6 | # environment prepared for running pmemkv-java build and tests. 7 | # 8 | 9 | # Pull base image 10 | FROM registry.fedoraproject.org/fedora:34 11 | MAINTAINER igor.chorazewicz@intel.com 12 | 13 | # Set required environment variables 14 | ENV OS fedora 15 | ENV OS_VER 34 16 | ENV PACKAGE_MANAGER rpm 17 | ENV NOTTY 1 18 | ENV JAVA_HOME /usr/lib/jvm/java-1.8.0 19 | 20 | # Additional parameters to build docker without building components 21 | ARG SKIP_PMDK_BUILD 22 | ARG SKIP_LIBPMEMOBJ_CPP_BUILD 23 | ARG SKIP_PMEMKV_BUILD 24 | ARG SKIP_DEPENDENCIES_BUILD 25 | ARG SKIP_MAVEN_RUNTIME_SETUP 26 | 27 | # Base development packages 28 | ARG BASE_DEPS="\ 29 | cmake \ 30 | gcc \ 31 | gcc-c++ \ 32 | git \ 33 | make" 34 | 35 | # Dependencies for compiling pmemkv-java project 36 | ARG PMEMKV_JAVA_DEPS="\ 37 | maven \ 38 | java-1.8.0-openjdk-devel" 39 | 40 | # PMDK's dependencies (optional; libpmemobj-devel package may be used instead) 41 | ARG PMDK_DEPS="\ 42 | autoconf \ 43 | automake \ 44 | daxctl-devel \ 45 | gdb \ 46 | man \ 47 | ndctl-devel \ 48 | pandoc \ 49 | python3 \ 50 | rpm-build \ 51 | rpm-build-libs \ 52 | rpmdevtools \ 53 | which" 54 | 55 | # Dependencies for compiling libpmemobj-cpp project (optional; libpmemobj++-devel package may be used instead) 56 | ARG LIBPMEMOBJ_CPP_DEPS="\ 57 | libatomic \ 58 | tbb-devel" 59 | 60 | # Dependencies for compiling pmemkv project (optional; pmemkv-devel package may be used instead) 61 | ARG PMEMKV_DEPS="\ 62 | memkind-devel \ 63 | rapidjson-devel \ 64 | tbb-devel" 65 | 66 | # Misc for our builds/CI (optional) 67 | ARG MISC_DEPS="\ 68 | clang \ 69 | hub \ 70 | perl-Text-Diff \ 71 | pkgconf \ 72 | sudo" 73 | 74 | # Update packages and install basic tools 75 | RUN dnf update -y \ 76 | && dnf install -y \ 77 | ${BASE_DEPS} \ 78 | ${PMEMKV_JAVA_DEPS} \ 79 | ${PMDK_DEPS} \ 80 | ${LIBPMEMOBJ_CPP_DEPS} \ 81 | ${PMEMKV_DEPS} \ 82 | ${MISC_DEPS} \ 83 | && dnf clean all 84 | 85 | # Install pmdk 86 | COPY install-pmdk.sh install-pmdk.sh 87 | RUN ./install-pmdk.sh rpm 88 | 89 | # Install pmdk c++ bindings 90 | COPY install-libpmemobj-cpp.sh install-libpmemobj-cpp.sh 91 | RUN ./install-libpmemobj-cpp.sh RPM 92 | 93 | # Prepare pmemkv 94 | COPY prepare-pmemkv.sh prepare-pmemkv.sh 95 | RUN ./prepare-pmemkv.sh RPM 96 | 97 | # Prepare extra maven params 98 | # It's executed and its result is exported within 'install-dependencies.sh' 99 | # To avoid setting this script up also in users' .bashrc, 100 | # for a container runtime, set 'SKIP_MAVEN_RUNTIME_SETUP' 101 | COPY setup-maven-settings.sh /opt/setup-maven-settings.sh 102 | 103 | # Install dependencies for the java binding so it can be built offline 104 | COPY install-dependencies.sh install-dependencies.sh 105 | RUN ./install-dependencies.sh RPM 106 | 107 | # Add user 108 | ENV USER user 109 | ENV USERPASS pass 110 | RUN useradd -m $USER \ 111 | && echo "$USER:$USERPASS" | chpasswd \ 112 | && gpasswd wheel -a $USER 113 | USER $USER 114 | -------------------------------------------------------------------------------- /utils/docker/images/Dockerfile.ubuntu-20.04: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright 2016-2021, Intel Corporation 3 | 4 | # 5 | # Dockerfile - a 'recipe' for Docker to build an image of ubuntu-based 6 | # environment prepared for running pmemkv-java build and tests. 7 | # 8 | 9 | # Pull base image 10 | FROM registry.hub.docker.com/library/ubuntu:20.04 11 | MAINTAINER igor.chorazewicz@intel.com 12 | 13 | # Set required environment variables 14 | ENV OS ubuntu 15 | ENV OS_VER 20.04 16 | ENV PACKAGE_MANAGER deb 17 | ENV NOTTY 1 18 | ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64 19 | 20 | # Additional parameters to build docker without building components 21 | ARG SKIP_PMDK_BUILD 22 | ARG SKIP_LIBPMEMOBJ_CPP_BUILD 23 | ARG SKIP_PMEMKV_BUILD 24 | ARG SKIP_DEPENDENCIES_BUILD 25 | ARG SKIP_MAVEN_RUNTIME_SETUP 26 | 27 | # Base development packages 28 | ARG BASE_DEPS="\ 29 | cmake \ 30 | build-essential \ 31 | git" 32 | 33 | # Dependencies for compiling pmemkv-java project 34 | ARG PMEMKV_JAVA_DEPS="\ 35 | maven \ 36 | openjdk-8-jdk" 37 | 38 | # PMDK's dependencies (optional; libpmemobj-dev package may be used instead) 39 | ARG PMDK_DEPS="\ 40 | autoconf \ 41 | automake \ 42 | debhelper \ 43 | devscripts \ 44 | gdb \ 45 | libdaxctl-dev \ 46 | libndctl-dev \ 47 | pandoc \ 48 | python3" 49 | 50 | # Dependencies for compiling libpmemobj-cpp project (optional; libpmemobj-cpp-dev package may be used instead) 51 | ARG LIBPMEMOBJ_CPP_DEPS="\ 52 | libatomic1 \ 53 | libtbb-dev \ 54 | libunwind8-dev" 55 | 56 | # Dependencies for compiling pmemkv project (optional; libpmemkv-dev package may be used instead) 57 | ARG PMEMKV_DEPS="\ 58 | libmemkind-dev \ 59 | libtbb-dev \ 60 | libunwind8-dev \ 61 | rapidjson-dev" 62 | 63 | # Misc for our builds/CI (optional) 64 | ARG MISC_DEPS="\ 65 | clang \ 66 | pkg-config \ 67 | sudo \ 68 | whois" 69 | 70 | ENV DEBIAN_FRONTEND noninteractive 71 | 72 | # Update the Apt cache and install basic tools 73 | RUN apt-get update \ 74 | && apt-get install -y --no-install-recommends \ 75 | ${BASE_DEPS} \ 76 | ${PMEMKV_JAVA_DEPS} \ 77 | ${PMDK_DEPS} \ 78 | ${LIBPMEMOBJ_CPP_DEPS} \ 79 | ${PMEMKV_DEPS} \ 80 | ${MISC_DEPS} \ 81 | && rm -rf /var/lib/apt/lists/* 82 | 83 | # Install pmdk 84 | COPY install-pmdk.sh install-pmdk.sh 85 | RUN ./install-pmdk.sh dpkg 86 | 87 | # Install pmdk c++ bindings 88 | COPY install-libpmemobj-cpp.sh install-libpmemobj-cpp.sh 89 | RUN ./install-libpmemobj-cpp.sh DEB 90 | 91 | # Prepare pmemkv 92 | COPY prepare-pmemkv.sh prepare-pmemkv.sh 93 | RUN ./prepare-pmemkv.sh DEB 94 | 95 | # Prepare extra maven params 96 | # It's executed and its result is exported within 'install-dependencies.sh' 97 | # To avoid setting this script up also in users' .bashrc, 98 | # for a container runtime, set 'SKIP_MAVEN_RUNTIME_SETUP' 99 | COPY setup-maven-settings.sh /opt/setup-maven-settings.sh 100 | 101 | # Install dependencies for the java binding so it can be built offline 102 | COPY install-dependencies.sh install-dependencies.sh 103 | RUN ./install-dependencies.sh DEB 104 | 105 | # Add user 106 | ENV USER user 107 | ENV USERPASS pass 108 | RUN useradd -m $USER -g sudo -p `mkpasswd $USERPASS` 109 | USER $USER 110 | -------------------------------------------------------------------------------- /utils/docker/images/Dockerfile.ubuntu-21.04_clean: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright 2016-2021, Intel Corporation 3 | 4 | # 5 | # Dockerfile - a 'recipe' for Docker to build an image of ubuntu-based 6 | # environment prepared for running pmemkv-java examples 7 | # e.g. with pmemkv downloaded from maven repository. 8 | # 9 | 10 | # Pull base image 11 | FROM registry.hub.docker.com/library/ubuntu:21.04 12 | MAINTAINER igor.chorazewicz@intel.com 13 | 14 | # Set required environment variables 15 | ENV OS ubuntu 16 | ENV OS_VER 21.04_clean 17 | ENV PACKAGE_MANAGER deb 18 | ENV NOTTY 1 19 | ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64 20 | 21 | # Additional parameters to build docker without building components 22 | ARG SKIP_MAVEN_RUNTIME_SETUP 23 | 24 | # Base development packages 25 | ARG BASE_DEPS="\ 26 | git" 27 | 28 | # Dependencies for compiling pmemkv-java example(s) 29 | ARG PMEMKV_JAVA_DEPS="\ 30 | libpmemkv-dev \ 31 | maven \ 32 | openjdk-8-jdk" 33 | 34 | # Misc for our builds/CI (optional) 35 | ARG MISC_DEPS="\ 36 | sudo \ 37 | whois" 38 | 39 | ENV DEBIAN_FRONTEND noninteractive 40 | 41 | # Update the Apt cache and install basic tools 42 | RUN apt-get update \ 43 | && apt-get install -y --no-install-recommends \ 44 | ${BASE_DEPS} \ 45 | ${PMEMKV_JAVA_DEPS} \ 46 | ${MISC_DEPS} \ 47 | && rm -rf /var/lib/apt/lists/* 48 | 49 | # Prepare extra maven params 50 | # It's executed and its result is exported within 'install-dependencies.sh' 51 | # To avoid setting this script up also in users' .bashrc, 52 | # for a container runtime, set 'SKIP_MAVEN_RUNTIME_SETUP' 53 | COPY setup-maven-settings.sh /opt/setup-maven-settings.sh 54 | 55 | # Setup only maven settings. 56 | # Offline dependencies are not useful within the image, since we need 57 | # the internet connection anyway (for downloading the pmemkv from maven). 58 | ARG SKIP_DEPENDENCIES_BUILD=1 59 | COPY install-dependencies.sh install-dependencies.sh 60 | RUN ./install-dependencies.sh 61 | 62 | # Add user 63 | ENV USER user 64 | ENV USERPASS pass 65 | RUN useradd -m $USER -g sudo -p `mkpasswd $USERPASS` 66 | USER $USER 67 | -------------------------------------------------------------------------------- /utils/docker/images/README.md: -------------------------------------------------------------------------------- 1 | # Content 2 | 3 | Dockerfiles and scripts placed in this directory are intended to be used as 4 | development process vehicles and part of continuous integration process. 5 | 6 | Images built out of those recipes may by used with docker or podman as 7 | development environment. 8 | Only those used on Travis/Github Actions are fully tested on a daily basis. 9 | In case of any problem, patches and Github issues are welcome. 10 | 11 | # How to build docker image 12 | 13 | ```sh 14 | docker build --build-arg https_proxy=http://proxy.com:port --build-arg http_proxy=http://proxy.com:port -t pmemkv-java:ubuntu-20.04 -f ./Dockerfile.ubuntu-20.04 . 15 | ``` 16 | 17 | # How to use docker image 18 | 19 | To run build and tests on local machine on docker: 20 | 21 | ```sh 22 | docker run --network=bridge --shm-size=4G -v /your/workspace/path/:/opt/workspace:z -w /opt/workspace/ -e CC=gcc -e CXX=g++ -e PKG_CONFIG_PATH=/opt/pmdk/lib/pkgconfig -it pmemkv-java:ubuntu-20.04 /bin/bash 23 | ``` 24 | 25 | To get strace working, add to docker commandline 26 | 27 | ```sh 28 | --cap-add SYS_PTRACE 29 | ``` 30 | 31 | -------------------------------------------------------------------------------- /utils/docker/images/build-image.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | # Copyright 2016-2021, Intel Corporation 4 | 5 | # 6 | # build-image.sh - prepares a Docker image with -based environment for 7 | # testing (or dev) purpose, tagged with ${CONTAINER_REG}:${OS}-${OS_VER}-${IMG_VER}, 8 | # according to the Dockerfile.${OS}-${OS_VER} file located in the same directory. 9 | # IMG_VER is a version of docker image (it usually relates to project's release tag) 10 | # and it defaults to "devel". 11 | # 12 | 13 | set -e 14 | IMG_VER=${IMG_VER:-devel} 15 | TAG="${OS}-${OS_VER}-${IMG_VER}" 16 | 17 | if [[ -z "${OS}" || -z "${OS_VER}" ]]; then 18 | echo "ERROR: The variables OS and OS_VER have to be set " \ 19 | "(e.g. OS=fedora, OS_VER=32)." 20 | exit 1 21 | fi 22 | 23 | if [[ -z "${CONTAINER_REG}" ]]; then 24 | echo "ERROR: CONTAINER_REG environment variable is not set " \ 25 | "(e.g. \"//\")." 26 | exit 1 27 | fi 28 | 29 | echo "Check if the file Dockerfile.${OS}-${OS_VER} exists" 30 | if [[ ! -f "Dockerfile.${OS}-${OS_VER}" ]]; then 31 | echo "Error: Dockerfile.${OS}-${OS_VER} does not exist." 32 | exit 1 33 | fi 34 | 35 | echo "Build a Docker image tagged with: ${CONTAINER_REG}:${TAG}" 36 | docker build -t ${CONTAINER_REG}:${TAG} \ 37 | --build-arg http_proxy=${http_proxy} \ 38 | --build-arg https_proxy=${https_proxy} \ 39 | -f Dockerfile.${OS}-${OS_VER} . 40 | -------------------------------------------------------------------------------- /utils/docker/images/install-dependencies.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | # Copyright 2019-2021, Intel Corporation 4 | 5 | # 6 | # install-dependencies.sh - install binding's dependencies, so it 7 | # can be built offline; and setup maven settings. 8 | # Both can be turned off using build arguments (see below if's). 9 | # 10 | 11 | set -e 12 | 13 | # Include setup of extra maven parameters... 14 | source /opt/setup-maven-settings.sh 15 | 16 | # ...and set the same script as an entrypoint for all users (newly defined in the future) 17 | if [ -n "${SKIP_MAVEN_RUNTIME_SETUP}" ]; then 18 | echo "Variable 'SKIP_MAVEN_RUNTIME_SETUP' is set; skipping maven setting setup" 19 | else 20 | echo "source /opt/setup-maven-settings.sh" >> /etc/skel/.bashrc 21 | fi 22 | 23 | if [ -n "${SKIP_DEPENDENCIES_BUILD}" ]; then 24 | echo "Variable 'SKIP_DEPENDENCIES_BUILD' is set; skipping building dependencies" 25 | exit 26 | fi 27 | 28 | MVN_PARAMS="${PMEMKV_MVN_PARAMS}" 29 | echo "Extra mvn params (taken from env): ${MVN_PARAMS}" 30 | 31 | PREFIX=/usr 32 | # common: release 1.5.0, 27.07.2021 33 | PMEMKV_VERSION="a92abed550ece9c5c70b6be17db8e9cb19e328e4" 34 | # common: release 1.2.0, 02.07.2021 35 | JAVA_VERSION="9a32f9f518198ae575242b448f61514c231b5a60" 36 | 37 | echo "Build and install PMEMKV (JNI needs it)" 38 | git clone https://github.com/pmem/pmemkv.git 39 | cd pmemkv 40 | git checkout ${PMEMKV_VERSION} 41 | mkdir build 42 | cd build 43 | 44 | cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo \ 45 | -DCMAKE_INSTALL_PREFIX=${PREFIX} \ 46 | -DENGINE_CMAP=OFF \ 47 | -DENGINE_CSMAP=OFF \ 48 | -DENGINE_VCMAP=OFF \ 49 | -DENGINE_VSMAP=OFF \ 50 | -DBUILD_DOC=OFF \ 51 | -DBUILD_EXAMPLES=OFF \ 52 | -DBUILD_TESTS=OFF \ 53 | -DTESTS_USE_VALGRIND=OFF 54 | make -j$(nproc) 55 | make -j$(nproc) install 56 | 57 | # 58 | # project's dependencies - all of the dependencies needed to run pmemkv-java will 59 | # be saved in the /opt/java directory. It makes building 60 | # of this project independent of network connection. 61 | echo "Save binding's dependencies in /opt/java" 62 | mkdir /opt/java/ 63 | 64 | deps_dir=$(mktemp -d) 65 | git clone https://github.com/pmem/pmemkv-java.git ${deps_dir} 66 | pushd ${deps_dir} 67 | git checkout ${JAVA_VERSION} 68 | 69 | mvn install -Dmaven.test.skip=true ${MVN_PARAMS} 70 | mvn javadoc:javadoc ${MVN_PARAMS} 71 | mvn dependency:go-offline ${MVN_PARAMS} 72 | mv -v ~/.m2/repository /opt/java/ 73 | 74 | popd 75 | rm -r ${deps_dir} 76 | 77 | echo "Uninstall pmemkv" 78 | cd ${WORKDIR}/pmemkv/build 79 | make -j$(nproc) uninstall 80 | 81 | echo "Remove installed binding files (from local mvn repository)" 82 | rm -r /opt/java/repository/io/pmem/* 83 | 84 | echo "Make the /opt/java directory world-readable" 85 | chmod -R a+r /opt/java 86 | -------------------------------------------------------------------------------- /utils/docker/images/install-libpmemobj-cpp.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | # Copyright 2019-2021, Intel Corporation 4 | 5 | # 6 | # install-libpmemobj-cpp.sh [package_type] 7 | # - installs PMDK C++ bindings (libpmemobj-cpp) 8 | # 9 | 10 | set -e 11 | 12 | if [ "${SKIP_LIBPMEMOBJ_CPP_BUILD}" ]; then 13 | echo "Variable 'SKIP_LIBPMEMOBJ_CPP_BUILD' is set; skipping building of libpmemobj-cpp" 14 | exit 15 | fi 16 | 17 | PREFIX=/usr 18 | PACKAGE_TYPE=${1^^} #To uppercase 19 | echo "PACKAGE_TYPE: ${PACKAGE_TYPE}" 20 | 21 | # common: 1.13.0 release; 27.07.2021 22 | LIBPMEMOBJ_CPP_VERSION="9599f724d4edc3a3d973bac14eeebdc1bc31d327" 23 | 24 | build_dir=$(mktemp -d -t libpmemobj-cpp-XXX) 25 | 26 | git clone https://github.com/pmem/libpmemobj-cpp --shallow-since=2020-12-01 ${build_dir} 27 | 28 | pushd ${build_dir} 29 | git checkout ${LIBPMEMOBJ_CPP_VERSION} 30 | 31 | mkdir build 32 | cd build 33 | 34 | # turn off all redundant components 35 | cmake .. -DCPACK_GENERATOR="${PACKAGE_TYPE}" -DCMAKE_INSTALL_PREFIX=${PREFIX} \ 36 | -DBUILD_EXAMPLES=OFF -DBUILD_TESTS=OFF -DTESTS_USE_VALGRIND=OFF -DBUILD_DOC=OFF -DBUILD_BENCHMARKS=OFF 37 | 38 | if [ "${PACKAGE_TYPE}" = "" ]; then 39 | make -j$(nproc) install 40 | else 41 | make -j$(nproc) package 42 | if [ "${PACKAGE_TYPE}" = "DEB" ]; then 43 | sudo dpkg -i libpmemobj++*.deb 44 | elif [ "${PACKAGE_TYPE}" = "RPM" ]; then 45 | sudo rpm -i libpmemobj++*.rpm 46 | fi 47 | fi 48 | 49 | popd 50 | rm -r ${build_dir} 51 | -------------------------------------------------------------------------------- /utils/docker/images/install-pmdk.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | # Copyright 2019-2021, Intel Corporation 4 | 5 | # 6 | # install-pmdk.sh [package_type] [install_prefix] - installs PMDK 7 | # 8 | 9 | set -e 10 | 11 | if [ "${SKIP_PMDK_BUILD}" ]; then 12 | echo "Variable 'SKIP_PMDK_BUILD' is set; skipping building of PMDK" 13 | exit 14 | fi 15 | 16 | PACKAGE_TYPE=$1 17 | PREFIX=${2:-/usr} 18 | echo "PACKAGE_TYPE: ${PACKAGE_TYPE}" 19 | 20 | # master: 1.11.0, 02.07.2021 21 | PMDK_VERSION="8583fcfd68764ac6779e6f93db89b06971b26704" 22 | 23 | git clone https://github.com/pmem/pmdk --shallow-since=2020-12-01 24 | cd pmdk 25 | git checkout ${PMDK_VERSION} 26 | 27 | if [ "${PACKAGE_TYPE}" = "" ]; then 28 | make -j$(nproc) install prefix=${PREFIX} 29 | else 30 | make -j$(nproc) BUILD_PACKAGE_CHECK=n ${PACKAGE_TYPE} 31 | if [ "${PACKAGE_TYPE}" = "dpkg" ]; then 32 | sudo dpkg -i dpkg/libpmem_*.deb dpkg/libpmem-dev_*.deb 33 | sudo dpkg -i dpkg/libpmemobj_*.deb dpkg/libpmemobj-dev_*.deb 34 | elif [ "${PACKAGE_TYPE}" = "rpm" ]; then 35 | sudo rpm -i rpm/*/pmdk-debuginfo-*.rpm 36 | sudo rpm -i rpm/*/libpmem-*.rpm 37 | sudo rpm -i rpm/*/libpmemobj-*.rpm 38 | fi 39 | fi 40 | 41 | cd .. 42 | rm -r pmdk 43 | -------------------------------------------------------------------------------- /utils/docker/images/prepare-pmemkv.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | # Copyright 2019-2021, Intel Corporation 4 | 5 | # 6 | # prepare-pmemkv.sh - prepare pmemkv packages 7 | # 8 | 9 | set -e 10 | 11 | if [ "${SKIP_PMEMKV_BUILD}" ]; then 12 | echo "Variable 'SKIP_PMEMKV_BUILD' is set; skipping building of pmemkv" 13 | exit 14 | fi 15 | 16 | PREFIX=/usr 17 | PACKAGE_TYPE=${1} 18 | echo "PACKAGE_TYPE: ${PACKAGE_TYPE}" 19 | if [ -z "${PACKAGE_TYPE}" ]; then 20 | echo "PACKAGE_TYPE is not set" 21 | exit 1 22 | fi 23 | 24 | # master: Merge pull request #1033 from karczex/pmemkv_cpp_always_avialable; 29.07.2021 25 | current_pmemkv_version="0b5707aabc1050433394019b19bd0983e6f1631d" 26 | 27 | # stable-1.4: 1.4 release; 15.02.2021 28 | stable_1_4_pmemkv_version="ecb8fd65c5b07ed002d1018418ef809ab50d4e18" 29 | 30 | # stable-1.5: release 1.5.0, 27.07.2021 31 | stable_1_5_pmemkv_version="a92abed550ece9c5c70b6be17db8e9cb19e328e4" 32 | 33 | prepare_pmemkv () { 34 | pmemkv_version="${1}" 35 | version_name="${2}" 36 | git checkout "${pmemkv_version}" 37 | mkdir /opt/"${version_name}" 38 | mkdir build 39 | cd build 40 | # turn off all redundant components 41 | cmake .. -DCPACK_GENERATOR="${PACKAGE_TYPE}" -DCMAKE_INSTALL_PREFIX=${PREFIX} \ 42 | -DBUILD_EXAMPLES=OFF -DBUILD_TESTS=OFF -DTESTS_USE_VALGRIND=OFF -DBUILD_DOC=OFF 43 | make -j$(nproc) package 44 | mv * /opt/"${version_name}" 45 | cd .. 46 | rm -rf build 47 | } 48 | 49 | git clone https://github.com/pmem/pmemkv 50 | cd pmemkv 51 | 52 | prepare_pmemkv "${current_pmemkv_version}" "pmemkv-master" 53 | prepare_pmemkv "${stable_1_4_pmemkv_version}" "pmemkv-stable-1.4" 54 | prepare_pmemkv "${stable_1_5_pmemkv_version}" "pmemkv-stable-1.5" 55 | 56 | cd .. 57 | rm -r pmemkv 58 | -------------------------------------------------------------------------------- /utils/docker/images/push-image.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | # Copyright 2016-2021, Intel Corporation 4 | 5 | # 6 | # push-image.sh - pushes the Docker image tagged as described in 7 | # ./build-image.sh, to the ${CONTAINER_REG}. 8 | # 9 | # The script utilizes ${CONTAINER_REG_USER} and ${CONTAINER_REG_PASS} variables to 10 | # log in to the ${CONTAINER_REG}. 11 | # 12 | 13 | set -e 14 | IMG_VER=${IMG_VER:-devel} 15 | TAG="${OS}-${OS_VER}-${IMG_VER}" 16 | 17 | if [[ -z "${OS}" || -z "${OS_VER}" ]]; then 18 | echo "ERROR: The variables OS and OS_VER have to be set " \ 19 | "(e.g. OS=fedora, OS_VER=32)." 20 | exit 1 21 | fi 22 | 23 | if [[ -z "${CONTAINER_REG}" ]]; then 24 | echo "ERROR: CONTAINER_REG environment variable is not set " \ 25 | "(e.g. \"//\")." 26 | exit 1 27 | fi 28 | 29 | if [[ -z "${CONTAINER_REG_USER}" || -z "${CONTAINER_REG_PASS}" ]]; then 30 | echo "ERROR: variables CONTAINER_REG_USER=\"${CONTAINER_REG_USER}\" " \ 31 | "and CONTAINER_REG_PASS=\"${CONTAINER_REG_PASS}\"" \ 32 | "have to be set properly to allow login to the Container Registry." 33 | exit 1 34 | fi 35 | 36 | echo "Check if the image tagged with ${CONTAINER_REG}:${TAG} exists locally" 37 | if [[ ! $(docker images -a | awk -v pattern="^${CONTAINER_REG}:${TAG}\$" \ 38 | '$1":"$2 ~ pattern') ]] 39 | then 40 | echo "ERROR: Docker image tagged ${CONTAINER_REG}:${TAG} does not exist locally." 41 | exit 1 42 | fi 43 | 44 | echo "Log in to the Container Registry: ${CONTAINER_REG}" 45 | echo "${CONTAINER_REG_PASS}" | docker login "${CONTAINER_REG}" -u="${CONTAINER_REG_USER}" --password-stdin 46 | 47 | echo "Push the image '${CONTAINER_REG}:${TAG}' to the Container Registry." 48 | docker push ${CONTAINER_REG}:${TAG} 49 | echo "Image pushed." 50 | -------------------------------------------------------------------------------- /utils/docker/images/setup-maven-settings.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | # Copyright 2021, Intel Corporation 4 | 5 | # 6 | # setup-maven-settings.sh - setup some extra settings for maven 7 | # It's executed in 'install-dependencies.sh', but it can also be 8 | # run locally (or in a custom docker container) to setup 9 | # these extra params for run-*.sh scripts. 10 | # 11 | 12 | # Split proxies into host & port; remove possible leftover "/" 13 | if [[ -n "${http_proxy}" ]]; then 14 | http_proxy_ip=$(echo ${http_proxy} | cut -d: -f2 | sed 's/\///g') 15 | http_proxy_port=$(echo ${http_proxy} | cut -d: -f3 | sed 's/\///g') 16 | fi 17 | if [[ -n "${https_proxy}" ]]; then 18 | https_proxy_ip=$(echo ${https_proxy} | cut -d: -f2 | sed 's/\///g') 19 | https_proxy_port=$(echo ${https_proxy} | cut -d: -f3 | sed 's/\///g') 20 | fi 21 | 22 | mvn_params='' 23 | [ -n "${http_proxy_ip}" ] && mvn_params="${mvn_params} -Dhttp.proxyHost=${http_proxy_ip}" 24 | [ -n "${http_proxy_port}" ] && mvn_params="${mvn_params} -Dhttp.proxyPort=${http_proxy_port}" 25 | [ -n "${https_proxy_ip}" ] && mvn_params="${mvn_params} -Dhttps.proxyHost=${https_proxy_ip}" 26 | [ -n "${https_proxy_port}" ] && mvn_params="${mvn_params} -Dhttps.proxyPort=${https_proxy_port}" 27 | 28 | # Export for current user/current shell 29 | export PMEMKV_MVN_PARAMS="${mvn_params}" 30 | -------------------------------------------------------------------------------- /utils/docker/prepare-for-build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | # Copyright 2019-2020, Intel Corporation 4 | 5 | # 6 | # prepare-for-build.sh - prepare the Docker image for the build 7 | # 8 | 9 | set -e 10 | 11 | PREFIX=/usr 12 | 13 | function sudo_password() { 14 | echo $USERPASS | sudo -Sk $* 15 | } 16 | 17 | function install_pmemkv() { 18 | pmemkv_version=${1} 19 | echo "Install pmemkv (${pmemkv_version}):" 20 | 21 | cd /opt/pmemkv-$pmemkv_version/ 22 | if [ "${PACKAGE_MANAGER}" = "deb" ]; then 23 | sudo_password dpkg -i libpmemkv*.deb 24 | elif [ "${PACKAGE_MANAGER}" = "rpm" ]; then 25 | sudo_password rpm -i libpmemkv*.rpm 26 | else 27 | echo "PACKAGE_MANAGER env variable not set or set improperly ('deb' or 'rpm' supported)." 28 | exit 1 29 | fi 30 | cd - 31 | } 32 | 33 | function use_preinstalled_java_deps() { 34 | mkdir -p ~/.m2/repository 35 | cp -r /opt/java/repository ~/.m2/ 36 | } 37 | 38 | function run_example() { 39 | example_name=${1} 40 | # Find current pmemkv-binding package and path to example's jar 41 | jar_path=$(find ../pmemkv-binding/target/ | grep -E "pmemkv-([0-9.]+).jar") 42 | example_path=$(find . | grep -E "${example_name}-([0-9.]+).jar$") 43 | 44 | java -ea -Xms1G -cp ${jar_path}:${example_path} ${example_name} 45 | } 46 | 47 | function run_standalone_example() { 48 | example_name=${1} 49 | # Find path to example's jar with dependencies 50 | example_path=$(find . | grep -E "${example_name}-([0-9.]+).jar-with-dependencies.jar$") 51 | 52 | java -ea -Xms1G -cp ${example_path} ${example_name} 53 | } 54 | 55 | # this should be run only on CIs 56 | if [ "$CI_RUN" == "YES" ]; then 57 | sudo_password chown -R $(id -u).$(id -g) $WORKDIR 58 | fi || true 59 | -------------------------------------------------------------------------------- /utils/docker/pull-or-rebuild-image.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | # Copyright 2016-2021, Intel Corporation 4 | 5 | # 6 | # pull-or-rebuild-image.sh - rebuilds the Docker image used in the 7 | # current build (if necessary) or pulls it from the Container Registry. 8 | # Docker image is tagged as described in ./images/build-image.sh, 9 | # but IMG_VER defaults in this script to "latest" (just in case it's 10 | # used locally without building any images). 11 | # 12 | # If Docker was rebuilt and all requirements are fulfilled (more details in 13 | # push_image function below) image will be pushed to the ${CONTAINER_REG}. 14 | # 15 | # The script rebuilds the Docker image if: 16 | # 1. the Dockerfile for the current OS version (Dockerfile.${OS}-${OS_VER}) 17 | # or any .sh script in the Dockerfiles directory were modified and committed, or 18 | # 2. "rebuild" param was passed as a first argument to this script. 19 | # 20 | # The script pulls the Docker image if: 21 | # 1. it does not have to be rebuilt (based on commited changes), or 22 | # 2. "pull" param was passed as a first argument to this script. 23 | # 24 | 25 | set -e 26 | 27 | source $(dirname $0)/set-ci-vars.sh 28 | 29 | IMG_VER=${IMG_VER:-latest} 30 | TAG="${OS}-${OS_VER}-${IMG_VER}" 31 | IMAGES_DIR_NAME=images 32 | BASE_DIR=utils/docker/${IMAGES_DIR_NAME} 33 | 34 | if [[ -z "${OS}" || -z "${OS_VER}" ]]; then 35 | echo "ERROR: The variables OS and OS_VER have to be set " \ 36 | "(e.g. OS=fedora, OS_VER=32)." 37 | exit 1 38 | fi 39 | 40 | if [[ -z "${CONTAINER_REG}" ]]; then 41 | echo "ERROR: CONTAINER_REG environment variable is not set " \ 42 | "(e.g. \"//\")." 43 | exit 1 44 | fi 45 | 46 | function build_image() { 47 | echo "Building the Docker image for the Dockerfile.${OS}-${OS_VER}" 48 | pushd ${IMAGES_DIR_NAME} 49 | ./build-image.sh 50 | popd 51 | } 52 | 53 | function pull_image() { 54 | echo "Pull the image '${CONTAINER_REG}:${TAG}' from the Container Registry." 55 | docker pull ${CONTAINER_REG}:${TAG} 56 | } 57 | 58 | function push_image { 59 | # Check if the image has to be pushed to the Container Registry: 60 | # - only upstream (not forked) repository, 61 | # - stable-* or master branch, 62 | # - not a pull_request event, 63 | # - and PUSH_IMAGE flag was set for current build. 64 | if [[ "${CI_REPO_SLUG}" == "${GITHUB_REPO}" \ 65 | && (${CI_BRANCH} == stable-* || ${CI_BRANCH} == master) \ 66 | && ${CI_EVENT_TYPE} != "pull_request" \ 67 | && ${PUSH_IMAGE} == "1" ]] 68 | then 69 | echo "The image will be pushed to the Container Registry: ${CONTAINER_REG}" 70 | pushd ${IMAGES_DIR_NAME} 71 | ./push-image.sh 72 | popd 73 | else 74 | echo "Skip pushing the image to the Container Registry." 75 | fi 76 | } 77 | 78 | # If "rebuild" or "pull" are passed to the script as param, force rebuild/pull. 79 | if [[ "${1}" == "rebuild" ]]; then 80 | build_image 81 | push_image 82 | exit 0 83 | elif [[ "${1}" == "pull" ]]; then 84 | pull_image 85 | exit 0 86 | fi 87 | 88 | # Determine if we need to rebuild the image or just pull it from 89 | # the Container Registry, based on commited changes. 90 | if [ -n "${CI_COMMIT_RANGE}" ]; then 91 | commits=$(git rev-list ${CI_COMMIT_RANGE}) 92 | else 93 | commits=${CI_COMMIT} 94 | fi 95 | 96 | if [[ -z "${commits}" ]]; then 97 | echo "'commits' variable is empty. Docker image will be pulled." 98 | fi 99 | 100 | echo "Commits in the commit range:" 101 | for commit in ${commits}; do echo ${commit}; done 102 | 103 | echo "Files modified within the commit range:" 104 | files=$(for commit in ${commits}; do git diff-tree --no-commit-id --name-only \ 105 | -r ${commit}; done | sort -u) 106 | for file in ${files}; do echo ${file}; done 107 | 108 | # Check if committed file modifications require the Docker image to be rebuilt 109 | for file in ${files}; do 110 | # Check if modified files are relevant to the current build 111 | if [[ ${file} =~ ^(${BASE_DIR})\/Dockerfile\.(${OS})-(${OS_VER})$ ]] \ 112 | || [[ ${file} =~ ^(${BASE_DIR})\/.*\.sh$ ]] 113 | then 114 | build_image 115 | push_image 116 | exit 0 117 | fi 118 | done 119 | 120 | # Getting here means rebuilding the Docker image isn't required (based on changed files). 121 | # Pull the image from the Container Registry or rebuild anyway, if pull fails. 122 | if ! pull_image; then 123 | build_image 124 | push_image 125 | fi 126 | -------------------------------------------------------------------------------- /utils/docker/run-build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | # Copyright 2019-2021, Intel Corporation 4 | 5 | # 6 | # run-build.sh - is called inside a Docker container; 7 | # checks bindings' building and installation with given version of pmemkv 8 | # 9 | 10 | set -e 11 | 12 | source $(dirname ${0})/prepare-for-build.sh 13 | MVN_PARAMS="${PMEMKV_MVN_PARAMS}" 14 | 15 | # install pmemkv 16 | pmemkv_version=${1} 17 | install_pmemkv ${pmemkv_version} 18 | 19 | echo 20 | echo "###########################################################" 21 | echo "### Verifying building and installing of the java bindings" 22 | echo "###########################################################" 23 | use_preinstalled_java_deps 24 | cd ${WORKDIR} 25 | mvn install -e ${MVN_PARAMS} 26 | 27 | echo 28 | echo "###########################################################" 29 | echo "### Verifying execution of examples" 30 | echo "###########################################################" 31 | cd examples 32 | run_example StringExample 33 | run_standalone_example StringExample 34 | run_example ByteBufferExample 35 | run_example MixedTypesExample 36 | run_example IteratorExample 37 | # PicturesExample is a GUI application, so just test compilation. 38 | run_example PicturesExample 39 | -------------------------------------------------------------------------------- /utils/docker/run-doc-update.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | # Copyright 2018-2022, Intel Corporation 4 | 5 | # 6 | # run-doc-update.sh - is called inside a Docker container, 7 | # to build docs for 'valid branches' and to create a pull request 8 | # with and update of javadocs, html files (on 'docs' branch). 9 | # 10 | 11 | set -e 12 | 13 | source $(dirname ${0})/prepare-for-build.sh 14 | 15 | if [[ -z "${DOC_UPDATE_GITHUB_TOKEN}" || -z "${DOC_UPDATE_BOT_NAME}" || -z "${DOC_REPO_OWNER}" ]]; then 16 | echo "To build documentation and upload it as a Github pull request, variables " \ 17 | "'DOC_UPDATE_BOT_NAME', 'DOC_REPO_OWNER' and 'DOC_UPDATE_GITHUB_TOKEN' have to " \ 18 | "be provided. For more details please read CONTRIBUTING.md" 19 | exit 0 20 | fi 21 | 22 | # Set up required variables 23 | BOT_NAME=${DOC_UPDATE_BOT_NAME} 24 | DOC_REPO_OWNER=${DOC_REPO_OWNER} 25 | REPO_NAME=${REPO:-"pmemkv-java"} 26 | export GITHUB_TOKEN=${DOC_UPDATE_GITHUB_TOKEN} # export for hub command 27 | REPO_DIR=$(mktemp -d -t pmemkvjava-XXX) 28 | ARTIFACTS_DIR=$(mktemp -d -t ARTIFACTS-XXX) 29 | MVN_PARAMS="${PMEMKV_MVN_PARAMS}" 30 | 31 | # Only 'master' or 'stable-*' branches are valid; determine docs location dir on 'docs' branch 32 | TARGET_BRANCH=${CI_BRANCH} 33 | if [[ "${TARGET_BRANCH}" == "master" ]]; then 34 | TARGET_DOCS_DIR="master" 35 | elif [[ ${TARGET_BRANCH} == stable-* ]]; then 36 | TARGET_DOCS_DIR=v$(echo ${TARGET_BRANCH} | cut -d"-" -f2 -s) 37 | else 38 | echo "Skipping docs build, this script should be run only on master or stable-* branches." 39 | echo "TARGET_BRANCH is set to: \'${TARGET_BRANCH}\'." 40 | exit 0 41 | fi 42 | if [ -z "${TARGET_DOCS_DIR}" ]; then 43 | echo "ERROR: Target docs location for branch: ${TARGET_BRANCH} is not set." 44 | exit 1 45 | fi 46 | 47 | ORIGIN="https://${GITHUB_TOKEN}@github.com/${BOT_NAME}/${REPO_NAME}" 48 | UPSTREAM="https://github.com/${DOC_REPO_OWNER}/${REPO_NAME}" 49 | 50 | install_pmemkv master 51 | 52 | pushd ${REPO_DIR} 53 | echo "Clone repo:" 54 | git clone ${ORIGIN} ${REPO_DIR} 55 | cd ${REPO_DIR} 56 | git remote add upstream ${UPSTREAM} 57 | 58 | git config --local user.name ${BOT_NAME} 59 | git config --local user.email "${BOT_NAME}@intel.com" 60 | hub config --global hub.protocol https 61 | 62 | git remote update 63 | git checkout -B ${TARGET_BRANCH} upstream/${TARGET_BRANCH} 64 | 65 | echo "Build docs:" 66 | use_preinstalled_java_deps 67 | mvn install -Dmaven.test.skip=true -e ${MVN_PARAMS} 68 | mvn javadoc:javadoc -e ${MVN_PARAMS} 69 | cp -r ${REPO_DIR}/pmemkv-binding/target/site/apidocs ${ARTIFACTS_DIR}/ 70 | 71 | # Checkout 'docs' branch and copy docs there 72 | GH_PAGES_NAME="${TARGET_DOCS_DIR}-docs-update" 73 | git checkout -B ${GH_PAGES_NAME} upstream/docs 74 | git clean -dfx 75 | 76 | # Clean old content, since some files might have been deleted 77 | rm -rf ./${TARGET_DOCS_DIR} 78 | mkdir -p ./${TARGET_DOCS_DIR}/html/ 79 | 80 | cp -rf ${ARTIFACTS_DIR}/apidocs/* ./${TARGET_DOCS_DIR}/html/ 81 | 82 | echo "Add and push changes:" 83 | # git commit command may fail if there is nothing to commit. 84 | # In that case we want to force push anyway (there might be open pull request with 85 | # changes which were reverted). 86 | git add -A 87 | git commit -m "doc: automatic docs update" && true 88 | git push -f ${ORIGIN} ${GH_PAGES_NAME} 89 | 90 | echo "Make or update pull request:" 91 | # When there is already an open PR or there are no changes an error is thrown, which we ignore. 92 | hub pull-request -f -b ${DOC_REPO_OWNER}:docs -h ${BOT_NAME}:${GH_PAGES_NAME} \ 93 | -m "doc: automatic docs update for ${TARGET_BRANCH}" && true 94 | 95 | popd 96 | -------------------------------------------------------------------------------- /utils/docker/run-maven-example.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | # Copyright 2019-2021, Intel Corporation 4 | 5 | # 6 | # run-maven-example.sh - is called inside a Docker container; 7 | # checks building of examples using pmemkv from maven repository 8 | # 9 | 10 | set -e 11 | 12 | source $(dirname ${0})/prepare-for-build.sh 13 | MVN_PARAMS="${PMEMKV_MVN_PARAMS}" 14 | 15 | echo 16 | echo "#############################################################" 17 | echo "### Apply patch (to use pmemkv from maven) and build examples" 18 | echo "#############################################################" 19 | cd ${WORKDIR}/examples 20 | 21 | # pmemkv package in maven repository has a bit different name 22 | # and there may be different version available. 23 | mvn package -Dpmemkv.packageName=pmemkv-root -Dpmemkv.packageVersion=1.2.0 -e ${MVN_PARAMS} 24 | 25 | echo 26 | echo "#############################################################" 27 | echo "### Verify execution of examples" 28 | echo "#############################################################" 29 | run_standalone_example StringExample 30 | run_standalone_example ByteBufferExample 31 | run_standalone_example MixedTypesExample 32 | run_standalone_example IteratorExample 33 | # PicturesExample is a GUI application, so just test compilation. 34 | run_standalone_example PicturesExample 35 | -------------------------------------------------------------------------------- /utils/docker/set-ci-vars.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | # Copyright 2020, Intel Corporation 4 | 5 | # 6 | # set-ci-vars.sh -- set CI variables common for both: 7 | # Travis and GitHub Actions CIs 8 | # 9 | 10 | set -e 11 | 12 | function get_commit_range_from_last_merge { 13 | # get commit id of the last merge 14 | LAST_MERGE=$(git log --merges --pretty=%H -1) 15 | LAST_COMMIT=$(git log --pretty=%H -1) 16 | RANGE_END="HEAD" 17 | if [ -n "$GITHUB_ACTIONS" ] && [ "$GITHUB_EVENT_NAME" == "pull_request" ] && [ "$LAST_MERGE" == "$LAST_COMMIT" ]; then 18 | # GitHub Actions commits its own merge in case of pull requests 19 | # so the first merge commit has to be skipped. 20 | 21 | LAST_COMMIT=$(git log --pretty=%H -2 | tail -n1) 22 | LAST_MERGE=$(git log --merges --pretty=%H -2 | tail -n1) 23 | # If still the last commit is a merge commit it means we're manually 24 | # merging changes (probably back from stable branch). We have to use 25 | # left parent of the merge and the current commit for COMMIT_RANGE. 26 | if [ "$LAST_MERGE" == "$LAST_COMMIT" ]; then 27 | LAST_MERGE=$(git log --merges --pretty=%P -2 | tail -n1 | cut -d" " -f1) 28 | RANGE_END=$LAST_COMMIT 29 | fi 30 | elif [ "$LAST_MERGE" == "$LAST_COMMIT" ] && 31 | ([ "$TRAVIS_EVENT_TYPE" == "push" ] || [ "$GITHUB_EVENT_NAME" == "push" ]); then 32 | # Other case in which last commit equals last merge, is when commiting 33 | # a manual merge. Push events don't set proper COMMIT_RANGE. 34 | # It has to be then set: from merge's left parent to the current commit. 35 | LAST_MERGE=$(git log --merges --pretty=%P -1 | cut -d" " -f1) 36 | fi 37 | if [ "$LAST_MERGE" == "" ]; then 38 | # possible in case of shallow clones 39 | # or new repos with no merge commits yet 40 | # - pick up the first commit 41 | LAST_MERGE=$(git log --pretty=%H | tail -n1) 42 | fi 43 | COMMIT_RANGE="$LAST_MERGE..$RANGE_END" 44 | # make sure it works now 45 | if ! git rev-list $COMMIT_RANGE >/dev/null; then 46 | COMMIT_RANGE="" 47 | fi 48 | echo $COMMIT_RANGE 49 | } 50 | 51 | COMMIT_RANGE_FROM_LAST_MERGE=$(get_commit_range_from_last_merge) 52 | 53 | if [ -n "$TRAVIS" ]; then 54 | CI_COMMIT=$TRAVIS_COMMIT 55 | CI_COMMIT_RANGE="${TRAVIS_COMMIT_RANGE/.../..}" 56 | CI_BRANCH=$TRAVIS_BRANCH 57 | CI_EVENT_TYPE=$TRAVIS_EVENT_TYPE 58 | CI_REPO_SLUG=$TRAVIS_REPO_SLUG 59 | 60 | # CI_COMMIT_RANGE is usually invalid for force pushes - fix it when used 61 | # with non-upstream repository 62 | if [ -n "$CI_COMMIT_RANGE" -a "$CI_REPO_SLUG" != "$GITHUB_REPO" ]; then 63 | if ! git rev-list $CI_COMMIT_RANGE; then 64 | CI_COMMIT_RANGE=$COMMIT_RANGE_FROM_LAST_MERGE 65 | fi 66 | fi 67 | 68 | case "$TRAVIS_CPU_ARCH" in 69 | "amd64") 70 | CI_CPU_ARCH="x86_64" 71 | ;; 72 | *) 73 | CI_CPU_ARCH=$TRAVIS_CPU_ARCH 74 | ;; 75 | esac 76 | 77 | elif [ -n "$GITHUB_ACTIONS" ]; then 78 | CI_COMMIT=$GITHUB_SHA 79 | CI_COMMIT_RANGE=$COMMIT_RANGE_FROM_LAST_MERGE 80 | CI_BRANCH=$(echo $GITHUB_REF | cut -d'/' -f3) 81 | CI_REPO_SLUG=$GITHUB_REPOSITORY 82 | CI_CPU_ARCH="x86_64" # GitHub Actions supports only x86_64 83 | 84 | case "$GITHUB_EVENT_NAME" in 85 | "schedule") 86 | CI_EVENT_TYPE="cron" 87 | ;; 88 | *) 89 | CI_EVENT_TYPE=$GITHUB_EVENT_NAME 90 | ;; 91 | esac 92 | 93 | else 94 | CI_COMMIT=$(git log --pretty=%H -1) 95 | CI_COMMIT_RANGE=$COMMIT_RANGE_FROM_LAST_MERGE 96 | CI_CPU_ARCH="x86_64" 97 | fi 98 | 99 | export CI_COMMIT=$CI_COMMIT 100 | export CI_COMMIT_RANGE=$CI_COMMIT_RANGE 101 | export CI_BRANCH=$CI_BRANCH 102 | export CI_EVENT_TYPE=$CI_EVENT_TYPE 103 | export CI_REPO_SLUG=$CI_REPO_SLUG 104 | export CI_CPU_ARCH=$CI_CPU_ARCH 105 | 106 | echo CI_COMMIT=$CI_COMMIT 107 | echo CI_COMMIT_RANGE=$CI_COMMIT_RANGE 108 | echo CI_BRANCH=$CI_BRANCH 109 | echo CI_EVENT_TYPE=$CI_EVENT_TYPE 110 | echo CI_REPO_SLUG=$CI_REPO_SLUG 111 | echo CI_CPU_ARCH=$CI_CPU_ARCH 112 | -------------------------------------------------------------------------------- /utils/eclipse-formatter-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | --------------------------------------------------------------------------------