This commit is contained in:
2026-05-31 20:01:28 +00:00
parent e7ec6083cb
commit db5ecd3dfd
28 changed files with 2090 additions and 2155 deletions

View File

@@ -12,11 +12,9 @@ import (
"sync"
"time"
"gordenko.dev/dima/qb"
"gordenko.dev/dima/qb/atree"
"gordenko.dev/dima/qb/bin"
"gordenko.dev/dima/qb/freelist"
"gordenko.dev/dima/qb/recovery"
"gordenko.dev/dima/qb/txlog"
)
@@ -24,11 +22,11 @@ func JoinSnapshotFileName(dir string, logNumber int) string {
return filepath.Join(dir, fmt.Sprintf("%d.snapshot", logNumber))
}
type metricLockEntry struct {
XLock bool
RLocks int
WaitQueue []any
}
// type metricLockEntry struct {
// XLock bool
// RLocks int
// WaitQueue []any
// }
type Database struct {
mutex sync.Mutex
@@ -37,16 +35,17 @@ type Database struct {
rLocksToRelease []uint32
metrics map[uint32]*_metric
//metricLockEntries map[uint32]*metricLockEntry
freeList *freelist.FreeList
dir string
databaseName string
txlog *txlog.Writer
atree *atree.Atree
tcpPort int
logfile *os.File
logger *log.Logger
exitCh chan struct{}
waitGroup *sync.WaitGroup
dataFreeList *freelist.FreeList
indexFreeList *freelist.FreeList
dir string
databaseName string
txlog *txlog.Writer
atree *atree.Atree
tcpPort int
logfile *os.File
logger *log.Logger
exitCh chan struct{}
waitGroup *sync.WaitGroup
}
type Options struct {
@@ -82,16 +81,25 @@ func New(opt Options) (_ *Database, err error) {
return nil, errors.New("WaitGroup option is required")
}
filePath := filepath.Join(opt.Dir, opt.DatabaseName+".free")
// deltaFreeListFile, err := os.OpenFile(
// filepath.Join(opt.Dir, opt.DatabaseName+".deltafree"),
// os.O_RDWR|os.O_CREATE,
// 0666,
// )
// if err != nil {
// return nil, err
// }
freeListFile, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0666)
if err != nil {
return nil, err
}
dataFreeList, err := freelist.New(freelist.Options{
PageSize: 2048,
BaseFilePath: filepath.Join(opt.Dir, opt.DatabaseName+".free_data_base"),
DeltaFilePath: filepath.Join(opt.Dir, opt.DatabaseName+".free_data_delta"),
})
freeList, err := freelist.New(freelist.Options{
PageSize: 2048,
File: freeListFile,
indexFreeList, err := freelist.New(freelist.Options{
PageSize: 2048,
BaseFilePath: filepath.Join(opt.Dir, opt.DatabaseName+".free_index_base"),
DeltaFilePath: filepath.Join(opt.Dir, opt.DatabaseName+".free_index_delta"),
})
s := &Database{
@@ -100,12 +108,13 @@ func New(opt Options) (_ *Database, err error) {
databaseName: opt.DatabaseName,
metrics: make(map[uint32]*_metric),
//metricLockEntries: make(map[uint32]*metricLockEntry),
freeList: freeList,
tcpPort: opt.TCPPort,
logfile: opt.Logfile,
logger: log.New(opt.Logfile, "", log.LstdFlags),
exitCh: opt.ExitCh,
waitGroup: opt.WaitGroup,
dataFreeList: dataFreeList,
indexFreeList: indexFreeList,
tcpPort: opt.TCPPort,
logfile: opt.Logfile,
logger: log.New(opt.Logfile, "", log.LstdFlags),
exitCh: opt.ExitCh,
waitGroup: opt.WaitGroup,
}
return s, nil
}
@@ -143,88 +152,89 @@ func (s *Database) ListenAndServe() (err error) {
}
func (s *Database) recovery() {
advisor, err := recovery.NewRecoveryAdvisor(recovery.RecoveryAdvisorOptions{
Dir: s.dir,
VerifySnapshot: s.verifySnapshot,
})
if err != nil {
panic(err)
}
recipe, err := advisor.GetRecipe()
if err != nil {
qb.Abort(qb.GetRecoveryRecipeFailed, err)
}
var logNumber int
if recipe != nil {
if recipe.Snapshot != "" {
err = s.loadSnapshot(recipe.Snapshot)
if err != nil {
qb.Abort(qb.LoadSnapshotFailed, err)
}
}
for _, changesFileName := range recipe.Changes {
err = s.replayChanges(changesFileName)
if err != nil {
qb.Abort(qb.ReplayChangesFailed, err)
}
}
logNumber = recipe.LogNumber
}
s.txlog, err = txlog.NewWriter(txlog.WriterOptions{
Dir: s.dir,
LogNumber: logNumber,
AppendToWorkerQueue: s.appendJobToWorkerQueue,
FreeList: s.freeList,
Atree: s.atree,
ExitCh: s.exitCh,
WaitGroup: s.waitGroup,
})
if err != nil {
qb.Abort(qb.CreateChangesWriterFailed, err)
}
go s.txlog.Run()
// fileNames, err := s.searchREDOFiles()
// FIX
// advisor, err := recovery.NewRecoveryAdvisor(recovery.RecoveryAdvisorOptions{
// Dir: s.dir,
// VerifySnapshot: s.verifySnapshot,
// })
// if err != nil {
// qb.Abort(qb.SearchREDOFilesFailed, err)
// panic(err)
// }
// if len(fileNames) > 0 {
// for _, fileName := range fileNames {
// err = s.replayREDOFile(fileName)
// recipe, err := advisor.GetRecipe()
// if err != nil {
// qb.Abort(qb.GetRecoveryRecipeFailed, err)
// }
// var logNumber int
// if recipe != nil {
// if recipe.Snapshot != "" {
// err = s.loadSnapshot(recipe.Snapshot)
// if err != nil {
// qb.Abort(qb.ReplayREDOFileFailed, err)
// qb.Abort(qb.LoadSnapshotFailed, err)
// }
// }
// for _, changesFileName := range recipe.Changes {
// err = s.replayChanges(changesFileName)
// if err != nil {
// qb.Abort(qb.ReplayChangesFailed, err)
// }
// }
// logNumber = recipe.LogNumber
// }
// s.txlog, err = txlog.NewWriter(txlog.WriterOptions{
// Dir: s.dir,
// LogNumber: logNumber,
// AppendToWorkerQueue: s.appendJobToWorkerQueue,
// FreeList: s.freeList,
// Atree: s.atree,
// ExitCh: s.exitCh,
// WaitGroup: s.waitGroup,
// })
// if err != nil {
// qb.Abort(qb.CreateChangesWriterFailed, err)
// }
// go s.txlog.Run()
// // fileNames, err := s.searchREDOFiles()
// // if err != nil {
// // qb.Abort(qb.SearchREDOFilesFailed, err)
// // }
// // if len(fileNames) > 0 {
// // for _, fileName := range fileNames {
// // err = s.replayREDOFile(fileName)
// // if err != nil {
// // qb.Abort(qb.ReplayREDOFileFailed, err)
// // }
// // }
// // for _, fileName := range fileNames {
// // err = os.Remove(fileName)
// // if err != nil {
// // qb.Abort(qb.RemoveREDOFileFailed, err)
// // }
// // }
// // }
// if recipe != nil {
// if recipe.CompleteSnapshot {
// err = s.dumpSnapshot(logNumber)
// if err != nil {
// qb.Abort(qb.DumpSnapshotFailed, err)
// }
// }
// for _, fileName := range fileNames {
// for _, fileName := range recipe.ToDelete {
// err = os.Remove(fileName)
// if err != nil {
// qb.Abort(qb.RemoveREDOFileFailed, err)
// qb.Abort(qb.RemoveRecipeFileFailed, err)
// }
// }
// }
if recipe != nil {
if recipe.CompleteSnapshot {
err = s.dumpSnapshot(logNumber)
if err != nil {
qb.Abort(qb.DumpSnapshotFailed, err)
}
}
for _, fileName := range recipe.ToDelete {
err = os.Remove(fileName)
if err != nil {
qb.Abort(qb.RemoveRecipeFileFailed, err)
}
}
}
}
// func (s *Database) searchREDOFiles() ([]string, error) {