[osmosis-dev] calling DataPostbox.release() multiple times
Richard Hansen
rhansen at bbn.com
Wed Jan 18 23:17:48 GMT 2012
On 2012-01-18 07:23, Brett Henderson wrote:
>
> On 16 January 2012 07:22, Richard Hansen <rhansen at bbn.com> wrote:
>
>> On 2012-01-15 07:34, Brett Henderson wrote:
>>
>>> You're correct in saying that Releasable classes can be released
>>> multiple times, however that is not typically how they're used
>>> in the Osmosis pipeline.
>>
>> Does it make sense to change the Releasable API definition to say
>> that release can only be called once? Or might that break
>> multiple-sink stages like merge?
>
> I've updated the Releasable API definition to say that implementations
> should support release being called multiple times but that it isn't
> mandatory and cannot be relied on by clients.
Cool. With that change, no other changes should be necessary.
> release() and outputRelease() have been designed to support re-use. I
> don't think I've tested it, but I believe it will work. The two
> variables you mention are initialized near the start of those methods
> and only read after the xxxxReleased flags have been set so their
> initial state isn't important. However I can see that is confusing so
> I've modified their initial state to match their final state of true
> (I'll check it in shortly).
I agree with that change. The only other thing I would suggest is a
comment indicating that the class is designed to support reuse. (Or are
all tasks supposed to be reusable?)
>
> Your patch would probably work but I'd prefer to continue to support
> re-use rather than to use that variable for a second purpose.
Good point. With your Releasable contract change, the patch is
unnecessary anyway.
>
>> An alternative is to increase the burden on the users of
>> DataPostbox. They could be required to either ensure that the output
>> thread restarts or avoid calling DataPostbox.release() once the
>> output thread exits. For example, EntityBuffer.run() could set an
>> 'outputThreadIsRunning' boolean at the top and clear it at the end.
>> Then EntityBuffer.release() would be modified to only call
>> buffer.release() if outputThreadIsRunning is true.
>
> Race conditions between threads are tough to avoid, and I believe the
> above change would introduce one. If the output thread hasn't entered
> EntityBuffer.run yet and the outputThreadIsRunning flag hasn't been set,
> but the calling thread encounters an early exception and calls
> EntityBuffer.release, the calling thread will think that the output
> thread isn't running and there is no need to perform release
> functionality. This would then lead to the output thread blocking when
> it finally does start.
Yes, you are correct -- there is a race condition in that scheme.
Concurrency is fun, isn't it? :)
>
> The way the class is constructed now, each thread will synchronise at
> the initialize, complete and release methods. If either thread skips
> straight to release
Oh, I didn't realize that was possible. That makes it hard if not
impossible to support both reuse and multiple calls to release().
> then the other thread detects that as an error
> condition and aborts appropriately, but in all cases both threads will
> synchronise around release before exiting. The only reason to
> synchronise around release is to support re-use which may never be used
> in practice but it should work well. We can't even rely on the
> initialize methods being called because it is possible for a thread to
> fail before that is called.
>
> I'd rather leave the class as it is designed now. It's a tradeoff
> between supporting re-use and incurring the limitation that every call
> to release must be matched by a call to outputRelease in another
> thread. I don't think it's possible to have it both ways.
I agree with your analysis.
Thanks for making the changes!
-Richard
More information about the osmosis-dev
mailing list