| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.apache.bookkeeper.bookie; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.List; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| * Used to determine if the prior shutdown was unclean or not. It does so |
| * by adding a file to each ledger directory after successful start-up |
| * and removing the file on graceful shutdown. |
| * Any abrupt termination will cause one or more of these files to not be cleared |
| * and so on the subsequent boot-up, the presence of any of these files will |
| * indicate an unclean shutdown. |
| */ |
| public class UncleanShutdownDetectionImpl implements UncleanShutdownDetection { |
| private static final Logger LOG = LoggerFactory.getLogger(UncleanShutdownDetectionImpl.class); |
| private final LedgerDirsManager ledgerDirsManager; |
| static final String DIRTY_FILENAME = "DIRTY"; |
| |
| public UncleanShutdownDetectionImpl(LedgerDirsManager ledgerDirsManager) { |
| this.ledgerDirsManager = ledgerDirsManager; |
| } |
| |
| @Override |
| public void registerStartUp() throws IOException { |
| for (File ledgerDir : ledgerDirsManager.getAllLedgerDirs()) { |
| try { |
| File dirtyFile = new File(ledgerDir, DIRTY_FILENAME); |
| if (dirtyFile.createNewFile()) { |
| LOG.info("Created dirty file in ledger dir: {}", ledgerDir.getAbsolutePath()); |
| } else { |
| LOG.info("Dirty file already exists in ledger dir: {}", ledgerDir.getAbsolutePath()); |
| } |
| |
| } catch (IOException e) { |
| LOG.error("Unable to register start-up (so an unclean shutdown cannot" |
| + " be detected). Dirty file of ledger dir {} could not be created.", |
| ledgerDir.getAbsolutePath(), e); |
| throw e; |
| } |
| } |
| } |
| |
| @Override |
| public void registerCleanShutdown() { |
| for (File ledgerDir : ledgerDirsManager.getAllLedgerDirs()) { |
| try { |
| File dirtyFile = new File(ledgerDir, DIRTY_FILENAME); |
| if (dirtyFile.exists()) { |
| boolean deleted = dirtyFile.delete(); |
| |
| if (!deleted) { |
| LOG.error("Unable to register a clean shutdown. The dirty file of " |
| + " ledger dir {} could not be deleted.", |
| ledgerDir.getAbsolutePath()); |
| } |
| } else { |
| LOG.error("Unable to register a clean shutdown. The dirty file of " |
| + " ledger dir {} does not exist.", |
| ledgerDir.getAbsolutePath()); |
| } |
| } catch (Throwable t) { |
| LOG.error("Unable to register a clean shutdown. An error occurred while deleting " |
| + " the dirty file of ledger dir {}.", |
| ledgerDir.getAbsolutePath(), t); |
| } |
| } |
| } |
| |
| @Override |
| public boolean lastShutdownWasUnclean() { |
| boolean unclean = false; |
| List<String> dirtyFiles = new ArrayList<>(); |
| try { |
| for (File ledgerDir : ledgerDirsManager.getAllLedgerDirs()) { |
| File dirtyFile = new File(ledgerDir, DIRTY_FILENAME); |
| if (dirtyFile.exists()) { |
| dirtyFiles.add(dirtyFile.getAbsolutePath()); |
| unclean = true; |
| } |
| } |
| } catch (Throwable t) { |
| LOG.error("Unable to determine if last shutdown was unclean (defaults to unclean)", t); |
| unclean = true; |
| } |
| |
| if (!dirtyFiles.isEmpty()) { |
| LOG.info("Dirty files exist on boot-up indicating an unclean shutdown. Dirty files: {}", |
| String.join(",", dirtyFiles)); |
| } |
| |
| return unclean; |
| } |
| } |