SQLite na RAM: serialize e deserialize em Go

O SQLite pode rodar inteiramente na memória, sem nunca tocar o disco. E tem um truque pouco conhecido: dá para tirar um snapshot dos bytes do próprio banco e recarregá-lo depois, sem INSERT, sem reconstruir nada. As funções são sqlite3_serialize e sqlite3_deserialize.

Vou usar o driver modernc.org/sqlite, que é Go puro, sem CGo.

db, err := sql.Open("sqlite", ":memory:")
if err != nil {
	fatal(err)
}
db.SetMaxOpenConns(1)

A pegadinha está no SetMaxOpenConns(1). Um banco :memory: pertence à conexão que o abriu. Sem limitar a uma conexão, o pool do database/sql poderia abrir outra e essa veria um banco vazio e diferente.

Essas funções não estão na interface do database/sql. Chegamos nelas pelo escape hatch (*sql.Conn).Raw, usando uma interface que o driver implementa:

type serializer interface {
	Serialize() ([]byte, error)
	Deserialize([]byte) error
}

O snapshot devolve, byte a byte, o que seria o arquivo .sqlite em disco. Os primeiros 16 bytes são literalmente SQLite format 3\0:

func snapshot(db *sql.DB) ([]byte, error) {
	conn, err := db.Conn(context.Background())
	if err != nil {
		return nil, err
	}
	defer func() { _ = conn.Close() }()
	var buf []byte
	err = conn.Raw(func(dc any) error {
		s, ok := dc.(serializer)
		if !ok {
			return errors.New("the driver does not expose Serialize")
		}
		var serr error
		buf, serr = s.Serialize()
		return serr
	})
	return buf, err
}

O restore faz o caminho inverso. Depois dele, todas as tabelas e linhas estão de volta na memória.

func restore(db *sql.DB, buf []byte) error {
	conn, err := db.Conn(context.Background())
	if err != nil {
		return err
	}
	defer func() { _ = conn.Close() }()
	return conn.Raw(func(dc any) error {
		s, ok := dc.(serializer)
		if !ok {
			return errors.New("the driver does not expose Deserialize")
		}
		return s.Deserialize(buf)
	})
}

Você processa tudo em memória, rápido e sem deixar nada em texto puro no disco, e quando quiser persistir salva um único blob. Esse blob pode ir para o disco cifrado e aí ninguém lê o banco sem a chave.

código fonte completo

Cesar Gimenes

Última modificação
Tags: