1package gen
2
3import (
4	"math"
5	"time"
6
7	"github.com/influxdata/influxdb/models"
8)
9
10type SeriesGenerator interface {
11	// Next advances the series generator to the next series key.
12	Next() bool
13
14	// Key returns the series key.
15	// The returned value may be cached.
16	Key() []byte
17
18	// Name returns the name of the measurement.
19	// The returned value may be modified by a subsequent call to Next.
20	Name() []byte
21
22	// Tags returns the tag set.
23	// The returned value may be modified by a subsequent call to Next.
24	Tags() models.Tags
25
26	// Field returns the name of the field.
27	// The returned value may be modified by a subsequent call to Next.
28	Field() []byte
29
30	// TimeValuesGenerator returns a values sequence for the current series.
31	TimeValuesGenerator() TimeValuesSequence
32}
33
34type TimeSequenceSpec struct {
35	// Count specifies the maximum number of values to generate.
36	Count int
37
38	// Start specifies the starting time for the values.
39	Start time.Time
40
41	// Delta specifies the interval between time stamps.
42	Delta time.Duration
43
44	// Precision specifies the precision of timestamp intervals
45	Precision time.Duration
46}
47
48func (ts TimeSequenceSpec) ForTimeRange(tr TimeRange) TimeSequenceSpec {
49	// Truncate time range
50	if ts.Delta > 0 {
51		tr = tr.Truncate(ts.Delta)
52	} else {
53		tr = tr.Truncate(ts.Precision)
54	}
55
56	ts.Start = tr.Start
57
58	if ts.Delta > 0 {
59		intervals := int(tr.End.Sub(tr.Start) / ts.Delta)
60		if intervals > ts.Count {
61			// if the number of intervals in the specified time range exceeds
62			// the maximum count, move the start forward to limit the number of values
63			ts.Start = tr.End.Add(-time.Duration(ts.Count) * ts.Delta)
64		} else {
65			ts.Count = intervals
66		}
67	} else {
68		ts.Delta = tr.End.Sub(tr.Start) / time.Duration(ts.Count)
69		if ts.Delta < ts.Precision {
70			// count is too high for the range of time and precision
71			ts.Count = int(tr.End.Sub(tr.Start) / ts.Precision)
72			ts.Delta = ts.Precision
73		} else {
74			ts.Delta = ts.Delta.Round(ts.Precision)
75		}
76		ts.Precision = 0
77	}
78
79	return ts
80}
81
82type TimeRange struct {
83	Start time.Time
84	End   time.Time
85}
86
87func (t TimeRange) Truncate(d time.Duration) TimeRange {
88	return TimeRange{
89		Start: t.Start.Truncate(d),
90		End:   t.End.Truncate(d),
91	}
92}
93
94type TimeValuesSequence interface {
95	Reset()
96	Next() bool
97	Values() Values
98}
99
100type Values interface {
101	MinTime() int64
102	MaxTime() int64
103	Encode([]byte) ([]byte, error)
104}
105
106type cache struct {
107	key  []byte
108	tags models.Tags
109}
110
111type seriesGenerator struct {
112	name  []byte
113	tags  TagsSequence
114	field []byte
115	vg    TimeValuesSequence
116	n     int64
117
118	c cache
119}
120
121func NewSeriesGenerator(name []byte, field []byte, vg TimeValuesSequence, tags TagsSequence) SeriesGenerator {
122	return NewSeriesGeneratorLimit(name, field, vg, tags, math.MaxInt64)
123}
124
125func NewSeriesGeneratorLimit(name []byte, field []byte, vg TimeValuesSequence, tags TagsSequence, n int64) SeriesGenerator {
126	return &seriesGenerator{
127		name:  name,
128		field: field,
129		tags:  tags,
130		vg:    vg,
131		n:     n,
132	}
133}
134
135func (g *seriesGenerator) Next() bool {
136	if g.n > 0 {
137		g.n--
138		if g.tags.Next() {
139			g.c = cache{}
140			g.vg.Reset()
141			return true
142		}
143		g.n = 0
144	}
145
146	return false
147}
148
149func (g *seriesGenerator) Key() []byte {
150	if len(g.c.key) == 0 {
151		g.c.key = models.MakeKey(g.name, g.tags.Value())
152	}
153	return g.c.key
154}
155
156func (g *seriesGenerator) Name() []byte {
157	return g.name
158}
159
160func (g *seriesGenerator) Tags() models.Tags {
161	if len(g.c.tags) == 0 {
162		g.c.tags = g.tags.Value().Clone()
163	}
164	return g.c.tags
165}
166
167func (g *seriesGenerator) Field() []byte {
168	return g.field
169}
170
171func (g *seriesGenerator) TimeValuesGenerator() TimeValuesSequence {
172	return g.vg
173}
174