package io.atomix.storage.journal;
import io.netty.buffer.ByteBuf;
+import java.io.EOFException;
import java.io.IOException;
import org.eclipse.jdt.annotation.NonNullByDefault;
*
* @param obj the object
* @param buf target buffer
- * @throws IOException if an I/O error occurs
+ * @throws EOFException if the buffer does not have sufficient capacity
+ * @throws IOException if some other I/O error occurs
*/
void objectToBytes(T obj, ByteBuf buf) throws IOException;
}
import io.atomix.storage.journal.StorageException.TooLarge;
import io.atomix.storage.journal.index.JournalIndex;
import io.netty.buffer.Unpooled;
+import java.io.EOFException;
import java.io.IOException;
import java.nio.MappedByteBuffer;
import org.eclipse.jdt.annotation.NonNull;
final var bytes = Unpooled.wrappedBuffer(diskEntry.position(HEADER_BYTES));
try {
mapper.objectToBytes(entry, bytes);
- } catch (IOException e) {
+ } catch (EOFException e) {
// We ran out of buffer space: let's decide who's fault it is:
if (writeLimit == maxEntrySize) {
// - it is the entry and/or mapper. This is not exactly accurate, as there may be other serialization
// - it is us, as we do not have the capacity to hold maxEntrySize bytes
LOG.trace("Tail serialization with {} bytes available failed", writeLimit, e);
return null;
+ } catch (IOException e) {
+ throw new StorageException(e);
}
// Determine length, trim distEntry and compute checksum. We are okay with computeChecksum() consuming
import com.google.common.annotations.VisibleForTesting;
import io.atomix.utils.serializer.KryoJournalSerdesBuilder;
import io.netty.buffer.ByteBuf;
+import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
try {
serialize(obj, buffer);
} catch (KryoException e) {
- throw new IOException(e);
+ throw newIOException(e);
} finally {
// adjust writerIndex so that readableBytes() the bytes written
bytes.writerIndex(bytes.readerIndex() + buffer.position());
public T bytesToObject(final long index, final ByteBuf bytes) {
return deserialize(bytes.nioBuffer());
}
+
+ private static IOException newIOException(final KryoException cause) {
+ // We may have multiple nested KryoExceptions, intertwined with others, like IOExceptions. Let's find
+ // the deepest one.
+ var rootKryo = cause;
+ for (var nextCause = rootKryo.getCause(); nextCause != null; nextCause = nextCause.getCause()) {
+ if (nextCause instanceof KryoException kryo) {
+ rootKryo = kryo;
+ }
+ }
+ // It would be nice to have a better way of discerning these, but alas it is what it is.
+ if (rootKryo.getMessage().startsWith("Buffer overflow.")) {
+ final var ex = new EOFException();
+ ex.initCause(cause);
+ return ex;
+ }
+ return new IOException(rootKryo);
+ }
};
}