HBASE-980 Undo core of HBASE-975, caching of start and end row

git-svn-id: https://svn.apache.org/repos/asf/hadoop/hbase/trunk@711207 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael Stack 2008-11-04 08:28:49 +00:00
parent d6997a949f
commit 062e954a03
6 changed files with 61 additions and 190 deletions

View File

@ -61,6 +61,7 @@ Release 0.19.0 - Unreleased
HBASE-977 Arcane HStoreKey comparator bug HBASE-977 Arcane HStoreKey comparator bug
HBASE-979 REST web app is not started automatically HBASE-979 REST web app is not started automatically
HBASE-964 Startup stuck "waiting for root region" HBASE-964 Startup stuck "waiting for root region"
HBASE-980 Undo core of HBASE-975, caching of start and end row
IMPROVEMENTS IMPROVEMENTS
HBASE-901 Add a limit to key length, check key and value length on client side HBASE-901 Add a limit to key length, check key and value length on client side

View File

@ -30,11 +30,13 @@ import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.HStoreKey;
import org.apache.hadoop.hbase.util.Hash; import org.apache.hadoop.hbase.util.Hash;
import org.apache.hadoop.io.SequenceFile; import org.apache.hadoop.io.SequenceFile;
import org.apache.hadoop.io.Writable; import org.apache.hadoop.io.Writable;
import org.apache.hadoop.io.WritableComparable; import org.apache.hadoop.io.WritableComparable;
import org.onelab.filter.BloomFilter; import org.onelab.filter.BloomFilter;
import org.onelab.filter.Key;
/** /**
* On write, all keys are added to a bloom filter. On read, all keys are * On write, all keys are added to a bloom filter. On read, all keys are
@ -228,4 +230,13 @@ public class BloomFilterMapFile extends HBaseMapFile {
} }
} }
} }
/**
* Custom bloom filter key maker.
* @param key
* @return Key made of bytes of row only.
*/
protected static Key getBloomFilterKey(WritableComparable key) {
return new Key(((HStoreKey) key).getRow());
}
} }

View File

@ -41,26 +41,18 @@ import org.onelab.filter.Key;
*/ */
public class HBaseMapFile extends MapFile { public class HBaseMapFile extends MapFile {
private static final Log LOG = LogFactory.getLog(HBaseMapFile.class); private static final Log LOG = LogFactory.getLog(HBaseMapFile.class);
/**
* Values are instances of this class.
*/
public static final Class<? extends Writable> VALUE_CLASS = public static final Class<? extends Writable> VALUE_CLASS =
ImmutableBytesWritable.class; ImmutableBytesWritable.class;
/**
* Custom bloom filter key maker.
* @param key
* @return Key made of bytes of row only.
*/
protected static Key getBloomFilterKey(WritableComparable key) {
return new Key(((HStoreKey) key).getRow());
}
/** /**
* A reader capable of reading and caching blocks of the data file. * A reader capable of reading and caching blocks of the data file.
*/ */
public static class HBaseReader extends MapFile.Reader { public static class HBaseReader extends MapFile.Reader {
private final boolean blockCacheEnabled; private final boolean blockCacheEnabled;
private final HStoreKey firstKey;
private final HStoreKey finalKey;
private final String dirName;
/** /**
* @param fs * @param fs
@ -88,37 +80,17 @@ public class HBaseMapFile extends MapFile {
throws IOException { throws IOException {
super(fs, dirName, new HStoreKey.HStoreKeyWritableComparator(hri), super(fs, dirName, new HStoreKey.HStoreKeyWritableComparator(hri),
conf, false); // defer opening streams conf, false); // defer opening streams
this.dirName = dirName;
this.blockCacheEnabled = blockCacheEnabled; this.blockCacheEnabled = blockCacheEnabled;
open(fs, dirName, new HStoreKey.HStoreKeyWritableComparator(hri), conf); open(fs, dirName, new HStoreKey.HStoreKeyWritableComparator(hri), conf);
// Force reading of the mapfile index by calling midKey. // Force reading of the mapfile index by calling midKey. Reading the
// Reading the index will bring the index into memory over // index will bring the index into memory over here on the client and
// here on the client and then close the index file freeing // then close the index file freeing up socket connection and resources
// up socket connection and resources in the datanode. // in the datanode. Usually, the first access on a MapFile.Reader will
// Usually, the first access on a MapFile.Reader will load the // load the index force the issue in HStoreFile MapFiles because an
// index force the issue in HStoreFile MapFiles because an // access may not happen for some time; meantime we're using up datanode
// access may not happen for some time; meantime we're // resources (See HADOOP-2341). midKey() goes to index. Does not seek.
// using up datanode resources. See HADOOP-2341.
// Of note, midKey just goes to index. Does not seek.
midKey(); midKey();
// Read in the first and last key. Cache them. Make sure we are at start
// of the file.
reset();
HStoreKey key = new HStoreKey();
super.next(key, new ImmutableBytesWritable());
key.setHRegionInfo(hri);
this.firstKey = key;
// Set us back to start of file. Call to finalKey restores whatever
// the previous position.
reset();
// Get final key.
key = new HStoreKey();
super.finalKey(key);
key.setHRegionInfo(hri);
this.finalKey = key;
} }
@Override @Override
@ -129,71 +101,18 @@ public class HBaseMapFile extends MapFile {
return super.createDataFileReader(fs, dataFile, conf); return super.createDataFileReader(fs, dataFile, conf);
} }
final int blockSize = conf.getInt("hbase.hstore.blockCache.blockSize", final int blockSize = conf.getInt("hbase.hstore.blockCache.blockSize",
64 * 1024); 64 * 1024);
return new SequenceFile.Reader(fs, dataFile, conf) { return new SequenceFile.Reader(fs, dataFile, conf) {
@Override @Override
protected FSDataInputStream openFile(FileSystem fs, Path file, protected FSDataInputStream openFile(FileSystem fs, Path file,
int bufferSize, long length) throws IOException { int bufferSize, long length)
throws IOException {
return new FSDataInputStream(new BlockFSInputStream( return new FSDataInputStream(new BlockFSInputStream(
super.openFile(fs, file, bufferSize, length), length, super.openFile(fs, file, bufferSize, length), length,
blockSize)); blockSize));
} }
}; };
} }
@Override
public synchronized void finalKey(final WritableComparable fk)
throws IOException {
Writables.copyWritable(this.finalKey, fk);
}
/**
* @param hsk
* @return True if the file *could* contain <code>hsk</code> and false if
* outside the bounds of this files' start and end keys.
*/
public boolean containsKey(final HStoreKey hsk) {
return this.firstKey.compareTo(hsk) <= 0 &&
this.finalKey.compareTo(hsk) >= 0;
}
public String toString() {
HStoreKey midkey = null;
try {
midkey = (HStoreKey)midKey();
} catch (IOException ioe) {
LOG.warn("Failed get of midkey", ioe);
}
return "dirName=" + this.dirName + ", firstKey=" +
this.firstKey.toString() + ", midKey=" + midkey +
", finalKey=" + this.finalKey;
}
/**
* @return First key in this file. Can be null around construction time.
*/
public HStoreKey getFirstKey() {
return this.firstKey;
}
/**
* @return Final key in file. Can be null around construction time.
*/
public HStoreKey getFinalKey() {
return this.finalKey;
}
@Override
public synchronized WritableComparable getClosest(WritableComparable key,
Writable value, boolean before)
throws IOException {
if ((!before && ((HStoreKey)key).compareTo(this.finalKey) > 0) ||
(before && ((HStoreKey)key).compareTo(this.firstKey) < 0)) {
return null;
}
return super.getClosest(key, value, before);
}
} }
public static class HBaseWriter extends MapFile.Writer { public static class HBaseWriter extends MapFile.Writer {
@ -213,7 +132,7 @@ public class HBaseMapFile extends MapFile {
// Default for mapfiles is 128. Makes random reads faster if we // Default for mapfiles is 128. Makes random reads faster if we
// have more keys indexed and we're not 'next'-ing around in the // have more keys indexed and we're not 'next'-ing around in the
// mapfile. // mapfile.
setIndexInterval(conf.getInt("hbase.io.index.interval", 128)); setIndexInterval(conf.getInt("hbase.io.index.interval", 32));
} }
} }
} }

View File

@ -48,8 +48,6 @@ public class HalfMapFileReader extends BloomFilterMapFile.Reader {
private final boolean top; private final boolean top;
private final HStoreKey midkey; private final HStoreKey midkey;
private boolean firstNextCall = true; private boolean firstNextCall = true;
private final WritableComparable<HStoreKey> firstKey;
private final WritableComparable<HStoreKey> finalKey;
public HalfMapFileReader(final FileSystem fs, final String dirName, public HalfMapFileReader(final FileSystem fs, final String dirName,
final Configuration conf, final Range r, final Configuration conf, final Range r,
@ -76,18 +74,6 @@ public class HalfMapFileReader extends BloomFilterMapFile.Reader {
this.midkey.setHRegionInfo(hri); this.midkey.setHRegionInfo(hri);
// Is it top or bottom half? // Is it top or bottom half?
this.top = Reference.isTopFileRegion(r); this.top = Reference.isTopFileRegion(r);
// Firstkey comes back null if passed midkey is lower than first key in file
// and its a bottom half HalfMapFileReader, OR, if midkey is higher than
// the final key in the backing file. In either case, it means this half
// file is empty.
this.firstKey = this.top?
super.getClosest(this.midkey, new ImmutableBytesWritable()):
super.getFirstKey().compareTo(this.midkey) > 0?
null: super.getFirstKey();
this.finalKey = this.top?
super.getFinalKey():
super.getClosest(new HStoreKey.BeforeThisStoreKey(this.midkey),
new ImmutableBytesWritable(), true);
} }
/* /*
@ -108,12 +94,16 @@ public class HalfMapFileReader extends BloomFilterMapFile.Reader {
} }
} }
@SuppressWarnings("unchecked")
@Override @Override
public synchronized void finalKey(WritableComparable key) public synchronized void finalKey(WritableComparable key)
throws IOException { throws IOException {
Writables.copyWritable(this.finalKey, key); if (top) {
return; super.finalKey(key);
} else {
Writable value = new ImmutableBytesWritable();
WritableComparable found = super.getClosest(midkey, value, true);
Writables.copyWritable(found, key);
}
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -134,8 +124,8 @@ public class HalfMapFileReader extends BloomFilterMapFile.Reader {
// If top, the lowest possible key is first key. Do not have to check // If top, the lowest possible key is first key. Do not have to check
// what comes back from super getClosest. Will return exact match or // what comes back from super getClosest. Will return exact match or
// greater. // greater.
closest = (key.compareTo(getFirstKey()) < 0)? closest = (key.compareTo(this.midkey) < 0)?
getClosest(getFirstKey(), val): super.getClosest(key, val); this.midkey: super.getClosest(key, val);
} else { } else {
// We're serving bottom of the file. // We're serving bottom of the file.
if (key.compareTo(this.midkey) < 0) { if (key.compareTo(this.midkey) < 0) {
@ -143,8 +133,7 @@ public class HalfMapFileReader extends BloomFilterMapFile.Reader {
closest = super.getClosest(key, val); closest = super.getClosest(key, val);
// midkey was made against largest store file at time of split. Smaller // midkey was made against largest store file at time of split. Smaller
// store files could have anything in them. Check return value is // store files could have anything in them. Check return value is
// not beyond the midkey (getClosest returns exact match or next // not beyond the midkey (getClosest returns exact match or next after)
// after).
if (closest != null && closest.compareTo(this.midkey) >= 0) { if (closest != null && closest.compareTo(this.midkey) >= 0) {
// Don't let this value out. // Don't let this value out.
closest = null; closest = null;
@ -168,19 +157,17 @@ public class HalfMapFileReader extends BloomFilterMapFile.Reader {
throws IOException { throws IOException {
if (firstNextCall) { if (firstNextCall) {
firstNextCall = false; firstNextCall = false;
if (isEmpty()) { if (this.top) {
return false; // Seek to midkey. Midkey may not exist in this file. That should be
} // fine. Then we'll either be positioned at end or start of file.
// Seek and fill by calling getClosest on first key. WritableComparable nearest = getClosest(this.midkey, val);
if (this.firstKey != null) { // Now copy the midkey into the passed key.
Writables.copyWritable(this.firstKey, key); if (nearest != null) {
WritableComparable nearest = getClosest(key, val); Writables.copyWritable(nearest, key);
if (!key.equals(nearest)) { return true;
throw new IOException("Keys don't match and should: " +
key.toString() + ", " + nearest.toString());
} }
return false;
} }
return true;
} }
boolean result = super.next(key, val); boolean result = super.next(key, val);
if (!top && key.compareTo(midkey) >= 0) { if (!top && key.compareTo(midkey) >= 0) {
@ -189,15 +176,10 @@ public class HalfMapFileReader extends BloomFilterMapFile.Reader {
return result; return result;
} }
private boolean isEmpty() {
return this.firstKey == null;
}
@Override @Override
public synchronized void reset() throws IOException { public synchronized void reset() throws IOException {
if (top) { if (top) {
firstNextCall = true; firstNextCall = true;
// I don't think this is needed. seek(this.firstKey);
return; return;
} }
super.reset(); super.reset();
@ -210,19 +192,4 @@ public class HalfMapFileReader extends BloomFilterMapFile.Reader {
checkKey(key); checkKey(key);
return super.seek(key); return super.seek(key);
} }
}
@Override
public HStoreKey getFirstKey() {
return (HStoreKey)this.firstKey;
}
@Override
public HStoreKey getFinalKey() {
return (HStoreKey)this.finalKey;
}
@Override
public String toString() {
return super.toString() + ", half=" + (top? "top": "bottom");
}
}

View File

@ -1371,7 +1371,6 @@ public class HStore implements HConstants {
i >= 0 && !hasEnoughVersions(versions, results); i--) { i >= 0 && !hasEnoughVersions(versions, results); i--) {
MapFile.Reader map = maparray[i]; MapFile.Reader map = maparray[i];
synchronized(map) { synchronized(map) {
map.reset();
// Do the priming read // Do the priming read
ImmutableBytesWritable readval = new ImmutableBytesWritable(); ImmutableBytesWritable readval = new ImmutableBytesWritable();
HStoreKey readkey = (HStoreKey)map.getClosest(key, readval); HStoreKey readkey = (HStoreKey)map.getClosest(key, readval);
@ -1379,7 +1378,9 @@ public class HStore implements HConstants {
// map.getClosest returns null if the passed key is > than the // map.getClosest returns null if the passed key is > than the
// last key in the map file. getClosest is a bit of a misnomer // last key in the map file. getClosest is a bit of a misnomer
// since it returns exact match or the next closest key AFTER not // since it returns exact match or the next closest key AFTER not
// BEFORE. // BEFORE. We use getClosest because we're usually passed a
// key that has a timestamp of maximum long to indicate we want
// most recent update.
continue; continue;
} }
if (!readkey.matchesRowCol(key)) { if (!readkey.matchesRowCol(key)) {
@ -1868,9 +1869,6 @@ public class HStore implements HConstants {
* @throws IOException * @throws IOException
*/ */
private HStoreKey getFinalKey(final MapFile.Reader mf) throws IOException { private HStoreKey getFinalKey(final MapFile.Reader mf) throws IOException {
if (mf instanceof HBaseMapFile.HBaseReader) {
return ((HBaseMapFile.HBaseReader)mf).getFinalKey();
}
HStoreKey finalKey = new HStoreKey(); HStoreKey finalKey = new HStoreKey();
mf.finalKey(finalKey); mf.finalKey(finalKey);
finalKey.setHRegionInfo(this.info); finalKey.setHRegionInfo(this.info);
@ -1961,16 +1959,18 @@ public class HStore implements HConstants {
// Cast to HbaseReader. // Cast to HbaseReader.
HBaseMapFile.HBaseReader r = HBaseMapFile.HBaseReader r =
(HBaseMapFile.HBaseReader)this.readers.get(mapIndex); (HBaseMapFile.HBaseReader)this.readers.get(mapIndex);
// Get first, last, and mid keys.
// get the midkey r.reset();
HStoreKey firstKey = new HStoreKey();
HStoreKey lastKey = new HStoreKey();
r.next(firstKey, new ImmutableBytesWritable());
r.finalKey(lastKey);
HStoreKey mk = (HStoreKey)r.midKey(); HStoreKey mk = (HStoreKey)r.midKey();
if (mk != null) { if (mk != null) {
// if the midkey is the same as the first and last keys, then we cannot // if the midkey is the same as the first and last keys, then we cannot
// (ever) split this region. // (ever) split this region.
if (HStoreKey.equalsTwoRowKeys(info, mk.getRow(), if (HStoreKey.equalsTwoRowKeys(info, mk.getRow(), firstKey.getRow()) &&
r.getFirstKey().getRow()) && HStoreKey.equalsTwoRowKeys(info, mk.getRow(), lastKey.getRow())) {
HStoreKey.equalsTwoRowKeys(info, mk.getRow(),
r.getFinalKey().getRow())) {
return null; return null;
} }
return new StoreSize(maxSize, mk.getRow()); return new StoreSize(maxSize, mk.getRow());
@ -2070,4 +2070,4 @@ public class HStore implements HConstants {
HRegionInfo getHRegionInfo() { HRegionInfo getHRegionInfo() {
return this.info; return this.info;
} }
} }

View File

@ -23,17 +23,16 @@ import java.io.IOException;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hdfs.MiniDFSCluster;
import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.HBaseTestCase; import org.apache.hadoop.hbase.HBaseTestCase;
import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.HStoreKey; import org.apache.hadoop.hbase.HStoreKey;
import org.apache.hadoop.hbase.io.HBaseMapFile;
import org.apache.hadoop.hbase.io.HalfMapFileReader; import org.apache.hadoop.hbase.io.HalfMapFileReader;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.io.Reference; import org.apache.hadoop.hbase.io.Reference;
import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hdfs.MiniDFSCluster;
import org.apache.hadoop.io.MapFile; import org.apache.hadoop.io.MapFile;
import org.apache.hadoop.io.SequenceFile; import org.apache.hadoop.io.SequenceFile;
import org.apache.hadoop.io.WritableComparable; import org.apache.hadoop.io.WritableComparable;
@ -117,25 +116,6 @@ public class TestHStoreFile extends HBaseTestCase {
} }
} }
public void testContains() throws Exception {
HStoreFile hsf = new HStoreFile(this.conf, this.fs, this.dir,
HRegionInfo.FIRST_META_REGIONINFO,
Bytes.toBytes("colfamily"), 1234567890L, null);
MapFile.Writer writer =
hsf.getWriter(this.fs, SequenceFile.CompressionType.NONE, false, 0);
writeStoreFile(writer);
MapFile.Reader r = hsf.getReader(this.fs, false, false);
HBaseMapFile.HBaseReader reader =
(HBaseMapFile.HBaseReader)r;
// Store file should contain 'aa' and 'bb' but not 'AA' nor 'ZZ'.
assertTrue(reader.containsKey(new HStoreKey("aa", "bb")));
assertTrue(reader.containsKey(new HStoreKey("bb")));
assertTrue(reader.containsKey(new HStoreKey("zz")));
assertFalse(reader.containsKey(new HStoreKey("AA")));
assertFalse(reader.containsKey(new HStoreKey("{{")));
assertFalse(reader.containsKey(new HStoreKey()));
}
/** /**
* Test that our mechanism of writing store files in one region to reference * Test that our mechanism of writing store files in one region to reference
* store files in other regions works. * store files in other regions works.
@ -192,13 +172,6 @@ public class TestHStoreFile extends HBaseTestCase {
} }
} }
assertTrue(Bytes.equals(key.getRow(), finalKey)); assertTrue(Bytes.equals(key.getRow(), finalKey));
// Assert contains works properly.
HBaseMapFile.HBaseReader hbaseMapfileHalfReader =
(HBaseMapFile.HBaseReader)halfReader;
assertTrue(hbaseMapfileHalfReader.containsKey(midkey));
assertTrue(hbaseMapfileHalfReader.containsKey(new HStoreKey(finalKey)));
assertFalse(hbaseMapfileHalfReader.containsKey(new HStoreKey("aa")));
assertFalse(hbaseMapfileHalfReader.containsKey(new HStoreKey("{{")));
} }
/** /**