Search in sources :

Example 6 with OPlaceholder

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;
    }
}
Also used : OPlaceholder(com.orientechnologies.orient.core.db.record.OPlaceholder) OOfflineNodeException(com.orientechnologies.common.concur.OOfflineNodeException) OCallable(com.orientechnologies.common.util.OCallable) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) ODocument(com.orientechnologies.orient.core.record.impl.ODocument) HazelcastException(com.hazelcast.core.HazelcastException) HazelcastInstanceNotActiveException(com.hazelcast.core.HazelcastInstanceNotActiveException) OException(com.orientechnologies.common.exception.OException) ONeedRetryException(com.orientechnologies.common.concur.ONeedRetryException) HazelcastException(com.hazelcast.core.HazelcastException) ODistributedRedirectException(com.orientechnologies.orient.enterprise.channel.binary.ODistributedRedirectException) OIOException(com.orientechnologies.common.io.OIOException) OOfflineNodeException(com.orientechnologies.common.concur.OOfflineNodeException) ORecordId(com.orientechnologies.orient.core.id.ORecordId) HazelcastInstanceNotActiveException(com.hazelcast.core.HazelcastInstanceNotActiveException) ONeedRetryException(com.orientechnologies.common.concur.ONeedRetryException)

Example 7 with OPlaceholder

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);
    }
}
Also used : OPlaceholder(com.orientechnologies.orient.core.db.record.OPlaceholder) OException(com.orientechnologies.common.exception.OException) ONeedRetryException(com.orientechnologies.common.concur.ONeedRetryException) IOException(java.io.IOException) ORecordOperation(com.orientechnologies.orient.core.db.record.ORecordOperation) ONeedRetryException(com.orientechnologies.common.concur.ONeedRetryException) ORecord(com.orientechnologies.orient.core.record.ORecord)

Aggregations

OPlaceholder (com.orientechnologies.orient.core.db.record.OPlaceholder)7 ONeedRetryException (com.orientechnologies.common.concur.ONeedRetryException)5 OException (com.orientechnologies.common.exception.OException)4 ORecordId (com.orientechnologies.orient.core.id.ORecordId)4 ORecord (com.orientechnologies.orient.core.record.ORecord)4 IOException (java.io.IOException)3 ORecordOperation (com.orientechnologies.orient.core.db.record.ORecordOperation)2 ODocument (com.orientechnologies.orient.core.record.impl.ODocument)2 HazelcastException (com.hazelcast.core.HazelcastException)1 HazelcastInstanceNotActiveException (com.hazelcast.core.HazelcastInstanceNotActiveException)1 OOfflineNodeException (com.orientechnologies.common.concur.OOfflineNodeException)1 OIOException (com.orientechnologies.common.io.OIOException)1 OCallable (com.orientechnologies.common.util.OCallable)1 ORecordNotFoundException (com.orientechnologies.orient.core.exception.ORecordNotFoundException)1 OTransactionException (com.orientechnologies.orient.core.exception.OTransactionException)1 ORawBuffer (com.orientechnologies.orient.core.storage.ORawBuffer)1 ORecordDuplicatedException (com.orientechnologies.orient.core.storage.ORecordDuplicatedException)1 OPaginatedCluster (com.orientechnologies.orient.core.storage.impl.local.paginated.OPaginatedCluster)1 OTransactionOptimistic (com.orientechnologies.orient.core.tx.OTransactionOptimistic)1 ODistributedRedirectException (com.orientechnologies.orient.enterprise.channel.binary.ODistributedRedirectException)1