|
|||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD | ||||||||
java.lang.Objectorg.hd.d.pg2k.svrCore.vars.BasicVarMgr
public class BasicVarMgr
Base class to "manage" the set of system variables. This holds the actual values and does:
This has a mechanism for discarding duplicate messages as they arrive.
Attempts to reign in retained state and 'acceptability' window in case of extreme system memory pressure, ie this tries to avoid ever being the cause of OOMs.
Thread-safe; does not hold any externally-visible locks.
This implements the generic variable-manager interface.
| Nested Class Summary | |
|---|---|
private static class |
BasicVarMgr.MessageIDKey
Immutable message ID suitable for use as a key in detecting duplicates. |
| Field Summary | |
|---|---|
private static MemoryTools.SimpleLRUMapAutoSizeForHitRate<Tuple.Triple<SimpleVariableDefinition,EventPeriod,java.lang.Long>,EventVariableValue> |
_getEmptyNonAuthEVV_cache
Cache of recently-requested 'empty' non-auth EVVs. |
private static java.util.concurrent.atomic.AtomicInteger |
_loadEVVSConcurrency
Records the current loading concurrency across all instances; ref never null, value never negative. |
private DuplicateIDChecker<BasicVarMgr.MessageIDKey> |
_updatesSeen
Set of historical values that we check incoming message against for duplicates. |
private static java.text.SimpleDateFormat |
dateFmtEHFile
Format we use to insert into event history file name. |
protected boolean |
dontFilterDups
Unless true we screen out duplicate events/updates and those with silly timestamps. |
private boolean |
endPoint
If true then this variable set is at an end-point. |
static java.lang.String |
EVENT_STORE_FILENAME_PREFIX
Prefix to event history store file name. |
static java.lang.String |
EVENT_STORE_FILENAME_SUFFIX_SER_GZ
Suffix for GZIPped serialised event history store file name. |
static java.lang.String |
EVENT_STORE_NAMETERM
Terminator to go after event name in file store. |
private java.util.concurrent.ConcurrentMap<SimpleVariableDefinition,EventVariableValueSet> |
eventHistory
Map of event history; never null. |
private static java.util.Calendar |
GMTCalendar
Our private static instance of a GMT calendar. |
protected static boolean |
isDebugMode
If true, this class (and possibly its derivatives) are in debug mode. |
private java.util.Queue<Tuple.Triple<SimpleVariableDefinition,java.io.File,java.util.concurrent.locks.ReentrantLock>> |
loadOrder
Definitions and the files from which their event histories are to be loaded; never null but may be empty. |
static long |
MAX_APPARENT_MESSAGE_AGE_MS
Maximum apparent age of message wrt local clock for message to pass filtering. |
static long |
MAX_UPSTREAM_RETENTION_MS
Time after which items pending to go upstream are dropped after an error. |
private static int |
MIN_DUP_CHECK_RETENTION_MS
Minimum message retention time for duplicate checking (ms); strictly positive. |
private java.util.concurrent.ConcurrentMap<SimpleVariableDefinition,Tuple.Triple<SimpleVariableDefinition,java.io.File,java.util.concurrent.locks.ReentrantLock>> |
remainingToBeLoaded
This is the thread-safe collection of all items waiting to be loaded; never null but may be empty. |
private static boolean |
SAVE_EVENT_HISTORIES_GZIPPED
If true, GZIP the saved histories to save space and read/write time. |
private java.util.Hashtable<SimpleVariableDefinition,SimpleVariableValue> |
variables
Cached variable values as map; never null. |
| Constructor Summary | |
|---|---|
BasicVarMgr()
Create a normal set of managed system variables, initially empty. |
|
BasicVarMgr(boolean endPoint)
Create a set of managed system variables. |
|
BasicVarMgr(boolean endPoint,
boolean dontFilterDups)
Create a set of managed system variables. |
|
| Method Summary | |
|---|---|
private java.util.concurrent.Callable<java.lang.Object> |
_createLoaderCallable()
Creates a Callable that processes all outstanding queued loads; never null. |
private void |
_loadEVVS(Tuple.Triple<SimpleVariableDefinition,java.io.File,java.util.concurrent.locks.ReentrantLock> job)
Loads into the internal store the specified EVVS from its serialised form in the file. |
private void |
_mergeValues(SimpleVariableValue newValue,
boolean fromUpstream)
Merge a new value into a variable in the cache. |
protected void |
_setVariable(SimpleVariableValue newValue,
boolean fromUpstream)
Set variable for upstream and downstream values. |
static EventVariableValue |
getEmptyNonAuthEVV(SimpleVariableDefinition def,
EventPeriod intervalSelector,
long intervalNumber)
Get a non-authoritative empty EventVariableValue with the specified definition/period/interval; never null. |
private EventVariableValueSet |
getEventHistory(SimpleVariableDefinition def)
Get the current event history for the given definition; never null but may return an empty value. |
EventVariableValue |
getEventValue(SimpleVariableDefinition def,
EventPeriod intervalSelector,
boolean current)
Get the current partial, or previous full, event set at the specified interval; never returns null. |
EventVariableValue[] |
getEventValues(SimpleVariableDefinition def,
EventPeriod intervalSelector,
long intervalNumber,
java.util.BitSet whichValues)
Get the specified event sets for the specified intervals; never null. |
SimpleVariableValue |
getVariable(SimpleVariableDefinition var)
Get a single variable value; returns null if no such value or wrong type. |
SimpleVariableValue[] |
getVariables(long changedSince)
Get set of variable values altered on or after a given time, or all for -1; never null. |
boolean |
isEndPoint()
Returns true if this is at an endpoint. |
private boolean |
isNonDup(SimpleVariableValue svv)
Check/accept message (with true return value) if not a duplicate. |
void |
loadEventHistories(java.io.File dir,
boolean async)
Load event histories from disc. |
void |
saveEventHistories(java.io.File dir,
boolean justChanges,
boolean keepHistory,
boolean incremental)
Persist variables and events to disc. |
void |
setEventValue(EventVariableValue evv)
Set/override the specified event sets for the specified intervals; never null. |
void |
setVariable(SimpleVariableValue newValue)
Set variable. |
int |
setVariables(SimpleVariableValue[] newValues)
Update a number of variables at once for efficiency; returns the number set. |
private boolean |
timestampAcceptable(SimpleVariableValue value)
Returns true if the supplied timestamp from an incoming message/event/update is OK. |
| Methods inherited from class java.lang.Object |
|---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
| Field Detail |
|---|
protected static final boolean isDebugMode
private final boolean endPoint
protected final boolean dontFilterDups
This should be enabled by default since it will quietly eliminate many problems; it may have to be off to run replays of old data for example.
public static final long MAX_UPSTREAM_RETENTION_MS
This is taken to be somewhat longer than the longest time that the data could reasonably be useful at first glance, to allow for clock skew and other insults.
Everything can probably be discarded safely after this time; some values can probably be discarded much sooner.
public static final long MAX_APPARENT_MESSAGE_AGE_MS
private static final int MIN_DUP_CHECK_RETENTION_MS
We must not accept messages at all that are outwith this minimum window.
private final DuplicateIDChecker<BasicVarMgr.MessageIDKey> _updatesSeen
As a minimum we must retain messages at least MAX_PEER_CLOCK_SKEW_MS but preferably up to MAX_APPARENT_MESSAGE_AGE_MS + MAX_PEER_CLOCK_SKEW_MS.
A lock can be held on this instance to make multiple operations atomic.
private final java.util.Hashtable<SimpleVariableDefinition,SimpleVariableValue> variables
Used by:
A lock must be held on this object to do multiple operations atomically, but no other visible lock must be grabbed inside a lock on this.
Mappings are never remove()d from this table; it is limited in size to the maximum number of variables defined in SystemVariables.
Hashtable from SimpleVariableDefinition to SimpleVariableValue.
A Hashtable is used for thread-safety and because a lock on it can exclude other operations.
Never null.
private final java.util.concurrent.ConcurrentMap<SimpleVariableDefinition,EventVariableValueSet> eventHistory
No lock must be held on this object, eg to do multiple operations atomically.
Mappings are never remove()d from this table; it is limited in size to the maximum number of variables defined in SystemVariables.
Thread-safe Map from SimpleVariableDefinition to SimpleVariableValue.
Never null.
private static final java.util.concurrent.atomic.AtomicInteger _loadEVVSConcurrency
private static final MemoryTools.SimpleLRUMapAutoSizeForHitRate<Tuple.Triple<SimpleVariableDefinition,EventPeriod,java.lang.Long>,EventVariableValue> _getEmptyNonAuthEVV_cache
private static final java.util.Calendar GMTCalendar
private static final java.text.SimpleDateFormat dateFmtEHFile
private static final boolean SAVE_EVENT_HISTORIES_GZIPPED
public static final java.lang.String EVENT_STORE_FILENAME_PREFIX
public static final java.lang.String EVENT_STORE_NAMETERM
EVENT_STORE_FILENAME_PREFIX + name + EVENT_STORE_NAMETERM [ + date ] + legal suffix
The nameterm includes at least one character that cannot appear in an event name to avoid ambiguity where one name is a prefix of another.
public static final java.lang.String EVENT_STORE_FILENAME_SUFFIX_SER_GZ
private final java.util.Queue<Tuple.Triple<SimpleVariableDefinition,java.io.File,java.util.concurrent.locks.ReentrantLock>> loadOrder
Entries should be taken from this with poll() and immediately locked with the Lock which will have them processed in preferred order, or in random order while attempting to load a history on demand by using the iterator and remove() and immediately attempting to lock with a failure treated as if the item had not been in the queue at all (because another Thread has stolen it).
The lock must be released after the item is removed from allToBeLoaded.
ConcurrentLinkedQueue for thread-safe lock-free access.
private final java.util.concurrent.ConcurrentMap<SimpleVariableDefinition,Tuple.Triple<SimpleVariableDefinition,java.io.File,java.util.concurrent.locks.ReentrantLock>> remainingToBeLoaded
| Constructor Detail |
|---|
public BasicVarMgr()
public BasicVarMgr(boolean endPoint)
This instance does filter out duplicate messages and invalid timestamps.
endPoint - if true then mark the system as an end-point
public BasicVarMgr(boolean endPoint,
boolean dontFilterDups)
endPoint - if true then mark the system as an end-pointdontFilterDups - if true then do NOT filter out duplicate
or out-of-time messages| Method Detail |
|---|
public boolean isEndPoint()
private boolean timestampAcceptable(SimpleVariableValue value)
This can be used by other classes, eg upstream of a temporary network disconnect, to decide if it is worth retaining an old message or if it would simply get discarded anyway at the other end by a var manager instance.
Note that events may and non-event values/types may get expired at different rates.
private boolean isNonDup(SimpleVariableValue svv)
Note that we store the value hash to avoid keeping large message values in memory indefinitely.
In passing this removes any expired entries outside the valid time window.
public void setVariable(SimpleVariableValue newValue)
throws java.io.IOException
We validate the the name/type of the variable being presented.
For local and globalMap variables, the last value set is the one that can be retrieved.
setVariable in interface BasicVarMgrInterfacejava.lang.IllegalArgumentException - on attempt to:
set variable with value of wrong type or incompatible definition,
set non-existent or read-only variable (or these can be ignored)
java.io.IOException - in case of I/O difficulty
protected void _setVariable(SimpleVariableValue newValue,
boolean fromUpstream)
We validate the the name/type of the variable being presented.
Since this allows read-only values to be updated, this is only visible to derived classes.
For local and globalMap variables, the last value set is the one that can be retrieved.
When setting a globalMap variable, we revisit the list of potentially-live systems and trim it if need be.
If eliminating/filtering duplicates and updates with invalid timestamps we do so silently here.
fromUpstream - if true, we allow read-only variables to be set
in our cache as they represent updated values from the source
and we only allow updates with globalMaps of at least size 1
java.lang.IllegalArgumentException - on attempt to:
set variable with value of wrong type or incompatible definition,
set non-existent or read-only variable (or these can be ignored)private EventVariableValueSet getEventHistory(SimpleVariableDefinition def)
private void _loadEVVS(Tuple.Triple<SimpleVariableDefinition,java.io.File,java.util.concurrent.locks.ReentrantLock> job)
throws java.io.IOException,
java.util.InvalidPropertiesFormatException
In case of error nothing is posted to the internal store but the lock is released and the entry removed from remainingToBeLoaded.
java.io.IOException
java.util.InvalidPropertiesFormatException
private void _mergeValues(SimpleVariableValue newValue,
boolean fromUpstream)
We always immediately apply a local or override the value and globalMap entry of a global, though for a global it will probably require the value merged at the master's end-point coming back to sort things out, with some instability/flapping in the interim.
The update must already have been validated, eg must not have more than one globalMap entry if a set.
This deals with events as well as plain variables.
Takes a lock on variables to make this atomic.
newValue - a variable update/set coming upstream/downstreamfromUpstream - if true, this is an update coming downstream
public int setVariables(SimpleVariableValue[] newValues)
throws java.io.IOException
This implementation "fails fast" on the first error.
setVariables in interface BasicVarMgrInterfacejava.lang.IllegalArgumentException - on attempt to:
set variable with value of wrong type or incompatible definition,
set non-existent or read-only variable (or these can be ignored)
java.io.IOExceptionpublic SimpleVariableValue getVariable(SimpleVariableDefinition var)
This trims from the globalMap any apparently-dead systems, and stores any such trimmed variable back in the cache atomically so as to incrementally eliminate stale data and return only reasonably fresh data to the caller.
getVariable in interface BasicVarMgrInterfacevar - definition of variable to fetch; never null
java.lang.IllegalArgumentException - if var is nullpublic SimpleVariableValue[] getVariables(long changedSince)
This may be slow if there are many live variables.
This implementation never throws an IOException.
Note: we may limit the notion of "all" to be something a little greater than the maximum live-variable time window (ie variable lifetime), since beyond this the variable value has expired and is not deemed trustworthy anyway.
getVariables in interface BasicVarMgrInterface
public EventVariableValue getEventValue(SimpleVariableDefinition def,
EventPeriod intervalSelector,
boolean current)
The current set is the most timely, but may not contain enough data to be meaningful if the new interval has just started.
The previous set is complete and thus most likely to have enough samples to be useful, but is not completely current.
If the requested event set is not available, an empty synthetic one is created and returned. Thus, with this interface, it is not possible to distinguish between there being no events in the given interval or simply no data.
This calls getEventValues().
This implementation will not throw an IOException.
getEventValue in interface BasicVarMgrInterfacedef - event definition (must be for an event); never nullintervalSelector - never nullcurrent - if true the current event set is returned,
else the previous complete set is returned
java.lang.IllegalArgumentException - if the request arguments are invalid
public static EventVariableValue getEmptyNonAuthEVV(SimpleVariableDefinition def,
EventPeriod intervalSelector,
long intervalNumber)
def - valid event definition; never nullintervalSelector - valid period for the definition; never nullintervalNumber - valid interval number for the period; strictly positive
public EventVariableValue[] getEventValues(SimpleVariableDefinition def,
EventPeriod intervalSelector,
long intervalNumber,
java.util.BitSet whichValues)
getEventValues in interface BasicVarMgrInterfaceintervalNumber - the number of the first interval
for which data is potentially required;
if too far in the past or future then possibly no data
will be available,
zero is used to access the "all" bucketwhichValues - each true bit represents a slot for which data is
required, bit 0 indicating data from the slot within which
firstIntervalTime is located, bit 1 the previous slot, etc;
null is treated as the common case equivalent to just bit 0 setdef - event definition (must be for an event); never nullintervalSelector - never null
public void setEventValue(EventVariableValue evv)
This may ignore the call, and certainly will if the intervalNumber is outside the current time window it holds.
This will generally accept the value and store it if:
evv - non-null event value
public void saveEventHistories(java.io.File dir,
boolean justChanges,
boolean keepHistory,
boolean incremental)
throws java.io.IOException
Only persistent event data is saved, and generally each named event type has its data saved in a separate file, in a form that should be reasonably robust (eg a failure to load one item should not have all items unloadable).
This data may be stored in binary serialised or XML forms, but is usually GZIPped to save space and speed up read/write.
If some saves fail then this will try to continue with others, but throw one of the errors encountered (usually the last one) at the end, so as to save as much as possible.
The incremental mode helps keeps the duration of any one call as small as is reasonably possible, but will be somewhat less efficient then non-incremental mode.
This locks out other activity while saving to ensure consistency; it need not hold a lock continuously for whole period of the call as it would usually be enough to do so while collecting candidate histories to save, and while actually saving each one of them separately.
To avoid deadlocks, this takes a lock on this instance before taking any other lock.
dir - the directory to save to; never nulljustChanges - just write histories changed since the last save if possible,
else unconditionally save all persistent event historieskeepHistory - if true, try to roll the logs at least daily
to help keep a trail of older snapshot though the storage space
required may grow without bound,incremental - if true, then at most one event is saved,
chosen in such a way (eg by max time since last save or randomly)
that eventually all eligible histories will be saved
java.io.IOException
public void loadEventHistories(java.io.File dir,
boolean async)
throws java.io.IOException
Only the event history will be loaded.
If some loads fail then this will try to continue with others, but re-throw one of the errors encountered (usually the last one) at the end, so as to load as much as possible.
Though running this call concurrently with other (mutator) operations (or indeed other instances of this call) should be safe, such operation is not advised.
Should be called at most once, before any set (and get) operations.
We try to load largest-first to maximise concurrency.
dir - the directory to load from; never nullasync - if true then the caller will not be blocked waiting to load histories
(else if false the caller will be blocked until they are all loaded)
and if possible the event histories will be loaded in the background else as-needed,
blocking access to individual histories not yet loaded while they are loaded;
this only works for event histories with no state loaded at all
java.io.IOExceptionprivate java.util.concurrent.Callable<java.lang.Object> _createLoaderCallable()
err -
|
DHD Multimedia Gallery V1.53.0 | ||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD | ||||||||