This is an automated email from the ASF dual-hosted git repository.
dcapwell pushed a commit to branch cassandra-3.0
in repository https://gitbox.apache.org/repos/asf/cassandra.git
The following commit(s) were added to refs/heads/cassandra-3.0 by this push:
new db03460 stop_paranoid disk failure policy is ignored on
CorruptSSTableException after node is up
db03460 is described below
commit db034609554a3185c0808cc67e9f0c148cc912c4
Author: Stefan Miklosovic <[email protected]>
AuthorDate: Wed Jul 29 14:47:48 2020 -0700
stop_paranoid disk failure policy is ignored on CorruptSSTableException
after node is up
patch by Stefan Miklosovic; reviewed by David Capwell, Brandon Williams for
CASSANDRA-15191
---
CHANGES.txt | 1 +
.../AbstractLocalAwareExecutorService.java | 10 +-
.../org/apache/cassandra/db/ColumnFamilyStore.java | 8 +-
src/java/org/apache/cassandra/db/Directories.java | 3 +-
.../db/commitlog/CommitLogSegmentManager.java | 1 -
.../org/apache/cassandra/db/lifecycle/Tracker.java | 8 +
.../cassandra/io/sstable/format/SSTableReader.java | 6 +-
.../org/apache/cassandra/io/util/FileUtils.java | 2 +-
.../apache/cassandra/service/CassandraDaemon.java | 21 +-
.../cassandra/service/DefaultFSErrorHandler.java | 6 +-
.../cassandra/utils/JVMStabilityInspector.java | 30 +-
.../cassandra/distributed/impl/Instance.java | 4 +
...bilityInspectorCorruptSSTableExceptionTest.java | 205 ++++++
.../io/sstable/format/ForwardingSSTableReader.java | 766 +++++++++++++++++++++
.../org/apache/cassandra/db/DirectoriesTest.java | 3 +-
.../cassandra/utils/JVMStabilityInspectorTest.java | 14 +
16 files changed, 1045 insertions(+), 43 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index d22ba43..a755b7e 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
3.0.22:
+ * stop_paranoid disk failure policy is ignored on CorruptSSTableException
after node is up (CASSANDRA-15191)
* 3.x fails to start if commit log has range tombstones from a column which
is also deleted (CASSANDRA-15970)
* Forbid altering UDTs used in partition keys (CASSANDRA-15933)
* Fix empty/null json string representation (CASSANDRA-15896)
diff --git
a/src/java/org/apache/cassandra/concurrent/AbstractLocalAwareExecutorService.java
b/src/java/org/apache/cassandra/concurrent/AbstractLocalAwareExecutorService.java
index 4b1fe05..d666a36 100644
---
a/src/java/org/apache/cassandra/concurrent/AbstractLocalAwareExecutorService.java
+++
b/src/java/org/apache/cassandra/concurrent/AbstractLocalAwareExecutorService.java
@@ -29,9 +29,6 @@ import java.util.concurrent.TimeoutException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.apache.cassandra.io.FSError;
-import org.apache.cassandra.io.sstable.CorruptSSTableException;
-import org.apache.cassandra.io.util.FileUtils;
import org.apache.cassandra.utils.concurrent.SimpleCondition;
import org.apache.cassandra.utils.JVMStabilityInspector;
@@ -169,12 +166,7 @@ public abstract class AbstractLocalAwareExecutorService
implements LocalAwareExe
logger.error("Uncaught exception on thread {}",
Thread.currentThread(), t);
result = t;
failure = true;
- if (t instanceof CorruptSSTableException)
- FileUtils.handleCorruptSSTable((CorruptSSTableException)
t);
- else if (t instanceof FSError)
- FileUtils.handleFSError((FSError) t);
- else
- JVMStabilityInspector.inspectThrowable(t);
+ JVMStabilityInspector.inspectThrowable(t);
}
finally
{
diff --git a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
index 70c14c0..7de68f9 100644
--- a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
+++ b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
@@ -699,7 +699,7 @@ public class ColumnFamilyStore implements
ColumnFamilyStoreMBean
}
catch (IOException e)
{
- FileUtils.handleCorruptSSTable(new CorruptSSTableException(e,
entry.getKey().filenameFor(Component.STATS)));
+ JVMStabilityInspector.inspectThrowable(new
CorruptSSTableException(e, entry.getKey().filenameFor(Component.STATS)));
logger.error("Cannot read sstable {}; other IO error, skipping
table", entry, e);
continue;
}
@@ -729,19 +729,19 @@ public class ColumnFamilyStore implements
ColumnFamilyStoreMBean
}
catch (CorruptSSTableException ex)
{
- FileUtils.handleCorruptSSTable(ex);
+ JVMStabilityInspector.inspectThrowable(ex);
logger.error("Corrupt sstable {}; skipping table", entry, ex);
continue;
}
catch (FSError ex)
{
- FileUtils.handleFSError(ex);
+ JVMStabilityInspector.inspectThrowable(ex);
logger.error("Cannot read sstable {}; file system error,
skipping table", entry, ex);
continue;
}
catch (IOException ex)
{
- FileUtils.handleCorruptSSTable(new CorruptSSTableException(ex,
entry.getKey().filenameFor(Component.DATA)));
+ JVMStabilityInspector.inspectThrowable(new
CorruptSSTableException(ex, entry.getKey().filenameFor(Component.DATA)));
logger.error("Cannot read sstable {}; other IO error, skipping
table", entry, ex);
continue;
}
diff --git a/src/java/org/apache/cassandra/db/Directories.java
b/src/java/org/apache/cassandra/db/Directories.java
index 0f3b2b6..d169428 100644
--- a/src/java/org/apache/cassandra/db/Directories.java
+++ b/src/java/org/apache/cassandra/db/Directories.java
@@ -55,6 +55,7 @@ import org.apache.cassandra.io.util.FileUtils;
import org.apache.cassandra.io.sstable.*;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.cassandra.utils.FBUtilities;
+import org.apache.cassandra.utils.JVMStabilityInspector;
import org.apache.cassandra.utils.Pair;
/**
@@ -245,7 +246,7 @@ public class Directories
{
// don't just let the default exception handler do this, we
need the create loop to continue
logger.error("Failed to create {} directory", dir);
- FileUtils.handleFSError(e);
+ JVMStabilityInspector.inspectThrowable(e);
}
}
diff --git
a/src/java/org/apache/cassandra/db/commitlog/CommitLogSegmentManager.java
b/src/java/org/apache/cassandra/db/commitlog/CommitLogSegmentManager.java
index 7651d1c..c24aa12 100644
--- a/src/java/org/apache/cassandra/db/commitlog/CommitLogSegmentManager.java
+++ b/src/java/org/apache/cassandra/db/commitlog/CommitLogSegmentManager.java
@@ -161,7 +161,6 @@ public class CommitLogSegmentManager
}
catch (Throwable t)
{
- JVMStabilityInspector.inspectThrowable(t);
if (!CommitLog.handleCommitError("Failed managing
commit log segments", t))
return;
// sleep some arbitrary period to avoid spamming CL
diff --git a/src/java/org/apache/cassandra/db/lifecycle/Tracker.java
b/src/java/org/apache/cassandra/db/lifecycle/Tracker.java
index 9feaa3e..58c491c 100644
--- a/src/java/org/apache/cassandra/db/lifecycle/Tracker.java
+++ b/src/java/org/apache/cassandra/db/lifecycle/Tracker.java
@@ -486,4 +486,12 @@ public class Tracker
{
return view.get();
}
+
+ @VisibleForTesting
+ public void removeUnsafe(Set<SSTableReader> toRemove)
+ {
+ Pair<View, View> result = apply(view -> {
+ return updateLiveSet(toRemove, emptySet()).apply(view);
+ });
+ }
}
diff --git a/src/java/org/apache/cassandra/io/sstable/format/SSTableReader.java
b/src/java/org/apache/cassandra/io/sstable/format/SSTableReader.java
index 0ca1f3a..e7f9613 100644
--- a/src/java/org/apache/cassandra/io/sstable/format/SSTableReader.java
+++ b/src/java/org/apache/cassandra/io/sstable/format/SSTableReader.java
@@ -545,19 +545,19 @@ public abstract class SSTableReader extends SSTable
implements SelfRefCounted<SS
}
catch (CorruptSSTableException ex)
{
- FileUtils.handleCorruptSSTable(ex);
+ JVMStabilityInspector.inspectThrowable(ex);
logger.error("Corrupt sstable {}; skipping table",
entry, ex);
return;
}
catch (FSError ex)
{
- FileUtils.handleFSError(ex);
+ JVMStabilityInspector.inspectThrowable(ex);
logger.error("Cannot read sstable {}; file system
error, skipping table", entry, ex);
return;
}
catch (IOException ex)
{
- FileUtils.handleCorruptSSTable(new
CorruptSSTableException(ex, entry.getKey().filenameFor(Component.DATA)));
+ JVMStabilityInspector.inspectThrowable(new
CorruptSSTableException(ex, entry.getKey().filenameFor(Component.DATA)));
logger.error("Cannot read sstable {}; other IO error,
skipping table", entry, ex);
return;
}
diff --git a/src/java/org/apache/cassandra/io/util/FileUtils.java
b/src/java/org/apache/cassandra/io/util/FileUtils.java
index f9406e5..191e965 100644
--- a/src/java/org/apache/cassandra/io/util/FileUtils.java
+++ b/src/java/org/apache/cassandra/io/util/FileUtils.java
@@ -509,7 +509,7 @@ public final class FileUtils
*/
public static void handleFSErrorAndPropagate(FSError e)
{
- handleFSError(e);
+ JVMStabilityInspector.inspectThrowable(e);
throw propagate(e);
}
diff --git a/src/java/org/apache/cassandra/service/CassandraDaemon.java
b/src/java/org/apache/cassandra/service/CassandraDaemon.java
index 271f763..14d8aab 100644
--- a/src/java/org/apache/cassandra/service/CassandraDaemon.java
+++ b/src/java/org/apache/cassandra/service/CassandraDaemon.java
@@ -224,26 +224,15 @@ public class CassandraDaemon
public void uncaughtException(Thread t, Throwable e)
{
StorageMetrics.exceptions.inc();
- logger.error("Exception in thread " + t, e);
+ logger.error("Exception in thread {}", t, e);
Tracing.trace("Exception in thread {}", t, e);
for (Throwable e2 = e; e2 != null; e2 = e2.getCause())
{
- JVMStabilityInspector.inspectThrowable(e2);
-
- if (e2 instanceof FSError)
- {
- if (e2 != e) // make sure FSError gets logged exactly
once.
- logger.error("Exception in thread " + t, e2);
- FileUtils.handleFSError((FSError) e2);
- }
-
- if (e2 instanceof CorruptSSTableException)
- {
- if (e2 != e)
- logger.error("Exception in thread " + t, e2);
-
FileUtils.handleCorruptSSTable((CorruptSSTableException) e2);
- }
+ // make sure error gets logged exactly once.
+ if (e2 != e && (e2 instanceof FSError || e2 instanceof
CorruptSSTableException))
+ logger.error("Exception in thread {}", t, e2);
}
+ JVMStabilityInspector.inspectThrowable(e);
}
});
diff --git a/src/java/org/apache/cassandra/service/DefaultFSErrorHandler.java
b/src/java/org/apache/cassandra/service/DefaultFSErrorHandler.java
index 0413e0d..1c81f65 100644
--- a/src/java/org/apache/cassandra/service/DefaultFSErrorHandler.java
+++ b/src/java/org/apache/cassandra/service/DefaultFSErrorHandler.java
@@ -42,10 +42,11 @@ public class DefaultFSErrorHandler implements FSErrorHandler
if (!StorageService.instance.isSetupCompleted())
handleStartupFSError(e);
- JVMStabilityInspector.inspectThrowable(e);
switch (DatabaseDescriptor.getDiskFailurePolicy())
{
case stop_paranoid:
+ // exception not logged here on purpose as it is already logged
+ logger.error("Stopping transports as disk_failure_policy is "
+ DatabaseDescriptor.getDiskFailurePolicy());
StorageService.instance.stopTransports();
break;
}
@@ -57,11 +58,12 @@ public class DefaultFSErrorHandler implements FSErrorHandler
if (!StorageService.instance.isSetupCompleted())
handleStartupFSError(e);
- JVMStabilityInspector.inspectThrowable(e);
switch (DatabaseDescriptor.getDiskFailurePolicy())
{
case stop_paranoid:
case stop:
+ // exception not logged here on purpose as it is already logged
+ logger.error("Stopping transports as disk_failure_policy is "
+ DatabaseDescriptor.getDiskFailurePolicy());
StorageService.instance.stopTransports();
break;
case best_effort:
diff --git a/src/java/org/apache/cassandra/utils/JVMStabilityInspector.java
b/src/java/org/apache/cassandra/utils/JVMStabilityInspector.java
index 89ef129..b018e04 100644
--- a/src/java/org/apache/cassandra/utils/JVMStabilityInspector.java
+++ b/src/java/org/apache/cassandra/utils/JVMStabilityInspector.java
@@ -21,6 +21,7 @@ import java.io.FileNotFoundException;
import java.net.SocketException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
import com.google.common.annotations.VisibleForTesting;
@@ -32,6 +33,7 @@ import org.apache.cassandra.config.Config;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.io.FSError;
import org.apache.cassandra.io.sstable.CorruptSSTableException;
+import org.apache.cassandra.io.util.FileUtils;
import org.apache.cassandra.service.StorageService;
/**
@@ -55,6 +57,24 @@ public final class JVMStabilityInspector
*/
public static void inspectThrowable(Throwable t)
{
+ inspectThrowable(t, JVMStabilityInspector::inspectDiskError);
+ }
+
+ public static void inspectCommitLogThrowable(Throwable t)
+ {
+ inspectThrowable(t, JVMStabilityInspector::inspectCommitLogError);
+ }
+
+ private static void inspectDiskError(Throwable t)
+ {
+ if (t instanceof CorruptSSTableException)
+ FileUtils.handleCorruptSSTable((CorruptSSTableException) t);
+ else if (t instanceof FSError)
+ FileUtils.handleFSError((FSError) t);
+ }
+
+ public static void inspectThrowable(Throwable t, Consumer<Throwable> fn)
throws OutOfMemoryError
+ {
boolean isUnstable = false;
if (t instanceof OutOfMemoryError)
{
@@ -81,7 +101,9 @@ public final class JVMStabilityInspector
if (DatabaseDescriptor.getDiskFailurePolicy() ==
Config.DiskFailurePolicy.die)
if (t instanceof FSError || t instanceof CorruptSSTableException)
- isUnstable = true;
+ isUnstable = true;
+
+ fn.accept(t);
// Check for file handle exhaustion
if (t instanceof FileNotFoundException || t instanceof SocketException)
@@ -92,10 +114,10 @@ public final class JVMStabilityInspector
killer.killCurrentJVM(t);
if (t.getCause() != null)
- inspectThrowable(t.getCause());
+ inspectThrowable(t.getCause(), fn);
}
- public static void inspectCommitLogThrowable(Throwable t)
+ private static void inspectCommitLogError(Throwable t)
{
if (!StorageService.instance.isSetupCompleted())
{
@@ -103,8 +125,6 @@ public final class JVMStabilityInspector
killer.killCurrentJVM(t, true);
} else if (DatabaseDescriptor.getCommitFailurePolicy() ==
Config.CommitFailurePolicy.die)
killer.killCurrentJVM(t);
- else
- inspectThrowable(t);
}
public static void killCurrentJVM(Throwable t, boolean quiet)
diff --git
a/test/distributed/org/apache/cassandra/distributed/impl/Instance.java
b/test/distributed/org/apache/cassandra/distributed/impl/Instance.java
index 90e6787..8fa5966 100644
--- a/test/distributed/org/apache/cassandra/distributed/impl/Instance.java
+++ b/test/distributed/org/apache/cassandra/distributed/impl/Instance.java
@@ -83,6 +83,7 @@ import org.apache.cassandra.io.sstable.format.SSTableReader;
import org.apache.cassandra.io.util.DataInputBuffer;
import org.apache.cassandra.io.util.DataOutputBuffer;
import org.apache.cassandra.io.util.DataOutputPlus;
+import org.apache.cassandra.io.util.FileUtils;
import org.apache.cassandra.net.CompactEndpointSerializationHelper;
import org.apache.cassandra.net.IMessageSink;
import org.apache.cassandra.net.MessageIn;
@@ -91,6 +92,7 @@ import org.apache.cassandra.net.MessagingService;
import org.apache.cassandra.schema.LegacySchemaMigrator;
import org.apache.cassandra.service.CassandraDaemon;
import org.apache.cassandra.service.ClientState;
+import org.apache.cassandra.service.DefaultFSErrorHandler;
import org.apache.cassandra.service.PendingRangeCalculatorService;
import org.apache.cassandra.service.QueryState;
import org.apache.cassandra.service.StorageService;
@@ -504,6 +506,8 @@ public class Instance extends IsolatedExecutor implements
IInvokableInstance
sync(() -> {
try
{
+ FileUtils.setFSErrorHandler(new DefaultFSErrorHandler());
+
mkdirs();
assert
config.networkTopology().contains(config.broadcastAddress());
diff --git
a/test/distributed/org/apache/cassandra/distributed/test/JVMStabilityInspectorCorruptSSTableExceptionTest.java
b/test/distributed/org/apache/cassandra/distributed/test/JVMStabilityInspectorCorruptSSTableExceptionTest.java
new file mode 100644
index 0000000..98ca496
--- /dev/null
+++
b/test/distributed/org/apache/cassandra/distributed/test/JVMStabilityInspectorCorruptSSTableExceptionTest.java
@@ -0,0 +1,205 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.distributed.test;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.cassandra.config.Config.DiskFailurePolicy;
+import org.apache.cassandra.db.ColumnFamilyStore;
+import org.apache.cassandra.db.DecoratedKey;
+import org.apache.cassandra.db.Keyspace;
+import org.apache.cassandra.db.RowIndexEntry;
+import org.apache.cassandra.db.filter.ColumnFilter;
+import org.apache.cassandra.db.rows.SliceableUnfilteredRowIterator;
+import org.apache.cassandra.distributed.Cluster;
+import org.apache.cassandra.distributed.api.ConsistencyLevel;
+import org.apache.cassandra.distributed.api.IInvokableInstance;
+import
org.apache.cassandra.distributed.api.IIsolatedExecutor.SerializableCallable;
+import org.apache.cassandra.distributed.shared.AbstractBuilder;
+import org.apache.cassandra.distributed.shared.NetworkTopology;
+import org.apache.cassandra.gms.Gossiper;
+import org.apache.cassandra.io.sstable.CorruptSSTableException;
+import org.apache.cassandra.io.sstable.format.ForwardingSSTableReader;
+import org.apache.cassandra.io.sstable.format.SSTableReader;
+import org.apache.cassandra.io.sstable.format.SSTableReadsListener;
+import org.apache.cassandra.io.util.FileDataInput;
+import org.apache.cassandra.service.CassandraDaemon;
+import org.apache.cassandra.service.StorageService;
+
+import static org.apache.cassandra.distributed.api.Feature.GOSSIP;
+import static org.apache.cassandra.distributed.api.Feature.NATIVE_PROTOCOL;
+import static org.apache.cassandra.distributed.api.Feature.NETWORK;
+
+public class JVMStabilityInspectorCorruptSSTableExceptionTest extends
TestBaseImpl
+{
+ @Test
+ public void
testAbstractLocalAwareExecutorServiceOnIgnoredDiskFailurePolicy() throws
Exception
+ {
+ test(DiskFailurePolicy.ignore, true, true);
+ }
+
+ @Test
+ public void
testAbstractLocalAwareExecutorServiceOnStopParanoidDiskFailurePolicy() throws
Exception
+ {
+ test(DiskFailurePolicy.stop_paranoid, false, false);
+ }
+
+ private static void test(DiskFailurePolicy policy, boolean
expectNativeTransportRunning, boolean expectGossiperEnabled) throws Exception
+ {
+ String table = policy.name();
+ try (final Cluster cluster = init(getCluster(policy).start()))
+ {
+ IInvokableInstance node = cluster.get(1);
+ boolean[] setup = node.callOnInstance(() -> {
+ CassandraDaemon instanceForTesting =
CassandraDaemon.getInstanceForTesting();
+ instanceForTesting.completeSetup();
+ StorageService.instance.registerDaemon(instanceForTesting);
+ return new boolean[]{
StorageService.instance.isNativeTransportRunning(),
Gossiper.instance.isEnabled() };
+ });
+
+ // make sure environment is setup propertly
+ Assert.assertTrue("Native support is not running, test is not
ready!", setup[0]);
+ Assert.assertTrue("Gossiper is not running, test is not ready!",
setup[1]);
+
+ cluster.schemaChange("CREATE TABLE " + KEYSPACE + "." + table + "
(id bigint PRIMARY KEY)");
+ node.executeInternal("INSERT INTO " + KEYSPACE + "." + table + "
(id) VALUES (?)", 0L);
+ corruptTable(node, KEYSPACE, table);
+
+ try
+ {
+ cluster.coordinator(1).execute("SELECT * FROM " + KEYSPACE +
'.' + table + " WHERE id=?", ConsistencyLevel.ONE, 0L);
+ Assert.fail("Select should fail as we corrupted SSTable on
purpose.");
+ }
+ catch (final Exception ex)
+ {
+ // we expect that above query fails as we corrupted an sstable
+ }
+
+ waitForStop(!expectGossiperEnabled, node, new
SerializableCallable<Boolean>()
+ {
+ public Boolean call()
+ {
+ return Gossiper.instance.isEnabled();
+ }
+ });
+
+ waitForStop(!expectNativeTransportRunning, node, new
SerializableCallable<Boolean>()
+ {
+ public Boolean call()
+ {
+ return StorageService.instance.isNativeTransportRunning();
+ }
+ });
+ }
+ }
+
+ private static void waitForStop(boolean shouldWaitForStop,
+ IInvokableInstance node,
+ SerializableCallable<Boolean>
serializableCallable) throws Exception
+ {
+ int attempts = 3;
+ boolean running = true;
+
+ while (attempts > 0 && running)
+ {
+ try
+ {
+ running = node.callOnInstance(serializableCallable);
+ attempts--;
+ }
+ catch (final NoClassDefFoundError ex)
+ {
+ // gossiper throws this
+ Assert.assertEquals("Could not initialize class
org.apache.cassandra.service.StorageService", ex.getMessage());
+ running = false;
+ }
+ catch (final ExceptionInInitializerError ex)
+ {
+ // native thows this, ignore on purpose, this means that
native transport is closed.
+ running = false;
+ }
+
+ Thread.sleep(5000);
+ }
+
+ if (shouldWaitForStop && running)
+ {
+ Assert.fail("we did want a service to stop, but it did not.");
+ }
+
+ if (!shouldWaitForStop && !running)
+ {
+ Assert.fail("we did not want a service to stop, but it did.");
+ }
+ }
+
+ private static void corruptTable(IInvokableInstance node, String keyspace,
String table)
+ {
+ node.runOnInstance(() -> {
+ ColumnFamilyStore cf =
Keyspace.open(keyspace).getColumnFamilyStore(table);
+ cf.forceBlockingFlush();
+
+ Set<SSTableReader> remove = cf.getLiveSSTables();
+ Set<SSTableReader> replace = new HashSet<>();
+ for (SSTableReader r : remove)
+ replace.add(new CorruptedSSTableReader(r));
+
+ cf.getTracker().removeUnsafe(remove);
+ cf.addSSTables(replace);
+ });
+ }
+
+ private static AbstractBuilder<IInvokableInstance, Cluster,
Cluster.Builder> getCluster(DiskFailurePolicy diskFailurePolicy)
+ {
+ return Cluster.build()
+
.withNodeIdTopology(NetworkTopology.singleDcNetworkTopology(1, "dc0", "rack0"))
+ .withConfig(config -> config.with(NETWORK, GOSSIP,
NATIVE_PROTOCOL)
+ .set("disk_failure_policy",
diskFailurePolicy.name()));
+ }
+
+ private static final class CorruptedSSTableReader extends
ForwardingSSTableReader
+ {
+ public CorruptedSSTableReader(SSTableReader delegate)
+ {
+ super(delegate);
+ }
+
+ @Override
+ public SliceableUnfilteredRowIterator iterator(DecoratedKey key,
ColumnFilter selectedColumns, boolean reversed, boolean isForThrift,
SSTableReadsListener listener)
+ {
+ throw throwCorrupted();
+ }
+
+ @Override
+ public SliceableUnfilteredRowIterator iterator(FileDataInput file,
DecoratedKey key, RowIndexEntry indexEntry, ColumnFilter selectedColumns,
boolean reversed, boolean isForThrift)
+ {
+ throw throwCorrupted();
+ }
+
+ private CorruptSSTableException throwCorrupted()
+ {
+ throw new CorruptSSTableException(new IOException("failed to get
position"), descriptor.baseFilename());
+ }
+ }
+}
\ No newline at end of file
diff --git
a/test/distributed/org/apache/cassandra/io/sstable/format/ForwardingSSTableReader.java
b/test/distributed/org/apache/cassandra/io/sstable/format/ForwardingSSTableReader.java
new file mode 100644
index 0000000..bd92ca0
--- /dev/null
+++
b/test/distributed/org/apache/cassandra/io/sstable/format/ForwardingSSTableReader.java
@@ -0,0 +1,766 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.io.sstable.format;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import com.google.common.util.concurrent.RateLimiter;
+
+import org.apache.cassandra.cache.InstrumentingCache;
+import org.apache.cassandra.cache.KeyCacheKey;
+import org.apache.cassandra.db.ColumnFamilyStore;
+import org.apache.cassandra.db.DataRange;
+import org.apache.cassandra.db.DecoratedKey;
+import org.apache.cassandra.db.PartitionPosition;
+import org.apache.cassandra.db.RowIndexEntry;
+import org.apache.cassandra.db.filter.ColumnFilter;
+import org.apache.cassandra.db.rows.SliceableUnfilteredRowIterator;
+import org.apache.cassandra.dht.AbstractBounds;
+import org.apache.cassandra.dht.IPartitioner;
+import org.apache.cassandra.dht.Range;
+import org.apache.cassandra.dht.Token;
+import org.apache.cassandra.io.compress.CompressionMetadata;
+import org.apache.cassandra.io.sstable.Component;
+import org.apache.cassandra.io.sstable.ISSTableScanner;
+import org.apache.cassandra.io.sstable.SSTable;
+import org.apache.cassandra.io.sstable.metadata.StatsMetadata;
+import org.apache.cassandra.io.util.ChannelProxy;
+import org.apache.cassandra.io.util.FileDataInput;
+import org.apache.cassandra.io.util.RandomAccessReader;
+import org.apache.cassandra.io.util.SegmentedFile;
+import org.apache.cassandra.metrics.RestorableMeter;
+import org.apache.cassandra.utils.EstimatedHistogram;
+import org.apache.cassandra.utils.IFilter;
+import org.apache.cassandra.utils.Pair;
+import org.apache.cassandra.utils.concurrent.Ref;
+
+public abstract class ForwardingSSTableReader extends SSTableReader
+{
+ // This method is only accessiable via extension and not for calling
directly;
+ // to work around this, rely on reflection if the method gets called
+ private static final Method ESTIMATE_ROWS_FROM_INDEX;
+ static {
+ try
+ {
+ Method m =
SSTable.class.getDeclaredMethod("estimateRowsFromIndex",
RandomAccessReader.class);
+ m.setAccessible(true);
+ ESTIMATE_ROWS_FROM_INDEX = m;
+ }
+ catch (NoSuchMethodException e)
+ {
+ throw new AssertionError(e);
+ }
+ }
+
+ private final SSTableReader delegate;
+
+ public ForwardingSSTableReader(SSTableReader delegate)
+ {
+ super(delegate.descriptor, SSTable.componentsFor(delegate.descriptor),
+ delegate.metadata, delegate.maxDataAge,
delegate.getSSTableMetadata(),
+ delegate.openReason, delegate.header);
+ this.delegate = delegate;
+ this.first = delegate.first;
+ this.last = delegate.last;
+ }
+
+ @Override
+ public boolean equals(Object that)
+ {
+ return delegate.equals(that);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return delegate.hashCode();
+ }
+
+ @Override
+ public String getFilename()
+ {
+ return delegate.getFilename();
+ }
+
+ @Override
+ public void setupOnline()
+ {
+ delegate.setupOnline();
+ }
+
+ @Override
+ public boolean isKeyCacheSetup()
+ {
+ return delegate.isKeyCacheSetup();
+ }
+
+ @Override
+ public boolean loadSummary(SegmentedFile.Builder ibuilder,
SegmentedFile.Builder dbuilder)
+ {
+ return delegate.loadSummary(ibuilder, dbuilder);
+ }
+
+ @Override
+ public void saveSummary(SegmentedFile.Builder ibuilder,
SegmentedFile.Builder dbuilder)
+ {
+ delegate.saveSummary(ibuilder, dbuilder);
+ }
+
+ @Override
+ public void saveBloomFilter()
+ {
+ delegate.saveBloomFilter();
+ }
+
+ @Override
+ public void setReplaced()
+ {
+ delegate.setReplaced();
+ }
+
+ @Override
+ public boolean isReplaced()
+ {
+ return delegate.isReplaced();
+ }
+
+ @Override
+ public void runOnClose(Runnable runOnClose)
+ {
+ delegate.runOnClose(runOnClose);
+ }
+
+ @Override
+ public SSTableReader cloneWithRestoredStart(DecoratedKey restoredStart)
+ {
+ return delegate.cloneWithRestoredStart(restoredStart);
+ }
+
+ @Override
+ public SSTableReader cloneWithNewStart(DecoratedKey newStart, Runnable
runOnClose)
+ {
+ return delegate.cloneWithNewStart(newStart, runOnClose);
+ }
+
+ @Override
+ public SSTableReader cloneWithNewSummarySamplingLevel(ColumnFamilyStore
parent, int samplingLevel) throws IOException
+ {
+ return delegate.cloneWithNewSummarySamplingLevel(parent,
samplingLevel);
+ }
+
+ @Override
+ public RestorableMeter getReadMeter()
+ {
+ return delegate.getReadMeter();
+ }
+
+ @Override
+ public int getIndexSummarySamplingLevel()
+ {
+ return delegate.getIndexSummarySamplingLevel();
+ }
+
+ @Override
+ public long getIndexSummaryOffHeapSize()
+ {
+ return delegate.getIndexSummaryOffHeapSize();
+ }
+
+ @Override
+ public int getMinIndexInterval()
+ {
+ return delegate.getMinIndexInterval();
+ }
+
+ @Override
+ public double getEffectiveIndexInterval()
+ {
+ return delegate.getEffectiveIndexInterval();
+ }
+
+ @Override
+ public void releaseSummary()
+ {
+ delegate.releaseSummary();
+ }
+
+ @Override
+ public long getIndexScanPosition(PartitionPosition key)
+ {
+ return delegate.getIndexScanPosition(key);
+ }
+
+ @Override
+ public CompressionMetadata getCompressionMetadata()
+ {
+ return delegate.getCompressionMetadata();
+ }
+
+ @Override
+ public long getCompressionMetadataOffHeapSize()
+ {
+ return delegate.getCompressionMetadataOffHeapSize();
+ }
+
+ @Override
+ public void forceFilterFailures()
+ {
+ delegate.forceFilterFailures();
+ }
+
+ @Override
+ public IFilter getBloomFilter()
+ {
+ return delegate.getBloomFilter();
+ }
+
+ @Override
+ public long getBloomFilterSerializedSize()
+ {
+ return delegate.getBloomFilterSerializedSize();
+ }
+
+ @Override
+ public long getBloomFilterOffHeapSize()
+ {
+ return delegate.getBloomFilterOffHeapSize();
+ }
+
+ @Override
+ public long estimatedKeys()
+ {
+ return delegate.estimatedKeys();
+ }
+
+ @Override
+ public long estimatedKeysForRanges(Collection<Range<Token>> ranges)
+ {
+ return delegate.estimatedKeysForRanges(ranges);
+ }
+
+ @Override
+ public int getIndexSummarySize()
+ {
+ return delegate.getIndexSummarySize();
+ }
+
+ @Override
+ public int getMaxIndexSummarySize()
+ {
+ return delegate.getMaxIndexSummarySize();
+ }
+
+ @Override
+ public byte[] getIndexSummaryKey(int index)
+ {
+ return delegate.getIndexSummaryKey(index);
+ }
+
+ @Override
+ public Iterable<DecoratedKey> getKeySamples(Range<Token> range)
+ {
+ return delegate.getKeySamples(range);
+ }
+
+ @Override
+ public List<Pair<Long, Long>>
getPositionsForRanges(Collection<Range<Token>> ranges)
+ {
+ return delegate.getPositionsForRanges(ranges);
+ }
+
+ @Override
+ public KeyCacheKey getCacheKey(DecoratedKey key)
+ {
+ return delegate.getCacheKey(key);
+ }
+
+ @Override
+ public void cacheKey(DecoratedKey key, RowIndexEntry info)
+ {
+ delegate.cacheKey(key, info);
+ }
+
+ @Override
+ public RowIndexEntry getCachedPosition(DecoratedKey key, boolean
updateStats)
+ {
+ return delegate.getCachedPosition(key, updateStats);
+ }
+
+ @Override
+ protected RowIndexEntry getCachedPosition(KeyCacheKey unifiedKey, boolean
updateStats)
+ {
+ return delegate.getCachedPosition(unifiedKey, updateStats);
+ }
+
+ @Override
+ protected RowIndexEntry getPosition(PartitionPosition key, Operator op,
boolean updateCacheAndStats, boolean permitMatchPastLast, SSTableReadsListener
listener)
+ {
+ return delegate.getPosition(key, op, updateCacheAndStats,
permitMatchPastLast, listener);
+ }
+
+ @Override
+ public SliceableUnfilteredRowIterator iterator(DecoratedKey key,
ColumnFilter selectedColumns, boolean reversed, boolean isForThrift,
SSTableReadsListener listener)
+ {
+ return delegate.iterator(key, selectedColumns, reversed, isForThrift,
listener);
+ }
+
+ @Override
+ public SliceableUnfilteredRowIterator iterator(FileDataInput file,
DecoratedKey key, RowIndexEntry indexEntry, ColumnFilter selectedColumns,
boolean reversed, boolean isForThrift)
+ {
+ return delegate.iterator(file, key, indexEntry, selectedColumns,
reversed, isForThrift);
+ }
+
+ @Override
+ public DecoratedKey firstKeyBeyond(PartitionPosition token)
+ {
+ return delegate.firstKeyBeyond(token);
+ }
+
+ @Override
+ public long uncompressedLength()
+ {
+ return delegate.uncompressedLength();
+ }
+
+ @Override
+ public long onDiskLength()
+ {
+ return delegate.onDiskLength();
+ }
+
+ @Override
+ public double getCrcCheckChance()
+ {
+ return delegate.getCrcCheckChance();
+ }
+
+ @Override
+ public void setCrcCheckChance(double crcCheckChance)
+ {
+ delegate.setCrcCheckChance(crcCheckChance);
+ }
+
+ @Override
+ public void markObsolete(Runnable tidier)
+ {
+ delegate.markObsolete(tidier);
+ }
+
+ @Override
+ public boolean isMarkedCompacted()
+ {
+ return delegate.isMarkedCompacted();
+ }
+
+ @Override
+ public void markSuspect()
+ {
+ delegate.markSuspect();
+ }
+
+ @Override
+ public boolean isMarkedSuspect()
+ {
+ return delegate.isMarkedSuspect();
+ }
+
+ @Override
+ public ISSTableScanner getScanner()
+ {
+ return delegate.getScanner();
+ }
+
+ @Override
+ public ISSTableScanner getScanner(ColumnFilter columns, DataRange
dataRange, boolean isForThrift, SSTableReadsListener listener)
+ {
+ return delegate.getScanner(columns, dataRange, isForThrift, listener);
+ }
+
+ @Override
+ public ISSTableScanner getScanner(Range<Token> range, RateLimiter limiter)
+ {
+ return delegate.getScanner(range, limiter);
+ }
+
+ @Override
+ public ISSTableScanner getScanner(RateLimiter limiter)
+ {
+ return delegate.getScanner(limiter);
+ }
+
+ @Override
+ public ISSTableScanner getScanner(Collection<Range<Token>> ranges,
RateLimiter limiter)
+ {
+ return delegate.getScanner(ranges, limiter);
+ }
+
+ @Override
+ public ISSTableScanner
getScanner(Iterator<AbstractBounds<PartitionPosition>> rangeIterator)
+ {
+ return delegate.getScanner(rangeIterator);
+ }
+
+ @Override
+ public ISSTableScanner getScanner(ColumnFilter columns, DataRange
dataRange, RateLimiter limiter, boolean isForThrift, SSTableReadsListener
listener)
+ {
+ return delegate.getScanner(columns, dataRange, limiter, isForThrift,
listener);
+ }
+
+ @Override
+ public FileDataInput getFileDataInput(long position)
+ {
+ return delegate.getFileDataInput(position);
+ }
+
+ @Override
+ public boolean newSince(long age)
+ {
+ return delegate.newSince(age);
+ }
+
+ @Override
+ public void createLinks(String snapshotDirectoryPath)
+ {
+ delegate.createLinks(snapshotDirectoryPath);
+ }
+
+ @Override
+ public boolean isRepaired()
+ {
+ return delegate.isRepaired();
+ }
+
+ @Override
+ public long getBloomFilterFalsePositiveCount()
+ {
+ return delegate.getBloomFilterFalsePositiveCount();
+ }
+
+ @Override
+ public long getRecentBloomFilterFalsePositiveCount()
+ {
+ return delegate.getRecentBloomFilterFalsePositiveCount();
+ }
+
+ @Override
+ public long getBloomFilterTruePositiveCount()
+ {
+ return delegate.getBloomFilterTruePositiveCount();
+ }
+
+ @Override
+ public long getRecentBloomFilterTruePositiveCount()
+ {
+ return delegate.getRecentBloomFilterTruePositiveCount();
+ }
+
+ @Override
+ public InstrumentingCache<KeyCacheKey, RowIndexEntry> getKeyCache()
+ {
+ return delegate.getKeyCache();
+ }
+
+ @Override
+ public EstimatedHistogram getEstimatedPartitionSize()
+ {
+ return delegate.getEstimatedPartitionSize();
+ }
+
+ @Override
+ public EstimatedHistogram getEstimatedColumnCount()
+ {
+ return delegate.getEstimatedColumnCount();
+ }
+
+ @Override
+ public double getEstimatedDroppableTombstoneRatio(int gcBefore)
+ {
+ return delegate.getEstimatedDroppableTombstoneRatio(gcBefore);
+ }
+
+ @Override
+ public double getDroppableTombstonesBefore(int gcBefore)
+ {
+ return delegate.getDroppableTombstonesBefore(gcBefore);
+ }
+
+ @Override
+ public double getCompressionRatio()
+ {
+ return delegate.getCompressionRatio();
+ }
+
+ @Override
+ public long getMinTimestamp()
+ {
+ return delegate.getMinTimestamp();
+ }
+
+ @Override
+ public long getMaxTimestamp()
+ {
+ return delegate.getMaxTimestamp();
+ }
+
+ @Override
+ public int getMinLocalDeletionTime()
+ {
+ return delegate.getMinLocalDeletionTime();
+ }
+
+ @Override
+ public int getMaxLocalDeletionTime()
+ {
+ return delegate.getMaxLocalDeletionTime();
+ }
+
+ @Override
+ public boolean hasTombstones()
+ {
+ return delegate.hasTombstones();
+ }
+
+ @Override
+ public int getMinTTL()
+ {
+ return delegate.getMinTTL();
+ }
+
+ @Override
+ public int getMaxTTL()
+ {
+ return delegate.getMaxTTL();
+ }
+
+ @Override
+ public long getTotalColumnsSet()
+ {
+ return delegate.getTotalColumnsSet();
+ }
+
+ @Override
+ public long getTotalRows()
+ {
+ return delegate.getTotalRows();
+ }
+
+ @Override
+ public int getAvgColumnSetPerRow()
+ {
+ return delegate.getAvgColumnSetPerRow();
+ }
+
+ @Override
+ public int getSSTableLevel()
+ {
+ return delegate.getSSTableLevel();
+ }
+
+ @Override
+ public void reloadSSTableMetadata() throws IOException
+ {
+ delegate.reloadSSTableMetadata();
+ }
+
+ @Override
+ public StatsMetadata getSSTableMetadata()
+ {
+ return delegate.getSSTableMetadata();
+ }
+
+ @Override
+ public RandomAccessReader openDataReader(RateLimiter limiter)
+ {
+ return delegate.openDataReader(limiter);
+ }
+
+ @Override
+ public RandomAccessReader openDataReader()
+ {
+ return delegate.openDataReader();
+ }
+
+ @Override
+ public RandomAccessReader openIndexReader()
+ {
+ return delegate.openIndexReader();
+ }
+
+ @Override
+ public ChannelProxy getDataChannel()
+ {
+ return delegate.getDataChannel();
+ }
+
+ @Override
+ public ChannelProxy getIndexChannel()
+ {
+ return delegate.getIndexChannel();
+ }
+
+ @Override
+ public long getCreationTimeFor(Component component)
+ {
+ return delegate.getCreationTimeFor(component);
+ }
+
+ @Override
+ public long getKeyCacheHit()
+ {
+ return delegate.getKeyCacheHit();
+ }
+
+ @Override
+ public long getKeyCacheRequest()
+ {
+ return delegate.getKeyCacheRequest();
+ }
+
+ @Override
+ public void incrementReadCount()
+ {
+ delegate.incrementReadCount();
+ }
+
+ @Override
+ public boolean mayOverlapsWith(SSTableReader other)
+ {
+ return delegate.mayOverlapsWith(other);
+ }
+
+ @Override
+ public Ref<SSTableReader> tryRef()
+ {
+ return delegate.tryRef();
+ }
+
+ @Override
+ public Ref<SSTableReader> selfRef()
+ {
+ return delegate.selfRef();
+ }
+
+ @Override
+ public Ref<SSTableReader> ref()
+ {
+ return delegate.ref();
+ }
+
+ @Override
+ void setup(boolean trackHotness)
+ {
+ delegate.setup(trackHotness);
+ }
+
+ @Override
+ public void overrideReadMeter(RestorableMeter readMeter)
+ {
+ delegate.overrideReadMeter(readMeter);
+ }
+
+ @Override
+ public void addTo(Ref.IdentityCollection identities)
+ {
+ delegate.addTo(identities);
+ }
+
+ @Override
+ public IPartitioner getPartitioner()
+ {
+ return delegate.getPartitioner();
+ }
+
+ @Override
+ public DecoratedKey decorateKey(ByteBuffer key)
+ {
+ return delegate.decorateKey(key);
+ }
+
+ @Override
+ public String getIndexFilename()
+ {
+ return delegate.getIndexFilename();
+ }
+
+ @Override
+ public String getColumnFamilyName()
+ {
+ return delegate.getColumnFamilyName();
+ }
+
+ @Override
+ public String getKeyspaceName()
+ {
+ return delegate.getKeyspaceName();
+ }
+
+ @Override
+ public List<String> getAllFilePaths()
+ {
+ return delegate.getAllFilePaths();
+ }
+
+ @Override
+ protected long estimateRowsFromIndex(RandomAccessReader ifile) throws
IOException
+ {
+ try
+ {
+ return (Long) ESTIMATE_ROWS_FROM_INDEX.invoke(delegate, ifile);
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new AssertionError(e);
+ }
+ catch (InvocationTargetException e)
+ {
+ Throwable cause = e.getCause();
+ if (cause instanceof IOException)
+ throw (IOException) cause;
+ if (cause instanceof Error)
+ throw (Error) cause;
+ if (cause instanceof RuntimeException)
+ throw (RuntimeException) cause;
+ throw new RuntimeException(cause);
+ }
+ }
+
+ @Override
+ public long bytesOnDisk()
+ {
+ return delegate.bytesOnDisk();
+ }
+
+ @Override
+ public String toString()
+ {
+ return delegate.toString();
+ }
+
+ @Override
+ public synchronized void addComponents(Collection<Component> newComponents)
+ {
+ delegate.addComponents(newComponents);
+ }
+}
\ No newline at end of file
diff --git a/test/unit/org/apache/cassandra/db/DirectoriesTest.java
b/test/unit/org/apache/cassandra/db/DirectoriesTest.java
index 5ef001a..5cdfa0f 100644
--- a/test/unit/org/apache/cassandra/db/DirectoriesTest.java
+++ b/test/unit/org/apache/cassandra/db/DirectoriesTest.java
@@ -48,6 +48,7 @@ import org.apache.cassandra.io.util.FileUtils;
import org.apache.cassandra.schema.IndexMetadata;
import org.apache.cassandra.service.DefaultFSErrorHandler;
import org.apache.cassandra.utils.ByteBufferUtil;
+import org.apache.cassandra.utils.JVMStabilityInspector;
import org.apache.cassandra.utils.Pair;
import static org.junit.Assert.assertEquals;
@@ -332,7 +333,7 @@ public class DirectoriesTest
{
String[] path = new String[] {KS, "bad"};
File dir = new File(Directories.dataDirectories[0].location,
StringUtils.join(path, File.separator));
- FileUtils.handleFSError(new FSWriteError(new
IOException("Unable to create directory " + dir), dir));
+ JVMStabilityInspector.inspectThrowable(new FSWriteError(new
IOException("Unable to create directory " + dir), dir));
}
for (DataDirectory dd : Directories.dataDirectories)
diff --git
a/test/unit/org/apache/cassandra/utils/JVMStabilityInspectorTest.java
b/test/unit/org/apache/cassandra/utils/JVMStabilityInspectorTest.java
index 00447da..ecb2955 100644
--- a/test/unit/org/apache/cassandra/utils/JVMStabilityInspectorTest.java
+++ b/test/unit/org/apache/cassandra/utils/JVMStabilityInspectorTest.java
@@ -26,6 +26,8 @@ import org.junit.Test;
import org.apache.cassandra.config.Config;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.io.FSReadError;
+import org.apache.cassandra.io.FSWriteError;
+import org.apache.cassandra.io.sstable.CorruptSSTableException;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertFalse;
@@ -53,6 +55,18 @@ public class JVMStabilityInspectorTest
JVMStabilityInspector.inspectThrowable(new FSReadError(new
IOException(), "blah"));
assertTrue(killerForTests.wasKilled());
+ killerForTests.reset();
+ JVMStabilityInspector.inspectThrowable(new FSWriteError(new
IOException(), "blah"));
+ assertTrue(killerForTests.wasKilled());
+
+ killerForTests.reset();
+ JVMStabilityInspector.inspectThrowable(new
CorruptSSTableException(new IOException(), "blah"));
+ assertTrue(killerForTests.wasKilled());
+
+ killerForTests.reset();
+ JVMStabilityInspector.inspectThrowable(new RuntimeException(new
CorruptSSTableException(new IOException(), "blah")));
+ assertTrue(killerForTests.wasKilled());
+
DatabaseDescriptor.setCommitFailurePolicy(Config.CommitFailurePolicy.die);
killerForTests.reset();
JVMStabilityInspector.inspectCommitLogThrowable(new Throwable());
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]