2026-06-13 22:43:17 +00:00
|
|
|
|
package worker
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"fmt"
|
2026-06-13 19:53:27 +03:00
|
|
|
|
"sync"
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-05-14 16:06:37 +03:00
|
|
|
|
qb "gordenko.dev/dima/qb"
|
2026-02-10 14:02:11 +00:00
|
|
|
|
"gordenko.dev/dima/qb/atree"
|
2026-06-09 08:16:16 +03:00
|
|
|
|
"gordenko.dev/dima/qb/enc"
|
2026-06-13 22:43:17 +00:00
|
|
|
|
"gordenko.dev/dima/qb/inbox"
|
2026-05-10 19:15:11 +00:00
|
|
|
|
"gordenko.dev/dima/qb/proto"
|
2026-06-10 06:18:45 +03:00
|
|
|
|
"gordenko.dev/dima/qb/storage"
|
2026-02-10 14:02:11 +00:00
|
|
|
|
"gordenko.dev/dima/qb/transform"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2026-05-31 20:01:28 +00:00
|
|
|
|
// AddMetric - create metric in map and set Xlock, rwad - append to queue
|
|
|
|
|
|
// DeleteMetric - set Xlock
|
|
|
|
|
|
// DeleteSince - xLock (тупо редкая операция)
|
|
|
|
|
|
// Якийсь прапор поставити для pendingDelete, щоб read операції вставали в чергу
|
|
|
|
|
|
|
2026-02-10 14:02:11 +00:00
|
|
|
|
const (
|
|
|
|
|
|
QueryDone = 1
|
|
|
|
|
|
UntilFound = 2
|
|
|
|
|
|
UntilNotFound = 3
|
|
|
|
|
|
RangeFound = 15
|
|
|
|
|
|
NoMeasures = 16
|
|
|
|
|
|
NoMetric = 4
|
|
|
|
|
|
MetricDuplicate = 5
|
|
|
|
|
|
Succeed = 6
|
|
|
|
|
|
NewPage = 7
|
|
|
|
|
|
ExpiredMeasure = 8
|
|
|
|
|
|
NonMonotonicValue = 9
|
|
|
|
|
|
CanAppend = 10
|
|
|
|
|
|
WrongMetricType = 11
|
|
|
|
|
|
NoMeasuresToDelete = 12
|
|
|
|
|
|
DeleteFromAtreeNotNeeded = 13
|
|
|
|
|
|
DeleteFromAtreeRequired = 14
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2026-06-13 19:53:27 +03:00
|
|
|
|
type Worker struct {
|
2026-06-13 22:43:17 +00:00
|
|
|
|
inbox *inbox.Inbox
|
|
|
|
|
|
storageInbox *inbox.Inbox
|
2026-06-13 19:53:27 +03:00
|
|
|
|
dir string
|
|
|
|
|
|
snapshotNumber int
|
|
|
|
|
|
tmp []byte
|
2026-06-13 22:43:17 +00:00
|
|
|
|
metrics map[uint32]*Metric
|
2026-06-13 19:53:27 +03:00
|
|
|
|
exitCh chan struct{}
|
|
|
|
|
|
waitGroup *sync.WaitGroup
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-14 07:57:01 +03:00
|
|
|
|
type Options struct {
|
|
|
|
|
|
Inbox *inbox.Inbox
|
|
|
|
|
|
StorageInbox *inbox.Inbox
|
|
|
|
|
|
ReplayMetrics map[uint32]*storage.ReplayMetric
|
|
|
|
|
|
Dir string
|
|
|
|
|
|
ExitCh chan struct{}
|
|
|
|
|
|
WaitGroup *sync.WaitGroup
|
2026-06-13 19:53:27 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-14 07:57:01 +03:00
|
|
|
|
func New(opt Options) *Worker {
|
|
|
|
|
|
s := &Worker{
|
2026-06-13 22:43:17 +00:00
|
|
|
|
inbox: opt.Inbox,
|
|
|
|
|
|
storageInbox: opt.StorageInbox,
|
|
|
|
|
|
dir: opt.Dir,
|
|
|
|
|
|
tmp: make([]byte, 26),
|
2026-06-14 07:57:01 +03:00
|
|
|
|
metrics: make(map[uint32]*Metric),
|
2026-06-13 22:43:17 +00:00
|
|
|
|
exitCh: opt.ExitCh,
|
|
|
|
|
|
waitGroup: opt.WaitGroup,
|
2026-06-13 19:53:27 +03:00
|
|
|
|
}
|
2026-06-14 07:57:01 +03:00
|
|
|
|
|
|
|
|
|
|
for metricID, x := range opt.ReplayMetrics {
|
|
|
|
|
|
databuf := x.Buf[:storage.DataPagePayloadSize]
|
|
|
|
|
|
values := enc.NewValueDeltaCompressor(x.MetricType, x.FracDigits, databuf, x.ValuesSize)
|
|
|
|
|
|
s.metrics[metricID] = &Metric{
|
|
|
|
|
|
metricType: x.MetricType,
|
|
|
|
|
|
fracDigits: x.FracDigits,
|
|
|
|
|
|
lastPageNo: x.LastPageNo,
|
|
|
|
|
|
lastValue: values.LastValue(),
|
|
|
|
|
|
buffer: x.Buf,
|
|
|
|
|
|
timestamps: enc.NewTimeDeltaCompressor(databuf, x.TimestampsSize),
|
|
|
|
|
|
values: values,
|
|
|
|
|
|
indexLevelTails: x.IndexLevelTails,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return s
|
2026-06-13 19:53:27 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *Worker) ReleaseRLock(metricID uint32) {
|
2026-06-13 22:43:17 +00:00
|
|
|
|
// s.mutex.Lock()
|
|
|
|
|
|
// //s.rLocksToRelease = append(s.rLocksToRelease, metricID)
|
|
|
|
|
|
// s.mutex.Unlock()
|
2026-06-13 19:53:27 +03:00
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
// select {
|
|
|
|
|
|
// case s.signalCh <- struct{}{}:
|
|
|
|
|
|
// default:
|
|
|
|
|
|
// }
|
2026-06-13 19:53:27 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *Worker) Run() {
|
2026-02-10 14:02:11 +00:00
|
|
|
|
for {
|
|
|
|
|
|
select {
|
2026-06-13 22:43:17 +00:00
|
|
|
|
case <-s.inbox.Ready():
|
2026-06-13 19:53:27 +03:00
|
|
|
|
s.doWork()
|
|
|
|
|
|
|
|
|
|
|
|
case <-s.exitCh:
|
|
|
|
|
|
fmt.Println("worker done")
|
|
|
|
|
|
s.waitGroup.Done()
|
|
|
|
|
|
return
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 19:53:27 +03:00
|
|
|
|
func (s *Worker) doWork() {
|
2026-06-13 22:43:17 +00:00
|
|
|
|
queue := s.inbox.Drain()
|
2026-06-13 19:53:27 +03:00
|
|
|
|
|
|
|
|
|
|
//rLocksToRelease := s.rLocksToRelease
|
|
|
|
|
|
//s.rLocksToRelease = nil
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-06-13 19:53:27 +03:00
|
|
|
|
// for _, metricID := range rLocksToRelease {
|
|
|
|
|
|
// metric, ok := s.metrics[metricID]
|
|
|
|
|
|
// if !ok {
|
|
|
|
|
|
// qb.Abort(qb.NoMetricBug,
|
|
|
|
|
|
// fmt.Errorf("drainQueues: metric %d not found", metricID))
|
|
|
|
|
|
// }
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-06-13 19:53:27 +03:00
|
|
|
|
// if metric.XLock {
|
|
|
|
|
|
// qb.Abort(qb.XLockBug,
|
|
|
|
|
|
// fmt.Errorf("drainQueues: xlock is set for the metric %d",
|
|
|
|
|
|
// metricID))
|
|
|
|
|
|
// }
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-06-13 19:53:27 +03:00
|
|
|
|
// if metric.RLocks <= 0 {
|
|
|
|
|
|
// qb.Abort(qb.NoRLockBug,
|
|
|
|
|
|
// fmt.Errorf("drainQueues: rlock not set for the metric %d",
|
|
|
|
|
|
// metricID))
|
|
|
|
|
|
// }
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-06-13 19:53:27 +03:00
|
|
|
|
// metric.RLocks--
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-06-13 19:53:27 +03:00
|
|
|
|
// if len(metric.WaitQueue) > 0 {
|
|
|
|
|
|
// s.processMetricQueue(metricID, metric)
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-06-13 19:53:27 +03:00
|
|
|
|
for _, untyped := range queue {
|
2026-02-10 14:02:11 +00:00
|
|
|
|
switch req := untyped.(type) {
|
2026-06-13 22:43:17 +00:00
|
|
|
|
case AppendMeasuresReq:
|
|
|
|
|
|
s.AppendMeasures(req)
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-06-10 06:18:45 +03:00
|
|
|
|
case storage.Changes:
|
2026-06-13 07:13:03 +00:00
|
|
|
|
s.applyCommits(req) // all metrics only
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
case ListCurrentValuesReq:
|
2026-02-10 14:02:11 +00:00
|
|
|
|
s.tryListCurrentValues(req) // all metrics only
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
case RangeScanReq:
|
|
|
|
|
|
s.RangeScan(req)
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
case FullScanReq:
|
2026-02-10 14:02:11 +00:00
|
|
|
|
s.tryFullScan(req)
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
case AddMetricReq:
|
|
|
|
|
|
s.AddMetric(req)
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
case DeleteMetricReq:
|
|
|
|
|
|
s.DeleteMetric(req)
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
case DeleteMeasuresReq:
|
|
|
|
|
|
s.DeleteMeasures(req)
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
case GetMetricReq:
|
|
|
|
|
|
s.GetMetric(req)
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
|
|
|
|
|
default:
|
2026-05-14 16:06:37 +03:00
|
|
|
|
qb.Abort(qb.UnknownWorkerQueueItemBug,
|
2026-02-10 14:02:11 +00:00
|
|
|
|
fmt.Errorf("bug: unknown worker queue item type %T", req))
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-31 20:01:28 +00:00
|
|
|
|
// суть у тому що треба запускати запити, пока не зустріну XLock
|
2026-06-13 22:43:17 +00:00
|
|
|
|
func (s *Worker) processMetricQueue(metricID uint32, metric *Metric, tmp []byte) {
|
2026-05-31 20:01:28 +00:00
|
|
|
|
if len(metric.WaitQueue) == 0 {
|
2026-02-10 14:02:11 +00:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-31 20:01:28 +00:00
|
|
|
|
for _, untyped := range metric.WaitQueue {
|
2026-02-10 14:02:11 +00:00
|
|
|
|
switch req := untyped.(type) {
|
2026-06-13 22:43:17 +00:00
|
|
|
|
case RangeScanReq:
|
2026-05-31 20:01:28 +00:00
|
|
|
|
metric.StartRangeScan(req)
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
case FullScanReq:
|
2026-05-31 20:01:28 +00:00
|
|
|
|
metric.StartFullScan(req)
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
case GetMetricReq:
|
|
|
|
|
|
s.GetMetric(req)
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
case AppendMeasuresReq:
|
2026-06-14 07:57:01 +03:00
|
|
|
|
metric.StartAppendMeasures(req, tmp, s.storageInbox)
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
case DeleteMetricReq:
|
2026-05-31 20:01:28 +00:00
|
|
|
|
s.startDeleteMetric(metric, req)
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
case DeleteMeasuresReq:
|
2026-05-31 20:01:28 +00:00
|
|
|
|
s.startDeleteMeasures(metric, req)
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-05-31 20:01:28 +00:00
|
|
|
|
default:
|
|
|
|
|
|
qb.Abort(qb.UnknownMetricWaitQueueItemBug,
|
|
|
|
|
|
fmt.Errorf("bug: unknown metric wait queue item type %T", req))
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
type AddMetricReq struct {
|
2026-02-10 14:02:11 +00:00
|
|
|
|
MetricID uint32
|
|
|
|
|
|
ResultCh chan byte
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
func (s *Worker) AddMetric(req AddMetricReq) {
|
2026-02-10 14:02:11 +00:00
|
|
|
|
_, ok := s.metrics[req.MetricID]
|
|
|
|
|
|
if ok {
|
|
|
|
|
|
req.ResultCh <- MetricDuplicate
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2026-06-13 19:53:27 +03:00
|
|
|
|
fmt.Println("metric not found. Success")
|
2026-05-10 19:15:11 +00:00
|
|
|
|
req.ResultCh <- Succeed // new
|
|
|
|
|
|
|
|
|
|
|
|
// lockEntry, ok := s.metricLockEntries[req.MetricID]
|
|
|
|
|
|
// if ok {
|
|
|
|
|
|
// lockEntry.WaitQueue = append(lockEntry.WaitQueue, req)
|
|
|
|
|
|
// } else {
|
|
|
|
|
|
// s.metricLockEntries[req.MetricID] = &metricLockEntry{
|
|
|
|
|
|
// XLock: true,
|
|
|
|
|
|
// }
|
|
|
|
|
|
// req.ResultCh <- Succeed
|
|
|
|
|
|
// }
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
func (s *Worker) processTryAddMetricReqsImmediatelyAfterDelete(reqs []AddMetricReq) {
|
2026-02-10 14:02:11 +00:00
|
|
|
|
if len(reqs) == 0 {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
var (
|
|
|
|
|
|
req = reqs[0]
|
|
|
|
|
|
waitQueue []any
|
|
|
|
|
|
)
|
|
|
|
|
|
if len(reqs) > 1 {
|
|
|
|
|
|
for _, req := range reqs[1:] {
|
|
|
|
|
|
waitQueue = append(waitQueue, req)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-05-10 19:15:11 +00:00
|
|
|
|
// FIX
|
|
|
|
|
|
// s.metricLockEntries[req.MetricID] = &metricLockEntry{
|
|
|
|
|
|
// XLock: true,
|
|
|
|
|
|
// WaitQueue: waitQueue,
|
|
|
|
|
|
// }
|
2026-02-10 14:02:11 +00:00
|
|
|
|
req.ResultCh <- Succeed
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
type GetMetricResult struct {
|
|
|
|
|
|
MetricType qb.MetricType
|
|
|
|
|
|
FracDigits byte
|
|
|
|
|
|
ResultCode byte
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type GetMetricReq struct {
|
2026-02-10 14:02:11 +00:00
|
|
|
|
MetricID uint32
|
2026-06-13 22:43:17 +00:00
|
|
|
|
ResultCh chan GetMetricResult
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
func (s *Worker) GetMetric(req GetMetricReq) {
|
2026-02-10 14:02:11 +00:00
|
|
|
|
metric, ok := s.metrics[req.MetricID]
|
|
|
|
|
|
if ok {
|
2026-06-13 22:43:17 +00:00
|
|
|
|
req.ResultCh <- GetMetricResult{
|
2026-02-10 14:02:11 +00:00
|
|
|
|
ResultCode: Succeed,
|
2026-06-14 07:57:01 +03:00
|
|
|
|
MetricType: metric.MetricType(),
|
|
|
|
|
|
FracDigits: metric.FracDigits(),
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
} else {
|
2026-06-13 22:43:17 +00:00
|
|
|
|
req.ResultCh <- GetMetricResult{
|
2026-02-10 14:02:11 +00:00
|
|
|
|
ResultCode: NoMetric,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
type DeleteMetricResult struct {
|
|
|
|
|
|
ResultCode byte
|
|
|
|
|
|
RootPageNo uint32
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type DeleteMetricReq struct {
|
2026-02-10 14:02:11 +00:00
|
|
|
|
MetricID uint32
|
2026-06-13 22:43:17 +00:00
|
|
|
|
ResultCh chan DeleteMetricResult
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
func (s *Worker) DeleteMetric(req DeleteMetricReq) {
|
2026-05-10 19:15:11 +00:00
|
|
|
|
// 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)
|
|
|
|
|
|
// }
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
func (s *Worker) startDeleteMetric(metric *Metric, req DeleteMetricReq) {
|
2026-05-10 19:15:11 +00:00
|
|
|
|
// FIX
|
|
|
|
|
|
// s.metricLockEntries[req.MetricID] = &metricLockEntry{
|
|
|
|
|
|
// XLock: true,
|
|
|
|
|
|
// }
|
|
|
|
|
|
// req.ResultCh <- tryDeleteMetricResult{
|
|
|
|
|
|
// ResultCode: Succeed,
|
|
|
|
|
|
// RootPageNo: metric.RootPageNo,
|
|
|
|
|
|
// }
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
type DeleteMeasuresResult struct {
|
|
|
|
|
|
ResultCode byte
|
|
|
|
|
|
RootPageNo uint32
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type DeleteMeasuresReq struct {
|
2026-02-10 14:02:11 +00:00
|
|
|
|
MetricID uint32
|
|
|
|
|
|
Since uint32
|
2026-06-13 22:43:17 +00:00
|
|
|
|
ResultCh chan DeleteMeasuresResult
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
func (s *Worker) DeleteMeasures(req DeleteMeasuresReq) {
|
2026-05-10 19:15:11 +00:00
|
|
|
|
// 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)
|
|
|
|
|
|
// }
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
func (s *Worker) startDeleteMeasures(metric *Metric, req DeleteMeasuresReq) {
|
2026-05-10 19:15:11 +00:00
|
|
|
|
// 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,
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 19:53:27 +03:00
|
|
|
|
func (s *Worker) onMeasuresAppendCommited(rec storage.MeasuresAppendCommited) {
|
2026-02-10 14:02:11 +00:00
|
|
|
|
metric, ok := s.metrics[rec.MetricID]
|
|
|
|
|
|
if !ok {
|
2026-05-14 16:06:37 +03:00
|
|
|
|
qb.Abort(qb.NoMetricBug,
|
2026-05-31 20:01:28 +00:00
|
|
|
|
fmt.Errorf("finAppendMeasures: metric %d not found",
|
2026-02-10 14:02:11 +00:00
|
|
|
|
rec.MetricID))
|
|
|
|
|
|
}
|
2026-06-13 07:13:03 +00:00
|
|
|
|
metric.OnMeasuresAppendCommited(rec)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 19:53:27 +03:00
|
|
|
|
func (s *Worker) onMeasuresAppendWithGrowCommited(rec storage.MeasuresAppendWithGrowCommited) {
|
2026-06-13 07:13:03 +00:00
|
|
|
|
metric, ok := s.metrics[rec.MetricID]
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
qb.Abort(qb.NoMetricBug,
|
|
|
|
|
|
fmt.Errorf("finAppendMeasures: metric %d not found",
|
|
|
|
|
|
rec.MetricID))
|
|
|
|
|
|
}
|
|
|
|
|
|
metric.OnMeasuresAppendWithGrowCommited(rec)
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
type AppendMeasuresResult struct {
|
|
|
|
|
|
ResultCode byte
|
|
|
|
|
|
Written int
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type AppendMeasuresReq struct {
|
2026-02-10 14:02:11 +00:00
|
|
|
|
MetricID uint32
|
2026-05-10 19:15:11 +00:00
|
|
|
|
Measures []proto.Measure
|
2026-06-13 22:43:17 +00:00
|
|
|
|
ResultCh chan AppendMeasuresResult
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
func (s *Worker) AppendMeasures(req AppendMeasuresReq) {
|
2026-02-10 14:02:11 +00:00
|
|
|
|
metric, ok := s.metrics[req.MetricID]
|
|
|
|
|
|
if !ok {
|
2026-06-13 22:43:17 +00:00
|
|
|
|
req.ResultCh <- AppendMeasuresResult{
|
2026-02-10 14:02:11 +00:00
|
|
|
|
ResultCode: NoMetric,
|
|
|
|
|
|
}
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2026-05-31 20:01:28 +00:00
|
|
|
|
if metric.XLock {
|
|
|
|
|
|
metric.WaitQueue = append(metric.WaitQueue, req)
|
|
|
|
|
|
return
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
2026-06-14 07:57:01 +03:00
|
|
|
|
metric.StartAppendMeasures(req, s.tmp, s.storageInbox)
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
type RangeScanResult struct {
|
|
|
|
|
|
ResultCode byte
|
|
|
|
|
|
FracDigits byte
|
|
|
|
|
|
RootPageNo uint32
|
|
|
|
|
|
LastPageNo uint32
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type RangeScanReq struct {
|
2026-02-10 14:02:11 +00:00
|
|
|
|
MetricID uint32
|
|
|
|
|
|
Since uint32
|
|
|
|
|
|
Until uint32
|
2026-05-14 16:06:37 +03:00
|
|
|
|
MetricType qb.MetricType
|
2026-02-10 14:02:11 +00:00
|
|
|
|
ResponseWriter atree.WorkerMeasureConsumer
|
2026-06-13 22:43:17 +00:00
|
|
|
|
ResultCh chan RangeScanResult
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
func (s *Worker) RangeScan(req RangeScanReq) {
|
2026-02-10 14:02:11 +00:00
|
|
|
|
metric, ok := s.metrics[req.MetricID]
|
|
|
|
|
|
if !ok {
|
2026-06-13 22:43:17 +00:00
|
|
|
|
req.ResultCh <- RangeScanResult{
|
2026-02-10 14:02:11 +00:00
|
|
|
|
ResultCode: NoMetric,
|
|
|
|
|
|
}
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2026-06-14 07:57:01 +03:00
|
|
|
|
if metric.MetricType() != req.MetricType {
|
2026-06-13 22:43:17 +00:00
|
|
|
|
req.ResultCh <- RangeScanResult{
|
2026-02-10 14:02:11 +00:00
|
|
|
|
ResultCode: WrongMetricType,
|
|
|
|
|
|
}
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-31 20:01:28 +00:00
|
|
|
|
if metric.XLock {
|
|
|
|
|
|
metric.WaitQueue = append(metric.WaitQueue, req)
|
|
|
|
|
|
return
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-31 20:01:28 +00:00
|
|
|
|
metric.StartRangeScan(req)
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
type FullScanResult struct {
|
|
|
|
|
|
ResultCode byte
|
|
|
|
|
|
FracDigits byte
|
|
|
|
|
|
LastPageNo uint32
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type FullScanReq struct {
|
2026-02-10 14:02:11 +00:00
|
|
|
|
MetricID uint32
|
2026-05-14 16:06:37 +03:00
|
|
|
|
MetricType qb.MetricType
|
2026-02-10 14:02:11 +00:00
|
|
|
|
ResponseWriter atree.WorkerMeasureConsumer
|
2026-06-13 22:43:17 +00:00
|
|
|
|
ResultCh chan FullScanResult
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
func (s *Worker) tryFullScan(req FullScanReq) {
|
2026-02-10 14:02:11 +00:00
|
|
|
|
metric, ok := s.metrics[req.MetricID]
|
|
|
|
|
|
if !ok {
|
2026-06-13 22:43:17 +00:00
|
|
|
|
req.ResultCh <- FullScanResult{
|
2026-02-10 14:02:11 +00:00
|
|
|
|
ResultCode: NoMetric,
|
|
|
|
|
|
}
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2026-06-14 07:57:01 +03:00
|
|
|
|
if metric.MetricType() != req.MetricType {
|
2026-06-13 22:43:17 +00:00
|
|
|
|
req.ResultCh <- FullScanResult{
|
2026-02-10 14:02:11 +00:00
|
|
|
|
ResultCode: WrongMetricType,
|
|
|
|
|
|
}
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-31 20:01:28 +00:00
|
|
|
|
if metric.XLock {
|
|
|
|
|
|
metric.WaitQueue = append(metric.WaitQueue, req)
|
|
|
|
|
|
return
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
2026-05-31 20:01:28 +00:00
|
|
|
|
metric.StartFullScan(req)
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
type ListCurrentValuesReq struct {
|
2026-02-10 14:02:11 +00:00
|
|
|
|
MetricIDs []uint32
|
|
|
|
|
|
ResponseWriter *transform.CurrentValueWriter
|
|
|
|
|
|
ResultCh chan struct{}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
func (s *Worker) tryListCurrentValues(req ListCurrentValuesReq) {
|
2026-02-10 14:02:11 +00:00
|
|
|
|
for _, metricID := range req.MetricIDs {
|
|
|
|
|
|
metric, ok := s.metrics[metricID]
|
|
|
|
|
|
if ok {
|
|
|
|
|
|
req.ResponseWriter.BufferValue(transform.CurrentValue{
|
|
|
|
|
|
MetricID: metricID,
|
2026-06-13 08:01:42 +03:00
|
|
|
|
Timestamp: metric.LastTimestamp(),
|
|
|
|
|
|
Value: metric.LastValue(),
|
2026-02-10 14:02:11 +00:00
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
req.ResultCh <- struct{}{}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////
|
|
|
|
|
|
|
2026-06-13 19:53:27 +03:00
|
|
|
|
func (s *Worker) applyCommits(req storage.Changes) {
|
2026-06-13 07:13:03 +00:00
|
|
|
|
for _, untyped := range req.Commits {
|
2026-02-10 14:02:11 +00:00
|
|
|
|
switch rec := untyped.(type) {
|
2026-06-13 07:13:03 +00:00
|
|
|
|
case storage.MetricAddCommited:
|
|
|
|
|
|
s.onMetricAddCommited(rec)
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-06-13 07:13:03 +00:00
|
|
|
|
case storage.MetricDeleteCommited:
|
|
|
|
|
|
s.onMetricDeleteCommited(rec)
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-06-13 07:13:03 +00:00
|
|
|
|
case storage.MeasuresAppendCommited:
|
|
|
|
|
|
s.onMeasuresAppendCommited(rec)
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-06-13 08:01:42 +03:00
|
|
|
|
case storage.MeasuresAppendWithGrowCommited:
|
2026-06-13 07:13:03 +00:00
|
|
|
|
s.onMeasuresAppendWithGrowCommited(rec)
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-06-13 07:13:03 +00:00
|
|
|
|
case storage.MeasuresDeleteCommited:
|
|
|
|
|
|
s.onMeasuresDeleteCommited(rec)
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-09 08:16:16 +03:00
|
|
|
|
if req.SnapshotNumberCh != nil {
|
|
|
|
|
|
s.snapshotNumber++
|
2026-06-14 07:57:01 +03:00
|
|
|
|
err := WriteSnapshot(WriteSnapshotIn{
|
2026-06-09 08:16:16 +03:00
|
|
|
|
SnapshotNumber: s.snapshotNumber,
|
|
|
|
|
|
Dir: s.dir,
|
2026-06-10 06:18:45 +03:00
|
|
|
|
WriteBufferSize: 4 * 1024 * 1024, // 1mb
|
2026-06-09 08:16:16 +03:00
|
|
|
|
Metrics: s.metrics,
|
|
|
|
|
|
FrozenIndexPagesCount: req.FrozenIndexPagesCount,
|
|
|
|
|
|
IndexPageNumbers: req.IndexPageNumbers,
|
|
|
|
|
|
FrozenDataPagesCount: req.FrozenDataPagesCount,
|
|
|
|
|
|
DataPageNumbers: req.DataPageNumbers,
|
|
|
|
|
|
})
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
qb.Abort(qb.WriteSnapshotFailed, err)
|
2026-05-31 20:01:28 +00:00
|
|
|
|
}
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-06-09 08:16:16 +03:00
|
|
|
|
req.SnapshotNumberCh <- s.snapshotNumber
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 19:53:27 +03:00
|
|
|
|
func (s *Worker) onMetricAddCommited(rec storage.MetricAddCommited) {
|
2026-05-31 20:01:28 +00:00
|
|
|
|
// fix lock
|
2026-02-10 14:02:11 +00:00
|
|
|
|
_, ok := s.metrics[rec.MetricID]
|
|
|
|
|
|
if ok {
|
2026-05-14 16:06:37 +03:00
|
|
|
|
qb.Abort(qb.MetricAddedBug,
|
2026-02-10 14:02:11 +00:00
|
|
|
|
fmt.Errorf("addMetric: metric %d already added",
|
|
|
|
|
|
rec.MetricID))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-31 20:01:28 +00:00
|
|
|
|
// if !lockEntry.XLock {
|
|
|
|
|
|
// qb.Abort(qb.NoXLockBug,
|
|
|
|
|
|
// fmt.Errorf("addMetric: xlock not set for the metric %d",
|
|
|
|
|
|
// rec.MetricID))
|
|
|
|
|
|
// }
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-06-09 08:16:16 +03:00
|
|
|
|
// lockEntry.XLock = false
|
|
|
|
|
|
// delete(s.metricLockEntries, rec.MetricID)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 19:53:27 +03:00
|
|
|
|
func (s *Worker) addMetric(rec storage.MetricAddRecord) {
|
2026-02-10 14:02:11 +00:00
|
|
|
|
var (
|
2026-06-12 06:11:57 +00:00
|
|
|
|
buf = make([]byte, storage.DataPageSize)
|
|
|
|
|
|
databuf = buf[:storage.DataPagePayloadSize]
|
2026-02-10 14:02:11 +00:00
|
|
|
|
)
|
2026-06-13 22:43:17 +00:00
|
|
|
|
s.metrics[rec.MetricID] = &Metric{
|
2026-06-09 08:16:16 +03:00
|
|
|
|
metricType: rec.MetricType,
|
2026-06-12 06:11:57 +00:00
|
|
|
|
fracDigits: rec.FracDigits,
|
|
|
|
|
|
buffer: buf,
|
|
|
|
|
|
timestamps: enc.NewTimeDeltaCompressor(databuf, 0),
|
|
|
|
|
|
values: enc.NewValueDeltaCompressor(rec.MetricType, rec.FracDigits, databuf, 0),
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 19:53:27 +03:00
|
|
|
|
func (s *Worker) onMetricDeleteCommited(rec storage.MetricDeleteCommited) {
|
2026-05-31 20:01:28 +00:00
|
|
|
|
metric, ok := s.metrics[rec.MetricID]
|
2026-02-10 14:02:11 +00:00
|
|
|
|
if !ok {
|
2026-05-14 16:06:37 +03:00
|
|
|
|
qb.Abort(qb.NoMetricBug,
|
2026-02-10 14:02:11 +00:00
|
|
|
|
fmt.Errorf("deleteMetric: metric %d not found",
|
|
|
|
|
|
rec.MetricID))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-31 20:01:28 +00:00
|
|
|
|
if !metric.XLock {
|
2026-05-14 16:06:37 +03:00
|
|
|
|
qb.Abort(qb.NoXLockBug,
|
2026-02-10 14:02:11 +00:00
|
|
|
|
fmt.Errorf("deleteMetric: xlock not set for the metric %d",
|
|
|
|
|
|
rec.MetricID))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
var addMetricReqs []AddMetricReq
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-05-31 20:01:28 +00:00
|
|
|
|
if len(metric.WaitQueue) > 0 {
|
|
|
|
|
|
for _, untyped := range metric.WaitQueue {
|
2026-02-10 14:02:11 +00:00
|
|
|
|
switch req := untyped.(type) {
|
2026-05-10 19:15:11 +00:00
|
|
|
|
// case tryAppendMeasureReq:
|
|
|
|
|
|
// req.ResultCh <- tryAppendMeasureResult{
|
|
|
|
|
|
// MetricID: req.MetricID,
|
|
|
|
|
|
// ResultCode: NoMetric,
|
|
|
|
|
|
// }
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
case RangeScanReq:
|
|
|
|
|
|
req.ResultCh <- RangeScanResult{
|
2026-02-10 14:02:11 +00:00
|
|
|
|
ResultCode: NoMetric,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
case FullScanReq:
|
|
|
|
|
|
req.ResultCh <- FullScanResult{
|
2026-02-10 14:02:11 +00:00
|
|
|
|
ResultCode: NoMetric,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
case AddMetricReq:
|
2026-02-10 14:02:11 +00:00
|
|
|
|
addMetricReqs = append(addMetricReqs, req)
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
case DeleteMetricReq:
|
|
|
|
|
|
req.ResultCh <- DeleteMetricResult{
|
2026-02-10 14:02:11 +00:00
|
|
|
|
ResultCode: NoMetric,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
case DeleteMeasuresReq:
|
|
|
|
|
|
req.ResultCh <- DeleteMeasuresResult{
|
2026-02-10 14:02:11 +00:00
|
|
|
|
ResultCode: NoMetric,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 22:43:17 +00:00
|
|
|
|
case GetMetricReq:
|
|
|
|
|
|
req.ResultCh <- GetMetricResult{
|
2026-02-10 14:02:11 +00:00
|
|
|
|
ResultCode: NoMetric,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
2026-05-14 16:06:37 +03:00
|
|
|
|
qb.Abort(qb.UnknownMetricWaitQueueItemBug,
|
2026-02-10 14:02:11 +00:00
|
|
|
|
fmt.Errorf("bug: unknown metric wait queue item type %T", req))
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
delete(s.metrics, rec.MetricID)
|
|
|
|
|
|
|
2026-06-10 06:18:45 +03:00
|
|
|
|
// ADD in storage
|
2026-05-31 20:01:28 +00:00
|
|
|
|
// if len(rec.FreePageNumbers) > 0 {
|
|
|
|
|
|
// s.freeList.AddPages(rec.FreePageNumbers)
|
|
|
|
|
|
// }
|
2026-02-10 14:02:11 +00:00
|
|
|
|
|
|
|
|
|
|
if len(addMetricReqs) > 0 {
|
|
|
|
|
|
s.processTryAddMetricReqsImmediatelyAfterDelete(addMetricReqs)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 19:53:27 +03:00
|
|
|
|
func (s *Worker) onMeasuresDeleteCommited(rec storage.MeasuresDeleteCommited) {
|
2026-02-10 14:02:11 +00:00
|
|
|
|
metric, ok := s.metrics[rec.MetricID]
|
|
|
|
|
|
if !ok {
|
2026-05-14 16:06:37 +03:00
|
|
|
|
qb.Abort(qb.NoMetricBug,
|
2026-02-10 14:02:11 +00:00
|
|
|
|
fmt.Errorf("deleteMeasures: metric %d not found",
|
|
|
|
|
|
rec.MetricID))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-31 20:01:28 +00:00
|
|
|
|
if !metric.XLock {
|
2026-05-14 16:06:37 +03:00
|
|
|
|
qb.Abort(qb.NoXLockBug,
|
2026-02-10 14:02:11 +00:00
|
|
|
|
fmt.Errorf("deleteMeasures: xlock not set for the metric %d",
|
|
|
|
|
|
rec.MetricID))
|
|
|
|
|
|
}
|
2026-06-13 07:13:03 +00:00
|
|
|
|
metric.OnMeasuresDeleteCommited(rec)
|
2026-05-31 20:01:28 +00:00
|
|
|
|
metric.XLock = false
|
2026-06-10 06:18:45 +03:00
|
|
|
|
// FIX add in storage
|
2026-05-31 20:01:28 +00:00
|
|
|
|
// if len(rec.FreePageNumbers) > 0 {
|
|
|
|
|
|
// s.freeList.AddPages(rec.FreePageNumbers)
|
|
|
|
|
|
// }
|
2026-06-13 19:53:27 +03:00
|
|
|
|
//s.doAfterReleaseXLock(rec.MetricID, metric)
|
2026-02-10 14:02:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-13 19:53:27 +03:00
|
|
|
|
// func (s *Database) doAfterReleaseXLock(metricID uint32, metric *_metric) {
|
|
|
|
|
|
// if len(metric.WaitQueue) > 0 {
|
|
|
|
|
|
// s.processMetricQueue(metricID, metric)
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|