Files
qb/database/proc.go

585 lines
13 KiB
Go
Raw Normal View History

2026-02-10 14:02:11 +00:00
package database
import (
"fmt"
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-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
)
func (s *Database) worker() {
for {
select {
case <-s.workerSignalCh:
s.DoWork()
}
}
}
func (s *Database) DoWork() {
s.mutex.Lock()
rLocksToRelease := s.rLocksToRelease
workerQueue := s.workerQueue
s.rLocksToRelease = nil
s.workerQueue = nil
s.mutex.Unlock()
for _, metricID := range rLocksToRelease {
2026-05-31 20:01:28 +00:00
metric, ok := s.metrics[metricID]
2026-02-10 14:02:11 +00:00
if !ok {
2026-05-31 20:01:28 +00:00
qb.Abort(qb.NoMetricBug,
fmt.Errorf("drainQueues: metric %d not found", metricID))
2026-02-10 14:02:11 +00:00
}
2026-05-31 20:01:28 +00:00
if metric.XLock {
2026-05-14 16:06:37 +03:00
qb.Abort(qb.XLockBug,
2026-02-10 14:02:11 +00:00
fmt.Errorf("drainQueues: xlock is set for the metric %d",
metricID))
}
2026-05-31 20:01:28 +00:00
if metric.RLocks <= 0 {
2026-05-14 16:06:37 +03:00
qb.Abort(qb.NoRLockBug,
2026-02-10 14:02:11 +00:00
fmt.Errorf("drainQueues: rlock not set for the metric %d",
metricID))
}
2026-05-31 20:01:28 +00:00
metric.RLocks--
2026-02-10 14:02:11 +00:00
2026-05-31 20:01:28 +00:00
if len(metric.WaitQueue) > 0 {
s.processMetricQueue(metricID, metric)
2026-02-10 14:02:11 +00:00
}
}
for _, untyped := range workerQueue {
switch req := untyped.(type) {
case tryAppendMeasuresReq:
s.tryAppendMeasures(req)
2026-06-10 06:18:45 +03:00
case storage.Changes:
2026-02-10 14:02:11 +00:00
s.applyChanges(req) // all metrics only
case tryListCurrentValuesReq:
s.tryListCurrentValues(req) // all metrics only
case tryRangeScanReq:
s.tryRangeScan(req)
case tryFullScanReq:
s.tryFullScan(req)
case tryAddMetricReq:
s.tryAddMetric(req)
case tryDeleteMetricReq:
s.tryDeleteMetric(req)
case tryDeleteMeasuresReq:
s.tryDeleteMeasures(req)
case tryGetMetricReq:
s.tryGetMetric(req)
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
func (s *Database) processMetricQueue(metricID uint32, metric *_metric) {
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) {
case tryRangeScanReq:
2026-05-31 20:01:28 +00:00
metric.StartRangeScan(req)
2026-02-10 14:02:11 +00:00
case tryFullScanReq:
2026-05-31 20:01:28 +00:00
metric.StartFullScan(req)
2026-02-10 14:02:11 +00:00
case tryGetMetricReq:
s.tryGetMetric(req)
2026-05-31 20:01:28 +00:00
case tryAppendMeasuresReq:
2026-06-12 00:29:02 +03:00
//metric.StartAppendMeasures(req, s.storage.Append) FIX
2026-02-10 14:02:11 +00:00
2026-05-31 20:01:28 +00:00
case tryDeleteMetricReq:
s.startDeleteMetric(metric, req)
2026-02-10 14:02:11 +00:00
2026-05-31 20:01:28 +00:00
case tryDeleteMeasuresReq:
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
}
}
}
type tryAddMetricReq struct {
MetricID uint32
ResultCh chan byte
}
func (s *Database) tryAddMetric(req tryAddMetricReq) {
_, ok := s.metrics[req.MetricID]
if ok {
req.ResultCh <- MetricDuplicate
return
}
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
}
func (s *Database) processTryAddMetricReqsImmediatelyAfterDelete(reqs []tryAddMetricReq) {
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
}
type tryGetMetricReq struct {
MetricID uint32
ResultCh chan Metric
}
func (s *Database) tryGetMetric(req tryGetMetricReq) {
metric, ok := s.metrics[req.MetricID]
if ok {
req.ResultCh <- Metric{
ResultCode: Succeed,
2026-06-09 08:16:16 +03:00
MetricType: metric.metricType,
FracDigits: metric.fracDigits,
2026-02-10 14:02:11 +00:00
}
} else {
req.ResultCh <- Metric{
ResultCode: NoMetric,
}
}
}
type tryDeleteMetricReq struct {
MetricID uint32
ResultCh chan tryDeleteMetricResult
}
func (s *Database) tryDeleteMetric(req tryDeleteMetricReq) {
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
}
func (s *Database) startDeleteMetric(metric *_metric, req tryDeleteMetricReq) {
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
}
type tryDeleteMeasuresReq struct {
MetricID uint32
Since uint32
ResultCh chan tryDeleteMeasuresResult
}
func (s *Database) tryDeleteMeasures(req tryDeleteMeasuresReq) {
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
}
func (s *Database) startDeleteMeasures(metric *_metric, req tryDeleteMeasuresReq) {
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-10 06:18:45 +03:00
func (s *Database) finAppendMeasures(rec storage.AppendMeasuresSummary) {
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-05-31 20:01:28 +00:00
metric.FinAppendMeasures(rec)
2026-02-10 14:02:11 +00:00
}
type tryAppendMeasuresReq struct {
MetricID uint32
2026-05-10 19:15:11 +00:00
Measures []proto.Measure
2026-02-10 14:02:11 +00:00
ResultCh chan tryAppendMeasuresResult
}
func (s *Database) tryAppendMeasures(req tryAppendMeasuresReq) {
metric, ok := s.metrics[req.MetricID]
if !ok {
req.ResultCh <- tryAppendMeasuresResult{
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-12 00:29:02 +03:00
//metric.StartAppendMeasures(req, s.storage.Append) FIX
2026-02-10 14:02:11 +00:00
}
type tryRangeScanReq struct {
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
ResultCh chan rangeScanResult
}
func (s *Database) tryRangeScan(req tryRangeScanReq) {
metric, ok := s.metrics[req.MetricID]
if !ok {
req.ResultCh <- rangeScanResult{
ResultCode: NoMetric,
}
return
}
2026-06-09 08:16:16 +03:00
if metric.metricType != req.MetricType {
2026-02-10 14:02:11 +00:00
req.ResultCh <- rangeScanResult{
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
}
type tryFullScanReq struct {
MetricID uint32
2026-05-14 16:06:37 +03:00
MetricType qb.MetricType
2026-02-10 14:02:11 +00:00
ResponseWriter atree.WorkerMeasureConsumer
ResultCh chan fullScanResult
}
func (s *Database) tryFullScan(req tryFullScanReq) {
metric, ok := s.metrics[req.MetricID]
if !ok {
req.ResultCh <- fullScanResult{
ResultCode: NoMetric,
}
return
}
2026-06-09 08:16:16 +03:00
if metric.metricType != req.MetricType {
2026-02-10 14:02:11 +00:00
req.ResultCh <- fullScanResult{
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
}
type tryListCurrentValuesReq struct {
MetricIDs []uint32
ResponseWriter *transform.CurrentValueWriter
ResultCh chan struct{}
}
func (s *Database) tryListCurrentValues(req tryListCurrentValuesReq) {
for _, metricID := range req.MetricIDs {
metric, ok := s.metrics[metricID]
if ok {
req.ResponseWriter.BufferValue(transform.CurrentValue{
MetricID: metricID,
2026-06-09 08:16:16 +03:00
Timestamp: metric.timestamps.LastTimestamp(),
Value: metric.lastValue,
2026-02-10 14:02:11 +00:00
})
}
}
req.ResultCh <- struct{}{}
}
///////////////////////////////////////////////////////
2026-06-10 06:18:45 +03:00
func (s *Database) applyChanges(req storage.Changes) {
2026-02-10 14:02:11 +00:00
for _, untyped := range req.Records {
switch rec := untyped.(type) {
2026-06-10 06:18:45 +03:00
case storage.MetricAddRecord:
2026-06-09 08:16:16 +03:00
s.applyAddMetric(rec)
2026-02-10 14:02:11 +00:00
2026-06-10 06:18:45 +03:00
case storage.MetricDeleteRecord:
2026-02-10 14:02:11 +00:00
s.deleteMetric(rec)
2026-06-10 06:18:45 +03:00
// case storage.AppendedMeasure:
2026-05-10 19:15:11 +00:00
// s.appendMeasure(rec)
2026-02-10 14:02:11 +00:00
2026-06-10 06:18:45 +03:00
case storage.AppendMeasuresSummary:
2026-05-31 20:01:28 +00:00
s.finAppendMeasures(rec)
2026-02-10 14:02:11 +00:00
2026-06-10 06:18:45 +03:00
// case storage.AppendedMeasureWithOverflowExtended:
2026-05-10 19:15:11 +00:00
// s.appendMeasureAfterOverflow(rec)
2026-02-10 14:02:11 +00:00
2026-06-10 06:18:45 +03:00
case storage.DeletedMeasures:
2026-02-10 14:02:11 +00:00
s.deleteMeasures(rec)
}
}
2026-06-09 08:16:16 +03:00
if req.SnapshotNumberCh != nil {
s.snapshotNumber++
err := writeSnapshot(writeSnapshotIn{
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-10 06:18:45 +03:00
func (s *Database) applyAddMetric(rec storage.MetricAddRecord) {
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-10 06:18:45 +03:00
func (s *Database) 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
)
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-10 06:18:45 +03:00
func (s *Database) deleteMetric(rec storage.MetricDeleteRecord) {
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))
}
var addMetricReqs []tryAddMetricReq
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
case tryRangeScanReq:
req.ResultCh <- rangeScanResult{
ResultCode: NoMetric,
}
case tryFullScanReq:
req.ResultCh <- fullScanResult{
ResultCode: NoMetric,
}
case tryAddMetricReq:
addMetricReqs = append(addMetricReqs, req)
case tryDeleteMetricReq:
req.ResultCh <- tryDeleteMetricResult{
ResultCode: NoMetric,
}
case tryDeleteMeasuresReq:
req.ResultCh <- tryDeleteMeasuresResult{
ResultCode: NoMetric,
}
case tryGetMetricReq:
req.ResultCh <- Metric{
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-10 06:18:45 +03:00
func (s *Database) deleteMeasures(rec storage.DeletedMeasures) {
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))
}
metric.DeleteMeasures()
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)
// }
s.doAfterReleaseXLock(rec.MetricID, metric)
2026-02-10 14:02:11 +00:00
}
2026-05-31 20:01:28 +00:00
func (s *Database) doAfterReleaseXLock(metricID uint32, metric *_metric) {
if len(metric.WaitQueue) > 0 {
s.processMetricQueue(metricID, metric)
2026-02-10 14:02:11 +00:00
}
}