-
Notifications
You must be signed in to change notification settings - Fork 902
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
Improve DefaultEntryLogger read performance. #4038
Changes from 6 commits
c2bd20b
071c9fd
d27256f
f6f7b36
95d40a9
9d25baf
47ed592
114294c
f8a68ef
2b22752
5ad1133
f389666
1796a4d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -30,7 +30,7 @@ | |||||||||
/** | ||||||||||
* A Buffered channel without a write buffer. Only reads are buffered. | ||||||||||
*/ | ||||||||||
public class BufferedReadChannel extends BufferedChannelBase { | ||||||||||
public class BufferedReadChannel extends BufferedChannelBase { | ||||||||||
|
||||||||||
// The capacity of the read buffer. | ||||||||||
protected final int readCapacity; | ||||||||||
|
@@ -43,9 +43,12 @@ public class BufferedReadChannel extends BufferedChannelBase { | |||||||||
|
||||||||||
long invocationCount = 0; | ||||||||||
long cacheHitCount = 0; | ||||||||||
private long fileSize = -1; | ||||||||||
private final boolean sealed; | ||||||||||
|
||||||||||
public BufferedReadChannel(FileChannel fileChannel, int readCapacity) { | ||||||||||
public BufferedReadChannel(FileChannel fileChannel, int readCapacity, boolean sealed) { | ||||||||||
super(fileChannel); | ||||||||||
this.sealed = sealed; | ||||||||||
this.readCapacity = readCapacity; | ||||||||||
this.readBuffer = Unpooled.buffer(readCapacity); | ||||||||||
} | ||||||||||
|
@@ -64,10 +67,22 @@ public int read(ByteBuf dest, long pos) throws IOException { | |||||||||
return read(dest, pos, dest.writableBytes()); | ||||||||||
} | ||||||||||
|
||||||||||
@Override | ||||||||||
public long size() throws IOException { | ||||||||||
if (sealed) { | ||||||||||
if (fileSize == -1) { | ||||||||||
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. nit: if the file is already "sealed", should we read the size in the constructor? This way we wouldn't have any concurrency issues here if 2 threads call 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. The |
||||||||||
fileSize = validateAndGetFileChannel().size(); | ||||||||||
} | ||||||||||
return fileSize; | ||||||||||
} else { | ||||||||||
return validateAndGetFileChannel().size(); | ||||||||||
} | ||||||||||
} | ||||||||||
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. Would there be a benefit to override this logic in 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. The FileChnanel doesn't have 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. @hangc0276 I was referring to bookkeeper/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/BufferedChannel.java Lines 49 to 52 in 2209734
Is the challenge in that case that the same file could have a BufferedReadChannel instance and a BufferedChannel instance at the same time? 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. I'm not got you fully, the BufferedChannel means the corresponding file is writing, it override the
#4038 (comment) |
||||||||||
|
||||||||||
public synchronized int read(ByteBuf dest, long pos, int length) throws IOException { | ||||||||||
invocationCount++; | ||||||||||
long currentPosition = pos; | ||||||||||
long eof = validateAndGetFileChannel().size(); | ||||||||||
long eof = size(); | ||||||||||
// return -1 if the given position is greater than or equal to the file's current size. | ||||||||||
if (pos >= eof) { | ||||||||||
return -1; | ||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -63,6 +63,8 @@ class EntryLoggerAllocator { | |
private final boolean entryLogPreAllocationEnabled; | ||
private final ByteBufAllocator byteBufAllocator; | ||
final ByteBuf logfileHeader = Unpooled.buffer(DefaultEntryLogger.LOGFILE_HEADER_SIZE); | ||
private long writingLogId = -1; | ||
private long writingCompactingLogId = -1; | ||
|
||
EntryLoggerAllocator(ServerConfiguration conf, LedgerDirsManager ledgerDirsManager, | ||
DefaultEntryLogger.RecentEntryLogsStatus recentlyCreatedEntryLogsStatus, long logId, | ||
|
@@ -90,21 +92,28 @@ synchronized long getPreallocatedLogId() { | |
return preallocatedLogId; | ||
} | ||
|
||
public boolean isSealed(long logId) { | ||
return logId != writingLogId && logId != writingCompactingLogId; | ||
} | ||
Comment on lines
+95
to
+97
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. Isn't this misleading if it is called "isSealed"? 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.
|
||
|
||
BufferedLogChannel createNewLog(File dirForNextEntryLog) throws IOException { | ||
synchronized (createEntryLogLock) { | ||
BufferedLogChannel bc; | ||
if (!entryLogPreAllocationEnabled){ | ||
if (!entryLogPreAllocationEnabled) { | ||
// create a new log directly | ||
bc = allocateNewLog(dirForNextEntryLog); | ||
writingLogId = bc.getLogId(); | ||
return bc; | ||
} else { | ||
// allocate directly to response request | ||
if (null == preallocation){ | ||
if (null == preallocation) { | ||
bc = allocateNewLog(dirForNextEntryLog); | ||
writingLogId = bc.getLogId(); | ||
} else { | ||
// has a preallocated entry log | ||
try { | ||
bc = preallocation.get(); | ||
writingLogId = bc.getLogId(); | ||
} catch (ExecutionException ee) { | ||
if (ee.getCause() instanceof IOException) { | ||
throw (IOException) (ee.getCause()); | ||
|
@@ -115,7 +124,7 @@ BufferedLogChannel createNewLog(File dirForNextEntryLog) throws IOException { | |
throw new IOException("Task to allocate a new entry log is cancelled.", ce); | ||
} catch (InterruptedException ie) { | ||
Thread.currentThread().interrupt(); | ||
throw new IOException("Intrrupted when waiting a new entry log to be allocated.", ie); | ||
throw new IOException("Interrupted when waiting a new entry log to be allocated.", ie); | ||
} | ||
} | ||
// preallocate a new log in background upon every call | ||
|
@@ -127,10 +136,16 @@ BufferedLogChannel createNewLog(File dirForNextEntryLog) throws IOException { | |
|
||
BufferedLogChannel createNewLogForCompaction(File dirForNextEntryLog) throws IOException { | ||
synchronized (createCompactionLogLock) { | ||
return allocateNewLog(dirForNextEntryLog, COMPACTING_SUFFIX); | ||
BufferedLogChannel bc = allocateNewLog(dirForNextEntryLog, COMPACTING_SUFFIX); | ||
writingCompactingLogId = bc.getLogId(); | ||
return bc; | ||
} | ||
} | ||
|
||
void clearCompactingLogId() { | ||
writingCompactingLogId = -1; | ||
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. Do we need to guard this by 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. No need this, the 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.
What do you mean? 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. Just wondering if there's a chance that writingLogId and writingCompactingLogId field changes wouldn't be visible for another thread that reads these fields. 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.
The method 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.
Make sense, make it volatile. |
||
} | ||
|
||
private synchronized BufferedLogChannel allocateNewLog(File dirForNextEntryLog) throws IOException { | ||
return allocateNewLog(dirForNextEntryLog, ".log"); | ||
} | ||
|
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.
Do we need to keep the original constructor method and create a new one with
sealed
flag? Because theBufferedReadChannel
class is public and the constructor is also public, other applications may use this channel to create instances. If we change the constructor directly, it will break the compatibility with the old versions.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.
Make sense.