private List<Entry> appendResults( ByteBuffer key, ByteBuffer columnStart, ByteBuffer columnEnd, List<Entry> entries, LimitTracker limit, TransactionHandle txh) { if (limit.limitExhausted()) return null; List<Entry> results = null; for (int readAttempt = 0; readAttempt < maxReadRetryAttempts; readAttempt++) { try { results = edgeStore.getSlice(key, columnStart, columnEnd, limit.getLimit(), txh); break; } catch (StorageException e) { if (e instanceof TemporaryStorageException) { if (readAttempt < maxReadRetryAttempts - 1) temporaryStorageException(e); else throw readException(e, maxReadRetryAttempts); } else throw readException(e); } } limit.retrieved(results.size()); if (entries == null) return results; else { entries.addAll(results); return entries; } }
@Override public long[] indexRetrieval(Object key, TitanKey pt, InternalTitanTransaction tx) { Preconditions.checkArgument( pt.isSimple(), "Currently, only simple properties are supported for index retrieval"); Preconditions.checkArgument( pt.hasIndex(), "Cannot retrieve for given property key - it does not have an index"); long[] vertices = null; Preconditions.checkArgument( pt.getDataType().isInstance(key), "Specified object is incompatible with property data type [" + pt.getName() + "]"); for (int readAttempt = 0; readAttempt < maxReadRetryAttempts; readAttempt++) { try { if (pt.isUnique()) { ByteBuffer value = propertyIndex.get(getIndexKey(key), getKeyedIndexColumn(pt), tx.getTxHandle()); if (value != null) { vertices = new long[1]; vertices[0] = VariableLong.readPositive(value); } } else { ByteBuffer startColumn = VariableLong.positiveByteBuffer(pt.getID()); List<Entry> entries = propertyIndex.getSlice( getIndexKey(key), startColumn, ByteBufferUtil.nextBiggerBuffer(startColumn), tx.getTxHandle()); vertices = new long[entries.size()]; int i = 0; for (Entry ent : entries) { vertices[i++] = VariableLong.readPositive(ent.getValue()); } } break; } catch (StorageException e) { if (e instanceof TemporaryStorageException) { if (readAttempt < maxReadRetryAttempts - 1) temporaryStorageException(e); else throw readException(e, maxReadRetryAttempts); } else throw readException(e); } } if (vertices == null) return new long[0]; else return vertices; }
@Override public boolean containsVertexID(long id, InternalTitanTransaction tx) { log.trace("Checking node existence for {}", id); for (int readAttempt = 0; readAttempt < maxReadRetryAttempts; readAttempt++) { try { return edgeStore.containsKey(IDHandler.getKey(id), tx.getTxHandle()); } catch (StorageException e) { if (e instanceof TemporaryStorageException) { if (readAttempt < maxReadRetryAttempts - 1) temporaryStorageException(e); else throw readException(e, maxReadRetryAttempts); } else throw readException(e); } } throw new AssertionError("Illegal program state"); }
@Override public RecordIterator<Long> getVertexIDs(final InternalTitanTransaction tx) { if (!(edgeStore instanceof ScanKeyColumnValueStore)) throw new UnsupportedOperationException( "The configured storage backend does not support global graph operations - use Faunus instead"); for (int readAttempt = 0; readAttempt < maxReadRetryAttempts; readAttempt++) { try { final RecordIterator<ByteBuffer> keyiter = ((ScanKeyColumnValueStore) edgeStore).getKeys(tx.getTxHandle()); return new RecordIterator<Long>() { @Override public boolean hasNext() throws StorageException { return keyiter.hasNext(); } @Override public Long next() throws StorageException { return IDHandler.getKeyID(keyiter.next()); } @Override public void close() throws StorageException { keyiter.close(); } }; } catch (StorageException e) { if (e instanceof TemporaryStorageException) { if (readAttempt < maxReadRetryAttempts - 1) temporaryStorageException(e); else throw readException(e, maxReadRetryAttempts); } else throw readException(e); } } throw new AssertionError("Illegal program state"); }
@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); } } } }