Merge pull request #170 from benbjohnson/remove-sync-lock-2
Remove SQLite write lock during WAL sync
This commit is contained in:
26
db.go
26
db.go
@@ -751,27 +751,6 @@ func (db *DB) Sync(ctx context.Context) (err error) {
|
|||||||
return fmt.Errorf("ensure wal exists: %w", err)
|
return fmt.Errorf("ensure wal exists: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start a transaction. This will be promoted immediately after.
|
|
||||||
tx, err := db.db.Begin()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("begin: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure write transaction rolls back before returning.
|
|
||||||
defer func() {
|
|
||||||
if e := rollback(tx); e != nil && err == nil {
|
|
||||||
err = e
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Insert into the lock table to promote to a write tx. The lock table
|
|
||||||
// insert will never actually occur because our tx will be rolled back,
|
|
||||||
// however, it will ensure our tx grabs the write lock. Unfortunately,
|
|
||||||
// we can't call "BEGIN IMMEDIATE" as we are already in a transaction.
|
|
||||||
if _, err := tx.ExecContext(ctx, `INSERT INTO _litestream_lock (id) VALUES (1);`); err != nil {
|
|
||||||
return fmt.Errorf("_litestream_lock: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify our last sync matches the current state of the WAL.
|
// Verify our last sync matches the current state of the WAL.
|
||||||
// This ensures that we have an existing generation & that the last sync
|
// This ensures that we have an existing generation & that the last sync
|
||||||
// position of the real WAL hasn't been overwritten by another process.
|
// position of the real WAL hasn't been overwritten by another process.
|
||||||
@@ -818,11 +797,6 @@ func (db *DB) Sync(ctx context.Context) (err error) {
|
|||||||
checkpoint = true
|
checkpoint = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release write lock before checkpointing & exiting.
|
|
||||||
if err := tx.Rollback(); err != nil {
|
|
||||||
return fmt.Errorf("rollback write tx: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Issue the checkpoint.
|
// Issue the checkpoint.
|
||||||
if checkpoint {
|
if checkpoint {
|
||||||
changed = true
|
changed = true
|
||||||
|
|||||||
@@ -607,6 +607,11 @@ func (r *FileReplica) snapshot(ctx context.Context, generation string, index int
|
|||||||
r.muf.Lock()
|
r.muf.Lock()
|
||||||
defer r.muf.Unlock()
|
defer r.muf.Unlock()
|
||||||
|
|
||||||
|
// Issue a passive checkpoint to flush any pages to disk before snapshotting.
|
||||||
|
if _, err := r.db.db.ExecContext(ctx, `PRAGMA wal_checkpoint(PASSIVE);`); err != nil {
|
||||||
|
return fmt.Errorf("pre-snapshot checkpoint: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Acquire a read lock on the database during snapshot to prevent checkpoints.
|
// Acquire a read lock on the database during snapshot to prevent checkpoints.
|
||||||
tx, err := r.db.db.Begin()
|
tx, err := r.db.db.Begin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
5
s3/s3.go
5
s3/s3.go
@@ -649,6 +649,11 @@ func (r *Replica) snapshot(ctx context.Context, generation string, index int) er
|
|||||||
r.muf.Lock()
|
r.muf.Lock()
|
||||||
defer r.muf.Unlock()
|
defer r.muf.Unlock()
|
||||||
|
|
||||||
|
// Issue a passive checkpoint to flush any pages to disk before snapshotting.
|
||||||
|
if _, err := r.db.SQLDB().ExecContext(ctx, `PRAGMA wal_checkpoint(PASSIVE);`); err != nil {
|
||||||
|
return fmt.Errorf("pre-snapshot checkpoint: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Acquire a read lock on the database during snapshot to prevent checkpoints.
|
// Acquire a read lock on the database during snapshot to prevent checkpoints.
|
||||||
tx, err := r.db.SQLDB().Begin()
|
tx, err := r.db.SQLDB().Begin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user