2022-12-09 02:01:07 +00:00
|
|
|
// Copyright (C) 2022 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package rangedloop
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"storj.io/common/uuid"
|
|
|
|
"storj.io/storj/satellite/metabase"
|
|
|
|
"storj.io/storj/satellite/metabase/segmentloop"
|
|
|
|
)
|
|
|
|
|
|
|
|
// MetabaseRangeSplitter implements RangeSplitter.
|
|
|
|
type MetabaseRangeSplitter struct {
|
|
|
|
db *metabase.DB
|
|
|
|
|
2023-01-06 08:37:32 +00:00
|
|
|
asOfSystemInterval time.Duration
|
|
|
|
batchSize int
|
2022-12-09 02:01:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// MetabaseSegmentProvider implements SegmentProvider.
|
|
|
|
type MetabaseSegmentProvider struct {
|
|
|
|
db *metabase.DB
|
|
|
|
|
2023-01-06 08:37:32 +00:00
|
|
|
uuidRange UUIDRange
|
|
|
|
asOfSystemTime time.Time
|
|
|
|
asOfSystemInterval time.Duration
|
|
|
|
batchSize int
|
2022-12-09 02:01:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewMetabaseRangeSplitter creates the segment provider.
|
2023-01-19 16:17:01 +00:00
|
|
|
func NewMetabaseRangeSplitter(db *metabase.DB, asOfSystemInterval time.Duration, batchSize int) *MetabaseRangeSplitter {
|
|
|
|
return &MetabaseRangeSplitter{
|
2023-01-06 08:37:32 +00:00
|
|
|
db: db,
|
|
|
|
asOfSystemInterval: asOfSystemInterval,
|
|
|
|
batchSize: batchSize,
|
2022-12-09 02:01:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// CreateRanges splits the segment table into chunks.
|
|
|
|
func (provider *MetabaseRangeSplitter) CreateRanges(nRanges int, batchSize int) ([]SegmentProvider, error) {
|
|
|
|
uuidRanges, err := CreateUUIDRanges(uint32(nRanges))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
asOfSystemTime := time.Now()
|
|
|
|
|
|
|
|
rangeProviders := []SegmentProvider{}
|
|
|
|
for _, uuidRange := range uuidRanges {
|
|
|
|
rangeProviders = append(rangeProviders, &MetabaseSegmentProvider{
|
2023-01-06 08:37:32 +00:00
|
|
|
db: provider.db,
|
|
|
|
uuidRange: uuidRange,
|
|
|
|
asOfSystemTime: asOfSystemTime,
|
|
|
|
asOfSystemInterval: provider.asOfSystemInterval,
|
|
|
|
batchSize: batchSize,
|
2022-12-09 02:01:07 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
return rangeProviders, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Iterate loops over a part of the segment table.
|
|
|
|
func (provider *MetabaseSegmentProvider) Iterate(ctx context.Context, fn func([]segmentloop.Segment) error) error {
|
|
|
|
var startStreamID uuid.UUID
|
|
|
|
var endStreamID uuid.UUID
|
|
|
|
|
|
|
|
if provider.uuidRange.Start != nil {
|
|
|
|
startStreamID = *provider.uuidRange.Start
|
|
|
|
}
|
|
|
|
if provider.uuidRange.End != nil {
|
|
|
|
endStreamID = *provider.uuidRange.End
|
|
|
|
}
|
|
|
|
|
|
|
|
return provider.db.IterateLoopSegments(ctx, metabase.IterateLoopSegments{
|
2023-01-06 08:37:32 +00:00
|
|
|
BatchSize: provider.batchSize,
|
|
|
|
AsOfSystemTime: provider.asOfSystemTime,
|
|
|
|
AsOfSystemInterval: provider.asOfSystemInterval,
|
|
|
|
StartStreamID: startStreamID,
|
|
|
|
EndStreamID: endStreamID,
|
2022-12-09 02:01:07 +00:00
|
|
|
}, func(ctx context.Context, iterator metabase.LoopSegmentsIterator) error {
|
|
|
|
segments := make([]segmentloop.Segment, 0, provider.batchSize)
|
|
|
|
|
|
|
|
segment := metabase.LoopSegmentEntry{}
|
|
|
|
for iterator.Next(ctx, &segment) {
|
|
|
|
err := ctx.Err()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
segments = append(segments, segmentloop.Segment(segment))
|
|
|
|
|
|
|
|
if len(segments) >= provider.batchSize {
|
|
|
|
err = fn(segments)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// prepare for next batch
|
|
|
|
segments = segments[:0]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// send last batch
|
|
|
|
if len(segments) > 0 {
|
|
|
|
return fn(segments)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|