6
6
"math"
7
7
"strings"
8
8
9
- "github.com/apache/arrow/go/v8 /arrow"
10
- "github.com/apache/arrow/go/v8 /arrow/array"
11
- "github.com/apache/arrow/go/v8 /arrow/memory"
9
+ "github.com/apache/arrow/go/v10 /arrow"
10
+ "github.com/apache/arrow/go/v10 /arrow/array"
11
+ "github.com/apache/arrow/go/v10 /arrow/memory"
12
12
"github.com/go-kit/log"
13
13
"github.com/polarsignals/frostdb"
14
14
frost "github.com/polarsignals/frostdb"
@@ -17,12 +17,15 @@ import (
17
17
"github.com/polarsignals/frostdb/query"
18
18
"github.com/polarsignals/frostdb/query/logicalplan"
19
19
"github.com/prometheus/client_golang/prometheus"
20
+ "github.com/segmentio/parquet-go"
21
+ "github.com/thanos-io/objstore/providers/filesystem"
22
+
20
23
"github.com/prometheus/prometheus/model/exemplar"
24
+ "github.com/prometheus/prometheus/model/histogram"
21
25
"github.com/prometheus/prometheus/model/labels"
26
+ "github.com/prometheus/prometheus/model/metadata"
22
27
"github.com/prometheus/prometheus/storage"
23
28
"github.com/prometheus/prometheus/tsdb/chunkenc"
24
- "github.com/segmentio/parquet-go"
25
- "github.com/thanos-io/objstore/providers/filesystem"
26
29
)
27
30
28
31
type FrostDB struct {
@@ -38,6 +41,14 @@ type FrostAppender struct {
38
41
tableRef * frostdb.Table
39
42
}
40
43
44
+ func (f * FrostAppender ) AppendHistogram (ref storage.SeriesRef , l labels.Labels , t int64 , h * histogram.Histogram , fh * histogram.FloatHistogram ) (storage.SeriesRef , error ) {
45
+ panic ("histogram not supported" )
46
+ }
47
+
48
+ func (f * FrostAppender ) UpdateMetadata (ref storage.SeriesRef , l labels.Labels , m metadata.Metadata ) (storage.SeriesRef , error ) {
49
+ panic ("metadata not supported" )
50
+ }
51
+
41
52
type FrostQuerier struct {
42
53
* FrostDB
43
54
}
@@ -47,8 +58,8 @@ func Open(dir string, reg prometheus.Registerer, logger log.Logger) (*FrostDB, e
47
58
bucket , err := filesystem .NewBucket (dir )
48
59
ctx := context .Background ()
49
60
store , err := frost .New (
50
- logger ,
51
- reg ,
61
+ frost . WithLogger ( logger ) ,
62
+ frost . WithRegistry ( reg ) ,
52
63
frost .WithWAL (),
53
64
frost .WithStoragePath (dir ),
54
65
frost .WithBucketStorage (bucket ),
@@ -67,7 +78,7 @@ func Open(dir string, reg prometheus.Registerer, logger log.Logger) (*FrostDB, e
67
78
return nil , err
68
79
}
69
80
table , err := db .Table (
70
- "metrics" ,
81
+ tableMetrics ,
71
82
frost .NewTableConfig (schema ),
72
83
)
73
84
if err != nil {
@@ -92,10 +103,10 @@ func (f *FrostQuerier) LabelValues(name string, matchers ...*labels.Matcher) ([]
92
103
)
93
104
94
105
sets := map [uint64 ]* series {}
95
- err := engine .ScanTable ("metrics" ).
106
+ err := engine .ScanTable (tableMetrics ).
96
107
Filter (promMatchersToFrostDBExprs (matchers )).
97
108
Distinct (logicalplan .Col ("labels." + name )).
98
- Execute (context .Background (), func (ar arrow.Record ) error {
109
+ Execute (context .Background (), func (ctx context. Context , ar arrow.Record ) error {
99
110
defer ar .Release ()
100
111
parseRecordIntoSeriesSet (ar , sets )
101
112
return nil
@@ -105,7 +116,7 @@ func (f *FrostQuerier) LabelValues(name string, matchers ...*labels.Matcher) ([]
105
116
}
106
117
107
118
s := flattenSeriesSets (sets )
108
- names := []string {}
119
+ names := make ( []string , 0 , len ( s . sets ))
109
120
for _ , s := range s .sets {
110
121
for _ , l := range s .l {
111
122
names = append (names , l .Value )
@@ -139,10 +150,10 @@ func (f *FrostQuerier) LabelNames(matchers ...*labels.Matcher) ([]string, storag
139
150
)
140
151
141
152
sets := map [string ]struct {}{}
142
- err := engine .ScanTable ("metrics" ).
143
- Project (logicalplan .DynCol ("labels" )).
153
+ err := engine .ScanTable (tableMetrics ).
154
+ Project (logicalplan .DynCol (columnLabels )).
144
155
Filter (promMatchersToFrostDBExprs (matchers )).
145
- Execute (context .Background (), func (ar arrow.Record ) error {
156
+ Execute (context .Background (), func (ctx context. Context , ar arrow.Record ) error {
146
157
defer ar .Release ()
147
158
for i := 0 ; i < int (ar .NumCols ()); i ++ {
148
159
sets [ar .ColumnName (i )] = struct {}{}
@@ -172,20 +183,20 @@ func (f *FrostQuerier) Select(sortSeries bool, hints *storage.SelectHints, match
172
183
)
173
184
174
185
sets := map [uint64 ]* series {}
175
- err := engine .ScanTable ("metrics" ).
186
+ err := engine .ScanTable (tableMetrics ).
176
187
Filter (logicalplan .And (
177
188
logicalplan .And (
178
- logicalplan .Col ("timestamp" ).Gt (logicalplan .Literal (hints .Start )),
179
- logicalplan .Col ("timestamp" ).Lt (logicalplan .Literal (hints .End )),
189
+ logicalplan .Col (columnTimestamp ).Gt (logicalplan .Literal (hints .Start )),
190
+ logicalplan .Col (columnTimestamp ).Lt (logicalplan .Literal (hints .End )),
180
191
),
181
192
promMatchersToFrostDBExprs (matchers ),
182
193
)).
183
194
Project (
184
- logicalplan .DynCol ("labels" ),
185
- logicalplan .Col ("timestamp" ),
186
- logicalplan .Col ("value" ),
195
+ logicalplan .DynCol (columnLabels ),
196
+ logicalplan .Col (columnTimestamp ),
197
+ logicalplan .Col (columnValue ),
187
198
).
188
- Execute (context .Background (), func (ar arrow.Record ) error {
199
+ Execute (context .Background (), func (ctx context. Context , ar arrow.Record ) error {
189
200
defer ar .Release ()
190
201
parseRecordIntoSeriesSet (ar , sets )
191
202
return nil
@@ -260,39 +271,48 @@ func (f *FrostDB) ChunkQuerier(ctx context.Context, mint, maxt int64) (storage.C
260
271
return nil , nil
261
272
}
262
273
274
+ const (
275
+ tableMetrics = "metrics"
276
+ columnLabels = "labels"
277
+ columnTimestamp = "timestamp"
278
+ columnValue = "value"
279
+ )
280
+
263
281
func promSchema () (* dynparquet.Schema , error ) {
264
282
return dynparquet .SchemaFromDefinition (& schemapb.Schema {
265
283
Name : "metrics_schema" ,
266
284
Columns : []* schemapb.Column {{
267
- Name : "labels" ,
285
+ Name : columnLabels ,
268
286
StorageLayout : & schemapb.StorageLayout {
269
287
Type : schemapb .StorageLayout_TYPE_STRING ,
270
288
Encoding : schemapb .StorageLayout_ENCODING_RLE_DICTIONARY ,
271
289
Nullable : true ,
272
290
},
273
291
Dynamic : true ,
274
292
}, {
275
- Name : "timestamp" ,
293
+ Name : columnTimestamp ,
276
294
StorageLayout : & schemapb.StorageLayout {
277
295
Type : schemapb .StorageLayout_TYPE_INT64 ,
278
296
},
279
297
Dynamic : false ,
280
298
}, {
281
- Name : "value" ,
299
+ Name : columnValue ,
282
300
StorageLayout : & schemapb.StorageLayout {
283
301
Type : schemapb .StorageLayout_TYPE_DOUBLE ,
284
302
},
285
303
Dynamic : false ,
286
304
}},
287
- SortingColumns : []* schemapb.SortingColumn {{
288
- Name : "labels" ,
289
- NullsFirst : true ,
290
- Direction : schemapb .SortingColumn_DIRECTION_ASCENDING ,
291
- },
305
+ SortingColumns : []* schemapb.SortingColumn {
306
+ {
307
+ Name : columnLabels ,
308
+ NullsFirst : true ,
309
+ Direction : schemapb .SortingColumn_DIRECTION_ASCENDING ,
310
+ },
292
311
{
293
- Name : "timestamp" ,
312
+ Name : columnTimestamp ,
294
313
Direction : schemapb .SortingColumn_DIRECTION_ASCENDING ,
295
- }},
314
+ },
315
+ },
296
316
})
297
317
}
298
318
@@ -306,6 +326,18 @@ type arrowSeries struct {
306
326
* series
307
327
}
308
328
329
+ func (a * arrowSeries ) AtHistogram () (int64 , * histogram.Histogram ) {
330
+ panic ("histogram not supported" )
331
+ }
332
+
333
+ func (a * arrowSeries ) AtFloatHistogram () (int64 , * histogram.FloatHistogram ) {
334
+ panic ("histogram not supported" )
335
+ }
336
+
337
+ func (a * arrowSeries ) AtT () int64 {
338
+ return a .series .ts [a .index ]
339
+ }
340
+
309
341
func (a * arrowSeriesSet ) Next () bool {
310
342
a .index ++
311
343
return a .index < len (a .sets )
@@ -322,22 +354,27 @@ func (a *arrowSeriesSet) Err() error { return nil }
322
354
func (a * arrowSeriesSet ) Warnings () storage.Warnings { return nil }
323
355
324
356
func (a * arrowSeries ) Labels () labels.Labels { return a .l }
325
- func (a * arrowSeries ) Iterator () chunkenc.Iterator {
357
+
358
+ func (a * arrowSeries ) Iterator (iterator chunkenc.Iterator ) chunkenc.Iterator {
359
+ // TODO: Use iterator here?
326
360
return a
327
361
}
328
362
329
- func (a * arrowSeries ) Next () bool {
363
+ func (a * arrowSeries ) Next () chunkenc. ValueType {
330
364
a .index ++
331
- return a .index < len (a .ts )
365
+ if a .index < len (a .ts ) {
366
+ return chunkenc .ValFloat
367
+ }
368
+ return chunkenc .ValNone
332
369
}
333
370
334
- func (a * arrowSeries ) Seek (i int64 ) bool {
371
+ func (a * arrowSeries ) Seek (i int64 ) chunkenc. ValueType {
335
372
for ; a .index < len (a .series .ts ); a .index ++ {
336
373
if a .series .ts [a .index ] >= i {
337
- return true
374
+ return chunkenc . ValFloat
338
375
}
339
376
}
340
- return false
377
+ return chunkenc . ValNone
341
378
}
342
379
343
380
func (a * arrowSeries ) At () (int64 , float64 ) {
@@ -377,26 +414,34 @@ type series struct {
377
414
}
378
415
379
416
func parseRecord (r arrow.Record ) map [uint64 ]* series {
380
-
381
417
seriesset := map [uint64 ]* series {}
382
418
383
419
for i := 0 ; i < int (r .NumRows ()); i ++ {
384
420
lbls := labels.Labels {}
385
421
var ts int64
386
422
var v float64
387
423
for j := 0 ; j < int (r .NumCols ()); j ++ {
424
+ columnName := r .ColumnName (j )
388
425
switch {
389
- case r . ColumnName ( j ) == "timestamp" :
426
+ case columnName == columnTimestamp :
390
427
ts = r .Column (j ).(* array.Int64 ).Value (i )
391
- case r . ColumnName ( j ) == "value" :
428
+ case columnName == columnValue :
392
429
v = r .Column (j ).(* array.Float64 ).Value (i )
393
430
default :
394
- name := strings .TrimPrefix (r .ColumnName (j ), "labels." )
395
- value := r .Column (j ).(* array.Binary ).Value (i )
431
+ name := strings .TrimPrefix (columnName , "labels." )
432
+ nameColumn , err := DictionaryFromRecord (r , columnName )
433
+ if err != nil {
434
+ continue
435
+ }
436
+ if nameColumn .IsNull (i ) {
437
+ continue
438
+ }
439
+
440
+ value := StringValueFromDictionary (nameColumn , i )
396
441
if string (value ) != "" {
397
442
lbls = append (lbls , labels.Label {
398
443
Name : name ,
399
- Value : string ( value ) ,
444
+ Value : value ,
400
445
})
401
446
}
402
447
}
@@ -417,6 +462,31 @@ func parseRecord(r arrow.Record) map[uint64]*series {
417
462
return seriesset
418
463
}
419
464
465
+ func DictionaryFromRecord (ar arrow.Record , name string ) (* array.Dictionary , error ) {
466
+ indices := ar .Schema ().FieldIndices (name )
467
+ if len (indices ) != 1 {
468
+ return nil , fmt .Errorf ("expected 1 column named %q, got %d" , name , len (indices ))
469
+ }
470
+
471
+ col , ok := ar .Column (indices [0 ]).(* array.Dictionary )
472
+ if ! ok {
473
+ return nil , fmt .Errorf ("expected column %q to be a dictionary column, got %T" , name , ar .Column (indices [0 ]))
474
+ }
475
+
476
+ return col , nil
477
+ }
478
+
479
+ func StringValueFromDictionary (arr * array.Dictionary , i int ) string {
480
+ switch dict := arr .Dictionary ().(type ) {
481
+ case * array.Binary :
482
+ return string (dict .Value (arr .GetValueIndex (i )))
483
+ case * array.String :
484
+ return dict .Value (arr .GetValueIndex (i ))
485
+ default :
486
+ panic (fmt .Sprintf ("unsupported dictionary type: %T" , dict ))
487
+ }
488
+ }
489
+
420
490
// merge's a,b into an ordered list, maintains this same order for the floats
421
491
func merge (a , b []int64 , af , bf []float64 ) ([]int64 , []float64 ) {
422
492
0 commit comments