| 
									
										
										
										
											2019-03-08 22:43:58 +08:00
										 |  |  | // Copyright 2019 The Prometheus Authors
 | 
					
						
							|  |  |  | // Licensed under the Apache License, Version 2.0 (the "License");
 | 
					
						
							|  |  |  | // you may not use this file except in compliance with the License.
 | 
					
						
							|  |  |  | // You may obtain a copy of the License at
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Unless required by applicable law or agreed to in writing, software
 | 
					
						
							|  |  |  | // distributed under the License is distributed on an "AS IS" BASIS,
 | 
					
						
							|  |  |  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
					
						
							|  |  |  | // See the License for the specific language governing permissions and
 | 
					
						
							|  |  |  | // limitations under the License.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Inspired / copied / modified from https://gitlab.com/cznic/strutil/blob/master/strutil.go,
 | 
					
						
							|  |  |  | // which is MIT licensed, so:
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Copyright (c) 2014 The strutil Authors. All rights reserved.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package remote | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-12 07:44:23 +08:00
										 |  |  | import ( | 
					
						
							|  |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2020-07-30 15:45:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-24 17:46:31 +08:00
										 |  |  | 	"github.com/prometheus/client_golang/prometheus" | 
					
						
							|  |  |  | 	"github.com/prometheus/client_golang/prometheus/promauto" | 
					
						
							| 
									
										
										
										
											2020-10-22 17:00:08 +08:00
										 |  |  | 	"go.uber.org/atomic" | 
					
						
							| 
									
										
										
										
											2019-03-12 07:44:23 +08:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2019-03-08 22:43:58 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-24 17:46:31 +08:00
										 |  |  | var noReferenceReleases = promauto.NewCounter(prometheus.CounterOpts{ | 
					
						
							|  |  |  | 	Namespace: namespace, | 
					
						
							|  |  |  | 	Subsystem: subsystem, | 
					
						
							|  |  |  | 	Name:      "string_interner_zero_reference_releases_total", | 
					
						
							|  |  |  | 	Help:      "The number of times release has been called for strings that are not interned.", | 
					
						
							|  |  |  | }) | 
					
						
							| 
									
										
										
										
											2019-03-08 22:43:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | type pool struct { | 
					
						
							|  |  |  | 	mtx  sync.RWMutex | 
					
						
							| 
									
										
										
										
											2019-03-12 07:44:23 +08:00
										 |  |  | 	pool map[string]*entry | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type entry struct { | 
					
						
							| 
									
										
										
										
											2020-07-30 15:45:42 +08:00
										 |  |  | 	refs atomic.Int64 | 
					
						
							| 
									
										
										
										
											2019-10-09 23:41:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	s string | 
					
						
							| 
									
										
										
										
											2019-03-08 22:43:58 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-30 15:45:42 +08:00
										 |  |  | func newEntry(s string) *entry { | 
					
						
							|  |  |  | 	return &entry{s: s} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-08 22:43:58 +08:00
										 |  |  | func newPool() *pool { | 
					
						
							|  |  |  | 	return &pool{ | 
					
						
							| 
									
										
										
										
											2019-03-12 07:44:23 +08:00
										 |  |  | 		pool: map[string]*entry{}, | 
					
						
							| 
									
										
										
										
											2019-03-08 22:43:58 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *pool) intern(s string) string { | 
					
						
							|  |  |  | 	if s == "" { | 
					
						
							|  |  |  | 		return "" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	p.mtx.RLock() | 
					
						
							|  |  |  | 	interned, ok := p.pool[s] | 
					
						
							|  |  |  | 	p.mtx.RUnlock() | 
					
						
							|  |  |  | 	if ok { | 
					
						
							| 
									
										
										
										
											2020-07-30 15:45:42 +08:00
										 |  |  | 		interned.refs.Inc() | 
					
						
							| 
									
										
										
										
											2019-03-12 07:44:23 +08:00
										 |  |  | 		return interned.s | 
					
						
							| 
									
										
										
										
											2019-03-08 22:43:58 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	p.mtx.Lock() | 
					
						
							|  |  |  | 	defer p.mtx.Unlock() | 
					
						
							|  |  |  | 	if interned, ok := p.pool[s]; ok { | 
					
						
							| 
									
										
										
										
											2020-07-30 15:45:42 +08:00
										 |  |  | 		interned.refs.Inc() | 
					
						
							| 
									
										
										
										
											2019-03-12 07:44:23 +08:00
										 |  |  | 		return interned.s | 
					
						
							| 
									
										
										
										
											2019-03-08 22:43:58 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-30 15:45:42 +08:00
										 |  |  | 	p.pool[s] = newEntry(s) | 
					
						
							|  |  |  | 	p.pool[s].refs.Store(1) | 
					
						
							| 
									
										
										
										
											2019-03-08 22:43:58 +08:00
										 |  |  | 	return s | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-12 07:44:23 +08:00
										 |  |  | func (p *pool) release(s string) { | 
					
						
							|  |  |  | 	p.mtx.RLock() | 
					
						
							|  |  |  | 	interned, ok := p.pool[s] | 
					
						
							|  |  |  | 	p.mtx.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							| 
									
										
										
										
											2019-04-24 17:46:31 +08:00
										 |  |  | 		noReferenceReleases.Inc() | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2019-03-12 07:44:23 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-30 15:45:42 +08:00
										 |  |  | 	refs := interned.refs.Dec() | 
					
						
							| 
									
										
										
										
											2019-03-12 07:44:23 +08:00
										 |  |  | 	if refs > 0 { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	p.mtx.Lock() | 
					
						
							|  |  |  | 	defer p.mtx.Unlock() | 
					
						
							| 
									
										
										
										
											2020-07-30 15:45:42 +08:00
										 |  |  | 	if interned.refs.Load() != 0 { | 
					
						
							| 
									
										
										
										
											2019-03-12 07:44:23 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	delete(p.pool, s) | 
					
						
							|  |  |  | } |