HBASE-868 and HBASE-871 Incrementing binary rows cause strange behavior once table splits AND Major compaction periodicity should be specifyable at the column family level, not cluster wide

git-svn-id: https://svn.apache.org/repos/asf/hadoop/hbase/trunk@692963 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael Stack 2008-09-08 00:14:10 +00:00
parent 2e13c047ab
commit 3b540886df
14 changed files with 231 additions and 123 deletions

View File

@ -58,6 +58,8 @@ Release 0.18.0 - Unreleased
HBASE-864 Deadlock in regionserver HBASE-864 Deadlock in regionserver
HBASE-865 Fix javadoc warnings (Rong-En Fan via Jim Kellerman) HBASE-865 Fix javadoc warnings (Rong-En Fan via Jim Kellerman)
HBASE-872 Getting exceptions in shell when creating/disabling tables HBASE-872 Getting exceptions in shell when creating/disabling tables
HBASE-868 Incrementing binary rows cause strange behavior once table
splits (Jonathan Gray via Stack)
IMPROVEMENTS IMPROVEMENTS
HBASE-801 When a table haven't disable, shell could response in a "user HBASE-801 When a table haven't disable, shell could response in a "user
@ -78,6 +80,8 @@ Release 0.18.0 - Unreleased
(Sishen Freecity via Stack) (Sishen Freecity via Stack)
HBASE-874 deleting a table kills client rpc; no subsequent communication if HBASE-874 deleting a table kills client rpc; no subsequent communication if
shell or thrift server, etc. (Jonathan Gray via Jim Kellerman) shell or thrift server, etc. (Jonathan Gray via Jim Kellerman)
HBASE-871 Major compaction periodicity should be specifyable at the column
family level, not cluster wide (Jonathan Gray via Stack)
NEW FEATURES NEW FEATURES
HBASE-787 Postgresql to HBase table replication example (Tim Sell via Stack) HBASE-787 Postgresql to HBase table replication example (Tim Sell via Stack)

View File

@ -93,6 +93,9 @@ public interface HConstants {
/** Parameter name for how often threads should wake up */ /** Parameter name for how often threads should wake up */
static final String THREAD_WAKE_FREQUENCY = "hbase.server.thread.wakefrequency"; static final String THREAD_WAKE_FREQUENCY = "hbase.server.thread.wakefrequency";
/** Parameter name for how often a region should should perform a major compaction */
static final String MAJOR_COMPACTION_PERIOD = "hbase.hregion.majorcompaction";
/** Parameter name for HBase instance root directory */ /** Parameter name for HBase instance root directory */
static final String HBASE_DIR = "hbase.rootdir"; static final String HBASE_DIR = "hbase.rootdir";

View File

@ -23,6 +23,7 @@ import java.io.DataInput;
import java.io.DataOutput; import java.io.DataOutput;
import java.io.IOException; import java.io.IOException;
import org.apache.hadoop.hbase.HStoreKey;
import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.JenkinsHash; import org.apache.hadoop.hbase.util.JenkinsHash;
import org.apache.hadoop.io.VersionedWritable; import org.apache.hadoop.io.VersionedWritable;
@ -397,12 +398,12 @@ public class HRegionInfo extends VersionedWritable implements WritableComparable
} }
// Compare start keys. // Compare start keys.
result = Bytes.compareTo(this.startKey, other.startKey); result = HStoreKey.compareTwoRowKeys(other, this.startKey, other.startKey);
if (result != 0) { if (result != 0) {
return result; return result;
} }
// Compare end keys. // Compare end keys.
return Bytes.compareTo(this.endKey, other.endKey); return HStoreKey.compareTwoRowKeys(other, this.endKey, other.endKey);
} }
} }

View File

@ -26,6 +26,7 @@ import java.io.IOException;
import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.io.WritableComparable; import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.io.WritableComparator;
/** /**
* A Key for a stored row. * A Key for a stored row.
@ -73,6 +74,29 @@ public class HStoreKey implements WritableComparable {
this(row, Long.MAX_VALUE); this(row, Long.MAX_VALUE);
} }
/**
* Create an HStoreKey specifying the row and timestamp
* The column and table names default to the empty string
*
* @param row row key
* @param hri
*/
public HStoreKey(final byte [] row, final HRegionInfo hri) {
this(row, HConstants.EMPTY_BYTE_ARRAY, hri);
}
/**
* Create an HStoreKey specifying the row and timestamp
* The column and table names default to the empty string
*
* @param row row key
* @param timestamp timestamp value
* @param hri HRegionInfo
*/
public HStoreKey(final byte [] row, long timestamp, final HRegionInfo hri) {
this(row, HConstants.EMPTY_BYTE_ARRAY, timestamp, hri);
}
/** /**
* Create an HStoreKey specifying the row and timestamp * Create an HStoreKey specifying the row and timestamp
* The column and table names default to the empty string * The column and table names default to the empty string
@ -188,7 +212,7 @@ public class HStoreKey implements WritableComparable {
* @param other the source key * @param other the source key
*/ */
public HStoreKey(HStoreKey other) { public HStoreKey(HStoreKey other) {
this(other.row, other.column, other.timestamp); this(other.row, other.column, other.timestamp, other.regionInfo);
} }
/** /**
@ -257,7 +281,7 @@ public class HStoreKey implements WritableComparable {
* @see #matchesRowFamily(HStoreKey) * @see #matchesRowFamily(HStoreKey)
*/ */
public boolean matchesRowCol(HStoreKey other) { public boolean matchesRowCol(HStoreKey other) {
return Bytes.equals(this.row, other.row) && return HStoreKey.equalsTwoRowKeys(this.regionInfo, this.row, other.row) &&
Bytes.equals(column, other.column); Bytes.equals(column, other.column);
} }
@ -271,7 +295,7 @@ public class HStoreKey implements WritableComparable {
* @see #matchesRowFamily(HStoreKey) * @see #matchesRowFamily(HStoreKey)
*/ */
public boolean matchesWithoutColumn(HStoreKey other) { public boolean matchesWithoutColumn(HStoreKey other) {
return Bytes.equals(this.row, other.row) && return equalsTwoRowKeys(this.regionInfo, this.row, other.row) &&
this.timestamp >= other.getTimestamp(); this.timestamp >= other.getTimestamp();
} }
@ -286,7 +310,7 @@ public class HStoreKey implements WritableComparable {
*/ */
public boolean matchesRowFamily(HStoreKey that) { public boolean matchesRowFamily(HStoreKey that) {
int delimiterIndex = getFamilyDelimiterIndex(this.column); int delimiterIndex = getFamilyDelimiterIndex(this.column);
return Bytes.equals(this.row, that.row) && return equalsTwoRowKeys(this.regionInfo, this.row, that.row) &&
Bytes.compareTo(this.column, 0, delimiterIndex, that.column, 0, Bytes.compareTo(this.column, 0, delimiterIndex, that.column, 0,
delimiterIndex) == 0; delimiterIndex) == 0;
} }
@ -317,15 +341,19 @@ public class HStoreKey implements WritableComparable {
/** {@inheritDoc} */ /** {@inheritDoc} */
public int compareTo(Object o) { public int compareTo(Object o) {
HStoreKey other = (HStoreKey)o; return compareTo(this.regionInfo, this, (HStoreKey)o);
int result = compareTwoRowKeys(this.regionInfo, this.row, other.row); }
static int compareTo(final HRegionInfo hri, final HStoreKey left,
final HStoreKey right) {
int result = compareTwoRowKeys(hri, left.getRow(), right.getRow());
if (result != 0) { if (result != 0) {
return result; return result;
} }
result = this.column == null && other.column == null? 0: result = left.getColumn() == null && right.getColumn() == null? 0:
this.column == null && other.column != null? -1: left.getColumn() == null && right.getColumn() != null? -1:
this.column != null && other.column == null? 1: left.getColumn() != null && right.getColumn() == null? 1:
Bytes.compareTo(this.column, other.column); Bytes.compareTo(left.getColumn(), right.getColumn());
if (result != 0) { if (result != 0) {
return result; return result;
} }
@ -333,9 +361,9 @@ public class HStoreKey implements WritableComparable {
// wrong but it is intentional. This way, newer timestamps are first // wrong but it is intentional. This way, newer timestamps are first
// found when we iterate over a memcache and newer versions are the // found when we iterate over a memcache and newer versions are the
// first we trip over when reading from a store file. // first we trip over when reading from a store file.
if (this.timestamp < other.timestamp) { if (left.getTimestamp() < right.getTimestamp()) {
result = 1; result = 1;
} else if (this.timestamp > other.timestamp) { } else if (left.getTimestamp() > right.getTimestamp()) {
result = -1; result = -1;
} }
return result; return result;
@ -482,9 +510,8 @@ public class HStoreKey implements WritableComparable {
if(rowCompare == 0) if(rowCompare == 0)
rowCompare = Bytes.compareTo(keysA[1], KeysB[1]); rowCompare = Bytes.compareTo(keysA[1], KeysB[1]);
return rowCompare; return rowCompare;
} else {
return Bytes.compareTo(rowA, rowB);
} }
return Bytes.compareTo(rowA, rowB);
} }
/** /**
@ -513,10 +540,14 @@ public class HStoreKey implements WritableComparable {
break; break;
} }
} }
byte [] row = new byte[offset]; byte [] row = rowKey;
byte [] timestamp = HConstants.EMPTY_BYTE_ARRAY;
if (offset != -1) {
row = new byte[offset];
System.arraycopy(rowKey, 0, row, 0, offset); System.arraycopy(rowKey, 0, row, 0, offset);
byte [] timestamp = new byte[rowKey.length - offset - 1]; timestamp = new byte[rowKey.length - offset - 1];
System.arraycopy(rowKey, offset+1, timestamp, 0,rowKey.length - offset - 1); System.arraycopy(rowKey, offset+1, timestamp, 0,rowKey.length - offset - 1);
}
byte[][] elements = new byte[2][]; byte[][] elements = new byte[2][];
elements[0] = row; elements[0] = row;
elements[1] = timestamp; elements[1] = timestamp;
@ -538,4 +569,20 @@ public class HStoreKey implements WritableComparable {
this.column = Bytes.readByteArray(in); this.column = Bytes.readByteArray(in);
this.timestamp = in.readLong(); this.timestamp = in.readLong();
} }
/**
* Passed as comparator for memcache and for store files. See HBASE-868.
*/
public static class HStoreKeyWritableComparator extends WritableComparator {
private final HRegionInfo hri;
public HStoreKeyWritableComparator(final HRegionInfo hri) {
super(HStoreKey.class);
this.hri = hri;
}
public int compare(final WritableComparable left, final WritableComparable right) {
return compareTo(this.hri, (HStoreKey)left, (HStoreKey)right);
}
}
} }

View File

@ -37,6 +37,7 @@ import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.HRegionLocation; import org.apache.hadoop.hbase.HRegionLocation;
import org.apache.hadoop.hbase.HServerAddress; import org.apache.hadoop.hbase.HServerAddress;
import org.apache.hadoop.hbase.HStoreKey;
import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.LocalHBaseCluster; import org.apache.hadoop.hbase.LocalHBaseCluster;
import org.apache.hadoop.hbase.MasterNotRunningException; import org.apache.hadoop.hbase.MasterNotRunningException;
@ -323,7 +324,7 @@ public class HConnectionManager implements HConstants {
if (currentRegion != null) { if (currentRegion != null) {
byte[] endKey = currentRegion.getEndKey(); byte[] endKey = currentRegion.getEndKey();
if (endKey == null || if (endKey == null ||
Bytes.equals(endKey, HConstants.EMPTY_BYTE_ARRAY)) { HStoreKey.equalsTwoRowKeys(currentRegion, endKey, HConstants.EMPTY_BYTE_ARRAY)) {
// We have reached the end of the table and we're done // We have reached the end of the table and we're done
break; break;
} }
@ -636,8 +637,10 @@ public class HConnectionManager implements HConstants {
// this one. the exception case is when the endkey is EMPTY_START_ROW, // this one. the exception case is when the endkey is EMPTY_START_ROW,
// signifying that the region we're checking is actually the last // signifying that the region we're checking is actually the last
// region in the table. // region in the table.
if (Bytes.equals(endKey, HConstants.EMPTY_END_ROW) || if (HStoreKey.equalsTwoRowKeys(possibleRegion.getRegionInfo(),
Bytes.compareTo(endKey, row) > 0) { endKey, HConstants.EMPTY_END_ROW) ||
HStoreKey.compareTwoRowKeys(possibleRegion.getRegionInfo(),
endKey, row) > 0) {
return possibleRegion; return possibleRegion;
} }
} }
@ -684,7 +687,8 @@ public class HConnectionManager implements HConstants {
// by nature of the map, we know that the start key has to be < // by nature of the map, we know that the start key has to be <
// otherwise it wouldn't be in the headMap. // otherwise it wouldn't be in the headMap.
if (Bytes.compareTo(endKey, row) <= 0) { if (HStoreKey.compareTwoRowKeys(possibleRegion.getRegionInfo(),
endKey, row) <= 0) {
// delete any matching entry // delete any matching entry
HRegionLocation rl = HRegionLocation rl =
tableLocations.remove(matchingRegions.lastKey()); tableLocations.remove(matchingRegions.lastKey());

View File

@ -5,6 +5,7 @@ import java.io.IOException;
import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.HBaseConfiguration;
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.io.RowResult; import org.apache.hadoop.hbase.io.RowResult;
import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Bytes;
@ -47,9 +48,10 @@ class MetaScanner implements HConstants {
HRegionInfo.createRegionName(tableName, null, ZEROES); HRegionInfo.createRegionName(tableName, null, ZEROES);
// Scan over each meta region // Scan over each meta region
ScannerCallable callable = null;
do { do {
ScannerCallable callable = new ScannerCallable(connection, callable = new ScannerCallable(connection, META_TABLE_NAME,
META_TABLE_NAME, COLUMN_FAMILY_ARRAY, startRow, LATEST_TIMESTAMP, null); COLUMN_FAMILY_ARRAY, startRow, LATEST_TIMESTAMP, null);
// Open scanner // Open scanner
connection.getRegionServerWithRetries(callable); connection.getRegionServerWithRetries(callable);
try { try {
@ -67,7 +69,7 @@ class MetaScanner implements HConstants {
callable.setClose(); callable.setClose();
connection.getRegionServerWithRetries(callable); connection.getRegionServerWithRetries(callable);
} }
} while (Bytes.compareTo(startRow, LAST_ROW) != 0); } while (HStoreKey.compareTwoRowKeys(callable.getHRegionInfo(), startRow, LAST_ROW) != 0);
} }
/** /**

View File

@ -20,7 +20,9 @@
package org.apache.hadoop.hbase.master; package org.apache.hadoop.hbase.master;
import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.HServerAddress; import org.apache.hadoop.hbase.HServerAddress;
import org.apache.hadoop.hbase.HStoreKey;
import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Bytes;
@ -90,7 +92,8 @@ public class MetaRegion implements Comparable<MetaRegion> {
public int compareTo(MetaRegion other) { public int compareTo(MetaRegion other) {
int result = Bytes.compareTo(this.regionName, other.getRegionName()); int result = Bytes.compareTo(this.regionName, other.getRegionName());
if(result == 0) { if(result == 0) {
result = Bytes.compareTo(this.startKey, other.getStartKey()); result = HStoreKey.compareTwoRowKeys(HRegionInfo.FIRST_META_REGIONINFO,
this.startKey, other.getStartKey());
if (result == 0) { if (result == 0) {
// Might be on different host? // Might be on different host?
result = this.server.compareTo(other.server); result = this.server.compareTo(other.server);

View File

@ -132,12 +132,14 @@ public class HRegion implements HConstants {
} }
// A's start key is null but B's isn't. Assume A comes before B // A's start key is null but B's isn't. Assume A comes before B
} else if ((srcB.getStartKey() == null) // A is not null but B is } else if ((srcB.getStartKey() == null) // A is not null but B is
|| (Bytes.compareTo(srcA.getStartKey(), srcB.getStartKey()) > 0)) { // A > B || (HStoreKey.compareTwoRowKeys(srcA.getRegionInfo(),
srcA.getStartKey(), srcB.getStartKey()) > 0)) { // A > B
a = srcB; a = srcB;
b = srcA; b = srcA;
} }
if (!Bytes.equals(a.getEndKey(), b.getStartKey())) { if (!HStoreKey.equalsTwoRowKeys(srcA.getRegionInfo(),
a.getEndKey(), b.getStartKey())) {
throw new IOException("Cannot merge non-adjacent regions"); throw new IOException("Cannot merge non-adjacent regions");
} }
return merge(a, b); return merge(a, b);
@ -181,13 +183,19 @@ public class HRegion implements HConstants {
HTableDescriptor tabledesc = a.getTableDesc(); HTableDescriptor tabledesc = a.getTableDesc();
HLog log = a.getLog(); HLog log = a.getLog();
Path basedir = a.getBaseDir(); Path basedir = a.getBaseDir();
final byte [] startKey = Bytes.equals(a.getStartKey(), EMPTY_BYTE_ARRAY) || final byte [] startKey = HStoreKey.equalsTwoRowKeys(a.getRegionInfo(),
Bytes.equals(b.getStartKey(), EMPTY_BYTE_ARRAY) ? EMPTY_BYTE_ARRAY : a.getStartKey(), EMPTY_BYTE_ARRAY) ||
Bytes.compareTo(a.getStartKey(), b.getStartKey()) <= 0 ? HStoreKey.equalsTwoRowKeys(a.getRegionInfo(),
b.getStartKey(), EMPTY_BYTE_ARRAY) ? EMPTY_BYTE_ARRAY :
HStoreKey.compareTwoRowKeys(a.getRegionInfo(), a.getStartKey(),
b.getStartKey()) <= 0 ?
a.getStartKey() : b.getStartKey(); a.getStartKey() : b.getStartKey();
final byte [] endKey = Bytes.equals(a.getEndKey(), EMPTY_BYTE_ARRAY) || final byte [] endKey = HStoreKey.equalsTwoRowKeys(a.getRegionInfo(),
Bytes.equals(b.getEndKey(), EMPTY_BYTE_ARRAY) ? EMPTY_BYTE_ARRAY : a.getEndKey(), EMPTY_BYTE_ARRAY) ||
Bytes.compareTo(a.getEndKey(), b.getEndKey()) <= 0 ? HStoreKey.equalsTwoRowKeys(b.getRegionInfo(), b.getEndKey(),
EMPTY_BYTE_ARRAY) ? EMPTY_BYTE_ARRAY :
HStoreKey.compareTwoRowKeys(a.getRegionInfo(), a.getEndKey(),
b.getEndKey()) <= 0 ?
b.getEndKey() : a.getEndKey(); b.getEndKey() : a.getEndKey();
HRegionInfo newRegionInfo = new HRegionInfo(tabledesc, startKey, endKey); HRegionInfo newRegionInfo = new HRegionInfo(tabledesc, startKey, endKey);
@ -232,7 +240,7 @@ public class HRegion implements HConstants {
} }
for (HStoreFile hsf: srcFiles) { for (HStoreFile hsf: srcFiles) {
HStoreFile dst = new HStoreFile(conf, fs, basedir, HStoreFile dst = new HStoreFile(conf, fs, basedir,
newRegionInfo.getEncodedName(), colFamily, -1, null); newRegionInfo, colFamily, -1, null);
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("Renaming " + hsf + " to " + dst); LOG.debug("Renaming " + hsf + " to " + dst);
} }
@ -718,12 +726,12 @@ public class HRegion implements HConstants {
// Add start/end key checking: hbase-428. // Add start/end key checking: hbase-428.
byte [] startKey = this.regionInfo.getStartKey(); byte [] startKey = this.regionInfo.getStartKey();
byte [] endKey = this.regionInfo.getEndKey(); byte [] endKey = this.regionInfo.getEndKey();
if (Bytes.equals(startKey, midKey)) { if (HStoreKey.equalsTwoRowKeys(this.regionInfo,startKey, midKey)) {
LOG.debug("Startkey (" + startKey + ") and midkey + (" + LOG.debug("Startkey (" + startKey + ") and midkey + (" +
midKey + ") are same, not splitting"); midKey + ") are same, not splitting");
return null; return null;
} }
if (Bytes.equals(midKey, endKey)) { if (HStoreKey.equalsTwoRowKeys(this.regionInfo,midKey, endKey)) {
LOG.debug("Endkey and midkey are same, not splitting"); LOG.debug("Endkey and midkey are same, not splitting");
return null; return null;
} }
@ -769,15 +777,15 @@ public class HRegion implements HConstants {
// A reference to the bottom half of the hsf store file. // A reference to the bottom half of the hsf store file.
HStoreFile.Reference aReference = new HStoreFile.Reference( HStoreFile.Reference aReference = new HStoreFile.Reference(
this.regionInfo.getEncodedName(), h.getFileId(), this.regionInfo.getEncodedName(), h.getFileId(),
new HStoreKey(midKey), HStoreFile.Range.bottom); new HStoreKey(midKey, this.regionInfo), HStoreFile.Range.bottom);
HStoreFile a = new HStoreFile(this.conf, fs, splits, HStoreFile a = new HStoreFile(this.conf, fs, splits,
regionAInfo.getEncodedName(), h.getColFamily(), -1, aReference); regionAInfo, h.getColFamily(), -1, aReference);
// Reference to top half of the hsf store file. // Reference to top half of the hsf store file.
HStoreFile.Reference bReference = new HStoreFile.Reference( HStoreFile.Reference bReference = new HStoreFile.Reference(
this.regionInfo.getEncodedName(), h.getFileId(), this.regionInfo.getEncodedName(), h.getFileId(),
new HStoreKey(midKey), HStoreFile.Range.top); new HStoreKey(midKey), HStoreFile.Range.top);
HStoreFile b = new HStoreFile(this.conf, fs, splits, HStoreFile b = new HStoreFile(this.conf, fs, splits,
regionBInfo.getEncodedName(), h.getColFamily(), -1, bReference); regionBInfo, h.getColFamily(), -1, bReference);
h.splitStoreFile(a, b, this.fs); h.splitStoreFile(a, b, this.fs);
} }
@ -1142,7 +1150,7 @@ public class HRegion implements HConstants {
checkRow(row); checkRow(row);
checkColumn(column); checkColumn(column);
// Don't need a row lock for a simple get // Don't need a row lock for a simple get
HStoreKey key = new HStoreKey(row, column, timestamp); HStoreKey key = new HStoreKey(row, column, timestamp, this.regionInfo);
Cell[] result = getStore(column).get(key, numVersions); Cell[] result = getStore(column).get(key, numVersions);
// Guarantee that we return null instead of a zero-length array, // Guarantee that we return null instead of a zero-length array,
// if there are no results to return. // if there are no results to return.
@ -1178,7 +1186,7 @@ public class HRegion implements HConstants {
checkColumn(column); checkColumn(column);
} }
} }
HStoreKey key = new HStoreKey(row, ts); HStoreKey key = new HStoreKey(row, ts, this.regionInfo);
Integer lid = getLock(lockid,row); Integer lid = getLock(lockid,row);
HashSet<HStore> storeSet = new HashSet<HStore>(); HashSet<HStore> storeSet = new HashSet<HStore>();
try { try {
@ -1242,14 +1250,14 @@ public class HRegion implements HConstants {
byte [] closestKey = store.getRowKeyAtOrBefore(row); byte [] closestKey = store.getRowKeyAtOrBefore(row);
// if it happens to be an exact match, we can stop looping // if it happens to be an exact match, we can stop looping
if (HStoreKey.equalsTwoRowKeys(regionInfo,row, closestKey)) { if (HStoreKey.equalsTwoRowKeys(regionInfo,row, closestKey)) {
key = new HStoreKey(closestKey); key = new HStoreKey(closestKey, this.regionInfo);
break; break;
} }
// otherwise, we need to check if it's the max and move to the next // otherwise, we need to check if it's the max and move to the next
if (closestKey != null if (closestKey != null
&& (key == null || HStoreKey.compareTwoRowKeys( && (key == null || HStoreKey.compareTwoRowKeys(
regionInfo,closestKey, key.getRow()) > 0) ) { regionInfo,closestKey, key.getRow()) > 0) ) {
key = new HStoreKey(closestKey); key = new HStoreKey(closestKey, this.regionInfo);
} }
} }
if (key == null) { if (key == null) {
@ -1401,7 +1409,8 @@ public class HRegion implements HConstants {
try { try {
List<byte []> deletes = null; List<byte []> deletes = null;
for (BatchOperation op: b) { for (BatchOperation op: b) {
HStoreKey key = new HStoreKey(row, op.getColumn(), commitTime); HStoreKey key = new HStoreKey(row, op.getColumn(), commitTime,
this.regionInfo);
byte[] val = null; byte[] val = null;
if (op.isPut()) { if (op.isPut()) {
val = op.getValue(); val = op.getValue();
@ -1524,7 +1533,7 @@ public class HRegion implements HConstants {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
try { try {
for (HStore store : stores.values()) { for (HStore store : stores.values()) {
List<HStoreKey> keys = store.getKeys(new HStoreKey(row, ts), List<HStoreKey> keys = store.getKeys(new HStoreKey(row, ts, this.regionInfo),
ALL_VERSIONS, now); ALL_VERSIONS, now);
TreeMap<HStoreKey, byte []> edits = new TreeMap<HStoreKey, byte []>(); TreeMap<HStoreKey, byte []> edits = new TreeMap<HStoreKey, byte []>();
for (HStoreKey key: keys) { for (HStoreKey key: keys) {
@ -1557,8 +1566,8 @@ public class HRegion implements HConstants {
// find the HStore for the column family // find the HStore for the column family
HStore store = getStore(family); HStore store = getStore(family);
// find all the keys that match our criteria // find all the keys that match our criteria
List<HStoreKey> keys = store.getKeys(new HStoreKey(row, timestamp), List<HStoreKey> keys = store.getKeys(new HStoreKey(row, timestamp,
ALL_VERSIONS, now); this.regionInfo), ALL_VERSIONS, now);
// delete all the cells // delete all the cells
TreeMap<HStoreKey, byte []> edits = new TreeMap<HStoreKey, byte []>(); TreeMap<HStoreKey, byte []> edits = new TreeMap<HStoreKey, byte []>();
for (HStoreKey key: keys) { for (HStoreKey key: keys) {
@ -1585,7 +1594,7 @@ public class HRegion implements HConstants {
final long ts, final int versions) final long ts, final int versions)
throws IOException { throws IOException {
checkReadOnly(); checkReadOnly();
HStoreKey origin = new HStoreKey(row, column, ts); HStoreKey origin = new HStoreKey(row, column, ts, this.regionInfo);
Set<HStoreKey> keys = getKeys(origin, versions); Set<HStoreKey> keys = getKeys(origin, versions);
if (keys.size() > 0) { if (keys.size() > 0) {
TreeMap<HStoreKey, byte []> edits = new TreeMap<HStoreKey, byte []>(); TreeMap<HStoreKey, byte []> edits = new TreeMap<HStoreKey, byte []>();
@ -1958,7 +1967,7 @@ public class HRegion implements HConstants {
this.resultSets = new TreeMap[scanners.length]; this.resultSets = new TreeMap[scanners.length];
this.keys = new HStoreKey[scanners.length]; this.keys = new HStoreKey[scanners.length];
for (int i = 0; i < scanners.length; i++) { for (int i = 0; i < scanners.length; i++) {
keys[i] = new HStoreKey(); keys[i] = new HStoreKey(HConstants.EMPTY_BYTE_ARRAY,regionInfo);
resultSets[i] = new TreeMap<byte [], Cell>(Bytes.BYTES_COMPARATOR); resultSets[i] = new TreeMap<byte [], Cell>(Bytes.BYTES_COMPARATOR);
if(scanners[i] != null && !scanners[i].next(keys[i], resultSets[i])) { if(scanners[i] != null && !scanners[i].next(keys[i], resultSets[i])) {
closeScanner(i); closeScanner(i);
@ -1984,8 +1993,10 @@ public class HRegion implements HConstants {
for (int i = 0; i < this.keys.length; i++) { for (int i = 0; i < this.keys.length; i++) {
if (scanners[i] != null && if (scanners[i] != null &&
(chosenRow == null || (chosenRow == null ||
(Bytes.compareTo(keys[i].getRow(), chosenRow) < 0) || (HStoreKey.compareTwoRowKeys(regionInfo,
((Bytes.compareTo(keys[i].getRow(), chosenRow) == 0) && keys[i].getRow(), chosenRow) < 0) ||
((HStoreKey.compareTwoRowKeys(regionInfo, keys[i].getRow(),
chosenRow) == 0) &&
(keys[i].getTimestamp() > chosenTimestamp)))) { (keys[i].getTimestamp() > chosenTimestamp)))) {
chosenRow = keys[i].getRow(); chosenRow = keys[i].getRow();
chosenTimestamp = keys[i].getTimestamp(); chosenTimestamp = keys[i].getTimestamp();
@ -2002,7 +2013,7 @@ public class HRegion implements HConstants {
for (int i = 0; i < scanners.length; i++) { for (int i = 0; i < scanners.length; i++) {
if (scanners[i] != null && if (scanners[i] != null &&
Bytes.compareTo(keys[i].getRow(), chosenRow) == 0) { HStoreKey.compareTwoRowKeys(regionInfo,keys[i].getRow(), chosenRow) == 0) {
// NOTE: We used to do results.putAll(resultSets[i]); // NOTE: We used to do results.putAll(resultSets[i]);
// but this had the effect of overwriting newer // but this had the effect of overwriting newer
// values with older ones. So now we only insert // values with older ones. So now we only insert
@ -2024,7 +2035,7 @@ public class HRegion implements HConstants {
// If the current scanner is non-null AND has a lower-or-equal // If the current scanner is non-null AND has a lower-or-equal
// row label, then its timestamp is bad. We need to advance it. // row label, then its timestamp is bad. We need to advance it.
while ((scanners[i] != null) && while ((scanners[i] != null) &&
(Bytes.compareTo(keys[i].getRow(), chosenRow) <= 0)) { (HStoreKey.compareTwoRowKeys(regionInfo,keys[i].getRow(), chosenRow) <= 0)) {
resultSets[i].clear(); resultSets[i].clear();
if (!scanners[i].next(keys[i], resultSets[i])) { if (!scanners[i].next(keys[i], resultSets[i])) {
closeScanner(i); closeScanner(i);
@ -2206,7 +2217,8 @@ public class HRegion implements HConstants {
byte [] row = r.getRegionName(); byte [] row = r.getRegionName();
Integer lid = meta.obtainRowLock(row); Integer lid = meta.obtainRowLock(row);
try { try {
HStoreKey key = new HStoreKey(row, COL_REGIONINFO, System.currentTimeMillis()); HStoreKey key = new HStoreKey(row, COL_REGIONINFO,
System.currentTimeMillis(), r.getRegionInfo());
TreeMap<HStoreKey, byte[]> edits = new TreeMap<HStoreKey, byte[]>(); TreeMap<HStoreKey, byte[]> edits = new TreeMap<HStoreKey, byte[]>();
edits.put(key, Writables.getBytes(r.getRegionInfo())); edits.put(key, Writables.getBytes(r.getRegionInfo()));
meta.update(edits); meta.update(edits);
@ -2307,9 +2319,9 @@ public class HRegion implements HConstants {
*/ */
public static boolean rowIsInRange(HRegionInfo info, final byte [] row) { public static boolean rowIsInRange(HRegionInfo info, final byte [] row) {
return ((info.getStartKey().length == 0) || return ((info.getStartKey().length == 0) ||
(Bytes.compareTo(info.getStartKey(), row) <= 0)) && (HStoreKey.compareTwoRowKeys(info,info.getStartKey(), row) <= 0)) &&
((info.getEndKey().length == 0) || ((info.getEndKey().length == 0) ||
(Bytes.compareTo(info.getEndKey(), row) > 0)); (HStoreKey.compareTwoRowKeys(info,info.getEndKey(), row) > 0));
} }
/** /**

View File

@ -188,7 +188,12 @@ public class HStore implements HConstants {
} }
this.desiredMaxFileSize = maxFileSize; this.desiredMaxFileSize = maxFileSize;
this.majorCompactionTime = conf.getLong("hbase.hregion.majorcompaction", 86400000); this.majorCompactionTime = conf.getLong(HConstants.MAJOR_COMPACTION_PERIOD, 86400000);
if (family.getValue(HConstants.MAJOR_COMPACTION_PERIOD) != null) {
String strCompactionTime = family.getValue(HConstants.MAJOR_COMPACTION_PERIOD);
this.majorCompactionTime = (new Long(strCompactionTime)).longValue();
}
this.maxFilesToCompact = conf.getInt("hbase.hstore.compaction.max", 10); this.maxFilesToCompact = conf.getInt("hbase.hstore.compaction.max", 10);
this.storeSize = 0L; this.storeSize = 0L;
@ -319,7 +324,8 @@ public class HStore implements HConstants {
|| !HStoreKey.matchingFamily(family.getName(), column)) { || !HStoreKey.matchingFamily(family.getName(), column)) {
continue; continue;
} }
HStoreKey k = new HStoreKey(key.getRow(), column, val.getTimestamp()); HStoreKey k = new HStoreKey(key.getRow(), column, val.getTimestamp(),
this.info);
reconstructedCache.put(k, val.getVal()); reconstructedCache.put(k, val.getVal());
editsCount++; editsCount++;
// Every 2k edits, tell the reporter we're making progress. // Every 2k edits, tell the reporter we're making progress.
@ -390,7 +396,7 @@ public class HStore implements HConstants {
if (isReference) { if (isReference) {
reference = HStoreFile.readSplitInfo(p, fs); reference = HStoreFile.readSplitInfo(p, fs);
} }
curfile = new HStoreFile(conf, fs, basedir, info.getEncodedName(), curfile = new HStoreFile(conf, fs, basedir, this.info,
family.getName(), fid, reference); family.getName(), fid, reference);
long storeSeqId = -1; long storeSeqId = -1;
try { try {
@ -424,7 +430,9 @@ public class HStore implements HConstants {
// Try fixing this file.. if we can. Use the hbase version of fix. // Try fixing this file.. if we can. Use the hbase version of fix.
// Need to remove the old index file first else fix won't go ahead. // Need to remove the old index file first else fix won't go ahead.
this.fs.delete(new Path(mapfile, MapFile.INDEX_FILE_NAME), false); this.fs.delete(new Path(mapfile, MapFile.INDEX_FILE_NAME), false);
long count = MapFile.fix(this.fs, mapfile, HStoreFile.HbaseMapFile.KEY_CLASS, // TODO: This is going to fail if we are to rebuild a file from
// meta because it won't have right comparator: HBASE-848.
long count = MapFile.fix(this.fs, mapfile, HStoreKey.class,
HStoreFile.HbaseMapFile.VALUE_CLASS, false, this.conf); HStoreFile.HbaseMapFile.VALUE_CLASS, false, this.conf);
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("Fixed index on " + mapfile.toString() + "; had " + LOG.debug("Fixed index on " + mapfile.toString() + "; had " +
@ -589,7 +597,7 @@ public class HStore implements HConstants {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
// A. Write the Maps out to the disk // A. Write the Maps out to the disk
HStoreFile flushedFile = new HStoreFile(conf, fs, basedir, HStoreFile flushedFile = new HStoreFile(conf, fs, basedir,
info.getEncodedName(), family.getName(), -1L, null); this.info, family.getName(), -1L, null);
MapFile.Writer out = flushedFile.getWriter(this.fs, this.compression, MapFile.Writer out = flushedFile.getWriter(this.fs, this.compression,
this.family.isBloomfilter(), cache.size()); this.family.isBloomfilter(), cache.size());
out.setIndexInterval(family.getMapFileIndexInterval()); out.setIndexInterval(family.getMapFileIndexInterval());
@ -873,8 +881,7 @@ public class HStore implements HConstants {
// Step through them, writing to the brand-new MapFile // Step through them, writing to the brand-new MapFile
HStoreFile compactedOutputFile = new HStoreFile(conf, fs, HStoreFile compactedOutputFile = new HStoreFile(conf, fs,
this.compactionDir, info.getEncodedName(), family.getName(), this.compactionDir, this.info, family.getName(), -1L, null);
-1L, null);
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("started compaction of " + rdrs.size() + " files into " + LOG.debug("started compaction of " + rdrs.size() + " files into " +
FSUtils.getPath(compactedOutputFile.getMapFilePath())); FSUtils.getPath(compactedOutputFile.getMapFilePath()));
@ -962,7 +969,7 @@ public class HStore implements HConstants {
} }
} }
HStoreKey sk = keys[smallestKey]; HStoreKey sk = keys[smallestKey];
if (Bytes.equals(lastRow, sk.getRow()) if (HStoreKey.equalsTwoRowKeys(info,lastRow, sk.getRow())
&& Bytes.equals(lastColumn, sk.getColumn())) { && Bytes.equals(lastColumn, sk.getColumn())) {
timesSeen++; timesSeen++;
} else { } else {
@ -1045,7 +1052,7 @@ public class HStore implements HConstants {
try { try {
// 1. Moving the new MapFile into place. // 1. Moving the new MapFile into place.
HStoreFile finalCompactedFile = new HStoreFile(conf, fs, basedir, HStoreFile finalCompactedFile = new HStoreFile(conf, fs, basedir,
info.getEncodedName(), family.getName(), -1, null); this.info, family.getName(), -1, null);
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("moving " + FSUtils.getPath(compactedFile.getMapFilePath()) + LOG.debug("moving " + FSUtils.getPath(compactedFile.getMapFilePath()) +
" to " + FSUtils.getPath(finalCompactedFile.getMapFilePath())); " to " + FSUtils.getPath(finalCompactedFile.getMapFilePath()));
@ -1207,7 +1214,7 @@ public class HStore implements HConstants {
} }
} }
} }
} else if (Bytes.compareTo(key.getRow(), readkey.getRow()) < 0) { } else if (HStoreKey.compareTwoRowKeys(info,key.getRow(), readkey.getRow()) < 0) {
// if we've crossed into the next row, then we can just stop // if we've crossed into the next row, then we can just stop
// iterating // iterating
break; break;
@ -1774,7 +1781,7 @@ public class HStore implements HConstants {
} }
static HStoreKey stripTimestamp(HStoreKey key) { static HStoreKey stripTimestamp(HStoreKey key) {
return new HStoreKey(key.getRow(), key.getColumn()); return new HStoreKey(key.getRow(), key.getColumn(), key.getHRegionInfo());
} }
/* /*
@ -1789,7 +1796,7 @@ public class HStore implements HConstants {
// if the origin's column is empty, then we're matching any column // if the origin's column is empty, then we're matching any column
if (Bytes.equals(origin.getColumn(), HConstants.EMPTY_BYTE_ARRAY)) { if (Bytes.equals(origin.getColumn(), HConstants.EMPTY_BYTE_ARRAY)) {
// if the row matches, then... // if the row matches, then...
if (Bytes.equals(target.getRow(), origin.getRow())) { if (HStoreKey.equalsTwoRowKeys(info, target.getRow(), origin.getRow())) {
// check the timestamp // check the timestamp
return target.getTimestamp() <= origin.getTimestamp(); return target.getTimestamp() <= origin.getTimestamp();
} }
@ -1810,7 +1817,7 @@ public class HStore implements HConstants {
// if the origin's column is empty, then we're matching any column // if the origin's column is empty, then we're matching any column
if (Bytes.equals(origin.getColumn(), HConstants.EMPTY_BYTE_ARRAY)) { if (Bytes.equals(origin.getColumn(), HConstants.EMPTY_BYTE_ARRAY)) {
// if the row matches, then... // if the row matches, then...
return Bytes.equals(target.getRow(), origin.getRow()); return HStoreKey.equalsTwoRowKeys(info, target.getRow(), origin.getRow());
} }
// otherwise, we want to match on row and column // otherwise, we want to match on row and column
return target.matchesRowCol(origin); return target.matchesRowCol(origin);
@ -1869,8 +1876,8 @@ public class HStore implements HConstants {
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 (Bytes.equals(mk.getRow(), firstKey.getRow()) && if (HStoreKey.equalsTwoRowKeys(info, mk.getRow(), firstKey.getRow()) &&
Bytes.equals(mk.getRow(), lastKey.getRow())) { HStoreKey.equalsTwoRowKeys(info, mk.getRow(), lastKey.getRow())) {
return null; return null;
} }
return new StoreSize(maxSize, mk.getRow()); return new StoreSize(maxSize, mk.getRow());
@ -1957,4 +1964,8 @@ public class HStore implements HConstants {
return key; return key;
} }
} }
HRegionInfo getHRegionInfo() {
return this.info;
}
} }

View File

@ -119,25 +119,28 @@ public class HStoreFile implements HConstants {
private final HBaseConfiguration conf; private final HBaseConfiguration conf;
private final FileSystem fs; private final FileSystem fs;
private final Reference reference; private final Reference reference;
private final HRegionInfo hri;
/** /**
* Constructor that fully initializes the object * Constructor that fully initializes the object
* @param conf Configuration object * @param conf Configuration object
* @param basedir qualified path that is parent of region directory * @param basedir qualified path that is parent of region directory
* @param encodedRegionName file name friendly name of the region
* @param colFamily name of the column family * @param colFamily name of the column family
* @param fileId file identifier * @param fileId file identifier
* @param ref Reference to another HStoreFile. * @param ref Reference to another HStoreFile.
* @param hri The region info for this file (HACK HBASE-868). TODO: Fix.
* @throws IOException * @throws IOException
*/ */
HStoreFile(HBaseConfiguration conf, FileSystem fs, Path basedir, HStoreFile(HBaseConfiguration conf, FileSystem fs, Path basedir,
int encodedRegionName, byte [] colFamily, long fileId, final HRegionInfo hri, byte [] colFamily, long fileId,
final Reference ref) throws IOException { final Reference ref)
throws IOException {
this.conf = conf; this.conf = conf;
this.fs = fs; this.fs = fs;
this.basedir = basedir; this.basedir = basedir;
this.encodedRegionName = encodedRegionName; this.encodedRegionName = hri.getEncodedName();
this.colFamily = colFamily; this.colFamily = colFamily;
this.hri = hri;
long id = fileId; long id = fileId;
if (id == -1) { if (id == -1) {
@ -431,7 +434,7 @@ public class HStoreFile implements HConstants {
"HStoreFile reference"); "HStoreFile reference");
} }
return new BloomFilterMapFile.Writer(conf, fs, return new BloomFilterMapFile.Writer(conf, fs,
getMapFilePath().toString(), compression, bloomFilter, nrows); getMapFilePath().toString(), compression, bloomFilter, nrows, this.hri);
} }
/** /**
@ -584,7 +587,6 @@ public class HStoreFile implements HConstants {
* Hbase customizations of MapFile. * Hbase customizations of MapFile.
*/ */
static class HbaseMapFile extends MapFile { static class HbaseMapFile extends MapFile {
static final Class<? extends Writable> KEY_CLASS = HStoreKey.class;
static final Class<? extends Writable> VALUE_CLASS = static final Class<? extends Writable> VALUE_CLASS =
ImmutableBytesWritable.class; ImmutableBytesWritable.class;
@ -672,9 +674,10 @@ public class HStoreFile implements HConstants {
* @throws IOException * @throws IOException
*/ */
public HbaseWriter(Configuration conf, FileSystem fs, String dirName, public HbaseWriter(Configuration conf, FileSystem fs, String dirName,
SequenceFile.CompressionType compression) SequenceFile.CompressionType compression, final HRegionInfo hri)
throws IOException { throws IOException {
super(conf, fs, dirName, KEY_CLASS, VALUE_CLASS, compression); super(conf, fs, dirName, new HStoreKey.HStoreKeyWritableComparator(hri),
VALUE_CLASS, compression);
// 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.
@ -788,14 +791,15 @@ public class HStoreFile implements HConstants {
* @param compression * @param compression
* @param filter * @param filter
* @param nrows * @param nrows
* @param hri
* @throws IOException * @throws IOException
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Writer(Configuration conf, FileSystem fs, String dirName, public Writer(Configuration conf, FileSystem fs, String dirName,
SequenceFile.CompressionType compression, final boolean filter, SequenceFile.CompressionType compression, final boolean filter,
int nrows) int nrows, final HRegionInfo hri)
throws IOException { throws IOException {
super(conf, fs, dirName, compression); super(conf, fs, dirName, compression, hri);
this.dirName = dirName; this.dirName = dirName;
this.fs = fs; this.fs = fs;
if (filter) { if (filter) {

View File

@ -119,8 +119,10 @@ class HStoreScanner implements InternalScanner {
for (int i = 0; i < this.keys.length; i++) { for (int i = 0; i < this.keys.length; i++) {
if (scanners[i] != null && if (scanners[i] != null &&
(chosenRow == null || (chosenRow == null ||
(Bytes.compareTo(keys[i].getRow(), chosenRow) < 0) || (HStoreKey.compareTwoRowKeys(store.getHRegionInfo(),
((Bytes.compareTo(keys[i].getRow(), chosenRow) == 0) && keys[i].getRow(), chosenRow) < 0) ||
((HStoreKey.compareTwoRowKeys(store.getHRegionInfo(),
keys[i].getRow(), chosenRow) == 0) &&
(keys[i].getTimestamp() > chosenTimestamp)))) { (keys[i].getTimestamp() > chosenTimestamp)))) {
chosenRow = keys[i].getRow(); chosenRow = keys[i].getRow();
chosenTimestamp = keys[i].getTimestamp(); chosenTimestamp = keys[i].getTimestamp();
@ -150,7 +152,8 @@ class HStoreScanner implements InternalScanner {
while ((scanners[i] != null while ((scanners[i] != null
&& !filtered && !filtered
&& moreToFollow) && moreToFollow)
&& (Bytes.compareTo(keys[i].getRow(), chosenRow) == 0)) { && (HStoreKey.compareTwoRowKeys(store.getHRegionInfo(),
keys[i].getRow(), chosenRow) == 0)) {
// If we are doing a wild card match or there are multiple // If we are doing a wild card match or there are multiple
// matchers per column, we need to scan all the older versions of // matchers per column, we need to scan all the older versions of
// this row to pick up the rest of the family members // this row to pick up the rest of the family members
@ -165,7 +168,7 @@ class HStoreScanner implements InternalScanner {
// values with older ones. So now we only insert // values with older ones. So now we only insert
// a result if the map does not contain the key. // a result if the map does not contain the key.
HStoreKey hsk = new HStoreKey(key.getRow(), HConstants.EMPTY_BYTE_ARRAY, HStoreKey hsk = new HStoreKey(key.getRow(), HConstants.EMPTY_BYTE_ARRAY,
key.getTimestamp()); key.getTimestamp(), this.store.getHRegionInfo());
for (Map.Entry<byte [], Cell> e : resultSets[i].entrySet()) { for (Map.Entry<byte [], Cell> e : resultSets[i].entrySet()) {
hsk.setColumn(e.getKey()); hsk.setColumn(e.getKey());
if (HLogEdit.isDeleted(e.getValue().getValue())) { if (HLogEdit.isDeleted(e.getValue().getValue())) {
@ -202,7 +205,8 @@ class HStoreScanner implements InternalScanner {
// If the current scanner is non-null AND has a lower-or-equal // If the current scanner is non-null AND has a lower-or-equal
// row label, then its timestamp is bad. We need to advance it. // row label, then its timestamp is bad. We need to advance it.
while ((scanners[i] != null) && while ((scanners[i] != null) &&
(Bytes.compareTo(keys[i].getRow(), chosenRow) <= 0)) { (HStoreKey.compareTwoRowKeys(store.getHRegionInfo(),
keys[i].getRow(), chosenRow) <= 0)) {
resultSets[i].clear(); resultSets[i].clear();
if (!scanners[i].next(keys[i], resultSets[i])) { if (!scanners[i].next(keys[i], resultSets[i])) {
closeScanner(i); closeScanner(i);

View File

@ -61,12 +61,10 @@ class Memcache {
// so no additional synchronization is required. // so no additional synchronization is required.
// The currently active sorted map of edits. // The currently active sorted map of edits.
private volatile SortedMap<HStoreKey, byte[]> memcache = private volatile SortedMap<HStoreKey, byte[]> memcache;
createSynchronizedSortedMap();
// Snapshot of memcache. Made for flusher. // Snapshot of memcache. Made for flusher.
private volatile SortedMap<HStoreKey, byte[]> snapshot = private volatile SortedMap<HStoreKey, byte[]> snapshot;
createSynchronizedSortedMap();
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
@ -75,7 +73,10 @@ class Memcache {
*/ */
public Memcache() { public Memcache() {
this.ttl = HConstants.FOREVER; this.ttl = HConstants.FOREVER;
this.regionInfo = null; // Set default to be the first meta region.
this.regionInfo = HRegionInfo.FIRST_META_REGIONINFO;
this.memcache = createSynchronizedSortedMap();
this.snapshot = createSynchronizedSortedMap();
} }
/** /**
@ -86,14 +87,18 @@ class Memcache {
public Memcache(final long ttl, HRegionInfo regionInfo) { public Memcache(final long ttl, HRegionInfo regionInfo) {
this.ttl = ttl; this.ttl = ttl;
this.regionInfo = regionInfo; this.regionInfo = regionInfo;
this.memcache = createSynchronizedSortedMap();
this.snapshot = createSynchronizedSortedMap();
} }
/* /*
* Utility method. * Utility method using HSKWritableComparator
* @return sycnhronized sorted map of HStoreKey to byte arrays. * @return sycnhronized sorted map of HStoreKey to byte arrays.
*/ */
private static SortedMap<HStoreKey, byte[]> createSynchronizedSortedMap() { private SortedMap<HStoreKey, byte[]> createSynchronizedSortedMap() {
return Collections.synchronizedSortedMap(new TreeMap<HStoreKey, byte []>()); return Collections.synchronizedSortedMap(
new TreeMap<HStoreKey, byte []>(
new HStoreKey.HStoreKeyWritableComparator(this.regionInfo)));
} }
/** /**
@ -229,7 +234,7 @@ class Memcache {
if (b == null) { if (b == null) {
return a; return a;
} }
return Bytes.compareTo(a, b) <= 0? a: b; return HStoreKey.compareTwoRowKeys(regionInfo, a, b) <= 0? a: b;
} }
/** /**
@ -259,14 +264,13 @@ class Memcache {
synchronized (map) { synchronized (map) {
// Make an HSK with maximum timestamp so we get past most of the current // Make an HSK with maximum timestamp so we get past most of the current
// rows cell entries. // rows cell entries.
HStoreKey hsk = new HStoreKey(row, HConstants.LATEST_TIMESTAMP); HStoreKey hsk = new HStoreKey(row, HConstants.LATEST_TIMESTAMP, this.regionInfo);
SortedMap<HStoreKey, byte []> tailMap = map.tailMap(hsk); SortedMap<HStoreKey, byte []> tailMap = map.tailMap(hsk);
// Iterate until we fall into the next row; i.e. move off current row // Iterate until we fall into the next row; i.e. move off current row
for (Map.Entry<HStoreKey, byte []> es: tailMap.entrySet()) { for (Map.Entry<HStoreKey, byte []> es: tailMap.entrySet()) {
HStoreKey itKey = es.getKey(); HStoreKey itKey = es.getKey();
if (Bytes.compareTo(itKey.getRow(), row) <= 0) { if (HStoreKey.compareTwoRowKeys(regionInfo, itKey.getRow(), row) <= 0)
continue; continue;
}
// Note: Not suppressing deletes or expired cells. // Note: Not suppressing deletes or expired cells.
result = itKey.getRow(); result = itKey.getRow();
break; break;
@ -330,14 +334,16 @@ class Memcache {
} }
} }
} }
} else if (Bytes.compareTo(key.getRow(), itKey.getRow()) < 0) { } else if (HStoreKey.compareTwoRowKeys(regionInfo, key.getRow(),
itKey.getRow()) < 0) {
break; break;
} }
} }
// Remove expired victims from the map. // Remove expired victims from the map.
for (HStoreKey v: victims) for (HStoreKey v: victims) {
map.remove(v); map.remove(v);
} }
}
/** /**
* @param row Row to look for. * @param row Row to look for.
@ -377,8 +383,8 @@ class Memcache {
final Set<HStoreKey> deletes) { final Set<HStoreKey> deletes) {
// We want the earliest possible to start searching from. Start before // We want the earliest possible to start searching from. Start before
// the candidate key in case it turns out a delete came in later. // the candidate key in case it turns out a delete came in later.
HStoreKey search_key = candidateKeys.isEmpty()? new HStoreKey(row): HStoreKey search_key = candidateKeys.isEmpty()? new HStoreKey(row, this.regionInfo):
new HStoreKey(candidateKeys.firstKey().getRow()); new HStoreKey(candidateKeys.firstKey().getRow(), this.regionInfo);
List<HStoreKey> victims = new ArrayList<HStoreKey>(); List<HStoreKey> victims = new ArrayList<HStoreKey>();
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
@ -409,7 +415,8 @@ class Memcache {
deletedOrExpiredRow = found_key; deletedOrExpiredRow = found_key;
} }
} else { } else {
if (HStore.notExpiredAndNotInDeletes(this.ttl, found_key, now, deletes)) { if (HStore.notExpiredAndNotInDeletes(this.ttl,
found_key, now, deletes)) {
candidateKeys.put(stripTimestamp(found_key), candidateKeys.put(stripTimestamp(found_key),
new Long(found_key.getTimestamp())); new Long(found_key.getTimestamp()));
} else { } else {
@ -469,7 +476,8 @@ class Memcache {
// not a delete record. // not a delete record.
boolean deleted = HLogEdit.isDeleted(headMap.get(found_key)); boolean deleted = HLogEdit.isDeleted(headMap.get(found_key));
if (lastRowFound != null && if (lastRowFound != null &&
!Bytes.equals(lastRowFound, found_key.getRow()) && !deleted) { !HStoreKey.equalsTwoRowKeys(regionInfo, lastRowFound,
found_key.getRow()) && !deleted) {
break; break;
} }
// If this isn't a delete, record it as a candidate key. Also // If this isn't a delete, record it as a candidate key. Also
@ -496,7 +504,7 @@ class Memcache {
// smaller acceptable candidate keys would have caused us to start // smaller acceptable candidate keys would have caused us to start
// our search earlier in the list, and we wouldn't be searching here. // our search earlier in the list, and we wouldn't be searching here.
SortedMap<HStoreKey, byte[]> thisRowTailMap = SortedMap<HStoreKey, byte[]> thisRowTailMap =
headMap.tailMap(new HStoreKey(headMap.lastKey().getRow())); headMap.tailMap(new HStoreKey(headMap.lastKey().getRow(), this.regionInfo));
Iterator<HStoreKey> key_iterator = thisRowTailMap.keySet().iterator(); Iterator<HStoreKey> key_iterator = thisRowTailMap.keySet().iterator();
do { do {
HStoreKey found_key = key_iterator.next(); HStoreKey found_key = key_iterator.next();
@ -521,7 +529,7 @@ class Memcache {
} }
static HStoreKey stripTimestamp(HStoreKey key) { static HStoreKey stripTimestamp(HStoreKey key) {
return new HStoreKey(key.getRow(), key.getColumn()); return new HStoreKey(key.getRow(), key.getColumn(), key.getHRegionInfo());
} }
/* /*
@ -636,7 +644,8 @@ class Memcache {
if (origin.getColumn() != null && origin.getColumn().length == 0) { if (origin.getColumn() != null && origin.getColumn().length == 0) {
// if the current and origin row don't match, then we can jump // if the current and origin row don't match, then we can jump
// out of the loop entirely. // out of the loop entirely.
if (!Bytes.equals(key.getRow(), origin.getRow())) { if (!HStoreKey.equalsTwoRowKeys(regionInfo, key.getRow(),
origin.getRow())) {
break; break;
} }
// if the rows match but the timestamp is newer, skip it so we can // if the rows match but the timestamp is newer, skip it so we can
@ -788,7 +797,6 @@ class Memcache {
results.put(column, c); results.put(column, c);
} }
this.currentRow = getNextRow(this.currentRow); this.currentRow = getNextRow(this.currentRow);
} }
// Set the timestamp to the largest one for the row if we would otherwise // Set the timestamp to the largest one for the row if we would otherwise
// return HConstants.LATEST_TIMESTAMP // return HConstants.LATEST_TIMESTAMP

View File

@ -101,7 +101,7 @@ implements ChangedReadersObserver {
// Advance the readers to the first pos. // Advance the readers to the first pos.
for (i = 0; i < readers.length; i++) { for (i = 0; i < readers.length; i++) {
keys[i] = new HStoreKey(); keys[i] = new HStoreKey(HConstants.EMPTY_BYTE_ARRAY, this.store.getHRegionInfo());
if (firstRow != null && firstRow.length != 0) { if (firstRow != null && firstRow.length != 0) {
if (findFirstRow(i, firstRow)) { if (findFirstRow(i, firstRow)) {
continue; continue;
@ -159,7 +159,8 @@ implements ChangedReadersObserver {
for (int i = 0; i < keys.length; i++) { for (int i = 0; i < keys.length; i++) {
// Fetch the data // Fetch the data
while ((keys[i] != null) while ((keys[i] != null)
&& (Bytes.compareTo(keys[i].getRow(), viableRow.getRow()) == 0)) { && (HStoreKey.compareTwoRowKeys(store.getHRegionInfo(),
keys[i].getRow(), viableRow.getRow()) == 0)) {
// If we are doing a wild card match or there are multiple matchers // If we are doing a wild card match or there are multiple matchers
// per column, we need to scan all the older versions of this row // per column, we need to scan all the older versions of this row
@ -187,7 +188,8 @@ implements ChangedReadersObserver {
// Advance the current scanner beyond the chosen row, to // Advance the current scanner beyond the chosen row, to
// a valid timestamp, so we're ready next time. // a valid timestamp, so we're ready next time.
while ((keys[i] != null) while ((keys[i] != null)
&& ((Bytes.compareTo(keys[i].getRow(), viableRow.getRow()) <= 0) && ((HStoreKey.compareTwoRowKeys(store.getHRegionInfo(),
keys[i].getRow(), viableRow.getRow()) <= 0)
|| (keys[i].getTimestamp() > this.timestamp) || (keys[i].getTimestamp() > this.timestamp)
|| (! columnMatch(i)))) { || (! columnMatch(i)))) {
getNext(i); getNext(i);
@ -246,8 +248,10 @@ implements ChangedReadersObserver {
// column matches and the timestamp of the row is less than or equal // column matches and the timestamp of the row is less than or equal
// to this.timestamp, so we do not need to test that here // to this.timestamp, so we do not need to test that here
&& ((viableRow == null) && ((viableRow == null)
|| (Bytes.compareTo(keys[i].getRow(), viableRow) < 0) || (HStoreKey.compareTwoRowKeys(store.getHRegionInfo(),
|| ((Bytes.compareTo(keys[i].getRow(), viableRow) == 0) keys[i].getRow(), viableRow) < 0)
|| ((HStoreKey.compareTwoRowKeys(store.getHRegionInfo(),
keys[i].getRow(), viableRow) == 0)
&& (keys[i].getTimestamp() > viableTimestamp)))) { && (keys[i].getTimestamp() > viableTimestamp)))) {
if (ttl == HConstants.FOREVER || now < keys[i].getTimestamp() + ttl) { if (ttl == HConstants.FOREVER || now < keys[i].getTimestamp() + ttl) {
viableRow = keys[i].getRow(); viableRow = keys[i].getRow();
@ -273,7 +277,7 @@ implements ChangedReadersObserver {
private boolean findFirstRow(int i, final byte [] firstRow) throws IOException { private boolean findFirstRow(int i, final byte [] firstRow) throws IOException {
ImmutableBytesWritable ibw = new ImmutableBytesWritable(); ImmutableBytesWritable ibw = new ImmutableBytesWritable();
HStoreKey firstKey HStoreKey firstKey
= (HStoreKey)readers[i].getClosest(new HStoreKey(firstRow), ibw); = (HStoreKey)readers[i].getClosest(new HStoreKey(firstRow, this.store.getHRegionInfo()), ibw);
if (firstKey == null) { if (firstKey == null) {
// Didn't find it. Close the scanner and return TRUE // Didn't find it. Close the scanner and return TRUE
closeSubScanner(i); closeSubScanner(i);

View File

@ -34,6 +34,7 @@ import org.apache.hadoop.io.WritableComparable;
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.HStoreKey; import org.apache.hadoop.hbase.HStoreKey;
/** /**
* Test HStoreFile * Test HStoreFile
@ -126,7 +127,7 @@ public class TestHStoreFile extends HBaseTestCase {
throws IOException { throws IOException {
// Make a store file and write data to it. // Make a store file and write data to it.
HStoreFile hsf = new HStoreFile(this.conf, this.fs, this.dir, HStoreFile hsf = new HStoreFile(this.conf, this.fs, this.dir,
JenkinsHash.hash(Bytes.toBytes(getName())), HRegionInfo.FIRST_META_REGIONINFO,
Bytes.toBytes("colfamily"), 1234567890L, null); Bytes.toBytes("colfamily"), 1234567890L, null);
MapFile.Writer writer = MapFile.Writer writer =
hsf.getWriter(this.fs, SequenceFile.CompressionType.NONE, false, 0); hsf.getWriter(this.fs, SequenceFile.CompressionType.NONE, false, 0);
@ -145,7 +146,7 @@ public class TestHStoreFile extends HBaseTestCase {
midkey, HStoreFile.Range.top); midkey, HStoreFile.Range.top);
HStoreFile refHsf = new HStoreFile(this.conf, this.fs, HStoreFile refHsf = new HStoreFile(this.conf, this.fs,
new Path(DIR, getName()), new Path(DIR, getName()),
JenkinsHash.hash(Bytes.toBytes(getName() + "_reference")), HRegionInfo.FIRST_META_REGIONINFO,
hsf.getColFamily(), 456, reference); hsf.getColFamily(), 456, reference);
// Assert that reference files are written and that we can write and // Assert that reference files are written and that we can write and
// read the info reference file at least. // read the info reference file at least.