package coprocessor;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellScanner;
import org.apache.hadoop.hbase.Coprocessor;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver;
import org.apache.hadoop.hbase.coprocessor.ObserverContext;
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
import org.apache.hadoop.hbase.regionserver.HRegion;
import org.apache.hadoop.hbase.util.Bytes;
import util.HBaseHelper;
// cc DuplicateRegionObserverExample Example of attempting to load the same observer multiple times
// vv DuplicateRegionObserverExample
public class DuplicateRegionObserverExample extends BaseRegionObserver {
public static final Log LOG = LogFactory.getLog(HRegion.class);
public static final byte[] FIXED_COLUMN = Bytes.toBytes("@@@GET_COUNTER@@@");
private static AtomicInteger counter = new AtomicInteger(0);
@Override
public void preGetOp(ObserverContext<RegionCoprocessorEnvironment> e,
Get get, List<Cell> results) throws IOException {
int count = counter.incrementAndGet();
LOG.info("Current preGet count: " + count + " [" + this + "]");
}
@Override
public void postGetOp(ObserverContext<RegionCoprocessorEnvironment> e,
Get get, List<Cell> results) throws IOException {
Put put = new Put(get.getRow());
put.addColumn(get.getRow(), FIXED_COLUMN, Bytes.toBytes(counter.get()));
CellScanner scanner = put.cellScanner();
scanner.advance();
Cell cell = scanner.current();
LOG.debug("Adding fake cell: " + cell);
results.add(cell);
}
public static void main(String[] args) throws IOException {
Configuration conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.quorum", "master-1.internal.larsgeorge.com," +
"master-2.internal.larsgeorge.com,master-3.internal.larsgeorge.com");
HBaseHelper helper = HBaseHelper.getHelper(conf);
helper.dropTable("testtable");
Connection connection = ConnectionFactory.createConnection(conf);
TableName tableName = TableName.valueOf("testtable");
HTableDescriptor htd = new HTableDescriptor(tableName)
.addFamily(new HColumnDescriptor("colfam1"))
.addCoprocessor(DuplicateRegionObserverExample.class.getCanonicalName(),
null, Coprocessor.PRIORITY_USER, null)
.addCoprocessor(DuplicateRegionObserverExample.class.getCanonicalName(),
null, Coprocessor.PRIORITY_USER, null);
// ^^ DuplicateRegionObserverExample
/* Does not work as expected! Will throw the following exception:
Exception in thread "main" java.io.IOException: Coprocessor \
coprocessor.DuplicateRegionObserverExample already exists.
at org.apache.hadoop.hbase.HTableDescriptor.addCoprocessor(HTableDescriptor.java:1232)
at coprocessor.DuplicateRegionObserverExample.main(DuplicateRegionObserverExample.java:69)
...
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
*/
// vv DuplicateRegionObserverExample
Admin admin = connection.getAdmin();
admin.createTable(htd);
System.out.println(admin.getTableDescriptor(tableName));
System.out.println("Adding rows to table...");
helper.fillTable("testtable", 1, 10, 10, "colfam1");
Table table = connection.getTable(tableName);
Get get = new Get(Bytes.toBytes("row-1"));
Result result = table.get(get);
helper.dumpResult(result);
table.close();
admin.close();
connection.close();
}
}
// ^^ DuplicateRegionObserverExample
/*
Adding coprocessor using HBase shell uses its own table attribute insertion
with no check during the ALTER command:
$ hbase shell
HBase Shell; enter 'help<RETURN>' for list of supported commands.
Type "exit<RETURN>" to leave the HBase Shell
Version 1.1.1, rd0a115a7267f54e01c72c603ec53e91ec418292f, Tue Jun 23 14:44:07 PDT 2015
hbase(main):001:0> create 'testtable', 'colfam1'
0 row(s) in 2.1750 seconds
=> Hbase::Table - testtable
hbase(main):002:0> alter 'testtable', 'coprocessor' => 'file:///opt/hbase-book/hbase-book-ch04-2.0.jar|coprocessor.DuplicateRegionObserverExample|'
Updating all regions with the new schema...
0/1 regions updated.
1/1 regions updated.
Done.
0 row(s) in 3.9970 seconds
hbase(main):003:0> describe 'testtable'
Table testtable is ENABLED
testtable, {TABLE_ATTRIBUTES => {coprocessor$1 => 'file:///opt/hbase-book/hbase-book-ch04-2.0.jar|coprocessor.DuplicateRegionObserverExample|'}
COLUMN FAMILIES DESCRIPTION
{NAME => 'colfam1', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => '0', VERSIONS => '1', COMPRESSION => 'NONE', MIN_VERSIONS => '0', TTL => 'FOREVER', KEEP_DELETED_CELLS => 'FALSE', BLOC
KSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'true'}
1 row(s) in 0.0680 seconds
hbase(main):004:0> alter 'testtable', 'coprocessor' => 'file:///opt/hbase-book/hbase-book-ch04-2.0.jar|coprocessor.DuplicateRegionObserverExample|'
Updating all regions with the new schema...
1/1 regions updated.
Done.
0 row(s) in 2.1740 seconds
hbase(main):005:0> describe 'testtable'
Table testtable is ENABLED
testtable, {TABLE_ATTRIBUTES => {coprocessor$1 => 'file:///opt/hbase-book/hbase-book-ch04-2.0.jar|coprocessor.DuplicateRegionObserverExample|', coprocessor$2 => 'file:///opt/hbase-book/hbase-book-ch04-2.0.jar|copr
ocessor.DuplicateRegionObserverExample|'}
COLUMN FAMILIES DESCRIPTION
{NAME => 'colfam1', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => '0', VERSIONS => '1', COMPRESSION => 'NONE', MIN_VERSIONS => '0', TTL => 'FOREVER', KEEP_DELETED_CELLS => 'FALSE', BLOC
KSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'true'}
1 row(s) in 0.0200 seconds
hbase(main):006:0> put 'testtable', 'row-1', 'colfam1:col1', 'val1'
0 row(s) in 0.1090 seconds
hbase(main):007:0> get 'testtable', 'row-1'
COLUMN CELL
colfam1:col1 timestamp=1439549519940, value=val1
row-1:@@@GET_COUNTER@@@ timestamp=9223372036854775807, value=\x00\x00\x00\x02
row-1:@@@GET_COUNTER@@@ timestamp=9223372036854775807, value=\x00\x00\x00\x02
3 row(s) in 0.0380 seconds
hbase(main):008:0> get 'testtable', 'row-1'
COLUMN CELL
colfam1:col1 timestamp=1439549519940, value=val1
row-1:@@@GET_COUNTER@@@ timestamp=9223372036854775807, value=\x00\x00\x00\x04
row-1:@@@GET_COUNTER@@@ timestamp=9223372036854775807, value=\x00\x00\x00\x04
3 row(s) in 0.0200 seconds
hbase(main):009:0>
*/