package edu.washington.cs.oneswarm; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Logger; import edu.washington.cs.oneswarm.ui.gwt.BackendErrorLog; /** * Class which periodically profiles the overall state of the F2F plugin to * check invariants that we expect, thread liveness, etc. * * If an error is detected, it is logged as a reportable bug in the UI. */ public class HealthChecker extends Thread { private static Logger logger = Logger.getLogger(HealthChecker.class.getName()); public static final List<String> EXPECTED_THREAD_NAMES = new ArrayList<String>(); public HealthChecker() { setDaemon(true); setName("OneSwarmHealthChecker"); for (String s : new String[] { "DelayedSearchQueue", "QueueLengthChecker", "CommunityServer polling", "torrent pruning and F2F startstop", "OS Friend Connector", }) { EXPECTED_THREAD_NAMES.add(s); } } @Override public void run() { try { // Wait until a minute after startup before first run to allow // everything to boot Thread.sleep(60 * 1000); } catch (Exception e) { } while (true) { try { // Inspect the set of running threads and timers for the // expected set. Thread[] threads = new Thread[Thread.activeCount()]; Thread.enumerate(threads); Set<String> currentNames = new HashSet<String>(); for (Thread t : threads) { if (t != null) { currentNames.add(t.getName()); } } // If a thread has died, remove it from the expected set after // logging // the error to avoid polluting the log. List<String> toRemove = new ArrayList<String>(); for (String expected : EXPECTED_THREAD_NAMES) { if (currentNames.contains(expected) == false) { String errorStr = "*** Required thread seems to have died: " + expected; logger.severe(errorStr); BackendErrorLog.get().logString(errorStr); toRemove.add(expected); } } for (String r : toRemove) { EXPECTED_THREAD_NAMES.remove(r); } Thread.sleep(30 * 1000); } catch (Throwable t) { logger.warning("Unhandled error in the health checker: " + t.toString()); t.printStackTrace(); } } } }