├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── .travis.yml ├── LICENSE ├── README.md ├── debian ├── changelog ├── compat ├── control ├── debhelper.log ├── librados-java.docs ├── librados-java.install └── rules ├── mvnw ├── pom.xml └── src ├── main └── java │ └── com │ └── ceph │ ├── rados │ ├── Completion.java │ ├── IoCTX.java │ ├── Library.java │ ├── ListCtx.java │ ├── Rados.java │ ├── RadosBase.java │ ├── ReadOp.java │ ├── exceptions │ │ ├── ErrorCode.java │ │ ├── RadosAlreadyConnectedException.java │ │ ├── RadosArgumentOutOfDomainException.java │ │ ├── RadosException.java │ │ ├── RadosInvalidArgumentException.java │ │ ├── RadosNotFoundException.java │ │ ├── RadosOperationInProgressException.java │ │ ├── RadosPermissionException.java │ │ ├── RadosReadOnlyException.java │ │ └── RadosTimeoutException.java │ └── jna │ │ ├── Rados.java │ │ ├── RadosClusterInfo.java │ │ ├── RadosObjectInfo.java │ │ └── RadosPoolInfo.java │ ├── radosstriper │ ├── IoCTXStriper.java │ ├── Library.java │ ├── RadosStriper.java │ └── jna │ │ └── RadosStriper.java │ └── rbd │ ├── Library.java │ ├── Rbd.java │ ├── RbdException.java │ ├── RbdImage.java │ └── jna │ ├── Rbd.java │ ├── RbdImageInfo.java │ └── RbdSnapInfo.java └── test ├── docker ├── Dockerfile ├── entrypoint.sh ├── run-test.sh └── validate-cluster.sh └── java └── com └── ceph ├── rados ├── RadosBaseTest.java ├── TestRados.java └── exceptions │ └── ErrorCodeTest.java ├── radosstriper └── TestRadosStriper.java └── rbd └── TestRbd.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | *.jar 3 | ceph.conf 4 | keyring.* 5 | target 6 | *.iml 7 | .idea 8 | /.settings/ 9 | /ceph/ 10 | /.classpath 11 | /.project 12 | /bin/ 13 | build-indep-stamp 14 | configure-stamp 15 | debian/files 16 | debian/*.debhelper.log 17 | debian/*.substvars 18 | debian/librados-java 19 | pom.xml.releaseBackup 20 | release.properties 21 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceph/rados-java/f8838669e1527261cffc3bfeb4e7b953507bbeaa/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | 2 | sudo: required 3 | 4 | services: 5 | - docker 6 | 7 | before_install: 8 | - docker build -t rados-java-test src/test/docker 9 | 10 | script: 11 | - docker run -d --name rados-java-test --net=host -v $(pwd):/build -e MON_IP=$(ip -4 -o a | awk '/eth|ens|eno|enp/ { sub ("/..", "", $4); print $4 }') -e CEPH_PUBLIC_NETWORK=$(grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}/[0-9]\{1,2\}' /proc/net/fib_trie | grep -vE "^127|0$" | head -1) rados-java-test 12 | - sudo ./src/test/docker/validate-cluster.sh 13 | - docker exec -it rados-java-test /build/src/test/docker/run-test.sh 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Wido den Hollander 2 | 3 | 4 | Apache License 5 | Version 2.0, January 2004 6 | http://www.apache.org/licenses/ 7 | 8 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 9 | 10 | 1. Definitions. 11 | 12 | "License" shall mean the terms and conditions for use, reproduction, 13 | and distribution as defined by Sections 1 through 9 of this document. 14 | 15 | "Licensor" shall mean the copyright owner or entity authorized by 16 | the copyright owner that is granting the License. 17 | 18 | "Legal Entity" shall mean the union of the acting entity and all 19 | other entities that control, are controlled by, or are under common 20 | control with that entity. For the purposes of this definition, 21 | "control" means (i) the power, direct or indirect, to cause the 22 | direction or management of such entity, whether by contract or 23 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 24 | outstanding shares, or (iii) beneficial ownership of such entity. 25 | 26 | "You" (or "Your") shall mean an individual or Legal Entity 27 | exercising permissions granted by this License. 28 | 29 | "Source" form shall mean the preferred form for making modifications, 30 | including but not limited to software source code, documentation 31 | source, and configuration files. 32 | 33 | "Object" form shall mean any form resulting from mechanical 34 | transformation or translation of a Source form, including but 35 | not limited to compiled object code, generated documentation, 36 | and conversions to other media types. 37 | 38 | "Work" shall mean the work of authorship, whether in Source or 39 | Object form, made available under the License, as indicated by a 40 | copyright notice that is included in or attached to the work 41 | (an example is provided in the Appendix below). 42 | 43 | "Derivative Works" shall mean any work, whether in Source or Object 44 | form, that is based on (or derived from) the Work and for which the 45 | editorial revisions, annotations, elaborations, or other modifications 46 | represent, as a whole, an original work of authorship. For the purposes 47 | of this License, Derivative Works shall not include works that remain 48 | separable from, or merely link (or bind by name) to the interfaces of, 49 | the Work and Derivative Works thereof. 50 | 51 | "Contribution" shall mean any work of authorship, including 52 | the original version of the Work and any modifications or additions 53 | to that Work or Derivative Works thereof, that is intentionally 54 | submitted to Licensor for inclusion in the Work by the copyright owner 55 | or by an individual or Legal Entity authorized to submit on behalf of 56 | the copyright owner. For the purposes of this definition, "submitted" 57 | means any form of electronic, verbal, or written communication sent 58 | to the Licensor or its representatives, including but not limited to 59 | communication on electronic mailing lists, source code control systems, 60 | and issue tracking systems that are managed by, or on behalf of, the 61 | Licensor for the purpose of discussing and improving the Work, but 62 | excluding communication that is conspicuously marked or otherwise 63 | designated in writing by the copyright owner as "Not a Contribution." 64 | 65 | "Contributor" shall mean Licensor and any individual or Legal Entity 66 | on behalf of whom a Contribution has been received by Licensor and 67 | subsequently incorporated within the Work. 68 | 69 | 2. Grant of Copyright License. Subject to the terms and conditions of 70 | this License, each Contributor hereby grants to You a perpetual, 71 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 72 | copyright license to reproduce, prepare Derivative Works of, 73 | publicly display, publicly perform, sublicense, and distribute the 74 | Work and such Derivative Works in Source or Object form. 75 | 76 | 3. Grant of Patent License. Subject to the terms and conditions of 77 | this License, each Contributor hereby grants to You a perpetual, 78 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 79 | (except as stated in this section) patent license to make, have made, 80 | use, offer to sell, sell, import, and otherwise transfer the Work, 81 | where such license applies only to those patent claims licensable 82 | by such Contributor that are necessarily infringed by their 83 | Contribution(s) alone or by combination of their Contribution(s) 84 | with the Work to which such Contribution(s) was submitted. If You 85 | institute patent litigation against any entity (including a 86 | cross-claim or counterclaim in a lawsuit) alleging that the Work 87 | or a Contribution incorporated within the Work constitutes direct 88 | or contributory patent infringement, then any patent licenses 89 | granted to You under this License for that Work shall terminate 90 | as of the date such litigation is filed. 91 | 92 | 4. Redistribution. You may reproduce and distribute copies of the 93 | Work or Derivative Works thereof in any medium, with or without 94 | modifications, and in Source or Object form, provided that You 95 | meet the following conditions: 96 | 97 | (a) You must give any other recipients of the Work or 98 | Derivative Works a copy of this License; and 99 | 100 | (b) You must cause any modified files to carry prominent notices 101 | stating that You changed the files; and 102 | 103 | (c) You must retain, in the Source form of any Derivative Works 104 | that You distribute, all copyright, patent, trademark, and 105 | attribution notices from the Source form of the Work, 106 | excluding those notices that do not pertain to any part of 107 | the Derivative Works; and 108 | 109 | (d) If the Work includes a "NOTICE" text file as part of its 110 | distribution, then any Derivative Works that You distribute must 111 | include a readable copy of the attribution notices contained 112 | within such NOTICE file, excluding those notices that do not 113 | pertain to any part of the Derivative Works, in at least one 114 | of the following places: within a NOTICE text file distributed 115 | as part of the Derivative Works; within the Source form or 116 | documentation, if provided along with the Derivative Works; or, 117 | within a display generated by the Derivative Works, if and 118 | wherever such third-party notices normally appear. The contents 119 | of the NOTICE file are for informational purposes only and 120 | do not modify the License. You may add Your own attribution 121 | notices within Derivative Works that You distribute, alongside 122 | or as an addendum to the NOTICE text from the Work, provided 123 | that such additional attribution notices cannot be construed 124 | as modifying the License. 125 | 126 | You may add Your own copyright statement to Your modifications and 127 | may provide additional or different license terms and conditions 128 | for use, reproduction, or distribution of Your modifications, or 129 | for any such Derivative Works as a whole, provided Your use, 130 | reproduction, and distribution of the Work otherwise complies with 131 | the conditions stated in this License. 132 | 133 | 5. Submission of Contributions. Unless You explicitly state otherwise, 134 | any Contribution intentionally submitted for inclusion in the Work 135 | by You to the Licensor shall be under the terms and conditions of 136 | this License, without any additional terms or conditions. 137 | Notwithstanding the above, nothing herein shall supersede or modify 138 | the terms of any separate license agreement you may have executed 139 | with Licensor regarding such Contributions. 140 | 141 | 6. Trademarks. This License does not grant permission to use the trade 142 | names, trademarks, service marks, or product names of the Licensor, 143 | except as required for reasonable and customary use in describing the 144 | origin of the Work and reproducing the content of the NOTICE file. 145 | 146 | 7. Disclaimer of Warranty. Unless required by applicable law or 147 | agreed to in writing, Licensor provides the Work (and each 148 | Contributor provides its Contributions) on an "AS IS" BASIS, 149 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 150 | implied, including, without limitation, any warranties or conditions 151 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 152 | PARTICULAR PURPOSE. You are solely responsible for determining the 153 | appropriateness of using or redistributing the Work and assume any 154 | risks associated with Your exercise of permissions under this License. 155 | 156 | 8. Limitation of Liability. In no event and under no legal theory, 157 | whether in tort (including negligence), contract, or otherwise, 158 | unless required by applicable law (such as deliberate and grossly 159 | negligent acts) or agreed to in writing, shall any Contributor be 160 | liable to You for damages, including any direct, indirect, special, 161 | incidental, or consequential damages of any character arising as a 162 | result of this License or out of the use or inability to use the 163 | Work (including but not limited to damages for loss of goodwill, 164 | work stoppage, computer failure or malfunction, or any and all 165 | other commercial damages or losses), even if such Contributor 166 | has been advised of the possibility of such damages. 167 | 168 | 9. Accepting Warranty or Additional Liability. While redistributing 169 | the Work or Derivative Works thereof, You may choose to offer, 170 | and charge a fee for, acceptance of support, warranty, indemnity, 171 | or other liability obligations and/or rights consistent with this 172 | License. However, in accepting such obligations, You may act only 173 | on Your own behalf and on Your sole responsibility, not on behalf 174 | of any other Contributor, and only if You agree to indemnify, 175 | defend, and hold each Contributor harmless for any liability 176 | incurred by, or claims asserted against, such Contributor by reason 177 | of your accepting any such warranty or additional liability. 178 | 179 | END OF TERMS AND CONDITIONS -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RADOS Java 2 | These are Java bindings for [librados](https://docs.ceph.com/en/latest/rados/api/librados/) (C) which use JNA. 3 | 4 | Both RADOS and RBD are implemented in these bindings. 5 | 6 | By using JNA there is no need for building the bindings against any header 7 | you can use them on any system where JNA and librados are present. 8 | 9 | # Maven 10 | ## Building 11 | 12 | ```bash 13 | $ mvn clean install (-Dcom.ceph.rados.skipTests) 14 | ``` 15 | 16 | ## Tests 17 | 18 | ```bash 19 | $ mvn test 20 | ``` 21 | 22 | You can also run specific tests: 23 | 24 | ```bash 25 | mvn -Dtest=com.ceph.rados.TestRados 26 | ``` 27 | 28 | ```bash 29 | mvn -Dtest=com.ceph.rbd.TestRbd 30 | ``` 31 | 32 | # Unit Tests 33 | The tests require a running Ceph cluster. By default it will read /etc/ceph/ceph.conf 34 | and use "admin" as a cephx id. 35 | 36 | All tests will be performed on the pools "data" (RADOS) and "rbd" (RBD). 37 | 38 | These pools have to EXIST prior to running the tests and should be EMPTY! 39 | 40 | DO NOT RUN THESE TESTS ON A PRODUCTION PLATFORM. 41 | 42 | You can overrride this by setting these environment variables: 43 | * RADOS_JAVA_ID 44 | * RADOS_JAVA_CONFIG_FILE 45 | * RADOS_JAVA_POOL 46 | 47 | N.B.: You need to make sure jna.jar and junit.jar are present in /usr/share/java 48 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | librados-java (1.0) unstable; urgency=low 2 | 3 | * Release of version 1.0 4 | 5 | -- Wido den Hollander Fri, 11 Sep 2015 14:26:19 +0200 6 | 7 | librados-java (0.1.1) unstable; urgency=low 8 | 9 | * Release of version 0.1.1 10 | 11 | -- Wido den Hollander Wed, 22 May 2013 15:24:00 +0100 12 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: librados-java 2 | Section: libs 3 | Priority: extra 4 | Maintainer: Wido den Hollander 5 | Build-Depends: debhelper (>= 7), openjdk-7-jdk | openjdk-8-jdk, maven (>= 3) 6 | Standards-Version: 3.8.1 7 | Homepage: http://www.github.com/ceph/rados-java 8 | 9 | Package: librados-java 10 | Architecture: all 11 | Depends: librados2 (>= 0.80), librbd1 (>= 0.80) 12 | Description: Java JNA bindings for librados and librbd 13 | -------------------------------------------------------------------------------- /debian/debhelper.log: -------------------------------------------------------------------------------- 1 | dh_installdirs 2 | -------------------------------------------------------------------------------- /debian/librados-java.docs: -------------------------------------------------------------------------------- 1 | README 2 | LICENSE -------------------------------------------------------------------------------- /debian/librados-java.install: -------------------------------------------------------------------------------- 1 | /usr/share/java/rados-*.jar -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | export DH_VERBOSE=1 4 | export DH_OPTIONS 5 | 6 | VERSION := $(shell grep '^ ' pom.xml| cut -d'>' -f2 |cut -d'<' -f1) 7 | 8 | configure: configure-stamp 9 | configure-stamp: 10 | dh_testdir 11 | touch configure-stamp 12 | 13 | build: build-indep 14 | 15 | build-indep: build-indep-stamp 16 | 17 | build-indep-stamp: configure 18 | mvn clean 19 | mvn -DskipTests install 20 | touch $@ 21 | 22 | clean: 23 | dh_testdir 24 | dh_testroot 25 | rm -f build-arch-stamp build-indep-stamp configure-stamp 26 | dh_clean 27 | 28 | install: 29 | dh_testdir 30 | dh_testroot 31 | dh_prep -s 32 | 33 | mkdir -p debian/tmp/usr/share/java 34 | cp target/rados-${VERSION}.jar debian/tmp/usr/share/java 35 | dh_link usr/share/java/rados-${VERSION}.jar usr/share/java/rados.jar 36 | cp target/dependencies/jna*.jar debian/tmp/usr/share/java 37 | 38 | dh_installdirs 39 | dh_install 40 | 41 | binary: install 42 | dh_install 43 | dh_installchangelogs 44 | dh_link 45 | dh_compress 46 | dh_fixperms 47 | dh_installdeb 48 | dh_gencontrol 49 | dh_md5sums 50 | dh_builddeb 51 | -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # 58 | # Look for the Apple JDKs first to preserve the existing behaviour, and then look 59 | # for the new JDKs provided by Oracle. 60 | # 61 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then 62 | # 63 | # Apple JDKs 64 | # 65 | export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home 66 | fi 67 | 68 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then 69 | # 70 | # Apple JDKs 71 | # 72 | export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home 73 | fi 74 | 75 | if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then 76 | # 77 | # Oracle JDKs 78 | # 79 | export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home 80 | fi 81 | 82 | if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then 83 | # 84 | # Apple JDKs 85 | # 86 | export JAVA_HOME=`/usr/libexec/java_home` 87 | fi 88 | ;; 89 | esac 90 | 91 | if [ -z "$JAVA_HOME" ] ; then 92 | if [ -r /etc/gentoo-release ] ; then 93 | JAVA_HOME=`java-config --jre-home` 94 | fi 95 | fi 96 | 97 | if [ -z "$M2_HOME" ] ; then 98 | ## resolve links - $0 may be a link to maven's home 99 | PRG="$0" 100 | 101 | # need this for relative symlinks 102 | while [ -h "$PRG" ] ; do 103 | ls=`ls -ld "$PRG"` 104 | link=`expr "$ls" : '.*-> \(.*\)$'` 105 | if expr "$link" : '/.*' > /dev/null; then 106 | PRG="$link" 107 | else 108 | PRG="`dirname "$PRG"`/$link" 109 | fi 110 | done 111 | 112 | saveddir=`pwd` 113 | 114 | M2_HOME=`dirname "$PRG"`/.. 115 | 116 | # make it fully qualified 117 | M2_HOME=`cd "$M2_HOME" && pwd` 118 | 119 | cd "$saveddir" 120 | # echo Using m2 at $M2_HOME 121 | fi 122 | 123 | # For Cygwin, ensure paths are in UNIX format before anything is touched 124 | if $cygwin ; then 125 | [ -n "$M2_HOME" ] && 126 | M2_HOME=`cygpath --unix "$M2_HOME"` 127 | [ -n "$JAVA_HOME" ] && 128 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 129 | [ -n "$CLASSPATH" ] && 130 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 131 | fi 132 | 133 | # For Migwn, ensure paths are in UNIX format before anything is touched 134 | if $mingw ; then 135 | [ -n "$M2_HOME" ] && 136 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 137 | [ -n "$JAVA_HOME" ] && 138 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 139 | # TODO classpath? 140 | fi 141 | 142 | if [ -z "$JAVA_HOME" ]; then 143 | javaExecutable="`which javac`" 144 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 145 | # readlink(1) is not available as standard on Solaris 10. 146 | readLink=`which readlink` 147 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 148 | if $darwin ; then 149 | javaHome="`dirname \"$javaExecutable\"`" 150 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 151 | else 152 | javaExecutable="`readlink -f \"$javaExecutable\"`" 153 | fi 154 | javaHome="`dirname \"$javaExecutable\"`" 155 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 156 | JAVA_HOME="$javaHome" 157 | export JAVA_HOME 158 | fi 159 | fi 160 | fi 161 | 162 | if [ -z "$JAVACMD" ] ; then 163 | if [ -n "$JAVA_HOME" ] ; then 164 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 165 | # IBM's JDK on AIX uses strange locations for the executables 166 | JAVACMD="$JAVA_HOME/jre/sh/java" 167 | else 168 | JAVACMD="$JAVA_HOME/bin/java" 169 | fi 170 | else 171 | JAVACMD="`which java`" 172 | fi 173 | fi 174 | 175 | if [ ! -x "$JAVACMD" ] ; then 176 | echo "Error: JAVA_HOME is not defined correctly." >&2 177 | echo " We cannot execute $JAVACMD" >&2 178 | exit 1 179 | fi 180 | 181 | if [ -z "$JAVA_HOME" ] ; then 182 | echo "Warning: JAVA_HOME environment variable is not set." 183 | fi 184 | 185 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 186 | 187 | # For Cygwin, switch paths to Windows format before running java 188 | if $cygwin; then 189 | [ -n "$M2_HOME" ] && 190 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 191 | [ -n "$JAVA_HOME" ] && 192 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 193 | [ -n "$CLASSPATH" ] && 194 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 195 | fi 196 | 197 | # traverses directory structure from process work directory to filesystem root 198 | # first directory with .mvn subdirectory is considered project base directory 199 | find_maven_basedir() { 200 | local basedir=$(pwd) 201 | local wdir=$(pwd) 202 | while [ "$wdir" != '/' ] ; do 203 | if [ -d "$wdir"/.mvn ] ; then 204 | basedir=$wdir 205 | break 206 | fi 207 | wdir=$(cd "$wdir/.."; pwd) 208 | done 209 | echo "${basedir}" 210 | } 211 | 212 | # concatenates all lines of a file 213 | concat_lines() { 214 | if [ -f "$1" ]; then 215 | echo "$(tr -s '\n' ' ' < "$1")" 216 | fi 217 | } 218 | 219 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} 220 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 221 | 222 | # Provide a "standardized" way to retrieve the CLI args that will 223 | # work with both Windows and non-Windows executions. 224 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 225 | export MAVEN_CMD_LINE_ARGS 226 | 227 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 228 | 229 | exec "$JAVACMD" \ 230 | $MAVEN_OPTS \ 231 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 232 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 233 | ${WRAPPER_LAUNCHER} "$@" 234 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | com.ceph 6 | rados 7 | jar 8 | 0.7.0 9 | rados java bindings 10 | Java API for the RADOS C library 11 | https://ceph.io/ 12 | 13 | 14 | Apache License, Version 2.0 15 | http://www.apache.org/licenses/LICENSE-2.0.txt 16 | 17 | 18 | 19 | http://www.github.com/ceph/rados-java 20 | scm:git:https://github.com/ceph/rados-java 21 | scm:git:https://github.com/ceph/rados-java 22 | 23 | 24 | 25 | wido 26 | Wido den Hollander 27 | wido@denhollander.io 28 | https://blog.widodh.nl/ 29 | 30 | 31 | 32 | 33 | UTF-8 34 | false 35 | 36 | 37 | 38 | install 39 | 40 | 41 | org.apache.maven.plugins 42 | maven-release-plugin 43 | 2.5.2 44 | 45 | 46 | org.apache.maven.plugins 47 | maven-compiler-plugin 48 | 3.1 49 | 50 | 1.8 51 | 1.8 52 | 53 | 54 | 55 | org.apache.maven.plugins 56 | maven-dependency-plugin 57 | 58 | 59 | copy-dependencies 60 | package 61 | 62 | copy-dependencies 63 | 64 | 65 | ${project.build.directory}/dependencies 66 | runtime 67 | 68 | 69 | 70 | 71 | 72 | org.apache.maven.plugins 73 | maven-javadoc-plugin 74 | 2.10.3 75 | 76 | 77 | org.apache.maven.plugins 78 | maven-surefire-plugin 79 | 2.19.1 80 | 81 | ${com.ceph.rados.skipTests} 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | net.java.dev.jna 91 | jna 92 | 5.5.0 93 | 94 | 95 | 96 | junit 97 | junit 98 | 4.11 99 | test 100 | 101 | 102 | 103 | org.mockito 104 | mockito-all 105 | 1.10.19 106 | test 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rados/Completion.java: -------------------------------------------------------------------------------- 1 | package com.ceph.rados; 2 | 3 | import static com.ceph.rados.Library.rados; 4 | 5 | import java.io.Closeable; 6 | import java.io.IOException; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | import java.util.concurrent.Callable; 10 | 11 | import com.ceph.rados.exceptions.RadosException; 12 | import com.sun.jna.Callback; 13 | import com.sun.jna.Pointer; 14 | import com.sun.jna.ptr.PointerByReference; 15 | 16 | public class Completion extends RadosBase implements Closeable { 17 | // Static members 18 | private static Map completionMap = new HashMap<>(); 19 | private static int nextCompletionId = 1; 20 | 21 | // Instance members 22 | private boolean safe; 23 | private boolean complete; 24 | 25 | // Callback support 26 | private static Callback completeCallback = new Callback() { 27 | @SuppressWarnings("unused") 28 | public void callback(Pointer completionPointer, Pointer callbackContext) throws RadosException { 29 | final int completionId = (int) Pointer.nativeValue(callbackContext); 30 | Completion completion; 31 | synchronized (completionMap) { 32 | completion = completionMap.get(completionId); 33 | } 34 | 35 | // If the completion has not been closed yet, call the handler. 36 | if (completion != null) { 37 | completion.complete = true; 38 | completion.onComplete(); 39 | } 40 | } 41 | }; 42 | private static Callback safeCallback = new Callback() { 43 | @SuppressWarnings("unused") 44 | public void callback(Pointer completionPointer, Pointer callbackContext) throws RadosException { 45 | final int completionId = (int) Pointer.nativeValue(callbackContext); 46 | Completion completion; 47 | synchronized (completionMap) { 48 | completion = completionMap.get(completionId); 49 | } 50 | 51 | // If the completion has not been closed yet, call the handler. 52 | if (completion != null) { 53 | completion.safe = true; 54 | completion.onSafe(); 55 | } 56 | } 57 | }; 58 | 59 | // Instance members 60 | private Pointer pointer; 61 | private int id; 62 | 63 | /** 64 | * Constructs a completion to use with asynchronous operations. 65 | *

66 | * The complete and safe callbacks correspond to operations being acked and 67 | * committed, respectively. The callbacks are called in order of receipt, so 68 | * the safe callback may be triggered before the complete callback, and vice 69 | * versa. This is affected by journalling on the OSDs. 70 | *

71 | * NOTE: Read operations only get a complete callback. 72 | * 73 | * @param notifyOnComplete 74 | * If true, onComplete() is called when the operation is in 75 | * memory on all replicas 76 | * @param notifyOnSafe 77 | * If true, onSafe() is called when the operation is on stable 78 | * storage on all replicas 79 | * @throws RadosException 80 | */ 81 | public Completion(final boolean notifyOnComplete, final boolean notifyOnSafe) throws RadosException { 82 | super(); 83 | final PointerByReference pointerByReference = new PointerByReference(); 84 | 85 | // Generate an ID for this completion. 86 | synchronized (completionMap) { 87 | id = nextCompletionId++; 88 | if (id <= 0) { 89 | id = 1; 90 | nextCompletionId = 2; 91 | } 92 | 93 | // If callbacks will be registered, then also record this object in 94 | // the global completion map 95 | // so that it can be accessed from the callback handlers. 96 | if (notifyOnComplete || notifyOnSafe) 97 | completionMap.put(id, this); 98 | } 99 | 100 | // Create the completion object. 101 | if (notifyOnComplete || notifyOnSafe) { 102 | handleReturnCode(new Callable() { 103 | @Override 104 | public Integer call() throws Exception { 105 | return rados.rados_aio_create_completion(Pointer.createConstant((long) id), notifyOnComplete ? completeCallback : null, 106 | notifyOnSafe ? safeCallback : null, pointerByReference); 107 | } 108 | }, "Failed to create completion with callbacks"); 109 | 110 | } else { 111 | handleReturnCode(new Callable() { 112 | @Override 113 | public Integer call() throws Exception { 114 | return rados.rados_aio_create_completion(null, null, null, pointerByReference); 115 | } 116 | }, "Failed to create completion"); 117 | } 118 | pointer = pointerByReference.getValue(); 119 | } 120 | 121 | /** 122 | * Block until the operation completes. This means it is in memory on all 123 | * replicas. 124 | * 125 | * @throws RadosException 126 | */ 127 | public void waitForComplete() throws RadosException { 128 | handleReturnCode(new Callable() { 129 | @Override 130 | public Integer call() throws Exception { 131 | return rados.rados_aio_wait_for_complete(getPointer()); 132 | } 133 | }, "Failed to wait for AIO completion"); 134 | } 135 | 136 | /** 137 | * Block until the operation is safe. This means it is on stable storage on all 138 | * replicas. 139 | * 140 | * @throws RadosException 141 | */ 142 | public void waitForSafe() throws RadosException { 143 | handleReturnCode(new Callable() { 144 | @Override 145 | public Integer call() throws Exception { 146 | return rados.rados_aio_wait_for_safe(getPointer()); 147 | } 148 | }, "Failed to wait for AIO safe"); 149 | } 150 | 151 | /** 152 | * Override this function to implement callback handling. If notifyOnSafe is 153 | * true, this function is called when the operation is in memory on all 154 | * replicas. 155 | */ 156 | public void onComplete() { 157 | } 158 | 159 | /** 160 | * Override this function to implement callback handling. If 161 | * notifyOnComplete is true, this function is called when the operation is 162 | * on stable storage on all replicas. 163 | */ 164 | public void onSafe() { 165 | } 166 | 167 | /** 168 | * Release a completion 169 | *

170 | * Call this when you no longer need the completion. It may not be freed 171 | * immediately if the operation is not acked and committed. 172 | */ 173 | @Override 174 | public void close() throws IOException { 175 | rados.rados_aio_release(getPointer()); 176 | if (id > 0) { 177 | synchronized (completionMap) { 178 | completionMap.remove(id); 179 | } 180 | id = 0; 181 | } 182 | } 183 | 184 | /** 185 | * @return A unique ID identifying the completion. 186 | */ 187 | public int getId() { 188 | return id; 189 | } 190 | 191 | /** 192 | * @return True if the safe callback is enabled has occurred, else false. 193 | */ 194 | public boolean isSafe() { 195 | return safe; 196 | } 197 | 198 | /** 199 | * @return True if the complete callback is enabled has occurred, else 200 | * false. 201 | */ 202 | public boolean isComplete() { 203 | return complete; 204 | } 205 | 206 | public Pointer getPointer() { 207 | return pointer; 208 | } 209 | 210 | @Override 211 | public int hashCode() { 212 | final int prime = 31; 213 | int result = 1; 214 | result = prime * result + id; 215 | return result; 216 | } 217 | 218 | @Override 219 | public boolean equals(Object that) { 220 | if (this == that) 221 | return true; 222 | if (that == null) 223 | return false; 224 | if (!(that instanceof Completion)) 225 | return false; 226 | return (id == ((Completion) that).id); 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rados/Library.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados 3 | * 4 | * Copyright (C) 2013 Wido den Hollander 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | 19 | package com.ceph.rados; 20 | 21 | import com.ceph.rados.jna.Rados; 22 | 23 | import com.sun.jna.Native; 24 | import com.sun.jna.Pointer; 25 | 26 | import static java.nio.charset.StandardCharsets.UTF_8; 27 | 28 | final class Library { 29 | final static Rados rados; 30 | 31 | static { 32 | rados = Rados.INSTANCE; 33 | } 34 | 35 | private Library() {} 36 | 37 | /** 38 | * Free memory pointed to by ptr. 39 | */ 40 | static void free(Pointer ptr) { 41 | Pointer.nativeValue(ptr, 0L); 42 | } 43 | 44 | /** 45 | * Convert the data pointed to by {@code ptr} to a String. 46 | */ 47 | static String getString(Pointer ptr) { 48 | final long len = ptr.indexOf(0, (byte)0); 49 | assert (len != -1): "C-Strings must be \\0 terminated."; 50 | 51 | final byte[] data = ptr.getByteArray(0, (int)len); 52 | return new String(data, UTF_8); 53 | } 54 | 55 | /** 56 | * Calls {@link #toStringArray(Pointer[], int)}. 57 | */ 58 | static String[] toStringArray(Pointer[] ptrArr) { 59 | return toStringArray(ptrArr, ptrArr.length); 60 | } 61 | 62 | /** 63 | * Convert the given array of native pointers to "char" in 64 | * UTF-8 encoding to an array of Strings. 65 | * 66 | * note The memory used by the elements of the original array 67 | * is freed and ptrArr is modified. 68 | */ 69 | static String[] toStringArray(Pointer[] ptrArr, final int size) { 70 | try { 71 | final String[] result = new String[size]; 72 | for (int i = 0; i < size; ++i) { 73 | result[i] = Library.getString(ptrArr[i]); 74 | } 75 | return result; 76 | } finally { 77 | for (int i = 0; i < size; ++i) { 78 | Library.free(ptrArr[i]); 79 | ptrArr[i] = null; 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rados/ListCtx.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados 3 | * 4 | * Copyright (C) 2013 Wido den Hollander 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | 19 | package com.ceph.rados; 20 | 21 | import java.util.Arrays; 22 | 23 | import com.ceph.rados.exceptions.RadosException; 24 | 25 | import com.sun.jna.Memory; 26 | import com.sun.jna.Native; 27 | import com.sun.jna.Pointer; 28 | 29 | import static com.ceph.rados.Library.rados; 30 | 31 | /** 32 | * Used by 33 | */ 34 | public class ListCtx { 35 | Pointer list; 36 | String [] ids; 37 | int size; 38 | int limit; 39 | 40 | /** 41 | * @param limit 42 | * @param list 43 | */ 44 | protected ListCtx(int limit, Pointer list) { 45 | this.limit = limit; 46 | this.ids = new String[limit]; 47 | this.list = list; 48 | this.size = 0; 49 | } 50 | 51 | /** 52 | * List a subset of objects in a pool 53 | * 54 | * @return the number of ids get or 0 when the end of the list is reached 55 | * @throws RadosException 56 | */ 57 | public int nextObjects() throws RadosException { 58 | if (list == null) { 59 | return 0; 60 | } 61 | Pointer entry = new Memory(Native.POINTER_SIZE); 62 | int i = 0; 63 | while (i < limit && rados.rados_nobjects_list_next(list.getPointer(0), entry, null, null) == 0) { 64 | ids[i] = entry.getPointer(0).getString(0); 65 | i++; 66 | } 67 | if (i < limit) { 68 | // closing it 69 | rados.rados_nobjects_list_close(list.getPointer(0)); 70 | list = null; 71 | } 72 | this.size = i; 73 | return this.size; 74 | } 75 | /** 76 | * List a subset of objects in a pool after skipping a set of ids 77 | * 78 | * @param skip the number of skipped element 79 | * @return the number of ids get or 0 when the end of the list is reached 80 | * @throws RadosException 81 | */ 82 | public int nextObjects(long skip) throws RadosException { 83 | if (list == null) { 84 | return 0; 85 | } 86 | Pointer entry = new Memory(Native.POINTER_SIZE); 87 | long j = 0; 88 | while (j < skip && rados.rados_nobjects_list_next(list.getPointer(0), entry, null, null) == 0) { 89 | j++; 90 | } 91 | int i = 0; 92 | while (i < limit && rados.rados_nobjects_list_next(list.getPointer(0), entry, null, null) == 0) { 93 | ids[i] = entry.getPointer(0).getString(0); 94 | i++; 95 | } 96 | if (i < limit) { 97 | // closing it 98 | rados.rados_nobjects_list_close(list.getPointer(0)); 99 | list = null; 100 | } 101 | this.size = i; 102 | return this.size; 103 | } 104 | /** 105 | * 106 | * @return size of the returned Array 107 | */ 108 | public int size() { 109 | if (list == null) { 110 | return 0; 111 | } 112 | return this.size; 113 | } 114 | /** 115 | * 116 | * @return the Array of ids (limit by size and by the last call to nextObjects) 117 | */ 118 | public String[] getObjects() { 119 | return Arrays.copyOf(this.ids, this.size); 120 | } 121 | /** 122 | * Close the underlying pointer to list of objects 123 | */ 124 | public void close() { 125 | if (list != null) { 126 | rados.rados_nobjects_list_close(list.getPointer(0)); 127 | list = null; 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rados/Rados.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados 3 | * 4 | * Copyright (C) 2013 Wido den Hollander 5 | * Copyright (C) 2014 1&1 - Behar Veliqi 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with 9 | * the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, 14 | * software distributed under the License is distributed on 15 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 16 | * either express or implied. See the License for the specific 17 | * language governing permissions and limitations under the License. 18 | */ 19 | 20 | package com.ceph.rados; 21 | 22 | import com.ceph.rados.exceptions.RadosException; 23 | import com.ceph.rados.jna.RadosClusterInfo; 24 | import com.sun.jna.ptr.IntByReference; 25 | import com.sun.jna.ptr.PointerByReference; 26 | import com.sun.jna.Pointer; 27 | import com.sun.jna.Memory; 28 | import com.sun.jna.Native; 29 | 30 | import java.io.File; 31 | import java.util.concurrent.Callable; 32 | 33 | import static com.ceph.rados.Library.rados; 34 | 35 | public class Rados extends RadosBase { 36 | /** 37 | * flags for ReadOp.operate and (maybe later) WriteOp.operate 38 | * See librados operate flags for more information 39 | */ 40 | public static final int OPERATION_NOFLAG = 0; 41 | public static final int OPERATION_BALANCE_READS = 1; 42 | public static final int OPERATION_LOCALIZE_READS = 2; 43 | public static final int OPERATION_ORDER_READS_WRITES = 4; 44 | public static final int OPERATION_IGNORE_CACHE = 8; 45 | public static final int OPERATION_SKIPRWLOCKS = 16; 46 | public static final int OPERATION_IGNORE_OVERLAY = 32; 47 | public static final int OPERATION_FULL_TRY = 64; 48 | 49 | protected Pointer clusterPtr; 50 | private boolean connected; 51 | 52 | /** 53 | * Construct a RADOS Object which invokes rados_create 54 | * 55 | * @param id 56 | * the cephx id to authenticate with 57 | */ 58 | public Rados(String id) { 59 | PointerByReference clusterPtr = new PointerByReference(); 60 | rados.rados_create(clusterPtr, id); 61 | this.clusterPtr = clusterPtr.getValue(); 62 | } 63 | 64 | 65 | /** 66 | * Construct a RADOS Object which invokes rados_create2 67 | * 68 | * @param clustername The name of the cluster (usually "ceph"). 69 | * @param name The name of the user (e.g., client.admin, client.user) 70 | * @param flags Flag options (future use). 71 | */ 72 | 73 | public Rados (String clustername, String name, long flags) { 74 | PointerByReference clusterPtr = new PointerByReference(); 75 | rados.rados_create2(clusterPtr, clustername, name, flags); 76 | this.clusterPtr = clusterPtr.getValue(); 77 | } 78 | 79 | 80 | /** 81 | * Construct a RADOS Object which invokes rados_create 82 | */ 83 | public Rados() { 84 | this(null); 85 | } 86 | 87 | /** 88 | * Some methods should not be called when not connected 89 | * or vise versa 90 | */ 91 | private void verifyConnected(boolean required) throws RadosException { 92 | if (required && !this.connected) { 93 | throw new RadosException("This method should not be called in a disconnected state."); 94 | } 95 | if (!required && this.connected) { 96 | throw new RadosException("This method should not be called in a connected state."); 97 | } 98 | } 99 | 100 | /** 101 | * Read a Ceph configuration file 102 | * 103 | * @param file 104 | * A file object with the path to a ceph.conf 105 | * @throws RadosException 106 | */ 107 | public void confReadFile(final File file) throws RadosException { 108 | handleReturnCode(new Callable() { 109 | @Override 110 | public Integer call() throws Exception { 111 | return rados.rados_conf_read_file(clusterPtr, file.getAbsolutePath()); 112 | } 113 | }, "Failed reading configuration file %s", file.getAbsolutePath()); 114 | } 115 | 116 | /** 117 | * Set a RADOS configuration option 118 | * 119 | * @param option 120 | * the name of the option 121 | * @param value 122 | * the value configuration value 123 | * @throws RadosException 124 | */ 125 | public void confSet(final String option, final String value) throws RadosException { 126 | handleReturnCode(new Callable() { 127 | @Override 128 | public Integer call() throws Exception { 129 | return rados.rados_conf_set(clusterPtr, option, value); 130 | } 131 | }, "Could not set configuration option %s", option); 132 | } 133 | 134 | /** 135 | * Retrieve a RADOS configuration option's value 136 | * 137 | * @param option 138 | * the name of the option 139 | * @return 140 | * the value of the option 141 | * @throws RadosException 142 | */ 143 | public String confGet(final String option) throws RadosException { 144 | final byte[] buf = new byte[256]; 145 | handleReturnCode(new Callable() { 146 | @Override 147 | public Integer call() throws Exception { 148 | return rados.rados_conf_get(clusterPtr, option, buf, buf.length); 149 | } 150 | }, "Unable to retrieve the value of configuration option %s", option); 151 | return Native.toString(buf); 152 | } 153 | 154 | /** 155 | * Connect to the Ceph cluster 156 | * 157 | * @throws RadosException 158 | */ 159 | public void connect() throws RadosException { 160 | handleReturnCode(new Callable() { 161 | @Override 162 | public Integer call() throws Exception { 163 | return rados.rados_connect(clusterPtr); 164 | } 165 | }, "Failed to connect to the Ceph cluster"); 166 | this.connected = true; 167 | } 168 | 169 | /** 170 | * Get the cluster's fsid 171 | * 172 | * @return 173 | * A string containing the cluster's fsid 174 | * @throws RadosException 175 | */ 176 | public String clusterFsid() throws RadosException { 177 | this.verifyConnected(true); 178 | final byte[] buf = new byte[256]; 179 | handleReturnCode(new Callable() { 180 | @Override 181 | public Integer call() throws Exception { 182 | return rados.rados_cluster_fsid(clusterPtr, buf, buf.length); 183 | } 184 | }, "Failed to retrieve the cluster's fsid"); 185 | return Native.toString(buf); 186 | } 187 | 188 | /** 189 | * Get the cluster stats 190 | * 191 | * @return RadosClusterInfo 192 | * @throws RadosException 193 | */ 194 | public RadosClusterInfo clusterStat() throws RadosException { 195 | this.verifyConnected(true); 196 | final RadosClusterInfo result = new RadosClusterInfo(); 197 | handleReturnCode(new Callable() { 198 | @Override 199 | public Integer call() throws Exception { 200 | return rados.rados_cluster_stat(clusterPtr, result); 201 | } 202 | }, "Failed to retrieve cluster's status"); 203 | return result; 204 | } 205 | 206 | /** 207 | * Create a RADOS pool 208 | * 209 | * @param name 210 | * the name of the pool to be created 211 | * @throws RadosException 212 | */ 213 | public void poolCreate(final String name) throws RadosException { 214 | this.verifyConnected(true); 215 | handleReturnCode(new Callable() { 216 | @Override 217 | public Integer call() throws Exception { 218 | return rados.rados_pool_create(clusterPtr, name); 219 | } 220 | }, "Failed to create pool %s", name); 221 | } 222 | 223 | /** 224 | * Create a RADOS pool and set a auid 225 | * 226 | * @param name 227 | * the name of the pool to be created 228 | * @param auid 229 | * the owner ID for the new pool 230 | * @throws RadosException 231 | */ 232 | public void poolCreate(final String name, final long auid) throws RadosException { 233 | this.verifyConnected(true); 234 | handleReturnCode(new Callable() { 235 | @Override 236 | public Integer call() throws Exception { 237 | return rados.rados_pool_create_with_auid(clusterPtr, name, auid); 238 | } 239 | }, "Failed to create pool %s with auid %s", name, auid); 240 | } 241 | 242 | /** 243 | * Create a RADOS pool and set a auid and crushrule 244 | * 245 | * @param name 246 | * the name of the pool to be created 247 | * @param auid 248 | * the owner ID for the new pool 249 | * @param crushrule 250 | * the crushrule for this pool 251 | * @throws RadosException 252 | */ 253 | public void poolCreate(final String name, final long auid, final long crushrule) throws RadosException { 254 | this.verifyConnected(true); 255 | handleReturnCode(new Callable() { 256 | @Override 257 | public Integer call() throws Exception { 258 | return rados.rados_pool_create_with_all(clusterPtr, name, auid, crushrule); 259 | } 260 | }, "Failed to create pool %s with auid %s and crushrule %s", name, auid, crushrule); 261 | } 262 | 263 | /** 264 | * Delete a RADOS pool 265 | * 266 | * @param name 267 | * the name of the pool to be deleted 268 | * @throws RadosException 269 | */ 270 | public void poolDelete(final String name) throws RadosException { 271 | this.verifyConnected(true); 272 | handleReturnCode(new Callable() { 273 | @Override 274 | public Integer call() throws Exception { 275 | return rados.rados_pool_delete(clusterPtr, name); 276 | } 277 | }, "Failed to delete pool %s", name); 278 | } 279 | 280 | /** 281 | * Java finalizer to make sure librados is correctly released if shutDown has not been called explicitly. 282 | */ 283 | protected void finalize() throws Throwable { 284 | // make sure that librados is correctly released 285 | if (this.clusterPtr != null) { 286 | rados.rados_shutdown(this.clusterPtr); 287 | this.clusterPtr = null; 288 | } 289 | super.finalize(); 290 | } 291 | 292 | /** 293 | * List all the RADOS pools 294 | * 295 | * @return String[] list of pools 296 | * @throws RadosException 297 | */ 298 | public String[] poolList() throws RadosException { 299 | this.verifyConnected(true); 300 | byte[] temp_buf = new byte[0]; 301 | int len = rados.rados_pool_list(this.clusterPtr, temp_buf, temp_buf.length); 302 | final byte[] buf = getPoolList(len); 303 | return new String(buf).split("\0"); 304 | } 305 | 306 | private byte[] getPoolList(int len) throws RadosException { 307 | final byte[] buf = new byte[len]; 308 | handleReturnCode(new Callable() { 309 | @Override 310 | public Integer call() throws Exception { 311 | return rados.rados_pool_list(clusterPtr, buf, buf.length); 312 | } 313 | }, "Failed to retrieve list of pools"); 314 | return buf; 315 | } 316 | 317 | /** 318 | * Get the ID of a RADOS pool 319 | * 320 | * @param name 321 | * The name of the pool 322 | * @return long 323 | * @throws RadosException 324 | */ 325 | public long poolLookup(final String name) throws RadosException { 326 | return handleReturnCode(new Callable() { 327 | @Override 328 | public Long call() throws Exception { 329 | return rados.rados_pool_lookup(Rados.this.clusterPtr, name); 330 | } 331 | }, "Failed to retrieve id of the pool"); 332 | } 333 | 334 | /** 335 | * Get the name of a RADOS pool 336 | * 337 | * @param id 338 | * The id of the pool 339 | * @return String 340 | * @throws RadosException 341 | */ 342 | public String poolReverseLookup(final long id) throws RadosException { 343 | final byte[] buf = new byte[512]; 344 | handleReturnCode(new Callable() { 345 | @Override 346 | public Integer call() throws Exception { 347 | return rados.rados_pool_reverse_lookup(clusterPtr, id, buf, buf.length); 348 | } 349 | }, "Failed to fetch name of the pool"); 350 | return new String(buf).trim(); 351 | } 352 | 353 | /** 354 | * Create a IoCTX 355 | * 356 | * @param pool 357 | * The name of the RADOS pool 358 | * @return IoCTX 359 | * @throws RadosException 360 | */ 361 | public IoCTX ioCtxCreate(final String pool) throws RadosException { 362 | final Pointer p = new Memory(Native.POINTER_SIZE); 363 | handleReturnCode(new Callable() { 364 | @Override 365 | public Integer call() throws Exception { 366 | return rados.rados_ioctx_create(clusterPtr, pool, p); 367 | } 368 | }, "Failed to create the IoCTX for pool %s", pool); 369 | return new IoCTX(p); 370 | } 371 | 372 | /** 373 | * Destroy a IoCTX 374 | * 375 | * @param io 376 | * A IoCTX object 377 | */ 378 | public void ioCtxDestroy(IoCTX io) { 379 | rados.rados_ioctx_destroy(io.getPointer()); 380 | } 381 | 382 | 383 | /** 384 | * Get the global unique ID of the current connection 385 | * 386 | * @return long 387 | */ 388 | public long getInstanceId() throws RadosException { 389 | this.verifyConnected(true); 390 | return rados.rados_get_instance_id(this.clusterPtr); 391 | } 392 | 393 | /** 394 | * Get the librados version 395 | * 396 | * @return a int array with the minor, major and extra version 397 | */ 398 | public static int[] getVersion() { 399 | IntByReference minor = new IntByReference(); 400 | IntByReference major = new IntByReference(); 401 | IntByReference extra = new IntByReference(); 402 | rados.rados_version(minor, major, extra); 403 | return new int[]{minor.getValue(), major.getValue(), extra.getValue()}; 404 | } 405 | 406 | /** 407 | * Shuts rados down 408 | */ 409 | public void shutDown() { 410 | if (this.clusterPtr != null) { 411 | rados.rados_shutdown(this.clusterPtr); 412 | this.clusterPtr = null; 413 | } 414 | } 415 | 416 | /** 417 | * Executes commands in module: 'mon' 418 | * 419 | * To list commands execute "get_command_descriptions" 420 | * 421 | * @param commands Commands to execute 422 | * @param in inputbuffer 423 | * @return Returns a RadosCommandResult-object 424 | * @throws RadosException 425 | */ 426 | public RadosCommandResult executeRadosMonCommand(final String[] commands, final String in) throws RadosException { 427 | final PointerByReference outBuf = new PointerByReference(); 428 | final IntByReference outBufLen = new IntByReference(); 429 | final PointerByReference statusBuf = new PointerByReference(); 430 | final IntByReference statusBufLen = new IntByReference(); 431 | 432 | int r = rados.rados_mon_command(this.clusterPtr, commands, commands.length, in, in.length(), outBuf, outBufLen, statusBuf, statusBufLen); 433 | 434 | final String status = (statusBuf.getValue() == null ? "" : new String(statusBuf.getValue().getByteArray(0, statusBufLen.getValue()))); 435 | 436 | if (r != 0) 437 | throw new RadosException("Error when executing Rados monitor commands: " + status, r); 438 | 439 | final String out = (outBuf.getValue() == null ? "" : new String(outBuf.getValue().getByteArray(0, outBufLen.getValue()))); 440 | 441 | return new RadosCommandResult(out, status); 442 | } 443 | 444 | /** 445 | * Executes commands in module: 'mon' 446 | * 447 | * To list commands execute "get_command_descriptions" 448 | * 449 | * @param commands Command to execute 450 | * @param target Monitor target to execute commands 451 | * @param in inputbuffer 452 | * @return Returns a RadosCommandResult-object 453 | * @throws RadosException 454 | */ 455 | public RadosCommandResult executeRadosMonCommandTarget(final String[] commands, final String target, final String in) throws RadosException { 456 | final PointerByReference outBuf = new PointerByReference(); 457 | final IntByReference outBufLen = new IntByReference(); 458 | final PointerByReference statusBuf = new PointerByReference(); 459 | final IntByReference statusBufLen = new IntByReference(); 460 | 461 | int r = rados.rados_mon_command_target(this.clusterPtr, target, commands, commands.length, in, in.length(), outBuf, outBufLen, statusBuf, statusBufLen); 462 | 463 | final String status = (statusBuf.getValue() == null ? "" : new String(statusBuf.getValue().getByteArray(0, statusBufLen.getValue()))); 464 | 465 | if (r != 0) 466 | throw new RadosException("Error when executing Rados monitor commands: " + status, r); 467 | 468 | final String out = (outBuf.getValue() == null ? "" : new String(outBuf.getValue().getByteArray(0, outBufLen.getValue()))); 469 | 470 | return new RadosCommandResult(out, status); 471 | } 472 | 473 | /** 474 | * Executes commands in module: 'osd' 475 | * 476 | * To list commands execute "get_command_descriptions" 477 | * 478 | * @param commands Command to execute 479 | * @param osdId OSD used to process this commands 480 | * @param in inputbuffer 481 | * @return Returns a RadosCommandResult-object 482 | * @throws RadosException 483 | */ 484 | public RadosCommandResult executeRadosOsdCommand(final String[] commands, final int osdId, final String in) throws RadosException { 485 | final PointerByReference outBuf = new PointerByReference(); 486 | final IntByReference outBufLen = new IntByReference(); 487 | final PointerByReference statusBuf = new PointerByReference(); 488 | final IntByReference statusBufLen = new IntByReference(); 489 | 490 | int r = rados.rados_osd_command(this.clusterPtr, osdId, commands, commands.length, in, in.length(), outBuf, outBufLen, statusBuf, statusBufLen); 491 | 492 | final String status = (statusBuf.getValue() == null ? "" : new String(statusBuf.getValue().getByteArray(0, statusBufLen.getValue()))); 493 | 494 | if (r != 0) 495 | throw new RadosException("Error when executing Rados osd command: " + status, r); 496 | 497 | final String out = (outBuf.getValue() == null ? "" : new String(outBuf.getValue().getByteArray(0, outBufLen.getValue()))); 498 | 499 | return new RadosCommandResult(out, status); 500 | } 501 | 502 | /** 503 | * Result returned by RadosCommands 504 | */ 505 | public class RadosCommandResult { 506 | 507 | private final String output; 508 | private final String statusOutput; 509 | 510 | protected RadosCommandResult(String output, String statusOutput) { 511 | this.output = output; 512 | this.statusOutput = statusOutput; 513 | } 514 | 515 | /** 516 | * Get the output of the RadosCommand 517 | * 518 | * @return a String containing the output of the RadosCommand 519 | */ 520 | public String getOutput() { 521 | return output; 522 | } 523 | 524 | /** 525 | * Get the status of the RadosCommand 526 | * 527 | * @return a String containing the status of the RadosCommand 528 | */ 529 | public String getStatus() { 530 | return statusOutput; 531 | } 532 | } 533 | } 534 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rados/RadosBase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados 3 | * 4 | * Copyright (C) 2014 1&1 - Behar Veliqi 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | package com.ceph.rados; 19 | 20 | import com.ceph.rados.exceptions.ErrorCode; 21 | import com.ceph.rados.exceptions.RadosAlreadyConnectedException; 22 | import com.ceph.rados.exceptions.RadosArgumentOutOfDomainException; 23 | import com.ceph.rados.exceptions.RadosException; 24 | import com.ceph.rados.exceptions.RadosInvalidArgumentException; 25 | import com.ceph.rados.exceptions.RadosNotFoundException; 26 | import com.ceph.rados.exceptions.RadosOperationInProgressException; 27 | import com.ceph.rados.exceptions.RadosPermissionException; 28 | import com.ceph.rados.exceptions.RadosReadOnlyException; 29 | import com.ceph.rados.exceptions.RadosTimeoutException; 30 | 31 | import java.util.concurrent.Callable; 32 | 33 | /** 34 | * Base class for doing all the exception handling. 35 | */ 36 | public class RadosBase { 37 | 38 | /** 39 | * @param callable to be called 40 | * @param errorMsg the error message to be used if any errors occur 41 | * @param errorMsgArgs the arguments for the error message 42 | * @param the type of number for the return value (Integer, Long, ...) 43 | * @return the value returned by the callable 44 | * @throws RadosException if callable throws an exception or returns a negative value 45 | */ 46 | final protected T handleReturnCode(Callable callable, String errorMsg, Object... errorMsgArgs) 47 | throws RadosException { 48 | T result = call(callable); 49 | if (result.intValue() < 0) { 50 | throwException(result.intValue(), String.format(errorMsg, errorMsgArgs)); 51 | } 52 | return result; 53 | } 54 | 55 | private T call(Callable callable) throws RadosException { 56 | T result; 57 | try { 58 | result = callable.call(); 59 | } catch (Exception ex) { 60 | final String unknownErrorMsg = String.format("Unknown exception: %s: %s", 61 | ex.getClass().getSimpleName(), ex.getMessage()); 62 | throw new RadosException(unknownErrorMsg, ex); 63 | } 64 | return result; 65 | } 66 | 67 | public static void throwException(int errorCode, String msg) throws RadosException { 68 | String exceptionMessage; 69 | ErrorCode errorCodeEnum = ErrorCode.getEnum(errorCode); 70 | if (errorCodeEnum != null) { 71 | exceptionMessage = String.format("%s; %s: %s", msg, errorCodeEnum.name(), errorCodeEnum.getErrorMessage()); 72 | switch (errorCodeEnum) { 73 | case EPERM: 74 | throw new RadosPermissionException(exceptionMessage, errorCode); 75 | case ENOENT: 76 | throw new RadosNotFoundException(exceptionMessage, errorCode); 77 | case EINVAL: 78 | throw new RadosInvalidArgumentException(exceptionMessage, errorCode); 79 | case EROFS: 80 | throw new RadosReadOnlyException(exceptionMessage, errorCode); 81 | case EDOM: 82 | throw new RadosArgumentOutOfDomainException(exceptionMessage, errorCode); 83 | case EISCONN: 84 | throw new RadosAlreadyConnectedException(exceptionMessage, errorCode); 85 | case ETIMEDOUT: 86 | throw new RadosTimeoutException(exceptionMessage, errorCode); 87 | case EINPROGRESS: 88 | throw new RadosOperationInProgressException(exceptionMessage, errorCode); 89 | } 90 | } else { 91 | exceptionMessage = String.format("%s; error code: %d", msg, errorCode); 92 | } 93 | 94 | throw new RadosException(exceptionMessage, errorCode); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rados/ReadOp.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with 6 | * the License. You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, 11 | * software distributed under the License is distributed on 12 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 13 | * either express or implied. See the License for the specific 14 | * language governing permissions and limitations under the License. 15 | * 16 | * *********** 17 | * * history * 18 | * *********** 19 | * 2014-08-15 - initial implementation supporting ranged reads only 20 | */ 21 | 22 | package com.ceph.rados; 23 | 24 | import static com.ceph.rados.Library.rados; 25 | 26 | import java.nio.ByteBuffer; 27 | import java.util.concurrent.Callable; 28 | 29 | import com.ceph.rados.exceptions.RadosException; 30 | 31 | import com.sun.jna.Pointer; 32 | import com.sun.jna.ptr.IntByReference; 33 | import com.sun.jna.ptr.LongByReference; 34 | 35 | public class ReadOp extends RadosBase implements AutoCloseable { 36 | 37 | public static class ReadResult { 38 | private final ByteBuffer buf; 39 | final LongByReference bytesread; 40 | final IntByReference rval; 41 | ReadResult(long buflen) throws RadosException { 42 | if ( buflen > Integer.MAX_VALUE ) { 43 | throw new RadosException("rados_read_op_read Java byte[] buffer cannot be longer than "+Integer.MAX_VALUE); 44 | } 45 | buf = ByteBuffer.allocateDirect((int) buflen); 46 | bytesread = new LongByReference(); 47 | rval = new IntByReference(); 48 | } 49 | public ByteBuffer getBuffer() { return buf; } 50 | public long getBytesRead() { return bytesread.getValue(); } 51 | public int getRVal() { return rval.getValue(); } 52 | 53 | /** 54 | * Use this method if you do error handling with exceptions. 55 | * 56 | * Use it like the following: 57 | * ReadOp readOp = iocontext.readOpCreate(); 58 | * ReadOp.ReadResult readResult = readOp.queueRead(offset, size); 59 | * ... 60 | * readOp.operate(name, flags); 61 | * readResult.raiseExceptionOnError(); 62 | * // here you can be sure that the read operation has been successful 63 | * 64 | * 65 | * @param errorMsg the error message to use for the exception. Can be a format string 66 | * @param errorMsgArgs the arguments for the error message if the message is a format string 67 | * @throws RadosException Thrown if the result of the operation is not successful 68 | */ 69 | public void raiseExceptionOnError(String errorMsg, Object... errorMsgArgs) throws RadosException { 70 | int returnCode = getRVal(); 71 | if (returnCode < 0) { 72 | throwException(returnCode, String.format(errorMsg, errorMsgArgs)); 73 | } 74 | } 75 | } 76 | 77 | private final Pointer ioctxPtr; 78 | private Pointer readOpPtr; 79 | 80 | /** 81 | * Create a new read_op object. 82 | * 83 | * This constructor should never be called, ReadOp 84 | * objects are created by the IoCTX class and returned 85 | * when creating a ReadOp there. 86 | */ 87 | ReadOp(Pointer ioctx_p, Pointer readop_p) { 88 | this.ioctxPtr = ioctx_p; 89 | this.readOpPtr = readop_p; 90 | } 91 | 92 | Pointer getPointer() { 93 | return readOpPtr; 94 | } 95 | 96 | /** 97 | * Add a read operation to the rados_read_op_t via rados_read_op_read. Note returned 98 | * ReadResult is not populated until after the operate() call. 99 | * 100 | * @param offset starting offset into the object 101 | * @param len length of the read 102 | * @return Java object which will hold results of the requested read after operate() is called 103 | * @throws RadosException 104 | */ 105 | public ReadResult queueRead(long offset, long len) throws RadosException { 106 | ReadResult r = new ReadResult(len); 107 | rados.rados_read_op_read(readOpPtr, offset, len, r.getBuffer(), r.bytesread, r.rval); 108 | return r; 109 | } 110 | 111 | /** 112 | * Executes operations added to the rados_read_op_t. 113 | * 114 | * @param oid the name of the object to operate on 115 | * @param flags the flags for the operation 116 | * @return rados_read_op_operate return value 117 | * @see librados operation flags 118 | */ 119 | public void operate(final String oid, final int flags) throws RadosException { 120 | handleReturnCode(new Callable() { 121 | @Override 122 | public Number call() throws Exception { 123 | return rados.rados_read_op_operate(readOpPtr, ioctxPtr, oid, flags); 124 | } 125 | }, "ReadOp.operate(%s, %d)", oid, flags); 126 | } 127 | 128 | @Override 129 | public void close() { 130 | if (readOpPtr != null) { 131 | rados.rados_release_read_op(readOpPtr); 132 | readOpPtr = null; 133 | } 134 | } 135 | } -------------------------------------------------------------------------------- /src/main/java/com/ceph/rados/exceptions/ErrorCode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados 3 | * 4 | * Copyright (C) 2014 1&1 - Behar Veliqi 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | package com.ceph.rados.exceptions; 19 | 20 | /** 21 | * Contains all native error codes with appropriate names and messages. 22 | */ 23 | public enum ErrorCode { 24 | 25 | EPERM(-1, "Operation not permitted"), 26 | ENOENT(-2, "No such file or directory"), 27 | ESRCH(-3, "No such process"), 28 | EINTR(-4, "Interrupted system call"), 29 | EIO(-5, "I/O error"), 30 | ENXIO(-6, "No such device or address"), 31 | E2BIG(-7, "Argument list too long"), 32 | ENOEXEC(-8, "Exec format error"), 33 | EBADF(-9, "Bad file number"), 34 | ECHILD(-10, "No child processes"), 35 | EAGAIN(-11, "Try again"), 36 | ENOMEM(-12, "Out of memory"), 37 | EACCES(-13, "Permission denied"), 38 | EFAULT(-14, "Bad address"), 39 | ENOTBLK(-15, "Block device required"), 40 | EBUSY(-16, "Device or resource busy"), 41 | EEXIST(-17, "File exists"), 42 | EXDEV(-18, "Cross-device link"), 43 | ENODEV(-19, "No such device"), 44 | ENOTDIR(-20, "Not a directory"), 45 | EISDIR(-21, "Is a directory"), 46 | EINVAL(-22, "Invalid argument"), 47 | ENFILE(-23, "File table overflow"), 48 | EMFILE(-24, "Too many open files"), 49 | ENOTTY(-25, "Not a typewriter"), 50 | ETXTBSY(-26, "Text file busy"), 51 | EFBIG(-27, "File too large"), 52 | ENOSPC(-28, "No space left on device"), 53 | ESPIPE(-29, "Illegal seek"), 54 | EROFS(-30, "Read-only file system"), 55 | EMLINK(-31, "Too many links"), 56 | EPIPE(-32, "Broken pipe"), 57 | EDOM(-33, "Argument out of range"), 58 | ERANGE(-34, "Result too large"), 59 | EDEADLK(-35, "Resource deadlock would occur"), 60 | ENAMETOOLONG(-36, "Name too long"), 61 | ENOLCK(-37, "No record locks available"), 62 | ENOSYS(-38, "Function not implemented"), 63 | ENOTEMPTY(-39, "Directory not empty"), 64 | ELOOP(-40, "Too many symbolic links"), 65 | ENOMSG(-42, "No errorMessage of desired type"), 66 | EIDRM(-43, "Identifier removed"), 67 | ECHRNG(-44, "Channel number out of range"), 68 | EL2NSYNC(-45, "Level 2 not synchronized"), 69 | EL3HLT(-46, "Level 3 halted"), 70 | EL3RST(-47, "Level 3 reset"), 71 | ELNRNG(-48, "Link number out of range"), 72 | EUNATCH(-49, "Protocol driver not attached"), 73 | ENOCSI(-50, "No CSI structure available"), 74 | EL2HLT(-51, "Level 2 halted"), 75 | EBADE(-52, "Invalid exchange"), 76 | EBADR(-53, "Invalid request descriptor"), 77 | EXFULL(-54, "Exchange full"), 78 | ENOANO(-55, "No anode"), 79 | EBADRQC(-56, "Invalid request errorCode"), 80 | EBADSLT(-57, "Invalid slot"), 81 | EBFONT(-59, "Bad font file format"), 82 | ENOSTR(-60, "Not a stream"), 83 | ENODATA(-61, "No data available"), 84 | ETIME(-62, "Stream timeout"), 85 | ENOSR(-63, "Out of streams resources"), 86 | ENONET(-64, "Machine is not on the network"), 87 | ENOPKG(-65, "Package not installed"), 88 | EREMOTE(-66, "Object is remote"), 89 | ENOLINK(-67, "Link has been severed"), 90 | EADV(-68, "Advertise error"), 91 | ESRMNT(-69, "Srmount error"), 92 | ECOMM(-70, "Communication error on send"), 93 | EPROTO(-71, "Protocol error"), 94 | EMULTIHOP(-72, "Multihop attempted"), 95 | EDOTDOT(-73, "RFS specific error"), 96 | EBADMSG(-74, "Not a data errorMessage"), 97 | EOVERFLOW(-75, "Value too large for defined data type"), 98 | ENOTUNIQ(-76, "Name not unique on network"), 99 | EBADFD(-77, "File descriptor in bad state"), 100 | EREMCHG(-78, "Remote address changed"), 101 | ELIBACC(-79, "Can not access a needed shared library"), 102 | ELIBBAD(-80, "Accessing a corrupted shared library"), 103 | ELIBSCN(-81, ".lib section in a.out corrupted"), 104 | ELIBMAX(-82, "Attempting to link in too many shared libraries"), 105 | ELIBEXEC(-83, "Cannot exec a shared library directly"), 106 | EILSEQ(-84, "Illegal byte sequence"), 107 | ERESTART(-85, "Interrupted system call should be restarted"), 108 | ESTRPIPE(-86, "Streams pipe error"), 109 | EUSERS(-87, "Too many users"), 110 | ENOTSOCK(-88, "Socket operation on non-socket"), 111 | EDESTADDRREQ(-89, "Destination address required"), 112 | EMSGSIZE(-90, "errorMessage too long"), 113 | EPROTOTYPE(-91, "Protocol wrong type for socket"), 114 | ENOPROTOOPT(-92, "Protocol not available"), 115 | EPROTONOSUPPORT(-93, "Protocol not supported"), 116 | ESOCKTNOSUPPORT(-94, "Socket type not supported"), 117 | EOPNOTSUPP(-95, "Operation not supported on transport endpoint"), 118 | EPFNOSUPPORT(-96, "Protocol family not supported"), 119 | EAFNOSUPPORT(-97, "Address family not supported by protocol"), 120 | EADDRINUSE(-98, "Address already in use"), 121 | EADDRNOTAVAIL(-99, "Cannot assign requested address"), 122 | ENETDOWN(-100, "Network is down"), 123 | ENETUNREACH(-101, "Network is unreachable"), 124 | ENETRESET(-102, "Network dropped connection because of reset"), 125 | ECONNABORTED(-103, "Software caused connection abort"), 126 | ECONNRESET(-104, "Connection reset by peer"), 127 | ENOBUFS(-105, "No buffer space available"), 128 | EISCONN(-106, "Transport endpoint is already connected"), 129 | ENOTCONN(-107, "Transport endpoint is not connected"), 130 | ESHUTDOWN(-108, "Cannot send after transport endpoint shutdown"), 131 | ETOOMANYREFS(-109, "Too many references: cannot splice"), 132 | ETIMEDOUT(-110, "Connection timed out"), 133 | ECONNREFUSED(-111, "Connection refused"), 134 | EHOSTDOWN(-112, "Host is down"), 135 | EHOSTUNREACH(-113, "No route to host"), 136 | EALREADY(-114, "Operation already in progress"), 137 | EINPROGRESS(-115, "Operation now in progress"), 138 | ESTALE(-116, "Stale NFS file handle"), 139 | EUCLEAN(-117, "Structure needs cleaning"), 140 | ENOTNAM(-118, "Not a XENIX named type file"), 141 | ENAVAIL(-119, "No XENIX semaphores available"), 142 | EISNAM(-120, "Is a named type file"), 143 | EREMOTEIO(-121, "Remote I/O error"), 144 | EDQUOT(-122, "Quota exceeded"), 145 | ENOMEDIUM(-123, "No medium found"), 146 | EMEDIUMTYPE(-124, "Wrong medium type"), 147 | ECANCELED(-125, "Operation Canceled"), 148 | ENOKEY(-126, "Required key not available"), 149 | EKEYEXPIRED(-127, "Key has expired"), 150 | EKEYREVOKED(-128, "Key has been revoked"), 151 | EKEYREJECTED(-129, "Key was rejected by service"), 152 | EOWNERDEAD(-130, "Owner died"), 153 | ENOTRECOVERABLE(-131, "State not recoverable"); 154 | 155 | private final int errorCode; 156 | private final String errorMessage; 157 | 158 | ErrorCode(int errorCode, String errorMessage) { 159 | this.errorCode = errorCode; 160 | this.errorMessage = errorMessage; 161 | } 162 | 163 | public int getErrorCode() { 164 | return errorCode; 165 | } 166 | 167 | public String getErrorMessage() { 168 | return errorMessage; 169 | } 170 | 171 | 172 | /** 173 | * @param errorCode the error code 174 | * @return appropriate name of the error depending on the code 175 | */ 176 | public static String getErrorName(int errorCode) { 177 | ErrorCode error = ErrorCode.getEnum(errorCode); 178 | if (error != null) { 179 | return error.name(); 180 | } 181 | return "UNKNOWN_ERROR"; 182 | } 183 | 184 | /** 185 | * @param errorCode the error code 186 | * @return appropriate message containing an explanation of the code 187 | */ 188 | public static String getErrorMessage(int errorCode) { 189 | ErrorCode error = ErrorCode.getEnum(errorCode); 190 | if (error != null) { 191 | return error.getErrorMessage(); 192 | } 193 | return String.format("Unknown error code: %d", errorCode); 194 | } 195 | 196 | /** 197 | * @param errorCode the error code 198 | * @return the ErrorCode enum representing the error code 199 | */ 200 | public static ErrorCode getEnum(int errorCode) { 201 | for (ErrorCode value : values()) { 202 | if(value.errorCode == errorCode) { 203 | return value; 204 | } 205 | } 206 | return null; 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rados/exceptions/RadosAlreadyConnectedException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados 3 | * 4 | * Copyright (C) 2014 1&1 - Behar Veliqi 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | package com.ceph.rados.exceptions; 19 | 20 | /** 21 | * Thrown when an operation is being called which is not allowed 22 | * in a already connected state. 23 | */ 24 | public class RadosAlreadyConnectedException extends RadosException { 25 | 26 | /** 27 | * @param message the message 28 | * @param returnValue the native error code 29 | */ 30 | public RadosAlreadyConnectedException(String message, int returnValue) { 31 | super(message, returnValue); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rados/exceptions/RadosArgumentOutOfDomainException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados 3 | * 4 | * Copyright (C) 2014 1&1 - Behar Veliqi 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | package com.ceph.rados.exceptions; 19 | 20 | /** 21 | * Thrown when an argument is out of domain 22 | */ 23 | public class RadosArgumentOutOfDomainException extends RadosException { 24 | 25 | /** 26 | * @param message the message 27 | * @param returnValue the native error code 28 | */ 29 | public RadosArgumentOutOfDomainException(String message, int returnValue) { 30 | super(message, returnValue); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rados/exceptions/RadosException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados 3 | * 4 | * Copyright (C) 2013 Wido den Hollander 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | 19 | package com.ceph.rados.exceptions; 20 | 21 | import java.io.IOException; 22 | 23 | public class RadosException extends IOException { 24 | 25 | protected int returnValue; 26 | 27 | /** 28 | * Throw a a RadosException 29 | * 30 | * @param message 31 | * The error message 32 | */ 33 | public RadosException(String message) { 34 | super(message); 35 | } 36 | 37 | /** 38 | * Throw a a RadosException 39 | * 40 | * @param message 41 | * The error message 42 | * @param returnValue 43 | * The return value of the rados_ call 44 | */ 45 | public RadosException(String message, int returnValue) { 46 | super(message + " (" + returnValue + ")"); 47 | this.returnValue = returnValue; 48 | } 49 | 50 | /** 51 | * @param message the message 52 | * @param cause the cause 53 | */ 54 | public RadosException(String message, Throwable cause) { 55 | super(message, cause); 56 | } 57 | 58 | /** 59 | * Get the return value passed on to the constructor 60 | * 61 | * @return int 62 | */ 63 | public int getReturnValue() { 64 | return this.returnValue; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rados/exceptions/RadosInvalidArgumentException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados 3 | * 4 | * Copyright (C) 2014 1&1 - Behar Veliqi 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | package com.ceph.rados.exceptions; 19 | 20 | /** 21 | * Thrown when a invalid argument is being passed 22 | */ 23 | public class RadosInvalidArgumentException extends RadosException { 24 | 25 | /** 26 | * @param message the message 27 | * @param returnValue the native error code 28 | */ 29 | public RadosInvalidArgumentException(String message, int returnValue) { 30 | super(message, returnValue); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rados/exceptions/RadosNotFoundException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados 3 | * 4 | * Copyright (C) 2014 1&1 - Behar Veliqi 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | package com.ceph.rados.exceptions; 19 | 20 | /** 21 | * Thrown when not able to found given object 22 | */ 23 | public class RadosNotFoundException extends RadosException { 24 | 25 | /** 26 | * @param message the message 27 | * @param returnValue the native error code 28 | */ 29 | public RadosNotFoundException(String message, int returnValue) { 30 | super(message, returnValue); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rados/exceptions/RadosOperationInProgressException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados 3 | * 4 | * Copyright (C) 2014 1&1 - Behar Veliqi 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | package com.ceph.rados.exceptions; 19 | 20 | /** 21 | * Thrown when a operation is being called which is already in progress, e.g. Rados#connect() 22 | */ 23 | public class RadosOperationInProgressException extends RadosException { 24 | 25 | /** 26 | * @param message the message 27 | * @param returnValue the native error code 28 | */ 29 | public RadosOperationInProgressException(String message, int returnValue) { 30 | super(message, returnValue); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rados/exceptions/RadosPermissionException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados 3 | * 4 | * Copyright (C) 2014 1&1 - Behar Veliqi 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | package com.ceph.rados.exceptions; 19 | 20 | /** 21 | * Thrown when an operation it not permitted 22 | */ 23 | public class RadosPermissionException extends RadosException { 24 | 25 | /** 26 | * @param message the message 27 | * @param returnValue the native error code 28 | */ 29 | public RadosPermissionException(String message, int returnValue) { 30 | super(message, returnValue); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rados/exceptions/RadosReadOnlyException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados 3 | * 4 | * Copyright (C) 2014 1&1 - Behar Veliqi 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | package com.ceph.rados.exceptions; 19 | 20 | /** 21 | * Thrown when only ready only operations are allowed 22 | */ 23 | public class RadosReadOnlyException extends RadosException { 24 | 25 | /** 26 | * @param message the message 27 | * @param returnValue the native error code 28 | */ 29 | public RadosReadOnlyException(String message, int returnValue) { 30 | super(message, returnValue); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rados/exceptions/RadosTimeoutException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados 3 | * 4 | * Copyright (C) 2014 1&1 - Behar Veliqi 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | package com.ceph.rados.exceptions; 19 | 20 | /** 21 | * Thrown when a timeout occurs 22 | */ 23 | public class RadosTimeoutException extends RadosException { 24 | 25 | /** 26 | * @param message the message 27 | * @param returnValue the native error code 28 | */ 29 | public RadosTimeoutException(String message, int returnValue) { 30 | super(message, returnValue); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rados/jna/Rados.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados 3 | * 4 | * Copyright (C) 2013 Wido den Hollander 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | 19 | package com.ceph.rados.jna; 20 | 21 | import java.nio.ByteBuffer; 22 | 23 | import com.sun.jna.Callback; 24 | import com.sun.jna.Library; 25 | import com.sun.jna.Native; 26 | import com.sun.jna.Pointer; 27 | import com.sun.jna.ptr.IntByReference; 28 | import com.sun.jna.ptr.LongByReference; 29 | import com.sun.jna.ptr.PointerByReference; 30 | 31 | public interface Rados extends Library { 32 | 33 | Rados INSTANCE = (Rados) Native.loadLibrary("rados", Rados.class); 34 | 35 | void rados_version(IntByReference major, IntByReference minor, IntByReference extra); 36 | int rados_create(PointerByReference cluster, String id); 37 | int rados_create2(PointerByReference cluster, String clustername, String name, long flags); 38 | int rados_conf_read_file(Pointer cluster, String path); 39 | int rados_conf_set(Pointer cluster, String option, String value); 40 | int rados_conf_get(Pointer cluster, String option, byte[] buf, int len); 41 | int rados_cluster_fsid(Pointer cluster, byte[] buf, int len); 42 | int rados_cluster_stat(Pointer cluster, RadosClusterInfo result); 43 | int rados_connect(Pointer cluster); 44 | int rados_pool_create(Pointer cluster, String name); 45 | int rados_pool_create_with_auid(Pointer cluster, String name, long auid); 46 | int rados_pool_create_with_all(Pointer cluster, String name, long auid, long crushrule); 47 | int rados_pool_create_with_crush_rule(Pointer cluster, String name, long crushrule); 48 | int rados_pool_delete(Pointer cluster, String name); 49 | int rados_pool_list(Pointer cluster, byte[] buf, int len); 50 | long rados_pool_lookup(Pointer cluster, String name); 51 | int rados_pool_reverse_lookup(Pointer cluster, long id, byte[] buf, long len); 52 | int rados_ioctx_pool_stat(Pointer ioctx, RadosPoolInfo result); 53 | long rados_get_instance_id(Pointer cluster); 54 | int rados_ioctx_create(Pointer cluster, String pool, Pointer ioctx); 55 | void rados_ioctx_destroy(Pointer ioctx); 56 | void rados_ioctx_set_namespace(Pointer ioctx, String namespace); 57 | long rados_ioctx_get_id(Pointer ioctx); 58 | int rados_ioctx_pool_set_auid(Pointer ioctx, long auid); 59 | int rados_ioctx_pool_get_auid(Pointer ioctx, LongByReference auid); 60 | int rados_ioctx_get_pool_name(Pointer ioctx, byte[] buf, int len); 61 | void rados_ioctx_locator_set_key(Pointer ioctx, String key); 62 | int rados_ioctx_snap_create(Pointer ioctx, String snapname); 63 | int rados_ioctx_snap_remove(Pointer ioctx, String snapname); 64 | int rados_ioctx_snap_lookup(Pointer ioctx, String snapname, LongByReference id); 65 | int rados_ioctx_snap_get_name(Pointer ioctx, long id, byte[] buf, long len); 66 | int rados_ioctx_snap_get_stamp(Pointer ioctx, long id, LongByReference time); 67 | int rados_ioctx_snap_list(Pointer ioctx, byte[] buf, int len); 68 | int rados_nobjects_list_open(Pointer ioctx, Pointer list); 69 | int rados_nobjects_list_next(Pointer list, Pointer entry, byte[] key, byte[] nspace); 70 | void rados_nobjects_list_close(Pointer list); 71 | int rados_write(Pointer ioctx, String oid, byte[] buf, int len, long off); 72 | int rados_write_full(Pointer ioctx, String oid, byte[] buf, int len); 73 | int rados_append(Pointer ioctx, String oid, byte[] buf, int len); 74 | int rados_read(Pointer ioctx, String oid, byte[] buf, int len, long off); 75 | int rados_remove(Pointer ioctx, String oid); 76 | int rados_trunc(Pointer ioctx, String oid, long size); 77 | int rados_clone_range(Pointer ioctx, String dst, long dst_off, String src, long src_off, long len); 78 | int rados_stat(Pointer ioctxo, String oi, LongByReference size, LongByReference mtime); 79 | Pointer rados_create_read_op(); 80 | void rados_release_read_op(Pointer read_op); 81 | void rados_read_op_read(Pointer read_op, long offset, long len, ByteBuffer direct_buffer, LongByReference bytes_read, IntByReference prval); 82 | int rados_read_op_operate(Pointer read_op, Pointer ioctx, String oid, int flags); 83 | int rados_shutdown(Pointer cluster); 84 | 85 | // Asynchronous I/O 86 | int rados_aio_create_completion(Pointer callbackContext, Callback callbackComplete, Callback callbackSafe, PointerByReference completion); 87 | void rados_aio_release(Pointer completion); 88 | int rados_aio_flush(Pointer completion); 89 | int rados_aio_write(Pointer ioctx, String oid, Pointer completion, byte[] buffer, int length, long offset); 90 | int rados_aio_write_full(Pointer ioctx, String oid, Pointer completion, byte[] buffer, int length); 91 | int rados_aio_wait_for_complete(Pointer completion); 92 | int rados_aio_wait_for_safe(Pointer completion); 93 | 94 | // read, write, remove, iterate extended attributes 95 | int rados_getxattr(Pointer ioctx, String oid, String xattrName, byte[] buf, long len); 96 | int rados_setxattr(Pointer ioctx, String oid, String xattrName, byte[] buf, long len); 97 | int rados_rmxattr(Pointer ioctx, String oid, String xattrName); 98 | int rados_getxattrs(Pointer ioctx, String oid, Pointer iterator); 99 | int rados_getxattrs_next(Pointer iterator, PointerByReference attr_name, PointerByReference attr_value, IntByReference len); 100 | int rados_getxattrs_end(Pointer iterator); 101 | 102 | // Rados commands 103 | int rados_mon_command(Pointer cluster, String[] cmd, int cmdLen, String inbuf, int inbufLen, PointerByReference outBuf, IntByReference outBufLen, PointerByReference statusBuf, IntByReference statusBufLen); 104 | int rados_mon_command_target(Pointer cluster, String target, String[] cmd, int cmdLen, String inbuf, int inbufLen, PointerByReference outBuf, IntByReference outBufLen, PointerByReference statusBuf, IntByReference statusBufLen); 105 | int rados_osd_command(Pointer cluster, int osdId, String[] cmd, int cmdLen, String inbuf, int inbufLen, PointerByReference outBuf, IntByReference outBufLen, PointerByReference statusBuf, IntByReference statusBufLen); 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rados/jna/RadosClusterInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados 3 | * 4 | * Copyright (C) 2013 Wido den Hollander 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | 19 | package com.ceph.rados.jna; 20 | 21 | import com.sun.jna.Structure; 22 | import java.util.List; 23 | import java.util.Arrays; 24 | 25 | public class RadosClusterInfo extends Structure { 26 | public long kb; 27 | public long kb_used; 28 | public long kb_avail; 29 | public long num_objects; 30 | 31 | protected List getFieldOrder() { 32 | return Arrays.asList("kb", "kb_used", "kb_avail", "num_objects"); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rados/jna/RadosObjectInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados 3 | * 4 | * Copyright (C) 2013 Wido den Hollander 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | 19 | package com.ceph.rados.jna; 20 | 21 | public class RadosObjectInfo { 22 | 23 | private String oid; 24 | private long size; 25 | private long mtime; 26 | 27 | public RadosObjectInfo(String oid, long size, long mtime) { 28 | this.oid = oid; 29 | this.size = size; 30 | this.mtime = mtime; 31 | } 32 | 33 | /** 34 | * Return the object name 35 | * @return String 36 | */ 37 | public String getOid() { 38 | return this.oid; 39 | } 40 | 41 | /** 42 | * Returns the size in bytes 43 | * @return long 44 | */ 45 | public long getSize() { 46 | return this.size; 47 | } 48 | 49 | /** 50 | * Returns the modification time 51 | * @return long 52 | */ 53 | public long getMtime() { 54 | return this.mtime; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rados/jna/RadosPoolInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados 3 | * 4 | * Copyright (C) 2013 Wido den Hollander 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | 19 | package com.ceph.rados.jna; 20 | 21 | import com.sun.jna.Structure; 22 | import java.util.List; 23 | import java.util.Arrays; 24 | 25 | public class RadosPoolInfo extends Structure { 26 | public long num_bytes; 27 | public long num_kb; 28 | public long num_objects; 29 | public long num_object_clones; 30 | public long num_object_copies; 31 | public long num_objects_missing_on_primary; 32 | public long num_objects_unfound; 33 | public long num_objects_degraded; 34 | public long num_rd; 35 | public long num_rd_kb; 36 | public long num_wr; 37 | public long num_wr_kb; 38 | 39 | protected List getFieldOrder() { 40 | return Arrays.asList("num_bytes", "num_kb", "num_objects", "num_object_clones", 41 | "num_object_copies", "num_objects_missing_on_primary", 42 | "num_objects_unfound", "num_objects_degraded", 43 | "num_rd", "num_rd_kb", "num_wr", "num_wr_kb"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/radosstriper/IoCTXStriper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Striper Java - Java bindings for librados 3 | * 4 | * Copyright (C) 2013 Wido den Hollander 5 | * 2016 Arno Broekhof 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | package com.ceph.radosstriper; 19 | 20 | 21 | import static com.ceph.radosstriper.Library.rados; 22 | 23 | import java.io.Closeable; 24 | import java.util.concurrent.Callable; 25 | 26 | import com.ceph.rados.RadosBase; 27 | import com.ceph.rados.exceptions.RadosException; 28 | import com.ceph.rados.jna.RadosObjectInfo; 29 | import com.sun.jna.Native; 30 | import com.sun.jna.Pointer; 31 | import com.sun.jna.ptr.LongByReference; 32 | 33 | public class IoCTXStriper extends RadosBase implements AutoCloseable { 34 | 35 | private static final int EXT_ATTR_MAX_LEN = 4096; 36 | 37 | private Pointer ioCtxStriperPtr; 38 | 39 | /** 40 | * Create a new IO Striper Context object 41 | *

42 | * This constructor should never be called, IO Context 43 | * objects are created by the RADOS class and returned 44 | * when creating a IO Striper Context there 45 | */ 46 | public IoCTXStriper(Pointer p) { 47 | this.ioCtxStriperPtr = p; 48 | } 49 | 50 | 51 | /** 52 | * Return the pointer to the IO Striper Context 53 | *

54 | * This method is used internally and by the RADOS class 55 | * to destroy a IO Context 56 | * 57 | * @return Pointer 58 | */ 59 | public Pointer getPointer() { 60 | return this.ioCtxStriperPtr.getPointer(0); 61 | } 62 | 63 | /** 64 | * Write to an object 65 | * 66 | * @param oid The object to write to 67 | * @param buf The content to write 68 | * @param length The length to write 69 | * @param offset The offset when writing 70 | * @throws RadosException 71 | */ 72 | public void write(final String oid, final byte[] buf, final int length, final long offset) throws RadosException, IllegalArgumentException { 73 | if (offset < 0) { 74 | throw new IllegalArgumentException("Offset shouldn't be a negative value"); 75 | } 76 | if (buf.length < length) { 77 | throw new IllegalArgumentException("Length shouldn't be a smaller than Buffer length"); 78 | } 79 | handleReturnCode(new Callable() { 80 | @Override 81 | public Integer call() throws Exception { 82 | return rados.rados_striper_write(getPointer(), oid, buf, length, offset); 83 | } 84 | }, "Failed writing %s bytes with offset %s to %s", length, offset, oid); 85 | } 86 | 87 | /** 88 | * Write to an object 89 | * 90 | * @param oid The object to write to 91 | * @param buf The content to write 92 | * @param offset The offset when writing 93 | * @throws RadosException 94 | */ 95 | public void write(final String oid, final byte[] buf, final long offset) throws RadosException, IllegalArgumentException { 96 | this.write(oid, buf, buf.length, offset); 97 | } 98 | 99 | /** 100 | * Write to an object without an offset 101 | * 102 | * @param oid The object to write to 103 | * @param buf The content to write 104 | * @throws RadosException 105 | */ 106 | public void write(String oid, byte[] buf) throws RadosException { 107 | this.writeFull(oid, buf, buf.length); 108 | } 109 | 110 | /** 111 | * Write an entire object 112 | * The object is filled with the provided data. If the object exists, it is atomically truncated and then written. 113 | * 114 | * @param oid The object to write to 115 | * @param buf The content to write 116 | * @param len The length of the data to write 117 | * @throws RadosException 118 | */ 119 | public void writeFull(final String oid, final byte[] buf, final int len) throws RadosException { 120 | handleReturnCode(new Callable() { 121 | @Override 122 | public Integer call() throws Exception { 123 | return rados.rados_striper_write_full(getPointer(), oid, buf, len); 124 | } 125 | }, "Failed to write %s bytes to %s", len, oid); 126 | } 127 | 128 | /** 129 | * Sets the object layout's stripe unit of a rados striper for future objects. 130 | * This layout will be used when new objects are created (by writing to them) 131 | * Already existing objects will be opened with their own layout. 132 | * 133 | * @param stripeUnit the stripe_unit value of the new object layout 134 | * @returns 0 on success, negative error code on failure 135 | */ 136 | public int setStripeUnit(final int stripeUnit) throws RadosException { 137 | return handleReturnCode(new Callable() { 138 | @Override 139 | public Integer call() throws Exception { 140 | return rados.rados_striper_set_object_layout_stripe_unit(getPointer(), stripeUnit); 141 | } 142 | }, "Failed to set stripe unit to: %s", stripeUnit); 143 | } 144 | 145 | /** 146 | * Sets the object layout's stripe count of a rados striper for future objects. 147 | * This layout will be used when new objects are created (by writing to them) 148 | * Already existing objects will be opened with their own layout. 149 | * 150 | * @param stripeCount the stripe_count value of the new object layout 151 | * @returns 0 on success, negative error code on failure 152 | */ 153 | public int setStripeCount(final int stripeCount) throws RadosException { 154 | return handleReturnCode(new Callable() { 155 | @Override 156 | public Integer call() throws Exception { 157 | return rados.rados_striper_set_object_layout_stripe_count(getPointer(), stripeCount); 158 | } 159 | }, "Failed to set stripe count to: %s", stripeCount); 160 | } 161 | 162 | /** 163 | * Sets the object layout's object_size of a rados striper for future objects. 164 | * This layout will be used when new objects are created (by writing to them) 165 | * Already existing objects will be opened with their own layout. 166 | * 167 | * @param stripeObjectSize the targetted striper 168 | * @returns 0 on success, negative error code on failure 169 | */ 170 | public int setStripeObjectSize(final int stripeObjectSize) throws RadosException { 171 | return handleReturnCode(new Callable() { 172 | @Override 173 | public Integer call() throws Exception { 174 | return rados.rados_striper_set_object_layout_object_size(getPointer(), stripeObjectSize); 175 | } 176 | }, "Failed to set stripe object size to: %s", stripeObjectSize); 177 | } 178 | 179 | /** 180 | * Write to an object without an offset 181 | * 182 | * @param oid The object to write to 183 | * @param buf The content to write 184 | * @param offset The offset when writing 185 | * @throws RadosException 186 | */ 187 | public void write(String oid, String buf, long offset) throws RadosException { 188 | this.write(oid, buf.getBytes(), offset); 189 | } 190 | 191 | /** 192 | * Write to an object without an offset 193 | * 194 | * @param oid The object to write to 195 | * @param buf The content to write 196 | * @throws RadosException 197 | */ 198 | public void write(String oid, String buf) throws RadosException { 199 | this.write(oid, buf.getBytes()); 200 | } 201 | 202 | /** 203 | * Read data from an object 204 | * 205 | * @param oid The object's name 206 | * @param length Amount of bytes to read 207 | * @param offset The offset where to start reading 208 | * @param buf The buffer to store the result 209 | * @return Number of bytes read or negative on error 210 | * @throws RadosException 211 | */ 212 | public int read(final String oid, final int length, final long offset, final byte[] buf) 213 | throws RadosException { 214 | if (length < 0) { 215 | throw new IllegalArgumentException("Length shouldn't be a negative value"); 216 | } 217 | if (offset < 0) { 218 | throw new IllegalArgumentException("Offset shouldn't be a negative value"); 219 | } 220 | 221 | return handleReturnCode(new Callable() { 222 | @Override 223 | public Integer call() throws Exception { 224 | return rados.rados_striper_read(getPointer(), oid, buf, length, offset); 225 | } 226 | }, "Failed to read object %s using offset %s and length %s", oid, offset, length); 227 | } 228 | 229 | /** 230 | * Resize an object 231 | * 232 | * @param oid The object to resize 233 | * @param size The new length of the object. If this enlarges the object, 234 | * the new area is logically filled with 235 | * zeroes. If this shrinks the object, the excess data is removed. 236 | * @throws RadosException 237 | */ 238 | public void truncate(final String oid, final long size) throws RadosException { 239 | if (size < 0) { 240 | throw new IllegalArgumentException("Size shouldn't be a negative value"); 241 | } 242 | handleReturnCode(new Callable() { 243 | @Override 244 | public Integer call() throws Exception { 245 | return rados.rados_striper_trunc(getPointer(), oid, size); 246 | } 247 | }, "Failed resizing objects %s to %s bytes", oid, size); 248 | } 249 | 250 | /** 251 | * @param oid The name to append to 252 | * @param buf The data to append 253 | * @param len The number of bytes to write from buf 254 | * @throws RadosException 255 | */ 256 | public void append(final String oid, final byte[] buf, final int len) throws RadosException { 257 | handleReturnCode(new Callable() { 258 | @Override 259 | public Integer call() throws Exception { 260 | return rados.rados_striper_append(getPointer(), oid, buf, len); 261 | } 262 | }, "Failed appending %s bytes to object %s", len, oid); 263 | } 264 | 265 | /** 266 | * Append data to an object 267 | * 268 | * @param oid The name to append to 269 | * @param buf The data to append 270 | * @throws RadosException 271 | */ 272 | public void append(String oid, byte[] buf) throws RadosException { 273 | this.append(oid, buf, buf.length); 274 | } 275 | 276 | /** 277 | * Append data to an object 278 | * 279 | * @param oid The name to append to 280 | * @param buf The data to append 281 | * @throws RadosException 282 | */ 283 | public void append(String oid, String buf) throws RadosException { 284 | this.append(oid, buf.getBytes()); 285 | } 286 | 287 | /** 288 | * Remove an object 289 | * 290 | * @param oid The object to remove 291 | * @throws RadosException 292 | */ 293 | public void remove(final String oid) throws RadosException { 294 | handleReturnCode(new Callable() { 295 | @Override 296 | public Integer call() throws Exception { 297 | return rados.rados_striper_remove(getPointer(), oid); 298 | } 299 | }, "Failed removing object %s", oid); 300 | } 301 | 302 | /** 303 | * Stat an object 304 | * 305 | * @param oid The name of the object 306 | * @return RadosObjectInfo 307 | * The size and mtime of the object 308 | * @throws RadosException 309 | */ 310 | public RadosObjectInfo stat(final String oid) throws RadosException { 311 | final LongByReference size = new LongByReference(); 312 | final LongByReference mtime = new LongByReference(); 313 | handleReturnCode(new Callable() { 314 | @Override 315 | public Integer call() throws Exception { 316 | return rados.rados_striper_stat(getPointer(), oid, size, mtime); 317 | } 318 | }, "Failed performing a stat on object %s", oid); 319 | return new RadosObjectInfo(oid, size.getValue(), mtime.getValue()); 320 | } 321 | 322 | /** 323 | * Get the value of an extended attribute on an object. 324 | * 325 | * @param oid The name of the object 326 | * @param xattrName The name of the extended attribute 327 | * @return The value of the extended attribute 328 | * @throws RadosException on failure -- common error codes: 329 | * -34 (ERANGE) : value exceeds buffer 330 | * -61 (ENODATA) : no such attribute 331 | */ 332 | public String getExtendedAttribute(final String oid, final String xattrName) throws RadosException { 333 | final byte[] buf = new byte[EXT_ATTR_MAX_LEN]; 334 | handleReturnCode(new Callable() { 335 | @Override 336 | public Integer call() throws Exception { 337 | return rados.rados_striper_getxattr(getPointer(), oid, xattrName, buf, buf.length); 338 | } 339 | }, "Failed to get extended attribute %s on %s", xattrName, oid); 340 | // else... 341 | return Native.toString(buf); 342 | } 343 | 344 | /** 345 | * Set an extended attribute on an object. 346 | * 347 | * @param oid The name of the object 348 | * @param xattrName The name of the extended attribute 349 | * @param val The value of the extended attribute 350 | * @throws IllegalArgumentException attribute value is too long 351 | * @throws RadosException on failure 352 | */ 353 | public void setExtendedAttribute(final String oid, final String xattrName, String val) throws IllegalArgumentException, RadosException { 354 | final byte[] buf = Native.toByteArray(val); 355 | if (buf.length > EXT_ATTR_MAX_LEN) { 356 | throw new IllegalArgumentException("Length of attribute value must not exceed " + EXT_ATTR_MAX_LEN); 357 | } 358 | // else... 359 | handleReturnCode(new Callable() { 360 | @Override 361 | public Integer call() throws Exception { 362 | return rados.rados_striper_setxattr(getPointer(), oid, xattrName, buf, buf.length); 363 | } 364 | }, "Failed to set extended attribute %s on %s", xattrName, oid); 365 | } 366 | 367 | /** 368 | * Delete an extended attribute from an object. 369 | * 370 | * @param oid The name of the object 371 | * @param xattrName The name of the extended attribute 372 | * @throws RadosException on failure 373 | */ 374 | public void removeExtendedAttribute(final String oid, final String xattrName) throws RadosException { 375 | handleReturnCode(new Callable() { 376 | @Override 377 | public Integer call() throws Exception { 378 | return rados.rados_striper_rmxattr(getPointer(), oid, xattrName); 379 | } 380 | }, "Failed to remove extended attribute %s from %s", xattrName, oid); 381 | } 382 | 383 | /** 384 | * Closes this resource, relinquishing any underlying resources. 385 | * This method is invoked automatically on objects managed by the 386 | * {@code try}-with-resources statement. 387 | * 388 | *

While this interface method is declared to throw {@code 389 | * Exception}, implementers are strongly encouraged to 390 | * declare concrete implementations of the {@code close} method to 391 | * throw more specific exceptions, or to throw no exception at all 392 | * if the close operation cannot fail. 393 | * 394 | *

Cases where the close operation may fail require careful 395 | * attention by implementers. It is strongly advised to relinquish 396 | * the underlying resources and to internally mark the 397 | * resource as closed, prior to throwing the exception. The {@code 398 | * close} method is unlikely to be invoked more than once and so 399 | * this ensures that the resources are released in a timely manner. 400 | * Furthermore it reduces problems that could arise when the resource 401 | * wraps, or is wrapped, by another resource. 402 | * 403 | *

Implementers of this interface are also strongly advised 404 | * to not have the {@code close} method throw {@link 405 | * InterruptedException}. 406 | * 407 | * This exception interacts with a thread's interrupted status, 408 | * and runtime misbehavior is likely to occur if an {@code 409 | * InterruptedException} is {@linkplain Throwable#addSuppressed 410 | * suppressed}. 411 | * 412 | * More generally, if it would cause problems for an 413 | * exception to be suppressed, the {@code AutoCloseable.close} 414 | * method should not throw it. 415 | * 416 | *

Note that unlike the {@link Closeable#close close} 417 | * method of {@link Closeable}, this {@code close} method 418 | * is not required to be idempotent. In other words, 419 | * calling this {@code close} method more than once may have some 420 | * visible side effect, unlike {@code Closeable.close} which is 421 | * required to have no effect if called more than once. 422 | * 423 | * However, implementers of this interface are strongly encouraged 424 | * to make their {@code close} methods idempotent. 425 | * 426 | * @throws Exception if this resource cannot be closed 427 | */ 428 | @Override 429 | public void close() throws Exception { 430 | rados.rados_striper_destroy(getPointer()); 431 | } 432 | } 433 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/radosstriper/Library.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados 3 | * 4 | * Copyright (C) 2013 Wido den Hollander 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | 19 | package com.ceph.radosstriper; 20 | 21 | 22 | import com.ceph.radosstriper.jna.RadosStriper; 23 | import com.sun.jna.Pointer; 24 | 25 | import static java.nio.charset.StandardCharsets.UTF_8; 26 | 27 | final class Library { 28 | final static RadosStriper rados; 29 | 30 | static { 31 | rados = RadosStriper.INSTANCE; 32 | } 33 | 34 | private Library() { 35 | } 36 | 37 | /** 38 | * Free memory pointed to by ptr. 39 | */ 40 | static void free(Pointer ptr) { 41 | Pointer.nativeValue(ptr, 0L); 42 | } 43 | 44 | /** 45 | * Convert the data pointed to by {@code ptr} to a String. 46 | */ 47 | static String getString(Pointer ptr) { 48 | final long len = ptr.indexOf(0, (byte) 0); 49 | assert (len != -1) : "C-Strings must be \\0 terminated."; 50 | 51 | final byte[] data = ptr.getByteArray(0, (int) len); 52 | return new String(data, UTF_8); 53 | } 54 | 55 | /** 56 | * Calls {@link #toStringArray(Pointer[], int)}. 57 | */ 58 | static String[] toStringArray(Pointer[] ptrArr) { 59 | return toStringArray(ptrArr, ptrArr.length); 60 | } 61 | 62 | /** 63 | * Convert the given array of native pointers to "char" in 64 | * UTF-8 encoding to an array of Strings. 65 | *

66 | * note The memory used by the elements of the original array 67 | * is freed and ptrArr is modified. 68 | */ 69 | static String[] toStringArray(Pointer[] ptrArr, final int size) { 70 | try { 71 | final String[] result = new String[size]; 72 | for (int i = 0; i < size; ++i) { 73 | result[i] = Library.getString(ptrArr[i]); 74 | } 75 | return result; 76 | } finally { 77 | for (int i = 0; i < size; ++i) { 78 | Library.free(ptrArr[i]); 79 | ptrArr[i] = null; 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/radosstriper/RadosStriper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Striper Java - Java bindings for librados 3 | * 4 | * Copyright (C) 2013 Wido den Hollander 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | package com.ceph.radosstriper; 19 | 20 | 21 | import com.ceph.rados.IoCTX; 22 | import com.ceph.rados.Rados; 23 | import com.ceph.rados.exceptions.RadosException; 24 | import static com.ceph.radosstriper.Library.rados; 25 | import com.sun.jna.Memory; 26 | import com.sun.jna.Native; 27 | import com.sun.jna.Pointer; 28 | 29 | import java.util.concurrent.Callable; 30 | 31 | public class RadosStriper extends Rados { 32 | private static final int EXT_ATTR_MAX_LEN = 4096; 33 | 34 | public RadosStriper(String id) { 35 | super(id); 36 | } 37 | 38 | public RadosStriper(String clustername, String name, long flags) { 39 | super(clustername, name, flags); 40 | } 41 | 42 | public IoCTXStriper ioCtxCreateStriper(final IoCTX ioCTX) throws RadosException { 43 | final Pointer p = new Memory(Native.POINTER_SIZE); 44 | handleReturnCode(new Callable() { 45 | @Override 46 | public Integer call() throws Exception { 47 | return rados.rados_striper_create(ioCTX.getPointer(), p); 48 | } 49 | }, "Failed to create the IoCTX Striper"); 50 | return new IoCTXStriper(p); 51 | } 52 | 53 | public void destroy(IoCTXStriper ioCTXStriper) { 54 | rados.rados_striper_destroy(ioCTXStriper.getPointer()); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/radosstriper/jna/RadosStriper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Striper Java - Java bindings for librados 3 | * 4 | * Copyright (C) 2013 Wido den Hollander 5 | * 2016 Arno Broekhof 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | package com.ceph.radosstriper.jna; 19 | 20 | import com.sun.jna.Library; 21 | import com.sun.jna.Native; 22 | import com.sun.jna.Pointer; 23 | import com.sun.jna.ptr.LongByReference; 24 | 25 | public interface RadosStriper extends Library { 26 | 27 | RadosStriper INSTANCE = (RadosStriper) Native.loadLibrary("radosstriper", RadosStriper.class); 28 | 29 | 30 | int rados_striper_create(Pointer ioctx, Pointer striper); 31 | 32 | void rados_striper_destroy(Pointer striper); 33 | 34 | int rados_striper_set_object_layout_stripe_unit(Pointer striper, int stripe_unit); 35 | 36 | int rados_striper_set_object_layout_stripe_count(Pointer striper, int stripe_count); 37 | 38 | int rados_striper_set_object_layout_object_size(Pointer striper, int object_size); 39 | 40 | int rados_striper_write(Pointer striper, String oid, byte[] buf, int len, long off); 41 | 42 | int rados_striper_write_full(Pointer striper, String oid, byte[] buf, int len); 43 | 44 | int rados_striper_append(Pointer striper, String oid, byte[] buf, int len); 45 | 46 | int rados_striper_read(Pointer striper, String oid, byte[] buf, int len, long off); 47 | 48 | int rados_striper_remove(Pointer striper, String oid); 49 | 50 | int rados_striper_trunc(Pointer striper, String oid, long size); 51 | 52 | int rados_striper_getxattr(Pointer striper, String oid, String xattrName, byte[] buf, long len); 53 | 54 | int rados_striper_setxattr(Pointer striper, String oid, String xattrName, byte[] buf, long len); 55 | 56 | int rados_striper_rmxattr(Pointer striper, String oid, String xattrName); 57 | 58 | int rados_striper_stat(Pointer striper, String oi, LongByReference size, LongByReference mtime); 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rbd/Library.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados and librbd 3 | * 4 | * Copyright (C) 2013 Wido den Hollander 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | 19 | package com.ceph.rbd; 20 | 21 | import com.ceph.rbd.jna.Rbd; 22 | 23 | import com.sun.jna.Native; 24 | import com.sun.jna.Pointer; 25 | 26 | import static java.nio.charset.StandardCharsets.UTF_8; 27 | 28 | final class Library { 29 | final static Rbd rbd; 30 | 31 | static { 32 | rbd = Rbd.INSTANCE; 33 | } 34 | 35 | private Library() {} 36 | 37 | /** 38 | * Free memory pointed to by ptr. 39 | */ 40 | static void free(Pointer ptr) { 41 | Pointer.nativeValue(ptr, 0L); 42 | } 43 | 44 | /** 45 | * Convert the data pointed to by {@code ptr} to a String. 46 | */ 47 | static String getString(Pointer ptr) { 48 | final long len = ptr.indexOf(0, (byte)0); 49 | assert (len != -1): "C-Strings must be \\0 terminated."; 50 | 51 | final byte[] data = ptr.getByteArray(0, (int)len); 52 | return new String(data, UTF_8); 53 | } 54 | 55 | /** 56 | * Calls {@link #toStringArray(Pointer[], int)}. 57 | */ 58 | static String[] toStringArray(Pointer[] ptrArr) { 59 | return toStringArray(ptrArr, ptrArr.length); 60 | } 61 | 62 | /** 63 | * Convert the given array of native pointers to "char" in 64 | * UTF-8 encoding to an array of Strings. 65 | * 66 | * note The memory used by the elements of the original array 67 | * is freed and ptrArr is modified. 68 | */ 69 | static String[] toStringArray(Pointer[] ptrArr, final int size) { 70 | try { 71 | final String[] result = new String[size]; 72 | for (int i = 0; i < size; ++i) { 73 | result[i] = Library.getString(ptrArr[i]); 74 | } 75 | return result; 76 | } finally { 77 | for (int i = 0; i < size; ++i) { 78 | Library.free(ptrArr[i]); 79 | ptrArr[i] = null; 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rbd/Rbd.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados and librbd 3 | * 4 | * Copyright (C) 2013 Wido den Hollander 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | 19 | package com.ceph.rbd; 20 | 21 | import com.ceph.rados.IoCTX; 22 | import com.sun.jna.ptr.IntByReference; 23 | import com.sun.jna.ptr.LongByReference; 24 | import com.sun.jna.Pointer; 25 | import com.sun.jna.Memory; 26 | import com.sun.jna.Native; 27 | 28 | import static com.ceph.rbd.Library.rbd; 29 | 30 | public class Rbd { 31 | 32 | Pointer io; 33 | 34 | 35 | /** 36 | * Get the librbd version 37 | * 38 | * @return a int array with the minor, major and extra version 39 | */ 40 | public static int[] getVersion() { 41 | IntByReference minor = new IntByReference(); 42 | IntByReference major = new IntByReference(); 43 | IntByReference extra = new IntByReference(); 44 | rbd.rbd_version(minor, major, extra); 45 | int[] returnValue = {minor.getValue(), major.getValue(), extra.getValue()}; 46 | return returnValue; 47 | } 48 | 49 | public Rbd(IoCTX io) { 50 | this.io = io.getPointer(); 51 | } 52 | 53 | /** 54 | * Create a new RBD image 55 | * 56 | * @param name 57 | * The name of the new image 58 | * @param size 59 | * The size of the new image in bytes 60 | * @param order 61 | * Object/block size, as a power of two 62 | * @throws RbdException 63 | */ 64 | public void create(String name, long size, int order) throws RbdException { 65 | IntByReference orderRef = new IntByReference(order); 66 | int r = rbd.rbd_create(this.io, name, size, orderRef); 67 | if (r < 0) { 68 | throw new RbdException("Failed to create image " + name, r); 69 | } 70 | } 71 | 72 | /** 73 | * Create a new RBD image 74 | * 75 | * @param name 76 | * The name of the new image 77 | * @param size 78 | * The size of the new image in bytes 79 | * @throws RbdException 80 | */ 81 | public void create(String name, long size) throws RbdException { 82 | this.create(name, size, 0); 83 | } 84 | 85 | /** 86 | * Create a new RBD v2 image 87 | * 88 | * @param name 89 | * The name of the new image 90 | * @param size 91 | * The size of the new image in bytes 92 | * @param features 93 | * Initial feature bits 94 | * @param order 95 | * Object/block size, as a power of two 96 | * @throws RbdException 97 | */ 98 | public void create(String name, long size, long features, int order) throws RbdException { 99 | IntByReference orderRef = new IntByReference(order); 100 | int r = rbd.rbd_create2(this.io, name, size, features, orderRef); 101 | if (r < 0) { 102 | throw new RbdException("Failed to create image " + name, r); 103 | } 104 | } 105 | 106 | /** 107 | * Create a new RBD v2 image 108 | * 109 | * @param name 110 | * The name of the new image 111 | * @param size 112 | * The size of the new image in bytes 113 | * @param features 114 | * Initial feature bits 115 | * @throws RbdException 116 | */ 117 | public void create(String name, long size, long features) throws RbdException { 118 | this.create(name, size, features, 0); 119 | } 120 | 121 | /** 122 | * Create a new RBD v2 image 123 | * 124 | * @param name 125 | * The name of the new image 126 | * @param size 127 | * The size of the new image in bytes 128 | * @param features 129 | * Initial feature bits 130 | * @param order 131 | * Object/block size, as a power of two 132 | * @param stripe_unit 133 | * Stripe unit size, in bytes. 134 | * @param stripe_count 135 | * Number of objects to stripe over before looping 136 | * @throws RbdException 137 | */ 138 | public void create(String name, long size, long features, int order, long stripe_unit, long stripe_count) throws RbdException { 139 | IntByReference orderRef = new IntByReference(order); 140 | int r = rbd.rbd_create3(this.io, name, size, features, orderRef, stripe_unit, stripe_count); 141 | if (r < 0) { 142 | throw new RbdException("Failed to create image " + name, r); 143 | } 144 | } 145 | 146 | /** 147 | * Remove a RBD image 148 | * 149 | * @param name 150 | * The name of the image 151 | * @throws RbdException 152 | */ 153 | public void remove(String name) throws RbdException { 154 | int r = rbd.rbd_remove(this.io, name); 155 | if (r < 0) { 156 | throw new RbdException("Failed to remove image " + name, r); 157 | } 158 | } 159 | 160 | /** 161 | * Rename a RBD image 162 | * 163 | * @param srcName 164 | * The source name 165 | * @param destName 166 | * The new name for the image 167 | * @throws RbdException 168 | */ 169 | public void rename(String srcName, String destName) throws RbdException { 170 | int r = rbd.rbd_rename(this.io, srcName, destName); 171 | if (r < 0) { 172 | throw new RbdException("Failed to rename image " + srcName + " to " + destName, r); 173 | } 174 | } 175 | 176 | /** 177 | * List all RBD images in this pool 178 | * 179 | * @return String[] 180 | * @throws RbdException 181 | */ 182 | public String[] list() throws RbdException { 183 | int initialBufferSize = 1024; 184 | return list(initialBufferSize); 185 | } 186 | 187 | /** 188 | * List all RBD images in this pool 189 | * 190 | * @param initialBufferSize 191 | * Initial size of the byte buffer holding image names 192 | * @return String[] 193 | * Array of image names in the pool 194 | * @throws RbdException 195 | */ 196 | public String[] list(int initialBufferSize) throws RbdException { 197 | LongByReference sizePointer = new LongByReference(initialBufferSize); 198 | byte[] names = new byte[initialBufferSize]; 199 | 200 | int r = rbd.rbd_list(this.io, names, sizePointer); 201 | if (r < 0 && r != -34) { 202 | throw new RbdException("Failed to list RBD images", r); 203 | } 204 | 205 | // -34 (-ERANGE) is returned if the byte buffers are not big enough 206 | if (r == -34 || sizePointer.getValue() > initialBufferSize) { 207 | names = new byte[(int) sizePointer.getValue()]; 208 | r = rbd.rbd_list(this.io, names, sizePointer); 209 | if (r < 0) { 210 | throw new RbdException("Failed to list RBD images", r); 211 | } 212 | } 213 | 214 | return new String(names).split("\0"); 215 | } 216 | 217 | /** 218 | * Open a RBD image 219 | * 220 | * @param name 221 | * The name of the image you want to open 222 | * @throws RbdException 223 | * @return RbdImage 224 | */ 225 | public RbdImage open(String name) throws RbdException { 226 | return this.open(name, null); 227 | } 228 | 229 | /** 230 | * Open a RBD image with a specific snapshot 231 | * 232 | * @param name 233 | * The name of the image you want to open 234 | * @param snapName 235 | * The name of the snapshot to open 236 | * @throws RbdException 237 | * @return RbdImage 238 | */ 239 | public RbdImage open(String name, String snapName) throws RbdException { 240 | Pointer p = new Memory(Native.POINTER_SIZE); 241 | int r = rbd.rbd_open(this.io, name, p, snapName); 242 | if (r < 0) { 243 | throw new RbdException("Failed to open image " + name, r); 244 | } 245 | return new RbdImage(p, name); 246 | } 247 | 248 | /** 249 | * Open a RBD image read only 250 | * 251 | * @param name 252 | * The name of the image you want to open 253 | * @throws RbdException 254 | * @return RbdImage 255 | */ 256 | public RbdImage openReadOnly(String name) throws RbdException { 257 | return this.openReadOnly(name, null); 258 | } 259 | 260 | /** 261 | * Open a RBD image with a specific snapshot read only 262 | * 263 | * @param name 264 | * The name of the image you want to open 265 | * @param snapName 266 | * The name of the snapshot to open 267 | * @throws RbdException 268 | * @return RbdImage 269 | */ 270 | public RbdImage openReadOnly(String name, String snapName) throws RbdException { 271 | Pointer p = new Memory(Native.POINTER_SIZE); 272 | int r = rbd.rbd_open_read_only(this.io, name, p, snapName); 273 | if (r < 0) { 274 | throw new RbdException("Failed to open image " + name, r); 275 | } 276 | return new RbdImage(p, name); 277 | } 278 | 279 | /** 280 | * Close a RBD image 281 | * 282 | * @param image 283 | * The RbdImage object 284 | * @throws RbdException 285 | */ 286 | public void close(RbdImage image) throws RbdException { 287 | int r = rbd.rbd_close(image.getPointer()); 288 | if (r < 0) { 289 | throw new RbdException("Failed to close image", r); 290 | } 291 | } 292 | 293 | /** 294 | * Clone a RBD image 295 | * 296 | * @param parentImage 297 | * The name of the parent image 298 | * @param parentSnap 299 | * The snapshot of the parent image (has to be protected) 300 | * @param childIo 301 | * The IoCTX for the child image 302 | * @param childName 303 | * The name for the child image 304 | * @param features 305 | * The RBD features 306 | * @param order 307 | * Object/block size, as a power of two 308 | * @param stripe_unit 309 | * Stripe unit size, in bytes. 310 | * @param stripe_count 311 | * Number of objects to stripe over before looping 312 | * @throws RbdException 313 | */ 314 | public void clone(String parentImage, String parentSnap, IoCTX childIo, 315 | String childName, long features, int order, long stripe_unit, 316 | long stripe_count) throws RbdException { 317 | IntByReference orderRef = new IntByReference(order); 318 | int r = rbd.rbd_clone2(this.io, parentImage, parentSnap, childIo.getPointer(), childName, features, orderRef, stripe_unit, stripe_count); 319 | if (r < 0) { 320 | throw new RbdException("Failed to clone image " + parentImage + "@" + parentSnap + " to " + childName, r); 321 | } 322 | } 323 | 324 | /** 325 | * Clone a RBD image 326 | * 327 | * @param parentImage 328 | * The name of the parent image 329 | * @param parentSnap 330 | * The snapshot of the parent image (has to be protected) 331 | * @param childIo 332 | * The IoCTX for the child image 333 | * @param childName 334 | * The name for the child image 335 | * @param features 336 | * The RBD features 337 | * @param order 338 | * Object/block size, as a power of two 339 | * @throws RbdException 340 | */ 341 | public void clone(String parentImage, String parentSnap, IoCTX childIo, 342 | String childName, long features, int order) throws RbdException { 343 | IntByReference orderRef = new IntByReference(order); 344 | int r = rbd.rbd_clone(this.io, parentImage, parentSnap, childIo.getPointer(), childName, features, orderRef); 345 | if (r < 0) { 346 | throw new RbdException("Failed to clone image " + parentImage + "@" + parentSnap + " to " + childName, r); 347 | } 348 | } 349 | 350 | /** 351 | * Copy a RBD image 352 | * 353 | * @param sourceImage 354 | * The source RbdImage 355 | * @param destImage 356 | * The destination RbdImage 357 | * @throws RbdException 358 | */ 359 | public void copy(RbdImage sourceImage, RbdImage destImage) throws RbdException { 360 | int r = rbd.rbd_copy2(sourceImage.getPointer(), destImage.getPointer()); 361 | if (r < 0) { 362 | throw new RbdException("Failed to copy image " + sourceImage.getName() + " to " + destImage.getName(), r); 363 | } 364 | } 365 | } 366 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rbd/RbdException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados and librbd 3 | * 4 | * Copyright (C) 2013 Wido den Hollander 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | 19 | package com.ceph.rbd; 20 | 21 | import java.io.IOException; 22 | 23 | public class RbdException extends IOException { 24 | 25 | protected int returnValue; 26 | 27 | /** 28 | * Throw a a RbdException 29 | * 30 | * @param message 31 | * The error message 32 | */ 33 | public RbdException(String message) { 34 | super(message); 35 | } 36 | 37 | /** 38 | * Throw a a RbdException 39 | * 40 | * @param message 41 | * The error message 42 | * @param returnValue 43 | * The return value of the rados_ call 44 | */ 45 | public RbdException(String message, int returnValue) { 46 | super(message); 47 | this.returnValue = returnValue; 48 | } 49 | 50 | /** 51 | * Get the return value passed on to the constructor 52 | * 53 | * @return int 54 | */ 55 | public int getReturnValue() { 56 | return this.returnValue; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rbd/RbdImage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados and librbd 3 | * 4 | * Copyright (C) 2013 Wido den Hollander 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | 19 | package com.ceph.rbd; 20 | 21 | import com.ceph.rbd.jna.RbdImageInfo; 22 | import com.ceph.rbd.jna.RbdSnapInfo; 23 | import com.sun.jna.Pointer; 24 | import com.sun.jna.Memory; 25 | import com.sun.jna.Native; 26 | import com.sun.jna.ptr.IntByReference; 27 | import com.sun.jna.ptr.LongByReference; 28 | import com.sun.jna.ptr.PointerByReference; 29 | import java.io.Closeable; 30 | import java.io.IOException; 31 | import java.util.ArrayList; 32 | import java.util.List; 33 | import java.util.Arrays; 34 | 35 | import static com.ceph.rbd.Library.rbd; 36 | import com.sun.jna.NativeLong; 37 | 38 | public class RbdImage implements Closeable { 39 | 40 | private Pointer image; 41 | private String name; 42 | 43 | public RbdImage(Pointer image, String name) { 44 | this.image = image; 45 | this.name = name; 46 | } 47 | 48 | /** 49 | * Returns the name of the image 50 | * 51 | * @return String 52 | */ 53 | public String getName() { 54 | return this.name; 55 | } 56 | 57 | /** 58 | * Return the pointer to the RBD image 59 | * 60 | * This method is used internally and by the RBD class 61 | * to close a RBD image 62 | * 63 | * @return Pointer 64 | */ 65 | public Pointer getPointer() { 66 | return this.image.getPointer(0); 67 | } 68 | 69 | /** 70 | * Get information about a RBD image 71 | * 72 | * @return RbdImageInfo 73 | * @throws RbdException 74 | */ 75 | public RbdImageInfo stat() throws RbdException { 76 | RbdImageInfo info = new RbdImageInfo(); 77 | int r = rbd.rbd_stat(this.getPointer(), info, 0); 78 | if (r < 0) { 79 | throw new RbdException("Failed to stat the RBD image", r); 80 | } 81 | return info; 82 | } 83 | 84 | /** 85 | * Find out if the format of the RBD image is the old format 86 | * or not 87 | * 88 | * @return boolean 89 | * @throws RbdException 90 | */ 91 | public boolean isOldFormat() throws RbdException { 92 | IntByReference old = new IntByReference(); 93 | int r = rbd.rbd_get_old_format(this.getPointer(), old); 94 | if (r < 0) { 95 | throw new RbdException("Failed to get the RBD format", r); 96 | } 97 | 98 | return old.getValue() == 1; 99 | } 100 | 101 | /** 102 | * Create a RBD snapshot 103 | * 104 | * @param snapName 105 | * The name for the snapshot 106 | * @throws RbdException 107 | */ 108 | public void snapCreate(String snapName) throws RbdException { 109 | int r = rbd.rbd_snap_create(this.getPointer(), snapName); 110 | if (r < 0) { 111 | throw new RbdException("Failed to create snapshot " + snapName, r); 112 | } 113 | } 114 | 115 | /** 116 | * Remove a RBD snapshot 117 | * 118 | * @param snapName 119 | * The name of the snapshot 120 | * @throws RbdException 121 | */ 122 | public void snapRemove(String snapName) throws RbdException { 123 | int r = rbd.rbd_snap_remove(this.getPointer(), snapName); 124 | if (r < 0) { 125 | throw new RbdException("Failed to remove snapshot " + snapName, r); 126 | } 127 | } 128 | 129 | /** 130 | * Rollback a RBD snapshot 131 | * 132 | * @param snapName 133 | * The name of the snapshot 134 | * @throws RbdException 135 | */ 136 | public void snapRollBack(String snapName) throws RbdException{ 137 | int r = rbd.rbd_snap_rollback(this.getPointer(), snapName); 138 | if (r < 0) { 139 | throw new RbdException("Failed to rollback snapshot " + snapName, r); 140 | } 141 | } 142 | 143 | /** 144 | * Protect a snapshot 145 | * 146 | * @param snapName 147 | * The name of the snapshot 148 | * @throws RbdException 149 | */ 150 | public void snapProtect(String snapName) throws RbdException { 151 | int r = rbd.rbd_snap_protect(this.getPointer(), snapName); 152 | if (r < 0) { 153 | throw new RbdException("Failed to protect snapshot " + snapName, r); 154 | } 155 | } 156 | 157 | /** 158 | * Unprotect a RBD snapshot 159 | * 160 | * @param snapName 161 | * The name of the snapshot 162 | * @throws RbdException 163 | */ 164 | public void snapUnprotect(String snapName) throws RbdException { 165 | int r = rbd.rbd_snap_unprotect(this.getPointer(), snapName); 166 | if (r < 0) { 167 | throw new RbdException("Failed to unprotect snapshot " + snapName, r); 168 | } 169 | } 170 | 171 | /** 172 | * Tells if a snapshot is protected or not 173 | * 174 | * @param snapName 175 | * The name of the snapshot 176 | * @return boolean 177 | * @throws RbdException 178 | */ 179 | public boolean snapIsProtected(String snapName) throws RbdException { 180 | IntByReference isProtected = new IntByReference(); 181 | int r = rbd.rbd_snap_is_protected(this.getPointer(), snapName, isProtected); 182 | if (r < 0) { 183 | throw new RbdException("Failed to find out if snapshot " + snapName + " is protected", r); 184 | } 185 | 186 | return isProtected.getValue() == 1; 187 | } 188 | 189 | /** 190 | * List all snapshots 191 | * 192 | * @return List 193 | * @throws RbdException 194 | */ 195 | public List snapList() throws RbdException { 196 | return snapList(128); 197 | } 198 | 199 | /** 200 | * List all snapshots 201 | * 202 | * @param initialBufferSize 203 | * Initial size of the byte buffer holding snapshot names 204 | * @return List 205 | * @throws RbdException 206 | */ 207 | public List snapList(int initialBufferSize) throws RbdException { 208 | IntByReference maxSnaps = new IntByReference(initialBufferSize); 209 | RbdSnapInfo[] snaps; 210 | int snapCount; 211 | 212 | do { 213 | snaps = new RbdSnapInfo[maxSnaps.getValue()]; 214 | snapCount = rbd.rbd_snap_list(this.getPointer(), snaps, maxSnaps); 215 | // -34 is -ERANGE 216 | } while (snapCount == -34); 217 | 218 | if (snapCount < 0) { 219 | throw new RbdException("Failed to list snapshots", snapCount); 220 | } 221 | 222 | /* 223 | * Before clearing the backing list (well, just the name strings) 224 | * we'll disable auto sync so that junk doesn't repopulate the info 225 | * struct. 226 | * 227 | * FIXME: this is dumb, and I'm not exactly sure how to fix it, though 228 | * it does work. Note that this should be fine as long as you don't 229 | * re-use the RbdSnapInfo as a parameter to another native function. 230 | */ 231 | for (int i = 0; i < snapCount; i++) { 232 | snaps[i].setAutoSynch(false); 233 | } 234 | 235 | rbd.rbd_snap_list_end(snaps); 236 | 237 | return Arrays.asList(snaps).subList(0, snapCount); 238 | } 239 | 240 | /** 241 | * Write data to an RBD image 242 | * 243 | * @param data 244 | * The to be written data 245 | * @param offset 246 | * Where to start writing 247 | * @param length 248 | * The number of bytes to write 249 | * @throws RbdException 250 | */ 251 | public void write(byte[] data, long offset, int length) throws RbdException { 252 | if (length < 1) { 253 | throw new RbdException("There should be at least one byte to write"); 254 | } 255 | 256 | int r = rbd.rbd_write(this.getPointer(), offset, length, data); 257 | if (r < 0) { 258 | throw new RbdException("Failed writing " + length + " bytes starting at offset " + offset, r); 259 | } 260 | } 261 | 262 | /** 263 | * Write data to an RBD image 264 | * 265 | * @param data 266 | * The to be written data 267 | * @param offset 268 | * Where to start writing 269 | */ 270 | public void write(byte[] data, long offset) throws RbdException { 271 | this.write(data, offset, data.length); 272 | } 273 | 274 | /** 275 | * Write data to an RBD image 276 | * 277 | * @param data 278 | * The to be written data 279 | */ 280 | public void write(byte[] data) throws RbdException { 281 | this.write(data, 0, data.length); 282 | } 283 | 284 | /** 285 | * Read from an RBD image 286 | * 287 | * @param offset 288 | * Where to start reading 289 | * @param buffer 290 | * The buffer to store the result 291 | * @param length 292 | * The amount of bytes to read 293 | * @return int 294 | * The amount of bytes read 295 | */ 296 | public int read(long offset, byte[] buffer, int length) { 297 | return rbd.rbd_read(this.getPointer(), offset, length, buffer); 298 | } 299 | 300 | /** 301 | * Resize an RBD image 302 | * 303 | * @param size 304 | * The new size for the RBD image 305 | * @throws RbdException 306 | */ 307 | public void resize(long size) throws RbdException { 308 | int r = rbd.rbd_resize(this.getPointer(), size); 309 | if (r < 0) { 310 | throw new RbdException("Failed to resize the RBD image", r); 311 | } 312 | } 313 | 314 | public void flatten() throws RbdException { 315 | int r = rbd.rbd_flatten(this.getPointer()); 316 | if (r < 0) { 317 | throw new RbdException("Failed to flatten the RBD image", r); 318 | } 319 | } 320 | 321 | /** 322 | * List children of a snapshot 323 | * 324 | * @param snapname 325 | * Name of the snapshot on RBD image 326 | * @return 327 | * List of children with each element in the list in pool/image format 328 | * @throws RbdException 329 | */ 330 | public List listChildren(String snapname) throws RbdException { 331 | // Set the snapshot to read from 332 | int r = rbd.rbd_snap_set(this.getPointer(), snapname); 333 | 334 | if (r < 0) { 335 | throw new RbdException("Failed to set snapshot name to " + snapname, r); 336 | } 337 | 338 | try { //try-catch block for un-setting snapshot 339 | 340 | // Length of the buffers containing names of snapshot children is unknown at this point. Use a buffer of size 1024 to list snapshot children. If the 341 | // buffers are not large enough, use the actual buffer sizes from the response to set up the correct sized buffers and list the snapshot children 342 | // again 343 | 344 | int initialBufferSize = 1024; 345 | int childCount; 346 | 347 | LongByReference poolBufferSize = new LongByReference(initialBufferSize); 348 | LongByReference imageBufferSize = new LongByReference(initialBufferSize); 349 | 350 | byte pools[]; 351 | byte images[]; 352 | 353 | do { 354 | pools = new byte[(int) poolBufferSize.getValue()]; 355 | images = new byte[(int) imageBufferSize.getValue()]; 356 | childCount = rbd.rbd_list_children(this.getPointer(), pools, poolBufferSize, images, imageBufferSize); 357 | // -34 (-ERANGE) is returned if the byte buffers are not big enough 358 | } while (childCount == -34); 359 | 360 | if (childCount < 0) { 361 | throw new RbdException("Failed to list snap children", r); 362 | } 363 | 364 | List poolImageList = new ArrayList(); 365 | 366 | if (childCount > 0) { 367 | // Gather pool names and image names 368 | String[] poolNames = new String(pools).split("\0"); 369 | String[] imageNames = new String(images).split("\0"); 370 | 371 | if (poolNames.length != imageNames.length) { 372 | throw new RbdException("Mismatch between number of pools and images, pools = " + poolNames.length + ", images = " + imageNames.length); 373 | } 374 | 375 | // Construct "pool-name/image-name" for each child 376 | for (int i = 0; i < poolNames.length; i++) { 377 | poolImageList.add(poolNames[i] + '/' + imageNames[i]); 378 | } 379 | } 380 | 381 | return poolImageList; 382 | } finally { 383 | // Un-set the snapshot 384 | rbd.rbd_snap_set(this.getPointer(), new String()); 385 | } 386 | } 387 | 388 | @Override 389 | public void close() throws RbdException { 390 | int rc = rbd.rbd_close(this.getPointer()); 391 | if (rc < 0) { 392 | throw new RbdException("Failed to close image " + name, rc); 393 | } 394 | } 395 | } 396 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rbd/jna/Rbd.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados and librbd 3 | * 4 | * Copyright (C) 2013 Wido den Hollander 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | 19 | package com.ceph.rbd.jna; 20 | 21 | import com.sun.jna.Library; 22 | import com.sun.jna.Native; 23 | import com.sun.jna.Pointer; 24 | import com.sun.jna.ptr.IntByReference; 25 | import com.sun.jna.ptr.LongByReference; 26 | import com.sun.jna.ptr.PointerByReference; 27 | 28 | public interface Rbd extends Library { 29 | 30 | Rbd INSTANCE = (Rbd) Native.loadLibrary("rbd", Rbd.class); 31 | 32 | void rbd_version(IntByReference major, IntByReference minor, IntByReference extra); 33 | int rbd_create(Pointer io, String name, long size, IntByReference order); 34 | int rbd_create2(Pointer io, String name, long size, long features, IntByReference order); 35 | int rbd_create3(Pointer io, String name, long size, long features, IntByReference order, long stripe_unit, long stripe_count); 36 | int rbd_list(Pointer io, byte[] names, LongByReference size); 37 | int rbd_remove(Pointer io, String name); 38 | int rbd_rename(Pointer io, String srcname, String destname); 39 | int rbd_open_read_only(Pointer io, String name, Pointer image, String snap_name); 40 | int rbd_open(Pointer io, String name, Pointer image, String snap_name); 41 | int rbd_close(Pointer image); 42 | int rbd_stat(Pointer image, RbdImageInfo info, long infosize); 43 | int rbd_get_old_format(Pointer image, IntByReference old); 44 | int rbd_clone(Pointer p_io, String p_name, String p_snapname, 45 | Pointer c_io, String c_name, long features, IntByReference order); 46 | int rbd_clone2(Pointer p_io, String p_name, String p_snapname, 47 | Pointer c_io, String c_name, long features, IntByReference order, 48 | long stripe_unit, long stripe_count); 49 | int rbd_snap_create(Pointer image, String snapname); 50 | int rbd_snap_remove(Pointer image, String snapname); 51 | int rbd_snap_rollback(Pointer image, String snapname); 52 | int rbd_snap_protect(Pointer image, String snapname); 53 | int rbd_snap_unprotect(Pointer image, String snapname); 54 | int rbd_snap_is_protected(Pointer image, String snap_name, IntByReference is_protected); 55 | int rbd_snap_list(Pointer image, RbdSnapInfo[] snaps, IntByReference max_snaps); 56 | void rbd_snap_list_end(RbdSnapInfo[] snaps); 57 | int rbd_write(Pointer image, long offset, int len, byte[] buf); 58 | int rbd_read(Pointer image, long offset, int length, byte[] buffer); 59 | int rbd_copy2(Pointer source_image, Pointer dest_image); 60 | int rbd_resize(Pointer source_image, long size); 61 | int rbd_flatten(Pointer image); 62 | int rbd_snap_set(Pointer image, String snapname); 63 | int rbd_list_children(Pointer image, byte[] pools, LongByReference pools_len, byte[] images, LongByReference images_len); 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rbd/jna/RbdImageInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados and librbd 3 | * 4 | * Copyright (C) 2013 Wido den Hollander 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | 19 | package com.ceph.rbd.jna; 20 | 21 | import com.sun.jna.Structure; 22 | import java.util.List; 23 | import java.util.Arrays; 24 | 25 | public class RbdImageInfo extends Structure implements Structure.ByReference { 26 | public long size; 27 | public long obj_size; 28 | public long num_objs; 29 | public int order; 30 | public byte[] block_name_prefix; 31 | public long parent_pool; 32 | public byte[] parent_name; 33 | 34 | public RbdImageInfo() { 35 | super(); 36 | this.block_name_prefix = new byte[24]; 37 | this.parent_name = new byte[96]; 38 | } 39 | 40 | protected List getFieldOrder() { 41 | return Arrays.asList("size", "obj_size", "num_objs", "order", 42 | "block_name_prefix", "parent_pool", 43 | "parent_name"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/ceph/rbd/jna/RbdSnapInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados and librbd 3 | * 4 | * Copyright (C) 2013 Wido den Hollander 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | 19 | package com.ceph.rbd.jna; 20 | 21 | import com.sun.jna.Structure; 22 | import com.sun.jna.Pointer; 23 | import java.util.List; 24 | import java.util.Arrays; 25 | 26 | public class RbdSnapInfo extends Structure { 27 | public long id; 28 | public long size; 29 | public String name; 30 | 31 | public RbdSnapInfo() { 32 | // Required for the toArray method 33 | } 34 | 35 | public RbdSnapInfo(Pointer p) { 36 | super(p); 37 | } 38 | 39 | protected List getFieldOrder() { 40 | return Arrays.asList("id", "size", "name"); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # DOCKER-VERSION 1.0.0 2 | # 3 | # Ceph docker image for testing rados-java 4 | # based on the Demo Image by Sébastien Han "seb@redhat.com" 5 | # 6 | # VERSION 0.0.1 7 | 8 | FROM ceph/base:tag-build-master-jewel-ubuntu-16.04 9 | MAINTAINER Arno Broekhof "arnobroekhof@gmail.com" 10 | 11 | # Add bootstrap script 12 | ADD entrypoint.sh /entrypoint.sh 13 | 14 | # Add OpenJDK 8 15 | RUN apt-get update && \ 16 | apt-get -y --no-install-recommends install openjdk-8-jdk libjna-java 17 | 18 | # Add volumes for Ceph config and data 19 | VOLUME ["/etc/ceph","/var/lib/ceph"] 20 | 21 | # Expose the Ceph ports 22 | EXPOSE 6789 6800 6801 6802 6803 6804 6805 80 5000 23 | 24 | # Execute the entrypoint 25 | ENTRYPOINT ["/entrypoint.sh"] 26 | -------------------------------------------------------------------------------- /src/test/docker/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | : ${CLUSTER:=ceph} 5 | : ${RGW_NAME:=$(hostname -s)} 6 | : ${MON_NAME:=$(hostname -s)} 7 | : ${RGW_CIVETWEB_PORT:=80} 8 | : ${NETWORK_AUTO_DETECT:=1} 9 | : ${RESTAPI_IP:=0.0.0.0} 10 | : ${RESTAPI_PORT:=5000} 11 | : ${RESTAPI_BASE_URL:=/api/v0.1} 12 | : ${RESTAPI_LOG_LEVEL:=warning} 13 | : ${RESTAPI_LOG_FILE:=/var/log/ceph/ceph-restapi.log} 14 | 15 | CEPH_OPTS="--cluster ${CLUSTER}" 16 | 17 | 18 | # FUNCTIONS 19 | # Log arguments with timestamp 20 | function log { 21 | if [ -z "$*" ]; then 22 | return 1 23 | fi 24 | 25 | TIMESTAMP=$(date '+%F %T') 26 | echo "${TIMESTAMP} $0: $*" 27 | return 0 28 | } 29 | 30 | function create_socket_dir { 31 | mkdir -p /var/run/ceph 32 | chown ceph. /var/run/ceph 33 | } 34 | 35 | ####### 36 | # MON # 37 | ####### 38 | 39 | function bootstrap_mon { 40 | if [[ ! -n "$CEPH_PUBLIC_NETWORK" && ${NETWORK_AUTO_DETECT} -eq 0 ]]; then 41 | log "ERROR- CEPH_PUBLIC_NETWORK must be defined as the name of the network for the OSDs" 42 | exit 1 43 | fi 44 | 45 | if [[ ! -n "$MON_IP" && ${NETWORK_AUTO_DETECT} -eq 0 ]]; then 46 | log "ERROR- MON_IP must be defined as the IP address of the monitor" 47 | exit 1 48 | fi 49 | 50 | if [ ${NETWORK_AUTO_DETECT} -ne 0 ]; then 51 | NIC_MORE_TRAFFIC=$(grep -vE "lo:|face|Inter" /proc/net/dev | sort -n -k 2 | tail -1 | awk '{ sub (":", "", $1); print $1 }') 52 | if command -v ip; then 53 | if [ ${NETWORK_AUTO_DETECT} -eq 1 ]; then 54 | MON_IP=$(ip -6 -o a s $NIC_MORE_TRAFFIC | awk '{ sub ("/..", "", $4); print $4 }') 55 | if [ -z "$MON_IP" ]; then 56 | MON_IP=$(ip -4 -o a s $NIC_MORE_TRAFFIC | awk '{ sub ("/..", "", $4); print $4 }') 57 | CEPH_PUBLIC_NETWORK=$(ip r | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}/[0-9]\{1,2\}' | head -1) 58 | fi 59 | elif [ ${NETWORK_AUTO_DETECT} -eq 4 ]; then 60 | MON_IP=$(ip -4 -o a s $NIC_MORE_TRAFFIC | awk '{ sub ("/..", "", $4); print $4 }') 61 | CEPH_PUBLIC_NETWORK=$(ip r | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}/[0-9]\{1,2\}' | head -1) 62 | elif [ ${NETWORK_AUTO_DETECT} -eq 6 ]; then 63 | MON_IP=$(ip -6 -o a s $NIC_MORE_TRAFFIC | awk '{ sub ("/..", "", $4); print $4 }') 64 | CEPH_PUBLIC_NETWORK=$(ip r | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}/[0-9]\{1,2\}' | head -1) 65 | fi 66 | # best effort, only works with ipv4 67 | # it is tough to find the ip from the nic only using /proc 68 | # so we just take on of the addresses available 69 | # which is fairely safe given that containers usually have a single nic 70 | else 71 | MON_IP=$(grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' /proc/net/fib_trie | grep -vEw "^127|255$|0$" | head -1) 72 | CEPH_PUBLIC_NETWORK=$(grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}/[0-9]\{1,2\}' /proc/net/fib_trie | grep -vE "^127|^0" | head -1) 73 | fi 74 | fi 75 | 76 | if [[ -z "$MON_IP" || -z "$CEPH_PUBLIC_NETWORK" ]]; then 77 | log "ERROR- it looks like we have not been able to discover the network settings" 78 | exit 1 79 | fi 80 | 81 | # bootstrap MON 82 | if [ ! -e /etc/ceph/${CLUSTER}.conf ]; then 83 | fsid=$(uuidgen) 84 | cat </etc/ceph/${CLUSTER}.conf 85 | [global] 86 | fsid = $fsid 87 | mon initial members = ${MON_NAME} 88 | mon host = ${MON_IP} 89 | auth cluster required = cephx 90 | auth service required = cephx 91 | auth client required = cephx 92 | osd crush chooseleaf type = 0 93 | osd journal size = 100 94 | osd pool default pg num = 8 95 | osd pool default pgp num = 8 96 | osd pool default size = 1 97 | public network = ${CEPH_PUBLIC_NETWORK} 98 | cluster network = ${CEPH_PUBLIC_NETWORK} 99 | ENDHERE 100 | 101 | # For ext4 102 | if [ "$(findmnt -n -o FSTYPE -T /var/lib/ceph)" = "ext4" ]; then 103 | cat <> /etc/ceph/${CLUSTER}.conf 104 | osd max object name len = 256 105 | osd max object namespace len = 64 106 | ENDHERE 107 | fi 108 | 109 | # Generate administrator key 110 | ceph-authtool /etc/ceph/${CLUSTER}.client.admin.keyring --create-keyring --gen-key -n client.admin --set-uid=0 --cap mon 'allow *' --cap osd 'allow *' --cap mds 'allow' 111 | 112 | # Generate the mon. key 113 | ceph-authtool /etc/ceph/${CLUSTER}.mon.keyring --create-keyring --gen-key -n mon. --cap mon 'allow *' 114 | 115 | # Generate initial monitor map 116 | monmaptool --create --add ${MON_NAME} ${MON_IP} --fsid ${fsid} /etc/ceph/monmap-${CLUSTER} 117 | fi 118 | 119 | # If we don't have a monitor keyring, this is a new monitor 120 | if [ ! -e /var/lib/ceph/mon/${CLUSTER}-${MON_NAME}/keyring ]; then 121 | 122 | if [ ! -e /etc/ceph/${CLUSTER}.client.admin.keyring ]; then 123 | log "ERROR- /etc/ceph/${CLUSTER}.client.admin.keyring must exist; get it from your existing mon" 124 | exit 2 125 | fi 126 | 127 | if [ ! -e /etc/ceph/${CLUSTER}.mon.keyring ]; then 128 | log "ERROR- /etc/ceph/${CLUSTER}.mon.keyring must exist. You can extract it from your current monitor by running 'ceph ${CEPH_OPTS} auth get mon. -o /tmp/${CLUSTER}.mon.keyring'" 129 | exit 3 130 | fi 131 | 132 | if [ ! -e /etc/ceph/monmap-${CLUSTER} ]; then 133 | log "ERROR- /etc/ceph/monmap-${CLUSTER} must exist. You can extract it from your current monitor by running 'ceph ${CEPH_OPTS} mon getmap -o /tmp/monmap-${CLUSTER}'" 134 | exit 4 135 | fi 136 | 137 | # Import the client.admin keyring and the monitor keyring into a new, temporary one 138 | ceph-authtool /tmp/${CLUSTER}.mon.keyring --create-keyring --import-keyring /etc/ceph/${CLUSTER}.client.admin.keyring 139 | ceph-authtool /tmp/${CLUSTER}.mon.keyring --import-keyring /etc/ceph/${CLUSTER}.mon.keyring 140 | 141 | # Make the monitor directory 142 | mkdir -p /var/lib/ceph/mon/${CLUSTER}-${MON_NAME} 143 | 144 | # Make user 'ceph' the owner of all the tree 145 | chown ceph. /var/lib/ceph/bootstrap-{osd,mds,rgw} 146 | 147 | # Prepare the monitor daemon's directory with the map and keyring 148 | chown -R ceph. /var/lib/ceph/mon 149 | ceph-mon ${CEPH_OPTS} --mkfs -i ${MON_NAME} --monmap /etc/ceph/monmap-${CLUSTER} --keyring /tmp/${CLUSTER}.mon.keyring 150 | ceph-mon ${CEPH_OPTS} --setuser ceph --setgroup ceph --mkfs -i ${MON_NAME} --monmap /etc/ceph/monmap-${CLUSTER} --keyring /tmp/${CLUSTER}.mon.keyring --mon-data /var/lib/ceph/mon/${CLUSTER}-${MON_NAME} 151 | 152 | # Clean up the temporary key 153 | rm /tmp/${CLUSTER}.mon.keyring 154 | fi 155 | 156 | # start MON 157 | create_socket_dir 158 | chown -R ceph. /var/lib/ceph/mon 159 | ceph-mon ${CEPH_OPTS} -i ${MON_NAME} --public-addr "${MON_IP}:6789" --setuser ceph --setgroup ceph 160 | 161 | # change replica size 162 | ceph ${CEPH_OPTS} osd pool set rbd size 1 163 | } 164 | 165 | 166 | ####### 167 | # OSD # 168 | ####### 169 | 170 | function bootstrap_osd { 171 | if [ ! -e /var/lib/ceph/osd/${CLUSTER}-0/keyring ]; then 172 | # bootstrap OSD 173 | mkdir -p /var/lib/ceph/osd/${CLUSTER}-0 174 | ceph ${CEPH_OPTS} osd create 175 | chown -R ceph. /var/lib/ceph/osd/${CLUSTER}-0 176 | ceph-osd ${CEPH_OPTS} -i 0 --mkfs --setuser ceph --setgroup ceph 177 | ceph ${CEPH_OPTS} auth get-or-create osd.0 osd 'allow *' mon 'allow profile osd' -o /var/lib/ceph/osd/${CLUSTER}-0/keyring 178 | ceph ${CEPH_OPTS} osd crush add 0 1 root=default host=localhost 179 | fi 180 | 181 | # start OSD 182 | chown -R ceph. /var/lib/ceph/osd/${CLUSTER}-0 183 | ceph-osd ${CEPH_OPTS} -i 0 --setuser ceph --setgroup ceph 184 | } 185 | 186 | 187 | ####### 188 | # MDS # 189 | ####### 190 | 191 | function bootstrap_mds { 192 | if [ ! -e /var/lib/ceph/mds/${CLUSTER}-0/keyring ]; then 193 | # create ceph filesystem 194 | ceph ${CEPH_OPTS} osd pool create cephfs_data 8 195 | ceph ${CEPH_OPTS} osd pool create cephfs_metadata 8 196 | ceph ${CEPH_OPTS} fs new cephfs cephfs_metadata cephfs_data 197 | 198 | # bootstrap MDS 199 | mkdir -p /var/lib/ceph/mds/${CLUSTER}-0 200 | ceph ${CEPH_OPTS} auth get-or-create mds.0 mds 'allow' osd 'allow *' mon 'allow profile mds' > /var/lib/ceph/mds/${CLUSTER}-0/keyring 201 | chown -R ceph. /var/lib/ceph/mds/${CLUSTER}-0 202 | fi 203 | 204 | # start MDS 205 | ceph-mds ${CEPH_OPTS} -i 0 --setuser ceph --setgroup ceph 206 | } 207 | 208 | ####### 209 | # RGW # 210 | ####### 211 | 212 | function bootstrap_rgw { 213 | if [ ! -e /var/lib/ceph/radosgw/${RGW_NAME}/keyring ]; then 214 | # bootstrap RGW 215 | mkdir -p /var/lib/ceph/radosgw/${RGW_NAME} 216 | ceph ${CEPH_OPTS} auth get-or-create client.radosgw.gateway osd 'allow rwx' mon 'allow rw' -o /var/lib/ceph/radosgw/${RGW_NAME}/keyring 217 | chown -R ceph. /var/lib/ceph/radosgw/${RGW_NAME} 218 | fi 219 | 220 | # start RGW 221 | radosgw ${CEPH_OPTS} -c /etc/ceph/${CLUSTER}.conf -n client.radosgw.gateway -k /var/lib/ceph/radosgw/${RGW_NAME}/keyring --rgw-socket-path="" --rgw-frontends="civetweb port=${RGW_CIVETWEB_PORT}" --setuser ceph --setgroup ceph 222 | } 223 | 224 | function bootstrap_demo_user { 225 | if [ -n "$CEPH_DEMO_UID" ] && [ -n "$CEPH_DEMO_ACCESS_KEY" ] && [ -n "$CEPH_DEMO_SECRET_KEY" ]; then 226 | if [ -f /ceph-demo-user ]; then 227 | log "Demo user already exists with credentials:" 228 | cat /ceph-demo-user 229 | else 230 | log "Setting up a demo user..." 231 | radosgw-admin user create --uid=$CEPH_DEMO_UID --display-name="Ceph demo user" --access-key=$CEPH_DEMO_ACCESS_KEY --secret-key=$CEPH_DEMO_SECRET_KEY 232 | sed -i s/AWS_ACCESS_KEY_PLACEHOLDER/$CEPH_DEMO_ACCESS_KEY/ /root/.s3cfg 233 | sed -i s/AWS_SECRET_KEY_PLACEHOLDER/$CEPH_DEMO_SECRET_KEY/ /root/.s3cfg 234 | echo "Access key: $CEPH_DEMO_ACCESS_KEY" > /ceph-demo-user 235 | echo "Secret key: $CEPH_DEMO_SECRET_KEY" >> /ceph-demo-user 236 | 237 | if [ -n "$CEPH_DEMO_BUCKET" ]; then 238 | log "Creating bucket..." 239 | s3cmd mb s3://$CEPH_DEMO_BUCKET 240 | fi 241 | fi 242 | fi 243 | } 244 | 245 | ####### 246 | # NFS # 247 | ####### 248 | 249 | function bootstrap_nfs { 250 | # Init RPC 251 | rpcbind || return 0 252 | rpc.statd -L || return 0 253 | rpc.idmapd || return 0 254 | 255 | # start ganesha 256 | exec /usr/bin/ganesha.nfsd -F ${GANESHA_OPTIONS} ${GANESHA_EPOCH} 257 | } 258 | 259 | ####### 260 | # API # 261 | ####### 262 | 263 | function bootstrap_rest_api { 264 | if [[ ! "$(egrep "\[client.restapi\]" /etc/ceph/${CLUSTER}.conf)" ]]; then 265 | cat <>/etc/ceph/${CLUSTER}.conf 266 | [client.restapi] 267 | public addr = ${RESTAPI_IP}:${RESTAPI_PORT} 268 | restapi base url = ${RESTAPI_BASE_URL} 269 | restapi log level = ${RESTAPI_LOG_LEVEL} 270 | log file = ${RESTAPI_LOG_FILE} 271 | ENDHERE 272 | fi 273 | 274 | # start ceph-rest-api 275 | ceph-rest-api ${CEPH_OPTS} -n client.admin & 276 | } 277 | 278 | ######### 279 | # WATCH # 280 | ######### 281 | 282 | mkdir -p /var/lib/ceph/bootstrap-{osd,mds,rgw} 283 | bootstrap_mon 284 | bootstrap_osd 285 | bootstrap_mds 286 | bootstrap_rgw 287 | bootstrap_demo_user 288 | bootstrap_rest_api 289 | bootstrap_nfs 290 | log "SUCCESS" 291 | exec ceph ${CEPH_OPTS} -w 292 | -------------------------------------------------------------------------------- /src/test/docker/run-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -xe 3 | 4 | # create data pool for testing 5 | ceph osd pool create data 128 128 6 | 7 | # sleep for 2 seconds to ensure the pool is created 8 | sleep 2 9 | 10 | cd /build 11 | ./mvnw clean test 12 | -------------------------------------------------------------------------------- /src/test/docker/validate-cluster.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -xe 3 | 4 | container_name=rados-java-test 5 | 6 | 7 | # FUNCTIONS 8 | function wait_for_daemon () { 9 | timeout=20 10 | daemon_to_test=$1 11 | while [ $timeout -ne 0 ]; do 12 | if eval $daemon_to_test; then 13 | return 0 14 | fi 15 | sleep 1 16 | let timeout=timeout-1 17 | done 18 | return 1 19 | } 20 | 21 | function ceph_status { 22 | echo "Waiting for Ceph to be ready" 23 | return $(wait_for_daemon "docker exec $container_name ceph health | grep -sq HEALTH_OK") 24 | } 25 | 26 | function test_demo_mon { 27 | return $(wait_for_daemon "docker exec $container_name ceph -s | grep -sq quorum") 28 | } 29 | 30 | function test_demo_osd { 31 | return $(wait_for_daemon "docker exec $container_name ceph -s | grep -sq '1 osds: 1 up, 1 in'") 32 | } 33 | 34 | function test_demo_rgw { 35 | return $(wait_for_daemon "docker exec $container_name ceph osd dump | grep -sq rgw") 36 | } 37 | 38 | function test_demo_mds { 39 | echo "Waiting for the MDS to be ready" 40 | # NOTE(leseb): metadata server always takes up to 5 sec to run 41 | # so we first check if the pools exit, from that we assume that 42 | # the process will start. We stop waiting after 10 seconds. 43 | return $(wait_for_daemon "docker exec $container_name ceph osd dump | grep -sq cephfs && docker exec $container_name ceph -s | grep -sq 'up:active'") 44 | } 45 | 46 | # MAIN 47 | ceph_status # wait for the cluster to stabilize 48 | test_demo_mon 49 | test_demo_osd 50 | test_demo_rgw 51 | test_demo_mds 52 | ceph_status # wait again for the cluster to stabilize (mds pools) 53 | 54 | if ! docker ps | grep $container_name; then 55 | echo "looks like $container_name container died :(" 56 | exit 1 57 | fi 58 | -------------------------------------------------------------------------------- /src/test/java/com/ceph/rados/RadosBaseTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados 3 | * 4 | * Copyright (C) 2014 1&1 - Behar Veliqi 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | package com.ceph.rados; 19 | 20 | import com.ceph.rados.exceptions.RadosAlreadyConnectedException; 21 | import com.ceph.rados.exceptions.RadosArgumentOutOfDomainException; 22 | import com.ceph.rados.exceptions.RadosException; 23 | import com.ceph.rados.exceptions.RadosInvalidArgumentException; 24 | import com.ceph.rados.exceptions.RadosNotFoundException; 25 | import com.ceph.rados.exceptions.RadosOperationInProgressException; 26 | import com.ceph.rados.exceptions.RadosPermissionException; 27 | import com.ceph.rados.exceptions.RadosReadOnlyException; 28 | import com.ceph.rados.exceptions.RadosTimeoutException; 29 | import org.junit.Before; 30 | import org.junit.Test; 31 | 32 | import java.util.concurrent.Callable; 33 | 34 | import static org.junit.Assert.assertEquals; 35 | import static org.mockito.Mockito.mock; 36 | import static org.mockito.Mockito.when; 37 | 38 | 39 | public class RadosBaseTest { 40 | 41 | private RadosBase radosBase; 42 | private Callable callable; 43 | private String msg = "error message"; 44 | 45 | @Before 46 | @SuppressWarnings("unchecked") 47 | public void setUp() throws Exception { 48 | radosBase = new RadosBase(); 49 | callable = mock(Callable.class); 50 | } 51 | 52 | @Test 53 | public void testReturnCodeZero() throws Exception { 54 | when(callable.call()).thenReturn(0); 55 | final Integer result = radosBase.handleReturnCode(callable, msg); 56 | 57 | assertEquals(result.intValue(), 0); 58 | } 59 | 60 | @Test(expected = RadosException.class) 61 | public void testCallableThrowsGeneralException() throws Exception { 62 | when(callable.call()).thenThrow(new Exception("fail")); 63 | 64 | radosBase.handleReturnCode(callable, msg); 65 | } 66 | 67 | @Test(expected = RadosPermissionException.class) 68 | public void testReturnCodeMinus1() throws Exception { 69 | when(callable.call()).thenReturn(-1); 70 | 71 | radosBase.handleReturnCode(callable, msg); 72 | } 73 | 74 | @Test(expected = RadosNotFoundException.class) 75 | public void testReturnCodeMinus2() throws Exception { 76 | when(callable.call()).thenReturn(-2); 77 | 78 | radosBase.handleReturnCode(callable, msg); 79 | } 80 | 81 | @Test(expected = RadosInvalidArgumentException.class) 82 | public void testReturnCodeMinus22() throws Exception { 83 | when(callable.call()).thenReturn(-22); 84 | 85 | radosBase.handleReturnCode(callable, msg); 86 | } 87 | 88 | @Test(expected = RadosReadOnlyException.class) 89 | public void testReturnCodeMinus30() throws Exception { 90 | when(callable.call()).thenReturn(-30); 91 | 92 | radosBase.handleReturnCode(callable, msg); 93 | } 94 | 95 | @Test(expected = RadosArgumentOutOfDomainException.class) 96 | public void testReturnCodeMinus33() throws Exception { 97 | when(callable.call()).thenReturn(-33); 98 | 99 | radosBase.handleReturnCode(callable, msg); 100 | } 101 | 102 | @Test(expected = RadosAlreadyConnectedException.class) 103 | public void testReturnCodeMinus106() throws Exception { 104 | when(callable.call()).thenReturn(-106); 105 | 106 | radosBase.handleReturnCode(callable, msg); 107 | } 108 | 109 | @Test(expected = RadosTimeoutException.class) 110 | public void testReturnCodeMinus110() throws Exception { 111 | when(callable.call()).thenReturn(-110); 112 | 113 | radosBase.handleReturnCode(callable, msg); 114 | } 115 | 116 | @Test(expected = RadosOperationInProgressException.class) 117 | public void testReturnCodeMinus115() throws Exception { 118 | when(callable.call()).thenReturn(-115); 119 | 120 | radosBase.handleReturnCode(callable, msg); 121 | } 122 | 123 | @Test(expected = RadosException.class) 124 | public void testUnhandledReturnCode() throws Exception { 125 | when(callable.call()).thenReturn(-131); 126 | 127 | Exception ex = null; 128 | try { 129 | radosBase.handleReturnCode(callable, msg); 130 | } catch (Exception error) { 131 | ex = error; 132 | throw error; 133 | } finally { 134 | assert (ex != null); 135 | assertEquals(ex.getMessage(), msg + "; ENOTRECOVERABLE: State not recoverable (-131)"); 136 | } 137 | 138 | } 139 | 140 | } 141 | -------------------------------------------------------------------------------- /src/test/java/com/ceph/rados/exceptions/ErrorCodeTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados 3 | * 4 | * Copyright (C) 2014 1&1 - Behar Veliqi 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | package com.ceph.rados.exceptions; 19 | 20 | import org.junit.Test; 21 | 22 | import static org.junit.Assert.assertEquals; 23 | 24 | public class ErrorCodeTest { 25 | 26 | private static final int UNKNOWN_ERROR_CODE = -250; 27 | private static final int EPERM = -1; 28 | 29 | 30 | @Test 31 | public void testGetErrorName() throws Exception { 32 | final String errorName = ErrorCode.getErrorName(EPERM); 33 | 34 | assertEquals(errorName, "EPERM"); 35 | } 36 | 37 | @Test 38 | public void testGetErrorNameUnknown() throws Exception { 39 | final String errorName = ErrorCode.getErrorName(UNKNOWN_ERROR_CODE); 40 | 41 | assertEquals(errorName, "UNKNOWN_ERROR"); 42 | } 43 | 44 | @Test 45 | public void testgetErrorMessage() throws Exception { 46 | final String errorMessage = ErrorCode.getErrorMessage(EPERM); 47 | 48 | assertEquals(errorMessage, "Operation not permitted"); 49 | } 50 | 51 | @Test 52 | public void testgetErrorMessageUnknown() throws Exception { 53 | final String errorMessage = ErrorCode.getErrorMessage(UNKNOWN_ERROR_CODE); 54 | 55 | assertEquals(errorMessage, "Unknown error code: " + UNKNOWN_ERROR_CODE); 56 | } 57 | 58 | @Test 59 | public void testEnum() throws Exception { 60 | final ErrorCode epermEnum = ErrorCode.getEnum(EPERM); 61 | 62 | assertEquals(epermEnum, ErrorCode.EPERM); 63 | } 64 | 65 | @Test 66 | public void testEnumUnknown() throws Exception { 67 | final ErrorCode epermEnum = ErrorCode.getEnum(UNKNOWN_ERROR_CODE); 68 | 69 | assertEquals(epermEnum, null); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/test/java/com/ceph/radosstriper/TestRadosStriper.java: -------------------------------------------------------------------------------- 1 | package com.ceph.radosstriper; 2 | 3 | 4 | import com.ceph.rados.IoCTX; 5 | import com.ceph.rados.Rados; 6 | import org.junit.AfterClass; 7 | import static org.junit.Assert.assertEquals; 8 | import static org.junit.Assert.assertNotNull; 9 | import static org.junit.Assert.assertTrue; 10 | import org.junit.BeforeClass; 11 | import org.junit.Test; 12 | 13 | import java.io.File; 14 | import java.util.Random; 15 | 16 | public class TestRadosStriper { 17 | private static String ENV_CONFIG_FILE = System.getenv("RADOS_JAVA_CONFIG_FILE"); 18 | private static String ENV_ID = System.getenv("RADOS_JAVA_ID"); 19 | private static String ENV_POOL = System.getenv("RADOS_JAVA_POOL"); 20 | 21 | private static final String CONFIG_FILE = ENV_CONFIG_FILE == null ? "/etc/ceph/ceph.conf" : ENV_CONFIG_FILE; 22 | private static final String ID = ENV_ID == null ? "admin" : ENV_ID; 23 | private static final String POOL = ENV_POOL == null ? "data" : ENV_POOL; 24 | 25 | private static RadosStriper rados; 26 | private static IoCTXStriper ioctx; 27 | 28 | @BeforeClass 29 | public static void setUp() throws Exception { 30 | rados = new RadosStriper(ID); 31 | rados.confReadFile(new File(CONFIG_FILE)); 32 | rados.connect(); 33 | ioctx = rados.ioCtxCreateStriper(rados.ioCtxCreate(POOL)); 34 | } 35 | 36 | /** 37 | * This test verifies if we can get the version out of librados 38 | * It's currently hardcoded to expect at least 0.48.0 39 | */ 40 | @Test 41 | public void testGetVersion() { 42 | int[] version = Rados.getVersion(); 43 | assertTrue(version[0] >= 0); 44 | assertTrue(version[1] >= 48); 45 | assertTrue(version[2] >= 0); 46 | } 47 | 48 | @AfterClass 49 | public static void tearDown() throws Exception { 50 | rados.destroy(ioctx); 51 | rados.shutDown(); 52 | 53 | 54 | } 55 | 56 | @Test 57 | public void testClusterFsid() throws Exception { 58 | assertNotNull("The fsid returned was null", rados.clusterFsid()); 59 | } 60 | 61 | @Test 62 | public void testPoolList() throws Exception { 63 | String[] pools = rados.poolList(); 64 | assertNotNull(pools); 65 | assertTrue("We expect at least 1 pool (the one using here)", pools.length >= 1); 66 | } 67 | 68 | 69 | @Test 70 | public void testPoolLookup() throws Exception { 71 | long id = rados.poolLookup(POOL); 72 | assertTrue("The POOL ID should be at least 0", id >= 0); 73 | 74 | String name = rados.poolReverseLookup(id); 75 | assertEquals("The POOL names didn't match!", POOL, name); 76 | } 77 | 78 | @Test 79 | public void testInstanceId() throws Exception { 80 | long id = rados.getInstanceId(); 81 | assertTrue("The id should be greater than 0", id > 0); 82 | } 83 | 84 | /** 85 | * This is an pretty extensive test which creates an object 86 | * writes data, appends, truncates verifies the written data 87 | * and finally removes the object 88 | */ 89 | @Test 90 | public void testIoCtxWriteListAndRead() throws Exception { 91 | /** 92 | * The object we will write to with the data 93 | */ 94 | String oid = "rados-java"; 95 | byte[] content = "junit wrote this".getBytes(); 96 | 97 | ioctx.write(oid, content); 98 | 99 | /** 100 | * We simply append the already written data 101 | */ 102 | ioctx.append(oid, content); 103 | assertEquals("The size doesn't match after the append", content.length * 2, ioctx.stat(oid).getSize()); 104 | 105 | /** 106 | * We now resize the object to it's original size 107 | */ 108 | ioctx.truncate(oid, content.length); 109 | assertEquals("The size doesn't match after the truncate", content.length, ioctx.stat(oid).getSize()); 110 | 111 | ioctx.remove(oid); 112 | } 113 | 114 | /** 115 | * This test creates an object, appends some data and removes it afterwards 116 | */ 117 | @Test 118 | public void testIoCtxStripedWriteAndAppendBytes() throws Exception { 119 | /** 120 | * The object we will write to with the data 121 | */ 122 | String oid = "rados-java-striped"; 123 | 124 | try { 125 | byte[] buffer = new byte[8192]; 126 | // use a fix seed so that we always get the same data 127 | new Random(42).nextBytes(buffer); 128 | 129 | ioctx.write(oid, buffer); 130 | 131 | /** 132 | * We simply append the parts of the already written data 133 | */ 134 | ioctx.append(oid, buffer, buffer.length / 2); 135 | 136 | int expectedFileSize = buffer.length + buffer.length / 2; 137 | assertEquals("The size doesn't match after the append", expectedFileSize, ioctx.stat(oid).getSize()); 138 | 139 | byte[] readBuffer = new byte[expectedFileSize]; 140 | ioctx.read(oid, expectedFileSize, 0, readBuffer); 141 | for (int i = 0; i < buffer.length; i++) { 142 | assertEquals(buffer[i], readBuffer[i]); 143 | } 144 | for (int i = 0; i < buffer.length / 2; i++) { 145 | assertEquals(buffer[i], readBuffer[i + buffer.length]); 146 | } 147 | } finally { 148 | ioctx.remove(oid); 149 | } 150 | } 151 | 152 | /** 153 | * This test tests write of partial buffer 154 | */ 155 | @Test 156 | public void testIoCtxWritePartialBuffer() throws Exception { 157 | /** 158 | * The object we will write to with the data 159 | */ 160 | String oid = "rados-java-partial"; 161 | int write_len = 5; 162 | byte[] content = "junit wrote this".getBytes(); 163 | 164 | ioctx.write(oid, content, write_len, 0); 165 | 166 | /** 167 | * We now check for expected size 168 | */ 169 | assertEquals("The size doesn't match length param", write_len, ioctx.stat(oid).getSize()); 170 | 171 | ioctx.remove(oid); 172 | } 173 | 174 | } 175 | -------------------------------------------------------------------------------- /src/test/java/com/ceph/rbd/TestRbd.java: -------------------------------------------------------------------------------- 1 | /* 2 | * RADOS Java - Java bindings for librados and librbd 3 | * 4 | * Copyright (C) 2013 Wido den Hollander 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on 14 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 15 | * either express or implied. See the License for the specific 16 | * language governing permissions and limitations under the License. 17 | */ 18 | 19 | package com.ceph.rbd; 20 | 21 | import com.ceph.rbd.jna.RbdImageInfo; 22 | import com.ceph.rbd.jna.RbdSnapInfo; 23 | import com.ceph.rados.Rados; 24 | import com.ceph.rados.exceptions.RadosException; 25 | import com.ceph.rados.IoCTX; 26 | 27 | import java.io.File; 28 | import java.util.Arrays; 29 | import java.util.List; 30 | 31 | import org.junit.AfterClass; 32 | import org.junit.BeforeClass; 33 | import org.junit.Test; 34 | 35 | import static org.junit.Assert.assertEquals; 36 | import static org.junit.Assert.assertFalse; 37 | import static org.junit.Assert.assertNotNull; 38 | import static org.junit.Assert.assertTrue; 39 | import static org.junit.Assert.fail; 40 | 41 | import java.security.SecureRandom; 42 | import java.math.BigInteger; 43 | 44 | public final class TestRbd { 45 | /** 46 | This test reads it's configuration from the environment 47 | Possible variables: 48 | * RADOS_JAVA_ID 49 | * RADOS_JAVA_CONFIG_FILE 50 | * RADOS_JAVA_POOL 51 | */ 52 | 53 | private static String ENV_CONFIG_FILE = System.getenv("RADOS_JAVA_CONFIG_FILE"); 54 | private static String ENV_ID = System.getenv("RADOS_JAVA_ID"); 55 | private static String ENV_POOL = System.getenv("RADOS_JAVA_POOL"); 56 | 57 | private static final String CONFIG_FILE = ENV_CONFIG_FILE == null ? "/etc/ceph/ceph.conf" : ENV_CONFIG_FILE; 58 | private static final String ID = ENV_ID == null ? "admin" : ENV_ID; 59 | private static final String POOL = ENV_POOL == null ? "rbd" : ENV_POOL; 60 | 61 | private static Rados rados; 62 | private static IoCTX ioctx; 63 | 64 | private void cleanupImage(Rados r, IoCTX io, String image) throws RadosException, RbdException { 65 | if (r != null) { 66 | if (io != null) { 67 | Rbd rbd = new Rbd(ioctx); 68 | rbd.remove(image); 69 | } 70 | } 71 | } 72 | 73 | @BeforeClass 74 | public static void setUp() throws Exception { 75 | rados = new Rados(ID); 76 | rados.confReadFile(new File(CONFIG_FILE)); 77 | rados.connect(); 78 | ioctx = rados.ioCtxCreate(POOL); 79 | String [] allOids = ioctx.listObjects(); 80 | for (int i = 0; i < allOids.length; i++) { 81 | ioctx.remove(allOids[i]); 82 | } 83 | } 84 | 85 | @AfterClass 86 | public static void tearDown() throws Exception { 87 | rados.ioCtxDestroy(ioctx); 88 | rados.shutDown(); 89 | } 90 | 91 | /** 92 | This test verifies if we can get the version out of librados 93 | It's currently hardcoded to expect at least 0.48.0 94 | */ 95 | @Test 96 | public void testGetVersion() { 97 | int[] version = Rbd.getVersion(); 98 | assertTrue(version[0] >= 0); 99 | assertTrue(version[1] >= 1); 100 | assertTrue(version[2] >= 8); 101 | } 102 | 103 | @Test 104 | public void testEmptyListImages() throws Exception { 105 | try { 106 | Rbd rbd = new Rbd(ioctx); 107 | 108 | List imageList = Arrays.asList(rbd.list()); 109 | assertTrue("There were more then 0 (" + imageList.size() + ") images in the pool", imageList.size() == 0); 110 | } catch (RbdException e) { 111 | fail(e.getMessage() + ": " + e.getReturnValue()); 112 | } 113 | } 114 | 115 | @Test 116 | public void testCreateListAndRemoveImage() throws Exception { 117 | long imageSize = 10485760; 118 | String imageName = "testimage1"; 119 | String newImageName = "testimage2"; 120 | 121 | try { 122 | Rbd rbd = new Rbd(ioctx); 123 | rbd.create(imageName, imageSize); 124 | 125 | String[] images = rbd.list(); 126 | assertTrue("There were no images in the pool", images.length > 0); 127 | 128 | rbd.rename(imageName, newImageName); 129 | 130 | RbdImage image = rbd.open(newImageName); 131 | RbdImageInfo info = image.stat(); 132 | 133 | assertEquals("The size of the image didn't match", imageSize, info.size); 134 | 135 | rbd.close(image); 136 | } catch (RbdException e) { 137 | fail(e.getMessage() + ": " + e.getReturnValue()); 138 | } finally { 139 | cleanupImage(rados, ioctx, newImageName); 140 | } 141 | } 142 | 143 | @Test 144 | public void testCreateFormatOne() throws Exception { 145 | String imageName = "imageformat1"; 146 | long imageSize = 10485760; 147 | 148 | try { 149 | Rbd rbd = new Rbd(ioctx); 150 | rbd.create(imageName, imageSize); 151 | 152 | RbdImage image = rbd.open(imageName); 153 | 154 | boolean oldFormat = image.isOldFormat(); 155 | 156 | assertTrue("The image wasn't the old (1) format", oldFormat); 157 | 158 | rbd.close(image); 159 | } catch (RbdException e) { 160 | fail(e.getMessage() + ": " + e.getReturnValue()); 161 | } finally { 162 | cleanupImage(rados, ioctx, imageName); 163 | } 164 | } 165 | 166 | @Test 167 | public void testCreateFormatTwo() throws Exception { 168 | String imageName = "imageformat2"; 169 | long imageSize = 10485760; 170 | 171 | try { 172 | // We only want layering and format 2 173 | int features = (1<<0); 174 | 175 | Rbd rbd = new Rbd(ioctx); 176 | rbd.create(imageName, imageSize, features, 0); 177 | 178 | RbdImage image = rbd.open(imageName); 179 | 180 | boolean oldFormat = image.isOldFormat(); 181 | 182 | assertTrue("The image wasn't the new (2) format", !oldFormat); 183 | 184 | rbd.close(image); 185 | } catch (RbdException e) { 186 | fail(e.getMessage() + ": " + e.getReturnValue()); 187 | } finally { 188 | cleanupImage(rados, ioctx, imageName); 189 | } 190 | } 191 | 192 | @Test 193 | public void testCreateAndClone() throws Exception { 194 | String imageName = "baseimage-" + System.currentTimeMillis(); 195 | String childImageName = imageName + "-child1"; 196 | long imageSize = 10485760; 197 | String snapName = "mysnapshot"; 198 | 199 | try { 200 | // We only want layering and format 2 201 | int features = (1<<0); 202 | 203 | Rbd rbd = new Rbd(ioctx); 204 | rbd.create(imageName, imageSize, features, 0); 205 | 206 | RbdImage image = rbd.open(imageName); 207 | 208 | boolean oldFormat = image.isOldFormat(); 209 | 210 | assertTrue("The image wasn't the new (2) format", !oldFormat); 211 | 212 | image.snapCreate(snapName); 213 | image.snapProtect(snapName); 214 | 215 | List snaps = image.snapList(); 216 | assertEquals("There should only be one snapshot", 1, snaps.size()); 217 | 218 | rbd.clone(imageName, snapName, ioctx, childImageName, features, 0); 219 | 220 | boolean isProtected = image.snapIsProtected(snapName); 221 | assertTrue("The snapshot was not protected", isProtected); 222 | 223 | rbd.remove(childImageName); 224 | 225 | image.snapUnprotect(snapName); 226 | image.snapRemove(snapName); 227 | 228 | rbd.close(image); 229 | 230 | rbd.remove (imageName); 231 | } catch (RbdException e) { 232 | fail(e.getMessage() + ": " + e.getReturnValue()); 233 | } 234 | } 235 | 236 | @Test 237 | public void testSnapList() throws Exception { 238 | String imageName = "baseimage-" + System.currentTimeMillis(); 239 | long imageSize = 10485760; 240 | String snapName = "mysnapshot"; 241 | int numSnaps = 32; 242 | int initialBufferSize = 16; 243 | 244 | try { 245 | // We only want layering and format 2 246 | int features = (1<<0); 247 | 248 | Rbd rbd = new Rbd(ioctx); 249 | rbd.create(imageName, imageSize, features, 0); 250 | 251 | RbdImage image = rbd.open(imageName); 252 | 253 | boolean oldFormat = image.isOldFormat(); 254 | 255 | assertTrue("The image wasn't the new (2) format", !oldFormat); 256 | 257 | List snapsEmpty = image.snapList(initialBufferSize); 258 | assertEquals("There should not be any snapshots for the image", 0, snapsEmpty.size()); 259 | 260 | for (int i = 0; i < numSnaps; i++) { 261 | image.snapCreate(snapName + "-" + i); 262 | image.snapProtect(snapName + "-" + i); 263 | } 264 | 265 | List snaps = image.snapList(initialBufferSize); 266 | assertEquals("The amount of snapshots does not match", numSnaps, snaps.size()); 267 | 268 | for (int i = 0; i < numSnaps; i++) { 269 | image.snapUnprotect(snapName + "-" + i); 270 | image.snapRemove(snapName + "-" + i); 271 | } 272 | 273 | rbd.close(image); 274 | rbd.remove(imageName); 275 | } catch (RbdException e) { 276 | fail(e.getMessage() + ": " + e.getReturnValue()); 277 | } 278 | } 279 | 280 | @Test 281 | public void testCreateAndWriteAndRead() throws Exception { 282 | String imageName = "imageforwritetest"; 283 | long imageSize = 10485760; 284 | 285 | try { 286 | // We only want layering and format 2 287 | int features = (1<<0); 288 | 289 | Rbd rbd = new Rbd(ioctx); 290 | rbd.create(imageName, imageSize, features, 0); 291 | 292 | RbdImage image = rbd.open(imageName); 293 | 294 | String buf = "ceph"; 295 | 296 | // Write the initial data 297 | image.write(buf.getBytes()); 298 | 299 | // Start writing after what we just wrote 300 | image.write(buf.getBytes(), buf.length(), buf.length()); 301 | 302 | byte[] data = new byte[buf.length()]; 303 | image.read(0, data, buf.length()); 304 | assertEquals("Did din't get back what we wrote", new String(data), buf); 305 | 306 | rbd.close(image); 307 | } catch (RbdException e) { 308 | fail(e.getMessage() + ": " + e.getReturnValue()); 309 | } finally { 310 | cleanupImage(rados, ioctx, imageName); 311 | } 312 | } 313 | 314 | @Test 315 | public void testCopy() throws Exception { 316 | String imageName1 = "imagecopy1"; 317 | String imageName2 = "imagecopy2"; 318 | long imageSize = 10485760; 319 | 320 | try { 321 | // We only want layering and format 2 322 | int features = (1<<0); 323 | 324 | Rbd rbd = new Rbd(ioctx); 325 | rbd.create(imageName1, imageSize, features, 0); 326 | rbd.create(imageName2, imageSize, features, 0); 327 | 328 | RbdImage image1 = rbd.open(imageName1); 329 | RbdImage image2 = rbd.open(imageName2); 330 | 331 | SecureRandom random = new SecureRandom(); 332 | String buf = new BigInteger(130, random).toString(32); 333 | image1.write(buf.getBytes()); 334 | 335 | rbd.copy(image1, image2); 336 | 337 | byte[] data = new byte[buf.length()]; 338 | long bytes = image2.read(0, data, buf.length()); 339 | assertEquals("The copy seem to have failed. The data we read didn't match", new String(data), buf); 340 | 341 | rbd.close(image1); 342 | rbd.close(image2); 343 | } catch (RbdException e) { 344 | fail(e.getMessage() + ": " + e.getReturnValue()); 345 | } finally { 346 | cleanupImage(rados, ioctx, imageName1); 347 | cleanupImage(rados, ioctx, imageName2); 348 | } 349 | } 350 | 351 | @Test 352 | public void testResize() throws Exception { 353 | String imageName = "imageforresizetest"; 354 | long initialSize = 10485760; 355 | long newSize = initialSize * 2; 356 | 357 | try { 358 | // We only want layering and format 2 359 | int features = (1<<0); 360 | 361 | Rbd rbd = new Rbd(ioctx); 362 | rbd.create(imageName, initialSize, features, 0); 363 | RbdImage image = rbd.open(imageName); 364 | image.resize(newSize); 365 | RbdImageInfo info = image.stat(); 366 | 367 | assertEquals("The new size of the image didn't match", newSize, info.size); 368 | 369 | rbd.close(image); 370 | } catch (RbdException e) { 371 | fail(e.getMessage() + ": " + e.getReturnValue()); 372 | } finally { 373 | cleanupImage(rados, ioctx, imageName); 374 | } 375 | } 376 | 377 | @Test 378 | public void testCloneAndFlatten() throws Exception { 379 | String parentImageName = "parentimage"; 380 | String cloneImageName = "childimage"; 381 | String snapName = "snapshot"; 382 | long imageSize = 10485760; 383 | 384 | try { 385 | 386 | Rbd rbd = new Rbd(ioctx); 387 | 388 | // We only want layering and format 2 389 | int features = (1 << 0); 390 | 391 | // Create the parent image 392 | rbd.create(parentImageName, imageSize, features, 0); 393 | 394 | // Open the parent image 395 | RbdImage parentImage = rbd.open(parentImageName); 396 | 397 | // Verify that image is in format 2 398 | boolean oldFormat = parentImage.isOldFormat(); 399 | assertTrue("The image wasn't the new (2) format", !oldFormat); 400 | 401 | // Create a snapshot on the parent image 402 | parentImage.snapCreate(snapName); 403 | 404 | // Verify that snapshot exists 405 | List snaps = parentImage.snapList(); 406 | assertEquals("There should only be one snapshot", 1, snaps.size()); 407 | 408 | // Protect the snapshot 409 | parentImage.snapProtect(snapName); 410 | 411 | // Verify that snapshot is protected 412 | boolean isProtected = parentImage.snapIsProtected(snapName); 413 | assertTrue("The snapshot was not protected", isProtected); 414 | 415 | // Clone the parent image using the snapshot 416 | rbd.clone(parentImageName, snapName, ioctx, cloneImageName, features, 0); 417 | 418 | // Open the cloned image 419 | RbdImage cloneImage = rbd.open(cloneImageName); 420 | 421 | // Flatten the cloned image 422 | cloneImage.flatten(); 423 | 424 | // Unprotect the snapshot, this will succeed only after the clone is flattened 425 | parentImage.snapUnprotect(snapName); 426 | 427 | // Verify that snapshot is not protected 428 | isProtected = parentImage.snapIsProtected(snapName); 429 | assertTrue("The snapshot was protected", !isProtected); 430 | 431 | // Delete the snapshot, this will succeed only after the clone is flattened and snapshot is unprotected 432 | parentImage.snapRemove(snapName); 433 | 434 | // Close both the parent and cloned images 435 | rbd.close(cloneImage); 436 | rbd.close(parentImage); 437 | } catch (RbdException e) { 438 | fail(e.getMessage() + ": " + e.getReturnValue()); 439 | } finally { 440 | cleanupImage(rados, ioctx, parentImageName); 441 | cleanupImage(rados, ioctx, cloneImageName); 442 | } 443 | } 444 | 445 | @Test 446 | public void testListImages() throws Exception { 447 | String testImage = "testimage"; 448 | long imageSize = 10485760; 449 | int imageCount = 3; 450 | 451 | try { 452 | Rbd rbd = new Rbd(ioctx); 453 | 454 | for (int i = 1; i <= imageCount; i++) { 455 | rbd.create(testImage + i, imageSize); 456 | } 457 | 458 | // List images without providing initial buffer size 459 | List imageList = Arrays.asList(rbd.list()); 460 | assertTrue("There were less than " + imageCount + " images in the pool", imageList.size() >= imageCount); 461 | 462 | for (int i = 1; i <= imageCount; i++) { 463 | assertTrue("Pool does not contain image testimage" + i, imageList.contains(testImage + i)); 464 | } 465 | 466 | // List images and provide initial buffer size 467 | imageList = null; 468 | imageList = Arrays.asList(rbd.list(testImage.length())); 469 | assertTrue("There were less than " + imageCount + " images in the pool", imageList.size() >= imageCount); 470 | 471 | for (int i = 1; i <= imageCount; i++) { 472 | assertTrue("Pool does not contain image testimage" + i, imageList.contains(testImage + i)); 473 | } 474 | } catch (RbdException e) { 475 | fail(e.getMessage() + ": " + e.getReturnValue()); 476 | } finally { 477 | for (int i = 1; i <= imageCount; i++) { 478 | cleanupImage(rados, ioctx, testImage + i); 479 | } 480 | } 481 | } 482 | 483 | @Test 484 | public void testListChildren() throws Exception { 485 | try { 486 | Rbd rbd = new Rbd(ioctx); 487 | 488 | String parentImageName = "parentimage"; 489 | String childImageName = "childImage"; 490 | String snapName = "snapshot"; 491 | long imageSize = 10485760; 492 | int childCount = 3; 493 | 494 | // We only want layering and format 2 495 | int features = (1 << 0); 496 | 497 | // Create the parent image 498 | rbd.create(parentImageName, imageSize, features, 0); 499 | 500 | // Open the parent image 501 | RbdImage parentImage = rbd.open(parentImageName); 502 | 503 | // Verify that image is in format 2 504 | boolean oldFormat = parentImage.isOldFormat(); 505 | assertTrue("The image wasn't the new (2) format", !oldFormat); 506 | 507 | // Create a snapshot on the parent image 508 | parentImage.snapCreate(snapName); 509 | 510 | // Verify that snapshot exists 511 | List snaps = parentImage.snapList(); 512 | assertEquals("There should only be one snapshot", 1, snaps.size()); 513 | 514 | // Protect the snapshot 515 | parentImage.snapProtect(snapName); 516 | 517 | // Verify that snapshot is protected 518 | boolean isProtected = parentImage.snapIsProtected(snapName); 519 | assertTrue("The snapshot was not protected", isProtected); 520 | 521 | for (int i = 1; i <= childCount; i++) { 522 | // Clone the parent image using the snapshot 523 | rbd.clone(parentImageName, snapName, ioctx, childImageName + i, features, 0); 524 | } 525 | 526 | // List the children of snapshot 527 | List children = parentImage.listChildren(snapName); 528 | 529 | // Verify that two children are returned and the list contains their names 530 | assertEquals("Snapshot should have " + childCount + " children", childCount, children.size()); 531 | 532 | for (int i = 1; i <= childCount; i++) { 533 | assertTrue(POOL + '/' + childImageName + i + " should be listed as a child", children.contains(POOL + '/' + childImageName + i)); 534 | } 535 | 536 | // Delete the cloned images 537 | for (int i = 1; i <= childCount; i++) { 538 | rbd.remove(childImageName + i); 539 | } 540 | 541 | // Unprotect the snapshot, this will succeed only after the clone is flattened 542 | parentImage.snapUnprotect(snapName); 543 | 544 | // Verify that snapshot is not protected 545 | isProtected = parentImage.snapIsProtected(snapName); 546 | assertTrue("The snapshot was protected", !isProtected); 547 | 548 | // Delete the snapshot 549 | parentImage.snapRemove(snapName); 550 | 551 | // Close the parent imgag 552 | rbd.close(parentImage); 553 | 554 | // Delete the parent image 555 | rbd.remove(parentImageName); 556 | } catch (RbdException e) { 557 | fail(e.getMessage() + ": " + e.getReturnValue()); 558 | } 559 | } 560 | } 561 | --------------------------------------------------------------------------------