-
Notifications
You must be signed in to change notification settings - Fork 181
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add
Publisher.fromInputStream(InputStream, ByteArrayMapper)
(#2989)
Motivation: Existing `Publisher.fromInputStream(InputStream)` contract has a side effect of an extra allocation in case the pre-allocated byte-array was not completely full of data. Modifications: - Add `Publisher.fromInputStream(InputStream, ByteArrayMapper)` that allows users to decide how to use the buffer region with data; - Deprecate pre-existing `Publisher.fromInputStream(InputStream)` and `Publisher.fromInputStream(InputStream, int)` overloads; - Update all existing use-cases to use `BufferAllocator.wrap` as a method reference as a `ByteArrayMapper`; Result: No impact on throughput and latency for `BlockingStreamingHttpClient` requests with `InputStream` payload (8Kb, 16Kb, 24Kb), but significant reduction in memory allocations and number of GC runs per benchmark: Allocations: ~2Gb/s -> ~1.4Gb/s Young Collection GC Count: 29 -> 23 Alloc Outside TLABs: 7.33 GiB -> 5.04 GiB
- Loading branch information
1 parent
63089ee
commit 434da83
Showing
10 changed files
with
191 additions
and
61 deletions.
There are no files selected for viewing
79 changes: 79 additions & 0 deletions
79
servicetalk-concurrent-api/src/main/java/io/servicetalk/concurrent/api/ByteArrayMapper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
/* | ||
* Copyright © 2024 Apple Inc. and the ServiceTalk project authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package io.servicetalk.concurrent.api; | ||
|
||
import io.servicetalk.concurrent.api.FromInputStreamPublisher.ToByteArrayMapper; | ||
|
||
import static io.servicetalk.concurrent.api.FromInputStreamPublisher.DEFAULT_MAX_BUFFER_SIZE; | ||
import static io.servicetalk.concurrent.api.FromInputStreamPublisher.ToByteArrayMapper.DEFAULT_TO_BYTE_ARRAY_MAPPER; | ||
|
||
/** | ||
* A mapper to transform {@code byte[]} buffer regions into a desired type {@code T}. | ||
* | ||
* @param <T> Type of the result of this mapper | ||
*/ | ||
@FunctionalInterface | ||
public interface ByteArrayMapper<T> { | ||
|
||
/** | ||
* Maps a specified {@code byte[]} buffer region into a {@code T}. | ||
* <p> | ||
* The mapper can operate only within the specified region of the {@code buffer}, which can be safely used without a | ||
* need to copy data. Access to other parts of the buffer may lead to unexpected results and due care should be | ||
* taken to avoid leaking that data through the returned type {@code T}. | ||
* | ||
* @param buffer {@code byte[]} buffer with data | ||
* @param offset the offset of the region | ||
* @param length the length of the region | ||
* @return result of type {@code T} | ||
*/ | ||
T map(byte[] buffer, int offset, int length); | ||
|
||
/** | ||
* Returns the maximum allowed buffer size for the {@link #map(byte[], int, int)} operation. | ||
* <p> | ||
* Must be a positive number. | ||
* | ||
* @return the maximum allowed buffer size for the {@link #map(byte[], int, int)} operation | ||
*/ | ||
default int maxBufferSize() { | ||
return DEFAULT_MAX_BUFFER_SIZE; | ||
} | ||
|
||
/** | ||
* Mapper from the buffer region to an independent {@code byte[]} buffer. | ||
* <p> | ||
* Returns {@link #toByteArray(int)} with default {@link #maxBufferSize()}. | ||
* | ||
* @return a mapper from the buffer region to an independent {@code byte[]} buffer | ||
*/ | ||
static ByteArrayMapper<byte[]> toByteArray() { | ||
return DEFAULT_TO_BYTE_ARRAY_MAPPER; | ||
} | ||
|
||
/** | ||
* Mapper from the buffer region to an independent {@code byte[]} buffer. | ||
* <p> | ||
* Returns the original {@code byte[]} buffer as-is if it was completely full of data or allocates a new buffer for | ||
* the specified length and copies data. Returned {@code byte[]} buffer is always completely full. | ||
* | ||
* @param maxBufferSize the value for {@link #maxBufferSize()} | ||
* @return a mapper from the buffer region to an independent {@code byte[]} buffer | ||
*/ | ||
static ByteArrayMapper<byte[]> toByteArray(final int maxBufferSize) { | ||
return new ToByteArrayMapper(maxBufferSize); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.