HBASE-1347 HTable.incrementColumnValue does not take negative 'amount'
git-svn-id: https://svn.apache.org/repos/asf/hadoop/hbase/trunk@770991 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
c8cdf88bf3
commit
4ce9bb1e86
|
@ -99,6 +99,8 @@ Release 0.20.0 - Unreleased
|
||||||
(Evgeny Ryabitskiy via Stack)
|
(Evgeny Ryabitskiy via Stack)
|
||||||
HBASE-1322 hbase-1234 broke TestAtomicIncrement; fix and reenable
|
HBASE-1322 hbase-1234 broke TestAtomicIncrement; fix and reenable
|
||||||
(Evgeny Ryabitskiy and Ryan Rawson via Stack)
|
(Evgeny Ryabitskiy and Ryan Rawson via Stack)
|
||||||
|
HBASE-1347 HTable.incrementColumnValue does not take negative 'amount'
|
||||||
|
(Evgeny Ryabitskiy via Stack)
|
||||||
|
|
||||||
IMPROVEMENTS
|
IMPROVEMENTS
|
||||||
HBASE-1089 Add count of regions on filesystem to master UI; add percentage
|
HBASE-1089 Add count of regions on filesystem to master UI; add percentage
|
||||||
|
|
|
@ -2701,7 +2701,8 @@ public class HRegion implements HConstants {
|
||||||
"/"+ Bytes.toString(column));
|
"/"+ Bytes.toString(column));
|
||||||
value = Bytes.toBytes(amount);
|
value = Bytes.toBytes(amount);
|
||||||
} else {
|
} else {
|
||||||
value = incrementBytes(value, amount);
|
if (amount == 0) return Bytes.toLong(value);
|
||||||
|
value = Bytes.incrementBytes(value, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
BatchUpdate b = new BatchUpdate(row, ts);
|
BatchUpdate b = new BatchUpdate(row, ts);
|
||||||
|
@ -2713,34 +2714,4 @@ public class HRegion implements HConstants {
|
||||||
releaseRowLock(lid);
|
releaseRowLock(lid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte [] incrementBytes(byte[] value, long amount) throws IOException {
|
|
||||||
// Hopefully this doesn't happen too often.
|
|
||||||
if (value.length < Bytes.SIZEOF_LONG) {
|
|
||||||
byte [] newvalue = new byte[Bytes.SIZEOF_LONG];
|
|
||||||
System.arraycopy(value, 0, newvalue, newvalue.length - value.length,
|
|
||||||
value.length);
|
|
||||||
value = newvalue;
|
|
||||||
} else if (value.length > Bytes.SIZEOF_LONG) {
|
|
||||||
throw new DoNotRetryIOException("Increment Bytes - value too big: " +
|
|
||||||
value.length);
|
|
||||||
}
|
|
||||||
return binaryIncrement(value, amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte [] binaryIncrement(byte [] value, long amount) {
|
|
||||||
for(int i=0;i<value.length;i++) {
|
|
||||||
int cur = (int)(amount >> (8 * i)) % 256;
|
|
||||||
int val = value[value.length-i-1] & 0xff;
|
|
||||||
int total = cur + val;
|
|
||||||
if(total > 255) {
|
|
||||||
amount += ((long)256 << (8 * i));
|
|
||||||
total %= 256;
|
|
||||||
}
|
|
||||||
value[value.length-i-1] = (byte)total;
|
|
||||||
amount = (amount >> (8 * (i + 1))) << (8 * (i + 1));
|
|
||||||
if(amount == 0) return value;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -27,6 +27,7 @@ import java.nio.ByteBuffer;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
import org.apache.hadoop.hbase.DoNotRetryIOException;
|
||||||
import org.apache.hadoop.hbase.HConstants;
|
import org.apache.hadoop.hbase.HConstants;
|
||||||
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
|
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
|
||||||
import org.apache.hadoop.io.RawComparator;
|
import org.apache.hadoop.io.RawComparator;
|
||||||
|
@ -910,4 +911,89 @@ public class Bytes {
|
||||||
}
|
}
|
||||||
return - (low+1);
|
return - (low+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bytewise binary increment/deincrement of long contained in byte array
|
||||||
|
* on given amount.
|
||||||
|
*
|
||||||
|
* @param value - array of bytes containing long (length <= SIZEOF_LONG)
|
||||||
|
* @param amount value will be incremented on (deincremented if negative)
|
||||||
|
* @return array of bytes containing incremented long (length == SIZEOF_LONG)
|
||||||
|
* @throws IOException - if value.length > SIZEOF_LONG
|
||||||
|
*/
|
||||||
|
public static byte [] incrementBytes(byte[] value, long amount)
|
||||||
|
throws IOException {
|
||||||
|
byte[] val = value;
|
||||||
|
if (val.length < SIZEOF_LONG) {
|
||||||
|
// Hopefully this doesn't happen too often.
|
||||||
|
byte [] newvalue;
|
||||||
|
if (val[0] < 0) {
|
||||||
|
byte [] negativeValue = {-1, -1, -1, -1, -1, -1, -1, -1};
|
||||||
|
newvalue = negativeValue;
|
||||||
|
} else {
|
||||||
|
newvalue = new byte[SIZEOF_LONG];
|
||||||
|
}
|
||||||
|
System.arraycopy(val, 0, newvalue, newvalue.length - val.length,
|
||||||
|
val.length);
|
||||||
|
val = newvalue;
|
||||||
|
} else if (val.length > SIZEOF_LONG) {
|
||||||
|
throw new DoNotRetryIOException("Increment Bytes - value too big: " +
|
||||||
|
val.length);
|
||||||
|
}
|
||||||
|
if(amount == 0) return val;
|
||||||
|
if(val[0] < 0){
|
||||||
|
return binaryIncrementNeg(val, amount);
|
||||||
|
}
|
||||||
|
return binaryIncrementPos(val, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* increment/deincrement for positive value */
|
||||||
|
private static byte [] binaryIncrementPos(byte [] value, long amount) {
|
||||||
|
long amo = amount;
|
||||||
|
int sign = 1;
|
||||||
|
if (amount < 0) {
|
||||||
|
amo = -amount;
|
||||||
|
sign = -1;
|
||||||
|
}
|
||||||
|
for(int i=0;i<value.length;i++) {
|
||||||
|
int cur = ((int)amo % 256) * sign;
|
||||||
|
amo = (amo >> 8);
|
||||||
|
int val = value[value.length-i-1] & 0x0ff;
|
||||||
|
int total = val + cur;
|
||||||
|
if(total > 255) {
|
||||||
|
amo += sign;
|
||||||
|
total %= 256;
|
||||||
|
} else if (total < 0) {
|
||||||
|
amo -= sign;
|
||||||
|
}
|
||||||
|
value[value.length-i-1] = (byte)total;
|
||||||
|
if (amo == 0) return value;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* increment/deincrement for negative value */
|
||||||
|
private static byte [] binaryIncrementNeg(byte [] value, long amount) {
|
||||||
|
long amo = amount;
|
||||||
|
int sign = 1;
|
||||||
|
if (amount < 0) {
|
||||||
|
amo = -amount;
|
||||||
|
sign = -1;
|
||||||
|
}
|
||||||
|
for(int i=0;i<value.length;i++) {
|
||||||
|
int cur = ((int)amo % 256) * sign;
|
||||||
|
amo = (amo >> 8);
|
||||||
|
int val = ((~value[value.length-i-1]) & 0x0ff) + 1;
|
||||||
|
int total = cur - val;
|
||||||
|
if(total >= 0) {
|
||||||
|
amo += sign;
|
||||||
|
} else if (total < -256) {
|
||||||
|
amo -= sign;
|
||||||
|
total %= 256;
|
||||||
|
}
|
||||||
|
value[value.length-i-1] = (byte)total;
|
||||||
|
if (amo == 0) return value;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -88,6 +88,9 @@ public class TestAtomicIncrement extends HBaseClusterTestCase {
|
||||||
assertEquals(3L, table.incrementColumnValue(row, column, 1));
|
assertEquals(3L, table.incrementColumnValue(row, column, 1));
|
||||||
|
|
||||||
assertEquals(-2L, table.incrementColumnValue(row, column, -5));
|
assertEquals(-2L, table.incrementColumnValue(row, column, -5));
|
||||||
|
assertEquals(-502L, table.incrementColumnValue(row, column, -500));
|
||||||
|
assertEquals(1500L, table.incrementColumnValue(row, column, 2002));
|
||||||
|
assertEquals(1501L, table.incrementColumnValue(row, column, 1));
|
||||||
|
|
||||||
row = Bytes.toBytes("foo3");
|
row = Bytes.toBytes("foo3");
|
||||||
byte[] value2 = {1,2,3,4,5,6,7,8,9};
|
byte[] value2 = {1,2,3,4,5,6,7,8,9};
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.hadoop.hbase.util;
|
package org.apache.hadoop.hbase.util;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
@ -113,4 +114,40 @@ public class TestBytes extends TestCase {
|
||||||
assertEquals(5, Bytes.binarySearch(arr, key3, 1, 1,
|
assertEquals(5, Bytes.binarySearch(arr, key3, 1, 1,
|
||||||
Bytes.BYTES_RAWCOMPARATOR));
|
Bytes.BYTES_RAWCOMPARATOR));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testIncrementBytes() throws IOException {
|
||||||
|
|
||||||
|
assertTrue(checkTestIncrementBytes(10, 1));
|
||||||
|
assertTrue(checkTestIncrementBytes(12, 123435445));
|
||||||
|
assertTrue(checkTestIncrementBytes(124634654, 1));
|
||||||
|
assertTrue(checkTestIncrementBytes(10005460, 5005645));
|
||||||
|
assertTrue(checkTestIncrementBytes(1, -1));
|
||||||
|
assertTrue(checkTestIncrementBytes(10, -1));
|
||||||
|
assertTrue(checkTestIncrementBytes(10, -5));
|
||||||
|
assertTrue(checkTestIncrementBytes(1005435000, -5));
|
||||||
|
assertTrue(checkTestIncrementBytes(10, -43657655));
|
||||||
|
assertTrue(checkTestIncrementBytes(-1, 1));
|
||||||
|
assertTrue(checkTestIncrementBytes(-26, 5034520));
|
||||||
|
assertTrue(checkTestIncrementBytes(-10657200, 5));
|
||||||
|
assertTrue(checkTestIncrementBytes(-12343250, 45376475));
|
||||||
|
assertTrue(checkTestIncrementBytes(-10, -5));
|
||||||
|
assertTrue(checkTestIncrementBytes(-12343250, -5));
|
||||||
|
assertTrue(checkTestIncrementBytes(-12, -34565445));
|
||||||
|
assertTrue(checkTestIncrementBytes(-1546543452, -34565445));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean checkTestIncrementBytes(long val, long amount)
|
||||||
|
throws IOException {
|
||||||
|
byte[] value = Bytes.toBytes(val);
|
||||||
|
byte [] testValue = {-1, -1, -1, -1, -1, -1, -1, -1};
|
||||||
|
if (value[0] > 0) {
|
||||||
|
testValue = new byte[Bytes.SIZEOF_LONG];
|
||||||
|
}
|
||||||
|
System.arraycopy(value, 0, testValue, testValue.length - value.length,
|
||||||
|
value.length);
|
||||||
|
|
||||||
|
long incrementResult = Bytes.toLong(Bytes.incrementBytes(value, amount));
|
||||||
|
|
||||||
|
return (Bytes.toLong(testValue) + amount) == incrementResult;
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue