[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
I agree. I guess my concern is that the scenario in
which the P2 solution is helpful is, IMO, unlikely. One of the problems
is that I view threads as being used for only a few seconds at a time, while I
expect that conversations will typically last much longer than that. So, what is the harm in P2? I
suppose the main harm is in the name of the routine: getServiceReference(). In
my opinion, a “get” doesn’t sound like a create, and so I
would be surprised if I got a newly created object with each call to get(). If
the API to do create were called createServiceReference() instead, I suppose I
would be less uncomfortable about it. I suppose the question would then
be, how the client get the “current” conversational service
reference for the reference, as I believe that the most common case is that
there will only be one conversation going at a time, especially when the client
is conversation scoped. Michael From: Barack,
Ron [mailto:ron.barack@sap.com] Hi Michael, So my understanding of
the scenario was wrong... the component isn't a middleman, he's a funnel.
All the requests that come in, regardless of the client conversation go into
the same conversation with amazon. In this case, the deeper
problem is not the race condition of setConversationID, but whether or not
ServiceReference is thread safe, and in particular if the service invocation
must be implemented in a thread safe manner. AFAIK, the spec
currently makes no such statement. OTOH, do we say anywhere that service
reference are NOT thread safe. Should we? I believe your code
sample to be correct, and believe that it's the client's responsibility to
handle synchronization in this case. I'm not sure how to even express the
behavior that the runtime would need, in order to relieve the client of this
responsiblity. But that wasn't my
understanding of Issue-8. Issue-8 is, I thought, 2 threads, both of which
want to participate in seperate conversations, using the same service
reference. Does everyone now agree that they cannot? In a way,
your solution is consistent with P2... which also does not proposal any
new functionality, but says to use the tools that already there to solve the
problem. In your scenario, where the reference is shared, the client must
perform synchronization. In my scenario, where different
threads participate in different conversations, then ComponentContext
must be used as a ServiceReference factory. Ron
Von:
Michael Rowley [mailto:mrowley@bea.com] Ron, Thanks for taking on my
challenge. Responses inline... From: Barack,
Ron [mailto:ron.barack@sap.com] 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. <MR>I’ve
always described conversational services as being designed to enable
conversations between components that can possibly take days (as would this
book buying example).</MR> 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. <MR>It
doesn’t sound like that would solve the problem that my hypothetical
developer is trying to solve. He is trying to maintain a single
outstanding conversation with Amazon, in order to batch up orders of books
(possibly to qualify for free shipping?). Your solution seems to
introduce multiple simultaneous conversations, which would defeat the purpose
of this batching. Also, RequestContext...getConversationID() called
from within the BookBatch component would not return anything, since the
communication to BookBatch would probably be non-conversational – after
all, it is composite scoped.</MR> What I
don't understand is howthe 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. <MR>I’m not
arguing for P1. I’m arguing that whatever solution we come up with
should solve the scenario that I laid forth, since it is, I believe, the most
common scenario where people will run into this problem. And, naturally,
I’d like for it to be fairly easy to use. I suspect that the
solution will include some kind of lock, from the time that the client decides
to set the ConversationID, until the business method is called. Perhaps
like this: void
buyBook(String ISBN) {
if (storeRef.getConversation() != null) {
storeRef.getService().addToCart(ISBN);
} else {
synchronized(storeRef) {
if (storeRef.getConversation() ==
null) {
storeRef.setConversationID(chooseID());
}
storeRef.getService().addToCart(ISBN);
} // synchronized
}
if (isTimeToCheckOut())
checkOut(); }
In this solution, the
call first call in the conversation has to be in a mutex section with the code
that sets the conversation ID, so it will not be concurrent. However, all
subsequent calls on the conversation can be concurrent. Note that this
solution is neither P1 nor P2. It basically just says that Java
synchronization needs to be used. </MR> Michael Ron Von:
Michael Rowley [mailto:mrowley@bea.com] 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. 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 {
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 {
if (storeRef.getConversation() == null)
storeRef.setConversationID(chooseID());
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 |
[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]