db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Apache Wiki <wikidi...@apache.org>
Subject [Db-derby Wiki] Update of "NetworkServerSessionManagement" by BryanPendleton
Date Sat, 20 May 2006 23:46:07 GMT
Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Db-derby Wiki" for change notification.

The following page has been changed by BryanPendleton:
http://wiki.apache.org/db-derby/NetworkServerSessionManagement

New page:
The Network Server is capable of managing multiple simultaneous JDBC
connections with its clients. We call this "Session Management",
and this page discusses some of the intricacies of the implementation.

This page was constructed as part of the work on DERBY-1326, DERBY-1219,
and DERBY-51 (and possibly others?),
although the page is intended to endure after the bugs are fixed, providing
background information about the implementation.

== Introduction ==

The principal objects involved in session management are the {{{Session}}} and
the {{{DRDAConnThread}}}.

The server considers threads to be more expensive than socket connections.
The server is generally willing to accept an arbitrarily large number of
socket connections from clients at the same time, but has a limit on the
number of threads that it is willing to create.  So there may be more
{{{Session}}} instances than {{{DRDAConnThread}}} instances.

Also, the server is willing to discard the {{{Session}}} instance when
the client disconnects, whereas Thread creation and destruction is
considered expensive, so the server caches and re-uses threads.

So the server tracks threads and sessions separately, and uses a queueing
model to associate work requests ({{{Session}}}) with workers (Threads).

== Session ==

There is a {{{Session}}} instance for each physical socket
connection that the server has with a client. Via the {{{Session}}} object, the
Network Server can access the various Database objects that the session
is using.

{{{Session}}} instances are created by the Client Thread, and are tracked in
the Network Server's {{{sessionTable}}}.

== DRDAConnThread ==

There are typically several {{{DRDAConnThread}}} instances in
the Network Server.
These threads carry out work on behalf of {{{Session}}} instances. 

{{{DRDAConnThread}}} instances are created by the Client Thread, and are
tracked in the Network Server's thread list.

== Dispatching work to threads ==

The server uses a very simple mechanism, called the {{{RunQueue}}}, to
rendezvous and dispatch work to threads.

Any {{{DRDAConnThread}}} instance can service any {{{Session}}} instance, so the
Network Server uses a very simple first-come,first-serve policy for
matching up sessions and threads. To avoid starvation, there is a
time-slicing mechanism as well.

Conceptually, the {{{RunQueue}}} may be in any of three states at any
given time:
 * If there are more {{{Session}}} needing work than there are available
   {{{DRDAConnThread}}} instances, than the {{{RunQueue}}} holds the sessions
   which are awaiting a thread.
 * If there are more {{{DRDAConnThread}}} instances than there are {{{Session}}} 
   needing work, then the idle threads wait on the {{{RunQueue}}} for work to
   become ready.
 * If there are exactly as many active {{{Session}}} instances as there are
   {{{DRDAConnThread}}} instances, then the {{{RunQueue}}} is empty and inactive.

Thus, depending on the current balance of work-needing-a-thread versus
threads-needing-work-to-do, the {{{RunQueue}}} at any given instant may be
viewed either as a queue of work ({{{Session}}} instances), or as a queue of
threads ({{{DRDAConnThread}}} instances).

Of course, this is strictly a conceptual viewpoint, because at the physical
level, the {{{RunQueue}}} as a collection object (it is a Java Vector) only ever
actually holds {{{Session}}} instances. When the server is in the state of
"there are idle threads waiting for work to do", there is no explicit
collection object which contains that list of idle threads; instead there is
merely a "virtual" collection defined as "the threads which are currently
waiting on the {{{RunQueue}}} in {{{NetworkServerImpl.getNextSession()}}}".

== Session Lifetime ==

A {{{Session}}} instance is created by the Client Thread when a new socket
connection is accepted from a client. The {{{Session}}} object is added to
the Network Server {{{sessionTable}}} at that time.

The {{{Session}}} object is held until the client disconnects,
which is typically
handled by throwing a disconnect exception on the server side. The
{{{DRDAConnThread}}} catches the disconnect exception, removes the session
from the Network Server {{{sessionTable}}}, closes it, and discards it.

(I think that if the client disconnects at a point where there are currently
more {{{Session}}} instances than {{{DRDAConnThread}}} instances,
and the client's {{{Session}}} is currently on the {{{RunQueue}}},
then the Network Server will not detect
the client disconnect until the next time that the {{{Session}}} moves to the
head of the {{{RunQueue}}} and is dispatched to a thread for processing. But I
haven't yet set up this situation in the debugger, so I'm not sure about
this part.)

== DRDAConnThread Lifetime ==

A {{{DRDAConnThread}}} instance is created by the Client Thread when it detects
that a new {{{Session}}} has just been created,
and there aren't any free threads
currently, and the server has not yet reached its maximum number of threads.

Note that since there is no explicit collection object which contains the
list of idle threads, the server code maintains a simple counter of the
number of idle threads.

{{{DRDAConnThread}}} instances are only destroyed when the Network Server shuts
down. The mechanism for shutting down a {{{DRDAConnThread}}} instance is
cooperative (that is, we don't call {{{Thread.stop())}}}: the Network Server calls
the thread's {{{close()}}} method, which sets a flag on the thread, and the
thread checks the flag periodically and exits its {{{run()}}} method if it
discovers the {{{closed()}}} flag is set.

Note specifically here, with respect to DERBY-1326, that when the
{{{DRDAConnThread}}} notices that it has been closed, immediately upon returning
from the {{{getNextSession()}}} call in its {{{run()}}} method, that it does '''not'''
perform any shutdown processing for the {{{Session}}} that it was told to process.
This can cause a "hang", as discussed in DERBY-1219.

== Network Server startup ==

When the Network Server starts up, it starts the embedded Derby engine, but
does not start any {{{Session}}} or {{{DRDAConnThread}}}. Those objects will be
created on demand when new client connections are made, as described above.

== Network Server shutdown ==

When the Network Server shuts down, it makes a concerted effort to clean up
its resources:
 * It shuts down the Client Thread
 * It goes through the {{{sessionTable}}} and closes all the {{{Session}}} objects
 * It goes through the Thread list and closes and interrupts each {{{DRDAConnThread}}}
 * It closes the master socket on which it accepts connections

There are several observations worth making here:
 * It seems like it might be better to close the master socket first, rather
   than at the end, since otherwise there is the chance that new connections
   will continue to accumulate during the shutdown processing (though since
   the Client Thread has been interrupted, no new work should get started for
   such connection attempts).
 * Note that we do not close down the embedded Derby engine here. This is the
   essence of bug DERBY-51. Basically, the Network Server does not know
   whether or not it should shut down the embedded engine, because it is
   possible to have an application in which there are both local threads
   accessing the database directly, and client threads accessing the database
   over the network, and just because we are shutting down the Network Server
   does not necessarily mean that we no longer want to access the database
   from the local threads.
 * Lastly, note that in addition to closing each {{{DRDAConnThread}}}, we also call
   {{{interrupt()}}} on those threads. This awakens the thread if it was blocked in
   a {{{wait()}}} call, so that it can notice the fact that it's been closed.

== Network Server restart ==

The Network Server has a feature by which it can restart itself, without
needing to shut down and restart the entire application which contains the
Network Server. The Network Server does this automatically when it detects
that the underlying Derby engine has been shut down? The checkDataSource
test contains some code which triggers this restart processing.

When the Network Server restarts itself, it does the following:
 * It goes through the {{{RunQueue}}} and closes all sessions in the {{{RunQueue}}}.
 * It goes through each {{{DRDAConnThread}}} and closes the thread
 * It releases its pointer to the Derby engine, to allow it to be collected.
 * It then starts up a new instance of the Derby engine.

There are several observations worth making here.
 * Note that while Network Server shutdown closes every session in the
   {{{sessionTable}}}, Network Server restart only closes the sessions in the
   {{{RunQueue}}}.
 * Note that while Network Server shutdown both {{{closes()}}} and 
   {{{interrupts()}}}
   each {{{DRDAConnThread}}} instance, Network Server restart just 
   {{{closes()}}} the
   threads. This means that the threads may not become aware that they have
   been closed until some later time, when they awaken from whatever 
   {{{wait()}}}
   call they were blocked in.
 * Note that Network Server shutdown terminates the Client Thread, while
   Network Server restart leaves the Client Thread alone. This means that
   new {{{Session}}} may be coming in during the restart processing.

== Changing the Session Management code ==

I think that there are a number of problems in the Session Management code
which need to be addressed, as part of the bugs DERBY-1326 and DERBY-51, and
possibly others.

However, before we proceed to changing the code, I want to make sure that
we are correctly understanding the current operation of the code, so I'm
only taking the wiki page this far right now, and I intend to return to
this page at a later date and start to propose changes to the code, once
we've reviewed the material so far.

Mime
View raw message