← Prev in month ← Prev in thread

AW: ISSUE 8: Concurrency model for Service Reference instances

From
Barack, Ron <>
Date
2008-02-21T22:15:41+00:00
ID
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