org.cloudgraph.hbase.mutation.Update Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cloudgraph-hbase Show documentation
Show all versions of cloudgraph-hbase Show documentation
CloudGraph(tm) is a suite of Service Data Object (SDO) 2.1 services designed for relational and big-table style "cloud" databases, such as HBase and others.
/**
* 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.mutation;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cloudgraph.config.CloudGraphConfig;
import org.cloudgraph.hbase.io.DistributedWriter;
import org.cloudgraph.hbase.io.RowWriter;
import org.cloudgraph.hbase.io.TableWriter;
import org.cloudgraph.hbase.service.HBaseDataConverter;
import org.cloudgraph.hbase.service.ServiceContext;
import org.cloudgraph.state.GraphState;
import org.cloudgraph.state.GraphState.Edge;
import org.cloudgraph.store.service.GraphServiceException;
import org.plasma.sdo.PlasmaDataObject;
import org.plasma.sdo.PlasmaEdge;
import org.plasma.sdo.PlasmaNode;
import org.plasma.sdo.PlasmaProperty;
import org.plasma.sdo.PlasmaSetting;
import org.plasma.sdo.PlasmaType;
import org.plasma.sdo.access.RequiredPropertyException;
import org.plasma.sdo.core.CoreConstants;
import org.plasma.sdo.core.CoreDataObject;
import org.plasma.sdo.core.NullValue;
import org.plasma.sdo.core.SnapshotMap;
import org.plasma.sdo.profile.KeyType;
import commonj.sdo.ChangeSummary.Setting;
import commonj.sdo.DataGraph;
import commonj.sdo.DataObject;
import commonj.sdo.Property;
public class Update extends DefaultMutation implements Collector {
private static Log log = LogFactory.getLog(Update.class);
public Update(ServiceContext context, SnapshotMap snapshotMap, String username) {
super(context, snapshotMap, username);
}
@Override
public void collect(DataGraph dataGraph, PlasmaDataObject dataObject,
DistributedWriter graphWriter,
TableWriter tableWriter,
RowWriter rowWriter)
throws IllegalAccessException, IOException
{
PlasmaType type = (PlasmaType)dataObject.getType();
// FIXME: get rid of cast - define instance properties in 'base type'
Timestamp snapshotDate = (Timestamp)((CoreDataObject)dataObject).getValue(CoreConstants.PROPERTY_NAME_SNAPSHOT_TIMESTAMP);
if (snapshotDate == null)
throw new RequiredPropertyException("instance property '" + CoreConstants.PROPERTY_NAME_SNAPSHOT_TIMESTAMP
+ "' is required to update entity '"
+ type.getURI() + "#" + type.getName() + "'");
if (log.isDebugEnabled())
log.debug(dataObject + " timestamp: " + String.valueOf(snapshotDate));
checkLock(dataObject, type, snapshotDate);
updateOptimistic(dataObject, type, rowWriter);
List settings = dataGraph.getChangeSummary().getOldValues(dataObject);
for (Setting setting: settings) // for every changed value
{
PlasmaProperty property = (PlasmaProperty)setting.getProperty();
if (property.isKey(KeyType.primary))
continue; // cannot be modified on an update
if (property.getConcurrent() != null)
continue; // processed above
if (property.isReadOnly())
throw new IllegalAccessException("attempt to modify read-only property, "
+ property);
Object dataValue = dataObject.get(property);
if (dataValue != null)
if (log.isDebugEnabled())
log.debug("updating " + property.toString());
else
if (log.isDebugEnabled())
log.debug("removing " + property.toString());
byte[] valueBytes = null;
if (!property.getType().isDataType()) {
if (!property.isMany()) {
valueBytes = this.collectSingular(graphWriter, tableWriter, rowWriter,
dataObject, setting, property, dataValue);
}
else {
valueBytes = this.collectMulti(graphWriter, tableWriter, rowWriter,
dataObject, setting, property, dataValue);
}
}
else {
// FIXME: research best way to encode multiple
// primitives as bytes
if (dataValue != null)
valueBytes = HBaseDataConverter.INSTANCE.toBytes(
property, dataValue);
}
if (valueBytes != null) {
this.updateCell(rowWriter, dataObject,
property, valueBytes);
}
else {
this.deleteCell(rowWriter, dataObject,
property);
}
}
}
private byte[] collectSingular(DistributedWriter graphWriter,
TableWriter tableWriter, RowWriter rowWriter,
PlasmaDataObject dataObject,
Setting setting, PlasmaProperty property, Object value) throws IOException
{
byte[] valueBytes = null;
// get old value setting/value - can be List or single data-object
Object oldValue = setting.getValue();
PlasmaNode dataNode = (PlasmaNode)dataObject;
List edges = dataNode.getEdges(property);
// remove old value if exists from graph state
if (!(oldValue instanceof NullValue)) {
if (!(oldValue instanceof List)) {
DataObject oldOpposite = (DataObject)oldValue;
rowWriter.getGraphState().removeSequence(oldOpposite);
boolean typeBound = CloudGraphConfig.getInstance().findTable(
((PlasmaType)oldOpposite.getType()).getQualifiedName()) != null;
// FIXME: if old opposite is a duplicate of current, new row key is removed
// and never re-added and graph assembly thinks its an internal edge
if (typeBound)
rowWriter.getGraphState().removeRowKey(oldOpposite);
}
else
throw new GraphServiceException("unexpected List as old value for property, "
+ property.toString());
}
// if has a new value
if (value != null) {
// add the new value into graph state
this.addRowKeys(dataObject, dataNode, property, edges, graphWriter,
tableWriter, rowWriter);
List stateEdges = this.findUpdateEdges(dataNode, property,
edges, graphWriter, rowWriter);
rowWriter.getGraphState().addEdges(dataNode, stateEdges);
// Create a formatted column value
// for this edge.
String valueString = rowWriter.getGraphState().marshalEdges(
dataNode, stateEdges);
valueBytes = valueString.getBytes(GraphState.charset);
if (log.isDebugEnabled())
log.debug("saving edges (singular): " + valueString);
}
return valueBytes;
}
private byte[] collectMulti(DistributedWriter graphWriter,
TableWriter tableWriter, RowWriter rowWriter,
PlasmaDataObject dataObject,
Setting setting, PlasmaProperty property, Object value) throws IOException
{
byte[] valueBytes = null;
// get old value setting/value - can be List or single data-object
Object oldValue = setting.getValue();
PlasmaNode dataNode = (PlasmaNode)dataObject;
List edges = dataNode.getEdges(property);
// get old edges from change summary
HashMap oldEdgeMap = getOldEdgeMap(
oldValue, property);
// add the new plasma edge values into graph state
this.addRowKeys(dataObject, dataNode, property, edges, graphWriter,
tableWriter, rowWriter);
List updateEdges = this.findUpdateEdges(dataNode, property,
edges, graphWriter, rowWriter);
rowWriter.getGraphState().addEdges(dataNode, updateEdges);
// convert to state edge map to compare w/existing
Edge[] updatedEdges = rowWriter.getGraphState().createEdges(dataNode, updateEdges);
Map updatedEdgeMap = new HashMap();
for (int i = 0; i < updatedEdges.length; i++)
updatedEdgeMap.put(updatedEdges[i].getUuid(), updatedEdges[i]);
// fetch the existing edges from data store and marshall as edges
byte[] existingValue = rowWriter.fetchColumnValue(dataObject, property);
Edge[] existingEdges = null;
if (existingValue != null && existingValue.length > 0)
existingEdges = rowWriter.getGraphState().unmarshalEdges(existingValue);
// merge
if (log.isDebugEnabled()) {
log.debug("merging existing: " + toString(existingEdges)
+ " updated: " + toString(updatedEdges)
+ " old: " + toString(oldEdgeMap));
}
List list = new ArrayList();
for (Edge updated : updatedEdges)
list.add(updated);
if (existingEdges != null)
for (Edge existing : existingEdges) {
// Only add existing edge if NOT found in updated in graph and change summary
if (!updatedEdgeMap.containsKey(existing.getUuid())) {
DataObject oldDataObject = oldEdgeMap.get(existing.getUuid());
if (oldDataObject == null) {
if (log.isDebugEnabled())
log.debug("adding existing: " + existing);
list.add(existing);
}
else { // edge is obsolete - move to history
if (log.isDebugEnabled())
log.debug("archiving existing: " + existing);
rowWriter.getGraphState().removeSequence(oldDataObject);
boolean typeBound = CloudGraphConfig.getInstance().findTable(
((PlasmaType)oldDataObject.getType()).getQualifiedName()) != null;
if (typeBound)
rowWriter.getGraphState().removeRowKey(oldDataObject);
}
} // else added it already above
}
Edge[] resultEdges = new Edge[list.size()];
list.toArray(resultEdges);
String valueString = rowWriter.getGraphState().marshalEdges(resultEdges);
valueBytes = valueString.getBytes(GraphState.charset);
if (log.isDebugEnabled()) {
log.debug("saving edges (multi): " + valueString);
for (Edge e : resultEdges) {
log.debug("saving edge: " + e);
rowWriter.getGraphState().getUUID(e.getType(), e.getId()); // ensure it exists
}
}
return valueBytes;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy