This chapter describes the constraints on service re-entrant calls and provides general guidelines for making calls between service threads.
This chapter includes the following sections:
Coherence does not support re-entrant calls. A "re-entrant service call" occurs when a service thread, in the act of processing a request, makes a request to that same service. As all requests to a service are delivered by using the inbound queue, and Coherence uses a thread-per-request model, each reentrant request would consume an additional thread (the calling thread would block while awaiting a response). Note that this is distinct from the similar-sounding concept of recursion.
The Coherence architecture is based on a collection of services. Each Coherence service consists of the Coherence code that implements the service, along with an associated configuration. The service runs on an allocated pool of threads with associated queues that receive requests and return responses.
A service is defined as a unique combination of a service name and a service type (such as Invocation, Replicated, or Distributed). For example, you can call from a distributed service Dist-Customers
into a distributed service named Dist-Inventory
, or from a distributed service named Dist-Customers
into a replicated service named Repl-Catalog
. Service names are configured in the cache configuration file using the <service-name>
element.
In the current implementation of Coherence, it is irrelevant whether the "call" is local or remote. This complicates the use of key association to support the efficient assembly of parent-child relationships. If you use key association to co-locate a Parent object with all of its Child objects, then you cannot send an EntryProcessor
to the parent object and have that EntryProcessor
"grab" the (local) Child objects. This is true even though the Child objects are in-process.
To access both a parent object and its child objects, you can do any of the following:
Embed the child objects within the parent object (using an "aggregate" pattern) or,
Use direct access to the server-side backing map (which requires advanced knowledge to do safely), or
Run the logic on another service (for example, Invocation targeted by using PartitionedService.getKeyOwner
), and have that service access the data by using NamedCache
interfaces, or
Place the child objects on another service which would allow reentrant calls (but incur network access since there is no affinity between partitions in different cache services).
Using the aggregate pattern is probably the best solution for most use cases. However, if this is impractical (due to size restrictions, for example), and there is a requirement to access both the parent and child objects without using a client/server model, the Invocation service approach is probably the best compromise for most use cases.
Even when re-entrancy is allowed, one should be very careful to avoid saturating the thread pool and causing catastrophic deadlock. For example, if service A calls service B, and service B calls service A, there is a possibility that enough concurrent calls could fill a thread pool, which would cause a form of deadlock. As with traditional locking, using ordered access (for example, service A can call service B, but not vice versa) can help.
So:
Service A calling into service A is never allowed
Service A calling into service B, and service B calling back into service A is technically allowed but is deadlock-prone and should be avoided if at all possible.
Service A calling into service B, and service B calling into service C, and service C calling back into service A is similarly restricted
Service A calling into service B is allowed
Service A calling into service B, and service B calling into service C, and service A calling into service C is similarly allowed
A service thread is defined as any thread involved in fulfilling a Coherence API request. Service threads may invoke any of the following entities:
Map Listeners
Membership Listeners
Custom Serialization/Deserialization such as ExternalizableLite
implementations
Backing Map Listeners
CacheLoader
/CacheStore
Modules
Query logic such as Aggregators
, Filters
, ValueExtractors
and Comparators
Entry Processors
Triggers
InvocationService
Invocables
These entities should never make re-entrant calls back into their own services.
Membership listeners can observe the active set of members participating in the cluster or a specific service. Membership listener threading can be complex; thus, re-entrant calls from a member listener to any Coherence service should be avoided.