final class GlobalEventManager
extends java.lang.Object
DirtyShareManager
and are posted here for further handling. Objects which
wish to process such events register
and deregister
via the DirtyShareManager
.
Events also are collected
via the
DirtyShareManager
. Since all access is managed throught that
interface, this class is package private.
This class is described as a "clearinghouse" rather than a "dispatcher",
because events are not dispatched via a "push" model. Rather, they are
collected by an instance of this object (one per physical database), and
await requests
by interested parties (i.e.,
registrants). This is a "pull" model for distributing these events.
A registrant registers interest in a particular type of DMO. Only events
which affect DMO types for which interest has been registered are collected
in this object's event queue. All other events are discarded upon receipt.
The following methods are used by a DirtyShareManager
to
enqueue events:
enqueueInsert(String, Persistable)
enqueueDelete(String, Serializable)
enqueueUpdate(String, Persistable, String[])
When a registrant collects new events, only those events which did not originate in that registrant's own context are provided. It is assumed that other mechanisms already exist to process "local" events.
The "pull" model of event distribution is used to prevent unnecessary event
traffic, since in the common case, very few objects are interested in
receiving such events. At the time of writing, this event distribution
mechanism is intended primarily to support the need for certain
AdaptiveQuery
instances to invalidate their results in
response to DMO changes in other sessions. By default, this is limited to
instances of AdaptiveFind
, which are more sensitive to such
changes than common AdaptiveQuery
instances.
Because a pull-based event model cannot be certain when all interested parties have processed each applicable event (or whether they ever will), some safeguards have been established to prevent both the premature release of needed events, and to prevent the unnecessary accumulation of old events which are no longer useful.
Each registrant is assigned a unique, sequential (ascending) registrant identifier upon registration. Registrants are tracked by these IDs. Each event is assigned a unique, sequential (ascending) event identifier, using the same sequence. Thus, IDs are unique across both all registrants and all events, and they are guaranteed to increase sequentially. When an event is enqueued, its ID is guaranteed to be higher than the registrant(s) interested in it.
When a registrant requests events, it provides the ID of the last event it retrieved. All new events (if any) collected after that ID are retrieved. When a registrant is no longer interested in events, it deregisters itself. Events older than the oldest registrant are purged at various points.
To prevent an idle registrant from pinning old events in the queue, an idle timeout check is applied at various points. If a registrant has been idle longer than the permitted timeout value, it is automatically deregistered. The next time that registrant requests new events (if ever), an exception is thrown, and it is up to the registrant to update its state accordingly.
In case a context is interrupted unexpectedly, all of its registrants are automatically deregistered. Even if this were not the case, the idle timeout would eventually clean up these resources.
TODO: enable directory-based configuration of idle timeout.
Modifier and Type | Class and Description |
---|---|
private static class |
GlobalEventManager.Context
Object which tracks registrants associated with the current session,
primarily for end-of-context cleanup purposes.
|
private static class |
GlobalEventManager.EventWrapper
Object which wraps a change event to remember the unique identifier of
the session which originated the event.
|
private class |
GlobalEventManager.PurgeWorker
A worker which purges idle registrants from the registrant map and
expired events from the event queue in a dedicated, daemon thread.
|
private static class |
GlobalEventManager.Registrant
A party which is interested in tracking index change for a particular
DMO type.
|
Modifier and Type | Field and Description |
---|---|
private ContextLocal<GlobalEventManager.Context> |
context
Object which tracks registrants by context for cleanup purposes
|
private Database |
database
Database for which this object manages global DMO change events
|
private static long |
DEFAULT_IDLE_TIME
Default time for a registrant to be idle before being expired
|
private java.util.concurrent.ConcurrentMap<java.lang.String,java.util.concurrent.atomic.AtomicInteger> |
entities
Map of entity names to reference counts of interested parties
|
private java.util.List<GlobalEventManager.EventWrapper> |
eventQueue
Event queue
|
private long |
idleTimeout
Time for a registrant to be idle before being expired
|
private java.util.SortedMap<java.lang.Long,GlobalEventManager.Registrant> |
interested
Map of interested party (registrant) IDs to registrants
|
private static java.util.logging.Logger |
log
Logger
|
private long |
nextID
Variable from which unique registrant and event IDs are assigned
|
Constructor and Description |
---|
GlobalEventManager(Database database)
Constructor
|
Modifier and Type | Method and Description |
---|---|
private void |
cleanupContext(GlobalEventManager.Context ctx)
Invoked when a context is ending, this method deregisters any
registrants associated with the local context.
|
(package private) void |
deregister(long id)
Deregister interest in index changes for a particular DMO type.
|
private void |
deregister(long id,
boolean purge)
Deregister interest in index changes for a particular DMO type.
|
(package private) void |
enqueueDelete(java.lang.String entity,
java.io.Serializable primaryKey)
Enqueue a DMO delete event, if any registrant is interested in it.
|
private void |
enqueueEvent(GlobalChangeEvent event)
Enqueue a DMO update, insert, or delete event.
|
(package private) void |
enqueueInsert(java.lang.String entity,
Persistable dmo)
Enqueue a DMO insert event, if any registrant is interested in it.
|
(package private) void |
enqueueUpdate(java.lang.String entity,
Persistable dmo,
java.lang.String[] properties)
Enqueue a DMO update event, if any registrant is interested in it.
|
(package private) GlobalChangeEvent[] |
getEvents(long registerID,
long lastID)
Retrieve any events which have been enqueued, which are newer than
lastID , and which correspond to the DMO entity for which
the specified registrant previously has registered interest. |
private boolean |
isEntityReferenced(java.lang.String entity)
Report whether any registrant is interested in events about the given
DMO type.
|
(package private) long |
register(java.lang.String entity)
Register interest in index changes for a particular DMO type.
|
private void |
resetQueue()
Reset the event queue by instantiating a new, empty queue and discarding
the old one, if any.
|
private void |
updateEntityRefCount(java.lang.String entity,
int delta)
Modify a reference count for the given DMO entity.
|
private static final java.util.logging.Logger log
private static final long DEFAULT_IDLE_TIME
private final Database database
private final java.util.SortedMap<java.lang.Long,GlobalEventManager.Registrant> interested
private final java.util.concurrent.ConcurrentMap<java.lang.String,java.util.concurrent.atomic.AtomicInteger> entities
private final ContextLocal<GlobalEventManager.Context> context
private final long idleTimeout
private java.util.List<GlobalEventManager.EventWrapper> eventQueue
private volatile long nextID
GlobalEventManager(Database database)
database
- Database for which events are tracked by this object.long register(java.lang.String entity)
entity
- DMO entity name.deregister(long)
void deregister(long id)
Invocation of this method triggers a purge sweep in a separate thread.
id
- Unique identifier previously assigned to the registrant to be
deregistered.register(String)
GlobalChangeEvent[] getEvents(long registerID, long lastID) throws EventRegistrationException
lastID
, and which correspond to the DMO entity for which
the specified registrant previously has registered interest.
As a side effect of this method, expired events may be detected, which are then purged from the event queue.
registerID
- A unique identifier for an object which has registered interest
in record-changing events.lastID
- A unique identifier representing the last event retrieved by
the caller. If less than 0, it is assumed no events have yet
been retrieved since the caller registered interest in these
events.null
if no
such events have been collected.EventRegistrationException
- if registerID
is invalid or has expired.void enqueueUpdate(java.lang.String entity, Persistable dmo, java.lang.String[] properties)
entity
- DMO entity name; identifies DMO type affected by update.dmo
- The DMO instance in its post-update state.properties
- Names of all properties which have been updated.void enqueueInsert(java.lang.String entity, Persistable dmo)
entity
- DMO entity name; identifies DMO type affected by insert.dmo
- The new DMO instance.void enqueueDelete(java.lang.String entity, java.io.Serializable primaryKey)
entity
- DMO entity name; identifies DMO type affected by update.primaryKey
- Primary key ID of the deleted DMO instance.private void enqueueEvent(GlobalChangeEvent event)
Invocation of this method triggers a purge sweep in a separate thread.
event
- Event object which encapsulates information about the change.private void deregister(long id, boolean purge)
Invocation of this method may trigger a purge sweep in a separate thread.
id
- Unique identifier previously assigned to the registrant to be deregistered.purge
- true
to trigger a purge sweep in a separate thread
after the deregistration takes place; else false
.private void updateEntityRefCount(java.lang.String entity, int delta)
entity
- DMO entity name.delta
- Amount to adjust the reference count. Should be 1 to increment
or -1 to decrement.private boolean isEntityReferenced(java.lang.String entity)
entity
- DMO entity name.true
if any registrant is interested in the given
DMO type, else false
.private void resetQueue()
private void cleanupContext(GlobalEventManager.Context ctx)
Invocation of this method triggers a purge sweep in a separate thread if any "orphaned" registrants were detected.
ctx
- Context requiring cleanup at end of life.