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)
{