gitlab.com/CoiaPrant/sqlite3@v1.19.1/testdata/tcl/mmap1.test (about)

     1  # 2013 March 20
     2  #
     3  # The author disclaims copyright to this source code.  In place of
     4  # a legal notice, here is a blessing:
     5  #
     6  #    May you do good and not evil.
     7  #    May you find forgiveness for yourself and forgive others.
     8  #    May you share freely, never taking more than you give.
     9  #
    10  #***********************************************************************
    11  #
    12  
    13  set testdir [file dirname $argv0]
    14  source $testdir/tester.tcl
    15  ifcapable !mmap||!incrblob {
    16    finish_test
    17    return
    18  }
    19  source $testdir/lock_common.tcl
    20  set testprefix mmap1
    21  
    22  proc nRead {db} {
    23    set bt [btree_from_db $db]
    24    db_enter $db
    25    array set stats [btree_pager_stats $bt]
    26    db_leave $db
    27    # puts [array get stats]
    28    return $stats(read)
    29  }
    30  
    31  # Return a Tcl script that registers a user-defined scalar function 
    32  # named rblob() with database handle $dbname. The function returns a
    33  # sequence of pseudo-random blobs based on seed value $seed.
    34  #
    35  proc register_rblob_code {dbname seed} {
    36    return [subst -nocommands {
    37      set ::rcnt $seed
    38      proc rblob {n} {
    39        set ::rcnt [expr (([set ::rcnt] << 3) + [set ::rcnt] + 456) & 0xFFFFFFFF]
    40        set str [format %.8x [expr [set ::rcnt] ^ 0xbdf20da3]]
    41        string range [string repeat [set str] [expr [set n]/4]] 1 [set n]
    42      }
    43      $dbname func rblob rblob
    44    }]
    45  }
    46  
    47  
    48  # For cases 1.1 and 1.4, the number of pages read using xRead() is 4 on
    49  # unix and 9 on windows. The difference is that windows only ever maps
    50  # an integer number of OS pages (i.e. creates mappings that are a multiple
    51  # of 4KB in size). Whereas on unix any sized mapping may be created.
    52  #
    53  foreach {t mmap_size nRead c2init} {
    54    1.1 { PRAGMA mmap_size = 67108864 } /[49]/ {PRAGMA mmap_size = 0}
    55    1.2 { PRAGMA mmap_size =    53248 } 150    {PRAGMA mmap_size = 0}
    56    1.3 { PRAGMA mmap_size =        0 } 344    {PRAGMA mmap_size = 0}
    57    1.4 { PRAGMA mmap_size = 67108864 } /[49]/ {PRAGMA mmap_size = 67108864 }
    58    1.5 { PRAGMA mmap_size =    53248 } 150    {PRAGMA mmap_size = 67108864 }
    59    1.6 { PRAGMA mmap_size =        0 } 344    {PRAGMA mmap_size = 67108864 }
    60  } {
    61  
    62    do_multiclient_test tn {
    63      sql1 {PRAGMA cache_size=2000}
    64      sql2 {PRAGMA cache_size=2000}
    65  
    66      sql1 {PRAGMA page_size=1024}
    67      sql1 $mmap_size
    68      sql2 $c2init
    69  
    70      code2 [register_rblob_code db2 0]
    71  
    72      sql2 {
    73        PRAGMA page_size=1024;
    74        PRAGMA auto_vacuum = 1;
    75        CREATE TABLE t1(a, b, UNIQUE(a, b));
    76        INSERT INTO t1 VALUES(rblob(500), rblob(500));
    77        INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --    2
    78        INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --    4
    79        INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --    8
    80        INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --   16
    81        INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --   32
    82      }
    83      do_test $t.$tn.1 {
    84        sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count"
    85      } {32 ok 77}
    86  
    87      # Have connection 2 shrink the file. Check connection 1 can still read it.
    88      sql2 { DELETE FROM t1 WHERE rowid%2; }
    89      do_test $t.$tn.2 {
    90        sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count"
    91      } "16 ok [expr {42+[nonzero_reserved_bytes]}]"
    92  
    93      # Have connection 2 grow the file. Check connection 1 can still read it.
    94      sql2 { INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1 }
    95      do_test $t.$tn.3 {
    96        sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count"
    97      } {32 ok 79}
    98  
    99      # Have connection 2 grow the file again. Check connection 1 is still ok.
   100      sql2 { INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1 }
   101      do_test $t.$tn.4 {
   102        sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count"
   103      } {64 ok 149}
   104  
   105      # Check that the number of pages read by connection 1 indicates that the
   106      # "PRAGMA mmap_size" command worked.
   107      if {[nonzero_reserved_bytes]==0} {
   108        do_test $t.$tn.5 { nRead db } $nRead
   109      }
   110    }
   111  }
   112  
   113  set ::rcnt 0
   114  proc rblob {n} {
   115    set ::rcnt [expr (($::rcnt << 3) + $::rcnt + 456) & 0xFFFFFFFF]
   116    set str [format %.8x [expr $::rcnt ^ 0xbdf20da3]]
   117    string range [string repeat $str [expr $n/4]] 1 $n
   118  }
   119  
   120  reset_db
   121  db func rblob rblob
   122  
   123  ifcapable wal {
   124    do_execsql_test 2.1 {
   125      PRAGMA auto_vacuum = 1;
   126      PRAGMA mmap_size = 67108864;
   127      PRAGMA journal_mode = wal;
   128      CREATE TABLE t1(a, b, UNIQUE(a, b));
   129      INSERT INTO t1 VALUES(rblob(500), rblob(500));
   130      INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --    2
   131      INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --    4
   132      INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --    8
   133      INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --   16
   134      INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --   32
   135      PRAGMA wal_checkpoint;
   136    } {67108864 wal 0 103 103}
   137  
   138    do_execsql_test 2.2 {
   139      PRAGMA auto_vacuum;
   140      SELECT count(*) FROM t1;
   141    } {1 32}
   142  
   143    if {[permutation] != "inmemory_journal"} {
   144      do_test 2.3 {
   145        sqlite3 db2 test.db
   146        db2 func rblob rblob
   147        db2 eval {
   148          DELETE FROM t1 WHERE (rowid%4);
   149            PRAGMA wal_checkpoint;
   150        }
   151        db2 eval {
   152          INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --    16
   153          SELECT count(*) FROM t1;
   154        }
   155      } {16}
   156  
   157      do_execsql_test 2.4 {
   158        PRAGMA wal_checkpoint;
   159      } {0 24 24}
   160      db2 close
   161    }
   162  }
   163  
   164  reset_db
   165  execsql { PRAGMA mmap_size = 67108864; }
   166  db func rblob rblob
   167  do_execsql_test 3.1 {
   168    PRAGMA auto_vacuum = 1;
   169  
   170    CREATE TABLE t1(a, b, UNIQUE(a, b));
   171    INSERT INTO t1 VALUES(rblob(500), rblob(500));
   172    INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --    2
   173    INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --    4
   174    INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --    8
   175  
   176    CREATE TABLE t2(a, b, UNIQUE(a, b));
   177    INSERT INTO t2 SELECT * FROM t1;
   178  } {}
   179  
   180  do_test 3.2 {
   181    set nRow 0
   182    db eval {SELECT * FROM t2 ORDER BY a, b} {
   183      if {$nRow==4} { db eval { DELETE FROM t1 } }
   184      incr nRow
   185    }
   186    set nRow
   187  } {8}
   188  
   189  #-------------------------------------------------------------------------
   190  # Ensure that existing cursors using xFetch() pages see changes made
   191  # to rows using the incrblob API.
   192  #
   193  reset_db
   194  execsql { PRAGMA mmap_size = 67108864; }
   195  set aaa [string repeat a 400]
   196  set bbb [string repeat b 400]
   197  set ccc [string repeat c 400]
   198  set ddd [string repeat d 400]
   199  set eee [string repeat e 400]
   200  
   201  do_execsql_test 4.1 {
   202    PRAGMA page_size = 1024;
   203    CREATE TABLE t1(x);
   204    INSERT INTO t1 VALUES($aaa);
   205    INSERT INTO t1 VALUES($bbb);
   206    INSERT INTO t1 VALUES($ccc);
   207    INSERT INTO t1 VALUES($ddd);
   208    SELECT * FROM t1;
   209    BEGIN;
   210  } [list $aaa $bbb $ccc $ddd]
   211  
   212  do_test 4.2 {
   213    set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy]
   214    sqlite3_step $::STMT
   215    sqlite3_column_text $::STMT 0
   216  } $aaa
   217  
   218  do_test 4.3 {
   219    foreach r {2 3 4} {
   220      set fd [db incrblob t1 x $r]
   221      puts -nonewline $fd $eee
   222      close $fd
   223    }
   224  
   225    set res [list]
   226    while {"SQLITE_ROW" == [sqlite3_step $::STMT]} {
   227      lappend res [sqlite3_column_text $::STMT 0]
   228    }
   229    set res
   230  } [list $eee $eee $eee]
   231  
   232  do_test 4.4 {
   233    sqlite3_finalize $::STMT
   234  } SQLITE_OK
   235  
   236  do_execsql_test 4.5 { COMMIT }
   237  
   238  #-------------------------------------------------------------------------
   239  # Ensure that existing cursors holding xFetch() references are not
   240  # confused if those pages are moved to make way for the root page of a
   241  # new table or index.
   242  #
   243  reset_db
   244  execsql { PRAGMA mmap_size = 67108864; }
   245  do_execsql_test 5.1 {
   246    PRAGMA auto_vacuum = 2;
   247    PRAGMA page_size = 1024;
   248    CREATE TABLE t1(x);
   249    INSERT INTO t1 VALUES($aaa);
   250    INSERT INTO t1 VALUES($bbb);
   251    INSERT INTO t1 VALUES($ccc);
   252    INSERT INTO t1 VALUES($ddd);
   253  
   254    PRAGMA auto_vacuum;
   255    SELECT * FROM t1;
   256  } [list 2 $aaa $bbb $ccc $ddd]
   257  
   258  do_test 5.2 {
   259    set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy]
   260    sqlite3_step $::STMT
   261    sqlite3_column_text $::STMT 0
   262  } $aaa
   263  
   264  do_execsql_test 5.3 {
   265    CREATE TABLE t2(x);
   266    INSERT INTO t2 VALUES('tricked you!');
   267    INSERT INTO t2 VALUES('tricked you!');
   268  }
   269  
   270  do_test 5.4 {
   271    sqlite3_step $::STMT
   272    sqlite3_column_text $::STMT 0
   273  } $bbb
   274  
   275  do_test 5.5 {
   276    sqlite3_finalize $::STMT
   277  } SQLITE_OK
   278  
   279  #
   280  # The "6.*" tests are designed to test the interaction of mmap with file
   281  # truncation (e.g. on Win32) via the VACUUM command.
   282  #
   283  forcedelete test2.db
   284  sqlite3 db2 test2.db
   285  do_test 6.0 {
   286    db2 eval {
   287      PRAGMA auto_vacuum = 0;
   288      PRAGMA page_size = 4096;
   289    }
   290  } {}
   291  do_test 6.1 {
   292    db2 eval {
   293      CREATE TABLE t1(x);
   294      INSERT INTO t1(x) VALUES(randomblob(1000000));
   295    }
   296  } {}
   297  do_test 6.2 {
   298    db2 eval {
   299      PRAGMA mmap_size = 1048576;
   300    }
   301  } {1048576}
   302  do_test 6.3 {
   303    expr {[file size test2.db] > 1000000}
   304  } {1}
   305  do_test 6.4 {
   306    db2 eval {
   307      DELETE FROM t1;
   308    }
   309  } {}
   310  do_test 6.5 {
   311    expr {[file size test2.db] > 1000000}
   312  } {1}
   313  do_test 6.6 {
   314    db2 eval {
   315      VACUUM;
   316    }
   317  } {}
   318  do_test 6.7 {
   319    expr {[file size test2.db] < 1000000}
   320  } {1}
   321  db2 close
   322  
   323  finish_test