Motivation:
Allocating memory is expensive, which is why we pool our allocations.
The cleaner, when used with pooled memory, should then return that memory to the pool instead of deallocating it.
The purpose of the cleaner is, after all, to avoid having to track the reference counts so precisely.
Modification:
The NativeMemoryCleanerDrop is now able to either recover lost memory segments, when a buffer wasn't closed explicitly
and is being cleaned by the GC, or return the buffer to the pool via ordinary drop.
The GatedCleanable has been added, because buffer ownership transfer involves generating new memory segments,
and in those cases we need to invalidate the old cleanables without deallocating the tracked memory segment or returning
it to the pool more than once.
Result:
The pooledDirectWithCleaner allocator is now able to reuse memory segments, even when their references are forgotten and
they processed by the cleaner thread.
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
Motivation:
We wish to make as little use of Unsafe as possible, yet have a flexible buffer API.
With the proposed support for shared segments, we're able to clean up our buffer API and simplify the implementation.
Modification:
With shared segments, we are able to implement TransferSend using supported APIs.
This allows us to remove RendezvousSend, and also our hacks in Statics.
TransferSend now works by first creating a shared segment and using that for the handover.
On the receiving end, if the segment was originally thread-confined, it will once again become
confined, but this time to the receiver thread.
Shared segments are just passed directly to their new owners.
Pooled allocators always create shared memory segments for their buffers, so they can be
shared easily via the pool.
Result:
We now have buffer ownership transfer with nice, convenient, APIs, and we have buffer pooling,
all using supported APIs.
The `Buf` type no longer needs any other qualifying type annotations to specify.
It is itself a non-parameterised type now, which makes it a lot simpler for people to use.
It's wealth of accessor methods have also been expanded, and tests have been added.
There is, however, still a fair number of methods to add before it resembles a `ByteBuf` replacement.
The intent is that this will hide the BBuf implementation in the long run.
For the time being, it highlights an issue with the Rc family of types and their generics, and specifically how they are complicated to compose with other interfaces.
Motivation:
We don't intend on support buffers bigger than 2 GiB, which is the max IO transfer size
on Linux.
Modification:
Change buffer read/write indexes to be ints, and add checks to allocators.
Result:
BBuf is now int-sized and indexed.
Motivation:
Keeping track of refcounts is hard for client code.
It is much easier to rely on the GC for cleanup.
Modification:
Add a new pool, native allocator implementation, that uses the Cleaner API to prevent leaks.
Native memory accounting, which is not built into the JDK for MemorySegments, has also been added to the allocators so the Cleaner based implementation can be tested.
Result:
We have a leak resistant allocator for BBuf.
Motivation: The MemoryAccess API now takes MemorySegment instead of MemoryAddress.
Modification: Remove the MemoryAddress field and use MemorySegment everywhere.
Result: The code now compiles again.
Motivation:
We want to be able to compare the performance of the existing ByteBuf implementation, and the new MemorySegment based BBuf.
Modification:
Copy the existing access benchmark for ByteBuf, and modify the copy to use the new BBuf instead.
Result:
We are able to get our first benchmark runs with BBuf.
The cost of accessing memory in BBuf is roughly twice that of the comparable ByteBuf implementations.
I think we'll need to improve this if we want BBuf to be a viable path forward.
Motivation:
Make it easier to use the existing ByteBuf and the new BBuf in the same source files.
To help transitioning between, and comparing, the two APIs.
Modification:
The new ...b2.ByteBuf class has been renamed to BBuf to avoid clashing with the existing ByteBuf name.
Result:
It's easier to make use of both classes in the same source files, since both can be imported independently.
Motivation:
Future versions of Java will introduce a new API for working with off-heap and on-heap memory alike.
This API _could_ potentially relieve us of many of our use cases for Unsafe.
We wish to explore how suitable these APIs are for this task.
Modification:
Add an entirely separate version of the Netty ByteBuf API, implemented in terms of MemorySegment.
No existing code is changed at this time.
The current prototype is only to prove the concept, and does not aim to be a full replacement.
Result:
We are able to build a fairly nice API, but with caveats.
Restrictions in the current (JDK 16 EA) MemorySegment API, around how ownership is transferred between threads, means we are currently still relying on Unsafe.
While our use of Unsafe could be reduced, it can not be eliminated in our ByteBuf API, because we are relying on it to work around the current ownership restrictions.
I believe it is _possible_ to create a safe ownership transfer API at the JDK level, so hopefully this restriction can be lifted in the future.