Search in sources :

Example 1 with IndexTransaction

use of com.thinkaurelius.titan.diskstorage.indexing.IndexTransaction in project titan by thinkaurelius.

the class StandardTitanGraph method prepareCommit.

public ModificationSummary prepareCommit(final Collection<InternalRelation> addedRelations, final Collection<InternalRelation> deletedRelations, final Predicate<InternalRelation> filter, final BackendTransaction mutator, final StandardTitanTx tx, final boolean acquireLocks) throws BackendException {
    ListMultimap<Long, InternalRelation> mutations = ArrayListMultimap.create();
    ListMultimap<InternalVertex, InternalRelation> mutatedProperties = ArrayListMultimap.create();
    List<IndexSerializer.IndexUpdate> indexUpdates = Lists.newArrayList();
    //1) Collect deleted edges and their index updates and acquire edge locks
    for (InternalRelation del : Iterables.filter(deletedRelations, filter)) {
        Preconditions.checkArgument(del.isRemoved());
        for (int pos = 0; pos < del.getLen(); pos++) {
            InternalVertex vertex = del.getVertex(pos);
            if (pos == 0 || !del.isLoop()) {
                if (del.isProperty())
                    mutatedProperties.put(vertex, del);
                mutations.put(vertex.longId(), del);
            }
            if (acquireLock(del, pos, acquireLocks)) {
                Entry entry = edgeSerializer.writeRelation(del, pos, tx);
                mutator.acquireEdgeLock(idManager.getKey(vertex.longId()), entry);
            }
        }
        indexUpdates.addAll(indexSerializer.getIndexUpdates(del));
    }
    //2) Collect added edges and their index updates and acquire edge locks
    for (InternalRelation add : Iterables.filter(addedRelations, filter)) {
        Preconditions.checkArgument(add.isNew());
        for (int pos = 0; pos < add.getLen(); pos++) {
            InternalVertex vertex = add.getVertex(pos);
            if (pos == 0 || !add.isLoop()) {
                if (add.isProperty())
                    mutatedProperties.put(vertex, add);
                mutations.put(vertex.longId(), add);
            }
            if (!vertex.isNew() && acquireLock(add, pos, acquireLocks)) {
                Entry entry = edgeSerializer.writeRelation(add, pos, tx);
                mutator.acquireEdgeLock(idManager.getKey(vertex.longId()), entry.getColumn());
            }
        }
        indexUpdates.addAll(indexSerializer.getIndexUpdates(add));
    }
    //3) Collect all index update for vertices
    for (InternalVertex v : mutatedProperties.keySet()) {
        indexUpdates.addAll(indexSerializer.getIndexUpdates(v, mutatedProperties.get(v)));
    }
    //4) Acquire index locks (deletions first)
    for (IndexSerializer.IndexUpdate update : indexUpdates) {
        if (!update.isCompositeIndex() || !update.isDeletion())
            continue;
        CompositeIndexType iIndex = (CompositeIndexType) update.getIndex();
        if (acquireLock(iIndex, acquireLocks)) {
            mutator.acquireIndexLock((StaticBuffer) update.getKey(), (Entry) update.getEntry());
        }
    }
    for (IndexSerializer.IndexUpdate update : indexUpdates) {
        if (!update.isCompositeIndex() || !update.isAddition())
            continue;
        CompositeIndexType iIndex = (CompositeIndexType) update.getIndex();
        if (acquireLock(iIndex, acquireLocks)) {
            mutator.acquireIndexLock((StaticBuffer) update.getKey(), ((Entry) update.getEntry()).getColumn());
        }
    }
    //5) Add relation mutations
    for (Long vertexid : mutations.keySet()) {
        Preconditions.checkArgument(vertexid > 0, "Vertex has no id: %s", vertexid);
        List<InternalRelation> edges = mutations.get(vertexid);
        List<Entry> additions = new ArrayList<Entry>(edges.size());
        List<Entry> deletions = new ArrayList<Entry>(Math.max(10, edges.size() / 10));
        for (InternalRelation edge : edges) {
            InternalRelationType baseType = (InternalRelationType) edge.getType();
            assert baseType.getBaseType() == null;
            for (InternalRelationType type : baseType.getRelationIndexes()) {
                if (type.getStatus() == SchemaStatus.DISABLED)
                    continue;
                for (int pos = 0; pos < edge.getArity(); pos++) {
                    if (!type.isUnidirected(Direction.BOTH) && !type.isUnidirected(EdgeDirection.fromPosition(pos)))
                        //Directionality is not covered
                        continue;
                    if (edge.getVertex(pos).longId() == vertexid) {
                        StaticArrayEntry entry = edgeSerializer.writeRelation(edge, type, pos, tx);
                        if (edge.isRemoved()) {
                            deletions.add(entry);
                        } else {
                            Preconditions.checkArgument(edge.isNew());
                            int ttl = getTTL(edge);
                            if (ttl > 0) {
                                entry.setMetaData(EntryMetaData.TTL, ttl);
                            }
                            additions.add(entry);
                        }
                    }
                }
            }
        }
        StaticBuffer vertexKey = idManager.getKey(vertexid);
        mutator.mutateEdges(vertexKey, additions, deletions);
    }
    //6) Add index updates
    boolean has2iMods = false;
    for (IndexSerializer.IndexUpdate indexUpdate : indexUpdates) {
        assert indexUpdate.isAddition() || indexUpdate.isDeletion();
        if (indexUpdate.isCompositeIndex()) {
            IndexSerializer.IndexUpdate<StaticBuffer, Entry> update = indexUpdate;
            if (update.isAddition())
                mutator.mutateIndex(update.getKey(), Lists.newArrayList(update.getEntry()), KCVSCache.NO_DELETIONS);
            else
                mutator.mutateIndex(update.getKey(), KeyColumnValueStore.NO_ADDITIONS, Lists.newArrayList(update.getEntry()));
        } else {
            IndexSerializer.IndexUpdate<String, IndexEntry> update = indexUpdate;
            has2iMods = true;
            IndexTransaction itx = mutator.getIndexTransaction(update.getIndex().getBackingIndexName());
            String indexStore = ((MixedIndexType) update.getIndex()).getStoreName();
            if (update.isAddition())
                itx.add(indexStore, update.getKey(), update.getEntry(), update.getElement().isNew());
            else
                itx.delete(indexStore, update.getKey(), update.getEntry().field, update.getEntry().value, update.getElement().isRemoved());
        }
    }
    return new ModificationSummary(!mutations.isEmpty(), has2iMods);
}
Also used : LongArrayList(com.carrotsearch.hppc.LongArrayList) IndexTransaction(com.thinkaurelius.titan.diskstorage.indexing.IndexTransaction) IndexEntry(com.thinkaurelius.titan.diskstorage.indexing.IndexEntry) InternalRelation(com.thinkaurelius.titan.graphdb.internal.InternalRelation) StaticArrayEntry(com.thinkaurelius.titan.diskstorage.util.StaticArrayEntry) StaticArrayEntry(com.thinkaurelius.titan.diskstorage.util.StaticArrayEntry) IndexEntry(com.thinkaurelius.titan.diskstorage.indexing.IndexEntry) MixedIndexType(com.thinkaurelius.titan.graphdb.types.MixedIndexType) AtomicLong(java.util.concurrent.atomic.AtomicLong) InternalVertex(com.thinkaurelius.titan.graphdb.internal.InternalVertex) CompositeIndexType(com.thinkaurelius.titan.graphdb.types.CompositeIndexType) InternalRelationType(com.thinkaurelius.titan.graphdb.internal.InternalRelationType)

Example 2 with IndexTransaction

use of com.thinkaurelius.titan.diskstorage.indexing.IndexTransaction in project titan by thinkaurelius.

the class BackendTransaction method getIndexTransaction.

public IndexTransaction getIndexTransaction(String index) {
    Preconditions.checkArgument(StringUtils.isNotBlank(index));
    IndexTransaction itx = indexTx.get(index);
    Preconditions.checkNotNull(itx, "Unknown index: " + index);
    return itx;
}
Also used : IndexTransaction(com.thinkaurelius.titan.diskstorage.indexing.IndexTransaction)

Example 3 with IndexTransaction

use of com.thinkaurelius.titan.diskstorage.indexing.IndexTransaction in project titan by thinkaurelius.

the class BackendTransaction method rollback.

/**
     * Rolls back all transactions and makes sure that this does not get cut short
     * by exceptions. If exceptions occur, the storage exception takes priority on re-throw.
     * @throws BackendException
     */
@Override
public void rollback() throws BackendException {
    Throwable excep = null;
    for (IndexTransaction itx : indexTx.values()) {
        try {
            itx.rollback();
        } catch (Throwable e) {
            excep = e;
        }
    }
    storeTx.rollback();
    if (excep != null) {
        //throw any encountered index transaction rollback exceptions
        if (excep instanceof BackendException)
            throw (BackendException) excep;
        else
            throw new PermanentBackendException("Unexpected exception", excep);
    }
}
Also used : IndexTransaction(com.thinkaurelius.titan.diskstorage.indexing.IndexTransaction)

Example 4 with IndexTransaction

use of com.thinkaurelius.titan.diskstorage.indexing.IndexTransaction in project titan by thinkaurelius.

the class StandardTransactionLogProcessor method fixSecondaryFailure.

private void fixSecondaryFailure(final StandardTransactionId txId, final TxEntry entry) {
    logRecoveryMsg("Attempting to repair partially failed transaction [%s]", txId);
    if (entry.entry == null) {
        logRecoveryMsg("Trying to repair expired or unpersisted transaction [%s] (Ignore in startup)", txId);
        return;
    }
    boolean userLogFailure = true;
    boolean secIndexFailure = true;
    final Predicate<String> isFailedIndex;
    final TransactionLogHeader.Entry commitEntry = entry.entry;
    final TransactionLogHeader.SecondaryFailures secFail = entry.failures;
    if (secFail != null) {
        userLogFailure = secFail.userLogFailure;
        secIndexFailure = !secFail.failedIndexes.isEmpty();
        isFailedIndex = new Predicate<String>() {

            @Override
            public boolean apply(@Nullable String s) {
                return secFail.failedIndexes.contains(s);
            }
        };
    } else {
        isFailedIndex = Predicates.alwaysTrue();
    }
    // I) Restore external indexes
    if (secIndexFailure) {
        //1) Collect all elements (vertices and relations) and the indexes for which they need to be restored
        final SetMultimap<String, IndexRestore> indexRestores = HashMultimap.create();
        BackendOperation.execute(new Callable<Boolean>() {

            @Override
            public Boolean call() throws Exception {
                StandardTitanTx tx = (StandardTitanTx) graph.newTransaction();
                try {
                    for (TransactionLogHeader.Modification modification : commitEntry.getContentAsModifications(serializer)) {
                        InternalRelation rel = ModificationDeserializer.parseRelation(modification, tx);
                        //Collect affected vertex indexes
                        for (MixedIndexType index : getMixedIndexes(rel.getType())) {
                            if (index.getElement() == ElementCategory.VERTEX && isFailedIndex.apply(index.getBackingIndexName())) {
                                assert rel.isProperty();
                                indexRestores.put(index.getBackingIndexName(), new IndexRestore(rel.getVertex(0).longId(), ElementCategory.VERTEX, getIndexId(index)));
                            }
                        }
                        //See if relation itself is affected
                        for (RelationType relType : rel.getPropertyKeysDirect()) {
                            for (MixedIndexType index : getMixedIndexes(relType)) {
                                if (index.getElement().isInstance(rel) && isFailedIndex.apply(index.getBackingIndexName())) {
                                    assert rel.id() instanceof RelationIdentifier;
                                    indexRestores.put(index.getBackingIndexName(), new IndexRestore(rel.id(), ElementCategory.getByClazz(rel.getClass()), getIndexId(index)));
                                }
                            }
                        }
                    }
                } finally {
                    if (tx.isOpen())
                        tx.rollback();
                }
                return true;
            }
        }, readTime);
        //2) Restore elements per backing index
        for (final String indexName : indexRestores.keySet()) {
            final StandardTitanTx tx = (StandardTitanTx) graph.newTransaction();
            try {
                BackendTransaction btx = tx.getTxHandle();
                final IndexTransaction indexTx = btx.getIndexTransaction(indexName);
                BackendOperation.execute(new Callable<Boolean>() {

                    @Override
                    public Boolean call() throws Exception {
                        Map<String, Map<String, List<IndexEntry>>> restoredDocs = Maps.newHashMap();
                        for (IndexRestore restore : indexRestores.get(indexName)) {
                            TitanSchemaVertex indexV = (TitanSchemaVertex) tx.getVertex(restore.indexId);
                            MixedIndexType index = (MixedIndexType) indexV.asIndexType();
                            TitanElement element = restore.retrieve(tx);
                            if (element != null) {
                                graph.getIndexSerializer().reindexElement(element, index, restoredDocs);
                            } else {
                                //Element is deleted
                                graph.getIndexSerializer().removeElement(restore.elementId, index, restoredDocs);
                            }
                        }
                        indexTx.restore(restoredDocs);
                        indexTx.commit();
                        return true;
                    }

                    @Override
                    public String toString() {
                        return "IndexMutation";
                    }
                }, persistenceTime);
            } finally {
                if (tx.isOpen())
                    tx.rollback();
            }
        }
    }
    // II) Restore log messages
    final String logTxIdentifier = (String) commitEntry.getMetadata().get(LogTxMeta.LOG_ID);
    if (userLogFailure && logTxIdentifier != null) {
        TransactionLogHeader txHeader = new TransactionLogHeader(txCounter.incrementAndGet(), times.getTime(), times);
        final StaticBuffer userLogContent = txHeader.serializeUserLog(serializer, commitEntry, txId);
        BackendOperation.execute(new Callable<Boolean>() {

            @Override
            public Boolean call() throws Exception {
                final Log userLog = graph.getBackend().getUserLog(logTxIdentifier);
                Future<Message> env = userLog.add(userLogContent);
                if (env.isDone()) {
                    env.get();
                }
                return true;
            }
        }, persistenceTime);
    }
}
Also used : IndexTransaction(com.thinkaurelius.titan.diskstorage.indexing.IndexTransaction) InternalRelation(com.thinkaurelius.titan.graphdb.internal.InternalRelation) InternalRelationType(com.thinkaurelius.titan.graphdb.internal.InternalRelationType) RelationType(com.thinkaurelius.titan.core.RelationType) TitanElement(com.thinkaurelius.titan.core.TitanElement) List(java.util.List) TransactionLogHeader(com.thinkaurelius.titan.graphdb.database.log.TransactionLogHeader) MixedIndexType(com.thinkaurelius.titan.graphdb.types.MixedIndexType) TitanSchemaVertex(com.thinkaurelius.titan.graphdb.types.vertices.TitanSchemaVertex) RelationIdentifier(com.thinkaurelius.titan.graphdb.relations.RelationIdentifier) StandardTitanTx(com.thinkaurelius.titan.graphdb.transaction.StandardTitanTx) TitanException(com.thinkaurelius.titan.core.TitanException) ExecutionException(java.util.concurrent.ExecutionException) Future(java.util.concurrent.Future) Map(java.util.Map)

Example 5 with IndexTransaction

use of com.thinkaurelius.titan.diskstorage.indexing.IndexTransaction in project titan by thinkaurelius.

the class BackendTransaction method getIndexTransactionHandle.

public IndexTransaction getIndexTransactionHandle(String index) {
    Preconditions.checkArgument(StringUtils.isNotBlank(index));
    IndexTransaction itx = indexTx.get(index);
    Preconditions.checkNotNull(itx, "Unknown index: " + index);
    return itx;
}
Also used : IndexTransaction(com.thinkaurelius.titan.diskstorage.indexing.IndexTransaction)

Aggregations

IndexTransaction (com.thinkaurelius.titan.diskstorage.indexing.IndexTransaction)5 InternalRelation (com.thinkaurelius.titan.graphdb.internal.InternalRelation)2 InternalRelationType (com.thinkaurelius.titan.graphdb.internal.InternalRelationType)2 MixedIndexType (com.thinkaurelius.titan.graphdb.types.MixedIndexType)2 LongArrayList (com.carrotsearch.hppc.LongArrayList)1 RelationType (com.thinkaurelius.titan.core.RelationType)1 TitanElement (com.thinkaurelius.titan.core.TitanElement)1 TitanException (com.thinkaurelius.titan.core.TitanException)1 IndexEntry (com.thinkaurelius.titan.diskstorage.indexing.IndexEntry)1 StaticArrayEntry (com.thinkaurelius.titan.diskstorage.util.StaticArrayEntry)1 TransactionLogHeader (com.thinkaurelius.titan.graphdb.database.log.TransactionLogHeader)1 InternalVertex (com.thinkaurelius.titan.graphdb.internal.InternalVertex)1 RelationIdentifier (com.thinkaurelius.titan.graphdb.relations.RelationIdentifier)1 StandardTitanTx (com.thinkaurelius.titan.graphdb.transaction.StandardTitanTx)1 CompositeIndexType (com.thinkaurelius.titan.graphdb.types.CompositeIndexType)1 TitanSchemaVertex (com.thinkaurelius.titan.graphdb.types.vertices.TitanSchemaVertex)1 List (java.util.List)1 Map (java.util.Map)1 ExecutionException (java.util.concurrent.ExecutionException)1 Future (java.util.concurrent.Future)1