Hi Eric, Jay

On Tue, Jun 9, 2009 at 3:30 PM, Eric Day<[email protected]> wrote:
> Hi Biping, Jay,
>
> Sorry on the late reply, I was at the JavaOne conference last week
> helping out at the Drizzle booth. :)

No worries!

I found it's really easy to make the userland switch work. We only
need to add a swapcontext() statement after
drizzleclient_vio_read/write in the
my_real_read/drizzleclient_net_real_write call, so the running session
can switch out when I/O fails. So we don't need too much changes in
this way.
But this way of implementation will do no good to the proposal of
architecture (cool thing!) mentioned on your blog. So I think choosing
the not so easy way will be more valuable, that is, making the
execution engine stateful.

For making the execution engine stateful, libdrizzle is a good
reference. We need something new:
1. _class EventListener_ used by the scheduler to register events like
data available event on sockets.
2. A new nonblocking Protocol implementation such as class
NonblockingProtocol : public Protocol
3. A state function stack set as member of the Session class which is
used to remember the state.
4. A serial of state functions which have the same signature and will
be pushed into the state stack.

How these new things work together:
If we turn on the pool of threads scheduler, the ProtocolFactory is
set to produce NonblockingProtocol objects when the scheduler plugin
gets initialized. Once a new client connection is accepted, a Session
object is created and is appended to the Wait for I/O list. The
scheduler registers I/O events of the new session to EventListener
telling "call me when data is available". The session is moved to
Ready for I/O list when notified by EventListener. State functions are
a little special (in what ways? explained later) since they may be
called a second time when a internal block point is no longer
blocking. I found it's always very easy for I/O read, since read
operation always exists at the head part of the execution call, that
means, before going further, we will check if enough data have already
been read. So another check will work well for the second time call.
But it's not the same for write, since I/O writes appear all over the
execution path. Who knows which write chocks up the buffer, causes a
real flush and maybe then causes a blocking.
For example, if we have an execution call:
exec_A (Session* session)
{
  if(!enough_have_been_read(session))
  {
    PUSH_STATE_FN(session, drizzle_state_read);
    retuen DRIZZLE_RETURN_OK;
  }
  foreach unit in to_be_executed_units
  {
    exec(unit);
    write_result(unit);
  }
}

Say, this exec_A is pushed into the stack and is called by
drizzle_state_loop(). If enough_have_been_read(session) is not
satisfied, we'll need to read in more data. So push a
drizzle_state_read into the stack. The next time we may get enough
data in the buffer, and then is able to go forward to the execution
statement. That's fine.
If we got blocked at some write_result(unit) call, yes, we know how
many units have already been executed, but how can we remember this
information for the second call of exec_A? It'll surely cause an error
if we do the execution for the same unit for more than once. Isn't it?
I'm thinking if only a callback stack is enough to remember these
information (including the local variables of the execution function).

In what ways are these state functions special?
- They have the same signature.
- If and only if one execution method has potential block points, it
needs a "state_fn" version.
- They always know where to continue when called for the another time.
- And more?


-- 
Cheers.

Biping MENG

Natural Language Processing(NLP) Lab
Dept. of Computer Science and Technology
Nanjing University

_______________________________________________
Mailing list: https://launchpad.net/~drizzle-discuss
Post to     : [email protected]
Unsubscribe : https://launchpad.net/~drizzle-discuss
More help   : https://help.launchpad.net/ListHelp

Reply via email to