Hi,

> Here's a question for you: could you tolerate a closeable mapped
> ByteBuffer which was somewhat slower to access?  It is hard to make a
> secure closeable mapped ByteBuffer: the question is how small the
> overhead of closeability can be made.

Lucene uses the ByteBuffer like a conventional byte[] arrays and expects as 
close performance to that as possible. In Java 7 and Java 8 there is for sure 
some large overhead because of missing Hotspot optimizations. In Java 9 we 
found out, that recent builds are now almost as fast as byte[] access. 
Completely destroying that improvement would be no good. :-(

We are also looking into using VarHandles instead of ByteBuffers directly 
(using the new MethodHandles methods to get a VarHandle on top of any 
ByteBuffer, although this does not really fit our use-case completely, because 
we cannot use views like long[] on top of a ByteBuffer, because we sometimes 
also need unaligned accesses). We will try to check this out as soon as first 
builds with VarHandles are available. Of course this would also not help, if a 
Closeable ByteBuffer would also slowdown the VarHandle accesses.

> But if the answer is "We can't tolerate *any* additional overhead, no
> matter how small" then there is no motivation to do any experiments.

It depends how small! If the speed is still somewhere between Java 8 ByteBuffer 
performance and the recent Hotspot improvements in Java 9, I agree with trying 
it out. But some volatile memory access on every access is a no-go. The code 
around ByteBufferIndexInput in Lucene is the most performance-critical critical 
code, because on every search query or sorting there is all the work happening 
in there (millions of iterations with positional ByteBuffer.get* calls). As 
ByteBuffers are limited to 2 GiB, we also need lots of hairy code to work 
around that limitation!

If you look at ByteBufferIndexInput's code you will see that we simply do stuff 
like trying to read from one bytebuffer and only if we catch an 
BufferUnderflowException we fall back to handling buffer switches: Instead of 
checking bounds on every access, we have fallback code only happening on 
exceptions. E.g. if you are 3 bytes before end of one buffer slice and read a 
long, it will throw BufferUnderflow. When this happens the code will fall back 
to read byte by byte from 2 different buffers and reassemble the long): 
https://goo.gl/g1jKcm Stuff like sorting will make heavy use of the 
ByteBufferIndexInput's (RandomAccessIndexInput interface's) methods like 
readXxx(long position) for stuff like quicksort with really hundreds of 
millions of items!

> Andrew.

Thanks,
Uwe

Reply via email to