SCM

[#1011142] exception using CopyIn - possible race condition

View Trackers | Bugs | Download .csv | Monitor

Date:
2011-12-27 12:28
Priority:
3
State:
Open
Submitted by:
Slobodan Jelenkovic (sjelen)
Assigned to:
Nobody (None)
Npgsql Version:
2.0.11
Category:
Group:
Resolution:
None
Summary:
exception using CopyIn - possible race condition

Detailed description
I'm are using CopyOut and CopyIn commands to copy a table from one db to another.
Sometimes, but not always we are getting this exception:
System.InvalidOperationException: Internal Error! Npgsql.NpgsqlReadyState
at Npgsql.NpgsqlState.SendCopyDone(NpgsqlConnector context)
at Npgsql.NpgsqlCopyIn.End()
at DataAccess.OfferProcessing.CopySelected(MyData data) in ...\DataAccess\OfferProcessing.cs:line

After looking into CopyIn.End() source I found:
if (IsActive)
{
// Stop Notification thread so we can process this message.
// See bug 1010796
using (_context.BlockNotificationThread())
{
_context.CurrentState.SendCopyDone(_context);
}
}

The "IsActive" property checks that connection is in NpgsqlCopyInState,
yet SendCopyDone throws exception saying connection is in NpgsqlReadyState.
So I suspect that another thread, perhaps from connection pool, interrupts my thread between these two lines and performs this state transition.

Would moving "if (IsActive)" inside "using (_context.BlockNotificationThread())" help?
I've also noticed that there are few other calls to SendCopyDone in Npgsql source that are not wrapper with "using (_context.BlockNotificationThread())", could that be the problem?

I'm are using following code to copy a table from one db to another, exception is thrown at "cin.End()" (this is basically CopyOut and CopyIn examples from the user manual combined together):

public void CopySelected(MyData data)
{
string targetTableName = string.Format("Table_Name_{0}", constructionData.OfferId);

NpgsqlConnection connSource = new NpgsqlConnection(Repository.GetUROOLConnectionString());
connSource.Open();

NpgsqlConnectionStringBuilder destBuilder = new NpgsqlConnectionStringBuilder(Repository.GetUROOLOfferSelectionConnectionString());
destBuilder.SyncNotification = true;
NpgsqlConnection connDest = new NpgsqlConnection(destBuilder.ConnectionString);
connDest.Open();

NpgsqlCommand createCommand = new NpgsqlCommand(@"CREATE TABLE " + targetTableName + "( userid bigint, email character varying(45), senddate timestamp with time zone NULL, constraint pk_"
+ targetTableName + " primary key (userid) ) WITH ( OIDS=FALSE )", connDest);
createCommand.ExecuteNonQuery();

NpgsqlCommand commandRead = new NpgsqlCommand("COPY " + targetTableName + " TO STDOUT WITH BINARY ", connSource);
NpgsqlCopyOut cout = new NpgsqlCopyOut(commandRead, connSource);

NpgsqlCommand commandWrite = new NpgsqlCommand("COPY " + targetTableName + " FROM STDIN WITH BINARY ", connDest);
NpgsqlCopyIn cin = new NpgsqlCopyIn(commandWrite, connDest);

try
{
cin.Start();
Stream copyInStream = cin.CopyStream;

cout.Start();
Stream copyOutStream = cout.CopyStream;
byte[] buf = cout.Read; // complete first row
copyInStream.Write(buf, 0, buf.Length);

int i;
copyOutStream.CopyTo(copyInStream, 20480);

copyInStream.Flush();
cout.End();
cin.End();

NpgsqlCommand dropCommand = new NpgsqlCommand(string.Format("DROP TABLE IF EXISTS {0}", targetTableName), connSource);
dropCommand.ExecuteNonQuery();
}
catch (Exception e)
{
Exception ex = null;
try
{
cin.Cancel("Undo copy"); // Sends CopyFail to server
}
catch (Exception e2)
{
// we should get an error in response to our cancel request:
if (!e2.ToString().Contains("Undo copy"))
{
ex = new Exception("Failed to cancel copy: " + e2 + " upon failure: " + e);
}
}
try
{
cout.End(); // return connection to Ready for Query state
}
catch (Exception e2)
{
ex = new Exception("Failed to revive from copy: " + e2 + " upon failure: " + e);
}
if (ex != null) throw ex;
throw;
}

}


Sometimes, but not always we are getting this exception:

Followup

Message
Date: 2011-12-28 16:41
Sender: Slobodan Jelenkovic

Update: Described exception only happens when working with
binary streams. If I remove "WITH BINARY" from commands,
everything works fine.
Date: 2011-12-27 14:58
Sender: Slobodan Jelenkovic

Forgot to mention: all data from the table gets copied, the
exception is thrown after the copy process.

Attached Files:

Changes:

No Changes Have Been Made to This Item

Powered By FusionForge