The problem:
I’m seeing a combination of E_FAIL and database corruption on each of two threads that each have their own connection open to a jet 4.0 mdb.
Scenario:
I have an application where:
Thread 1 is the main thread. It has an ADO Connection open to an Jet 4.0 mdb using the provider “Microsoft.Jet.OLEDB.4.0”. It is responsible for inserting data into one of two tables located in the mdb, via
hr = pADOConn->Execute("INSERT INTO ...", NULL, adCmdText|adExecuteNoRecords, NULL);
// occasionally returns E_FAIL
Thread 2 is a child of thread 1. It also has an ADO Connection open with the exact same connection string. It is responsible for iterating through records already present in each of the two tables, “pumping” each row up to a server, and then deleting the row out of the table. This is accomplished via (abbreviated to relevant parts only):
countSQL = "select count(*) from TABLE";
iRecCount = pADORstTable->Open(countSQL, pADOConn2, adOpenKeyset, adLockOptimistic, adCmdText);
for (iRecCtr = 0; iRecCtr < iRecCount; iRecCtr++)
{
// provides the capability to skip records
strSQL = "SELECT TOP 1 * FROM (SELECT TOP " + iSkipRecords +
" * FROM TABLE ORDER BY PriKey DESC)";
pADORst->Open(strSQL, pADOConn2, adOpenKeyset, adLockOptimistic, adCmdText);
pADORst->get_EOF(&vbEOF);
if (vbEOF)
break;
RstPriKey = GetFieldValueForPriKey(pADORst);
pADORst->Close();
pADORst->Release();
// pump record to server
...
// delete record
bstrSQL = "delete from TABLE where PriKey = " + RstPriKey;
hr = pADOConn2->Execute(bstrSQL, NULL, adCmdText|adExecuteNoRecords, NULL);
// occasionally returns E_FAIL
}
Workarounds:
- This was originally coded to use a single connection, which the child
thread was passed a pointer to. We’ve since split it into two separate connections. - The code originally created an ado recordset to perform the insert, and used the underlying ADO recordset to perform the pADORst->Delete(). Both have since been changed to use Conn->Execute(…)
- Our next thought is to move onto implementing a critical section, and pass that between the threads. This seems drastic, since it seems that ADO should be able to handle requests coming in from multiple connections.
- I’m familiar with Jet 4.0’s page level locking size of 4k, and I wonder if we’re hitting that, and need to switch to record level locking.
- I’ll entertain anyone else’s thoughts, drastic as they may be…
Edit 1:
Just tried wrapping both ->Execute()’s in a critical section; still setting E_FAIL occasionally from the DELETE FROM.
Edit 2:
Also tried closing the recordset immediately after retrieving primary key value (code updated to reflect changes)
Is there a more descriptive error message you are receiving? My guess is that is is a concurrency violation. You may try closing and releasing “pADORstTable” since both recordsets are operating on the same table. I would also close and release “pADORst” after EOF.