For C++ servers (and possibly others), it is possible to have 
per-connection state.  Assuming your service is named RPCIterator, you 
would want something vaguely like this...


boost::shared_ptr<server::TThreadedServer> server =
   boost::make_shared<server::TThreadedServer>(
      boost::make_shared<RPCIteratorProcessorFactory /*code generated*/>(
         boost::make_shared<RPCIteratorIfCloneFactory /* hand written 
*/>()),
      boost::make_shared<transport::TServerSocket>(12345 /*your socket 
number here*/),
      boost::make_shared<transport::TBufferedTransportFactory>(),
      boost::make_shared<protocol::TBinaryProtocolFactory>());


The implementation of RPCIteratorIfCloneFactory would look something like 
this...

class RPCIteratorIfCloneFactory : public RPCIterator::RPCIteratorIfFactory 
{
 public:
  virtual ~RPCIteratorIfCloneFactory() {}

  virtual RPCIterator::RPCIteratorIf* getHandler(const 
::apache::thrift::TConnectionInfo& connInfo)
  {
    return new RPCIteratorHandler; /* build your handler object here */
  }
  virtual void releaseHandler(RPCIterator::RPCIteratorIf* handler)
  {
    /*put any crazy cleanup customizations here */
    delete handler; 
  }
};


This approach gives you a unique instance of your handler class per 
connection.  If the connection dies, then releaseHandler will be called on 
it once all processing for that connection has completed.



From:   Stuart Reynolds <[email protected]>
To:     [email protected], 
Date:   02/11/2015 11:48 AM
Subject:        Best patterns for providing an iterator via thrift RPC
Sent by:        [email protected]



I'd like to provide access to something like a database iterator via a
thrift API (e.g. iterate through 1M+ DB records). This requires state
to be maintained on the server, although only for the duration of the
thrift TCP connection. (ie. you could argue that the server might
still be considered stateless).

Here's my first pass:

----
struct RPCIteratorID {
   int id;
   int dataTypeId;
}

// Get an iterator of type T1. 0 = means no results.
RPCIteratorID queryT1( queryParams );

// supply the iterator id. list.size!=maxResults == end.
list<T> getNext_T2( RPCIteratorID iter, int maxResults );


RPCIteratorID queryT2( queryParams );
list<T2> getNext_T2( RPCIteratorID iter, int maxResults );


RPCIteratorID queryT3( queryParams );
list<T3> getNext_T3( RPCIteratorID iter, int maxResults );
...
void closeIterator( RPCIteratorID iter );
----

If the TCP socket timesout or is close, the server calls closeIterator
for all open iterators on the connection.

Are there better design patterns for this?

- Stu

Reply via email to