In the source code of SQLite, btree.c, sqlite3BtreeBeginTrans function,
The code
do {
/* Call lockBtree() until either pBt-pPage1 is populated or
** lockBtree() returns something other than SQLITE_OK. lockBtree()
** may return SQLITE_OK but leave pBt-pPage1 set to 0 if after
** reading page 1 it discovers that the page-size of the database
** file is not pBt-pageSize. In this case lockBtree() will update
** pBt-pageSize to the page-size of the file on disk.
*/
while( pBt-pPage1==0 SQLITE_OK==(rc = lockBtree(pBt)) );
if( rc==SQLITE_OK wrflag ){
if( (pBt-btsFlags BTS_READ_ONLY)!=0 ){
rc = SQLITE_READONLY;
}else{
rc = sqlite3PagerBegin(pBt-pPager,wrflag1,sqlite3TempInMemory(p-db));
if( rc==SQLITE_OK ){
rc = newDatabase(pBt);
}
}
}
if( rc!=SQLITE_OK ){
unlockBtreeIfUnused(pBt);
}
}while( (rc0xFF)==SQLITE_BUSY pBt-inTransaction==TRANS_NONE
btreeInvokeBusyHandler(pBt) );
You can see pBt-inTransaction==TRANS_NONE is one of the condition that invoke
busy handler.
There is a simple way to simulate a situation that does not invoke busy handler:
1. begin a transaction without ?IMMEDIATE? and ?EXCLUSIVE?
2. run a read operation, like ?SELECT?. This will let pBt-inTransaction be
TRANS_READ
3. run a write operation, which will invoke sqlite3BtreeBeginTrans again. And
if it becomes SQLITE_BUSY, then btreeInvokeBusyHandler will be skiped and no
retry will happen.
So it?s the question I confused. Why SQLite skip invoking busy handler while
it's in TRANS (either read or write) ?