org.cloudgraph.hbase.service.GraphDispatcher Maven / Gradle / Ivy
/**
* CloudGraph Community Edition (CE) License
*
* This is a community release of CloudGraph, a dual-license suite of
* Service Data Object (SDO) 2.1 services designed for relational and
* big-table style "cloud" databases, such as HBase and others.
* This particular copy of the software is released under the
* version 2 of the GNU General Public License. CloudGraph was developed by
* TerraMeta Software, Inc.
*
* Copyright (c) 2013, TerraMeta Software, Inc. All rights reserved.
*
* General License information can be found below.
*
* This distribution may include materials developed by third
* parties. For license and attribution notices for these
* materials, please refer to the documentation that accompanies
* this distribution (see the "Licenses for Third-Party Components"
* appendix) or view the online documentation at
* .
*/
package org.cloudgraph.hbase.service;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.client.Mutation;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Row;
import org.apache.hadoop.hbase.util.Bytes;
import org.cloudgraph.hbase.io.TableWriter;
import org.cloudgraph.hbase.mutation.GraphMutationCollector;
import org.cloudgraph.store.service.DuplicateRowException;
import org.cloudgraph.store.service.GraphServiceException;
import org.plasma.sdo.access.DataAccessException;
import org.plasma.sdo.access.DataGraphDispatcher;
import org.plasma.sdo.core.SnapshotMap;
import commonj.sdo.DataGraph;
/**
* Propagates changes to a {@link commonj.sdo.DataGraph data graph} including
* any number of creates (inserts), modifications (updates) and deletes
* across one or more HBase table rows.
*
* For new (created) data graphs, a row key {org.cloudgraph.hbase.key.HBaseRowKeyFactory factory}
* is used to create a new composite HBase row key. The row key generation is
* driven by a configured CloudGraph row key {@link org.cloudgraph.config.RowKeyModel
* model} for a specific HTable {@link org.cloudgraph.config.Table configuration}.
* A minimal set of {@link org.cloudgraph.state.GraphState state} information is
* persisted with each new data graph.
*
*
* For data graphs with any other combination of changes, e.g.
* data object modifications, deletes, etc... an existing HBase
* row key is fetched using an HBase Get
* operation.
*
* @see org.cloudgraph.hbase.io.DistributedWriter
* @see org.cloudgraph.store.key.GraphRowKeyFactory
* @see org.cloudgraph.store.key.GraphColumnKeyFactory
* @see org.cloudgraph.state.GraphState
*
* @author Scott Cinnamond
* @since 0.5
*/
public class GraphDispatcher extends GraphMutationCollector
implements DataGraphDispatcher
{
private static Log log = LogFactory.getLog(GraphDispatcher.class);
public GraphDispatcher(ServiceContext context, SnapshotMap snapshotMap,
String username) {
super(context, snapshotMap, username);
}
public void close()
{
this.context.close();
}
/**
* Propagates changes to the given data graph including
* any number of creates (inserts), modifications (updates) and deletes
* to a single or multiple HBase tables and table rows.
* @return a map of internally managed concurrency property values and data
* store generated keys.
* @throws DuplicateRowException if for a new data graph, the generated row key
* already exists in the HBase table configured .
*/
public SnapshotMap commit(DataGraph dataGraph) {
if (username == null || username.length() == 0)
throw new IllegalArgumentException("expected username param not, '" + String.valueOf(username) + "'");
else
if (log.isDebugEnabled()) {
log.debug("current user is '" + username + "'");
}
try {
//FIXME: if an exception happens here we don't have table writers to close
// as required by the 1.0.0 HBase client API. Will cause resource bleed
Map> mutations = collectChanges(dataGraph);
TableWriter[] tableWriters = new TableWriter[mutations.keySet().size()];
mutations.keySet().toArray(tableWriters);
try {
this.writeChanges(tableWriters, mutations, this.username);
}
finally {
for (TableWriter tableWriter : tableWriters)
tableWriter.close();
}
return snapshotMap;
}
catch(IOException | IllegalAccessException e) {
throw new DataAccessException(e);
}
}
/**
* Propagates changes to the given array of data graphs including
* any number of creates (inserts), modifications (updates) and deletes
* to a single or multiple HBase tables and table rows. The given graphs may be heterogeneous, with
* different root data objects any 'shape' or depth.
* @return a map of internally managed concurrency property values and data
* store generated keys.
* @throws DuplicateRowException if for a new data graph, the generated row key
* already exists in the HBase table configured .
*/
public SnapshotMap commit(DataGraph[] dataGraphs) {
if (username == null || username.length() == 0)
throw new IllegalArgumentException("expected username param not, '" + String.valueOf(username) + "'");
else
if (log.isDebugEnabled()) {
log.debug("current user is '" + username + "'");
}
try {
// Note: multiple data graphs may share one or more data objects and here we force
// a write for each graph so the state will be saved and re-read from data store
// such that any common data object(s) state will be current.
for (DataGraph dataGraph : dataGraphs) {
Map> mutations = collectChanges(dataGraph);
TableWriter[] tableWriters = new TableWriter[mutations.keySet().size()];
mutations.keySet().toArray(tableWriters);
try {
this.writeChanges(tableWriters, mutations, this.username);
}
finally {
for (TableWriter tableWriter : tableWriters)
tableWriter.close();
}
}
return snapshotMap;
}
catch(IOException | IllegalAccessException e) {
throw new DataAccessException(e);
}
}
private void writeChanges(TableWriter[] tableWriters, Map> mutations, String jobName) throws IOException
{
for (TableWriter tableWriter : tableWriters) {
List tableMutations = mutations.get(tableWriter);
if (log.isDebugEnabled())
log.debug("commiting "+tableMutations.size()+" mutations to table: " + tableWriter.getTableConfig().getName());
if (log.isDebugEnabled()) {
for (Row row : tableMutations) {
log.debug("commiting "+row.getClass().getSimpleName()+" mutation to table: " + tableWriter.getTableConfig().getName());
debugRowValues(row);
}
}
Object[] results = new Object[tableMutations.size()];
try {
tableWriter.getTable().batch(tableMutations, results);
} catch (InterruptedException e) {
throw new GraphServiceException(e);
}
for (int i = 0; i < results.length; i++) {
if (results[i] == null) {
log.error("batch action (" + i + ") for job '"+jobName+"' failed with null result");
}
else {
if (log.isDebugEnabled())
log.debug("batch action (" + i + ") for job '"+jobName+"' succeeded with "+
String.valueOf(results[i]) + " result");
}
}
//tableWriter.getTable().flushCommits();
//FIXME: find what happened to flush
}
}
private void debugRowValues(Row row)
{
if (row instanceof Mutation) {
Mutation mutation = (Mutation)row;
NavigableMap> map = mutation.getFamilyCellMap();
StringBuilder buf = new StringBuilder();
Iterator iter = map.keySet().iterator();
buf.append("[");
int i = 0;
while (iter.hasNext()) {
if (i > 0)
buf.append(", ");
byte[] family = iter.next();
List list = map.get(family);
for (Cell cell : list) {
buf.append(Bytes.toString(family));
buf.append(":");
byte[] qual = CellUtil.cloneQualifier(cell);
buf.append(Bytes.toString(qual));
buf.append("=");
byte[] value = CellUtil.cloneValue(cell);
buf.append(Bytes.toString(value));
}
}
buf.append("]");
log.debug("values: "+buf.toString());
}
}
}
|
© 2015 - 2025 Weber Informatics LLC | Privacy Policy