Log the start-up checkpoint's figures under their own names (closes #117)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
Initialize scanned the row of PRAGMA wal_checkpoint(TRUNCATE), which is the busy flag, the frames in the WAL and the frames copied, into wal_pages, checkpointed and moved; and a completed TRUNCATE reads 0 for both counts. The line now logs busy, wal_frames and checkpointed_frames, plus wal_bytes, the WAL file's size read before the checkpoint, and is a warning when busy is 1. Tests open a database a second time while the first stays open, with and without a read open on the first, and check the line's figures. Model: opus-5-5
This commit is contained in:
@@ -245,6 +245,12 @@ func New(cfg *config.Config, logger *logger.Logger) (*Database, error) {
|
||||
return database, nil
|
||||
}
|
||||
|
||||
// The messages Initialize logs the start-up WAL checkpoint with.
|
||||
const (
|
||||
startupCheckpointMessage = "WAL checkpoint on startup"
|
||||
startupCheckpointIncompleteMessage = "WAL checkpoint on startup incomplete"
|
||||
)
|
||||
|
||||
// Initialize creates the database schema if it doesn't exist.
|
||||
func (d *Database) Initialize() error {
|
||||
// Set SQLite pragmas for performance. Per-connection settings (cache_size,
|
||||
@@ -266,19 +272,44 @@ func (d *Database) Initialize() error {
|
||||
}
|
||||
}
|
||||
|
||||
// Run WAL checkpoint on startup to consolidate any existing WAL
|
||||
var walPages, checkpointedPages, movedPages int
|
||||
// The start-up checkpoint copies the WAL a previous run left into the
|
||||
// database file and empties the WAL file; its frame counts then read 0,
|
||||
// so the WAL file's size is read first. There is no WAL file when the
|
||||
// database is new or the last run closed the database, which deletes it.
|
||||
var walBytes int64
|
||||
|
||||
err := d.writer.QueryRowContext(context.Background(),
|
||||
wal, err := os.Stat(d.path + walFileSuffix)
|
||||
if err == nil {
|
||||
walBytes = wal.Size()
|
||||
} else if !errors.Is(err, os.ErrNotExist) {
|
||||
d.logger.Warn("Failed to read the WAL file's size on startup",
|
||||
"error", err)
|
||||
}
|
||||
|
||||
var busy, walFrames, checkpointedFrames int
|
||||
|
||||
err = d.writer.QueryRowContext(context.Background(),
|
||||
"PRAGMA wal_checkpoint(TRUNCATE)",
|
||||
).Scan(&walPages, &checkpointedPages, &movedPages)
|
||||
if err != nil {
|
||||
).Scan(&busy, &walFrames, &checkpointedFrames)
|
||||
|
||||
switch {
|
||||
case err != nil:
|
||||
d.logger.Warn("Failed to checkpoint WAL on startup", "error", err)
|
||||
} else {
|
||||
d.logger.Info("WAL checkpoint on startup",
|
||||
"wal_pages", walPages,
|
||||
"checkpointed", checkpointedPages,
|
||||
"moved", movedPages,
|
||||
case busy != 0:
|
||||
// Another process using the database kept the checkpoint from
|
||||
// copying or emptying all of the WAL.
|
||||
d.logger.Warn(startupCheckpointIncompleteMessage,
|
||||
"wal_bytes", walBytes,
|
||||
"busy", busy,
|
||||
"wal_frames", walFrames,
|
||||
"checkpointed_frames", checkpointedFrames,
|
||||
)
|
||||
default:
|
||||
d.logger.Info(startupCheckpointMessage,
|
||||
"wal_bytes", walBytes,
|
||||
"busy", busy,
|
||||
"wal_frames", walFrames,
|
||||
"checkpointed_frames", checkpointedFrames,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user