Skip to content

Commit b720bd6

Browse files
committed
Close translog writer if exception on write channel (#29401)
Today we close the translog write tragically if we experience any I/O exception on a write. These tragic closes lead to use closing the translog and failing the engine. Yet, there is one case that is missed which is when we touch the write channel during a read (checking if reading from the writer would put us past what has been flushed). This commit addresses this by closing the writer tragically if we encounter an I/O exception on the write channel while reading. This becomes interesting when we consider that this method is invoked from the engine through the translog as part of getting a document from the translog. This means we have to consider closing the translog here as well which will cascade up into us finally failing the engine. Note that there is no semantic change to, for example, primary/replica resync and recovery. These actions will take a snapshot of the translog which syncs the translog to disk. If an I/O exception occurs during the sync we already close the writer tragically and once we have synced we do not ever read past the position that was synced while taking the snapshot.
1 parent 3ef753e commit b720bd6

File tree

2 files changed

+27
-9
lines changed

2 files changed

+27
-9
lines changed

server/src/main/java/org/elasticsearch/index/translog/Translog.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,16 @@ public Operation readOperation(Location location) throws IOException {
584584
if (current.generation == location.generation) {
585585
// no need to fsync here the read operation will ensure that buffers are written to disk
586586
// if they are still in RAM and we are reading onto that position
587-
return current.read(location);
587+
try {
588+
return current.read(location);
589+
} catch (final IOException e) {
590+
try {
591+
closeOnTragicEvent(e);
592+
} catch (final Exception inner) {
593+
e.addSuppressed(inner);
594+
}
595+
throw e;
596+
}
588597
} else {
589598
// read backwards - it's likely we need to read on that is recent
590599
for (int i = readers.size() - 1; i >= 0; i--) {

server/src/main/java/org/elasticsearch/index/translog/TranslogWriter.java

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -380,16 +380,25 @@ public boolean syncUpTo(long offset) throws IOException {
380380

381381
@Override
382382
protected void readBytes(ByteBuffer targetBuffer, long position) throws IOException {
383-
if (position + targetBuffer.remaining() > getWrittenOffset()) {
384-
synchronized (this) {
385-
// we only flush here if it's really really needed - try to minimize the impact of the read operation
386-
// in some cases ie. a tragic event we might still be able to read the relevant value
387-
// which is not really important in production but some test can make most strict assumptions
388-
// if we don't fail in this call unless absolutely necessary.
389-
if (position + targetBuffer.remaining() > getWrittenOffset()) {
390-
outputStream.flush();
383+
try {
384+
if (position + targetBuffer.remaining() > getWrittenOffset()) {
385+
synchronized (this) {
386+
// we only flush here if it's really really needed - try to minimize the impact of the read operation
387+
// in some cases ie. a tragic event we might still be able to read the relevant value
388+
// which is not really important in production but some test can make most strict assumptions
389+
// if we don't fail in this call unless absolutely necessary.
390+
if (position + targetBuffer.remaining() > getWrittenOffset()) {
391+
outputStream.flush();
392+
}
391393
}
392394
}
395+
} catch (final IOException e) {
396+
try {
397+
closeWithTragicEvent(e);
398+
} catch (final IOException inner) {
399+
e.addSuppressed(inner);
400+
}
401+
throw e;
393402
}
394403
// we don't have to have a lock here because we only write ahead to the file, so all writes has been complete
395404
// for the requested location.

0 commit comments

Comments
 (0)