732 lines
33 KiB
C++
732 lines
33 KiB
C++
/*
|
|
Copyright (c) Microsoft Corporation
|
|
|
|
All rights reserved.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
|
|
compliance with the License. You may obtain a copy of the License
|
|
at http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER
|
|
EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
|
|
TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
|
|
|
|
|
|
See the Apache Version 2.0 License for specific language governing permissions and
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <channelitem.h>
|
|
|
|
class RChannelBufferPrefetchInfo;
|
|
enum TransformType;
|
|
|
|
/* this is a stub object that is e.g. passed to parsers and marshalers
|
|
when they are initialized. For example, DryadVertexProgramBase
|
|
inherits from this interface and is set as the context for all
|
|
parsers and marshalers in that vertex so that they can access
|
|
configuration parameters, etc. */
|
|
class RChannelContext : public IDrRefCounter
|
|
{
|
|
public:
|
|
virtual ~RChannelContext();
|
|
};
|
|
|
|
typedef DrRef<RChannelContext> RChannelContextRef;
|
|
|
|
class RChannelInterruptHandler
|
|
{
|
|
public:
|
|
/* When the byte-oriented layer from which a channel is reading
|
|
signals an error condition by delivering a Restart or Abort
|
|
buffer, the application may wish to learn this immediately
|
|
rather than waiting for the error item to be delivered (for
|
|
example, the application may be blocking reads from the channel
|
|
indefinitely, yet still want timely error notifications.) In
|
|
this case, the application can register an interrupt handler
|
|
which will be called back when an error occurs, or during Drain
|
|
if no error occurs.
|
|
|
|
interruptItem is the terminatino item which will eventually be
|
|
delivered. The callee of ProcessInterrupt should call IncRef on
|
|
interruptItem if it wants to store a reference to the item.
|
|
*/
|
|
virtual void ProcessInterrupt(RChannelItem* interruptItem) = 0;
|
|
};
|
|
|
|
|
|
class RChannelItemArrayReaderHandler
|
|
{
|
|
public:
|
|
RChannelItemArrayReaderHandler();
|
|
virtual ~RChannelItemArrayReaderHandler();
|
|
|
|
/* This sets the maximum number of items which will be delivered
|
|
via the ProcessItemArray callback. The default value is 1. */
|
|
void SetMaximumArraySize(UInt32 maximumArraySize);
|
|
UInt32 GetMaximumArraySize();
|
|
|
|
/* When an asynchronous item is ready to be delivered on a channel
|
|
this method is called on the handler object passed to the
|
|
associated call to RChannelReader::SupplyHandler().
|
|
|
|
If deliveredArray is empty and the asynchronous read was not
|
|
cancelled, then the channel has completed, i.e. a termination
|
|
item has been delivered to some other synchronous or
|
|
asynchronous read method. If there are multiple outstanding
|
|
reads the order of delivery is undefined so an empty array may
|
|
appear on one handler before the termination item has actually
|
|
been delivered.
|
|
|
|
If an asynchronous read is cancelled ProcessItem is called
|
|
before the Cancel call completes. If the array is empty in this
|
|
case it is impossible to determine from the ProcessItem
|
|
callback whether it occurred because of successful cancellation
|
|
or because a termination item has been delivered to the
|
|
application.
|
|
*/
|
|
virtual void ProcessItemArray(RChannelItemArray* deliveredArray) = 0;
|
|
|
|
/* there are two types of asynchronous handler: queued and
|
|
immediate. If the handler is queued, then it is called on a
|
|
worker thread which is specifically assigned for processing
|
|
items, and the application should perform as much computation
|
|
as necessary on the calling thread before returning.
|
|
|
|
If the handler is immediate then it may be called on a variety
|
|
of different threads, including I/O processing threads, and the
|
|
application should return as soon as possible. Immediate
|
|
handlers are suitable, for example, for waking up a synchronous
|
|
thread which has been blocking on a read, or for queueing a
|
|
work item to an application's private thread pool if the
|
|
standard thread pool is for some reason inappropriate.
|
|
|
|
In general rather than implementing the ImmediateDispatch
|
|
method the application should just inherit from
|
|
RChannelItemReaderHandlerImmediate or
|
|
RChannelItemReaderHandlerQueued.
|
|
*/
|
|
virtual bool ImmediateDispatch() = 0;
|
|
|
|
private:
|
|
UInt32 m_maximumArraySize;
|
|
};
|
|
|
|
/* the base class for an immediate item array handler, see
|
|
RChannelItemArrayReaderHandler::ImmediateDispatch above. */
|
|
class RChannelItemArrayReaderHandlerQueued :
|
|
public RChannelItemArrayReaderHandler
|
|
{
|
|
public:
|
|
bool ImmediateDispatch();
|
|
};
|
|
|
|
/* the base class for a queued item array handler, see
|
|
RChannelItemArrayReaderHandler::ImmediateDispatch above. */
|
|
class RChannelItemArrayReaderHandlerImmediate :
|
|
public RChannelItemArrayReaderHandler
|
|
{
|
|
public:
|
|
bool ImmediateDispatch();
|
|
};
|
|
|
|
class RChannelItemReaderHandler :
|
|
public RChannelItemArrayReaderHandler
|
|
{
|
|
public:
|
|
virtual ~RChannelItemReaderHandler();
|
|
|
|
/* When an asynchronous item is ready to be delivered on a channel
|
|
this method is called on the handler object passed to the
|
|
associated call to RChannelReader::SupplyHandler().
|
|
|
|
If deliveredItem is NULL and the asynchronous read was not
|
|
cancelled, then the channel has completed, i.e. a termination
|
|
item has been delivered to some synchronous or asynchronous
|
|
read method. If there are multiple outstanding reads the order
|
|
of delivery is undefined so a NULL may appear on one handler
|
|
before the termination item has actually been delivered.
|
|
|
|
If an asynchronous read is cancelled ProcessItem is called with
|
|
NULL before the Cancel call completes. In this case it is
|
|
impossible to determine from the ProcessItem callback whether
|
|
it occurred because of successful cancellation or because a
|
|
termination item has been delivered to the application.
|
|
|
|
If deliveredItem is non-NULL then the callee now owns a
|
|
reference to deliveredItem.
|
|
*/
|
|
virtual void ProcessItem(RChannelItem* deliveredItem) = 0;
|
|
|
|
/* there are two types of asynchronous handler: queued and
|
|
immediate. If the handler is queued, then it is called on a
|
|
worker thread which is specifically assigned for processing
|
|
items, and the application should perform as much computation
|
|
as necessary on the calling thread before returning.
|
|
|
|
If the handler is immediate then it may be called on a variety
|
|
of different threads, including I/O processing threads, and the
|
|
application should return as soon as possible. Immediate
|
|
handlers are suitable, for example, for waking up a synchronous
|
|
thread which has been blocking on a read, or for queueing a
|
|
work item to an application's private thread pool if the
|
|
standard thread pool is for some reason inappropriate.
|
|
|
|
In general rather than implementing the ImmediateDispatch
|
|
method the application should just inherit from
|
|
RChannelItemReaderHandlerImmediate or
|
|
RChannelItemReaderHandlerQueued.
|
|
*/
|
|
virtual bool ImmediateDispatch() = 0;
|
|
|
|
/* implementation of RChannelItemArrayReaderHandler interface */
|
|
void ProcessItemArray(RChannelItemArray* deliveredArray);
|
|
};
|
|
|
|
/* the base class for an immediate item handler, see
|
|
RChannelItemReaderHandler::ImmediateDispatch above. */
|
|
class RChannelItemReaderHandlerQueued : public RChannelItemReaderHandler
|
|
{
|
|
public:
|
|
bool ImmediateDispatch();
|
|
};
|
|
|
|
/* the base class for a queued item handler, see
|
|
RChannelItemReaderHandler::ImmediateDispatch above. */
|
|
class RChannelItemReaderHandlerImmediate : public RChannelItemReaderHandler
|
|
{
|
|
public:
|
|
bool ImmediateDispatch();
|
|
};
|
|
|
|
class SyncItemReaderBase
|
|
{
|
|
public:
|
|
virtual DrError ReadItemSync(RChannelItemRef* item /* out */) = 0;
|
|
};
|
|
|
|
class RChannelReader : public SyncItemReaderBase
|
|
{
|
|
public:
|
|
virtual ~RChannelReader();
|
|
|
|
/* a client must call Start to cause the channel to start
|
|
generating items for the first time, or after a Drain has
|
|
completed before the channel is restarted.
|
|
|
|
prefetchCookie is passed to the byte-oriented buffer layer and
|
|
should be NULL for now.
|
|
*/
|
|
virtual void Start(RChannelBufferPrefetchInfo* prefetchCookie) = 0;
|
|
|
|
/* SupplyHandler passes a handler which will be "returned" via a
|
|
matching call to handler->ProcessItemArray. Multiple handlers
|
|
may be outstanding at a given time. The channel blocks when
|
|
there are no handlers available, so this is the primary flow
|
|
control mechanism to allow the reader to exert back-pressure on
|
|
a channel.
|
|
|
|
If the channel has not been started or has delivered a
|
|
termination item to the application since the last call to
|
|
Start, handler->ProcessItemArray will be called with an empty
|
|
array on the calling thread before SupplyHandler returns.
|
|
|
|
If there is an item waiting to be delivered and handler is an
|
|
RChannelItemReaderHandlerImmediate then handler will be called
|
|
back with the items on the calling thread before SupplyHandler
|
|
returns.
|
|
|
|
If handler is an RChannelItemReaderHandlerQueued it will never
|
|
be called back on the calling thread. If there are items
|
|
waiting to be delivered, a processing request will be queued
|
|
for the item with handler, otherwise handler will be queued
|
|
waiting for the next item to be ready.
|
|
|
|
If thread B submits an RChannelItemReaderHandlerImmediate with
|
|
a call to SupplyHandler that is overlapped with thread A's call
|
|
to SupplyHandler, B's immediate handler may be called on A's
|
|
calling thread before A's call to SupplyHandler returns.
|
|
|
|
After a handler has been submitted to SupplyHandler with a
|
|
given value of cancelCookie, that handler is guaranteed to be
|
|
returned before any matching call to Cancel with the same value
|
|
of cancelCookie returns. If there is no item available at the
|
|
time the handler is cancelled it will be called with an empty
|
|
array. cancelCookie may take any value, including NULL, however
|
|
it is safest to use NULL or the address of an object owned by
|
|
the caller. The cancellation mechanism is used internally by
|
|
the synchronous FetchNextItem call which uses an allocated heap
|
|
address as its cancelCookie. Using the heap address of an
|
|
object which has not been freed before the call to Cancel will
|
|
avoid any danger of a cookie collision.
|
|
|
|
For any item A which has already been returned via an async
|
|
handler or call to FetchNextItem when SupplyHandler is called
|
|
it is guaranteed that A's sequence number is less than or equal
|
|
to the sequence number of the item eventually returned on
|
|
handler. Beyond this constraint, if multiple handlers are
|
|
outstanding at once, or while calls to FetchNextItem are in
|
|
progress, the order of delivered items is undefined.
|
|
*/
|
|
virtual void SupplyHandler(RChannelItemArrayReaderHandler* handler,
|
|
void* cancelCookie) = 0;
|
|
|
|
/* any handler passed to SupplyHandler with value cancelCookie is
|
|
guaranteed to be returned before a call to Cancel completes. */
|
|
virtual void Cancel(void* cancelCookie) = 0;
|
|
|
|
/* FetchNextItemArray blocks waiting until an item is available, a
|
|
termination item is delivered on another thread, or the timeOut
|
|
interval has elapsed (timeOut can be DrTimeInterval_Infinite in
|
|
which case FetchNextItem will block indefinitely).
|
|
|
|
If the timeout expires FetchNextItemArray returns false and
|
|
*pItemArray is an empty array. Otherwise FetchNextItem returns
|
|
true and the any returned items are stored in
|
|
*pItemArray. *pItemArray may be empty even if
|
|
FetchNextItemArray returns true: this will happen if Start has
|
|
not been called or a termination item has already been
|
|
delivered on the channel since the last call to Start. At most
|
|
maxArraySize items will be delivered in *pItemArray, however
|
|
fewer may be delivered.
|
|
*/
|
|
virtual bool FetchNextItemArray(UInt32 maxArraySize,
|
|
RChannelItemArrayRef* pItemArray,
|
|
DrTimeInterval timeOut) = 0;
|
|
|
|
/* FetchNextItem blocks waiting until an item is available, a
|
|
termination item is delivered on another thread, or the timeOut
|
|
interval has elapsed (timeOut can be DrTimeInterval_Infinite in
|
|
which case FetchNextItem will block indefinitely).
|
|
|
|
If the timeout expires FetchNextItem returns false and *outItem
|
|
is NULL. Otherwise FetchNextItem returns true and the returned
|
|
item is stored in *outItem. *outItem may be NULL even if
|
|
FetchNextItem returns true: this will happen if Start has not
|
|
been called or a termination item has already been delivered on
|
|
the channel since the last call to Start.
|
|
*/
|
|
bool FetchNextItem(RChannelItemRef* pOutItem,
|
|
DrTimeInterval timeOut);
|
|
DrError ReadItemSync(RChannelItemRef* pOutItem /* out */);
|
|
|
|
/* Instruct the channel to stop reading items and prepare for
|
|
Drain. The interruptItem must be of type RChannelItem_Abort,
|
|
RChannelItem_Restart, RChannelItem_EndOfStream or
|
|
RChannelItem_ParseError. If the channel is an in-process FIFO
|
|
or a pipe which has not broken, the interruptItem will be
|
|
delivered to the remote end and the remote writer will
|
|
therefore be made aware of the channel close request. Interrupt
|
|
may be called multiple times after a channel has been Started
|
|
and before it has been Drained. The first call will have its
|
|
interruptItem delivered; subsequent interruptItems will be
|
|
discarded. If multiple calls to Interrupt are overlapped, the
|
|
call whose interruptItem gets delivered is undefined. The
|
|
caller's reference to interruptItem is not modified by this
|
|
call.
|
|
*/
|
|
virtual void Interrupt(RChannelItem* interruptItem) = 0;
|
|
|
|
/* Instruct the channel to return all outstanding handlers via
|
|
their handler->ProcessItem callbacks in preparation for either
|
|
closing or restarting the channel. Once the Drain method
|
|
returns all outstanding handler callbacks will have completed
|
|
and all waiting calls to FetchNextItem will have been unblocked
|
|
(though of course they may not have returned to the calling
|
|
thread). For obvious reasons, Drain may not be called from a
|
|
handler's ProcessItem callback.
|
|
|
|
If the channel is an in-process FIFO or a pipe which has not
|
|
broken, and Interrupt has not previously been called, Drain
|
|
will send an appropriate termination item to the write end. If
|
|
the writer has delivered a termination item to the reader
|
|
implementation, an item of the same type will be returned to
|
|
the writer. Otherwise an item of type RChannel_Abort will be
|
|
returned to the writer. If the RChannelReader client has not
|
|
read a ternmination item, then the item delivered by a call to
|
|
Drain which is not preceded by Interrupt is undefined, since
|
|
the implementation may have received a termination item which
|
|
has not yet been forwarded to the client.
|
|
*/
|
|
virtual void Drain() = 0;
|
|
|
|
/* If the writer has sent a termination item down the channel, it
|
|
is returned in pWriterDrainItem. If the reader has sent a
|
|
termination item to the writer (via Interrupt or drain) it is
|
|
returned in pReaderDrainItem. These termination items are set
|
|
to NULL when a channel is restarted. The returned items are
|
|
undefined if this call overlaps with a call to Start or Drain,
|
|
and it is illegal to call GetTerminationItem after Close has
|
|
been called. */
|
|
virtual void GetTerminationItems(RChannelItemRef* pWriterDrainItem,
|
|
RChannelItemRef* pReaderDrainItem) = 0;
|
|
|
|
/* After a call to Drain, this returns a status code and
|
|
optionally error metadata corresponding to the final status of
|
|
the channel. If the writer sent an error item,
|
|
GetTerminationStatus returns the error associated with that
|
|
item. Otherwise if the reader sent an Interrupt with an
|
|
EndOfStream item or called Drain after receiving an EndOfStream
|
|
item from the writer, GetTerminationStatus will return
|
|
DrError_EndOfStream (signalling clean termination). Otherwise
|
|
GetTerminationStatus returns DryadError_ProcessingInterrupted
|
|
which signifies that there was no error reported on the
|
|
channel, but the reader requested early termination. */
|
|
DrError GetTerminationStatus(DryadMetaDataRef* pErrorData);
|
|
|
|
/* Close may only be called if Start has never been called, or if
|
|
Drain has completed since the last call to Start. Close must be
|
|
called before the RChannelReader is destroyed. After Close has
|
|
been called no other methods may be called on RChannelReader.
|
|
*/
|
|
virtual void Close() = 0;
|
|
|
|
/* Get the total length in bytes of the channel. This is known
|
|
only after the channel has been opened. */
|
|
virtual bool GetTotalLength(UInt64* pLen) = 0;
|
|
|
|
/* Get the total expected length in bytes of the channel. This may
|
|
be known even before the channel is opened. If
|
|
GetExpectedLength returns false, *pLen is undefined. */
|
|
virtual bool GetExpectedLength(UInt64* pLen) = 0;
|
|
virtual void SetExpectedLength(UInt64 expectedLength) = 0;
|
|
|
|
/* Get the URI of the channel. */
|
|
virtual const char* GetURI() = 0;
|
|
|
|
void SetTransformType(TransformType t) { m_transform = t; }
|
|
TransformType GetTransformType() { return m_transform; }
|
|
|
|
private:
|
|
TransformType m_transform;
|
|
};
|
|
|
|
|
|
class RChannelItemArrayWriterHandler
|
|
{
|
|
public:
|
|
virtual ~RChannelItemArrayWriterHandler();
|
|
|
|
/* this interface is called whenever an async write (started by
|
|
RChannelWriter::WriteItemList) completes. If WriteItemList was
|
|
called with the flush flag set, this handler will not be
|
|
returned until the underlying channel has reported that the
|
|
write has completed. Otherwise this handler may be called
|
|
before the item has been written to the channel.
|
|
|
|
Normally status is RChannelItem_Data, however if the underlying
|
|
channel implementation has requested a restart or abort, status
|
|
will be RChannelItem_Restart or RChannelItem_Abort
|
|
respectively. If WriteItem was called before the channel was
|
|
started, or after a termination item had been written, then
|
|
status will be RChannelItem_EndOfStream. If status is not
|
|
RChannelItem_Data the item may or may not have actually been
|
|
written to the output, regardless of whether a flush was
|
|
requested (if status is RChannelItem_EndOfStream the item has
|
|
definitely not been written to the output).
|
|
|
|
If the item marshaler encountered any errors the error
|
|
descriptions will be returned in failureArray. This is an array
|
|
of items: each element is non-NULL if and only if the
|
|
corresponding item in the original list had a marshal error. If
|
|
there were no marshaling errors, failureArray will be NULL.
|
|
*/
|
|
virtual void ProcessWriteArrayCompleted(RChannelItemType status,
|
|
RChannelItemArray*
|
|
failureArray) = 0;
|
|
};
|
|
|
|
class RChannelItemWriterHandler :
|
|
public RChannelItemArrayWriterHandler
|
|
{
|
|
public:
|
|
virtual ~RChannelItemWriterHandler();
|
|
|
|
/* this interface is called whenever an async write (started by
|
|
RChannelWriter::WriteItem) completes. If WriteItem was called
|
|
with the flush flag set, this handler will not be returned
|
|
until the underlying channel has reported that the write has
|
|
completed. Otherwise this handler may be called before the item
|
|
has been written to the channel.
|
|
|
|
Normally status is RChannelItem_Data, however if the underlying
|
|
channel implementation has requested a restart or abort, status
|
|
will be RChannelItem_Restart or RChannelItem_Abort
|
|
respectively. If WriteItem was called before the channel was
|
|
started, or after a termination item had been written, then
|
|
status will be RChannelItem_EndOfStream. If status is not
|
|
RChannelItem_Data the item may or may not have actually been
|
|
written to the output, regardless of whether a flush was
|
|
requested (if status is RChannelItem_EndOfStream the item has
|
|
definitely not been written to the output).
|
|
|
|
If the item marshaler encountered an error the error
|
|
description will be returned in marshalFailureItem. The callee
|
|
does not own a reference to marshalFailureItem.
|
|
*/
|
|
virtual void ProcessWriteCompleted(RChannelItemType status,
|
|
RChannelItem* marshalFailureItem) = 0;
|
|
|
|
/* implementation of RChannelItemArrayWriterHandler interface */
|
|
void ProcessWriteArrayCompleted(RChannelItemType status,
|
|
RChannelItemArray* failureArray);
|
|
};
|
|
|
|
class SyncItemWriterBase
|
|
{
|
|
public:
|
|
/* A client should call WriteMapOutputItem or
|
|
WriteMapOutputItemConsumingReference whenever it wants to send
|
|
an item to the output channel. The latter consumes a reference
|
|
to item, the former does not. */
|
|
virtual void WriteItemSyncConsumingReference(RChannelItemRef& item) = 0;
|
|
void WriteItemSyncConsumingFreeReference(RChannelItem* item);
|
|
void WriteItemSync(RChannelItem* item);
|
|
virtual DrError GetWriterStatus() = 0;
|
|
};
|
|
|
|
/*
|
|
The RChannelWriter is the primary mechanism for writing
|
|
application-specific structured items to an underlying byte-oriented
|
|
channel.
|
|
|
|
The application first calls Start, then sends a series of items,
|
|
primarily of type RChannelItem_Data, though markers may be
|
|
interspersed, followed by a termination item of type
|
|
RChannelItem_Restart, RChannelItem_Abort or
|
|
RChannelItem_EndOfStream. In the case of a pipe which has not
|
|
broken, the termination item will be sent to the remote end so that
|
|
the consuming process learns the reason for the pipe closure.
|
|
|
|
After sending a termination item no further items will be sent on
|
|
the channel until a call to Drain has completed. After this point
|
|
the channel may call Start again in the case of a restart, and start
|
|
sending items again.
|
|
|
|
Each item is marshaled into the byte-stream using an
|
|
application-specific marshaler object which must co-operate with the
|
|
application so that bare RChannelItem objects can be cast by it into
|
|
objects containing meaningful data.
|
|
*/
|
|
class RChannelWriter : public SyncItemWriterBase
|
|
{
|
|
public:
|
|
virtual ~RChannelWriter();
|
|
|
|
/* a client must call Start before writing items to the channel
|
|
the first time, or after a Drain has completed before writing
|
|
to a restarted channel.
|
|
*/
|
|
virtual void Start() = 0;
|
|
|
|
/* WriteItem queues item for async write to the channel.
|
|
handler->ProcessWriteCompleted will be called when the async
|
|
write "completes."
|
|
|
|
If flushAfter is false the handler may be returned before the
|
|
item has actually been written on the underlying channel. If
|
|
flushAfter is true the handler will not be returned until the
|
|
underlying channel has reported that the item has been
|
|
written. Setting flushAfter potentially causes the underlying
|
|
channel to write a partial buffer and should be used sparingly
|
|
where performance is important.
|
|
|
|
WriteItem transfers the caller's reference to item to the
|
|
channel and it is guaranteed that handler will be called before
|
|
the next call to Drain completes. If Start has not yet been
|
|
called or a termination item has been queued since the last
|
|
call to Start, handler->ProcessWriteCompleted will be called
|
|
with status RChannelItem_EndOfStream on the caller's stack
|
|
before WriteItem returns.
|
|
|
|
Flow control is exercised by having the channel refrain from
|
|
calling handler->ProcessWriteCompleted if the underlying
|
|
stream has blocked. Therefore the application should limit the
|
|
total number of outstanding calls to WriteItem in flight whose
|
|
handlers have not yet been returned. Async items are serialized
|
|
to a queue and marshaled on a worker thread, and handler is
|
|
returned after this marshaling completes, so in the common case
|
|
where the underlying channel has not blocked, the application
|
|
should allow enough outstanding handlers to account for this
|
|
delay in order to avoid "bubbles" in the processing pipeline.
|
|
|
|
Once a call to WriteItem passing item A has completed, then any
|
|
items which are subsequently submitted to the channel are
|
|
guaranteed to appear after A. Beyond this constraint, if calls
|
|
to WriteItem and/or WriteItemSync are overlapped the order of
|
|
serialization to the channel is undefined.
|
|
*/
|
|
virtual void WriteItemArray(RChannelItemArrayRef& itemArray,
|
|
bool flushAfter,
|
|
RChannelItemArrayWriterHandler* handler) = 0;
|
|
void WriteItem(RChannelItem* item,
|
|
bool flushAfter,
|
|
RChannelItemArrayWriterHandler* handler);
|
|
|
|
/* WriteItemArraySync submits item to be written to the channel and
|
|
may block indefinitely if the underlying channel has blocked.
|
|
|
|
If flush is false, WriteItemArraySync may return before the array
|
|
has actually been sent to the underlying channel. If flush is
|
|
true WriteItemListSync will not return until the underlying
|
|
channel reports that item has been written. Setting flush
|
|
potentially causes the underlying channel to write a partial
|
|
buffer and should be used sparingly where efficiency is
|
|
crucial.
|
|
|
|
If the marshaler encounters an error when marshaling any item
|
|
in the list, and pFailureArray is non-NULL, then pFailureArray
|
|
will be filled in with an array of the same size as the
|
|
original itemList. This array will contain non-NULL elements
|
|
corresponding to any item in itemList which had a marshal
|
|
error. If pFailureArray is non-NULL and there are no marshaling
|
|
errors, *pFailureArray=NULL on return.
|
|
|
|
WriteItemListSync always consunes the caller's reference to
|
|
each item in the list and leaves itemList empty. If Start has
|
|
not yet been called or a termination item has been queued since
|
|
the last call to Start WriteItemListSync returns
|
|
RChannelItem_EndOfStream, no item is written to the channel,
|
|
and *pFailureArray is guaranteed to be NULL if pFailureArray is
|
|
non-NULL. Otherwise, normally status is RChannelItem_Data,
|
|
however if the underlying channel implementation has requested
|
|
a restart or abort, status will be RChannelItem_Restart or
|
|
RChannelItem_Abort respectively. If status is
|
|
RChannelItem_Restart or RChannelItem_Abort the item in the list
|
|
may or may not have actually been written to the output,
|
|
regardless of whether a flush was requested.
|
|
|
|
Once a call to WriteItemListSync passing item A has completed,
|
|
then any items which are subsequently submitted to the channel
|
|
are guaranteed to appear after A. Beyond this constraint, if
|
|
calls to WriteItem and/or WriteItemSync are overlapped the
|
|
order of serialization to the channel is undefined.
|
|
*/
|
|
virtual RChannelItemType
|
|
WriteItemArraySync(RChannelItemArrayRef& itemArray,
|
|
bool flush,
|
|
RChannelItemArrayRef* pFailureArray) = 0;
|
|
|
|
/* WriteItemSync submits item to be written to the channel and may
|
|
block indefinitely if the underlying channel has blocked.
|
|
|
|
If flush is false, WriteItemSync may return before item has
|
|
actually been sent to the underlying channel. If flush is true
|
|
WriteItemSync will not return until the underlying channel
|
|
reports that item has been written. Setting flush potentially
|
|
causes the underlying channel to write a partial buffer and
|
|
should be used sparingly where efficiency is crucial.
|
|
|
|
If the marshaler encounters an error when marshaling item and
|
|
pMarshalFailureItem is non-NULL, *pMarshalFailureItem will
|
|
contain an item describing that error. In this case item has
|
|
not been marshaled to the channel, however *pMarshalFailureItem
|
|
has been. If there is no marshaling error and
|
|
pMarshalFailureItem is non-NULL, *pMarshalFailureItem is NULL.
|
|
|
|
WriteItemSync does not consume the caller's reference to
|
|
item. If Start has not yet been called or a termination item
|
|
has been queued since the last call to Start WriteItemSync
|
|
returns RChannelItem_EndOfStream, item is not written to the
|
|
channel, and *pMarshalFailureItem is guaranteed to be NULL if
|
|
pMarshalFailureItem is non-NULL. Otherwise, normally status is
|
|
RChannelItem_Data, however if the underlying channel
|
|
implementation has requested a restart or abort, status will be
|
|
RChannelItem_Restart or RChannelItem_Abort respectively. If
|
|
status is RChannelItem_Restart or RChannelItem_Abort the item
|
|
may or may not have actually been written to the output,
|
|
regardless of whether a flush was requested.
|
|
|
|
Once a call to WriteItemSync passing item A has completed, then
|
|
any items which are subsequently submitted to the channel are
|
|
guaranteed to appear after A. Beyond this constraint, if calls
|
|
to WriteItem and/or WriteItemSync are overlapped the order of
|
|
serialization to the channel is undefined.
|
|
*/
|
|
RChannelItemType
|
|
WriteItemSync(RChannelItem* item,
|
|
bool flush,
|
|
RChannelItemRef* pMarshalFailureItem);
|
|
void WriteItemSyncConsumingReference(RChannelItemRef& item);
|
|
|
|
/* Drain may not be called until after a termination item has been
|
|
written to the channel using a call to WriteItemListSync,
|
|
WriteItemSync, WriteItemList or WriteItem which has
|
|
return. Drain will not return until the underlying channel has
|
|
drained and all outstanding async handlers submitted to
|
|
WriteItem or WriteItemList have been returned. At this point
|
|
any calls to WriteItemSync or WriteItemListSync will be
|
|
unblocked, though of course they may not have returned to the
|
|
caller.
|
|
|
|
If the application does not wish to block waiting for Drain it
|
|
should wait until the handler submitted with the termination
|
|
item has returned (or use a blocking call to WriteItemSync or
|
|
WriteItemListSync). This handler will not be returned until the
|
|
underlying channel has drained, and it is always the last
|
|
handler to be returned, so Drain will not block after it has
|
|
been returned.
|
|
|
|
The call to Drain will block waiting for the "remote end" of
|
|
the channel to signal that the channel has been shut down. In
|
|
the case of a file or stream this happens immediately. In the
|
|
case of a pipe or FIFO this happens only when the reader end
|
|
calls Interrupt or Drain, and the item sent to the reader's
|
|
Interrupt command is delivered by the writer's Drain and stored
|
|
in *pRemoteStatus if pRemoteStatus is non-NULL. The item will
|
|
be type RChannelItem_Abort, RChannelItem_Restart,
|
|
RChannelItem_ParseError or RChannelItem_EndOfStream. The
|
|
writer's call to Drain will block for at most a time interval
|
|
of timeOut before returning. If the timeout period expires
|
|
before the remote end's drain item is received and
|
|
pRemoteStatus is non-NULL, *pRemoteStatus will be set to NULL.
|
|
*/
|
|
virtual void Drain(DrTimeInterval timeOut,
|
|
RChannelItemRef* pRemoteStatus) = 0;
|
|
|
|
/* (*pWriterDrainItem) is set to the termination item written to
|
|
the channel, or NULL if no termination item has been written
|
|
since the most recent call to Start. *pReaderDrainItem is set
|
|
to the remote status item returned by the most recent call to
|
|
Drain, or NULL if Drain has not been called since the last call
|
|
to Start. The return values are undefined if this call overlaps
|
|
with a call to Start or Drain, and it is illegal to call
|
|
GetTerminationItems after Close has been called.
|
|
*/
|
|
virtual void GetTerminationItems(RChannelItemRef* pWriterDrainItem,
|
|
RChannelItemRef* pReaderDrainItem) = 0;
|
|
|
|
/* This returns an error corresponding to the most recent
|
|
termination item written to the channel. It is illegal to call
|
|
GetTerminationStatus before sending a termination item. */
|
|
DrError GetTerminationStatus(DryadMetaDataRef* pErrorData);
|
|
|
|
DrError GetWriterStatus();
|
|
|
|
/* Close may not be called unless Start has never been called or
|
|
Drain has completed since the last call to Start. After Close
|
|
is called the channel may not be restarted. */
|
|
virtual void Close() = 0;
|
|
|
|
/* Get/set a hint about the total length the channel is expected
|
|
to be. Some channel implementations can use this to improve
|
|
write performance and decrease disk fragmentation. A value of 0
|
|
(the default) means that the size is unknown. */
|
|
virtual UInt64 GetInitialSizeHint() = 0;
|
|
virtual void SetInitialSizeHint(UInt64 hint) = 0;
|
|
|
|
/* Get the URI of the channel. */
|
|
virtual const char* GetURI() = 0;
|
|
|
|
void SetTransformType(TransformType t) { m_transform = t; }
|
|
TransformType GetTransformType() { return m_transform; }
|
|
|
|
private:
|
|
TransformType m_transform;
|
|
|
|
};
|