]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
manager: human-readable numerical IDs (instead of uuids used previously)
authorVasek Sraier <git@vakabus.cz>
Sat, 17 Jul 2021 08:39:48 +0000 (10:39 +0200)
committerAleš Mrázek <ales.mrazek@nic.cz>
Fri, 8 Apr 2022 14:17:52 +0000 (16:17 +0200)
manager/knot_resolver_manager/kres_manager.py
manager/knot_resolver_manager/kresd_controller/interface.py
manager/knot_resolver_manager/kresd_controller/supervisord/__init__.py
manager/knot_resolver_manager/kresd_controller/supervisord/config.py
manager/knot_resolver_manager/kresd_controller/systemd/__init__.py

index a1820a7971338993e1094214bce0341e749950a6..f369d05a0a24edc6ff6fe4cce68e671f349856b7 100644 (file)
@@ -1,8 +1,9 @@
 import asyncio
+import itertools
 import logging
+import weakref
 from subprocess import SubprocessError
-from typing import List, Optional, Set, Type
-from uuid import uuid4
+from typing import List, Optional, Type
 
 from knot_resolver_manager.constants import KRESD_CONFIG_FILE
 from knot_resolver_manager.exceptions import ValidationException
@@ -15,14 +16,43 @@ from .datamodel import KresConfig
 logger = logging.getLogger(__name__)
 
 
+class _PrettyID:
+    """
+    ID object. Effectively only a wrapper around an int, so that the references
+    behave normally (bypassing integer interning and other optimizations)
+    """
+
+    def __init__(self, n: int):
+        self._id = n
+
+    def __str__(self):
+        return str(self._id)
+
+    def __hash__(self) -> int:
+        return self._id
+
+    def __eq__(self, o: object) -> bool:
+        return isinstance(o, _PrettyID) and self._id == o._id
+
+
 class _PrettyIDAllocator:
+    """
+    Pretty numeric ID allocator. Keeps weak refences to the IDs it has
+    allocated. The IDs get recycled once the previously allocated ID
+    objects get garbage collected
+    """
+
     def __init__(self):
-        self._used: Set[int] = set()
+        self._used: "weakref.WeakSet[_PrettyID]" = weakref.WeakSet()
 
-    def free(self, n: int):
-        assert n in self._used
-        self._used.remove(n)
+    def alloc(self) -> _PrettyID:
+        for i in itertools.count(start=1):
+            val = _PrettyID(i)
+            if val not in self._used:
+                self._used.add(val)
+                return val
 
+        raise RuntimeError("Reached an end of an infinite loop. How?")
 
 
 class KresManager:
@@ -53,13 +83,14 @@ class KresManager:
         self._manager_lock = asyncio.Lock()
         self._controller: SubprocessController
         self._last_used_config: Optional[KresConfig] = None
+        self._id_allocator = _PrettyIDAllocator()
 
     async def load_system_state(self):
         async with self._manager_lock:
             await self._collect_already_running_children()
 
     async def _spawn_new_worker(self):
-        subprocess = await self._controller.create_subprocess(SubprocessType.KRESD, str(uuid4()))
+        subprocess = await self._controller.create_subprocess(SubprocessType.KRESD, self._id_allocator.alloc())
         await subprocess.start()
         self._workers.append(subprocess)
 
@@ -71,7 +102,14 @@ class KresManager:
         await kresd.stop()
 
     async def _collect_already_running_children(self):
-        self._workers.extend(await self._controller.get_all_running_instances())
+        for subp in await self._controller.get_all_running_instances():
+            if subp.type == SubprocessType.KRESD:
+                self._workers.append(subp)
+            elif subp.type == SubprocessType.GC:
+                assert self._gc is None
+                self._gc = subp
+            else:
+                raise RuntimeError("unexpected subprocess type")
 
     async def _rolling_restart(self):
         for kresd in self._workers:
index cadd0c44a203d09becd8c75b6e7a1891293283fb..7a87843376de3c432ec90ad89e218c825236906d 100644 (file)
@@ -65,7 +65,7 @@ class SubprocessController:
         """
         raise NotImplementedError()
 
-    async def create_subprocess(self, subprocess_type: SubprocessType, id_hint: str) -> Subprocess:
+    async def create_subprocess(self, subprocess_type: SubprocessType, id_hint: object) -> Subprocess:
         """
         Return a Subprocess object which can be operated on. The subprocess is not
         started or in any way active after this call. That has to be performaed manually
index ab88a3e0555d5c7ca8598d461445959f7a85616e..383df85bb0f5fe8fb3b67a50109a4c206db51805 100644 (file)
@@ -22,9 +22,9 @@ logger = logging.getLogger(__name__)
 
 
 class SupervisordSubprocess(Subprocess):
-    def __init__(self, controller: "SupervisordSubprocessController", id_: str, type_: SubprocessType):
+    def __init__(self, controller: "SupervisordSubprocessController", id_: object, type_: SubprocessType):
         self._controller: "SupervisordSubprocessController" = controller
-        self._id: str = id_
+        self._id = id_
         self._type: SubprocessType = type_
 
     @property
@@ -103,5 +103,5 @@ class SupervisordSubprocessController(SubprocessController):
         assert subprocess in self._running_instances
         await restart(subprocess.id)
 
-    async def create_subprocess(self, subprocess_type: SubprocessType, id_hint: str) -> Subprocess:
+    async def create_subprocess(self, subprocess_type: SubprocessType, id_hint: object) -> Subprocess:
         return SupervisordSubprocess(self, id_hint, subprocess_type)
index 0572cde8283d3c827b4c30ff5d1a406d570b8c40..ae77b729c03f5a2b669dbb30c2128fc833944eba 100644 (file)
@@ -131,7 +131,7 @@ def list_fatal_subprocesses_ids() -> List[str]:
     return [pr["name"] for pr in processes if pr["statename"] == "FATAL"]
 
 
-def create_id(type_name: SubprocessType, id_: str) -> str:
+def create_id(type_name: SubprocessType, id_: object) -> str:
     return f"{type_name.name}_{id_}"
 
 
index 9aaaefab029dc76ab2556366074b5a1f0fcfd961..98a0e3707158e630475ede2cac86aa875e2ac429 100644 (file)
@@ -21,7 +21,7 @@ class SystemdSubprocess(Subprocess):
     def __init__(
         self,
         type_: SubprocessType,
-        id_: str,
+        id_: object,
         systemd_type: systemd.SystemdType,
         persistance_type: SystemdPersistanceType = SystemdPersistanceType.PERSISTENT,
     ):
@@ -128,5 +128,5 @@ class SystemdSubprocessController(SubprocessController):
     async def shutdown_controller(self) -> None:
         pass
 
-    async def create_subprocess(self, subprocess_type: SubprocessType, id_hint: str) -> Subprocess:
+    async def create_subprocess(self, subprocess_type: SubprocessType, id_hint: object) -> Subprocess:
         return SystemdSubprocess(subprocess_type, id_hint, self._systemd_type, self._persistance_type)