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/08/27 22:19:44 UTC

svn commit: r990251 - in /cassandra/trunk: ./ src/java/org/apache/cassandra/db/ src/java/org/apache/cassandra/db/migration/ test/unit/org/apache/cassandra/db/

Author: jbellis
Date: Fri Aug 27 20:19:44 2010
New Revision: 990251

URL: http://svn.apache.org/viewvc?rev=990251&view=rev
Log:
replace CF graveyard with CFS.removeAllSSTables (which is recursive to handle 2ary index files); also handle 2ary indexes in renaming migrations.
patch by jbellis and gdusbabek for CASSANDRA-1406

Modified:
    cassandra/trunk/CHANGES.txt
    cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
    cassandra/trunk/src/java/org/apache/cassandra/db/CompactionManager.java
    cassandra/trunk/src/java/org/apache/cassandra/db/SystemTable.java
    cassandra/trunk/src/java/org/apache/cassandra/db/Table.java
    cassandra/trunk/src/java/org/apache/cassandra/db/migration/DropColumnFamily.java
    cassandra/trunk/src/java/org/apache/cassandra/db/migration/DropKeyspace.java
    cassandra/trunk/src/java/org/apache/cassandra/db/migration/Migration.java
    cassandra/trunk/src/java/org/apache/cassandra/db/migration/RenameColumnFamily.java
    cassandra/trunk/src/java/org/apache/cassandra/db/migration/RenameKeyspace.java
    cassandra/trunk/test/unit/org/apache/cassandra/db/DefsTest.java

Modified: cassandra/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/cassandra/trunk/CHANGES.txt?rev=990251&r1=990250&r2=990251&view=diff
==============================================================================
--- cassandra/trunk/CHANGES.txt (original)
+++ cassandra/trunk/CHANGES.txt Fri Aug 27 20:19:44 2010
@@ -38,6 +38,7 @@ dev
  * Add CfDef.default_validation_class (CASSANDRA-891)
  * fix EstimatedHistogram.max (CASSANDRA-1413)
  * handle zero-length (or missing) rows during HH paging (CASSANDRA-1432)
+ * include secondary indexes during schema migrations (CASSANDRA-1406)
 
 
 0.7-beta1

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=990251&r1=990250&r2=990251&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java Fri Aug 27 20:19:44 2010
@@ -767,6 +767,15 @@ public class ColumnFamilyStore implement
         ssTables.replace(sstables, replacements);
     }
 
+    public void removeAllSSTables()
+    {
+        ssTables.replace(ssTables.getSSTables(), Collections.<SSTableReader>emptyList());
+        for (ColumnFamilyStore indexedCfs : indexedColumns.values())
+        {
+            indexedCfs.removeAllSSTables();
+        }
+    }
+
     /**
      * submits flush sort on the flushSorter executor, which will in turn submit to flushWriter when sorted.
      * TODO because our executors use CallerRunsPolicy, when flushSorter fills up, no writes will proceed
@@ -1547,6 +1556,33 @@ public class ColumnFamilyStore implement
         return postFlushExecutor.submit(runnable);
     }
 
+    // if this errors out, we are in a world of hurt.
+    public void renameSSTables(String newCfName) throws IOException
+    {
+        // complete as much of the job as possible.  Don't let errors long the way prevent as much renaming as possible
+        // from happening.
+        IOException mostRecentProblem = null;
+        for (File existing : DefsTable.getFiles(table, columnFamily))
+        {
+            try
+            {
+                String newFileName = existing.getName().replaceFirst("\\w+-", newCfName + "-");
+                FileUtils.renameWithConfirm(existing, new File(existing.getParent(), newFileName));
+            }
+            catch (IOException ex)
+            {
+                mostRecentProblem = ex;
+            }
+        }
+        if (mostRecentProblem != null)
+            throw new IOException("One or more IOExceptions encountered while renaming files. Most recent problem is included.", mostRecentProblem);
+
+        for (ColumnFamilyStore indexedCfs : indexedColumns.values())
+        {
+            indexedCfs.renameSSTables(indexedCfs.columnFamily.replace(columnFamily, newCfName));
+        }
+    }
+
     public static Future<?> submitPostFlush(Runnable runnable)
     {
         return postFlushExecutor.submit(runnable);

Modified: cassandra/trunk/src/java/org/apache/cassandra/db/CompactionManager.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/db/CompactionManager.java?rev=990251&r1=990250&r2=990251&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/db/CompactionManager.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/db/CompactionManager.java Fri Aug 27 20:19:44 2010
@@ -76,53 +76,6 @@ public class CompactionManager implement
 
     private CompactionExecutor executor = new CompactionExecutor();
     private Map<ColumnFamilyStore, Integer> estimatedCompactions = new NonBlockingHashMap<ColumnFamilyStore, Integer>();
-
-    /** cleans up data files for CFs that have been dropped. */
-    public Future submitGraveyardCleanup()
-    {
-        Callable c =  new Callable()
-        {
-            public Object call() throws Exception
-            {
-                logger.debug("Cleaning up abandoned column families...");
-                ColumnFamily dropped = SystemTable.getDroppedCFs();
-                if (dropped == null)
-                    // there is nothing that needs to be cleaned up.
-                    return null;
-                Collection<IColumn> successes = new ArrayList<IColumn>();
-                for (IColumn col : dropped.getSortedColumns())
-                {
-                    if (!col.isMarkedForDelete())
-                    {
-                        final String[] parts = new String(col.name()).split("-");
-                        // table-cfname-cfid
-                        for (String dataDir : DatabaseDescriptor.getAllDataFileLocationsForTable(parts[0]))
-                        {
-                            File dir = new File(dataDir);
-                            if (dir.exists())
-                            {
-                                File[] dbFiles = dir.listFiles(new FileFilter()
-                                {
-                                    public boolean accept(File pathname)
-                                    {
-                                        return pathname.getName().startsWith(parts[1] + "-") && pathname.exists();
-                                    }
-                                });
-                                for (File f : dbFiles)
-                                {
-                                    FileUtils.deleteWithConfirm(f);
-                                }
-                            }
-                        }
-                        successes.add(col);
-                    }
-                }
-                SystemTable.deleteDroppedCfMarkers(successes);
-                return null;
-            }
-        };
-        return executor.submit(c);
-    }
     
     /**
      * Call this whenever a compaction might be needed on the given columnfamily.

Modified: cassandra/trunk/src/java/org/apache/cassandra/db/SystemTable.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/db/SystemTable.java?rev=990251&r1=990250&r2=990251&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/db/SystemTable.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/db/SystemTable.java Fri Aug 27 20:19:44 2010
@@ -51,7 +51,6 @@ public class SystemTable
     public static final String STATUS_CF = "LocationInfo"; // keep the old CF string for backwards-compatibility
     private static final byte[] LOCATION_KEY = "L".getBytes(UTF_8);
     private static final byte[] BOOTSTRAP_KEY = "Bootstrap".getBytes(UTF_8);
-    private static final byte[] GRAVEYARD_KEY = "Graveyard".getBytes(UTF_8);
     private static final byte[] COOKIE_KEY = "Cookies".getBytes(UTF_8);
     private static final byte[] BOOTSTRAP = "B".getBytes(UTF_8);
     private static final byte[] TOKEN = "Token".getBytes(UTF_8);
@@ -337,38 +336,6 @@ public class SystemTable
         }
     }
 
-    public static ColumnFamily getDroppedCFs() throws IOException
-    {
-        ColumnFamilyStore cfs = Table.open(Table.SYSTEM_TABLE).getColumnFamilyStore(SystemTable.STATUS_CF);
-        return cfs.getColumnFamily(QueryFilter.getSliceFilter(decorate(GRAVEYARD_KEY), new QueryPath(STATUS_CF), "".getBytes(), "".getBytes(), false, 100));
-    }
-    
-    public static void deleteDroppedCfMarkers(Collection<IColumn> cols) throws IOException
-    {
-        RowMutation rm = new RowMutation(Table.SYSTEM_TABLE, GRAVEYARD_KEY);
-        long now = System.currentTimeMillis();
-        for (IColumn col : cols)
-            rm.delete(new QueryPath(STATUS_CF, null, col.name()), new TimestampClock(now));
-        rm.apply();
-    }
-    
-    /** when a cf is dropped, it needs to be marked so its files get deleted at some point. */
-    public static void markForRemoval(CFMetaData cfm)
-    {
-        ColumnFamily cf = ColumnFamily.create(Table.SYSTEM_TABLE, STATUS_CF);
-        cf.addColumn(new Column((cfm.tableName + "-" + cfm.cfName + "-" + cfm.cfId).getBytes(), ArrayUtils.EMPTY_BYTE_ARRAY, new TimestampClock(System.currentTimeMillis())));
-        RowMutation rm = new RowMutation(Table.SYSTEM_TABLE, GRAVEYARD_KEY);
-        rm.add(cf);
-        try
-        {
-            rm.apply();
-        }
-        catch (IOException e)
-        {
-            throw new RuntimeException(e);
-        }
-    }
-
     public static class StorageMetadata
     {
         private Token token;

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=990251&r1=990250&r2=990251&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/db/Table.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/db/Table.java Fri Aug 27 20:19:44 2010
@@ -19,7 +19,6 @@
 package org.apache.cassandra.db;
 
 import java.io.IOError;
-import java.lang.management.ManagementFactory;
 import java.util.*;
 import java.io.IOException;
 import java.io.File;
@@ -37,9 +36,6 @@ import org.apache.cassandra.io.sstable.S
 import org.apache.cassandra.io.sstable.SSTableReader;
 import org.apache.cassandra.io.util.FileUtils;
 
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-
 import org.apache.commons.lang.ArrayUtils;
 
 import org.apache.cassandra.service.StorageService;
@@ -251,10 +247,7 @@ public class Table
         }
 
         for (CFMetaData cfm : new ArrayList<CFMetaData>(DatabaseDescriptor.getTableDefinition(table).cfMetaData().values()))
-        {
-            ColumnFamilyStore cfs = ColumnFamilyStore.createColumnFamilyStore(table, cfm.cfName);
-            columnFamilyStores.put(cfm.cfId, cfs);
-        }
+            initCf(cfm.cfId, cfm.cfName);
 
         // check 10x as often as the lifetime, so we can exceed lifetime by 10% at most
         int checkMs = DatabaseDescriptor.getMemtableLifetimeMS() / 10;
@@ -271,28 +264,33 @@ public class Table
         flushTimer.schedule(flushTask, checkMs, checkMs);
     }
     
-    /** removes a cf from internal structures (doesn't change disk files). */
     public void dropCf(Integer cfId) throws IOException
     {
         assert columnFamilyStores.containsKey(cfId);
         ColumnFamilyStore cfs = columnFamilyStores.remove(cfId);
-        if (cfs != null)
+        if (cfs == null)
+            return;
+        
+        unloadCf(cfs);
+        cfs.removeAllSSTables();
+    }
+    
+    // disassociate a cfs from this table instance.
+    private void unloadCf(ColumnFamilyStore cfs) throws IOException
+    {
+        try
         {
-            try
-            {
-                cfs.forceBlockingFlush();
-            }
-            catch (ExecutionException e)
-            {
-                throw new IOException(e);
-            }
-            catch (InterruptedException e)
-            {
-                throw new IOException(e);
-            }
-            
-            cfs.unregisterMBean();
+            cfs.forceBlockingFlush();
         }
+        catch (ExecutionException e)
+        {
+            throw new IOException(e);
+        }
+        catch (InterruptedException e)
+        {
+            throw new IOException(e);
+        }
+        cfs.unregisterMBean();
     }
     
     /** adds a cf to internal structures, ends up creating disk files). */
@@ -306,7 +304,10 @@ public class Table
     /** basically a combined drop and add */
     public void renameCf(Integer cfId, String newName) throws IOException
     {
-        dropCf(cfId);
+        assert columnFamilyStores.containsKey(cfId);
+        ColumnFamilyStore cfs = columnFamilyStores.remove(cfId);
+        unloadCf(cfs);
+        cfs.renameSSTables(newName);
         initCf(cfId, newName);
     }
 

Modified: cassandra/trunk/src/java/org/apache/cassandra/db/migration/DropColumnFamily.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/db/migration/DropColumnFamily.java?rev=990251&r1=990250&r2=990251&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/db/migration/DropColumnFamily.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/db/migration/DropColumnFamily.java Fri Aug 27 20:19:44 2010
@@ -92,14 +92,8 @@ public class DropColumnFamily extends Mi
         if (!clientMode)
         {
             Table.open(ksm.name).dropCf(cfm.cfId);
-            
-            // indicate that some files need to be deleted (eventually)
-            SystemTable.markForRemoval(cfm);
-            
             // we don't really need a new segment, but let's force it to be consistent with other operations.
             CommitLog.instance().forceNewSegment();
-    
-            Migration.cleanupDeadFiles(blockOnFileDeletion);
         }
     }
     

Modified: cassandra/trunk/src/java/org/apache/cassandra/db/migration/DropKeyspace.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/db/migration/DropKeyspace.java?rev=990251&r1=990250&r2=990251&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/db/migration/DropKeyspace.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/db/migration/DropKeyspace.java Fri Aug 27 20:19:44 2010
@@ -73,7 +73,6 @@ public class DropKeyspace extends Migrat
             if (!clientMode)
             {
                 table.dropCf(cfm.cfId);
-                SystemTable.markForRemoval(cfm);
             }
         }
                         
@@ -83,8 +82,6 @@ public class DropKeyspace extends Migrat
         if (!clientMode)
         {
             CommitLog.instance().forceNewSegment();
-            Migration.cleanupDeadFiles(blockOnFileDeletion);
-            
             // clear up any local hinted data for this keyspace.
             HintedHandOffManager.renameHints(name, null);
         }

Modified: cassandra/trunk/src/java/org/apache/cassandra/db/migration/Migration.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/db/migration/Migration.java?rev=990251&r1=990250&r2=990251&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/db/migration/Migration.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/db/migration/Migration.java Fri Aug 27 20:19:44 2010
@@ -227,28 +227,7 @@ public abstract class Migration
                              now);
         return rm;
     }
-    
-    static void cleanupDeadFiles(boolean wait)
-    {
-        Future cleanup = CompactionManager.instance.submitGraveyardCleanup();
-        if (wait)
-        {
-            // notify the compaction manager that it needs to clean up the dropped cf files.
-            try
-            {
-                cleanup.get();
-            }
-            catch (InterruptedException e)
-            {
-                throw new RuntimeException(e);
-            }
-            catch (ExecutionException e)
-            {
-                throw new RuntimeException(e);
-            }
-        } 
-    }
-    
+        
     public byte[] serialize() throws IOException
     {
         // super deflate

Modified: cassandra/trunk/src/java/org/apache/cassandra/db/migration/RenameColumnFamily.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/db/migration/RenameColumnFamily.java?rev=990251&r1=990250&r2=990251&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/db/migration/RenameColumnFamily.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/db/migration/RenameColumnFamily.java Fri Aug 27 20:19:44 2010
@@ -87,8 +87,6 @@ public class RenameColumnFamily extends 
     {
         // leave it up to operators to ensure there are no writes going on durng the file rename. Just know that
         // attempting row mutations on oldcfName right now would be really bad.
-        if (!clientMode)
-            renameCfStorageFiles(tableName, oldName, newName);
         
         // reset defs.
         KSMetaData oldKsm = DatabaseDescriptor.getTableDefinition(tableName);
@@ -113,28 +111,6 @@ public class RenameColumnFamily extends 
         }
     }
     
-    // if this errors out, we are in a world of hurt.
-    private static void renameCfStorageFiles(String table, String oldCfName, String newCfName) throws IOException
-    {
-        // complete as much of the job as possible.  Don't let errors long the way prevent as much renaming as possible
-        // from happening.
-        IOException mostRecentProblem = null;
-        for (File existing : DefsTable.getFiles(table, oldCfName))
-        {
-            try
-            {
-                String newFileName = existing.getName().replaceFirst("\\w+-", newCfName + "-");
-                FileUtils.renameWithConfirm(existing, new File(existing.getParent(), newFileName));
-            }
-            catch (IOException ex)
-            {
-                mostRecentProblem = ex;
-            }
-        }
-        if (mostRecentProblem != null)
-            throw new IOException("One or more IOExceptions encountered while renaming files. Most recent problem is included.", mostRecentProblem);
-    }
-    
     public void subdeflate(org.apache.cassandra.db.migration.avro.Migration mi)
     {
         org.apache.cassandra.db.migration.avro.RenameColumnFamily rcf = new org.apache.cassandra.db.migration.avro.RenameColumnFamily();

Modified: cassandra/trunk/src/java/org/apache/cassandra/db/migration/RenameKeyspace.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/db/migration/RenameKeyspace.java?rev=990251&r1=990250&r2=990251&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/db/migration/RenameKeyspace.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/db/migration/RenameKeyspace.java Fri Aug 27 20:19:44 2010
@@ -36,6 +36,8 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 
+import org.apache.commons.lang.StringUtils;
+
 public class RenameKeyspace extends Migration
 {
     private String oldName;
@@ -119,26 +121,17 @@ public class RenameKeyspace extends Migr
     
     private static void renameKsStorageFiles(String oldKs, String newKs) throws IOException
     {
-        IOException mostRecentProblem = null;
-        Set<String> cfNames = DatabaseDescriptor.getTableDefinition(oldKs).cfMetaData().keySet();
-        for (String cfName : cfNames)
+        ArrayList<File> failed = new ArrayList<File>();
+        for (String dataDir : DatabaseDescriptor.getAllDataFileLocations())
         {
-            for (File existing : DefsTable.getFiles(oldKs, cfName))
-            {
-                try
-                {
-                    File newParent = new File(existing.getParentFile().getParent(), newKs);
-                    newParent.mkdirs();
-                    FileUtils.renameWithConfirm(existing, new File(newParent, existing.getName()));
-                }
-                catch (IOException ex)
-                {
-                    mostRecentProblem = ex;
-                }
-            }
+            File ksDir = new File(dataDir, oldKs);
+            if (ksDir.exists())
+                if (!ksDir.renameTo(new File(dataDir, newKs)))
+                    failed.add(ksDir);
         }
-        if (mostRecentProblem != null)
-            throw new IOException("One or more IOExceptions encountered while renaming files. Most recent problem is included.", mostRecentProblem);
+
+        if (!failed.isEmpty())
+            throw new IOException("One or more problems encountered while renaming " + StringUtils.join(failed, ","));
     }
     
     public void subdeflate(org.apache.cassandra.db.migration.avro.Migration mi)

Modified: cassandra/trunk/test/unit/org/apache/cassandra/db/DefsTest.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/test/unit/org/apache/cassandra/db/DefsTest.java?rev=990251&r1=990250&r2=990251&view=diff
==============================================================================
--- cassandra/trunk/test/unit/org/apache/cassandra/db/DefsTest.java (original)
+++ cassandra/trunk/test/unit/org/apache/cassandra/db/DefsTest.java Fri Aug 27 20:19:44 2010
@@ -18,10 +18,12 @@
 
 package org.apache.cassandra.db;
 
+import java.io.File;
 import java.io.IOException;
 import java.util.*;
 import java.util.concurrent.ExecutionException;
 
+import org.apache.commons.lang.StringUtils;
 import org.junit.Test;
 
 import org.apache.cassandra.CleanupHelper;
@@ -218,8 +220,12 @@ public class DefsTest extends CleanupHel
         assert !success : "This mutation should have failed since the CF no longer exists.";
 
         // verify that the files are gone.
-        assert DefsTable.getFiles(cfm.tableName, cfm.cfName).size() == 0;
-    }    
+        for (File file : DefsTable.getFiles(cfm.tableName, cfm.cfName))
+        {
+            if (file.getPath().endsWith("Data.db") && !new File(file.getPath().replace("Data.db", "Compacted")).exists())
+                throw new AssertionError("undeleted file " + file);
+        }
+    }
     
     @Test
     public void renameCf() throws ConfigurationException, IOException, ExecutionException, InterruptedException
@@ -373,7 +379,6 @@ public class DefsTest extends CleanupHel
         assert newKs.cfMetaData().containsKey(cfName);
         assert newKs.cfMetaData().get(cfName).tableName.equals(newKsName);
         assert DefsTable.getFiles(newKs.name, cfName).size() > 0;
-        assert DefsTable.getFiles(oldKs.name, cfName).size() == 0;
         
         // read on old should fail.
         try