-
Notifications
You must be signed in to change notification settings - Fork 41.6k
RandomAccessDataFile depletes its FilePool if seek fails #9370
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
Conversation
|
Thanks for the PR. Can you please provide so more information about the change that you're proposing and why you believe it to be necessary. A test that reproduces the apparent deadlock would be most welcome. |
|
I tried to write a demo, but failed. I will try my best to explain this case. I found this problem from a running java process. According to the thread stack dump, a thread is blocked at // org.springframework.boot.loader.data.RandomAccessDataFile.FilePool.close()
public void close() throws IOException {
this.available.acquireUninterruptibly(this.size);In private class FilePool {
private final Semaphore available;But in the heap dump, in the blocked thread, the state of
public class Semaphore implements java.io.Serializable {
private static final long serialVersionUID = -3222578661600680210L;
/** All mechanics via AbstractQueuedSynchronizer subclass */
private final Sync sync;
/**
* Synchronization implementation for semaphore. Uses AQS state
* to represent permits. Subclassed into fair and nonfair
* versions.
*/
abstract static class Sync extends AbstractQueuedSynchronizer {public abstract class AbstractQueuedSynchronizer
extends AbstractOwnableSynchronizer
implements java.io.Serializable {
/**
* The synchronization state.
*/
private volatile int state;Which needs a Semaphore permit do not be released. but there are no other threads blocked at
According to RandomAccessFile file = this.file;
if (file == null) {
file = RandomAccessDataFile.this.filePool.acquire();
file.seek(RandomAccessDataFile.this.offset + this.position);
}
try {
if (b == null) {
int rtn = file.read();
moveOn(rtn == -1 ? 0 : 1);
return rtn;
}
else {
return (int) moveOn(file.read(b, off, cappedLen));
}
}
finally {
if (this.file == null) {
RandomAccessDataFile.this.filePool.release(file);
}
}If
|
|
I wonder if we can just push the public int doRead(byte[] b, int off, int len) throws IOException {
if (len == 0) {
return 0;
}
int cappedLen = cap(len);
if (cappedLen <= 0) {
return -1;
}
RandomAccessFile file = this.file;
try {
if (this.file == null) {
file = RandomAccessDataFile.this.filePool.acquire();
file.seek(RandomAccessDataFile.this.offset + this.position);
}
if (b == null) {
int rtn = file.read();
moveOn(rtn == -1 ? 0 : 1);
return rtn;
}
else {
return (int) moveOn(file.read(b, off, cappedLen));
}
}
finally {
if (this.file == null && file != null) {
RandomAccessDataFile.this.filePool.release(file);
}
}
} |
|
@hengyunabc Thanks again for the PR and for the analysis of the problem. As suggested by @philwebb above, we decided to fix it in a slightly different way. Please see e11b7af for details. |
|
Surround with try/finally will be better? // org.springframework.boot.loader.data.RandomAccessDataFile.FilePool.release(RandomAccessFile)
public void release(RandomAccessFile file) {
try {
this.files.add(file);
} finally {
this.available.release();
}
} |
No description provided.