Subject Re: [IB-Architect] Messaging API
Author Jim Starkey
At 11:56 AM 5/17/00 -0700, Jason Wharton wrote:
>>Some questions:
>>
>> 1. How do you wait for a message?
>
>Like I said, you prepare a SELECT statement against a message table and
>(perhaps optionally) supply an AST to receive notification when a message is
>available. This would require an enhanced API call similar to
>isc_dsql_prepare() except you would need to pass in a proc address for the
>AST.
>

I'm sorry, but I don't follow. Does the isc_dsql_execute() block
if there are not records or does it return zero records? When is
the AST called and what is it passed? If the program wants to block,
does it do an indefinite wait and expect the AST to wake it up? How
do you avoid the race condition between the program waiting and the
ast firing? How do you make this platform independent?

Also, what does the transaction handle mean on isc_dsql_execute
for a prepared message table retrieval?

>The alternative if an AST wasn't provided is to use an API call or a call
>using the statement info call to allow the client to poll a flag that would
>be maintained internal to the GDSxx client if there was a message waiting or
>not on a per statement handle basis.

How do you handle the race condition between the client returning
"no messages" and the arrival of a message? If it is the client
program's responsibility to wait, the poll has returned "no messages"
but the ast to wake the program has already fired, how does the
program wake up?

>
>Either the main thread in a GUI type app could use Idle events to poll it
>(thus it would be synchronized automatically this way) or a consol or
>service type of app could have a sub-thread polling it.
>

Could you give us your API extensions for this?

>In short, is all that needs to happen is something needs to say "go get 'em"
>and then message fetches can be performed.

Everything you have described is on the client. Surely the server must
be involved somwhere.

>> 2. How do you wait for messages from a number of message tables?
>
>You would be limited to use a single statement per each message table. You
>would use up one statement handle per each message type you wanted to wait
>for.

OK, what happens if you try to prepare more than one message statement
for a table, possibly with different predicates. Do you get an error?
If so, how do you build a complex problem with subsystems written by
different folks? If its not an error, do all the message statements
get a message?

>
>> 3. What happens to a result set when another message appears?
>
>That's a good question. I suppose it depends upon how and when they are
>introduced into the message queue table.

It's your design. Tell us what you think should happen.

>
>> 4. Could you explain what the server does in response to an
>> insert into a message table?
>
>
>Where things would probably need to differ is to have the ability to set a
>column value in the message table at the time it is being committed. I think
>a message table should have a system defined column (different than a
>DB_KEY) that is populated from a system defined generator at the time the
>record is committed.
>

This is somewhat of a problem. As you are probably aware, all data
pages are flushed to disk before the transaction state on the TIP page
is committed and the transaction lock released. Setting a commit time
generator value to a message record requires that the record be written
and the corresponding data page re-written. It is not possible to do
this atomically with the transaction commit. Worse, since the SuperServer
tried to batch commits, the problem is intractable.

Can you find a mechanism that doesn't break the fundamental architecture
of the system?

>This way you would have a pure sequence that represented the committed order
>of the records in the message queue table. This would allow the client to be
>able to hinge on that sequence and "walk" it. Each time it fetched messages
>its sequence would be incremented to ignore previous messsages.
>
>During the same process as setting these sequence stamps it could be
>initializing the necessary activities to notify the clients that have a
>registered interest in the newly committed messages. Each registered message
>statement would have its former sequence and it would walk the new messages
>looking for a match. If there was a match then it would stop and send
>notification. If there was no match it would simply increment the sequence
>and move forward.
>


In the classic architecture, communication among database processes
is limited to a shared disk, a common lock manager (implemented with
shared memory), and a common event manager (again implemented with
shared memory). Both the lock manager and event manager have very
simple data structures but turn out to be very hairy code for a
number of reasons, among the the need to avoid creating resource
intensive hots spots, the need to be absolutely bomb-proof, and
the requirement that all pointer be self-relative. Your design
seems to require that all data structures required to execute
a prepared statement (which is just about everything) be available
in shared memory. Worse, those data structure are arbitrarily large,
which is quite inconsistent with using Sys-V shared memory, which
must be declared in size at creation time.

Perhaps you could find a scheme with a less demanding implementation?

Jim Starkey