Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error invalid transaction handle [DNET87] #100

Closed
firebird-automations opened this issue Apr 2, 2007 · 23 comments
Closed

Error invalid transaction handle [DNET87] #100

firebird-automations opened this issue Apr 2, 2007 · 23 comments

Comments

@firebird-automations
Copy link

Submitted by: Ralf Giese (rgiese)

Attachments:
Demo.cs

We've developed a client-server application using .NET Data Provider
1.6.3 in the data layer of the server. Each client has a separate
data access object on the server and is calling it via .NET Remoting.
The application worked fine in a production environment with about 12
clients for several month's. Then I updated the data provider to v2.0.
After a timespan from some hours to some days one of the data access
objects began to return IscExceptions, mostly "invalid transaction
handle (expecting explicit transaction start)", on almost all following
calls until the server was restarted. No changes with implementing
data provider v1.7.1, so I had to go back to v1.6.3.

I built a test environment and tried to reproduce and debug the error.
Each data access object of my application contains a common
FbConnection object and some FbDataAdapters with FbCommands for
multiple use. There are procedures using temporary FbCommands too,
e. g. each call creates a new FbCommannd object with the common
connection object. There's no explicit Dispose() for those commands,
so disposing should be done by garbage collector later. At the end of
each call to the data access object the common connection will be
closed for further use in the connection pool.

In normal operation state FbConnection.Close() releases all prepared
commands and removes them from inner connection. I found, that in error
state FbConnection.PreparedCommands doesn't contain the FbCommand
object that rises the exception during FbCommand.Execute(). So this
command isn't released and if it is used again subsequent it has still
an (unvalid) prepared GdsStatement. The GdsDatabase of this statement
meanwhile can point to an inner connection of the connection pool that
is closed or used by another thread. Calling GdsStatement.Execute() on
such an unvalid statement rises an IscError.

But why PreparedCommands dosn't contains the command when closing
connection? When garbage collector disposes an FbCommand object with an
open FbConnection object, it calls
FbConnectionInternal.RemovePreparedCommand() in FbCommand.Release().
In RemovePreparedCommand() the garbage collection thread calls
PreparedCommands (get) and can cause a conflict with an application
thread there. Sometimes the application thread creates a new ArrayList
for prepared commands and adds the first command. After that the
garbage collection thread creates a new empty ArrayList and replaces
the ArrayList with the new command.

I checked csv for .Net Data Provider v1.6.3. There's a
GC.SuppressFinalize() in the constructor of the FbCommand class.
Therefore no errors occur in that version.

I added a explicit Dispose() to each temporary FbCommand and no further
errors occured. Is this the recommended way to use FbCommand? I think
it would be useful to modify the provider to prevent that garbage
collection threat can reach code that is still executed by application
threads.

A simple test application is attached. The number of required cycles to
get the first error vary depending from used machine. On WinXP-SP2
workstation with Pentium 4 HT 3.2 GHz I needed up to about 50000 cycles
(2 hours). On a second machine with Pentium 4 2.2 GHz (without hyper
threading!) I got first error after about 150 cycles (40 seconds) yet.

To gain the effect on the first mentioned machine I temporary modified
FbConnectionInternal:

-----

// next line for test only
Random delayRadom = new Random();

public ArrayList PreparedCommands
{
get
{
if (this.preparedCommands == null)
{
// next 2 lines for test only
int delay = delayRadom.Next(2);
System.Threading.Thread.Sleep(delay);

        this\.preparedCommands = new ArrayList\(\);
    \}

    return this\.preparedCommands;
\}

}

-----

With this changes error occured on first machine after about 50 cycles.

Commits: 0ca5628 0c0eb2c

@firebird-automations
Copy link
Author

Modified by: Ralf Giese (rgiese)

Attachment: Demo.cs [ 10320 ]

@firebird-automations
Copy link
Author

Modified by: Ralf Giese (rgiese)

environment: Firebird CS 1.5.3.4870
WinXP SP2

=>

Firebird Superserver 1.5.3.4870
WinXP SP2

@firebird-automations
Copy link
Author

Modified by: @carlosga

status: Open [ 1 ] => In Progress [ 3 ]

@firebird-automations
Copy link
Author

Modified by: @carlosga

priority: Major [ 3 ] => Critical [ 2 ]

Version: 2.1.0 Beta 2 [ 10120 ]

Version: 2.1.0 Beta 1 [ 10110 ]

Version: 2.0.1 [ 10101 ]

Version: 2.0.1 RC2 [ 10080 ]

Version: 2.0.1 RC 1 [ 10070 ]

Version: 2.1.0 Beta 3 [ 10140 ]

Fix Version: 2.1.0 RC 1 [ 10121 ]

@firebird-automations
Copy link
Author

Modified by: @carlosga

Fix Version: 2.1.0 [ 10102 ]

Fix Version: 2.1.0 RC 1 [ 10121 ] =>

@firebird-automations
Copy link
Author

Modified by: @cincuranet

Fix Version: 2.1.0 [ 10102 ] =>

@firebird-automations
Copy link
Author

Commented by: @carlosga

delayed for now to be fixed in 2.5

@firebird-automations
Copy link
Author

Modified by: @carlosga

Fix Version: 2.5.0 [ 10170 ]

@firebird-automations
Copy link
Author

Commented by: Daniel Junges (djunges)

wo are working with .net provider 2.1.0 and firebird 2.0.3. it's very strange because we have only two clients that receives this error message, and i don't know how to reproduce it on our office bacause it do not rises here for us. We are not using transactions on this software;

this error occurs since we have updated to .NET 3.5

Here are the Exception:

FirebirdSql.Data.FirebirdClient.FbException: invalid transaction handle (expecting explicit transaction start) ---> FirebirdSql.Data.Common.IscException: Exception of type 'FirebirdSql.Data.Common.IscException' was thrown.
at FirebirdSql.Data.Client.Gds.GdsConnection.ReadStatusVector()
at FirebirdSql.Data.Client.Gds.GdsConnection.ReadResponse()
at FirebirdSql.Data.Client.Gds.GdsDatabase.ReadResponse()
at FirebirdSql.Data.Client.Gds.GdsStatement.Execute()
at FirebirdSql.Data.FirebirdClient.FbCommand.ExecuteCommand(CommandBehavior behavior, Boolean returnsSet)
at FirebirdSql.Data.FirebirdClient.FbCommand.ExecuteReader(CommandBehavior behavior)
--- End of inner exception stack trace ---
at FirebirdSql.Data.FirebirdClient.FbCommand.ExecuteReader(CommandBehavior behavior)
at FirebirdSql.Data.FirebirdClient.FbCommand.ExecuteDbDataReader(CommandBehavior behavior)
at System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader(CommandBehavior behavior)
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(DataSet dataSet, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior)
at System.Data.Common.DbDataAdapter.Fill(DataSet dataSet)

regards
Daniel Junges

@firebird-automations
Copy link
Author

Modified by: @cincuranet

assignee: Carlos Guzman Alvarez [ carlosga_fb ] => Jiri Cincura [ cincura_net ]

@firebird-automations
Copy link
Author

Modified by: @cincuranet

Fix Version: 2.5.0 [ 10170 ] =>

@firebird-automations
Copy link
Author

Modified by: @cincuranet

status: In Progress [ 3 ] => Open [ 1 ]

@firebird-automations
Copy link
Author

Commented by: Ralf Giese (rgiese)

To fix issue you can change code in FbCommandBuilder.cs (SVN Rev. 666) as follows.

1. Add field in FbCommand class

private bool isAdded;

2. Add line to save state if command is added to list of prepared commands.

private void Prepare\(bool returnsSet\)
\{
    \.\.\.
    // Add this command to the active command list
    innerConn\.AddPreparedCommand\(this\);
    // new line:
    isAdded = true;
    \.\.\.

3. Modify Release() method to prevent calling code on InnerConnection after
command has been removed from list of prepared commands.

old code:

internal void Release\(\)
\{
    \.\.\.

    // Remove the command from the Prepared commands list
    if \(this\.connection \!= null && this\.connection\.State == ConnectionState\.Open\)
    \{
        this\.connection\.InnerConnection\.RemovePreparedCommand\(this\);
    \}
    \.\.\.

new code:

internal void Release\(\)
\{
    \.\.\.

    // Remove the command from the Prepared commands list
    if \(this\.isAdded\)
    \{
        if \(this\.connection \!= null && this\.connection\.State == ConnectionState\.Open\)
        \{
            this\.connection\.InnerConnection\.RemovePreparedCommand\(this\);
        \}
        this\.isAdded = false;
    \}
    \.\.\.

If connection is closing it releases this command und removes it from list.
If GC finalizer thread disposes command later and calls Release() again, it
doesn't try to remove command once more. So it can't cause any problems with
InnerConnection.

There didn't appear any errors in Demo test case application after provider was modifided.
I've also tested some further common scenarios of using FbCommand class without any problems.

@firebird-automations
Copy link
Author

Commented by: @cincuranet

r.717

@firebird-automations
Copy link
Author

Modified by: @cincuranet

status: Open [ 1 ] => Resolved [ 5 ]

resolution: Fixed [ 1 ]

Fix Version: 2.5.0 Alpha 3 [ 10261 ]

Fix Version: 2.5.0 [ 10170 ]

@firebird-automations
Copy link
Author

Commented by: Ralf Giese (rgiese)

Fix in rev. 717 simplifies the code changes decribes in my previous comment.
The simplified code solves the bug too but it doesn't work correctly if
FbCommand object is prepared and released more than once. This e.g. happens
if Connection or CommandText property is changed repeatedly. In these cases
the command is added to list of prepared commands again in Prepare(bool) but
not removed from this list in the subsequent Release().

@firebird-automations
Copy link
Author

Commented by: @cincuranet

OK, I see the point. I'll re-fix it this week.

@firebird-automations
Copy link
Author

Modified by: @cincuranet

status: Resolved [ 5 ] => Reopened [ 4 ]

resolution: Fixed [ 1 ] =>

@firebird-automations
Copy link
Author

Commented by: @cincuranet

r.731

@firebird-automations
Copy link
Author

Modified by: @cincuranet

status: Reopened [ 4 ] => Resolved [ 5 ]

resolution: Fixed [ 1 ]

@firebird-automations
Copy link
Author

Commented by: Ralf Giese (rgiese)

Fix in rev. 731 isn't correct yet.

line 794

if (!this.addedToPrepared)

must be changed to

if (this.addedToPrepared)

@firebird-automations
Copy link
Author

Commented by: @cincuranet

Ups, rest from previous fix. Committed fixed.

@firebird-automations
Copy link
Author

Modified by: @cincuranet

Fix Version: 2.5.0 [ 10170 ] =>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants