skills/litestream/references/PATTERNS.md
Condensed code patterns and anti-patterns for agents writing Litestream code.
DB Layer (db.go) → Database state, restoration, monitoring
Replica Layer (replica.go) → Replication mechanics only
Storage Layer → ReplicaClient implementations
func (db *DB) init() error {
if db.needsRestore() {
if err := db.restore(); err != nil {
return err
}
}
return db.replica.Start() // Replica focuses only on replication
}
// WRONG
func (r *Replica) Start() error {
if needsRestore() { // Wrong layer!
restoreDatabase()
}
}
func writeFileAtomic(path string, data []byte) error {
dir := filepath.Dir(path)
tmpFile, err := os.CreateTemp(dir, ".tmp-*")
if err != nil {
return fmt.Errorf("create temp file: %w", err)
}
tmpPath := tmpFile.Name()
defer func() {
if tmpFile != nil {
tmpFile.Close()
os.Remove(tmpPath)
}
}()
if _, err := tmpFile.Write(data); err != nil {
return fmt.Errorf("write temp file: %w", err)
}
if err := tmpFile.Sync(); err != nil {
return fmt.Errorf("sync temp file: %w", err)
}
if err := tmpFile.Close(); err != nil {
return fmt.Errorf("close temp file: %w", err)
}
tmpFile = nil
if err := os.Rename(tmpPath, path); err != nil {
os.Remove(tmpPath)
return fmt.Errorf("rename to final path: %w", err)
}
return nil
}
// WRONG - Can leave partial files on failure
os.WriteFile(path, data, 0644)
func (db *DB) validatePosition() error {
dpos, err := db.Pos()
if err != nil {
return err
}
rpos := replica.Pos()
if dpos.TXID < rpos.TXID {
return fmt.Errorf("database position (%v) behind replica (%v)", dpos, rpos)
}
return nil
}
// WRONG
if err := processFile(file); err != nil {
log.Printf("error: %v", err) // Just logging!
// Continuing is dangerous
}
func (db *DB) processFiles() error {
for _, file := range files {
if err := processFile(file); err != nil {
return fmt.Errorf("process file %s: %w", file, err)
}
}
return nil
}
r.mu.Lock()
defer r.mu.Unlock()
r.pos = pos
// WRONG - Race condition
r.mu.RLock()
defer r.mu.RUnlock()
r.pos = pos // Writing with RLock!
Always acquire in order: Store.mu → DB.mu → DB.chkMu → Replica.mu
f, err := os.Open(db.LTXPath(info.Level, info.MinTXID, info.MaxTXID))
if err == nil {
return f, nil // Local copy is complete and consistent
}
return replica.Client.OpenLTXFile(...) // Fall back to remote
// WRONG - Can get partial/corrupt data from eventually consistent storage
f, err := client.OpenLTXFile(ctx, level, minTXID, maxTXID, 0, 0)
info.CreatedAt = oldestSourceFile.CreatedAt
// WRONG - Loses timestamp granularity for point-in-time restores
info := <x.FileInfo{CreatedAt: time.Now()}
The lock page at 1 GB (0x40000000) must always be skipped:
lockPgno := ltx.LockPgno(pageSize)
if pgno == lockPgno {
continue
}
| Page Size | Lock Page Number |
|---|---|
| 4 KB | 262145 |
| 8 KB | 131073 |
| 16 KB | 65537 |
| 32 KB | 32769 |
db.verify() for snapshotsos.ErrNotExist for missing filesLTXFilesctx.Done() in long operations