SQLite

Check-in [3144ae40d2]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Do not write master journal filenames into server-mode journal files. Use SQLITE_MUTEX_STATIC_APP1 to protect critical sections in server.c.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | server-edition
Files: files | file ages | folders
SHA3-256: 3144ae40d2eb63dfd5587579a49163ea1add5947d624daa478ada13339495af4
User & Date: dan 2017-04-27 14:12:43.330
Context
2017-04-28
10:20
Use a different free-list format for server-mode databases in order to reduce contention. (check-in: 778e8a102d user: dan tags: server-edition)
2017-04-27
14:12
Do not write master journal filenames into server-mode journal files. Use SQLITE_MUTEX_STATIC_APP1 to protect critical sections in server.c. (check-in: 3144ae40d2 user: dan tags: server-edition)
13:05
If possible, delete the journal file when a database connection is closed. (check-in: d5b5326df2 user: dan tags: server-edition)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/pager.c.
6435
6436
6437
6438
6439
6440
6441




6442
6443
6444
6445
6446
6447
6448
  assert( isOpen(pPager->fd) || pPager->tempFile );
  if( 0==pagerFlushOnCommit(pPager, 1) ){
    /* If this is an in-memory db, or no pages have been written to, or this
    ** function has already been called, it is mostly a no-op.  However, any
    ** backup in progress needs to be restarted.  */
    sqlite3BackupRestart(pPager->pBackup);
  }else{




    if( pagerUseWal(pPager) ){
      PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache);
      PgHdr *pPageOne = 0;
      if( pList==0 ){
        /* Must have at least one page for the WAL commit flag.
        ** Ticket [2d1a5c67dfc2363e44f29d9bbd57f] 2011-05-18 */
        rc = sqlite3PagerGet(pPager, 1, &pPageOne, 0);







>
>
>
>







6435
6436
6437
6438
6439
6440
6441
6442
6443
6444
6445
6446
6447
6448
6449
6450
6451
6452
  assert( isOpen(pPager->fd) || pPager->tempFile );
  if( 0==pagerFlushOnCommit(pPager, 1) ){
    /* If this is an in-memory db, or no pages have been written to, or this
    ** function has already been called, it is mostly a no-op.  However, any
    ** backup in progress needs to be restarted.  */
    sqlite3BackupRestart(pPager->pBackup);
  }else{
    /* If this connection is in server mode, ignore any master journal. */
    if( pagerIsServer(pPager) ){
      zMaster = 0;
    }
    if( pagerUseWal(pPager) ){
      PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache);
      PgHdr *pPageOne = 0;
      if( pList==0 ){
        /* Must have at least one page for the WAL commit flag.
        ** Ticket [2d1a5c67dfc2363e44f29d9bbd57f] 2011-05-18 */
        rc = sqlite3PagerGet(pPager, 1, &pPageOne, 0);
Changes to src/server.c.
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include "sys/mman.h"
#include "sys/types.h"
#include "sys/stat.h"

typedef struct ServerHMA ServerHMA;

struct ServerGlobal {
  sqlite3_mutex *mutex;
  ServerHMA *pHma;
};
static struct ServerGlobal g_server;

/*
** There is one instance of the following structure for each distinct 
** HMA file opened by clients within this process. 
*/







<
|







46
47
48
49
50
51
52

53
54
55
56
57
58
59
60
#include "sys/mman.h"
#include "sys/types.h"
#include "sys/stat.h"

typedef struct ServerHMA ServerHMA;

struct ServerGlobal {

  ServerHMA *pHma;                /* Linked list of all ServerHMA objects */
};
static struct ServerGlobal g_server;

/*
** There is one instance of the following structure for each distinct 
** HMA file opened by clients within this process. 
*/
80
81
82
83
84
85
86













87
88
89
90
91
92
93
  int nLock;                      /* Number of entries in aLock[] */
  u32 *aLock;                     /* Mapped lock file */
};

#define SERVER_WRITE_LOCK 3
#define SERVER_READ_LOCK  2
#define SERVER_NO_LOCK    1














static int posixLock(int fd, int iSlot, int eLock, int bBlock){
  int res;
  struct flock l;
  short aType[4] = {0, F_UNLCK, F_RDLCK, F_WRLCK};
  assert( eLock==SERVER_WRITE_LOCK 
       || eLock==SERVER_READ_LOCK 







>
>
>
>
>
>
>
>
>
>
>
>
>







79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
  int nLock;                      /* Number of entries in aLock[] */
  u32 *aLock;                     /* Mapped lock file */
};

#define SERVER_WRITE_LOCK 3
#define SERVER_READ_LOCK  2
#define SERVER_NO_LOCK    1

/*
** Global mutex functions used by code in this file.
*/
static void serverEnterMutex(void){
  sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_APP1));
}
static void serverLeaveMutex(void){
  sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_APP1));
}
static void serverAssertMutexHeld(void){
  assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_APP1)) );
}

static int posixLock(int fd, int iSlot, int eLock, int bBlock){
  int res;
  struct flock l;
  short aType[4] = {0, F_UNLCK, F_RDLCK, F_WRLCK};
  assert( eLock==SERVER_WRITE_LOCK 
       || eLock==SERVER_READ_LOCK 
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144

static int serverOpenHma(Pager *pPager, const char *zPath, ServerHMA **ppHma){
  struct stat sStat;              /* Structure populated by stat() */
  int res;                        /* result of stat() */
  int rc = SQLITE_OK;             /* Return code */
  ServerHMA *pHma = 0;

  assert( sqlite3_mutex_held(g_server.mutex) );

  res = stat(zPath, &sStat);
  if( res!=0 ){
    sqlite3_log(SQLITE_CANTOPEN, "Failed to stat(%s)", zPath);
    rc = SQLITE_ERROR;
  }else{
    for(pHma=g_server.pHma; pHma; pHma=pHma->pNext){







|







142
143
144
145
146
147
148
149
150
151
152
153
154
155
156

static int serverOpenHma(Pager *pPager, const char *zPath, ServerHMA **ppHma){
  struct stat sStat;              /* Structure populated by stat() */
  int res;                        /* result of stat() */
  int rc = SQLITE_OK;             /* Return code */
  ServerHMA *pHma = 0;

  serverAssertMutexHeld();

  res = stat(zPath, &sStat);
  if( res!=0 ){
    sqlite3_log(SQLITE_CANTOPEN, "Failed to stat(%s)", zPath);
    rc = SQLITE_ERROR;
  }else{
    for(pHma=g_server.pHma; pHma; pHma=pHma->pNext){
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
/*
** Close the "connection" and *-hma file. This deletes the object passed
** as the first argument.
*/
void sqlite3ServerDisconnect(Server *p, sqlite3_file *dbfd){
  if( p->pHma ){
    ServerHMA *pHma = p->pHma;
    sqlite3_mutex_enter(g_server.mutex);
    if( p->iClient>=0 ){
      u32 *pSlot = serverClientSlot(p, p->iClient);
      *pSlot = 0;
      assert( pHma->aClient[p->iClient]==p );
      pHma->aClient[p->iClient] = 0;
      posixLock(pHma->fd, p->iClient+1, SERVER_NO_LOCK, 0);
    }
    if( dbfd 
     && pHma->nClient==1 
     && SQLITE_OK==sqlite3OsLock(dbfd, SQLITE_LOCK_EXCLUSIVE)
    ){
      unlink(pHma->zName);
    }
    serverDecrHmaRefcount(pHma);
    sqlite3_mutex_leave(g_server.mutex);
  }
  sqlite3_free(p->aLock);
  sqlite3_free(p);
}

static int serverRollbackClient(Server *p, int iBlock){
  int rc;







|














|







237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
/*
** Close the "connection" and *-hma file. This deletes the object passed
** as the first argument.
*/
void sqlite3ServerDisconnect(Server *p, sqlite3_file *dbfd){
  if( p->pHma ){
    ServerHMA *pHma = p->pHma;
    serverEnterMutex();
    if( p->iClient>=0 ){
      u32 *pSlot = serverClientSlot(p, p->iClient);
      *pSlot = 0;
      assert( pHma->aClient[p->iClient]==p );
      pHma->aClient[p->iClient] = 0;
      posixLock(pHma->fd, p->iClient+1, SERVER_NO_LOCK, 0);
    }
    if( dbfd 
     && pHma->nClient==1 
     && SQLITE_OK==sqlite3OsLock(dbfd, SQLITE_LOCK_EXCLUSIVE)
    ){
      unlink(pHma->zName);
    }
    serverDecrHmaRefcount(pHma);
    serverLeaveMutex();
  }
  sqlite3_free(p->aLock);
  sqlite3_free(p);
}

static int serverRollbackClient(Server *p, int iBlock){
  int rc;
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
  if( p==0 ){
    rc = SQLITE_NOMEM;
  }else{
    memset(p, 0, sizeof(Server));
    p->iClient = -1;
    p->pPager = pPager;

    sqlite3_mutex_enter(g_server.mutex);
    rc = serverOpenHma(pPager, zPath, &p->pHma);

    /* File is now mapped. Find a free client slot. */
    if( rc==SQLITE_OK ){
      int i;
      Server **aClient = p->pHma->aClient;
      int fd = p->pHma->fd;







|







307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
  if( p==0 ){
    rc = SQLITE_NOMEM;
  }else{
    memset(p, 0, sizeof(Server));
    p->iClient = -1;
    p->pPager = pPager;

    serverEnterMutex();
    rc = serverOpenHma(pPager, zPath, &p->pHma);

    /* File is now mapped. Find a free client slot. */
    if( rc==SQLITE_OK ){
      int i;
      Server **aClient = p->pHma->aClient;
      int fd = p->pHma->fd;
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
          *piClient = p->iClient = i;
          aClient[i] = p;
          *pSlot = 1;
        }
      }
    }

    sqlite3_mutex_leave(g_server.mutex);
  }

  if( rc!=SQLITE_OK ){
    sqlite3ServerDisconnect(p, 0);
    p = 0;
  }
  *ppOut = p;







|







341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
          *piClient = p->iClient = i;
          aClient[i] = p;
          *pSlot = 1;
        }
      }
    }

    serverLeaveMutex();
  }

  if( rc!=SQLITE_OK ){
    sqlite3ServerDisconnect(p, 0);
    p = 0;
  }
  *ppOut = p;
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
  if( iBlock<0 ){
    for(iBlock=0; iBlock<HMA_CLIENT_SLOTS; iBlock++){
      if( iBlock!=p->iClient && (v & (1<<iBlock)) ) break;
    }
  }
  assert( iBlock<HMA_CLIENT_SLOTS );

  sqlite3_mutex_enter(g_server.mutex);
  if( p->pHma->aClient[iBlock] ){
    bLocal = 1;
  }else{
    rc = posixLock(p->pHma->fd, iBlock+1, SERVER_WRITE_LOCK, 0);
  }

  if( bLocal==0 && rc==SQLITE_OK ){
    rc = serverRollbackClient(p, iBlock);

    /* Release the lock on slot iBlock */
    posixLock(p->pHma->fd, iBlock+1, SERVER_NO_LOCK, 0);
    if( rc==SQLITE_OK ){
      *pbRetry = 1;
    }
  }else{
    assert( rc==SQLITE_OK || rc==SQLITE_BUSY );
    rc = SQLITE_OK;
  }
  sqlite3_mutex_leave(g_server.mutex);

  return rc;
}

/*
** Begin a transaction.
*/







|


















|







364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
  if( iBlock<0 ){
    for(iBlock=0; iBlock<HMA_CLIENT_SLOTS; iBlock++){
      if( iBlock!=p->iClient && (v & (1<<iBlock)) ) break;
    }
  }
  assert( iBlock<HMA_CLIENT_SLOTS );

  serverEnterMutex();
  if( p->pHma->aClient[iBlock] ){
    bLocal = 1;
  }else{
    rc = posixLock(p->pHma->fd, iBlock+1, SERVER_WRITE_LOCK, 0);
  }

  if( bLocal==0 && rc==SQLITE_OK ){
    rc = serverRollbackClient(p, iBlock);

    /* Release the lock on slot iBlock */
    posixLock(p->pHma->fd, iBlock+1, SERVER_NO_LOCK, 0);
    if( rc==SQLITE_OK ){
      *pbRetry = 1;
    }
  }else{
    assert( rc==SQLITE_OK || rc==SQLITE_BUSY );
    rc = SQLITE_OK;
  }
  serverLeaveMutex();

  return rc;
}

/*
** Begin a transaction.
*/