diff --git a/CHANGES.txt b/CHANGES.txt index 7c54a9e588..dfe9c478b8 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -13,6 +13,7 @@ * Bogus deserialization of static cells from sstable (CASSANDRA-7684) * Fix NPE on compaction leftover cleanup for dropped table (CASSANDRA-7770) Merged from 2.0: + * Fix NPE in FileCacheService.sizeInBytes (CASSANDRA-7756) * Remove duplicates from StorageService.getJoiningNodes (CASSANDRA-7478) * Clone token map outside of hot gossip loops (CASSANDRA-7758) * Fix MS expiring map timeout for Paxos messages (CASSANDRA-7752) diff --git a/src/java/org/apache/cassandra/io/util/RandomAccessReader.java b/src/java/org/apache/cassandra/io/util/RandomAccessReader.java index 8347cd9998..81e45b5ad0 100644 --- a/src/java/org/apache/cassandra/io/util/RandomAccessReader.java +++ b/src/java/org/apache/cassandra/io/util/RandomAccessReader.java @@ -154,7 +154,10 @@ public class RandomAccessReader extends RandomAccessFile implements FileDataInpu public int getTotalBufferSize() { - return buffer.length; + //This may NPE so we make a ref + //https://issues.apache.org/jira/browse/CASSANDRA-7756 + byte[] ref = buffer; + return ref != null ? ref.length : 0; } public void reset() diff --git a/test/unit/org/apache/cassandra/io/util/BufferedRandomAccessFileTest.java b/test/unit/org/apache/cassandra/io/util/BufferedRandomAccessFileTest.java index 75de2618ec..cfabf620d2 100644 --- a/test/unit/org/apache/cassandra/io/util/BufferedRandomAccessFileTest.java +++ b/test/unit/org/apache/cassandra/io/util/BufferedRandomAccessFileTest.java @@ -19,6 +19,7 @@ */ package org.apache.cassandra.io.util; +import org.apache.cassandra.service.FileCacheService; import org.apache.cassandra.utils.ByteBufferUtil; import java.io.File; @@ -28,6 +29,11 @@ import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.util.Arrays; import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import static org.apache.cassandra.Util.expectEOF; import static org.apache.cassandra.Util.expectException; @@ -519,6 +525,70 @@ public class BufferedRandomAccessFileTest } } + @Test + public void testFileCacheService() throws IOException, InterruptedException + { + //see https://issues.apache.org/jira/browse/CASSANDRA-7756 + + final int THREAD_COUNT = 40; + ExecutorService executorService = Executors.newFixedThreadPool(THREAD_COUNT); + + SequentialWriter w1 = createTempFile("fscache1"); + SequentialWriter w2 = createTempFile("fscache2"); + + w1.write(new byte[30]); + w1.close(); + + w2.write(new byte[30]); + w2.close(); + + for (int i = 0; i < 20; i++) + { + + + RandomAccessReader r1 = RandomAccessReader.open(w1); + RandomAccessReader r2 = RandomAccessReader.open(w2); + + + FileCacheService.instance.put(r1); + FileCacheService.instance.put(r2); + + final CountDownLatch finished = new CountDownLatch(THREAD_COUNT); + final AtomicBoolean hadError = new AtomicBoolean(false); + + for (int k = 0; k < THREAD_COUNT; k++) + { + executorService.execute( new Runnable() + { + @Override + public void run() + { + try + { + long size = FileCacheService.instance.sizeInBytes(); + + while (size > 0) + size = FileCacheService.instance.sizeInBytes(); + } + catch (Throwable t) + { + t.printStackTrace(); + hadError.set(true); + } + finally + { + finished.countDown(); + } + } + }); + + } + + finished.await(); + assert !hadError.get(); + } + } + @Test public void testReadOnly() throws IOException {