Subject Re: [IBO] IB_Transaction.Pause
Author Geoff Worboys
> This means, that Resume restarts the same transaction, that
> has been paused or will pause stop the transaction and resume
> start a new one ?

Interbase itself does not support "pausing" a transaction - I suspect
such a concept is impossible. Pause/Resume is entirely a client
facility to prevent keeping physical transactions open unnecessarily.
So when you Resume you will get a new physical transaction - for this
reason you must take control over when Pause is called.

Pause(true) - will commit any changes and pause the client transaction
(but stop the physical/server transaction.

Pause(false) - will rollback any changes and pause the client
transaction (but stop the physical/server transaction.


In my applications I maintain three different timeouts (one timer,
just testing for three different amounts of time active on a
transaction).

Level1 - Only applies to transactions that have no posts pending (the
user is not editing/inserting anything). Probably the transaction is
simply active because not all records have been retrieved. I consider
such transactions "safe" to pause (stop the physical transaction)
because the user will not lose any changes. (See notes below about
risks.)

Level2 - Applies to transaction that have outstanding posts (the user
is editing/inserting records). This is considerably less "safe",
because I will rollback any changes after this timeout is reached. So
obviously I wait a bit longer before applying this timeout.

Level3 - I apply to transactions that already have PauseDisabled.
There are no OAT issues here, but after this very long timeout I
consider that the user must have gone home so I cancel the transaction
altogether and close the form.



> Could it be, that this decides the WithRestart-Parameter
> of Resume or what else is it for?

The WithRestart controls whether I both to actually start a NEW
transaction when the Pause state is resumed. In normal situations you
will be resuming because a user has come back to the application, so
you will supply WithRestart=true in order to start a new transaction
and refresh the datasets.

However in abnormal situations (such as my Level3 timeout above), all
I want to do is close the form, so I call WithRestart=false so that
the function does not bother to start a new transaction and refresh
the datasets.



> > I had not envisaged anyone calling pause while a transaction
> > was not active and so I did not check/prevent the pause from
> > occuring in that situation.
>
> Why not ? When I just open a dataset, the transaction is
> tsInactive, but nevertheless I want to pause it after some time.

Sorry, we are misunderstanding each other. tsInactive is simply a
transaction state. When paused the the state moves to
CommitRefreshPending or RollbackRefreshPending - because when the
transaction is resumed it will (probably) perform a Refresh -
depending on the WithRestart parameter.

There is no issue here as far as I can tell. If you want to see what
the physical transaction is doing (the state of concern with respect
to OAT) then check the Started property of the transaction.


> I worked through your TransationPausing-example some days ago,
> but I didn't like the idea of using the Application.OnMessage-
> Event. But I think, I will give it a try. Some questions:
> With (Msg.message >= WM_KEYFIRST) and (Msg.message <= WM_KEYLAST)
> you find out, if the user has pressed any key ?

AFAIK yes, any keystroke while the application is focused/active.
Note that it will NOT receive messages when the application is in the
background.

> Is (Msg.message >= WM_MOUSEFIRST) and (Msg.message <= WM_MOUSELAST)
> only true, when the user presses a mousebutton, or even when he
> moves the mouse ?

Also includes mouse moves. Again, AFAIK, only while the application
is focused/active.

Note that the overheads I impose in the OnMessage handler are very
small. I have been using this concept in production applications for
some time without apparent problem.


> In the last row of the OnSessionTimer-Event you do a PostMessage
> ( Handle, WM_APP + 1, 0, 0 ); What is it for ?

Please read the help file, it shows extended comments next to most of
the interesting lines of code. The comments below this line are...

"Rather than hold-up the response to the timer message I post a
message back to this window which will result in the presentation of a
modal form - see the ShowPauseMessage procedure."


I just noticed that my copy of the tutorial (from 3.6.C) has lots of
the code commented out. Guido, does your copy show this? I dont
remember doing this. Jason, do you have any idea what that is about?


> Are you familar with the TimeoutProps of TIB_Transaction ?

Not very. These were introduced after I built the pause capability
and started using Pause in my applications. Since Pause capability is
doing what I want, I have not bothered following up on these.



Notes/Risks:

Pausing (and I believe, even the automation provided by TimeoutProps),
results in the physical server transaction being stopped - which means
a new transaction context must be created when required. For this
reason TimeoutProps restricts its activity to Isolation=tiCommitted
transactions. Pause function does not check!

Therefore, if you have any transactions that should not be stopped for
some reason, you should either not include them in Pause automation OR
you should use DisablePause/EnablePause around such transaction
activity - and check the PauseDisabled state before trying to pause
transactions.

A good example of this is reporting. Reports should usually run from
a transaction with Isolation=tiConcurrency - and for a consistent view
of the data, the entire report should (normally) operate within the
context of a single physical transaction. When before starting the
report call IB_Transaction.DisablePause, when the report is finished
call IB_Transaction.EnablePause.


The reason for using Pause, rather than simply calling commit or
rollback, is so that the datasets can be refreshed very close to their
original states (except edit/insert states) when Resume is called.
This keeps the interface much more consistent and predictable for the
user (IMO). However when the datasets are refreshed, it is under a
new physical transaction.


I hope this helps explain what is going on. There is more detail in
the help file that accompanies the tutorial.

Geoff Worboys
Telesis Computing