/** * 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.hadoop.hdfs.server.namenode; import java.io.IOException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.hdfs.server.protocol.AutoEditsRollerInterface; import org.apache.hadoop.hdfs.util.InjectionEvent; import org.apache.hadoop.util.InjectionHandler; public class AutomaticEditsRoller implements Runnable { public static final Log LOG = LogFactory.getLog(AutomaticEditsRoller.class); final AutoEditsRollerInterface namenode; long nextRollTime = 0; private volatile boolean running = true; private Object lock = new Object(); public AutomaticEditsRoller(AutoEditsRollerInterface namenode) { this.namenode = namenode; } public void setNextRollTime(long nextRollTime) { LOG.info("Scheduled Automatic Rolling at " + nextRollTime); synchronized (lock) { this.nextRollTime = nextRollTime; lock.notifyAll(); } } /** * Signal the automatic edits roller thread to exit. * We cannot interrupt the thread unless we can allow edits corruption * in the last transactions, which is not the case for cases like manual * failover. */ public void stop() { synchronized (lock) { running = false; lock.notifyAll(); } } @Override public void run() { if (namenode == null) { LOG.warn("Name node passed to AutomaticEditsRoller is NULL."); return; } LOG.info("Automatic Edits Roller started..."); try { while (running && (!namenode.isNamesystemInitialized() || namenode .isNamesystemRunning())) { // If it is not ready for an automatic roll, // wait for a while. long timeNow = System.currentTimeMillis(); try { synchronized (lock) { if (!namenode.isNamesystemInitialized() || nextRollTime <= 0) { lock.wait(1000); continue; } else if (nextRollTime > timeNow) { lock.wait(nextRollTime - timeNow + 1); continue; } } } catch (InterruptedException e) { LOG.warn("Interrupted", e); return; } // There is a short window between checking the timestamp // and actually issuing the roll. There is a small chance // that another roll happens in between and the automatic // roll happens for an almost empty segment. We are fine // with it in this version for simplicity of the codes. // Roll Edit Logs try { // There is a chance that the automatic roll happens // in safe mode, so it got lost. We allow it for code // simplicity. Safe mode usually is only on for admin // operations. We can wait for a roll after the operations // if we really care about it. nextRollTime = 0; namenode.rollEditLogAdmin(); InjectionHandler .processEvent(InjectionEvent.FSEDIT_AFTER_AUTOMATIC_ROLL); } catch (IOException e) { LOG.warn("Exception when trying to roll edit logs", e); } } } finally { LOG.info("Automatic Edits Roller Exiting..."); } } }