xsharp.eu • VO Question: dbServer FieldGET issue - Page 2
Page 2 of 2

VO Question: dbServer FieldGET issue

Posted: Tue Nov 05, 2019 2:36 pm
by ic2
Hello Jamal,

Good detective work!

Please keep us posted about what Joachim replies.

Dick

VO Question: dbServer FieldGET issue

Posted: Thu Nov 14, 2019 5:57 pm
by Jamal
Hi All,

Joachim just replied and could not duplicate the issue.

In the mean time I think I may have found out the culprit: it has to do with multi-threading and DBF workarea gets all mixed up.

Disclaimer: I am no multi-threading expert, my conclusions may not be accurate.

I was creating a timer using code like the incomplete sample below. When the timer kicked in, the OpenDBFCallBack() is called. This function only opens another DBF, checks some values, closes dbServer and returns, but somehow, this affected bBrowser dbServer workarea in another unrelated datawindow1 where a bBrowser:refresh() was called by its refresh timer. The workarea got overwritten and no longer the same and thus FIELDGET("SOMEFIELD") crashed because my code that handles bBrowser on DataWindow1 innocently thinks it is still working with the same original workarea and its same dbf structure.

Here the a sample code:

_dll FUNCTION CreateTimerQueue() as ptr PASCAL:Kernel32.CreateTimerQueue

Code: Select all


function Test() as void pascal 
 	local hTimer as ptr
 	local arg := 1234 as int
       local gDoneEvent as ptr   
       LOCAL gTimerQueue as ptr

 	gDoneEvent := CreateEvent(null_ptr, true, FALSE, null_ptr)

 	// Create the timer queue.
 	gTimerQueue := CreateTimerQueue()

 	// Set a timer to call the timer routine every 5 minutes.
       //  Time in milliseconds. Multiply the time value by 60000. 5 MINUTES = 5*60000 
 	CreateTimerQueueTimer( @hTimer, gTimerQueue, @OpenDBFCallBack(), @arg , 1*60000, 1*60000, 0)

	return

function OpenDBFCallBack() as void pascal
// open dbf server, check some values
// close dbServer and return
return

Note: even before using the above CreateTimerQueueTimer(), I had issues with bBrowser sometimes failing with similar issues.

I had DbSetRestoreWorkarea(false) in the Start() of my app. I will do more tests to see if setting it to True makes a difference.

Jamal

VO Question: dbServer FieldGET issue

Posted: Thu Nov 14, 2019 6:41 pm
by wriedmann
Hi Jamal,
if you are not using multithreading in your application, then this is not the cause.
In VO both the RDDs and the Garbage Collector are no thread safe, but according to the Microsoft docs https://docs.microsoft.com/de-de/window ... mer-queues this call does not creates an own thread.
There must be something other that confused the runtime and make it close the wrong server.
Wolfgang

VO Question: dbServer FieldGET issue

Posted: Thu Nov 14, 2019 6:59 pm
by Jamal
Hi Wolfgang,

You most likely right. If you notice I wrote:
Note: even before using the above CreateTimerQueueTimer(), I had issues with bBrowser sometimes failing with similar issues.

But my feeling is that it has to do with the way VO is handling works areas and may be the DbSetRestoreWorkarea(false) is the cause. I can't rule anything out at this point.

Jamal

VO Question: dbServer FieldGET issue

Posted: Thu Nov 14, 2019 7:10 pm
by wriedmann
Hi Jamal,

yes, I have noted that.
But in my applications (and I'm using bBrowser heavily) I had never this issue.
Do you are using a hybrid approach somewhere (mixed functions and servers9?
Wolfgang

VO Question: dbServer FieldGET issue

Posted: Thu Nov 14, 2019 7:33 pm
by Jamal
Hi Wolfgang,

It use mostly dbServer methods in my apps, and if I overrode any dbServer methods (for speed) I write for example:

Code: Select all

METHOD FIELDPUT( uField, uValue ) CLASS _JamalDBServer

	LOCAL wPos as DWORD
	LOCAL dwCurrentWorkArea as DWORD

	
	VODBSelect( wWorkArea, @dwCurrentWorkArea ) // select workrea
	
	wPos := __GetFldPos( uField, wFieldCount )
	
	VODBFieldPut( wPos, uValue )
	
	__DBSSetSelect( dwCurrentWorkArea )  //SE-060527  - restore workarea

	RETURN uValue   
Jamal

VO Question: dbServer FieldGET issue

Posted: Thu Nov 14, 2019 8:48 pm
by Karl-Heinz
Hi Jamal,

take a look at the __DBSSetSelect() sources. If you don´t use the DbSetRestoreWorkarea(TRUE) setting, the global var __glRestoreWorkarea never becomes true. So either use DbSetRestoreWorkarea(TRUE) or restore the workarea within your FieldPut()

Code: Select all

FUNCTION __DBSSetSelect(dwNew AS DWORD) AS DWORD PASCAL
   //SE-060527
   IF __glRestoreWorkarea    <---------------------------------------
      RETURN VODBSetSelect(LONGINT(dwNew))
   ENDIF
   RETURN dwNew
regards
Karl-Heinz

VO Question: dbServer FieldGET issue

Posted: Thu Nov 14, 2019 9:19 pm
by robert
Jamal, Karl-Heinz,

I suggest to set DbSetRestoreWorkarea(TRUE) .
In fact I will make that the default for the next build.
In VO switching workareas (especially when there are many fields) can be quite expensive. The runtime removes the fieldnames from the active table from the memvar/fields list and then adds the fields of the new area.
We added this setting as optimization.
But in X# things work differently, so there is no need anymore to suppress workarea switching. See
https://github.com/X-Sharp/XSharpPublic ... .prg#L1694
to see what we are doing: we are only changing the active workarea number.

Robert

VO Question: dbServer FieldGET issue

Posted: Thu Nov 14, 2019 10:19 pm
by Jamal
Hi Karl, Robert,

I will use DbSetRestoreWorkarea(TRUE) from now on in my VO apps.

Hopefully, this cures the issues.

Jamal