-
Notifications
You must be signed in to change notification settings - Fork 235
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(s3stream/wal): fail all IO operations once the WAL is failed (#1841)
fix(s3stream/wal): fail all IO operations once the WAL is failed (#1840) * refactor: remove `WALChannel#writeAndFlush` * refactor: introduce `WALChannel#retry` * refactor: introduce `AbstractWALChannel` * fix(s3stream/wal): fail all IO operations once the WAL is failed * refactor: check failed before each IO operation --------- Signed-off-by: Ning Yu <[email protected]>
- Loading branch information
1 parent
a3f3c9f
commit 34ba11e
Showing
9 changed files
with
196 additions
and
123 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
121 changes: 121 additions & 0 deletions
121
s3stream/src/main/java/com/automq/stream/s3/wal/util/AbstractWALChannel.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,121 @@ | ||
/* | ||
* Copyright 2024, AutoMQ HK Limited. | ||
* | ||
* The use of this file is governed by the Business Source License, | ||
* as detailed in the file "/LICENSE.S3Stream" included in this repository. | ||
* | ||
* As of the Change Date specified in that file, in accordance with | ||
* the Business Source License, use of this software will be governed | ||
* by the Apache License, Version 2.0 | ||
*/ | ||
|
||
package com.automq.stream.s3.wal.util; | ||
|
||
import com.automq.stream.utils.Threads; | ||
import io.netty.buffer.ByteBuf; | ||
import java.io.IOException; | ||
import java.util.concurrent.TimeUnit; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
public abstract class AbstractWALChannel implements WALChannel { | ||
|
||
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractWALChannel.class); | ||
|
||
/** | ||
* Flag to indicate if the WAL has failed. | ||
* It will be set to true if an IO operation fails continuously, and it will never be reset. | ||
* Any IO operation will fail immediately if this flag is true. | ||
*/ | ||
private volatile boolean failed = false; | ||
|
||
@Override | ||
public void write(ByteBuf src, long position) throws IOException { | ||
checkFailed(); | ||
doWrite(src, position); | ||
} | ||
|
||
@Override | ||
public void retryWrite(ByteBuf src, long position, long retryIntervalMillis, | ||
long retryTimeoutMillis) throws IOException { | ||
checkFailed(); | ||
retry(() -> write(src, position), retryIntervalMillis, retryTimeoutMillis); | ||
} | ||
|
||
@Override | ||
public void flush() throws IOException { | ||
checkFailed(); | ||
doFlush(); | ||
} | ||
|
||
@Override | ||
public void retryFlush(long retryIntervalMillis, long retryTimeoutMillis) throws IOException { | ||
checkFailed(); | ||
retry(this::flush, retryIntervalMillis, retryTimeoutMillis); | ||
} | ||
|
||
@Override | ||
public int read(ByteBuf dst, long position, int length) throws IOException { | ||
checkFailed(); | ||
return doRead(dst, position, length); | ||
} | ||
|
||
@Override | ||
public int retryRead(ByteBuf dst, long position, int length, long retryIntervalMillis, | ||
long retryTimeoutMillis) throws IOException { | ||
checkFailed(); | ||
return retry(() -> read(dst, position, length), retryIntervalMillis, retryTimeoutMillis); | ||
} | ||
|
||
private void retry(IORunnable runnable, long retryIntervalMillis, long retryTimeoutMillis) throws IOException { | ||
retry(IOSupplier.from(runnable), retryIntervalMillis, retryTimeoutMillis); | ||
} | ||
|
||
private <T> T retry(IOSupplier<T> supplier, long retryIntervalMillis, long retryTimeoutMillis) throws IOException { | ||
long start = System.nanoTime(); | ||
long retryTimeoutNanos = TimeUnit.MILLISECONDS.toNanos(retryTimeoutMillis); | ||
while (true) { | ||
try { | ||
return supplier.get(); | ||
} catch (IOException e) { | ||
if (System.nanoTime() - start > retryTimeoutNanos) { | ||
failed = true; | ||
LOGGER.error("Failed to execute IO operation, retry timeout", e); | ||
throw e; | ||
} | ||
checkFailed(); | ||
LOGGER.warn("Failed to execute IO operation, retrying in {}ms, error: {}", retryIntervalMillis, e.getMessage()); | ||
Threads.sleep(retryIntervalMillis); | ||
} | ||
} | ||
} | ||
|
||
private void checkFailed() throws IOException { | ||
if (failed) { | ||
IOException e = new IOException("Failed to execute IO operation, WAL failed"); | ||
LOGGER.error("Failed to execute IO operation, WAL failed", e); | ||
throw e; | ||
} | ||
} | ||
|
||
protected abstract void doWrite(ByteBuf src, long position) throws IOException; | ||
|
||
protected abstract void doFlush() throws IOException; | ||
|
||
protected abstract int doRead(ByteBuf dst, long position, int length) throws IOException; | ||
|
||
private interface IOSupplier<T> { | ||
T get() throws IOException; | ||
|
||
static IOSupplier<Void> from(IORunnable runnable) { | ||
return () -> { | ||
runnable.run(); | ||
return null; | ||
}; | ||
} | ||
} | ||
|
||
private interface IORunnable { | ||
void run() throws IOException; | ||
} | ||
} |
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
Oops, something went wrong.