vec.go 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. // Copyright 2014 The Prometheus Authors
  2. // Licensed under the Apache License, Version 2.0 (the "License");
  3. // you may not use this file except in compliance with the License.
  4. // You may obtain a copy of the License at
  5. //
  6. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. package prometheus
  14. import (
  15. "fmt"
  16. "sync"
  17. "github.com/prometheus/common/model"
  18. )
  19. // metricVec is a Collector to bundle metrics of the same name that differ in
  20. // their label values. metricVec is not used directly (and therefore
  21. // unexported). It is used as a building block for implementations of vectors of
  22. // a given metric type, like GaugeVec, CounterVec, SummaryVec, HistogramVec, and
  23. // UntypedVec.
  24. type metricVec struct {
  25. mtx sync.RWMutex // Protects the children.
  26. children map[uint64][]metricWithLabelValues
  27. desc *Desc
  28. newMetric func(labelValues ...string) Metric
  29. hashAdd func(h uint64, s string) uint64 // replace hash function for testing collision handling
  30. hashAddByte func(h uint64, b byte) uint64
  31. }
  32. // newMetricVec returns an initialized metricVec.
  33. func newMetricVec(desc *Desc, newMetric func(lvs ...string) Metric) *metricVec {
  34. return &metricVec{
  35. children: map[uint64][]metricWithLabelValues{},
  36. desc: desc,
  37. newMetric: newMetric,
  38. hashAdd: hashAdd,
  39. hashAddByte: hashAddByte,
  40. }
  41. }
  42. // metricWithLabelValues provides the metric and its label values for
  43. // disambiguation on hash collision.
  44. type metricWithLabelValues struct {
  45. values []string
  46. metric Metric
  47. }
  48. // Describe implements Collector. The length of the returned slice
  49. // is always one.
  50. func (m *metricVec) Describe(ch chan<- *Desc) {
  51. ch <- m.desc
  52. }
  53. // Collect implements Collector.
  54. func (m *metricVec) Collect(ch chan<- Metric) {
  55. m.mtx.RLock()
  56. defer m.mtx.RUnlock()
  57. for _, metrics := range m.children {
  58. for _, metric := range metrics {
  59. ch <- metric.metric
  60. }
  61. }
  62. }
  63. func (m *metricVec) getMetricWithLabelValues(lvs ...string) (Metric, error) {
  64. h, err := m.hashLabelValues(lvs)
  65. if err != nil {
  66. return nil, err
  67. }
  68. return m.getOrCreateMetricWithLabelValues(h, lvs), nil
  69. }
  70. func (m *metricVec) getMetricWith(labels Labels) (Metric, error) {
  71. h, err := m.hashLabels(labels)
  72. if err != nil {
  73. return nil, err
  74. }
  75. return m.getOrCreateMetricWithLabels(h, labels), nil
  76. }
  77. func (m *metricVec) withLabelValues(lvs ...string) Metric {
  78. metric, err := m.getMetricWithLabelValues(lvs...)
  79. if err != nil {
  80. panic(err)
  81. }
  82. return metric
  83. }
  84. func (m *metricVec) with(labels Labels) Metric {
  85. metric, err := m.getMetricWith(labels)
  86. if err != nil {
  87. panic(err)
  88. }
  89. return metric
  90. }
  91. // DeleteLabelValues removes the metric where the variable labels are the same
  92. // as those passed in as labels (same order as the VariableLabels in Desc). It
  93. // returns true if a metric was deleted.
  94. //
  95. // It is not an error if the number of label values is not the same as the
  96. // number of VariableLabels in Desc. However, such inconsistent label count can
  97. // never match an actual metric, so the method will always return false in that
  98. // case.
  99. //
  100. // Note that for more than one label value, this method is prone to mistakes
  101. // caused by an incorrect order of arguments. Consider Delete(Labels) as an
  102. // alternative to avoid that type of mistake. For higher label numbers, the
  103. // latter has a much more readable (albeit more verbose) syntax, but it comes
  104. // with a performance overhead (for creating and processing the Labels map).
  105. // See also the CounterVec example.
  106. func (m *metricVec) DeleteLabelValues(lvs ...string) bool {
  107. m.mtx.Lock()
  108. defer m.mtx.Unlock()
  109. h, err := m.hashLabelValues(lvs)
  110. if err != nil {
  111. return false
  112. }
  113. return m.deleteByHashWithLabelValues(h, lvs)
  114. }
  115. // Delete deletes the metric where the variable labels are the same as those
  116. // passed in as labels. It returns true if a metric was deleted.
  117. //
  118. // It is not an error if the number and names of the Labels are inconsistent
  119. // with those of the VariableLabels in Desc. However, such inconsistent Labels
  120. // can never match an actual metric, so the method will always return false in
  121. // that case.
  122. //
  123. // This method is used for the same purpose as DeleteLabelValues(...string). See
  124. // there for pros and cons of the two methods.
  125. func (m *metricVec) Delete(labels Labels) bool {
  126. m.mtx.Lock()
  127. defer m.mtx.Unlock()
  128. h, err := m.hashLabels(labels)
  129. if err != nil {
  130. return false
  131. }
  132. return m.deleteByHashWithLabels(h, labels)
  133. }
  134. // deleteByHashWithLabelValues removes the metric from the hash bucket h. If
  135. // there are multiple matches in the bucket, use lvs to select a metric and
  136. // remove only that metric.
  137. func (m *metricVec) deleteByHashWithLabelValues(h uint64, lvs []string) bool {
  138. metrics, ok := m.children[h]
  139. if !ok {
  140. return false
  141. }
  142. i := m.findMetricWithLabelValues(metrics, lvs)
  143. if i >= len(metrics) {
  144. return false
  145. }
  146. if len(metrics) > 1 {
  147. m.children[h] = append(metrics[:i], metrics[i+1:]...)
  148. } else {
  149. delete(m.children, h)
  150. }
  151. return true
  152. }
  153. // deleteByHashWithLabels removes the metric from the hash bucket h. If there
  154. // are multiple matches in the bucket, use lvs to select a metric and remove
  155. // only that metric.
  156. func (m *metricVec) deleteByHashWithLabels(h uint64, labels Labels) bool {
  157. metrics, ok := m.children[h]
  158. if !ok {
  159. return false
  160. }
  161. i := m.findMetricWithLabels(metrics, labels)
  162. if i >= len(metrics) {
  163. return false
  164. }
  165. if len(metrics) > 1 {
  166. m.children[h] = append(metrics[:i], metrics[i+1:]...)
  167. } else {
  168. delete(m.children, h)
  169. }
  170. return true
  171. }
  172. // Reset deletes all metrics in this vector.
  173. func (m *metricVec) Reset() {
  174. m.mtx.Lock()
  175. defer m.mtx.Unlock()
  176. for h := range m.children {
  177. delete(m.children, h)
  178. }
  179. }
  180. func (m *metricVec) hashLabelValues(vals []string) (uint64, error) {
  181. if err := validateLabelValues(vals, len(m.desc.variableLabels)); err != nil {
  182. return 0, err
  183. }
  184. h := hashNew()
  185. for _, val := range vals {
  186. h = m.hashAdd(h, val)
  187. h = m.hashAddByte(h, model.SeparatorByte)
  188. }
  189. return h, nil
  190. }
  191. func (m *metricVec) hashLabels(labels Labels) (uint64, error) {
  192. if err := validateValuesInLabels(labels, len(m.desc.variableLabels)); err != nil {
  193. return 0, err
  194. }
  195. h := hashNew()
  196. for _, label := range m.desc.variableLabels {
  197. val, ok := labels[label]
  198. if !ok {
  199. return 0, fmt.Errorf("label name %q missing in label map", label)
  200. }
  201. h = m.hashAdd(h, val)
  202. h = m.hashAddByte(h, model.SeparatorByte)
  203. }
  204. return h, nil
  205. }
  206. // getOrCreateMetricWithLabelValues retrieves the metric by hash and label value
  207. // or creates it and returns the new one.
  208. //
  209. // This function holds the mutex.
  210. func (m *metricVec) getOrCreateMetricWithLabelValues(hash uint64, lvs []string) Metric {
  211. m.mtx.RLock()
  212. metric, ok := m.getMetricWithHashAndLabelValues(hash, lvs)
  213. m.mtx.RUnlock()
  214. if ok {
  215. return metric
  216. }
  217. m.mtx.Lock()
  218. defer m.mtx.Unlock()
  219. metric, ok = m.getMetricWithHashAndLabelValues(hash, lvs)
  220. if !ok {
  221. // Copy to avoid allocation in case wo don't go down this code path.
  222. copiedLVs := make([]string, len(lvs))
  223. copy(copiedLVs, lvs)
  224. metric = m.newMetric(copiedLVs...)
  225. m.children[hash] = append(m.children[hash], metricWithLabelValues{values: copiedLVs, metric: metric})
  226. }
  227. return metric
  228. }
  229. // getOrCreateMetricWithLabelValues retrieves the metric by hash and label value
  230. // or creates it and returns the new one.
  231. //
  232. // This function holds the mutex.
  233. func (m *metricVec) getOrCreateMetricWithLabels(hash uint64, labels Labels) Metric {
  234. m.mtx.RLock()
  235. metric, ok := m.getMetricWithHashAndLabels(hash, labels)
  236. m.mtx.RUnlock()
  237. if ok {
  238. return metric
  239. }
  240. m.mtx.Lock()
  241. defer m.mtx.Unlock()
  242. metric, ok = m.getMetricWithHashAndLabels(hash, labels)
  243. if !ok {
  244. lvs := m.extractLabelValues(labels)
  245. metric = m.newMetric(lvs...)
  246. m.children[hash] = append(m.children[hash], metricWithLabelValues{values: lvs, metric: metric})
  247. }
  248. return metric
  249. }
  250. // getMetricWithHashAndLabelValues gets a metric while handling possible
  251. // collisions in the hash space. Must be called while holding the read mutex.
  252. func (m *metricVec) getMetricWithHashAndLabelValues(h uint64, lvs []string) (Metric, bool) {
  253. metrics, ok := m.children[h]
  254. if ok {
  255. if i := m.findMetricWithLabelValues(metrics, lvs); i < len(metrics) {
  256. return metrics[i].metric, true
  257. }
  258. }
  259. return nil, false
  260. }
  261. // getMetricWithHashAndLabels gets a metric while handling possible collisions in
  262. // the hash space. Must be called while holding read mutex.
  263. func (m *metricVec) getMetricWithHashAndLabels(h uint64, labels Labels) (Metric, bool) {
  264. metrics, ok := m.children[h]
  265. if ok {
  266. if i := m.findMetricWithLabels(metrics, labels); i < len(metrics) {
  267. return metrics[i].metric, true
  268. }
  269. }
  270. return nil, false
  271. }
  272. // findMetricWithLabelValues returns the index of the matching metric or
  273. // len(metrics) if not found.
  274. func (m *metricVec) findMetricWithLabelValues(metrics []metricWithLabelValues, lvs []string) int {
  275. for i, metric := range metrics {
  276. if m.matchLabelValues(metric.values, lvs) {
  277. return i
  278. }
  279. }
  280. return len(metrics)
  281. }
  282. // findMetricWithLabels returns the index of the matching metric or len(metrics)
  283. // if not found.
  284. func (m *metricVec) findMetricWithLabels(metrics []metricWithLabelValues, labels Labels) int {
  285. for i, metric := range metrics {
  286. if m.matchLabels(metric.values, labels) {
  287. return i
  288. }
  289. }
  290. return len(metrics)
  291. }
  292. func (m *metricVec) matchLabelValues(values []string, lvs []string) bool {
  293. if len(values) != len(lvs) {
  294. return false
  295. }
  296. for i, v := range values {
  297. if v != lvs[i] {
  298. return false
  299. }
  300. }
  301. return true
  302. }
  303. func (m *metricVec) matchLabels(values []string, labels Labels) bool {
  304. if len(labels) != len(values) {
  305. return false
  306. }
  307. for i, k := range m.desc.variableLabels {
  308. if values[i] != labels[k] {
  309. return false
  310. }
  311. }
  312. return true
  313. }
  314. func (m *metricVec) extractLabelValues(labels Labels) []string {
  315. labelValues := make([]string, len(labels))
  316. for i, k := range m.desc.variableLabels {
  317. labelValues[i] = labels[k]
  318. }
  319. return labelValues
  320. }