// $Id: AlternatingFlushSchedulerV1.java,v 1.2 2006-07-31 16:35:52 patrick Exp $
package diskCacheV111.hsmControl.flush.driver ;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.EOFException;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import diskCacheV111.hsmControl.flush.HsmFlushControlCore;
import diskCacheV111.hsmControl.flush.HsmFlushSchedulable;
import diskCacheV111.pools.PoolCellInfo;
import diskCacheV111.pools.PoolCostInfo;
import diskCacheV111.pools.StorageClassFlushInfo;
import dmg.cells.nucleus.CellAdapter;
import dmg.util.CommandInterpreter;
import org.dcache.util.Args;
import static org.dcache.util.ByteUnit.KiB;
import static org.dcache.util.ByteUnit.MiB;
/**
* @author Patrick Fuhrmann patrick.fuhrmann@desy.de
* @version 0.0, Dec 03, 2005
*
*/
public class AlternatingFlushSchedulerV1 implements HsmFlushSchedulable {
private static final Logger _log =
LoggerFactory.getLogger(AlternatingFlushSchedulerV1.class);
private HsmFlushControlCore _core;
private CommandInterpreter _interpreter;
private AltParameter _parameter = new AltParameter() ;
private Map<String, PoolSet> _hostMap = new HashMap<>() ;
private boolean _suspendFlushing;
/**
* Our Pool class. Contains things we need to remember.
* Is stored with setDriverHandle to avoid our own
* bookkeeping.
*/
private static final int STATE_IDLE = 0 ;
private static final int STATE_WAITING_FOR_MODE_CHANGE = 1 ;
private static final int STATE_WAITING_FOR_IO_DONE = 2 ;
private static final int STATE_WAITING_FOR_FLUSH_READY = 4 ;
/**
*
*-----------------------------------------------------------------------------------
*
* OUR INTERNAL POOL REPRESENTATION
*
*/
private class Pool implements HsmFlushControlCore.DriverHandle {
private String _name;
private int _flushCounter;
private long _totalSpace;
private long _preciousSpace;
private PoolSet _hostPoolMap;
private boolean _expectedReadOnly;
private int _preciousFileCount;
private String _hostTag;
private boolean _previousWasRdOnly;
private long _oldestTimestamp;
private HsmFlushControlCore.Pool _pool;
private Pool( String name , HsmFlushControlCore.Pool pool ){
_name = name ;
update( pool ) ;
// _pool.queryMode() ;
if( _pool.isActive() ) {
linkUs();
}
}
private PoolSet getParentPoolSet(){
return _hostPoolMap ;
}
private void refreshLocalVariables(){
PoolCellInfo cellInfo = _pool.getCellInfo() ;
if( cellInfo == null ) {
return;
}
PoolCostInfo costInfo = cellInfo.getPoolCostInfo() ;
PoolCostInfo.PoolSpaceInfo spaceInfo = costInfo.getSpaceInfo() ;
_totalSpace = spaceInfo.getTotalSpace() ;
_preciousSpace = spaceInfo.getPreciousSpace() ;
_preciousFileCount = countTotalPending() ;
_oldestTimestamp = getOldestFileTimestamp() ;
}
private void update(HsmFlushControlCore.Pool pool){
_pool = pool ;
if( ! _pool.isActive() ) {
return;
}
//
refreshLocalVariables() ;
//
if( _hostPoolMap == null ) {
linkUs();
}
}
private void linkUs(){
PoolCellInfo cellInfo = _pool.getCellInfo() ;
Map<String, String> tagMap = cellInfo.getTagMap() ;
_hostTag = tagMap.get("hostname");
_hostTag = _hostTag == null ? ( "x-"+_name ) : _hostTag ;
_hostPoolMap = _hostMap.get(_hostTag);
if( _hostPoolMap == null ) {
_hostPoolMap = new PoolSet(_hostTag);
}
_hostMap.put( _hostTag , _hostPoolMap ) ;
_hostPoolMap.put( _name , this ) ;
}
private void setReadOnly( boolean readOnly ){
_previousWasRdOnly = _pool.isReadOnly() ;
_expectedReadOnly = readOnly ;
_pool.setReadOnly(readOnly);
}
private boolean isReady(){
return ( _pool != null ) && _pool.isActive() && _pool.isPoolIoModeKnown() ;
}
private void flush(){
_flushCounter += flushPool( _pool );
}
private boolean isFlushing(){
// return countStorageClassesFlushing(pool) > 0 ;
return _flushCounter > 0 ;
}
private int countTotalPending(){
return countTotalPendingPool( _pool ) ;
}
private long getOldestFileTimestamp(){
return getOldestFileTimestampPool( _pool ) ;
}
public String toString(){
if( isReady() ){
return _name + " precious file count : "+_preciousFileCount+" core : "+ _pool ;
}else{
return _name+" Not Ready" ;
}
}
///////////////////////////////////////////////////////////////////////
//
// state engine for a pool.
//
private void timer() {
}
public void poolIoModeUpdated( boolean newIsReadOnly ){
}
public void flushingDone( HsmFlushControlCore.FlushInfo flushInfo ){
_flushCounter -- ;
}
public void poolFlushInfoUpdated( HsmFlushControlCore.Pool pool ){
if( ! _pool.isActive() ) {
return;
}
//
refreshLocalVariables() ;
}
}
/**
*
*-----------------------------------------------------------------------------------
*
* OUR INTERNAL HOST REPRESENTATION
*
*/
private static final int PS_IDLE = 0 ;
private static final int PS_WAITING_FOR_STATE_CHANGE = 1 ;
private static final int PS_WAITING_FOR_FLUSH_DONE = 2 ;
private class PoolSet {
private Map<String, Pool> _poolMap = new HashMap<>() ;
private String _name;
private int _progressState = PS_IDLE ;
private long _progressStarted;
private boolean _expectedReadOnly;
private PoolSet( String name ){
_name = name ;
}
public void put( String name , Pool pool ){
_poolMap.put( name , pool ) ;
}
public Pool get( String name ){
return _poolMap.get(name);
}
public Set<?> keySet(){ return _poolMap.keySet() ; }
public Collection<? extends Pool> values(){ return _poolMap.values() ; }
public Set<? extends Map.Entry<String,Pool>> entrySet(){ return _poolMap.entrySet() ; }
public void poolIoModeUpdated( Pool ip , boolean newIsReadOnly ){
if(_parameter._p_poolset) {
_log.info("PROGRESS-H(" + _name + "/" + ip._name + ") new pool i/o mode " + newIsReadOnly);
}
//
// new pool mode arrived, in wrong state
//
if( _progressState != PS_WAITING_FOR_STATE_CHANGE ){
_log.warn("PROGRESS-H("+_name+"/"+ip._name+
") Warning : new pool i/o mode arrived unexpectedly in state "+_progressState);
return ;
}
//
// wrong pool mode arrived
//
if( ip._expectedReadOnly != newIsReadOnly ){
_log.warn("PROGRESS-H("+_name+"/"+ip._name+") Warning : got I/O mode rdonly="+newIsReadOnly+" expected rdOnly="+_expectedReadOnly);
return ;
}
//
// Do have all pools if this poolSet the correct mode ?
//
int total = 0 ;
int modeOk = 0 ;
for (Object o : _poolMap.values()) {
Pool ipool = (Pool) o;
if (!ipool._pool.isActive()) {
continue;
}
total++;
if (!(ipool._pool.isReadOnly() ^ ipool._expectedReadOnly)) {
modeOk++;
}
}
if(_parameter._p_poolset) {
_log.info("PROGRESS-H(" + _name + "/" + ip._name + ") new pool i/o mode total=" + total + ";rdOnly=" + modeOk);
}
//
// not yet
//
if( modeOk < total ) {
return;
}
//
//
if( _expectedReadOnly ){
//
// all pools are readyOnly; flush them all.
//
if(_parameter._p_poolset) {
_log.info("PROGRESS-H(" + _name + "/" + ip._name + ") new pool i/o mode done; Flushing all");
}
int flushed = 0 ;
for (Object o : _poolMap.values()) {
Pool ipool = (Pool) o;
ipool._flushCounter = 0;
ipool.flush();
if (ipool._flushCounter > 0) {
flushed++;
}
}
if( flushed > 0 ){
if(_parameter._p_poolset) {
_log.info("PROGRESS-H(" + _name + "/" + ip._name + ") new pool i/o mode done; flushed " + flushed + " pools");
}
newState( PS_WAITING_FOR_FLUSH_DONE ) ;
}else{
if(_parameter._p_poolset) {
_log.info("PROGRESS-H(" + _name + "/" + ip._name + ") new pool i/o mode done; nothing to flush; switching back to read/write");
}
switchToNewPoolMode(false);
}
}else{
if(_parameter._p_poolset) {
_log.info("PROGRESS-H(" + _name + "/" + ip._name + ") new pool i/o mode done; Switching back to IDLE");
}
newState( PS_IDLE ) ;
}
}
public boolean inProgress(){ return _progressState != 0 ; }
public void flushingDone( Pool ip , String storageClassName , HsmFlushControlCore.FlushInfo flushInfo ){
if(_parameter._p_poolset) {
_log.info("PROGRESS-H(" + _name + "/" + ip._name + ") flushingDone");
}
//
// check if all are done
//
int total = 0 ;
int flushDone = 0 ;
for (Object o : _poolMap.values()) {
Pool ipool = (Pool) o;
if (!ipool._pool.isActive()) {
continue;
}
total++;
if (ipool._flushCounter == 0) {
flushDone++;
}
}
if(_parameter._p_poolset) {
_log.info("PROGRESS-H(" + _name + "/" + ip._name + ") flushing done : total=" + total + ";flushDone=" + flushDone);
}
if( flushDone < total ) {
return;
}
switchToNewPoolMode(false);
}
private void flushAll(){
if(_parameter._p_poolset) {
_log.info("PROGRESS-H(" + _name + ") flush all; switching to readOnly");
}
switchToNewPoolMode(true);
}
private void newState( int state ){
_progressState = state ;
_progressStarted = System.currentTimeMillis() ;
}
private void switchToNewPoolMode( boolean readOnly ){
newState( PS_WAITING_FOR_STATE_CHANGE ) ;
_expectedReadOnly = readOnly ;
for (Object o : _poolMap.values()) {
Pool ip = (Pool) o;
if (readOnly) {
//
// store current mode; if this was already rdOnly we shouldn't
// reset it after we are done.
//
//
ip.setReadOnly(readOnly);
//
} else { // read write or whatever it was before.
//
ip.setReadOnly(ip._previousWasRdOnly);
}
}
}
}
/*
*
*-----------------------------------------------------------------------------------
*/
private Pool getInternalPool( HsmFlushControlCore.Pool pool ){
Pool ip = (Pool)pool.getDriverHandle() ;
if( ip == null ){
_log.warn("getInternalPool : Yet unconfigured pool arrived "+pool.getName()+"; configuring");
pool.setDriverHandle( ip = new Pool( pool.getName() , pool ) ) ;
}
return ip ;
}
public AlternatingFlushSchedulerV1( CellAdapter cell , HsmFlushControlCore core ){
_log.info("AlternateFlush started");
_core = core ;
_interpreter = new CommandInterpreter( this ) ;
}
//--------------------------------------------------------------------------------------
//
// call backs from the flush manager.
//
@Override
public void init(){
if(_parameter._p_events) {
_log.info("EVENT : Initiating ...");
}
Args args = _core.getDriverArgs() ;
//
// printout what we got from our master
//
for( int i = 0 ; i < args.argc() ; i++ ){
_log.info(" args "+i+" : "+args.argv(i)) ;
}
for( int i = 0 ; i < args.optc() ; i++ ){
_log.info(" opts "+args.optv(i)+"="+args.getOpt(args.optv(i))) ;
}
for (Object o : _core.getConfiguredPools()) {
_log.info(" configured pool : " + (o).toString());
}
//
// Walk through the already known pools, create our internal presentation
// and send the 'queryPoolIoMode'.
//
for (Object o : _core.getConfiguredPools()) {
HsmFlushControlCore.Pool pool = (HsmFlushControlCore.Pool) o;
Pool ip = getInternalPool(pool);
_log.info("init : " + pool.getName() + " " + ip);
}
String tmp = args.getOpt("driver-config-file") ;
if( tmp != null ) {
_parameter = new AltParameter(new File(tmp));
}
}
//--------------------------------------------------------------------------------------
//
// properties got updated.
//
@Override
public void propertiesUpdated( Map<String,Object> properties ){
if(_parameter._p_events) {
_log.info("EVENT : propertiesUpdated : " + properties);
}
_parameter.propertiesUpdated( properties ) ;
}
//--------------------------------------------------------------------------------------
//
// pool I/O mode got updated.
//
@Override
public void poolIoModeUpdated( String poolName , HsmFlushControlCore.Pool pool ){
if(_parameter._p_events) {
_log.info("EVENT : poolIoModeUpdated : " + pool);
}
if( ! pool.isActive() ){
_log.warn("poolIoModeUpdated : Pool "+poolName+" not yet active (ignoring)");
return ;
}
Pool ip = getInternalPool( pool ) ;
ip.poolIoModeUpdated( pool.isReadOnly() ) ;
PoolSet poolSet = ip.getParentPoolSet() ;
poolSet.poolIoModeUpdated( ip , pool.isReadOnly() ) ;
}
@Override
public void flushingDone( String poolName , String storageClassName , HsmFlushControlCore.FlushInfo flushInfo ){
if(_parameter._p_events) {
_log.info("EVENT : flushingDone : pool =" + poolName + ";class=" + storageClassName /* + "flushInfo="+flushInfo */);
}
HsmFlushControlCore.Pool pool = _core.getPoolByName( poolName ) ;
if( pool == null ){
_log.warn("flushingDone : for a non configured pool : "+poolName);
return ;
}
if( ! pool.isActive() ){
_log.warn("flushingDone : Pool "+poolName+" not yet active (ignoring)");
return ;
}
Pool ip = getInternalPool( pool ) ;
ip.flushingDone( flushInfo ) ;
if( ip._flushCounter == 0 ){
PoolSet poolSet = ip.getParentPoolSet() ;
poolSet.flushingDone( ip , storageClassName , flushInfo ) ;
}
}
@Override
public void poolFlushInfoUpdated( String poolName , HsmFlushControlCore.Pool pool ){
if(_parameter._p_events) {
_log.info("EVENT : poolFlushInfoUpdated : " + pool.getName());
}
//
if( ! pool.isActive() ){
_log.warn("poolFlushInfoUpdated : Pool "+poolName+" not yet active (ignoring)");
return ;
}
Pool ip = getInternalPool( pool ) ;
ip.poolFlushInfoUpdated(pool);
}
@Override
public void reset(){
if(_parameter._p_events) {
_log.info("EVENT : reset");
}
}
@Override
public void timer(){
if(_parameter._p_events) {
_log.info("EVENT : timer");
}
//
// check if the property file has been changed.
//
_parameter.updateIfNeeded() ;
//
// run the pool timer
//
for (Map.Entry<String, PoolSet> hostEntry : _hostMap.entrySet()) {
PoolSet hostMap = hostEntry.getValue();
for (Map.Entry<String, Pool> e : hostMap.entrySet()) {
e.getValue().timer();
}
}
//
// do the rule processing
//
if( ! _suspendFlushing ) {
processPoolsetRules();
}
}
/**
* Executes the external command with CommandInterpreter (using our ac_xx) commands.
*/
@Override
public void command( Args args ){
if(_parameter._p_events) {
_log.info("EVENT : command : " + args);
}
if (args.argc() == 0) {
return;
}
try{
Object reply = _interpreter.command( args ) ;
if( reply == null ) {
throw new
Exception("Null pointer from command call");
}
_log.info("Command returns : "+reply.toString() );
}catch(Exception ee ){
_log.warn("Command returns an exception ("+ee.getClass().getName()+") : " + ee.toString());
}
}
@Override
public void prepareUnload(){
if(_parameter._p_events) {
_log.info("EVENT : Preparing unload (ignoring)");
}
}
@Override
public void configuredPoolAdded( String poolName ){
if(_parameter._p_events) {
_log.info("EVENT : Configured pool added : " + poolName);
}
HsmFlushControlCore.Pool pool = _core.getPoolByName( poolName ) ;
if( pool == null ){
_log.warn("Pool not found in _core database : "+poolName);
return ;
}
if( ! pool.isActive() ){
_log.warn("Pool "+poolName+" not yet active (ignoring)");
return ;
}
Pool ip = getInternalPool( pool ) ;
}
@Override
public void poolSetupUpdated(){
if(_parameter._p_events) {
_log.info("EVENT : Pool Setup updated (ignoring)");
}
}
@Override
public void configuredPoolRemoved( String poolName ){
if(_parameter._p_events) {
_log.info("EVENT : Configured pool removed : " + poolName + " (ignoring)");
}
}
//-----------------------------------------------------------------------------------------
//
// RULE ENGINE
//
private void processPoolsetRules(){
if(_parameter._p_rules) {
_log.info("RULES : Processing PoolSet Rules...");
}
int totalAvailable = 0 ;
int totalReadOnly = 0 ;
int totalFlushing = 0 ;
int inProgress = 0 ;
//
// get some statistics on the known pools.
// (available,flushing, rdOnly). Add them to the
// candidate list if 'isCandidate' returns true.
//
ArrayList<Pool> candidates = new ArrayList<>() ;
HashSet<String> rdOnlyHash = new HashSet<>() ;
for (Object o : _core.getConfiguredPools()) {
HsmFlushControlCore.Pool pool = (HsmFlushControlCore.Pool) o;
Pool ip = (Pool) pool.getDriverHandle();
if ((ip == null) || (!ip.isReady())) {
continue;
}
totalAvailable++;
if (ip.isFlushing()) {
totalFlushing++;
}
if (pool.isReadOnly()) {
totalReadOnly++;
rdOnlyHash.add(pool.getName());
}
if (ip.getParentPoolSet().inProgress()) {
inProgress++;
continue;
}
if (isCandidate(ip)) {
candidates.add(ip);
}
}
if(_parameter._p_rules) {
_log.info("RULES : statistics : " +
"total=" + totalAvailable +
";readOnly=" + totalReadOnly +
";flushing=" + totalFlushing +
";progress=" + inProgress +
";candidates=" + candidates.size());
}
if(candidates.isEmpty()){
if(_parameter._p_rules) {
_log.info("RULES : no candidates found");
}
return ;
}
//if( totalReadOnly > (int)( (double)totalAvailable * _parameter._percentageToFlush ) ){
// if(_parameter._p_rules)_log.info("RULES : too many pools ReadOnly ("+totalReadOnly+" out of "+totalAvailable+")") ;
// return ;
//}
// DEBUG
if(_parameter._p_rules){
for (Object candidate : candidates) {
Pool pp = (Pool) candidate;
_log.info("RULES : weight of " + pp._name + " " + getPoolMetric(pp));
}
}
Collections.sort( candidates , _poolComparator );
//
Pool ip = candidates.get(0);
if(_parameter._p_rules) {
_log.info("RULES : weight of top " + ip._name + " " + getPoolMetric(ip));
}
//
// step through all candidates and check if they would overbook the max number
// of rdOnly pools.
//
PoolSet best = null ;
for (Object candidate : candidates) {
Pool pp = (Pool) candidate;
PoolSet ps = pp.getParentPoolSet();
if (_parameter._p_rules) {
_log.info("RULES : checking " + pp._name + "/" + ps._name + " " + getPoolMetric(pp));
}
Collection<String> potentialRdOnlyPools = new HashSet<>(rdOnlyHash);
for (Object o : ps.keySet()) {
potentialRdOnlyPools.add(o.toString());
}
if (_parameter._p_rules) {
_log.info("RULES : potential rdOnlyPools : " + potentialRdOnlyPools);
}
int total = potentialRdOnlyPools.size();
if (total > (int) ((double) totalAvailable * _parameter._percentageToFlush)) {
if (_parameter._p_rules) {
_log.info("RULES : " + ps._name + " would be too many pools ReadOnly (" + total + " out of " + totalAvailable + ")");
}
continue;
}
best = ps;
break;
}
if( best == null){
if(_parameter._p_rules) {
_log.info("RULES : no candidates found after all");
}
return ;
}
if(_parameter._p_rules) {
_log.info("RULES : flushing poolset : " + best._name + " with pools " + best
.keySet());
}
best.flushAll() ;
}
private PoolComparator _poolComparator = new PoolComparator() ;
public class PoolComparator implements Comparator<Pool> {
@Override
public int compare( Pool a , Pool b ){
double da = getPoolMetric( a ) ;
double db = getPoolMetric( b ) ;
return db == da ? 0 : da > db ? -1 : 1 ;
}
}
private double getPoolMetric( Pool ip ){
return
(
(double)ip._preciousSpace / (double) (MiB.toBytes(_parameter._maxPreciousStored)) +
(double)ip._preciousFileCount / (double) ( _parameter._maxFilesStored ) +
((double)( System.currentTimeMillis() - ip._oldestTimestamp ) / (double)(_parameter._maxTimeStored * 60000L) ) )
/ 3.0 ;
}
private boolean isCandidate( Pool ip ){
ip.refreshLocalVariables();
return
( ip._preciousSpace > (MiB.toBytes(_parameter._maxPreciousStored))) ||
( ip._preciousFileCount > _parameter._maxFilesStored ) ||
( ip._oldestTimestamp + ( _parameter._maxTimeStored * 60000L ) < System.currentTimeMillis() )
;
}
//-------------------------------------------------------------------------------------------
//
// C O M M A N D S
//
public static final String hh_dummy = "# dummy call" ;
public String ac_dummy_$_1_99( Args args ){
return args.toString();
}
public static final String hh_suspend = "# suspend next flush sequence, not preemptive";
public String ac_suspend( Args args ){
_suspendFlushing = true ;
return "" ;
}
public static final String hh_resume = "# resume flush sequence";
public String ac_resume( Args args ){
_suspendFlushing = false ;
return "" ;
}
public static final String hh_list_pools = "[-p [-l]] [-c]" ;
public String ac_list_pools( Args args ){
boolean parentView = args.hasOption("p") ;
boolean configuredView = args.hasOption("c") ;
boolean extended = args.hasOption("e") ;
if( parentView ){
for (Map.Entry<String, PoolSet> hostEntry : _hostMap.entrySet()) {
String hostName = hostEntry.getKey();
PoolSet hostMap = hostEntry.getValue();
_log.info(" >>" + hostName + "<<");
for (Map.Entry<String, Pool> e : hostMap.entrySet()) {
String name = e.getKey();
_log.info(" " + name + (extended ? e.getValue()
.toString() : ""));
}
}
}else if( configuredView ){
for (Object o : _core.getConfiguredPools()) {
HsmFlushControlCore.Pool pool = (HsmFlushControlCore.Pool) o;
_log.info(String.valueOf(pool));
}
}
return "";
}
public String ac_flush_poolset = "<poolSetName>" ;
public String ac_flush_poolset_$_1(Args args ){
String poolSetName = args.argv(0) ;
PoolSet poolSet = _hostMap.get(poolSetName);
if( poolSet == null ) {
throw new
IllegalArgumentException("PoolSet not found : " + poolSetName);
}
if( poolSet.inProgress() ) {
throw new
IllegalArgumentException("PoolSet in progress : " + poolSetName);
}
poolSet.flushAll();
return "" ;
}
//-------------------------------------------------------------------------------------------
//
// C O N V E N I E N E N T F U N C T I O N S
//
/**
*
* Convenient method to flush all pending storage classes of the specified pool.
*
* @param ip Internal pool representation.
*/
private int flushPool( HsmFlushControlCore.Pool pool ){
int flushing = 0 ;
for (Object o : pool.getFlushInfos()) {
HsmFlushControlCore.FlushInfo info = (HsmFlushControlCore.FlushInfo) o;
StorageClassFlushInfo flush = info.getStorageClassFlushInfo();
long size = flush.getTotalPendingFileSize();
_log.info("flushPool : class = " + info
.getName() + " size = " + size + " flushing = " + info
.isFlushing());
//
// is precious size > 0 and are we not yet flushing ?
//
try {
if ((size > 0L) && !info.isFlushing()) {
_log.info("flushPool : !!! flushing " + _parameter._flushAtOnce + " of " + pool
.getName() + " " + info.getName());
info.flush(_parameter._flushAtOnce);
flushing++;
}
} catch (Exception ee) {
_log.warn("flushPool : Problem flushing " + pool
.getName() + " " + info.getName() + " " + ee);
}
}
return flushing ;
}
/**
* Counts the number pending requests per pool.
*
* @return Number of flush requests per pool.
*/
private int countTotalActivePool( HsmFlushControlCore.Pool pool ){
int total = 0 ;
for (Object o : pool.getFlushInfos()) {
HsmFlushControlCore.FlushInfo info = (HsmFlushControlCore.FlushInfo) o;
StorageClassFlushInfo flush = info.getStorageClassFlushInfo();
total += flush.getActiveCount();
}
return total ;
}
/**
* Counts the number pending requests per pool.
*
* @return Number of flush requests per pool.
*/
private int countTotalPendingPool( HsmFlushControlCore.Pool pool ){
int total = 0 ;
for (Object o : pool.getFlushInfos()) {
HsmFlushControlCore.FlushInfo info = (HsmFlushControlCore.FlushInfo) o;
StorageClassFlushInfo flush = info.getStorageClassFlushInfo();
total += flush.getRequestCount();
}
return total ;
}
/**
* Gets the oldest file of this pool.
*
* @return Timestamp of the oldest file of this pool.
*/
private long getOldestFileTimestampPool( HsmFlushControlCore.Pool pool ){
long oldest = System.currentTimeMillis() ;
for (Object o : pool.getFlushInfos()) {
HsmFlushControlCore.FlushInfo info = (HsmFlushControlCore.FlushInfo) o;
StorageClassFlushInfo flush = info.getStorageClassFlushInfo();
oldest = Math.min(oldest, flush.getOldestFileTimestamp());
}
return oldest ;
}
/**
* Determines how many storage classes are in the process of being flushed on this pool.
*
* @return Number of storage class in progress of been flushed on this pool.
*/
private int countStorageClassesFlushing( HsmFlushControlCore.Pool pool ){
int flushing = 0 ;
for (Object o : pool.getFlushInfos()) {
if (((HsmFlushControlCore.FlushInfo) o).isFlushing()) {
flushing++;
}
}
return flushing ;
}
////////////////////////////////////////////////////////////////////////////
//
// Parameter handling
//
private static String PARAMETER_MAX_FILE = "max.files" ;
private static String PARAMETER_MAX_MINUTES = "max.minutes" ;
private static String PARAMETER_MAX_MEGABYTES = "max.megabytes" ;
private static String PARAMETER_TIMER = "timer" ;
private static String PARAMETER_MODE = "mode" ;
private static String PARAMETER_FLUSH_PERCENTAGE = "max.rdonly.fraction" ;
private static String PARAMETER_FLUSH_ATONCE = "flush.atonce" ;
private static String PARAMETER_RULE_TYPE = "rules.type" ;
private static String PARAMETER_PRINT_EVENTS = "print.events" ;
private static String PARAMETER_PRINT_RULES = "print.rules" ;
private static String PARAMETER_PRINT_POOL_PROGRESS = "print.pool.progress" ;
private static String PARAMETER_PRINT_POOLSET_PROGRESS = "print.poolset.progress" ;
//
//
private class AltParameter extends Parameter {
private long _maxFilesStored = 500L ;
private long _maxPreciousStored = KiB.toBytes(500L);
private long _maxTimeStored = ( 2L * 60L ) ;
private long _timer = ( 60L ) ;
private double _percentageToFlush = 0.5 ;
private int _countToFlush = 5 ;
private int _flushAtOnce;
private boolean _p_events;
private boolean _p_rules;
private boolean _p_poolset;
// private boolean _p_pool = false ;
// private String _mode = "auto" ;
// private String _ruleType = "poolset" ;
public AltParameter( ){ }
public AltParameter( File configFile ){ super( configFile ) ; }
public void propertiesUpdated( Map<String, Object> properties ){
Set<String> keys = new HashSet<>( properties.keySet() ) ;
//
// for all properties we support, try to change the values
// accordingly.
//
for (String key : keys) {
try {
if (key.equals(PARAMETER_MAX_FILE)) {
_maxFilesStored = handleLong(properties, PARAMETER_MAX_FILE, 0, 999999999);
} else if (key.equals(PARAMETER_MAX_MEGABYTES)) {
_maxPreciousStored = handleLong(properties, PARAMETER_MAX_MEGABYTES, 0, 999999999);
} else if (key.equals(PARAMETER_MAX_MINUTES)) {
_maxTimeStored = handleLong(properties, PARAMETER_MAX_MINUTES, 0, 999999999);
} else if (key.equals(PARAMETER_TIMER)) {
_timer = handleLong(properties, PARAMETER_TIMER, 0, 999999999);
} else if (key.equals(PARAMETER_FLUSH_ATONCE)) {
_flushAtOnce = handleInt(properties, PARAMETER_FLUSH_ATONCE, 0, 999999999);
} else if (key.equals(PARAMETER_PRINT_EVENTS)) {
_p_events = handleBoolean(properties, PARAMETER_PRINT_EVENTS);
} else if (key.equals(PARAMETER_PRINT_RULES)) {
_p_rules = handleBoolean(properties, PARAMETER_PRINT_RULES);
} else if (key.equals(PARAMETER_PRINT_POOLSET_PROGRESS)) {
_p_poolset = handleBoolean(properties, PARAMETER_PRINT_POOLSET_PROGRESS);
} else if (key.equals(PARAMETER_FLUSH_PERCENTAGE)) {
_percentageToFlush = handleDouble(properties, PARAMETER_FLUSH_PERCENTAGE, 0.0, 1.0);
// }else if( key.equals( PARAMETER_PRINT_POOL_PROGRESS ) ){
// _p_pool = handleBoolean( properties , PARAMETER_PRINT_POOL_PROGRESS ) ;
// }else if( key.equals( PARAMETER_MODE ) ){
// _mode = handleString( properties , PARAMETER_MODE , new String [] { "auto" , "manual" } ) ;
// }else if( key.equals( PARAMETER_RULE_TYPE ) ){
// _mode = handleString( properties , PARAMETER_RULE_TYPE , new String [] { "pool" , "poolset" } ) ;
} else {
//
// remove the key to inform the requestor that we don't
// support this property.
//
properties.remove(key);
}
} catch (Exception ee) {
_log.warn("Exception while seting " + key + " " + ee);
}
}
//
// do as it would have been a query
//
properties.put(PARAMETER_MAX_FILE , String.valueOf(_maxFilesStored)) ;
properties.put(PARAMETER_MAX_MEGABYTES , String.valueOf(_maxPreciousStored)) ;
properties.put(PARAMETER_MAX_MINUTES , String.valueOf(_maxTimeStored)) ;
properties.put(PARAMETER_TIMER , String.valueOf(_timer)) ;
properties.put(PARAMETER_FLUSH_PERCENTAGE , String.valueOf(_percentageToFlush)) ;
properties.put(PARAMETER_FLUSH_ATONCE , String.valueOf(_flushAtOnce)) ;
properties.put(PARAMETER_PRINT_EVENTS , String.valueOf(_p_events)) ;
properties.put(PARAMETER_PRINT_RULES , String.valueOf(_p_rules)) ;
properties.put(PARAMETER_PRINT_POOLSET_PROGRESS , String.valueOf(_p_poolset)) ;
// properties.put( PARAMETER_MODE , _mode ) ;
// properties.put( PARAMETER_RULE_TYPE , _ruleType ) ;
// properties.put( PARAMETER_PRINT_POOL_PROGRESS , ""+ _p_pool) ;
}
}
private class Parameter {
private long _configLastModified;
private File _configFile;
private Parameter(){}
private Parameter( File configFile ){
_configFile = configFile ;
}
protected void updateIfNeeded(){
if( _configFile == null ) {
return;
}
try{
Map<String, Object> map = updateConfigIfNewer(_configFile) ;
if( map == null ) {
return;
}
propertiesUpdated( map ) ;
}catch(Exception ee ){
}
}
private Map<String, Object> updateConfigIfNewer(File configFile) throws IOException {
if( ! configFile.exists() ) {
return null;
}
long lastModified = configFile.lastModified() ;
if( lastModified <= _configLastModified ) {
return null;
}
_configLastModified = lastModified ;
return readConfigFile( configFile ) ;
}
private Map<String, Object> readConfigFile(File configFile) throws IOException {
BufferedReader br = new BufferedReader( new FileReader( configFile ) ) ;
Map<String, Object> map = new HashMap<>() ;
try{
String line;
while( ( line = br.readLine() ) != null ){
line = line.trim() ;
if(line.isEmpty() || line.startsWith("#") ) {
continue;
}
int pos = line.indexOf('=') ;
if( ( pos <= 0 ) || ( pos == ( line.length() - 1 ) ) ) {
continue;
}
String key = line.substring(0,pos).trim() ;
if(key.isEmpty()) {
continue;
}
String value = line.substring(pos+1).trim() ;
if(value.isEmpty()) {
continue;
}
map.put( key , value ) ;
}
}catch(EOFException eof){
}finally{
try{ br.close() ; }catch(IOException ee ){}
}
return map ;
}
protected String handleString( Map<?,?> properties , String key , String [] options ){
Object obj = properties.get( key ) ;
if( obj == null ) {
throw new IllegalArgumentException("No Value for " + key);
}
String x = obj.toString() ;
if( options == null ) {
return x;
}
for (String option : options) {
if (option.equals(x)) {
return x;
}
}
throw new
IllegalArgumentException("Value for "+key+" is not legal" );
}
protected int handleInt( Map<String, Object> properties , String key , int minValue , int maxValue ){
Object obj = properties.get( key ) ;
if( obj == null ) {
throw new IllegalArgumentException("No Value for " + key);
}
int count = Integer.parseInt( obj.toString() ) ;
if( ( count < minValue ) || ( count > maxValue ) ) {
throw new
IllegalArgumentException("Value for " + key + " not in range " + minValue + " < n < " + maxValue);
}
return count ;
}
protected double handleDouble( Map<String, Object> properties , String key , double minValue , double maxValue ){
Object obj = properties.get( key ) ;
if( obj == null ) {
throw new IllegalArgumentException("No Value for " + key);
}
double count = Double.parseDouble( obj.toString() ) ;
if( ( count < minValue ) || ( count > maxValue ) ) {
throw new
IllegalArgumentException("Value for " + key + " not in range " + minValue + " < n < " + maxValue);
}
return count ;
}
protected long handleLong( Map<String, Object> properties , String key , long minValue , long maxValue ){
Object obj = properties.get( key ) ;
if( obj == null ) {
throw new IllegalArgumentException("No Value for " + key);
}
long count = Integer.parseInt( obj.toString() ) ;
if( ( count < minValue ) || ( count > maxValue ) ) {
throw new
IllegalArgumentException("Value for " + key + " not in range " + minValue + " < n < " + maxValue);
}
return count ;
}
protected boolean handleBoolean( Map<String, Object> properties , String key ){
Object obj = properties.get( key ) ;
if( obj == null ) {
throw new IllegalArgumentException("No Value for " + key);
}
if( obj.toString().equals("true") ){
return true ;
}else if( obj.toString().equals("false") ){
return false ;
}else{
throw new
IllegalArgumentException("Value for "+key+" must be boolean (true/false)" );
}
}
}
}