moat-kv 0.70.24__py3-none-any.whl → 0.71.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- moat/kv/__init__.py +6 -7
- moat/kv/_cfg.yaml +5 -8
- moat/kv/actor/__init__.py +2 -1
- moat/kv/actor/deletor.py +4 -1
- moat/kv/auth/__init__.py +12 -13
- moat/kv/auth/_test.py +4 -1
- moat/kv/auth/password.py +11 -7
- moat/kv/backend/mqtt.py +4 -8
- moat/kv/client.py +20 -39
- moat/kv/code.py +3 -3
- moat/kv/command/data.py +4 -3
- moat/kv/command/dump/__init__.py +29 -29
- moat/kv/command/internal.py +2 -3
- moat/kv/command/job.py +1 -2
- moat/kv/command/type.py +3 -6
- moat/kv/data.py +9 -8
- moat/kv/errors.py +16 -8
- moat/kv/mock/__init__.py +2 -12
- moat/kv/model.py +28 -32
- moat/kv/obj/__init__.py +3 -3
- moat/kv/obj/command.py +3 -3
- moat/kv/runner.py +4 -5
- moat/kv/server.py +106 -126
- moat/kv/types.py +8 -6
- {moat_kv-0.70.24.dist-info → moat_kv-0.71.6.dist-info}/METADATA +7 -6
- moat_kv-0.71.6.dist-info/RECORD +47 -0
- {moat_kv-0.70.24.dist-info → moat_kv-0.71.6.dist-info}/WHEEL +1 -1
- moat_kv-0.71.6.dist-info/licenses/LICENSE +3 -0
- moat_kv-0.71.6.dist-info/licenses/LICENSE.APACHE2 +202 -0
- moat_kv-0.71.6.dist-info/licenses/LICENSE.MIT +20 -0
- moat_kv-0.71.6.dist-info/top_level.txt +1 -0
- build/lib/docs/source/conf.py +0 -201
- build/lib/examples/pathify.py +0 -45
- build/lib/moat/kv/__init__.py +0 -19
- build/lib/moat/kv/_cfg.yaml +0 -97
- build/lib/moat/kv/_main.py +0 -91
- build/lib/moat/kv/actor/__init__.py +0 -98
- build/lib/moat/kv/actor/deletor.py +0 -139
- build/lib/moat/kv/auth/__init__.py +0 -444
- build/lib/moat/kv/auth/_test.py +0 -166
- build/lib/moat/kv/auth/password.py +0 -234
- build/lib/moat/kv/auth/root.py +0 -58
- build/lib/moat/kv/backend/__init__.py +0 -67
- build/lib/moat/kv/backend/mqtt.py +0 -74
- build/lib/moat/kv/backend/serf.py +0 -45
- build/lib/moat/kv/client.py +0 -1025
- build/lib/moat/kv/code.py +0 -236
- build/lib/moat/kv/codec.py +0 -11
- build/lib/moat/kv/command/__init__.py +0 -1
- build/lib/moat/kv/command/acl.py +0 -180
- build/lib/moat/kv/command/auth.py +0 -261
- build/lib/moat/kv/command/code.py +0 -293
- build/lib/moat/kv/command/codec.py +0 -186
- build/lib/moat/kv/command/data.py +0 -265
- build/lib/moat/kv/command/dump/__init__.py +0 -143
- build/lib/moat/kv/command/error.py +0 -149
- build/lib/moat/kv/command/internal.py +0 -248
- build/lib/moat/kv/command/job.py +0 -433
- build/lib/moat/kv/command/log.py +0 -53
- build/lib/moat/kv/command/server.py +0 -114
- build/lib/moat/kv/command/type.py +0 -201
- build/lib/moat/kv/config.py +0 -46
- build/lib/moat/kv/data.py +0 -216
- build/lib/moat/kv/errors.py +0 -561
- build/lib/moat/kv/exceptions.py +0 -126
- build/lib/moat/kv/mock/__init__.py +0 -101
- build/lib/moat/kv/mock/mqtt.py +0 -159
- build/lib/moat/kv/mock/serf.py +0 -250
- build/lib/moat/kv/mock/tracer.py +0 -63
- build/lib/moat/kv/model.py +0 -1069
- build/lib/moat/kv/obj/__init__.py +0 -646
- build/lib/moat/kv/obj/command.py +0 -241
- build/lib/moat/kv/runner.py +0 -1347
- build/lib/moat/kv/server.py +0 -2809
- build/lib/moat/kv/types.py +0 -513
- debian/moat-kv/usr/lib/python3/dist-packages/docs/source/conf.py +0 -201
- debian/moat-kv/usr/lib/python3/dist-packages/examples/pathify.py +0 -45
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/__init__.py +0 -19
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/_cfg.yaml +0 -97
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/_main.py +0 -91
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/actor/__init__.py +0 -98
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/actor/deletor.py +0 -139
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/__init__.py +0 -444
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/_test.py +0 -166
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/password.py +0 -234
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/root.py +0 -58
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/backend/__init__.py +0 -67
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/backend/mqtt.py +0 -74
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/backend/serf.py +0 -45
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/client.py +0 -1025
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/code.py +0 -236
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/codec.py +0 -11
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/__init__.py +0 -1
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/acl.py +0 -180
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/auth.py +0 -261
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/code.py +0 -293
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/codec.py +0 -186
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/data.py +0 -265
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/dump/__init__.py +0 -143
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/error.py +0 -149
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/internal.py +0 -248
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/job.py +0 -433
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/log.py +0 -53
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/server.py +0 -114
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/type.py +0 -201
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/config.py +0 -46
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/data.py +0 -216
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/errors.py +0 -561
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/exceptions.py +0 -126
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/__init__.py +0 -101
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/mqtt.py +0 -159
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/serf.py +0 -250
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/tracer.py +0 -63
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/model.py +0 -1069
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/obj/__init__.py +0 -646
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/obj/command.py +0 -241
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/runner.py +0 -1347
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/server.py +0 -2809
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/types.py +0 -513
- docs/source/conf.py +0 -201
- examples/pathify.py +0 -45
- moat/kv/backend/serf.py +0 -45
- moat/kv/codec.py +0 -11
- moat/kv/mock/serf.py +0 -250
- moat_kv-0.70.24.dist-info/RECORD +0 -137
- moat_kv-0.70.24.dist-info/top_level.txt +0 -9
- {moat_kv-0.70.24.dist-info → moat_kv-0.71.6.dist-info}/licenses/LICENSE.txt +0 -0
@@ -1,45 +0,0 @@
|
|
1
|
-
#!/usr/bin/python3
|
2
|
-
|
3
|
-
# Batch-convert data. In this case I had some entries which were stored as
|
4
|
-
# a list, but using Path made much more sense (esp when you need to
|
5
|
-
# view/edit the yaml export).
|
6
|
-
|
7
|
-
import anyio
|
8
|
-
from moat.kv.client import open_client
|
9
|
-
from moat.util import P, yload, Path
|
10
|
-
import asyncclick as click
|
11
|
-
|
12
|
-
|
13
|
-
def conv(m, s: str) -> bool:
|
14
|
-
try:
|
15
|
-
d = m.value[s]
|
16
|
-
except KeyError:
|
17
|
-
return 0
|
18
|
-
if isinstance(d, Path):
|
19
|
-
return 0
|
20
|
-
if not isinstance(d, Sequence):
|
21
|
-
return 0
|
22
|
-
d = Path.build(d)
|
23
|
-
m.value[s] = d
|
24
|
-
return 1
|
25
|
-
|
26
|
-
|
27
|
-
@click.command()
|
28
|
-
@click.argument("path", type=P)
|
29
|
-
@click.argument("keys", type=str, nargs=-1)
|
30
|
-
async def main(path, keys):
|
31
|
-
if not keys:
|
32
|
-
keys = "src dest dst state".split()
|
33
|
-
with open("/etc/moat.kv.cfg") as cff:
|
34
|
-
cfg = yload(cff)
|
35
|
-
async with open_client(**cfg) as client:
|
36
|
-
async for m in client.get_tree(path, nchain=2):
|
37
|
-
n = 0
|
38
|
-
for k in keys:
|
39
|
-
n += conv(m, k)
|
40
|
-
if n:
|
41
|
-
await client.set(ORIG + m.path, value=m.value, chain=m.chain)
|
42
|
-
|
43
|
-
|
44
|
-
if __name__ == "__main__":
|
45
|
-
main()
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# pylint: disable=W0703,C0103
|
2
|
-
from __future__ import annotations
|
3
|
-
|
4
|
-
__path__ = __import__("pkgutil").extend_path(__path__, __name__)
|
5
|
-
|
6
|
-
try:
|
7
|
-
import warning
|
8
|
-
import pkg_resources # part of setuptools
|
9
|
-
|
10
|
-
with warnings.filterwarnings("ignore"):
|
11
|
-
_version = pkg_resources.require("moat.kv")[0].version
|
12
|
-
del pkg_resources
|
13
|
-
del warnings
|
14
|
-
|
15
|
-
_version_tuple = tuple(int(x) for x in _version.split("."))
|
16
|
-
|
17
|
-
except Exception: # pragma: no cover
|
18
|
-
_version = "0.0.1"
|
19
|
-
_version_tuple = (0, 0, 1)
|
@@ -1,97 +0,0 @@
|
|
1
|
-
conn:
|
2
|
-
# client: controls how to talk to the MoaT-KV server
|
3
|
-
host: localhost
|
4
|
-
port: 27586
|
5
|
-
ssl: false
|
6
|
-
# ssl:
|
7
|
-
# cert: '/path/to/cert.pem',key='/path/to/cert.key'
|
8
|
-
init_timeout: 5
|
9
|
-
# time to wait for connection plus greeting
|
10
|
-
auth: null
|
11
|
-
# no auth used by default
|
12
|
-
name: null
|
13
|
-
# defaults to a seqnum
|
14
|
-
config:
|
15
|
-
prefix: !P :.moat.kv.config
|
16
|
-
errors:
|
17
|
-
prefix: !P :.moat.kv.error
|
18
|
-
codes:
|
19
|
-
prefix: !P :.moat.kv.code.proc
|
20
|
-
modules:
|
21
|
-
prefix: !P :.moat.kv.code.module
|
22
|
-
runner: # for moat.kv.runner.RunnerRoot
|
23
|
-
# storage for runnable commands
|
24
|
-
prefix: !P :.moat.kv.run"
|
25
|
-
# storage for runner states
|
26
|
-
state: !P :.moat.kv.state"
|
27
|
-
|
28
|
-
name: "run"
|
29
|
-
# Serf event name, suffixed by subpath
|
30
|
-
|
31
|
-
start_delay: 1
|
32
|
-
# time to wait between job starts. Not optional.
|
33
|
-
|
34
|
-
ping: -15
|
35
|
-
# set an I-am-running message every those-many seconds
|
36
|
-
# positive: set in moat.kv, negative: broadcast to :moat.kv.run tag
|
37
|
-
|
38
|
-
actor:
|
39
|
-
# Actor config, required for Runner
|
40
|
-
cycle: 20
|
41
|
-
nodes: -1
|
42
|
-
splits: 5
|
43
|
-
n_hosts: 3
|
44
|
-
version: 1
|
45
|
-
sub:
|
46
|
-
# tags for various runner modes
|
47
|
-
group: "any"
|
48
|
-
single: "at"
|
49
|
-
all: "all"
|
50
|
-
server:
|
51
|
-
# server-side configuration
|
52
|
-
buffer: 10
|
53
|
-
# per-stream buffer
|
54
|
-
|
55
|
-
backend: "mqtt"
|
56
|
-
# default
|
57
|
-
mqtt:
|
58
|
-
uri: "mqtt://localhost:1883"
|
59
|
-
serf:
|
60
|
-
host: "localhost"
|
61
|
-
port: 7373
|
62
|
-
|
63
|
-
# event message path/topic prefix
|
64
|
-
root: !P moat.kv
|
65
|
-
|
66
|
-
paranoia: False
|
67
|
-
# typecheck server-to-server updates?
|
68
|
-
#
|
69
|
-
# which addresses/ports to accept MoaT-KV connections on
|
70
|
-
bind: [{}]
|
71
|
-
bind_default:
|
72
|
-
# default values for all elements of "bind"
|
73
|
-
host: "localhost"
|
74
|
-
port: PORT
|
75
|
-
ssl: False
|
76
|
-
change:
|
77
|
-
length: 5
|
78
|
-
# chain length: use max nr of network sections +1
|
79
|
-
ping:
|
80
|
-
cycle: 10
|
81
|
-
gap: 2
|
82
|
-
# asyncserf.Actor config timing for server sync
|
83
|
-
# ping also controls minimum server startup time
|
84
|
-
delete:
|
85
|
-
# asyncserf.Actor config timing for deletion
|
86
|
-
cycle: 100
|
87
|
-
gap: 10
|
88
|
-
version: 1
|
89
|
-
paranoia: false
|
90
|
-
# typecheck server>server updates?
|
91
|
-
|
92
|
-
# how does a new server reach existing nodes, to download state?
|
93
|
-
domain: null
|
94
|
-
# domain in which to look up node names, if not in hostmap
|
95
|
-
hostmap: # map MoaT-KV server names to connect destinations
|
96
|
-
test1: ["localhost", 27586]
|
97
|
-
test2: ["does-not-exist.invalid", 27586]
|
@@ -1,91 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
"""
|
3
|
-
Basic DistKV support
|
4
|
-
|
5
|
-
"""
|
6
|
-
|
7
|
-
from __future__ import annotations
|
8
|
-
|
9
|
-
import logging
|
10
|
-
|
11
|
-
import asyncclick as click
|
12
|
-
from moat.util import attrdict, combine_dict, load_subgroup, CFG, ensure_cfg
|
13
|
-
|
14
|
-
from moat.kv.auth import gen_auth
|
15
|
-
from moat.kv.client import client_scope
|
16
|
-
|
17
|
-
logger = logging.getLogger(__name__)
|
18
|
-
|
19
|
-
|
20
|
-
ensure_cfg("moat.kv")
|
21
|
-
|
22
|
-
|
23
|
-
class NullObj:
|
24
|
-
"""
|
25
|
-
This helper defers raising an exception until one of its attributes is
|
26
|
-
actually accessed.
|
27
|
-
"""
|
28
|
-
|
29
|
-
def __init__(self, exc):
|
30
|
-
self._exc = exc
|
31
|
-
|
32
|
-
def __call__(self, *a, **kw):
|
33
|
-
raise self._exc
|
34
|
-
|
35
|
-
def __await__(self):
|
36
|
-
raise self._exc
|
37
|
-
|
38
|
-
def __getattr__(self, k):
|
39
|
-
if k[0] == "_" and k not in ("_request", "_cfg"):
|
40
|
-
return object.__getattribute__(self, k)
|
41
|
-
raise self._exc
|
42
|
-
|
43
|
-
|
44
|
-
@load_subgroup(sub_pre="moat.kv.command", sub_post="cli", ext_pre="moat.kv", ext_post="_main.cli")
|
45
|
-
@click.option("-h", "--host", default=None, help=f"Host to use. Default: {CFG.kv.conn.host}")
|
46
|
-
@click.option(
|
47
|
-
"-p",
|
48
|
-
"--port",
|
49
|
-
type=int,
|
50
|
-
default=None,
|
51
|
-
help=f"Port to use. Default: {CFG.kv.conn.port}",
|
52
|
-
)
|
53
|
-
@click.option(
|
54
|
-
"-a",
|
55
|
-
"--auth",
|
56
|
-
type=str,
|
57
|
-
default=None,
|
58
|
-
help="Auth params. =file or 'type param=value…' Default: _anon",
|
59
|
-
)
|
60
|
-
@click.option("-m", "--metadata", is_flag=True, help="Include/print metadata.")
|
61
|
-
@click.pass_context
|
62
|
-
async def cli(ctx, host, port, auth, metadata):
|
63
|
-
"""The MoaT Key-Value subsystem.
|
64
|
-
|
65
|
-
All commands (except 'server' and 'dump') connect to a MoaT-KV server.
|
66
|
-
"""
|
67
|
-
obj = ctx.obj
|
68
|
-
cfg = attrdict()
|
69
|
-
if host is not None:
|
70
|
-
cfg.host = host
|
71
|
-
if port is not None:
|
72
|
-
cfg.port = port
|
73
|
-
|
74
|
-
if auth is not None:
|
75
|
-
cfg.auth = gen_auth(auth)
|
76
|
-
if obj.DEBUG:
|
77
|
-
cfg.auth._DEBUG = True
|
78
|
-
|
79
|
-
cfg = combine_dict(attrdict(kv=attrdict(conn=cfg)), obj.cfg, cls=attrdict)
|
80
|
-
|
81
|
-
obj.meta = 3 if metadata else False
|
82
|
-
|
83
|
-
try:
|
84
|
-
if ctx.invoked_subcommand in {None, "server", "dump"}:
|
85
|
-
obj.client = NullObj(RuntimeError("Not a client command"))
|
86
|
-
else:
|
87
|
-
obj.client = await client_scope(**cfg.kv)
|
88
|
-
except OSError as exc:
|
89
|
-
obj.client = NullObj(exc)
|
90
|
-
else:
|
91
|
-
logger.debug("Connected.")
|
@@ -1,98 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
This module implements a :class:`asyncactor.Actor` which works on top of
|
3
|
-
a MoaT-KV client.
|
4
|
-
"""
|
5
|
-
from __future__ import annotations
|
6
|
-
|
7
|
-
from asyncactor import Actor
|
8
|
-
from asyncactor.abc import MonitorStream, Transport
|
9
|
-
|
10
|
-
__all__ = [
|
11
|
-
"ClientActor",
|
12
|
-
"ActorState",
|
13
|
-
"BrokenState",
|
14
|
-
"DetachedState",
|
15
|
-
"PartialState",
|
16
|
-
"CompleteState",
|
17
|
-
]
|
18
|
-
|
19
|
-
|
20
|
-
class ClientActor(Actor):
|
21
|
-
def __init__(self, client, *a, topic, **kw):
|
22
|
-
super().__init__(ClientTransport(client, topic), *a, **kw)
|
23
|
-
|
24
|
-
|
25
|
-
class ClientTransport(Transport):
|
26
|
-
"""
|
27
|
-
This class exports the client's direct messaging interface to the
|
28
|
-
actor.
|
29
|
-
"""
|
30
|
-
|
31
|
-
def __init__(self, client, topic):
|
32
|
-
self.client = client
|
33
|
-
self.topic = topic
|
34
|
-
|
35
|
-
def monitor(self):
|
36
|
-
return ClientMonitor(self)
|
37
|
-
|
38
|
-
async def send(self, payload):
|
39
|
-
await self.client.msg_send(self.topic, payload)
|
40
|
-
|
41
|
-
|
42
|
-
class ClientMonitor(MonitorStream):
|
43
|
-
_mon1 = None
|
44
|
-
_mon2 = None
|
45
|
-
_it = None
|
46
|
-
|
47
|
-
async def __aenter__(self):
|
48
|
-
self._mon1 = self.transport.client.msg_monitor(self.transport.topic)
|
49
|
-
self._mon2 = await self._mon1.__aenter__()
|
50
|
-
return self
|
51
|
-
|
52
|
-
async def __aexit__(self, *tb):
|
53
|
-
return await self._mon1.__aexit__(*tb)
|
54
|
-
|
55
|
-
def __aiter__(self):
|
56
|
-
self._it = self._mon2.__aiter__()
|
57
|
-
return self
|
58
|
-
|
59
|
-
async def __anext__(self):
|
60
|
-
msg = await self._it.__anext__()
|
61
|
-
return msg.data
|
62
|
-
|
63
|
-
|
64
|
-
# The following events are used by Runner etc. to notify running jobs
|
65
|
-
# about the current connectivity state.
|
66
|
-
#
|
67
|
-
class ActorState:
|
68
|
-
"""base class for states"""
|
69
|
-
|
70
|
-
def __init__(self, msg=None):
|
71
|
-
self.msg = msg
|
72
|
-
|
73
|
-
def __repr__(self):
|
74
|
-
return "<%s:%r>" % (self.__class__.__name__, self.msg)
|
75
|
-
|
76
|
-
|
77
|
-
class BrokenState(ActorState):
|
78
|
-
"""I have no idea what's happening, probably nothing good"""
|
79
|
-
|
80
|
-
pass
|
81
|
-
|
82
|
-
|
83
|
-
class DetachedState(ActorState):
|
84
|
-
"""I am detached, my actor group is not visible"""
|
85
|
-
|
86
|
-
pass
|
87
|
-
|
88
|
-
|
89
|
-
class PartialState(ActorState):
|
90
|
-
"""Some but not all members of my actor group are visible"""
|
91
|
-
|
92
|
-
pass
|
93
|
-
|
94
|
-
|
95
|
-
class CompleteState(ActorState):
|
96
|
-
"""All members of my actor group are visible"""
|
97
|
-
|
98
|
-
pass
|
@@ -1,139 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
This module implements additional code for the server-side DeleteActor,
|
3
|
-
which is used to clean up the list of deleted nodes.
|
4
|
-
"""
|
5
|
-
|
6
|
-
from __future__ import annotations
|
7
|
-
|
8
|
-
import weakref
|
9
|
-
from collections import deque
|
10
|
-
|
11
|
-
import anyio
|
12
|
-
from asyncactor import Actor, PingEvent, TagEvent
|
13
|
-
from asyncactor.backend import get_transport
|
14
|
-
|
15
|
-
TAGS = 4
|
16
|
-
|
17
|
-
|
18
|
-
class DeleteActor:
|
19
|
-
_enabled = None
|
20
|
-
|
21
|
-
def __init__(self, server):
|
22
|
-
self._server = weakref.ref(server)
|
23
|
-
self.deleted = deque()
|
24
|
-
self.tags = []
|
25
|
-
self.actor = None
|
26
|
-
|
27
|
-
self.max_seen = 0
|
28
|
-
self.n_tags = 0
|
29
|
-
self.n_pings = 0
|
30
|
-
self.n_nodes = 0
|
31
|
-
|
32
|
-
@property
|
33
|
-
def server(self):
|
34
|
-
return self._server()
|
35
|
-
|
36
|
-
async def tock_me(self):
|
37
|
-
"""
|
38
|
-
Add the current tock to our buffer.
|
39
|
-
|
40
|
-
This is updated whenever a new leader is selected.
|
41
|
-
"""
|
42
|
-
self.tags.append(self.server.tock)
|
43
|
-
self.tags = self.tags[-TAGS:]
|
44
|
-
await self.actor.set_value((self.tags[0], self.tags[-1]))
|
45
|
-
|
46
|
-
def add_deleted(self, nodes: NodeSet): # noqa: F821
|
47
|
-
"""
|
48
|
-
These nodes are deleted. Remember them for some time.
|
49
|
-
"""
|
50
|
-
if self.n_nodes == 0:
|
51
|
-
return
|
52
|
-
self.deleted.append((self.server.tock, nodes))
|
53
|
-
|
54
|
-
def purge_to(self, tock):
|
55
|
-
"""
|
56
|
-
Sufficient time has passed since this tock was seen, while all
|
57
|
-
Delete actor nodes were active. Finally flush the entries that have
|
58
|
-
been deleted before it.
|
59
|
-
"""
|
60
|
-
while self.deleted and self.deleted[0][0] < tock:
|
61
|
-
d = self.deleted.popleft()
|
62
|
-
self.server.purge_deleted(d[1])
|
63
|
-
|
64
|
-
async def enable(self, n):
|
65
|
-
"""
|
66
|
-
Enable this actor, as a group of N.
|
67
|
-
"""
|
68
|
-
if self.actor is None:
|
69
|
-
self._enabled = True
|
70
|
-
else:
|
71
|
-
await self.actor.enable(n)
|
72
|
-
self.n_tags = 0
|
73
|
-
self.n_pings = 0
|
74
|
-
self.n_nodes = n
|
75
|
-
|
76
|
-
async def disable(self, n: int = 0):
|
77
|
-
"""
|
78
|
-
Disable this actor. It will still listen, and require N Delete
|
79
|
-
actor members in order to flush its deletion entries.
|
80
|
-
|
81
|
-
Completely disable deletion flushing by passing n=0.
|
82
|
-
"""
|
83
|
-
if self.actor is None:
|
84
|
-
self._enabled = False
|
85
|
-
else:
|
86
|
-
await self.actor.disable()
|
87
|
-
self.n_tags = 0
|
88
|
-
self.n_pings = 0
|
89
|
-
self.n_nodes = n
|
90
|
-
|
91
|
-
async def run(self, evt: anyio.abc.Event = None):
|
92
|
-
"""
|
93
|
-
The task that monitors the Delete actor.
|
94
|
-
"""
|
95
|
-
try:
|
96
|
-
T = get_transport("moat_kv")
|
97
|
-
async with Actor(
|
98
|
-
T(self.server.backend, *self.server.cfg.server.root, "del"),
|
99
|
-
name=self.server.node.name,
|
100
|
-
cfg=self.server.cfg.server.delete,
|
101
|
-
enabled=False,
|
102
|
-
) as actor:
|
103
|
-
self.actor = actor
|
104
|
-
if self._enabled is not None:
|
105
|
-
if self._enabled:
|
106
|
-
await actor.enable()
|
107
|
-
else:
|
108
|
-
await actor.disable()
|
109
|
-
if evt is not None:
|
110
|
-
evt.set()
|
111
|
-
async for evt in actor:
|
112
|
-
if isinstance(evt, PingEvent):
|
113
|
-
val = evt.value
|
114
|
-
if val is None:
|
115
|
-
self.n_pings = self.n_tags = 0
|
116
|
-
continue
|
117
|
-
if len(evt.msg.history) < self.n_nodes:
|
118
|
-
self.n_pings = self.n_tags = 0
|
119
|
-
continue
|
120
|
-
self.n_pings += 1
|
121
|
-
if self.n_pings > self.n_nodes:
|
122
|
-
mx, self.max_seen = (
|
123
|
-
self.max_seen,
|
124
|
-
max(self.max_seen, val[1]),
|
125
|
-
)
|
126
|
-
if val[0] > mx > 0:
|
127
|
-
await self.server.resync_deleted(evt.msg.history)
|
128
|
-
continue
|
129
|
-
self.purge_to(val[0])
|
130
|
-
self.max_seen = max(self.max_seen, val[1])
|
131
|
-
|
132
|
-
elif isinstance(evt, TagEvent):
|
133
|
-
if actor.history_size == self.n_nodes:
|
134
|
-
self.n_tags += 1
|
135
|
-
if self.n_tags > 2:
|
136
|
-
self.purge_to(self.tags[0])
|
137
|
-
await self.tock_me()
|
138
|
-
finally:
|
139
|
-
self.actor = None
|