You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by ap...@apache.org on 2009/06/16 06:34:02 UTC
svn commit: r785076 [2/18] - in /hadoop/hbase/trunk_on_hadoop-0.18.3: ./
bin/ conf/ src/java/ src/java/org/apache/hadoop/hbase/
src/java/org/apache/hadoop/hbase/client/
src/java/org/apache/hadoop/hbase/filter/
src/java/org/apache/hadoop/hbase/io/ src/j...
Modified: hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/KeyValue.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/KeyValue.java?rev=785076&r1=785075&r2=785076&view=diff
==============================================================================
--- hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/KeyValue.java (original)
+++ hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/KeyValue.java Tue Jun 16 04:33:56 2009
@@ -25,11 +25,11 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.hbase.io.HeapSize;
import org.apache.hadoop.hbase.io.hfile.HFile;
import org.apache.hadoop.hbase.util.Bytes;
-import org.apache.hadoop.hbase.io.HeapSize;
-import org.apache.hadoop.io.Writable;
import org.apache.hadoop.io.RawComparator;
+import org.apache.hadoop.io.Writable;
/**
* An HBase Key/Value. Instances of this class are immutable. They are not
@@ -59,6 +59,8 @@
* Colon character in UTF-8
*/
public static final char COLUMN_FAMILY_DELIMITER = ':';
+
+ public static final byte[] COLUMN_FAMILY_DELIM_ARRAY = new byte[]{COLUMN_FAMILY_DELIMITER};
/**
* Comparator for plain key/values; i.e. non-catalog table key/values.
@@ -118,26 +120,45 @@
return compare(a, 0, a.length, b, 0, b.length);
}
};
+
+ /**
+ * Get the appropriate row comparator for the specified table.
+ *
+ * Hopefully we can get rid of this, I added this here because it's replacing
+ * something in HSK. We should move completely off of that.
+ *
+ * @param tableName The table name.
+ * @return The comparator.
+ */
+ public static KeyComparator getRowComparator(byte [] tableName) {
+ if(Bytes.equals(HTableDescriptor.ROOT_TABLEDESC.getName(),tableName)) {
+ return ROOT_COMPARATOR.getRawComparator();
+ }
+ if(Bytes.equals(HTableDescriptor.META_TABLEDESC.getName(), tableName)) {
+ return META_COMPARATOR.getRawComparator();
+ }
+ return COMPARATOR.getRawComparator();
+ }
// Size of the timestamp and type byte on end of a key -- a long + a byte.
- private static final int TIMESTAMP_TYPE_SIZE =
+ public static final int TIMESTAMP_TYPE_SIZE =
Bytes.SIZEOF_LONG /* timestamp */ +
Bytes.SIZEOF_BYTE /*keytype*/;
// Size of the length shorts and bytes in key.
- private static final int KEY_INFRASTRUCTURE_SIZE =
+ public static final int KEY_INFRASTRUCTURE_SIZE =
Bytes.SIZEOF_SHORT /*rowlength*/ +
Bytes.SIZEOF_BYTE /*columnfamilylength*/ +
TIMESTAMP_TYPE_SIZE;
// How far into the key the row starts at. First thing to read is the short
// that says how long the row is.
- private static final int ROW_OFFSET =
+ public static final int ROW_OFFSET =
Bytes.SIZEOF_INT /*keylength*/ +
Bytes.SIZEOF_INT /*valuelength*/;
// Size of the length ints in a KeyValue datastructure.
- private static final int KEYVALUE_INFRASTRUCTURE_SIZE = ROW_OFFSET;
+ public static final int KEYVALUE_INFRASTRUCTURE_SIZE = ROW_OFFSET;
/**
* Key type.
@@ -145,10 +166,13 @@
* enum ordinals . They change if item is removed or moved. Do our own codes.
*/
public static enum Type {
+ Minimum((byte)0),
Put((byte)4),
+
Delete((byte)8),
DeleteColumn((byte)12),
DeleteFamily((byte)14),
+
// Maximum is used when searching; you look from maximum on down.
Maximum((byte)255);
@@ -233,194 +257,200 @@
this.offset = offset;
this.length = length;
}
+
+ /** Temporary constructors until 880/1249 is committed to remove deps */
/**
- * Constructs KeyValue structure filled with null value.
- * @param row - row key (arbitrary byte array)
- * @param timestamp
+ * Temporary.
*/
- public KeyValue(final String row, final long timestamp) {
- this(Bytes.toBytes(row), timestamp);
+ public KeyValue(final byte [] row, final byte [] column) {
+ this(row, column, HConstants.LATEST_TIMESTAMP, null);
}
-
+
+ public KeyValue(final byte [] row, final byte [] column, long ts) {
+ this(row, column, ts, null);
+ }
+
+ public KeyValue(final byte [] row, final byte [] column, long ts,
+ byte [] value) {
+ this(row, column, ts, Type.Put, value);
+ }
+
+ public KeyValue(final byte [] row, final byte [] column, long ts, Type type,
+ byte [] value) {
+ int rlength = row == null ? 0 : row.length;
+ int vlength = value == null ? 0 : value.length;
+ int clength = column == null ? 0 : column.length;
+ this.bytes = createByteArray(row, 0, rlength, column, 0, clength,
+ ts, type, value, 0, vlength);
+ this.length = this.bytes.length;
+ this.offset = 0;
+ }
+
+ /** Constructors that build a new backing byte array from fields */
+
/**
* Constructs KeyValue structure filled with null value.
* @param row - row key (arbitrary byte array)
* @param timestamp
*/
public KeyValue(final byte [] row, final long timestamp) {
- this(row, null, timestamp, Type.Put, null);
- }
-
- /**
- * Constructs KeyValue structure filled with null value.
- * @param row - row key (arbitrary byte array)
- * @param column Column with delimiter between family and qualifier
- */
- public KeyValue(final String row, final String column) {
- this(row, column, null);
+ this(row, timestamp, Type.Put);
}
/**
* Constructs KeyValue structure filled with null value.
* @param row - row key (arbitrary byte array)
- * @param column Column with delimiter between family and qualifier
- */
- public KeyValue(final byte [] row, final byte [] column) {
- this(row, column, null);
- }
-
- /**
- * Constructs KeyValue structure filled with specified value.
- * @param row - row key (arbitrary byte array)
- * @param column Column with delimiter between family and qualifier
- * @param value
- */
- public KeyValue(final String row, final String column, final byte [] value) {
- this(Bytes.toBytes(row), Bytes.toBytes(column), value);
- }
-
- /**
- * Constructs KeyValue structure filled with specified value.
- * @param row - row key (arbitrary byte array)
- * @param column Column with delimiter between family and qualifier
- * @param value
+ * @param timestamp
*/
- public KeyValue(final byte [] row, final byte [] column, final byte [] value) {
- this(row, column, HConstants.LATEST_TIMESTAMP, value);
+ public KeyValue(final byte [] row, final long timestamp, Type type) {
+ this(row, null, null, timestamp, type, null);
}
-
/**
* Constructs KeyValue structure filled with null value.
* @param row - row key (arbitrary byte array)
- * @param column Column with delimiter between family and qualifier
- * @param ts
+ * @param family family name
+ * @param qualifier column qualifier
*/
- public KeyValue(final String row, final String column, final long ts) {
- this(row, column, ts, null);
+ public KeyValue(final byte [] row, final byte [] family,
+ final byte [] qualifier) {
+ this(row, family, qualifier, HConstants.LATEST_TIMESTAMP, Type.Put);
}
/**
* Constructs KeyValue structure filled with null value.
* @param row - row key (arbitrary byte array)
- * @param column Column with delimiter between family and qualifier
- * @param ts
- */
- public KeyValue(final byte [] row, final byte [] column, final long ts) {
- this(row, column, ts, Type.Put);
- }
-
- /**
- * Constructs KeyValue structure filled with specified value.
- * @param row - row key (arbitrary byte array)
- * @param column Column with delimiter between family and qualifier
- * @param timestamp
- * @param value
+ * @param family family name
+ * @param qualifier column qualifier
*/
- public KeyValue(final String row, final String column,
- final long timestamp, final byte [] value) {
- this(Bytes.toBytes(row),
- column == null? HConstants.EMPTY_BYTE_ARRAY: Bytes.toBytes(column),
- timestamp, value);
+ public KeyValue(final byte [] row, final byte [] family,
+ final byte [] qualifier, final byte [] value) {
+ this(row, family, qualifier, HConstants.LATEST_TIMESTAMP, Type.Put, value);
}
/**
- * Constructs KeyValue structure filled with specified value.
- * @param row - row key (arbitrary byte array)
- * @param column Column with delimiter between family and qualifier
- * @param timestamp
- * @param value
+ * Constructs KeyValue structure filled with specified values.
+ * @param row row key
+ * @param family family name
+ * @param qualifier column qualifier
+ * @param timestamp version timestamp
+ * @param type key type
+ * @throws IllegalArgumentException
*/
- public KeyValue(final byte [] row, final byte [] column,
- final long timestamp, final byte [] value) {
- this(row, column, timestamp, Type.Put, value);
+ public KeyValue(final byte[] row, final byte[] family,
+ final byte[] qualifier, final long timestamp, Type type) {
+ this(row, family, qualifier, timestamp, type, null);
}
-
+
/**
- * Constructs KeyValue structure filled with specified value.
- * @param row - row key (arbitrary byte array)
- * @param column Column with delimiter between family and qualifier
- * @param timestamp
- * @param type
- * @param value
+ * Constructs KeyValue structure filled with specified values.
+ * @param row row key
+ * @param family family name
+ * @param qualifier column qualifier
+ * @param timestamp version timestamp
+ * @param value column value
+ * @throws IllegalArgumentException
*/
- public KeyValue(final String row, final String column,
- final long timestamp, final Type type, final byte [] value) {
- this(Bytes.toBytes(row), Bytes.toBytes(column), timestamp, type,
- value);
+ public KeyValue(final byte[] row, final byte[] family,
+ final byte[] qualifier, final long timestamp, final byte[] value) {
+ this(row, family, qualifier, timestamp, Type.Put, value);
}
-
+
/**
- * Constructs KeyValue structure filled with null value.
- * @param row - row key (arbitrary byte array)
- * @param column Column with delimiter between family and qualifier
- * @param timestamp
- * @param type
+ * Constructs KeyValue structure filled with specified values.
+ * @param row row key
+ * @param family family name
+ * @param qualifier column qualifier
+ * @param timestamp version timestamp
+ * @param type key type
+ * @param value column value
+ * @throws IllegalArgumentException
*/
- public KeyValue(final byte [] row, final byte [] column,
- final long timestamp, final Type type) {
- this(row, 0, row.length, column, 0, column == null? 0: column.length,
- timestamp, type, null, 0, -1);
- }
-
- /**
- * Constructs KeyValue structure filled with specified value.
- * @param row - row key (arbitrary byte array)
- * @param column Column with delimiter between family and qualifier
- * @param timestamp
- * @param type
- * @param value
+ public KeyValue(final byte[] row, final byte[] family,
+ final byte[] qualifier, final long timestamp, Type type,
+ final byte[] value) {
+ this(row, family, qualifier, 0, qualifier==null ? 0 : qualifier.length,
+ timestamp, type, value, 0, value==null ? 0 : value.length);
+ }
+
+ /**
+ * Constructs KeyValue structure filled with specified values.
+ * @param row row key
+ * @param family family name
+ * @param qualifier column qualifier
+ * @param qoffset qualifier offset
+ * @param qlength qualifier length
+ * @param timestamp version timestamp
+ * @param type key type
+ * @param value column value
+ * @param voffset value offset
+ * @param vlength value length
+ * @throws IllegalArgumentException
*/
- public KeyValue(final byte [] row, final byte [] column,
- final long timestamp, final Type type, final byte [] value) {
- this(row, 0, row.length, column, 0, column == null? 0: column.length,
- timestamp, type, value, 0, value == null? 0: value.length);
+ public KeyValue(byte [] row, byte [] family,
+ byte [] qualifier, int qoffset, int qlength, long timestamp, Type type,
+ byte [] value, int voffset, int vlength) {
+ this(row, 0, row==null ? 0 : row.length,
+ family, 0, family==null ? 0 : family.length,
+ qualifier, qoffset, qlength, timestamp, type,
+ value, voffset, vlength);
}
/**
- * Constructs KeyValue structure filled with specified value.
- * @param row - row key (arbitrary byte array)
- * @param roffset
- * @param rlength
- * @param column Column with delimiter between family and qualifier
- * @param coffset Where to start reading the column.
- * @param clength How long column is (including the family/qualifier delimiter.
- * @param timestamp
- * @param type
- * @param value
- * @param voffset
- * @param vlength
+ * Constructs KeyValue structure filled with specified values.
+ * <p>
+ * Column is split into two fields, family and qualifier.
+ * @param row row key
+ * @param roffset row offset
+ * @param rlength row length
+ * @param family family name
+ * @param foffset family offset
+ * @param flength family length
+ * @param qualifier column qualifier
+ * @param qoffset qualifier offset
+ * @param qlength qualifier length
+ * @param timestamp version timestamp
+ * @param type key type
+ * @param value column value
+ * @param voffset value offset
+ * @param vlength value length
* @throws IllegalArgumentException
*/
public KeyValue(final byte [] row, final int roffset, final int rlength,
- final byte [] column, final int coffset, int clength,
+ final byte [] family, final int foffset, final int flength,
+ final byte [] qualifier, final int qoffset, final int qlength,
final long timestamp, final Type type,
- final byte [] value, final int voffset, int vlength) {
- this.bytes = createByteArray(row, roffset, rlength, column, coffset,
- clength, timestamp, type, value, voffset, vlength);
+ final byte [] value, final int voffset, final int vlength) {
+ this.bytes = createByteArray(row, roffset, rlength,
+ family, foffset, flength, qualifier, qoffset, qlength,
+ timestamp, type, value, voffset, vlength);
this.length = bytes.length;
this.offset = 0;
}
/**
* Write KeyValue format into a byte array.
- * @param row - row key (arbitrary byte array)
- * @param roffset
- * @param rlength
- * @param column
- * @param coffset
- * @param clength
- * @param timestamp
- * @param type
- * @param value
- * @param voffset
- * @param vlength
- * @return
+ *
+ * @param row row key
+ * @param roffset row offset
+ * @param rlength row length
+ * @param family family name
+ * @param foffset family offset
+ * @param flength family length
+ * @param qualifier column qualifier
+ * @param qoffset qualifier offset
+ * @param qlength qualifier length
+ * @param timestamp version timestamp
+ * @param type key type
+ * @param value column value
+ * @param voffset value offset
+ * @param vlength value length
+ * @return The newly created byte array.
*/
static byte [] createByteArray(final byte [] row, final int roffset,
- final int rlength,
- final byte [] column, final int coffset, int clength,
+ final int rlength, final byte [] family, final int foffset, int flength,
+ final byte [] qualifier, final int qoffset, int qlength,
final long timestamp, final Type type,
final byte [] value, final int voffset, int vlength) {
if (rlength > Short.MAX_VALUE) {
@@ -429,24 +459,30 @@
if (row == null) {
throw new IllegalArgumentException("Row is null");
}
- // If column is non-null, figure where the delimiter is at.
- int delimiteroffset = 0;
- if (column != null && column.length > 0) {
- delimiteroffset = getFamilyDelimiterIndex(column, coffset, clength);
- if (delimiteroffset > Byte.MAX_VALUE) {
- throw new IllegalArgumentException("Family > " + Byte.MAX_VALUE);
- }
+ // Family length
+ flength = family == null ? 0 : flength;
+ if (flength > Byte.MAX_VALUE) {
+ throw new IllegalArgumentException("Family > " + Byte.MAX_VALUE);
+ }
+ // Qualifier length
+ qlength = qualifier == null ? 0 : qlength;
+ if (qlength > Integer.MAX_VALUE - rlength - flength) {
+ throw new IllegalArgumentException("Qualifier > " + Integer.MAX_VALUE);
}
- // Value length
- vlength = value == null? 0: vlength;
- // Column length - minus delimiter
- clength = column == null || column.length == 0? 0: clength - 1;
- long longkeylength = KEY_INFRASTRUCTURE_SIZE + rlength + clength;
+ // Key length
+ long longkeylength = KEY_INFRASTRUCTURE_SIZE + rlength + flength + qlength;
if (longkeylength > Integer.MAX_VALUE) {
throw new IllegalArgumentException("keylength " + longkeylength + " > " +
Integer.MAX_VALUE);
}
int keylength = (int)longkeylength;
+ // Value length
+ vlength = value == null? 0 : vlength;
+ if (vlength > HConstants.MAXIMUM_VALUE_LENGTH) {
+ throw new IllegalArgumentException("Valuer > " +
+ HConstants.MAXIMUM_VALUE_LENGTH);
+ }
+
// Allocate right-sized byte array.
byte [] bytes = new byte[KEYVALUE_INFRASTRUCTURE_SIZE + keylength + vlength];
// Write key, value and key row length.
@@ -455,15 +491,12 @@
pos = Bytes.putInt(bytes, pos, vlength);
pos = Bytes.putShort(bytes, pos, (short)(rlength & 0x0000ffff));
pos = Bytes.putBytes(bytes, pos, row, roffset, rlength);
- // Write out column family length.
- pos = Bytes.putByte(bytes, pos, (byte)(delimiteroffset & 0x0000ff));
- if (column != null && column.length != 0) {
- // Write family.
- pos = Bytes.putBytes(bytes, pos, column, coffset, delimiteroffset);
- // Write qualifier.
- delimiteroffset++;
- pos = Bytes.putBytes(bytes, pos, column, coffset + delimiteroffset,
- column.length - delimiteroffset);
+ pos = Bytes.putByte(bytes, pos, (byte)(flength & 0x0000ff));
+ if(flength != 0) {
+ pos = Bytes.putBytes(bytes, pos, family, foffset, flength);
+ }
+ if(qlength != 0) {
+ pos = Bytes.putBytes(bytes, pos, qualifier, qoffset, qlength);
}
pos = Bytes.putLong(bytes, pos, timestamp);
pos = Bytes.putByte(bytes, pos, type.getCode());
@@ -472,6 +505,46 @@
}
return bytes;
}
+
+ /**
+ * Write KeyValue format into a byte array.
+ * <p>
+ * Takes column in the form <code>family:qualifier</code>
+ * @param row - row key (arbitrary byte array)
+ * @param roffset
+ * @param rlength
+ * @param column
+ * @param coffset
+ * @param clength
+ * @param timestamp
+ * @param type
+ * @param value
+ * @param voffset
+ * @param vlength
+ * @return The newly created byte array.
+ */
+ static byte [] createByteArray(final byte [] row, final int roffset,
+ final int rlength,
+ final byte [] column, final int coffset, int clength,
+ final long timestamp, final Type type,
+ final byte [] value, final int voffset, int vlength) {
+ // If column is non-null, figure where the delimiter is at.
+ int delimiteroffset = 0;
+ if (column != null && column.length > 0) {
+ delimiteroffset = getFamilyDelimiterIndex(column, coffset, clength);
+ if (delimiteroffset > Byte.MAX_VALUE) {
+ throw new IllegalArgumentException("Family > " + Byte.MAX_VALUE);
+ }
+ } else {
+ return createByteArray(row,roffset,rlength,null,0,0,null,0,0,timestamp,
+ type,value,voffset,vlength);
+ }
+ int flength = delimiteroffset-coffset;
+ int qlength = clength - flength - 1;
+ return createByteArray(row, roffset, rlength, column, coffset,
+ flength, column, delimiteroffset+1, qlength, timestamp, type,
+ value, voffset, vlength);
+ }
// Needed doing 'contains' on List. Only compares the key portion, not the
// value.
@@ -485,37 +558,36 @@
return result;
}
+ //---------------------------------------------------------------------------
+ //
+ // KeyValue cloning
+ //
+ //---------------------------------------------------------------------------
+
/**
- * @param timestamp
+ * Clones a row.
+ *
+ * @param timestamp The new time stamp for the row.
* @return Clone of bb's key portion with only the row and timestamp filled in.
- * @throws IOException
*/
public KeyValue cloneRow(final long timestamp) {
return new KeyValue(getBuffer(), getRowOffset(), getRowLength(),
- null, 0, 0, timestamp, Type.codeToType(getType()), null, 0, 0);
- }
-
- /**
- * @return Clone of bb's key portion with type set to Type.Delete.
- * @throws IOException
- */
- public KeyValue cloneDelete() {
- return createKey(Type.Delete);
+ null, 0, 0, null, 0, 0,
+ timestamp, Type.codeToType(getType()), null, 0, 0);
}
/**
* @return Clone of bb's key portion with type set to Type.Maximum. Use this
* doing lookups where you are doing getClosest. Using Maximum, you'll be
* sure to trip over all of the other key types since Maximum sorts first.
- * @throws IOException
*/
public KeyValue cloneMaximum() {
return createKey(Type.Maximum);
}
- /*
- * Make a clone with the new type.
- * Does not copy value.
+ /**
+ * Make a clone with the new type. Does not copy value.
+ *
* @param newtype New type to set on clone of this key.
* @return Clone of this key with type set to <code>newtype</code>
*/
@@ -531,6 +603,12 @@
return new KeyValue(other, 0, other.length);
}
+ //---------------------------------------------------------------------------
+ //
+ // String representation
+ //
+ //---------------------------------------------------------------------------
+
public String toString() {
return keyToString(this.bytes, this.offset + ROW_OFFSET, getKeyLength()) +
"/vlen=" + getValueLength();
@@ -545,6 +623,7 @@
}
/**
+ * Use for logging.
* @param b Key portion of a KeyValue.
* @param o Offset to start of key
* @param l Length of key.
@@ -552,7 +631,7 @@
*/
public static String keyToString(final byte [] b, final int o, final int l) {
int rowlength = Bytes.toShort(b, o);
- String row = Bytes.toString(b, o + Bytes.SIZEOF_SHORT, rowlength);
+ String row = Bytes.toStringBinary(b, o + Bytes.SIZEOF_SHORT, rowlength);
int columnoffset = o + Bytes.SIZEOF_SHORT + 1 + rowlength;
int familylength = b[columnoffset - 1];
int columnlength = l - ((columnoffset - o) + TIMESTAMP_TYPE_SIZE);
@@ -563,11 +642,20 @@
columnlength - familylength);
long timestamp = Bytes.toLong(b, o + (l - TIMESTAMP_TYPE_SIZE));
byte type = b[o + l - 1];
+// return row + "/" + family +
+// (family != null && family.length() > 0? COLUMN_FAMILY_DELIMITER: "") +
+// qualifier + "/" + timestamp + "/" + Type.codeToType(type);
return row + "/" + family +
- (family != null && family.length() > 0? COLUMN_FAMILY_DELIMITER: "") +
+ (family != null && family.length() > 0? ":" :"") +
qualifier + "/" + timestamp + "/" + Type.codeToType(type);
}
+ //---------------------------------------------------------------------------
+ //
+ // Public Member Accessors
+ //
+ //---------------------------------------------------------------------------
+
/**
* @return The byte array backing this KeyValue.
*/
@@ -589,7 +677,13 @@
return length;
}
- /*
+ //---------------------------------------------------------------------------
+ //
+ // Length and Offset Calculators
+ //
+ //---------------------------------------------------------------------------
+
+ /**
* Determines the total length of the KeyValue stored in the specified
* byte array and offset. Includes all headers.
* @param bytes byte array
@@ -603,41 +697,189 @@
}
/**
- * @return Copy of the key portion only. Used compacting and testing.
+ * @return Key offset in backing buffer..
*/
- public byte [] getKey() {
- int keylength = getKeyLength();
- byte [] key = new byte[keylength];
- System.arraycopy(getBuffer(), getKeyOffset(), key, 0, keylength);
- return key;
+ public int getKeyOffset() {
+ return this.offset + ROW_OFFSET;
}
public String getKeyString() {
- return Bytes.toString(getBuffer(), getKeyOffset(), getKeyLength());
+ return Bytes.toStringBinary(getBuffer(), getKeyOffset(), getKeyLength());
}
/**
- * @return Key offset in backing buffer..
+ * @return Length of key portion.
*/
- public int getKeyOffset() {
- return this.offset + ROW_OFFSET;
+ public int getKeyLength() {
+ return Bytes.toInt(this.bytes, this.offset);
}
/**
- * @return Row length.
+ * @return Value offset
*/
- public short getRowLength() {
- return Bytes.toShort(this.bytes, getKeyOffset());
+ public int getValueOffset() {
+ return getKeyOffset() + getKeyLength();
+ }
+
+ /**
+ * @return Value length
+ */
+ public int getValueLength() {
+ return Bytes.toInt(this.bytes, this.offset + Bytes.SIZEOF_INT);
}
/**
- * @return Offset into backing buffer at which row starts.
+ * @return Row offset
*/
public int getRowOffset() {
return getKeyOffset() + Bytes.SIZEOF_SHORT;
}
+
+ /**
+ * @return Row length
+ */
+ public short getRowLength() {
+ return Bytes.toShort(this.bytes, getKeyOffset());
+ }
+
+ /**
+ * @return Family offset
+ */
+ public int getFamilyOffset() {
+ return getFamilyOffset(getRowLength());
+ }
+
+ /**
+ * @return Family offset
+ */
+ public int getFamilyOffset(int rlength) {
+ return this.offset + ROW_OFFSET + Bytes.SIZEOF_SHORT + rlength + Bytes.SIZEOF_BYTE;
+ }
+
+ /**
+ * @return Family length
+ */
+ public byte getFamilyLength() {
+ return getFamilyLength(getFamilyOffset());
+ }
+
+ /**
+ * @return Family length
+ */
+ public byte getFamilyLength(int foffset) {
+ return this.bytes[foffset-1];
+ }
+
+ /**
+ * @return Qualifier offset
+ */
+ public int getQualifierOffset() {
+ return getQualifierOffset(getFamilyOffset());
+ }
+
+ /**
+ * @return Qualifier offset
+ */
+ public int getQualifierOffset(int foffset) {
+ return foffset + getFamilyLength(foffset);
+ }
+
+ /**
+ * @return Qualifier length
+ */
+ public int getQualifierLength() {
+ return getQualifierLength(getRowLength(),getFamilyLength());
+ }
+
+ /**
+ * @return Qualifier length
+ */
+ public int getQualifierLength(int rlength, int flength) {
+ return getKeyLength() -
+ (KEY_INFRASTRUCTURE_SIZE + rlength + flength);
+ }
+
+ /**
+ * @return Column (family + qualifier) length
+ */
+ public int getTotalColumnLength() {
+ int rlength = getRowLength();
+ int foffset = getFamilyOffset(rlength);
+ return getTotalColumnLength(rlength,foffset);
+ }
+
+ /**
+ * @return Column (family + qualifier) length
+ */
+ public int getTotalColumnLength(int rlength, int foffset) {
+ int flength = getFamilyLength(foffset);
+ int qlength = getQualifierLength(rlength,flength);
+ return flength + qlength;
+ }
+
+ /**
+ * @return Timestamp offset
+ */
+ public int getTimestampOffset() {
+ return getTimestampOffset(getKeyLength());
+ }
+
+ /**
+ * @param keylength Pass if you have it to save on a int creation.
+ * @return Timestamp offset
+ */
+ public int getTimestampOffset(final int keylength) {
+ return getKeyOffset() + keylength - TIMESTAMP_TYPE_SIZE;
+ }
/**
+ * @return True if this KeyValue has a LATEST_TIMESTAMP timestamp.
+ */
+ public boolean isLatestTimestamp() {
+ return Bytes.compareTo(getBuffer(), getTimestampOffset(), Bytes.SIZEOF_LONG,
+ HConstants.LATEST_TIMESTAMP_BYTES, 0, Bytes.SIZEOF_LONG) == 0;
+ }
+
+ public boolean updateLatestStamp(final byte [] now) {
+ int tsOffset = getTimestampOffset();
+ if(Bytes.compareTo(now, 0, Bytes.SIZEOF_LONG,
+ this.bytes, tsOffset, Bytes.SIZEOF_LONG) < 0) {
+ System.arraycopy(now, 0, this.bytes, tsOffset, Bytes.SIZEOF_LONG);
+ return true;
+ }
+ return false;
+ }
+
+ //---------------------------------------------------------------------------
+ //
+ // Methods that return copies of fields
+ //
+ //---------------------------------------------------------------------------
+
+ /**
+ * @return Copy of the key portion only. Used compacting and testing.
+ */
+ public byte [] getKey() {
+ int keylength = getKeyLength();
+ byte [] key = new byte[keylength];
+ System.arraycopy(getBuffer(), getKeyOffset(), key, 0, keylength);
+ return key;
+ }
+
+ /**
+ * Do not use unless you have to. Use {@link #getBuffer()} with appropriate
+ * offset and lengths instead.
+ * @return Value in a new byte array.
+ */
+ public byte [] getValue() {
+ int o = getValueOffset();
+ int l = getValueLength();
+ byte [] result = new byte[l];
+ System.arraycopy(getBuffer(), o, result, 0, l);
+ return result;
+ }
+
+ /**
* Do not use this unless you have to.
* Use {@link #getBuffer()} with appropriate offsets and lengths instead.
* @return Row in a new byte array.
@@ -667,24 +909,9 @@
}
/**
- * @param keylength Pass if you have it to save on a int creation.
- * @return Offset into backing buffer at which timestamp starts.
- */
- int getTimestampOffset(final int keylength) {
- return getKeyOffset() + keylength - TIMESTAMP_TYPE_SIZE;
- }
-
- /**
- * @return True if a {@link Type#Delete}.
- */
- public boolean isDeleteType() {
- return getType() == Type.Delete.getCode();
- }
-
- /**
* @return Type of this KeyValue.
*/
- byte getType() {
+ public byte getType() {
return getType(getKeyLength());
}
@@ -697,99 +924,170 @@
}
/**
- * @return Length of key portion.
+ * @return True if Delete KeyValue type.
*/
- public int getKeyLength() {
- return Bytes.toInt(this.bytes, this.offset);
+ public boolean isDeleteType() {
+ return getType() == Type.Delete.code;
}
/**
- * @return Value length
+ * @return True if DeleteColumn KeyValue type.
*/
- public int getValueLength() {
- return Bytes.toInt(this.bytes, this.offset + Bytes.SIZEOF_INT);
+ public boolean isDeleteColumnType() {
+ return getType() == Type.DeleteColumn.code;
}
/**
- * @return Offset into backing buffer at which value starts.
+ * Do not use this unless you have to.
+ * Use {@link #getBuffer()} with appropriate offsets and lengths instead.
+ * @return Returns column. Makes a copy. Inserts delimiter.
*/
- public int getValueOffset() {
- return getKeyOffset() + getKeyLength();
+ public byte [] getColumn() {
+ int fo = getFamilyOffset();
+ int fl = getFamilyLength(fo);
+ int ql = getQualifierLength();
+ byte [] result = new byte[fl + 1 + ql];
+ System.arraycopy(this.bytes, fo, result, 0, fl);
+ result[fl] = COLUMN_FAMILY_DELIMITER;
+ System.arraycopy(this.bytes, fo + fl, result,
+ fl + 1, ql);
+ return result;
}
/**
- * Do not use unless you have to. Use {@link #getBuffer()} with appropriate
- * offset and lengths instead.
- * @return Value in a new byte array.
+ * Do not use this unless you have to.
+ * Use {@link #getBuffer()} with appropriate offsets and lengths instead.
+ * @return Returns family. Makes a copy.
*/
- public byte [] getValue() {
- int o = getValueOffset();
- int l = getValueLength();
+ public byte [] getFamily() {
+ int o = getFamilyOffset();
+ int l = getFamilyLength(o);
byte [] result = new byte[l];
- System.arraycopy(getBuffer(), o, result, 0, l);
+ System.arraycopy(this.bytes, o, result, 0, l);
return result;
}
/**
- * @return Offset into backing buffer at which the column begins
- */
- public int getColumnOffset() {
- return getColumnOffset(getRowLength());
- }
-
- /**
- * @param rowlength - length of row.
- * @return Offset into backing buffer at which the column begins
- */
- public int getColumnOffset(final int rowlength) {
- return getRowOffset() + rowlength + 1;
- }
-
- /**
- * @param columnoffset Pass if you have it to save on an int creation.
- * @return Length of family portion of column.
+ * Do not use this unless you have to.
+ * Use {@link #getBuffer()} with appropriate offsets and lengths instead.
+ * @return Returns qualifier. Makes a copy.
*/
- int getFamilyLength(final int columnoffset) {
- return this.bytes[columnoffset - 1];
+ public byte [] getQualifier() {
+ int o = getQualifierOffset();
+ int l = getQualifierLength();
+ byte [] result = new byte[l];
+ System.arraycopy(this.bytes, o, result, 0, l);
+ return result;
}
+ //---------------------------------------------------------------------------
+ //
+ // KeyValue splitter
+ //
+ //---------------------------------------------------------------------------
+
/**
- * @param columnoffset Pass if you have it to save on an int creation.
- * @return Length of column.
- */
- public int getColumnLength(final int columnoffset) {
- return getColumnLength(columnoffset, getKeyLength());
+ * Utility class that splits a KeyValue buffer into separate byte arrays.
+ * <p>
+ * Should get rid of this if we can, but is very useful for debugging.
+ */
+ public static class SplitKeyValue {
+ private byte [][] split;
+ SplitKeyValue() {
+ this.split = new byte[6][];
+ }
+ public void setRow(byte [] value) { this.split[0] = value; }
+ public void setFamily(byte [] value) { this.split[1] = value; }
+ public void setQualifier(byte [] value) { this.split[2] = value; }
+ public void setTimestamp(byte [] value) { this.split[3] = value; }
+ public void setType(byte [] value) { this.split[4] = value; }
+ public void setValue(byte [] value) { this.split[5] = value; }
+ public byte [] getRow() { return this.split[0]; }
+ public byte [] getFamily() { return this.split[1]; }
+ public byte [] getQualifier() { return this.split[2]; }
+ public byte [] getTimestamp() { return this.split[3]; }
+ public byte [] getType() { return this.split[4]; }
+ public byte [] getValue() { return this.split[5]; }
}
-
- int getColumnLength(final int columnoffset, final int keylength) {
- return (keylength + ROW_OFFSET) - (columnoffset - this.offset) -
- TIMESTAMP_TYPE_SIZE;
+
+ public SplitKeyValue split() {
+ SplitKeyValue split = new SplitKeyValue();
+ int splitOffset = this.offset;
+ int keyLen = Bytes.toInt(bytes, splitOffset);
+ splitOffset += Bytes.SIZEOF_INT;
+ int valLen = Bytes.toInt(bytes, splitOffset);
+ splitOffset += Bytes.SIZEOF_INT;
+ short rowLen = Bytes.toShort(bytes, splitOffset);
+ splitOffset += Bytes.SIZEOF_SHORT;
+ byte [] row = new byte[rowLen];
+ System.arraycopy(bytes, splitOffset, row, 0, rowLen);
+ splitOffset += rowLen;
+ split.setRow(row);
+ byte famLen = bytes[splitOffset];
+ splitOffset += Bytes.SIZEOF_BYTE;
+ byte [] family = new byte[famLen];
+ System.arraycopy(bytes, splitOffset, family, 0, famLen);
+ splitOffset += famLen;
+ split.setFamily(family);
+ int colLen = keyLen -
+ (rowLen + famLen + Bytes.SIZEOF_SHORT + Bytes.SIZEOF_BYTE +
+ Bytes.SIZEOF_LONG + Bytes.SIZEOF_BYTE);
+ byte [] qualifier = new byte[colLen];
+ System.arraycopy(bytes, splitOffset, qualifier, 0, colLen);
+ splitOffset += colLen;
+ split.setQualifier(qualifier);
+ byte [] timestamp = new byte[Bytes.SIZEOF_LONG];
+ System.arraycopy(bytes, splitOffset, timestamp, 0, Bytes.SIZEOF_LONG);
+ splitOffset += Bytes.SIZEOF_LONG;
+ split.setTimestamp(timestamp);
+ byte [] type = new byte[1];
+ type[0] = bytes[splitOffset];
+ splitOffset += Bytes.SIZEOF_BYTE;
+ split.setType(type);
+ byte [] value = new byte[valLen];
+ System.arraycopy(bytes, splitOffset, value, 0, valLen);
+ split.setValue(value);
+ return split;
}
-
+
+ //---------------------------------------------------------------------------
+ //
+ // Compare specified fields against those contained in this KeyValue
+ //
+ //---------------------------------------------------------------------------
+
/**
* @param family
* @return True if matching families.
*/
public boolean matchingFamily(final byte [] family) {
- int o = getColumnOffset();
- // Family length byte is just before the column starts.
- int l = this.bytes[o - 1];
+ int o = getFamilyOffset();
+ int l = getFamilyLength(o);
return Bytes.compareTo(family, 0, family.length, this.bytes, o, l) == 0;
}
/**
+ * @param qualifier
+ * @return True if matching qualifiers.
+ */
+ public boolean matchingQualifier(final byte [] qualifier) {
+ int o = getQualifierOffset();
+ int l = getQualifierLength();
+ return Bytes.compareTo(qualifier, 0, qualifier.length,
+ this.bytes, o, l) == 0;
+ }
+
+ /**
* @param column Column minus its delimiter
- * @param familylength Length of family in passed <code>column</code>
* @return True if column matches.
* @see #matchingColumn(byte[])
*/
- public boolean matchingColumnNoDelimiter(final byte [] column,
- final int familylength) {
- int o = getColumnOffset();
- int l = getColumnLength(o);
- int f = getFamilyLength(o);
- return compareColumns(getBuffer(), o, l, f,
- column, 0, column.length, familylength) == 0;
+ public boolean matchingColumnNoDelimiter(final byte [] column) {
+ int rl = getRowLength();
+ int o = getFamilyOffset(rl);
+ int fl = getFamilyLength(o);
+ int l = fl + getQualifierLength(rl,fl);
+ return Bytes.compareTo(column, 0, column.length, this.bytes, o, l) == 0;
}
/**
@@ -798,14 +1096,40 @@
*/
public boolean matchingColumn(final byte [] column) {
int index = getFamilyDelimiterIndex(column, 0, column.length);
- int o = getColumnOffset();
- int l = getColumnLength(o);
- int result = Bytes.compareTo(getBuffer(), o, index, column, 0, index);
- if (result != 0) {
+ int rl = getRowLength();
+ int o = getFamilyOffset(rl);
+ int fl = getFamilyLength(o);
+ int ql = getQualifierLength(rl,fl);
+ if(Bytes.compareTo(column, 0, index, this.bytes, o, fl) != 0) {
+ return false;
+ }
+ return Bytes.compareTo(column, index + 1, column.length - (index + 1),
+ this.bytes, o + fl, ql) == 0;
+ }
+
+ /**
+ *
+ * @param family column family
+ * @param qualifier column qualifier
+ * @return True if column matches
+ */
+ public boolean matchingColumn(final byte[] family, final byte[] qualifier) {
+ int rl = getRowLength();
+ int o = getFamilyOffset(rl);
+ int fl = getFamilyLength(o);
+ int ql = getQualifierLength(rl,fl);
+ if(Bytes.compareTo(family, 0, family.length, this.bytes, o, family.length)
+ != 0) {
return false;
}
- return Bytes.compareTo(getBuffer(), o + index, l - index,
- column, index + 1, column.length - (index + 1)) == 0;
+ if(qualifier == null || qualifier.length == 0) {
+ if(ql == 0) {
+ return true;
+ }
+ return false;
+ }
+ return Bytes.compareTo(qualifier, 0, qualifier.length,
+ this.bytes, o + fl, ql) == 0;
}
/**
@@ -817,7 +1141,7 @@
* @param roffset
* @param rlength
* @param rfamilylength Offset of family delimiter in right column.
- * @return
+ * @return The result of the comparison.
*/
static int compareColumns(final byte [] left, final int loffset,
final int llength, final int lfamilylength,
@@ -843,41 +1167,33 @@
}
/**
- * @return Returns column String with delimiter added back. Expensive!
+ * @return True if column is empty.
*/
- public String getColumnString() {
- int o = getColumnOffset();
- int l = getColumnLength(o);
- int familylength = getFamilyLength(o);
- return Bytes.toString(this.bytes, o, familylength) +
- COLUMN_FAMILY_DELIMITER + Bytes.toString(this.bytes,
- o + familylength, l - familylength);
+ public boolean isEmptyColumn() {
+ return getQualifierLength() == 0;
}
/**
- * Do not use this unless you have to.
- * Use {@link #getBuffer()} with appropriate offsets and lengths instead.
- * @return Returns column. Makes a copy. Inserts delimiter.
- */
- public byte [] getColumn() {
- int o = getColumnOffset();
- int l = getColumnLength(o);
- int familylength = getFamilyLength(o);
- byte [] result = new byte[l + 1];
- System.arraycopy(getBuffer(), o, result, 0, familylength);
- result[familylength] = COLUMN_FAMILY_DELIMITER;
- System.arraycopy(getBuffer(), o + familylength, result,
- familylength + 1, l - familylength);
+ * Splits a column in family:qualifier form into separate byte arrays.
+ *
+ * @param c The column.
+ * @return The parsed column.
+ */
+ public static byte [][] parseColumn(byte [] c) {
+ final byte [][] result = new byte [2][];
+ final int index = getFamilyDelimiterIndex(c, 0, c.length);
+ if (index == -1) {
+ throw new IllegalArgumentException("Impossible column name: " + c);
+ }
+ result[0] = new byte [index];
+ System.arraycopy(c, 0, result[0], 0, index);
+ final int len = c.length - (index + 1);
+ result[1] = new byte[len];
+ System.arraycopy(c, index + 1 /*Skip delimiter*/, result[1], 0,
+ len);
return result;
}
-
- /**
- * @return True if column is empty.
- */
- public boolean isEmptyColumn() {
- return getColumnLength(getColumnOffset()) == 0;
- }
-
+
/**
* @param b
* @return Index of the family-qualifier colon delimiter character in passed
@@ -1026,7 +1342,8 @@
* @return Result comparing rows.
*/
public int compareRows(final KeyValue left, final KeyValue right) {
- return compareRows(left, left.getRowLength(), right, right.getRowLength());
+ return compareRows(left, left.getRowLength(), right,
+ right.getRowLength());
}
/**
@@ -1058,28 +1375,27 @@
return getRawComparator().compareRows(left, loffset, llength,
right, roffset, rlength);
}
-
+
public int compareColumns(final KeyValue left, final byte [] right,
final int roffset, final int rlength, final int rfamilyoffset) {
- int offset = left.getColumnOffset();
- int length = left.getColumnLength(offset);
+ int offset = left.getFamilyOffset();
+ int length = left.getFamilyLength() + left.getQualifierLength();
return getRawComparator().compareColumns(left.getBuffer(), offset, length,
left.getFamilyLength(offset),
right, roffset, rlength, rfamilyoffset);
}
int compareColumns(final KeyValue left, final short lrowlength,
- final int lkeylength, final KeyValue right, final short rrowlength,
- final int rkeylength) {
- int loffset = left.getColumnOffset(lrowlength);
- int roffset = right.getColumnOffset(rrowlength);
- int llength = left.getColumnLength(loffset, lkeylength);
- int rlength = right.getColumnLength(roffset, rkeylength);
- int lfamilylength = left.getFamilyLength(loffset);
- int rfamilylength = right.getFamilyLength(roffset);
- return getRawComparator().compareColumns(left.getBuffer(), loffset,
- llength, lfamilylength,
- right.getBuffer(), roffset, rlength, rfamilylength);
+ final KeyValue right, final short rrowlength) {
+ int lfoffset = left.getFamilyOffset(lrowlength);
+ int rfoffset = right.getFamilyOffset(rrowlength);
+ int lclength = left.getTotalColumnLength(lrowlength,lfoffset);
+ int rclength = right.getTotalColumnLength(rrowlength, rfoffset);
+ int lfamilylength = left.getFamilyLength(lfoffset);
+ int rfamilylength = right.getFamilyLength(rfoffset);
+ return getRawComparator().compareColumns(left.getBuffer(), lfoffset,
+ lclength, lfamilylength,
+ right.getBuffer(), rfoffset, rclength, rfamilylength);
}
/**
@@ -1095,10 +1411,7 @@
if (!matchingRows(left, lrowlength, right, rrowlength)) {
return false;
}
- int lkeylength = left.getKeyLength();
- int rkeylength = right.getKeyLength();
- return compareColumns(left, lrowlength, lkeylength,
- right, rrowlength, rkeylength) == 0;
+ return compareColumns(left, lrowlength, right, rrowlength) == 0;
}
/**
@@ -1140,7 +1453,8 @@
public boolean matchingRows(final byte [] left, final int loffset,
final int llength,
final byte [] right, final int roffset, final int rlength) {
- int compare = compareRows(left, loffset, llength, right, roffset, rlength);
+ int compare = compareRows(left, loffset, llength,
+ right, roffset, rlength);
if (compare != 0) {
return false;
}
@@ -1171,7 +1485,6 @@
/**
* @return Comparator that ignores timestamps; useful counting versions.
- * @throws IOException
*/
public KVComparator getComparatorIgnoringTimestamps() {
KVComparator c = null;
@@ -1214,20 +1527,44 @@
*/
public static KeyValue createFirstOnRow(final byte [] row,
final long ts) {
- return createFirstOnRow(row, null, ts);
+ return new KeyValue(row, null, null, ts, Type.Maximum);
}
/**
* @param row - row key (arbitrary byte array)
* @param ts - timestamp
- * @return First possible key on passed <code>row</code>, column and timestamp.
+ * @return First possible key on passed <code>row</code>, column and timestamp
*/
public static KeyValue createFirstOnRow(final byte [] row, final byte [] c,
final long ts) {
- return new KeyValue(row, c, ts, Type.Maximum);
+ byte [][] split = parseColumn(c);
+ return new KeyValue(row, split[0], split[1], ts, Type.Maximum);
+ }
+
+ /**
+ * @param row - row key (arbitrary byte array)
+ * @param f - family name
+ * @param q - column qualifier
+ * @return First possible key on passed <code>row</code>, and column.
+ */
+ public static KeyValue createFirstOnRow(final byte [] row, final byte [] f,
+ final byte [] q) {
+ return new KeyValue(row, f, q, HConstants.LATEST_TIMESTAMP, Type.Maximum);
}
/**
+ * @param row - row key (arbitrary byte array)
+ * @param f - family name
+ * @param q - column qualifier
+ * @param ts - timestamp
+ * @return First possible key on passed <code>row</code>, column and timestamp
+ */
+ public static KeyValue createFirstOnRow(final byte [] row, final byte [] f,
+ final byte [] q, final long ts) {
+ return new KeyValue(row, f, q, ts, Type.Maximum);
+ }
+
+ /**
* @param b
* @param o
* @param l
@@ -1255,7 +1592,8 @@
// "---" + Bytes.toString(right, roffset, rlength));
final int metalength = 7; // '.META.' length
int lmetaOffsetPlusDelimiter = loffset + metalength;
- int leftFarDelimiter = getDelimiterInReverse(left, lmetaOffsetPlusDelimiter,
+ int leftFarDelimiter = getDelimiterInReverse(left,
+ lmetaOffsetPlusDelimiter,
llength - metalength, HRegionInfo.DELIMITER);
int rmetaOffsetPlusDelimiter = roffset + metalength;
int rightFarDelimiter = getDelimiterInReverse(right,
@@ -1363,6 +1701,9 @@
return compare;
}
+ // if row matches, and no column in the 'left' AND put type is 'minimum',
+ // then return that left is larger than right.
+
// Compare column family. Start compare past row and family length.
int lcolumnoffset = Bytes.SIZEOF_SHORT + lrowlength + 1 + loffset;
int rcolumnoffset = Bytes.SIZEOF_SHORT + rrowlength + 1 + roffset;
@@ -1370,12 +1711,24 @@
(lcolumnoffset - loffset);
int rcolumnlength = rlength - TIMESTAMP_TYPE_SIZE -
(rcolumnoffset - roffset);
+
+ // This supports 'last key on a row' - the magic is if there is no column in the
+ // left operand, and the left operand has a type of '0' - magical value,
+ // then we say the left is bigger. This will let us seek to the last key in
+ // a row.
+
+ byte ltype = left[loffset + (llength - 1)];
+
+ if (lcolumnlength == 0 && ltype == Type.Minimum.getCode()) {
+ return 1; // left is bigger.
+ }
+
compare = Bytes.compareTo(left, lcolumnoffset, lcolumnlength, right,
rcolumnoffset, rcolumnlength);
if (compare != 0) {
return compare;
}
-
+
if (!this.ignoreTimestamp) {
// Get timestamps.
long ltimestamp = Bytes.toLong(left,
@@ -1391,7 +1744,8 @@
if (!this.ignoreType) {
// Compare types. Let the delete types sort ahead of puts; i.e. types
// of higher numbers sort before those of lesser numbers
- byte ltype = left[loffset + (llength - 1)];
+
+ // ltype is defined above
byte rtype = right[roffset + (rlength - 1)];
return (0xff & rtype) - (0xff & ltype);
}
@@ -1402,7 +1756,7 @@
return compare(left, 0, left.length, right, 0, right.length);
}
- protected int compareRows(byte [] left, int loffset, int llength,
+ public int compareRows(byte [] left, int loffset, int llength,
byte [] right, int roffset, int rlength) {
return Bytes.compareTo(left, loffset, llength, right, roffset, rlength);
}
@@ -1430,7 +1784,9 @@
// HeapSize
public long heapSize() {
- return this.length;
+ int dataLen = bytes.length + (bytes.length % 8);
+ return HeapSize.OBJECT + HeapSize.BYTE_ARRAY + dataLen +
+ (2 * HeapSize.INT);
}
// Writable
Modified: hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/RegionHistorian.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/RegionHistorian.java?rev=785076&r1=785075&r2=785076&view=diff
==============================================================================
--- hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/RegionHistorian.java (original)
+++ hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/RegionHistorian.java Tue Jun 16 04:33:56 2009
@@ -29,8 +29,10 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.HTable;
-import org.apache.hadoop.hbase.io.BatchUpdate;
+import org.apache.hadoop.hbase.client.Put;
+import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.io.Cell;
import org.apache.hadoop.hbase.util.Bytes;
@@ -57,17 +59,17 @@
"EEE, d MMM yyyy HH:mm:ss");
- private static enum HistorianColumnKey {
- REGION_CREATION ( Bytes.toBytes(COLUMN_FAMILY_HISTORIAN_STR+"creation")),
- REGION_OPEN ( Bytes.toBytes(COLUMN_FAMILY_HISTORIAN_STR+"open")),
- REGION_SPLIT ( Bytes.toBytes(COLUMN_FAMILY_HISTORIAN_STR+"split")),
- REGION_COMPACTION ( Bytes.toBytes(COLUMN_FAMILY_HISTORIAN_STR+"compaction")),
- REGION_FLUSH ( Bytes.toBytes(COLUMN_FAMILY_HISTORIAN_STR+"flush")),
- REGION_ASSIGNMENT ( Bytes.toBytes(COLUMN_FAMILY_HISTORIAN_STR+"assignment"));
+ private static enum HistorianQualifierKey {
+ REGION_CREATION ( Bytes.toBytes("creation")),
+ REGION_OPEN ( Bytes.toBytes("open")),
+ REGION_SPLIT ( Bytes.toBytes("split")),
+ REGION_COMPACTION ( Bytes.toBytes("compaction")),
+ REGION_FLUSH ( Bytes.toBytes("flush")),
+ REGION_ASSIGNMENT ( Bytes.toBytes("assignment"));
- byte[] key;
+ byte[] key;
- HistorianColumnKey(byte[] key) {
+ HistorianQualifierKey(byte[] key) {
this.key = key;
}
}
@@ -101,7 +103,7 @@
* Region name as a string
* @return List of RegionHistoryInformation or null if we're offline.
*/
- public List<RegionHistoryInformation> getRegionHistory(String regionName) {
+ public List<RegionHistoryInformation> getRegionHistory(byte [] regionName) {
if (!isOnline()) {
return null;
}
@@ -113,15 +115,17 @@
* moment to retrieve all version and to have the column key information.
* To be changed when HTable.getRow handles versions.
*/
- for (HistorianColumnKey keyEnu : HistorianColumnKey.values()) {
+ for (HistorianQualifierKey keyEnu : HistorianQualifierKey.values()) {
byte[] columnKey = keyEnu.key;
- Cell[] cells = this.metaTable.get(Bytes.toBytes(regionName),
- columnKey, ALL_VERSIONS);
- if (cells != null) {
- for (Cell cell : cells) {
- informations.add(historian.new RegionHistoryInformation(cell
- .getTimestamp(), Bytes.toString(columnKey).split(":")[1], Bytes
- .toString(cell.getValue())));
+ Get get = new Get(regionName);
+ get.addColumn(CATALOG_HISTORIAN_FAMILY, columnKey);
+ get.setMaxVersions(ALL_VERSIONS);
+ Result result = this.metaTable.get(get);
+
+ if (result != null) {
+ for(KeyValue kv : result.raw()) {
+ informations.add(historian.new RegionHistoryInformation(
+ kv.getTimestamp(), columnKey, kv.getValue()));
}
}
}
@@ -138,7 +142,7 @@
* @param serverName
*/
public void addRegionAssignment(HRegionInfo info, String serverName) {
- add(HistorianColumnKey.REGION_ASSIGNMENT.key, "Region assigned to server "
+ add(HistorianQualifierKey.REGION_ASSIGNMENT.key, "Region assigned to server "
+ serverName, info);
}
@@ -147,7 +151,7 @@
* @param info
*/
public void addRegionCreation(HRegionInfo info) {
- add(HistorianColumnKey.REGION_CREATION.key, "Region creation", info);
+ add(HistorianQualifierKey.REGION_CREATION.key, "Region creation", info);
}
/**
@@ -156,7 +160,7 @@
* @param address
*/
public void addRegionOpen(HRegionInfo info, HServerAddress address) {
- add(HistorianColumnKey.REGION_OPEN.key, "Region opened on server : "
+ add(HistorianQualifierKey.REGION_OPEN.key, "Region opened on server : "
+ address.getHostname(), info);
}
@@ -171,7 +175,7 @@
HRegionInfo newInfo2) {
HRegionInfo[] infos = new HRegionInfo[] { newInfo1, newInfo2 };
for (HRegionInfo info : infos) {
- add(HistorianColumnKey.REGION_SPLIT.key, SPLIT_PREFIX +
+ add(HistorianQualifierKey.REGION_SPLIT.key, SPLIT_PREFIX +
oldInfo.getRegionNameAsString(), info);
}
}
@@ -188,7 +192,7 @@
// such danger compacting; compactions are not allowed when
// Flusher#flushSomeRegions is run.
if (LOG.isDebugEnabled()) {
- add(HistorianColumnKey.REGION_COMPACTION.key,
+ add(HistorianQualifierKey.REGION_COMPACTION.key,
"Region compaction completed in " + timeTaken, info);
}
}
@@ -211,9 +215,8 @@
* @param text
* @param info
*/
- private void add(byte[] column,
- String text, HRegionInfo info) {
- add(column, text, info, LATEST_TIMESTAMP);
+ private void add(byte [] qualifier, String text, HRegionInfo info) {
+ add(qualifier, text, info, LATEST_TIMESTAMP);
}
/**
@@ -223,18 +226,19 @@
* @param info
* @param timestamp
*/
- private void add(byte[] column,
- String text, HRegionInfo info, long timestamp) {
+ private void add(byte [] qualifier, String text, HRegionInfo info,
+ long timestamp) {
if (!isOnline()) {
// Its a noop
return;
}
if (!info.isMetaRegion()) {
- BatchUpdate batch = new BatchUpdate(info.getRegionName());
- batch.setTimestamp(timestamp);
- batch.put(column, Bytes.toBytes(text));
+ Put put = new Put(info.getRegionName());
+ put.setTimeStamp(timestamp);
+ put.add(HConstants.CATALOG_HISTORIAN_FAMILY, qualifier,
+ Bytes.toBytes(text));
try {
- this.metaTable.commit(batch);
+ this.metaTable.put(put);
} catch (IOException ioe) {
LOG.warn("Unable to '" + text + "'", ioe);
}
@@ -252,34 +256,35 @@
private long timestamp;
- private String event;
+ private byte [] event = null;
- private String description;
+ private byte [] description = null;
/**
* @param timestamp
* @param event
* @param description
*/
- public RegionHistoryInformation(long timestamp, String event,
- String description) {
+ public RegionHistoryInformation(long timestamp, byte [] event,
+ byte [] description) {
this.timestamp = timestamp;
this.event = event;
this.description = description;
}
-
+
+
public int compareTo(RegionHistoryInformation otherInfo) {
return -1 * Long.valueOf(timestamp).compareTo(otherInfo.getTimestamp());
}
/** @return the event */
public String getEvent() {
- return event;
+ return Bytes.toString(event);
}
/** @return the description */
public String getDescription() {
- return description;
+ return Bytes.toString(description);
}
/** @return the timestamp */
Modified: hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/WritableComparator.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/WritableComparator.java?rev=785076&r1=785075&r2=785076&view=diff
==============================================================================
--- hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/WritableComparator.java (original)
+++ hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/WritableComparator.java Tue Jun 16 04:33:56 2009
@@ -23,6 +23,7 @@
import org.apache.hadoop.io.Writable;
-public interface WritableComparator<T> extends Writable, Comparator<T> {
-// No methods, just bring the two interfaces together
-}
+/**
+ * Interface that brings writable and comparable together
+ */
+public interface WritableComparator<T> extends Writable, Comparator<T> {}
Added: hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/client/Delete.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/client/Delete.java?rev=785076&view=auto
==============================================================================
--- hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/client/Delete.java (added)
+++ hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/client/Delete.java Tue Jun 16 04:33:56 2009
@@ -0,0 +1,313 @@
+/*
+ * Copyright 2009 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.hbase.client;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.hadoop.io.Writable;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.util.Bytes;
+
+/**
+ * Used to perform Delete operations on a single row.
+ * <p>
+ * To delete an entire row, instantiate a Delete object with the row
+ * to delete. To further define the scope of what to delete, perform
+ * additional methods as outlined below.
+ * <p>
+ * To delete specific families, execute {@link #deleteFamily(byte []) deleteFamily}
+ * for each family to delete.
+ * <p>
+ * To delete multiple versions of specific columns, execute
+ * {@link #deleteColumns(byte [],byte []) deleteColumns}
+ * for each column to delete.
+ * <p>
+ * To delete specific versions of specific columns, execute
+ * {@link #deleteColumn(byte [],byte [],long) deleteColumn}
+ * for each column version to delete.
+ * <p>
+ * Specifying timestamps calling constructor, deleteFamily, and deleteColumns
+ * will delete all versions with a timestamp less than or equal to that
+ * specified. Specifying a timestamp to deleteColumn will delete versions
+ * only with a timestamp equal to that specified.
+ * <p>The timestamp passed to the constructor is only used ONLY for delete of
+ * rows. For anything less -- a deleteColumn, deleteColumns or
+ * deleteFamily -- then you need to use the method overrides that take a
+ * timestamp. The constructor timestamp is not referenced.
+ */
+public class Delete implements Writable {
+ private byte [] row = null;
+ // This ts is only used when doing a deleteRow. Anything less,
+ private long ts;
+ private long lockId = -1L;
+ private final Map<byte [], List<KeyValue>> familyMap =
+ new TreeMap<byte [], List<KeyValue>>(Bytes.BYTES_COMPARATOR);
+
+ /** Constructor for Writable. DO NOT USE */
+ public Delete() {
+ this(null);
+ }
+
+ /**
+ * Create a Delete operation for the specified row.
+ * <p>
+ * If no further operations are done, this will delete everything
+ * associated with the specified row (all versions of all columns in all
+ * families).
+ * @param row row key
+ */
+ public Delete(byte [] row) {
+ this(row, HConstants.LATEST_TIMESTAMP, null);
+ }
+
+ /**
+ * Create a Delete operation for the specified row and timestamp, using
+ * an optional row lock.
+ * <p>
+ * If no further operations are done, this will delete all columns in all
+ * families of the specified row with a timestamp less than or equal to the
+ * specified timestamp.
+ * @param row row key
+ * @param timestamp maximum version timestamp
+ * @param rowLock previously acquired row lock, or null
+ */
+ public Delete(byte [] row, long timestamp, RowLock rowLock) {
+ this.row = row;
+ this.ts = timestamp;
+ if (rowLock != null) {
+ this.lockId = rowLock.getLockId();
+ }
+ }
+
+ /**
+ * Delete all versions of all columns of the specified family.
+ * <p>
+ * Overrides previous calls to deleteColumn and deleteColumns for the
+ * specified family.
+ * @param family family name
+ */
+ public void deleteFamily(byte [] family) {
+ this.deleteFamily(family, HConstants.LATEST_TIMESTAMP);
+ }
+
+ /**
+ * Delete all columns of the specified family with a timestamp less than
+ * or equal to the specified timestamp.
+ * <p>
+ * Overrides previous calls to deleteColumn and deleteColumns for the
+ * specified family.
+ * @param family family name
+ * @param timestamp maximum version timestamp
+ */
+ public void deleteFamily(byte [] family, long timestamp) {
+ List<KeyValue> list = familyMap.get(family);
+ if(list == null) {
+ list = new ArrayList<KeyValue>();
+ } else if(!list.isEmpty()) {
+ list.clear();
+ }
+ list.add(new KeyValue(row, family, null, timestamp, KeyValue.Type.DeleteFamily));
+ familyMap.put(family, list);
+ }
+
+ /**
+ * Delete all versions of the specified column.
+ * @param family family name
+ * @param qualifier column qualifier
+ */
+ public void deleteColumns(byte [] family, byte [] qualifier) {
+ this.deleteColumns(family, qualifier, HConstants.LATEST_TIMESTAMP);
+ }
+
+ /**
+ * Delete all versions of the specified column with a timestamp less than
+ * or equal to the specified timestamp.
+ * @param family family name
+ * @param qualifier column qualifier
+ * @param timestamp maximum version timestamp
+ */
+ public void deleteColumns(byte [] family, byte [] qualifier, long timestamp) {
+ List<KeyValue> list = familyMap.get(family);
+ if (list == null) {
+ list = new ArrayList<KeyValue>();
+ }
+ list.add(new KeyValue(this.row, family, qualifier, timestamp,
+ KeyValue.Type.DeleteColumn));
+ familyMap.put(family, list);
+ }
+
+ /**
+ * Delete the latest version of the specified column.
+ * This is an expensive call in that on the server-side, it first does a
+ * get to find the latest versions timestamp. Then it adds a delete using
+ * the fetched cells timestamp.
+ * @param family family name
+ * @param qualifier column qualifier
+ */
+ public void deleteColumn(byte [] family, byte [] qualifier) {
+ this.deleteColumn(family, qualifier, HConstants.LATEST_TIMESTAMP);
+ }
+
+ /**
+ * Delete the specified version of the specified column.
+ * @param family family name
+ * @param qualifier column qualifier
+ * @param timestamp version timestamp
+ */
+ public void deleteColumn(byte [] family, byte [] qualifier, long timestamp) {
+ List<KeyValue> list = familyMap.get(family);
+ if(list == null) {
+ list = new ArrayList<KeyValue>();
+ }
+ list.add(new KeyValue(
+ this.row, family, qualifier, timestamp, KeyValue.Type.Delete));
+ familyMap.put(family, list);
+ }
+
+ /**
+ * Delete the latest version of the specified column, given in
+ * <code>family:qualifier</code> notation.
+ * @param column colon-delimited family and qualifier
+ */
+ public void deleteColumn(byte [] column) {
+ byte [][] parts = KeyValue.parseColumn(column);
+ this.deleteColumn(parts[0], parts[1], HConstants.LATEST_TIMESTAMP);
+ }
+
+ /**
+ * Method for retrieving the delete's familyMap
+ * @return familyMap
+ */
+ public Map<byte [], List<KeyValue>> getFamilyMap() {
+ return this.familyMap;
+ }
+
+ /**
+ * Method for retrieving the delete's row
+ * @return row
+ */
+ public byte [] getRow() {
+ return this.row;
+ }
+
+ /**
+ * Method for retrieving the delete's RowLock
+ * @return RowLock
+ */
+ public RowLock getRowLock() {
+ return new RowLock(this.row, this.lockId);
+ }
+
+ /**
+ * Method for retrieving the delete's lock ID.
+ *
+ * @return The lock ID.
+ */
+ public long getLockId() {
+ return this.lockId;
+ }
+
+ /**
+ * Method for retrieving the delete's timestamp
+ * @return timestamp
+ */
+ public long getTimeStamp() {
+ return this.ts;
+ }
+
+ /**
+ * @return string
+ */
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("row=");
+ sb.append(Bytes.toString(this.row));
+ sb.append(", ts=");
+ sb.append(this.ts);
+ sb.append(", families={");
+ boolean moreThanOne = false;
+ for(Map.Entry<byte [], List<KeyValue>> entry : this.familyMap.entrySet()) {
+ if(moreThanOne) {
+ sb.append(", ");
+ } else {
+ moreThanOne = true;
+ }
+ sb.append("(family=");
+ sb.append(Bytes.toString(entry.getKey()));
+ sb.append(", keyvalues=(");
+ boolean moreThanOneB = false;
+ for(KeyValue kv : entry.getValue()) {
+ if(moreThanOneB) {
+ sb.append(", ");
+ } else {
+ moreThanOneB = true;
+ }
+ sb.append(kv.toString());
+ }
+ sb.append(")");
+ }
+ sb.append("}");
+ return sb.toString();
+ }
+
+ //Writable
+ public void readFields(final DataInput in) throws IOException {
+ this.row = Bytes.readByteArray(in);
+ this.ts = in.readLong();
+ this.lockId = in.readLong();
+ this.familyMap.clear();
+ int numFamilies = in.readInt();
+ for(int i=0;i<numFamilies;i++) {
+ byte [] family = Bytes.readByteArray(in);
+ int numColumns = in.readInt();
+ List<KeyValue> list = new ArrayList<KeyValue>(numColumns);
+ for(int j=0;j<numColumns;j++) {
+ KeyValue kv = new KeyValue();
+ kv.readFields(in);
+ list.add(kv);
+ }
+ this.familyMap.put(family, list);
+ }
+ }
+
+ public void write(final DataOutput out) throws IOException {
+ Bytes.writeByteArray(out, this.row);
+ out.writeLong(this.ts);
+ out.writeLong(this.lockId);
+ out.writeInt(familyMap.size());
+ for(Map.Entry<byte [], List<KeyValue>> entry : familyMap.entrySet()) {
+ Bytes.writeByteArray(out, entry.getKey());
+ List<KeyValue> list = entry.getValue();
+ out.writeInt(list.size());
+ for(KeyValue kv : list) {
+ kv.write(out);
+ }
+ }
+ }
+}
\ No newline at end of file
Added: hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/client/Get.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/client/Get.java?rev=785076&view=auto
==============================================================================
--- hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/client/Get.java (added)
+++ hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/client/Get.java Tue Jun 16 04:33:56 2009
@@ -0,0 +1,398 @@
+/**
+ * Copyright 2009 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.client;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.Map;
+import java.util.NavigableSet;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.filter.RowFilterInterface;
+import org.apache.hadoop.hbase.io.HbaseObjectWritable;
+import org.apache.hadoop.hbase.io.TimeRange;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.io.Writable;
+
+/**
+ * Used to perform Get operations on a single row.
+ * <p>
+ * To get everything for a row, instantiate a Get object with the row to get.
+ * To further define the scope of what to get, perform additional methods as
+ * outlined below.
+ * <p>
+ * To get all columns from specific families, execute {@link #addFamily(byte[]) addFamily}
+ * for each family to retrieve.
+ * <p>
+ * To get specific columns, execute {@link #addColumn(byte[], byte[]) addColumn}
+ * for each column to retrieve.
+ * <p>
+ * To only retrieve columns within a specific range of version timestamps,
+ * execute {@link #setTimeRange(long, long) setTimeRange}.
+ * <p>
+ * To only retrieve columns with a specific timestamp, execute
+ * {@link #setTimeStamp(long) setTimestamp}.
+ * <p>
+ * To limit the number of versions of each column to be returned, execute
+ * {@link #setMaxVersions(int) setMaxVersions}.
+ * <p>
+ * To add a filter, execute {@link #setFilter(RowFilterInterface) setFilter}.
+ */
+public class Get implements Writable {
+ private byte [] row = null;
+ private long lockId = -1L;
+ private int maxVersions = 1;
+ private RowFilterInterface filter = null;
+ private TimeRange tr = new TimeRange();
+ private Map<byte [], NavigableSet<byte []>> familyMap =
+ new TreeMap<byte [], NavigableSet<byte []>>(Bytes.BYTES_COMPARATOR);
+
+ /** Constructor for Writable. DO NOT USE */
+ public Get() {}
+
+ /**
+ * Create a Get operation for the specified row.
+ * <p>
+ * If no further operations are done, this will get the latest version of
+ * all columns in all families of the specified row.
+ * @param row row key
+ */
+ public Get(byte [] row) {
+ this(row, null);
+ }
+
+ /**
+ * Create a Get operation for the specified row, using an existing row lock.
+ * <p>
+ * If no further operations are done, this will get the latest version of
+ * all columns in all families of the specified row.
+ * @param row row key
+ * @param rowLock previously acquired row lock, or null
+ */
+ public Get(byte [] row, RowLock rowLock) {
+ this.row = row;
+ if(rowLock != null) {
+ this.lockId = rowLock.getLockId();
+ }
+ }
+
+ /**
+ * Get all columns from the specified family.
+ * <p>
+ * Overrides previous calls to addColumn for this family.
+ * @param family family name
+ * @return the Get object
+ */
+ public Get addFamily(byte [] family) {
+ familyMap.remove(family);
+ familyMap.put(family, null);
+ return this;
+ }
+
+ /**
+ * Get the column from the specific family with the specified qualifier.
+ * <p>
+ * Overrides previous calls to addFamily for this family.
+ * @param family family name
+ * @param qualifier column qualifier
+ * @return the Get objec
+ */
+ public Get addColumn(byte [] family, byte [] qualifier) {
+ NavigableSet<byte []> set = familyMap.get(family);
+ if(set == null) {
+ set = new TreeSet<byte []>(Bytes.BYTES_COMPARATOR);
+ }
+ set.add(qualifier);
+ familyMap.put(family, set);
+ return this;
+ }
+
+ /**
+ * Adds an array of columns specified the old format, family:qualifier.
+ * <p>
+ * Overrides previous calls to addFamily for any families in the input.
+ * @param columns array of columns, formatted as <pre>family:qualifier</pre>
+ */
+ public Get addColumns(byte [][] columns) {
+ if (columns == null) return this;
+ for(int i = 0; i < columns.length; i++) {
+ try {
+ addColumn(columns[i]);
+ } catch(Exception e) {}
+ }
+ return this;
+ }
+
+ /**
+ * @param column Old format column.
+ * @return This.
+ */
+ public Get addColumn(final byte [] column) {
+ if (column == null) return this;
+ byte [][] split = KeyValue.parseColumn(column);
+ addColumn(split[0], split[1]);
+ return this;
+ }
+
+ /**
+ * Get versions of columns only within the specified timestamp range,
+ * [minStamp, maxStamp).
+ * @param minStamp minimum timestamp value, inclusive
+ * @param maxStamp maximum timestamp value, exclusive
+ * @throws IOException if invalid time range
+ */
+ public Get setTimeRange(long minStamp, long maxStamp)
+ throws IOException {
+ tr = new TimeRange(minStamp, maxStamp);
+ return this;
+ }
+
+ /**
+ * Get versions of columns with the specified timestamp.
+ * @param timestamp version timestamp
+ */
+ public Get setTimeStamp(long timestamp) {
+ try {
+ tr = new TimeRange(timestamp, timestamp+1);
+ } catch(IOException e) {
+ // Will never happen
+ }
+ return this;
+ }
+
+ /**
+ * Get all available versions.
+ */
+ public Get setMaxVersions() {
+ this.maxVersions = Integer.MAX_VALUE;
+ return this;
+ }
+
+ /**
+ * Get up to the specified number of versions of each column.
+ * @param maxVersions maximum versions for each column
+ * @throws IOException if invalid number of versions
+ */
+ public Get setMaxVersions(int maxVersions) throws IOException {
+ if(maxVersions <= 0) {
+ throw new IOException("maxVersions must be positive");
+ }
+ this.maxVersions = maxVersions;
+ return this;
+ }
+
+ /**
+ * Apply the specified server-side filter when performing the Get.
+ * @param filter filter to run on the server
+ */
+ public Get setFilter(RowFilterInterface filter) {
+ this.filter = filter;
+ return this;
+ }
+
+ /** Accessors */
+
+ /**
+ * Method for retrieving the get's row
+ * @return row
+ */
+ public byte [] getRow() {
+ return this.row;
+ }
+
+ /**
+ * Method for retrieving the get's RowLock
+ * @return RowLock
+ */
+ public RowLock getRowLock() {
+ return new RowLock(this.row, this.lockId);
+ }
+
+ /**
+ * Method for retrieving the get's lockId
+ * @return lockId
+ */
+ public long getLockId() {
+ return this.lockId;
+ }
+
+ /**
+ * Method for retrieving the get's maximum number of version
+ * @return the maximum number of version to fetch for this get
+ */
+ public int getMaxVersions() {
+ return this.maxVersions;
+ }
+
+ /**
+ * Method for retrieving the get's TimeRange
+ * @return timeRange
+ */
+ public TimeRange getTimeRange() {
+ return this.tr;
+ }
+
+ /**
+ * Method for retrieving the keys in the familyMap
+ * @return keys in the current familyMap
+ */
+ public Set<byte[]> familySet() {
+ return this.familyMap.keySet();
+ }
+
+ /**
+ * Method for retrieving the number of families to get from
+ * @return number of families
+ */
+ public int numFamilies() {
+ return this.familyMap.size();
+ }
+
+ /**
+ * Method for checking if any families have been inserted into this Get
+ * @return true if familyMap is non empty false otherwise
+ */
+ public boolean hasFamilies() {
+ return !this.familyMap.isEmpty();
+ }
+
+ /**
+ * Method for retrieving the get's familyMap
+ * @return familyMap
+ */
+ public Map<byte[],NavigableSet<byte[]>> getFamilyMap() {
+ return this.familyMap;
+ }
+
+ /**
+ * @return String
+ */
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("row=");
+ sb.append(Bytes.toString(this.row));
+ sb.append(", maxVersions=");
+ sb.append("" + this.maxVersions);
+ sb.append(", timeRange=");
+ sb.append("[" + this.tr.getMin() + "," + this.tr.getMax() + ")");
+ sb.append(", families=");
+ if(this.familyMap.size() == 0) {
+ sb.append("ALL");
+ return sb.toString();
+ }
+ boolean moreThanOne = false;
+ for(Map.Entry<byte [], NavigableSet<byte[]>> entry :
+ this.familyMap.entrySet()) {
+ if(moreThanOne) {
+ sb.append("), ");
+ } else {
+ moreThanOne = true;
+ sb.append("{");
+ }
+ sb.append("(family=");
+ sb.append(Bytes.toString(entry.getKey()));
+ sb.append(", columns=");
+ if(entry.getValue() == null) {
+ sb.append("ALL");
+ } else {
+ sb.append("{");
+ boolean moreThanOneB = false;
+ for(byte [] column : entry.getValue()) {
+ if(moreThanOneB) {
+ sb.append(", ");
+ } else {
+ moreThanOneB = true;
+ }
+ sb.append(Bytes.toString(column));
+ }
+ sb.append("}");
+ }
+ }
+ sb.append("}");
+ return sb.toString();
+ }
+
+ //Writable
+ public void readFields(final DataInput in)
+ throws IOException {
+ this.row = Bytes.readByteArray(in);
+ this.lockId = in.readLong();
+ this.maxVersions = in.readInt();
+ boolean hasFilter = in.readBoolean();
+ if(hasFilter) {
+ this.filter =
+ (RowFilterInterface)HbaseObjectWritable.readObject(in, null);
+ }
+ this.tr = new TimeRange();
+ tr.readFields(in);
+ int numFamilies = in.readInt();
+ this.familyMap =
+ new TreeMap<byte [],NavigableSet<byte []>>(Bytes.BYTES_COMPARATOR);
+ for(int i=0; i<numFamilies; i++) {
+ byte [] family = Bytes.readByteArray(in);
+ boolean hasColumns = in.readBoolean();
+ NavigableSet<byte []> set = null;
+ if(hasColumns) {
+ int numColumns = in.readInt();
+ set = new TreeSet<byte []>(Bytes.BYTES_COMPARATOR);
+ for(int j=0; j<numColumns; j++) {
+ byte [] qualifier = Bytes.readByteArray(in);
+ set.add(qualifier);
+ }
+ }
+ this.familyMap.put(family, set);
+ }
+ }
+
+ public void write(final DataOutput out)
+ throws IOException {
+ Bytes.writeByteArray(out, this.row);
+ out.writeLong(this.lockId);
+ out.writeInt(this.maxVersions);
+ if(this.filter == null) {
+ out.writeBoolean(false);
+ } else {
+ out.writeBoolean(true);
+ HbaseObjectWritable.writeObject(out, this.filter,
+ RowFilterInterface.class, null);
+ }
+ tr.write(out);
+ out.writeInt(familyMap.size());
+ for(Map.Entry<byte [], NavigableSet<byte []>> entry :
+ familyMap.entrySet()) {
+ Bytes.writeByteArray(out, entry.getKey());
+ NavigableSet<byte []> columnSet = entry.getValue();
+ if(columnSet == null) {
+ out.writeBoolean(false);
+ } else {
+ out.writeBoolean(true);
+ out.writeInt(columnSet.size());
+ for(byte [] qualifier : columnSet) {
+ Bytes.writeByteArray(out, qualifier);
+ }
+ }
+ }
+ }
+}
Modified: hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/client/HBaseAdmin.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/client/HBaseAdmin.java?rev=785076&r1=785075&r2=785076&view=diff
==============================================================================
--- hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/client/HBaseAdmin.java (original)
+++ hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/client/HBaseAdmin.java Tue Jun 16 04:33:56 2009
@@ -21,6 +21,7 @@
import java.io.IOException;
import java.util.Map;
+import java.util.NavigableMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -34,8 +35,9 @@
import org.apache.hadoop.hbase.MasterNotRunningException;
import org.apache.hadoop.hbase.RegionException;
import org.apache.hadoop.hbase.RemoteExceptionHandler;
-import org.apache.hadoop.hbase.io.Cell;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.hadoop.hbase.client.Scan;
+import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.io.RowResult;
import org.apache.hadoop.hbase.ipc.HMasterInterface;
import org.apache.hadoop.hbase.ipc.HRegionInterface;
@@ -51,7 +53,8 @@
*/
public class HBaseAdmin {
private final Log LOG = LogFactory.getLog(this.getClass().getName());
- private final HConnection connection;
+// private final HConnection connection;
+ final HConnection connection;
private volatile HBaseConfiguration conf;
private final long pause;
private final int numRetries;
@@ -121,11 +124,13 @@
return this.connection.listTables();
}
- public HTableDescriptor getTableDescriptor(final String tableName)
- throws IOException {
- return getTableDescriptor(Bytes.toBytes(tableName));
- }
+ /**
+ * Method for getting the tableDescriptor
+ * @param tableName as a byte []
+ * @return the tableDescriptor
+ * @throws IOException
+ */
public HTableDescriptor getTableDescriptor(final byte [] tableName)
throws IOException {
return this.connection.getHTableDescriptor(tableName);
@@ -238,19 +243,22 @@
for (int tries = 0; tries < numRetries; tries++) {
long scannerId = -1L;
try {
- scannerId =
- server.openScanner(firstMetaServer.getRegionInfo().getRegionName(),
- HConstants.COL_REGIONINFO_ARRAY, tableName,
- HConstants.LATEST_TIMESTAMP, null);
- RowResult values = server.next(scannerId);
+ Scan scan = new Scan().addColumn(HConstants.CATALOG_FAMILY,
+ HConstants.REGIONINFO_QUALIFIER);
+
+ scannerId = server.openScanner(
+ firstMetaServer.getRegionInfo().getRegionName(),
+ scan);
+ Result values = server.next(scannerId);
if (values == null || values.size() == 0) {
break;
}
boolean found = false;
- for (Map.Entry<byte [], Cell> e: values.entrySet()) {
- if (Bytes.equals(e.getKey(), HConstants.COL_REGIONINFO)) {
+ NavigableMap<byte[], byte[]> infoValues = values.getFamilyMap(HConstants.CATALOG_FAMILY);
+ for (Map.Entry<byte [], byte []> e: infoValues.entrySet()) {
+ if (Bytes.equals(e.getKey(), HConstants.REGIONINFO_QUALIFIER)) {
info = (HRegionInfo) Writables.getWritable(
- e.getValue().getValue(), info);
+ e.getValue(), info);
if (Bytes.equals(info.getTableDesc().getName(), tableName)) {
found = true;
@@ -566,7 +574,7 @@
newargs[i + xtraArgsCount] = args[i];
}
}
- modifyTable(HConstants.META_TABLE_NAME, HConstants.MODIFY_CLOSE_REGION,
+ modifyTable(HConstants.META_TABLE_NAME, HConstants.Modify.CLOSE_REGION,
newargs);
}
@@ -589,7 +597,7 @@
* @throws IOException
*/
public void flush(final byte [] tableNameOrRegionName) throws IOException {
- modifyTable(tableNameOrRegionName, HConstants.MODIFY_TABLE_FLUSH);
+ modifyTable(tableNameOrRegionName, HConstants.Modify.TABLE_FLUSH);
}
/**
@@ -611,7 +619,7 @@
* @throws IOException
*/
public void compact(final byte [] tableNameOrRegionName) throws IOException {
- modifyTable(tableNameOrRegionName, HConstants.MODIFY_TABLE_COMPACT);
+ modifyTable(tableNameOrRegionName, HConstants.Modify.TABLE_COMPACT);
}
/**
@@ -635,7 +643,7 @@
*/
public void majorCompact(final byte [] tableNameOrRegionName)
throws IOException {
- modifyTable(tableNameOrRegionName, HConstants.MODIFY_TABLE_MAJOR_COMPACT);
+ modifyTable(tableNameOrRegionName, HConstants.Modify.TABLE_MAJOR_COMPACT);
}
/**
@@ -657,7 +665,7 @@
* @throws IOException
*/
public void split(final byte [] tableNameOrRegionName) throws IOException {
- modifyTable(tableNameOrRegionName, HConstants.MODIFY_TABLE_SPLIT);
+ modifyTable(tableNameOrRegionName, HConstants.Modify.TABLE_SPLIT);
}
/*
@@ -667,7 +675,8 @@
* @param op
* @throws IOException
*/
- private void modifyTable(final byte [] tableNameOrRegionName, final int op)
+ private void modifyTable(final byte [] tableNameOrRegionName,
+ final HConstants.Modify op)
throws IOException {
if (tableNameOrRegionName == null) {
throw new IllegalArgumentException("Pass a table name or region name");
@@ -689,7 +698,7 @@
*/
public void modifyTable(final byte [] tableName, HTableDescriptor htd)
throws IOException {
- modifyTable(tableName, HConstants.MODIFY_TABLE_SET_HTD, htd);
+ modifyTable(tableName, HConstants.Modify.TABLE_SET_HTD, htd);
}
/**
@@ -702,7 +711,8 @@
* @param args operation specific arguments
* @throws IOException
*/
- public void modifyTable(final byte [] tableName, int op, Object... args)
+ public void modifyTable(final byte [] tableName, HConstants.Modify op,
+ Object... args)
throws IOException {
if (this.master == null) {
throw new MasterNotRunningException("master has been shut down");
@@ -715,7 +725,7 @@
Writable[] arr = null;
try {
switch (op) {
- case HConstants.MODIFY_TABLE_SET_HTD:
+ case TABLE_SET_HTD:
if (args == null || args.length < 1 ||
!(args[0] instanceof HTableDescriptor)) {
throw new IllegalArgumentException("SET_HTD requires a HTableDescriptor");
@@ -725,10 +735,10 @@
this.master.modifyTable(tableName, op, arr);
break;
- case HConstants.MODIFY_TABLE_COMPACT:
- case HConstants.MODIFY_TABLE_SPLIT:
- case HConstants.MODIFY_TABLE_MAJOR_COMPACT:
- case HConstants.MODIFY_TABLE_FLUSH:
+ case TABLE_COMPACT:
+ case TABLE_SPLIT:
+ case TABLE_MAJOR_COMPACT:
+ case TABLE_FLUSH:
if (args != null && args.length > 0) {
arr = new Writable[1];
if (args[0] instanceof byte[]) {
@@ -745,7 +755,7 @@
this.master.modifyTable(tableName, op, arr);
break;
- case HConstants.MODIFY_CLOSE_REGION:
+ case CLOSE_REGION:
if (args == null || args.length < 1) {
throw new IllegalArgumentException("Requires at least a region name");
}