This commit is contained in:
2026-06-15 05:32:15 +03:00
parent 80309aab99
commit ca125c99d2
16 changed files with 685 additions and 1350 deletions

View File

@@ -33,11 +33,75 @@ type Metric struct {
values qb.ValueCompressor
xLock bool
rLocks int
WaitQueue []any
waitQueue []any
indexLevelTails []storage.IndexLevelTail // root - last element
capturedState *CapturedState
}
// індекси
// Metric encode format:
// metricID - 4b
// metricType - 1b
// fracDigits - 1b
// lastPageNo - 4b
// timestamps size - 2b
// values size - 2b
// timestams payload - Nb
// values payload - Nb
// index levels count - varsize
// [
// records qty - varsize
// records - Nb
// ]
func (s *Metric) WriteTo(w io.Writer) (err error) {
_, err = w.Write([]byte{
byte(s.metricType),
s.fracDigits,
})
if err != nil {
return
}
err = bin.WriteUint32(w, s.lastPageNo)
if err != nil {
return
}
err = bin.WriteUint16(w, uint16(s.timestamps.CommitedSize()))
if err != nil {
return
}
err = bin.WriteUint16(w, uint16(s.values.CommitedSize()))
if err != nil {
return
}
// timestamps payload
err = s.timestamps.WriteCommitedTo(w)
if err != nil {
return
}
// values payload
err = s.values.WriteCommitedTo(w)
if err != nil {
return
}
// indexes
_, err = bin.WriteVarSize(w, len(s.indexLevelTails))
if err != nil {
return
}
for _, level := range s.indexLevelTails {
_, err = bin.WriteVarSize(w, level.RecordsCount)
if err != nil {
return
}
_, err = w.Write(level.Buffer[:level.RecordsCount*storage.IndexRecordSize])
if err != nil {
return
}
}
return
}
func (s *Metric) MetricType() qb.MetricType {
return s.metricType
}
@@ -60,26 +124,12 @@ func (s *Metric) LastTimestamp() uint32 {
return s.timestamps.LastTimestamp()
}
func (s *Metric) OnMeasuresDeleteCommited(rec storage.MeasuresDeleteCommited) {
//s.timestamps.Reset()
//s.values.Reset()
s.xLock = false
// s.Timestamps.Renew()
// s.Values.Renew()
// s.LastPageNo = 0
// s.Since = 0
// s.SinceValue = 0
// s.Until = 0
s.indexLevelTails = nil
s.lastPageNo = 0
s.lastValue = 0
}
// REQUESTS
func (s *Metric) AppendMeasures(req AppendMeasuresReq, tmp []byte, storageInbox *inbox.Inbox) {
if s.capturedState != nil {
s.WaitQueue = append(s.WaitQueue, req)
if s.xLock || s.capturedState != nil {
s.waitQueue = append(s.waitQueue, req)
return
}
var (
timestamps = s.timestamps
@@ -188,7 +238,6 @@ func (s *Metric) AppendMeasures(req AppendMeasuresReq, tmp []byte, storageInbox
// скопіювати. Причому можна скопіювати зрізи chunks
if len(pages) > 0 {
fmt.Println("push pages")
// пишу в storage довгим шляхом через redo файл і запис в data файл
storageInbox.Push(storage.MeasuresAppendWithGrow{
MetricID: req.MetricID,
@@ -206,7 +255,6 @@ func (s *Metric) AppendMeasures(req AppendMeasuresReq, tmp []byte, storageInbox
ResultCh: req.ResultCh,
})
} else {
fmt.Println("push simple")
// короткий шлях - запис лише в storage
storageInbox.Push(storage.MeasuresAppend{
MetricID: req.MetricID,
@@ -221,6 +269,143 @@ func (s *Metric) AppendMeasures(req AppendMeasuresReq, tmp []byte, storageInbox
}
}
func (s *Metric) DeleteMeasures(req DeleteMeasuresReq) {
if s.xLock || s.capturedState != nil {
s.waitQueue = append(s.waitQueue, req)
return
}
since := s.timestamps.FirstTimestamp()
until := s.timestamps.LastTimestamp()
if since == 0 || (req.Since > 0 && until < req.Since) {
req.ResultCh <- NoMeasuresToDelete
}
// if s.RootPageNo > 0 {
// req.ResultCh <- tryDeleteMeasuresResult{
// ResultCode: DeleteFromAtreeRequired,
// RootPageNo: metric.RootPageNo,
// }
// } else {
// req.ResultCh <- tryDeleteMeasuresResult{
// ResultCode: DeleteFromAtreeNotNeeded,
// }
// }
}
func (s *Metric) StartRangeScan(req RangeScanReq) {
if s.xLock {
s.waitQueue = append(s.waitQueue, req)
return
}
// if s.timestamps.CommitedSize() == 0 {
// req.ResultCh <- RangeScanResult{
// ResultCode: QueryDone,
// }
// return
// }
// if req.Since > s.timestamps.LastTimestamp() {
// req.ResultCh <- RangeScanResult{
// ResultCode: QueryDone,
// }
// return
// }
// if req.Until < s.Since {
// if s.RootPageNo > 0 {
// req.ResultCh <- RangeScanResult{
// ResultCode: UntilNotFound,
// RootPageNo: s.RootPageNo,
// FracDigits: s.fracDigits,
// }
// s.rLocks++
// return
// } else {
// req.ResultCh <- RangeScanResult{
// ResultCode: QueryDone,
// }
// return
// }
// }
timestampDecompressor := s.timestamps.CreateDecompressor()
valueDecompressor := s.values.CreateDecompressor(s.metricType, s.fracDigits)
for {
timestamp, done := timestampDecompressor.NextValue()
if done {
break
}
value, done := valueDecompressor.NextValue()
if done {
qb.Abort(qb.HasTimestampNoValueBug, ErrNoValueBug)
}
if timestamp <= req.Until {
req.ResponseWriter.FeedNoSend(timestamp, value)
if timestamp < req.Since {
req.ResultCh <- RangeScanResult{
ResultCode: QueryDone,
}
return
}
}
}
if s.lastPageNo > 0 {
req.ResultCh <- RangeScanResult{
ResultCode: UntilFound,
LastPageNo: s.lastPageNo,
FracDigits: s.fracDigits,
}
s.rLocks++
} else {
req.ResultCh <- RangeScanResult{
ResultCode: QueryDone,
}
}
}
func (s *Metric) StartFullScan(req FullScanReq) {
if s.xLock {
s.waitQueue = append(s.waitQueue, req)
return
}
if s.timestamps.CommitedSize() == 0 {
req.ResultCh <- FullScanResult{
ResultCode: QueryDone,
}
return
}
timestampDecompressor := s.timestamps.CreateDecompressor()
valueDecompressor := s.values.CreateDecompressor(s.metricType, s.fracDigits)
for {
timestamp, done := timestampDecompressor.NextValue()
if done {
break
}
//fmt.Println("ts:", timestamp)
value, done := valueDecompressor.NextValue()
if done {
qb.Abort(qb.HasTimestampNoValueBug, ErrNoValueBug)
}
//fmt.Println("value:", value)
req.ResponseWriter.FeedNoSend(timestamp, value)
}
if s.lastPageNo > 0 {
req.ResultCh <- FullScanResult{
ResultCode: UntilFound,
LastPageNo: s.lastPageNo,
FracDigits: s.fracDigits,
}
s.rLocks++
} else {
req.ResultCh <- FullScanResult{
ResultCode: QueryDone,
}
}
}
// COMMITS
func (s *Metric) OnMeasuresAppendCommited(rec storage.MeasuresAppendCommited) {
// Видаляю state. Оригінальні Timestamps і Values вже мають останню версію
s.capturedState = nil
@@ -252,175 +437,18 @@ func (s *Metric) OnMeasuresAppendWithGrowCommited(rec storage.MeasuresAppendWith
}
}
// READ
func (s *Metric) OnMeasuresDeleteCommited(rec storage.MeasuresDeleteCommited) {
//s.timestamps.Reset()
//s.values.Reset()
s.xLock = false
// s.Timestamps.Renew()
// s.Values.Renew()
func (s *Metric) StartRangeScan(req RangeScanReq) {
// if s.Since == 0 {
// req.ResultCh <- rangeScanResult{
// ResultCode: QueryDone,
// }
// return
// }
// if req.Since > s.Until {
// req.ResultCh <- rangeScanResult{
// ResultCode: QueryDone,
// }
// return
// }
// if req.Until < s.Since {
// if s.RootPageNo > 0 {
// req.ResultCh <- rangeScanResult{
// ResultCode: UntilNotFound,
// RootPageNo: s.RootPageNo,
// FracDigits: s.FracDigits,
// }
// s.RLocks++
// return
// } else {
// req.ResultCh <- rangeScanResult{
// ResultCode: QueryDone,
// }
// return
// }
// }
// timestampDecompressor := s.timestamps.CreateDecompressor()
// valueDecompressor := s.values.CreateDecompressor(s.metricType, s.fracDigits)
// for {
// timestamp, done := timestampDecompressor.NextValue()
// if done {
// break
// }
// value, done := valueDecompressor.NextValue()
// if done {
// qb.Abort(qb.HasTimestampNoValueBug, ErrNoValueBug)
// }
// if timestamp <= req.Until {
// req.ResponseWriter.FeedNoSend(timestamp, value)
// if timestamp < req.Since {
// req.ResultCh <- rangeScanResult{
// ResultCode: QueryDone,
// }
// return
// }
// }
// }
// if s.lastPageNo > 0 {
// req.ResultCh <- rangeScanResult{
// ResultCode: UntilFound,
// LastPageNo: s.lastPageNo,
// FracDigits: s.fracDigits,
// }
// s.RLocks++
// } else {
// req.ResultCh <- rangeScanResult{
// ResultCode: QueryDone,
// }
// }
}
func (s *Metric) StartFullScan(req FullScanReq) {
// if s.Since == 0 {
// req.ResultCh <- fullScanResult{
// ResultCode: QueryDone,
// }
// return
// }
timestampDecompressor := s.timestamps.CreateDecompressor()
valueDecompressor := s.values.CreateDecompressor(s.metricType, s.fracDigits)
for {
timestamp, done := timestampDecompressor.NextValue()
if done {
break
}
//fmt.Println("ts:", timestamp)
value, done := valueDecompressor.NextValue()
if done {
qb.Abort(qb.HasTimestampNoValueBug, ErrNoValueBug)
}
//fmt.Println("value:", value)
req.ResponseWriter.FeedNoSend(timestamp, value)
}
// if s.lastPageNo > 0 {
// req.ResultCh <- FullScanResult{
// ResultCode: UntilFound,
// LastPageNo: s.lastPageNo,
// FracDigits: s.fracDigits,
// }
// s.rLocks++
// } else {
req.ResultCh <- FullScanResult{
ResultCode: QueryDone,
}
//}
}
// індекси
// Metric encode format:
// metricID - 4b
// metricType - 1b
// fracDigits - 1b
// lastPageNo - 4b
// timestamps size - 2b
// values size - 2b
// timestams payload - Nb
// values payload - Nb
// index levels count - varsize
// [
// records qty - varsize
// records - Nb
// ]
func (s *Metric) WriteTo(w io.Writer) (err error) {
_, err = w.Write([]byte{
byte(s.metricType),
s.fracDigits,
})
if err != nil {
return
}
err = bin.WriteUint32(w, s.lastPageNo)
if err != nil {
return
}
err = bin.WriteUint16(w, uint16(s.timestamps.CommitedSize()))
if err != nil {
return
}
err = bin.WriteUint16(w, uint16(s.values.CommitedSize()))
if err != nil {
return
}
// timestamps payload
err = s.timestamps.WriteCommitedTo(w)
if err != nil {
return
}
// values payload
err = s.values.WriteCommitedTo(w)
if err != nil {
return
}
// indexes
_, err = bin.WriteVarSize(w, len(s.indexLevelTails))
if err != nil {
return
}
for _, level := range s.indexLevelTails {
_, err = bin.WriteVarSize(w, level.RecordsCount)
if err != nil {
return
}
_, err = w.Write(level.Buffer[:level.RecordsCount*storage.IndexRecordSize])
if err != nil {
return
}
}
return
// s.LastPageNo = 0
// s.Since = 0
// s.SinceValue = 0
// s.Until = 0
s.indexLevelTails = nil
s.lastPageNo = 0
s.lastValue = 0
}

View File

@@ -147,31 +147,22 @@ func (s *Worker) doWork() {
switch req := untyped.(type) {
case AppendMeasuresReq:
s.AppendMeasures(req)
case storage.Changes:
s.applyCommits(req) // all metrics only
case ListCurrentValuesReq:
s.ListCurrentValues(req) // all metrics only
case RangeScanReq:
s.RangeScan(req)
case FullScanReq:
s.FullScan(req)
case AddMetricReq:
s.AddMetric(req)
case DeleteMetricReq:
s.DeleteMetric(req)
case DeleteMeasuresReq:
s.DeleteMeasures(req)
case GetMetricReq:
s.GetMetric(req)
default:
qb.Abort(qb.UnknownWorkerQueueItemBug,
fmt.Errorf("bug: unknown worker queue item type %T", req))
@@ -181,30 +172,23 @@ func (s *Worker) doWork() {
// суть у тому що треба запускати запити, пока не зустріну XLock
func (s *Worker) processMetricQueue(metricID uint32, metric *Metric, tmp []byte) {
if len(metric.WaitQueue) == 0 {
if len(metric.waitQueue) == 0 {
return
}
for _, untyped := range metric.WaitQueue {
for _, untyped := range metric.waitQueue {
switch req := untyped.(type) {
case RangeScanReq:
metric.StartRangeScan(req)
case FullScanReq:
metric.StartFullScan(req)
case GetMetricReq:
s.GetMetric(req)
case AppendMeasuresReq:
metric.AppendMeasures(req, tmp, s.storageInbox)
case DeleteMetricReq:
s.startDeleteMetric(metric, req)
s.DeleteMetric(req)
case DeleteMeasuresReq:
s.startDeleteMeasures(metric, req)
metric.DeleteMeasures(req)
default:
qb.Abort(qb.UnknownMetricWaitQueueItemBug,
fmt.Errorf("bug: unknown metric wait queue item type %T", req))
@@ -222,7 +206,6 @@ type AddMetricReq struct {
func (s *Worker) AddMetric(req AddMetricReq) {
_, ok := s.metrics[req.MetricID]
if ok {
fmt.Println("add metric duplicate")
req.ResultCh <- MetricDuplicate
return
}
@@ -246,27 +229,6 @@ func (s *Worker) AddMetric(req AddMetricReq) {
})
}
func (s *Worker) processTryAddMetricReqsImmediatelyAfterDelete(reqs []AddMetricReq) {
if len(reqs) == 0 {
return
}
var (
req = reqs[0]
waitQueue []any
)
if len(reqs) > 1 {
for _, req := range reqs[1:] {
waitQueue = append(waitQueue, req)
}
}
// FIX
// s.metricLockEntries[req.MetricID] = &metricLockEntry{
// XLock: true,
// WaitQueue: waitQueue,
// }
req.ResultCh <- Succeed
}
type GetMetricResult struct {
MetricType qb.MetricType
FracDigits byte
@@ -293,116 +255,43 @@ func (s *Worker) GetMetric(req GetMetricReq) {
}
}
type DeleteMetricResult struct {
ResultCode byte
RootPageNo uint32
}
type DeleteMetricReq struct {
MetricID uint32
ResultCh chan DeleteMetricResult
ResultCh chan byte
}
func (s *Worker) DeleteMetric(req DeleteMetricReq) {
// FIX
// metric, ok := s.metrics[req.MetricID]
// if !ok {
// req.ResultCh <- tryDeleteMetricResult{
// ResultCode: NoMetric,
// }
// return
// }
// lockEntry, ok := s.metricLockEntries[req.MetricID]
// if ok {
// lockEntry.WaitQueue = append(lockEntry.WaitQueue, req)
// } else {
// s.startDeleteMetric(metric, req)
// }
}
func (s *Worker) startDeleteMetric(metric *Metric, req DeleteMetricReq) {
// FIX
// s.metricLockEntries[req.MetricID] = &metricLockEntry{
// XLock: true,
// }
// req.ResultCh <- tryDeleteMetricResult{
// ResultCode: Succeed,
// RootPageNo: metric.RootPageNo,
// }
}
type DeleteMeasuresResult struct {
ResultCode byte
RootPageNo uint32
metric, ok := s.metrics[req.MetricID]
if !ok {
req.ResultCh <- NoMetric
return
}
if metric.xLock {
metric.waitQueue = append(metric.waitQueue, req)
} else {
// collect all pages, than
s.storageInbox.Push(storage.MetricDelete{
MetricID: req.MetricID,
FreeIndexPages: nil,
FreeDataPages: nil,
ResultCh: req.ResultCh,
})
}
}
type DeleteMeasuresReq struct {
MetricID uint32
Since uint32
ResultCh chan DeleteMeasuresResult
ResultCh chan byte
}
func (s *Worker) DeleteMeasures(req DeleteMeasuresReq) {
// FIX
// metric, ok := s.metrics[req.MetricID]
// if !ok {
// req.ResultCh <- tryDeleteMeasuresResult{
// ResultCode: NoMetric,
// }
// return
// }
// if metric.Since == 0 || (req.Since > 0 && metric.Until < req.Since) {
// req.ResultCh <- tryDeleteMeasuresResult{
// ResultCode: NoMeasuresToDelete,
// }
// }
// lockEntry, ok := s.metricLockEntries[req.MetricID]
// if ok {
// lockEntry.WaitQueue = append(lockEntry.WaitQueue, req)
// } else {
// s.startDeleteMeasures(metric, req)
// }
}
func (s *Worker) startDeleteMeasures(metric *Metric, req DeleteMeasuresReq) {
// FIX
// s.metricLockEntries[req.MetricID] = &metricLockEntry{
// XLock: true,
// }
// if metric.RootPageNo > 0 {
// req.ResultCh <- tryDeleteMeasuresResult{
// ResultCode: DeleteFromAtreeRequired,
// RootPageNo: metric.RootPageNo,
// }
// } else {
// req.ResultCh <- tryDeleteMeasuresResult{
// ResultCode: DeleteFromAtreeNotNeeded,
// }
// }
}
func (s *Worker) onMeasuresAppendCommited(rec storage.MeasuresAppendCommited) {
metric, ok := s.metrics[rec.MetricID]
metric, ok := s.metrics[req.MetricID]
if !ok {
qb.Abort(qb.NoMetricBug,
fmt.Errorf("onMeasuresAppendCommited: metric %d not found",
rec.MetricID))
req.ResultCh <- NoMetric
return
}
metric.OnMeasuresAppendCommited(rec)
}
func (s *Worker) onMeasuresAppendWithGrowCommited(rec storage.MeasuresAppendWithGrowCommited) {
metric, ok := s.metrics[rec.MetricID]
if !ok {
qb.Abort(qb.NoMetricBug,
fmt.Errorf("finAppendMeasures: metric %d not found",
rec.MetricID))
}
metric.OnMeasuresAppendWithGrowCommited(rec)
metric.DeleteMeasures(req)
}
type AppendMeasuresReq struct {
@@ -420,10 +309,10 @@ func (s *Worker) AppendMeasures(req AppendMeasuresReq) {
return
}
if metric.xLock {
metric.WaitQueue = append(metric.WaitQueue, req)
return
metric.waitQueue = append(metric.waitQueue, req)
} else {
metric.AppendMeasures(req, s.tmp, s.storageInbox)
}
metric.AppendMeasures(req, s.tmp, s.storageInbox)
}
type RangeScanResult struct {
@@ -456,13 +345,11 @@ func (s *Worker) RangeScan(req RangeScanReq) {
}
return
}
if metric.xLock {
metric.WaitQueue = append(metric.WaitQueue, req)
return
metric.waitQueue = append(metric.waitQueue, req)
} else {
metric.StartRangeScan(req)
}
metric.StartRangeScan(req)
}
type FullScanResult struct {
@@ -492,12 +379,11 @@ func (s *Worker) FullScan(req FullScanReq) {
}
return
}
if metric.xLock {
metric.WaitQueue = append(metric.WaitQueue, req)
return
metric.waitQueue = append(metric.waitQueue, req)
} else {
metric.StartFullScan(req)
}
metric.StartFullScan(req)
}
type ListCurrentValuesReq struct {
@@ -566,65 +452,43 @@ func (s *Worker) onMetricAddCommited(rec storage.MetricAddCommited) {
metric, ok := s.metrics[rec.MetricID]
if !ok {
qb.Abort(qb.MetricAddedBug,
fmt.Errorf("metric %d not found after commit", rec.MetricID))
fmt.Errorf("onMetricAddCommited: metric %d not found", rec.MetricID))
}
metric.xLock = false
rec.ResultCh <- Succeed // new
rec.ResultCh <- Succeed
}
func (s *Worker) onMetricDeleteCommited(rec storage.MetricDeleteCommited) {
metric, ok := s.metrics[rec.MetricID]
if !ok {
qb.Abort(qb.NoMetricBug,
fmt.Errorf("deleteMetric: metric %d not found",
rec.MetricID))
fmt.Errorf("onMetricDeleteCommited: metric %d not found", rec.MetricID))
}
if !metric.xLock {
qb.Abort(qb.NoXLockBug,
fmt.Errorf("deleteMetric: xlock not set for the metric %d",
rec.MetricID))
}
var addMetricReqs []AddMetricReq
if len(metric.WaitQueue) > 0 {
for _, untyped := range metric.WaitQueue {
if len(metric.waitQueue) > 0 {
for _, untyped := range metric.waitQueue {
switch req := untyped.(type) {
// case tryAppendMeasureReq:
// req.ResultCh <- tryAppendMeasureResult{
// MetricID: req.MetricID,
// ResultCode: NoMetric,
// }
case AppendMeasuresReq:
req.ResultCh <- storage.MeasuresAppendResult{
ResultCode: NoMetric,
WrittenCount: 0,
}
case RangeScanReq:
req.ResultCh <- RangeScanResult{
ResultCode: NoMetric,
}
case FullScanReq:
req.ResultCh <- FullScanResult{
ResultCode: NoMetric,
}
case AddMetricReq:
addMetricReqs = append(addMetricReqs, req)
case DeleteMetricReq:
req.ResultCh <- DeleteMetricResult{
ResultCode: NoMetric,
}
req.ResultCh <- NoMetric
case DeleteMeasuresReq:
req.ResultCh <- DeleteMeasuresResult{
ResultCode: NoMetric,
}
req.ResultCh <- NoMetric
case GetMetricReq:
req.ResultCh <- GetMetricResult{
ResultCode: NoMetric,
}
default:
qb.Abort(qb.UnknownMetricWaitQueueItemBug,
fmt.Errorf("bug: unknown metric wait queue item type %T", req))
@@ -632,36 +496,39 @@ func (s *Worker) onMetricDeleteCommited(rec storage.MetricDeleteCommited) {
}
}
delete(s.metrics, rec.MetricID)
//
rec.ResultCh <- Succeed
}
// ADD in storage
// if len(rec.FreePageNumbers) > 0 {
// s.freeList.AddPages(rec.FreePageNumbers)
// }
if len(addMetricReqs) > 0 {
s.processTryAddMetricReqsImmediatelyAfterDelete(addMetricReqs)
func (s *Worker) onMeasuresAppendCommited(rec storage.MeasuresAppendCommited) {
metric, ok := s.metrics[rec.MetricID]
if !ok {
qb.Abort(qb.NoMetricBug,
fmt.Errorf("onMeasuresAppendCommited: metric %d not found",
rec.MetricID))
}
metric.OnMeasuresAppendCommited(rec)
}
func (s *Worker) onMeasuresAppendWithGrowCommited(rec storage.MeasuresAppendWithGrowCommited) {
metric, ok := s.metrics[rec.MetricID]
if !ok {
qb.Abort(qb.NoMetricBug,
fmt.Errorf("onMeasuresAppendWithGrowCommited: metric %d not found",
rec.MetricID))
}
metric.OnMeasuresAppendWithGrowCommited(rec)
}
func (s *Worker) onMeasuresDeleteCommited(rec storage.MeasuresDeleteCommited) {
metric, ok := s.metrics[rec.MetricID]
if !ok {
qb.Abort(qb.NoMetricBug,
fmt.Errorf("deleteMeasures: metric %d not found",
rec.MetricID))
}
if !metric.xLock {
qb.Abort(qb.NoXLockBug,
fmt.Errorf("deleteMeasures: xlock not set for the metric %d",
rec.MetricID))
fmt.Errorf("onMeasuresDeleteCommited: metric %d not found", rec.MetricID))
}
metric.OnMeasuresDeleteCommited(rec)
metric.xLock = false
// FIX add in storage
// if len(rec.FreePageNumbers) > 0 {
// s.freeList.AddPages(rec.FreePageNumbers)
// }
//s.doAfterReleaseXLock(rec.MetricID, metric)
}