@@ -107,6 +107,7 @@ type CustomSampler struct {
107107 config * gql.GetSamplingConfigSamplingSamplingConfig
108108 regexCache map [string ]* regexp.Regexp
109109 mutex sync.RWMutex
110+ regexMutex sync.RWMutex
110111}
111112
112113// NewCustomSampler creates a new CustomSampler with the given sampler function
@@ -139,7 +140,17 @@ func (cs *CustomSampler) IsSamplingEnabled() bool {
139140
140141// getCachedRegex gets a cached regex pattern
141142func (cs * CustomSampler ) getCachedRegex (pattern string ) (* regexp.Regexp , error ) {
142- // Will always be locked by the caller.
143+ result := getExitingCachedRegex (cs , pattern )
144+ if result != nil {
145+ return result , nil
146+ }
147+
148+ // There was not a cached regex, so we need to compile and cache it.
149+ cs .regexMutex .Lock ()
150+ defer cs .regexMutex .Unlock ()
151+
152+ // Between checking and here we had to release the lock, so we need to check
153+ // again to see if someone else has already compiled and cached the regex.
143154 if regex , exists := cs .regexCache [pattern ]; exists {
144155 return regex , nil
145156 }
@@ -150,9 +161,22 @@ func (cs *CustomSampler) getCachedRegex(pattern string) (*regexp.Regexp, error)
150161 }
151162
152163 cs .regexCache [pattern ] = compiled
164+
153165 return compiled , nil
154166}
155167
168+ func getExitingCachedRegex (cs * CustomSampler , pattern string ) * regexp.Regexp {
169+ cs .regexMutex .RLock ()
170+ defer cs .regexMutex .RUnlock ()
171+
172+ // Will always be locked by the caller.
173+ if regex , exists := cs .regexCache [pattern ]; exists {
174+ return regex
175+ }
176+
177+ return nil
178+ }
179+
156180type matchable interface {
157181 attribute.Value | attribute.Key | string | log.Value
158182}
0 commit comments