Add recovery logging

This commit is contained in:
Ben Johnson
2020-11-10 12:10:46 -07:00
parent 2941a2433f
commit b9e9bd93e8
3 changed files with 26 additions and 25 deletions

42
db.go
View File

@@ -58,6 +58,11 @@ func (db *DB) Path() string {
return db.path return db.path
} }
// AbsPath returns the full path to the database.
func (db *DB) AbsPath() string {
return filepath.Join(db.fs.TargetPath, db.path)
}
// WALPath returns the full path to the real WAL. // WALPath returns the full path to the real WAL.
func (db *DB) WALPath() string { func (db *DB) WALPath() string {
return filepath.Join(db.fs.TargetPath, db.path+"-wal") return filepath.Join(db.fs.TargetPath, db.path+"-wal")
@@ -101,28 +106,34 @@ func (db *DB) Open() (err error) {
return err return err
} }
db.logger = log.New(db.logFile, "", log.LstdFlags) db.logger = log.New(db.logFile, "", log.LstdFlags)
db.logger.Printf("opening: path=%s", db.path)
db.logger.Printf("open: %s", db.path)
// If database file exists, read & set the header. // If database file exists, read & set the header.
if err := db.readHeader(); os.IsNotExist(err) { if err := db.readHeader(); os.IsNotExist(err) {
db.logger.Printf("opening: db not found")
db.setHeader(nil) // invalidate header for missing file db.setHeader(nil) // invalidate header for missing file
} else if err != nil { } else if err != nil {
db.logger.Printf("opening: cannot read db header: %s", err)
db.setHeader(nil) // invalidate header db.setHeader(nil) // invalidate header
db.logger.Printf("cannot read db header: %s", err)
} }
// If WAL is enabled & WAL file exists, attempt to recover. // If WAL is enabled & WAL file exists, attempt to recover.
if db.isWALEnabled { if err := db.recover(); err != nil {
if err := db.recoverWAL(); err != nil { return fmt.Errorf("recover wal: %w", err)
return fmt.Errorf("recover wal: %w", err)
}
} }
db.logger.Printf("open: %s", db.path)
return nil return nil
} }
func (db *DB) recoverWAL() error { func (db *DB) recover() error {
// Ignore if the DB is invalid.
if !db.valid() {
db.logger.Printf("recovering: invalid db, skipping; valid-header:%v wal-enabled=%v", db.isHeaderValid, db.isWALEnabled)
return nil
}
// Check for the existence of the real & shadow WAL. // Check for the existence of the real & shadow WAL.
// We need to sync up between the two. // We need to sync up between the two.
hasShadowWAL, err := db.shadowWALExists() hasShadowWAL, err := db.shadowWALExists()
@@ -134,13 +145,6 @@ func (db *DB) recoverWAL() error {
return fmt.Errorf("check real wal: %w", err) return fmt.Errorf("check real wal: %w", err)
} }
// Neither the real WAL or shadow WAL exist so no pages have been written
// since the DB's journal mode has been set to "wal". In this case, do
// nothing and wait for the first WAL write to occur.
if !hasShadowWAL && !hasRealWAL {
return nil
}
if hasRealWAL { if hasRealWAL {
if hasShadowWAL { if hasShadowWAL {
return db.recoverRealAndShadowWALs() return db.recoverRealAndShadowWALs()
@@ -151,11 +155,15 @@ func (db *DB) recoverWAL() error {
if hasShadowWAL { if hasShadowWAL {
return db.recoverShadowWALOnly() return db.recoverShadowWALOnly()
} }
db.logger.Printf("recovering: no WALs available, skipping")
return nil // no-op, wait for first WAL write return nil // no-op, wait for first WAL write
} }
// recoverRealWALOnly copies the real WAL to the active shadow WAL. // recoverRealWALOnly copies the real WAL to the active shadow WAL.
func (db *DB) recoverRealWALOnly() error { func (db *DB) recoverRealWALOnly() error {
db.logger.Printf("recovering: real WAL only")
// Open real WAL to read from. // Open real WAL to read from.
r, err := os.Open(db.WALPath()) r, err := os.Open(db.WALPath())
if err != nil { if err != nil {
@@ -259,11 +267,13 @@ func (db *DB) createActiveShadowWAL(hdr sqlite.WALHeader) (f *os.File, err error
// recoverShadowWALOnly verifies the last page in the shadow WAL matches the // recoverShadowWALOnly verifies the last page in the shadow WAL matches the
// contents of the database page. // contents of the database page.
func (db *DB) recoverShadowWALOnly() error { func (db *DB) recoverShadowWALOnly() error {
db.logger.Printf("recovering: shadow WAL only")
panic("TODO") panic("TODO")
} }
// recoverRealAndShadowWALs verifies the last page of the real & shadow WALs match. // recoverRealAndShadowWALs verifies the last page of the real & shadow WALs match.
func (db *DB) recoverRealAndShadowWALs() error { func (db *DB) recoverRealAndShadowWALs() error {
db.logger.Printf("recovering: real & shadow WAL")
panic("TODO") panic("TODO")
} }
@@ -281,7 +291,7 @@ func (db *DB) Close() (err error) {
// readHeader reads the SQLite header and sets the initial DB flags. // readHeader reads the SQLite header and sets the initial DB flags.
func (db *DB) readHeader() error { func (db *DB) readHeader() error {
f, err := os.Open(db.path) f, err := os.Open(db.AbsPath())
if err != nil { if err != nil {
return err return err
} }

View File

@@ -74,7 +74,6 @@ func (f *FileSystem) DB(path string) *DB {
f.mu.RLock() f.mu.RLock()
defer f.mu.RUnlock() defer f.mu.RUnlock()
db := f.dbs[path] db := f.dbs[path]
println("dbg/fs.db?", path, db != nil)
return db return db
} }

View File

@@ -59,7 +59,6 @@ func (n *Node) srcpath() string {
// DB returns the DB object associated with the node, if any. // DB returns the DB object associated with the node, if any.
// If node points to a "-wal" file then the associated DB is returned. // If node points to a "-wal" file then the associated DB is returned.
func (n *Node) DB() *DB { func (n *Node) DB() *DB {
println("dbg/node.db", n.path, n.fs != nil, n.path == "")
if strings.HasPrefix(n.path, sqlite.WALSuffix) { if strings.HasPrefix(n.path, sqlite.WALSuffix) {
return n.fs.DB(strings.TrimSuffix(n.path, sqlite.WALSuffix)) return n.fs.DB(strings.TrimSuffix(n.path, sqlite.WALSuffix))
} }
@@ -103,12 +102,6 @@ func (n *Node) Attr(ctx context.Context, a *fuse.Attr) (err error) {
// Lookup need not to handle the names "." and "..". // Lookup need not to handle the names "." and "..".
func (n *Node) Lookup(ctx context.Context, name string) (_ fs.Node, err error) { func (n *Node) Lookup(ctx context.Context, name string) (_ fs.Node, err error) {
path := filepath.Join(n.path, name) path := filepath.Join(n.path, name)
// Meta directories should not be visible.
if IsMetaDir(path) {
return nil, syscall.ENOENT
}
srcpath := filepath.Join(n.fs.TargetPath, path) srcpath := filepath.Join(n.fs.TargetPath, path)
if _, err := os.Stat(srcpath); os.IsNotExist(err) { if _, err := os.Stat(srcpath); os.IsNotExist(err) {
return nil, syscall.ENOENT return nil, syscall.ENOENT
@@ -293,7 +286,6 @@ func (n *Node) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenR
if err != nil { if err != nil {
return nil, err return nil, err
} }
println("dbg/open")
return NewHandle(n, f), nil return NewHandle(n, f), nil
} }