Subject | Phantom connections? |
---|---|
Author | Josh Higgs |
Post date | 2004-12-01T07:03:59Z |
Morning all
Interbase WI-06.0.1.6
Delphi 5
IBObjects (4 something - how do I tell?)
I have a utility that requires exclusive use to a database because the .gdb
will be renamed moved etc. Hence, just prior to that action, it checks to
ensure that the file is not in use. Even before that, it connects to the
.gdb, does a couple of queries, and then disconnects.
The problem is that it (sometimes, on some customer sites), it reports the
database is in use. The reason for this is because in the
connection/queries/disconnection process, IB_Objects is creating not one,
but two connections to the database, and releases only one on disconnection.
The source code looks a bit like this:
function TdmUpgrade.GetDatabaseRelease(
DatabaseObject: TDatabaseObject): TFileVersion;
var
lVersionI : integer;
begin
if txnUpgrade.intransaction then
raise Exception.create('txnUpgrade.intransaction in
TdmUpgrade.GetDatabaseRelease');
//At this point Interbase properties reports 0 attachments to 0
databases - OK
ConnectSystemDatabase(DatabaseObject);
try
//At this point Interbase properties reports 1 attachment to 1
database - OK
txnUpgrade.starttransaction;
try
if VersionExists then //This function call creates another attachment
lVersionI := qryVersionExists.GeneratorValue('GEN_VERSION', 0)
else
lVersionI := 0;
result := VersionIntToFV(lVersionI);
finally
if txnUpgrade.intransaction then
txnUpgrade.commit;
end; //try..finally for txnUpgrade.commit;
finally
//At this point Interbase properties reports 2 attachments to 1 database
DisconnectSystemDatabase;
//At this point Interbase properties reports 1 attachments to 1 database
end; //try..finally for database disconnection
end;
function TdmUpgrade.VersionExists: boolean;
begin
result := false;
try
with qryVersionExists do
begin
close;
//At this point Interbase properties reports 1 attachment to 1
database - OK
open;
//At this point Interbase properties reports 2 attachments to 1
database - NOT OK
if fieldbyname('rdb$generator_name').isnull then
exit;
result := true;
end; //with qryVersionExists do
finally
qryVersionExists.close;
end; //try..finally for qryVersionExists.close;
//At this point Interbase properties reports 2 attachments to 1 database -
NOT OK
end;
It is the open call that creates the second attachment.
qryVersionExists is a TIB_Cursor
qryVersionExists.IB_Transaction = txnUpgrade
qryVersionExists.IB_Connection = ibcSystemDatabase (which is the one that
gets connected in ConnectSystemDatabase)
txnUpgrade.IB_Connection = ibcSystemDatabase
qryVersionExists.IB_Session = ibsSystemDatabase
txnUpgrade.IB_Session = ibsSystemDatabase
ibsSystemDatabase.DefaultConnection = ibcSystemDatabase
qryVersionExists, txnUpgrade, ibcSystemDatabase and ibsSystemDatabase all
exist on the same datamodule with ibsSystemDatabase being created first.
The second connection is being created with a call to isc_start_multiple in
TIB_Transaction.API_Start - the call stack is as follows:
TIB_Transaction.API_Start
TIB_Statement.SysStart
TIB_Statement.CheckTransaction(true)
TIB_Statement.SysExecute
TIB_Dataset.SysExecute
TIB_Dataset.SysOpen
TIB_Dataset.Open
TdmUpgrade.VersionExists
TdmUpgrade.GetDatabaseRelease($197B560) <- pointer to my DatabaseObject
A clip from APIStart is executing this code:
with IB_Session do
begin
errcode := isc_conn_lost;
ticks := GetTickCount + 2000;
while ( errcode = isc_conn_lost ) and ( ticks > GetTickCount ) do
errcode := isc_start_multiple( @status,
PtrHandle,
ConnectionCount,
pteb );
<-------------- extra connection created here
if errcode <> 0 then HandleException( Self );
end;
I do not understand why starting a transaction would create another
connection when it already has one. The crazy thing is that it doesn't
happen all the time, but (at the moment) I can reproduce it relatively
reliably with a particular customer's database.
After disconnection, the remaining 1 attachment to 1 database is not
released for a couple of minutes, but by then my program has long since
decided that the file is already in use.
Any ideas?
Thanks
Josh
Interbase WI-06.0.1.6
Delphi 5
IBObjects (4 something - how do I tell?)
I have a utility that requires exclusive use to a database because the .gdb
will be renamed moved etc. Hence, just prior to that action, it checks to
ensure that the file is not in use. Even before that, it connects to the
.gdb, does a couple of queries, and then disconnects.
The problem is that it (sometimes, on some customer sites), it reports the
database is in use. The reason for this is because in the
connection/queries/disconnection process, IB_Objects is creating not one,
but two connections to the database, and releases only one on disconnection.
The source code looks a bit like this:
function TdmUpgrade.GetDatabaseRelease(
DatabaseObject: TDatabaseObject): TFileVersion;
var
lVersionI : integer;
begin
if txnUpgrade.intransaction then
raise Exception.create('txnUpgrade.intransaction in
TdmUpgrade.GetDatabaseRelease');
//At this point Interbase properties reports 0 attachments to 0
databases - OK
ConnectSystemDatabase(DatabaseObject);
try
//At this point Interbase properties reports 1 attachment to 1
database - OK
txnUpgrade.starttransaction;
try
if VersionExists then //This function call creates another attachment
lVersionI := qryVersionExists.GeneratorValue('GEN_VERSION', 0)
else
lVersionI := 0;
result := VersionIntToFV(lVersionI);
finally
if txnUpgrade.intransaction then
txnUpgrade.commit;
end; //try..finally for txnUpgrade.commit;
finally
//At this point Interbase properties reports 2 attachments to 1 database
DisconnectSystemDatabase;
//At this point Interbase properties reports 1 attachments to 1 database
end; //try..finally for database disconnection
end;
function TdmUpgrade.VersionExists: boolean;
begin
result := false;
try
with qryVersionExists do
begin
close;
//At this point Interbase properties reports 1 attachment to 1
database - OK
open;
//At this point Interbase properties reports 2 attachments to 1
database - NOT OK
if fieldbyname('rdb$generator_name').isnull then
exit;
result := true;
end; //with qryVersionExists do
finally
qryVersionExists.close;
end; //try..finally for qryVersionExists.close;
//At this point Interbase properties reports 2 attachments to 1 database -
NOT OK
end;
It is the open call that creates the second attachment.
qryVersionExists is a TIB_Cursor
qryVersionExists.IB_Transaction = txnUpgrade
qryVersionExists.IB_Connection = ibcSystemDatabase (which is the one that
gets connected in ConnectSystemDatabase)
txnUpgrade.IB_Connection = ibcSystemDatabase
qryVersionExists.IB_Session = ibsSystemDatabase
txnUpgrade.IB_Session = ibsSystemDatabase
ibsSystemDatabase.DefaultConnection = ibcSystemDatabase
qryVersionExists, txnUpgrade, ibcSystemDatabase and ibsSystemDatabase all
exist on the same datamodule with ibsSystemDatabase being created first.
The second connection is being created with a call to isc_start_multiple in
TIB_Transaction.API_Start - the call stack is as follows:
TIB_Transaction.API_Start
TIB_Statement.SysStart
TIB_Statement.CheckTransaction(true)
TIB_Statement.SysExecute
TIB_Dataset.SysExecute
TIB_Dataset.SysOpen
TIB_Dataset.Open
TdmUpgrade.VersionExists
TdmUpgrade.GetDatabaseRelease($197B560) <- pointer to my DatabaseObject
A clip from APIStart is executing this code:
with IB_Session do
begin
errcode := isc_conn_lost;
ticks := GetTickCount + 2000;
while ( errcode = isc_conn_lost ) and ( ticks > GetTickCount ) do
errcode := isc_start_multiple( @status,
PtrHandle,
ConnectionCount,
pteb );
<-------------- extra connection created here
if errcode <> 0 then HandleException( Self );
end;
I do not understand why starting a transaction would create another
connection when it already has one. The crazy thing is that it doesn't
happen all the time, but (at the moment) I can reproduce it relatively
reliably with a particular customer's database.
After disconnection, the remaining 1 attachment to 1 database is not
released for a couple of minutes, but by then my program has long since
decided that the file is already in use.
Any ideas?
Thanks
Josh