Commit Graph

262 Commits

Author SHA1 Message Date
Chris Vest
92c178ceb9 The BufTest.pooledBuffersMustResetStateBeforeReuse should run for all allocators 2020-11-23 18:10:58 +01:00
Chris Vest
eb7717b00a Move benchmarks to their own directory 2020-11-23 18:10:27 +01:00
Chris Vest
6e23ba139d
Merge pull request #2 from netty/cache-key
Include year and week number in build cache key
2020-11-23 12:00:43 +01:00
Chris Vest
5037d546e1 Include year and week number in build cache key
Also schedule a build to run at 06:30 in the morning, every Monday.
This way, the JDK and Netty 5 snapshots will be updated in the build cache every week.
2020-11-23 10:56:11 +01:00
Chris Vest
854a2a95dd Remove cruft from CI build workflow file 2020-11-21 21:40:57 +01:00
Chris Vest
c91478341b
Merge pull request #1 from netty/gh-workflow
Add a GitHub workflow for building PRs
2020-11-21 21:35:29 +01:00
Chris Vest
b171449de9 Try yet another different caching mechanism 2020-11-21 17:00:30 +01:00
Chris Vest
87d23f52db Try a different caching mechanism 2020-11-21 15:26:10 +01:00
Chris Vest
1f9ab72a44 Add more examples 2020-11-20 22:22:01 +01:00
Chris Vest
f3e494bce3 Add first example on how to use the new buffer API 2020-11-20 16:07:52 +01:00
Chris Vest
308b4df3b6 Try fixing multi-line workflow commands 2020-11-20 16:07:52 +01:00
Chris Vest
72eb5d3bcb Try adding a build cache that uses githubs package repo as a cache
Inspired by https://dev.to/dtinth/caching-docker-builds-in-github-actions-which-approach-is-the-fastest-a-research-18ei
2020-11-20 14:38:38 +01:00
Chris Vest
023bb64a25 Update MemSegBuf with the latest panama-foreign API changes 2020-11-20 14:01:14 +01:00
Chris Vest
1706df49b8
Add a GitHub workflow for building PRs 2020-11-20 12:52:31 +01:00
Chris Vest
a4ecc1b184 Add toString methods to the buffer implementations 2020-11-20 12:44:09 +01:00
Chris Vest
53d2e4b955 Pooled buffers must reset their state before reuse
Motivation:
Buffers should always behave the same, regardless of their underlying implementation and how they are allocated.

Modification:
The SizeClassedMemoryPool did not properly reset the internal buffer state prior to reusing them.
The offsets, byte order, and contents are now cleared before a buffer is reused.

Result:
There is no way to observe externally whether a buffer was reused or not.
2020-11-20 11:53:26 +01:00
Chris Vest
b0acb61f03 Explain the make build in the README.md file 2020-11-18 17:32:42 +01:00
Chris Vest
59b564ddc8 Add a docker-based build
Motivation:
Because of the current dependency on snapshot versions of the Panama Foreign version of OpenJDK 16, this project is fairly involved to build.

Modification:
To make it easier for newcomers to build the binaries for this project, a docker-based build is added.
The docker image is constructed such that it contains a fresh snapshot build of the right fork of Java.
A make file has also been added, which encapsulates the common commands one would use for working with the docker build.

Result:
It is now easy for newcomers to make builds, and run tests, of this project, as long as they have a working docker installation.
2020-11-18 17:16:37 +01:00
Chris Vest
a1785e8161 Move the MemorySegment based Buf implementation to its own package, and break the remaining bits of tight coupling. 2020-11-17 15:53:40 +01:00
Chris Vest
3efa93841e Rename the 'b2' package to 'api' 2020-11-17 15:40:13 +01:00
Chris Vest
0ad7f648ae Get the benchmarks running again 2020-11-17 15:34:46 +01:00
Chris Vest
b3aff17f5a Fix checkstyle so the build passes 2020-11-17 15:26:58 +01:00
Chris Vest
84e992c2c9 Move all files into the incubator repo 2020-11-17 15:26:58 +01:00
Chris Vest
07dd86dc56 Move ByteIterator to collect everything in one package 2020-11-17 15:26:58 +01:00
Chris Vest
11b0d69757 Simplify CompositeBuf.ensureWritable 2020-11-17 15:26:58 +01:00
Chris Vest
a535fb8cd8 Fix a bug in Buf.ensureWritable for pooled buffers
Motivation:
Resource lifetime was not correctly handled.

Modification:
We cannot call drop(buf) on a pooled buffer in order to release its memory from within ensureWritable, because that will send() the buffer back to the pool, which implies closing the buffer instance.
Instead, ensureWritable has to always work with untethered memory, so new APIs are added to AllocatorControl for releasing untethered memory.
The implementation already existed, because it was used by NativeMemoryCleanerDrop.

Result:
Buf.ensureWritable no longer closes pooled buffers.
2020-11-17 15:26:58 +01:00
Chris Vest
9c54aa43b4 Add Buf.ensureWritable
Motivation:
Having buffers that are able to expand to accommodate more data on demand is a great convenience.

Modification:
Composite and MemSeg buffers are now able to mutate their backing storage, to increase their capacity.
This required some tricky integration with allocators via AllocatorControl.
Basically, it's now possible to allocate memory that is NOT bound by any life time, so that it can be attached to the life time that already exists for the buffer being expanded.

Result:
Buffers can now be expanded via Buf.ensureWritable.
2020-11-17 15:26:58 +01:00
Chris Vest
ec9395d36e Run all Buf tests on slices as well.
Motivation:
Slices should behave identical to normal and composite buffers in all but a very select few aspects related to ownership.

Modification:
Extend the test generation to also produce slice-versions of nearly all test cases. Both slices that cover the entire buffer, and slices that only cover a part of their parent buffer.
Also fix a handful of bugs that this uncovered.

Result:
Buffer slices are now tested much more thoroughly, and a few bugs were fixed.
2020-11-17 15:26:57 +01:00
Chris Vest
bb5aff940f Update method names and javadocs
Motivation:
There's a desire to be able to clearly tell from a method name, whether or not it updates the reader or writer offsets.

Modification:
The accessor methods that take offsets as arguments (and thus do not update reader or writer offsets) have now been changed to follow a get/set naming pattern.
The methods that *do* update reader and writer offsets are still following a read/write naming pattern.

Result:
This makes it even more clear, whether or not the relative offsets are updated or not.
2020-11-17 15:26:57 +01:00
Chris Vest
ca32784fe8 Remove Codegen code generator for the buffer API.
Motivation:
With the number of primitive accessor methods reduced due to only having the configured byte order, it no longer makes sense to maintain the code generator.

Modification:
Delete Codegen.

Result:
Less code to maintain.
2020-11-17 15:26:57 +01:00
Chris Vest
d306998cea Migrate new buffer API tests to JUnit 5
Motivation:
This reduces the number of test classes because we can express the same with parameterized tests in JUnit 5.
This also removes the strictly tree-shaped dependencies between the tests.

Modification:
Change the new buffer API tests to use JUnit 5 and AssertJ.

Result:
A single test for all buffer implementations.
2020-11-17 15:26:57 +01:00
Chris Vest
a63f3e609d Add Buf.iterateReverse
Motivation:
We have the ability to iterate through the bytes in a buffer with the ByteIterator, but another important use case is being able to iterate through the bytes in reverse order.

Modification:
Add methods for iterating through the bytes in a buffer in reverse order. Also update the copyInto methods to make use of it. Also add a bit of missing javadocs, and argument checks.

Result:
We can also use ByteIterator for efficiently processing data within a buffer in reverse order.
2020-11-17 15:26:57 +01:00
Chris Vest
68795fb1a5 Introduce ByteIterator, and Buf.iterate
Motivation:
We need a simple API to efficiently iterate a buffer.
We've used the ByteProcessor so far, and while its internal iteration API is simple, it looses some efficiency by forcing code to only consider one byte at a time.

Modification:
The ByteIterator fills the same niche as the ByteProcessor, but uses external iteration instead of internal iteration.
This allows integrators to control the pace of iteration, and it makes it possible to expose methods for consuming bytes in bulk; one long of 8 bytes at a time.
This makes it possible to use the iterator in SIMD-Within-A-Register, or SWAR, data processing algorithms.

Result:
We have a ByteIterator for efficiently processing data within a buffer.
2020-11-17 15:26:57 +01:00
Chris Vest
91be83444d Add copyInto methods to the Buf interface
Motivation:
Copy methods are useful for bulk moving data into more convenient locations for what comes next in a given context.

Modification:
Add bulk copyInto methods for copying regions of buffer contents into arrays, byte buffers, and other Buf instances.
Some of these implementations are not optimised at this point, however, since we're primarily concerned with getting the API right at this point, and implementation maturity comes later.

Result:
We can now bulk copy data from a Buf into other convenient forms.
2020-11-17 15:26:57 +01:00
Chris Vest
fdeed0c94e Allocator takes size as an int instead of a long.
Motivation:
We don't want to support buffers larger than what can be addressed with an int.
This ensures we won't run into trouble with the max IO size on various operating systems.
2020-11-17 15:26:57 +01:00
Chris Vest
2c5be51ec6 Add an Rc.isSendable method
Motivation:
Reference counted objects may be stateful and cannot always be sent or transfer their ownership.
It's desirable that integrators can check whether or not an object can be sent.

Modification:
Add an Rc.isSendable method that returns true if the object can be sent, and false otherwise.
Implementors of the Rc interface, and extenders or RcSupport, can then implement whatever special logic they need for restricting sending in certain situations.

Result:
It's possible to test if an object supports send() or not in any given situation.
2020-11-17 15:26:57 +01:00
Chris Vest
6d4ad29149 Implement Composite buffers
Motivation:
Composite buffers make it possible to combine the data from multiple buffers and present them as one, without copying the contents. Each access primitive has slightly higher overhead, though, so it is encouraged to make measurements before decided whether to compose or copy.

Modification:
A CompositeBuf implementation has been added, along with a Buf#compose factory method.
The composite buffer behaves exactly the same as non-composed buffers.
2020-11-17 15:26:57 +01:00
Chris Vest
7f9ed7dec7 Implement Buf.slice()
Motivation:
Slicing gives you a derived buffer. This is useful for sending along just the part of a buffer that has the relevant data, or to get a new buffer instance for the same data, but with independent read and write offsets.

Modification:
Add slice() methods to the Buf interface, and implement them for MemSegBuf.
Buffer slices increments the reference count of the parent buffer, which prevents the parent from being send()-able.
Slices are themselves also not send()-able.
This is because send() involves ownership transfer, while slicing is like lending out mutable borrows.
The send() capability returns to the parent buffer once all slices are closed.
2020-11-17 15:26:57 +01:00
Chris Vest
99ad2cc120 Cleanup in BufTest to make it more extensible in the future 2020-11-17 15:26:57 +01:00
Chris Vest
b5ac0fdbe6 Remove LE/BE accessor method variants from the Buf interface
Motivation:
Having method variants for explicit endians made the API too wide.

Modification:
Remove all LE/BE accessor method variants from the Buf API and implementation.

Result:
The Buf API is now simpler.
2020-11-17 15:26:57 +01:00
Chris Vest
0aed8daad4 Hide the memory segment buffer implementation behind the MemoryManager interface
Motivation:
We'd like to separate the API and the implementation, so we can make other implementations in the future.
This will allow us to deliver the API changes without the new MemorySegment implementation.

Modification:
The MemoryManager interface abstracts away the implementation details of the concrete buffer type, and how to allocate and deallocate them.

Result:
Knowledge of MemorySegments are now confined to just the MemSegBuf and MemoryManager implementation classes.
2020-11-17 15:26:57 +01:00
Chris Vest
cfb45597f0 Rename BBufTest to BufTest
Motivation:
The BBufTest was implemented entirely in terms of the Buf interface.
There is no reason for it to reference any particular implementation.

Modification:
BBufTest and friends are renamed to just BufTest.

Result:
Tests are now named after the API surface they test.
2020-11-17 15:26:57 +01:00
Chris Vest
4147d7d51d Generate BE, LE, and configured byte order accessor methods
Motivation:
As previously stated, we wish to have configurable byte order on our buffers.

Modification:
Update the generator to produce 3 variants of accessors; for configured byte order, for BE and for LE.
Also run the generator and include the new code in the commit.

Result:
We now have configurable byte order for our buffers, and explicit accessors for both BE and LE.
2020-11-17 15:26:57 +01:00
Chris Vest
8941fab5fa Prepare for configurable byte order in Buf.
Motivation:
Different protocols will prefer to use different default byte order, so it makes sense if our buffers support a configurable byte order as well.

Modification:
Break all accessor methods into 3 variants; one that uses default (configured) byte order, and two others that use big- and little-endian, respectively.

Result:
Buffers can be allocated with any byte order desired, and this byte order can even be changed later in rare cases where that's useful.
The Buf API also has accessors that explicitly uses BE or LE byte order, for when you don't want to rely on the configured default.
2020-11-17 15:26:57 +01:00
Chris Vest
1f4e33b42a Add a BBuf allocator for direct memory, that is also managed by a Cleaner
Motivation:
 Client code sometimes struggle with managing their buffer reference counts correctly,
 so there's a use case for buffers that are deallocated by cleaners.

Modification:
 Add another allocator, directWithCleaner, which registers all the native memory segments with cleaners.

Result:
 It's possible to get unpooled direct buffers, that are automatically deallocated by a cleaner if they are no longer strongly
 referenced.
 The same is not necessary for heap buffers, since they can be garbage collected like normal objects.
2020-11-17 15:26:57 +01:00
Chris Vest
1aa439991a Make cleaner in pooledDirectWithCleaner return segments to pool instead of deallocating
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.
2020-11-17 15:26:57 +01:00
Chris Vest
0055837b75 Generate complete and tested Buf API
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.
2020-11-17 15:26:57 +01:00
Chris Vest
94e3a00fd4 Update with support for shared segments
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.
2020-11-17 15:26:57 +01:00
Chris Vest
f6e5d26ce8 Fix compilation and all checkstyle complaints 2020-11-17 15:26:57 +01:00
Chris Vest
09f9b5a158 Flesh out the Buf interface and simplify the generics
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.
2020-11-17 15:26:57 +01:00