Skip to content

disk I/O error during large transactions on Windows using WAL #330

@Hakkin

Description

@Hakkin

I am getting "disk I/O error" during large transactions with WAL on Windows.

Initially hit this while trying to insert a large amount of hash blobs into a DB in a single transaction, below is a reproducer.

I can't seem to trigger this on Linux, and it only seems to trigger when using WAL journal mode, so I suppose it's something in the Windows-specific WAL code.

Issue occurs on both previous and latest release version.

package main

import (
	"database/sql"
	"encoding/binary"
	"errors"
	"fmt"
	"log"

	"github.com/ncruces/go-sqlite3"
	_ "github.com/ncruces/go-sqlite3/driver"
	_ "github.com/ncruces/go-sqlite3/embed"
)

func sqliteError(err error) error {
	if e := sqlite3.ExtendedErrorCode(0); errors.As(err, &e) {
		return fmt.Errorf("%w (%d)", err, e)
	}
	return err
}

func main() {
	db, err := sql.Open("sqlite3", "file:hashes.db?_pragma=journal_mode(wal)")
	if err != nil {
		log.Fatalf("open: %v", sqliteError(err))
	}
	defer db.Close()

	db.SetMaxOpenConns(1)

	_, err = db.Exec(`
		CREATE TABLE IF NOT EXISTS hashes (
			hash BLOB,
			PRIMARY KEY (hash ASC)
		) WITHOUT ROWID;
	`)
	if err != nil {
		log.Fatalf("create: %v", sqliteError(err))
	}

	stmt, err := db.Prepare(`INSERT INTO hashes(hash) VALUES (?);`)
	if err != nil {
		log.Fatalf("prepare: %v", sqliteError(err))
	}

	var total uint64
	var hash [8]byte
	for batchSize := uint64(1); ; batchSize *= 2 {
		log.Printf("batch = %d", batchSize)
		tx, err := db.Begin()
		if err != nil {
			log.Fatalf("begin: %v", sqliteError(err))
		}
		txStmt := tx.Stmt(stmt)
		for i := uint64(0); i < batchSize; i++ {
			binary.BigEndian.PutUint64(hash[:], total+i)
			_, err = txStmt.Exec(hash[:])
			if err != nil {
				log.Fatalf("exec: %v", sqliteError(err))
			}
		}
		err = tx.Commit()
		if err != nil {
			log.Fatalf("commit: %v", sqliteError(err))
		}
		total += batchSize
	}
}
2025/11/05 19:48:17 batch = 1
2025/11/05 19:48:17 batch = 2
2025/11/05 19:48:17 batch = 4
2025/11/05 19:48:17 batch = 8
2025/11/05 19:48:17 batch = 16
2025/11/05 19:48:17 batch = 32
2025/11/05 19:48:17 batch = 64
2025/11/05 19:48:17 batch = 128
2025/11/05 19:48:17 batch = 256
2025/11/05 19:48:17 batch = 512
2025/11/05 19:48:17 batch = 1024
2025/11/05 19:48:17 batch = 2048
2025/11/05 19:48:17 batch = 4096
2025/11/05 19:48:17 batch = 8192
2025/11/05 19:48:17 batch = 16384
2025/11/05 19:48:17 batch = 32768
2025/11/05 19:48:18 batch = 65536
2025/11/05 19:48:18 batch = 131072
2025/11/05 19:48:19 batch = 262144
2025/11/05 19:48:20 batch = 524288
2025/11/05 19:48:23 batch = 1048576
2025/11/05 19:48:28 batch = 2097152
2025/11/05 19:48:34 exec: sqlite3: disk I/O error (5386)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions