mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-09-15 21:00:27 +00:00
Fix bbolt recover
This commit is contained in:
@@ -53,7 +53,7 @@ type CacheFile struct {
|
|||||||
rdrcTimeout time.Duration
|
rdrcTimeout time.Duration
|
||||||
optimisticTimeout time.Duration
|
optimisticTimeout time.Duration
|
||||||
DB *bbolt.DB
|
DB *bbolt.DB
|
||||||
resetAccess sync.Mutex
|
dbAccess sync.RWMutex
|
||||||
saveMetadataAccess sync.Mutex
|
saveMetadataAccess sync.Mutex
|
||||||
saveMetadata *adapter.FakeIPMetadata
|
saveMetadata *adapter.FakeIPMetadata
|
||||||
saveMetadataTimer *time.Timer
|
saveMetadataTimer *time.Timer
|
||||||
@@ -180,19 +180,29 @@ func (c *CacheFile) start() error {
|
|||||||
var db *bbolt.DB
|
var db *bbolt.DB
|
||||||
for range 10 {
|
for range 10 {
|
||||||
db, err = bbolt.Open(c.path, fileMode, &options)
|
db, err = bbolt.Open(c.path, fileMode, &options)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, bboltErrors.ErrTimeout) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if E.IsMulti(err, bboltErrors.ErrInvalid, bboltErrors.ErrChecksum, bboltErrors.ErrVersionMismatch) {
|
||||||
|
rmErr := filemanager.Remove(c.ctx, c.path)
|
||||||
|
if rmErr != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err = checkDatabase(db)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if errors.Is(err, bboltErrors.ErrTimeout) {
|
c.logger.Error("database corrupted: ", err, ": resetting")
|
||||||
continue
|
db.Close()
|
||||||
|
rmErr := filemanager.Remove(c.ctx, c.path)
|
||||||
|
if rmErr != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
if E.IsMulti(err, bboltErrors.ErrInvalid, bboltErrors.ErrChecksum, bboltErrors.ErrVersionMismatch) {
|
|
||||||
rmErr := filemanager.Remove(c.ctx, c.path)
|
|
||||||
if rmErr != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -230,46 +240,83 @@ func (c *CacheFile) start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *CacheFile) Close() error {
|
func (c *CacheFile) Close() error {
|
||||||
if c.DB == nil {
|
c.dbAccess.RLock()
|
||||||
|
db := c.DB
|
||||||
|
c.dbAccess.RUnlock()
|
||||||
|
if db == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return c.DB.Close()
|
return db.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkDatabase(db *bbolt.DB) error {
|
||||||
|
return db.View(func(tx *bbolt.Tx) error {
|
||||||
|
var checkErr error
|
||||||
|
for txErr := range tx.Check() {
|
||||||
|
if checkErr == nil {
|
||||||
|
checkErr = txErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return checkErr
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CacheFile) database() *bbolt.DB {
|
||||||
|
c.dbAccess.RLock()
|
||||||
|
defer c.dbAccess.RUnlock()
|
||||||
|
return c.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CacheFile) view(fn func(tx *bbolt.Tx) error) (err error) {
|
func (c *CacheFile) view(fn func(tx *bbolt.Tx) error) (err error) {
|
||||||
|
db := c.database()
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
r := recover()
|
||||||
c.resetDB()
|
if r != nil {
|
||||||
|
c.resetDB(db, r)
|
||||||
err = E.New("database corrupted: ", r)
|
err = E.New("database corrupted: ", r)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return c.DB.View(fn)
|
return db.View(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CacheFile) batch(fn func(tx *bbolt.Tx) error) (err error) {
|
func (c *CacheFile) batch(fn func(tx *bbolt.Tx) error) (err error) {
|
||||||
|
db := c.database()
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
r := recover()
|
||||||
c.resetDB()
|
if r != nil {
|
||||||
|
c.resetDB(db, r)
|
||||||
err = E.New("database corrupted: ", r)
|
err = E.New("database corrupted: ", r)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return c.DB.Batch(fn)
|
err = db.Batch(fn)
|
||||||
|
var panicErr bbolt.PanickedError
|
||||||
|
if errors.As(err, &panicErr) {
|
||||||
|
c.resetDB(db, panicErr.Reason)
|
||||||
|
return E.New("database corrupted: ", panicErr.Reason)
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CacheFile) update(fn func(tx *bbolt.Tx) error) (err error) {
|
func (c *CacheFile) update(fn func(tx *bbolt.Tx) error) (err error) {
|
||||||
|
db := c.database()
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
r := recover()
|
||||||
c.resetDB()
|
if r != nil {
|
||||||
|
c.resetDB(db, r)
|
||||||
err = E.New("database corrupted: ", r)
|
err = E.New("database corrupted: ", r)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return c.DB.Update(fn)
|
return db.Update(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CacheFile) resetDB() {
|
func (c *CacheFile) resetDB(failedDB *bbolt.DB, reason any) {
|
||||||
c.resetAccess.Lock()
|
c.dbAccess.Lock()
|
||||||
defer c.resetAccess.Unlock()
|
defer c.dbAccess.Unlock()
|
||||||
c.DB.Close()
|
if c.DB != failedDB {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.logger.Error("database corrupted: ", reason, ": resetting")
|
||||||
|
failedDB.Close()
|
||||||
filemanager.Remove(c.ctx, c.path)
|
filemanager.Remove(c.ctx, c.path)
|
||||||
db, err := bbolt.Open(c.path, 0o666, &bbolt.Options{Timeout: time.Second})
|
db, err := bbolt.Open(c.path, 0o666, &bbolt.Options{Timeout: time.Second})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ require (
|
|||||||
github.com/oschwald/maxminddb-golang v1.13.1
|
github.com/oschwald/maxminddb-golang v1.13.1
|
||||||
github.com/pkg/sftp v1.13.10
|
github.com/pkg/sftp v1.13.10
|
||||||
github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1
|
github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1
|
||||||
github.com/sagernet/bbolt v0.0.0-20260821040940-d7518b45c52b
|
github.com/sagernet/bbolt v0.0.0-20260823094646-e24805439c9c
|
||||||
github.com/sagernet/cors v1.2.1
|
github.com/sagernet/cors v1.2.1
|
||||||
github.com/sagernet/cronet-go v0.0.0-20260807162344-ec9a39c5ba3b
|
github.com/sagernet/cronet-go v0.0.0-20260807162344-ec9a39c5ba3b
|
||||||
github.com/sagernet/cronet-go/all v0.0.0-20260807162344-ec9a39c5ba3b
|
github.com/sagernet/cronet-go/all v0.0.0-20260807162344-ec9a39c5ba3b
|
||||||
|
|||||||
@@ -238,8 +238,8 @@ github.com/safchain/ethtool v0.3.0 h1:gimQJpsI6sc1yIqP/y8GYgiXn/NjgvpM0RNoWLVVmP
|
|||||||
github.com/safchain/ethtool v0.3.0/go.mod h1:SA9BwrgyAqNo7M+uaL6IYbxpm5wk3L7Mm6ocLW+CJUs=
|
github.com/safchain/ethtool v0.3.0/go.mod h1:SA9BwrgyAqNo7M+uaL6IYbxpm5wk3L7Mm6ocLW+CJUs=
|
||||||
github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1 h1:qi+ijeREa0yfAaO+NOcZ81gv4uzOfALUIdhkiIFvmG4=
|
github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1 h1:qi+ijeREa0yfAaO+NOcZ81gv4uzOfALUIdhkiIFvmG4=
|
||||||
github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1/go.mod h1:JULDuzTMn2gyZFcjpTVZP4/UuwAdbHJ0bum2RdjXojU=
|
github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1/go.mod h1:JULDuzTMn2gyZFcjpTVZP4/UuwAdbHJ0bum2RdjXojU=
|
||||||
github.com/sagernet/bbolt v0.0.0-20260821040940-d7518b45c52b h1:gjt/KuFojUO9PXzkWCpkIx/3Kd1VyJ/iR2PwS7gx8js=
|
github.com/sagernet/bbolt v0.0.0-20260823094646-e24805439c9c h1:JdEDkgiwsDxiZb4+dQYgVOU/lND+jZxFmN5y/q49EXk=
|
||||||
github.com/sagernet/bbolt v0.0.0-20260821040940-d7518b45c52b/go.mod h1:7/qFPFH5fqK5XQeY8EA1Qpaly08Av77p38Zt50ieQww=
|
github.com/sagernet/bbolt v0.0.0-20260823094646-e24805439c9c/go.mod h1:7/qFPFH5fqK5XQeY8EA1Qpaly08Av77p38Zt50ieQww=
|
||||||
github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ=
|
github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ=
|
||||||
github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI=
|
github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI=
|
||||||
github.com/sagernet/cronet-go v0.0.0-20260807162344-ec9a39c5ba3b h1:SfX10lRxbq9ixHm4OZ4/7q+TSpK4Gh0lEVrPaIAB/K0=
|
github.com/sagernet/cronet-go v0.0.0-20260807162344-ec9a39c5ba3b h1:SfX10lRxbq9ixHm4OZ4/7q+TSpK4Gh0lEVrPaIAB/K0=
|
||||||
|
|||||||
Reference in New Issue
Block a user