Skip to content

Commit

Permalink
Alternative implementation.
Browse files Browse the repository at this point in the history
Signed-off-by: Ben Timby <btimby@gmail.com>
  • Loading branch information
btimby committed Aug 2, 2024
1 parent 653d70f commit 047af34
Show file tree
Hide file tree
Showing 5 changed files with 19 additions and 16 deletions.
9 changes: 5 additions & 4 deletions prometheus_client/metrics.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
from threading import RLock
import time
import types
from typing import (
Expand All @@ -15,7 +16,7 @@
)
from .registry import Collector, CollectorRegistry, REGISTRY
from .samples import Exemplar, Sample
from .utils import floatToGoString, INF, Lock
from .utils import floatToGoString, INF

T = TypeVar('T', bound='MetricWrapperBase')
F = TypeVar("F", bound=Callable[..., Any])
Expand Down Expand Up @@ -143,7 +144,7 @@ def __init__(self: T,

if self._is_parent():
# Prepare the fields needed for child metrics.
self._lock = Lock()
self._lock = RLock()
self._metrics: Dict[Sequence[str], T] = {}

if self._is_observable():
Expand Down Expand Up @@ -696,7 +697,7 @@ class Info(MetricWrapperBase):

def _metric_init(self):
self._labelname_set = set(self._labelnames)
self._lock = Lock()
self._lock = RLock()
self._value = {}

def info(self, val: Dict[str, str]) -> None:
Expand Down Expand Up @@ -758,7 +759,7 @@ def __init__(self,

def _metric_init(self) -> None:
self._value = 0
self._lock = Lock()
self._lock = RLock()

def state(self, state: str) -> None:
"""Set enum metric state."""
Expand Down
4 changes: 2 additions & 2 deletions prometheus_client/registry.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from abc import ABC, abstractmethod
import copy
from threading import RLock
from typing import Dict, Iterable, List, Optional

from .metrics_core import Metric
from .utils import Lock


# Ideally this would be a Protocol, but Protocols are only available in Python >= 3.8.
Expand All @@ -30,7 +30,7 @@ def __init__(self, auto_describe: bool = False, target_info: Optional[Dict[str,
self._collector_to_names: Dict[Collector, List[str]] = {}
self._names_to_collectors: Dict[str, Collector] = {}
self._auto_describe = auto_describe
self._lock = Lock()
self._lock = RLock()
self._target_info: Optional[Dict[str, str]] = {}
self.set_target_info(target_info)

Expand Down
6 changes: 0 additions & 6 deletions prometheus_client/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import math
from threading import _PyRLock # type: ignore[attr-defined]

INF = float("inf")
MINUS_INF = float("-inf")
Expand All @@ -23,8 +22,3 @@ def floatToGoString(d):
mantissa = f'{s[0]}.{s[1:dot]}{s[dot + 1:]}'.rstrip('0.')
return f'{mantissa}e+0{dot - 1}'
return s


class Lock(_PyRLock):
def locked(self):
return bool(self._count)
6 changes: 3 additions & 3 deletions prometheus_client/values.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import os
from threading import RLock
import warnings

from .mmap_dict import mmap_key, MmapedDict
from .utils import Lock


class MutexValue:
Expand All @@ -13,7 +13,7 @@ class MutexValue:
def __init__(self, typ, metric_name, name, labelnames, labelvalues, help_text, **kwargs):
self._value = 0.0
self._exemplar = None
self._lock = Lock()
self._lock = RLock()

def inc(self, amount):
with self._lock:
Expand Down Expand Up @@ -50,7 +50,7 @@ def MultiProcessValue(process_identifier=os.getpid):
# Use a single global lock when in multi-processing mode
# as we presume this means there is no threading going on.
# This avoids the need to also have mutexes in __MmapDict.
lock = Lock()
lock = RLock()

class MmapedValue:
"""A float protected by a mutex backed by a per-process mmaped file."""
Expand Down
10 changes: 9 additions & 1 deletion tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@
from prometheus_client.metrics import _get_use_created


def is_locked(lock):
"Tries to obtain a lock, returns True on success, False on failure."
locked = lock.acquire(blocking=False)
if locked:
lock.release()
return not locked


def assert_not_observable(fn, *args, **kwargs):
"""
Assert that a function call falls with a ValueError exception containing
Expand Down Expand Up @@ -963,7 +971,7 @@ def test_restricted_registry_does_not_yield_while_locked(self):
m = Metric('target', 'Target metadata', 'info')
m.samples = [Sample('target_info', {'foo': 'bar'}, 1)]
for _ in registry.restricted_registry(['target_info', 's_sum']).collect():
self.assertFalse(registry._lock.locked())
self.assertFalse(is_locked(registry._lock))


if __name__ == '__main__':
Expand Down

0 comments on commit 047af34

Please sign in to comment.