OASIS Mailing List ArchivesView the OASIS mailing list archive below
or browse/search using MarkMail.

 


Help: OASIS Mailing Lists Help | MarkMail Help

sca-j message

[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]


Subject: Re: AW: [sca-j] AW: ISSUE 8: Concurrency model for Service Referenceinstances



Ron,

Good discussion.....comment inline as <mje>...</mje>

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>

22/02/2008 18:25

To
"Michael Rowley" <mrowley@bea.com>, "OASIS Java" <sca-j@lists.oasis-open.org>
cc
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?

<mje>I had always taken the view that a ServiceReference or indeed a reference object, should be thread safe and as a result callable from multiple threads at the "same time".
I think that we should make statements about thread safety in the spec.</mje>
 
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.

<mje>I'm not convinced that we should expect the runtime to police this stuff - the timing of when to end a conversation is up to the client and the client needs to control it.
Mechanics to allow the system to provide the control could be unwieldy.</mje>
 
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?

<mje>I never thought that was possible.  The solution to that requirement is the simple one of having each thread have its own reference object, obtained via the context API, not a single shared injected reference.</mje>
 
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.

<mje>I agree with that approach, for multiple simultaneous conversations. For me the problem is multiple sequential conversations using a single reference object, where the transition from one conversation to the next requires careful control.  I've posted my solution to that problem in a separate email (I'm hoping for a gold star  ;-) ).</mje>
 
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








[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]