-
Notifications
You must be signed in to change notification settings - Fork 3.7k
[improve][tiered storage] Reduce cpu usage when offloading the ledger #15063
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
Merged
Merged
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
d869a96
[imporve][tiered storage] Reduce cpu usage when offloading the ledger
zymap 9cd00c4
Fix the failure ci
zymap e5cf090
Address comment
zymap 3d33df8
Address comments
zymap c509c46
remove unused changes
zymap cd263ff
Using ByteBuf to avoid new bytes every time
zymap 8e5d6c8
Merge remote-tracking branch 'apache/master' into fix-offload-cpu-issue
zymap 187f2ec
Release buf when the stream close
zymap 8396ada
Fix the ut failure
zymap bb8a3da
Fix the checkstyle
zymap bc90b45
Fix the tests
zymap 0f03052
Merge remote-tracking branch 'apache/master' into fix-offload-cpu-issue
zymap fcb7fd4
Address comment
zymap 485fad4
fix the style issue
zymap 3d48050
Merge remote-tracking branch 'apache/master' into fix-offload-cpu-issue
zymap b0b24b4
Address comments
zymap f7fc0d0
Merge remote-tracking branch 'apache/master' into fix-offload-cpu-issue
zymap b3cbc6d
Merge remote-tracking branch 'apache/master' into fix-offload-cpu-issue
zymap f18b8dd
Merge remote-tracking branch 'apache/master' into fix-offload-cpu-issue
zymap 2c39652
Merge remote-tracking branch 'apache/master' into fix-offload-cpu-issue
zymap File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 |
|---|---|---|
|
|
@@ -20,6 +20,7 @@ | |
|
|
||
| import static com.google.common.base.Preconditions.checkState; | ||
| import com.google.common.collect.Lists; | ||
| import com.google.common.primitives.Ints; | ||
| import io.netty.buffer.ByteBuf; | ||
| import io.netty.buffer.CompositeByteBuf; | ||
| import java.io.IOException; | ||
|
|
@@ -28,6 +29,7 @@ | |
| import java.util.List; | ||
| import java.util.concurrent.ExecutionException; | ||
| import java.util.concurrent.TimeUnit; | ||
| import java.util.concurrent.atomic.AtomicBoolean; | ||
| import org.apache.bookkeeper.client.api.LedgerEntries; | ||
| import org.apache.bookkeeper.client.api.LedgerEntry; | ||
| import org.apache.bookkeeper.client.api.ReadHandle; | ||
|
|
@@ -46,6 +48,9 @@ public class BlockAwareSegmentInputStreamImpl extends BlockAwareSegmentInputStre | |
| private static final Logger log = LoggerFactory.getLogger(BlockAwareSegmentInputStreamImpl.class); | ||
|
|
||
| static final int[] BLOCK_END_PADDING = new int[]{ 0xFE, 0xDC, 0xDE, 0xAD }; | ||
| static final byte[] BLOCK_END_PADDING_BYTES = Ints.toByteArray(0xFEDCDEAD); | ||
|
|
||
| private final ByteBuf paddingBuf = PulsarByteBufAllocator.DEFAULT.buffer(128, 128); | ||
|
|
||
| private final ReadHandle ledger; | ||
| private final long startEntryId; | ||
|
|
@@ -69,6 +74,8 @@ public class BlockAwareSegmentInputStreamImpl extends BlockAwareSegmentInputStre | |
| private List<ByteBuf> entriesByteBuf = null; | ||
| private LedgerOffloaderStats offloaderStats; | ||
| private String topicName; | ||
| private int currentOffset = 0; | ||
| private final AtomicBoolean close = new AtomicBoolean(false); | ||
|
|
||
| public BlockAwareSegmentInputStreamImpl(ReadHandle ledger, long startEntryId, int blockSize) { | ||
| this.ledger = ledger; | ||
|
|
@@ -87,6 +94,52 @@ public BlockAwareSegmentInputStreamImpl(ReadHandle ledger, long startEntryId, in | |
| this.topicName = ledgerName; | ||
| } | ||
|
|
||
| private ByteBuf readEntries(int len) throws IOException { | ||
| checkState(bytesReadOffset >= DataBlockHeaderImpl.getDataStartOffset()); | ||
| checkState(bytesReadOffset < blockSize); | ||
|
|
||
| // once reach the end of entry buffer, read more, if there is more | ||
| if (bytesReadOffset < dataBlockFullOffset | ||
| && entriesByteBuf.isEmpty() | ||
| && startEntryId + blockEntryCount <= ledger.getLastAddConfirmed()) { | ||
| entriesByteBuf = readNextEntriesFromLedger(startEntryId + blockEntryCount, ENTRIES_PER_READ); | ||
| } | ||
|
|
||
| if (!entriesByteBuf.isEmpty() | ||
|
zymap marked this conversation as resolved.
|
||
| && bytesReadOffset + entriesByteBuf.get(0).readableBytes() <= blockSize) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Needn't check every time, maybe it just need check then entriesByteBuf's 0 element changes. |
||
| // always read from the first ByteBuf in the list, once read all of its content remove it. | ||
| ByteBuf entryByteBuf = entriesByteBuf.get(0); | ||
| int readableBytes = entryByteBuf.readableBytes(); | ||
| int read = Math.min(readableBytes, len); | ||
| ByteBuf buf = entryByteBuf.slice(currentOffset, read); | ||
| buf.retain(); | ||
| currentOffset += read; | ||
| entryByteBuf.readerIndex(currentOffset); | ||
| bytesReadOffset += read; | ||
|
|
||
| if (entryByteBuf.readableBytes() == 0) { | ||
| entryByteBuf.release(); | ||
| entriesByteBuf.remove(0); | ||
| blockEntryCount++; | ||
| currentOffset = 0; | ||
| } | ||
|
|
||
| return buf; | ||
| } else { | ||
| // no space for a new entry or there are no more entries | ||
| // set data block full, return end padding | ||
| if (dataBlockFullOffset == blockSize) { | ||
|
zymap marked this conversation as resolved.
|
||
| dataBlockFullOffset = bytesReadOffset; | ||
| } | ||
| paddingBuf.clear(); | ||
| for (int i = 0; i < Math.min(len, paddingBuf.capacity()); i++) { | ||
| paddingBuf.writeByte(BLOCK_END_PADDING_BYTES[(bytesReadOffset++ - dataBlockFullOffset) | ||
| % BLOCK_END_PADDING_BYTES.length]); | ||
| } | ||
| return paddingBuf.retain(); | ||
| } | ||
| } | ||
|
|
||
| // read ledger entries. | ||
| private int readEntries() throws IOException { | ||
| checkState(bytesReadOffset >= DataBlockHeaderImpl.getDataStartOffset()); | ||
|
|
@@ -161,6 +214,46 @@ private List<ByteBuf> readNextEntriesFromLedger(long start, long maxNumberEntrie | |
| } | ||
| } | ||
|
|
||
| @Override | ||
| public int read(byte[] b, int off, int len) throws IOException { | ||
|
zymap marked this conversation as resolved.
|
||
| if (b == null) { | ||
| throw new NullPointerException("The given bytes are null"); | ||
| } else if (off < 0 || len < 0 || len > b.length - off) { | ||
| throw new IndexOutOfBoundsException("off=" + off + ", len=" + len + ", b.length=" + b.length); | ||
| } else if (len == 0) { | ||
| return 0; | ||
| } | ||
|
|
||
| int offset = off; | ||
| int readLen = len; | ||
| int readBytes = 0; | ||
| // reading header | ||
| if (dataBlockHeaderStream.available() > 0) { | ||
| int read = dataBlockHeaderStream.read(b, off, len); | ||
| offset += read; | ||
| readLen -= read; | ||
| readBytes += read; | ||
| bytesReadOffset += read; | ||
|
zymap marked this conversation as resolved.
|
||
| } | ||
| if (readLen == 0) { | ||
| return readBytes; | ||
| } | ||
|
|
||
| // reading ledger entries | ||
| if (bytesReadOffset < blockSize) { | ||
|
zymap marked this conversation as resolved.
|
||
| readLen = Math.min(readLen, blockSize - bytesReadOffset); | ||
| ByteBuf readEntries = readEntries(readLen); | ||
| int read = readEntries.readableBytes(); | ||
| readEntries.readBytes(b, offset, read); | ||
| readEntries.release(); | ||
| readBytes += read; | ||
| return readBytes; | ||
| } | ||
|
|
||
| // reached end | ||
| return -1; | ||
|
zymap marked this conversation as resolved.
|
||
| } | ||
|
|
||
| @Override | ||
| public int read() throws IOException { | ||
| // reading header | ||
|
|
@@ -180,11 +273,20 @@ public int read() throws IOException { | |
|
|
||
| @Override | ||
| public void close() throws IOException { | ||
| super.close(); | ||
| dataBlockHeaderStream.close(); | ||
| if (!entriesByteBuf.isEmpty()) { | ||
| entriesByteBuf.forEach(buf -> buf.release()); | ||
| entriesByteBuf.clear(); | ||
| // The close method will be triggered twice in the BlobStoreManagedLedgerOffloader#offload method. | ||
| // The stream resource used by the try-with block which will called the close | ||
| // And through debug, writeBlobStore.uploadMultipartPart in the offload method also will trigger | ||
| // the close method. | ||
| // So we add the close variable to avoid release paddingBuf twice. | ||
| if (!close.compareAndSet(false, true)) { | ||
| super.close(); | ||
| dataBlockHeaderStream.close(); | ||
| if (!entriesByteBuf.isEmpty()) { | ||
| entriesByteBuf.forEach(buf -> buf.release()); | ||
| entriesByteBuf.clear(); | ||
| } | ||
| paddingBuf.clear(); | ||
| paddingBuf.release(); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -203,6 +305,10 @@ public int getBlockSize() { | |
| return blockSize; | ||
| } | ||
|
|
||
| public int getDataBlockFullOffset() { | ||
| return dataBlockFullOffset; | ||
| } | ||
|
|
||
| @Override | ||
| public int getBlockEntryCount() { | ||
| return blockEntryCount; | ||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.