You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by jb...@apache.org on 2010/10/22 01:14:59 UTC

svn commit: r1026177 - in /cassandra/trunk: ./ src/java/org/apache/cassandra/db/ src/java/org/apache/cassandra/db/commitlog/ src/java/org/apache/cassandra/service/ test/unit/org/apache/cassandra/ test/unit/org/apache/cassandra/db/

Author: jbellis
Date: Thu Oct 21 23:14:59 2010
New Revision: 1026177

URL: http://svn.apache.org/viewvc?rev=1026177&view=rev
Log:
fix commitlog recovery deleting the newly-created segment as well as the old ones
patch by jbellis; reviewed by gdusbabek for CASSANDRA-1644

Modified:
    cassandra/trunk/CHANGES.txt
    cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
    cassandra/trunk/src/java/org/apache/cassandra/db/Table.java
    cassandra/trunk/src/java/org/apache/cassandra/db/commitlog/BatchCommitLogExecutorService.java
    cassandra/trunk/src/java/org/apache/cassandra/db/commitlog/CommitLog.java
    cassandra/trunk/src/java/org/apache/cassandra/service/StorageService.java
    cassandra/trunk/test/unit/org/apache/cassandra/CleanupHelper.java
    cassandra/trunk/test/unit/org/apache/cassandra/db/RecoveryManager2Test.java
    cassandra/trunk/test/unit/org/apache/cassandra/db/RecoveryManager3Test.java
    cassandra/trunk/test/unit/org/apache/cassandra/db/RecoveryManagerTest.java

Modified: cassandra/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/cassandra/trunk/CHANGES.txt?rev=1026177&r1=1026176&r2=1026177&view=diff
==============================================================================
--- cassandra/trunk/CHANGES.txt (original)
+++ cassandra/trunk/CHANGES.txt Thu Oct 21 23:14:59 2010
@@ -54,6 +54,8 @@ dev
  * cli --file option (CASSANDRA-1616)
  * reduce automatically chosen memtable sizes by 50% (CASSANDRA-1641)
  * move endpoint cache from snitch to strategy (CASSANDRA-1643)
+ * fix commitlog recovery deleting the newly-created segment as well as
+   the old ones (CASSANDRA-1644)
 
 
 0.7-beta2
@@ -95,8 +97,6 @@ dev
  * Add CfDef.default_validation_class (CASSANDRA-891)
  * fix EstimatedHistogram.max (CASSANDRA-1413)
  * quorum read optimization (CASSANDRA-1622)
-
-
  * handle zero-length (or missing) rows during HH paging (CASSANDRA-1432)
  * include secondary indexes during schema migrations (CASSANDRA-1406)
  * fix commitlog header race during schema change (CASSANDRA-1435)

Modified: cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java?rev=1026177&r1=1026176&r2=1026177&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java Thu Oct 21 23:14:59 2010
@@ -575,7 +575,7 @@ public class ColumnFamilyStore implement
 
             assert memtable == oldMemtable;
             memtable.freeze();
-            final CommitLogSegment.CommitLogContext ctx = writeCommitLog ? CommitLog.instance().getContext() : null;
+            final CommitLogSegment.CommitLogContext ctx = writeCommitLog ? CommitLog.instance.getContext() : null;
             logger.info("switching in a fresh Memtable for " + columnFamily + " at " + ctx);
 
             // submit the memtable for any indexed sub-cfses, and our own.
@@ -605,7 +605,7 @@ public class ColumnFamilyStore implement
                     {
                         // if we're not writing to the commit log, we are replaying the log, so marking
                         // the log header with "you can discard anything written before the context" is not valid
-                        CommitLog.instance().discardCompletedSegments(metadata.cfId, ctx);
+                        CommitLog.instance.discardCompletedSegments(metadata.cfId, ctx);
                     }
                 }
             });

Modified: cassandra/trunk/src/java/org/apache/cassandra/db/Table.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/db/Table.java?rev=1026177&r1=1026176&r2=1026177&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/db/Table.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/db/Table.java Thu Oct 21 23:14:59 2010
@@ -62,9 +62,8 @@ public class Table
      */
     static final ReentrantReadWriteLock flusherLock = new ReentrantReadWriteLock(true);
 
-    // This is a result of pushing down the point in time when storage directories get created.  It used to happen in
-    // CassandraDaemon, but it is possible to call Table.open without a running daemon, so it made sense to ensure
-    // proper directories here.
+    // It is possible to call Table.open without a running daemon, so it makes sense to ensure
+    // proper directories here as well as in CassandraDaemon.
     static
     {
         try
@@ -73,7 +72,7 @@ public class Table
         }
         catch (IOException ex)
         {
-            throw new RuntimeException(ex);
+            throw new IOError(ex);
         }
     }
 
@@ -350,7 +349,7 @@ public class Table
         try
         {
             if (writeCommitLog)
-                CommitLog.instance().add(mutation, serializedMutation);
+                CommitLog.instance.add(mutation, serializedMutation);
         
             DecoratedKey key = StorageService.getPartitioner().decorateKey(mutation.key());
             for (ColumnFamily cf : mutation.getColumnFamilies())

Modified: cassandra/trunk/src/java/org/apache/cassandra/db/commitlog/BatchCommitLogExecutorService.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/db/commitlog/BatchCommitLogExecutorService.java?rev=1026177&r1=1026176&r2=1026177&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/db/commitlog/BatchCommitLogExecutorService.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/db/commitlog/BatchCommitLogExecutorService.java Thu Oct 21 23:14:59 2010
@@ -95,7 +95,7 @@ class BatchCommitLogExecutorService exte
         // now sync and set the tasks' values (which allows thread calling get() to proceed)
         try
         {
-            CommitLog.instance().sync();
+            CommitLog.instance.sync();
         }
         catch (IOException e)
         {

Modified: cassandra/trunk/src/java/org/apache/cassandra/db/commitlog/CommitLog.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/db/commitlog/CommitLog.java?rev=1026177&r1=1026176&r2=1026177&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/db/commitlog/CommitLog.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/db/commitlog/CommitLog.java Thu Oct 21 23:14:59 2010
@@ -80,15 +80,7 @@ public class CommitLog
 
     static final Logger logger = LoggerFactory.getLogger(CommitLog.class);
 
-    public static CommitLog instance()
-    {
-        return CLHandle.instance;
-    }
-
-    private static class CLHandle
-    {
-        public static final CommitLog instance = new CommitLog();
-    }
+    public static final CommitLog instance = new CommitLog();
 
     private final Deque<CommitLogSegment> segments = new ArrayDeque<CommitLogSegment>();
 
@@ -97,11 +89,6 @@ public class CommitLog
         SEGMENT_SIZE = size;
     }
 
-    public int getSegmentCount()
-    {
-        return segments.size();
-    }
-
     private final ICommitLogExecutorService executor;
 
     /**
@@ -112,10 +99,19 @@ public class CommitLog
     */
     private CommitLog()
     {
+        try
+        {
+            DatabaseDescriptor.createAllDirectories();
+        }
+        catch (IOException e)
+        {
+            throw new IOError(e);
+        }
+
         // all old segments are recovered and deleted before CommitLog is instantiated.
         // All we need to do is create a new one.
         segments.add(new CommitLogSegment());
-        
+
         if (DatabaseDescriptor.getCommitLogSync() == Config.CommitLogSync.periodic)
         {
             executor = new PeriodicCommitLogExecutorService();
@@ -157,6 +153,22 @@ public class CommitLog
         }
     }
 
+    public void resetUnsafe()
+    {
+        segments.clear();
+        segments.add(new CommitLogSegment());
+    }
+
+    private boolean manages(String name)
+    {
+        for (CommitLogSegment segment : segments)
+        {
+            if (segment.getPath().endsWith(name))
+                return true;
+        }
+        return false;
+    }
+
     public static void recover() throws IOException
     {
         String directory = DatabaseDescriptor.getCommitLogLocation();
@@ -164,11 +176,17 @@ public class CommitLog
         {
             public boolean accept(File dir, String name)
             {
-                return CommitLogSegment.possibleCommitLogFile(name);
+                // we used to try to avoid instantiating commitlog (thus creating an empty segment ready for writes)
+                // until after recover was finished.  this turns out to be fragile; it is less error-prone to go
+                // ahead and allow writes before recover(), and just skip active segments when we do.
+                return CommitLogSegment.possibleCommitLogFile(name) && !instance.manages(name);
             }
         });
         if (files.length == 0)
+        {
+            logger.info("No commitlog files found; skipping replay");
             return;
+        }
 
         Arrays.sort(files, new FileUtils.FileComparator());
         logger.info("Replaying " + StringUtils.join(files, ", "));

Modified: cassandra/trunk/src/java/org/apache/cassandra/service/StorageService.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/service/StorageService.java?rev=1026177&r1=1026176&r2=1026177&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/service/StorageService.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/service/StorageService.java Thu Oct 21 23:14:59 2010
@@ -339,8 +339,6 @@ public class StorageService implements I
         initialized = true;
         isClientMode = false;
 
-        DatabaseDescriptor.createAllDirectories();
-
         try
         {
             GCInspector.instance.start();

Modified: cassandra/trunk/test/unit/org/apache/cassandra/CleanupHelper.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/test/unit/org/apache/cassandra/CleanupHelper.java?rev=1026177&r1=1026176&r2=1026177&view=diff
==============================================================================
--- cassandra/trunk/test/unit/org/apache/cassandra/CleanupHelper.java (original)
+++ cassandra/trunk/test/unit/org/apache/cassandra/CleanupHelper.java Thu Oct 21 23:14:59 2010
@@ -24,6 +24,7 @@ import java.io.IOException;
 import org.junit.BeforeClass;
 
 import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.db.commitlog.CommitLog;
 import org.apache.cassandra.io.util.FileUtils;
 
 import org.slf4j.Logger;
@@ -39,6 +40,7 @@ public class CleanupHelper extends Schem
         mkdirs();
         cleanup();
         mkdirs();
+        CommitLog.instance.resetUnsafe(); // cleanup screws w/ CommitLog, this brings it back to safe state
     }
 
     public static void cleanup() throws IOException

Modified: cassandra/trunk/test/unit/org/apache/cassandra/db/RecoveryManager2Test.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/test/unit/org/apache/cassandra/db/RecoveryManager2Test.java?rev=1026177&r1=1026176&r2=1026177&view=diff
==============================================================================
--- cassandra/trunk/test/unit/org/apache/cassandra/db/RecoveryManager2Test.java (original)
+++ cassandra/trunk/test/unit/org/apache/cassandra/db/RecoveryManager2Test.java Thu Oct 21 23:14:59 2010
@@ -62,6 +62,7 @@ public class RecoveryManager2Test extend
 
         logger.debug("begin manual replay");
         // replay the commit log (nothing should be replayed since everything was flushed)
+        CommitLog.instance.resetUnsafe();
         CommitLog.recover();
 
         // since everything that was flushed was removed (i.e. clearUnsafe)

Modified: cassandra/trunk/test/unit/org/apache/cassandra/db/RecoveryManager3Test.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/test/unit/org/apache/cassandra/db/RecoveryManager3Test.java?rev=1026177&r1=1026176&r2=1026177&view=diff
==============================================================================
--- cassandra/trunk/test/unit/org/apache/cassandra/db/RecoveryManager3Test.java (original)
+++ cassandra/trunk/test/unit/org/apache/cassandra/db/RecoveryManager3Test.java Thu Oct 21 23:14:59 2010
@@ -31,6 +31,7 @@ import org.apache.cassandra.CleanupHelpe
 import org.apache.cassandra.Util;
 import org.apache.cassandra.config.DatabaseDescriptor;
 import org.apache.cassandra.db.commitlog.CommitLog;
+import org.apache.cassandra.io.util.FileUtils;
 
 import static org.apache.cassandra.Util.column;
 import static org.apache.cassandra.db.TableTest.assertColumns;
@@ -66,10 +67,10 @@ public class RecoveryManager3Test extend
         for (File file : new File(DatabaseDescriptor.getCommitLogLocation()).listFiles())
         {
             if (file.getName().endsWith(".header"))
-                if (!file.delete())
-                    throw new AssertionError();
+                FileUtils.deleteWithConfirm(file);
         }
 
+        CommitLog.instance.resetUnsafe(); // disassociate segments from live CL
         CommitLog.recover();
 
         assertColumns(Util.getColumnFamily(table1, dk, "Standard1"), "col1");

Modified: cassandra/trunk/test/unit/org/apache/cassandra/db/RecoveryManagerTest.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/test/unit/org/apache/cassandra/db/RecoveryManagerTest.java?rev=1026177&r1=1026176&r2=1026177&view=diff
==============================================================================
--- cassandra/trunk/test/unit/org/apache/cassandra/db/RecoveryManagerTest.java (original)
+++ cassandra/trunk/test/unit/org/apache/cassandra/db/RecoveryManagerTest.java Thu Oct 21 23:14:59 2010
@@ -63,6 +63,7 @@ public class RecoveryManagerTest extends
         table1.getColumnFamilyStore("Standard1").clearUnsafe();
         table2.getColumnFamilyStore("Standard3").clearUnsafe();
 
+        CommitLog.instance.resetUnsafe(); // disassociate segments from live CL
         CommitLog.recover();
 
         assertColumns(Util.getColumnFamily(table1, dk, "Standard1"), "col1");