Subject RE: [ib-support] Re: Need advise
Author Wilson, Fred
Dan, as Sean has already answered, the client is not thread safe, so, *yes*,
you do need to do something about serializing the FB API calls. We do it in
the 3rd layer, as nothing calls the first API wrapper directly.


Best regards,
Fred Wilson
SE, Bell & Howell
fred.wilson@...



-----Original Message-----
From: nitaligavino <Dan.Crea@...> [mailto:Dan.Crea@...]
Sent: Tuesday, December 17, 2002 11:44 AM
To: ib-support@yahoogroups.com
Subject: [ib-support] Re: Need advise


Hi Fred:

First, thank you for all your help!
I'm doing the same thing but without synchronization objects. I have
three classes that wrap the FB API and provide our specific logic,
FBDatabase, FBRecord and FBVariant. Each thread, or client, within
the application creates and destroys it's own object instance of
these wrappers so there is no sharing of these objects across threads
and therefore no need to serialize calls. What is however shared are
the raw FB API calls that I "expect" to be thread safe. For example,
each thread creates their own FBRecord object when it wants to fetch
data. So T1 may be calling Retrieve() at the same time T2 is calling
Retrieve() and so on. To the wrapper that's okay because each thread
has its own instance, but what about to the isc_dsql_fetch() call? (
see snip-it )


AT_LONG FBDatabase::Retrieve(AT_SQL_STATEMENT_HANDLE *hStmt,
AT_SQL_RECORD_SET_DATA *pSqlResults)
{
ISC_LONG lResult = -1;

if(hStmt != 0 && *hStmt != 0 && pSqlResults != 0)
{
// Perform a fetch on this statement handle
ISC_STATUS status[20];

lResult = isc_dsql_fetch(status, hStmt, 1,
pSqlResults);
ErrorHandler("IBDatabase::Fetch", "isc_dsql_fetch",
status);

// EOR, end of record
if(lResult == 100)
lResult = 0;
else
lResult = (ISC_OP_SUCCESS(status) ? 1 : -1);
}

return(lResult);
}

It sounds as if I need to serialize the calls into the FB API. So no
two threads can call a FB API method at the same time. So from the
above, I would need to have a global lock that would lock around the
call to isc_dsql_fetch() so that only 1 thread can call fetch at a
time. Which would also mean that while T1 is in the fetch call, no
other client could call a database method. Is this how your usage
works?

I considered this but it seems that serializing the FB API should not
be required. It should be thread safe itself and if not that's a
bug. Not to mention the performance degradation that will occur.

Dan


--- In ib-support@yahoogroups.com, "Wilson, Fred" <fred.wilson@b...>
wrote:
> We do, basically, the same thing.
> We have the FB API calls in a library. There is a layer around
that, which
> was some applcaition specific methods (speed related), and lastly,
wrapped
> out the outside of all that, is the general database library.
> Within any application (multi-threaded) you need keep the
individual method
> calls separate between threads, such that one thread doesn't call
one of the
> methods, before another thread has finished.
> Way early on, in our developement, we figured that out ;)
> Anyway, we're on the Windoze platform, coding in C++ (and C down
lower). We
> use Critical Sections within the outer library, to control access
inside the
> individual methods. Without something like that, one thread could
call a
> method within the library, and get some of the database specific
buffers
> setup, or actually be between the individual API calls, and get
swapped out
> by another thread, that would then start executing the method
within the
> library. That won't work at all.
> Here's a little code snip of one of the outer library methods,
showing our
> use of Critical Sections:
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> First, one of the constructors and the destructor:
>
> //------------------------------------------------------------------
--------
> -
> IDFSemaphore::IDFSemaphore( BHInterbaseAccess* pIB, const bool
loggingOn)
> : mLoggingOn(loggingOn)
> {
> InitializeCriticalSection(&mCS);
> mAppName = GetApplicationName();
> mComputerName = GetCompName();
> mpCDKI = new CDKInterface( pIB );
> }
> //------------------------------------------------------------------
--------
> -
> IDFSemaphore::~IDFSemaphore()
> {
> DeleteCriticalSection(&mCS);
> delete mpCDKI;
> mpCDKI = NULL;
> }
>
> Next, part of one of the method's within the same library (class):
>
>
> errCode IDFSemaphore::OpenExclusive( String& idfname )
> {
> errCode rslt = ERR_NONE;
> String strSQL;
> short actualCC;
> IBColumn colbuf[ 2 ];
> IBColumn ibc;
> ui32 ui32Status;
> ui32 ui32ID;
>
> // Setting up where the returned parameters will be stored
> colbuf[ 0 ].shSize = sizeof( ui32Status ) ;
> colbuf[ 0 ].pData = ( buffer ) &ui32Status;
> colbuf[ 1 ].shSize = sizeof( ui32ID ) ;
> colbuf[ 1 ].pData = ( buffer ) &ui32ID;
> int info;
> ibc.shSize = sizeof( info );
> ibc.pData = (buffer) &info;
>
> EnterCriticalSection(&mCS);
> try
> {
> BHInterbaseAccess* pIB = mpCDKI->GetIBPtr();
>
> if (pIB == NULL)
> {
> LeaveCriticalSection(&mCS);
> return ERR_DATABASE;
> }
>
> try
> {
> pIB->Transaction( BHInterbaseAccess::begin );
>
> if (pIB->Status.GetValue() != ERR_NONE)
> rslt = pIB->Status.GetValue();
> else
> {
> // Check if IDF is fully loaded
> strSQL = String("select * from sp_OpenDS( '") + idfname
+ "',
> 'PDF')";
> pIB->ExecuteAndFetch( strSQL.c_str(), colbuf, 2,
actualCC );
>
> if (pIB->Status.GetValue() != ERR_NONE)
> rslt = pIB->Status.GetValue();
> else if (ui32Status != ERR_NONE)
> rslt = ERR_NO_DATASET;
>
> <SNIPPED A BUNCH OF OTHER METHOD CALLS >
>
> }
> else if( info == DB_EXCLUSIVE )
> rslt = ERR_LOCKED;
> else if( info == DB_FATAL_ERROR )
> rslt = ERR_DATABASE;
> else if ( info < 0 )
> rslt = ERR_INVALID_CONDITION;
> else
> rslt = ERR_DATASET_INUSE;
> }
> if (rslt == ERR_NONE)
> LogMessage(el_IDFSEMAPHOREEXCLUSIVE, idfname,
DB_EXCLUSIVE);
> else
> pIB->ErrorCleanUp();
> }
> catch (...)
> {
> pIB->ErrorCleanUp();
> rslt = ERR_DATABASE;
> }
> LeaveCriticalSection(&mCS);
> }
> catch(...)
> {
> LeaveCriticalSection(&mCS);
> }
> return rslt;
> }
>
> You'll have to control thread access (in a multi-threaded
application), into
> the FB API calls.
>
>
> Best regards,
> Fred Wilson
> SE, Bell & Howell
> fred.wilson@b...
>
>
>
> -----Original Message-----
> From: nitaligavino <Dan.Crea@a...> [mailto:Dan.Crea@a...]
> Sent: Monday, December 16, 2002 12:20 PM
> To: ib-support@yahoogroups.com
> Subject: [ib-support] Re: Need advise
>
>
> Hi Fred:
> Direct API access, ibase.h. I'm do my development in c / c++. The
> application is cross-platform, Solaris and Windows. I'm seeing
this
> issue on W2k. I have not done any extensive testing on Unix so I
> don't know if this is platform specific or not.
>
> Dan
>
>
> --- In ib-support@yahoogroups.com, "Wilson, Fred"
<fred.wilson@b...>
> wrote:
> > Ok, also, how are you accessing the database, that is with what
tool
> (s)
> > (IBO, IBX, etc), or are you accessing the database directly
through
> the API
> > ??
> >
> >
> > Best regards,
> > Fred Wilson
> > SE, Bell & Howell
> > fred.wilson@b...
> >
> >
> >
> > -----Original Message-----
> > From: nitaligavino <Dan.Crea@a...> [mailto:Dan.Crea@a...]
> > Sent: Monday, December 16, 2002 11:46 AM
> > To: ib-support@yahoogroups.com
> > Subject: [ib-support] Re: Need advise
> >
> >
> > Hi Fred:
> > I have a single multithread application. Each thread creates its
> own
> > connection to the database when the thread is started. These
> threads
> > then live thought the application lifecycle. When there is db
work
> > to be done, an idle thread is woken up and it creates a new
> > transaction. On work completion the transaction is committed or
> > rolledback. Typically, I have at most 12 threads or 12
connections
> > to the database. But this number varies.
> >
> > This issue is reproducible, but not at will. I have not been
able
> to
> > create a tester that can produce this on demand. However I run
> into
> > this problem at least 1 time every two days or when the
> applications
> > load increases and all threads are running.
> >
> >
> >
> > --- In ib-support@yahoogroups.com, "Wilson, Fred"
> <fred.wilson@b...>
> > wrote:
> > > How are you executing those two calls "at the same time" ??
> > > Is this from a single application, with multiple threads, or
from
> > two
> > > separate applications ??
> > >
> > > Best regards,
> > > Fred Wilson
> > > SE, Bell & Howell
> > > fred.wilson@b...
> > >
> > >
> > >
> > > -----Original Message-----
> > > From: nitaligavino <Dan.Crea@a...> [mailto:Dan.Crea@a...]
> > > Sent: Monday, December 16, 2002 11:21 AM
> > > To: ib-support@yahoogroups.com
> > > Subject: [ib-support] Need advise
> > >
> > >
> > > Hello:
> > >
> > > I seem to be running into a reoccurring issue I was hopping
> someone
> > > might be able to offer some advise on. It seems, under the
right
> > > conditions, the FB gds32 becomes stalled and any call into the
> > gds32,
> > > via the gds32 API's, will block indefinitely until you
terminate
> > the
> > > application. I have narrowed it down to the following two
calls:
> > >
> > > isc_dsql_fetch(...)
> > > isc_dsql_execute_immediate(...)
> > >
> > > For some reason, if these two calls occur at the same time the
> > gds32
> > > locks and becomes stalled never to return to the caller again.
> > >
> > > Has anyone else experienced an issue like this?
> > > Can anyone offer some advise on how to work around this issue
or
> > how
> > > to figure out what exactly is happing?
> > >
> > > Also, during the stall, I ran iblockpr to see if there was a
> > deadlock
> > > reported. See snip-it. From what I understand of the output,
> > which
> > > is not much, no deadlock occurred.
> > >
> > > P.S Does anyone know how to read this stuff!!
> > >
> > > LOCK_HEADER BLOCK
> > > Version: 114, Active owner: 0, Length: 32768,
> Used:
> > > 24884
> > > Semmask: 0x0, Flags: 0x0001
> > > Enqs: 160067, Converts: 0, Rejects: 21625,
> > Blocks:
> > > 0
> > > Deadlock scans: 13, Deadlocks: 0, Scan
> interval:
> > 10
> > > Acquires: 385444, Acquire blocks: 0, Spin count:
0
> > > Mutex wait: 0.0%
> > > Hash slots: 101, Hash lengths (min/avg/max): 0/
> 0/ 3
> > > Remove node: 0, Insert queue: 0, Insert
> > prior:
> > > 0
> > > Owners (19): forward: 16852, backward: 23968
> > > Free owners (24): forward: 17984, backward:
16920
> > > Free locks (32): forward: 13792, backward:
13136
> > > Free requests (67): forward: 23392, backward:
23296
> > > Lock Ordering: Enabled
> > >
> > >
> > >
> > >
> > >
> > > To unsubscribe from this group, send an email to:
> > > ib-support-unsubscribe@egroups.com
> > >
> > >
> > >
> > > Your use of Yahoo! Groups is subject to
> > http://docs.yahoo.com/info/terms/
> > >
> > >
> > >
> > > [Non-text portions of this message have been removed]
> >
> >
> >
> > To unsubscribe from this group, send an email to:
> > ib-support-unsubscribe@egroups.com
> >
> >
> >
> > Your use of Yahoo! Groups is subject to
> http://docs.yahoo.com/info/terms/
> >
> >
> >
> > [Non-text portions of this message have been removed]
>
>
>
> To unsubscribe from this group, send an email to:
> ib-support-unsubscribe@egroups.com
>
>
>
> Your use of Yahoo! Groups is subject to
http://docs.yahoo.com/info/terms/
>
>
>
> [Non-text portions of this message have been removed]



To unsubscribe from this group, send an email to:
ib-support-unsubscribe@egroups.com



Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/



[Non-text portions of this message have been removed]