Search in sources :

Example 1 with IDatasetLifecycleManager

use of org.apache.asterix.common.api.IDatasetLifecycleManager in project asterixdb by apache.

the class RemoteRecoveryManager method startFailbackProcess.

@Override
public void startFailbackProcess() {
    int maxRecoveryAttempts = replicationProperties.getMaxRemoteRecoveryAttempts();
    PersistentLocalResourceRepository resourceRepository = (PersistentLocalResourceRepository) runtimeContext.getLocalResourceRepository();
    IDatasetLifecycleManager datasetLifeCycleManager = runtimeContext.getDatasetLifecycleManager();
    Map<String, ClusterPartition[]> nodePartitions = runtimeContext.getMetadataProperties().getNodePartitions();
    while (true) {
        //start recovery steps
        try {
            if (maxRecoveryAttempts <= 0) {
                //to avoid infinite loop in case of unexpected behavior.
                throw new IllegalStateException("Failed to perform remote recovery.");
            }
            /*** Prepare for Recovery ***/
            //1. check remote replicas states
            replicationManager.initializeReplicasState();
            int activeReplicasCount = replicationManager.getActiveReplicasCount();
            if (activeReplicasCount == 0) {
                throw new IllegalStateException("no ACTIVE remote replica(s) exists to perform remote recovery");
            }
            //2. clean any memory data that could've existed from previous failed recovery attempt
            datasetLifeCycleManager.closeAllDatasets();
            //3. remove any existing storage data and initialize storage metadata
            resourceRepository.deleteStorageData(true);
            resourceRepository.initializeNewUniverse(ClusterProperties.INSTANCE.getStorageDirectoryName());
            //4. select remote replicas to recover from per lost replica data
            failbackRecoveryReplicas = constructRemoteRecoveryPlan();
            /*** Start Recovery Per Lost Replica ***/
            for (Entry<String, Set<String>> remoteReplica : failbackRecoveryReplicas.entrySet()) {
                String replicaId = remoteReplica.getKey();
                Set<String> ncsToRecoverFor = remoteReplica.getValue();
                Set<Integer> partitionsIds = new HashSet<>();
                for (String node : ncsToRecoverFor) {
                    partitionsIds.addAll((Arrays.asList(nodePartitions.get(node))).stream().map(ClusterPartition::getPartitionId).collect(Collectors.toList()));
                }
                //1. Request indexes metadata and LSM components
                replicationManager.requestReplicaFiles(replicaId, partitionsIds, new HashSet<String>());
            }
            break;
        } catch (IOException e) {
            if (LOGGER.isLoggable(Level.WARNING)) {
                LOGGER.log(Level.WARNING, "Failed during remote recovery. Attempting again...", e);
            }
            maxRecoveryAttempts--;
        }
    }
}
Also used : Set(java.util.Set) HashSet(java.util.HashSet) IOException(java.io.IOException) IDatasetLifecycleManager(org.apache.asterix.common.api.IDatasetLifecycleManager) PersistentLocalResourceRepository(org.apache.asterix.transaction.management.resource.PersistentLocalResourceRepository) HashSet(java.util.HashSet) ClusterPartition(org.apache.asterix.common.cluster.ClusterPartition)

Example 2 with IDatasetLifecycleManager

use of org.apache.asterix.common.api.IDatasetLifecycleManager in project asterixdb by apache.

the class CorrelatedPrefixMergePolicyTest method mockMergePolicy.

private ILSMMergePolicy mockMergePolicy(IndexInfo... indexes) {
    Map<String, String> properties = new HashMap<>();
    properties.put(CorrelatedPrefixMergePolicyFactory.KEY_MAX_COMPONENT_COUNT, String.valueOf(MAX_COMPONENT_COUNT));
    properties.put(CorrelatedPrefixMergePolicyFactory.KEY_MAX_COMPONENT_SIZE, String.valueOf(MAX_COMPONENT_SIZE));
    Set<IndexInfo> indexInfos = new HashSet<>();
    for (IndexInfo info : indexes) {
        indexInfos.add(info);
    }
    DatasetInfo dsInfo = Mockito.mock(DatasetInfo.class);
    Mockito.when(dsInfo.getDatsetIndexInfos()).thenReturn(indexInfos);
    IDatasetLifecycleManager manager = Mockito.mock(IDatasetLifecycleManager.class);
    Mockito.when(manager.getDatasetInfo(DATASET_ID)).thenReturn(dsInfo);
    ILSMMergePolicy policy = new CorrelatedPrefixMergePolicy(manager, DATASET_ID);
    policy.configure(properties);
    return policy;
}
Also used : IDatasetLifecycleManager(org.apache.asterix.common.api.IDatasetLifecycleManager) HashMap(java.util.HashMap) DatasetInfo(org.apache.asterix.common.context.DatasetInfo) IndexInfo(org.apache.asterix.common.context.IndexInfo) ILSMMergePolicy(org.apache.hyracks.storage.am.lsm.common.api.ILSMMergePolicy) HashSet(java.util.HashSet) CorrelatedPrefixMergePolicy(org.apache.asterix.common.context.CorrelatedPrefixMergePolicy)

Example 3 with IDatasetLifecycleManager

use of org.apache.asterix.common.api.IDatasetLifecycleManager in project asterixdb by apache.

the class ReplicationCheckpointManager method doSharpCheckpoint.

/**
     * Performs a sharp checkpoint. All datasets are flushed and all transaction
     * log files are deleted except the files that are needed for dead replicas.
     */
@Override
public synchronized void doSharpCheckpoint() throws HyracksDataException {
    LOGGER.info("Starting sharp checkpoint...");
    final IDatasetLifecycleManager datasetLifecycleManager = txnSubsystem.getAsterixAppRuntimeContextProvider().getDatasetLifecycleManager();
    datasetLifecycleManager.flushAllDatasets();
    long minFirstLSN;
    // If shutting down, need to check if we need to keep any remote logs for dead replicas
    if (txnSubsystem.getAsterixAppRuntimeContextProvider().getAppContext().isShuttingdown()) {
        final Set<String> deadReplicaIds = txnSubsystem.getAsterixAppRuntimeContextProvider().getAppContext().getReplicationManager().getDeadReplicasIds();
        if (deadReplicaIds.isEmpty()) {
            // No dead replicas => no need to keep any log
            minFirstLSN = SHARP_CHECKPOINT_LSN;
        } else {
            // Get min LSN of dead replicas remote resources
            minFirstLSN = getDeadReplicasMinFirstLSN(deadReplicaIds);
        }
    } else {
        // Start up complete checkpoint. Avoid deleting remote recovery logs.
        minFirstLSN = txnSubsystem.getRecoveryManager().getMinFirstLSN();
    }
    capture(minFirstLSN, true);
    if (minFirstLSN == SHARP_CHECKPOINT_LSN) {
        // No need to keep any logs
        txnSubsystem.getLogManager().renewLogFiles();
    } else {
        // Delete only log files with LSNs < any dead replica partition minimum LSN
        txnSubsystem.getLogManager().deleteOldLogFiles(minFirstLSN);
    }
    LOGGER.info("Completed sharp checkpoint.");
}
Also used : IDatasetLifecycleManager(org.apache.asterix.common.api.IDatasetLifecycleManager)

Example 4 with IDatasetLifecycleManager

use of org.apache.asterix.common.api.IDatasetLifecycleManager in project asterixdb by apache.

the class RecoveryManager method startRecoveryRedoPhase.

private synchronized void startRecoveryRedoPhase(Set<Integer> partitions, ILogReader logReader, long lowWaterMarkLSN, Set<Integer> winnerJobSet) throws IOException, ACIDException {
    int redoCount = 0;
    int jobId = -1;
    long resourceId;
    long maxDiskLastLsn;
    long lsn = -1;
    ILSMIndex index = null;
    LocalResource localResource = null;
    DatasetLocalResource localResourceMetadata = null;
    boolean foundWinner = false;
    JobEntityCommits jobEntityWinners = null;
    IAppRuntimeContextProvider appRuntimeContext = txnSubsystem.getAsterixAppRuntimeContextProvider();
    IDatasetLifecycleManager datasetLifecycleManager = appRuntimeContext.getDatasetLifecycleManager();
    Map<Long, LocalResource> resourcesMap = localResourceRepository.loadAndGetAllResources();
    Map<Long, Long> resourceId2MaxLSNMap = new HashMap<>();
    TxnId tempKeyTxnId = new TxnId(-1, -1, -1, null, -1, false);
    ILogRecord logRecord = null;
    try {
        logReader.initializeScan(lowWaterMarkLSN);
        logRecord = logReader.next();
        while (logRecord != null) {
            if (IS_DEBUG_MODE) {
                LOGGER.info(logRecord.getLogRecordForDisplay());
            }
            lsn = logRecord.getLSN();
            jobId = logRecord.getJobId();
            foundWinner = false;
            switch(logRecord.getLogType()) {
                case LogType.UPDATE:
                    if (partitions.contains(logRecord.getResourcePartition())) {
                        if (winnerJobSet.contains(jobId)) {
                            foundWinner = true;
                        } else if (jobId2WinnerEntitiesMap.containsKey(jobId)) {
                            jobEntityWinners = jobId2WinnerEntitiesMap.get(jobId);
                            tempKeyTxnId.setTxnId(jobId, logRecord.getDatasetId(), logRecord.getPKHashValue(), logRecord.getPKValue(), logRecord.getPKValueSize());
                            if (jobEntityWinners.containsEntityCommitForTxnId(lsn, tempKeyTxnId)) {
                                foundWinner = true;
                            }
                        }
                        if (foundWinner) {
                            resourceId = logRecord.getResourceId();
                            localResource = resourcesMap.get(resourceId);
                            /*******************************************************************
                                 * [Notice]
                                 * -> Issue
                                 * Delete index may cause a problem during redo.
                                 * The index operation to be redone couldn't be redone because the corresponding index
                                 * may not exist in NC due to the possible index drop DDL operation.
                                 * -> Approach
                                 * Avoid the problem during redo.
                                 * More specifically, the problem will be detected when the localResource of
                                 * the corresponding index is retrieved, which will end up with 'null'.
                                 * If null is returned, then just go and process the next
                                 * log record.
                                 *******************************************************************/
                            if (localResource == null) {
                                LOGGER.log(Level.WARNING, "resource was not found for resource id " + resourceId);
                                logRecord = logReader.next();
                                continue;
                            }
                            /*******************************************************************/
                            //get index instance from IndexLifeCycleManager
                            //if index is not registered into IndexLifeCycleManager,
                            //create the index using LocalMetadata stored in LocalResourceRepository
                            //get partition path in this node
                            localResourceMetadata = (DatasetLocalResource) localResource.getResource();
                            index = (ILSMIndex) datasetLifecycleManager.get(localResource.getPath());
                            if (index == null) {
                                //#. create index instance and register to indexLifeCycleManager
                                index = (ILSMIndex) localResourceMetadata.createInstance(serviceCtx);
                                datasetLifecycleManager.register(localResource.getPath(), index);
                                datasetLifecycleManager.open(localResource.getPath());
                                //#. get maxDiskLastLSN
                                ILSMIndex lsmIndex = index;
                                try {
                                    maxDiskLastLsn = ((AbstractLSMIOOperationCallback) lsmIndex.getIOOperationCallback()).getComponentLSN(lsmIndex.getImmutableComponents());
                                } catch (HyracksDataException e) {
                                    datasetLifecycleManager.close(localResource.getPath());
                                    throw e;
                                }
                                //#. set resourceId and maxDiskLastLSN to the map
                                resourceId2MaxLSNMap.put(resourceId, maxDiskLastLsn);
                            } else {
                                maxDiskLastLsn = resourceId2MaxLSNMap.get(resourceId);
                            }
                            if (lsn > maxDiskLastLsn) {
                                redo(logRecord, datasetLifecycleManager);
                                redoCount++;
                            }
                        }
                    }
                    break;
                case LogType.JOB_COMMIT:
                case LogType.ENTITY_COMMIT:
                case LogType.ABORT:
                case LogType.FLUSH:
                case LogType.WAIT:
                case LogType.MARKER:
                    //do nothing
                    break;
                default:
                    throw new ACIDException("Unsupported LogType: " + logRecord.getLogType());
            }
            logRecord = logReader.next();
        }
        LOGGER.info("Logs REDO phase completed. Redo logs count: " + redoCount);
    } finally {
        //close all indexes
        Set<Long> resourceIdList = resourceId2MaxLSNMap.keySet();
        for (long r : resourceIdList) {
            datasetLifecycleManager.close(resourcesMap.get(r).getPath());
        }
    }
}
Also used : HashMap(java.util.HashMap) ILSMIndex(org.apache.hyracks.storage.am.lsm.common.api.ILSMIndex) Checkpoint(org.apache.asterix.common.transactions.Checkpoint) HyracksDataException(org.apache.hyracks.api.exceptions.HyracksDataException) DatasetLocalResource(org.apache.asterix.common.dataflow.DatasetLocalResource) LocalResource(org.apache.hyracks.storage.common.LocalResource) ACIDException(org.apache.asterix.common.exceptions.ACIDException) DatasetLocalResource(org.apache.asterix.common.dataflow.DatasetLocalResource) IDatasetLifecycleManager(org.apache.asterix.common.api.IDatasetLifecycleManager) TxnId(org.apache.asterix.transaction.management.service.recovery.TxnId) IAppRuntimeContextProvider(org.apache.asterix.common.transactions.IAppRuntimeContextProvider) ILogRecord(org.apache.asterix.common.transactions.ILogRecord)

Example 5 with IDatasetLifecycleManager

use of org.apache.asterix.common.api.IDatasetLifecycleManager in project asterixdb by apache.

the class RecoveryManager method rollbackTransaction.

@Override
public void rollbackTransaction(ITransactionContext txnContext) throws ACIDException {
    int abortedJobId = txnContext.getJobId().getId();
    // Obtain the first/last log record LSNs written by the Job
    long firstLSN = txnContext.getFirstLSN();
    /**
         * The effect of any log record with LSN below minFirstLSN has already been written to disk and
         * will not be rolled back. Therefore, we will set the first LSN of the job to the maximum of
         * minFirstLSN and the job's first LSN.
         */
    try {
        long localMinFirstLSN = getLocalMinFirstLSN();
        firstLSN = Math.max(firstLSN, localMinFirstLSN);
    } catch (HyracksDataException e) {
        throw new ACIDException(e);
    }
    long lastLSN = txnContext.getLastLSN();
    if (LOGGER.isLoggable(Level.INFO)) {
        LOGGER.info("rollbacking transaction log records from " + firstLSN + " to " + lastLSN);
    }
    // check if the transaction actually wrote some logs.
    if (firstLSN == TransactionManagementConstants.LogManagerConstants.TERMINAL_LSN || firstLSN > lastLSN) {
        if (LOGGER.isLoggable(Level.INFO)) {
            LOGGER.info("no need to roll back as there were no operations by the job " + txnContext.getJobId());
        }
        return;
    }
    // While reading log records from firstLsn to lastLsn, collect uncommitted txn's Lsns
    if (LOGGER.isLoggable(Level.INFO)) {
        LOGGER.info("collecting loser transaction's LSNs from " + firstLSN + " to " + lastLSN);
    }
    Map<TxnId, List<Long>> jobLoserEntity2LSNsMap = new HashMap<>();
    TxnId tempKeyTxnId = new TxnId(-1, -1, -1, null, -1, false);
    int updateLogCount = 0;
    int entityCommitLogCount = 0;
    int logJobId = -1;
    long currentLSN = -1;
    TxnId loserEntity = null;
    List<Long> undoLSNSet = null;
    //get active partitions on this node
    Set<Integer> activePartitions = localResourceRepository.getActivePartitions();
    ILogReader logReader = logMgr.getLogReader(false);
    try {
        logReader.initializeScan(firstLSN);
        ILogRecord logRecord = null;
        while (currentLSN < lastLSN) {
            logRecord = logReader.next();
            if (logRecord == null) {
                break;
            } else {
                currentLSN = logRecord.getLSN();
                if (IS_DEBUG_MODE) {
                    LOGGER.info(logRecord.getLogRecordForDisplay());
                }
            }
            logJobId = logRecord.getJobId();
            if (logJobId != abortedJobId) {
                continue;
            }
            tempKeyTxnId.setTxnId(logJobId, logRecord.getDatasetId(), logRecord.getPKHashValue(), logRecord.getPKValue(), logRecord.getPKValueSize());
            switch(logRecord.getLogType()) {
                case LogType.UPDATE:
                    if (activePartitions.contains(logRecord.getResourcePartition())) {
                        undoLSNSet = jobLoserEntity2LSNsMap.get(tempKeyTxnId);
                        if (undoLSNSet == null) {
                            loserEntity = new TxnId(logJobId, logRecord.getDatasetId(), logRecord.getPKHashValue(), logRecord.getPKValue(), logRecord.getPKValueSize(), true);
                            undoLSNSet = new LinkedList<>();
                            jobLoserEntity2LSNsMap.put(loserEntity, undoLSNSet);
                        }
                        undoLSNSet.add(currentLSN);
                        updateLogCount++;
                        if (IS_DEBUG_MODE) {
                            LOGGER.info(Thread.currentThread().getId() + "======> update[" + currentLSN + "]:" + tempKeyTxnId);
                        }
                    }
                    break;
                case LogType.ENTITY_COMMIT:
                    if (activePartitions.contains(logRecord.getResourcePartition())) {
                        jobLoserEntity2LSNsMap.remove(tempKeyTxnId);
                        entityCommitLogCount++;
                        if (IS_DEBUG_MODE) {
                            LOGGER.info(Thread.currentThread().getId() + "======> entity_commit[" + currentLSN + "]" + tempKeyTxnId);
                        }
                    }
                    break;
                case LogType.JOB_COMMIT:
                    throw new ACIDException("Unexpected LogType(" + logRecord.getLogType() + ") during abort.");
                case LogType.ABORT:
                case LogType.FLUSH:
                case LogType.WAIT:
                case LogType.MARKER:
                    //ignore
                    break;
                default:
                    throw new ACIDException("Unsupported LogType: " + logRecord.getLogType());
            }
        }
        if (currentLSN != lastLSN) {
            throw new ACIDException("LastLSN mismatch: lastLSN(" + lastLSN + ") vs currentLSN(" + currentLSN + ") during abort( " + txnContext.getJobId() + ")");
        }
        //undo loserTxn's effect
        LOGGER.log(Level.INFO, "undoing loser transaction's effect");
        IDatasetLifecycleManager datasetLifecycleManager = txnSubsystem.getAsterixAppRuntimeContextProvider().getDatasetLifecycleManager();
        //TODO sort loser entities by smallest LSN to undo in one pass.
        Iterator<Entry<TxnId, List<Long>>> iter = jobLoserEntity2LSNsMap.entrySet().iterator();
        int undoCount = 0;
        while (iter.hasNext()) {
            Map.Entry<TxnId, List<Long>> loserEntity2LSNsMap = iter.next();
            undoLSNSet = loserEntity2LSNsMap.getValue();
            // The step below is important since the upsert operations must be done in reverse order.
            Collections.reverse(undoLSNSet);
            for (long undoLSN : undoLSNSet) {
                //here, all the log records are UPDATE type. So, we don't need to check the type again.
                //read the corresponding log record to be undone.
                logRecord = logReader.read(undoLSN);
                if (logRecord == null) {
                    throw new ACIDException("IllegalState exception during abort( " + txnContext.getJobId() + ")");
                }
                if (IS_DEBUG_MODE) {
                    LOGGER.info(logRecord.getLogRecordForDisplay());
                }
                undo(logRecord, datasetLifecycleManager);
                undoCount++;
            }
        }
        if (LOGGER.isLoggable(Level.INFO)) {
            LOGGER.info("undone loser transaction's effect");
            LOGGER.info("[RecoveryManager's rollback log count] update/entityCommit/undo:" + updateLogCount + "/" + entityCommitLogCount + "/" + undoCount);
        }
    } finally {
        logReader.close();
    }
}
Also used : HashMap(java.util.HashMap) Checkpoint(org.apache.asterix.common.transactions.Checkpoint) HyracksDataException(org.apache.hyracks.api.exceptions.HyracksDataException) ILogReader(org.apache.asterix.common.transactions.ILogReader) ACIDException(org.apache.asterix.common.exceptions.ACIDException) IDatasetLifecycleManager(org.apache.asterix.common.api.IDatasetLifecycleManager) TxnId(org.apache.asterix.transaction.management.service.recovery.TxnId) Entry(java.util.Map.Entry) List(java.util.List) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) ILogRecord(org.apache.asterix.common.transactions.ILogRecord) Map(java.util.Map) HashMap(java.util.HashMap)

Aggregations

IDatasetLifecycleManager (org.apache.asterix.common.api.IDatasetLifecycleManager)12 HyracksDataException (org.apache.hyracks.api.exceptions.HyracksDataException)4 IOException (java.io.IOException)3 HashMap (java.util.HashMap)3 HashSet (java.util.HashSet)3 ACIDException (org.apache.asterix.common.exceptions.ACIDException)3 Set (java.util.Set)2 INcApplicationContext (org.apache.asterix.common.api.INcApplicationContext)2 Checkpoint (org.apache.asterix.common.transactions.Checkpoint)2 ILogRecord (org.apache.asterix.common.transactions.ILogRecord)2 PersistentLocalResourceRepository (org.apache.asterix.transaction.management.resource.PersistentLocalResourceRepository)2 TxnId (org.apache.asterix.transaction.management.service.recovery.TxnId)2 ILSMMergePolicy (org.apache.hyracks.storage.am.lsm.common.api.ILSMMergePolicy)2 ByteBuffer (java.nio.ByteBuffer)1 ArrayList (java.util.ArrayList)1 LinkedList (java.util.LinkedList)1 List (java.util.List)1 Map (java.util.Map)1 Entry (java.util.Map.Entry)1 ClusterPartition (org.apache.asterix.common.cluster.ClusterPartition)1