The app runs under IIS.  It may use SQLServer database(s); but the only issue 
here is the Firebird database we're using.  We were not having problems with 
lost connections in SQLServer (where the default is NO POOLING, anyway).

Yes, we can simulate it consistently by using multithreading to simulate 
simultaneous users in a web environment.  It bombs every time.

Here's a typical error:
==================================================
Object reference not set to an instance of an object.
System.NullReferenceException: Object reference not set to an instance of an 
object.
   at FirebirdSql.Data.Client.Gds.GdsDatabase.get_Send()
   at FirebirdSql.Data.Client.Gds.GdsStatement.Fetch()
   at FirebirdSql.Data.FirebirdClient.FbCommand.Fetch()
   at FirebirdSql.Data.FirebirdClient.FbDataReader.Read()
   at System.Data.Common.DataAdapter.FillLoadDataRow(SchemaMapping mapping)
   at System.Data.Common.DataAdapter.FillFromReader(DataSet dataset, DataTable 
datatable, String srcTable, DataReaderContainer dataReader, Int32 startRecord, 
Int32 maxRecords, DataColumn parentChapterColumn, Object parentChapterValue)
   at System.Data.Common.DataAdapter.Fill(DataTable[] dataTables, IDataReader 
dataReader, Int32 startRecord, Int32 maxRecords)
   at System.Data.Common.DbDataAdapter.FillInternal(DataSet dataset, 
DataTable[] datatables, Int32 startRecord, Int32 maxRecords, String srcTable, 
IDbCommand command, CommandBehavior behavior)
   at System.Data.Common.DbDataAdapter.Fill(DataTable[] dataTables, Int32 
startRecord, Int32 maxRecords, IDbCommand command, CommandBehavior behavior)
   at System.Data.Common.DbDataAdapter.Fill(DataTable dataTable)
   at [et-cetera -- back up through the stack]
==================================================

I could provide a sample, but I'm not sure it's worth the effort, since I'm 
quite sure what the problem was.  I'd have to spend a lot of time creating a 
sample database and sample tables and data, and writing multithreading code to 
spawn off a bunch of threads doing large queries.  I can't just turn you loose 
in the real thing, with proprietary and confidential data.

The deal was we were having lingering connections.  Even if you disconnected, 
the system maintained a sort of "open connection" in the pool which could be 
reused for the next connection request, thus saving a small amount of overhead. 
 It was suggested that we "clear all pools" when disconnecting.

The trouble we eventually ran into was that when we cleared all pools, anyone 
else who was connected would lose his connection.  Not nice.  In order to 
reproduce this in testing, I had to spawn off a bunch of threads to connect, do 
some work and disconnect, each thread clearing all pools.  If I just tested 
with one connection, I never could get an error, for obvious reasons.  Well, it 
didn't take long at all to run into chaos.  The first guy out would clear the 
pool(s), and then everybody else blew up.


If we did not clear the pools, the error would not occur, but then we'd still 
be maintaining connection pools and the attendant overhead (back to our 
original problem).  So we just did away with the whole smash:  stop using 
pools, and stop clearing them.  (Either thing would fix it:  Either connect 
without pooling - in which case you had your own resources and anyone else who 
cleared a connection pool wouldn't touch you - or don't clear pools.  But if 
you connect with pooling and don't clear them, you leave connections out there 
waiting to be reused at the next connection request.)  Problem solved.  It only 
takes about ¼ second extra time to connect without pooling, anyway.  That beats 
blowing up!

Apparently the connections of different simultaneous users using a web app is 
quite similar to multithreading.

BTW, I could also solve the problem by putting a lock on the code, but that was 
not a desirable solution, since it forced all users of the DB code to file 
through in turn, which could cause a bottleneck in a well used web app.  I 
demonstrated in multithreading tests that this stopped the error while 
continuing to share pools and clear them; but it only did it by forcing only 
one process at a time to be connected, and not allowing the next one through 
the gate until the first one was out.  That defeats the whole purpose, and 
prevents simultaneous access by multiple users.  My testing showed that it took 
all the threads longer to get done this way, vs running simultaneously.  So the 
better solution was to allow simultaneous access without pooling, each one with 
independent resources, which was a little more overhead, but a lot less waiting 
in line for database access.
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
-----Original Message-----
From: Jiri Cincura [mailto:[email protected]] 
Sent: Saturday, February 20, 2010 9:27 AM
To: For users and developers of the Firebird .NET providers
Subject: Re: [Firebird-net-provider] connection pooling in a 
multithreadingenvironment

On Fri, Feb 5, 2010 at 03:17, Bruce Tiffany <[email protected]> wrote:
> We encountered an error in FB 2.1.0 and 2.5.1 in some web applications:

Is the application run under IIS?

> Similar errors were occurring too frequently from various Firebird

Does it mean you can simulate it consistently?

> Specifically, the line "this.ExecuteCommand(behavior,true);".  Because
> this line is enclosed within a try/catch block, the exception is
> handled.  However, this alters program flow to the catch block.  Inside

What's the IscException exactly?

> But I was able to finally figure it out.  I was able to reproduce the
> error in a multithreaded environment.  When I locked the code which

Can you show us the test case? Are you aware of, that the provider
*isn't* thread safe?

> called the DLL which uses Firebird, the error went away.  Without the
> lock, the error also did not occur when our SQL DLL (issuing Firebird
> queries) was called serially (sequential calls rather than parallel).

Was for these commands separate connection used? Or very careful
synchronization (if you understand the protocol internals).

> This gave me a hunch as to what the problem was.  I tried commenting out
> the "FbConnection.ClearAllPools()" statement, and voila!  End of error.

Where you commented it out?

> We had started clearing all pools a few years ago because we were seeing
> persistent connections on our servers, because the .NET Data Provider
> pools connections even after they are closed, so that they can be reused
> on the next call to the database.  The pooled connection stays "alive"
> on the server until the application is closed; unfortunately, since
> these were web applications, they were never truly closed.  So, when any

That's not true. You can specify the connection lifetime. And also -
assuming IIS - the process is ended to recycle worker proces.

-- 
Jiri {x2} Cincura (CTO x2develop.com)
http://blog.cincura.net/ | http://www.ID3renamer.com

------------------------------------------------------------------------------
Download Intel&#174; Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
_______________________________________________
Firebird-net-provider mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/firebird-net-provider

------------------------------------------------------------------------------
Download Intel&#174; Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
_______________________________________________
Firebird-net-provider mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/firebird-net-provider

Reply via email to