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

org.cloudgraph.hbase.graph.DistributedAssembler 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.graph;

import java.io.IOException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.util.Bytes;
import org.cloudgraph.common.CloudGraphConstants;
import org.cloudgraph.common.concurrent.GraphMetricVisitor;
import org.cloudgraph.hbase.io.DistributedReader;
import org.cloudgraph.hbase.io.RowReader;
import org.cloudgraph.hbase.io.TableReader;
import org.cloudgraph.state.GraphState;
import org.cloudgraph.state.GraphState.Edge;
import org.cloudgraph.store.service.GraphServiceException;
import org.plasma.query.collector.Selection;
import org.plasma.sdo.PlasmaDataObject;
import org.plasma.sdo.PlasmaProperty;
import org.plasma.sdo.PlasmaType;
import org.plasma.sdo.core.CoreConstants;
import org.plasma.sdo.core.CoreDataObject;
import org.plasma.sdo.core.CoreNode;

import commonj.sdo.Property;

/**
 * Supports the assembly of a directed data graph which may span multiple
 * HBase tables and/or rows by maintaining a stack of
 * row readers annotated with graph "level" and other information. 
 * This allows a specific row reader to be determined for any data object within a graph
 * based entirely or in part on its level within the graph. 
 * This is essential for data object types which are not 
 * configured as root types within any table, and yet a specific
 * row reader must be determined. 
 * 
 * @see org.cloudgraph.hbase.io.DistributedReader
 * @see org.cloudgraph.hbase.io.TableReader
 * @see org.cloudgraph.hbase.io.RowReader
 * @author Scott Cinnamond
 * @since 0.5.1
 */
public abstract class DistributedAssembler extends DefaultAssembler 
    implements HBaseGraphAssembler
{
    private static Log log = LogFactory.getLog(DistributedAssembler.class);

	protected DistributedReader distributedReader;

	/**
	 * Constructor. 
	 * @param rootType the distributed graph root type
	 * @param selection the selection collector
	 * @param distributedReader the distributed reader
	 * @param snapshotDate the query snapshot date
	 */
	public DistributedAssembler(PlasmaType rootType,
			Selection selection,
			DistributedReader distributedReader,
			Timestamp snapshotDate) {
		super(rootType, selection, 
			distributedReader.getRootTableReader(),
			snapshotDate);
		this.distributedReader = distributedReader;
	}

	/**
     * Recursively re-constitutes a data graph distributed across multiple
     * HBase tables and/or rows, starting with the given HBase client result row. 
     * 

* To retrieve the graph use {@link GraphAssembler#getDataGraph()}. * a map of selected SDO properties. Properties are mapped by * selected types required in the result graph. *

* @param resultRow the HBase client * result (row). */ @Override public void assemble(Result resultRow) { this.root = createRoot(resultRow); RowReader rowReader = this.rootTableReader.createRowReader( this.root, resultRow); this.distributedReader.mapRowReader(this.root, rowReader); // FIXME: are there not supposed to be instance // properties on data object? Why must we // go into core object. CoreDataObject root = (CoreDataObject)this.root; root.getValueObject().put( CloudGraphConstants.ROW_KEY, rowReader.getRowKey()); long before = System.currentTimeMillis(); try { assemble(this.root, null, null, rowReader, 0); } catch (IOException e) { throw new GraphServiceException(e); } long after = System.currentTimeMillis(); root.getValueObject().put( CloudGraphConstants.GRAPH_ASSEMBLY_TIME, Long.valueOf(after - before)); GraphMetricVisitor visitor = new GraphMetricVisitor(); this.root.accept(visitor); root.getValueObject().put( CloudGraphConstants.GRAPH_NODE_COUNT, Long.valueOf(visitor.getCount())); root.getValueObject().put( CloudGraphConstants.GRAPH_DEPTH, Long.valueOf(visitor.getDepth())); root.getValueObject().put( CloudGraphConstants.GRAPH_THREAD_COUNT, Long.valueOf(visitor.getThreadCount())); List tables = new ArrayList(); for (TableReader tableReader : this.distributedReader.getTableReaders()) { tables.add(tableReader.getTableName()); } root.getValueObject().put( CloudGraphConstants.GRAPH_TABLE_NAMES, tables); } /** * Populates the given data object target, recursively fetching * data for and linking related data objects which make up the * resulting directed graph. * @param target the current data object target * @param source the source or parent data object * @param sourceProperty the source (reference) property * @param rowReader the current row reader * @param level the current graph level * @throws IOException if a remote or network exception occurs. */ protected abstract void assemble(PlasmaDataObject target, PlasmaDataObject source, PlasmaProperty sourceProperty, RowReader rowReader, int level) throws IOException; protected void assembleEdge(PlasmaDataObject target, PlasmaProperty prop, Edge edge, PlasmaDataObject child, RowReader childRowReader, int level) throws IOException { this.distributedReader.mapRowReader(child, childRowReader); if (log.isDebugEnabled()) log.debug("traverse: (" + prop.getName() + ") " + String.valueOf(edge.getId())); assemble(child, target, prop, childRowReader, level+1); } protected UUID reconstituteUUID(Result result, TableReader tableReader) { // need to reconstruct the original graph, so need original UUID byte[] rootUuid = result.getValue(Bytes.toBytes( tableReader.getTableConfig().getDataColumnFamilyName()), Bytes.toBytes(GraphState.ROOT_UUID_COLUMN_NAME)); if (rootUuid == null) throw new GraphServiceException("expected column: " + tableReader.getTableConfig().getDataColumnFamilyName() + ":" + GraphState.ROOT_UUID_COLUMN_NAME); String uuidStr = null; uuidStr = new String(rootUuid, tableReader.getTableConfig().getCharset()); return UUID.fromString(uuidStr); } /** * Creates contained child data object with the same type * as the given containment property or of a specific sub-type * as determined by querying the graph state, as represented in the * given state Edge. * * @param target the container data object * @param prop the containment property * @param edge the state edge * @return the new child data object * @throws IOException */ protected PlasmaDataObject createChild(PlasmaDataObject target, PlasmaProperty prop, Edge edge) throws IOException { PlasmaType edgeType = edge.getType(); if (log.isDebugEnabled()) log.debug("creating data object (" + edge.getUuid()+ ") type: " + edgeType.toString()); PlasmaDataObject child = (PlasmaDataObject)target.createDataObject(prop, edge.getType()); child.resetUUID(UUID.fromString(edge.getUuid())); CoreNode childNode = ((CoreNode)child); childNode.setValue(CoreConstants.PROPERTY_NAME_SNAPSHOT_TIMESTAMP, snapshotDate); childNode.getValueObject().put( CloudGraphConstants.GRAPH_NODE_THREAD_NAME, Thread.currentThread().getName()); return child; } /** * Creates contained child data object with the same type * as the given containment property or of a specific sub-type * as determined by querying the graph state, as represented in the * given state Edge, but using the given external row root UUID * @param target the container data object * @param prop the containment property * @param edge the state edge * @param rootUuid the external row root UUID * @return the new child data object * @throws IOException */ protected PlasmaDataObject createChild(PlasmaDataObject target, PlasmaProperty prop, Edge edge, UUID rootUuid) throws IOException { PlasmaType edgeType = edge.getType(); if (log.isDebugEnabled()) log.debug("creating data object (" + rootUuid.toString() + ") type: " + edgeType.toString()); PlasmaDataObject child = (PlasmaDataObject)target.createDataObject(prop, edge.getType()); child.resetUUID(rootUuid); CoreNode childNode = ((CoreNode)child); childNode.setValue(CoreConstants.PROPERTY_NAME_SNAPSHOT_TIMESTAMP, snapshotDate); childNode.getValueObject().put( CloudGraphConstants.GRAPH_NODE_THREAD_NAME, Thread.currentThread().getName()); return child; } /** * Peeks at the first edge and determines whether * an external edge collection * @param edges the state edges * @param rowReader the reader * @return whether * an external edge collection * @throws IOException */ protected boolean isExternal(Edge[] edges, RowReader rowReader) throws IOException { if (edges.length > 0) { return rowReader.getGraphState().findRowKey( edges[0].getUuid()) != null; } else { return false; } } protected Set getProperties(PlasmaDataObject target, PlasmaDataObject source, PlasmaProperty sourceProperty, int level) { Set props; if (sourceProperty != null) { //props = this.selection.getInheritedProperties(target.getType(), sourceProperty, level); props = this.selection.getInheritedProperties(target.getType(), level); if (props.size() == 0) { if (log.isDebugEnabled()) log.debug("no properties for " + target.toString() + " at level: " + level + " for source edge, " + sourceProperty.toString() + " - aborting traversal"); } } else { props = this.selection.getInheritedProperties(target.getType(), level); if (props.size() == 0) { if (log.isDebugEnabled()) log.debug("no properties for " + target.toString() + " at level: " + level + " - aborting traversal"); } } return props; } /** * Resets the assembler. */ @Override public void clear() { this.root = null; this.distributedReader.clear(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy