8
8
"fmt"
9
9
"io"
10
10
"sort"
11
-
12
- "github.com/dolthub/swiss"
11
+ "sync"
13
12
14
13
"github.com/prometheus/prometheus/model/labels"
15
14
"github.com/prometheus/prometheus/storage"
@@ -24,8 +23,15 @@ import (
24
23
25
24
// LOKW is the magic number for the Loki WAL format.
26
25
var (
27
- magicNumber = uint32 (0x4C4F4B57 )
28
- magicBuf [4 ]byte
26
+ magicNumber = uint32 (0x4C4F4B57 )
27
+ magicBuf [4 ]byte
28
+ streamSegmentPool = sync.Pool {
29
+ New : func () interface {} {
30
+ return & streamSegment {
31
+ entries : make ([]* logproto.Entry , 0 , 4096 ),
32
+ }
33
+ },
34
+ }
29
35
)
30
36
31
37
func init () {
@@ -37,9 +43,10 @@ type streamID struct {
37
43
}
38
44
39
45
type SegmentWriter struct {
40
- streams * swiss. Map [streamID , * streamSegment ]
46
+ streams map [streamID ] * streamSegment
41
47
buf1 encoding.Encbuf
42
48
inputSize int64
49
+ idxWriter * index.Writer
43
50
}
44
51
45
52
type streamSegment struct {
@@ -49,12 +56,21 @@ type streamSegment struct {
49
56
maxt int64
50
57
}
51
58
59
+ func (s * streamSegment ) Reset () {
60
+ s .entries = s .entries [:0 ]
61
+ }
62
+
52
63
// NewWalSegmentWriter creates a new WalSegmentWriter.
53
- func NewWalSegmentWriter () * SegmentWriter {
54
- return & SegmentWriter {
55
- streams : swiss. NewMap [ streamID , * streamSegment ]( 64 ),
56
- buf1 : encoding . EncWith ( make ([] byte , 0 , 4 )),
64
+ func NewWalSegmentWriter () ( * SegmentWriter , error ) {
65
+ idxWriter , err := index . NewWriter ()
66
+ if err != nil {
67
+ return nil , err
57
68
}
69
+ return & SegmentWriter {
70
+ streams : make (map [streamID ]* streamSegment , 64 ),
71
+ buf1 : encoding .EncWith (make ([]byte , 0 , 4 )),
72
+ idxWriter : idxWriter ,
73
+ }, nil
58
74
}
59
75
60
76
// Labels are passed a string `{foo="bar",baz="qux"}` `{foo="foo",baz="foo"}`. labels.Labels => Symbols foo, baz , qux
@@ -66,22 +82,18 @@ func (b *SegmentWriter) Append(tenantID, labelsString string, lbls labels.Labels
66
82
b .inputSize += int64 (len (e .Line ))
67
83
}
68
84
id := streamID {labels : labelsString , tenant : tenantID }
69
- s , ok := b .streams . Get ( id )
85
+ s , ok := b .streams [ id ]
70
86
if ! ok {
71
87
if lbls .Get (tsdb .TenantLabel ) == "" {
72
88
lbls = labels .NewBuilder (lbls ).Set (tsdb .TenantLabel , tenantID ).Labels ()
73
89
}
74
- s = & streamSegment {
75
- // todo: should be pooled.
76
- // prometheus bucketed pool
77
- // https://pkg.go.dev/github.com/prometheus/prometheus/util/pool
78
- entries : make ([]* logproto.Entry , 0 , 64 ),
79
- lbls : lbls ,
80
- tenantID : tenantID ,
81
- }
90
+ s = streamSegmentPool .Get ().(* streamSegment )
91
+ s .Reset ()
92
+ s .lbls = lbls
93
+ s .tenantID = tenantID
82
94
s .maxt = entries [len (entries )- 1 ].Timestamp .UnixNano ()
83
95
s .entries = append (s .entries , entries ... )
84
- b .streams . Put ( id , s )
96
+ b .streams [ id ] = s
85
97
return
86
98
}
87
99
@@ -105,22 +117,25 @@ func (b *SegmentWriter) Append(tenantID, labelsString string, lbls labels.Labels
105
117
func (b * SegmentWriter ) WriteTo (w io.Writer ) (int64 , error ) {
106
118
var (
107
119
total int64
108
- streams = make ([]* streamSegment , 0 , b .streams . Count ( ))
120
+ streams = make ([]* streamSegment , 0 , len ( b .streams ))
109
121
)
110
122
111
123
// Collect all streams and sort them by tenantID and labels.
112
- b .streams .Iter (func (k streamID , v * streamSegment ) bool {
113
- streams = append (streams , v )
114
- return false
115
- })
124
+ for _ , s := range b .streams {
125
+ if len (s .entries ) == 0 {
126
+ continue
127
+ }
128
+ streams = append (streams , s )
129
+ }
130
+
116
131
sort .Slice (streams , func (i , j int ) bool {
117
132
if streams [i ].tenantID != streams [j ].tenantID {
118
133
return streams [i ].tenantID < streams [j ].tenantID
119
134
}
120
135
return labels .Compare (streams [i ].lbls , streams [j ].lbls ) < 0
121
136
})
122
137
123
- idxw , err := index . NewWriter ( context . TODO () )
138
+ err := b . idxWriter . Reset ( )
124
139
if err != nil {
125
140
return total , err
126
141
}
@@ -143,7 +158,7 @@ func (b *SegmentWriter) WriteTo(w io.Writer) (int64, error) {
143
158
144
159
// Add symbols
145
160
for _ , symbol := range symbols {
146
- if err := idxw .AddSymbol (symbol ); err != nil {
161
+ if err := b . idxWriter .AddSymbol (symbol ); err != nil {
147
162
return total , err
148
163
}
149
164
}
@@ -163,7 +178,7 @@ func (b *SegmentWriter) WriteTo(w io.Writer) (int64, error) {
163
178
if err != nil {
164
179
return total , err
165
180
}
166
- err = idxw .AddSeries (storage .SeriesRef (i ), s .lbls , chunks.Meta {
181
+ err = b . idxWriter .AddSeries (storage .SeriesRef (i ), s .lbls , chunks.Meta {
167
182
MinTime : s .entries [0 ].Timestamp .UnixNano (),
168
183
MaxTime : s .entries [len (s .entries )- 1 ].Timestamp .UnixNano (),
169
184
Ref : chunks .NewChunkRef (uint64 (total ), uint64 (n )),
@@ -175,11 +190,11 @@ func (b *SegmentWriter) WriteTo(w io.Writer) (int64, error) {
175
190
176
191
}
177
192
178
- if err := idxw .Close (); err != nil {
193
+ if err := b . idxWriter .Close (); err != nil {
179
194
return total , err
180
195
}
181
196
182
- buf , closer , err := idxw .Buffer ()
197
+ buf , closer , err := b . idxWriter .Buffer ()
183
198
if err != nil {
184
199
return total , err
185
200
}
@@ -226,7 +241,11 @@ func (s *streamSegment) WriteTo(w io.Writer) (n int64, err error) {
226
241
// Reset clears the writer.
227
242
// After calling Reset, the writer can be reused.
228
243
func (b * SegmentWriter ) Reset () {
229
- b .streams .Clear ()
244
+ for _ , s := range b .streams {
245
+ s := s
246
+ streamSegmentPool .Put (s )
247
+ }
248
+ b .streams = make (map [streamID ]* streamSegment , 64 )
230
249
b .buf1 .Reset ()
231
250
b .inputSize = 0
232
251
}
0 commit comments