Search in sources :

Example 1 with ODistributedConflictResolver

use of com.orientechnologies.orient.server.distributed.conflict.ODistributedConflictResolver in project orientdb by orientechnologies.

the class OConflictResolverDatabaseRepairer method repairRecords.

private boolean repairRecords(final ODatabaseDocumentInternal db, final List<ORecordId> rids) {
    final ODistributedConfiguration dCfg = dManager.getDatabaseConfiguration(databaseName);
    final int maxAutoRetry = OGlobalConfiguration.DISTRIBUTED_CONCURRENT_TX_MAX_AUTORETRY.getValueAsInteger();
    final int autoRetryDelay = OGlobalConfiguration.DISTRIBUTED_CONCURRENT_TX_AUTORETRY_DELAY.getValueAsInteger();
    final ODistributedRequestId requestId = new ODistributedRequestId(dManager.getLocalNodeId(), dManager.getNextMessageIdCounter());
    final ODistributedDatabase localDistributedDatabase = dManager.getMessageService().getDatabase(databaseName);
    final ODistributedTxContext ctx = localDistributedDatabase.registerTxContext(requestId);
    try {
        // ACQUIRE LOCKS WITH A LARGER TIMEOUT
        ODistributedTransactionManager.acquireMultipleRecordLocks(this, dManager, localDistributedDatabase, rids, maxAutoRetry, autoRetryDelay, null, ctx, 2000);
        try {
            final Set<String> clusterNames = new HashSet();
            for (ORecordId rid : rids) clusterNames.add(db.getClusterNameById(rid.getClusterId()));
            final Collection<String> involvedServers = dCfg.getServers(clusterNames);
            final Set<String> nonLocalServers = new HashSet<String>(involvedServers);
            nonLocalServers.remove(dManager.getLocalNodeName());
            if (nonLocalServers.isEmpty())
                return true;
            // CREATE LOCAL RESULT
            final OTxTaskResult localResult = new OTxTaskResult();
            for (ORecordId rid : rids) {
                final OStorageOperationResult<ORawBuffer> res;
                if (rid.getClusterPosition() > -1)
                    res = db.getStorage().readRecord(rid, null, true, false, null);
                else
                    res = null;
                if (res != null)
                    localResult.results.add(res.getResult());
                else
                    localResult.results.add(null);
            }
            ODistributedServerLog.debug(this, dManager.getLocalNodeName(), involvedServers.toString(), ODistributedServerLog.DIRECTION.OUT, "Auto repairing records %s on servers %s (reqId=%s)...", rids, involvedServers, requestId);
            // CREATE TX TASK
            final ORepairRecordsTask tx = new ORepairRecordsTask();
            for (ORecordId rid : rids) tx.add(new OReadRecordTask(rid));
            ODistributedResponse response = dManager.sendRequest(databaseName, clusterNames, nonLocalServers, tx, requestId.getMessageId(), ODistributedRequest.EXECUTION_MODE.RESPONSE, localResult, null);
            // MAP OF OCompletedTxTask SERVER/RECORDS. RECORD == NULL MEANS DELETE
            final Map<String, OCompleted2pcTask> repairMap = new HashMap<String, OCompleted2pcTask>(rids.size());
            for (String server : involvedServers) {
                final OCompleted2pcTask completedTask = new OCompleted2pcTask(requestId, false, tx.getPartitionKey());
                repairMap.put(server, completedTask);
            }
            try {
                if (response != null) {
                    final Object payload = response.getPayload();
                    if (payload instanceof Map) {
                        final Map<String, Object> map = (Map<String, Object>) payload;
                        // BROWSE FROM LOCAL RESULT
                        for (int i = 0; i < localResult.results.size(); ++i) {
                            final Map<Object, List<String>> groupedResult = new HashMap<Object, List<String>>();
                            final ORecordId rid = rids.get(i);
                            for (Map.Entry<String, Object> entry : map.entrySet()) {
                                if (entry.getValue() instanceof Throwable) {
                                    // ABORT IT
                                    ODistributedServerLog.info(this, dManager.getLocalNodeName(), entry.getKey(), ODistributedServerLog.DIRECTION.IN, "Error on auto repairing record %s on servers %s (error=%s)", rid, entry.getKey(), entry.getValue());
                                    return false;
                                }
                                final OTxTaskResult v = (OTxTaskResult) entry.getValue();
                                final Object remoteValue = v.results.get(i);
                                List<String> group = groupedResult.get(remoteValue);
                                if (group == null) {
                                    group = new ArrayList<String>();
                                    groupedResult.put(remoteValue, group);
                                }
                                group.add(entry.getKey());
                            }
                            if (groupedResult.size() == 1)
                                // NO CONFLICT, SKIP IT
                                continue;
                            ODocument config = null;
                            // EXECUTE THE CONFLICT RESOLVE PIPELINE: CONTINUE UNTIL THE WINNER IS NOT NULL (=RESOLVED)
                            Object winner = null;
                            Map<Object, List<String>> candidates = groupedResult;
                            for (ODistributedConflictResolver conflictResolver : conflictResolvers) {
                                final ODistributedConflictResolver.OConflictResult conflictResult = conflictResolver.onConflict(databaseName, db.getClusterNameById(rid.getClusterId()), rid, dManager, candidates, config);
                                winner = conflictResult.winner;
                                if (winner != null)
                                    // FOUND WINNER
                                    break;
                                candidates = conflictResult.candidates;
                            }
                            if (winner == null)
                                // NO WINNER, SKIP IT
                                continue;
                            for (Map.Entry<Object, List<String>> entry : groupedResult.entrySet()) {
                                final Object value = entry.getKey();
                                final List<String> servers = entry.getValue();
                                for (String server : servers) {
                                    ODistributedServerLog.debug(this, dManager.getLocalNodeName(), server, ODistributedServerLog.DIRECTION.OUT, "Preparing fix for record %s on servers %s, value=%s...", rid, server, winner);
                                    if (!winner.equals(value)) {
                                        final OCompleted2pcTask completedTask = repairMap.get(server);
                                        if (winner instanceof ORawBuffer && value instanceof ORawBuffer) {
                                            // UPDATE THE RECORD
                                            final ORawBuffer winnerRecord = (ORawBuffer) winner;
                                            completedTask.addFixTask(new OFixUpdateRecordTask(rid, winnerRecord.buffer, ORecordVersionHelper.setRollbackMode(winnerRecord.version), winnerRecord.recordType));
                                        } else if (winner instanceof ORecordNotFoundException && value instanceof ORawBuffer) {
                                            // DELETE THE RECORD
                                            completedTask.addFixTask(new OFixCreateRecordTask(rid, -1));
                                        } else if (value instanceof Throwable) {
                                        // MANAGE EXCEPTION
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            } finally {
                int repaired = 0;
                for (Map.Entry<String, OCompleted2pcTask> entry : repairMap.entrySet()) {
                    final String server = entry.getKey();
                    final OCompleted2pcTask task = entry.getValue();
                    repaired += task.getFixTasks().size();
                    if (dManager.getLocalNodeName().equals(server))
                        // EXECUTE IT LOCALLY
                        dManager.executeOnLocalNode(requestId, task, db);
                    else {
                        // EXECUTE REMOTELY
                        final List<String> servers = new ArrayList<String>();
                        servers.add(server);
                        // FILTER ONLY THE SERVER ONLINE
                        dManager.getAvailableNodes(servers, databaseName);
                        if (!servers.isEmpty()) {
                            response = dManager.sendRequest(databaseName, clusterNames, servers, task, dManager.getNextMessageIdCounter(), ODistributedRequest.EXECUTION_MODE.RESPONSE, null, null);
                        }
                    }
                }
                if (repaired == 0)
                    ODistributedServerLog.debug(this, dManager.getLocalNodeName(), involvedServers.toString(), ODistributedServerLog.DIRECTION.OUT, "Auto repairing completed. No fix is needed (reqId=%s)", repaired, requestId);
                else
                    ODistributedServerLog.info(this, dManager.getLocalNodeName(), involvedServers.toString(), ODistributedServerLog.DIRECTION.OUT, "Auto repairing completed. Sent %d fix messages for %d records (reqId=%s)", repaired, rids.size(), requestId);
            }
        } finally {
            // RELEASE LOCKS AND REMOVE TX CONTEXT
            localDistributedDatabase.popTxContext(requestId);
            ctx.destroy();
        }
    } catch (Throwable e) {
        ODistributedServerLog.debug(this, dManager.getLocalNodeName(), null, ODistributedServerLog.DIRECTION.NONE, "Error executing auto repairing (error=%s, reqId=%s)", e.toString(), requestId);
        return false;
    }
    return true;
}
Also used : ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) ODistributedConflictResolver(com.orientechnologies.orient.server.distributed.conflict.ODistributedConflictResolver) ORawBuffer(com.orientechnologies.orient.core.storage.ORawBuffer) ORecordNotFoundException(com.orientechnologies.orient.core.exception.ORecordNotFoundException) ODocument(com.orientechnologies.orient.core.record.impl.ODocument) ORecordId(com.orientechnologies.orient.core.id.ORecordId) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) ConcurrentMap(java.util.concurrent.ConcurrentMap)

Aggregations

ORecordNotFoundException (com.orientechnologies.orient.core.exception.ORecordNotFoundException)1 ORecordId (com.orientechnologies.orient.core.id.ORecordId)1 ODocument (com.orientechnologies.orient.core.record.impl.ODocument)1 ORawBuffer (com.orientechnologies.orient.core.storage.ORawBuffer)1 ODistributedConflictResolver (com.orientechnologies.orient.server.distributed.conflict.ODistributedConflictResolver)1 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)1 ConcurrentMap (java.util.concurrent.ConcurrentMap)1