diff --git a/CHANGES.txt b/CHANGES.txt
index a5b32205ba..ad2845f459 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
2.2
+ * Static Analysis to warn on unsafe use of Autocloseable instances (CASSANDRA-9431)
* Update commitlog archiving examples now that commitlog segments are
not recycled (CASSANDRA-9350)
* Extend Transactional API to sstable lifecycle management (CASSANDRA-8568)
diff --git a/build.xml b/build.xml
index cbedf201d7..bb401eed2b 100644
--- a/build.xml
+++ b/build.xml
@@ -68,8 +68,8 @@
-
-
+
+
@@ -114,6 +114,8 @@
+
+
@@ -1047,7 +1049,7 @@
-
@@ -1406,7 +1408,7 @@
@@ -1894,6 +1896,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
extends InstrumentingCache implements ICache
map.clear();
}
+ @SuppressWarnings("resource")
public V get(K key)
{
RefCountedMemory mem = map.get(key);
@@ -172,6 +173,7 @@ public class SerializingCache implements ICache
}
}
+ @SuppressWarnings("resource")
public void put(K key, V value)
{
RefCountedMemory mem = serialize(value);
@@ -193,6 +195,7 @@ public class SerializingCache implements ICache
old.unreference();
}
+ @SuppressWarnings("resource")
public boolean putIfAbsent(K key, V value)
{
RefCountedMemory mem = serialize(value);
@@ -216,6 +219,7 @@ public class SerializingCache implements ICache
return old == null;
}
+ @SuppressWarnings("resource")
public boolean replace(K key, V oldToReplace, V value)
{
// if there is no old value in our map, we fail
@@ -259,6 +263,7 @@ public class SerializingCache implements ICache
public void remove(K key)
{
+ @SuppressWarnings("resource")
RefCountedMemory mem = map.remove(key);
if (mem != null)
mem.unreference();
diff --git a/src/java/org/apache/cassandra/db/BatchlogManager.java b/src/java/org/apache/cassandra/db/BatchlogManager.java
index f5137fdfe0..dd84ac88b9 100644
--- a/src/java/org/apache/cassandra/db/BatchlogManager.java
+++ b/src/java/org/apache/cassandra/db/BatchlogManager.java
@@ -148,20 +148,17 @@ public class BatchlogManager implements BatchlogManagerMBean
private static ByteBuffer serializeMutations(Collection mutations, int version)
{
- DataOutputBuffer buf = new DataOutputBuffer();
-
- try
+ try (DataOutputBuffer buf = new DataOutputBuffer())
{
buf.writeInt(mutations.size());
for (Mutation mutation : mutations)
Mutation.serializer.serialize(mutation, buf, version);
+ return buf.buffer();
}
catch (IOException e)
{
throw new AssertionError(); // cannot happen.
}
-
- return buf.buffer();
}
private void replayAllFailedBatches() throws ExecutionException, InterruptedException
diff --git a/src/java/org/apache/cassandra/db/ColumnFamily.java b/src/java/org/apache/cassandra/db/ColumnFamily.java
index 006ced78c4..a7243a2fba 100644
--- a/src/java/org/apache/cassandra/db/ColumnFamily.java
+++ b/src/java/org/apache/cassandra/db/ColumnFamily.java
@@ -521,9 +521,11 @@ public abstract class ColumnFamily implements Iterable| , IRowCacheEntry
public ByteBuffer toBytes()
{
- DataOutputBuffer out = new DataOutputBuffer();
- serializer.serialize(this, out, MessagingService.current_version);
- return ByteBuffer.wrap(out.getData(), 0, out.getLength());
+ try (DataOutputBuffer out = new DataOutputBuffer())
+ {
+ serializer.serialize(this, out, MessagingService.current_version);
+ return ByteBuffer.wrap(out.getData(), 0, out.getLength());
+ }
}
diff --git a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
index b41ac75b99..63ffb167cc 100644
--- a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
+++ b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
@@ -1795,6 +1795,7 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean
return repairedSSTables;
}
+ @SuppressWarnings("resource")
public RefViewFragment selectAndReference(Function> filter)
{
while (true)
@@ -1966,6 +1967,7 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean
*
* @param range The range of keys and columns within those keys to fetch
*/
+ @SuppressWarnings("resource")
private AbstractScanIterator getSequentialIterator(final DataRange range, long now)
{
assert !(range.keyRange() instanceof Range) || !((Range>)range.keyRange()).isWrapAround() || range.keyRange().right.isMinimum() : range.keyRange();
@@ -1980,24 +1982,27 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean
{
protected Row computeNext()
{
- // pull a row out of the iterator
- if (!iterator.hasNext())
- return endOfData();
+ while (true)
+ {
+ // pull a row out of the iterator
+ if (!iterator.hasNext())
+ return endOfData();
- Row current = iterator.next();
- DecoratedKey key = current.key;
+ Row current = iterator.next();
+ DecoratedKey key = current.key;
- if (!range.stopKey().isMinimum() && range.stopKey().compareTo(key) < 0)
- return endOfData();
+ if (!range.stopKey().isMinimum() && range.stopKey().compareTo(key) < 0)
+ return endOfData();
- // skipping outside of assigned range
- if (!range.contains(key))
- return computeNext();
+ // skipping outside of assigned range
+ if (!range.contains(key))
+ continue;
- if (logger.isTraceEnabled())
- logger.trace("scanned {}", metadata.getKeyValidator().getString(key.getKey()));
+ if (logger.isTraceEnabled())
+ logger.trace("scanned {}", metadata.getKeyValidator().getString(key.getKey()));
- return current;
+ return current;
+ }
}
public void close() throws IOException
diff --git a/src/java/org/apache/cassandra/db/Memtable.java b/src/java/org/apache/cassandra/db/Memtable.java
index 55b0bfe9a4..ccf92be84d 100644
--- a/src/java/org/apache/cassandra/db/Memtable.java
+++ b/src/java/org/apache/cassandra/db/Memtable.java
@@ -423,19 +423,21 @@ public class Memtable implements Comparable
private static int estimateRowOverhead(final int count)
{
// calculate row overhead
- final OpOrder.Group group = new OpOrder().start();
- int rowOverhead;
- MemtableAllocator allocator = MEMORY_POOL.newAllocator();
- ConcurrentNavigableMap rows = new ConcurrentSkipListMap<>();
- final Object val = new Object();
- for (int i = 0 ; i < count ; i++)
- rows.put(allocator.clone(new BufferDecoratedKey(new LongToken(i), ByteBufferUtil.EMPTY_BYTE_BUFFER), group), val);
- double avgSize = ObjectSizes.measureDeep(rows) / (double) count;
- rowOverhead = (int) ((avgSize - Math.floor(avgSize)) < 0.05 ? Math.floor(avgSize) : Math.ceil(avgSize));
- rowOverhead -= ObjectSizes.measureDeep(new LongToken(0));
- rowOverhead += AtomicBTreeColumns.EMPTY_SIZE;
- allocator.setDiscarding();
- allocator.setDiscarded();
- return rowOverhead;
+ try (final OpOrder.Group group = new OpOrder().start())
+ {
+ int rowOverhead;
+ MemtableAllocator allocator = MEMORY_POOL.newAllocator();
+ ConcurrentNavigableMap rows = new ConcurrentSkipListMap<>();
+ final Object val = new Object();
+ for (int i = 0; i < count; i++)
+ rows.put(allocator.clone(new BufferDecoratedKey(new LongToken(i), ByteBufferUtil.EMPTY_BYTE_BUFFER), group), val);
+ double avgSize = ObjectSizes.measureDeep(rows) / (double) count;
+ rowOverhead = (int) ((avgSize - Math.floor(avgSize)) < 0.05 ? Math.floor(avgSize) : Math.ceil(avgSize));
+ rowOverhead -= ObjectSizes.measureDeep(new LongToken(0));
+ rowOverhead += AtomicBTreeColumns.EMPTY_SIZE;
+ allocator.setDiscarding();
+ allocator.setDiscarded();
+ return rowOverhead;
+ }
}
}
diff --git a/src/java/org/apache/cassandra/db/MutationVerbHandler.java b/src/java/org/apache/cassandra/db/MutationVerbHandler.java
index 92bfdb5cf7..3baa93e927 100644
--- a/src/java/org/apache/cassandra/db/MutationVerbHandler.java
+++ b/src/java/org/apache/cassandra/db/MutationVerbHandler.java
@@ -59,18 +59,20 @@ public class MutationVerbHandler implements IVerbHandler
*/
private void forwardToLocalNodes(Mutation mutation, MessagingService.Verb verb, byte[] forwardBytes, InetAddress from) throws IOException
{
- DataInputStream in = new DataInputStream(new FastByteArrayInputStream(forwardBytes));
- int size = in.readInt();
-
- // tell the recipients who to send their ack to
- MessageOut message = new MessageOut<>(verb, mutation, Mutation.serializer).withParameter(Mutation.FORWARD_FROM, from.getAddress());
- // Send a message to each of the addresses on our Forward List
- for (int i = 0; i < size; i++)
+ try (DataInputStream in = new DataInputStream(new FastByteArrayInputStream(forwardBytes)))
{
- InetAddress address = CompactEndpointSerializationHelper.deserialize(in);
- int id = in.readInt();
- Tracing.trace("Enqueuing forwarded write to {}", address);
- MessagingService.instance().sendOneWay(message, id, address);
+ int size = in.readInt();
+
+ // tell the recipients who to send their ack to
+ MessageOut message = new MessageOut<>(verb, mutation, Mutation.serializer).withParameter(Mutation.FORWARD_FROM, from.getAddress());
+ // Send a message to each of the addresses on our Forward List
+ for (int i = 0; i < size; i++)
+ {
+ InetAddress address = CompactEndpointSerializationHelper.deserialize(in);
+ int id = in.readInt();
+ Tracing.trace("Enqueuing forwarded write to {}", address);
+ MessagingService.instance().sendOneWay(message, id, address);
+ }
}
}
}
diff --git a/src/java/org/apache/cassandra/db/RangeSliceReply.java b/src/java/org/apache/cassandra/db/RangeSliceReply.java
index 5964ea8be6..ed1f523a64 100644
--- a/src/java/org/apache/cassandra/db/RangeSliceReply.java
+++ b/src/java/org/apache/cassandra/db/RangeSliceReply.java
@@ -57,7 +57,10 @@ public class RangeSliceReply
public static RangeSliceReply read(byte[] body, int version) throws IOException
{
- return serializer.deserialize(new DataInputStream(new FastByteArrayInputStream(body)), version);
+ try (DataInputStream dis = new DataInputStream(new FastByteArrayInputStream(body)))
+ {
+ return serializer.deserialize(dis, version);
+ }
}
private static class RangeSliceReplySerializer implements IVersionedSerializer
diff --git a/src/java/org/apache/cassandra/db/SizeEstimatesRecorder.java b/src/java/org/apache/cassandra/db/SizeEstimatesRecorder.java
index b0c114a3be..c68109ce11 100644
--- a/src/java/org/apache/cassandra/db/SizeEstimatesRecorder.java
+++ b/src/java/org/apache/cassandra/db/SizeEstimatesRecorder.java
@@ -82,6 +82,7 @@ public class SizeEstimatesRecorder extends MigrationListener implements Runnable
}
}
+ @SuppressWarnings("resource")
private void recordSizeEstimates(ColumnFamilyStore table, Collection> localRanges)
{
// for each local primary range, estimate (crudely) mean partition size and partitions count.
@@ -90,22 +91,24 @@ public class SizeEstimatesRecorder extends MigrationListener implements Runnable
{
// filter sstables that have partitions in this range.
Refs refs = null;
- while (refs == null)
- {
- ColumnFamilyStore.ViewFragment view = table.select(table.viewFilter(Range.makeRowRange(range)));
- refs = Refs.tryRef(view.sstables);
- }
-
long partitionsCount, meanPartitionSize;
+
try
{
+ while (refs == null)
+ {
+ ColumnFamilyStore.ViewFragment view = table.select(table.viewFilter(Range.makeRowRange(range)));
+ refs = Refs.tryRef(view.sstables);
+ }
+
// calculate the estimates.
partitionsCount = estimatePartitionsCount(refs, range);
meanPartitionSize = estimateMeanPartitionSize(refs);
}
finally
{
- refs.release();
+ if (refs != null)
+ refs.release();
}
estimates.put(range, Pair.create(partitionsCount, meanPartitionSize));
diff --git a/src/java/org/apache/cassandra/db/SystemKeyspace.java b/src/java/org/apache/cassandra/db/SystemKeyspace.java
index 67a3162e0b..9956728aea 100644
--- a/src/java/org/apache/cassandra/db/SystemKeyspace.java
+++ b/src/java/org/apache/cassandra/db/SystemKeyspace.java
@@ -437,17 +437,16 @@ public final class SystemKeyspace
private static Map truncationAsMapEntry(ColumnFamilyStore cfs, long truncatedAt, ReplayPosition position)
{
- DataOutputBuffer out = new DataOutputBuffer();
- try
+ try (DataOutputBuffer out = new DataOutputBuffer())
{
ReplayPosition.serializer.serialize(position, out);
out.writeLong(truncatedAt);
+ return Collections.singletonMap(cfs.metadata.cfId, ByteBuffer.wrap(out.getData(), 0, out.getLength()));
}
catch (IOException e)
{
throw new RuntimeException(e);
}
- return Collections.singletonMap(cfs.metadata.cfId, ByteBuffer.wrap(out.getData(), 0, out.getLength()));
}
public static ReplayPosition getTruncatedPosition(UUID cfId)
@@ -1116,9 +1115,8 @@ public final class SystemKeyspace
private static ByteBuffer rangeToBytes(Range range)
{
- try
+ try (DataOutputBuffer out = new DataOutputBuffer())
{
- DataOutputBuffer out = new DataOutputBuffer();
Range.tokenSerializer.serialize(range, out, MessagingService.VERSION_22);
return out.buffer();
}
diff --git a/src/java/org/apache/cassandra/db/commitlog/CommitLog.java b/src/java/org/apache/cassandra/db/commitlog/CommitLog.java
index a8dda28d14..a81145d961 100644
--- a/src/java/org/apache/cassandra/db/commitlog/CommitLog.java
+++ b/src/java/org/apache/cassandra/db/commitlog/CommitLog.java
@@ -257,12 +257,10 @@ public class CommitLog implements CommitLogMBean
}
Allocation alloc = allocator.allocate(mutation, (int) totalSize);
- try
+ ICRC32 checksum = CRC32Factory.instance.create();
+ final ByteBuffer buffer = alloc.getBuffer();
+ try (BufferedDataOutputStreamPlus dos = new DataOutputBufferFixed(buffer))
{
- ICRC32 checksum = CRC32Factory.instance.create();
- final ByteBuffer buffer = alloc.getBuffer();
- BufferedDataOutputStreamPlus dos = new DataOutputBufferFixed(buffer);
-
// checksummed length
dos.writeInt((int) size);
checksum.update(buffer, buffer.position() - 4, 4);
diff --git a/src/java/org/apache/cassandra/db/commitlog/CommitLogArchiver.java b/src/java/org/apache/cassandra/db/commitlog/CommitLogArchiver.java
index 27abae3838..02072de6ab 100644
--- a/src/java/org/apache/cassandra/db/commitlog/CommitLogArchiver.java
+++ b/src/java/org/apache/cassandra/db/commitlog/CommitLogArchiver.java
@@ -63,11 +63,8 @@ public class CommitLogArchiver
public CommitLogArchiver()
{
Properties commitlog_commands = new Properties();
- InputStream stream = null;
- try
+ try (InputStream stream = getClass().getClassLoader().getResourceAsStream("commitlog_archiving.properties"))
{
- stream = getClass().getClassLoader().getResourceAsStream("commitlog_archiving.properties");
-
if (stream == null)
{
logger.debug("No commitlog_archiving properties found; archive + pitr will be disabled");
@@ -113,10 +110,7 @@ public class CommitLogArchiver
{
throw new RuntimeException("Unable to load commitlog_archiving.properties", e);
}
- finally
- {
- FileUtils.closeQuietly(stream);
- }
+
}
public void maybeArchive(final CommitLogSegment segment)
diff --git a/src/java/org/apache/cassandra/db/commitlog/CommitLogReplayer.java b/src/java/org/apache/cassandra/db/commitlog/CommitLogReplayer.java
index 6f9039d822..a59e70e8a4 100644
--- a/src/java/org/apache/cassandra/db/commitlog/CommitLogReplayer.java
+++ b/src/java/org/apache/cassandra/db/commitlog/CommitLogReplayer.java
@@ -268,6 +268,7 @@ public class CommitLogReplayer
}
}
+ @SuppressWarnings("resource")
public void recover(File file) throws IOException
{
CommitLogDescriptor desc = CommitLogDescriptor.fromFileName(file.getName());
@@ -340,6 +341,7 @@ public class CommitLogReplayer
FileDataInput sectionReader = reader;
if (compressor != null)
+ {
try
{
int start = (int) reader.getFilePointer();
@@ -363,6 +365,7 @@ public class CommitLogReplayer
logger.error("Unexpected exception decompressing section {}", e);
continue;
}
+ }
if (!replaySyncSection(sectionReader, replayEnd, desc))
break;
@@ -469,9 +472,9 @@ public class CommitLogReplayer
void replayMutation(byte[] inputBuffer, int size,
final long entryLocation, final CommitLogDescriptor desc) throws IOException
{
- FastByteArrayInputStream bufIn = new FastByteArrayInputStream(inputBuffer, 0, size);
+
final Mutation mutation;
- try
+ try (FastByteArrayInputStream bufIn = new FastByteArrayInputStream(inputBuffer, 0, size))
{
mutation = Mutation.serializer.deserialize(new DataInputStream(bufIn),
desc.getMessagingVersion(),
@@ -499,15 +502,12 @@ public class CommitLogReplayer
{
JVMStabilityInspector.inspectThrowable(t);
File f = File.createTempFile("mutation", "dat");
- DataOutputStream out = new DataOutputStream(new FileOutputStream(f));
- try
+
+ try (DataOutputStream out = new DataOutputStream(new FileOutputStream(f)))
{
out.write(inputBuffer, 0, size);
}
- finally
- {
- out.close();
- }
+
String st = String.format("Unexpected error deserializing mutation; saved to %s and ignored. This may be caused by replaying a mutation against a table with the same name but incompatible schema. Exception follows: ",
f.getAbsolutePath());
logger.error(st, t);
diff --git a/src/java/org/apache/cassandra/db/commitlog/CommitLogSegment.java b/src/java/org/apache/cassandra/db/commitlog/CommitLogSegment.java
index d04690dafb..ee160c3b1d 100644
--- a/src/java/org/apache/cassandra/db/commitlog/CommitLogSegment.java
+++ b/src/java/org/apache/cassandra/db/commitlog/CommitLogSegment.java
@@ -160,6 +160,7 @@ public abstract class CommitLogSegment
* Allocate space in this buffer for the provided mutation, and return the allocated Allocation object.
* Returns null if there is not enough space in this segment, and a new segment is needed.
*/
+ @SuppressWarnings("resource") //we pass the op order around
Allocation allocate(Mutation mutation, int size)
{
final OpOrder.Group opGroup = appendOrder.start();
diff --git a/src/java/org/apache/cassandra/db/compaction/AbstractCompactionStrategy.java b/src/java/org/apache/cassandra/db/compaction/AbstractCompactionStrategy.java
index 38107c0c1f..97e7041ebc 100644
--- a/src/java/org/apache/cassandra/db/compaction/AbstractCompactionStrategy.java
+++ b/src/java/org/apache/cassandra/db/compaction/AbstractCompactionStrategy.java
@@ -268,6 +268,7 @@ public abstract class AbstractCompactionStrategy
* allow for a more memory efficient solution if we know the sstable don't overlap (see
* LeveledCompactionStrategy for instance).
*/
+ @SuppressWarnings("resource")
public ScannerList getScanners(Collection sstables, Range range)
{
RateLimiter limiter = CompactionManager.instance.getRateLimiter();
diff --git a/src/java/org/apache/cassandra/db/compaction/CompactionManager.java b/src/java/org/apache/cassandra/db/compaction/CompactionManager.java
index 20793258b7..ffed554d5b 100644
--- a/src/java/org/apache/cassandra/db/compaction/CompactionManager.java
+++ b/src/java/org/apache/cassandra/db/compaction/CompactionManager.java
@@ -42,6 +42,7 @@ import javax.management.openmbean.OpenDataException;
import javax.management.openmbean.TabularData;
import com.google.common.base.Predicate;
+import com.google.common.base.Throwables;
import com.google.common.collect.*;
import com.google.common.util.concurrent.*;
import org.slf4j.Logger;
@@ -70,9 +71,11 @@ import org.apache.cassandra.metrics.CompactionMetrics;
import org.apache.cassandra.repair.Validator;
import org.apache.cassandra.service.ActiveRepairService;
import org.apache.cassandra.service.StorageService;
+import org.apache.cassandra.utils.CloseableIterator;
import org.apache.cassandra.utils.FBUtilities;
import org.apache.cassandra.utils.JVMStabilityInspector;
import org.apache.cassandra.utils.MerkleTree;
+import org.apache.cassandra.utils.Pair;
import org.apache.cassandra.utils.WrappedRunnable;
import org.apache.cassandra.utils.UUIDGen;
import org.apache.cassandra.utils.concurrent.OpOrder;
@@ -243,6 +246,7 @@ public class CompactionManager implements CompactionManagerMBean
}
}
+ @SuppressWarnings("resource")
private AllSSTableOpStatus parallelAllSSTableOperation(final ColumnFamilyStore cfs, final OneSSTableOperation operation, OperationType operationType) throws ExecutionException, InterruptedException
{
try (LifecycleTransaction compacting = cfs.markAllCompacting(operationType);)
@@ -259,7 +263,8 @@ public class CompactionManager implements CompactionManagerMBean
}
Iterable sstables = operation.filterSSTables(compacting.originals());
- List> futures = new ArrayList<>();
+ List>> futures = new ArrayList<>();
+
for (final SSTableReader sstable : sstables)
{
@@ -270,7 +275,7 @@ public class CompactionManager implements CompactionManagerMBean
}
final LifecycleTransaction txn = compacting.split(singleton(sstable));
- futures.add(executor.submit(new Callable |