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 2009/06/23 19:48:01 UTC

svn commit: r787760 - in /incubator/cassandra/trunk: src/java/org/apache/cassandra/db/ src/java/org/apache/cassandra/io/ src/java/org/apache/cassandra/loader/ test/unit/org/apache/cassandra/io/

Author: jbellis
Date: Tue Jun 23 17:48:00 2009
New Revision: 787760

URL: http://svn.apache.org/viewvc?rev=787760&view=rev
Log:
encapsulate sstable index
patch by jbellis; reviewed by Eric Evans for CASSANDRA-224

Modified:
    incubator/cassandra/trunk/src/java/org/apache/cassandra/db/BinaryMemtable.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/db/Memtable.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/io/BufferedRandomAccessFile.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/io/SSTable.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/loader/Loader.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/loader/PreLoad.java
    incubator/cassandra/trunk/test/unit/org/apache/cassandra/io/SSTableTest.java

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/db/BinaryMemtable.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/db/BinaryMemtable.java?rev=787760&r1=787759&r2=787760&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/db/BinaryMemtable.java (original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/db/BinaryMemtable.java Tue Jun 23 17:48:00 2009
@@ -160,7 +160,7 @@
                 bf.add(key);
             }
         }
-        ssTable.closeRename(bf);
+        ssTable.close(bf);
         cfStore.storeLocation( ssTable.getDataFileLocation(), bf );
         columnFamilies_.clear();       
     }

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java?rev=787760&r1=787759&r2=787760&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java (original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java Tue Jun 23 17:48:00 2009
@@ -25,7 +25,6 @@
 import javax.management.ObjectName;
 import java.util.*;
 import java.util.concurrent.*;
-import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -46,7 +45,6 @@
 import org.apache.cassandra.concurrent.DebuggableThreadPoolExecutor;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.collections.IteratorUtils;
-import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.collections.comparators.ReverseComparator;
 
 import org.cliffc.high_scale_lib.NonBlockingHashMap;
@@ -994,7 +992,7 @@
                     SSTable.storeBloomFilter(newfile, compactedBloomFilters.get(0));
                 }
             }
-            SSTable.delete(file);
+            SSTable.open(file, null).delete();
         }
         finally
         {
@@ -1183,7 +1181,7 @@
 
         if (ssTableRange != null)
         {
-            ssTableRange.closeRename(compactedRangeBloomFilter);
+            ssTableRange.close(compactedRangeBloomFilter);
             if (fileList != null)
             {
                 fileList.add(ssTableRange.getDataFileLocation());
@@ -1360,7 +1358,7 @@
         if (ssTable != null)
         {
             // TODO if all the keys were the same nothing will be done here
-            ssTable.closeRename(compactedBloomFilter);
+            ssTable.close(compactedBloomFilter);
             newfile = ssTable.getDataFileLocation();
         }
         lock_.writeLock().lock();
@@ -1379,7 +1377,7 @@
             }
             for (String file : files)
             {
-                SSTable.delete(file);
+                SSTable.open(file, null).delete();
             }
         }
         finally

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/db/Memtable.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/db/Memtable.java?rev=787760&r1=787759&r2=787760&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/db/Memtable.java (original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/db/Memtable.java Tue Jun 23 17:48:00 2009
@@ -282,7 +282,7 @@
                 bf.add(key);
             }
         }
-        ssTable.closeRename(bf);
+        ssTable.close(bf);
         cfStore.onMemtableFlush(cLogCtx);
         cfStore.storeLocation( ssTable.getDataFileLocation(), bf );
         buffer.close();

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/io/BufferedRandomAccessFile.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/io/BufferedRandomAccessFile.java?rev=787760&r1=787759&r2=787760&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/io/BufferedRandomAccessFile.java (original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/io/BufferedRandomAccessFile.java Tue Jun 23 17:48:00 2009
@@ -155,6 +155,7 @@
     public void close() throws IOException
     {
         this.flush();
+        this.buff_ = null;
         super.close();
     }
     

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/io/SSTable.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/io/SSTable.java?rev=787760&r1=787759&r2=787760&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/io/SSTable.java (original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/io/SSTable.java Tue Jun 23 17:48:00 2009
@@ -48,8 +48,6 @@
 public class SSTable
 {
     private static Logger logger_ = Logger.getLogger(SSTable.class);
-    /* use this as a monitor to lock when loading index. */
-    private static Object indexLoadLock_ = new Object();
     /* Every 128th key is an index. */
     private static final int indexInterval_ = 128;
     /* Required extension for temporary files created during compactions. */
@@ -61,40 +59,14 @@
      */
     private static Map<String, BloomFilter> bfs_ = new Hashtable<String, BloomFilter>();
 
+    private static FileSSTableMap openedFiles = new FileSSTableMap();
+
 
     public static int indexInterval()
     {
         return indexInterval_;
     }
 
-    /*
-     * Maintains a list of KeyPosition objects per SSTable file loaded.
-     * We do this so that we don't read the index file into memory multiple
-     * times.
-     *
-     * The positions here refer to positions _in the index file_, not in
-     * the sstable file directly.  So looking up a data location is a two
-     * step process: use this map to find the location of the original index
-     * entry, then read the data file at the location given by the index.
-    */
-    static IndexMap indexMetadataMap_ = new IndexMap();
-
-    /**
-     * This method deletes both the specified data file
-     * and the associated index file
-     *
-     * @param dataFile - data file associated with the SSTable
-     */
-    public static void delete(String dataFile) throws IOException
-    {
-        /* remove the cached index table from memory */
-        indexMetadataMap_.remove(dataFile);
-
-        deleteWithConfirm(new File(dataFile));
-        deleteWithConfirm(new File(indexFilename(dataFile)));
-        deleteWithConfirm(new File(filterFilename(dataFile)));
-    }
-
     private static void deleteWithConfirm(File file) throws IOException
     {
         assert file.exists() : "attempted to delete non-existing file " + file.getName();
@@ -104,19 +76,18 @@
         }
     }
 
+    // todo can we refactor to take list of sstables?
     public static int getApproximateKeyCount(List<String> dataFiles)
     {
         int count = 0;
 
-        for (String dataFile : dataFiles)
+        for (String dataFileName : dataFiles)
         {
-            List<KeyPosition> index = indexMetadataMap_.get(dataFile);
-            if (index != null)
-            {
-                int indexKeyCount = index.size();
-                count = count + (indexKeyCount + 1) * indexInterval_;
-                logger_.debug("index size for bloom filter calc for file  : " + dataFile + "   : " + count);
-            }
+            SSTable sstable = openedFiles.get(dataFileName);
+            assert sstable != null;
+            int indexKeyCount = sstable.getIndexPositions().size();
+            count = count + (indexKeyCount + 1) * indexInterval_;
+            logger_.debug("index size for bloom filter calc for file  : " + dataFileName + "   : " + count);
         }
 
         return count;
@@ -127,21 +98,17 @@
      */
     public static List<String> getIndexedKeys()
     {
-        Set<String> indexFiles = indexMetadataMap_.keySet();
-        List<KeyPosition> positions = new ArrayList<KeyPosition>();
-
-        for (String indexFile : indexFiles)
-        {
-            positions.addAll(indexMetadataMap_.get(indexFile));
-        }
-
         List<String> indexedKeys = new ArrayList<String>();
-        for (KeyPosition kp : positions)
+
+        for (SSTable sstable : openedFiles.values())
         {
-            indexedKeys.add(kp.key);
+            for (KeyPosition kp : sstable.getIndexPositions())
+            {
+                indexedKeys.add(kp.key);
+            }
         }
-
         Collections.sort(indexedKeys);
+
         return indexedKeys;
     }
 
@@ -204,17 +171,25 @@
     private BufferedRandomAccessFile indexRAF_;
     private String lastWrittenKey_;
     private IPartitioner partitioner_;
+    List<KeyPosition> indexPositions_;
+
 
     public static synchronized SSTable open(String dataFileName, IPartitioner partitioner) throws IOException
     {
-        SSTable sstable = new SSTable(dataFileName, partitioner);
-        sstable.dataWriter_.close(); // todo this is dumb
-        if (indexMetadataMap_.get(dataFileName) == null)
+        SSTable sstable = openedFiles.get(dataFileName);
+        if (sstable == null)
         {
+            assert partitioner != null;
+            sstable = new SSTable(dataFileName, partitioner);
+            sstable.dataWriter_.close(); // todo this is dumb
+            sstable.indexRAF_.close();
+
             long start = System.currentTimeMillis();
             sstable.loadIndexFile();
             sstable.loadBloomFilter();
             logger_.debug("INDEX LOAD TIME for "  + dataFileName + ": " + (System.currentTimeMillis() - start) + " ms.");
+
+            openedFiles.put(dataFileName, sstable);
         }
         return sstable;
     }
@@ -242,6 +217,11 @@
         return parts[0];
     }
 
+    public List<KeyPosition> getIndexPositions()
+    {
+        return indexPositions_;
+    }
+
     private void loadBloomFilter() throws IOException
     {
         assert bfs_.get(dataFile_) == null;
@@ -252,7 +232,7 @@
     private void loadIndexFile() throws IOException
     {
         BufferedRandomAccessFile input = new BufferedRandomAccessFile(indexFilename(), "r");
-        ArrayList<KeyPosition> indexEntries = new ArrayList<KeyPosition>();
+        indexPositions_ = new ArrayList<KeyPosition>();
 
         int i = 0;
         long indexSize = input.length();
@@ -267,11 +247,9 @@
             input.readLong();
             if (i++ % indexInterval_ == 0)
             {
-                indexEntries.add(new KeyPosition(decoratedKey, indexPosition, partitioner_));
+                indexPositions_.add(new KeyPosition(decoratedKey, indexPosition, partitioner_));
             }
         }
-
-        indexMetadataMap_.put(dataFile_, indexEntries);
     }
 
     private static String indexFilename(String dataFile)
@@ -339,13 +317,11 @@
 
         if (keysWritten++ % indexInterval_ != 0)
             return;
-        List<KeyPosition> indexEntries = SSTable.indexMetadataMap_.get(dataFile_);
-        if (indexEntries == null)
+        if (indexPositions_ == null)
         {
-            indexEntries = new ArrayList<KeyPosition>();
-            SSTable.indexMetadataMap_.put(dataFile_, indexEntries);
+            indexPositions_ = new ArrayList<KeyPosition>();
         }
-        indexEntries.add(new KeyPosition(decoratedKey, indexPosition, partitioner_));
+        indexPositions_.add(new KeyPosition(decoratedKey, indexPosition, partitioner_));
         logger_.trace("wrote index of " + decoratedKey + " at " + indexPosition);
     }
 
@@ -367,7 +343,7 @@
     /** get the position in the index file to start scanning to find the given key (at most indexInterval keys away) */
     private static long getIndexScanPosition(String decoratedKey, IFileReader dataReader, IPartitioner partitioner)
     {
-        List<KeyPosition> positions = indexMetadataMap_.get(dataReader.getFileName());
+        List<KeyPosition> positions = openedFiles.get(dataReader.getFileName()).getIndexPositions();
         assert positions != null && positions.size() > 0;
         int index = Collections.binarySearch(positions, new KeyPosition(decoratedKey, -1, partitioner));
         if (index < 0)
@@ -509,6 +485,16 @@
         return next(clientKey, columnFamilyName, cnNames);
     }
 
+    private static String rename(String tmpFilename)
+    {
+        String filename = tmpFilename.replace("-" + temporaryFile_, "");
+        new File(tmpFilename).renameTo(new File(filename));
+        return filename;
+    }
+
+    /**
+     * Renames temporary SSTable files to valid data, index, and bloom filter files
+     */
     public void close(BloomFilter bf) throws IOException
     {
         // bloom filter
@@ -525,29 +511,12 @@
 
         // main data
         dataWriter_.close(); // calls force
-    }
-    
-    private static String rename(String tmpFilename)
-    {
-        String filename = tmpFilename.replace("-" + temporaryFile_, "");
-        new File(tmpFilename).renameTo(new File(filename));
-        return filename;
-    }
 
-    /**
-     * Renames temporary SSTable files to valid data, index, and bloom filter files
-     */
-    public void closeRename(BloomFilter bf) throws IOException
-    {
-    	close(bf);
-
-        String oldDataFileName = dataFile_;
         rename(indexFilename());
         rename(filterFilename());
         dataFile_ = rename(dataFile_); // important to do this last since index & filter file names are derived from it
 
-    	List<KeyPosition> positions = SSTable.indexMetadataMap_.remove(oldDataFileName);
-    	SSTable.indexMetadataMap_.put(dataFile_, positions);
+        openedFiles.put(dataFile_, this);
     }
 
     /**
@@ -570,11 +539,29 @@
         }
     }
 
+    public void delete() throws IOException
+    {
+        deleteWithConfirm(new File(dataFile_));
+        deleteWithConfirm(new File(indexFilename(dataFile_)));
+        deleteWithConfirm(new File(filterFilename(dataFile_)));
+    }
+
     /** obviously only for testing */
     public static void forceBloomFilterFailures(String filename)
     {
         SSTable.bfs_.put(filename, BloomFilter.alwaysMatchingBloomFilter());
     }
+
+    static void reopenUnsafe() throws IOException // testing only
+    {
+        Collection<SSTable> sstables = new ArrayList<SSTable>(openedFiles.values());
+        openedFiles.clear();
+        bfs_.clear();
+        for (SSTable sstable : sstables)
+        {
+            SSTable.open(sstable.dataFile_, sstable.partitioner_);
+        }
+    }
 }
 
 /**
@@ -608,19 +595,15 @@
     }
 }
 
-/**
- * wraps a Map to ensure that all filenames used as keys are cannonicalized.
- * (Note that cannonical paths are cached by the JDK so the performance hit is negligible.)
- */
-class IndexMap
+class FileSSTableMap
 {
-    private final Hashtable<String, List<KeyPosition>> hashtable = new Hashtable<String, List<KeyPosition>>();
+    private final HashMap<String, SSTable> map = new HashMap<String, SSTable>();
 
-    private String cannonicalize(String filename)
+    public SSTable get(String filename)
     {
         try
         {
-            return new File(filename).getCanonicalPath();
+            return map.get(new File(filename).getCanonicalPath());
         }
         catch (IOException e)
         {
@@ -628,28 +611,25 @@
         }
     }
 
-    public List<KeyPosition> get(String filename)
+    public SSTable put(String filename, SSTable value)
     {
-        return hashtable.get(cannonicalize(filename));
+        try
+        {
+            return map.put(new File(filename).getCanonicalPath(), value);
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException(e);
+        }
     }
 
-    public List<KeyPosition> put(String filename, List<KeyPosition> value)
+    public Collection<SSTable> values()
     {
-        return hashtable.put(cannonicalize(filename), value);
+        return map.values();
     }
 
     public void clear()
     {
-        hashtable.clear();
-    }
-
-    public Set<String> keySet()
-    {
-        return hashtable.keySet();
+        map.clear();
     }
-
-    public List<KeyPosition> remove(String filename)
-    {
-        return hashtable.remove(cannonicalize(filename));
-    }
-}
+}
\ No newline at end of file

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/loader/Loader.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/loader/Loader.java?rev=787760&r1=787759&r2=787760&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/loader/Loader.java (original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/loader/Loader.java Tue Jun 23 17:48:00 2009
@@ -39,7 +39,6 @@
 import org.apache.cassandra.db.RowMutation;
 import org.apache.cassandra.db.Table;
 import org.apache.cassandra.io.SSTable;
-import org.apache.cassandra.locator.EndPointSnitch;
 import org.apache.cassandra.net.EndPoint;
 import org.apache.cassandra.service.StorageService;
 import org.apache.cassandra.utils.LogUtil;
@@ -48,7 +47,6 @@
 import org.apache.lucene.analysis.Token;
 import org.apache.lucene.analysis.TokenStream;
 import org.apache.lucene.analysis.standard.StandardAnalyzer;
-import org.apache.cassandra.utils.*;
 
 
 /**
@@ -336,7 +334,7 @@
             */
 
             // TODO Hmm need to double check here
-            SSTable.delete(ssTables.get(0));
+            SSTable.open(ssTables.get(0), null).delete();
             logger_.info("Finished all the requisite clean up ...");
         }
     }

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/loader/PreLoad.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/loader/PreLoad.java?rev=787760&r1=787759&r2=787760&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/loader/PreLoad.java (original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/loader/PreLoad.java Tue Jun 23 17:48:00 2009
@@ -19,7 +19,6 @@
 package org.apache.cassandra.loader;
 
 import java.io.BufferedReader;
-import java.io.File;
 import java.io.FileInputStream;
 import java.io.InputStreamReader;
 import java.util.List;
@@ -117,7 +116,7 @@
              * Do the cleanup necessary. Delete all commit logs and
              * the SSTables and reset the load state in the StorageService.
             */
-            SSTable.delete(ssTables.get(0));
+            SSTable.open(ssTables.get(0), null).delete();
         }
         logger_.info("Finished all the requisite clean up ...");
     }

Modified: incubator/cassandra/trunk/test/unit/org/apache/cassandra/io/SSTableTest.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/test/unit/org/apache/cassandra/io/SSTableTest.java?rev=787760&r1=787759&r2=787760&view=diff
==============================================================================
--- incubator/cassandra/trunk/test/unit/org/apache/cassandra/io/SSTableTest.java (original)
+++ incubator/cassandra/trunk/test/unit/org/apache/cassandra/io/SSTableTest.java Tue Jun 23 17:48:00 2009
@@ -33,11 +33,10 @@
 {
     @Test
     public void testSingleWrite() throws IOException {
-        File f = File.createTempFile("sstable", "");
-        SSTable ssTable;
+        File f = File.createTempFile("sstable", "-" + SSTable.temporaryFile_);
 
         // write test data
-        ssTable = new SSTable(f.getParent(), f.getName(), new OrderPreservingPartitioner());
+        SSTable ssTable = new SSTable(f.getParent(), f.getName(), new OrderPreservingPartitioner());
         BloomFilter bf = new BloomFilter(1000, 8);
         Random random = new Random();
         byte[] bytes = new byte[1024];
@@ -49,14 +48,14 @@
         ssTable.close(bf);
 
         // verify
-        verifySingle(f, bytes, key);
-        SSTable.indexMetadataMap_.clear(); // force reloading the index
-        verifySingle(f, bytes, key);
+        verifySingle(ssTable.dataFile_, bytes, key);
+        SSTable.reopenUnsafe(); // force reloading the index
+        verifySingle(ssTable.dataFile_, bytes, key);
     }
 
-    private void verifySingle(File f, byte[] bytes, String key) throws IOException
+    private void verifySingle(String filename, byte[] bytes, String key) throws IOException
     {
-        SSTable ssTable = SSTable.open(f.getPath() + "-Data.db", new OrderPreservingPartitioner());
+        SSTable ssTable = SSTable.open(filename, new OrderPreservingPartitioner());
         FileStruct fs = new FileStruct(SequenceFile.bufferedReader(ssTable.dataFile_, 128 * 1024), new OrderPreservingPartitioner());
         fs.seekTo(key);
         int size = fs.getBufIn().readInt();
@@ -67,8 +66,7 @@
 
     @Test
     public void testManyWrites() throws IOException {
-        File f = File.createTempFile("sstable", "");
-        SSTable ssTable;
+        File f = File.createTempFile("sstable", "-" + SSTable.temporaryFile_);
 
         TreeMap<String, byte[]> map = new TreeMap<String,byte[]>();
         for ( int i = 100; i < 1000; ++i )
@@ -77,7 +75,7 @@
         }
 
         // write
-        ssTable = new SSTable(f.getParent(), f.getName(), new OrderPreservingPartitioner());
+        SSTable ssTable = new SSTable(f.getParent(), f.getName(), new OrderPreservingPartitioner());
         BloomFilter bf = new BloomFilter(1000, 8);
         for (String key: map.navigableKeySet())
         {
@@ -86,16 +84,16 @@
         ssTable.close(bf);
 
         // verify
-        verifyMany(f, map);
-        SSTable.indexMetadataMap_.clear(); // force reloading the index
-        verifyMany(f, map);
+        verifyMany(ssTable.dataFile_, map);
+        SSTable.reopenUnsafe(); // force reloading the index
+        verifyMany(ssTable.dataFile_, map);
     }
 
-    private void verifyMany(File f, TreeMap<String, byte[]> map) throws IOException
+    private void verifyMany(String filename, TreeMap<String, byte[]> map) throws IOException
     {
         List<String> keys = new ArrayList(map.keySet());
         Collections.shuffle(keys);
-        SSTable ssTable = SSTable.open(f.getPath() + "-Data.db", new OrderPreservingPartitioner());
+        SSTable ssTable = SSTable.open(filename, new OrderPreservingPartitioner());
         FileStruct fs = new FileStruct(SequenceFile.bufferedReader(ssTable.dataFile_, 128 * 1024), new OrderPreservingPartitioner());
         for (String key : keys)
         {