mirror of https://github.com/apache/cassandra
ScrubTest should generate out-of-order SSTable on the fly
with some other ScrubTest fixes. patch by yukim; reviewed by Stefania Alborghetti for CASSANDRA-9880
This commit is contained in:
parent
b090ed6938
commit
df3b6027bc
|
|
@ -1281,7 +1281,6 @@
|
|||
<testmacro inputdir="${test.unit.src}" exclude="**/pig/*.java" timeout="${test.timeout}">
|
||||
<jvmarg value="-Dlegacy-sstable-root=${test.data}/legacy-sstables"/>
|
||||
<jvmarg value="-Dinvalid-legacy-sstable-root=${test.data}/invalid-legacy-sstables"/>
|
||||
<jvmarg value="-Dcorrupt-sstable-root=${test.data}/corrupt-sstables"/>
|
||||
<jvmarg value="-Dmigration-sstable-root=${test.data}/migration-sstables"/>
|
||||
<jvmarg value="-Dcassandra.ring_delay_ms=1000"/>
|
||||
<jvmarg value="-Dcassandra.tolerate_sstable_size=true"/>
|
||||
|
|
@ -1302,7 +1301,6 @@
|
|||
<testmacrohelper inputdir="${test.unit.src}" filelist="@{test.file.list}" poffset="@{testlist.offset}" exclude="**/*.java" timeout="${test.timeout}">
|
||||
<jvmarg value="-Dlegacy-sstable-root=${test.data}/legacy-sstables"/>
|
||||
<jvmarg value="-Dinvalid-legacy-sstable-root=${test.data}/invalid-legacy-sstables"/>
|
||||
<jvmarg value="-Dcorrupt-sstable-root=${test.data}/corrupt-sstables"/>
|
||||
<jvmarg value="-Dmigration-sstable-root=${test.data}/migration-sstables"/>
|
||||
<jvmarg value="-Dcassandra.ring_delay_ms=1000"/>
|
||||
<jvmarg value="-Dcassandra.tolerate_sstable_size=true"/>
|
||||
|
|
@ -1323,7 +1321,6 @@
|
|||
exclude="**/*.java" timeout="${test.timeout}" testtag="compression">
|
||||
<jvmarg value="-Dlegacy-sstable-root=${test.data}/legacy-sstables"/>
|
||||
<jvmarg value="-Dinvalid-legacy-sstable-root=${test.data}/invalid-legacy-sstables"/>
|
||||
<jvmarg value="-Dcorrupt-sstable-root=${test.data}/corrupt-sstables"/>
|
||||
<jvmarg value="-Dmigration-sstable-root=${test.data}/migration-sstables"/>
|
||||
<jvmarg value="-Dcassandra.test.compression=true"/>
|
||||
<jvmarg value="-Dcassandra.ring_delay_ms=1000"/>
|
||||
|
|
@ -1355,7 +1352,6 @@
|
|||
<test name="${test.name}" methods="${test.methods}"/>
|
||||
<jvmarg value="-Dlegacy-sstable-root=${test.data}/legacy-sstables"/>
|
||||
<jvmarg value="-Dinvalid-legacy-sstable-root=${test.data}/invalid-legacy-sstables"/>
|
||||
<jvmarg value="-Dcorrupt-sstable-root=${test.data}/corrupt-sstables"/>
|
||||
<jvmarg value="-Dmigration-sstable-root=${test.data}/migration-sstables"/>
|
||||
<jvmarg value="-Dcassandra.ring_delay_ms=1000"/>
|
||||
<jvmarg value="-Dcassandra.tolerate_sstable_size=true"/>
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@ public class Scrubber implements Closeable
|
|||
private final RowIndexEntry.IndexSerializer rowIndexEntrySerializer;
|
||||
|
||||
private final boolean isOffline;
|
||||
private final boolean keepOriginals;
|
||||
|
||||
private SSTableReader newSstable;
|
||||
private SSTableReader newInOrderSstable;
|
||||
|
|
@ -86,7 +85,7 @@ public class Scrubber implements Closeable
|
|||
|
||||
public Scrubber(ColumnFamilyStore cfs, LifecycleTransaction transaction, boolean skipCorrupted, boolean isOffline, boolean checkData) throws IOException
|
||||
{
|
||||
this(cfs, transaction, skipCorrupted, new OutputHandler.LogOutput(), isOffline, checkData, false);
|
||||
this(cfs, transaction, skipCorrupted, new OutputHandler.LogOutput(), isOffline, checkData);
|
||||
}
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
|
|
@ -95,8 +94,7 @@ public class Scrubber implements Closeable
|
|||
boolean skipCorrupted,
|
||||
OutputHandler outputHandler,
|
||||
boolean isOffline,
|
||||
boolean checkData,
|
||||
boolean keepOriginals) throws IOException
|
||||
boolean checkData) throws IOException
|
||||
{
|
||||
this.cfs = cfs;
|
||||
this.transaction = transaction;
|
||||
|
|
@ -104,7 +102,6 @@ public class Scrubber implements Closeable
|
|||
this.outputHandler = outputHandler;
|
||||
this.skipCorrupted = skipCorrupted;
|
||||
this.isOffline = isOffline;
|
||||
this.keepOriginals = keepOriginals;
|
||||
this.rowIndexEntrySerializer = sstable.descriptor.version.getSSTableFormat().getIndexSerializer(sstable.metadata,
|
||||
sstable.descriptor.version,
|
||||
sstable.header);
|
||||
|
|
|
|||
|
|
@ -1251,7 +1251,6 @@ public abstract class SSTableReader extends SSTable implements SelfRefCounted<SS
|
|||
{
|
||||
if (this.first.compareTo(this.last) > 0)
|
||||
{
|
||||
selfRef().release();
|
||||
throw new IllegalStateException(String.format("SSTable first key %s > last key %s", this.first, this.last));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ public class StandaloneScrubber
|
|||
try (LifecycleTransaction txn = LifecycleTransaction.offline(OperationType.SCRUB, sstable))
|
||||
{
|
||||
txn.obsoleteOriginals(); // make sure originals are deleted and avoid NPE if index is missing, CASSANDRA-9591
|
||||
try (Scrubber scrubber = new Scrubber(cfs, txn, options.skipCorrupted, handler, true, !options.noValidate, false))
|
||||
try (Scrubber scrubber = new Scrubber(cfs, txn, options.skipCorrupted, handler, true, !options.noValidate))
|
||||
{
|
||||
scrubber.scrub();
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -1 +0,0 @@
|
|||
3942663153
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,8 +0,0 @@
|
|||
Statistics.db
|
||||
CRC.db
|
||||
TOC.txt
|
||||
Data.db
|
||||
Index.db
|
||||
Summary.db
|
||||
Digest.adler32
|
||||
Filter.db
|
||||
|
|
@ -18,54 +18,52 @@
|
|||
*/
|
||||
package org.apache.cassandra.db;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOError;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOError;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
import org.apache.cassandra.Util;
|
||||
import org.apache.cassandra.UpdateBuilder;
|
||||
import org.apache.cassandra.cql3.QueryProcessor;
|
||||
import org.apache.cassandra.db.partitions.*;
|
||||
import org.apache.cassandra.db.marshal.BytesType;
|
||||
import org.apache.cassandra.db.marshal.UUIDType;
|
||||
import org.apache.cassandra.db.compaction.OperationType;
|
||||
import org.apache.cassandra.db.lifecycle.LifecycleTransaction;
|
||||
import org.apache.cassandra.db.rows.Row;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.exceptions.RequestExecutionException;
|
||||
import org.apache.cassandra.io.compress.CompressionMetadata;
|
||||
import org.apache.cassandra.io.sstable.format.SSTableFormat;
|
||||
import org.apache.cassandra.io.sstable.format.SSTableReader;
|
||||
import org.apache.cassandra.io.sstable.format.SSTableWriter;
|
||||
import org.apache.cassandra.schema.KeyspaceParams;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.apache.cassandra.config.*;
|
||||
import org.apache.cassandra.OrderedJUnit4ClassRunner;
|
||||
import org.apache.cassandra.SchemaLoader;
|
||||
import org.apache.cassandra.UpdateBuilder;
|
||||
import org.apache.cassandra.Util;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.cql3.Operator;
|
||||
import org.apache.cassandra.cql3.QueryProcessor;
|
||||
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.index.SecondaryIndex;
|
||||
import org.apache.cassandra.db.lifecycle.LifecycleTransaction;
|
||||
import org.apache.cassandra.db.marshal.*;
|
||||
import org.apache.cassandra.db.partitions.Partition;
|
||||
import org.apache.cassandra.db.partitions.PartitionUpdate;
|
||||
import org.apache.cassandra.dht.ByteOrderedPartitioner;
|
||||
import org.apache.cassandra.dht.IPartitioner;
|
||||
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.Component;
|
||||
import org.apache.cassandra.io.sstable.Descriptor;
|
||||
import org.apache.cassandra.io.sstable.SSTableRewriter;
|
||||
import org.apache.cassandra.OrderedJUnit4ClassRunner;
|
||||
import org.apache.cassandra.SchemaLoader;
|
||||
import org.apache.cassandra.io.sstable.SSTableTxnWriter;
|
||||
import org.apache.cassandra.io.sstable.format.SSTableReader;
|
||||
import org.apache.cassandra.io.util.FileUtils;
|
||||
import org.apache.cassandra.schema.KeyspaceParams;
|
||||
import org.apache.cassandra.service.StorageService;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.OutputHandler;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
|
@ -306,74 +304,84 @@ public class ScrubTest
|
|||
@Test
|
||||
public void testScrubOutOfOrder() throws Exception
|
||||
{
|
||||
CompactionManager.instance.disableAutoCompaction();
|
||||
Keyspace keyspace = Keyspace.open(KEYSPACE);
|
||||
String columnFamily = CF3;
|
||||
ColumnFamilyStore cfs = keyspace.getColumnFamilyStore(columnFamily);
|
||||
cfs.clearUnsafe();
|
||||
|
||||
/*
|
||||
* Code used to generate an outOfOrder sstable. The test for out-of-order key in BigTableWriter must also be commented out.
|
||||
* The test also assumes an ordered partitioner.
|
||||
List<String> keys = Arrays.asList("t", "a", "b", "z", "c", "y", "d");
|
||||
SSTableWriter writer = new SSTableWriter(cfs.getTempSSTablePath(new File(System.getProperty("corrupt-sstable-root"))),
|
||||
SSTableWriter writer = SSTableWriter.create(cfs.metadata,
|
||||
Descriptor.fromFilename(filename),
|
||||
keys.size(),
|
||||
0L,
|
||||
0,
|
||||
DatabaseDescriptor.getPartitioner(),
|
||||
SerializationHeader.make(cfs.metadata, Collections.emptyList()));
|
||||
|
||||
for (String k : keys)
|
||||
{
|
||||
RowUpdateBuilder builder = new RowUpdateBuilder(cfs.metadata, 0L, Util.dk(k));
|
||||
PartitionUpdate update = builder.clustering("someName")
|
||||
.add("val", "someValue")
|
||||
.buildUpdate();
|
||||
|
||||
writer.append(update.unfilteredIterator());
|
||||
}
|
||||
writer.finish(false);
|
||||
*/
|
||||
|
||||
String root = System.getProperty("corrupt-sstable-root");
|
||||
assert root != null;
|
||||
|
||||
File rootDir = new File(root);
|
||||
assert rootDir.isDirectory();
|
||||
Descriptor desc = new Descriptor("la", rootDir, KEYSPACE, columnFamily, 1, SSTableFormat.Type.BIG);
|
||||
CFMetaData metadata = Schema.instance.getCFMetaData(desc.ksname, desc.cfname);
|
||||
// This test assumes ByteOrderPartitioner to create out-of-order SSTable
|
||||
IPartitioner oldPartitioner = DatabaseDescriptor.getPartitioner();
|
||||
DatabaseDescriptor.setPartitioner(new ByteOrderedPartitioner());
|
||||
|
||||
// Create out-of-order SSTable
|
||||
File tempDir = File.createTempFile("ScrubTest.testScrubOutOfOrder", "").getParentFile();
|
||||
// create ks/cf directory
|
||||
File tempDataDir = new File(tempDir, String.join(File.separator, KEYSPACE, CF3));
|
||||
tempDataDir.mkdirs();
|
||||
try
|
||||
{
|
||||
SSTableReader.open(desc, metadata);
|
||||
fail("SSTR validation should have caught the out-of-order rows");
|
||||
CompactionManager.instance.disableAutoCompaction();
|
||||
Keyspace keyspace = Keyspace.open(KEYSPACE);
|
||||
String columnFamily = CF3;
|
||||
ColumnFamilyStore cfs = keyspace.getColumnFamilyStore(columnFamily);
|
||||
cfs.clearUnsafe();
|
||||
|
||||
List<String> keys = Arrays.asList("t", "a", "b", "z", "c", "y", "d");
|
||||
String filename = cfs.getSSTablePath(tempDataDir);
|
||||
Descriptor desc = Descriptor.fromFilename(filename);
|
||||
|
||||
try (SSTableTxnWriter writer = SSTableTxnWriter.create(desc,
|
||||
keys.size(),
|
||||
0L,
|
||||
0,
|
||||
SerializationHeader.make(cfs.metadata,
|
||||
Collections.emptyList())))
|
||||
{
|
||||
|
||||
for (String k : keys)
|
||||
{
|
||||
PartitionUpdate update = UpdateBuilder.create(cfs.metadata, Util.dk(k))
|
||||
.newRow("someName").add("val", "someValue")
|
||||
.build();
|
||||
|
||||
writer.append(update.unfilteredIterator());
|
||||
}
|
||||
writer.finish(false);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
SSTableReader.open(desc, cfs.metadata);
|
||||
fail("SSTR validation should have caught the out-of-order rows");
|
||||
}
|
||||
catch (IllegalStateException ise)
|
||||
{ /* this is expected */ }
|
||||
|
||||
// open without validation for scrubbing
|
||||
Set<Component> components = new HashSet<>();
|
||||
if (new File(desc.filenameFor(Component.COMPRESSION_INFO)).exists())
|
||||
components.add(Component.COMPRESSION_INFO);
|
||||
components.add(Component.DATA);
|
||||
components.add(Component.PRIMARY_INDEX);
|
||||
components.add(Component.FILTER);
|
||||
components.add(Component.STATS);
|
||||
components.add(Component.SUMMARY);
|
||||
components.add(Component.TOC);
|
||||
|
||||
SSTableReader sstable = SSTableReader.openNoValidation(desc, components, cfs);
|
||||
if (sstable.last.compareTo(sstable.first) < 0)
|
||||
sstable.last = sstable.first;
|
||||
|
||||
try (LifecycleTransaction txn = LifecycleTransaction.offline(OperationType.SCRUB, sstable);
|
||||
Scrubber scrubber = new Scrubber(cfs, txn, false, true, true))
|
||||
{
|
||||
scrubber.scrub();
|
||||
}
|
||||
cfs.loadNewSSTables();
|
||||
assertOrderedAll(cfs, 7);
|
||||
sstable.selfRef().release();
|
||||
}
|
||||
catch (IllegalStateException ise) { /* this is expected */ }
|
||||
|
||||
// open without validation for scrubbing
|
||||
Set<Component> components = new HashSet<>();
|
||||
//components.add(Component.COMPRESSION_INFO);
|
||||
components.add(Component.DATA);
|
||||
components.add(Component.PRIMARY_INDEX);
|
||||
components.add(Component.FILTER);
|
||||
components.add(Component.STATS);
|
||||
components.add(Component.SUMMARY);
|
||||
components.add(Component.TOC);
|
||||
|
||||
SSTableReader sstable = SSTableReader.openNoValidation(desc, components, cfs);
|
||||
if (sstable.last.compareTo(sstable.first) < 0)
|
||||
sstable.last = sstable.first;
|
||||
|
||||
try (LifecycleTransaction txn = LifecycleTransaction.offline(OperationType.SCRUB, sstable);
|
||||
Scrubber scrubber = new Scrubber(cfs, txn, false, new OutputHandler.LogOutput(), true, true, true))
|
||||
finally
|
||||
{
|
||||
scrubber.scrub();
|
||||
FileUtils.deleteRecursive(tempDataDir);
|
||||
// reset partitioner
|
||||
DatabaseDescriptor.setPartitioner(oldPartitioner);
|
||||
}
|
||||
cfs.loadNewSSTables();
|
||||
assertOrderedAll(cfs, 7);
|
||||
sstable.selfRef().release();
|
||||
}
|
||||
|
||||
private void overrideWithGarbage(SSTableReader sstable, ByteBuffer key1, ByteBuffer key2) throws IOException
|
||||
|
|
|
|||
Loading…
Reference in New Issue