diff --git a/src/test/org/apache/hadoop/hbase/regionserver/TestHRegion.java b/src/test/org/apache/hadoop/hbase/regionserver/TestHRegion.java index f1ec6de..bdb4da2 100644 --- a/src/test/org/apache/hadoop/hbase/regionserver/TestHRegion.java +++ b/src/test/org/apache/hadoop/hbase/regionserver/TestHRegion.java @@ -60,9 +60,13 @@ public class TestHRegion extends HBaseTestCase { // Test names private final byte[] tableName = Bytes.toBytes("testtable");; private final byte[] qual1 = Bytes.toBytes("qual1"); + private final byte[] qual2 = Bytes.toBytes("qual2"); + private final byte[] qual3 = Bytes.toBytes("qual3"); private final byte[] value1 = Bytes.toBytes("value1"); private final byte[] value2 = Bytes.toBytes("value2"); private final byte [] row = Bytes.toBytes("rowA"); + private final byte [] row2 = Bytes.toBytes("rowB"); + private final byte [] row3 = Bytes.toBytes("rowC"); /** * @see org.apache.hadoop.hbase.HBaseTestCase#setUp() @@ -1246,7 +1250,6 @@ public class TestHRegion extends HBaseTestCase { byte [] col2 = Bytes.toBytes("Pub222"); - Put put = new Put(row1); put.add(family, col1, Bytes.toBytes(10L)); region.put(put); @@ -1275,7 +1278,132 @@ public class TestHRegion extends HBaseTestCase { List results = new ArrayList(); assertEquals(false, s.next(results)); assertEquals(0, results.size()); + } + public void testIncrementColumnValue_UpdatingInPlace() throws IOException { + initHRegion(tableName, getName(), fam1); + long value = 1L; + long amount = 3L; + + Put put = new Put(row); + put.add(fam1, qual1, Bytes.toBytes(value)); + region.put(put); + long result = region.incrementColumnValue(row, fam1, qual1, amount, true); + assertEquals(value+amount, result); + + Store store = region.getStore(fam1); + assertEquals(1, store.memstore.kvset.size()); + assertTrue(store.memstore.snapshot.isEmpty()); + + assertICV(row, fam1, qual1, value+amount); + } + + public void testIncrementColumnValue_ConcurrentFlush() throws IOException { + initHRegion(tableName, getName(), fam1); + + long value = 1L; + long amount = 3L; + + Put put = new Put(row); + put.add(fam1, qual1, Bytes.toBytes(value)); + region.put(put); + + // now increment during a flush + Thread t = new Thread() { + public void run() { + try { + region.flushcache(); + } catch (IOException e) { + LOG.info("test ICV, got IOE during flushcache()"); + } + } + }; + t.start(); + long r = region.incrementColumnValue(row, fam1, qual1, amount, true); + assertEquals(value+amount, r); + + // this also asserts there is only 1 KeyValue in the set. + assertICV(row, fam1, qual1, value+amount); + } + + public void testIncrementColumnValue_UpdatingInPlace_Negative() + throws IOException { + initHRegion(tableName, getName(), fam1); + + long value = 3L; + long amount = -1L; + + Put put = new Put(row); + put.add(fam1, qual1, Bytes.toBytes(value)); + region.put(put); + + long result = region.incrementColumnValue(row, fam1, qual1, amount, true); + assertEquals(value+amount, result); + + assertICV(row, fam1, qual1, value+amount); + } + + public void testIncrementColumnValue_AddingNew() + throws IOException { + initHRegion(tableName, getName(), fam1); + + long value = 1L; + long amount = 3L; + + Put put = new Put(row); + put.add(fam1, qual1, Bytes.toBytes(value)); + put.add(fam1, qual2, Bytes.toBytes(value)); + region.put(put); + + long result = region.incrementColumnValue(row, fam1, qual3, amount, true); + assertEquals(amount, result); + + Get get = new Get(row); + get.addColumn(fam1, qual3); + Result rr = region.get(get, null); + assertEquals(1, rr.size()); + + // ensure none of the other cols were incremented. + assertICV(row, fam1, qual1, value); + assertICV(row, fam1, qual2, value); + assertICV(row, fam1, qual3, amount); + } + + public void testIncrementColumnValue_UpdatingFromSF() throws IOException { + initHRegion(tableName, getName(), fam1); + + long value = 1L; + long amount = 3L; + + Put put = new Put(row); + put.add(fam1, qual1, Bytes.toBytes(value)); + put.add(fam1, qual2, Bytes.toBytes(value)); + region.put(put); + + // flush to disk. + region.flushcache(); + + Store store = region.getStore(fam1); + assertEquals(0, store.memstore.kvset.size()); + + long r = region.incrementColumnValue(row, fam1, qual1, amount, true); + assertEquals(value+amount, r); + + assertICV(row, fam1, qual1, value+amount); + } + + public void testIncrementColumnValue_AddingNewAfterSFCheck() + throws IOException { + initHRegion(tableName, getName(), fam1); + + long value = 1L; + long amount = 3L; + + Put put = new Put(row); + put.add(fam1, qual1, Bytes.toBytes(value)); + put.add(fam1, qual2, Bytes.toBytes(value)); + region.put(put); + region.flushcache(); + + Store store = region.getStore(fam1); + assertEquals(0, store.memstore.kvset.size()); + + long r = region.incrementColumnValue(row, fam1, qual3, amount, true); + assertEquals(amount, r); + + assertICV(row, fam1, qual3, amount); + + region.flushcache(); + + // ensure that this gets to disk. + assertICV(row, fam1, qual3, amount); } + + private void assertICV(byte [] row, + byte [] familiy, + byte[] qualifier, + long amount) throws IOException { + // run a get and see? + Get get = new Get(row); + get.addColumn(familiy, qualifier); + Result result = region.get(get, null); + assertEquals(1, result.size()); + + KeyValue kv = result.raw()[0]; + long r = Bytes.toLong(kv.getValue()); + assertEquals(amount, r); + } + + public void testScanner_Wildcard_FromMemStoreAndFiles_EnforceVersions() throws IOException { diff --git a/src/test/org/apache/hadoop/hbase/regionserver/TestStore.java b/src/test/org/apache/hadoop/hbase/regionserver/TestStore.java index 68a3558..6328de9 100644 --- a/src/test/org/apache/hadoop/hbase/regionserver/TestStore.java +++ b/src/test/org/apache/hadoop/hbase/regionserver/TestStore.java @@ -232,139 +232,59 @@ public class TestStore extends TestCase { ////////////////////////////////////////////////////////////////////////////// // IncrementColumnValue tests ////////////////////////////////////////////////////////////////////////////// - /** - * Testing if the update in place works. When you want to update a value that - * is already in memstore, you don't delete it and put a new one, but just - * update the value in the original KeyValue - * @throws IOException + /* + * test the internal details of how ICV works, especially during a flush scenario. */ - public void testIncrementColumnValue_UpdatingInPlace() throws IOException { + public void testIncrementColumnValue_ICVDuringFlush() + throws IOException { init(this.getName()); - //Put data in memstore - long value = 1L; - long amount = 3L; - this.store.add(new KeyValue(row, family, qf1, Bytes.toBytes(value))); - - Store.ICVResult vas = this.store.incrementColumnValue(row, family, qf1, amount); - assertEquals(value+amount, vas.value); - store.add(vas.kv); - Get get = new Get(row); - get.addColumn(family, qf1); - NavigableSet qualifiers = - new ConcurrentSkipListSet(Bytes.BYTES_COMPARATOR); - qualifiers.add(qf1); - List result = new ArrayList(); - this.store.get(get, qualifiers, result); - assertEquals(value + amount, Bytes.toLong(result.get(0).getValue())); - } + long oldValue = 1L; + long newValue = 3L; + this.store.add(new KeyValue(row, family, qf1, + System.currentTimeMillis(), + Bytes.toBytes(oldValue))); - /** - * Same as above but for a negative number - * @throws IOException - */ - public void testIncrementColumnValue_UpdatingInPlace_Negative() - throws IOException { - init(this.getName()); + // snapshot the store. + this.store.snapshot(); - //Put data in memstore - long value = 3L; - long amount = -1L; - this.store.add(new KeyValue(row, family, qf1, Bytes.toBytes(value))); - - Store.ICVResult vas = this.store.incrementColumnValue(row, family, qf1, amount); - assertEquals(vas.value, value+amount); - store.add(vas.kv); - Get get = new Get(row); - get.addColumn(family, qf1); - NavigableSet qualifiers = - new ConcurrentSkipListSet(Bytes.BYTES_COMPARATOR); - qualifiers.add(qf1); - List result = new ArrayList(); - this.store.get(get, qualifiers, result); - assertEquals(value + amount, Bytes.toLong(result.get(0).getValue())); - } - - /** - * When there is no mathing key already, adding a new. - * @throws IOException - */ - public void testIncrementColumnValue_AddingNew() throws IOException { - init(this.getName()); - - //Put data in memstore - long value = 1L; - long amount = 3L; - this.store.add(new KeyValue(row, family, qf1, Bytes.toBytes(value))); - this.store.add(new KeyValue(row, family, qf2, Bytes.toBytes(value))); - - Store.ICVResult vas = this.store.incrementColumnValue(row, family, qf3, amount); - store.add(vas.kv); - Get get = new Get(row); - get.addColumn(family, qf3); - NavigableSet qualifiers = - new ConcurrentSkipListSet(Bytes.BYTES_COMPARATOR); - qualifiers.add(qf3); - List result = new ArrayList(); - this.store.get(get, qualifiers, result); - assertEquals(amount, Bytes.toLong(result.get(0).getValue())); - } + // add other things: + this.store.add(new KeyValue(row, family, qf2, + System.currentTimeMillis(), + Bytes.toBytes(oldValue))); - /** - * When we have the key in a file add a new key + value to memstore with the - * updates value. - * @throws IOException - */ - public void testIncrementColumnValue_UpdatingFromSF() throws IOException { - init(this.getName()); - - //Put data in memstore - long value = 1L; - long amount = 3L; - this.store.add(new KeyValue(row, family, qf1, Bytes.toBytes(value))); - this.store.add(new KeyValue(row, family, qf2, Bytes.toBytes(value))); - - flush(1); - - Store.ICVResult vas = this.store.incrementColumnValue(row, family, qf1, amount); - store.add(vas.kv); + // update during the snapshot. + long ret = this.store.updateColumnValue(row, family, qf1, newValue); + + // memstore should have grown by some amount. + assertTrue(ret > 0); + + // then flush. + this.store.flushCache(id++); + assertEquals(1, this.store.getStorefiles().size()); + // from the one we inserted up there, and a new one + assertEquals(2, this.store.memstore.kvset.size()); + + // how many key/values for this row are there? Get get = new Get(row); get.addColumn(family, qf1); - NavigableSet qualifiers = - new ConcurrentSkipListSet(Bytes.BYTES_COMPARATOR); - qualifiers.add(qf1); - List result = new ArrayList(); - this.store.get(get, qualifiers, result); - assertEquals(value + amount, Bytes.toLong(result.get(0).getValue())); - } + get.setMaxVersions(); // all versions. + List results = new ArrayList(); + + NavigableSet cols = new TreeSet(); + cols.add(qf1); + + this.store.get(get, cols, results); + assertEquals(2, results.size()); + + long ts1 = results.get(0).getTimestamp(); + long ts2 = results.get(1).getTimestamp(); + + assertTrue(ts1 > ts2); + + assertEquals(newValue, Bytes.toLong(results.get(0).getValue())); + assertEquals(oldValue, Bytes.toLong(results.get(1).getValue())); - /** - * Same as testIncrementColumnValue_AddingNew() except that the keys are - * checked in file not in memstore - * @throws IOException - */ - public void testIncrementColumnValue_AddingNewAfterSFCheck() - throws IOException { - init(this.getName()); - - //Put data in memstore - long value = 1L; - long amount = 3L; - this.store.add(new KeyValue(row, family, qf1, Bytes.toBytes(value))); - this.store.add(new KeyValue(row, family, qf2, Bytes.toBytes(value))); - - flush(1); - - Store.ICVResult vas = this.store.incrementColumnValue(row, family, qf3, amount); - store.add(vas.kv); - Get get = new Get(row); - get.addColumn(family, qf3); - NavigableSet qualifiers = - new ConcurrentSkipListSet(Bytes.BYTES_COMPARATOR); - qualifiers.add(qf3); - List result = new ArrayList(); - this.store.get(get, qualifiers, result); - assertEquals(amount, Bytes.toLong(result.get(0).getValue())); } public void testIncrementColumnValue_ICVDuringFlush()