package eu.fbk.knowledgestore.datastore.hbase.utils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import com.google.common.base.Preconditions;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.client.coprocessor.AggregationClient;
import org.apache.hadoop.hbase.util.Bytes;
import org.openrdf.model.URI;
import eu.fbk.knowledgestore.data.Record;
import eu.fbk.knowledgestore.data.XPath;
public class HBaseUtils extends AbstractHBaseUtils {
/** The map tableName -> table handle */
private static Map<String, HTable> tableNameHandleMap = new HashMap<String, HTable>();
public HBaseUtils(final Properties properties) {
super(properties);
}
/**
* Gets a handle of a specific table.
* @param tableName of the table to be accessed.
* @return HTable of the table found.
*/
@Override
public HTable getTable(String tableName) {
logger.debug("NATIVE Begin of getTable for " + tableName);
HTable table = tableNameHandleMap.get(tableName);
if (table != null) {
logger.debug("NATIVE Found a cached handle for table " + tableName);
return table;
}
try {
logger.debug("NATIVE Looking for a handle of table: " + tableName);
HBaseAdmin admin = new HBaseAdmin(this.getHbcfg());
HTableDescriptor[] resources = admin.listTables(tableName);
Preconditions.checkElementIndex(0, resources.length, "no table " + tableName + " found");
admin.close();
table = new HTable(this.getHbcfg(), tableName);
} catch (IOException e) {
logger.error("NATIVE Error while trying to obtain table: " + tableName);
logger.error(e.getMessage());
};
tableNameHandleMap.put(tableName, table);
logger.debug("NATIVE Cached a handle of table: " + tableName);
return table;
}
/**
* Commits work done.
*/
@Override
public void commit() {
}
/**
* Rollbacks work done.
*/
@Override
public void rollback() {
}
/**
* Gets a scanner for a specific table
* @param tableName to get the scanner from
* @param scan for the specific table
* @param conf object to get a hold of an HBase table
*/
@Override
public ResultScanner getScanner(String tableName, Scan scan) {
logger.debug("NATIVE Begin of getScanner(" + tableName + ", " + scan + ")");
HTable tab = (HTable) getTable(tableName);
ResultScanner resScanner = null;
try {
resScanner = tab.getScanner(scan);
} catch (IOException e) {
logger.error("Error while trying to obtain a ResultScanner: " + tableName);
logger.error(e.getMessage());
}
return resScanner;
}
/**
* Process put operations on an HBase table.
*/
@Override
public void processPut(Record record, String tabName,
String famName, String quaName) {
logger.debug("NATIVE Begin processPut(" + record + ", " + tabName + ")");
HTable hTable = getTable(tabName);
try {
Put op = createPut(record, tabName, famName, quaName);
hTable.put(op);
} catch (IOException e) {
logger.error("Error while attempting to perform operations at HBaseDataTransactions.");
logger.error(e.getMessage());
}
}
/**
* Process delete operations on an HBase table.
*/
@Override
public void processDelete(URI id, String tabName,
String famName, String quaName) {
logger.debug("NATIVE Begin processDelete(" + id + ", " + tabName + ")");
HTable hTable = getTable(tabName);
try {
Delete op = createDelete(id, tabName);
hTable.delete(op);
} catch (IOException e) {
logger.error("Error while attempting to perform operations at HBaseDataTransactions.");
logger.error(e.getMessage());
}
}
/**
* Gets a Record based on information passed.
* @param tableName to do the get.
* @param id of the Record needed
* @throws IOException
*/
@Override
public Record get(String tableName, URI id) throws IOException {
logger.debug("NATIVE Begin of get(" + tableName + ", " + id + ")");
HTable selTable = getTable(tableName);
Record resGotten = null;
if (selTable != null) {
// Resource's Key
Get get = new Get(Bytes.toBytes(id.toString()));
Result rs = selTable.get(get);
logger.debug("Value obtained: " + new String(rs.value()));
final AvroSerializer serializer = getSerializer();
resGotten = (Record) serializer.fromBytes(rs.value());
}
return resGotten;
}
@Override
public List<Record> get(String tableName,
List<URI> ids) throws IOException {
logger.debug("NATIVE Begin of get(" + tableName + ", " + ids + ")");
HTable selTable = getTable(tableName);
List<Record> resGotten = new ArrayList<Record> ();
List<Get> gets = new ArrayList<Get> ();
AvroSerializer serializer = getSerializer();
for (URI id : ids) {
gets.add(new Get(Bytes.toBytes(id.toString())));
}
Result[] results = selTable.get(gets);
//TODO check if this is ok
for (Result res : results) {
final byte[] bytes = res.value();
if (bytes != null) {
resGotten.add((Record) serializer.fromBytes(bytes));
}
}
return resGotten;
}
/**
* Creates puts for HBase
* @param record
* @throws IOException
*/
@Override
public Put createPut(Record record, String tableName,
String famName, String quaName) throws IOException {
HTable hTable = getTable(tableName);
Put put = null;
if (hTable != null) {
// Transforming data model record into an Avro record
AvroSerializer serializer = getSerializer();
final byte[] bytes = serializer.toBytes(record);
// Resource's Key
put = new Put(Bytes.toBytes(record.getID().toString()));
// Resource's Value
put.add(Bytes.toBytes(famName), Bytes.toBytes(quaName), bytes);
}
return put;
}
/**
* Creates deletes for HBase tables
* @param record
* @param tableName
* @param conf
* @return
* @throws IOException
*/
@Override
public Delete createDelete(URI id, String tableName) throws IOException {
Delete del = null;
HTable hTable = getTable(tableName);
if (hTable != null) {
del = new Delete(Bytes.toBytes(id.toString()));
}
return del;
}
/**
* Checking for errors after operations have been processed.
* @param objs
* @return
*/
@Override
public List<Object> checkForErrors(Object[] objs) {
List<Object> errors = new ArrayList<Object>();
if (objs != null) {
for (int cont = 0; cont < objs.length; cont ++) {
if (objs[cont] == null) {
logger.debug("A operation could not be performed.");
errors.add(objs[cont]);
}
}
}
return errors;
}
/**
* Gets a number of record of tableName matching condition
* @param tableName the table name
* @param familyName the family
* @param condition to match
* @throws IOException
*/
@Override
public long count(String tableName, String familyName, XPath condition) throws IOException {
logger.debug("NATIVE Begin count");
// clone the current conf
org.apache.hadoop.conf.Configuration customConf = new org.apache.hadoop.conf.Configuration(super.getHbcfg());
// Increase RPC timeout, in case of a slow computation
customConf.setLong("hbase.rpc.timeout", 600000);
// Default is 1, set to a higher value for faster scanner.next(..)
customConf.setLong("hbase.client.scanner.caching", 1000);
/*
System.out.println("HBaseUtils begin of |customConf|");
Configuration.dumpConfiguration(customConf, new PrintWriter(System.out));
System.out.println("\nHBaseUtils end of |customConf|");
*/
AggregationClient agClient = new AggregationClient(customConf);
long rowCount = 0;
byte[] tName = Bytes.toBytes(tableName);
try {
Scan scan = getScan(tableName, familyName);
rowCount = agClient.rowCount(tName, null, scan);
} catch (Throwable e) {
throw new IOException(e.toString());
}
return rowCount;
}
@Override
public void begin() {
}
}