Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial disk mode support #401

Merged
merged 6 commits into from
Nov 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ libdqlite_la_SOURCES = \
src/leader.c \
src/lib/addr.c \
src/lib/buffer.c \
src/lib/fs.c \
src/lib/transport.c \
src/logger.c \
src/message.c \
Expand Down
25 changes: 25 additions & 0 deletions include/dqlite.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,16 @@ int dqlite_node_set_failure_domain(dqlite_node *n, unsigned long long code);
int dqlite_node_set_snapshot_params(dqlite_node *n, unsigned snapshot_threshold,
unsigned snapshot_trailing);

/**
* WARNING: This is an experimental API.
*
* By default dqlite holds the SQLite database file and WAL in memory. By enabling
* disk-mode, dqlite will hold the SQLite database file on-disk while keeping the WAL
* in memory. Has to be called after `dqlite_node_create` and before
* `dqlite_node_start`.
*/
int dqlite_node_enable_disk_mode(dqlite_node *n);

/**
* Start a dqlite node.
*
Expand Down Expand Up @@ -305,6 +315,8 @@ dqlite_node_id dqlite_generate_node_id(const char *address);
*/
int dqlite_vfs_init(sqlite3_vfs *vfs, const char *name);

int dqlite_vfs_enable_disk(sqlite3_vfs *vfs);

/**
* Release all memory used internally by a SQLite VFS object that was
* initialized using @qlite_vfs_init.
Expand Down Expand Up @@ -386,6 +398,11 @@ int dqlite_vfs_shallow_snapshot(sqlite3_vfs *vfs,
struct dqlite_buffer bufs[],
unsigned n);

int dqlite_vfs_snapshot_disk(sqlite3_vfs *vfs,
const char *filename,
struct dqlite_buffer bufs[],
unsigned n);

/**
* Return the number of database pages (excluding WAL).
*/
Expand All @@ -401,4 +418,12 @@ int dqlite_vfs_restore(sqlite3_vfs *vfs,
const void *data,
size_t n);

/**
* Restore a snapshot of the main database file and of the WAL file.
*/
int dqlite_vfs_restore_disk(sqlite3_vfs *vfs,
const char *filename,
const void *data,
size_t main_size,
size_t wal_size);
#endif /* DQLITE_H */
6 changes: 5 additions & 1 deletion src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
* TODO: make this thread safe. */
static unsigned serial = 1;

int config__init(struct config *c, dqlite_node_id id, const char *address)
int config__init(struct config *c, dqlite_node_id id,
const char *address, const char *dir)
{
int rv;
c->id = id;
Expand All @@ -46,6 +47,9 @@ int config__init(struct config *c, dqlite_node_id id, const char *address)
c->logger.emit = loggerDefaultEmit;
c->failure_domain = 0;
c->weight = 0;
strncpy(c->dir, dir, sizeof(c->dir)-1);
c->dir[sizeof(c->dir)-1] = '\0';
c->disk = false;
serial++;
return 0;
}
Expand Down
5 changes: 4 additions & 1 deletion src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@ struct config
char name[256]; /* VFS/replication registriatio name */
unsigned long long failure_domain; /* User-provided failure domain */
unsigned long long int weight; /* User-provided node weight */
char dir[1024]; /* Data dir for on-disk database */
bool disk; /* Disk-mode or not */
};

/**
* Initialize the config object with required values and set the rest to sane
* defaults. A copy will be made of the given @address.
*/
int config__init(struct config *c, dqlite_node_id id, const char *address);
int config__init(struct config *c, dqlite_node_id id,
const char *address, const char *dir);

/**
* Release any memory held by the config object.
Expand Down
46 changes: 38 additions & 8 deletions src/db.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,53 @@
#include "db.h"
#include "tracing.h"

/* Limit taken from sqlite unix vfs. */
#define MAX_PATHNAME 512

/* Open a SQLite connection and set it to follower mode. */
static int open_follower_conn(const char *filename,
const char *vfs,
unsigned page_size,
sqlite3 **conn);

void db__init(struct db *db, struct config *config, const char *filename)
int db__init(struct db *db, struct config *config, const char *filename)
{
tracef("db init %s", filename);
tracef("db init %s", filename);
int rv;

db->config = config;
db->filename = sqlite3_malloc((int)(strlen(filename) + 1));
assert(db->filename != NULL); /* TODO: return an error instead */
if (db->filename == NULL) {
rv = DQLITE_NOMEM;
goto err;
}
strcpy(db->filename, filename);
db->path = sqlite3_malloc(MAX_PATHNAME + 1);
if (db->path == NULL) {
rv = DQLITE_NOMEM;
goto err_after_filename_alloc;
}
if (db->config->disk) {
rv = snprintf(db->path, MAX_PATHNAME + 1, "%s/%s", db->config->dir, db->filename);
} else {
rv = snprintf(db->path, MAX_PATHNAME + 1, "%s", db->filename);
}
if (rv < 0 || rv >= MAX_PATHNAME + 1) {
goto err_after_path_alloc;
}

db->follower = NULL;
db->tx_id = 0;
db->read_lock = 0;
QUEUE__INIT(&db->leaders);
return 0;

err_after_path_alloc:
sqlite3_free(db->path);
err_after_filename_alloc:
sqlite3_free(db->filename);
err:
return rv;
}

void db__close(struct db *db)
Expand All @@ -34,19 +64,17 @@ void db__close(struct db *db)
rc = sqlite3_close(db->follower);
assert(rc == SQLITE_OK);
}
sqlite3_free(db->path);
sqlite3_free(db->filename);
}

int db__open_follower(struct db *db)
{
int rc;
assert(db->follower == NULL);
rc = open_follower_conn(db->filename, db->config->name,
rc = open_follower_conn(db->path, db->config->name,
db->config->page_size, &db->follower);
if (rc != 0) {
return rc;
}
return 0;
return rc;
}

static int open_follower_conn(const char *filename,
Expand All @@ -59,8 +87,10 @@ static int open_follower_conn(const char *filename,
char *msg = NULL;
int rc;

tracef("open follower conn: %s page_size:%u", filename, page_size);
rc = sqlite3_open_v2(filename, conn, flags, vfs);
if (rc != SQLITE_OK) {
tracef("open_v2 failed %d", rc);
goto err;
}

Expand Down
4 changes: 3 additions & 1 deletion src/db.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ struct db
{
struct config *config; /* Dqlite configuration */
char *filename; /* Database filename */
char *path; /* Used for on-disk db */
sqlite3 *follower; /* Follower connection */
queue leaders; /* Open leader connections */
unsigned tx_id; /* Current ongoing transaction ID, if any */
Expand All @@ -24,8 +25,9 @@ struct db
* Initialize a database object.
*
* The given @filename will be copied.
* Return 0 on success.
*/
void db__init(struct db *db, struct config *config, const char *filename);
int db__init(struct db *db, struct config *config, const char *filename);

/**
* Release all memory associated with a database object.
Expand Down
33 changes: 33 additions & 0 deletions src/dqlite.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ int dqlite_vfs_init(sqlite3_vfs *vfs, const char *name)
return VfsInit(vfs, name);
}

int dqlite_vfs_enable_disk(sqlite3_vfs *vfs)
{
return VfsEnableDisk(vfs);
}

void dqlite_vfs_close(sqlite3_vfs *vfs)
{
VfsClose(vfs);
Expand Down Expand Up @@ -47,6 +52,25 @@ int dqlite_vfs_snapshot(sqlite3_vfs *vfs,
return VfsSnapshot(vfs, filename, data, n);
}

int dqlite_vfs_snapshot_disk(sqlite3_vfs *vfs,
const char *filename,
struct dqlite_buffer bufs[],
unsigned n)
{
int rv;
if (n != 2) {
return -1;
}

rv = VfsDiskSnapshotDb(vfs, filename, &bufs[0]);
if (rv != 0) {
return rv;
}

rv = VfsDiskSnapshotWal(vfs, filename, &bufs[1]);
return rv;
}

int dqlite_vfs_num_pages(sqlite3_vfs *vfs,
const char *filename,
unsigned *n)
Expand All @@ -69,3 +93,12 @@ int dqlite_vfs_restore(sqlite3_vfs *vfs,
{
return VfsRestore(vfs, filename, data, n);
}

int dqlite_vfs_restore_disk(sqlite3_vfs *vfs,
const char *filename,
const void *data,
size_t main_size,
size_t wal_size)
{
return VfsDiskRestore(vfs, filename, data, main_size, wal_size);
}
Loading