package eu.fbk.knowledgestore.datastore.hbase.utils;
import static eu.fbk.knowledgestore.datastore.hbase.utils.HBaseConstants.HBASE_REGION_MEMSTORE_FLUSH_SIZE;
import static eu.fbk.knowledgestore.datastore.hbase.utils.HBaseConstants.HBASE_REGION_NRESERVATION_BLOCKS;
import static eu.fbk.knowledgestore.datastore.hbase.utils.HBaseConstants.OMID_REGION_MEMSTORE_FLUSH_SIZE_OPT;
import static eu.fbk.knowledgestore.datastore.hbase.utils.HBaseConstants.OMID_REGION_NRESERVATION_BLOCKS_OPT;
import static eu.fbk.knowledgestore.datastore.hbase.utils.HBaseConstants.OMID_TSO_DEFAULT_HOST_OPT;
import static eu.fbk.knowledgestore.datastore.hbase.utils.HBaseConstants.OMID_TSO_DEFAULT_PORT_OPT;
import static eu.fbk.knowledgestore.datastore.hbase.utils.HBaseConstants.OMID_TSO_HOST;
import static eu.fbk.knowledgestore.datastore.hbase.utils.HBaseConstants.OMID_TSO_PORT;
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 javax.annotation.Nullable;
import com.yahoo.omid.transaction.RollbackException;
import com.yahoo.omid.transaction.TTable;
import com.yahoo.omid.transaction.Transaction;
import com.yahoo.omid.transaction.TransactionException;
import com.yahoo.omid.transaction.TransactionManager;
import org.apache.hadoop.hbase.client.Delete;
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.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.util.Bytes;
import org.openrdf.model.URI;
import eu.fbk.knowledgestore.data.Record;
import eu.fbk.knowledgestore.data.Stream;
import eu.fbk.knowledgestore.data.XPath;
import eu.fbk.knowledgestore.datastore.hbase.HBaseScanIterator;
import eu.fbk.knowledgestore.runtime.DataCorruptedException;
/**
* Implements HBase operations using Yahoo!'s Omid.
*/
public class OmidHBaseUtils extends AbstractHBaseUtils {
/** Transaction Manager used inside Yahoo!'s OMID. */
private static TransactionManager tranManager;
/** Transaction to be started. */
private Transaction t1;
/** The map tableName -> table handle */
private static Map<String, TTable> tableNameHandleMap = new HashMap<String, TTable>();
/**
* Constructor.
*
* @param properties
* the configuration properties
*/
public OmidHBaseUtils(final Properties properties) {
// setting basic configuration inside parent class.
super(properties);
getHbcfg().setInt(
HBASE_REGION_MEMSTORE_FLUSH_SIZE,
Integer.parseInt(properties.getProperty(HBASE_REGION_MEMSTORE_FLUSH_SIZE, ""
+ OMID_REGION_MEMSTORE_FLUSH_SIZE_OPT)));
getHbcfg().setInt(
HBASE_REGION_NRESERVATION_BLOCKS,
Integer.parseInt(properties.getProperty(HBASE_REGION_NRESERVATION_BLOCKS, ""
+ OMID_REGION_NRESERVATION_BLOCKS_OPT)));
getHbcfg().set(OMID_TSO_HOST,
properties.getProperty(OMID_TSO_HOST, OMID_TSO_DEFAULT_HOST_OPT));
getHbcfg().setInt(
OMID_TSO_PORT,
Integer.parseInt(properties.getProperty(OMID_TSO_PORT, ""
+ OMID_TSO_DEFAULT_PORT_OPT)));
// Creating transaction manager
try {
tranManager = new TransactionManager(this.getHbcfg());
} catch (IOException e) {
logger.error("Error trying to create a TransactionManager of OMID.");
logger.error(e.getMessage());
}
}
/**
* Commits work done.
*/
@Override
public void commit() throws DataCorruptedException, IOException, IllegalStateException{
try {
tranManager.commit(t1);
} catch (RollbackException e) {
rollback();
throw new IOException("Error trying to commit transaction.", e);
} catch (TransactionException e) {
rollback();
throw new IOException("Error trying to commit transaction.", e);
}
}
/**
* Rollbacks work done.
*/
@Override
public void rollback() throws DataCorruptedException, IOException, IllegalStateException{
try {
tranManager.rollback(t1);
} catch (Exception e) {
throw new DataCorruptedException("Error trying to rollback a Transaction.", e);
}
}
/**
* Gets a handle of a specific table.
* @param tableName of the table to be accessed.
* @return HTable of the table found.
*/
@Override
public Object getTable(String tableName) {
logger.debug("OMID Begin of getTable for " + tableName);
TTable table = tableNameHandleMap.get(tableName);
if (table != null) {
logger.debug("OMIDE Found a cached handle for table " + tableName);
return table;
}
try {
table = new TTable(this.getHbcfg(), tableName);
} catch (IOException e) {
logger.error("OMID Error trying to get a TransactionTable of OMID.");
logger.error(e.getMessage());
}
tableNameHandleMap.put(tableName, table);
logger.debug("OMID Cached a handle of table: " + tableName);
return table;
}
@Override
public void processPut(Record record, String tabName,
String famName, String quaName) {
logger.debug("OMID Begin processPut(" + record + ", " + tabName + ")");
TTable tTable = (TTable) getTable(tabName);
Put op = null;
try {
op = createPut(record, tabName, famName, quaName);
tTable.put(t1, op);
//TODO rollback is there is an exception
} catch (IllegalArgumentException e) {
//TODO propagate exceptions
logger.error("Error while attempting to perform operations at HBaseDataTransactions.");
logger.error(e.getMessage());
} catch (IOException e) {
//TODO propagate exceptions
logger.error("Error while attempting to perform operations at HBaseDataTransactions.");
logger.error(e.getMessage());
}
}
@Override
public void begin() {
try {
t1 = tranManager.begin();
} catch (TransactionException e) {
logger.error("Error while attempting to perform operations at HBaseDataTransactions.");
logger.error(e.getMessage());
}
}
@Override
public void processDelete(URI id, String tabName,
String famName, String quaName) {
logger.debug("OMID Begin processDelete(" + id + ", " + tabName + ")");
TTable tTable = (TTable) getTable(tabName);
Delete op = null;
try {
op = createDelete(id, tabName);
tTable.delete(t1, op);
} catch (IllegalArgumentException e) {
logger.error("Error while attempting to perform operations at HBaseDataTransactions.");
logger.error(e.getMessage());
} 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("OMID Begin of get(" + tableName + ", " + id + ")");
TTable tTable = (TTable) getTable(tableName);
Record resGotten = null;
if (tTable != null) {
// Resource's Key
Get get = new Get(Bytes.toBytes(id.toString())).setMaxVersions(1);
Result rs = tTable.get(t1, 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("OMID Begin of get(" + tableName + ", " + ids + ")");
TTable tTable = (TTable)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())));
}
// OMID does support the usage of a list of gets
Result[] results = tTable.get(t1, gets);
for (Result res : results) {
final byte[] bytes = res.value();
if (bytes != null) {
resGotten.add((Record) serializer.fromBytes(bytes));
}
}
return resGotten;
}
@Override
public List<Object> checkForErrors(Object[] objs) {
return new ArrayList<Object>();
}
/**
* Gets a number of record of tableName matching condition
*
* @param tableName
* to scan
* @param condition
* to match
* @param scan
* to scan
* @throws IOException
*/
@Override
public long count(final String tableName, final String familyName,
@Nullable final XPath condition) throws IOException {
logger.debug("OMID Begin count");
// VERY INEFFICIENT: to be improved!
final Stream<Record> cur = Stream.create(new HBaseScanIterator(this, tableName,
familyName, condition, null, getServerFilterFlag()));
try {
return cur.count();
} finally {
cur.close();
}
}
/**
* 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("OMID Begin of getScanner(" + tableName + ", " + scan + ")");
TTable tTable = (TTable)getTable(tableName);
ResultScanner resScanner = null;
try {
resScanner = tTable.getScanner(t1, scan);
} catch (IOException e) {
logger.error("Error while trying to obtain a ResultScanner: " + tableName);
logger.error(e.getMessage());
}
return resScanner;
}
}