This commit is contained in:
2026-05-15 00:28:46 +00:00
5 changed files with 231 additions and 267 deletions

View File

@@ -202,6 +202,20 @@ func (s *ReverseCumulativeDeltaCompressor) Unlock() {
s.state = nil s.state = nil
} }
func (s *ReverseCumulativeDeltaCompressor) Renew() {
s.buf = conbuf.New(nil)
s.pos = 0
//
s.baseValue = 0
s.lastDelta = 0
s.lastDeltaSize = 0
s.h = 0
}
func (s *ReverseCumulativeDeltaCompressor) Chunks() [][]byte {
return s.buf.Chunks()
}
// DECOMPRESSOR // DECOMPRESSOR
type ReverseCumulativeDeltaDecompressor struct { type ReverseCumulativeDeltaDecompressor struct {

View File

@@ -10,8 +10,6 @@ import (
"gordenko.dev/dima/qb/atree" "gordenko.dev/dima/qb/atree"
"gordenko.dev/dima/qb/bin" "gordenko.dev/dima/qb/bin"
"gordenko.dev/dima/qb/bufreader" "gordenko.dev/dima/qb/bufreader"
"gordenko.dev/dima/qb/chunkenc"
"gordenko.dev/dima/qb/conbuf"
"gordenko.dev/dima/qb/proto" "gordenko.dev/dima/qb/proto"
"gordenko.dev/dima/qb/transform" "gordenko.dev/dima/qb/transform"
"gordenko.dev/dima/qb/txlog" "gordenko.dev/dima/qb/txlog"
@@ -426,6 +424,7 @@ type FilledPage struct {
type tryAppendMeasuresResult struct { type tryAppendMeasuresResult struct {
ResultCode byte ResultCode byte
Written int
// MetricType diploma.MetricType // MetricType diploma.MetricType
// FracDigits byte // FracDigits byte
// Since uint32 // Since uint32
@@ -452,150 +451,6 @@ func (s *Database) AppendMeasures(req proto.AppendMeasuresReq) uint16 {
switch result.ResultCode { switch result.ResultCode {
case CanAppend: case CanAppend:
var (
rootPageNo = result.RootPageNo
prevPageNo = result.PrevPageNo
timestampsBuf = result.TimestampsBuf
valuesBuf = result.ValuesBuf
timestamps = result.Timestamps
values = result.Values
since = result.Since
until = result.Until
untilValue = result.UntilValue
//
//toAppendMeasures []proto.Measure
dataPages []atree.NotLinkedDataPage
)
for idx, measure := range req.Measures {
_ = idx
if since == 0 {
since = measure.Timestamp
} else {
if measure.Timestamp <= until {
// пишу в БД що вже встиг закодувати FIX
// if len(toAppendMeasures) > 0 {
// waitCh := s.txlog.WriteAppendMeasures(
// txlog.AppendedMeasures{
// MetricID: req.MetricID,
// Measures: toAppendMeasures,
// },
// false,
// )
// <-waitCh
// }
return proto.ErrExpiredMeasure
}
if result.MetricType == diploma.Cumulative && measure.Value < untilValue {
// пишу в БД що вже встиг закодувати FIX
// if len(toAppendMeasures) > 0 {
// waitCh := s.txlog.WriteAppendMeasures(
// txlog.AppendedMeasures{
// MetricID: req.MetricID,
// Measures: toAppendMeasures,
// },
// false,
// )
// <-waitCh
// }
return proto.ErrNonMonotonicValue
}
}
extraSpace := timestamps.CalcRequiredSpace(measure.Timestamp) +
values.CalcRequiredSpace(measure.Value)
totalSpace := timestamps.Size() + values.Size() + extraSpace
if totalSpace <= atree.DataPagePayloadSize {
// накопичую
timestamps.Append(measure.Timestamp)
values.Append(measure.Value)
//toAppendMeasures = append(toAppendMeasures, measure)
} else {
// сторінка заповнена
// if len(toAppendMeasures) > 0 {
// waitCh := s.txlog.WriteAppendMeasures(
// txlog.AppendedMeasures{
// MetricID: req.MetricID,
// Measures: toAppendMeasures,
// },
// true,
// )
// <-waitCh
// toAppendMeasures = nil
// }
pageData := make([]byte, atree.PageSize)
atree.ChunksToNotLinkedDataPage(pageData, atree.ChunksToNotLinkedDataPageReq{
//PrevPageNo: path.LastPageNo,
TimestampsChunks: timestampsBuf.Chunks(),
TimestampsSize: uint16(timestamps.Size()),
ValuesChunks: valuesBuf.Chunks(),
ValuesSize: uint16(values.Size()),
})
dataPages = append(dataPages, atree.NotLinkedDataPage{
Since: since,
Data: pageData,
})
// FIX
// prevPageNo = report.DataPageNo
// if report.IsRootChanged {
// rootPageNo = report.NewRootPageNo
// }
// waitCh := s.txlog.WriteAppendedMeasureWithOverflow(
// txlog.AppendedMeasureWithOverflow{
// MetricID: req.MetricID,
// Timestamp: measure.Timestamp,
// Value: measure.Value,
// IsDataPageReused: report.IsDataPageReused,
// DataPageNo: report.DataPageNo,
// IsRootChanged: report.IsRootChanged,
// RootPageNo: report.NewRootPageNo,
// ReusedIndexPages: report.ReusedIndexPages,
// },
// (idx+1) < len(req.Measures),
// )
// <-waitCh
timestampsBuf = conbuf.New(nil)
valuesBuf = conbuf.New(nil)
timestamps = chunkenc.NewReverseTimeDeltaCompressor(
timestampsBuf, 0)
if result.MetricType == diploma.Cumulative {
values = chunkenc.NewReverseCumulativeDeltaCompressor(
valuesBuf, 0, result.FracDigits)
} else {
values = chunkenc.NewReverseInstantDeltaCompressor(
valuesBuf, 0, result.FracDigits)
}
timestamps.Append(measure.Timestamp)
values.Append(measure.Value)
since = measure.Timestamp
}
until = measure.Timestamp
untilValue = measure.Value
}
waitCh := s.txlog.Append(txlog.AppendedPagesReq{
MetricID: req.MetricID,
Timestamp: until,
Value: untilValue,
LastPageNo: prevPageNo,
//Measures: toAppendMeasures,
},
)
<-waitCh
// report, err := s.atree.AppendDataPage(atree.AppendDataPageReq{}) // report, err := s.atree.AppendDataPage(atree.AppendDataPageReq{})
// if err != nil { // if err != nil {

View File

@@ -1,14 +1,14 @@
package database package database
import ( import (
octopus "gordenko.dev/dima/qb" "gordenko.dev/dima/qb"
"gordenko.dev/dima/qb/conbuf" "gordenko.dev/dima/qb/conbuf"
) )
// METRIC // METRIC
type _metric struct { type _metric struct {
MetricType octopus.MetricType MetricType qb.MetricType
FracDigits byte FracDigits byte
RootPageNo uint32 RootPageNo uint32
LastPageNo uint32 LastPageNo uint32
@@ -16,10 +16,10 @@ type _metric struct {
Since uint32 Since uint32
UntilValue float64 UntilValue float64
Until uint32 Until uint32
TimestampsBuf *conbuf.ContinuousBuffer //TimestampsBuf *conbuf.ContinuousBuffer
ValuesBuf *conbuf.ContinuousBuffer //ValuesBuf *conbuf.ContinuousBuffer
Timestamps octopus.TimestampCompressor Timestamps qb.TimestampCompressor
Values octopus.ValueCompressor Values qb.ValueCompressor
} }
func (s *_metric) ReinitBy(timestamp uint32, value float64) { func (s *_metric) ReinitBy(timestamp uint32, value float64) {

View File

@@ -3,7 +3,7 @@ package database
import ( import (
"fmt" "fmt"
diploma "gordenko.dev/dima/qb" qb "gordenko.dev/dima/qb"
"gordenko.dev/dima/qb/atree" "gordenko.dev/dima/qb/atree"
"gordenko.dev/dima/qb/chunkenc" "gordenko.dev/dima/qb/chunkenc"
"gordenko.dev/dima/qb/conbuf" "gordenko.dev/dima/qb/conbuf"
@@ -51,19 +51,19 @@ func (s *Database) DoWork() {
for _, metricID := range rLocksToRelease { for _, metricID := range rLocksToRelease {
lockEntry, ok := s.metricLockEntries[metricID] lockEntry, ok := s.metricLockEntries[metricID]
if !ok { if !ok {
diploma.Abort(diploma.NoLockEntryBug, qb.Abort(qb.NoLockEntryBug,
fmt.Errorf("drainQueues: lockEntry not found for the metric %d", fmt.Errorf("drainQueues: lockEntry not found for the metric %d",
metricID)) metricID))
} }
if lockEntry.XLock { if lockEntry.XLock {
diploma.Abort(diploma.XLockBug, qb.Abort(qb.XLockBug,
fmt.Errorf("drainQueues: xlock is set for the metric %d", fmt.Errorf("drainQueues: xlock is set for the metric %d",
metricID)) metricID))
} }
if lockEntry.RLocks <= 0 { if lockEntry.RLocks <= 0 {
diploma.Abort(diploma.NoRLockBug, qb.Abort(qb.NoRLockBug,
fmt.Errorf("drainQueues: rlock not set for the metric %d", fmt.Errorf("drainQueues: rlock not set for the metric %d",
metricID)) metricID))
} }
@@ -73,7 +73,7 @@ func (s *Database) DoWork() {
if len(lockEntry.WaitQueue) > 0 { if len(lockEntry.WaitQueue) > 0 {
metric, ok := s.metrics[metricID] metric, ok := s.metrics[metricID]
if !ok { if !ok {
diploma.Abort(diploma.NoMetricBug, qb.Abort(qb.NoMetricBug,
fmt.Errorf("drainQueues: metric %d not found", metricID)) fmt.Errorf("drainQueues: metric %d not found", metricID))
} }
s.processMetricQueue(metricID, metric, lockEntry) s.processMetricQueue(metricID, metric, lockEntry)
@@ -117,7 +117,7 @@ func (s *Database) DoWork() {
s.tryGetMetric(req) s.tryGetMetric(req)
default: default:
diploma.Abort(diploma.UnknownWorkerQueueItemBug, qb.Abort(qb.UnknownWorkerQueueItemBug,
fmt.Errorf("bug: unknown worker queue item type %T", req)) fmt.Errorf("bug: unknown worker queue item type %T", req))
} }
} }
@@ -169,7 +169,7 @@ func (s *Database) processMetricQueue(metricID uint32, metric *_metric, lockEntr
s.startDeleteMeasures(metric, req) s.startDeleteMeasures(metric, req)
default: default:
diploma.Abort(diploma.UnknownMetricWaitQueueItemBug, qb.Abort(qb.UnknownMetricWaitQueueItemBug,
fmt.Errorf("bug: unknown metric wait queue item type %T", req)) fmt.Errorf("bug: unknown metric wait queue item type %T", req))
} }
@@ -373,7 +373,7 @@ type ReadBound struct {
// return // return
// } // }
// if metric.MetricType == diploma.Cumulative && req.Value < metric.UntilValue { // if metric.MetricType == qb.Cumulative && req.Value < metric.UntilValue {
// req.ResultCh <- tryAppendMeasureResult{ // req.ResultCh <- tryAppendMeasureResult{
// MetricID: req.MetricID, // MetricID: req.MetricID,
// ResultCode: NonMonotonicValue, // ResultCode: NonMonotonicValue,
@@ -434,26 +434,26 @@ type ReadBound struct {
// func (s *Database) appendMeasure(rec txlog.AppendedMeasure) { // func (s *Database) appendMeasure(rec txlog.AppendedMeasure) {
// metric, ok := s.metrics[rec.MetricID] // metric, ok := s.metrics[rec.MetricID]
// if !ok { // if !ok {
// diploma.Abort(diploma.NoMetricBug, // qb.Abort(qb.NoMetricBug,
// fmt.Errorf("appendMeasure: metric %d not found", // fmt.Errorf("appendMeasure: metric %d not found",
// rec.MetricID)) // rec.MetricID))
// } // }
// lockEntry, ok := s.metricLockEntries[rec.MetricID] // lockEntry, ok := s.metricLockEntries[rec.MetricID]
// if !ok { // if !ok {
// diploma.Abort(diploma.NoLockEntryBug, // qb.Abort(qb.NoLockEntryBug,
// fmt.Errorf("appendMeasure: lockEntry not found for the metric %d", // fmt.Errorf("appendMeasure: lockEntry not found for the metric %d",
// rec.MetricID)) // rec.MetricID))
// } // }
// if lockEntry.XLock { // if lockEntry.XLock {
// diploma.Abort(diploma.XLockBug, // qb.Abort(qb.XLockBug,
// fmt.Errorf("appendMeasure: xlock is set for the metric %d", // fmt.Errorf("appendMeasure: xlock is set for the metric %d",
// rec.MetricID)) // rec.MetricID))
// } // }
// if lockEntry.RLocks <= 0 { // if lockEntry.RLocks <= 0 {
// diploma.Abort(diploma.NoRLockBug, // qb.Abort(qb.NoRLockBug,
// fmt.Errorf("appendMeasure: rlock not set for the metric %d", // fmt.Errorf("appendMeasure: rlock not set for the metric %d",
// rec.MetricID)) // rec.MetricID))
// } // }
@@ -481,58 +481,49 @@ type ReadBound struct {
func (s *Database) appendMeasures(rec txlog.AppendedMeasures) { func (s *Database) appendMeasures(rec txlog.AppendedMeasures) {
metric, ok := s.metrics[rec.MetricID] metric, ok := s.metrics[rec.MetricID]
if !ok { if !ok {
diploma.Abort(diploma.NoMetricBug, qb.Abort(qb.NoMetricBug,
fmt.Errorf("appendMeasureAfterOverflow: metric %d not found", fmt.Errorf("appendMeasureAfterOverflow: metric %d not found",
rec.MetricID)) rec.MetricID))
} }
lockEntry, ok := s.metricLockEntries[rec.MetricID] metric.Values.Unlock()
if !ok { metric.Timestamps.Unlock()
diploma.Abort(diploma.NoLockEntryBug,
fmt.Errorf("appendMeasureAfterOverflow: lockEntry not found for the metric %d",
rec.MetricID))
}
if !lockEntry.XLock { // lockEntry, ok := s.metricLockEntries[rec.MetricID]
diploma.Abort(diploma.NoXLockBug, // if !ok {
fmt.Errorf("appendMeasureAfterOverflow: xlock not set for the metric %d", // qb.Abort(qb.NoLockEntryBug,
rec.MetricID)) // fmt.Errorf("appendMeasureAfterOverflow: lockEntry not found for the metric %d",
} // rec.MetricID))
// }
for _, measure := range rec.Measures { // if !lockEntry.XLock {
if metric.Since == 0 { // qb.Abort(qb.NoXLockBug,
metric.Since = measure.Timestamp // fmt.Errorf("appendMeasureAfterOverflow: xlock not set for the metric %d",
metric.SinceValue = measure.Value // rec.MetricID))
} // }
metric.Timestamps.Append(measure.Timestamp) // lockEntry.XLock = false
metric.Values.Append(measure.Value) // s.doAfterReleaseXLock(rec.MetricID, metric, lockEntry)
metric.Until = measure.Timestamp
metric.UntilValue = measure.Value
}
lockEntry.XLock = false
s.doAfterReleaseXLock(rec.MetricID, metric, lockEntry)
} }
// func (s *Database) appendMeasureAfterOverflow(extended txlog.AppendedMeasureWithOverflowExtended) { // func (s *Database) appendMeasureAfterOverflow(extended txlog.AppendedMeasureWithOverflowExtended) {
// rec := extended.Record // rec := extended.Record
// metric, ok := s.metrics[rec.MetricID] // metric, ok := s.metrics[rec.MetricID]
// if !ok { // if !ok {
// diploma.Abort(diploma.NoMetricBug, // qb.Abort(qb.NoMetricBug,
// fmt.Errorf("appendMeasureAfterOverflow: metric %d not found", // fmt.Errorf("appendMeasureAfterOverflow: metric %d not found",
// rec.MetricID)) // rec.MetricID))
// } // }
// lockEntry, ok := s.metricLockEntries[rec.MetricID] // lockEntry, ok := s.metricLockEntries[rec.MetricID]
// if !ok { // if !ok {
// diploma.Abort(diploma.NoLockEntryBug, // qb.Abort(qb.NoLockEntryBug,
// fmt.Errorf("appendMeasureAfterOverflow: lockEntry not found for the metric %d", // fmt.Errorf("appendMeasureAfterOverflow: lockEntry not found for the metric %d",
// rec.MetricID)) // rec.MetricID))
// } // }
// if !lockEntry.XLock { // if !lockEntry.XLock {
// diploma.Abort(diploma.NoXLockBug, // qb.Abort(qb.NoXLockBug,
// fmt.Errorf("appendMeasureAfterOverflow: xlock not set for the metric %d", // fmt.Errorf("appendMeasureAfterOverflow: xlock not set for the metric %d",
// rec.MetricID)) // rec.MetricID))
// } // }
@@ -583,74 +574,170 @@ func (s *Database) tryAppendMeasures(req tryAppendMeasuresReq) {
} }
func (s *Database) startAppendMeasures(metric *_metric, req tryAppendMeasuresReq, lockEntry *metricLockEntry) { func (s *Database) startAppendMeasures(metric *_metric, req tryAppendMeasuresReq, lockEntry *metricLockEntry) {
if lockEntry != nil {
if lockEntry.RLocks > 0 {
lockEntry.WaitQueue = append(lockEntry.WaitQueue, req)
return
}
lockEntry.XLock = true
} else {
s.metricLockEntries[req.MetricID] = &metricLockEntry{
XLock: true,
}
}
var ( var (
timestampsBuf *conbuf.ContinuousBuffer timestamps = metric.Timestamps
valuesBuf *conbuf.ContinuousBuffer values = metric.Values
timestamps diploma.TimestampCompressor
values diploma.ValueCompressor dataPages []atree.NotLinkedDataPage
resultCode byte
written int
) )
if metric.Since > 0 { metric.Values.Lock()
timestampsBuf = metric.TimestampsBuf.Copy() metric.Timestamps.Lock()
valuesBuf = metric.ValuesBuf.Copy()
timestamps = chunkenc.NewReverseTimeDeltaOfDeltaCompressor( for idx, measure := range req.Measures {
timestampsBuf, metric.Timestamps.Size()) if metric.Since == 0 {
metric.Since = measure.Timestamp
if metric.MetricType == diploma.Cumulative {
values = chunkenc.NewReverseCumulativeDeltaCompressor(
valuesBuf, metric.Values.Size(), metric.FracDigits)
} else { } else {
values = chunkenc.NewReverseInstantDeltaCompressor( // FIX - у випадку помилки треба в транзакції зберегти що помилка, але також зафіксувати скільки елементів збережено.
valuesBuf, metric.Values.Size(), metric.FracDigits) // якщо idx == 0 - одразу знімаю блокування і нічого не відправляю в txlog
} if measure.Timestamp <= metric.Until {
} else { if idx == 0 {
timestampsBuf = conbuf.New(nil) metric.Values.Unlock()
valuesBuf = conbuf.New(nil) metric.Timestamps.Unlock()
timestamps = chunkenc.NewReverseTimeDeltaOfDeltaCompressor(
timestampsBuf, 0)
if metric.MetricType == diploma.Cumulative {
values = chunkenc.NewReverseCumulativeDeltaCompressor(
valuesBuf, 0, metric.FracDigits)
} else {
values = chunkenc.NewReverseInstantDeltaCompressor(
valuesBuf, 0, metric.FracDigits)
}
}
req.ResultCh <- tryAppendMeasuresResult{ req.ResultCh <- tryAppendMeasuresResult{
ResultCode: CanAppend, ResultCode: ExpiredMeasure,
// MetricType: metric.MetricType,
// FracDigits: metric.FracDigits,
// Since: metric.Since,
// Until: metric.Until,
// UntilValue: metric.UntilValue,
// RootPageNo: metric.RootPageNo,
// PrevPageNo: metric.LastPageNo,
// TimestampsBuf: timestampsBuf,
// ValuesBuf: valuesBuf,
// Timestamps: timestamps,
// Values: values,
} }
return
}
resultCode = ExpiredMeasure
written = idx
break
}
if metric.MetricType == qb.Cumulative && measure.Value < metric.UntilValue {
if idx == 0 {
metric.Values.Unlock()
metric.Timestamps.Unlock()
req.ResultCh <- tryAppendMeasuresResult{
ResultCode: NonMonotonicValue,
}
return
}
resultCode = NonMonotonicValue
written = idx
break
}
}
// fix - 1 + 8 bytes
extraSpace := timestamps.CalcRequiredSpace(measure.Timestamp) +
values.CalcRequiredSpace(measure.Value)
totalSpace := timestamps.Size() + values.Size() + extraSpace
if totalSpace <= atree.DataPagePayloadSize {
// накопичую
timestamps.Append(measure.Timestamp)
values.Append(measure.Value)
} else {
// сторінка заповнена
pageData := make([]byte, atree.PageSize)
// prevPageNo - виставляю в txlog, коли забираю номер сторінки із freeList або генерую новий
atree.ChunksToNotLinkedDataPage(pageData, atree.ChunksToNotLinkedDataPageReq{
TimestampsChunks: timestamps.Chunks(),
TimestampsSize: uint16(timestamps.Size()),
ValuesChunks: values.Chunks(),
ValuesSize: uint16(values.Size()),
})
dataPages = append(dataPages, atree.NotLinkedDataPage{
Since: metric.Since,
Data: pageData,
})
// FIX
// prevPageNo = report.DataPageNo
// if report.IsRootChanged {
// rootPageNo = report.NewRootPageNo
// }
// waitCh := s.txlog.WriteAppendedMeasureWithOverflow(
// txlog.AppendedMeasureWithOverflow{
// MetricID: req.MetricID,
// Timestamp: measure.Timestamp,
// Value: measure.Value,
// IsDataPageReused: report.IsDataPageReused,
// DataPageNo: report.DataPageNo,
// IsRootChanged: report.IsRootChanged,
// RootPageNo: report.NewRootPageNo,
// ReusedIndexPages: report.ReusedIndexPages,
// },
// (idx+1) < len(req.Measures),
// )
// <-waitCh
timestamps.Renew()
values.Renew()
timestamps.Append(measure.Timestamp)
values.Append(measure.Value)
metric.Since = measure.Timestamp
}
metric.Until = measure.Timestamp
metric.UntilValue = measure.Value
}
// виділити змінені байти.
// скопіювати. Причому можна скопіювати зрізи chunks
if len(dataPages) > 0 {
// пишу в txlog довгим шляхом через redo файл і запис в data файл
} else {
// короткий шлях - запис лише в txlog
}
// waitCh := s.txlog.Append(txlog.AppendedPagesReq{
// MetricID: req.MetricID,
// Timestamp: until,
// Value: untilValue,
// LastPageNo: prevPageNo,
// //Measures: toAppendMeasures,
// },
// )
// <-waitCh
// if lockEntry != nil {
// if lockEntry.RLocks > 0 {
// lockEntry.WaitQueue = append(lockEntry.WaitQueue, req)
// return
// }
// lockEntry.XLock = true
// } else {
// s.metricLockEntries[req.MetricID] = &metricLockEntry{
// XLock: true,
// }
// }
}
type PartialChange struct {
Data [][]byte
Size int
Offset int
}
type AppendedMeasures struct {
RootPageNo uint32
LastPageNo uint32
DataPages []atree.ChunksToNotLinkedDataPageReq
Values PartialChange
Timestamps PartialChange
ResultCh chan tryAppendMeasuresResult
} }
type tryRangeScanReq struct { type tryRangeScanReq struct {
MetricID uint32 MetricID uint32
Since uint32 Since uint32
Until uint32 Until uint32
MetricType diploma.MetricType MetricType qb.MetricType
ResponseWriter atree.WorkerMeasureConsumer ResponseWriter atree.WorkerMeasureConsumer
ResultCh chan rangeScanResult ResultCh chan rangeScanResult
} }
@@ -739,7 +826,7 @@ func (*Database) startRangeScan(metric *_metric, req tryRangeScanReq) bool {
value, done := valueDecompressor.NextValue() value, done := valueDecompressor.NextValue()
if done { if done {
diploma.Abort(diploma.HasTimestampNoValueBug, ErrNoValueBug) qb.Abort(qb.HasTimestampNoValueBug, ErrNoValueBug)
} }
if timestamp <= req.Until { if timestamp <= req.Until {
@@ -770,7 +857,7 @@ func (*Database) startRangeScan(metric *_metric, req tryRangeScanReq) bool {
type tryFullScanReq struct { type tryFullScanReq struct {
MetricID uint32 MetricID uint32
MetricType diploma.MetricType MetricType qb.MetricType
ResponseWriter atree.WorkerMeasureConsumer ResponseWriter atree.WorkerMeasureConsumer
ResultCh chan fullScanResult ResultCh chan fullScanResult
} }
@@ -834,7 +921,7 @@ func (*Database) startFullScan(metric *_metric, req tryFullScanReq) bool {
} }
value, done := valueDecompressor.NextValue() value, done := valueDecompressor.NextValue()
if done { if done {
diploma.Abort(diploma.HasTimestampNoValueBug, ErrNoValueBug) qb.Abort(qb.HasTimestampNoValueBug, ErrNoValueBug)
} }
req.ResponseWriter.FeedNoSend(timestamp, value) req.ResponseWriter.FeedNoSend(timestamp, value)
} }
@@ -913,31 +1000,31 @@ func (s *Database) applyChanges(req txlog.Changes) {
func (s *Database) addMetric(rec txlog.AddedMetric) { func (s *Database) addMetric(rec txlog.AddedMetric) {
_, ok := s.metrics[rec.MetricID] _, ok := s.metrics[rec.MetricID]
if ok { if ok {
diploma.Abort(diploma.MetricAddedBug, qb.Abort(qb.MetricAddedBug,
fmt.Errorf("addMetric: metric %d already added", fmt.Errorf("addMetric: metric %d already added",
rec.MetricID)) rec.MetricID))
} }
lockEntry, ok := s.metricLockEntries[rec.MetricID] lockEntry, ok := s.metricLockEntries[rec.MetricID]
if !ok { if !ok {
diploma.Abort(diploma.NoLockEntryBug, qb.Abort(qb.NoLockEntryBug,
fmt.Errorf("addMetric: lockEntry not found for the metric %d", fmt.Errorf("addMetric: lockEntry not found for the metric %d",
rec.MetricID)) rec.MetricID))
} }
if !lockEntry.XLock { if !lockEntry.XLock {
diploma.Abort(diploma.NoXLockBug, qb.Abort(qb.NoXLockBug,
fmt.Errorf("addMetric: xlock not set for the metric %d", fmt.Errorf("addMetric: xlock not set for the metric %d",
rec.MetricID)) rec.MetricID))
} }
var ( var (
values diploma.ValueCompressor values qb.ValueCompressor
timestampsBuf = conbuf.New(nil) timestampsBuf = conbuf.New(nil)
valuesBuf = conbuf.New(nil) valuesBuf = conbuf.New(nil)
) )
if rec.MetricType == diploma.Cumulative { if rec.MetricType == qb.Cumulative {
values = chunkenc.NewReverseCumulativeDeltaCompressor( values = chunkenc.NewReverseCumulativeDeltaCompressor(
valuesBuf, 0, byte(rec.FracDigits)) valuesBuf, 0, byte(rec.FracDigits))
} else { } else {
@@ -961,20 +1048,20 @@ func (s *Database) addMetric(rec txlog.AddedMetric) {
func (s *Database) deleteMetric(rec txlog.DeletedMetric) { func (s *Database) deleteMetric(rec txlog.DeletedMetric) {
_, ok := s.metrics[rec.MetricID] _, ok := s.metrics[rec.MetricID]
if !ok { if !ok {
diploma.Abort(diploma.NoMetricBug, qb.Abort(qb.NoMetricBug,
fmt.Errorf("deleteMetric: metric %d not found", fmt.Errorf("deleteMetric: metric %d not found",
rec.MetricID)) rec.MetricID))
} }
lockEntry, ok := s.metricLockEntries[rec.MetricID] lockEntry, ok := s.metricLockEntries[rec.MetricID]
if !ok { if !ok {
diploma.Abort(diploma.NoLockEntryBug, qb.Abort(qb.NoLockEntryBug,
fmt.Errorf("deleteMetric: lockEntry not found for the metric %d", fmt.Errorf("deleteMetric: lockEntry not found for the metric %d",
rec.MetricID)) rec.MetricID))
} }
if !lockEntry.XLock { if !lockEntry.XLock {
diploma.Abort(diploma.NoXLockBug, qb.Abort(qb.NoXLockBug,
fmt.Errorf("deleteMetric: xlock not set for the metric %d", fmt.Errorf("deleteMetric: xlock not set for the metric %d",
rec.MetricID)) rec.MetricID))
} }
@@ -1019,7 +1106,7 @@ func (s *Database) deleteMetric(rec txlog.DeletedMetric) {
} }
default: default:
diploma.Abort(diploma.UnknownMetricWaitQueueItemBug, qb.Abort(qb.UnknownMetricWaitQueueItemBug,
fmt.Errorf("bug: unknown metric wait queue item type %T", req)) fmt.Errorf("bug: unknown metric wait queue item type %T", req))
} }
} }
@@ -1039,20 +1126,20 @@ func (s *Database) deleteMetric(rec txlog.DeletedMetric) {
func (s *Database) deleteMeasures(rec txlog.DeletedMeasures) { func (s *Database) deleteMeasures(rec txlog.DeletedMeasures) {
metric, ok := s.metrics[rec.MetricID] metric, ok := s.metrics[rec.MetricID]
if !ok { if !ok {
diploma.Abort(diploma.NoMetricBug, qb.Abort(qb.NoMetricBug,
fmt.Errorf("deleteMeasures: metric %d not found", fmt.Errorf("deleteMeasures: metric %d not found",
rec.MetricID)) rec.MetricID))
} }
lockEntry, ok := s.metricLockEntries[rec.MetricID] lockEntry, ok := s.metricLockEntries[rec.MetricID]
if !ok { if !ok {
diploma.Abort(diploma.NoLockEntryBug, qb.Abort(qb.NoLockEntryBug,
fmt.Errorf("deleteMeasures: lockEntry not found for the metric %d", fmt.Errorf("deleteMeasures: lockEntry not found for the metric %d",
rec.MetricID)) rec.MetricID))
} }
if !lockEntry.XLock { if !lockEntry.XLock {
diploma.Abort(diploma.NoXLockBug, qb.Abort(qb.NoXLockBug,
fmt.Errorf("deleteMeasures: xlock not set for the metric %d", fmt.Errorf("deleteMeasures: xlock not set for the metric %d",
rec.MetricID)) rec.MetricID))
} }

8
qb.go
View File

@@ -26,7 +26,11 @@ type TimestampCompressor interface {
CalcRequiredSpace(uint32) int CalcRequiredSpace(uint32) int
Append(uint32) Append(uint32)
Size() int Size() int
Chunks() [][]byte
DeleteLast() DeleteLast()
Renew()
Lock()
Unlock()
//LastTimestamp() uint32 //LastTimestamp() uint32
} }
@@ -34,7 +38,11 @@ type ValueCompressor interface {
CalcRequiredSpace(float64) int CalcRequiredSpace(float64) int
Append(float64) Append(float64)
Size() int Size() int
Chunks() [][]byte
DeleteLast() DeleteLast()
Renew() // створює новий conbuf, але не чіпає state
Lock()
Unlock()
//LastValue() float64 //LastValue() float64
} }