diff --git a/ambry-api/src/test/java/com.github.ambry/store/MockWrite.java b/ambry-api/src/test/java/com.github.ambry/store/MockWrite.java index 23e54f3302..9a87cda8ce 100644 --- a/ambry-api/src/test/java/com.github.ambry/store/MockWrite.java +++ b/ambry-api/src/test/java/com.github.ambry/store/MockWrite.java @@ -16,6 +16,7 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; +import java.util.Objects; /** @@ -53,8 +54,8 @@ public void appendFrom(ReadableByteChannel channel, long size) throws StoreExcep } catch (IOException e) { // The IOException message may vary in different java versions. As code evolves, we may need to update IO_ERROR_STR // in StoreException (based on java version that is being employed) to correctly capture disk I/O related errors. - StoreErrorCodes errorCode = - e.getMessage().equals(StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError : StoreErrorCodes.Unknown_Error; + StoreErrorCodes errorCode = Objects.equals(e.getMessage(), StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError + : StoreErrorCodes.Unknown_Error; throw new StoreException(errorCode.toString() + " while writing into store", e, errorCode); } buf.limit(savedLimit); diff --git a/ambry-replication/src/test/java/com.github.ambry.replication/ReplicationTest.java b/ambry-replication/src/test/java/com.github.ambry.replication/ReplicationTest.java index 56608c107d..5221f3d1e2 100644 --- a/ambry-replication/src/test/java/com.github.ambry.replication/ReplicationTest.java +++ b/ambry-replication/src/test/java/com.github.ambry.replication/ReplicationTest.java @@ -94,6 +94,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Properties; import java.util.Random; import java.util.Set; @@ -2002,8 +2003,9 @@ public void appendFrom(ReadableByteChannel channel, long size) throws StoreExcep sizeRead += channel.read(buf); } } catch (IOException e) { - StoreErrorCodes errorCode = e.getMessage().equals(StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError - : StoreErrorCodes.Unknown_Error; + StoreErrorCodes errorCode = + Objects.equals(e.getMessage(), StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError + : StoreErrorCodes.Unknown_Error; throw new StoreException(errorCode.toString() + " while writing into dummy log", e, errorCode); } buf.flip(); diff --git a/ambry-store/src/main/java/com.github.ambry.store/HardDeleter.java b/ambry-store/src/main/java/com.github.ambry.store/HardDeleter.java index 7f756a67fe..e70b4fcb4a 100644 --- a/ambry-store/src/main/java/com.github.ambry.store/HardDeleter.java +++ b/ambry-store/src/main/java/com.github.ambry.store/HardDeleter.java @@ -30,6 +30,7 @@ import java.util.EnumSet; import java.util.Iterator; import java.util.List; +import java.util.Objects; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -234,8 +235,8 @@ void performRecovery() throws StoreException { } } catch (IOException e) { metrics.hardDeleteExceptionsCount.inc(); - StoreErrorCodes errorCode = - e.getMessage().equals(StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError : StoreErrorCodes.Unknown_Error; + StoreErrorCodes errorCode = Objects.equals(e.getMessage(), StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError + : StoreErrorCodes.Unknown_Error; throw new StoreException(errorCode.toString() + " occurred while performing hard delete ", e, errorCode); } /* Now that all the blobs in the range were successfully hard deleted, the next time hard deletes can be resumed @@ -540,8 +541,8 @@ private void persistCleanupToken() throws IOException, StoreException { fileStream.getChannel().force(true); tempFile.renameTo(actual); } catch (IOException e) { - StoreErrorCodes errorCode = - e.getMessage().equals(StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError : StoreErrorCodes.Unknown_Error; + StoreErrorCodes errorCode = Objects.equals(e.getMessage(), StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError + : StoreErrorCodes.Unknown_Error; throw new StoreException( errorCode.toString() + " while persisting cleanup tokens to disk " + tempFile.getAbsoluteFile(), errorCode); } finally { @@ -621,8 +622,8 @@ private void performHardDeletes(List messageInfoList) throws StoreE diskIOScheduler.getSlice(HARD_DELETE_CLEANUP_JOB_NAME, HARD_DELETE_CLEANUP_JOB_NAME, logWriteInfo.size); } } catch (IOException e) { - StoreErrorCodes errorCode = - e.getMessage().equals(StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError : StoreErrorCodes.Unknown_Error; + StoreErrorCodes errorCode = Objects.equals(e.getMessage(), StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError + : StoreErrorCodes.Unknown_Error; throw new StoreException(errorCode.toString() + " while performing hard delete ", e, errorCode); } logger.trace("Performed hard deletes from {} to {} for {}", startToken, endToken, dataDir); diff --git a/ambry-store/src/main/java/com.github.ambry.store/IndexSegment.java b/ambry-store/src/main/java/com.github.ambry.store/IndexSegment.java index b1f8fd274c..fff65bc15b 100644 --- a/ambry-store/src/main/java/com.github.ambry.store/IndexSegment.java +++ b/ambry-store/src/main/java/com.github.ambry.store/IndexSegment.java @@ -41,6 +41,7 @@ import java.util.Map; import java.util.NavigableMap; import java.util.NavigableSet; +import java.util.Objects; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.ConcurrentSkipListMap; @@ -400,8 +401,8 @@ private void persistBloomFilter() throws StoreException { stream.writeLong(crcValue); stream.close(); } catch (IOException e) { - StoreErrorCodes errorCode = - e.getMessage().equals(StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError : StoreErrorCodes.Unknown_Error; + StoreErrorCodes errorCode = Objects.equals(e.getMessage(), StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError + : StoreErrorCodes.Unknown_Error; throw new StoreException(errorCode.toString() + " while trying to persist bloom filter", e, errorCode); } } @@ -448,12 +449,12 @@ private StoreKey getKeyAt(ByteBuffer mmap, int index) throws StoreException { mmap.position(firstKeyRelativeOffset + index * persistedEntrySize); storeKey = factory.getStoreKey(new DataInputStream(new ByteBufferInputStream(mmap))); } catch (InternalError e) { - throw e.getMessage().equals(StoreException.INTERNAL_ERROR_STR) ? new StoreException( + throw Objects.equals(e.getMessage(), StoreException.INTERNAL_ERROR_STR) ? new StoreException( "Internal error occurred due to unsafe memory access", e, StoreErrorCodes.IOError) : new StoreException("Unknown internal error while trying to get store key", e, StoreErrorCodes.Unknown_Error); } catch (IOException e) { - throw e.getMessage().equals(StoreException.IO_ERROR_STR) ? new StoreException( + throw Objects.equals(e.getMessage(), StoreException.IO_ERROR_STR) ? new StoreException( "IO error while trying to get store key", e, StoreErrorCodes.IOError) : new StoreException("Unknown IO error while trying to get store key", e, StoreErrorCodes.Unknown_Error); } catch (Throwable t) { @@ -700,8 +701,9 @@ void writeIndexSegmentToFile(Offset safeEndPoint) throws FileNotFoundException, // swap temp file with the original file temp.renameTo(getFile()); } catch (IOException e) { - StoreErrorCodes errorCode = e.getMessage().equals(StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError - : StoreErrorCodes.Unknown_Error; + StoreErrorCodes errorCode = + Objects.equals(e.getMessage(), StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError + : StoreErrorCodes.Unknown_Error; throw new StoreException( "IndexSegment : " + indexFile.getAbsolutePath() + " encountered " + errorCode.toString() + " while persisting index to disk", e, errorCode); @@ -794,8 +796,8 @@ private void map() throws StoreException { } catch (FileNotFoundException e) { throw new StoreException("File not found while mapping the segment of index", e, StoreErrorCodes.File_Not_Found); } catch (IOException e) { - StoreErrorCodes errorCode = - e.getMessage().equals(StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError : StoreErrorCodes.Unknown_Error; + StoreErrorCodes errorCode = Objects.equals(e.getMessage(), StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError + : StoreErrorCodes.Unknown_Error; throw new StoreException(errorCode.toString() + " while mapping the segment of index", e, errorCode); } finally { rwLock.writeLock().unlock(); @@ -906,8 +908,8 @@ private void readFromFile(File fileToRead, Journal journal) throws StoreExceptio StoreErrorCodes.Index_Creation_Failure); } } catch (IOException e) { - StoreErrorCodes errorCode = - e.getMessage().equals(StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError : StoreErrorCodes.Unknown_Error; + StoreErrorCodes errorCode = Objects.equals(e.getMessage(), StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError + : StoreErrorCodes.Unknown_Error; throw new StoreException("IndexSegment : " + indexFile.getAbsolutePath() + " encountered " + errorCode.toString() + " while reading from file ", e, errorCode); } diff --git a/ambry-store/src/main/java/com.github.ambry.store/Log.java b/ambry-store/src/main/java/com.github.ambry.store/Log.java index 7d08eb0f7b..b9b0f08179 100644 --- a/ambry-store/src/main/java/com.github.ambry.store/Log.java +++ b/ambry-store/src/main/java/com.github.ambry.store/Log.java @@ -23,6 +23,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ConcurrentNavigableMap; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.atomic.AtomicLong; @@ -326,7 +327,7 @@ private LogSegment checkArgsAndGetFirstSegment(long segmentCapacity) throws Stor * Creates {@link LogSegment} instances from {@code segmentFiles}. * @param segmentFiles the files that form the segments of the log. * @return {@code List} of {@link LogSegment} instances corresponding to {@code segmentFiles}. - * @throws IOException if there is an I/O error loading the segment files or creating {@link LogSegment} instances. + * @throws StoreException if there is an I/O error loading the segment files or creating {@link LogSegment} instances. */ private List getSegmentsToLoad(File[] segmentFiles) throws StoreException { List segments = new ArrayList<>(segmentFiles.length); @@ -391,8 +392,9 @@ private File allocate(String filename, long size) throws StoreException { try { diskSpaceAllocator.allocate(segmentFile, size); } catch (IOException e) { - StoreErrorCodes errorCode = e.getMessage().equals(StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError - : StoreErrorCodes.Unknown_Error; + StoreErrorCodes errorCode = + Objects.equals(e.getMessage(), StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError + : StoreErrorCodes.Unknown_Error; throw new StoreException(errorCode.toString() + " while allocating the file", e, errorCode); } } @@ -410,8 +412,8 @@ private void free(LogSegment logSegment) throws StoreException { logSegment.close(); diskSpaceAllocator.free(segmentFile, logSegment.getCapacityInBytes()); } catch (IOException e) { - StoreErrorCodes errorCode = - e.getMessage().equals(StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError : StoreErrorCodes.Unknown_Error; + StoreErrorCodes errorCode = Objects.equals(e.getMessage(), StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError + : StoreErrorCodes.Unknown_Error; throw new StoreException(errorCode.toString() + " while freeing log segment", e, errorCode); } } @@ -463,9 +465,26 @@ private void ensureCapacity(long writeSize) throws StoreException { Pair segmentNameAndFilename = getNextSegmentNameAndFilename(); logger.info("Allocating new segment with name: " + segmentNameAndFilename.getFirst()); File newSegmentFile = allocate(segmentNameAndFilename.getSecond(), segmentCapacity); - LogSegment newSegment = - new LogSegment(segmentNameAndFilename.getFirst(), newSegmentFile, segmentCapacity, metrics, true); - segmentsByName.put(segmentNameAndFilename.getFirst(), newSegment); + try { + LogSegment newSegment = + new LogSegment(segmentNameAndFilename.getFirst(), newSegmentFile, segmentCapacity, metrics, true); + segmentsByName.put(segmentNameAndFilename.getFirst(), newSegment); + } catch (StoreException e) { + logger.error("Failed to create new log segment {} with store exception: ", segmentNameAndFilename.getFirst(), e); + try { + diskSpaceAllocator.free(newSegmentFile, segmentCapacity); + remainingUnallocatedSegments.incrementAndGet(); + } catch (IOException exception) { + StoreErrorCodes errorCode = + Objects.equals(exception.getMessage(), StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError + : StoreErrorCodes.Unknown_Error; + throw new StoreException( + errorCode.toString() + " while freeing log segment " + segmentNameAndFilename.getFirst(), exception, + errorCode); + } finally { + metrics.overflowWriteError.inc(); + } + } } /** diff --git a/ambry-store/src/main/java/com.github.ambry.store/LogSegment.java b/ambry-store/src/main/java/com.github.ambry.store/LogSegment.java index fb60f3231e..81ea98486f 100644 --- a/ambry-store/src/main/java/com.github.ambry.store/LogSegment.java +++ b/ambry-store/src/main/java/com.github.ambry.store/LogSegment.java @@ -26,6 +26,7 @@ import java.nio.channels.ClosedChannelException; import java.nio.channels.FileChannel; import java.nio.channels.ReadableByteChannel; +import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @@ -135,8 +136,8 @@ class LogSegment implements Read, Write { } catch (FileNotFoundException e) { throw new StoreException("File not found while creating log segment", e, StoreErrorCodes.File_Not_Found); } catch (IOException e) { - StoreErrorCodes errorCode = - e.getMessage().equals(StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError : StoreErrorCodes.Unknown_Error; + StoreErrorCodes errorCode = Objects.equals(e.getMessage(), StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError + : StoreErrorCodes.Unknown_Error; throw new StoreException(errorCode.toString() + " while creating log segment", e, errorCode); } } @@ -164,8 +165,8 @@ public int appendFrom(ByteBuffer buffer) throws StoreException { } catch (ClosedChannelException e) { throw new StoreException("Channel closed while writing into the log segment", e, StoreErrorCodes.Channel_Closed); } catch (IOException e) { - StoreErrorCodes errorCode = - e.getMessage().equals(StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError : StoreErrorCodes.Unknown_Error; + StoreErrorCodes errorCode = Objects.equals(e.getMessage(), StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError + : StoreErrorCodes.Unknown_Error; throw new StoreException(errorCode.toString() + " while writing into the log segment", e, errorCode); } endOffset.addAndGet(bytesWritten); @@ -209,8 +210,9 @@ public void appendFrom(ReadableByteChannel channel, long size) throws StoreExcep bytesWritten += fileChannel.write(byteBufferForAppend, endOffset.get() + bytesWritten); } } catch (IOException e) { - StoreErrorCodes errorCode = e.getMessage().equals(StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError - : StoreErrorCodes.Unknown_Error; + StoreErrorCodes errorCode = + Objects.equals(e.getMessage(), StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError + : StoreErrorCodes.Unknown_Error; throw new StoreException(errorCode.toString() + " while writing into the log segment", e, errorCode); } } @@ -239,8 +241,8 @@ int appendFromDirectly(byte[] byteArray, int offset, int length) throws StoreExc directFile.write(byteArray, offset, length); endOffset.addAndGet(length); } catch (IOException e) { - StoreErrorCodes errorCode = - e.getMessage().equals(StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError : StoreErrorCodes.Unknown_Error; + StoreErrorCodes errorCode = Objects.equals(e.getMessage(), StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError + : StoreErrorCodes.Unknown_Error; throw new StoreException(errorCode.toString() + " while writing into segment via direct IO", e, errorCode); } return length; @@ -422,8 +424,8 @@ void setEndOffset(long endOffset) throws StoreException { fileChannel.position(endOffset); this.endOffset.set(endOffset); } catch (IOException e) { - StoreErrorCodes errorCode = - e.getMessage().equals(StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError : StoreErrorCodes.Unknown_Error; + StoreErrorCodes errorCode = Objects.equals(e.getMessage(), StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError + : StoreErrorCodes.Unknown_Error; throw new StoreException(errorCode.toString() + " while setting end offset of segment", e, errorCode); } } diff --git a/ambry-store/src/main/java/com.github.ambry.store/PersistentIndex.java b/ambry-store/src/main/java/com.github.ambry.store/PersistentIndex.java index 957aa461d2..e41fb5b502 100644 --- a/ambry-store/src/main/java/com.github.ambry.store/PersistentIndex.java +++ b/ambry-store/src/main/java/com.github.ambry.store/PersistentIndex.java @@ -32,6 +32,7 @@ import java.util.ListIterator; import java.util.Map; import java.util.NavigableSet; +import java.util.Objects; import java.util.Random; import java.util.Set; import java.util.TreeMap; @@ -828,8 +829,8 @@ private BlobReadOptions getDeletedBlobReadOptions(IndexValue value, StoreKey key + "]", StoreErrorCodes.ID_Deleted); } } catch (IOException e) { - StoreErrorCodes errorCode = - e.getMessage().equals(StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError : StoreErrorCodes.Unknown_Error; + StoreErrorCodes errorCode = Objects.equals(e.getMessage(), StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError + : StoreErrorCodes.Unknown_Error; throw new StoreException(errorCode.toString() + " when reading delete blob info from the log " + dataDir, e, errorCode); } @@ -1661,8 +1662,9 @@ public synchronized void write() throws StoreException { } catch (FileNotFoundException e) { throw new StoreException("File not found while writing index to file", e, StoreErrorCodes.File_Not_Found); } catch (IOException e) { - StoreErrorCodes errorCode = e.getMessage().equals(StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError - : StoreErrorCodes.Unknown_Error; + StoreErrorCodes errorCode = + Objects.equals(e.getMessage(), StoreException.IO_ERROR_STR) ? StoreErrorCodes.IOError + : StoreErrorCodes.Unknown_Error; throw new StoreException(errorCode.toString() + " while persisting index to disk", e, errorCode); } finally { context.stop(); diff --git a/ambry-store/src/test/java/com.github.ambry.store/BlobStoreTest.java b/ambry-store/src/test/java/com.github.ambry.store/BlobStoreTest.java index c49934db53..4a6a9971df 100644 --- a/ambry-store/src/test/java/com.github.ambry.store/BlobStoreTest.java +++ b/ambry-store/src/test/java/com.github.ambry.store/BlobStoreTest.java @@ -691,8 +691,8 @@ public void deleteAuthorizationFailureTest() throws Exception { MockId mockId = put(1, PUT_RECORD_SIZE, Utils.Infinite_Time).get(0); short[] accountIds = {-1, Utils.getRandomShort(TestUtils.RANDOM), -1, mockId.getAccountId(), Utils.getRandomShort(TestUtils.RANDOM)}; - short[] containerIds = {-1, -1, Utils.getRandomShort(TestUtils.RANDOM), Utils.getRandomShort( - TestUtils.RANDOM), mockId.getContainerId()}; + short[] containerIds = {-1, -1, Utils.getRandomShort(TestUtils.RANDOM), Utils.getRandomShort(TestUtils.RANDOM), + mockId.getContainerId()}; for (int i = 0; i < accountIds.length; i++) { verifyDeleteFailure(new MockId(mockId.getID(), accountIds[i], containerIds[i]), StoreErrorCodes.Authorization_Failure); @@ -723,8 +723,8 @@ public void getAuthorizationFailureTest() throws Exception { MockId mockId = put(1, PUT_RECORD_SIZE, Utils.Infinite_Time).get(0); short[] accountIds = {-1, Utils.getRandomShort(TestUtils.RANDOM), -1, mockId.getAccountId(), Utils.getRandomShort(TestUtils.RANDOM)}; - short[] containerIds = {-1, -1, Utils.getRandomShort(TestUtils.RANDOM), Utils.getRandomShort( - TestUtils.RANDOM), mockId.getContainerId()}; + short[] containerIds = {-1, -1, Utils.getRandomShort(TestUtils.RANDOM), Utils.getRandomShort(TestUtils.RANDOM), + mockId.getContainerId()}; for (int i = 0; i < accountIds.length; i++) { verifyGetFailure(new MockId(mockId.getID(), accountIds[i], containerIds[i]), StoreErrorCodes.Authorization_Failure); @@ -1102,6 +1102,17 @@ public void storeIoErrorCountTest() throws StoreException, IOException { } assertEquals("Mismatch in error count", 2, testStore2.getErrorCount().get()); + // test that when InternalError's error message is null, the error code should be Unknown_Error and store error count + // stays unchanged. + doThrow(new InternalError()).when(mockStoreKeyFactory).getStoreKey(any(DataInputStream.class)); + try { + testStore2.get(Collections.singletonList(id2), EnumSet.noneOf(StoreGetOptions.class)); + fail("should throw exception"); + } catch (StoreException e) { + assertEquals("Mismatch in error code", StoreErrorCodes.Unknown_Error, e.getErrorCode()); + } + assertEquals("Mismatch in error count", 2, testStore2.getErrorCount().get()); + // verify that StoreException.Unknown_Error could be captured by Get and error count stays unchanged. doThrow(new IOException("Unknown exception")).when(mockStoreKeyFactory).getStoreKey(any(DataInputStream.class)); try { diff --git a/ambry-store/src/test/java/com.github.ambry.store/IndexSegmentTest.java b/ambry-store/src/test/java/com.github.ambry.store/IndexSegmentTest.java index 34c1f49c4b..8ca41ba36c 100644 --- a/ambry-store/src/test/java/com.github.ambry.store/IndexSegmentTest.java +++ b/ambry-store/src/test/java/com.github.ambry.store/IndexSegmentTest.java @@ -49,7 +49,7 @@ import static org.junit.Assert.*; import static org.junit.Assume.*; -import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; @@ -388,6 +388,14 @@ public void memoryMapFailureTest() throws IOException, StoreException { } catch (StoreException e) { assertEquals("Mismatch in error code", StoreErrorCodes.IOError, e.getErrorCode()); } + // test that when IOException's error message is null, the error code should be Unknown_Error + doThrow(new IOException()).when(mockStoreKeyFactory).getStoreKey(any(DataInputStream.class)); + try { + indexSegment.seal(); + fail("should fail"); + } catch (StoreException e) { + assertEquals("Mismatch in error code", StoreErrorCodes.Unknown_Error, e.getErrorCode()); + } } /** diff --git a/ambry-store/src/test/java/com.github.ambry.store/IndexTest.java b/ambry-store/src/test/java/com.github.ambry.store/IndexTest.java index 48c1476dd3..62b3aff1f0 100644 --- a/ambry-store/src/test/java/com.github.ambry.store/IndexTest.java +++ b/ambry-store/src/test/java/com.github.ambry.store/IndexTest.java @@ -211,6 +211,11 @@ public MessageInfo getMessageInfo(Read read, long offset, StoreKeyFactory factor .getMessageInfo(any(Read.class), anyLong(), any(StoreKeyFactory.class)); verifyBlobReadOptions(state.deletedKeyWithPutInSameSegment, EnumSet.of(StoreGetOptions.Store_Include_Deleted), StoreErrorCodes.IOError); + // test that when IOException's error message is null, the error code should be Unknown_Error + doThrow(new IOException()).when(mockHardDelete) + .getMessageInfo(any(Read.class), anyLong(), any(StoreKeyFactory.class)); + verifyBlobReadOptions(state.deletedKeyWithPutInSameSegment, EnumSet.of(StoreGetOptions.Store_Include_Deleted), + StoreErrorCodes.Unknown_Error); } /** @@ -1169,6 +1174,14 @@ public void indexPersistorTest() throws IOException, StoreException { } catch (StoreException e) { assertEquals("StoreException error code mismatch ", StoreErrorCodes.IOError, e.getErrorCode()); } + // test that when IOException's error message is null, the error code should be Unknown_Error + try { + doThrow(new IOException()).when(mockLog).flush(); + state.index.close(); + fail("Should have thrown exception due to I/O error"); + } catch (StoreException e) { + assertEquals("StoreException error code mismatch ", StoreErrorCodes.Unknown_Error, e.getErrorCode()); + } Mockito.reset(mockLog); }