diff --git a/src/java/org/apache/cassandra/io/SSTable.java b/src/java/org/apache/cassandra/io/SSTable.java index dd5082f04317..e576cf33a56e 100644 --- a/src/java/org/apache/cassandra/io/SSTable.java +++ b/src/java/org/apache/cassandra/io/SSTable.java @@ -42,7 +42,6 @@ import org.apache.cassandra.utils.BloomFilter; import org.apache.cassandra.utils.FileUtils; import org.apache.cassandra.utils.LogUtil; -import org.apache.cassandra.dht.IPartitioner; /** * This class is built on top of the SequenceFile. It stores @@ -198,7 +197,7 @@ public static int indexInterval() * We do this so that we don't read the index file into memory multiple * times. */ - static Map> indexMetadataMap_ = new Hashtable>(); + static IndexMap indexMetadataMap_ = new IndexMap(); /** * This method deletes both the specified data file @@ -348,7 +347,7 @@ public static boolean isKeyInFile(String clientKey, String filename) * ctor to read the data in this file. */ public SSTable(String dataFileName, IPartitioner partitioner) throws IOException - { + { dataFile_ = dataFileName; partitioner_ = partitioner; init(); @@ -359,7 +358,7 @@ public SSTable(String dataFileName, IPartitioner partitioner) throws IOException * version for non DB writes to the SSTable. */ public SSTable(String directory, String filename, IPartitioner partitioner) throws IOException - { + { dataFile_ = directory + System.getProperty("file.separator") + filename + "-Data.db"; partitioner_ = partitioner; blockIndex_ = new TreeMap(partitioner_.getReverseDecoratedKeyComparator()); @@ -660,58 +659,43 @@ public void append(String decoratedKey, byte[] value) throws IOException public static Coordinate getCoordinates(String decoratedKey, IFileReader dataReader, IPartitioner partitioner) throws IOException { List indexInfo = indexMetadataMap_.get(dataReader.getFileName()); - int size = (indexInfo == null) ? 0 : indexInfo.size(); - long start = 0L; + assert indexInfo != null && indexInfo.size() > 0; + long start = 0L; long end; - if ( size > 0 ) + int index = Collections.binarySearch(indexInfo, new KeyPositionInfo(decoratedKey, partitioner)); + if ( index < 0 ) { - int index = Collections.binarySearch(indexInfo, new KeyPositionInfo(decoratedKey, partitioner)); - if ( index < 0 ) + /* + * We are here which means that the requested + * key is not an index. + */ + index = (++index)*(-1); + /* + * This means key is not present at all. Hence + * a scan is in order. + */ + start = (index == 0) ? 0 : indexInfo.get(index - 1).position(); + if ( index < indexInfo.size()) { - /* - * We are here which means that the requested - * key is not an index. - */ - index = (++index)*(-1); - /* - * This means key is not present at all. Hence - * a scan is in order. - */ - start = (index == 0) ? 0 : indexInfo.get(index - 1).position(); - if ( index < size ) - { - end = indexInfo.get(index).position(); - } - else - { - /* This is the Block Index in the file. */ - end = start; - } + end = indexInfo.get(index).position(); } else { - /* - * If we are here that means the key is in the index file - * and we can retrieve it w/o a scan. In reality we would - * like to have a retreive(key, fromPosition) but for now - * we use scan(start, start + 1) - a hack. - */ - start = indexInfo.get(index).position(); + /* This is the Block Index in the file. */ end = start; } } else { /* - * We are here which means there are less than - * 128 keys in the system and hence our only recourse - * is a linear scan from start to finish. Automatically - * use memory mapping since we have a huge file and very - * few keys. + * If we are here that means the key is in the index file + * and we can retrieve it w/o a scan. In reality we would + * like to have a retreive(key, fromPosition) but for now + * we use scan(start, start + 1) - a hack. */ - end = dataReader.getEOF(); - } - + start = indexInfo.get(index).position(); + end = start; + } return new Coordinate(start, end); } @@ -798,9 +782,9 @@ public void closeRename(BloomFilter bf) throws IOException String tmpDataFile = dataFile_; String dataFileName = dataFile_.replace("-" + temporaryFile_,""); File dataFile = new File(dataFile_); - dataFile.renameTo(new File(dataFileName)); - dataFile_ = dataFileName; - /* Now repair the in memory index associated with the old name */ + dataFile.renameTo(new File(dataFileName)); + dataFile_ = dataFileName; + /* Now repair the in memory index associated with the old name */ List keyPositionInfos = SSTable.indexMetadataMap_.remove(tmpDataFile); SSTable.indexMetadataMap_.put(dataFile_, keyPositionInfos); } @@ -829,5 +813,51 @@ private void close(byte[] footer, int size) throws IOException dataWriter_.writeDirect(BasicUtilities.longToByteArray(bloomFilterRelativePosition)); dataWriter_.close(); } - } + } + + /** + * 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.) + */ + static class IndexMap + { + private final Hashtable> hashtable = new Hashtable>(); + + private String cannonicalize(String filename) + { + try + { + return new File(filename).getCanonicalPath(); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + public List get(String filename) + { + return hashtable.get(cannonicalize(filename)); + } + + public List put(String filename, List value) + { + return hashtable.put(cannonicalize(filename), value); + } + + public void clear() + { + hashtable.clear(); + } + + public Set keySet() + { + return hashtable.keySet(); + } + + public List remove(String filename) + { + return hashtable.remove(cannonicalize(filename)); + } + } } diff --git a/test/unit/org/apache/cassandra/io/SSTableTest.java b/test/unit/org/apache/cassandra/io/SSTableTest.java index cc854eae8fb2..1d5359b83192 100644 --- a/test/unit/org/apache/cassandra/io/SSTableTest.java +++ b/test/unit/org/apache/cassandra/io/SSTableTest.java @@ -29,7 +29,7 @@ public void testSingleWrite() throws IOException { ssTable.close(bf); // verify - SSTable.indexMetadataMap_.clear(); + SSTable.indexMetadataMap_.clear(); // force reloading the index ssTable = new SSTable(f.getPath() + "-Data.db", new OrderPreservingPartitioner()); FileStruct fs = new FileStruct(SequenceFile.bufferedReader(ssTable.dataFile_, 128 * 1024), new OrderPreservingPartitioner()); fs.seekTo(key); @@ -60,7 +60,7 @@ public void testManyWrites() throws IOException { ssTable.close(bf); // verify - SSTable.indexMetadataMap_.clear(); + SSTable.indexMetadataMap_.clear(); // force reloading the index List keys = new ArrayList(map.keySet()); Collections.shuffle(keys); ssTable = new SSTable(f.getPath() + "-Data.db", new OrderPreservingPartitioner());