sca-j message
[Date Prev]
| [Thread Prev]
| [Thread Next]
| [Date Next]
--
[Date Index]
| [Thread Index]
| [List Home]
Subject: Re: [sca-j] AW: ISSUE 8: Concurrency model for Service Reference instances
- From: Mike Edwards <mike_edwards@uk.ibm.com>
- To: "OASIS Java" <sca-j@lists.oasis-open.org>
- Date: Fri, 22 Feb 2008 11:13:53 +0000
Folks,
I wonder whether we're really getting
to the heart of the problem here.
Let's step back and examine the whole
picture for a moment.
At one level, we have a concern over
the use of references by multiple threads.
At another level we have an interest
in understanding how multiple conversations can be conducted by a client.
These interact, but not in the way that
we have been discussing.
There is a third question lurking about
how Callbacks work in a multi-threaded environment. I'll get to that
one later.
First, let's take a look at a simple
non-conversational service and a client with a reference to that service.
I think that the scope of the client
matters little, in fact. It's the usage of the reference that matters.
I think that a reference to a stateless
service can happily be invoked at any time by any thread belonging to
the client component. If the client
has multiple threads, there may be some concerns about the order of
requests that get sent, but that is
a problem for the client to sort out. It won't matter to the service.
There
are certainly no concerns that there
will be any "technical" problems invoking the service operations.
Now, switch attention to a conversational
service and the reference to that service held by a client.
It seems to me very simple to express
a principle here: a single reference instance object represents
at most a single conversation. (
I say "at most" since I think that we have said that is possible
for such
a reference to be in "conversation
not started" state and for non conversational invocations to take
place in that state.)
Now the usage of that single reference
object can be handled in one of two ways:
1) all uses of the reference, by any
thread, are for one conversation and one conversation only
2) over time, the reference may be used
for multiple conversations, but serially - again, only one
conversation at a time
1) requires relatively little management
other than ensuring only one set-up of a conversation ID.
2) requires more control to ensure that
each conversation is started and ended in a controlled
fashion (ie setting of a conversationID,
calling of an endsConversation method etc, must be
serialized)
Let's express another principle: if
a client of a conversational service wants to conduct multiple
conversations at the same time, it must
use multiple reference objects, one for each conversation.
(This implies necessary use of the context
API to fetch new copies of reference objects)
I think that the main concern over multi-thread
use of a conversational reference is thus solved
in a relatively simple way. If
you stick with the idea that one reference is only involved in one
conversation at a time, then things
are relatively simple and only a small amount of mechanics
is required.
One comment I make is: "why
do we allow the client to set the conversationID?" What's the
purpose of this? The conversation
is primarily about enabling the same service provider
data to be reached - the conversation
ID matters far more to the provider than to the client.
I argue for removing the capability
for a client to set the conversation ID.
Now, that has dealt with conversational
references. That leaves callbacks. I'll leave those
for another email....
Yours, Mike.
Strategist - Emerging Technologies, SCA & SDO.
Co Chair OASIS SCA Assembly TC.
IBM Hursley Park, Mail Point 146, Winchester, SO21 2JN, Great Britain.
Phone & FAX: +44-1962-818014 Mobile: +44-7802-467431
Email: mike_edwards@uk.ibm.com
"Barack, Ron"
<ron.barack@sap.com>
21/02/2008 22:15
|
To
| "OASIS Java" <sca-j@lists.oasis-open.org>
|
cc
|
|
Subject
| [sca-j] AW: ISSUE 8: Concurrency model
for Service Reference instances |
|
Hi Michael,
Let me first make sure I understand
your scenario. The composite-scoped component is essentially a middle
man, involved in 2 conversations, with amazon on one side, and the customer
on the other. And the problem is to make sure that requests coming
in from the client conversation get passed to the correct amazon conversation.
Both conversations can be long running. Does that fit?
I think the scenario we had in
mind was much more oriented to short lived conversations. That is,
the case where the whole conversation with StoreRef takes place within
a single call to buy books. In this case, you simply have to replace the
injected field "storeRef" with an injected ComponentContext,
and the implementation of buyBook would call context.getService("storeRef").
Whether the component calls storeRef.setConversationID or not, you
never have any race conditions.
The situation is more complex
for these long-running conversations, and I think it's unsurprising that
the code would be, too. In this case, the code would need to map
from the client conversation ID, to the ID of the amazon conversation.
That is, instead of checking if storeRef.getConversation() is null,
the code would call something like lookupStoreRefId(context.getRequestContext().getServiceReference().getConversationID()).
If the value returned was non-null, the component it would set the
storeRef.conversationID accordingly. Otherwise, it sets the conversionID
to chooseID(). The method lookupStoreRefId probably would use a DB,
but could use an in memory map, or anything else.
What I don't understand is how
the alternative proposal, "P1", would work. Are you expecting
the runtime in inject storeRef's conversationID into some thread local
storage before invoking buyBooks? In this case, isn't the implication
that the runtime would be maintaining the map, just like proposal P2 demands
that the client do? Or are you assuming that the conversationID is
already on the thread from previous calls to setConversationID? In
this case, it's true that the client remains very simple, but the solution
requires
a) that the
calls in the conversation always occur in the same thread, and
b) that the
server will not be restarted during the lifetime of the conversation.
Ron
Von: Michael Rowley [mailto:mrowley@bea.com]
Gesendet: Donnerstag, 21. Februar 2008 20:45
An: OASIS Java; Barack, Ron
Betreff: ISSUE 8: Concurrency model for Service Reference instances
Here is the description of the issue 8 problem
(from the PPT on today’s call):
While the current text says that
a service reference represents a single conversation, it is not clear how
a multi-threaded client should protect a non-conversational service reference's
configuration (conversation id, callback, etc) so that it stays unmodified
by other threads until an actual invocation is executed.
Consider the following code snippet for example:
class AComponent {
@Reference ItemCheckerService srv;
void goCheckItem(long ticket, String itemId) {
ServiceReference sr = (ServiceReference) srv;
sr.setConversationID(ticket);
srv.check(itemId);
}
}
A simple synchronization may lead to strict serialization of remote calls
which is generally undesirable.
I think we should have a good idea of the
likely scenarios in which this multi-threading will happen. On today’s
call, Simon suggested that code could start its own threads. I agree
this is true, but I don’t want to concentrate on that case, since I think
people who go there are willing to be pretty sophisticated about the threading
logic.
I believe other cases are that the client
could be conversation or composite scoped. Stateless and request
scoped components are only active for one thread at a time. This
is implied by the semantics of the @Init and @Destroy methods, which are
called at the beginning and end of the scope lifetime. For a stateless
scope, that lifetime is one call. For request scope, it is one remotable
call (to be clarified based on one of our open issues).
The scenario where a conversation-scoped
client could be active in two threads at once is possible, but unlikely,
so I’ll concentrate on the case where the client is composite scoped.
Consider this scenario: a composite scoped
component exists for the purpose of batching up book orders to Amazon.
When orders come in to the BookBatch component, it forwards them
on to Amazon, using the shopping cart that is associated with the current
conversation. After a certain amount of time, or a certain number
of books, the current batch is purchased, and the conversation is ended.
When the next book order comes in, a new batch (conversation) will
be started. How might this look:
@Scope(“COMPOSITE”)
class BookBatch {
@Reference BookStore store;
void buyBook(String ISBN) {
store.addToCart(ISBN);
if
(isTimeToCheckOut())
checkOut();
}
boolean isTimeToCheckOut() {}
void checkOut() {}
}
This seems like a potentially common
scenario where the client would be multi-threaded. Now, to run into
the problem, we have to imagine that the client wanted to choose its own
conversation ID. So, perhaps it would look like this:
@Scope(“COMPOSITE”)
class BookBatch {
@Reference ServiceReference<BookStore> storeRef;
void buyBook(String ISBN) {
if
(storeRef.getConversation() == null)
storeRef.setConversationID(chooseID());
storeRef.getService().addToCart(ISBN);
if
(isTimeToCheckOut())
checkOut();
}
boolean isTimeToCheckOut() {}
void checkOut() {}
String chooseID() {} // Choose
a conversation ID for the next bookstore conversation.
}
In this version, we pick a new
conversation ID if a conversation isn’t already going and set it on the
service reference.
This version has a race condition!
Multiple threads could have null returned from getConversation()
and so multiple threads will attempt to choose the next conversation ID.
In this particular case, it probably doesn’t matter which one wins
that race, but I suppose that in some cases it would matter.
Is this the problem we are trying
to solve? If so, I’m not sure how the proposal in the PPT presentation
given today would help much.
Ron or Simon, would you be willing
to modify this class so that it works correctly given the proposed resolution
to issue 8?
Michael
Unless stated otherwise above:
IBM United Kingdom Limited - Registered in England and Wales with number
741598.
Registered office: PO Box 41, North Harbour, Portsmouth, Hampshire PO6
3AU
[Date Prev]
| [Thread Prev]
| [Thread Next]
| [Date Next]
--
[Date Index]
| [Thread Index]
| [List Home]