All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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