sca-j message
[Date Prev]
| [Thread Prev]
| [Thread Next]
| [Date Next]
--
[Date Index]
| [Thread Index]
| [List Home]
Subject: RE: [sca-j] ISSUE 8: PROPOSED RESOLUTION: Concurrency model for Service Reference instances
- From: "Peshev, Peter" <peter.peshev@sap.com>
- To: "Mike Edwards" <mike_edwards@uk.ibm.com>, "OASIS Java" <sca-j@lists.oasis-open.org>
- Date: Fri, 14 Mar 2008 14:32:41 +0100
Hi Mike,
I
don't have a problem with having whatever semantic we find appropriate and
more usable (get, create) as long as there is a single method in the API to
obtain a reference
I would prefer to not support 20% usecases
(multiple simultaneous conversations, reinjection and its description
of getServiceReference()), if they lead to further complication of the
API.
The multithreaded comment was because I was looking at
the beginning of the mail and the issue description in JIRA, later realized it
was debated heavily. Sorry.
Btw, you have my
+1 to get rid of the conversationId. If someone wishes that
much to use some manually created id for correlation among components, why
not pass it as parameter of the business
interface...
Best Regards
Peter
Peter,
I need to pick through your note - short though it is !
It touches on the really important points in this discussion.
Let's tackle the first one - with a
question I asked yesterday.
"Is it a
requirement for a client to be able to engage in multiple simultaneous
conversations with the same
conversational service?"
I
will admit that this is probably NOT the 80% case - but I think that this is a
capability that will be required by
more
sophisticated applications. It would seem to be very limiting to allow a
client to conduct multiple
simultaneous
conversations but only with different target services (this capability is
available, using the
current
specification).
Note that the
primary concern here is NOT thread safety but basic functionality.
Essentially it asks whether
a
client can have two or more reference instance objects which target the same
service, where each
instance represents
one conversation.
If we want to
support multiple simultaneous conversations, then we need APIs that will allow
the client
to create multiple reference
instance objects for a single reference (unless you can think of another
method of achieving the same function). I
am in favour of this capability.
Supporting clients with multiple threads seems a basic requirement of
supporting clients in the Java
language.
Preventing the use of threads does not seem a good plan, although I might
agree with the
need for a level of
structure such as implied by JSR 236. How thread safety links with
reference instance
objects is a good
question. I think that the emails exchanged between myself and Michael
Rowley have
shown that there is actually
no requirement to change anything in the current specification - the
client
can provide all the
synchronization that is required and the API does not need extending or
altering.
So, I agree with you
that a multithreaded client needs careful construction to address thread
synchronization issues.
I believe that we could improve the specification in this
area by a small new section that discusses
sychronization requirements and provides a simple example (code similar
in form to the material
exchanged
between myself & Michael Rowley). This would not change the
specification and would
be
non-normative.
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
"Peshev, Peter"
<peter.peshev@sap.com>
13/03/2008 19:22
|
To
| Simon Nash/UK/IBM@IBMGB, "OASIS
Java" <sca-j@lists.oasis-open.org>
|
cc
|
|
Subject
| RE: [sca-j] ISSUE 8: PROPOSED
RESOLUTION: Concurrency model for Service Reference
instances |
|
Hi,
At least to me a multi-threaded composite-scoped client
engaged in several conversations and desiring to set manually the conversationId
is not a convincing usecase that justifies the confusion of having two
methods in the API -- getServiceReference & createServiceReference.
If
somebody wishes to create such designs, than he\she should be on his\her own to
assure thread safety. In addition if a real productively used component is
designed to be multithreaded, than most probably it already would need some
synchronizations around its business data and methods.
Best Regards
Peter
From: Simon Nash [mailto:NASH@uk.ibm.com]
Sent: Thursday, 13. March 2008 20:44
To: OASIS
Java
Subject: RE: [sca-j] ISSUE 8: PROPOSED RESOLUTION: Concurrency
model for Service Reference instances
I would be OK with the semantics proposed by Michael.
I would prefer to keep "get" with these semantics than remove it entirely.
We would need to write slightly more formal words for the spec to define
exactly what the semantics are.
Simon
Simon C. Nash, IBM Distinguished
Engineer
Member of the IBM Academy of Technology
Tel. +44-1962-815156
Fax +44-1962-818999
"Michael Rowley"
<mrowley@bea.com>
13/03/2008 18:34
|
To
| Simon
Nash/UK/IBM@IBMGB, "OASIS Java"
<sca-j@lists.oasis-open.org>
|
cc
|
|
Subject
| RE: [sca-j] ISSUE 8: PROPOSED
RESOLUTION: Concurrency model for Service Reference
instances |
|
To record my
reaction to this on this thread...
An explicit createServiceReference method is a good
idea. Given this, I think that getServiceReference should either be
removed or its sematics should be that it returns the same service references as
was (or would be) injected for the component. In other words, its result
is not affected by calls to createServiceReference().
I don’t feel
strongly about whether we remove it or keep it with those semantics. I do
not, however, think that “get” should be given the liberal semantics that Simon
suggested.
Michael
From: Simon Nash
[mailto:NASH@uk.ibm.com]
Sent: Thursday, March 13, 2008 11:04
AM
To: OASIS Java
Subject: [sca-j] ISSUE 8: PROPOSED
RESOLUTION: Concurrency model for Service Reference instances
I presume the reference
is to a conceptual internal "set" that would occur as part of rewiring, and not
any "set" API call. With this understanding, your model for "get"
semantics makes sense.
In our last discussion of the issue there seemed
to be some support for introducing a createServiceReference() method on
ComponentContext to return a newly created ServiceReference object. This
solves the problem and is upward compatible with the existing API. We
would probably also need to add a createServiceReferences() method with similar
semantics.
The question then arises whether the semantics of
getServiceReference() or getServiceReferences() need to be specified more
tightly, for example to always return the same instance that was returned by a
previous call except in some specified list of cases. I believe this isn't
necessary or desirable, as it would over-constrain implementation
flexibility.
So my proposal is to resolve this issue by adding
the following methods to ComponentContext():
<B>
ServiceReference<B> createServiceReference(Class<B>
businessInterface, String referenceName) - Returns a newly created typed service
reference for a business interface type and a reference name. This method
MUST throw an IllegalArgumentException if the reference has multiplicity greater
than one.
<B>
Collection<ServiceReference<B>>
createServiceReferences(Class<B> businessInterface, String referenceName)
- Returns a list of newly created typed service references for a business
interface type and a reference name.
Simon
Simon
C. Nash, IBM Distinguished Engineer
Member of the IBM Academy of
Technology
Tel. +44-1962-815156 Fax +44-1962-818999
"Michael Rowley"
<mrowley@bea.com>
28/02/2008 21:50
|
To
| Simon
Nash/UK/IBM@IBMGB, "OASIS Java"
<sca-j@lists.oasis-open.org>
|
cc
|
|
Subject
| RE: [sca-j] AW: ISSUE 8:
Concurrency model for Service Reference
instances |
|
Wiring being changed
requires a call to set(), so naturally, after a set() the value of get() will be
different. If someone accesses a reference twice, without the reference
having been modified between those two accesses, then one would expect to get
the same thing.
Michael
From: Simon Nash
[mailto:NASH@uk.ibm.com]
Sent: Thursday, February 28, 2008 7:35
AM
To: OASIS Java
Subject: RE: [sca-j] AW: ISSUE 8:
Concurrency model for Service Reference instances
The semantics of getServiceReference() require it to return a
newly created object in some cases. Specifically, this will happen when
wiring has been changed, as we agreed in the resolution to issue 4. For
consistency and simplicity, I think this API should always return a newly
created object. The business logic can cache the result of a previous call
if it doesn't want a new object to be created.
Simon
Simon C. Nash, IBM Distinguished
Engineer
Member of the IBM Academy of Technology
Tel. +44-1962-815156
Fax +44-1962-818999
"Michael Rowley"
<mrowley@bea.com>
23/02/2008 16:05
|
To
| "Barack, Ron"
<ron.barack@sap.com>, "OASIS Java"
<sca-j@lists.oasis-open.org>
|
cc
|
|
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]
Sent: Friday, February 22, 2008 1:26
PM
To: Michael Rowley; OASIS Java
Subject: AW: [sca-j] AW:
ISSUE 8: Concurrency model for Service Reference instances
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]
Gesendet: Freitag, 22. Februar 2008
18:49
An: Barack, Ron; OASIS Java
Betreff: RE: [sca-j] AW:
ISSUE 8: Concurrency model for Service Reference instances
Ron,
Thanks for taking on my challenge.
Responses inline...
From: Barack, Ron
[mailto:ron.barack@sap.com]
Sent: Thursday, February 21, 2008 5:15
PM
To: OASIS Java
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.
<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]
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
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
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
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]