This commit is contained in:
2026-05-31 20:01:28 +00:00
parent e7ec6083cb
commit db5ecd3dfd
28 changed files with 2090 additions and 2155 deletions

View File

@@ -12,6 +12,11 @@ import (
"gordenko.dev/dima/qb/txlog"
)
// AddMetric - create metric in map and set Xlock, rwad - append to queue
// DeleteMetric - set Xlock
// DeleteSince - xLock (тупо редкая операция)
// Якийсь прапор поставити для pendingDelete, щоб read операції вставали в чергу
const (
QueryDone = 1
UntilFound = 2
@@ -49,46 +54,33 @@ func (s *Database) DoWork() {
s.mutex.Unlock()
for _, metricID := range rLocksToRelease {
lockEntry, ok := s.metricLockEntries[metricID]
metric, ok := s.metrics[metricID]
if !ok {
qb.Abort(qb.NoLockEntryBug,
fmt.Errorf("drainQueues: lockEntry not found for the metric %d",
metricID))
qb.Abort(qb.NoMetricBug,
fmt.Errorf("drainQueues: metric %d not found", metricID))
}
if lockEntry.XLock {
if metric.XLock {
qb.Abort(qb.XLockBug,
fmt.Errorf("drainQueues: xlock is set for the metric %d",
metricID))
}
if lockEntry.RLocks <= 0 {
if metric.RLocks <= 0 {
qb.Abort(qb.NoRLockBug,
fmt.Errorf("drainQueues: rlock not set for the metric %d",
metricID))
}
lockEntry.RLocks--
metric.RLocks--
if len(lockEntry.WaitQueue) > 0 {
metric, ok := s.metrics[metricID]
if !ok {
qb.Abort(qb.NoMetricBug,
fmt.Errorf("drainQueues: metric %d not found", metricID))
}
s.processMetricQueue(metricID, metric, lockEntry)
} else {
if lockEntry.RLocks == 0 {
delete(s.metricLockEntries, metricID)
}
if len(metric.WaitQueue) > 0 {
s.processMetricQueue(metricID, metric)
}
}
for _, untyped := range workerQueue {
switch req := untyped.(type) {
//case tryAppendMeasureReq:
// s.tryAppendMeasure(req)
case tryAppendMeasuresReq:
s.tryAppendMeasures(req)
@@ -123,64 +115,35 @@ func (s *Database) DoWork() {
}
}
func (s *Database) processMetricQueue(metricID uint32, metric *_metric, lockEntry *metricLockEntry) {
if len(lockEntry.WaitQueue) == 0 {
// суть у тому що треба запускати запити, пока не зустріну XLock
func (s *Database) processMetricQueue(metricID uint32, metric *_metric) {
if len(metric.WaitQueue) == 0 {
return
}
var modificationReqs []any
for _, untyped := range lockEntry.WaitQueue {
var rLockRequired bool
for _, untyped := range metric.WaitQueue {
switch req := untyped.(type) {
case tryRangeScanReq:
rLockRequired = s.startRangeScan(metric, req)
metric.StartRangeScan(req)
case tryFullScanReq:
rLockRequired = s.startFullScan(metric, req)
metric.StartFullScan(req)
case tryGetMetricReq:
s.tryGetMetric(req)
case tryAppendMeasuresReq:
metric.StartAppendMeasures(req, s.txlog.Append)
case tryDeleteMetricReq:
s.startDeleteMetric(metric, req)
case tryDeleteMeasuresReq:
s.startDeleteMeasures(metric, req)
default:
modificationReqs = append(modificationReqs, untyped)
}
if rLockRequired {
lockEntry.RLocks++
}
}
lockEntry.WaitQueue = nil
if lockEntry.RLocks > 0 {
lockEntry.WaitQueue = modificationReqs
} else {
for idx, untyped := range modificationReqs {
switch req := untyped.(type) {
//case tryAppendMeasureReq:
// s.startAppendMeasure(metric, req, nil)
case tryAppendMeasuresReq:
s.startAppendMeasures(metric, req, nil)
case tryDeleteMetricReq:
s.startDeleteMetric(metric, req)
case tryDeleteMeasuresReq:
s.startDeleteMeasures(metric, req)
default:
qb.Abort(qb.UnknownMetricWaitQueueItemBug,
fmt.Errorf("bug: unknown metric wait queue item type %T", req))
}
lockEntry, ok := s.metricLockEntries[metricID]
if ok {
start := idx + 1
if start < len(modificationReqs) {
lockEntry.WaitQueue = append(lockEntry.WaitQueue, modificationReqs[start:]...)
}
break
}
qb.Abort(qb.UnknownMetricWaitQueueItemBug,
fmt.Errorf("bug: unknown metric wait queue item type %T", req))
}
}
}
@@ -332,222 +295,16 @@ func (s *Database) startDeleteMeasures(metric *_metric, req tryDeleteMeasuresReq
// }
}
// type tryAppendMeasureReq struct {
// MetricID uint32
// Timestamp uint32
// Value float64
// ResultCh chan tryAppendMeasureResult
// }
// func (s *Database) tryAppendMeasure(req tryAppendMeasureReq) {
// metric, ok := s.metrics[req.MetricID]
// if !ok {
// req.ResultCh <- tryAppendMeasureResult{
// MetricID: req.MetricID,
// ResultCode: NoMetric,
// }
// return
// }
// lockEntry, ok := s.metricLockEntries[req.MetricID]
// if ok {
// if lockEntry.XLock {
// lockEntry.WaitQueue = append(lockEntry.WaitQueue, req)
// return
// }
// }
// s.startAppendMeasure(metric, req, lockEntry)
// }
type ReadBound struct {
ValuesPos int
ValuesLastValue float64
}
// func (s *Database) startAppendMeasure(metric *_metric, req tryAppendMeasureReq, lockEntry *metricLockEntry) {
// if req.Timestamp <= metric.Until {
// req.ResultCh <- tryAppendMeasureResult{
// MetricID: req.MetricID,
// ResultCode: ExpiredMeasure,
// }
// return
// }
// if metric.MetricType == qb.Cumulative && req.Value < metric.UntilValue {
// req.ResultCh <- tryAppendMeasureResult{
// MetricID: req.MetricID,
// ResultCode: NonMonotonicValue,
// }
// return
// }
// extraSpace := metric.Timestamps.CalcRequiredSpace(req.Timestamp) +
// metric.Values.CalcRequiredSpace(req.Value)
// totalSpace := metric.Timestamps.Size() + metric.Values.Size() + extraSpace
// if totalSpace <= atree.DataPagePayloadSize {
// if lockEntry != nil {
// lockEntry.RLocks++
// } else {
// s.metricLockEntries[req.MetricID] = &metricLockEntry{
// RLocks: 1,
// }
// }
// req.ResultCh <- tryAppendMeasureResult{
// MetricID: req.MetricID,
// Timestamp: req.Timestamp,
// Value: req.Value,
// ResultCode: CanAppend,
// }
// } else {
// 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,
// }
// }
// req.ResultCh <- tryAppendMeasureResult{
// MetricID: req.MetricID,
// Timestamp: req.Timestamp,
// Value: req.Value,
// ResultCode: NewPage,
// FilledPage: &FilledPage{
// Since: metric.Since,
// RootPageNo: metric.RootPageNo,
// PrevPageNo: metric.LastPageNo,
// TimestampsChunks: metric.TimestampsBuf.Chunks(),
// TimestampsSize: uint16(metric.Timestamps.Size()),
// ValuesChunks: metric.ValuesBuf.Chunks(),
// ValuesSize: uint16(metric.Values.Size()),
// },
// }
// }
// }
// func (s *Database) appendMeasure(rec txlog.AppendedMeasure) {
// metric, ok := s.metrics[rec.MetricID]
// if !ok {
// qb.Abort(qb.NoMetricBug,
// fmt.Errorf("appendMeasure: metric %d not found",
// rec.MetricID))
// }
// lockEntry, ok := s.metricLockEntries[rec.MetricID]
// if !ok {
// qb.Abort(qb.NoLockEntryBug,
// fmt.Errorf("appendMeasure: lockEntry not found for the metric %d",
// rec.MetricID))
// }
// if lockEntry.XLock {
// qb.Abort(qb.XLockBug,
// fmt.Errorf("appendMeasure: xlock is set for the metric %d",
// rec.MetricID))
// }
// if lockEntry.RLocks <= 0 {
// qb.Abort(qb.NoRLockBug,
// fmt.Errorf("appendMeasure: rlock not set for the metric %d",
// rec.MetricID))
// }
// if metric.Since == 0 {
// metric.Since = rec.Timestamp
// metric.SinceValue = rec.Value
// }
// metric.Timestamps.Append(rec.Timestamp)
// metric.Values.Append(rec.Value)
// metric.Until = rec.Timestamp
// metric.UntilValue = rec.Value
// lockEntry.RLocks--
// if len(lockEntry.WaitQueue) > 0 {
// s.processMetricQueue(rec.MetricID, metric, lockEntry)
// } else {
// if lockEntry.RLocks == 0 {
// delete(s.metricLockEntries, rec.MetricID)
// }
// }
// }
func (s *Database) appendMeasures(rec txlog.AppendedMeasures) {
func (s *Database) finAppendMeasures(rec txlog.AppendMeasuresSummary) {
metric, ok := s.metrics[rec.MetricID]
if !ok {
qb.Abort(qb.NoMetricBug,
fmt.Errorf("appendMeasureAfterOverflow: metric %d not found",
fmt.Errorf("finAppendMeasures: metric %d not found",
rec.MetricID))
}
metric.Values.Unlock()
metric.Timestamps.Unlock()
// lockEntry, ok := s.metricLockEntries[rec.MetricID]
// if !ok {
// qb.Abort(qb.NoLockEntryBug,
// fmt.Errorf("appendMeasureAfterOverflow: lockEntry not found for the metric %d",
// rec.MetricID))
// }
// if !lockEntry.XLock {
// qb.Abort(qb.NoXLockBug,
// fmt.Errorf("appendMeasureAfterOverflow: xlock not set for the metric %d",
// rec.MetricID))
// }
// lockEntry.XLock = false
// s.doAfterReleaseXLock(rec.MetricID, metric, lockEntry)
metric.FinAppendMeasures(rec)
}
// func (s *Database) appendMeasureAfterOverflow(extended txlog.AppendedMeasureWithOverflowExtended) {
// rec := extended.Record
// metric, ok := s.metrics[rec.MetricID]
// if !ok {
// qb.Abort(qb.NoMetricBug,
// fmt.Errorf("appendMeasureAfterOverflow: metric %d not found",
// rec.MetricID))
// }
// lockEntry, ok := s.metricLockEntries[rec.MetricID]
// if !ok {
// qb.Abort(qb.NoLockEntryBug,
// fmt.Errorf("appendMeasureAfterOverflow: lockEntry not found for the metric %d",
// rec.MetricID))
// }
// if !lockEntry.XLock {
// qb.Abort(qb.NoXLockBug,
// fmt.Errorf("appendMeasureAfterOverflow: xlock not set for the metric %d",
// rec.MetricID))
// }
// metric.ReinitBy(rec.Timestamp, rec.Value)
// if rec.IsRootChanged {
// metric.RootPageNo = rec.RootPageNo
// }
// metric.LastPageNo = rec.DataPageNo
// if rec.IsDataPageReused {
// s.freeList.DeleteReservedPages([]uint32{
// rec.DataPageNo,
// })
// }
// if len(rec.ReusedIndexPages) > 0 {
// s.freeList.DeleteReservedPages(rec.ReusedIndexPages)
// }
// lockEntry.XLock = false
// s.doAfterReleaseXLock(rec.MetricID, metric, lockEntry)
// }
type tryAppendMeasuresReq struct {
MetricID uint32
Measures []proto.Measure
@@ -562,175 +319,11 @@ func (s *Database) tryAppendMeasures(req tryAppendMeasuresReq) {
}
return
}
lockEntry, ok := s.metricLockEntries[req.MetricID]
if ok {
if lockEntry.XLock {
lockEntry.WaitQueue = append(lockEntry.WaitQueue, req)
return
}
if metric.XLock {
metric.WaitQueue = append(metric.WaitQueue, req)
return
}
s.startAppendMeasures(metric, req, lockEntry)
}
func (s *Database) startAppendMeasures(metric *_metric, req tryAppendMeasuresReq, lockEntry *metricLockEntry) {
var (
timestamps = metric.Timestamps
values = metric.Values
dataPages []atree.NotLinkedDataPage
resultCode byte
written int
)
metric.Values.Lock()
metric.Timestamps.Lock()
for idx, measure := range req.Measures {
if metric.Since == 0 {
metric.Since = measure.Timestamp
} else {
// FIX - у випадку помилки треба в транзакції зберегти що помилка, але також зафіксувати скільки елементів збережено.
// якщо idx == 0 - одразу знімаю блокування і нічого не відправляю в txlog
if measure.Timestamp <= metric.Until {
if idx == 0 {
metric.Values.Unlock()
metric.Timestamps.Unlock()
req.ResultCh <- tryAppendMeasuresResult{
ResultCode: ExpiredMeasure,
}
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
metric.StartAppendMeasures(req, s.txlog.Append)
}
type tryRangeScanReq struct {
@@ -757,102 +350,12 @@ func (s *Database) tryRangeScan(req tryRangeScanReq) {
return
}
lockEntry, ok := s.metricLockEntries[req.MetricID]
if ok {
if lockEntry.XLock {
lockEntry.WaitQueue = append(lockEntry.WaitQueue, req)
return
}
if metric.XLock {
metric.WaitQueue = append(metric.WaitQueue, req)
return
}
if s.startRangeScan(metric, req) {
if lockEntry != nil {
lockEntry.RLocks++
} else {
s.metricLockEntries[req.MetricID] = &metricLockEntry{
RLocks: 1,
}
}
}
}
func (*Database) startRangeScan(metric *_metric, req tryRangeScanReq) bool {
if metric.Since == 0 {
req.ResultCh <- rangeScanResult{
ResultCode: QueryDone,
}
return false
}
if req.Since > metric.Until {
req.ResultCh <- rangeScanResult{
ResultCode: QueryDone,
}
return false
}
if req.Until < metric.Since {
if metric.RootPageNo > 0 {
req.ResultCh <- rangeScanResult{
ResultCode: UntilNotFound,
RootPageNo: metric.RootPageNo,
FracDigits: metric.FracDigits,
}
return true
} else {
req.ResultCh <- rangeScanResult{
ResultCode: QueryDone,
}
return false
}
}
timestampDecompressor := chunkenc.NewReverseTimeDeltaDecompressor(
metric.TimestampsBuf,
metric.Timestamps.Size(),
)
valueDecompressor := chunkenc.NewReverseInstantDeltaDecompressor(
metric.ValuesBuf,
metric.Values.Size(),
metric.FracDigits,
)
for {
timestamp, done := timestampDecompressor.NextValue()
if done {
break
}
value, done := valueDecompressor.NextValue()
if done {
qb.Abort(qb.HasTimestampNoValueBug, ErrNoValueBug)
}
if timestamp <= req.Until {
req.ResponseWriter.FeedNoSend(timestamp, value)
if timestamp < req.Since {
req.ResultCh <- rangeScanResult{
ResultCode: QueryDone,
}
return false
}
}
}
if metric.LastPageNo > 0 {
req.ResultCh <- rangeScanResult{
ResultCode: UntilFound,
LastPageNo: metric.LastPageNo,
FracDigits: metric.FracDigits,
}
return true
} else {
req.ResultCh <- rangeScanResult{
ResultCode: QueryDone,
}
return false
}
metric.StartRangeScan(req)
}
type tryFullScanReq struct {
@@ -877,68 +380,11 @@ func (s *Database) tryFullScan(req tryFullScanReq) {
return
}
lockEntry, ok := s.metricLockEntries[req.MetricID]
if ok {
if lockEntry.XLock {
lockEntry.WaitQueue = append(lockEntry.WaitQueue, req)
return
}
}
if s.startFullScan(metric, req) {
if lockEntry != nil {
lockEntry.RLocks++
} else {
s.metricLockEntries[req.MetricID] = &metricLockEntry{
RLocks: 1,
}
}
}
}
func (*Database) startFullScan(metric *_metric, req tryFullScanReq) bool {
if metric.Since == 0 {
req.ResultCh <- fullScanResult{
ResultCode: QueryDone,
}
return false
}
timestampDecompressor := chunkenc.NewReverseTimeDeltaDecompressor(
metric.TimestampsBuf,
metric.Timestamps.Size(),
)
valueDecompressor := chunkenc.NewReverseInstantDeltaDecompressor(
metric.ValuesBuf,
metric.Values.Size(),
metric.FracDigits,
)
for {
timestamp, done := timestampDecompressor.NextValue()
if done {
break
}
value, done := valueDecompressor.NextValue()
if done {
qb.Abort(qb.HasTimestampNoValueBug, ErrNoValueBug)
}
req.ResponseWriter.FeedNoSend(timestamp, value)
}
if metric.LastPageNo > 0 {
req.ResultCh <- fullScanResult{
ResultCode: UntilFound,
LastPageNo: metric.LastPageNo,
FracDigits: metric.FracDigits,
}
return true
} else {
req.ResultCh <- fullScanResult{
ResultCode: QueryDone,
}
return false
if metric.XLock {
metric.WaitQueue = append(metric.WaitQueue, req)
return
}
metric.StartFullScan(req)
}
type tryListCurrentValuesReq struct {
@@ -975,8 +421,8 @@ func (s *Database) applyChanges(req txlog.Changes) {
// case txlog.AppendedMeasure:
// s.appendMeasure(rec)
case txlog.AppendedMeasures:
s.appendMeasures(rec)
case txlog.AppendMeasuresSummary:
s.finAppendMeasures(rec)
// case txlog.AppendedMeasureWithOverflowExtended:
// s.appendMeasureAfterOverflow(rec)
@@ -986,18 +432,38 @@ func (s *Database) applyChanges(req txlog.Changes) {
}
}
if req.ForceSnapshot || req.ExitWaitGroup != nil {
s.dumpSnapshot(req.LogNumber)
}
close(req.WaitCh)
if req.ExitWaitGroup != nil {
req.ExitWaitGroup.Done()
if req.MetricsCh != nil {
waitCh := make(chan struct{})
req.MetricsCh <- txlog.MetricsState{
Metrics: s.createMetricsState(),
WaitCh: waitCh,
}
// чекаю поки txlog запише снапшот, а отже можна змінювати буфери
<-waitCh
}
}
func (s *Database) createMetricsState() (metrics []txlog.Metric) {
for metricID, metric := range s.metrics {
x := txlog.Metric{
MetricID: metricID,
MetricType: metric.MetricType,
FracDigits: metric.FracDigits,
LastPageNo: metric.LastPageNo,
Since: metric.Since,
SinceValue: metric.SinceValue,
Until: metric.Until, // ?
UntilValue: metric.UntilValue, // ?
}
x.Timestamps, x.TimestampsSize = metric.Timestamps.Snapshot()
x.Values, x.ValuesSize = metric.Values.Snapshot()
metrics = append(metrics, x)
}
return
}
func (s *Database) addMetric(rec txlog.AddedMetric) {
// fix lock
_, ok := s.metrics[rec.MetricID]
if ok {
qb.Abort(qb.MetricAddedBug,
@@ -1005,18 +471,11 @@ func (s *Database) addMetric(rec txlog.AddedMetric) {
rec.MetricID))
}
lockEntry, ok := s.metricLockEntries[rec.MetricID]
if !ok {
qb.Abort(qb.NoLockEntryBug,
fmt.Errorf("addMetric: lockEntry not found for the metric %d",
rec.MetricID))
}
if !lockEntry.XLock {
qb.Abort(qb.NoXLockBug,
fmt.Errorf("addMetric: xlock not set for the metric %d",
rec.MetricID))
}
// if !lockEntry.XLock {
// qb.Abort(qb.NoXLockBug,
// fmt.Errorf("addMetric: xlock not set for the metric %d",
// rec.MetricID))
// }
var (
values qb.ValueCompressor
@@ -1033,12 +492,10 @@ func (s *Database) addMetric(rec txlog.AddedMetric) {
}
s.metrics[rec.MetricID] = &_metric{
MetricType: rec.MetricType,
FracDigits: byte(rec.FracDigits),
TimestampsBuf: timestampsBuf,
ValuesBuf: valuesBuf,
Timestamps: chunkenc.NewReverseTimeDeltaCompressor(timestampsBuf, 0),
Values: values,
MetricType: rec.MetricType,
FracDigits: byte(rec.FracDigits),
Timestamps: chunkenc.NewReverseTimeDeltaCompressor(timestampsBuf, 0),
Values: values,
}
lockEntry.XLock = false
@@ -1046,21 +503,14 @@ func (s *Database) addMetric(rec txlog.AddedMetric) {
}
func (s *Database) deleteMetric(rec txlog.DeletedMetric) {
_, ok := s.metrics[rec.MetricID]
metric, ok := s.metrics[rec.MetricID]
if !ok {
qb.Abort(qb.NoMetricBug,
fmt.Errorf("deleteMetric: metric %d not found",
rec.MetricID))
}
lockEntry, ok := s.metricLockEntries[rec.MetricID]
if !ok {
qb.Abort(qb.NoLockEntryBug,
fmt.Errorf("deleteMetric: lockEntry not found for the metric %d",
rec.MetricID))
}
if !lockEntry.XLock {
if !metric.XLock {
qb.Abort(qb.NoXLockBug,
fmt.Errorf("deleteMetric: xlock not set for the metric %d",
rec.MetricID))
@@ -1068,8 +518,8 @@ func (s *Database) deleteMetric(rec txlog.DeletedMetric) {
var addMetricReqs []tryAddMetricReq
if len(lockEntry.WaitQueue) > 0 {
for _, untyped := range lockEntry.WaitQueue {
if len(metric.WaitQueue) > 0 {
for _, untyped := range metric.WaitQueue {
switch req := untyped.(type) {
// case tryAppendMeasureReq:
// req.ResultCh <- tryAppendMeasureResult{
@@ -1112,11 +562,11 @@ func (s *Database) deleteMetric(rec txlog.DeletedMetric) {
}
}
delete(s.metrics, rec.MetricID)
delete(s.metricLockEntries, rec.MetricID)
if len(rec.FreePageNumbers) > 0 {
s.freeList.AddPages(rec.FreePageNumbers)
}
// ADD in txlog
// if len(rec.FreePageNumbers) > 0 {
// s.freeList.AddPages(rec.FreePageNumbers)
// }
if len(addMetricReqs) > 0 {
s.processTryAddMetricReqsImmediatelyAfterDelete(addMetricReqs)
@@ -1131,30 +581,22 @@ func (s *Database) deleteMeasures(rec txlog.DeletedMeasures) {
rec.MetricID))
}
lockEntry, ok := s.metricLockEntries[rec.MetricID]
if !ok {
qb.Abort(qb.NoLockEntryBug,
fmt.Errorf("deleteMeasures: lockEntry not found for the metric %d",
rec.MetricID))
}
if !lockEntry.XLock {
if !metric.XLock {
qb.Abort(qb.NoXLockBug,
fmt.Errorf("deleteMeasures: xlock not set for the metric %d",
rec.MetricID))
}
metric.DeleteMeasures()
lockEntry.XLock = false
if len(rec.FreePageNumbers) > 0 {
s.freeList.AddPages(rec.FreePageNumbers)
}
s.doAfterReleaseXLock(rec.MetricID, metric, lockEntry)
metric.XLock = false
// FIX add in txlog
// if len(rec.FreePageNumbers) > 0 {
// s.freeList.AddPages(rec.FreePageNumbers)
// }
s.doAfterReleaseXLock(rec.MetricID, metric)
}
func (s *Database) doAfterReleaseXLock(metricID uint32, metric *_metric, lockEntry *metricLockEntry) {
if len(lockEntry.WaitQueue) == 0 {
delete(s.metricLockEntries, metricID)
} else {
s.processMetricQueue(metricID, metric, lockEntry)
func (s *Database) doAfterReleaseXLock(metricID uint32, metric *_metric) {
if len(metric.WaitQueue) > 0 {
s.processMetricQueue(metricID, metric)
}
}