-
Notifications
You must be signed in to change notification settings - Fork 25.5k
Add direct access to current recycler stream page #135114
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
base: main
Are you sure you want to change the base?
Add direct access to current recycler stream page #135114
Conversation
… recycler_byte_improvements
… recycler_byte_improvements
… recycler_byte_improvements
… recycler_byte_improvements
…vements_with_bench
Pinging @elastic/es-distributed-indexing (Team:Distributed Indexing) |
…vements_with_bench
…vements_with_bench
@OutputTimeUnit(TimeUnit.NANOSECONDS) | ||
@State(Scope.Thread) | ||
@Fork(value = 1) | ||
public class RecyclerBytesStreamBenchmark { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a microbenchmark to allow testing the methods I was working on.
this.currentPageOffset = pageSize; | ||
// Always start with a page | ||
ensureCapacityFromPosition(1); | ||
nextPage(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Always start with an initial page to remove the requirement that the page allocation is in one of the write methods otherwise.
if (1 > (pageSize - currentPageOffset)) { | ||
if (1 > pageSize - currentPageOffset) { | ||
ensureCapacity(1); | ||
nextPage(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change because ensureCapacity now JUST allocates sufficient pages. Does not adjust write location.
ensureCapacity(length); | ||
currentPageOffset = this.currentPageOffset; | ||
writeMultiplePages(b, offset, length); | ||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Specifically add a branch for the extremely common scenario where the bytes fit in the current page.
} | ||
|
||
@Override | ||
public void writeVInt(int i) throws IOException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
vInt is very commonly written (header for bytes reference, map item count, etc, etc). Since it is pretty expensive to write we create a specific variant that works for the recycler stream variant.
if (offsetInPage == 0) { | ||
this.pageIndex = pageIndex - 1; | ||
this.currentPageOffset = pageSize; | ||
if (position > 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is the same except we need special handling for position 0 since the stream always has at least one page.
out.writeByte(b); | ||
assertEquals(b, out.bytes().get(PageCacheRecycler.BYTE_PAGE_SIZE)); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More test coverage.
This change makes a number of minor optimizations to the recycler bytes
stream. The most important change is that it allow cached direct access
to the current page. This helps in most scenarios where are write does
not cross page boundaries.
Additionally, it enables future subclasses to implement custom
serialization directly to the page with minimal bounds checks.
Finally, it always creates the first page in the ctor to remove guaranteed
expand calls in the first stream write.