use of com.orientechnologies.orient.core.db.record.OPlaceholder in project orientdb by orientechnologies.
the class ODistributedStorage method createRecord.
public OStorageOperationResult<OPhysicalPosition> createRecord(final ORecordId iRecordId, final byte[] iContent, final int iRecordVersion, final byte iRecordType, final int iMode, final ORecordCallback<Long> iCallback) {
resetLastValidBackup();
if (OScenarioThreadLocal.INSTANCE.isRunModeDistributed()) {
// ALREADY DISTRIBUTED
return wrapped.createRecord(iRecordId, iContent, iRecordVersion, iRecordType, iMode, iCallback);
}
checkClusterRebalanceIsNotRunning();
final String localNodeName = dManager.getLocalNodeName();
final ODistributedConfiguration dbCfg = distributedConfiguration;
// ASSIGN DESTINATION NODE
final int clusterId = iRecordId.getClusterId();
if (clusterId == ORID.CLUSTER_ID_INVALID)
throw new IllegalArgumentException("Cluster not valid");
checkNodeIsMaster(localNodeName, dbCfg, "Create record " + iRecordId);
final String clusterName = getClusterNameByRID(iRecordId);
checkWriteQuorum(dbCfg, clusterName, localNodeName);
try {
ODocument documentForClusterSelection = iRecordId.getRecord();
if (documentForClusterSelection == null) {
// DOCUMENT NOT FOUND: BUILD A TEMPORARY ONE
documentForClusterSelection = (ODocument) ORecordInternal.fill(new ODocument(), iRecordId, iRecordVersion, iContent, false);
}
checkForCluster(documentForClusterSelection, localNodeName, dbCfg);
final List<String> servers = dbCfg.getServers(clusterName, null);
if (servers.isEmpty())
// NO NODES: EXECUTE LOCALLY ONLY
return wrapped.createRecord(iRecordId, iContent, iRecordVersion, iRecordType, iMode, iCallback);
final String finalClusterName = clusterName;
final Set<String> clusterNames = Collections.singleton(finalClusterName);
// REMOVE CURRENT NODE BECAUSE IT HAS BEEN ALREADY EXECUTED LOCALLY
servers.remove(localNodeName);
Boolean executionModeSynch = dbCfg.isExecutionModeSynchronous(finalClusterName);
if (executionModeSynch == null)
executionModeSynch = iMode == 0;
final boolean syncMode = executionModeSynch;
// IN ANY CASE EXECUTE LOCALLY AND THEN DISTRIBUTE
return (OStorageOperationResult<OPhysicalPosition>) executeRecordOperationInLock(syncMode, iRecordId, new OCallable<Object, OCallable<Void, ODistributedRequestId>>() {
@Override
public Object call(OCallable<Void, ODistributedRequestId> unlockCallback) {
final OStorageOperationResult<OPhysicalPosition> localResult;
localResult = wrapped.createRecord(iRecordId, iContent, iRecordVersion, iRecordType, iMode, iCallback);
// UPDATE RID WITH NEW POSITION
iRecordId.setClusterPosition(localResult.getResult().clusterPosition);
final OPlaceholder localPlaceholder = new OPlaceholder(iRecordId, localResult.getResult().recordVersion);
if (!servers.isEmpty()) {
final OCreateRecordTask task = (OCreateRecordTask) dManager.getTaskFactoryManager().getFactoryByServerNames(servers).createTask(OCreateRecordTask.FACTORYID);
task.init(iRecordId, iContent, iRecordVersion, iRecordType);
task.setLastLSN(wrapped.getLSN());
if (syncMode) {
// SYNCHRONOUS CALL: REPLICATE IT
try {
final ODistributedResponse dResponse = dManager.sendRequest(getName(), clusterNames, servers, task, dManager.getNextMessageIdCounter(), EXECUTION_MODE.RESPONSE, localPlaceholder, unlockCallback, null);
final Object payload = dResponse.getPayload();
if (payload != null) {
if (payload instanceof Exception) {
executeUndoOnLocalServer(dResponse.getRequestId(), task);
if (payload instanceof ONeedRetryException)
throw (ONeedRetryException) payload;
throw OException.wrapException(new ODistributedException("Error on execution distributed create record"), (Exception) payload);
}
// COPY THE CLUSTER POS -> RID
final OPlaceholder masterPlaceholder = (OPlaceholder) payload;
iRecordId.copyFrom(masterPlaceholder.getIdentity());
return new OStorageOperationResult<OPhysicalPosition>(new OPhysicalPosition(masterPlaceholder.getIdentity().getClusterPosition(), masterPlaceholder.getVersion()));
}
} catch (RuntimeException e) {
executeUndoOnLocalServer(null, task);
throw e;
} catch (Exception e) {
executeUndoOnLocalServer(null, task);
throw ODatabaseException.wrapException(new ODistributedException("Cannot execute distributed create record"), e);
}
} else {
// ASYNCHRONOUSLY REPLICATE IT TO ALL THE OTHER NODES
asynchronousExecution(new OAsynchDistributedOperation(getName(), Collections.singleton(finalClusterName), servers, task, dManager.getNextMessageIdCounter(), localPlaceholder, unlockCallback, null));
}
} else
unlockCallback.call(null);
return localResult;
}
});
} catch (ODistributedRecordLockedException e) {
// PASS THROUGH
throw e;
} catch (ONeedRetryException e) {
localDistributedDatabase.getDatabaseRepairer().enqueueRepairRecord(iRecordId);
final ORecordId lockEntireCluster = iRecordId.copy();
lockEntireCluster.setClusterPosition(-1);
localDistributedDatabase.getDatabaseRepairer().enqueueRepairRecord(lockEntireCluster);
// PASS THROUGH
throw e;
} catch (HazelcastInstanceNotActiveException e) {
throw new OOfflineNodeException("Hazelcast instance is not available");
} catch (HazelcastException e) {
throw new OOfflineNodeException("Hazelcast instance is not available");
} catch (Exception e) {
localDistributedDatabase.getDatabaseRepairer().enqueueRepairRecord(iRecordId);
final ORecordId lockEntireCluster = iRecordId.copy();
lockEntireCluster.setClusterPosition(-1);
localDistributedDatabase.getDatabaseRepairer().enqueueRepairRecord(lockEntireCluster);
handleDistributedException("Cannot route create record operation for %s to the distributed node", e, iRecordId);
// UNREACHABLE
return null;
}
}
use of com.orientechnologies.orient.core.db.record.OPlaceholder in project orientdb by orientechnologies.
the class ODistributedTransactionManager method processCommitResult.
protected void processCommitResult(final String localNodeName, final OTransaction iTx, final OTxTask txTask, final Set<String> involvedClusters, final Iterable<ORecordOperation> tmpEntries, final Collection<String> nodes, final ODistributedRequestId reqId, final ODistributedResponse dResponse, final ODistributedTxContext ctx) throws InterruptedException {
final Object result = dResponse.getPayload();
if (result instanceof OTxTaskResult) {
final OTxTaskResult txResult = (OTxTaskResult) result;
final List<Object> list = txResult.results;
for (int i = 0; i < txTask.getTasks().size(); ++i) {
final Object o = list.get(i);
final OAbstractRecordReplicatedTask task = txTask.getTasks().get(i);
if (!OAbstract2pcTask.NON_LOCAL_CLUSTER.equals(o))
if (task instanceof OCreateRecordTask) {
final OCreateRecordTask t = (OCreateRecordTask) task;
iTx.updateIdentityAfterCommit(t.getRid(), ((OPlaceholder) o).getIdentity());
final ORecord rec = iTx.getRecord(t.getRid());
if (rec != null)
ORecordInternal.setVersion(rec, ((OPlaceholder) o).getVersion());
} else if (task instanceof OUpdateRecordTask) {
final OUpdateRecordTask t = (OUpdateRecordTask) task;
ORecordInternal.setVersion(iTx.getRecord(t.getRid()), (Integer) o);
} else if (task instanceof ODeleteRecordTask) {
}
}
// RESET DIRTY FLAGS TO AVOID CALLING AUTO-SAVE
for (ORecordOperation op : tmpEntries) {
final ORecord record = op.getRecord();
if (record != null)
ORecordInternal.unsetDirty(record);
}
if (ODistributedServerLog.isDebugEnabled())
ODistributedServerLog.debug(this, localNodeName, null, ODistributedServerLog.DIRECTION.NONE, "Distributed transaction %s completed", reqId);
// SEND THE 2PC ONLY TO THE SERVERS WITH THE SAME RESULT AS THE WINNING RESPONSE
final Collection<String> conflictServers = dResponse.getDistributedResponseManager().getConflictServers();
final Set<String> serverWithoutFollowup = dResponse.getDistributedResponseManager().getServersWithoutFollowup();
final Collection<String> okNodes;
if (conflictServers.isEmpty())
okNodes = serverWithoutFollowup;
else {
okNodes = new ArrayList<String>(serverWithoutFollowup);
okNodes.removeAll(conflictServers);
}
// EXCLUDE LOCAL SERVER
okNodes.remove(localNodeName);
if (!okNodes.isEmpty()) {
for (String node : okNodes) dResponse.getDistributedResponseManager().addFollowupToServer(node);
ODistributedServerLog.debug(this, localNodeName, okNodes.toString(), ODistributedServerLog.DIRECTION.OUT, "Distributed transaction %s sending 2pc: pending/conflicting servers are %s", reqId, conflictServers.toString());
// DO NOT REMOVE THE CONTEXT WAITING FOR ANY PENDING RESPONSE
final OCompleted2pcTask twopcTask = (OCompleted2pcTask) dManager.getTaskFactoryManager().getFactoryByServerNames(okNodes).createTask(OCompleted2pcTask.FACTORYID);
twopcTask.init(reqId, true, txTask.getPartitionKey());
sendTxCompleted(localNodeName, involvedClusters, okNodes, twopcTask);
}
} else if (result instanceof ODistributedRecordLockedException) {
if (ODistributedServerLog.isDebugEnabled())
ODistributedServerLog.debug(this, localNodeName, nodes.toString(), ODistributedServerLog.DIRECTION.IN, "Distributed transaction %s error: record %s is locked by %s", reqId, ((ODistributedRecordLockedException) result).getRid(), ((ODistributedRecordLockedException) result).getLockHolder());
throw (ODistributedRecordLockedException) result;
} else if (result instanceof Exception) {
// EXCEPTION: LOG IT AND ADD AS NESTED EXCEPTION
if (ODistributedServerLog.isDebugEnabled())
ODistributedServerLog.debug(this, localNodeName, nodes.toString(), ODistributedServerLog.DIRECTION.IN, "Distributed transaction %s received error: %s", reqId, result, result.toString());
// LET TO THE CALLER TO UNDO IT
if (result instanceof OTransactionException || result instanceof ONeedRetryException)
throw (RuntimeException) result;
if (result instanceof ORecordNotFoundException) {
// REPAIR THE RECORD IMMEDIATELY
localDistributedDatabase.getDatabaseRepairer().repairRecord((ORecordId) ((ORecordNotFoundException) result).getRid());
throw (ORecordNotFoundException) result;
}
throw OException.wrapException(new OTransactionException("Error on committing distributed transaction"), (Exception) result);
} else {
// UNKNOWN RESPONSE TYPE
if (ODistributedServerLog.isDebugEnabled())
ODistributedServerLog.info(this, localNodeName, nodes.toString(), ODistributedServerLog.DIRECTION.IN, "Distributed transaction %s error, received unknown response type: %s", reqId, result);
throw new OTransactionException("Error on committing distributed transaction, received unknown response type " + result);
}
}
Aggregations