From ce201b3a6be487bb3eb48e1d102ba246332aba66 Mon Sep 17 00:00:00 2001
From: MartinChoo <214582617@qq.com>
Date: Wed, 23 Jul 2025 17:43:40 +0800
Subject: [PATCH 08/12] Rekey multi process
src/sqlite3.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 90 insertions(+), 3 deletions(-)
@@ -15689,6 +15689,7 @@ typedef int VList;
#define RESERVED_BYTE (PENDING_BYTE+1)
#define SHARED_FIRST (PENDING_BYTE+2)
#define SHARED_SIZE 510
+#define SHARED_CODEC_BYTE (PENDING_BYTE+2097)
/*
** Wrapper around OS specific sqlite3_os_init() function.
@@ -38682,6 +38683,10 @@ struct unixFile {
#endif
};
+#ifdef SQLITE_HAS_CODEC
+static int CodecFileLock(Pager *pPager, short lockType);
+#endif
+
/* This variable holds the process id (pid) from when the xRandomness()
** method was called. If xOpen() is called from a different process id,
** indicating that a fork() has occurred, the PRNG will be reset.
@@ -39627,6 +39632,9 @@ struct unixInodeInfo {
sqlite3_mutex *pLockMutex; /* Hold this mutex for... */
int nShared; /* Number of SHARED locks held */
int nLock; /* Number of outstanding file locks */
+#if SQLITE_HAS_CODEC
+ void *codecPager;
+#endif
unsigned char eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */
unsigned char bProcessLock; /* An exclusive process lock is held */
UnixUnusedFd *pUnused; /* Unused file descriptors to close */
@@ -61697,6 +61705,9 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){
PAGERTRACE(("CLOSE %d\n", PAGERID(pPager)));
IOTRACE(("CLOSE %p\n", pPager))
sqlite3OsClose(pPager->jfd);
+#if SQLITE_OS_UNIX && defined(SQLITE_HAS_CODEC)
+ if( pPager->xCodec ) CodecFileLock(pPager, F_UNLCK);
+#endif
sqlite3OsClose(pPager->fd);
sqlite3PageFree(pTmp);
sqlite3PcacheClose(pPager->pPCache);
@@ -255500,6 +255511,54 @@ void sqlite3CodecDetach(void *ctx){
return;
}
+#if SQLITE_OS_UNIX
+static int CodecFileLock(Pager *pPager, short lockType)
+{
+ sqlite3_file *fd = pPager->fd;
+ unixFile *pFile = (unixFile *)fd;
+ unixInodeInfo *pInode = pFile->pInode;
+ if (pInode == NULL) {
+ sqlite3_log(SQLITE_IOERR_RDLOCK, "Codec file lock %d go wrong", lockType);
+ return SQLITE_IOERR_RDLOCK;
+ }
+ sqlite3_mutex_enter(pInode->pLockMutex);
+ // last conntection release the lock
+ if (lockType == F_UNLCK && pInode->nRef > 1) {
+ sqlite3_mutex_leave(pInode->pLockMutex);
+ return SQLITE_OK;
+ }
+ if (lockType == F_WRLCK && pInode->nRef > 1) {
+ sqlite3_mutex_leave(pInode->pLockMutex);
+ sqlite3_log(SQLITE_BUSY, "Codec file lock wrlock busy ref %d", pInode->nRef);
+ return SQLITE_BUSY;
+ }
+ if (lockType == F_RDLCK && pInode->codecPager != 0 && pInode->codecPager != pPager) {
+ sqlite3_mutex_leave(pInode->pLockMutex);
+ sqlite3_log(SQLITE_BUSY, "Codec exists file lock wrlock");
+ return SQLITE_BUSY;
+ }
+ struct flock lock;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = SHARED_CODEC_BYTE;
+ lock.l_len = 1;
+ // F_RDLCK, F_WRLCK, F_UNLCK
+ lock.l_type = lockType;
+ int rc = osSetPosixAdvisoryLock(pFile->h, &lock, pFile);
+ if (rc < 0) {
+ int tErrno = errno;
+ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
+ if (IS_LOCK_ERROR(rc)) {
+ storeLastErrno(pFile, tErrno);
+ }
+ sqlite3_log(rc, "Codec file lock %d: errno = %d", lockType, tErrno);
+ } else {
+ pInode->codecPager = (lockType == F_WRLCK ? pPager : 0);
+ }
+ sqlite3_mutex_leave(pInode->pLockMutex);
+ return rc;
+}
+#endif
+
int sqlite3CodecAttach(sqlite3* db, int nDb, const void *pKey, int nKey){
if(db == NULL){
return SQLITE_ERROR;
@@ -255519,6 +255578,18 @@ int sqlite3CodecAttach(sqlite3* db, int nDb, const void *pKey, int nKey){
return SQLITE_ERROR;
}
sqlite3_mutex_enter(db->mutex);
+ Pager *pPager = p->pBt->pPager;
+#if SQLITE_OS_UNIX
+ if (pPager->fd != NULL && isOpen(pPager->fd)) {
+ int ret = CodecFileLock(pPager, F_RDLCK);
+ if(ret != SQLITE_OK){
+ sqlite3_free(ctx);
+ sqlite3_mutex_leave(db->mutex);
+ sqlite3_log(ret, "sqlite3CodecAttach: codec lock error");
+ return ret;
+ }
+ }
+#endif
#ifdef SQLITE_CODEC_ATTACH_CHANGED
int rc = sqlite3CodecInitContext(ctx, p, pKey, nKey, nDb);
#else
@@ -255526,6 +255597,7 @@ int sqlite3CodecAttach(sqlite3* db, int nDb, const void *pKey, int nKey){
#endif /* SQLITE_CODEC_ATTACH_CHANGED */
if(rc != SQLITE_OK){
sqlite3_free(ctx);
+ sqlite3_mutex_leave(db->mutex);
return rc;
}
sqlite3PagerSetCodec(sqlite3BtreePager(p), sqlite3Codec, NULL, sqlite3CodecDetach, (void *)ctx);
@@ -255534,7 +255606,7 @@ int sqlite3CodecAttach(sqlite3* db, int nDb, const void *pKey, int nKey){
p->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED;
sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0);
sqlite3BtreeSecureDelete(p, 1);
- if(isOpen(p->pBt->pPager->fd)){
+ if(isOpen(pPager->fd)){
sqlite3BtreeSetAutoVacuum(p, SQLITE_DEFAULT_AUTOVACUUM);
}
@@ -255605,7 +255677,20 @@ int sqlite3_rekey_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey){
return rc;
}
sqlite3_mutex_enter(db->mutex);
- (void)sqlite3BtreeBeginTrans(p, 1, 0);
+ rc = sqlite3BtreeBeginTrans(p, 1, 0);
+ if(rc != SQLITE_OK){
+ sqlite3_mutex_leave(db->mutex);
+ sqlite3_log(rc, "sqlite3 rekey: error when begin trans %s.", sqlite3PagerFilename(pPager, 1));
+ return rc;
+ }
+#if SQLITE_OS_UNIX
+ if((rc = CodecFileLock(pPager, F_WRLCK)) != SQLITE_OK){
+ (void)sqlite3BtreeRollback(p, SQLITE_ABORT_ROLLBACK, 0);
+ sqlite3_mutex_leave(db->mutex);
+ sqlite3_log(rc, "sqlite3_rekey_v2: error when lock %s.", sqlite3PagerFilename(pPager, 1));
+ return rc;
+ }
+#endif
sqlite3PagerPagecount(pPager, &pageCount);
// support hmac algo changed by using rekey operation
int oldHmacAlgo = ctx->writeCtx->codecConst.hmacAlgo;
@@ -255640,8 +255725,10 @@ int sqlite3_rekey_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey){
}
(void)sqlite3BtreeRollback(p, SQLITE_ABORT_ROLLBACK, 0);
}
+#if SQLITE_OS_UNIX
+ (void)CodecFileLock(pPager, F_RDLCK);
+#endif
sqlite3_mutex_leave(db->mutex);
-
return rc;
}
--
2.47.0.windows.2