@@ -120,51 +120,61 @@ func (us *userStates) getViaContext(ctx context.Context) (*userState, bool, erro
120120 return state , ok , nil
121121}
122122
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 ) {
124124 userID , err := user .ExtractOrgID (ctx )
125125 if err != nil {
126- return nil , 0 , nil , fmt .Errorf ("no user id" )
126+ return nil , fmt .Errorf ("no user id" )
127127 }
128128
129129 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 )
130159 if ! ok {
160+ memUsers .Inc ()
161+ }
162+ state = stored .(* userState )
131163
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+ }
138166
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
161171 }
162172
163- fp , series , err := state .getSeries (labels )
173+ fp , series , err := state .getSeries (labels , record )
164174 return state , fp , series , err
165175}
166176
167- func (u * userState ) getSeries (metric labelPairs ) (model.Fingerprint , * memorySeries , error ) {
177+ func (u * userState ) getSeries (metric labelPairs , record * Record ) (model.Fingerprint , * memorySeries , error ) {
168178 rawFP := client .FastFingerprint (metric )
169179 u .fpLocker .Lock (rawFP )
170180 fp := u .mapper .mapFP (rawFP , metric )
@@ -178,36 +188,48 @@ func (u *userState) getSeries(metric labelPairs) (model.Fingerprint, *memorySeri
178188 return fp , series , nil
179189 }
180190
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 ) {
181201 // There's theoretically a relatively harmless race here if multiple
182202 // goroutines get the length of the series map at the same time, then
183203 // all proceed to add a new series. This is likely not worth addressing,
184204 // as this should happen rarely (all samples from one push are added
185205 // serially), and the overshoot in allowed series would be minimal.
186206 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 ))
189208 }
190209
191210 metricName , err := extract .MetricNameFromLabelPairs (metric )
192211 if err != nil {
193- u .fpLocker .Unlock (fp )
194- return fp , nil , err
212+ return nil , err
195213 }
196214
197215 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 )
200217 }
201218
202219 util .Event ().Log ("msg" , "new series" , "userID" , u .userID , "fp" , fp , "series" , metric )
203220 u .memSeriesCreatedTotal .Inc ()
204221 memSeries .Inc ()
205222
206- series = newMemorySeries (metric )
223+ record .Labels = append (record .Labels , Labels {
224+ Fingerprint : int64 (fp ),
225+ Labels : metric ,
226+ })
227+
228+ series := newMemorySeries (metric )
207229 u .fpToSeries .put (fp , series )
208230 u .index .add (metric , fp )
209231
210- return fp , series , nil
232+ return series , nil
211233}
212234
213235func (u * userState ) canAddSeriesFor (metric string ) bool {
0 commit comments