use of com.thinkaurelius.titan.graphdb.internal.InternalType in project titan by thinkaurelius.
the class StandardTitanGraph method commit.
public void commit(final Collection<InternalRelation> addedRelations, final Collection<InternalRelation> deletedRelations, final StandardTitanTx tx) {
// Setup
log.debug("Saving transaction. Added {}, removed {}", addedRelations.size(), deletedRelations.size());
final BackendTransaction mutator = tx.getTxHandle();
final boolean acquireLocks = tx.getConfiguration().hasAcquireLocks();
// 1. Assign TitanVertex IDs
if (!tx.getConfiguration().hasAssignIDsImmediately())
idAssigner.assignIDs(addedRelations);
Callable<List<StaticBuffer>> persist = new Callable<List<StaticBuffer>>() {
@Override
public List<StaticBuffer> call() throws Exception {
// 2. Collect deleted edges
ListMultimap<InternalVertex, InternalRelation> mutations = ArrayListMultimap.create();
if (deletedRelations != null && !deletedRelations.isEmpty()) {
for (InternalRelation del : deletedRelations) {
Preconditions.checkArgument(del.isRemoved());
for (int pos = 0; pos < del.getLen(); pos++) {
InternalVertex vertex = del.getVertex(pos);
if (pos == 0 || !del.isLoop())
mutations.put(vertex, del);
Direction dir = EdgeDirection.fromPosition(pos);
if (acquireLocks && del.getType().isUnique(dir) && ((InternalType) del.getType()).uniqueLock(dir)) {
Entry entry = edgeSerializer.writeRelation(del, pos, tx);
mutator.acquireEdgeLock(IDHandler.getKey(vertex.getID()), entry.getColumn(), entry.getValue());
}
}
// Update Indexes
if (del.isProperty()) {
if (acquireLocks)
indexSerializer.lockKeyedProperty((TitanProperty) del, mutator);
}
}
}
ListMultimap<InternalType, InternalRelation> otherEdgeTypes = ArrayListMultimap.create();
// 3. Sort Added Edges
for (InternalRelation relation : addedRelations) {
Preconditions.checkArgument(relation.isNew());
TitanType type = relation.getType();
// Give special treatment to edge type definitions
if (SystemTypeManager.prepersistedSystemTypes.contains(type)) {
InternalType itype = (InternalType) relation.getVertex(0);
otherEdgeTypes.put(itype, relation);
} else {
// STANDARD TitanRelation
for (int pos = 0; pos < relation.getLen(); pos++) {
InternalVertex vertex = relation.getVertex(pos);
if (pos == 0 || !relation.isLoop())
mutations.put(vertex, relation);
Direction dir = EdgeDirection.fromPosition(pos);
if (acquireLocks && relation.getType().isUnique(dir) && !vertex.isNew() && ((InternalType) relation.getType()).uniqueLock(dir)) {
Entry entry = edgeSerializer.writeRelation(relation, pos, tx);
mutator.acquireEdgeLock(IDHandler.getKey(vertex.getID()), entry.getColumn(), null);
}
}
}
// Update Indexes
if (relation.isProperty()) {
if (acquireLocks)
indexSerializer.lockKeyedProperty((TitanProperty) relation, mutator);
}
}
// 3. Persist
List<StaticBuffer> mutatedVertexKeys = new ArrayList<StaticBuffer>();
if (!otherEdgeTypes.isEmpty()) {
mutatedVertexKeys.addAll(persist(otherEdgeTypes, tx));
mutator.flush();
// Register new keys with indexprovider
for (InternalType itype : otherEdgeTypes.keySet()) {
if (itype.isPropertyKey() && itype.isNew())
indexSerializer.newPropertyKey((TitanKey) itype, mutator);
}
}
if (!mutations.isEmpty())
mutatedVertexKeys.addAll(persist(mutations, tx));
mutator.commit();
return mutatedVertexKeys;
}
@Override
public String toString() {
return "PersistingTransaction";
}
};
List<StaticBuffer> mutatedVertexKeys = BackendOperation.execute(persist, maxWriteRetryAttempts, retryStorageWaitTime);
for (StaticBuffer vertexKey : mutatedVertexKeys) edgeStoreCache.invalidate(vertexKey);
}
use of com.thinkaurelius.titan.graphdb.internal.InternalType in project titan by thinkaurelius.
the class AbstractVertexCentricQueryBuilder method compileSortKeyConstraints.
private static EdgeSerializer.TypedInterval[] compileSortKeyConstraints(InternalType type, StandardTitanTx tx, And<TitanRelation> conditions) {
long[] sortKeys = type.getSortKey();
EdgeSerializer.TypedInterval[] sortKeyConstraints = new EdgeSerializer.TypedInterval[type.getSortKey().length];
for (int i = 0; i < sortKeys.length; i++) {
InternalType pktype = (InternalType) tx.getExistingType(sortKeys[i]);
Interval interval = null;
// First check for equality constraints, since those are the most constraining
for (Iterator<Condition<TitanRelation>> iter = conditions.iterator(); iter.hasNext(); ) {
Condition<TitanRelation> cond = iter.next();
if (cond instanceof PredicateCondition) {
PredicateCondition<TitanType, TitanRelation> atom = (PredicateCondition) cond;
if (atom.getKey().equals(pktype) && atom.getPredicate() == Cmp.EQUAL && interval == null) {
interval = new PointInterval(atom.getValue());
iter.remove();
}
}
}
// and if so, find a bounding interval from the remaining constraints
if (interval == null && pktype.isPropertyKey() && Comparable.class.isAssignableFrom(((TitanKey) pktype).getDataType())) {
ProperInterval pint = new ProperInterval();
for (Iterator<Condition<TitanRelation>> iter = conditions.iterator(); iter.hasNext(); ) {
Condition<TitanRelation> cond = iter.next();
if (cond instanceof PredicateCondition) {
PredicateCondition<TitanType, TitanRelation> atom = (PredicateCondition) cond;
if (atom.getKey().equals(pktype)) {
TitanPredicate predicate = atom.getPredicate();
Object value = atom.getValue();
if (predicate instanceof Cmp) {
switch((Cmp) predicate) {
case NOT_EQUAL:
break;
case LESS_THAN:
if (pint.getEnd() == null || pint.getEnd().compareTo(value) >= 0) {
pint.setEnd((Comparable) value);
pint.setEndInclusive(false);
}
iter.remove();
break;
case LESS_THAN_EQUAL:
if (pint.getEnd() == null || pint.getEnd().compareTo(value) > 0) {
pint.setEnd((Comparable) value);
pint.setEndInclusive(true);
}
iter.remove();
break;
case GREATER_THAN:
if (pint.getStart() == null || pint.getStart().compareTo(value) <= 0) {
pint.setStart((Comparable) value);
pint.setStartInclusive(false);
}
iter.remove();
break;
case GREATER_THAN_EQUAL:
if (pint.getStart() == null || pint.getStart().compareTo(value) < 0) {
pint.setStart((Comparable) value);
pint.setStartInclusive(true);
}
iter.remove();
break;
}
}
}
} else if (cond instanceof Or) {
// Grab a probe so we can investigate what type of or-condition this is and whether it allows us to constrain this sort key
Condition probe = ((Or) cond).get(0);
if (probe instanceof PredicateCondition && ((PredicateCondition) probe).getKey().equals(pktype) && ((PredicateCondition) probe).getPredicate() == Cmp.EQUAL) {
// We make the assumption that this or-condition is a group of equality constraints for the same type (i.e. an unrolled Contain.IN)
// This assumption is enforced by precondition statements below
// TODO: Consider splitting query on sort key with a limited number (<=3) of possible values in or-clause
// Now, we find the smallest and largest value in this group of equality constraints to bound the interval
Comparable smallest = null, largest = null;
for (Condition child : cond.getChildren()) {
assert child instanceof PredicateCondition;
PredicateCondition pc = (PredicateCondition) child;
assert pc.getKey().equals(pktype);
assert pc.getPredicate() == Cmp.EQUAL;
Object v = pc.getValue();
if (smallest == null) {
smallest = (Comparable) v;
largest = (Comparable) v;
} else {
if (smallest.compareTo(v) > 0) {
smallest = (Comparable) v;
} else if (largest.compareTo(v) < 0) {
largest = (Comparable) v;
}
}
}
// due to probing, there must be at least one
assert smallest != null && largest != null;
if (pint.getEnd() == null || pint.getEnd().compareTo(largest) > 0) {
pint.setEnd(largest);
pint.setEndInclusive(true);
}
if (pint.getStart() == null || pint.getStart().compareTo(smallest) < 0) {
pint.setStart(smallest);
pint.setStartInclusive(true);
}
// We cannot remove this condition from remainingConditions, since its not exactly fulfilled (only bounded)
}
}
}
if (pint.isEmpty())
return null;
if (pint.getStart() != null || pint.getEnd() != null)
interval = pint;
}
sortKeyConstraints[i] = new EdgeSerializer.TypedInterval(pktype, interval);
if (interval == null || !interval.isPoint()) {
break;
}
}
return sortKeyConstraints;
}
use of com.thinkaurelius.titan.graphdb.internal.InternalType in project titan by thinkaurelius.
the class EdgeSerializer method parseRelation.
private RelationCache parseRelation(long vertexid, Entry data, boolean parseHeaderOnly, StandardTitanTx tx) {
assert vertexid > 0;
ReadBuffer column = data.getReadColumn();
ReadBuffer value = data.getReadValue();
LongObjectOpenHashMap properties = parseHeaderOnly ? null : new LongObjectOpenHashMap(4);
long[] typeAndDir = IDHandler.readEdgeType(column);
int dirID = (int) typeAndDir[1];
long typeId = typeAndDir[0];
Direction dir;
RelationType rtype;
switch(dirID) {
case PROPERTY_DIR:
dir = Direction.OUT;
rtype = RelationType.PROPERTY;
break;
case EDGE_OUT_DIR:
dir = Direction.OUT;
rtype = RelationType.EDGE;
break;
case EDGE_IN_DIR:
dir = Direction.IN;
rtype = RelationType.EDGE;
break;
default:
throw new IllegalArgumentException("Invalid dirID read from disk: " + dirID);
}
TitanType titanType = tx.getExistingType(typeId);
InternalType def = (InternalType) titanType;
long[] keysig = def.getSortKey();
if (!parseHeaderOnly && !titanType.isUnique(dir)) {
ReadBuffer sortKeyReader = def.getSortOrder() == Order.DESC ? column.invert() : column;
readInlineTypes(keysig, properties, sortKeyReader, tx);
}
long relationIdDiff, vertexIdDiff = 0;
if (titanType.isUnique(dir)) {
if (rtype == RelationType.EDGE)
vertexIdDiff = VariableLong.read(value);
relationIdDiff = VariableLong.read(value);
} else {
// Move position to end to read backwards
column.movePosition(column.length() - column.getPosition() - 1);
relationIdDiff = VariableLong.readBackward(column);
if (rtype == RelationType.EDGE)
vertexIdDiff = VariableLong.readBackward(column);
}
assert relationIdDiff + vertexid > 0;
long relationId = relationIdDiff + vertexid;
Object other;
switch(rtype) {
case EDGE:
Preconditions.checkArgument(titanType.isEdgeLabel());
other = vertexid + vertexIdDiff;
break;
case PROPERTY:
Preconditions.checkArgument(titanType.isPropertyKey());
TitanKey key = ((TitanKey) titanType);
other = hasGenericDataType(key) ? serializer.readClassAndObject(value) : serializer.readObjectNotNull(value, key.getDataType());
break;
default:
throw new AssertionError();
}
assert other != null;
if (!parseHeaderOnly) {
// value signature & sort key if unique
if (titanType.isUnique(dir)) {
readInlineTypes(keysig, properties, value, tx);
}
readInlineTypes(def.getSignature(), properties, value, tx);
// Third: read rest
while (value.hasRemaining()) {
TitanType type = tx.getExistingType(IDHandler.readInlineEdgeType(value));
Object pvalue = readInline(value, type);
assert pvalue != null;
properties.put(type.getID(), pvalue);
}
}
return new RelationCache(dir, typeId, relationId, other, properties);
}
use of com.thinkaurelius.titan.graphdb.internal.InternalType in project titan by thinkaurelius.
the class RelationComparator method compare.
@Override
public int compare(final InternalRelation r1, final InternalRelation r2) {
if (r1.equals(r2))
return 0;
// 0) RelationType
int reltypecompare = (r1.isProperty() ? 1 : 2) - (r2.isProperty() ? 1 : 2);
if (reltypecompare != 0)
return reltypecompare;
// 1) TitanType
InternalType t1 = (InternalType) r1.getType(), t2 = (InternalType) r2.getType();
int typecompare = t1.compareTo(t2);
if (typecompare != 0)
return typecompare;
assert t1.equals(t2);
// 2) Direction
Direction dir1 = null, dir2 = null;
for (int i = 0; i < r1.getLen(); i++) if (r1.getVertex(i).equals(vertex)) {
dir1 = EdgeDirection.fromPosition(i);
break;
}
for (int i = 0; i < r2.getLen(); i++) if (r2.getVertex(i).equals(vertex)) {
dir2 = EdgeDirection.fromPosition(i);
break;
}
// ("Either relation is not incident on vertex [%s]", vertex);
assert dir1 != null && dir2 != null;
int dirCompare = EdgeDirection.position(dir1) - EdgeDirection.position(dir2);
if (dirCompare != 0)
return dirCompare;
// Breakout: If type&direction are the same and the type is unique in the direction it follows that the relations are the same
if (t1.isUnique(dir1))
return 0;
// 3) Compare sort key values
for (long typeid : t1.getSortKey()) {
int keycompare = compareOnKey(r1, r2, typeid, t1.getSortOrder());
if (keycompare != 0)
return keycompare;
}
// 4) Compare property objects or other vertices
if (r1.isProperty()) {
Object o1 = ((TitanProperty) r1).getValue();
Object o2 = ((TitanProperty) r2).getValue();
Preconditions.checkArgument(o1 != null && o2 != null);
if (!o1.equals(o2)) {
int objectcompare = 0;
if (Comparable.class.isAssignableFrom(((TitanKey) t1).getDataType())) {
objectcompare = ((Comparable) o1).compareTo(o2);
} else {
objectcompare = System.identityHashCode(o1) - System.identityHashCode(o2);
}
if (objectcompare != 0)
return objectcompare;
}
} else {
Preconditions.checkArgument(r1.isEdge() && r2.isEdge());
int vertexcompare = r1.getVertex(EdgeDirection.position(dir1.opposite())).compareTo(r2.getVertex(EdgeDirection.position(dir1.opposite())));
if (vertexcompare != 0)
return vertexcompare;
}
// 5)compare relation ids
return r1.compareTo(r2);
}
use of com.thinkaurelius.titan.graphdb.internal.InternalType in project titan by thinkaurelius.
the class AbstractVertexCentricQueryBuilder method constructQuery.
protected BaseVertexCentricQuery constructQuery(RelationType returnType) {
assert returnType != null;
if (limit == 0)
return BaseVertexCentricQuery.emptyQuery();
// Prepare direction
if (returnType == RelationType.PROPERTY) {
if (dir == Direction.IN)
return BaseVertexCentricQuery.emptyQuery();
dir = Direction.OUT;
}
assert getVertexConstraint() == null || returnType == RelationType.EDGE;
// Prepare constraints
And<TitanRelation> conditions = QueryUtil.constraints2QNF(tx, constraints);
if (conditions == null)
return BaseVertexCentricQuery.emptyQuery();
assert limit > 0;
// Don't be smart with query limit adjustments - it just messes up the caching layer and penalizes when appropriate limits are set by the user!
int sliceLimit = limit;
// Construct (optimal) SliceQueries
EdgeSerializer serializer = tx.getEdgeSerializer();
List<BackendQueryHolder<SliceQuery>> queries;
if (!hasTypes()) {
BackendQueryHolder<SliceQuery> query = new BackendQueryHolder<SliceQuery>(serializer.getQuery(returnType), ((dir == Direction.BOTH || (returnType == RelationType.PROPERTY && dir == Direction.OUT)) && !conditions.hasChildren() && includeHidden), true, null);
if (sliceLimit != Query.NO_LIMIT && sliceLimit < Integer.MAX_VALUE / 3) {
// If only one direction is queried, ask for twice the limit from backend since approximately half will be filtered
if (dir != Direction.BOTH && (returnType == RelationType.EDGE || returnType == RelationType.RELATION))
sliceLimit *= 2;
// on properties, add some for the hidden properties on a vertex
if (!includeHidden && (returnType == RelationType.PROPERTY || returnType == RelationType.RELATION))
sliceLimit += 3;
}
query.getBackendQuery().setLimit(computeLimit(conditions, sliceLimit));
queries = ImmutableList.of(query);
// Add remaining conditions that only apply if no type is defined
if (!includeHidden)
conditions.add(new HiddenFilterCondition<TitanRelation>());
conditions.add(returnType);
} else {
Set<TitanType> ts = new HashSet<TitanType>(types.length);
queries = new ArrayList<BackendQueryHolder<SliceQuery>>(types.length + 4);
for (String typeName : types) {
InternalType type = getType(typeName);
if (type != null && (includeHidden || !type.isHidden())) {
ts.add(type);
if (type.isPropertyKey()) {
if (returnType == RelationType.EDGE)
throw new IllegalArgumentException("Querying for edges but including a property key: " + type.getName());
returnType = RelationType.PROPERTY;
}
if (type.isEdgeLabel()) {
if (returnType == RelationType.PROPERTY)
throw new IllegalArgumentException("Querying for properties but including an edge label: " + type.getName());
returnType = RelationType.EDGE;
}
// Construct sort key constraints (if any, and if not direction==Both)
EdgeSerializer.TypedInterval[] sortKeyConstraints = new EdgeSerializer.TypedInterval[type.getSortKey().length];
And<TitanRelation> remainingConditions = conditions;
boolean vertexConstraintApplies = type.getSortKey().length == 0 || conditions.hasChildren();
if (type.getSortKey().length > 0 && conditions.hasChildren()) {
remainingConditions = conditions.clone();
sortKeyConstraints = compileSortKeyConstraints(type, tx, remainingConditions);
// Constraints cannot be matched
if (sortKeyConstraints == null)
continue;
Interval interval;
if (sortKeyConstraints[sortKeyConstraints.length - 1] == null || (interval = sortKeyConstraints[sortKeyConstraints.length - 1].interval) == null || !interval.isPoint()) {
vertexConstraintApplies = false;
}
}
Direction[] dirs = { dir };
EdgeSerializer.VertexConstraint vertexConstraint = getVertexConstraint();
if (dir == Direction.BOTH && (hasSortKeyConstraints(sortKeyConstraints) || (vertexConstraintApplies && vertexConstraint != null))) {
// Split on direction in the presence of effective sort key constraints
dirs = new Direction[] { Direction.OUT, Direction.IN };
}
for (Direction dir : dirs) {
EdgeSerializer.VertexConstraint vertexCon = vertexConstraint;
if (vertexCon == null || !vertexConstraintApplies || type.isUnique(dir))
vertexCon = null;
EdgeSerializer.TypedInterval[] sortConstraints = sortKeyConstraints;
if (hasSortKeyConstraints(sortKeyConstraints) && type.isUnique(dir)) {
sortConstraints = new EdgeSerializer.TypedInterval[type.getSortKey().length];
}
boolean isFitted = !remainingConditions.hasChildren() && vertexConstraint == vertexCon && sortConstraints == sortKeyConstraints;
SliceQuery q = serializer.getQuery(type, dir, sortConstraints, vertexCon);
q.setLimit(computeLimit(remainingConditions, sliceLimit));
queries.add(new BackendQueryHolder<SliceQuery>(q, isFitted, true, null));
}
}
}
if (queries.isEmpty())
return BaseVertexCentricQuery.emptyQuery();
conditions.add(getTypeCondition(ts));
}
return new BaseVertexCentricQuery(QueryUtil.simplifyQNF(conditions), dir, queries, limit);
}
Aggregations