mirror of https://github.com/apache/cassandra
sstablescrub unit test hardening and docs
Patch by Berenguer Blasi, reviewed by brandonwilliams for CASSANDRA-16013
This commit is contained in:
parent
67f0c3491a
commit
a04ccf3297
|
|
@ -29,6 +29,13 @@ sstablescrub <options> <keyspace> <table>
|
|||
|
||||
=================================== ================================================================================
|
||||
--debug display stack traces
|
||||
-e,--header-fix <arg> Option whether and how to perform a check of the sstable serialization-headers and fix , fixable issues.
|
||||
Possible argument values:
|
||||
- validate-only: validate the serialization-headers, but do not fix those. Do not continue with scrub - i.e. only validate the header (dry-run of fix-only).
|
||||
- validate: (default) validate the serialization-headers, but do not fix those and only continue with scrub if no error were detected.
|
||||
- fix-only: validate and fix the serialization-headers, don't continue with scrub.
|
||||
- fix: validate and fix the serialization-headers, do not fix and do not continue with scrub if the serialization-header check encountered errors.
|
||||
- off: don't perform the serialization-header checks.
|
||||
-h,--help display this help message
|
||||
-m,--manifest-check only check and repair the leveled manifest, without actually scrubbing the sstables
|
||||
-n,--no-validate do not validate columns using column validator
|
||||
|
|
|
|||
|
|
@ -20,29 +20,41 @@ package org.apache.cassandra.tools;
|
|||
|
||||
import java.io.File;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.commons.cli.*;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.CommandLineParser;
|
||||
import org.apache.commons.cli.GnuParser;
|
||||
import org.apache.commons.cli.HelpFormatter;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
|
||||
import org.apache.cassandra.schema.Schema;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.db.ColumnFamilyStore;
|
||||
import org.apache.cassandra.db.Directories;
|
||||
import org.apache.cassandra.db.Keyspace;
|
||||
import org.apache.cassandra.db.compaction.*;
|
||||
import org.apache.cassandra.db.compaction.AbstractStrategyHolder;
|
||||
import org.apache.cassandra.db.compaction.CompactionManager;
|
||||
import org.apache.cassandra.db.compaction.CompactionStrategyManager;
|
||||
import org.apache.cassandra.db.compaction.LeveledCompactionStrategy;
|
||||
import org.apache.cassandra.db.compaction.LeveledManifest;
|
||||
import org.apache.cassandra.db.compaction.OperationType;
|
||||
import org.apache.cassandra.db.compaction.Scrubber;
|
||||
import org.apache.cassandra.db.lifecycle.LifecycleTransaction;
|
||||
import org.apache.cassandra.io.sstable.Component;
|
||||
import org.apache.cassandra.io.sstable.Descriptor;
|
||||
import org.apache.cassandra.io.sstable.SSTableHeaderFix;
|
||||
import org.apache.cassandra.io.sstable.format.SSTableReader;
|
||||
import org.apache.cassandra.io.sstable.*;
|
||||
import org.apache.cassandra.schema.Schema;
|
||||
import org.apache.cassandra.tools.BulkLoader.CmdLineOptions;
|
||||
import org.apache.cassandra.utils.JVMStabilityInspector;
|
||||
import org.apache.cassandra.utils.OutputHandler;
|
||||
import org.apache.cassandra.utils.Pair;
|
||||
|
||||
import static org.apache.cassandra.tools.BulkLoader.CmdLineOptions;
|
||||
|
||||
public class StandaloneScrubber
|
||||
{
|
||||
public static final String REINSERT_OVERFLOWED_TTL_OPTION_DESCRIPTION = "Rewrites rows with overflowed expiration date affected by CASSANDRA-14092 with " +
|
||||
|
|
@ -64,7 +76,11 @@ public class StandaloneScrubber
|
|||
public static void main(String args[])
|
||||
{
|
||||
Options options = Options.parseArgs(args);
|
||||
Util.initDatabaseDescriptor();
|
||||
|
||||
if (Boolean.getBoolean(Util.ALLOW_TOOL_REINIT_FOR_TEST))
|
||||
DatabaseDescriptor.toolInitialization(false); //Necessary for testing
|
||||
else
|
||||
Util.initDatabaseDescriptor();
|
||||
|
||||
try
|
||||
{
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ import com.google.common.collect.Lists;
|
|||
@SuppressWarnings("serial")
|
||||
public final class Util
|
||||
{
|
||||
static final String ALLOW_TOOL_REINIT_FOR_TEST = Util.class.getName() + "ALLOW_TOOL_REINIT_FOR_TEST"; // Necessary for testing
|
||||
public static final String ALLOW_TOOL_REINIT_FOR_TEST = Util.class.getName() + "ALLOW_TOOL_REINIT_FOR_TEST"; // Necessary for testing
|
||||
static final String RESET = "\u001B[0m";
|
||||
static final String BLUE = "\u001B[34m";
|
||||
static final String CYAN = "\u001B[36m";
|
||||
|
|
|
|||
|
|
@ -23,10 +23,12 @@ import java.io.FileInputStream;
|
|||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.apache.cassandra.OrderedJUnit4ClassRunner;
|
||||
import org.apache.cassandra.config.Config;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.cql3.Attributes;
|
||||
|
|
@ -37,12 +39,17 @@ import org.apache.cassandra.db.ExpirationDateOverflowHandling;
|
|||
import org.apache.cassandra.db.Keyspace;
|
||||
import org.apache.cassandra.db.rows.AbstractCell;
|
||||
import org.apache.cassandra.exceptions.InvalidRequestException;
|
||||
import org.apache.cassandra.tools.StandaloneScrubber;
|
||||
import org.apache.cassandra.tools.ToolRunner;
|
||||
import org.apache.cassandra.tools.ToolRunner.ToolResult;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.assertj.core.api.Assertions;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
@RunWith(OrderedJUnit4ClassRunner.class)
|
||||
public class TTLTest extends CQLTester
|
||||
{
|
||||
public static String NEGATIVE_LOCAL_EXPIRATION_TEST_DIR = "test/data/negative-local-expiration-test/%s";
|
||||
|
|
@ -54,6 +61,7 @@ public class TTLTest extends CQLTester
|
|||
public static final String COMPLEX_NOCLUSTERING = "table3";
|
||||
public static final String COMPLEX_CLUSTERING = "table4";
|
||||
private Config.CorruptedTombstoneStrategy corruptTombstoneStrategy;
|
||||
|
||||
@Before
|
||||
public void before()
|
||||
{
|
||||
|
|
@ -203,9 +211,20 @@ public class TTLTest extends CQLTester
|
|||
{
|
||||
// this tests writes corrupt tombstones on purpose, disable the strategy:
|
||||
DatabaseDescriptor.setCorruptedTombstoneStrategy(Config.CorruptedTombstoneStrategy.disabled);
|
||||
baseTestRecoverOverflowedExpiration(false, false);
|
||||
baseTestRecoverOverflowedExpiration(true, false);
|
||||
baseTestRecoverOverflowedExpiration(true, true);
|
||||
baseTestRecoverOverflowedExpiration(false, false, false);
|
||||
baseTestRecoverOverflowedExpiration(true, false, false);
|
||||
baseTestRecoverOverflowedExpiration(true, false, true);
|
||||
// we reset the corrupted ts strategy after each test in @After above
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecoverOverflowedExpirationWithSSTableScrub() throws Throwable
|
||||
{
|
||||
// this tests writes corrupt tombstones on purpose, disable the strategy:
|
||||
DatabaseDescriptor.setCorruptedTombstoneStrategy(Config.CorruptedTombstoneStrategy.disabled);
|
||||
baseTestRecoverOverflowedExpiration(false, false, false);
|
||||
baseTestRecoverOverflowedExpiration(false, true, false);
|
||||
baseTestRecoverOverflowedExpiration(false, true, true);
|
||||
// we reset the corrupted ts strategy after each test in @After above
|
||||
}
|
||||
|
||||
|
|
@ -276,16 +295,16 @@ public class TTLTest extends CQLTester
|
|||
}
|
||||
}
|
||||
|
||||
public void baseTestRecoverOverflowedExpiration(boolean runScrub, boolean reinsertOverflowedTTL) throws Throwable
|
||||
public void baseTestRecoverOverflowedExpiration(boolean runScrub, boolean runSStableScrub, boolean reinsertOverflowedTTL) throws Throwable
|
||||
{
|
||||
// simple column, clustering
|
||||
testRecoverOverflowedExpirationWithScrub(true, true, runScrub, reinsertOverflowedTTL);
|
||||
testRecoverOverflowedExpirationWithScrub(true, true, runScrub, runSStableScrub, reinsertOverflowedTTL);
|
||||
// simple column, noclustering
|
||||
testRecoverOverflowedExpirationWithScrub(true, false, runScrub, reinsertOverflowedTTL);
|
||||
testRecoverOverflowedExpirationWithScrub(true, false, runScrub, runSStableScrub, reinsertOverflowedTTL);
|
||||
// complex column, clustering
|
||||
testRecoverOverflowedExpirationWithScrub(false, true, runScrub, reinsertOverflowedTTL);
|
||||
testRecoverOverflowedExpirationWithScrub(false, true, runScrub, runSStableScrub, reinsertOverflowedTTL);
|
||||
// complex column, noclustering
|
||||
testRecoverOverflowedExpirationWithScrub(false, false, runScrub, reinsertOverflowedTTL);
|
||||
testRecoverOverflowedExpirationWithScrub(false, false, runScrub, runSStableScrub, reinsertOverflowedTTL);
|
||||
}
|
||||
|
||||
private void createTable(boolean simple, boolean clustering)
|
||||
|
|
@ -350,11 +369,11 @@ public class TTLTest extends CQLTester
|
|||
return AbstractCell.MAX_DELETION_TIME - nowInSecs;
|
||||
}
|
||||
|
||||
public void testRecoverOverflowedExpirationWithScrub(boolean simple, boolean clustering, boolean runScrub, boolean reinsertOverflowedTTL) throws Throwable
|
||||
public void testRecoverOverflowedExpirationWithScrub(boolean simple, boolean clustering, boolean runScrub, boolean runSStableScrub, boolean reinsertOverflowedTTL) throws Throwable
|
||||
{
|
||||
if (reinsertOverflowedTTL)
|
||||
{
|
||||
assert runScrub;
|
||||
assert runScrub || runSStableScrub;
|
||||
}
|
||||
|
||||
createTable(simple, clustering);
|
||||
|
|
@ -371,25 +390,49 @@ public class TTLTest extends CQLTester
|
|||
if (runScrub)
|
||||
{
|
||||
cfs.scrub(true, false, true, reinsertOverflowedTTL, 1);
|
||||
}
|
||||
|
||||
if (reinsertOverflowedTTL)
|
||||
{
|
||||
if (simple)
|
||||
assertRows(execute("SELECT * from %s"), row(1, 1, 1), row(2, 2, null));
|
||||
if (reinsertOverflowedTTL)
|
||||
{
|
||||
if (simple)
|
||||
assertRows(execute("SELECT * from %s"), row(1, 1, 1), row(2, 2, null));
|
||||
else
|
||||
assertRows(execute("SELECT * from %s"), row(1, 1, set("v11", "v12", "v13", "v14")), row(2, 2, set("v21", "v22", "v23", "v24")));
|
||||
|
||||
cfs.forceMajorCompaction();
|
||||
|
||||
if (simple)
|
||||
assertRows(execute("SELECT * from %s"), row(1, 1, 1), row(2, 2, null));
|
||||
else
|
||||
assertRows(execute("SELECT * from %s"), row(1, 1, set("v11", "v12", "v13", "v14")), row(2, 2, set("v21", "v22", "v23", "v24")));
|
||||
}
|
||||
else
|
||||
assertRows(execute("SELECT * from %s"), row(1, 1, set("v11", "v12", "v13", "v14")), row(2, 2, set("v21", "v22", "v23", "v24")));
|
||||
|
||||
cfs.forceMajorCompaction();
|
||||
|
||||
if (simple)
|
||||
assertRows(execute("SELECT * from %s"), row(1, 1, 1), row(2, 2, null));
|
||||
else
|
||||
assertRows(execute("SELECT * from %s"), row(1, 1, set("v11", "v12", "v13", "v14")), row(2, 2, set("v21", "v22", "v23", "v24")));
|
||||
{
|
||||
assertEmpty(execute("SELECT * from %s"));
|
||||
}
|
||||
}
|
||||
else
|
||||
if (runSStableScrub)
|
||||
{
|
||||
assertEmpty(execute("SELECT * from %s"));
|
||||
System.setProperty(org.apache.cassandra.tools.Util.ALLOW_TOOL_REINIT_FOR_TEST, "true"); // Necessary for testing
|
||||
|
||||
try
|
||||
{
|
||||
ToolResult tool;
|
||||
if (reinsertOverflowedTTL)
|
||||
tool = ToolRunner.invokeClass(StandaloneScrubber.class, "-r", KEYSPACE, cfs.name);
|
||||
else
|
||||
tool = ToolRunner.invokeClass(StandaloneScrubber.class, KEYSPACE, cfs.name);
|
||||
|
||||
Assertions.assertThat(tool.getStdout()).contains("Pre-scrub sstables snapshotted into");
|
||||
if (reinsertOverflowedTTL)
|
||||
Assertions.assertThat(tool.getStdout()).contains("Fixed 2 rows with overflowed local deletion time.");
|
||||
else
|
||||
Assertions.assertThat(tool.getStdout()).contains("Unable to recover 2 rows that were skipped.");
|
||||
tool.assertOnCleanExit();
|
||||
}
|
||||
finally
|
||||
{
|
||||
System.clearProperty(org.apache.cassandra.tools.Util.ALLOW_TOOL_REINIT_FOR_TEST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,21 +18,34 @@
|
|||
*/
|
||||
package org.apache.cassandra.db;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.io.IOError;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.apache.cassandra.db.lifecycle.LifecycleNewTracker;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.apache.cassandra.*;
|
||||
import org.apache.cassandra.OrderedJUnit4ClassRunner;
|
||||
import org.apache.cassandra.SchemaLoader;
|
||||
import org.apache.cassandra.UpdateBuilder;
|
||||
import org.apache.cassandra.Util;
|
||||
import org.apache.cassandra.cache.ChunkCache;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.cql3.Operator;
|
||||
|
|
@ -41,18 +54,27 @@ import org.apache.cassandra.cql3.UntypedResultSet;
|
|||
import org.apache.cassandra.db.compaction.CompactionManager;
|
||||
import org.apache.cassandra.db.compaction.OperationType;
|
||||
import org.apache.cassandra.db.compaction.Scrubber;
|
||||
import org.apache.cassandra.db.lifecycle.LifecycleNewTracker;
|
||||
import org.apache.cassandra.db.lifecycle.LifecycleTransaction;
|
||||
import org.apache.cassandra.db.marshal.LongType;
|
||||
import org.apache.cassandra.db.marshal.UUIDType;
|
||||
import org.apache.cassandra.db.partitions.Partition;
|
||||
import org.apache.cassandra.db.partitions.PartitionUpdate;
|
||||
import org.apache.cassandra.db.rows.EncodingStats;
|
||||
import org.apache.cassandra.dht.*;
|
||||
import org.apache.cassandra.dht.ByteOrderedPartitioner;
|
||||
import org.apache.cassandra.dht.IPartitioner;
|
||||
import org.apache.cassandra.dht.Murmur3Partitioner;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.exceptions.RequestExecutionException;
|
||||
import org.apache.cassandra.exceptions.WriteTimeoutException;
|
||||
import org.apache.cassandra.io.compress.CompressionMetadata;
|
||||
import org.apache.cassandra.io.sstable.*;
|
||||
import org.apache.cassandra.io.sstable.Component;
|
||||
import org.apache.cassandra.io.sstable.CorruptSSTableException;
|
||||
import org.apache.cassandra.io.sstable.Descriptor;
|
||||
import org.apache.cassandra.io.sstable.SSTableMultiWriter;
|
||||
import org.apache.cassandra.io.sstable.SSTableRewriter;
|
||||
import org.apache.cassandra.io.sstable.SSTableTxnWriter;
|
||||
import org.apache.cassandra.io.sstable.SimpleSSTableMultiWriter;
|
||||
import org.apache.cassandra.io.sstable.format.SSTableReader;
|
||||
import org.apache.cassandra.io.sstable.format.SSTableWriter;
|
||||
import org.apache.cassandra.io.sstable.format.big.BigTableWriter;
|
||||
|
|
@ -60,7 +82,11 @@ import org.apache.cassandra.io.sstable.metadata.MetadataCollector;
|
|||
import org.apache.cassandra.io.util.FileUtils;
|
||||
import org.apache.cassandra.schema.KeyspaceParams;
|
||||
import org.apache.cassandra.schema.TableMetadataRef;
|
||||
import org.apache.cassandra.tools.StandaloneScrubber;
|
||||
import org.apache.cassandra.tools.ToolRunner;
|
||||
import org.apache.cassandra.tools.ToolRunner.ToolResult;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.assertj.core.api.Assertions;
|
||||
|
||||
import static org.apache.cassandra.SchemaLoader.counterCFMD;
|
||||
import static org.apache.cassandra.SchemaLoader.createKeyspace;
|
||||
|
|
@ -79,9 +105,11 @@ public class ScrubTest
|
|||
public static final String INVALID_LEGACY_SSTABLE_ROOT_PROP = "invalid-legacy-sstable-root";
|
||||
|
||||
public static final String KEYSPACE = "Keyspace1";
|
||||
public static final String KEYSPACE2 = "Keyspace2";
|
||||
public static final String CF = "Standard1";
|
||||
public static final String CF2 = "Standard2";
|
||||
public static final String CF3 = "Standard3";
|
||||
public static final String CF4 = "Standard4";
|
||||
public static final String COUNTER_CF = "Counter1";
|
||||
public static final String CF_UUID = "UUIDKeys";
|
||||
public static final String CF_INDEX1 = "Indexed1";
|
||||
|
|
@ -110,6 +138,12 @@ public class ScrubTest
|
|||
SchemaLoader.compositeIndexCFMD(KEYSPACE, CF_INDEX2_BYTEORDERED, true).partitioner(ByteOrderedPartitioner.instance));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void clearClassEnv()
|
||||
{
|
||||
System.clearProperty(org.apache.cassandra.tools.Util.ALLOW_TOOL_REINIT_FOR_TEST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScrubOneRow() throws ExecutionException, InterruptedException
|
||||
{
|
||||
|
|
@ -712,4 +746,134 @@ public class ScrubTest
|
|||
rs = QueryProcessor.executeInternal(String.format("SELECT * FROM \"%s\".cf_with_duplicates_3_0", KEYSPACE));
|
||||
assertEquals(0, rs.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToolTestingEnvSetup()
|
||||
{
|
||||
createKeyspace(KEYSPACE2,
|
||||
KeyspaceParams.simple(1),
|
||||
standardCFMD(KEYSPACE2, CF),
|
||||
standardCFMD(KEYSPACE2, CF2),
|
||||
standardCFMD(KEYSPACE2, CF3),
|
||||
standardCFMD(KEYSPACE2, CF4),
|
||||
counterCFMD(KEYSPACE2, COUNTER_CF));
|
||||
|
||||
System.setProperty(org.apache.cassandra.tools.Util.ALLOW_TOOL_REINIT_FOR_TEST, "true"); // Necessary for testing
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScrubOneRowWithTool()
|
||||
{
|
||||
CompactionManager.instance.disableAutoCompaction();
|
||||
Keyspace keyspace = Keyspace.open(KEYSPACE2);
|
||||
ColumnFamilyStore cfs = keyspace.getColumnFamilyStore(CF);
|
||||
cfs.clearUnsafe();
|
||||
|
||||
// insert data and verify we get it back w/ range query
|
||||
fillCF(cfs, 1);
|
||||
assertOrderedAll(cfs, 1);
|
||||
|
||||
ToolResult tool = ToolRunner.invokeClass(StandaloneScrubber.class, KEYSPACE2, CF);
|
||||
Assertions.assertThat(tool.getStdout()).contains("Pre-scrub sstables snapshotted into");
|
||||
Assertions.assertThat(tool.getStdout()).contains("1 rows in new sstable and 0 empty");
|
||||
tool.assertOnCleanExit();
|
||||
|
||||
// check data is still there
|
||||
assertOrderedAll(cfs, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipScrubCorruptedCounterRowWithTool() throws IOException, WriteTimeoutException
|
||||
{
|
||||
int numPartitions = 1000;
|
||||
|
||||
CompactionManager.instance.disableAutoCompaction();
|
||||
Keyspace keyspace = Keyspace.open(KEYSPACE2);
|
||||
ColumnFamilyStore cfs = keyspace.getColumnFamilyStore(COUNTER_CF);
|
||||
cfs.clearUnsafe();
|
||||
|
||||
fillCounterCF(cfs, numPartitions);
|
||||
assertOrderedAll(cfs, numPartitions);
|
||||
assertEquals(1, cfs.getLiveSSTables().size());
|
||||
SSTableReader sstable = cfs.getLiveSSTables().iterator().next();
|
||||
|
||||
overrideWithGarbage(sstable, ByteBufferUtil.bytes("0"), ByteBufferUtil.bytes("1"));
|
||||
|
||||
// with skipCorrupted == false, the scrub is expected to fail
|
||||
try
|
||||
{
|
||||
ToolRunner.invokeClass(StandaloneScrubber.class, KEYSPACE2, COUNTER_CF);
|
||||
fail("Expected a CorruptSSTableException to be thrown");
|
||||
}
|
||||
catch (IOError err) {}
|
||||
|
||||
// with skipCorrupted == true, the corrupt rows will be skipped
|
||||
ToolResult tool = ToolRunner.invokeClass(StandaloneScrubber.class, "-s", KEYSPACE2, COUNTER_CF);
|
||||
Assertions.assertThat(tool.getStdout()).contains("0 empty");
|
||||
Assertions.assertThat(tool.getStdout()).contains("rows that were skipped");
|
||||
tool.assertOnCleanExit();
|
||||
|
||||
assertEquals(1, cfs.getLiveSSTables().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoCheckScrubMultiRowWithTool()
|
||||
{
|
||||
CompactionManager.instance.disableAutoCompaction();
|
||||
Keyspace keyspace = Keyspace.open(KEYSPACE2);
|
||||
ColumnFamilyStore cfs = keyspace.getColumnFamilyStore(CF2);
|
||||
cfs.clearUnsafe();
|
||||
|
||||
// insert data and verify we get it back w/ range query
|
||||
fillCF(cfs, 10);
|
||||
assertOrderedAll(cfs, 10);
|
||||
|
||||
ToolResult tool = ToolRunner.invokeClass(StandaloneScrubber.class, "-n", KEYSPACE2, CF2);
|
||||
Assertions.assertThat(tool.getStdout()).contains("Pre-scrub sstables snapshotted into");
|
||||
Assertions.assertThat(tool.getStdout()).contains("10 rows in new sstable and 0 empty");
|
||||
tool.assertOnCleanExit();
|
||||
|
||||
// check data is still there
|
||||
assertOrderedAll(cfs, 10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeaderFixWithTool()
|
||||
{
|
||||
CompactionManager.instance.disableAutoCompaction();
|
||||
Keyspace keyspace = Keyspace.open(KEYSPACE2);
|
||||
ColumnFamilyStore cfs = keyspace.getColumnFamilyStore(CF3);
|
||||
cfs.clearUnsafe();
|
||||
|
||||
fillCF(cfs, 1);
|
||||
assertOrderedAll(cfs, 1);
|
||||
|
||||
ToolResult tool = ToolRunner.invokeClass(StandaloneScrubber.class, "-e", "validate_only", KEYSPACE2, CF3);
|
||||
Assertions.assertThat(tool.getStdout()).contains("Not continuing with scrub, since '--header-fix validate-only' was specified.");
|
||||
tool.assertOnCleanExit();
|
||||
assertOrderedAll(cfs, 1);
|
||||
|
||||
tool = ToolRunner.invokeClass(StandaloneScrubber.class, "-e", "validate", KEYSPACE2, CF3);
|
||||
Assertions.assertThat(tool.getStdout()).contains("Pre-scrub sstables snapshotted into");
|
||||
Assertions.assertThat(tool.getStdout()).contains("1 rows in new sstable and 0 empty");
|
||||
tool.assertOnCleanExit();
|
||||
assertOrderedAll(cfs, 1);
|
||||
|
||||
tool = ToolRunner.invokeClass(StandaloneScrubber.class, "-e", "fix-only", KEYSPACE2, CF3);
|
||||
Assertions.assertThat(tool.getStdout()).contains("Not continuing with scrub, since '--header-fix fix-only' was specified.");
|
||||
tool.assertOnCleanExit();
|
||||
assertOrderedAll(cfs, 1);
|
||||
|
||||
tool = ToolRunner.invokeClass(StandaloneScrubber.class, "-e", "fix", KEYSPACE2, CF3);
|
||||
Assertions.assertThat(tool.getStdout()).contains("Pre-scrub sstables snapshotted into");
|
||||
Assertions.assertThat(tool.getStdout()).contains("1 rows in new sstable and 0 empty");
|
||||
tool.assertOnCleanExit();
|
||||
assertOrderedAll(cfs, 1);
|
||||
|
||||
tool = ToolRunner.invokeClass(StandaloneScrubber.class, "-e", "off", KEYSPACE2, CF3);
|
||||
Assertions.assertThat(tool.getStdout()).contains("Pre-scrub sstables snapshotted into");
|
||||
Assertions.assertThat(tool.getStdout()).contains("1 rows in new sstable and 0 empty");
|
||||
tool.assertOnCleanExit();
|
||||
assertOrderedAll(cfs, 1);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,12 @@ import static org.junit.Assert.assertEquals;
|
|||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/*
|
||||
* We are testing cmd line params here.
|
||||
* For sstable scrubbing tests look at {@link ScrubTest}
|
||||
* For TTL sstable scrubbing tests look at {@link TTLTest}
|
||||
*/
|
||||
|
||||
@RunWith(OrderedJUnit4ClassRunner.class)
|
||||
public class StandaloneScrubberTest extends OfflineToolUtils
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue