fusesource / leveldbjni

A Java Native Interface to LevelDB
BSD 3-Clause "New" or "Revised" License
535 stars 145 forks source link

Automatic fallback to use LevelDB native binary installed by OS package manager, instead of one bundled (leveldbjni-all) #90

Closed vorburger closed 7 years ago

vorburger commented 7 years ago

For use cases such as https://bugs.opendaylight.org/show_bug.cgi?id=7742,

the goal of this issue would to be make this kind of set-up work out of the box in leveldbjni (where "out of the box" = "just work", without having to set anything like custom environment variables, -D system properties and the like):

sudo dnf install leveldbjni <== or some other new RPM package
cd leveldbjni
mvn -Dtest=DBTest test

I suspect that this may require a little bit of work in http://fusesource.github.io/hawtjni/ ? The above currently doesn't work yet (fails with java.lang.UnsatisfiedLinkError: Could not load library. Reasons: [no leveldbjni64-99-master-SNAPSHOT in java.library.path, no leveldbjni-99-master-SNAPSHOT in java.library.path, no leveldbjni in java.library.path] at org.fusesource.hawtjni.runtime.Library.doLoad(Library.java:187)); probably because HawtJNI's Library only checks in the classpath's META-INF/native/, but cannot by itself detect native binary *.so libs installed by OS package manager?

chirino commented 7 years ago

So leveldbjni is not the same as the leveldb lib. leveldbjni contains the lelveldb lib statically compiled in and also all the JNI wrapper code used to access leveldb. In theory you could make it work if you did sudo dnf install leveldbjni to install the JNI version of the lib. Not sure anyone is going to be working on creating an RPM for leveldbjni.

vorburger commented 7 years ago

So leveldbjni is not the same as the leveldb lib. leveldbjni contains the lelveldb lib statically compiled in and also all the JNI wrapper code used to access leveldb.

Got it, I understand it better now; thanks for clarifying. (I've edited the original issue description to clarify that this is about it working O-O-B in connection with e.g. a sudo dnf install leveldbjni and not sudo dnf install leveldb.)

could make it work if you did sudo dnf install leveldbjni to install the JNI version of the lib. Not sure anyone is going to be working on creating an RPM for leveldbjni.

It appears that there IS a RPM already (see https://koji.fedoraproject.org/koji/packageinfo?packageID=18435; thanks to @skitt for pointed me to), but that's one of those RPM-for-Java-JAR thingies - that package, currently, does not directly provide a leveldbjni.so in e.g. /lib64, so that e.g. ldconfig & Co. can find it.

I say not directly provide because that RPM does have the SO in it somewhere (in /META-INF/native/linux64/ inside its leveldbjni-all.jar = leveldbjni-linux.jar which it installs into [/usr]/lib/java/), but that's... justement not what one would want, in this context, IMHO.

Just for future reference and repeatability for testing, check this out, if interested:

$ sudo dnf install leveldbjni

$ find /lib/ -name "*leveldb*"
/lib/java/leveldbjni
/lib/java/leveldbjni/leveldbjni.jar
/lib/java/leveldbjni-linux.jar
/lib/java/leveldbjni-all.jar
$ find /usr/lib/ -name "*leveldb*" 
/usr/lib/java/leveldbjni
/usr/lib/java/leveldbjni/leveldbjni.jar
/usr/lib/java/leveldbjni-linux.jar
/usr/lib/java/leveldbjni-all.jar

$ ldconfig -p | grep leveldb
NADA

Note that this is different from e.g. the this or any other lib package (FTR: This issue is now not about the leveldb anymore, that's separate and not directly related to leveldbjni.)

$ sudo dnf install leveldb

$ find /lib64/ -name "*leveldb*"
/lib64/libleveldb.so.1.0.7
/lib64/libleveldb.so.1
$ find /usr/lib64/ -name "*leveldb*"
/usr/lib64/libleveldb.so.1.0.7
/usr/lib64/libleveldb.so.1

$ ldconfig -p | grep leveldb
    libleveldb.so.1 (libc6,x86-64) => /lib64/libleveldb.so.1
vorburger commented 7 years ago

OK, just as a POC, the following isn't the expected end game, just proof that the approach would be viable, if it were industrialized by e.g. an RPM which correctly installed required native binary shared libraries:

For this POC we HAVE to manually install leveldb (see below), if this was industrialized then leveldbjni would have a dependency on leveldb and this would not be needed anymore; and we install leveldbjni just to grab the .so from inside it, but as explained above that package (currently) does not actually correctly install the .so in a usable form:

sudo dnf install leveldb
sudo dnf install leveldbjni
cp /lib/java/leveldbjni-linux.jar /tmp
cd /tmp
mv META-INF/native/linux64/libleveldbjni.so .
chmod +x libleveldbjni.so

if we now add this to the leveldbjni/leveldbjni-tests/pom.xml to make it use the *.so from /tmp:

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.19.1</version>
    <configuration>
       <systemPropertyVariables>
         <library.leveldbjni.path>/tmp/</library.leveldbjni.path>
       </systemPropertyVariables>
    </configuration>
  </plugin>

then the mvn test -P\!linux64 ran in it, as above, will now pass!

If we did about without installing leveldb, then it would still fail with java.lang.UnsatisfiedLinkError: Could not load library. Reasons: [/tmp/libleveldbjni.so: libleveldb.so.1: cannot open shared object file: No such file or directory, no leveldbjni in java.library.path]; NB how this is slightly confusing, Java seems to be pretty bad with giving a better root cause in case of UnsatisfiedLinkError, the real problem only because apparent if were to do:

ldd /tmp/libleveldbjni.so
    linux-vdso.so.1 (0x00007fffafd74000)
    libleveldb.so.1 => not found
    libsnappy.so.1 => /lib64/libsnappy.so.1 (0x00007f02b43a0000)
    libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f02b4018000)
    libm.so.6 => /lib64/libm.so.6 (0x00007f02b3d0f000)
    libc.so.6 => /lib64/libc.so.6 (0x00007f02b394c000)
    libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f02b3735000)
    /lib64/ld-linux-x86-64.so.2 (0x000055b3eecda000)
vorburger commented 7 years ago

https://github.com/fusesource/leveldbjni/pull/91 proposes some doc clarification related to this.

Re. RPM, see https://bugzilla.redhat.com/show_bug.cgi?id=1420383 => https://bugzilla.redhat.com/show_bug.cgi?id=1420433

vorburger commented 7 years ago

Self closing as timed out, as I have no intention to continue working on this. Background, FTR: due to https://fedoraproject.org/wiki/Packaging:Java#Packaging_JAR_files_that_use_JNI, it appears to be much more difficult than I originally thought it would be to get a RPM which just has the libleveldbjni.so in /lib64/ instead of wrapped inside /lib/java/leveldbjni-linux.jar ... I personally think this is fundamentally wrong, but it appears changing this would be bigger discussion than I'm motivated to have.

anuscool commented 6 years ago

I am getting this error in rocksdbjni,i am using latest rocksdb 5.9.2,with rocksdb 3.0 i am able to pass all test cases but it is failing with latest version.

Running org.fusesource.rocksdbjni.test.DBTest Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 1.906 sec <<< FAILURE! - in org.fusesource.rocksdbjni.test.DBTest warning(junit.framework.TestSuite$1) Time elapsed: 0.027 sec <<< FAILURE! junit.framework.AssertionFailedError: Exception in constructor: testOpen (java.lang.UnsatisfiedLinkError: Could not load library. Reasons: [no rocksdbjni64-99-master-SNAPSHOT in java.library.path, no rocksdbjni-99-master-SNAPSHOT in java.library.path, no rocksdbjni in java.library.path, /tmp/librocksdbjni-64-99-master-SNAPSHOT-3740711155003969935.so: /tmp/librocksdbjni-64-99-master-SNAPSHOT-3740711155003969935.so: undefined symbol: _ZTIN7rocksdb6LoggerE] at org.fusesource.hawtjni.runtime.Library.doLoad(Library.java:187)

vorburger commented 6 years ago

@anuscool why are you commenting about that in this (closed) issue on the leveldbjni project?

Probably more suitable for the https://github.com/fusesource/rocksdbjni/issues project?