cassandra-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bened...@apache.org
Subject [02/12] cassandra git commit: Scrub (recover) sstables even when -Index.db is missing
Date Tue, 07 Jul 2015 15:46:07 GMT
Scrub (recover) sstables even when -Index.db is missing

patch by mck; reviewed by stefania for CASSANDRA-9591


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/452d6a44
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/452d6a44
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/452d6a44

Branch: refs/heads/cassandra-2.1
Commit: 452d6a445a6935d3e7d0e0fdf59e87d2a2ff95e7
Parents: 62714a9
Author: Stefania Alborghetti <stefania.alborghetti@datastax.com>
Authored: Mon Jun 15 16:49:03 2015 +0800
Committer: Benedict Elliott Smith <benedict@apache.org>
Committed: Tue Jul 7 14:27:25 2015 +0100

----------------------------------------------------------------------
 CHANGES.txt                                     |  4 ++
 .../cassandra/db/compaction/Scrubber.java       | 36 +++++++++++----
 .../cassandra/io/sstable/SSTableReader.java     | 47 ++++++++++++++++----
 .../cassandra/tools/StandaloneScrubber.java     |  2 +-
 .../unit/org/apache/cassandra/db/ScrubTest.java | 25 +++++++++++
 5 files changed, 96 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/452d6a44/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index ca4d4b5..bd1db92 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,3 +1,7 @@
+2.0.18
+* Scrub (recover) sstables even when -Index.db is missing, (CASSANDRA-9591)
+
+
 2.0.17
  * Avoid NPE in AuthSuccess#decode (CASSANDRA-9727)
  * Add listen_address to system.local (CASSANDRA-9603)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/452d6a44/src/java/org/apache/cassandra/db/compaction/Scrubber.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/compaction/Scrubber.java b/src/java/org/apache/cassandra/db/compaction/Scrubber.java
index ea10855..dc60efa 100644
--- a/src/java/org/apache/cassandra/db/compaction/Scrubber.java
+++ b/src/java/org/apache/cassandra/db/compaction/Scrubber.java
@@ -96,7 +96,16 @@ public class Scrubber implements Closeable
                         ? new ScrubController(cfs)
                         : new CompactionController(cfs, Collections.singleton(sstable), CompactionManager.getDefaultGcBefore(cfs));
         this.isCommutative = cfs.metadata.getDefaultValidator().isCommutative();
-        this.expectedBloomFilterSize = Math.max(cfs.metadata.getIndexInterval(), (int)(SSTableReader.getApproximateKeyCount(toScrub,cfs.metadata)));
+
+        boolean hasIndexFile = (new File(sstable.descriptor.filenameFor(Component.PRIMARY_INDEX))).exists();
+        if (!hasIndexFile)
+        {
+            // if there's any corruption in the -Data.db then rows can't be skipped over.
but it's worth a shot.
+            outputHandler.warn("Missing component: " + sstable.descriptor.filenameFor(Component.PRIMARY_INDEX));
+        }
+
+        this.expectedBloomFilterSize = Math.max(cfs.metadata.getIndexInterval(),
+                hasIndexFile ? (int)(SSTableReader.getApproximateKeyCount(toScrub,cfs.metadata))
: 0);
 
         // loop through each row, deserializing to check for damage.
         // we'll also loop through the index at the same time, using the position from the
index to recover if the
@@ -105,7 +114,11 @@ public class Scrubber implements Closeable
         this.dataFile = isOffline
                         ? sstable.openDataReader()
                         : sstable.openDataReader(CompactionManager.instance.getRateLimiter());
-        this.indexFile = RandomAccessReader.open(new File(sstable.descriptor.filenameFor(Component.PRIMARY_INDEX)));
+
+        this.indexFile = hasIndexFile
+                ? RandomAccessReader.open(new File(sstable.descriptor.filenameFor(Component.PRIMARY_INDEX)))
+                : null;
+
         this.scrubInfo = new ScrubInfo(dataFile, sstable);
 
         this.currentRowPositionFromIndex = 0;
@@ -117,7 +130,8 @@ public class Scrubber implements Closeable
         outputHandler.output(String.format("Scrubbing %s (%s bytes)", sstable, dataFile.length()));
         try
         {
-            nextIndexKey = ByteBufferUtil.readWithShortLength(indexFile);
+            nextIndexKey = indexAvailable() ? ByteBufferUtil.readWithShortLength(indexFile)
: null;
+            if (indexAvailable())
             {
                 // throw away variable so we don't have a side effect in the assert
                 long firstRowPositionFromIndex = RowIndexEntry.serializer.deserialize(indexFile,
sstable.descriptor.version).position;
@@ -181,7 +195,7 @@ public class Scrubber implements Closeable
                         outputHandler.debug(String.format("Index doublecheck: row %s is %s
bytes", ByteBufferUtil.bytesToHex(currentIndexKey),  dataSizeFromIndex));
                 }
 
-                assert currentIndexKey != null || indexFile.isEOF();
+                assert currentIndexKey != null || !indexAvailable();
 
                 writer.mark();
                 try
@@ -198,10 +212,10 @@ public class Scrubber implements Closeable
                     if (dataSize > dataFile.length())
                         throw new IOError(new IOException("Impossible row size (greater than
file length): " + dataSize));
 
-                    if (dataStart != dataStartFromIndex)
+                    if (indexFile != null && dataStart != dataStartFromIndex)
                         outputHandler.warn(String.format("Data file row position %d differs
from index file row position %d", dataStart, dataStartFromIndex));
 
-                    if (dataSize != dataSizeFromIndex)
+                    if (indexFile != null && dataSize != dataSizeFromIndex)
                         outputHandler.warn(String.format("Data file row size %d differs from
index file row size %d", dataSize, dataSizeFromIndex));
 
                     SSTableIdentityIterator atoms = new SSTableIdentityIterator(sstable,
dataFile, key, dataSize, validateColumns);
@@ -317,8 +331,9 @@ public class Scrubber implements Closeable
         currentRowPositionFromIndex = nextRowPositionFromIndex;
         try
         {
-            nextIndexKey = indexFile.isEOF() ? null : ByteBufferUtil.readWithShortLength(indexFile);
-            nextRowPositionFromIndex = indexFile.isEOF()
+            nextIndexKey = !indexAvailable() ? null : ByteBufferUtil.readWithShortLength(indexFile);
+
+            nextRowPositionFromIndex = !indexAvailable()
                     ? dataFile.length()
                     : RowIndexEntry.serializer.deserialize(indexFile, sstable.descriptor.version).position;
         }
@@ -330,6 +345,11 @@ public class Scrubber implements Closeable
         }
     }
 
+    private boolean indexAvailable()
+    {
+        return indexFile != null && !indexFile.isEOF();
+    }
+
     private void seekToNextRow()
     {
         while(nextRowPositionFromIndex < dataFile.length())

http://git-wip-us.apache.org/repos/asf/cassandra/blob/452d6a44/src/java/org/apache/cassandra/io/sstable/SSTableReader.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/io/sstable/SSTableReader.java b/src/java/org/apache/cassandra/io/sstable/SSTableReader.java
index 15808e8..8919a09 100644
--- a/src/java/org/apache/cassandra/io/sstable/SSTableReader.java
+++ b/src/java/org/apache/cassandra/io/sstable/SSTableReader.java
@@ -157,7 +157,7 @@ public class SSTableReader extends SSTable implements Closeable
 
     public static SSTableReader openForBatch(Descriptor descriptor, Set<Component>
components, CFMetaData metadata, IPartitioner partitioner) throws IOException
     {
-        SSTableMetadata sstableMetadata = openMetadata(descriptor, components, partitioner);
+        SSTableMetadata sstableMetadata = openMetadata(descriptor, components, partitioner,
true);
         SSTableReader sstable = new SSTableReader(descriptor,
                                                   components,
                                                   metadata,
@@ -191,7 +191,7 @@ public class SSTableReader extends SSTable implements Closeable
                                       boolean validate) throws IOException
     {
         long start = System.nanoTime();
-        SSTableMetadata sstableMetadata = openMetadata(descriptor, components, partitioner);
+        SSTableMetadata sstableMetadata = openMetadata(descriptor, components, partitioner,
validate);
 
         SSTableReader sstable = new SSTableReader(descriptor,
                                                   components,
@@ -213,12 +213,17 @@ public class SSTableReader extends SSTable implements Closeable
         return sstable;
     }
 
-    private static SSTableMetadata openMetadata(Descriptor descriptor, Set<Component>
components, IPartitioner partitioner) throws IOException
+    private static SSTableMetadata openMetadata(Descriptor descriptor,
+                                                Set<Component> components,
+                                                IPartitioner partitioner,
+                                                boolean primaryIndexRequired) throws IOException
     {
         assert partitioner != null;
         // Minimum components without which we can't do anything
         assert components.contains(Component.DATA) : "Data component is missing for sstable"
+ descriptor;
-        assert components.contains(Component.PRIMARY_INDEX) : "Primary index component is
missing for sstable " + descriptor;
+
+        assert !primaryIndexRequired || components.contains(Component.PRIMARY_INDEX)
+                : "Primary index component is missing for sstable " + descriptor;
 
         logger.info("Opening {} ({} bytes)", descriptor, new File(descriptor.filenameFor(COMPONENT_DATA)).length());
 
@@ -382,11 +387,17 @@ public class SSTableReader extends SSTable implements Closeable
             readMeterSyncFuture.cancel(false);
 
         // Force finalizing mmapping if necessary
-        ifile.cleanup();
+
+        if (null != ifile)
+            ifile.cleanup();
+
         dfile.cleanup();
         // close the BF so it can be opened later.
-        bf.close();
-        indexSummary.close();
+        if (null != bf)
+            bf.close();
+
+        if (null != indexSummary)
+            indexSummary.close();
     }
 
     public void setTrackedBy(DataTracker tracker)
@@ -406,6 +417,12 @@ public class SSTableReader extends SSTable implements Closeable
             load(false, true);
             bf = FilterFactory.AlwaysPresent;
         }
+        else if (!components.contains(Component.PRIMARY_INDEX))
+        {
+            // avoid any reading of the missing primary index component.
+            // this should only happen during StandaloneScrubber
+            load(false, false);
+        }
         else if (!components.contains(Component.FILTER))
         {
             // bf is enabled, but filter component is missing.
@@ -454,7 +471,9 @@ public class SSTableReader extends SSTable implements Closeable
         if (recreateBloomFilter || !summaryLoaded)
             buildSummary(recreateBloomFilter, ibuilder, dbuilder, summaryLoaded);
 
-        ifile = ibuilder.complete(descriptor.filenameFor(Component.PRIMARY_INDEX));
+        if (components.contains(Component.PRIMARY_INDEX))
+            ifile = ibuilder.complete(descriptor.filenameFor(Component.PRIMARY_INDEX));
+
         dfile = dbuilder.complete(descriptor.filenameFor(Component.DATA));
         if (saveSummaryIfCreated && (recreateBloomFilter || !summaryLoaded)) // save
summary information to disk
             saveSummary(this, ibuilder, dbuilder);
@@ -462,6 +481,9 @@ public class SSTableReader extends SSTable implements Closeable
 
      private void buildSummary(boolean recreateBloomFilter, SegmentedFile.Builder ibuilder,
SegmentedFile.Builder dbuilder, boolean summaryLoaded) throws IOException
      {
+         if (!components.contains(Component.PRIMARY_INDEX))
+             return;
+
         // we read the positions in a BRAF so we don't have to worry about an entry spanning
a mmap boundary.
         RandomAccessReader primaryIndex = RandomAccessReader.open(new File(descriptor.filenameFor(Component.PRIMARY_INDEX)));
 
@@ -965,6 +987,9 @@ public class SSTableReader extends SSTable implements Closeable
             }
         }
 
+        if (ifile == null)
+            return null;
+
         // scan the on-disk index, starting at the nearest sampled position.
         // The check against IndexInterval is to be exit the loop in the EQ case when the
key looked for is not present
         // (bloom filter false positive). But note that for non-EQ cases, we might need to
check the first key of the
@@ -1063,6 +1088,9 @@ public class SSTableReader extends SSTable implements Closeable
         if (sampledPosition == -1)
             sampledPosition = 0;
 
+        if (ifile == null)
+            return null;
+
         Iterator<FileDataInput> segments = ifile.iterator(sampledPosition);
         while (segments.hasNext())
         {
@@ -1480,7 +1508,8 @@ public class SSTableReader extends SSTable implements Closeable
     private void dropPageCache()
     {
         dropPageCache(dfile.path);
-        dropPageCache(ifile.path);
+        if (null != ifile)
+            dropPageCache(ifile.path);
     }
 
     private void dropPageCache(String filePath)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/452d6a44/src/java/org/apache/cassandra/tools/StandaloneScrubber.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/tools/StandaloneScrubber.java b/src/java/org/apache/cassandra/tools/StandaloneScrubber.java
index 26768f3..8ace228 100644
--- a/src/java/org/apache/cassandra/tools/StandaloneScrubber.java
+++ b/src/java/org/apache/cassandra/tools/StandaloneScrubber.java
@@ -79,7 +79,7 @@ public class StandaloneScrubber
             for (Map.Entry<Descriptor, Set<Component>> entry : lister.list().entrySet())
             {
                 Set<Component> components = entry.getValue();
-                if (!components.contains(Component.DATA) || !components.contains(Component.PRIMARY_INDEX))
+                if (!components.contains(Component.DATA))
                     continue;
 
                 try

http://git-wip-us.apache.org/repos/asf/cassandra/blob/452d6a44/test/unit/org/apache/cassandra/db/ScrubTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/db/ScrubTest.java b/test/unit/org/apache/cassandra/db/ScrubTest.java
index 94c7e34..978b3e8 100644
--- a/test/unit/org/apache/cassandra/db/ScrubTest.java
+++ b/test/unit/org/apache/cassandra/db/ScrubTest.java
@@ -270,6 +270,31 @@ public class ScrubTest extends SchemaLoader
     }
 
     @Test
+    public void testScrubNoIndex() throws IOException, ExecutionException, InterruptedException,
ConfigurationException
+    {
+        CompactionManager.instance.disableAutoCompaction();
+        Keyspace keyspace = Keyspace.open(KEYSPACE);
+        ColumnFamilyStore cfs = keyspace.getColumnFamilyStore(CF);
+        cfs.clearUnsafe();
+
+        List<Row> rows;
+
+        // insert data and verify we get it back w/ range query
+        fillCF(cfs, 10);
+        rows = cfs.getRangeSlice(Util.range("", ""), null, new IdentityQueryFilter(), 1000);
+        assertEquals(10, rows.size());
+
+        for (SSTableReader sstable : cfs.getSSTables())
+            new File(sstable.descriptor.filenameFor(Component.PRIMARY_INDEX)).delete();
+
+        CompactionManager.instance.performScrub(cfs, false, true);
+
+        // check data is still there
+        rows = cfs.getRangeSlice(Util.range("", ""), null, new IdentityQueryFilter(), 1000);
+        assertEquals(10, rows.size());
+    }
+
+    @Test
     public void testScrubOutOfOrder() throws Exception
     {
         CompactionManager.instance.disableAutoCompaction();


Mime
View raw message