-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace DirectBuffer with Agrona DirectBuffer #68
Conversation
Travis has passed the Java 8 test, but failed the Java 7 tests due the third-party SBE tool being compiled with Java 8. As Java 7 was end of life in April 2015 I would respectfully suggest it is reasonable to discontinue the JDK 7 CI tests. |
I think replacing I do have some concerns on dropping Java 7 support, mostly for sake of Android. However, Android N seems to have limited support for Java 8 and there seems to be some support for Android 6.0 (API level 23) as well. I don't have any Android experience so I don't know how this works in practice. On the other hand, zero copy with If anyone use lmdbjni for Android I would like know if this is concern or not. Also if there are any users on Java 7 still. |
Some minor comments on the code.
There are not a lot of places where MutableDirectBuffer is instantiated in production code. Maybe add a utility method creating buffers only for tests? The
|
ab090fa
to
eac3d5f
Compare
Further to my earlier comment on CI failing due to a Java 8 dependency in the SBE Tool, upon further investigation the Java 8 requirement also extends to Agrona itself. I had hoped that it was isolated to the SBE Tool, therefore enabling a tactical workaround such as manually generating the flyweights. However Java 8 is also a requirement of Agrona:
In relation to the As the The main benefit of
It is called from some 48 call sites:
As such we now have a single location if conditional logic is required to select an alternate implementation in the future. Of more minor benefit, we also have reduced the length of lines that would have needed to manually instantiate Neverthess you are the maintainer, so I can switch back to creating Regarding the POM indentation, I have fixed this up and squashed it into the original commit for further review. |
Sorry for the late reply. I have been on vacation for a week. I agree that the |
There was one thing. Can we shade this dependency or is it a bad thing? I know this technique will be less relevant as Java 9 emerge but I'm curious about the general opinion. |
Agrona has had 20 releases in 16 months (see here and here). Any application that uses Agrona (eg Aeron, SBE) will probably want to use the latest Agrona. If LMDBJNI shades Agrona, this will complicate the classpath ordering of such applications. The two benefits I can see for shading are:
Personally I prefer to keep things simple and idiomatic by not shading the dependency. |
I maintain that using a ByteBuffer is the way to go (see #42), instead of relying on unsafe operations. It would keep the library light-weight, more portable and future-proof. Would also work with existing serialization code using ByteBuffer APIs, and would not stop anyone from using their favorite buffer wrappers, such as Agrona and many others out there. The opposite is not true. The only difficulty seems to be that HawtJNI does not generate native code that returns ByteBuffers. |
@phraktle I agree in principle (I'd still like to benchmark the result to ensure there is no regression though), but do you know if someone is working on making HawtJNI support this? |
Opened a ticket here: fusesource/hawtjni#25. In the meantime, perhaps a reasonable hack would be to create DirectByteBuffers from the pointer on the Java level (rather than in JNI). This does require reflection to make |
I think this change make sense irrespective if we change to ByteBuffer some time in the future. But maybe it's time I look into this issue. @phraktle: have you looked into how difficult it would be to implement that in HawtJNI? It's a bit unfortunate that the library grows with 224K though, at the same time, users sensitive to footprint would indeed probably solve that one way or another. I agree with @benalexau comment on shading (so let's not do that). |
I'll do a benchmark for the ByteBuffer reflection trick this coming week and see how it performs against DirectBuffer. |
Are we opposed to abandoning HawtJNI in favour of raw JNI or another JNI helper library? A few months ago I did a quick (and encouraging) experiment accessing LMDB via JNAerator-emitted BridJ bindings. I only used this combination as I had recent experience with them and an internal C++ library. I feel hand-crafted JNI or a more minimalist C-focused JNI binding generator (eg Gluegen) might be worth exploration, particularly given LMDB is such a small and stable API. |
I did some manual JNI hacking some time ago but that was a nightmare. I haven't looked closer at other JNI code generating tools. But since lmdbjni is quite mature I think our best bet is to solve it in HawtJNI. |
I haven't looked into how difficult it would be to do this in HawtJNI. Agree that manual JNI is too painful. Alternatives to HawtJNI could work also. Hopefully there will be a better FFI for Java: http://openjdk.java.net/jeps/191 In the meantime JNR-FFI looks pretty solid. |
JNR-FFI has a nice API but the performance seems so-so. http://stackoverflow.com/questions/22288909/jni-vs-jna-performance |
That link is about JNA, not JNR-FFI (https://github.com/jnr/jnr-ffi) |
Sorry, I confused the two. Couldn't find any benchmarks so I posted a question on their issue tracker. |
JavaCPP looks quite nice also, well maintained, lots of examples/documentation and promise "zero overhead compared to manually coded JNI functions". |
JavaCPP also appears to use |
I'm not familiar with JavaCPP, but as long as it can generate the JNI code for the LMDB wrapper easily and supports returning ByteBuffers, it should do the trick :) The reason why I mentioned JNR is that it seems widely used and might be the basis of JEP191 / Project Panama. |
I have been playing around with JavaCPP for a short while. Looks promising. |
I still think it would be nice to merge this PR given it would provide a foundation for benchmarking the latest improvements to To this end, LMDBJNI currently uses Such latency might border on immaterial versus the JNI call overhead and practical LMDB use cases, but I believe it needs to be benchmarked with a large enough workload to verify the GC pressure, reflection cost and bounds checking overhead. If the latency is of borderline difference I obviously prefer the cleaner, standards-oriented Separately I am also working on an LMDB DAO that persists SBE types via a Java annotation processor. SBE Pull Request 350 added some code generation features to support this work, so I am keen to finish this off and make it available for others. The annotation processor generated code is simpler and slightly fewer operations if I don't need to obtain the existing LMDBJNI Is @krisskross trying out porting to JavaCPP? Can I help out? Is there a |
Yes, I agree that the primary concern for LMDBJNI is performance. I'm also a bit worried about that extra allocation. The manual tests I did before indicated that it might hurt performance. I will not spend time rewriting LMDBJNI if the performance is worse than what we have today. Right now I'm just playing around with JavaCPP to get a feel for the work needed and it seems relatively straight forward. My C/C++ knowledge is a little shakey so any help in this area would sure be helpful. Cool initiative there with SBE! I was also doing something similar a while back in a project called Graphene. Ill have a closer look at the PR. I will merge the PR, in the meantime. Sorry for the detour. |
If it turns out that the overhead of the ByteBuffer wrapper allocation is indeed an issue, the reflective trick would still allow you to move the pointer without allocating a new one. |
Yes, I'll explore that option aswell. |
BTW, thanks for the PR @benalexau! |
@krisskross you're welcome. How did you want to tackle the JavaCPP piece? A branch here or in your own fork or something else? Regardless of whether we eventually end up with |
Stars is indeed how we measure stuff nowadays, right? ;-) No, but seriously HawtJNI is mostly abandoned so I agree that we should move away from it. Looks like JavaCPP makes it easy to access memory through both address and ByteBuffer. Right now I just play around in a private repository. I can create a public one if you're interested to have a look? |
Stars aren't everything, but in this case there's 30 times as many in one project vs the other, not to mention a commit log with similar polarisation. Given most of us aren't terribly interested in JNI and the Java 9 Happy to take a look at your private repo or a public one. I just don't want to duplicate work you have already done. It'd also be good to get informal feedback along the way, rather than a huge PR at the end. |
Cool, I'll create a repo later tonight and let you know when it's up. |
Got a reply from Charles Nutter regarding performance of JNR-FFI.
|
This PR adopts Agrona's
DirectBuffer
, rather than an early fork ofDirectBuffer
. Adopting Agrona yields several benefits:DirectBuffer
(read-only) andMutableDirectBuffer
(read/write) interfaces, which have the normal benefits of separating interfaces from implementations, plus exposing the most minimal API for each use caseThis PR includes:
DirectBuffer
Env
class, including tests of that defaultBuffers
utility class to centraliseMutableDirectBuffer
instantiation