All Downloads are FREE. Search and download functionalities are using the official Maven repository.

brooklyn.entity.group.zoneaware.AbstractZoneFailureDetector Maven / Gradle / Ivy

There is a newer version: 0.7.0-M1
Show newest version
package brooklyn.entity.group.zoneaware;

import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;

import brooklyn.entity.Entity;
import brooklyn.entity.group.DynamicCluster.ZoneFailureDetector;
import brooklyn.location.Location;

import com.google.common.annotations.Beta;
import com.google.common.base.Ticker;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

@Beta
public abstract class AbstractZoneFailureDetector implements ZoneFailureDetector {

    private final ConcurrentMap zoneHistories = Maps.newConcurrentMap();
    protected final Ticker ticker;
    
    public AbstractZoneFailureDetector() {
        this(Ticker.systemTicker());
    }
    
    public AbstractZoneFailureDetector(Ticker ticker) {
        this.ticker = ticker;
    }
    
    @Override
    public void onStartupSuccess(Location loc, Entity entity) {
        getZoneHistory(loc).onSuccess(currentTimeMillis());
    }

    @Override
    public void onStartupFailure(Location loc, Entity entity, Throwable cause) {
        getZoneHistory(loc).onFailure(currentTimeMillis(), cause);
    }

    @Override
    public boolean hasFailed(Location loc) {
        ZoneHistory zoneHistory = getZoneHistory(loc);
        return doHasFailed(loc, zoneHistory);
    }

    protected long currentTimeMillis() {
        return TimeUnit.NANOSECONDS.toMillis(ticker.read());
    }
    
    protected ZoneHistory getZoneHistory(Location loc) {
        ZoneHistory zoneHistory = zoneHistories.get(loc);
        if (zoneHistory == null) {
            ZoneHistory newZoneHistory = newZoneHistory(loc);
            ZoneHistory oldZoneHistory = zoneHistories.putIfAbsent(loc, newZoneHistory);
            zoneHistory = (oldZoneHistory != null) ? oldZoneHistory : newZoneHistory;
        }
        return zoneHistory;
    }

    protected ZoneHistory newZoneHistory(Location loc) {
        return new ZoneHistory();
    }

    /**
     * Warn: called should normally synchronize on zoneHistory while accessing it.
     */
    protected abstract boolean doHasFailed(Location loc, ZoneHistory zoneHistory);

    /**
     * Note: callers please don't side-effect the success/failures/causes fields directly!
     * Instead consider sub-classing ZoneHistory, and overriding {@link AbstractZoneFailureDetector#newZoneHistory(Location)}.
     */
    public static class ZoneHistory {
        public final List successes = Lists.newLinkedList();
        public final List failures = Lists.newLinkedList();
        public final List causes = Lists.newLinkedList();
        
        public synchronized void onSuccess(long date) {
            successes.add(date);
        }

        public synchronized void onFailure(long date, Throwable cause) {
            failures.add(date);
            causes.add(cause);
        }

        public synchronized void trimOlderThan(long date) {
            assert failures.size() == causes.size() : failures.size()+" failures, but "+causes.size()+" causes; bad synchronization by callers";

            for (Iterator iter = successes.iterator(); iter.hasNext();) {
                Long d = iter.next();
                if (d < date) iter.remove();
            }
            for (Iterator iter = failures.iterator(); iter.hasNext();) {
                Iterator causeIter = causes.iterator();
                Long d = iter.next();
                causeIter.next();
                if (d < date) {
                    iter.remove();
                    causeIter.remove();
                } else {
                    break;
                }
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy