Merge branch 'master' of https://gordenko.dev/dima/qb
This commit is contained in:
@@ -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 {
|
||||||
|
|||||||
147
database/api.go
147
database/api.go
@@ -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 {
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
305
database/proc.go
305
database/proc.go
@@ -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
8
qb.go
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user