Re: possible data corruption while scrolling through rows

abel deuring <[email protected]> Mon, 17 Jan 2005 16:47:11 +0100
Newsgroups gmane.comp.db.rekall.devel
Message-ID <[email protected]>
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.

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.

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

Abel