Annotation of embedaddon/sqlite3/src/notify.c, revision 1.1.1.1

1.1       misho       1: /*
                      2: ** 2009 March 3
                      3: **
                      4: ** The author disclaims copyright to this source code.  In place of
                      5: ** a legal notice, here is a blessing:
                      6: **
                      7: **    May you do good and not evil.
                      8: **    May you find forgiveness for yourself and forgive others.
                      9: **    May you share freely, never taking more than you give.
                     10: **
                     11: *************************************************************************
                     12: **
                     13: ** This file contains the implementation of the sqlite3_unlock_notify()
                     14: ** API method and its associated functionality.
                     15: */
                     16: #include "sqliteInt.h"
                     17: #include "btreeInt.h"
                     18: 
                     19: /* Omit this entire file if SQLITE_ENABLE_UNLOCK_NOTIFY is not defined. */
                     20: #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
                     21: 
                     22: /*
                     23: ** Public interfaces:
                     24: **
                     25: **   sqlite3ConnectionBlocked()
                     26: **   sqlite3ConnectionUnlocked()
                     27: **   sqlite3ConnectionClosed()
                     28: **   sqlite3_unlock_notify()
                     29: */
                     30: 
                     31: #define assertMutexHeld() \
                     32:   assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)) )
                     33: 
                     34: /*
                     35: ** Head of a linked list of all sqlite3 objects created by this process
                     36: ** for which either sqlite3.pBlockingConnection or sqlite3.pUnlockConnection
                     37: ** is not NULL. This variable may only accessed while the STATIC_MASTER
                     38: ** mutex is held.
                     39: */
                     40: static sqlite3 *SQLITE_WSD sqlite3BlockedList = 0;
                     41: 
                     42: #ifndef NDEBUG
                     43: /*
                     44: ** This function is a complex assert() that verifies the following 
                     45: ** properties of the blocked connections list:
                     46: **
                     47: **   1) Each entry in the list has a non-NULL value for either 
                     48: **      pUnlockConnection or pBlockingConnection, or both.
                     49: **
                     50: **   2) All entries in the list that share a common value for 
                     51: **      xUnlockNotify are grouped together.
                     52: **
                     53: **   3) If the argument db is not NULL, then none of the entries in the
                     54: **      blocked connections list have pUnlockConnection or pBlockingConnection
                     55: **      set to db. This is used when closing connection db.
                     56: */
                     57: static void checkListProperties(sqlite3 *db){
                     58:   sqlite3 *p;
                     59:   for(p=sqlite3BlockedList; p; p=p->pNextBlocked){
                     60:     int seen = 0;
                     61:     sqlite3 *p2;
                     62: 
                     63:     /* Verify property (1) */
                     64:     assert( p->pUnlockConnection || p->pBlockingConnection );
                     65: 
                     66:     /* Verify property (2) */
                     67:     for(p2=sqlite3BlockedList; p2!=p; p2=p2->pNextBlocked){
                     68:       if( p2->xUnlockNotify==p->xUnlockNotify ) seen = 1;
                     69:       assert( p2->xUnlockNotify==p->xUnlockNotify || !seen );
                     70:       assert( db==0 || p->pUnlockConnection!=db );
                     71:       assert( db==0 || p->pBlockingConnection!=db );
                     72:     }
                     73:   }
                     74: }
                     75: #else
                     76: # define checkListProperties(x)
                     77: #endif
                     78: 
                     79: /*
                     80: ** Remove connection db from the blocked connections list. If connection
                     81: ** db is not currently a part of the list, this function is a no-op.
                     82: */
                     83: static void removeFromBlockedList(sqlite3 *db){
                     84:   sqlite3 **pp;
                     85:   assertMutexHeld();
                     86:   for(pp=&sqlite3BlockedList; *pp; pp = &(*pp)->pNextBlocked){
                     87:     if( *pp==db ){
                     88:       *pp = (*pp)->pNextBlocked;
                     89:       break;
                     90:     }
                     91:   }
                     92: }
                     93: 
                     94: /*
                     95: ** Add connection db to the blocked connections list. It is assumed
                     96: ** that it is not already a part of the list.
                     97: */
                     98: static void addToBlockedList(sqlite3 *db){
                     99:   sqlite3 **pp;
                    100:   assertMutexHeld();
                    101:   for(
                    102:     pp=&sqlite3BlockedList; 
                    103:     *pp && (*pp)->xUnlockNotify!=db->xUnlockNotify; 
                    104:     pp=&(*pp)->pNextBlocked
                    105:   );
                    106:   db->pNextBlocked = *pp;
                    107:   *pp = db;
                    108: }
                    109: 
                    110: /*
                    111: ** Obtain the STATIC_MASTER mutex.
                    112: */
                    113: static void enterMutex(void){
                    114:   sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
                    115:   checkListProperties(0);
                    116: }
                    117: 
                    118: /*
                    119: ** Release the STATIC_MASTER mutex.
                    120: */
                    121: static void leaveMutex(void){
                    122:   assertMutexHeld();
                    123:   checkListProperties(0);
                    124:   sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
                    125: }
                    126: 
                    127: /*
                    128: ** Register an unlock-notify callback.
                    129: **
                    130: ** This is called after connection "db" has attempted some operation
                    131: ** but has received an SQLITE_LOCKED error because another connection
                    132: ** (call it pOther) in the same process was busy using the same shared
                    133: ** cache.  pOther is found by looking at db->pBlockingConnection.
                    134: **
                    135: ** If there is no blocking connection, the callback is invoked immediately,
                    136: ** before this routine returns.
                    137: **
                    138: ** If pOther is already blocked on db, then report SQLITE_LOCKED, to indicate
                    139: ** a deadlock.
                    140: **
                    141: ** Otherwise, make arrangements to invoke xNotify when pOther drops
                    142: ** its locks.
                    143: **
                    144: ** Each call to this routine overrides any prior callbacks registered
                    145: ** on the same "db".  If xNotify==0 then any prior callbacks are immediately
                    146: ** cancelled.
                    147: */
                    148: int sqlite3_unlock_notify(
                    149:   sqlite3 *db,
                    150:   void (*xNotify)(void **, int),
                    151:   void *pArg
                    152: ){
                    153:   int rc = SQLITE_OK;
                    154: 
                    155:   sqlite3_mutex_enter(db->mutex);
                    156:   enterMutex();
                    157: 
                    158:   if( xNotify==0 ){
                    159:     removeFromBlockedList(db);
                    160:     db->pBlockingConnection = 0;
                    161:     db->pUnlockConnection = 0;
                    162:     db->xUnlockNotify = 0;
                    163:     db->pUnlockArg = 0;
                    164:   }else if( 0==db->pBlockingConnection ){
                    165:     /* The blocking transaction has been concluded. Or there never was a 
                    166:     ** blocking transaction. In either case, invoke the notify callback
                    167:     ** immediately. 
                    168:     */
                    169:     xNotify(&pArg, 1);
                    170:   }else{
                    171:     sqlite3 *p;
                    172: 
                    173:     for(p=db->pBlockingConnection; p && p!=db; p=p->pUnlockConnection){}
                    174:     if( p ){
                    175:       rc = SQLITE_LOCKED;              /* Deadlock detected. */
                    176:     }else{
                    177:       db->pUnlockConnection = db->pBlockingConnection;
                    178:       db->xUnlockNotify = xNotify;
                    179:       db->pUnlockArg = pArg;
                    180:       removeFromBlockedList(db);
                    181:       addToBlockedList(db);
                    182:     }
                    183:   }
                    184: 
                    185:   leaveMutex();
                    186:   assert( !db->mallocFailed );
                    187:   sqlite3Error(db, rc, (rc?"database is deadlocked":0));
                    188:   sqlite3_mutex_leave(db->mutex);
                    189:   return rc;
                    190: }
                    191: 
                    192: /*
                    193: ** This function is called while stepping or preparing a statement 
                    194: ** associated with connection db. The operation will return SQLITE_LOCKED
                    195: ** to the user because it requires a lock that will not be available
                    196: ** until connection pBlocker concludes its current transaction.
                    197: */
                    198: void sqlite3ConnectionBlocked(sqlite3 *db, sqlite3 *pBlocker){
                    199:   enterMutex();
                    200:   if( db->pBlockingConnection==0 && db->pUnlockConnection==0 ){
                    201:     addToBlockedList(db);
                    202:   }
                    203:   db->pBlockingConnection = pBlocker;
                    204:   leaveMutex();
                    205: }
                    206: 
                    207: /*
                    208: ** This function is called when
                    209: ** the transaction opened by database db has just finished. Locks held 
                    210: ** by database connection db have been released.
                    211: **
                    212: ** This function loops through each entry in the blocked connections
                    213: ** list and does the following:
                    214: **
                    215: **   1) If the sqlite3.pBlockingConnection member of a list entry is
                    216: **      set to db, then set pBlockingConnection=0.
                    217: **
                    218: **   2) If the sqlite3.pUnlockConnection member of a list entry is
                    219: **      set to db, then invoke the configured unlock-notify callback and
                    220: **      set pUnlockConnection=0.
                    221: **
                    222: **   3) If the two steps above mean that pBlockingConnection==0 and
                    223: **      pUnlockConnection==0, remove the entry from the blocked connections
                    224: **      list.
                    225: */
                    226: void sqlite3ConnectionUnlocked(sqlite3 *db){
                    227:   void (*xUnlockNotify)(void **, int) = 0; /* Unlock-notify cb to invoke */
                    228:   int nArg = 0;                            /* Number of entries in aArg[] */
                    229:   sqlite3 **pp;                            /* Iterator variable */
                    230:   void **aArg;               /* Arguments to the unlock callback */
                    231:   void **aDyn = 0;           /* Dynamically allocated space for aArg[] */
                    232:   void *aStatic[16];         /* Starter space for aArg[].  No malloc required */
                    233: 
                    234:   aArg = aStatic;
                    235:   enterMutex();         /* Enter STATIC_MASTER mutex */
                    236: 
                    237:   /* This loop runs once for each entry in the blocked-connections list. */
                    238:   for(pp=&sqlite3BlockedList; *pp; /* no-op */ ){
                    239:     sqlite3 *p = *pp;
                    240: 
                    241:     /* Step 1. */
                    242:     if( p->pBlockingConnection==db ){
                    243:       p->pBlockingConnection = 0;
                    244:     }
                    245: 
                    246:     /* Step 2. */
                    247:     if( p->pUnlockConnection==db ){
                    248:       assert( p->xUnlockNotify );
                    249:       if( p->xUnlockNotify!=xUnlockNotify && nArg!=0 ){
                    250:         xUnlockNotify(aArg, nArg);
                    251:         nArg = 0;
                    252:       }
                    253: 
                    254:       sqlite3BeginBenignMalloc();
                    255:       assert( aArg==aDyn || (aDyn==0 && aArg==aStatic) );
                    256:       assert( nArg<=(int)ArraySize(aStatic) || aArg==aDyn );
                    257:       if( (!aDyn && nArg==(int)ArraySize(aStatic))
                    258:        || (aDyn && nArg==(int)(sqlite3MallocSize(aDyn)/sizeof(void*)))
                    259:       ){
                    260:         /* The aArg[] array needs to grow. */
                    261:         void **pNew = (void **)sqlite3Malloc(nArg*sizeof(void *)*2);
                    262:         if( pNew ){
                    263:           memcpy(pNew, aArg, nArg*sizeof(void *));
                    264:           sqlite3_free(aDyn);
                    265:           aDyn = aArg = pNew;
                    266:         }else{
                    267:           /* This occurs when the array of context pointers that need to
                    268:           ** be passed to the unlock-notify callback is larger than the
                    269:           ** aStatic[] array allocated on the stack and the attempt to 
                    270:           ** allocate a larger array from the heap has failed.
                    271:           **
                    272:           ** This is a difficult situation to handle. Returning an error
                    273:           ** code to the caller is insufficient, as even if an error code
                    274:           ** is returned the transaction on connection db will still be
                    275:           ** closed and the unlock-notify callbacks on blocked connections
                    276:           ** will go unissued. This might cause the application to wait
                    277:           ** indefinitely for an unlock-notify callback that will never 
                    278:           ** arrive.
                    279:           **
                    280:           ** Instead, invoke the unlock-notify callback with the context
                    281:           ** array already accumulated. We can then clear the array and
                    282:           ** begin accumulating any further context pointers without 
                    283:           ** requiring any dynamic allocation. This is sub-optimal because
                    284:           ** it means that instead of one callback with a large array of
                    285:           ** context pointers the application will receive two or more
                    286:           ** callbacks with smaller arrays of context pointers, which will
                    287:           ** reduce the applications ability to prioritize multiple 
                    288:           ** connections. But it is the best that can be done under the
                    289:           ** circumstances.
                    290:           */
                    291:           xUnlockNotify(aArg, nArg);
                    292:           nArg = 0;
                    293:         }
                    294:       }
                    295:       sqlite3EndBenignMalloc();
                    296: 
                    297:       aArg[nArg++] = p->pUnlockArg;
                    298:       xUnlockNotify = p->xUnlockNotify;
                    299:       p->pUnlockConnection = 0;
                    300:       p->xUnlockNotify = 0;
                    301:       p->pUnlockArg = 0;
                    302:     }
                    303: 
                    304:     /* Step 3. */
                    305:     if( p->pBlockingConnection==0 && p->pUnlockConnection==0 ){
                    306:       /* Remove connection p from the blocked connections list. */
                    307:       *pp = p->pNextBlocked;
                    308:       p->pNextBlocked = 0;
                    309:     }else{
                    310:       pp = &p->pNextBlocked;
                    311:     }
                    312:   }
                    313: 
                    314:   if( nArg!=0 ){
                    315:     xUnlockNotify(aArg, nArg);
                    316:   }
                    317:   sqlite3_free(aDyn);
                    318:   leaveMutex();         /* Leave STATIC_MASTER mutex */
                    319: }
                    320: 
                    321: /*
                    322: ** This is called when the database connection passed as an argument is 
                    323: ** being closed. The connection is removed from the blocked list.
                    324: */
                    325: void sqlite3ConnectionClosed(sqlite3 *db){
                    326:   sqlite3ConnectionUnlocked(db);
                    327:   enterMutex();
                    328:   removeFromBlockedList(db);
                    329:   checkListProperties(db);
                    330:   leaveMutex();
                    331: }
                    332: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>