-
Notifications
You must be signed in to change notification settings - Fork 151
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implements interrupt-safe transaction log
When an interrupt happened on a thread during writing the transaction log, the underlying FileChannel was closed as a result. Any further use (even from another threads) threw a java.nio.channels.ClosedChannelException rendering the transaction manager unusable since the transaction logs were never reopened. This commit changes this behavior, log file operations reopen the file if it was closed by an interrupt of another thread. fixes #45 Commit by Tibor Billes, Miklós Karakó, Balázs Póka
- Loading branch information
1 parent
1072c30
commit d13dc20
Showing
11 changed files
with
873 additions
and
41 deletions.
There are no files selected for viewing
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
104 changes: 104 additions & 0 deletions
104
btm/src/main/java/bitronix/tm/journal/InterruptibleLockedRandomAccessFile.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,104 @@ | ||
package bitronix.tm.journal; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
import java.io.RandomAccessFile; | ||
import java.nio.ByteBuffer; | ||
import java.nio.channels.FileChannel; | ||
import java.nio.channels.FileLock; | ||
|
||
public class InterruptibleLockedRandomAccessFile { | ||
|
||
private final File file; | ||
private final String mode; | ||
private RandomAccessFile openedFile; | ||
private FileChannel fileChannel; | ||
private FileLock fileLock; | ||
private long currentPosition = 0; | ||
private boolean closed; | ||
|
||
public InterruptibleLockedRandomAccessFile(final File file, final String mode) | ||
throws IOException { | ||
this.file = file; | ||
this.mode = mode; | ||
open(); | ||
} | ||
|
||
private synchronized void open() throws IOException { | ||
openedFile = new RandomAccessFile(file, mode); | ||
fileChannel = openedFile.getChannel(); | ||
|
||
final boolean shared = false; | ||
this.fileLock = fileChannel | ||
.tryLock(0, TransactionLogHeader.TIMESTAMP_HEADER, shared); | ||
if (this.fileLock == null) { | ||
throw new IOException("File " + file.getAbsolutePath() | ||
+ " is locked. Is another instance already running?"); | ||
} | ||
} | ||
|
||
public synchronized final void close() throws IOException { | ||
try { | ||
if (!fileLock.isValid()) { | ||
checkState(!fileChannel.isOpen(), "invalid/unhandled state"); | ||
return; | ||
} | ||
fileLock.release(); | ||
fileChannel.close(); | ||
openedFile.close(); | ||
} finally { | ||
closed = true; | ||
} | ||
} | ||
|
||
public synchronized void position(final long newPosition) throws IOException { | ||
checkNotClosed(); | ||
reopenFileChannelIfClosed(); | ||
|
||
fileChannel.position(newPosition); | ||
currentPosition = newPosition; | ||
} | ||
|
||
private void checkNotClosed() { | ||
checkState(!closed, "File has been closed"); | ||
} | ||
|
||
private static void checkState(final boolean expression, final String errorMessage) { | ||
if (!expression) { | ||
throw new IllegalStateException(errorMessage); | ||
} | ||
} | ||
|
||
public synchronized void force(final boolean metaData) throws IOException { | ||
checkNotClosed(); | ||
reopenFileChannelIfClosed(); | ||
|
||
fileChannel.force(metaData); | ||
} | ||
|
||
public synchronized int write(final ByteBuffer src, final long position) | ||
throws IOException { | ||
checkNotClosed(); | ||
reopenFileChannelIfClosed(); | ||
|
||
return fileChannel.write(src, position); | ||
} | ||
|
||
public synchronized void read(final ByteBuffer buffer) throws IOException { | ||
checkNotClosed(); | ||
reopenFileChannelIfClosed(); | ||
|
||
fileChannel.read(buffer); | ||
currentPosition = fileChannel.position(); | ||
} | ||
|
||
private void reopenFileChannelIfClosed() throws IOException { | ||
if (!fileChannel.isOpen()) { | ||
open(); | ||
} | ||
|
||
if (fileChannel.position() != currentPosition) { | ||
fileChannel.position(currentPosition); | ||
} | ||
} | ||
} |
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
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,18 @@ | ||
package bitronix.tm.journal; | ||
|
||
import java.io.UnsupportedEncodingException; | ||
import java.nio.ByteBuffer; | ||
|
||
public final class ByteBufferUtil { | ||
|
||
private ByteBufferUtil() { | ||
} | ||
|
||
public static ByteBuffer createByteBuffer(final String input) | ||
throws UnsupportedEncodingException { | ||
final byte[] inputArray = input.getBytes("UTF-8"); | ||
final ByteBuffer byteBuffer = ByteBuffer.wrap(inputArray); | ||
return byteBuffer; | ||
} | ||
|
||
} |
Oops, something went wrong.