Re: possible data corruption while scrolling through rows

Mike Richardson <mike-1gTsUfBLqWsG2Il/[email protected]> Tue, 18 Jan 2005 01:19:23 +0000
Newsgroups gmane.comp.db.rekall.devel
Message-ID <[email protected]>
On Monday 17 January 2005 15:47, abel deuring wrote:
> Mike Richardson wrote:
> > On Sunday 16 January 2005 23:22, abel deuring wrote:
> >>hi,
> >>
> >>I noticed the following bug in Rekall (I'm using version 2.2.3):
> >>
> >>If a form block has a sub block, it can happen that the contents of some
> >>rows of the sub block is deleted, when the user presses for example the
> >>up or down arrow quickly two or more times in the parent block. (The
> >>problem may perhaps also occur for a simple form block, if row updates
> >>take a long time -- I didn't read the sources carefully enough to tell
> >>for sure...)
> >>
> >>At some time during a call of KBFormBlock::doOperation e.g. for a down
> >>arrow keystroke, a progress bar is opened, and TKProgress::setDone calls
> >>qApp->processEvents. If the next key stroke arrives in the event queue
> >>before this call, processEvents causes another call of
> >>KBFormBlock::doOperation. The problem now is that
> >>KBFormBlock::doOperation is not reentrant safe. It happened to me quite
> >>often, that the first call of KBFormBlock::doOperation was at the point,
> >>where KBControl::clearValue() has been called, but where
> >>KBControl::getIniValue returns a non-empty value. Hence, during the
> >>second call of doOperation, KBControl::changed returns true, and all
> >>values of the affected row are deleted.
> >>
> >>I fixed this (more or less...) by not allowing recursive calls of
> >>doOperation. See the attached patch. It detects recursive calls and
> >>queues them so that the "real execution" can be deferred until the first
> >>call of doOperation is finished. This may lead to an unexpected
> >>behaviour, because the execution sequence for events can be changed, if
> >>events are queued for different block at the same time. Any comments?
> >
> > Wow! That is seriously subtle! I'll see about getting the fix in (tho' I
> > think I might use a QValueList rather than a linked list).
>
> Right, a QValueList is of course more "QT-ish" ;) Another possible issue
> is the integer field inOperation. If some future version of Rekall will
> use threads, using QSemaphore instead would be more robust.
>
> > Can you describe the circumstances that the progress bar can appear? I'm
> > curious in case there are some other places that this might arrise.
>
> TKProgress::setDone is called by KBQryLevel::InsertRC and by
> KBCopyExec::showProgress.

Ah, yes, I'd forgotton that

>
> But qApp->processEvents is called by more methods:
> KBDumper::dumpDetails, KBDumper::slotTimer, KBDumper::showProgress,
> KBLoader::loadDetails, KBLoader::slotTimer, KBLoader::showProgress,
> KBCopyExec::showProgress, KBErrorDlg::slotDetails,
> KBConductor::snapshot, TKProgress::setDone, TKTextEditor::print and
> TKTextEditor::printPreview.
>
> <comment type="back seat driver">
> I think the main question is, on which "level" qApp->processEvents
> is/should be called, and/or if/how events that can't be processed
> immediately can be queued for later execution.
>
> Of course, a decent program must handle user input and other events as
> quickly as possible, and some actions like database queries can take a
> long time, hence it makes sense to call qApp->processEvents from time to
> time. OTOH, making them reentrant safe can be quite complex, so I am
> wondering, if of how is it possible to check, if certain events can be
> executed immediately, or if it should queued for later execution. While
> my patch does just that, but only "locally", based on a symptom; but I
> think it is possible that other parts of Rekall might have similar
> reentrance problems, so it would perhaps be better to check for possible
> reentrance problems at a more centralized location.

My first thoughts are, what we are interested in is not QT events themselves - 
since that includes stuff like repaints - but "rekall" events, which would be 
stuff like keystrokes and button clicks. Keystokes either update values in 
controls, which should not be a problem unless the change triggers a "rekall" 
event, in which case they are in the same class as, say a button click.

In that case there are two cases. Keystrokes get fed through the KBNavigator 
class, so could probably be serialised there (ie., if KBNavigator gets a 
keystroke while it is processing a previous one, then it is queues); events 
like button clicks end up in an instance KBEvent (for the event they are 
triggering) which again gives a serialisation point. Actually, I guess that 
the two streams should be merged, probably at the form level. I hate this 
sort of stuff, its a real PITA to test (and to reproduce any problems !)

At some point - when Rekall gets around to supporting asynchronous transfers 
from databases - then it will have to be multithreaded, so, yes, the whole 
issue becomes more critical.

Gonna have to think about this one!

>
> This sounds quite vague, but I am not familiar enough with QT's event
> handling concept to write something more specific...
> </comment>
>
> Abel

Regards
Mike


> _______________________________________________
> Rekall-devel mailing list
> [email protected]
> http://www.mailman.a-i-s.co.uk/cgi-bin/mailman/listinfo/rekall-devel