org.hd.d.pg2k.svrCore.location
Class LoadBalancingUtils

java.lang.Object
  extended by org.hd.d.pg2k.svrCore.location.LoadBalancingUtils

public final class LoadBalancingUtils
extends java.lang.Object

Load-balancing utility functions for stand-alone and Web apps.


Nested Class Summary
static class LoadBalancingUtils.BWOrder
          Our simple sorting comparator for mirrors sorts by bandwidth (or other Long metric) then name.
private static class LoadBalancingUtils.MirrorInfo
          Immutable info on interaction with one remote mirror.
 
Field Summary
private static java.util.Hashtable<java.lang.String,java.lang.Long> _cache_gAM
          Private cache for getActiveMirrors().
private static long _cache_gAM_valid_until
          Time _cache_gAM is valid until; initially zero marking the cache as invalid.
private static java.util.Map<java.lang.String,LoadBalancingUtils.MirrorInfo> _cache_tIHSIU_mirrorStatus
          Private cache for testIfHTTPServerIsUp() for which mirrors are up.
private static int _MAX_STALE_GET_ACTIVE_MIRRORS_MS
          Roughly how stale getActiveMirrors() is prepared for its answers to be, ms.
private static java.util.SortedMap<java.lang.String,java.lang.Long> _NO_LIVE_MIRRORS
          Immutable empty Map to indicate no live mirrors.
private static int _tIHSIU_CONN_ATTEMPTS
          Number of connection attempts before deciding that remote host is dead; strictly positive.
private static int _tIHSIU_CONN_TIMEOUT_MS
          Connection establishment timeout allowed by testIfHTTPServerIsUp(), in ms.
static boolean LOG_BALANCING_DECISIONS
          If true then always log balancing decisions.
private static int MIRROR_RECHECK_MS
          Target/normal/mean time before we (re)test that a mirror is working, in ms.
 
Constructor Summary
private LoadBalancingUtils()
          Prevent construction of an instance.
 
Method Summary
static java.lang.String findFirstWorkingMirror(java.util.List<java.lang.String> orderedMirrorTags)
          Try the requested mirrors in turn, returning the full hostname of the first that is up, or null if none is available.
static java.util.SortedMap<java.lang.String,java.lang.Long> getActiveMirrors(SimpleVariablePipelineIF vars, boolean filterStale)
          Get active mirrors listed by mirror tag; may be empty but never null.
static java.lang.String makeMirrorHostnameFromTag(java.lang.String mirrorTag, java.lang.String domainName)
          Make full hostname of site given a mirror tag; never null/empty.
static java.lang.String makeMirrorNameFromTag(java.lang.String tag)
          Construct a full mirror host name from the mirror tag.
static java.util.List<java.lang.String> orderMirrorTagsBestBandwidthFirst(java.util.Map<java.lang.String,java.lang.Long> availableMirrors)
          Orders mirrors into "fastest first" order, returning a List of mirror tags and dropping any known unusable; never null.
static java.lang.Boolean testIfHTTPServerIsUp(java.lang.String hostAndPort, boolean checkAsynchronously)
          Tests if an HTTP Gallery mirror server is up and running and responding quickly.
static boolean testIfHTTPServerIsUp(java.net.URL serverURL)
          Tests if a Web server is up and running and responding quickly.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

LOG_BALANCING_DECISIONS

public static final boolean LOG_BALANCING_DECISIONS
If true then always log balancing decisions.

See Also:
Constant Field Values

_cache_gAM

private static final java.util.Hashtable<java.lang.String,java.lang.Long> _cache_gAM
Private cache for getActiveMirrors(). A map from mirror tag (String) to available bandwidth in bytes-per-second-per-new-client (Long).

A Hashtable is used for thread safety, but also a lock on this value is used as a lock by getActiveMirrors() where needed.

TODO: ensure that size is bounded and/or dead entries can be trimmed on memory shortage.


_cache_gAM_valid_until

private static long _cache_gAM_valid_until
Time _cache_gAM is valid until; initially zero marking the cache as invalid.


_MAX_STALE_GET_ACTIVE_MIRRORS_MS

private static final int _MAX_STALE_GET_ACTIVE_MIRRORS_MS
Roughly how stale getActiveMirrors() is prepared for its answers to be, ms.

See Also:
Constant Field Values

_NO_LIVE_MIRRORS

private static final java.util.SortedMap<java.lang.String,java.lang.Long> _NO_LIVE_MIRRORS
Immutable empty Map to indicate no live mirrors.


MIRROR_RECHECK_MS

private static final int MIRROR_RECHECK_MS
Target/normal/mean time before we (re)test that a mirror is working, in ms. Should be of the order of minutes to tens of minutes, (and the results may be effectively cached in pages' HTML for a while) but not so long as to make the system insensitive to extended outages or gross configuration errors.

We randomise this a little to help avoid (re)testing collisions between peers.

Testing may be slow and/or consume significant network resources.

We may asymmetrically retain positive results longer than negative ones.


_tIHSIU_CONN_TIMEOUT_MS

private static final int _tIHSIU_CONN_TIMEOUT_MS
Connection establishment timeout allowed by testIfHTTPServerIsUp(), in ms. Fairly short to make sure that a server is responding reasonably quickly, but long enough to allow for DNS lookup and the odd lost packet and some intermittent Net congestion.

Should be of the order of a few seconds to a few tens of seconds.


_tIHSIU_CONN_ATTEMPTS

private static final int _tIHSIU_CONN_ATTEMPTS
Number of connection attempts before deciding that remote host is dead; strictly positive.


_cache_tIHSIU_mirrorStatus

private static final java.util.Map<java.lang.String,LoadBalancingUtils.MirrorInfo> _cache_tIHSIU_mirrorStatus
Private cache for testIfHTTPServerIsUp() for which mirrors are up. Map from mirror full host name component of URL (not just the mirror tag) to last time server at that URL was tested and found to respond properly (eg fast enough and with no error) or not.

Uses a thread-safe Map implementation.

TODO: must cap size and/or ensure that dead entries can be trimmed especially under memory stress.

Constructor Detail

LoadBalancingUtils

private LoadBalancingUtils()
Prevent construction of an instance.

Method Detail

getActiveMirrors

public static final java.util.SortedMap<java.lang.String,java.lang.Long> getActiveMirrors(SimpleVariablePipelineIF vars,
                                                                                          boolean filterStale)
Get active mirrors listed by mirror tag; may be empty but never null. Retrieves the tags (cc-xxxxx) of active mirrors from system variables, filtering out stale entries and those without significant free bandwidth.

Returns a Map from the mirror tag to the per-client bandwidth that the mirror claims to have available.

This does not check names in DNS, or that mirrors are actually responding, just which mirrors claim to be up as recorded in the system variables.

If this cannot retrieve the variable values that it needs, then this routine returns an (immutable) empty result.

This does not re-compute its value on each call, but caches it for a while since it may be expensive to compute.

It is possible to optionally leave in "stale" entries so as to be able to "coast" for a little longer after loss of contact with the master.

Parameters:
vars - the system variables; never null
filterStale - if true, filter out stale entries; this result is not cached
Returns:
non-null immutable empty, or new mutable non-empty Map that is private to the caller

makeMirrorHostnameFromTag

public static java.lang.String makeMirrorHostnameFromTag(java.lang.String mirrorTag,
                                                         java.lang.String domainName)
Make full hostname of site given a mirror tag; never null/empty. The host name returned is relative to the given domain name.

No checking is done that the resulting name actually refers to a valid host.

Result is undefined if the tag is not a valid mirror tag.


makeMirrorNameFromTag

public static java.lang.String makeMirrorNameFromTag(java.lang.String tag)
Construct a full mirror host name from the mirror tag. Result is undefined if the tag is invalid.


findFirstWorkingMirror

public static java.lang.String findFirstWorkingMirror(java.util.List<java.lang.String> orderedMirrorTags)
Try the requested mirrors in turn, returning the full hostname of the first that is up, or null if none is available. The mirrors are tried in the order in the list.

The cache of mirror state is used, and updated if need be.

This routine may take considerable time to complete if this has to actually test the mirrors and they are down and/or network connectivity is poor.

Parameters:
orderedMirrorTags - valid mirror tags in the order the mirrors should be tried
Returns:
the full hostname of the first working mirror found, or null if none of the mirrors specified appear to be up

orderMirrorTagsBestBandwidthFirst

public static java.util.List<java.lang.String> orderMirrorTagsBestBandwidthFirst(java.util.Map<java.lang.String,java.lang.Long> availableMirrors)
Orders mirrors into "fastest first" order, returning a List of mirror tags and dropping any known unusable; never null. This accepts as input a set of mirror details as returned from getActiveMirrors() (a mapping from mirror tag to claimed available bandwidth per client).

The results will be ordered to be highest-bandwidth first, and then by name.

This will drop mirrors known from the cache to be dead/unreachable, and any mirrors that are much slower than the best available.

The result will be smaller when inappropriate/slow/dead mirrors are dropped from the result.

This does not synchronously attempt to verify the accuracy of the data that it has been passed, eg it does not do blocking DNS lookups nor make HTTP connections, so should always be reasonably fast. (It does however check the status of remote mirrors asynchronously, and won't return a candidate unless verified to be working.)

Parameters:
availableMirrors - mapping of mirror tags to available per-client bandwidth; never null
Returns:
private, mutable-unless-empty, best-first list of mirrors; may be empty and/or smaller than the input set but never null

testIfHTTPServerIsUp

public static java.lang.Boolean testIfHTTPServerIsUp(java.lang.String hostAndPort,
                                                     boolean checkAsynchronously)
Tests if an HTTP Gallery mirror server is up and running and responding quickly. The hostname or the hostname:port must be supplied; the "null" page will be polled (which should always work unless the host is down or busy).

Tests that the web server responds quickly and without error (we must get response code 200), to a request for its top-level page "/null.jsp" (redirections are allowed, eg to an index.html or index.jsp).

If an invalid (non-null) host name is supplied this will return false.

We should only do one of these at a time for a given host in order to avoid overloading any one remote mirror.

Note that even if we check synchronously, we may still record any result in the cache so that another caller may benefit. This also means that this routine can call itself recursively (with the checkAsynchronously argument false) via asynchronous threads.

Note that this may run as many threads as there are different hosts whose status is being requested. We could probably do better with non-blocking I/O and a single worker thread if there are many hosts to check, but the assumption is that there will not be.

Parameters:
hostAndPort - hostname or hostname:port for mirror; never null
checkAsynchronously - if false we check synchronously and block until we can return TRUE or FALSE, else we return immediately and check in the background
Returns:
TRUE if the specified server seems to be up and running, FALSE if the server seems to be down, and null if we do not know at the moment (never returns null for a synchronous check)

testIfHTTPServerIsUp

public static boolean testIfHTTPServerIsUp(java.net.URL serverURL)
Tests if a Web server is up and running and responding quickly. A full URL must be supplied.

Tests that the web server responds quickly and without error (we must get response code 200), to a HEAD request for a special light-weight page "/null.jsp" (redirections are allowed, eg to an index.html or index.jsp).

If an invalid (non-null) host name is supplied this will return false.

We should only do one of these at a time for a given host in order to avoid overloading any one remote mirror.

Parameters:
serverURL - full URL for remote server (page) to test; never null
Returns:
true if the specified server seems to be up and running, false otherwise

DHD Multimedia Gallery V1.60.69

Copyright (c) 1996-2012, Damon Hart-Davis. All rights reserved.