package com.linkedin.databus2.core;
/*
*
* Copyright 2013 LinkedIn Corp. All rights reserved
*
* Licensed 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.
*
*/
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
/** Implements a timer for linearly or exponentially increasing sleeps */
public class BackoffTimer
{
public static final String MODULE = BackoffTimerStaticConfigBuilder.class.getName();
public static final Logger LOG = Logger.getLogger(MODULE);
public static final long NO_MORE_RETRIES = -1L;
private final BackoffTimerStaticConfig _config;
private final String _name;
private long _retrySleepMs;
private int _retriesNum;
private long _retryStartTs;
public BackoffTimer(String name, BackoffTimerStaticConfig config)
{
_config = config;
_name = name;
reset();
}
/** Returns the counter configuration */
public BackoffTimerStaticConfig getConfig()
{
return _config;
}
/** The current sleep duration; -1 after a reset/success */
public long getCurrentSleepMs()
{
return _retrySleepMs;
}
/** The current number of error retries */
public int getRetriesNum()
{
return _retriesNum;
}
public int getRemainingRetriesNum()
{
return _config.getMaxRetryNum() >= 0 ? _config.getMaxRetryNum() - _retriesNum : Integer.MAX_VALUE;
}
public long getTotalRetryTime()
{
return _retryStartTs > 0 ? System.currentTimeMillis() - _retryStartTs : 0;
}
/** Reset the counter; e.g. after a success */
public void reset()
{
_retrySleepMs = _config.getInitSleep();
_retriesNum = 0;
_retryStartTs = -1;
}
/**
* Increments retries number and sleep
* @return the new sleep or NO_MORE_RETRIES if no more retries are allowed
* */
public long backoff()
{
if (0 == _retriesNum) _retryStartTs = System.currentTimeMillis();
++ _retriesNum;
_retrySleepMs = _config.calcNextSleep(_retrySleepMs);
if (_config.getMaxRetryNum() >= 0 && _retriesNum > _config.getMaxRetryNum()) return NO_MORE_RETRIES;
return _retrySleepMs;
}
/**
* Sleep for the current sleep time, including any backoff that has occurred.
* @return true if we slept for the total time; false if we were interrupted
*/
public boolean sleep()
{
if (0L >= _retrySleepMs) return true;
boolean debugLogEnabled = LOG.isDebugEnabled();
try
{
if (_retriesNum > 0) LOG.info(_name + ": error sleep, ms: " + _retrySleepMs);
else if(debugLogEnabled) LOG.debug(_name + ": sleeping for " + _retrySleepMs);
Thread.sleep(_retrySleepMs);
return true;
}
catch(InterruptedException ex)
{
LOG.info(_name + ": sleep interrupted");
return false;
}
}
/**
* Sleep for the current sleep time, including any backoff that has occurred.
* @return true if we slept for the total time; false if we were interrupted
*/
public boolean backoffAndSleep()
{
backoff();
return sleep();
}
@Override
public String toString() {
return "BackoffTimer [_config=" + _config + ", _name=" + _name
+ ", _retrySleepMs=" + _retrySleepMs + ", _retriesNum="
+ _retriesNum + ", _retryStartTs=" + _retryStartTs + "]";
}
}