SQLite

Changes On Branch rbu_exclusive_checkpoint
Login

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

Changes In Branch rbu_exclusive_checkpoint Excluding Merge-Ins

This is equivalent to a diff from 7bba415f to 00285ff1

2021-11-05
22:35
Add the rbu_exclusive_checkpoint query parameter to RBU. (check-in: c2d33ea9 user: drh tags: trunk)
22:23
New test cases for rbu_exclusive_checkpoint query parameter. (Closed-Leaf check-in: 00285ff1 user: drh tags: rbu_exclusive_checkpoint)
19:36
Add the SQLITE_OPEN_EXRESCODE flag for sqlite3_open_v2(). (check-in: ff9373f4 user: drh tags: trunk)
19:04
If the target database URI passed to sqlite3rbu_open() is contains the option "rbu_exclusive_checkpoint=1", hold an exclusive lock for the duration of any incremental checkpoint operation. (check-in: 7cb77296 user: dan tags: rbu_exclusive_checkpoint)
14:13
Update sqllimits1.test to account for recent changes to SQL function strftime(). (check-in: 7bba415f user: dan tags: trunk)
12:34
Use the FTS_CORRUPT_VTAB macro rather than a direct call to sqlite3Fts3Corrupt() in [2fad2a89527757b3] so that the build works in all cases. (check-in: 029c59cd user: drh tags: trunk)

Added ext/rbu/rbuexlock.test.































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# 2021 November 06
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#

source [file join [file dirname [info script]] rbu_common.tcl]
set ::testprefix rbuexlock

db close
sqlite3_shutdown
sqlite3_config_uri 1

# Create a simple RBU database. That expects to write to a table:
#
#   CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
#
proc create_rbu {filename} {
  forcedelete $filename
  sqlite3 rbu1 $filename  
  rbu1 eval {
    CREATE TABLE data_t1(a, b, c, rbu_control);
    INSERT INTO data_t1 VALUES(10, random(), random(), 0);
    INSERT INTO data_t1 VALUES(20, random(), random(), 0);
    INSERT INTO data_t1 VALUES(30, random(), random(), 0);
    INSERT INTO data_t1 VALUES(40, random(), random(), 0);
    INSERT INTO data_t1 VALUES(50, random(), random(), 0);
    INSERT INTO data_t1 VALUES(60, random(), random(), 0);
    INSERT INTO data_t1 VALUES(70, random(), random(), 0);
    INSERT INTO data_t1 VALUES(80, random(), random(), 0);
  }
  rbu1 close
  return $filename
}

reset_db

do_execsql_test 1.0 {
  CREATE TABLE t1(a PRIMARY KEY, b INT, c INT);
  CREATE INDEX t1b ON t1(b);
  CREATE INDEX t1c ON t1(c);
  INSERT INTO t1 VALUES(1, 2, 3);
}
create_rbu rbu1.db

do_test 1.1.0 {
  sqlite3rbu rbu file:test.db?rbu_exclusive_checkpoint=1 rbu1.db
  rbu step
} SQLITE_OK
do_catchsql_test 1.1.1 { SELECT * FROM t1 } {0 {1 2 3}}

do_test 1.2.0 {
  for {set ii 0} {$ii < 10} {incr ii} {
    rbu step
  }
  rbu step
} SQLITE_OK
do_catchsql_test 1.2.1 { SELECT * FROM t1 } {0 {1 2 3}}
do_test 1.2.2 {
  db eval {PRAGMA journal_mode}
} {delete}

do_test 1.3.0 {
  while {[file exists test.db-wal]==0} {
    rbu step
  }
} {}
do_catchsql_test 1.3.1 { SELECT * FROM t1 } {1 {database is locked}}
do_test 1.3.2 {
  db eval {PRAGMA journal_mode}
} {delete}


do_test 1.4.0 {
  rbu step
} SQLITE_OK
do_catchsql_test 1.4.1 { SELECT * FROM t1 } {1 {database is locked}}
do_test 1.4.2 {
  db eval {PRAGMA journal_mode}
} {delete}


rbu close

do_test 1.5.0 {
  file exists test.db-wal
} {1}
do_test 1.5.1 {
  sqlite3rbu rbu file:test.db?rbu_exclusive_checkpoint=1 rbu1.db
  file exists test.db-wal
} 1
do_catchsql_test 1.5.2 { SELECT * FROM t1 } {1 {database is locked}}
do_test 1.5.2 {
  db eval {PRAGMA journal_mode}
} {delete}


do_test 1.6.0 {
  rbu step
} SQLITE_OK
do_catchsql_test 1.6.1 { SELECT * FROM t1 } {1 {database is locked}}
do_test 1.6.2 {
  db eval {PRAGMA journal_mode}
} {delete}

do_test 1.7.0 {
  while {[rbu step]=="SQLITE_OK"} {}
  rbu close
} SQLITE_DONE
do_catchsql_test 1.7.2 { SELECT count(*) FROM t1 } {0 9}
do_test 1.7.2 {
  db eval {PRAGMA journal_mode}
} {delete}

reset_db
do_execsql_test 2.0 {
  CREATE TABLE t1(a PRIMARY KEY, b INT, c INT);
  CREATE INDEX t1b ON t1(b);
  CREATE INDEX t1c ON t1(c);
  INSERT INTO t1 VALUES(1, 2, 3);
}
create_rbu rbu1.db

do_test 2.1.0 {
  sqlite3rbu rbu file:test.db?rbu_exclusive_checkpoint=0 rbu1.db
  rbu step
} SQLITE_OK
do_catchsql_test 2.1.1 { SELECT * FROM t1 } {0 {1 2 3}}

do_test 2.2.0 {
  for {set ii 0} {$ii < 10} {incr ii} {
    rbu step
  }
  rbu step
} SQLITE_OK
do_catchsql_test 2.2.1 { SELECT * FROM t1 } {0 {1 2 3}}

do_test 2.3.0 {
  while {[file exists test.db-wal]==0} {
    rbu step
  }
} {}
do_test 2.3.1 {
  llength [db eval {SELECT * FROM t1}]
} {27}
do_test 2.3.2 {
  db eval {PRAGMA journal_mode}
} {wal}

do_test 2.4.0 {
  rbu step
} SQLITE_OK
do_test 2.4.1 {
  llength [db eval  {SELECT * FROM t1}]
} {27}
do_test 2.4.2 {
  db eval {PRAGMA journal_mode}
} {wal}

rbu close

do_test 2.5.0 {
  db eval {PRAGMA journal_mode}
} {wal}
do_execsql_test 2.5.1 {
  DELETE FROM t1;
} {}

create_rbu rbu1.db
do_test 3.1.0 {
  sqlite3rbu rbu file:test.db?rbu_exclusive_checkpoint=0 rbu1.db
  rbu step
} SQLITE_ERROR

do_test 3.1.1 {
  set rc [catch {rbu close} msg]
  lappend rc $msg
} {1 {SQLITE_ERROR - cannot update wal mode database}}
db eval {PRAGMA journal_mode=DELETE}

create_rbu rbu1.db
do_test 3.2.0 {
  sqlite3rbu rbu file:test.db?rbu_exclusive_checkpoint=0 rbu1.db
  rbu step
} SQLITE_OK

do_test 3.3.1 {
  set rc [catch {rbu close} msg]
  lappend rc $msg
} {0 SQLITE_OK}

db close
create_rbu rbu1.db
do_test 3.4.0 {
  sqlite3rbu rbu file:test.db?rbu_exclusive_checkpoint=0 rbu1.db
  rbu step
} SQLITE_OK
rbu close


finish_test

Changes to ext/rbu/sqlite3rbu.c.

105
106
107
108
109
110
111







112
113
114
115
116
117
118

/*
** Swap two objects of type TYPE.
*/
#if !defined(SQLITE_AMALGAMATION)
# define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;}
#endif








/*
** The rbu_state table is used to save the state of a partially applied
** update so that it can be resumed later. The table consists of integer
** keys mapped to values as follows:
**
** RBU_STATE_STAGE:







>
>
>
>
>
>
>







105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125

/*
** Swap two objects of type TYPE.
*/
#if !defined(SQLITE_AMALGAMATION)
# define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;}
#endif

/*
** Name of the URI option that causes RBU to take an exclusive lock as
** part of the incremental checkpoint operation.
*/
#define RBU_EXCLUSIVE_CHECKPOINT "rbu_exclusive_checkpoint"


/*
** The rbu_state table is used to save the state of a partially applied
** update so that it can be resumed later. The table consists of integer
** keys mapped to values as follows:
**
** RBU_STATE_STAGE:
2752
2753
2754
2755
2756
2757
2758




2759
2760
2761
2762

2763
2764
2765

2766
2767
2768
2769
2770
2771
2772
  return pRet;
}


/*
** Open the database handle and attach the RBU database as "rbu". If an
** error occurs, leave an error code and message in the RBU handle.




*/
static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){
  assert( p->rc || (p->dbMain==0 && p->dbRbu==0) );
  assert( p->rc || rbuIsVacuum(p) || p->zTarget!=0 );


  /* Open the RBU database */
  p->dbRbu = rbuOpenDbhandle(p, p->zRbu, 1);


  if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){
    sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p);
    if( p->zState==0 ){
      const char *zFile = sqlite3_db_filename(p->dbRbu, "main");
      p->zState = rbuMPrintf(p, "file://%s-vacuum?modeof=%s", zFile, zFile);
    }







>
>
>
>

|


>



>







2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
  return pRet;
}


/*
** Open the database handle and attach the RBU database as "rbu". If an
** error occurs, leave an error code and message in the RBU handle.
**
** If argument dbMain is not NULL, then it is a database handle already
** open on the target database. Use this handle instead of opening a new
** one.
*/
static void rbuOpenDatabase(sqlite3rbu *p, sqlite3 *dbMain, int *pbRetry){
  assert( p->rc || (p->dbMain==0 && p->dbRbu==0) );
  assert( p->rc || rbuIsVacuum(p) || p->zTarget!=0 );
  assert( dbMain==0 || rbuIsVacuum(p)==0 );

  /* Open the RBU database */
  p->dbRbu = rbuOpenDbhandle(p, p->zRbu, 1);
  p->dbMain = dbMain;

  if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){
    sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p);
    if( p->zState==0 ){
      const char *zFile = sqlite3_db_filename(p->dbRbu, "main");
      p->zState = rbuMPrintf(p, "file://%s-vacuum?modeof=%s", zFile, zFile);
    }
3124
3125
3126
3127
3128
3129
3130
3131

3132
3133

3134

3135

3136
3137
3138
3139












3140
3141
3142
3143
3144
3145
3146

  iOff = (i64)(pFrame->iDbPage-1) * p->pgsz;
  p->rc = pDb->pMethods->xWrite(pDb, p->aBuf, p->pgsz, iOff);
}


/*
** Take an EXCLUSIVE lock on the database file.

*/
static void rbuLockDatabase(sqlite3rbu *p){

  sqlite3_file *pReal = p->pTargetFd->pReal;

  assert( p->rc==SQLITE_OK );

  p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_SHARED);
  if( p->rc==SQLITE_OK ){
    p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_EXCLUSIVE);
  }












}

#if defined(_WIN32_WCE)
static LPWSTR rbuWinUtf8ToUnicode(const char *zFilename){
  int nChar;
  LPWSTR zWideFilename;








|
>

|
>
|
>
|
>
|
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>







3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175

  iOff = (i64)(pFrame->iDbPage-1) * p->pgsz;
  p->rc = pDb->pMethods->xWrite(pDb, p->aBuf, p->pgsz, iOff);
}


/*
** Take an EXCLUSIVE lock on the database file. Return SQLITE_OK if
** successful, or an SQLite error code otherwise.
*/
static int rbuLockDatabase(sqlite3 *db){
  int rc = SQLITE_OK;
  sqlite3_file *fd = 0;
  sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &fd);

  if( fd->pMethods ){
    rc = fd->pMethods->xLock(fd, SQLITE_LOCK_SHARED);
    if( rc==SQLITE_OK ){
      rc = fd->pMethods->xLock(fd, SQLITE_LOCK_EXCLUSIVE);
    }
  }
  return rc;
}

/*
** Return true if the database handle passed as the only argument
** was opened with the rbu_exclusive_checkpoint=1 URI parameter
** specified. Or false otherwise.
*/
static int rbuExclusiveCheckpoint(sqlite3 *db){
  const char *zUri = sqlite3_db_filename(db, 0);
  return sqlite3_uri_boolean(zUri, RBU_EXCLUSIVE_CHECKPOINT, 0);
}

#if defined(_WIN32_WCE)
static LPWSTR rbuWinUtf8ToUnicode(const char *zFilename){
  int nChar;
  LPWSTR zWideFilename;

3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208







3209
3210
3211
3212
3213
3214
3215
    /* Move the *-oal file to *-wal. At this point connection p->db is
    ** holding a SHARED lock on the target database file (because it is
    ** in WAL mode). So no other connection may be writing the db. 
    **
    ** In order to ensure that there are no database readers, an EXCLUSIVE
    ** lock is obtained here before the *-oal is moved to *-wal.
    */
    rbuLockDatabase(p);
    if( p->rc==SQLITE_OK ){
      rbuFileSuffix3(zBase, zWal);
      rbuFileSuffix3(zBase, zOal);

      /* Re-open the databases. */
      rbuObjIterFinalize(&p->objiter);
      sqlite3_close(p->dbRbu);
      sqlite3_close(p->dbMain);
      p->dbMain = 0;
      p->dbRbu = 0;








#if defined(_WIN32_WCE)
      {
        LPWSTR zWideOal;
        LPWSTR zWideWal;

        zWideOal = rbuWinUtf8ToUnicode(zOal);
        if( zWideOal ){







|
<
|
|

|
|
|
|
|
|

>
>
>
>
>
>
>







3219
3220
3221
3222
3223
3224
3225
3226

3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
    /* Move the *-oal file to *-wal. At this point connection p->db is
    ** holding a SHARED lock on the target database file (because it is
    ** in WAL mode). So no other connection may be writing the db. 
    **
    ** In order to ensure that there are no database readers, an EXCLUSIVE
    ** lock is obtained here before the *-oal is moved to *-wal.
    */
    sqlite3 *dbMain = 0;

    rbuFileSuffix3(zBase, zWal);
    rbuFileSuffix3(zBase, zOal);

    /* Re-open the databases. */
    rbuObjIterFinalize(&p->objiter);
    sqlite3_close(p->dbRbu);
    sqlite3_close(p->dbMain);
    p->dbMain = 0;
    p->dbRbu = 0;

    dbMain = rbuOpenDbhandle(p, p->zTarget, 1);
    if( dbMain ){
      assert( p->rc==SQLITE_OK );
      p->rc = rbuLockDatabase(dbMain);
    }

    if( p->rc==SQLITE_OK ){
#if defined(_WIN32_WCE)
      {
        LPWSTR zWideOal;
        LPWSTR zWideWal;

        zWideOal = rbuWinUtf8ToUnicode(zOal);
        if( zWideOal ){
3228
3229
3230
3231
3232
3233
3234
3235









3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
        }else{
          p->rc = SQLITE_IOERR_NOMEM;
        }
      }
#else
      p->rc = rename(zOal, zWal) ? SQLITE_IOERR : SQLITE_OK;
#endif










      if( p->rc==SQLITE_OK ){
        rbuOpenDatabase(p, 0);
        rbuSetupCheckpoint(p, 0);
      }
    }
  }

  sqlite3_free(zWal);
  sqlite3_free(zOal);
}








|
>
>
>
>
>
>
>
>
>
|
|
|
<







3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282

3283
3284
3285
3286
3287
3288
3289
        }else{
          p->rc = SQLITE_IOERR_NOMEM;
        }
      }
#else
      p->rc = rename(zOal, zWal) ? SQLITE_IOERR : SQLITE_OK;
#endif
    }

    if( p->rc!=SQLITE_OK 
     || rbuIsVacuum(p) 
     || rbuExclusiveCheckpoint(dbMain)==0 
    ){
      sqlite3_close(dbMain);
      dbMain = 0;
    }

    if( p->rc==SQLITE_OK ){
      rbuOpenDatabase(p, dbMain, 0);
      rbuSetupCheckpoint(p, 0);

    }
  }

  sqlite3_free(zWal);
  sqlite3_free(zOal);
}

3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
      /* If the first attempt to open the database file fails and the bRetry
      ** flag it set, this means that the db was not opened because it seemed
      ** to be a wal-mode db. But, this may have happened due to an earlier
      ** RBU vacuum operation leaving an old wal file in the directory.
      ** If this is the case, it will have been checkpointed and deleted
      ** when the handle was closed and a second attempt to open the 
      ** database may succeed.  */
      rbuOpenDatabase(p, &bRetry);
      if( bRetry ){
        rbuOpenDatabase(p, 0);
      }
    }

    if( p->rc==SQLITE_OK ){
      pState = rbuLoadState(p);
      assert( pState || p->rc!=SQLITE_OK );
      if( p->rc==SQLITE_OK ){







|

|







4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
      /* If the first attempt to open the database file fails and the bRetry
      ** flag it set, this means that the db was not opened because it seemed
      ** to be a wal-mode db. But, this may have happened due to an earlier
      ** RBU vacuum operation leaving an old wal file in the directory.
      ** If this is the case, it will have been checkpointed and deleted
      ** when the handle was closed and a second attempt to open the 
      ** database may succeed.  */
      rbuOpenDatabase(p, 0, &bRetry);
      if( bRetry ){
        rbuOpenDatabase(p, 0, 0);
      }
    }

    if( p->rc==SQLITE_OK ){
      pState = rbuLoadState(p);
      assert( pState || p->rc!=SQLITE_OK );
      if( p->rc==SQLITE_OK ){
4080
4081
4082
4083
4084
4085
4086








4087
4088
4089
4090
4091
4092
4093
          if( p->rc==SQLITE_OK ){
            rbuSetupOal(p, pState);
          }
        }
      }else if( p->eStage==RBU_STAGE_MOVE ){
        /* no-op */
      }else if( p->eStage==RBU_STAGE_CKPT ){








        rbuSetupCheckpoint(p, pState);
      }else if( p->eStage==RBU_STAGE_DONE ){
        p->rc = SQLITE_DONE;
      }else{
        p->rc = SQLITE_CORRUPT;
      }
    }







>
>
>
>
>
>
>
>







4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
          if( p->rc==SQLITE_OK ){
            rbuSetupOal(p, pState);
          }
        }
      }else if( p->eStage==RBU_STAGE_MOVE ){
        /* no-op */
      }else if( p->eStage==RBU_STAGE_CKPT ){
        if( !rbuIsVacuum(p) && rbuExclusiveCheckpoint(p->dbMain) ){
          /* If the rbu_exclusive_checkpoint=1 URI parameter was specified
          ** and an incremental checkpoint is being resumed, attempt an
          ** exclusive lock on the db file. If this fails, so be it.  */
          p->eStage = RBU_STAGE_DONE;
          rbuLockDatabase(p->dbMain);
          p->eStage = RBU_STAGE_CKPT;
        }
        rbuSetupCheckpoint(p, pState);
      }else if( p->eStage==RBU_STAGE_DONE ){
        p->rc = SQLITE_DONE;
      }else{
        p->rc = SQLITE_CORRUPT;
      }
    }
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
*/
sqlite3rbu *sqlite3rbu_open(
  const char *zTarget, 
  const char *zRbu,
  const char *zState
){
  if( zTarget==0 || zRbu==0 ){ return rbuMisuseError(); }
  /* TODO: Check that zTarget and zRbu are non-NULL */
  return openRbuHandle(zTarget, zRbu, zState);
}

/*
** Open a handle to begin or resume an RBU VACUUM operation.
*/
sqlite3rbu *sqlite3rbu_vacuum(







<







4168
4169
4170
4171
4172
4173
4174

4175
4176
4177
4178
4179
4180
4181
*/
sqlite3rbu *sqlite3rbu_open(
  const char *zTarget, 
  const char *zRbu,
  const char *zState
){
  if( zTarget==0 || zRbu==0 ){ return rbuMisuseError(); }

  return openRbuHandle(zTarget, zRbu, zState);
}

/*
** Open a handle to begin or resume an RBU VACUUM operation.
*/
sqlite3rbu *sqlite3rbu_vacuum(