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;
}
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);
}
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;
}
}
}
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;
}
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();
}
Aggregations