Add recovery logging
This commit is contained in:
40
db.go
40
db.go
@@ -58,6 +58,11 @@ func (db *DB) Path() string {
|
||||
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.
|
||||
func (db *DB) WALPath() string {
|
||||
return filepath.Join(db.fs.TargetPath, db.path+"-wal")
|
||||
@@ -101,28 +106,34 @@ func (db *DB) Open() (err error) {
|
||||
return err
|
||||
}
|
||||
db.logger = log.New(db.logFile, "", log.LstdFlags)
|
||||
|
||||
db.logger.Printf("open: %s", db.path)
|
||||
db.logger.Printf("opening: path=%s", db.path)
|
||||
|
||||
// If database file exists, read & set the header.
|
||||
if err := db.readHeader(); os.IsNotExist(err) {
|
||||
db.logger.Printf("opening: db not found")
|
||||
db.setHeader(nil) // invalidate header for missing file
|
||||
} else if err != nil {
|
||||
db.logger.Printf("opening: cannot read db header: %s", err)
|
||||
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 db.isWALEnabled {
|
||||
if err := db.recoverWAL(); err != nil {
|
||||
if err := db.recover(); err != nil {
|
||||
return fmt.Errorf("recover wal: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
db.logger.Printf("open: %s", db.path)
|
||||
|
||||
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.
|
||||
// We need to sync up between the two.
|
||||
hasShadowWAL, err := db.shadowWALExists()
|
||||
@@ -134,13 +145,6 @@ func (db *DB) recoverWAL() error {
|
||||
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 hasShadowWAL {
|
||||
return db.recoverRealAndShadowWALs()
|
||||
@@ -151,11 +155,15 @@ func (db *DB) recoverWAL() error {
|
||||
if hasShadowWAL {
|
||||
return db.recoverShadowWALOnly()
|
||||
}
|
||||
|
||||
db.logger.Printf("recovering: no WALs available, skipping")
|
||||
return nil // no-op, wait for first WAL write
|
||||
}
|
||||
|
||||
// recoverRealWALOnly copies the real WAL to the active shadow WAL.
|
||||
func (db *DB) recoverRealWALOnly() error {
|
||||
db.logger.Printf("recovering: real WAL only")
|
||||
|
||||
// Open real WAL to read from.
|
||||
r, err := os.Open(db.WALPath())
|
||||
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
|
||||
// contents of the database page.
|
||||
func (db *DB) recoverShadowWALOnly() error {
|
||||
db.logger.Printf("recovering: shadow WAL only")
|
||||
panic("TODO")
|
||||
}
|
||||
|
||||
// recoverRealAndShadowWALs verifies the last page of the real & shadow WALs match.
|
||||
func (db *DB) recoverRealAndShadowWALs() error {
|
||||
db.logger.Printf("recovering: real & shadow WAL")
|
||||
panic("TODO")
|
||||
}
|
||||
|
||||
@@ -281,7 +291,7 @@ func (db *DB) Close() (err error) {
|
||||
|
||||
// readHeader reads the SQLite header and sets the initial DB flags.
|
||||
func (db *DB) readHeader() error {
|
||||
f, err := os.Open(db.path)
|
||||
f, err := os.Open(db.AbsPath())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -74,7 +74,6 @@ func (f *FileSystem) DB(path string) *DB {
|
||||
f.mu.RLock()
|
||||
defer f.mu.RUnlock()
|
||||
db := f.dbs[path]
|
||||
println("dbg/fs.db?", path, db != nil)
|
||||
return db
|
||||
}
|
||||
|
||||
|
||||
8
node.go
8
node.go
@@ -59,7 +59,6 @@ func (n *Node) srcpath() string {
|
||||
// DB returns the DB object associated with the node, if any.
|
||||
// If node points to a "-wal" file then the associated DB is returned.
|
||||
func (n *Node) DB() *DB {
|
||||
println("dbg/node.db", n.path, n.fs != nil, n.path == "")
|
||||
if strings.HasPrefix(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 "..".
|
||||
func (n *Node) Lookup(ctx context.Context, name string) (_ fs.Node, err error) {
|
||||
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)
|
||||
if _, err := os.Stat(srcpath); os.IsNotExist(err) {
|
||||
return nil, syscall.ENOENT
|
||||
@@ -293,7 +286,6 @@ func (n *Node) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenR
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
println("dbg/open")
|
||||
return NewHandle(n, f), nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user