Search in sources :

Example 16 with ORecordOperation

use of com.orientechnologies.orient.core.db.record.ORecordOperation in project orientdb by orientechnologies.

the class ODistributedTransactionManager method createTxTask.

protected OTxTask createTxTask(final List<ORecordOperation> uResult) {
    final OTxTask txTask = new OTxTask();
    for (ORecordOperation op : uResult) {
        final ORecord record = op.getRecord();
        final OAbstractRecordReplicatedTask task;
        switch(op.type) {
            case ORecordOperation.CREATED:
                task = new OCreateRecordTask(record);
                break;
            case ORecordOperation.UPDATED:
                task = new OUpdateRecordTask(record);
                break;
            case ORecordOperation.DELETED:
                task = new ODeleteRecordTask(record);
                break;
            default:
                continue;
        }
        txTask.add(task);
    }
    return txTask;
}
Also used : ORecordOperation(com.orientechnologies.orient.core.db.record.ORecordOperation) ORecord(com.orientechnologies.orient.core.record.ORecord)

Example 17 with ORecordOperation

use of com.orientechnologies.orient.core.db.record.ORecordOperation in project orientdb by orientechnologies.

the class ODistributedTransactionManager method acquireMultipleRecordLocks.

/**
   * Acquires lock in block by using an optimistic approach with retry & random delay. In case any record is locked, all the lock
   * acquired so far are released before to retry.
   *
   * @throws InterruptedException
   */
protected void acquireMultipleRecordLocks(final OTransaction iTx, final int maxAutoRetry, final int autoRetryDelay, final ODistributedStorageEventListener eventListener, final ODistributedTxContext reqContext) throws InterruptedException {
    final List<ORecordId> recordsToLock = new ArrayList<ORecordId>();
    for (ORecordOperation op : iTx.getAllRecordEntries()) {
        recordsToLock.add((ORecordId) op.record.getIdentity());
    }
    acquireMultipleRecordLocks(this, dManager, localDistributedDatabase, recordsToLock, maxAutoRetry, autoRetryDelay, eventListener, reqContext, -1);
}
Also used : ORecordOperation(com.orientechnologies.orient.core.db.record.ORecordOperation) ORecordId(com.orientechnologies.orient.core.id.ORecordId)

Example 18 with ORecordOperation

use of com.orientechnologies.orient.core.db.record.ORecordOperation in project orientdb by orientechnologies.

the class ODistributedTransactionManager method checkForClusterIds.

protected void checkForClusterIds(final OTransaction iTx, final String localNodeName, final ODistributedConfiguration dbCfg) {
    for (ORecordOperation op : iTx.getAllRecordEntries()) {
        final ORecordId rid = (ORecordId) op.getRecord().getIdentity();
        switch(op.type) {
            case ORecordOperation.CREATED:
                final ORecordId newRid = rid.copy();
                if (rid.getClusterId() < 1) {
                    final String clusterName = ((OTransactionAbstract) iTx).getClusterName(op.getRecord());
                    if (clusterName != null) {
                        newRid.setClusterId(ODatabaseRecordThreadLocal.INSTANCE.get().getClusterIdByName(clusterName));
                        iTx.updateIdentityAfterCommit(rid, newRid);
                    }
                }
                if (storage.checkForCluster(op.getRecord(), localNodeName, dbCfg) != null)
                    iTx.updateIdentityAfterCommit(rid, newRid);
                break;
        }
    }
}
Also used : OTransactionAbstract(com.orientechnologies.orient.core.tx.OTransactionAbstract) ORecordOperation(com.orientechnologies.orient.core.db.record.ORecordOperation) ORecordId(com.orientechnologies.orient.core.id.ORecordId)

Example 19 with ORecordOperation

use of com.orientechnologies.orient.core.db.record.ORecordOperation in project orientdb by orientechnologies.

the class ODistributedTransactionManager method commit.

public List<ORecordOperation> commit(final ODatabaseDocumentTx database, final OTransaction iTx, final Runnable callback, final ODistributedStorageEventListener eventListener) {
    final String localNodeName = dManager.getLocalNodeName();
    try {
        OTransactionInternal.setStatus((OTransactionAbstract) iTx, OTransaction.TXSTATUS.BEGUN);
        final ODistributedConfiguration dbCfg = dManager.getDatabaseConfiguration(storage.getName());
        // CHECK THE LOCAL NODE IS THE OWNER OF THE CLUSTER IDS
        checkForClusterIds(iTx, localNodeName, dbCfg);
        // CREATE UNDO CONTENT FOR DISTRIBUTED 2-PHASE ROLLBACK
        final List<OAbstractRemoteTask> undoTasks = createUndoTasksFromTx(iTx);
        final int maxAutoRetry = OGlobalConfiguration.DISTRIBUTED_CONCURRENT_TX_MAX_AUTORETRY.getValueAsInteger();
        final int autoRetryDelay = OGlobalConfiguration.DISTRIBUTED_CONCURRENT_TX_AUTORETRY_DELAY.getValueAsInteger();
        Boolean executionModeSynch = dbCfg.isExecutionModeSynchronous(null);
        if (executionModeSynch == null)
            executionModeSynch = Boolean.TRUE;
        final boolean finalExecutionModeSynch = executionModeSynch;
        final ODistributedRequestId requestId = new ODistributedRequestId(dManager.getLocalNodeId(), dManager.getNextMessageIdCounter());
        final ODistributedTxContext ctx = localDistributedDatabase.registerTxContext(requestId);
        final AtomicBoolean lockReleased = new AtomicBoolean(true);
        try {
            acquireMultipleRecordLocks(iTx, maxAutoRetry, autoRetryDelay, eventListener, ctx);
            lockReleased.set(false);
            final List<ORecordOperation> uResult = (List<ORecordOperation>) OScenarioThreadLocal.executeAsDistributed(new Callable() {

                @Override
                public Object call() throws Exception {
                    return storage.commit(iTx, callback);
                }
            });
            try {
                localDistributedDatabase.getSyncConfiguration().setLastLSN(localNodeName, ((OLocalPaginatedStorage) storage.getUnderlying()).getLSN(), true);
            } catch (IOException e) {
                ODistributedServerLog.debug(this, dManager != null ? dManager.getLocalNodeName() : "?", null, ODistributedServerLog.DIRECTION.NONE, "Error on updating local LSN configuration for database '%s'", storage.getName());
            }
            // REMOVE THE TX OBJECT FROM DATABASE TO AVOID UND OPERATIONS ARE "LOST IN TRANSACTION"
            database.setDefaultTransactionMode();
            // After commit force the clean of dirty managers due to possible copy and miss clean.
            for (ORecordOperation ent : iTx.getAllRecordEntries()) {
                ORecordInternal.getDirtyManager(ent.getRecord()).clear();
            }
            final Set<String> involvedClusters = getInvolvedClusters(uResult);
            Set<String> nodes = getAvailableNodesButLocal(dbCfg, involvedClusters, localNodeName);
            if (nodes.isEmpty()) {
                // NO FURTHER NODES TO INVOLVE
                executionModeSynch = true;
                return null;
            }
            updateUndoTaskWithCreatedRecords(uResult, undoTasks);
            final OTxTaskResult localResult = createLocalTxResult(uResult);
            final OTxTask txTask = createTxTask(uResult);
            txTask.setLocalUndoTasks(undoTasks);
            try {
                txTask.setLastLSN(((OAbstractPaginatedStorage) storage.getUnderlying()).getLSN());
                OTransactionInternal.setStatus((OTransactionAbstract) iTx, OTransaction.TXSTATUS.COMMITTING);
                if (finalExecutionModeSynch) {
                    // SYNCHRONOUS, AUTO-RETRY IN CASE RECORDS ARE LOCKED
                    ODistributedResponse lastResult = null;
                    for (int retry = 1; retry <= maxAutoRetry; ++retry) {
                        boolean isLastRetry = maxAutoRetry == retry;
                        if (retry > 1) {
                            // REBUILD THE SERVER LIST
                            nodes = getAvailableNodesButLocal(dbCfg, involvedClusters, localNodeName);
                            if (nodes.isEmpty()) {
                                // NO FURTHER NODES TO INVOLVE
                                executionModeSynch = true;
                                return null;
                            }
                            ODistributedServerLog.debug(this, localNodeName, null, ODistributedServerLog.DIRECTION.NONE, "Retrying (%d/%d) transaction reqId=%s...", retry, maxAutoRetry, requestId);
                        }
                        // SYNCHRONOUS CALL: REPLICATE IT
                        lastResult = dManager.sendRequest(storage.getName(), involvedClusters, nodes, txTask, requestId.getMessageId(), EXECUTION_MODE.RESPONSE, localResult, null);
                        if (!processCommitResult(localNodeName, iTx, txTask, involvedClusters, uResult, nodes, autoRetryDelay, lastResult.getRequestId(), lastResult, isLastRetry)) {
                            // RETRY
                            Orient.instance().getProfiler().updateCounter("db." + database.getName() + ".distributedTxRetries", "Number of retries executed in distributed transaction", +1, "db.*.distributedTxRetries");
                            continue;
                        }
                        ODistributedServerLog.debug(this, localNodeName, null, ODistributedServerLog.DIRECTION.NONE, "Distributed transaction succeeded. Tasks: %s", txTask.getTasks());
                        // OK, DISTRIBUTED COMMIT SUCCEED
                        return null;
                    }
                    // ONLY CASE: ODistributedRecordLockedException MORE THAN AUTO-RETRY
                    ODistributedServerLog.debug(this, localNodeName, null, ODistributedServerLog.DIRECTION.NONE, "Distributed transaction retries exceed maximum auto-retries (%d). Task: %s - Tasks: %s", maxAutoRetry, txTask, txTask.getTasks());
                    // ROLLBACK TX
                    storage.executeUndoOnLocalServer(requestId, txTask);
                    sendTxCompleted(localNodeName, involvedClusters, nodes, lastResult.getRequestId(), false, txTask.getPartitionKey());
                    throw (RuntimeException) lastResult.getPayload();
                } else {
                    // ASYNC, MANAGE REPLICATION CALLBACK
                    final OCallable<Void, ODistributedRequestId> unlockCallback = new OCallable<Void, ODistributedRequestId>() {

                        @Override
                        public Void call(final ODistributedRequestId reqId) {
                            // FREE THE CONTEXT
                            if (lockReleased.compareAndSet(false, true)) {
                                localDistributedDatabase.popTxContext(requestId);
                                ctx.destroy();
                            }
                            return null;
                        }
                    };
                    executeAsyncTx(nodes, localResult, involvedClusters, txTask, requestId.getMessageId(), localNodeName, unlockCallback);
                }
            } catch (Throwable e) {
                // UNDO LOCAL TX
                storage.executeUndoOnLocalServer(requestId, txTask);
                executionModeSynch = true;
                if (e instanceof RuntimeException)
                    throw (RuntimeException) e;
                else if (e instanceof InterruptedException)
                    throw OException.wrapException(new ODistributedOperationException("Cannot commit transaction"), e);
                else
                    throw OException.wrapException(new ODistributedException("Cannot commit transaction"), e);
            }
        } catch (RuntimeException e) {
            executionModeSynch = true;
            throw e;
        } catch (InterruptedException e) {
            executionModeSynch = true;
            throw OException.wrapException(new ODistributedOperationException("Cannot commit transaction"), e);
        } catch (Exception e) {
            executionModeSynch = true;
            throw OException.wrapException(new ODistributedException("Cannot commit transaction"), e);
        } finally {
            if (executionModeSynch) {
                if (lockReleased.compareAndSet(false, true)) {
                    localDistributedDatabase.popTxContext(requestId);
                    ctx.destroy();
                }
            }
        }
    } catch (OValidationException e) {
        throw e;
    } catch (ODistributedRecordLockedException e) {
        throw e;
    } catch (OConcurrentCreateException e) {
        // REQUEST A REPAIR OF THE CLUSTER BECAUSE IS NOT ALIGNED
        localDistributedDatabase.getDatabaseRepairer().enqueueRepairCluster(e.getActualRid().getClusterId());
        throw e;
    } catch (OConcurrentModificationException e) {
        localDistributedDatabase.getDatabaseRepairer().enqueueRepairRecord((ORecordId) e.getRid());
        throw e;
    } catch (Exception e) {
        for (ORecordOperation op : iTx.getAllRecordEntries()) {
            if (iTx.hasRecordCreation()) {
                final ORecordId lockEntireCluster = (ORecordId) op.getRID().copy();
                localDistributedDatabase.getDatabaseRepairer().enqueueRepairCluster(lockEntireCluster.getClusterId());
            }
            localDistributedDatabase.getDatabaseRepairer().enqueueRepairRecord((ORecordId) op.getRID());
        }
        storage.handleDistributedException("Cannot route TX operation against distributed node", e);
    }
    return null;
}
Also used : Callable(java.util.concurrent.Callable) OCallable(com.orientechnologies.common.util.OCallable) OCallable(com.orientechnologies.common.util.OCallable) ORecordOperation(com.orientechnologies.orient.core.db.record.ORecordOperation) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) IOException(java.io.IOException) OException(com.orientechnologies.common.exception.OException) ONeedRetryException(com.orientechnologies.common.concur.ONeedRetryException) IOException(java.io.IOException) ORecordId(com.orientechnologies.orient.core.id.ORecordId) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean)

Example 20 with ORecordOperation

use of com.orientechnologies.orient.core.db.record.ORecordOperation in project orientdb by orientechnologies.

the class OTransactionRealAbstract method close.

public void close() {
    super.close();
    for (final ORecordOperation recordOperation : getAllRecordEntries()) {
        final ORecord record = recordOperation.getRecord();
        if (record instanceof ODocument) {
            final ODocument document = (ODocument) record;
            if (document.isDirty()) {
                document.undo();
            }
            changedDocuments.remove(document);
        }
    }
    for (ODocument changedDocument : changedDocuments) {
        changedDocument.undo();
    }
    changedDocuments.clear();
    updatedRids.clear();
    allEntries.clear();
    indexEntries.clear();
    recordIndexOperations.clear();
    newObjectCounter = -2;
    status = TXSTATUS.INVALID;
    database.setDefaultTransactionMode();
    userData.clear();
}
Also used : ORecordOperation(com.orientechnologies.orient.core.db.record.ORecordOperation) ORecord(com.orientechnologies.orient.core.record.ORecord) ODocument(com.orientechnologies.orient.core.record.impl.ODocument)

Aggregations

ORecordOperation (com.orientechnologies.orient.core.db.record.ORecordOperation)27 ODocument (com.orientechnologies.orient.core.record.impl.ODocument)13 ORecordId (com.orientechnologies.orient.core.id.ORecordId)11 ORecord (com.orientechnologies.orient.core.record.ORecord)11 OException (com.orientechnologies.common.exception.OException)7 IOException (java.io.IOException)7 OLiveResultListener (com.orientechnologies.orient.core.sql.query.OLiveResultListener)5 Test (org.testng.annotations.Test)5 OTransactionException (com.orientechnologies.orient.core.exception.OTransactionException)4 ORID (com.orientechnologies.orient.core.id.ORID)4 ONeedRetryException (com.orientechnologies.common.concur.ONeedRetryException)3 ODatabaseDocumentInternal (com.orientechnologies.orient.core.db.ODatabaseDocumentInternal)3 ODatabaseDocument (com.orientechnologies.orient.core.db.document.ODatabaseDocument)3 ODatabaseDocumentTx (com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx)3 ORecordNotFoundException (com.orientechnologies.orient.core.exception.ORecordNotFoundException)3 OCommandSQL (com.orientechnologies.orient.core.sql.OCommandSQL)3 CountDownLatch (java.util.concurrent.CountDownLatch)3 Test (org.junit.Test)3 ODatabaseException (com.orientechnologies.orient.core.exception.ODatabaseException)2 OStorageException (com.orientechnologies.orient.core.exception.OStorageException)2