blob: 33192c3092b519752ae34e80352ad26f4ec893b4 [file] [log] [blame]
/*
* 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;
}
}