← Prev in month
← Prev in thread
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:]
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
← Prev in month
← Prev in thread