Add the sqlite3rbu_rename_handler() API. To override the default routine that RBU uses to rename files.

FossilOrigin-Name: ebbb1f88e7b5d6cbe84d400f1a187acedb4c668d0b7e4c63bf1496e57da9b8ad
This commit is contained in:
dan 2022-11-07 18:00:18 +00:00
parent 49507d2af6
commit 40503750fa
6 changed files with 199 additions and 39 deletions

54
ext/rbu/rburename.test Normal file
View File

@ -0,0 +1,54 @@
# 2022 November 07
#
# 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 rburename
do_execsql_test 1.0 {
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1, 2);
INSERT INTO t1 VALUES(3, 4);
INSERT INTO t1 VALUES(5, 6);
}
forcedelete test.db-vacuum
proc my_rename {old new} {
lappend ::my_rename_calls [list [file tail $old] [file tail $new]]
file rename $old $new
}
do_test 1.1 {
sqlite3rbu_vacuum rbu test.db
rbu rename_handler my_rename
while {[rbu step]=="SQLITE_OK"} {}
rbu close
} SQLITE_DONE
do_test 1.2 {
set ::my_rename_calls
} {{test.db-oal test.db-wal}}
proc my_rename {old new} {
error "something went wrong"
}
do_test 1.3 {
sqlite3rbu_vacuum rbu test.db
rbu rename_handler my_rename
while {[rbu step]=="SQLITE_OK"} {}
list [catch { rbu close } msg] $msg
} {1 SQLITE_IOERR}
finish_test

View File

@ -393,6 +393,8 @@ struct sqlite3rbu {
int nPagePerSector; /* Pages per sector for pTargetFd */
i64 iOalSz;
i64 nPhaseOneStep;
void *pRenameArg;
int (*xRename)(void*, const char*, const char*);
/* The following state variables are used as part of the incremental
** checkpoint stage (eStage==RBU_STAGE_CKPT). See comments surrounding
@ -3241,32 +3243,7 @@ static void rbuMoveOalFile(sqlite3rbu *p){
}
if( p->rc==SQLITE_OK ){
#if defined(_WIN32_WCE)
{
LPWSTR zWideOal;
LPWSTR zWideWal;
zWideOal = rbuWinUtf8ToUnicode(zOal);
if( zWideOal ){
zWideWal = rbuWinUtf8ToUnicode(zWal);
if( zWideWal ){
if( MoveFileW(zWideOal, zWideWal) ){
p->rc = SQLITE_OK;
}else{
p->rc = SQLITE_IOERR;
}
sqlite3_free(zWideWal);
}else{
p->rc = SQLITE_IOERR_NOMEM;
}
sqlite3_free(zWideOal);
}else{
p->rc = SQLITE_IOERR_NOMEM;
}
}
#else
p->rc = rename(zOal, zWal) ? SQLITE_IOERR : SQLITE_OK;
#endif
p->rc = p->xRename(p->pRenameArg, zOal, zWal);
}
if( p->rc!=SQLITE_OK
@ -4005,6 +3982,7 @@ static sqlite3rbu *openRbuHandle(
/* Create the custom VFS. */
memset(p, 0, sizeof(sqlite3rbu));
sqlite3rbu_rename_handler(p, 0, 0);
rbuCreateVfs(p);
/* Open the target, RBU and state databases */
@ -4396,6 +4374,54 @@ int sqlite3rbu_savestate(sqlite3rbu *p){
return rc;
}
/*
** Default xRename callback for RBU.
*/
static int xDefaultRename(void *pArg, const char *zOld, const char *zNew){
int rc = SQLITE_OK;
#if defined(_WIN32_WCE)
{
LPWSTR zWideOld;
LPWSTR zWideNew;
zWideOld = rbuWinUtf8ToUnicode(zOld);
if( zWideOld ){
zWideNew = rbuWinUtf8ToUnicode(zNew);
if( zWideNew ){
if( MoveFileW(zWideOld, zWideNew) ){
rc = SQLITE_OK;
}else{
rc = SQLITE_IOERR;
}
sqlite3_free(zWideNew);
}else{
rc = SQLITE_IOERR_NOMEM;
}
sqlite3_free(zWideOld);
}else{
rc = SQLITE_IOERR_NOMEM;
}
}
#else
rc = rename(zOld, zNew) ? SQLITE_IOERR : SQLITE_OK;
#endif
return rc;
}
void sqlite3rbu_rename_handler(
sqlite3rbu *pRbu,
void *pArg,
int (*xRename)(void *pArg, const char *zOld, const char *zNew)
){
if( xRename ){
pRbu->xRename = xRename;
pRbu->pRenameArg = pArg;
}else{
pRbu->xRename = xDefaultRename;
pRbu->pRenameArg = 0;
}
}
/**************************************************************************
** Beginning of RBU VFS shim methods. The VFS shim modifies the behaviour
** of a standard VFS in the following ways:

View File

@ -544,6 +544,34 @@ SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int*pnTwo);
SQLITE_API int sqlite3rbu_state(sqlite3rbu *pRbu);
/*
** As part of applying an RBU update or performing an RBU vacuum operation,
** the system must at one point move the *-oal file to the equivalent *-wal
** path. Normally, it does this by invoking POSIX function rename(2) directly.
** Except on WINCE platforms, where it uses win32 API MoveFileW(). This
** function may be used to register a callback that the RBU module will invoke
** instead of one of these APIs.
**
** If a callback is registered with an RBU handle, it invokes it instead
** of rename(2) when it needs to move a file within the file-system. The
** first argument passed to the xRename() callback is a copy of the second
** argument (pArg) passed to this function. The second is the full path
** to the file to move and the third the full path to which it should be
** moved. The callback function should return SQLITE_OK to indicate
** success. If an error occurs, it should return an SQLite error code.
** In this case the RBU operation will be abandoned and the error returned
** to the RBU user.
**
** Passing a NULL pointer in place of the xRename argument to this function
** restores the default behaviour.
*/
SQLITE_API void sqlite3rbu_rename_handler(
sqlite3rbu *pRbu,
void *pArg,
int (*xRename)(void *pArg, const char *zOld, const char *zNew)
);
/*
** Create an RBU VFS named zName that accesses the underlying file-system
** via existing VFS zParent. Or, if the zParent parameter is passed NULL,

View File

@ -26,6 +26,14 @@
# endif
#endif
#include <assert.h>
#include <string.h>
typedef struct TestRbu TestRbu;
struct TestRbu {
sqlite3rbu *pRbu;
Tcl_Interp *interp;
Tcl_Obj *xRename;
};
/* From main.c */
extern const char *sqlite3ErrName(int);
@ -55,6 +63,20 @@ void test_rbu_delta(sqlite3_context *pCtx, int nArg, sqlite3_value **apVal){
Tcl_DecrRefCount(pScript);
}
static int xRenameCallback(void *pArg, const char *zOld, const char *zNew){
int rc = SQLITE_OK;
TestRbu *pTest = (TestRbu*)pArg;
Tcl_Obj *pEval = Tcl_DuplicateObj(pTest->xRename);
Tcl_IncrRefCount(pEval);
Tcl_ListObjAppendElement(pTest->interp, pEval, Tcl_NewStringObj(zOld, -1));
Tcl_ListObjAppendElement(pTest->interp, pEval, Tcl_NewStringObj(zNew, -1));
rc = Tcl_EvalObjEx(pTest->interp, pEval, TCL_GLOBAL_ONLY);
Tcl_DecrRefCount(pEval);
return rc ? SQLITE_IOERR : SQLITE_OK;
}
static int SQLITE_TCLAPI test_sqlite3rbu_cmd(
ClientData clientData,
@ -63,7 +85,8 @@ static int SQLITE_TCLAPI test_sqlite3rbu_cmd(
Tcl_Obj *CONST objv[]
){
int ret = TCL_OK;
sqlite3rbu *pRbu = (sqlite3rbu*)clientData;
TestRbu *pTest = (TestRbu*)clientData;
sqlite3rbu *pRbu = pTest->pRbu;
struct RbuCmd {
const char *zName;
int nArg;
@ -82,6 +105,7 @@ static int SQLITE_TCLAPI test_sqlite3rbu_cmd(
{"temp_size_limit", 3, "LIMIT"}, /* 10 */
{"temp_size", 2, ""}, /* 11 */
{"dbRbu_eval", 3, "SQL"}, /* 12 */
{"rename_handler", 3, "SCRIPT"},/* 13 */
{0,0,0}
};
int iCmd;
@ -127,6 +151,8 @@ static int SQLITE_TCLAPI test_sqlite3rbu_cmd(
}
ret = TCL_ERROR;
}
if( pTest->xRename ) Tcl_DecrRefCount(pTest->xRename);
ckfree(pTest);
break;
}
@ -214,6 +240,19 @@ static int SQLITE_TCLAPI test_sqlite3rbu_cmd(
break;
}
case 13: /* rename_handler */ {
Tcl_Obj *pScript = objv[2];
assert( !sqlite3_stricmp(aCmd[13].zName, "rename_handler") );
if( Tcl_GetCharLength(pScript)==0 ){
sqlite3rbu_rename_handler(pRbu, 0, 0);
}else{
pTest->xRename = Tcl_DuplicateObj(pScript);
Tcl_IncrRefCount(pTest->xRename);
sqlite3rbu_rename_handler(pRbu, pTest, xRenameCallback);
}
break;
}
default: /* seems unlikely */
assert( !"cannot happen" );
break;
@ -222,6 +261,18 @@ static int SQLITE_TCLAPI test_sqlite3rbu_cmd(
return ret;
}
static void createRbuWrapper(
Tcl_Interp *interp,
const char *zCmd,
sqlite3rbu *pRbu
){
TestRbu *pTest = (TestRbu*)ckalloc(sizeof(TestRbu));
memset(pTest, 0, sizeof(TestRbu));
pTest->pRbu = pRbu;
pTest->interp = interp;
Tcl_CreateObjCommand(interp, zCmd, test_sqlite3rbu_cmd, (ClientData)pTest, 0);
}
/*
** Tclcmd: sqlite3rbu CMD <target-db> <rbu-db> ?<state-db>?
*/
@ -247,7 +298,7 @@ static int SQLITE_TCLAPI test_sqlite3rbu(
if( objc==5 ) zStateDb = Tcl_GetString(objv[4]);
pRbu = sqlite3rbu_open(zTarget, zRbu, zStateDb);
Tcl_CreateObjCommand(interp, zCmd, test_sqlite3rbu_cmd, (ClientData)pRbu, 0);
createRbuWrapper(interp, zCmd, pRbu);
Tcl_SetObjResult(interp, objv[1]);
return TCL_OK;
}
@ -276,7 +327,7 @@ static int SQLITE_TCLAPI test_sqlite3rbu_vacuum(
if( zStateDb && zStateDb[0]=='\0' ) zStateDb = 0;
pRbu = sqlite3rbu_vacuum(zTarget, zStateDb);
Tcl_CreateObjCommand(interp, zCmd, test_sqlite3rbu_cmd, (ClientData)pRbu, 0);
createRbuWrapper(interp, zCmd, pRbu);
Tcl_SetObjResult(interp, objv[1]);
return TCL_OK;
}

View File

@ -1,5 +1,5 @@
C Minor\sdoc\supdates\sin\sspeed-check.sh.\sNo\scode\schanges.
D 2022-11-07T17:21:53.311
C Add\sthe\ssqlite3rbu_rename_handler()\sAPI.\sTo\soverride\sthe\sdefault\sroutine\sthat\sRBU\suses\sto\srename\sfiles.
D 2022-11-07T18:00:18.684
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -374,6 +374,7 @@ F ext/rbu/rbumisc.test 329986cf5dd51890c4eb906c2f960ebb773a79a64bed90f506b7c4178
F ext/rbu/rbumulti.test 5fb139058f37ddc5a113c5b93238de915b769b7792de41b44c983bc7c18cf5b9
F ext/rbu/rbupartial.test f25df014b8dbe3c5345851fba6e66f79ab237f57dc201b2d5f0dbae658ae5a4c
F ext/rbu/rbuprogress.test 857cf1f8166c83ef977edb9ef4fc42d80f71fbd798652b46ae2f3a7031870f8d
F ext/rbu/rburename.test a9b4aea612352b74c45de1757edd2ecb2079348b1d4cc734572dc29e55b1b376
F ext/rbu/rburesume.test dbdc4ca504e9c76375a69e5f0d91205db967dcc509a5166ca80231f8fda49eb1
F ext/rbu/rbusave.test f4190a1a86fccf84f723af5c93813365ae33feda35845ba107b59683d1cdd926
F ext/rbu/rbusplit.test b37e7b40b38760881dc9c854bd40b4744c6b6cd74990754eca3bda0f407051e8
@ -382,9 +383,9 @@ F ext/rbu/rbuvacuum.test 55e101e90168c2b31df6c9638fe73dc7f7cc666b6142266d1563697
F ext/rbu/rbuvacuum2.test 886add83fd74bcb02e6dd016ae5b585367bd58c5d0694c9d9ca7bdb1d1f578c2
F ext/rbu/rbuvacuum3.test 8addd82e4b83b4c93fa47428eae4fd0dbf410f8512c186f38e348feb49ba03dc
F ext/rbu/rbuvacuum4.test a78898e438a44803eb2bc897ba3323373c9f277418e2d6d76e90f2f1dbccfd10
F ext/rbu/sqlite3rbu.c 8737cabdfbee84bb25a7851ecef8b1312be332761238da9be6ddb10c62ad4291
F ext/rbu/sqlite3rbu.h 1dc88ab7bd32d0f15890ea08d23476c4198d3da3056985403991f8c9cd389812
F ext/rbu/test_rbu.c 03f6f177096a5f822d68d8e4069ad8907fe572c62ff2d19b141f59742821828a
F ext/rbu/sqlite3rbu.c 90b6b5be1cb6cbd9b7a7dc0c0641d5be63cf00cf9ec8c3b57d27217d28530ea9
F ext/rbu/sqlite3rbu.h 02d981e2d39c151391759e1a400e29c7388730812957ac3db8dad7f6c9f9cfc8
F ext/rbu/test_rbu.c ee6ede75147bc081fe9bc3931e6b206277418d14d3fbceea6fdc6216d9b47055
F ext/recover/dbdata.c 1d5353d3af247c4e0656f8f88a80564aa840644c1177212dd11a186dce4ab213
F ext/recover/recover1.test 02004eb8f9ec2825ba77e24742c18e45162cb21d27e76a3a435b83a759a1131a
F ext/recover/recover_common.tcl a61306c1eb45c0c3fc45652c35b2d4ec19729e340bdf65a272ce4c229cefd85a
@ -2054,8 +2055,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P e377c0a1ef030395293c5f24d7cb8e5b36ce972e9fac31b99c8425075486a46a
R f5acca92b76100558a23567d01b4e532
U stephan
Z f9eb95c0c00a0b5ae6e90e4af7b92086
P d2ed4116fbf1de3c840f84e05db6f29f7b489518ac07d56f61df153deab6bf6b
R 883198cf0956cf3ea945ee8907257d82
U dan
Z f0f97d889869754ab1656f4d9587d370
# Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
d2ed4116fbf1de3c840f84e05db6f29f7b489518ac07d56f61df153deab6bf6b
ebbb1f88e7b5d6cbe84d400f1a187acedb4c668d0b7e4c63bf1496e57da9b8ad