SQLite

Check-in [9a08371171]
Login

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

Overview
Comment:Invoke the SQLITE_FCNTL_SIZE_HINT opcode on the sqlite3_file_control() interface for database files before extending the size of the file. The VFS can use this hint to preallocate space.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | branch-3.6.1
Files: files | file ages | folders
SHA1: 9a083711712d652613c93b3ad96d4f7361376c7f
User & Date: drh 2010-05-17 15:33:24.000
Context
2010-05-17
15:52
An improvement to the SQLITE_FCNTL_SIZE_HINT change that invokes the hint less often and only when really needed. (check-in: a1d20ceb9c user: drh tags: branch-3.6.1)
15:33
Invoke the SQLITE_FCNTL_SIZE_HINT opcode on the sqlite3_file_control() interface for database files before extending the size of the file. The VFS can use this hint to preallocate space. (check-in: 9a08371171 user: drh tags: branch-3.6.1)
2010-03-03
15:49
Fix some extra instances of the problematic constant in util.c on the 3.6.1 branch. (check-in: 527c71d54e user: dan tags: branch-3.6.1)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/os_unix.c.
2050
2051
2052
2053
2054
2055
2056






2057
2058
2059
2060
2061
2062
2063
** Information and control of an open file handle.
*/
static int unixFileControl(sqlite3_file *id, int op, void *pArg){
  switch( op ){
    case SQLITE_FCNTL_LOCKSTATE: {
      *(int*)pArg = ((unixFile*)id)->locktype;
      return SQLITE_OK;






    }
  }
  return SQLITE_ERROR;
}

/*
** Return the sector size in bytes of the underlying block device for







>
>
>
>
>
>







2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
** Information and control of an open file handle.
*/
static int unixFileControl(sqlite3_file *id, int op, void *pArg){
  switch( op ){
    case SQLITE_FCNTL_LOCKSTATE: {
      *(int*)pArg = ((unixFile*)id)->locktype;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_SIZE_HINT: {
      sqlite3_int64 szFile = *(sqlite3_int64*)pArg;
      unixFile *pFile = (unixFile*)id;
      ftruncate(pFile->h, szFile);
      return SQLITE_OK;
    }
  }
  return SQLITE_ERROR;
}

/*
** Return the sector size in bytes of the underlying block device for
Changes to src/pager.c.
3028
3029
3030
3031
3032
3033
3034

3035
3036
3037
3038
3039
3040
3041
** every one of those pages out to the database file and mark them all
** as clean.
*/
static int pager_write_pagelist(PgHdr *pList){
  Pager *pPager;
  PgHdr *p;
  int rc;


  if( pList==0 ) return SQLITE_OK;
  pPager = pList->pPager;

  /* At this point there may be either a RESERVED or EXCLUSIVE lock on the
  ** database file. If there is already an EXCLUSIVE lock, the following
  ** calls to sqlite3OsLock() are no-ops.







>







3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
** every one of those pages out to the database file and mark them all
** as clean.
*/
static int pager_write_pagelist(PgHdr *pList){
  Pager *pPager;
  PgHdr *p;
  int rc;
  sqlite3_int64 szFile;          /* Final size of databsae file */

  if( pList==0 ) return SQLITE_OK;
  pPager = pList->pPager;

  /* At this point there may be either a RESERVED or EXCLUSIVE lock on the
  ** database file. If there is already an EXCLUSIVE lock, the following
  ** calls to sqlite3OsLock() are no-ops.
3058
3059
3060
3061
3062
3063
3064

3065
3066
3067
3068
3069
3070
3071
3072








3073
3074
3075
3076
3077
3078
3079
  }

  pList = sort_pagelist(pList);
  for(p=pList; p; p=p->pDirty){
    assert( p->dirty );
    p->dirty = 0;
  }

  while( pList ){

    /* If the file has not yet been opened, open it now. */
    if( !pPager->fd->pMethods ){
      assert(pPager->tempFile);
      rc = sqlite3PagerOpentemp(pPager, pPager->fd, pPager->vfsFlags);
      if( rc ) return rc;
    }









    /* If there are dirty pages in the page cache with page numbers greater
    ** than Pager.dbSize, this means sqlite3PagerTruncate() was called to
    ** make the file smaller (presumably by auto-vacuum code). Do not write
    ** any such pages to the file.
    */
    if( pList->pgno<=pPager->dbSize ){







>








>
>
>
>
>
>
>
>







3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
  }

  pList = sort_pagelist(pList);
  for(p=pList; p; p=p->pDirty){
    assert( p->dirty );
    p->dirty = 0;
  }
  szFile = pPager->pageSize * (sqlite3_int64)pPager->dbSize;
  while( pList ){

    /* If the file has not yet been opened, open it now. */
    if( !pPager->fd->pMethods ){
      assert(pPager->tempFile);
      rc = sqlite3PagerOpentemp(pPager, pPager->fd, pPager->vfsFlags);
      if( rc ) return rc;
    }

    /* Before the first write, give the VFS a hint of what the final
    ** file size will be.
    */
    if( szFile>0 ){
      sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile);
      szFile = 0;
    }

    /* If there are dirty pages in the page cache with page numbers greater
    ** than Pager.dbSize, this means sqlite3PagerTruncate() was called to
    ** make the file smaller (presumably by auto-vacuum code). Do not write
    ** any such pages to the file.
    */
    if( pList->pgno<=pPager->dbSize ){
Changes to src/sqlite.h.in.
694
695
696
697
698
699
700







701
702

703
704
705
706
707
708
709
** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging.  This
** opcode causes the xFileControl method to write the current state of
** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED],
** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE])
** into an integer that the pArg argument points to. This capability
** is used during testing and only needs to be supported when SQLITE_TEST
** is defined.







*/
#define SQLITE_FCNTL_LOCKSTATE        1


/*
** CAPI3REF: Mutex Handle {H17110} <S20130>
**
** The mutex module within SQLite defines [sqlite3_mutex] to be an
** abstract type for a mutex object.  The SQLite core never looks
** at the internal representation of an [sqlite3_mutex].  It only







>
>
>
>
>
>
>


>







694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging.  This
** opcode causes the xFileControl method to write the current state of
** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED],
** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE])
** into an integer that the pArg argument points to. This capability
** is used during testing and only needs to be supported when SQLITE_TEST
** is defined.
**
** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS
** layer a hint of how large the database file will grow to be during the
** current transaction.  This hint is not guaranteed to be accurate but it
** is often close.  The underlying VFS might choose to preallocate database
** file space based on this hint in order to help writes to the database
** file run faster.
*/
#define SQLITE_FCNTL_LOCKSTATE        1
#define SQLITE_FCNTL_SIZE_HINT        2

/*
** CAPI3REF: Mutex Handle {H17110} <S20130>
**
** The mutex module within SQLite defines [sqlite3_mutex] to be an
** abstract type for a mutex object.  The SQLite core never looks
** at the internal representation of an [sqlite3_mutex].  It only
Changes to test/filefmt.test.
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
       db close
       file delete -force test.db
       sqlite3 db test.db
       db eval "PRAGMA auto_vacuum=OFF"
       db eval "PRAGMA page_size=$pagesize"
       db eval {CREATE TABLE t1(x)}
       file size test.db
     } [expr $pagesize*2]
     do_test filefmt-1.5.$pagesize.2 {
       hexio_get_int [hexio_read test.db 16 2]
     } $pagesize
  }
}

# The page-size must be a power of 2







|







59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
       db close
       file delete -force test.db
       sqlite3 db test.db
       db eval "PRAGMA auto_vacuum=OFF"
       db eval "PRAGMA page_size=$pagesize"
       db eval {CREATE TABLE t1(x)}
       file size test.db
     } [expr {$pagesize*2<$sqlite_pending_byte ? $pagesize*2 : $pagesize*3}]
     do_test filefmt-1.5.$pagesize.2 {
       hexio_get_int [hexio_read test.db 16 2]
     } $pagesize
  }
}

# The page-size must be a power of 2
Changes to test/io.test.
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
      INSERT INTO abc SELECT * FROM abc;
      INSERT INTO abc SELECT * FROM abc;
      INSERT INTO abc SELECT * FROM abc;
    }
    # File has grown - showing there was a cache-spill - but there 
    # have been no calls to fsync():
    list [file size test.db] [nSync]
  } {31744 0}
  do_test io-3.3 {
    # The COMMIT requires a single fsync() - to the database file.
    execsql { COMMIT }
    list [file size test.db] [nSync]
  } {39936 1}
}








|







397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
      INSERT INTO abc SELECT * FROM abc;
      INSERT INTO abc SELECT * FROM abc;
      INSERT INTO abc SELECT * FROM abc;
    }
    # File has grown - showing there was a cache-spill - but there 
    # have been no calls to fsync():
    list [file size test.db] [nSync]
  } {38912 0}
  do_test io-3.3 {
    # The COMMIT requires a single fsync() - to the database file.
    execsql { COMMIT }
    list [file size test.db] [nSync]
  } {39936 1}
}