This commit is contained in:
2026-06-13 22:43:17 +00:00
parent 1d1fdb1f0b
commit 685c48f94f
28 changed files with 2492 additions and 2657 deletions

View File

@@ -6,39 +6,30 @@ import (
"log"
"net"
"os"
"path/filepath"
"sync"
"time"
"gordenko.dev/dima/qb"
"gordenko.dev/dima/qb/atree"
"gordenko.dev/dima/qb/inbox"
"gordenko.dev/dima/qb/recovery"
"gordenko.dev/dima/qb/storage"
"gordenko.dev/dima/qb/worker"
)
func JoinSnapshotFileName(dir string, snapshotNumber int) string {
return filepath.Join(dir, fmt.Sprintf("%d.snapshot", snapshotNumber))
}
func JoinWALFileName(dir string, snapshotNumber int) string {
return filepath.Join(dir, fmt.Sprintf("%d.wal", snapshotNumber))
}
// type metricLockEntry struct {
// XLock bool
// RLocks int
// WaitQueue []any
// }
//metricLockEntries map[uint32]*metricLockEntry
type Database struct {
mutex sync.Mutex
worker *Worker
//metricLockEntries map[uint32]*metricLockEntry
//dataFreeList *freelist.FreeList
//indexFreeList *freelist.FreeList
mutex sync.Mutex
dir string
databaseName string
workerInbox *inbox.Inbox
worker *worker.Worker
storage *storage.Writer
atree *atree.Atree
tcpPort int
logfile *os.File
logger *log.Logger
@@ -50,7 +41,6 @@ type Options struct {
TCPPort int
Dir string
DatabaseName string
RedoDir string
Logfile *os.File
ExitCh chan struct{}
WaitGroup *sync.WaitGroup
@@ -66,9 +56,6 @@ func New(opt Options) (_ *Database, err error) {
if opt.DatabaseName == "" {
return nil, errors.New("DatabaseName option is required")
}
if opt.RedoDir == "" {
return nil, errors.New("RedoDir option is required")
}
if opt.Logfile == nil {
return nil, errors.New("Logfile option is required")
}
@@ -79,40 +66,7 @@ func New(opt Options) (_ *Database, err error) {
return nil, errors.New("WaitGroup option is required")
}
// deltaFreeListFile, err := os.OpenFile(
// filepath.Join(opt.Dir, opt.DatabaseName+".deltafree"),
// 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"),
// DeltaFilePath: filepath.Join(opt.Dir, opt.DatabaseName+".free_data_delta"),
// })
// indexFreeList, err := freelist.New(freelist.Options{
// PageSize: 2048,
// BaseFilePath: filepath.Join(opt.Dir, opt.DatabaseName+".free_index"),
// DeltaFilePath: filepath.Join(opt.Dir, opt.DatabaseName+".free_index_delta"),
// })
worker := NewWorker(WorkerOptions{
//
Metrics: make(map[uint32]*_metric),
Dir: opt.Dir,
SaveToStorage: func(in any) {
fmt.Println("save to storage")
},
ExitCh: opt.ExitCh,
WaitGroup: opt.WaitGroup,
})
s := &Database{
worker: worker,
dir: opt.Dir,
databaseName: opt.DatabaseName,
//metricLockEntries: make(map[uint32]*metricLockEntry),
@@ -124,6 +78,42 @@ func New(opt Options) (_ *Database, err error) {
exitCh: opt.ExitCh,
waitGroup: opt.WaitGroup,
}
recoveryReport, err := recovery.Recovery(s.dir, s.databaseName)
if err != nil {
return
}
storageInbox := inbox.New()
s.workerInbox = inbox.New()
s.storage, err = storage.NewWriter(storage.WriterOptions{
Inbox: storageInbox,
WorkerInbox: s.workerInbox,
Dir: s.dir,
DatabaseName: s.databaseName,
WAL: recoveryReport.WAL,
IndexFreeList: recoveryReport.IndexFreeList,
DataFreeList: recoveryReport.DataFreeList,
ExitCh: s.exitCh,
WaitGroup: s.waitGroup,
})
if err != nil {
qb.Abort(qb.CreateChangesWriterFailed, err)
}
s.worker = worker.NewWorker(worker.WorkerOptions{
Inbox: s.workerInbox,
StorageInbox: storageInbox,
//Metrics: make(map[uint32]*_metric), FIX
Dir: opt.Dir,
// SaveToStorage: func(in any) {
// fmt.Println("save to storage")
// },
ExitCh: opt.ExitCh,
WaitGroup: opt.WaitGroup,
})
return s, nil
}
@@ -133,19 +123,6 @@ func (s *Database) ListenAndServe() (err error) {
return fmt.Errorf("net.Listen: %s; port=%d", err, s.tcpPort)
}
s.storage, err = storage.NewWriter(storage.WriterOptions{
Dir: s.dir,
//LogNumber: logNumber,
AppendToWorkerQueue: s.worker.AddJobToQueue,
//FreeList: s.freeList,
//Atree: s.atree,
ExitCh: s.exitCh,
WaitGroup: s.waitGroup,
})
if err != nil {
qb.Abort(qb.CreateChangesWriterFailed, err)
}
go s.storage.Run()
// s.atree, err = atree.New(atree.Options{
@@ -177,50 +154,14 @@ func (s *Database) ListenAndServe() (err error) {
// зробити object?
func (s *Database) replayChanges(snapshotNumber int) (err error) {
snapshot, err := readSnapshot(JoinSnapshotFileName(s.dir, snapshotNumber))
if err != nil {
return
}
// func (s *Database) replayChanges(snapshotNumber int) (err error) {
// snapshot, err := readSnapshot(JoinSnapshotFileName(s.dir, snapshotNumber))
// if err != nil {
// return
// }
walReader, err := storage.NewWALReader(storage.WALReaderOptions{
FileName: JoinWALFileName(s.dir, snapshotNumber),
BufferSize: 8 * 1024 * 1024,
})
if err != nil {
return err
}
walReplayer, err := NewWALReplayer(WALReplayerOptions{
WALReader: walReader,
Metrics: snapshot.Metrics,
FreeIndexPages: snapshot.IndexPageNumbers,
FreeDataPages: snapshot.DataPageNumbers,
})
if err != nil {
return
}
err = walReplayer.Replay()
if err != nil {
return
}
err = s.storage.WritePagesToAtree(walReplayer.IndexPages(), walReplayer.DataPages())
if err != nil {
return err
}
// FIX free pages sync
return nil
}
func (s *Database) relayMetricsToMetrics(replayMetrics map[uint32]*ReplayMetric) {
//for metricID, x := range replayMetrics {
//s.metrics[metricID] = x.ToMetric() FIX
//}
}
// return nil
// }
//func (s *Database) verifySnapshot(fileName string) (_ bool, err error) {
// file, err := os.Open(fileName)