wp
This commit is contained in:
@@ -6,13 +6,13 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
|
||||
qb "gordenko.dev/dima/qb"
|
||||
bin "gordenko.dev/dima/bin/little"
|
||||
"gordenko.dev/dima/qb"
|
||||
"gordenko.dev/dima/qb/atree"
|
||||
"gordenko.dev/dima/qb/bin"
|
||||
"gordenko.dev/dima/qb/bufreader"
|
||||
"gordenko.dev/dima/qb/proto"
|
||||
"gordenko.dev/dima/qb/storage"
|
||||
"gordenko.dev/dima/qb/transform"
|
||||
"gordenko.dev/dima/qb/txlog"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -213,7 +213,7 @@ func (s *Database) AddMetric(req proto.AddMetricReq) uint16 {
|
||||
|
||||
switch resultCode {
|
||||
case Succeed:
|
||||
s.txlog.Append(txlog.AddedMetric{
|
||||
s.storage.Append(storage.MetricAddRecord{
|
||||
MetricID: req.MetricID,
|
||||
MetricType: req.MetricType,
|
||||
FracDigits: req.FracDigits,
|
||||
@@ -286,20 +286,20 @@ func (s *Database) DeleteMetric(req proto.DeleteMetricReq) uint16 {
|
||||
|
||||
switch result.ResultCode {
|
||||
case Succeed:
|
||||
var (
|
||||
freePageNumbers []uint32
|
||||
)
|
||||
if result.RootPageNo > 0 {
|
||||
var err error
|
||||
freePageNumbers, err = s.atree.GetAllPages(result.RootPageNo)
|
||||
if err != nil {
|
||||
qb.Abort(qb.FailedAtreeRequest, err)
|
||||
}
|
||||
}
|
||||
s.txlog.Append(txlog.DeletedMetric{
|
||||
MetricID: req.MetricID,
|
||||
FreePageNumbers: freePageNumbers,
|
||||
})
|
||||
// var (
|
||||
// //freePageNumbers []uint32
|
||||
// )
|
||||
// if result.RootPageNo > 0 {
|
||||
// var err error
|
||||
// freePageNumbers, err = s.atree.GetAllPages(result.RootPageNo)
|
||||
// if err != nil {
|
||||
// qb.Abort(qb.FailedAtreeRequest, err)
|
||||
// }
|
||||
// }
|
||||
// s.storage.Append(storage.DeletedMetric{
|
||||
// MetricID: req.MetricID,
|
||||
// //FreePageNumbers: freePageNumbers, FIX
|
||||
// })
|
||||
//<-waitCh
|
||||
|
||||
case NoMetric:
|
||||
@@ -343,7 +343,7 @@ type FilledPage struct {
|
||||
|
||||
// switch result.ResultCode {
|
||||
// case CanAppend:
|
||||
// waitCh := s.txlog.Append(txlog.AppendedMeasure{
|
||||
// waitCh := s.storage.Append(storage.AppendedMeasure{
|
||||
// MetricID: req.MetricID,
|
||||
// Timestamp: req.Timestamp,
|
||||
// Value: req.Value,
|
||||
@@ -390,9 +390,9 @@ type FilledPage struct {
|
||||
// // }
|
||||
// // _ = report
|
||||
|
||||
// //waitCh := s.txlog.WriteAppended(path, report)
|
||||
// //waitCh := s.storage.WriteAppended(path, report)
|
||||
|
||||
// waitCh := s.txlog.Append(txlog.AppendedPagesReq{
|
||||
// waitCh := s.storage.Append(storage.AppendedPagesReq{
|
||||
// Legs: path.Legs,
|
||||
// MetricID: req.MetricID,
|
||||
// Timestamp: req.Timestamp,
|
||||
@@ -459,8 +459,8 @@ func (s *Database) AppendMeasures(req proto.AppendMeasuresReq) uint16 {
|
||||
// _ = report
|
||||
|
||||
// if len(toAppendMeasures) > 0 {
|
||||
// waitCh := s.txlog.WriteAppendMeasures(
|
||||
// txlog.AppendedMeasures{
|
||||
// waitCh := s.storage.WriteAppendMeasures(
|
||||
// storage.AppendedMeasures{
|
||||
// MetricID: req.MetricID,
|
||||
// Measures: toAppendMeasures,
|
||||
// },
|
||||
@@ -500,7 +500,7 @@ func (s *Database) DeleteMeasures(req proto.DeleteMeasuresReq) uint16 {
|
||||
|
||||
case DeleteFromAtreeNotNeeded:
|
||||
// регистрирую удаление в TransactionLog
|
||||
s.txlog.Append(txlog.DeletedMeasures{
|
||||
s.storage.Append(storage.DeletedMeasures{
|
||||
MetricID: req.MetricID,
|
||||
})
|
||||
//<-waitCh
|
||||
@@ -512,7 +512,7 @@ func (s *Database) DeleteMeasures(req proto.DeleteMeasuresReq) uint16 {
|
||||
qb.Abort(qb.FailedAtreeRequest, err)
|
||||
}
|
||||
// регистрирую удаление в TransactionLog
|
||||
s.txlog.Append(txlog.DeletedMeasures{
|
||||
s.storage.Append(storage.DeletedMeasures{
|
||||
MetricID: req.MetricID,
|
||||
FreePageNumbers: pageNumbers,
|
||||
})
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
"gordenko.dev/dima/qb/atree"
|
||||
"gordenko.dev/dima/qb/freelist"
|
||||
"gordenko.dev/dima/qb/txlog"
|
||||
"gordenko.dev/dima/qb/storage"
|
||||
)
|
||||
|
||||
func JoinSnapshotFileName(dir string, snapshotNumber int) string {
|
||||
@@ -41,7 +41,7 @@ type Database struct {
|
||||
dir string
|
||||
databaseName string
|
||||
snapshotNumber int
|
||||
txlog *txlog.Writer
|
||||
storage *storage.Writer
|
||||
atree *atree.Atree
|
||||
tcpPort int
|
||||
logfile *os.File
|
||||
@@ -186,7 +186,7 @@ func (s *Database) recovery() {
|
||||
// logNumber = recipe.LogNumber
|
||||
// }
|
||||
|
||||
// s.txlog, err = txlog.NewWriter(txlog.WriterOptions{
|
||||
// s.storage, err = storage.NewWriter(storage.WriterOptions{
|
||||
// Dir: s.dir,
|
||||
// LogNumber: logNumber,
|
||||
// AppendToWorkerQueue: s.appendJobToWorkerQueue,
|
||||
@@ -199,7 +199,7 @@ func (s *Database) recovery() {
|
||||
// qb.Abort(qb.CreateChangesWriterFailed, err)
|
||||
|
||||
// }
|
||||
// go s.txlog.Run()
|
||||
// go s.storage.Run()
|
||||
|
||||
// // fileNames, err := s.searchREDOFiles()
|
||||
// // if err != nil {
|
||||
@@ -249,7 +249,7 @@ func (s *Database) replayChanges(snapshotNumber int) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
walReader, err := txlog.NewReader(txlog.ReaderOptions{
|
||||
walReader, err := storage.NewWALReader(storage.WALReaderOptions{
|
||||
FileName: JoinWALFileName(s.dir, snapshotNumber),
|
||||
BufferSize: 8 * 1024 * 1024,
|
||||
})
|
||||
@@ -271,29 +271,21 @@ func (s *Database) replayChanges(snapshotNumber int) (err error) {
|
||||
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) rewritePagesFromLastWALPacket(list []any) error {
|
||||
// var (
|
||||
// indexPages []txlog.PageToWrite
|
||||
// dataPages []txlog.PageToWrite
|
||||
// )
|
||||
// for _, untyped := range list {
|
||||
// switch rec := untyped.(type) {
|
||||
// case txlog.WALRecordAppendMeasures:
|
||||
// metric, ok := s.metrics[rec.MetricID]
|
||||
// if !ok {
|
||||
// qb.Abort(qb.MetricNotFoundDuringReplay, nil)
|
||||
// }
|
||||
// //metric.ReplayAppendedMeasures(rec)
|
||||
|
||||
// default:
|
||||
// qb.Abort(qb.UnknownTxLogRecordTypeBug,
|
||||
// fmt.Errorf("bug: unknown record type %T in TransactionLog", rec))
|
||||
// }
|
||||
// }
|
||||
return nil
|
||||
func (s *Database) relayMetricsToMetrics(replayMetrics map[uint32]*ReplayMetric) {
|
||||
for metricID, x := range replayMetrics {
|
||||
s.metrics[metricID] = x.ToMetric()
|
||||
}
|
||||
}
|
||||
|
||||
// FIX
|
||||
@@ -314,14 +306,14 @@ func calculateDataBufferSize(payloadSize int) int {
|
||||
return bufferSize
|
||||
}
|
||||
}
|
||||
return atree.DataPageSize
|
||||
return storage.DataPageSize
|
||||
}
|
||||
|
||||
func allocateBuffers(requiredSpace int) (buf, databuf []byte) {
|
||||
bufferSize := calculateDataBufferSize(requiredSpace)
|
||||
buf = make([]byte, bufferSize)
|
||||
if bufferSize == atree.DataPageSize {
|
||||
databuf = buf[:atree.DataPagePayloadSize]
|
||||
if bufferSize == storage.DataPageSize {
|
||||
databuf = buf[:storage.DataPagePayloadSize]
|
||||
} else {
|
||||
databuf = buf
|
||||
}
|
||||
@@ -343,6 +335,20 @@ func growBuffers(in growBuffersIn) (buf, databuf []byte) {
|
||||
return
|
||||
}
|
||||
|
||||
type shrinkBufferIn struct {
|
||||
Buffer []byte
|
||||
TimestampsSize int
|
||||
ValuesSize int
|
||||
NewBufferSize int
|
||||
}
|
||||
|
||||
func shrinkBuffer(in shrinkBufferIn) []byte {
|
||||
buf := make([]byte, in.NewBufferSize)
|
||||
copy(buf, in.Buffer[:in.ValuesSize])
|
||||
copy(buf[:len(buf)-in.TimestampsSize], in.Buffer[len(in.Buffer)-in.TimestampsSize:])
|
||||
return buf
|
||||
}
|
||||
|
||||
//func (s *Database) verifySnapshot(fileName string) (_ bool, err error) {
|
||||
// file, err := os.Open(fileName)
|
||||
// if err != nil {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"gordenko.dev/dima/qb"
|
||||
"gordenko.dev/dima/qb/storage"
|
||||
)
|
||||
|
||||
func TestWriteReadSnapshot(t *testing.T) {
|
||||
@@ -87,3 +88,26 @@ func cmpMetric(replay *ReplayMetric, origin *_metric) error {
|
||||
// }
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestComposeHeadIndexPage(t *testing.T) {
|
||||
var (
|
||||
levelIdx = 0
|
||||
level = storage.IndexLevelTail{
|
||||
Buffer: []byte{
|
||||
1, 2, 3,
|
||||
},
|
||||
RecordsCount: 2,
|
||||
}
|
||||
head = &storage.HeadIndexPage{
|
||||
PageNo: 100,
|
||||
Checksum: 12345,
|
||||
Records: []byte{},
|
||||
}
|
||||
)
|
||||
page := composeHeadIndexPage(levelIdx, level, head)
|
||||
if page.PageNo != head.PageNo {
|
||||
t.Fatalf("PageNo: got %d are not equal expected %v",
|
||||
page.PageNo, head.PageNo)
|
||||
}
|
||||
// fix compare pages
|
||||
}
|
||||
|
||||
@@ -6,17 +6,17 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
diploma "gordenko.dev/dima/qb"
|
||||
"gordenko.dev/dima/qb"
|
||||
"gordenko.dev/dima/qb/proto"
|
||||
)
|
||||
|
||||
func timeBoundsOfAggregation(since, until proto.TimeBound, groupBy diploma.GroupBy, firstHourOfDay int) (s time.Time, u time.Time) {
|
||||
func timeBoundsOfAggregation(since, until proto.TimeBound, groupBy qb.GroupBy, firstHourOfDay int) (s time.Time, u time.Time) {
|
||||
switch groupBy {
|
||||
case diploma.GroupByHour, diploma.GroupByDay:
|
||||
case qb.GroupByHour, qb.GroupByDay:
|
||||
s = time.Date(since.Year, since.Month, since.Day, 0, 0, 0, 0, time.Local)
|
||||
u = time.Date(until.Year, until.Month, until.Day, 0, 0, 0, 0, time.Local)
|
||||
|
||||
case diploma.GroupByMonth:
|
||||
case qb.GroupByMonth:
|
||||
s = time.Date(since.Year, since.Month, 1, 0, 0, 0, 0, time.Local)
|
||||
u = time.Date(until.Year, until.Month, 1, 0, 0, 0, 0, time.Local)
|
||||
}
|
||||
|
||||
@@ -5,8 +5,7 @@ import (
|
||||
|
||||
bin "gordenko.dev/dima/bin/little"
|
||||
"gordenko.dev/dima/qb"
|
||||
"gordenko.dev/dima/qb/atree"
|
||||
"gordenko.dev/dima/qb/txlog"
|
||||
"gordenko.dev/dima/qb/storage"
|
||||
)
|
||||
|
||||
// METRIC
|
||||
@@ -31,7 +30,7 @@ type _metric struct {
|
||||
XLock bool
|
||||
RLocks int
|
||||
WaitQueue []any
|
||||
indexLevelTails []txlog.IndexLevelTail // root - last element
|
||||
indexLevelTails []storage.IndexLevelTail // root - last element
|
||||
}
|
||||
|
||||
//IndexLevels [][]IndexRec // root - last element
|
||||
@@ -60,7 +59,7 @@ func (s *_metric) DeleteMeasures() {
|
||||
// s.UntilValue = 0
|
||||
}
|
||||
|
||||
// func (s *_metric) startAppendMeasures(req tryAppendMeasuresReq, sendToStorage func(txlog.AppendedMeasures)) {
|
||||
// func (s *_metric) startAppendMeasures(req tryAppendMeasuresReq, sendToStorage func(storage.AppendedMeasures)) {
|
||||
func (s *_metric) StartAppendMeasures(req tryAppendMeasuresReq, sendToStorage func(any)) {
|
||||
var (
|
||||
// AppendedMeasures struct {
|
||||
@@ -78,7 +77,7 @@ func (s *_metric) StartAppendMeasures(req tryAppendMeasuresReq, sendToStorage fu
|
||||
timestamps = s.timestamps
|
||||
values = s.values
|
||||
|
||||
dataPages []txlog.DataPayload
|
||||
dataPages []storage.DataPayload
|
||||
|
||||
//written int
|
||||
//resultCode byte
|
||||
@@ -92,7 +91,7 @@ func (s *_metric) StartAppendMeasures(req tryAppendMeasuresReq, sendToStorage fu
|
||||
// s.Since = measure.Timestamp
|
||||
// } else {
|
||||
// FIX - у випадку помилки треба в транзакції зберегти що помилка, але також зафіксувати скільки елементів збережено.
|
||||
// якщо idx == 0 - одразу знімаю блокування і нічого не відправляю в txlog
|
||||
// якщо idx == 0 - одразу знімаю блокування і нічого не відправляю в storage
|
||||
if measure.Timestamp <= s.timestamps.LastTimestamp() {
|
||||
if idx == 0 {
|
||||
s.values.ForgetCapturedState()
|
||||
@@ -136,7 +135,7 @@ func (s *_metric) StartAppendMeasures(req tryAppendMeasuresReq, sendToStorage fu
|
||||
// накопичую
|
||||
timestamps.Compress(timestampCompressionWay, measure.Timestamp)
|
||||
values.Compress(valueCompressionWay, measure.Value)
|
||||
} else if len(s.buffer) < atree.DataPagePayloadSize {
|
||||
} else if len(s.buffer) < storage.DataPagePayloadSize {
|
||||
// allocate bigger buffer
|
||||
buffer := make([]byte, len(s.buffer)*2)
|
||||
// copy timestamps
|
||||
@@ -151,7 +150,7 @@ func (s *_metric) StartAppendMeasures(req tryAppendMeasuresReq, sendToStorage fu
|
||||
// сторінка заповнена
|
||||
since := s.timestamps.ReplaceSinceWithUntil()
|
||||
|
||||
dataPages = append(dataPages, txlog.DataPayload{
|
||||
dataPages = append(dataPages, storage.DataPayload{
|
||||
Since: since,
|
||||
Content: s.buffer,
|
||||
TimestampsSize: timestamps.Size(),
|
||||
@@ -180,8 +179,8 @@ func (s *_metric) StartAppendMeasures(req tryAppendMeasuresReq, sendToStorage fu
|
||||
// скопіювати. Причому можна скопіювати зрізи chunks
|
||||
|
||||
if len(dataPages) > 0 {
|
||||
// пишу в txlog довгим шляхом через redo файл і запис в data файл
|
||||
sendToStorage(txlog.AppendedMeasures{
|
||||
// пишу в storage довгим шляхом через redo файл і запис в data файл
|
||||
sendToStorage(storage.AppendedMeasures{
|
||||
MetricID: req.MetricID,
|
||||
LastPageNo: s.lastPageNo,
|
||||
TimestampsOffset: timestamps.Offset(), // state.Pos() з якої позиції дописувати дані на сторінку 0 (при відновленні)
|
||||
@@ -196,12 +195,12 @@ func (s *_metric) StartAppendMeasures(req tryAppendMeasuresReq, sendToStorage fu
|
||||
ResultCh: nil,
|
||||
})
|
||||
} else {
|
||||
// короткий шлях - запис лише в txlog
|
||||
// короткий шлях - запис лише в storage
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *_metric) FinAppendMeasures(rec txlog.AppendMeasuresSummary) {
|
||||
func (s *_metric) FinAppendMeasures(rec storage.AppendMeasuresSummary) {
|
||||
// Видаляю state. Оригінальні Timestamps і Values вже мають останню версію
|
||||
s.values.ForgetCapturedState()
|
||||
s.timestamps.ForgetCapturedState()
|
||||
@@ -209,7 +208,7 @@ func (s *_metric) FinAppendMeasures(rec txlog.AppendMeasuresSummary) {
|
||||
if rec.LastPageNo > 0 {
|
||||
s.lastPageNo = rec.LastPageNo
|
||||
}
|
||||
// В txlog я передав повний індекс. У нього додали елементи (можливо нові рівні).
|
||||
// В storage я передав повний індекс. У нього додали елементи (можливо нові рівні).
|
||||
// Тому проста заміна
|
||||
s.indexLevelTails = rec.Index
|
||||
}
|
||||
@@ -388,20 +387,6 @@ func (s *_metric) WriteTo(w io.Writer) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// var (
|
||||
// values qb.ValueCompressor
|
||||
// )
|
||||
// if s.metricType == qb.Cumulative {
|
||||
// values = enc.NewCumulativeDeltaCompressor(s.buffer, s.fracDigits)
|
||||
// } else {
|
||||
// values = enc.NewInstantDeltaCompressor(s.buffer, s.fracDigits)
|
||||
// }
|
||||
// values.RestoreState(valuesSize)
|
||||
// s.timestamps = enc.NewTimeDeltaCompressor(s.buffer)
|
||||
// s.timestamps.RestoreState(timestampsSize, until)
|
||||
// s.values = values
|
||||
// s.lastValue = s.values.LastValue()
|
||||
|
||||
// since - 4b
|
||||
// sinceValue - 8b -
|
||||
// untilValue - 8b
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"gordenko.dev/dima/qb/atree"
|
||||
"gordenko.dev/dima/qb/enc"
|
||||
"gordenko.dev/dima/qb/proto"
|
||||
"gordenko.dev/dima/qb/storage"
|
||||
"gordenko.dev/dima/qb/transform"
|
||||
"gordenko.dev/dima/qb/txlog"
|
||||
)
|
||||
|
||||
// AddMetric - create metric in map and set Xlock, rwad - append to queue
|
||||
@@ -83,7 +83,7 @@ func (s *Database) DoWork() {
|
||||
case tryAppendMeasuresReq:
|
||||
s.tryAppendMeasures(req)
|
||||
|
||||
case txlog.Changes:
|
||||
case storage.Changes:
|
||||
s.applyChanges(req) // all metrics only
|
||||
|
||||
case tryListCurrentValuesReq:
|
||||
@@ -132,7 +132,7 @@ func (s *Database) processMetricQueue(metricID uint32, metric *_metric) {
|
||||
s.tryGetMetric(req)
|
||||
|
||||
case tryAppendMeasuresReq:
|
||||
metric.StartAppendMeasures(req, s.txlog.Append)
|
||||
metric.StartAppendMeasures(req, s.storage.Append)
|
||||
|
||||
case tryDeleteMetricReq:
|
||||
s.startDeleteMetric(metric, req)
|
||||
@@ -294,7 +294,7 @@ func (s *Database) startDeleteMeasures(metric *_metric, req tryDeleteMeasuresReq
|
||||
// }
|
||||
}
|
||||
|
||||
func (s *Database) finAppendMeasures(rec txlog.AppendMeasuresSummary) {
|
||||
func (s *Database) finAppendMeasures(rec storage.AppendMeasuresSummary) {
|
||||
metric, ok := s.metrics[rec.MetricID]
|
||||
if !ok {
|
||||
qb.Abort(qb.NoMetricBug,
|
||||
@@ -322,7 +322,7 @@ func (s *Database) tryAppendMeasures(req tryAppendMeasuresReq) {
|
||||
metric.WaitQueue = append(metric.WaitQueue, req)
|
||||
return
|
||||
}
|
||||
metric.StartAppendMeasures(req, s.txlog.Append)
|
||||
metric.StartAppendMeasures(req, s.storage.Append)
|
||||
}
|
||||
|
||||
type tryRangeScanReq struct {
|
||||
@@ -408,25 +408,25 @@ func (s *Database) tryListCurrentValues(req tryListCurrentValuesReq) {
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
func (s *Database) applyChanges(req txlog.Changes) {
|
||||
func (s *Database) applyChanges(req storage.Changes) {
|
||||
for _, untyped := range req.Records {
|
||||
switch rec := untyped.(type) {
|
||||
case txlog.AddedMetric:
|
||||
case storage.MetricAddRecord:
|
||||
s.applyAddMetric(rec)
|
||||
|
||||
case txlog.DeletedMetric:
|
||||
case storage.MetricDeleteRecord:
|
||||
s.deleteMetric(rec)
|
||||
|
||||
// case txlog.AppendedMeasure:
|
||||
// case storage.AppendedMeasure:
|
||||
// s.appendMeasure(rec)
|
||||
|
||||
case txlog.AppendMeasuresSummary:
|
||||
case storage.AppendMeasuresSummary:
|
||||
s.finAppendMeasures(rec)
|
||||
|
||||
// case txlog.AppendedMeasureWithOverflowExtended:
|
||||
// case storage.AppendedMeasureWithOverflowExtended:
|
||||
// s.appendMeasureAfterOverflow(rec)
|
||||
|
||||
case txlog.DeletedMeasures:
|
||||
case storage.DeletedMeasures:
|
||||
s.deleteMeasures(rec)
|
||||
}
|
||||
}
|
||||
@@ -436,7 +436,7 @@ func (s *Database) applyChanges(req txlog.Changes) {
|
||||
err := writeSnapshot(writeSnapshotIn{
|
||||
SnapshotNumber: s.snapshotNumber,
|
||||
Dir: s.dir,
|
||||
WriteBufferSize: 1 * 1024 * 1024, // 1mb
|
||||
WriteBufferSize: 4 * 1024 * 1024, // 1mb
|
||||
Metrics: s.metrics,
|
||||
FrozenIndexPagesCount: req.FrozenIndexPagesCount,
|
||||
IndexPageNumbers: req.IndexPageNumbers,
|
||||
@@ -451,7 +451,7 @@ func (s *Database) applyChanges(req txlog.Changes) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Database) applyAddMetric(rec txlog.AddedMetric) {
|
||||
func (s *Database) applyAddMetric(rec storage.MetricAddRecord) {
|
||||
// fix lock
|
||||
_, ok := s.metrics[rec.MetricID]
|
||||
if ok {
|
||||
@@ -470,28 +470,26 @@ func (s *Database) applyAddMetric(rec txlog.AddedMetric) {
|
||||
// delete(s.metricLockEntries, rec.MetricID)
|
||||
}
|
||||
|
||||
func (s *Database) addMetric(rec txlog.AddedMetric) {
|
||||
func (s *Database) addMetric(rec storage.MetricAddRecord) {
|
||||
var (
|
||||
values qb.ValueCompressor
|
||||
buffer = make([]byte, minBufferSize)
|
||||
)
|
||||
|
||||
if rec.MetricType == qb.Cumulative {
|
||||
values = enc.NewCumulativeDeltaCompressor(buffer, byte(rec.FracDigits))
|
||||
values = enc.NewCumulativeDeltaCompressor(byte(rec.FracDigits), buffer, 0)
|
||||
} else {
|
||||
values = enc.NewInstantDeltaCompressor(buffer, byte(rec.FracDigits))
|
||||
values = enc.NewInstantDeltaCompressor(byte(rec.FracDigits), buffer, 0)
|
||||
}
|
||||
|
||||
s.metrics[rec.MetricID] = &_metric{
|
||||
metricType: rec.MetricType,
|
||||
fracDigits: byte(rec.FracDigits),
|
||||
buffer: buffer,
|
||||
timestamps: enc.NewTimeDeltaCompressor(buffer),
|
||||
timestamps: enc.NewTimeDeltaCompressor(buffer, 0),
|
||||
values: values,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Database) deleteMetric(rec txlog.DeletedMetric) {
|
||||
func (s *Database) deleteMetric(rec storage.MetricDeleteRecord) {
|
||||
metric, ok := s.metrics[rec.MetricID]
|
||||
if !ok {
|
||||
qb.Abort(qb.NoMetricBug,
|
||||
@@ -552,7 +550,7 @@ func (s *Database) deleteMetric(rec txlog.DeletedMetric) {
|
||||
}
|
||||
delete(s.metrics, rec.MetricID)
|
||||
|
||||
// ADD in txlog
|
||||
// ADD in storage
|
||||
// if len(rec.FreePageNumbers) > 0 {
|
||||
// s.freeList.AddPages(rec.FreePageNumbers)
|
||||
// }
|
||||
@@ -562,7 +560,7 @@ func (s *Database) deleteMetric(rec txlog.DeletedMetric) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Database) deleteMeasures(rec txlog.DeletedMeasures) {
|
||||
func (s *Database) deleteMeasures(rec storage.DeletedMeasures) {
|
||||
metric, ok := s.metrics[rec.MetricID]
|
||||
if !ok {
|
||||
qb.Abort(qb.NoMetricBug,
|
||||
@@ -577,7 +575,7 @@ func (s *Database) deleteMeasures(rec txlog.DeletedMeasures) {
|
||||
}
|
||||
metric.DeleteMeasures()
|
||||
metric.XLock = false
|
||||
// FIX add in txlog
|
||||
// FIX add in storage
|
||||
// if len(rec.FreePageNumbers) > 0 {
|
||||
// s.freeList.AddPages(rec.FreePageNumbers)
|
||||
// }
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
bin "gordenko.dev/dima/bin/little"
|
||||
qb "gordenko.dev/dima/qb"
|
||||
"gordenko.dev/dima/qb/atree"
|
||||
"gordenko.dev/dima/qb/txlog"
|
||||
"gordenko.dev/dima/qb"
|
||||
"gordenko.dev/dima/qb/enc"
|
||||
"gordenko.dev/dima/qb/storage"
|
||||
)
|
||||
|
||||
type ReplayMetric struct {
|
||||
@@ -17,7 +18,7 @@ type ReplayMetric struct {
|
||||
databuf []byte // якщо розмір buf == DataPageSize, то databuf буде менше (мінус футер)
|
||||
tSize int
|
||||
vSize int
|
||||
indexLevelTails []txlog.IndexLevelTail // root - last element
|
||||
indexLevelTails []storage.IndexLevelTail // root - last element
|
||||
}
|
||||
|
||||
func (s *ReplayMetric) ReadFrom(r io.Reader) (err error) {
|
||||
@@ -57,7 +58,7 @@ func (s *ReplayMetric) ReadFrom(r io.Reader) (err error) {
|
||||
}
|
||||
for range levelsCount {
|
||||
var (
|
||||
buf = make([]byte, atree.IndexPageSize)
|
||||
buf = make([]byte, storage.IndexPageSize)
|
||||
count int
|
||||
)
|
||||
count, err = bin.ReadVarSize(r)
|
||||
@@ -68,7 +69,7 @@ func (s *ReplayMetric) ReadFrom(r io.Reader) (err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
s.indexLevelTails = append(s.indexLevelTails, txlog.IndexLevelTail{
|
||||
s.indexLevelTails = append(s.indexLevelTails, storage.IndexLevelTail{
|
||||
Buffer: buf,
|
||||
RecordsCount: count,
|
||||
})
|
||||
@@ -76,115 +77,256 @@ func (s *ReplayMetric) ReadFrom(r io.Reader) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// func appendNewRecordsToIndexTail(level storage.IndexLevelTail, records []byte) {
|
||||
|
||||
// }
|
||||
|
||||
// func countReusedIndexPages(changedIndexLevels []storage.ChangedIndexLevel) (count int) {
|
||||
|
||||
// return
|
||||
// }
|
||||
|
||||
func (s *ReplayMetric) MeasuresAppend(rec storage.MeasuresAppendRecord) {
|
||||
timestampsSize := rec.TimestampsOffset - len(rec.Timestamps)
|
||||
// копіюю нові дані із WAL з урахуванням offset-ів
|
||||
copy(s.databuf[rec.ValuesOffset:], rec.Values)
|
||||
copy(s.databuf[len(s.databuf)-timestampsSize:], rec.Timestamps)
|
||||
//
|
||||
s.tSize = timestampsSize
|
||||
s.vSize = rec.ValuesOffset - len(rec.Values)
|
||||
}
|
||||
|
||||
type AppendMeasuresResult struct {
|
||||
IndexPages []txlog.PageToWrite
|
||||
DataPages []txlog.PageToWrite
|
||||
IndexPages []storage.PageToWrite
|
||||
DataPages []storage.PageToWrite
|
||||
ReusedIndexPagesCount int
|
||||
ReusedDataPagesCount int
|
||||
}
|
||||
|
||||
func (s *ReplayMetric) AppendedMeasures(rec txlog.WALRecordAppendMeasures, pagesNeeded bool) (result AppendMeasuresResult) {
|
||||
func (s *ReplayMetric) MeasuresAppendWithGrow(rec storage.MeasuresAppendWithGrowRecord, isLastPacket bool) (_ AppendMeasuresResult) {
|
||||
var (
|
||||
reusedIndexPages int
|
||||
reusedDataPages int
|
||||
indexPages []storage.PageToWrite
|
||||
dataPages []storage.PageToWrite
|
||||
)
|
||||
// Додати в index level tails недостаючі дані, або замінити
|
||||
for levelIdx, change := range rec.ChangedIndexLevels {
|
||||
var (
|
||||
head = change.HeadIndexPage
|
||||
newRecordsCount = len(change.TailRecords) / indexRecordSize
|
||||
)
|
||||
// 1. набиваю сторінки для перезапису в index файлі
|
||||
if isLastPacket {
|
||||
if head != nil {
|
||||
indexPages = append(indexPages,
|
||||
composeHeadIndexPage(levelIdx, s.indexLevelTails[levelIdx], head))
|
||||
}
|
||||
for _, x := range change.IndexPages {
|
||||
indexPages = append(indexPages, storage.PageToWrite{
|
||||
PageNo: x.PageNo,
|
||||
Content: x.Content,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Вношу зміни в поточні індексні хвости
|
||||
if levelIdx < len(s.indexLevelTails) {
|
||||
level := s.indexLevelTails[levelIdx]
|
||||
if change.CompletedIndexPage != nil {
|
||||
// попередній хвіст індексного рівня перетворився на сторінку,
|
||||
if head != nil {
|
||||
// попередній хвіст індексного рівня перетворився на head сторінку,
|
||||
// отже TailRecords - це новий хвіст
|
||||
// або копіюю дані, або алокую більший буфер?
|
||||
copy(level.Buffer, change.TailRecords)
|
||||
level.RecordsCount = len(change.TailRecords) / indexRecordSize
|
||||
level.RecordsCount = newRecordsCount
|
||||
} else {
|
||||
// TailRecords - це нові дані, які треба додати
|
||||
pos := level.RecordsCount * indexRecordSize
|
||||
copy(level.Buffer[pos:], change.TailRecords)
|
||||
level.RecordsCount += newRecordsCount
|
||||
}
|
||||
s.indexLevelTails[levelIdx] = level
|
||||
} else {
|
||||
var (
|
||||
recordsCount = len(change.TailRecords) / indexRecordSize
|
||||
buffer = make([]byte, atree.IndexPageSize)
|
||||
)
|
||||
copy(buffer, change.TailRecords)
|
||||
s.indexLevelTails = append(s.indexLevelTails, txlog.IndexLevelTail{
|
||||
Buffer: buffer,
|
||||
RecordsCount: recordsCount,
|
||||
// додаю новий індексний рівень
|
||||
buf := make([]byte, storage.IndexPageSize)
|
||||
copy(buf, change.TailRecords)
|
||||
//
|
||||
s.indexLevelTails = append(s.indexLevelTails, storage.IndexLevelTail{
|
||||
Buffer: buf,
|
||||
RecordsCount: newRecordsCount,
|
||||
})
|
||||
}
|
||||
|
||||
// 3. рахую кількість reused індексних сторінок
|
||||
if head != nil {
|
||||
if head.Reused {
|
||||
reusedIndexPages++
|
||||
}
|
||||
}
|
||||
for _, x := range change.IndexPages {
|
||||
if x.Reused {
|
||||
reusedIndexPages++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. набиваю сторінки для перезапису в data файлі
|
||||
if isLastPacket {
|
||||
dataPages = append(dataPages, composeHeadDataPage(s.databuf, rec.HeadDataPage))
|
||||
|
||||
for _, x := range rec.DataPages {
|
||||
dataPages = append(dataPages, storage.PageToWrite{
|
||||
PageNo: x.PageNo,
|
||||
Content: x.Content,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Перезаписати в buffer timestamps та values. Якщо розмір буферу недостатній -
|
||||
// спочатку створити більший
|
||||
// рахую кількість reused дата сторінок
|
||||
if rec.HeadDataPage.Reused {
|
||||
reusedDataPages++
|
||||
}
|
||||
for _, x := range rec.DataPages {
|
||||
if x.Reused {
|
||||
reusedDataPages++
|
||||
}
|
||||
}
|
||||
// HeadDataPage є полюбому, оскільки це транзакція із мінімум однією заповненою
|
||||
// data сторінкою. Отже TailTimestamps і TailValues - це нові хвости data рівня.
|
||||
copy(s.databuf, rec.TailValues)
|
||||
pos := len(s.databuf) - len(rec.TailTimestamps)
|
||||
copy(s.databuf[pos:], rec.TailTimestamps)
|
||||
|
||||
var (
|
||||
// CompletedDataPage є полюбому, оскільки це Record із мінімум одною заповненою
|
||||
// data сторінкою. Отже TailTimestamps і TailValues - це нові хвости data рівня.
|
||||
s.tSize = len(rec.TailTimestamps)
|
||||
s.vSize = len(rec.TailValues)
|
||||
|
||||
requiredSpace = len(rec.TailTimestamps) + len(rec.TailValues)
|
||||
databuf []byte
|
||||
)
|
||||
if requiredSpace < len(s.buf) {
|
||||
databuf = s.buf
|
||||
// fix - update sizes?
|
||||
if len(rec.DataPages) == 0 {
|
||||
s.lastPageNo = rec.HeadDataPage.PageNo
|
||||
} else {
|
||||
var buf []byte
|
||||
buf, databuf = allocateBuffers(requiredSpace)
|
||||
copy(databuf, rec.TailValues)
|
||||
pos := len(databuf) - len(rec.TailTimestamps)
|
||||
copy(databuf[pos:], rec.TailTimestamps)
|
||||
// fix - replace and remeber sizes?
|
||||
|
||||
s.buf = buf
|
||||
s.lastPageNo = rec.DataPages[len(rec.DataPages)-1].PageNo
|
||||
}
|
||||
|
||||
//rec.TailTimestamps
|
||||
//rec.TailValues
|
||||
return
|
||||
return AppendMeasuresResult{
|
||||
IndexPages: indexPages,
|
||||
DataPages: dataPages,
|
||||
ReusedIndexPagesCount: reusedIndexPages,
|
||||
ReusedDataPagesCount: reusedDataPages,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ReplayMetric) ApplyHeadDataPage(p txlog.CompletedDataPage) {
|
||||
// буфер має бути розміру сторінки
|
||||
if len(s.buf) != atree.DataPageSize {
|
||||
s.buf, s.databuf = growBuffers(growBuffersIn{
|
||||
databuf: s.databuf,
|
||||
tSize: s.tSize,
|
||||
vSize: s.vSize,
|
||||
requiredSpace: atree.DataPageSize,
|
||||
// HELPERS
|
||||
|
||||
func composeHeadIndexPage(levelIdx int, level storage.IndexLevelTail, head *storage.HeadIndexPage) storage.PageToWrite {
|
||||
// розраховую pos, з якого буду дописувати хвіст
|
||||
pos := level.RecordsCount * indexRecordSize
|
||||
// створюю копію сторінки
|
||||
page := make([]byte, storage.IndexPageSize)
|
||||
copy(page, level.Buffer[:pos]) // поточні дані
|
||||
copy(page[pos:], head.Records)
|
||||
// запечатати сторінку
|
||||
calculatedCRC := storage.SealIndexPage(storage.SealIndexPageIn{
|
||||
Content: page,
|
||||
RecordsCount: level.RecordsCount + len(head.Records)/indexRecordSize,
|
||||
ZeroLevel: levelIdx == 0,
|
||||
})
|
||||
// перевірка CRC
|
||||
if calculatedCRC != head.Checksum {
|
||||
qb.Abort(qb.WALReplayFailed,
|
||||
fmt.Errorf("calculated CRC %d not equal expected %d of head page %d on index level %d",
|
||||
calculatedCRC, head.Checksum, head.PageNo, levelIdx))
|
||||
}
|
||||
return storage.PageToWrite{
|
||||
PageNo: head.PageNo,
|
||||
Content: page,
|
||||
}
|
||||
}
|
||||
|
||||
func composeHeadDataPage(databuf []byte, head storage.HeadDataPage) storage.PageToWrite {
|
||||
// створюю копію сторінки
|
||||
var (
|
||||
page = make([]byte, storage.DataPageSize)
|
||||
timestampsSize = head.TimestampsOffset - len(head.Timestamps)
|
||||
)
|
||||
// копіюю поточні дані
|
||||
copy(page, databuf)
|
||||
// копіюю нові дані із WAL з урахуванням offset-ів
|
||||
copy(page[head.ValuesOffset:], head.Values)
|
||||
copy(page[len(page)-timestampsSize:], head.Timestamps)
|
||||
// запечатати сторінку
|
||||
calculatedCRC := storage.SealDataPage(storage.SealDataPageIn{
|
||||
Content: page,
|
||||
PrevPageNo: head.PrevPageNo,
|
||||
TimestampsSize: timestampsSize,
|
||||
ValuesSize: head.ValuesOffset + len(head.Values),
|
||||
})
|
||||
// перевірка CRC
|
||||
if calculatedCRC != head.Checksum {
|
||||
qb.Abort(qb.WALReplayFailed,
|
||||
fmt.Errorf("calculated CRC %d not equal expected %d of head data page %d",
|
||||
calculatedCRC, head.Checksum, head.PageNo))
|
||||
}
|
||||
return storage.PageToWrite{
|
||||
PageNo: head.PageNo,
|
||||
Content: page,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ReplayMetric) ToMetric() *_metric {
|
||||
var (
|
||||
values qb.ValueCompressor
|
||||
requiredSpace = s.tSize + s.vSize
|
||||
)
|
||||
bufferSize := calculateDataBufferSize(requiredSpace)
|
||||
if len(s.buf) > bufferSize {
|
||||
s.buf = shrinkBuffer(shrinkBufferIn{
|
||||
Buffer: s.buf,
|
||||
TimestampsSize: s.tSize,
|
||||
ValuesSize: s.vSize,
|
||||
NewBufferSize: bufferSize,
|
||||
})
|
||||
}
|
||||
// дописую дані по зміщенню
|
||||
pos := len(s.databuf) - p.TimestampsOffset - len(p.Timestamps)
|
||||
copy(s.databuf[pos:], p.Timestamps)
|
||||
copy(s.databuf[p.ValuesOffset:], p.Values)
|
||||
//
|
||||
s.tSize = p.TimestampsOffset + len(p.Timestamps)
|
||||
s.tSize = p.ValuesOffset + len(p.Values)
|
||||
|
||||
// fix - заполнить страницу
|
||||
// fix - check checksum
|
||||
if s.metricType == qb.Cumulative {
|
||||
values = enc.NewCumulativeDeltaCompressor(s.fracDigits, s.buf, s.vSize)
|
||||
} else {
|
||||
values = enc.NewInstantDeltaCompressor(s.fracDigits, s.buf, s.vSize)
|
||||
}
|
||||
return &_metric{
|
||||
metricType: s.metricType,
|
||||
fracDigits: s.fracDigits,
|
||||
lastPageNo: s.lastPageNo,
|
||||
lastValue: values.LastValue(),
|
||||
buffer: s.buf,
|
||||
timestamps: enc.NewTimeDeltaCompressor(s.buf, s.tSize),
|
||||
values: values,
|
||||
indexLevelTails: s.indexLevelTails,
|
||||
}
|
||||
}
|
||||
|
||||
// func (s *ReplayMetric) ApplyHeadIndexPages(changedIndexLevels txlog.ChangedIndexLevel) {
|
||||
// func (s *ReplayMetric) ApplyHeadDataPage(p storage.HeadDataPage) {
|
||||
// // буфер має бути розміру сторінки
|
||||
// if len(s.buf) != atree.DataPageSize {
|
||||
// s.buf, s.databuf = growBuffers(growBuffersIn{
|
||||
// databuf: s.databuf,
|
||||
// tSize: s.tSize,
|
||||
// vSize: s.vSize,
|
||||
// requiredSpace: atree.DataPageSize,
|
||||
// })
|
||||
// }
|
||||
// // дописую дані по зміщенню
|
||||
// pos := len(s.databuf) - p.TimestampsOffset - len(p.Timestamps)
|
||||
// copy(s.databuf[pos:], p.Timestamps)
|
||||
// copy(s.databuf[p.ValuesOffset:], p.Values)
|
||||
// //
|
||||
// s.tSize = p.TimestampsOffset + len(p.Timestamps)
|
||||
// s.tSize = p.ValuesOffset + len(p.Values)
|
||||
|
||||
// // fix - заполнить страницу
|
||||
// // fix - check checksum
|
||||
// }
|
||||
|
||||
// func (s *ReplayMetric) ApplyHeadIndexPages(changedIndexLevels storage.ChangedIndexLevel) {
|
||||
// for levelIdx, changedLevel := range changedIndexLevels {
|
||||
// p := changedLevel.CompletedIndexPage
|
||||
// if p != nil {
|
||||
// level := s.indexLevelTails[levelIdx]
|
||||
// copy(level.Buffer[level.RecordsCount*indexRecordSize:], p.Records)
|
||||
//
|
||||
|
||||
// // fix - заполнить страницу
|
||||
// // fix - check checksum
|
||||
|
||||
// s.indexPages = append(s.indexPages, txlog.PageToWrite{
|
||||
// PageNo: p.PageNo,
|
||||
// Content: level.Buffer,
|
||||
// })
|
||||
// }
|
||||
|
||||
// for _, x := range changedLevel.IndexPages {
|
||||
// s.indexPages = append(s.indexPages, txlog.PageToWrite{
|
||||
// PageNo: x.PageNo,
|
||||
// Content: x.Content,
|
||||
// })
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
bin "gordenko.dev/dima/bin/little"
|
||||
"gordenko.dev/dima/qb/atree"
|
||||
"gordenko.dev/dima/qb/storage"
|
||||
"gordenko.dev/dima/qb/util"
|
||||
)
|
||||
|
||||
@@ -177,11 +177,11 @@ func readSnapshot(fileName string) (out readSnapshotOut, err error) {
|
||||
for range metricsQty {
|
||||
var (
|
||||
metricID uint32
|
||||
buf = make([]byte, atree.DataPageSize)
|
||||
buf = make([]byte, storage.DataPageSize)
|
||||
// для простоти створюю буфер максимального розміру
|
||||
metric = &ReplayMetric{
|
||||
buf: buf,
|
||||
databuf: buf[:atree.DataPagePayloadSize],
|
||||
databuf: buf[:storage.DataPagePayloadSize],
|
||||
}
|
||||
)
|
||||
metricID, err = bin.ReadUint32(src)
|
||||
|
||||
@@ -4,22 +4,20 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
qb "gordenko.dev/dima/qb"
|
||||
"gordenko.dev/dima/qb/atree"
|
||||
"gordenko.dev/dima/qb/txlog"
|
||||
"gordenko.dev/dima/qb/storage"
|
||||
)
|
||||
|
||||
type WALReplayer struct {
|
||||
walReader *txlog.Reader
|
||||
walReader *storage.WALReader
|
||||
metrics map[uint32]*ReplayMetric
|
||||
freeIndexPages []uint32
|
||||
freeDataPages []uint32
|
||||
indexPages []txlog.PageToWrite
|
||||
dataPages []txlog.PageToWrite
|
||||
indexPages []storage.PageToWrite
|
||||
dataPages []storage.PageToWrite
|
||||
}
|
||||
|
||||
type WALReplayerOptions struct {
|
||||
WALReader *txlog.Reader
|
||||
WALReader *storage.WALReader
|
||||
Metrics map[uint32]*ReplayMetric // from snapshot
|
||||
FreeIndexPages []uint32 // from snapshot
|
||||
FreeDataPages []uint32 // from snapshot
|
||||
@@ -40,122 +38,80 @@ func NewWALReplayer(opt WALReplayerOptions) (*WALReplayer, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *WALReplayer) IndexPages() []storage.PageToWrite {
|
||||
return s.indexPages
|
||||
}
|
||||
|
||||
func (s *WALReplayer) DataPages() []storage.PageToWrite {
|
||||
return s.dataPages
|
||||
}
|
||||
|
||||
func (s *WALReplayer) Replay() error {
|
||||
for {
|
||||
records, isLast, err := s.walReader.NextPacket()
|
||||
records, isLastPacket, err := s.walReader.NextPacket()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if isLast {
|
||||
if len(records) > 0 {
|
||||
var appendRecords []txlog.WALRecordAppendMeasures
|
||||
for _, untyped := range records {
|
||||
rec, ok := untyped.(txlog.WALRecordAppendMeasures)
|
||||
if ok {
|
||||
appendRecords = append(appendRecords, rec)
|
||||
}
|
||||
}
|
||||
// prepare pages and rewrite
|
||||
indexPages, dataPages := pagesToWriteFromWALRecords(metrics, appendRecords)
|
||||
|
||||
err = s.txlog.WritePagesToAtree(indexPages, dataPages)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// для останнього rec - повторюємо запис сторінок
|
||||
// rewrite write pages
|
||||
//s.txlog.
|
||||
//return nil
|
||||
}
|
||||
|
||||
for _, rec := range records {
|
||||
if err = s.replayWALRecord(rec); err != nil {
|
||||
if err = s.replayRecord(rec, isLastPacket); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// func (s *WALReplayer) replayPacket(records []any, isLastPacket bool) {
|
||||
// for _, untyped := range records {
|
||||
// switch rec := untyped.(type) {
|
||||
// case txlog.WALRecordAppendMeasures:
|
||||
// s.onWALRecordAppendMeasures(rec, isLastPacket)
|
||||
// }
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
func (s *WALReplayer) replayWALRecord(untyped any) (err error) {
|
||||
func (s *WALReplayer) replayRecord(untyped any, isLastPacket bool) (err error) {
|
||||
switch rec := untyped.(type) {
|
||||
case txlog.AddedMetric:
|
||||
if err = s.onAddedMetric(rec); err != nil {
|
||||
case storage.MeasuresAppendRecord:
|
||||
if err = s.onMeasuresAppend(rec); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
case txlog.DeletedMetric:
|
||||
if err = s.onDeletedMetric(rec); err != nil {
|
||||
case storage.MeasuresAppendWithGrowRecord:
|
||||
if err = s.onMeasuresAppendWithGrow(rec, isLastPacket); err != nil {
|
||||
return
|
||||
}
|
||||
case storage.MetricAddRecord:
|
||||
if err = s.onMetricAdd(rec); err != nil {
|
||||
return
|
||||
}
|
||||
case storage.MetricDeleteRecord:
|
||||
if err = s.onMetricDelete(rec); err != nil {
|
||||
return
|
||||
}
|
||||
// case storage.DeletedMeasures:
|
||||
// metric, ok := s.metrics[rec.MetricID]
|
||||
// if ok {
|
||||
// metric.DeleteMeasures()
|
||||
// if len(rec.FreePageNumbers) > 0 {
|
||||
// s.freeList.AddPages(rec.FreePageNumbers)
|
||||
// }
|
||||
// }
|
||||
|
||||
// case txlog.AppendedMeasure:
|
||||
// metric, ok := s.metrics[rec.MetricID]
|
||||
// if ok {
|
||||
// metric.Timestamps.Append(rec.Timestamp)
|
||||
// metric.Values.Append(rec.Value)
|
||||
|
||||
// if metric.Since == 0 {
|
||||
// metric.Since = rec.Timestamp
|
||||
// metric.SinceValue = rec.Value
|
||||
// }
|
||||
|
||||
// metric.Until = rec.Timestamp
|
||||
// metric.UntilValue = rec.Value
|
||||
// }
|
||||
|
||||
case txlog.WALRecordAppendMeasures:
|
||||
// metric, ok := s.metrics[rec.MetricID]
|
||||
// if !ok {
|
||||
// qb.Abort(qb.MetricNotFoundDuringReplay, nil)
|
||||
// }
|
||||
//metric.ReplayAppendedMeasures(rec) FIX
|
||||
|
||||
// case txlog.DeletedMeasures:
|
||||
// metric, ok := s.metrics[rec.MetricID]
|
||||
// if ok {
|
||||
// metric.DeleteMeasures()
|
||||
// if len(rec.FreePageNumbers) > 0 {
|
||||
// s.freeList.AddPages(rec.FreePageNumbers)
|
||||
// }
|
||||
// }
|
||||
|
||||
default:
|
||||
qb.Abort(qb.UnknownTxLogRecordTypeBug,
|
||||
fmt.Errorf("bug: unknown record type %T in TransactionLog", rec))
|
||||
// default:
|
||||
// qb.Abort(qb.UnknownstorageRecordTypeBug,
|
||||
// fmt.Errorf("bug: unknown record type %T in TransactionLog", rec))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *WALReplayer) onAddedMetric(rec txlog.AddedMetric) (err error) {
|
||||
func (s *WALReplayer) onMetricAdd(rec storage.MetricAddRecord) (err error) {
|
||||
_, ok := s.metrics[rec.MetricID]
|
||||
if ok {
|
||||
return fmt.Errorf("metric %d add failed: already added", rec.MetricID)
|
||||
}
|
||||
var (
|
||||
buf = make([]byte, atree.DataPageSize)
|
||||
buf = make([]byte, storage.DataPageSize)
|
||||
)
|
||||
s.metrics[rec.MetricID] = &ReplayMetric{
|
||||
metricType: rec.MetricType,
|
||||
fracDigits: byte(rec.FracDigits),
|
||||
buf: buf,
|
||||
databuf: buf[:atree.DataPagePayloadSize],
|
||||
databuf: buf[:storage.DataPagePayloadSize],
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *WALReplayer) onDeletedMetric(rec txlog.DeletedMetric) error {
|
||||
func (s *WALReplayer) onMetricDelete(rec storage.MetricDeleteRecord) error {
|
||||
_, ok := s.metrics[rec.MetricID]
|
||||
if !ok {
|
||||
return fmt.Errorf("metric %d deletion failed: not found", rec.MetricID)
|
||||
@@ -166,15 +122,21 @@ func (s *WALReplayer) onDeletedMetric(rec txlog.DeletedMetric) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *WALReplayer) onAppendMeasures(rec txlog.WALRecordAppendMeasures, isLastPacket bool) {
|
||||
func (s *WALReplayer) onMeasuresAppend(rec storage.MeasuresAppendRecord) (err error) {
|
||||
metric, ok := s.metrics[rec.MetricID]
|
||||
if !ok {
|
||||
qb.Abort(qb.MetricNotFoundDuringReplay, nil)
|
||||
return fmt.Errorf("append measures failed: metric %d not found", rec.MetricID)
|
||||
}
|
||||
if isLastPacket {
|
||||
s.collectPagesToWrite(metric, rec)
|
||||
metric.MeasuresAppend(rec)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *WALReplayer) onMeasuresAppendWithGrow(rec storage.MeasuresAppendWithGrowRecord, isLastPacket bool) (err error) {
|
||||
metric, ok := s.metrics[rec.MetricID]
|
||||
if !ok {
|
||||
return fmt.Errorf("append measures failed: metric %d not found", rec.MetricID)
|
||||
}
|
||||
result := metric.AppendedMeasures(rec, isLastPacket)
|
||||
result := metric.MeasuresAppendWithGrow(rec, isLastPacket)
|
||||
//
|
||||
if isLastPacket {
|
||||
s.indexPages = append(s.indexPages, result.IndexPages...)
|
||||
@@ -183,22 +145,33 @@ func (s *WALReplayer) onAppendMeasures(rec txlog.WALRecordAppendMeasures, isLast
|
||||
//
|
||||
s.freeIndexPages = s.freeIndexPages[:len(s.freeIndexPages)-result.ReusedIndexPagesCount]
|
||||
s.freeDataPages = s.freeDataPages[:len(s.freeDataPages)-result.ReusedDataPagesCount]
|
||||
return
|
||||
}
|
||||
|
||||
func (s *WALReplayer) collectPagesToWrite(metric *ReplayMetric, rec txlog.WALRecordAppendMeasures) {
|
||||
metric.ApplyHeadDataPage(rec.CompletedDataPage)
|
||||
//func (s *WALReplayer) collectPagesToWrite(metric *ReplayMetric, rec storage.WALRecordAppendMeasures) {
|
||||
// metric.ApplyHeadDataPage(rec.CompletedDataPage)
|
||||
|
||||
s.dataPages = append(s.dataPages, txlog.PageToWrite{
|
||||
PageNo: p.PageNo,
|
||||
Content: metric.buf,
|
||||
})
|
||||
// s.dataPages = append(s.dataPages, storage.PageToWrite{
|
||||
// PageNo: p.PageNo,
|
||||
// Content: metric.buf,
|
||||
// })
|
||||
|
||||
for _, x := range rec.DataPages {
|
||||
s.dataPages = append(s.dataPages, txlog.PageToWrite{
|
||||
PageNo: x.PageNo,
|
||||
Content: x.Content,
|
||||
})
|
||||
}
|
||||
//metric.ApplyHeadIndexPages(rec.ChangedIndexLevels)
|
||||
// for _, x := range rec.DataPages {
|
||||
// s.dataPages = append(s.dataPages, storage.PageToWrite{
|
||||
// PageNo: x.PageNo,
|
||||
// Content: x.Content,
|
||||
// })
|
||||
// }
|
||||
//metric.ApplyHeadIndexPages(rec.ChangedIndexLevels)
|
||||
|
||||
}
|
||||
//}
|
||||
|
||||
// func (s *WALReplayer) replayPacket(records []any, isLastPacket bool) {
|
||||
// for _, untyped := range records {
|
||||
// switch rec := untyped.(type) {
|
||||
// case storage.WALRecordAppendMeasures:
|
||||
// s.onWALRecordAppendMeasures(rec, isLastPacket)
|
||||
// }
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
Reference in New Issue
Block a user