Peer-to-Peer Event Distribution
When a region or entry operation is performed, GemFire distributes the associated events in the distributed system according to system and cache configurations.
A distributed operation follows this sequence in a partitioned region:
- Apply the operation to the cache with the primary data entry, if appropriate.
- Do the distribution based on the subscription-attributes interest-policy of the other members.
- Invoke any listeners in the caches that receive the distribution.
- Invoke the listener in the cache with the primary data entry.
In the following figure:
- An API call in member M1 creates an entry.
- The partitioned region creates the new entry in the cache in M2. M2, the holder of the primary copy, drives the rest of the procedure.
These two operations occur simultaneously:
- The partitioned region creates a secondary copy of the entry in the cache in M3. Creating the secondary copy does not invoke the listener on M3.
- M2 distributes the event to M4. This distribution to the other members is based on their interest policies. M4 has an interest-policy of all , so it receives notification of all events anywhere in the region. Since M1 and M3 have an interest-policy of cache-content , and this event does not affect any pre-existing entry in their local caches, they do not receive the event.
The cache listener on M4 handles the notification of the remote event on M2.
Once everything on the other members has completed successfully, the original create operation on M2 succeeds and invokes the cache listener on M2.
A distributed operation follows this sequence in a distributed region:
- Apply the operation to the local cache, if appropriate.
- Invoke the local listeners.
- Do the distribution.
- Each member that receives the distribution carries out its own operation in response, which invokes any local listeners.
In the following figure:
- An entry is created through a direct API call on member M1.
- The create invokes the cache listener on M1.
- M1 distributes the event to the other members.
- M2 and M3 apply the remote change through their own local operations.
- M3 does a create, but M2 does an update, because the entry already existed in its cache.
- The cache listener on M2 receives callbacks for the local update. Since there is no cache listener on M3, the callbacks from the create on M3 are not handled. An API call in member M1 creates an entry.
For partitioned regions, GemFire guarantees ordering of events across threads, but for distributed regions it doesn’t. For multi-threaded applications that create distributed regions, you need to use your application synchronization to make sure that one operation completes before the next one begins. Distribution through the distributed-no-ack queue can work with multiple threads if you set the
conserve-sockets attribute to true. Then the threads share one queue, preserving the order of the events in distributed regions. Different threads can invoke the same listener, so if you allow different threads to send events, it can result in concurrent invocations of the listener. This is an issue only if the threads have some shared state - if they are incrementing a serial number, for example, or adding their events to a log queue. Then you need to make your code thread safe.