@@ -120,51 +120,61 @@ func (us *userStates) getViaContext(ctx context.Context) (*userState, bool, erro
120
120
return state , ok , nil
121
121
}
122
122
123
- func (us * userStates ) getOrCreateSeries (ctx context.Context , labels labelPairs ) (* userState , model. Fingerprint , * memorySeries , error ) {
123
+ func (us * userStates ) getOrCreate (ctx context.Context ) (* userState , error ) {
124
124
userID , err := user .ExtractOrgID (ctx )
125
125
if err != nil {
126
- return nil , 0 , nil , fmt .Errorf ("no user id" )
126
+ return nil , fmt .Errorf ("no user id" )
127
127
}
128
128
129
129
state , ok := us .get (userID )
130
+ if ok {
131
+ return state , nil
132
+ }
133
+
134
+ seriesInMetric := make ([]metricCounterShard , 0 , metricCounterShards )
135
+ for i := 0 ; i < metricCounterShards ; i ++ {
136
+ seriesInMetric = append (seriesInMetric , metricCounterShard {
137
+ m : map [string ]int {},
138
+ })
139
+ }
140
+
141
+ // Speculatively create a userState object and try to store it
142
+ // in the map. Another goroutine may have got there before
143
+ // us, in which case this userState will be discarded
144
+ state = & userState {
145
+ userID : userID ,
146
+ limits : us .limits ,
147
+ fpToSeries : newSeriesMap (),
148
+ fpLocker : newFingerprintLocker (16 * 1024 ),
149
+ index : newInvertedIndex (),
150
+ ingestedAPISamples : newEWMARate (0.2 , us .cfg .RateUpdatePeriod ),
151
+ ingestedRuleSamples : newEWMARate (0.2 , us .cfg .RateUpdatePeriod ),
152
+ seriesInMetric : seriesInMetric ,
153
+
154
+ memSeriesCreatedTotal : memSeriesCreatedTotal .WithLabelValues (userID ),
155
+ memSeriesRemovedTotal : memSeriesRemovedTotal .WithLabelValues (userID ),
156
+ }
157
+ state .mapper = newFPMapper (state .fpToSeries )
158
+ stored , ok := us .states .LoadOrStore (userID , state )
130
159
if ! ok {
160
+ memUsers .Inc ()
161
+ }
162
+ state = stored .(* userState )
131
163
132
- seriesInMetric := make ([]metricCounterShard , 0 , metricCounterShards )
133
- for i := 0 ; i < metricCounterShards ; i ++ {
134
- seriesInMetric = append (seriesInMetric , metricCounterShard {
135
- m : map [string ]int {},
136
- })
137
- }
164
+ return state , nil
165
+ }
138
166
139
- // Speculatively create a userState object and try to store it
140
- // in the map. Another goroutine may have got there before
141
- // us, in which case this userState will be discarded
142
- state = & userState {
143
- userID : userID ,
144
- limits : us .limits ,
145
- fpToSeries : newSeriesMap (),
146
- fpLocker : newFingerprintLocker (16 * 1024 ),
147
- index : newInvertedIndex (),
148
- ingestedAPISamples : newEWMARate (0.2 , us .cfg .RateUpdatePeriod ),
149
- ingestedRuleSamples : newEWMARate (0.2 , us .cfg .RateUpdatePeriod ),
150
- seriesInMetric : seriesInMetric ,
151
-
152
- memSeriesCreatedTotal : memSeriesCreatedTotal .WithLabelValues (userID ),
153
- memSeriesRemovedTotal : memSeriesRemovedTotal .WithLabelValues (userID ),
154
- }
155
- state .mapper = newFPMapper (state .fpToSeries )
156
- stored , ok := us .states .LoadOrStore (userID , state )
157
- if ! ok {
158
- memUsers .Inc ()
159
- }
160
- state = stored .(* userState )
167
+ func (us * userStates ) getOrCreateSeries (ctx context.Context , labels labelPairs , record * Record ) (* userState , model.Fingerprint , * memorySeries , error ) {
168
+ state , err := us .getOrCreate (ctx )
169
+ if err != nil {
170
+ return nil , 0 , nil , err
161
171
}
162
172
163
- fp , series , err := state .getSeries (labels )
173
+ fp , series , err := state .getSeries (labels , record )
164
174
return state , fp , series , err
165
175
}
166
176
167
- func (u * userState ) getSeries (metric labelPairs ) (model.Fingerprint , * memorySeries , error ) {
177
+ func (u * userState ) getSeries (metric labelPairs , record * Record ) (model.Fingerprint , * memorySeries , error ) {
168
178
rawFP := client .FastFingerprint (metric )
169
179
u .fpLocker .Lock (rawFP )
170
180
fp := u .mapper .mapFP (rawFP , metric )
@@ -178,36 +188,48 @@ func (u *userState) getSeries(metric labelPairs) (model.Fingerprint, *memorySeri
178
188
return fp , series , nil
179
189
}
180
190
191
+ series , err := u .createSeriesWithFingerprint (fp , metric , record )
192
+ if err != nil {
193
+ u .fpLocker .Unlock (fp )
194
+ return 0 , nil , err
195
+ }
196
+
197
+ return fp , series , nil
198
+ }
199
+
200
+ func (u * userState ) createSeriesWithFingerprint (fp model.Fingerprint , metric labelPairs , record * Record ) (* memorySeries , error ) {
181
201
// There's theoretically a relatively harmless race here if multiple
182
202
// goroutines get the length of the series map at the same time, then
183
203
// all proceed to add a new series. This is likely not worth addressing,
184
204
// as this should happen rarely (all samples from one push are added
185
205
// serially), and the overshoot in allowed series would be minimal.
186
206
if u .fpToSeries .length () >= u .limits .MaxSeriesPerUser (u .userID ) {
187
- u .fpLocker .Unlock (fp )
188
- return fp , nil , httpgrpc .Errorf (http .StatusTooManyRequests , "per-user series limit (%d) exceeded" , u .limits .MaxSeriesPerUser (u .userID ))
207
+ return nil , httpgrpc .Errorf (http .StatusTooManyRequests , "per-user series limit (%d) exceeded" , u .limits .MaxSeriesPerUser (u .userID ))
189
208
}
190
209
191
210
metricName , err := extract .MetricNameFromLabelPairs (metric )
192
211
if err != nil {
193
- u .fpLocker .Unlock (fp )
194
- return fp , nil , err
212
+ return nil , err
195
213
}
196
214
197
215
if ! u .canAddSeriesFor (string (metricName )) {
198
- u .fpLocker .Unlock (fp )
199
- return fp , nil , httpgrpc .Errorf (http .StatusTooManyRequests , "per-metric series limit (%d) exceeded for %s: %s" , u .limits .MaxSeriesPerMetric (u .userID ), metricName , metric )
216
+ return nil , httpgrpc .Errorf (http .StatusTooManyRequests , "per-metric series limit (%d) exceeded for %s: %s" , u .limits .MaxSeriesPerMetric (u .userID ), metricName , metric )
200
217
}
201
218
202
219
util .Event ().Log ("msg" , "new series" , "userID" , u .userID , "fp" , fp , "series" , metric )
203
220
u .memSeriesCreatedTotal .Inc ()
204
221
memSeries .Inc ()
205
222
206
- series = newMemorySeries (metric )
223
+ record .Labels = append (record .Labels , Labels {
224
+ Fingerprint : int64 (fp ),
225
+ Labels : metric ,
226
+ })
227
+
228
+ series := newMemorySeries (metric )
207
229
u .fpToSeries .put (fp , series )
208
230
u .index .add (metric , fp )
209
231
210
- return fp , series , nil
232
+ return series , nil
211
233
}
212
234
213
235
func (u * userState ) canAddSeriesFor (metric string ) bool {
0 commit comments