private void writeInlineEdge( DataOutput out, InternalRelation edge, TitanType type, boolean writeEdgeType) { assert type.isSimple(); assert writeEdgeType || type.isEdgeLabel() || (type.isPropertyKey() && !hasGenericDataType((TitanKey) type)); if (edge == null) { assert !writeEdgeType; if (type.isPropertyKey()) { out.writeObject(null); } else { assert type.isEdgeLabel(); VariableLong.writePositive(out, 0); } } else { if (writeEdgeType) { IDHandler.writeInlineEdgeType(out, type.getID(), idManager); } if (edge.isProperty()) { Object attribute = ((TitanProperty) edge).getAttribute(); if (hasGenericDataType((TitanKey) type)) out.writeClassAndObject(attribute); else out.writeObject(attribute); } else { assert edge.isUnidirected() && edge.isEdge(); VariableLong.writePositive(out, edge.getVertex(1).getID()); } } }
private <N extends InternalTitanVertex> void persist( ListMultimap<N, InternalRelation> mutatedEdges, Map<TitanType, TypeSignature> signatures, InternalTitanTransaction tx, StoreMutator mutator) throws StorageException { assert mutatedEdges != null && !mutatedEdges.isEmpty(); Collection<N> vertices = mutatedEdges.keySet(); // if (sortNodes) { // List<N> sortedvertices = new ArrayList<N>(vertices); // Collections.sort(sortedvertices, new Comparator<N>(){ // // @Override // public int compare(N o1, N o2) { // assert o1.getID()!=o2.getID(); // if (o1.getID()<o2.getID()) return -1; // else return 1; // } // // }); // vertices=sortedvertices; // } for (N node : vertices) { List<InternalRelation> edges = mutatedEdges.get(node); List<Entry> additions = new ArrayList<Entry>(edges.size()); List<ByteBuffer> deletions = new ArrayList<ByteBuffer>(Math.max(10, edges.size() / 10)); List<TitanProperty> properties = new ArrayList<TitanProperty>(); for (InternalRelation edge : edges) { if (edge.isRemoved()) { if (edge.isProperty()) { deleteIndexEntry((TitanProperty) edge, mutator); } deletions.add(getEntry(tx, edge, node, signatures, true).getColumn()); } else { assert edge.isNew(); if (edge.isProperty()) properties.add((TitanProperty) edge); additions.add(getEntry(tx, edge, node, signatures)); } } mutator.mutateEdges(IDHandler.getKey(node.getID()), additions, deletions); // Persist property index for retrieval for (TitanProperty prop : properties) { addIndexEntry(prop, mutator); } } }
private void assignIDs(Collection<InternalRelation> addedEdges, InternalTitanTransaction tx) { for (InternalRelation edge : addedEdges) { if (edge.isRemoved()) continue; if (edge.hasID()) continue; for (int i = 0; i < edge.getArity(); i++) { InternalTitanVertex node = edge.getVertex(i); if (!node.hasID()) { assert node.isNew(); assignID(node); } } assert !edge.hasID(); assignID(edge); } }
private void writeInlineEdge(DataOutput out, InternalRelation edge) { assert edge != null; writeInlineEdge(out, edge, edge.getType(), true); }
private Entry getEntry( InternalTitanTransaction tx, InternalRelation edge, InternalTitanVertex perspective, Map<TitanType, TypeSignature> signatures, boolean columnOnly) { TitanType et = edge.getType(); long etid = et.getID(); int dirID; if (edge.isProperty()) { dirID = 0; } else if (edge.getVertex(0).equals(perspective)) { // Out TitanRelation assert edge.isDirected() || edge.isUnidirected(); dirID = 2; } else { // In TitanRelation assert !edge.isUnidirected() && edge.getVertex(1).equals(perspective); dirID = 3; } int etIDLength = IDHandler.edgeTypeLength(etid, idManager); ByteBuffer column = null, value = null; if (et.isSimple()) { if (et.isFunctional()) { column = ByteBuffer.allocate(etIDLength); IDHandler.writeEdgeType(column, etid, dirID, idManager); } else { column = ByteBuffer.allocate(etIDLength + VariableLong.positiveLength(edge.getID())); IDHandler.writeEdgeType(column, etid, dirID, idManager); VariableLong.writePositive(column, edge.getID()); } column.flip(); if (!columnOnly) { if (edge.isEdge()) { long nodeIDDiff = ((TitanEdge) edge).getOtherVertex(perspective).getID() - perspective.getID(); int nodeIDDiffLength = VariableLong.length(nodeIDDiff); if (et.isFunctional()) { value = ByteBuffer.allocate(nodeIDDiffLength + VariableLong.positiveLength(edge.getID())); VariableLong.write(value, nodeIDDiff); VariableLong.writePositive(value, edge.getID()); } else { value = ByteBuffer.allocate(nodeIDDiffLength); VariableLong.write(value, nodeIDDiff); } value.flip(); } else { assert edge.isProperty(); DataOutput out = serializer.getDataOutput(defaultOutputCapacity, true); // Write object writeAttribute(out, (TitanProperty) edge); if (et.isFunctional()) { VariableLong.writePositive(out, edge.getID()); } value = out.getByteBuffer(); } } } else { TypeSignature ets = getSignature(tx, et, signatures); InternalRelation[] keys = new InternalRelation[ets.keyLength()], values = new InternalRelation[ets.valueLength()]; List<InternalRelation> rest = new ArrayList<InternalRelation>(); ets.sort(edge.getRelations(SimpleAtomicQuery.queryAll(edge), false), keys, values, rest); DataOutput out = serializer.getDataOutput(defaultOutputCapacity, true); IDHandler.writeEdgeType(out, etid, dirID, idManager); for (int i = 0; i < keys.length; i++) writeInlineEdge(out, keys[i], ets.getKeyType(i)); if (!et.isFunctional()) { VariableLong.writePositive(out, edge.getID()); } column = out.getByteBuffer(); if (!columnOnly) { out = serializer.getDataOutput(defaultOutputCapacity, true); if (edge.isEdge()) { long nodeIDDiff = ((TitanEdge) edge).getOtherVertex(perspective).getID() - perspective.getID(); VariableLong.write(out, nodeIDDiff); } else { assert edge.isProperty(); writeAttribute(out, (TitanProperty) edge); } if (et.isFunctional()) { assert edge.isEdge(); VariableLong.writePositive(out, edge.getID()); } for (int i = 0; i < values.length; i++) writeInlineEdge(out, values[i], ets.getValueType(i)); for (InternalRelation v : rest) writeInlineEdge(out, v); value = out.getByteBuffer(); } } return new Entry(column, value); }
@Override public void save( final Collection<InternalRelation> addedRelations, final Collection<InternalRelation> deletedRelations, final InternalTitanTransaction tx) throws StorageException { // Setup log.debug( "Saving transaction. Added {}, removed {}", addedRelations.size(), deletedRelations.size()); final Map<TitanType, TypeSignature> signatures = new HashMap<TitanType, TypeSignature>(); final TransactionHandle txh = tx.getTxHandle(); final StoreMutator mutator = getStoreMutator(txh); final boolean acquireLocks = tx.getTxConfiguration().hasAcquireLocks(); // 1. Assign TitanVertex IDs assignIDs(addedRelations, tx); for (int saveAttempt = 0; saveAttempt < maxWriteRetryAttempts; saveAttempt++) { // while (true) { //Indefinite loop, broken if no exception occurs, otherwise retried // or failed immediately try { // 2. Collect deleted edges ListMultimap<InternalTitanVertex, InternalRelation> mutations = ArrayListMultimap.create(); if (deletedRelations != null && !deletedRelations.isEmpty()) { for (InternalRelation del : deletedRelations) { assert del.isRemoved(); for (int pos = 0; pos < del.getArity(); pos++) { InternalTitanVertex node = del.getVertex(pos); if (pos == 0 || !del.isUnidirected()) { mutations.put(node, del); } if (pos == 0 && acquireLocks && del.getType().isFunctional() && ((InternalTitanType) del.getType()).isFunctionalLocking()) { Entry entry = getEntry(tx, del, node, signatures); mutator.acquireEdgeLock( IDHandler.getKey(node.getID()), entry.getColumn(), entry.getValue()); } } if (acquireLocks && del.isProperty()) { lockKeyedProperty((TitanProperty) del, mutator); } } } ListMultimap<InternalTitanType, InternalRelation> simpleEdgeTypes = null; ListMultimap<InternalTitanType, InternalRelation> otherEdgeTypes = null; // 3. Sort Added Edges for (InternalRelation edge : addedRelations) { if (edge.isRemoved()) continue; assert edge.isNew(); TitanType et = edge.getType(); // Give special treatment to edge type definitions if (SystemTypeManager.prepersistedSystemTypes.contains(et)) { assert edge.getVertex(0) instanceof InternalTitanType; InternalTitanType node = (InternalTitanType) edge.getVertex(0); assert node.hasID(); if (node.isSimple()) { if (simpleEdgeTypes == null) simpleEdgeTypes = ArrayListMultimap.create(); simpleEdgeTypes.put(node, edge); } else { if (otherEdgeTypes == null) otherEdgeTypes = ArrayListMultimap.create(); otherEdgeTypes.put(node, edge); } } else { // STANDARD TitanRelation assert (edge.getArity() == 1 && edge.isProperty()) || (edge.getArity() == 2 && edge.isEdge()); for (int pos = 0; pos < edge.getArity(); pos++) { InternalTitanVertex node = edge.getVertex(pos); assert node.hasID(); if (pos == 0 || !edge.isUnidirected()) { mutations.put(node, edge); } if (pos == 0 && acquireLocks && edge.getType().isFunctional() && !node.isNew() && ((InternalTitanType) edge.getType()).isFunctionalLocking()) { Entry entry = getEntry(tx, edge, node, signatures, true); mutator.acquireEdgeLock(IDHandler.getKey(node.getID()), entry.getColumn(), null); } } } if (acquireLocks && edge.isProperty()) { lockKeyedProperty((TitanProperty) edge, mutator); } } // 3. Persist if (simpleEdgeTypes != null) persist(simpleEdgeTypes, signatures, tx, mutator); if (otherEdgeTypes != null) persist(otherEdgeTypes, signatures, tx, mutator); mutator.flush(); // Commit saved EdgeTypes to TypeManager if (simpleEdgeTypes != null) commitEdgeTypes(simpleEdgeTypes.keySet()); if (otherEdgeTypes != null) commitEdgeTypes(otherEdgeTypes.keySet()); if (!mutations.isEmpty()) persist(mutations, signatures, tx, mutator); mutator.flush(); // Successfully completed - return to break out of loop break; } catch (Throwable e) { if (e instanceof TemporaryStorageException) { if (saveAttempt < maxWriteRetryAttempts - 1) temporaryStorageException(e); else throw new PermanentStorageException( "Tried committing " + maxWriteRetryAttempts + " times on temporary exception without success", e); } else if (e instanceof StorageException) { throw (StorageException) e; } else { throw new PermanentStorageException( "Unidentified exception occurred during persistence", e); } } } }