0
0
mirror of https://github.com/tursodatabase/libsql.git synced 2024-12-15 09:49:40 +00:00
ad hoc a72c066a8e
Wal related changes (#996)
wal extensions
2024-02-06 17:44:23 +00:00

305 lines
11 KiB
C

#include "sqlite3.h"
#include "src/wal.h"
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#define LIBSQL_IMPORT(name) extern __attribute__((import_module("libsql_host"), import_name(name)))
LIBSQL_IMPORT("close") int libsql_wasi_close(sqlite3_file*);
LIBSQL_IMPORT("read") int libsql_wasi_read(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
LIBSQL_IMPORT("write") int libsql_wasi_write(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst);
LIBSQL_IMPORT("truncate") int libsql_wasi_truncate(sqlite3_file*, sqlite3_int64 size);
LIBSQL_IMPORT("sync") int libsql_wasi_sync(sqlite3_file*, int flags);
LIBSQL_IMPORT("file_size") int libsql_wasi_file_size(sqlite3_file*, sqlite3_int64 *pSize);
typedef struct libsql_wasi_file {
const struct sqlite3_io_methods* pMethods;
int64_t fd;
} libsql_wasi_file;
// We're running in exclusive mode, so locks are noops.
// We need to handle locking in the host.
static int libsql_wasi_lock(sqlite3_file* f, int eLock) {
(void)f, (void)eLock;
return SQLITE_OK;
}
static int libsql_wasi_unlock(sqlite3_file* f, int eLock) {
(void)f, (void)eLock;
return SQLITE_OK;
}
static int libsql_wasi_check_reserved_lock(sqlite3_file* f, int *pResOut) {
(void)f, (void)pResOut;
return SQLITE_OK;
}
static int libsql_wasi_device_characteristics(sqlite3_file* f) {
(void)f;
return SQLITE_IOCAP_ATOMIC | SQLITE_IOCAP_SAFE_APPEND | SQLITE_IOCAP_SEQUENTIAL;
}
static int libsql_wasi_file_control(sqlite3_file* f, int opcode, void* arg) {
(void)opcode, (void)f, (void)arg;
return SQLITE_NOTFOUND;
}
static int libsql_wasi_sector_size(sqlite3_file* f) {
(void)f;
return 512;
}
static const sqlite3_io_methods wasi_io_methods = {
.iVersion = 1,
.xClose = &libsql_wasi_close,
.xRead = &libsql_wasi_read,
.xWrite = &libsql_wasi_write,
.xTruncate = &libsql_wasi_truncate,
.xSync = &libsql_wasi_sync,
.xFileSize = &libsql_wasi_file_size,
.xLock = &libsql_wasi_lock,
.xUnlock = &libsql_wasi_unlock,
.xCheckReservedLock = &libsql_wasi_check_reserved_lock,
.xFileControl = &libsql_wasi_file_control,
.xSectorSize = &libsql_wasi_sector_size,
.xDeviceCharacteristics = &libsql_wasi_device_characteristics,
};
LIBSQL_IMPORT("open_fd") int64_t libsql_wasi_open_fd(const char *zName, int flags);
LIBSQL_IMPORT("delete") int libsql_wasi_delete(sqlite3_vfs*, const char *zName, int syncDir);
LIBSQL_IMPORT("access") int libsql_wasi_access(sqlite3_vfs*, const char *zName, int flags, int *pResOut);
LIBSQL_IMPORT("full_pathname") int libsql_wasi_full_pathname(sqlite3_vfs*, const char *zName, int nOut, char *zOut);
LIBSQL_IMPORT("randomness") int libsql_wasi_randomness(sqlite3_vfs*, int nByte, char *zOut);
LIBSQL_IMPORT("sleep") int libsql_wasi_sleep(sqlite3_vfs*, int microseconds);
LIBSQL_IMPORT("current_time") int libsql_wasi_current_time(sqlite3_vfs*, double*);
LIBSQL_IMPORT("get_last_error") int libsql_wasi_get_last_error(sqlite3_vfs*, int, char*);
LIBSQL_IMPORT("current_time_64") int libsql_wasi_current_time_64(sqlite3_vfs*, sqlite3_int64*);
int libsql_wasi_vfs_open(sqlite3_vfs *vfs, const char *zName, sqlite3_file *file_, int flags, int *pOutFlags) {
libsql_wasi_file *file = (libsql_wasi_file*)file_;
file->fd = libsql_wasi_open_fd(zName, flags);
if (file->fd == 0) {
return SQLITE_CANTOPEN;
}
file->pMethods = &wasi_io_methods;
return SQLITE_OK;
}
sqlite3_vfs libsql_wasi_vfs = {
.iVersion = 2,
.szOsFile = sizeof(libsql_wasi_file),
.mxPathname = 100,
.zName = "libsql_wasi",
.xOpen = &libsql_wasi_vfs_open,
.xDelete = &libsql_wasi_delete,
.xAccess = &libsql_wasi_access,
.xFullPathname = &libsql_wasi_full_pathname,
.xRandomness = &libsql_wasi_randomness,
.xSleep = &libsql_wasi_sleep,
.xCurrentTime = &libsql_wasi_current_time,
.xGetLastError = &libsql_wasi_get_last_error,
.xCurrentTimeInt64 = &libsql_wasi_current_time_64,
};
libsql_wal_methods *the_wal_methods = NULL;
int libsql_wasi_wal_open(sqlite3_vfs* vfs, sqlite3_file* f, const char* path, int no_shm_mode, long long max_size, struct libsql_wal_methods* wal_methods, libsql_wal** wal) {
fprintf(stderr, "Opening virtual WAL at %s: %s\n", path, wal_methods->zName);
return the_wal_methods->xOpen(vfs, f, path, no_shm_mode, max_size, wal_methods, wal);
}
int libsql_wasi_wal_close(libsql_wal* wal, sqlite3* db, int sync_flags, int nBuf, unsigned char* zBuf) {
return the_wal_methods->xClose(wal, db, sync_flags, nBuf, zBuf);
}
void libsql_wasi_wal_limit(libsql_wal* wal, long long limit) {
return the_wal_methods->xLimit(wal, limit);
}
int libsql_wasi_wal_begin_read_transaction(libsql_wal* wal, int* out) {
return the_wal_methods->xBeginReadTransaction(wal, out);
}
void libsql_wasi_wal_end_read_transaction(libsql_wal* wal) {
return the_wal_methods->xEndReadTransaction(wal);
}
int libsql_wasi_wal_find_frame(libsql_wal* wal, unsigned int frame, unsigned int* out) {
return the_wal_methods->xFindFrame(wal, frame, out);
}
int libsql_wasi_wal_read_frame(libsql_wal* wal, unsigned int frame, int n, unsigned char* out) {
return the_wal_methods->xReadFrame(wal, frame, n, out);
}
unsigned int libsql_wasi_wal_dbsize(libsql_wal* wal) {
return the_wal_methods->xDbsize(wal);
}
int libsql_wasi_wal_begin_write_transaction(libsql_wal* wal) {
return the_wal_methods->xBeginWriteTransaction(wal);
}
int libsql_wasi_wal_end_write_transaction(libsql_wal* wal) {
return the_wal_methods->xEndWriteTransaction(wal);
}
int libsql_wasi_wal_undo(libsql_wal* wal, int (*xUndo)(void*, unsigned int), void* pUndoCtx) {
return the_wal_methods->xUndo(wal, xUndo, pUndoCtx);
}
void libsql_wasi_wal_savepoint(libsql_wal* wal, unsigned int* aWalData) {
return the_wal_methods->xSavepoint(wal, aWalData);
}
int libsql_wasi_wal_savepoint_undo(libsql_wal* wal, unsigned int* aWalData) {
return the_wal_methods->xSavepointUndo(wal, aWalData);
}
int libsql_wasi_wal_frames(libsql_wal* wal, int n, libsql_pghdr* aPgHdr, unsigned int cksum, int mode, int readonly) {
return the_wal_methods->xFrames(wal, n, aPgHdr, cksum, mode, readonly, NULL);
}
int libsql_wasi_wal_checkpoint(libsql_wal* wal, sqlite3* db, int eMode, int (*xBusy)(void*), void* pBusyArg, int sync_flags, int nBuf, unsigned char* zBuf, int* pnLog, int* pnCkpt) {
return the_wal_methods->xCheckpoint(wal, db, eMode, xBusy, pBusyArg, sync_flags, nBuf, zBuf, pnLog, pnCkpt);
}
int libsql_wasi_wal_callback(libsql_wal* wal) {
return the_wal_methods->xCallback(wal);
}
int libsql_wasi_wal_exclusive_mode(libsql_wal* wal, int op) {
return the_wal_methods->xExclusiveMode(wal, op);
}
int libsql_wasi_wal_heap_memory(libsql_wal* wal) {
return the_wal_methods->xHeapMemory(wal);
}
int libsql_wasi_wal_snapshot_get(libsql_wal* wal, sqlite3_snapshot** snapshot) {
return the_wal_methods->xSnapshotGet(wal, snapshot);
}
void libsql_wasi_wal_snapshot_open(libsql_wal* wal, sqlite3_snapshot* snapshot) {
return the_wal_methods->xSnapshotOpen(wal, snapshot);
}
int libsql_wasi_wal_snapshot_recover(libsql_wal* wal) {
return the_wal_methods->xSnapshotRecover(wal);
}
int libsql_wasi_wal_snapshot_check(libsql_wal* wal, sqlite3_snapshot* snapshot) {
return the_wal_methods->xSnapshotCheck(wal, snapshot);
}
void libsql_wasi_wal_snapshot_unlock(libsql_wal* wal) {
return the_wal_methods->xSnapshotUnlock(wal);
}
int libsql_wasi_wal_framesize(libsql_wal* wal) {
return the_wal_methods->xFramesize(wal);
}
sqlite3_file *libsql_wasi_wal_file(libsql_wal* wal) {
return the_wal_methods->xFile(wal);
}
int libsql_wasi_wal_writelock(libsql_wal* wal, int bLock) {
return the_wal_methods->xWriteLock(wal, bLock);
}
void libsql_wasi_wal_db(libsql_wal* wal, sqlite3* db) {
return the_wal_methods->xDb(wal, db);
}
int libsql_wasi_wal_pathname_len(int orig_len) {
return the_wal_methods->xPathnameLen(orig_len);
}
void libsql_wasi_get_wal_pathname(char *buf, const char *orig, int len) {
return the_wal_methods->xGetWalPathname(buf, orig, len);
}
int libsql_wasi_wal_pre_main_db_open(libsql_wal_methods *methods, const char *path) {
return 0;
}
libsql_wal_methods libsql_wasi_wal_methods = {
.iVersion = 1,
.xOpen = &libsql_wasi_wal_open,
.xClose = &libsql_wasi_wal_close,
.xLimit = &libsql_wasi_wal_limit,
.xBeginReadTransaction = &libsql_wasi_wal_begin_read_transaction,
.xEndReadTransaction = &libsql_wasi_wal_end_read_transaction,
.xFindFrame = &libsql_wasi_wal_find_frame,
.xReadFrame = &libsql_wasi_wal_read_frame,
.xDbsize = &libsql_wasi_wal_dbsize,
.xBeginWriteTransaction = &libsql_wasi_wal_begin_write_transaction,
.xEndWriteTransaction = &libsql_wasi_wal_end_write_transaction,
.xUndo = &libsql_wasi_wal_undo,
.xSavepoint = &libsql_wasi_wal_savepoint,
.xSavepointUndo = &libsql_wasi_wal_savepoint_undo,
.xFrames = &libsql_wasi_wal_frames,
.xCheckpoint = &libsql_wasi_wal_checkpoint,
.xCallback = &libsql_wasi_wal_callback,
.xExclusiveMode = &libsql_wasi_wal_exclusive_mode,
.xHeapMemory = &libsql_wasi_wal_heap_memory,
.xSnapshotGet = &libsql_wasi_wal_snapshot_get,
.xSnapshotOpen = &libsql_wasi_wal_snapshot_open,
.xSnapshotRecover = &libsql_wasi_wal_snapshot_recover,
.xSnapshotCheck = &libsql_wasi_wal_snapshot_check,
.xSnapshotUnlock = &libsql_wasi_wal_snapshot_unlock,
.xFramesize = &libsql_wasi_wal_framesize,
.xFile = &libsql_wasi_wal_file,
.xWriteLock = &libsql_wasi_wal_writelock,
.xDb = &libsql_wasi_wal_db,
.xPathnameLen = &libsql_wasi_wal_pathname_len,
.xGetWalPathname = &libsql_wasi_get_wal_pathname,
.xPreMainDbOpen = &libsql_wasi_wal_pre_main_db_open,
.bUsesShm = 0,
.zName = "libsql_wasi",
.pNext = NULL,
};
void libsql_wasi_init() {
the_wal_methods = libsql_wal_methods_find(NULL);
sqlite3_vfs_register(&libsql_wasi_vfs, 1);
libsql_wal_methods_register(&libsql_wasi_wal_methods);
fprintf(stderr, "WASI initialized\n");
}
sqlite3 *libsql_wasi_open_db(const char *filename) {
sqlite3 *db;
fprintf(stderr, "opening database %s\n", filename);
int rc = libsql_open(filename, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "libsql_wasi", "libsql_wasi");
if (rc != SQLITE_OK) {
fprintf(stderr, "Failed to open database: %s\n", sqlite3_errmsg(db));
return NULL;
}
fprintf(stderr, "opened database %s\n", filename);
rc = sqlite3_exec(db, "PRAGMA journal_mode=WAL;", NULL, NULL, NULL);
if (rc != SQLITE_OK) {
fprintf(stderr, "Failed to set journal mode: %s\n", sqlite3_errmsg(db));
return NULL;
}
return db;
}
int libsql_wasi_exec(sqlite3 *db, const char *sql) {
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
if (rc != SQLITE_OK) {
fprintf(stderr, "Failed to prepare statement: %s\n", sqlite3_errmsg(db));
return rc;
}
// Step in a loop until SQLITE_DONE or error
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {}
if (rc != SQLITE_DONE) {
fprintf(stderr, "Failed to execute statement: %s\n", sqlite3_errmsg(db));
return rc;
}
return SQLITE_OK;
}