SQLite

Check-in [9529ed88a7]
Login

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

Overview
Comment:Optimize the xMremap method in os_unix.c some.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | experimental-mmap
Files: files | file ages | folders
SHA1: 9529ed88a71fee02fae72dc86f0669bd6856ff92
User & Date: dan 2013-03-20 18:25:49.737
Context
2013-03-21
14:47
Do not use the Linux mremap() call. Use the same strategy for xMremap() as on OSX instead. (check-in: 5ed8ad780c user: dan tags: experimental-mmap)
2013-03-20
18:25
Optimize the xMremap method in os_unix.c some. (check-in: 9529ed88a7 user: dan tags: experimental-mmap)
14:26
When possible, use memory mapping when appending new pages to a database file. (check-in: 14135da3cd user: dan tags: experimental-mmap)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/os_unix.c.
4425
4426
4427
4428
4429
4430
4431










4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446

4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463

































4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475

4476
4477
4478
4479
4480

4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
#else
# define unixShmMap     0
# define unixShmLock    0
# define unixShmBarrier 0
# define unixShmUnmap   0
#endif /* #ifndef SQLITE_OMIT_WAL */











/*
** Map, remap or unmap part of the database file.
*/
static int unixMremap(
  sqlite3_file *fd,               /* Main database file */
  int flags,                      /* Mask of SQLITE_MREMAP_XXX flags */
  sqlite3_int64 iOff,             /* Offset to start mapping at */
  sqlite3_int64 nOld,             /* Size of old mapping, or zero */
  sqlite3_int64 nNew,             /* Size of new mapping, or zero */
  void **ppMap                    /* IN/OUT: Old/new mappings */
){
  unixFile *p = (unixFile *)fd;   /* The underlying database file */
  int rc = SQLITE_OK;             /* Return code */
  void *pNew = 0;                 /* New mapping */
  i64 nRnd;                       /* nNew rounded up to 4096 */


  assert( iOff==0 );
  nRnd = (nNew+4095) & ~(i64)((1 << 12)-1);

  /* If the SQLITE_MREMAP_EXTEND flag is set, then the size of the requested 
  ** mapping (nNew bytes) may be greater than the size of the database file.
  ** If this is the case, extend the file on disk using ftruncate().  */
  assert( nNew>0 || (flags & SQLITE_MREMAP_EXTEND)==0 );
  if( flags & SQLITE_MREMAP_EXTEND ){
    struct stat statbuf;          /* Low-level file information */
    rc = osFstat(p->h, &statbuf);
    if( rc==SQLITE_OK && nNew>statbuf.st_size ){
      rc = robust_ftruncate(p->h, nNew);
    }
    if( rc!=SQLITE_OK ) return rc;
  }


































#if defined(_GNU_SOURCE) && defined(__linux__)
  if( nRnd && nOld ){
    void *pOld = *ppMap;
    *ppMap = pNew = mremap(pOld, nOld, nNew, MREMAP_MAYMOVE);
    if( pNew==MAP_FAILED ){
      *ppMap = 0;
      return SQLITE_IOERR_MREMAP;
    }
    return SQLITE_OK;
  }
#endif


  if( nOld!=0 ){
    void *pOld = *ppMap;
    munmap(pOld, nOld);
  }


  if( nNew>0 ){
    int flags = PROT_READ;
    if( (p->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;
    pNew = mmap(0, nRnd, flags, MAP_SHARED, p->h, iOff);
    if( pNew==MAP_FAILED ){
      pNew = 0;
      rc = SQLITE_IOERR_MREMAP;
    }
  }

  *ppMap = pNew;







>
>
>
>
>
>
>
>
>
>














|
>


<














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

|

|








>
|

|


>
|


|







4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459

4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
#else
# define unixShmMap     0
# define unixShmLock    0
# define unixShmBarrier 0
# define unixShmUnmap   0
#endif /* #ifndef SQLITE_OMIT_WAL */

/*
** Arguments x and y are both integers. Argument y must be a power of 2.
** Round x up to the nearest integer multiple of y. For example:
**
**     ROUNDUP(0,  8) ->  0
**     ROUNDUP(13, 8) -> 16
**     ROUNDUP(32, 8) -> 32
*/
#define ROUNDUP(x,y)     (((x)+y-1)&~(y-1))

/*
** Map, remap or unmap part of the database file.
*/
static int unixMremap(
  sqlite3_file *fd,               /* Main database file */
  int flags,                      /* Mask of SQLITE_MREMAP_XXX flags */
  sqlite3_int64 iOff,             /* Offset to start mapping at */
  sqlite3_int64 nOld,             /* Size of old mapping, or zero */
  sqlite3_int64 nNew,             /* Size of new mapping, or zero */
  void **ppMap                    /* IN/OUT: Old/new mappings */
){
  unixFile *p = (unixFile *)fd;   /* The underlying database file */
  int rc = SQLITE_OK;             /* Return code */
  void *pNew = 0;                 /* New mapping */
  i64 nNewRnd;                    /* nNew rounded up */
  i64 nOldRnd;                    /* nOld rounded up */

  assert( iOff==0 );


  /* If the SQLITE_MREMAP_EXTEND flag is set, then the size of the requested 
  ** mapping (nNew bytes) may be greater than the size of the database file.
  ** If this is the case, extend the file on disk using ftruncate().  */
  assert( nNew>0 || (flags & SQLITE_MREMAP_EXTEND)==0 );
  if( flags & SQLITE_MREMAP_EXTEND ){
    struct stat statbuf;          /* Low-level file information */
    rc = osFstat(p->h, &statbuf);
    if( rc==SQLITE_OK && nNew>statbuf.st_size ){
      rc = robust_ftruncate(p->h, nNew);
    }
    if( rc!=SQLITE_OK ) return rc;
  }

  /* According to some sources, the effect of changing the size of the
  ** underlying file on mapped regions that correspond to the added or
  ** removed pages is undefined. However, there is reason to believe that
  ** on modern platforms like Linux or OSX, things just work. For example,
  ** it is possible to create a mapping larger than the file on disk and
  ** extend the file on disk later on.
  **
  ** Exploit this on OSX to reduce the number of munmap()/mmap() calls
  ** if the file size is changing. In this case all mappings are rounded
  ** up to the nearest 4MB. And if a new mapping is requested that has the
  ** same rounded size as an old mapping, the old mapping can simply be
  ** reused as is.
  **
  ** It would be possible to do the above on Linux too. However, Linux has
  ** the non-standard mremap() call to resize existing mappings, which can
  ** be used instead.  */
#if defined(__APPLE__)
  nNewRnd = ROUNDUP(nNew, 4096*1024);
  nOldRnd = ROUNDUP(nOld, 4096*1024);
#else
  nNewRnd = ROUNDUP(nNew, 4096*1);
  nOldRnd = ROUNDUP(nOld, 4096*1);
#endif

  /* On OSX or Linux, reuse the old mapping if it is the right size. */
#if defined(__APPLE__) || defined(__linux__)
  if( nNewRnd==nOldRnd ){
    return SQLITE_OK;
  }
#endif

  /* On Linux, if there is both an old and new mapping, resize the old 
  ** mapping using the non-standard mremap() call.  */
#if defined(_GNU_SOURCE) && defined(__linux__)
  if( nNewRnd && nOldRnd ){
    void *pOld = *ppMap;
    *ppMap = pNew = mremap(pOld, nOldRnd, nNewRnd, MREMAP_MAYMOVE);
    if( pNew==MAP_FAILED ){
      *ppMap = 0;
      return SQLITE_IOERR_MREMAP;
    }
    return SQLITE_OK;
  }
#endif

  /* If we get this far, unmap any old mapping. */
  if( nOldRnd!=0 ){
    void *pOld = *ppMap;
    munmap(pOld, nOldRnd);
  }

  /* And, if required, use mmap() to create a new mapping. */
  if( nNewRnd>0 ){
    int flags = PROT_READ;
    if( (p->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;
    pNew = mmap(0, nNewRnd, flags, MAP_SHARED, p->h, iOff);
    if( pNew==MAP_FAILED ){
      pNew = 0;
      rc = SQLITE_IOERR_MREMAP;
    }
  }

  *ppMap = pNew;