Source code for xotl.crdt.base

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ---------------------------------------------------------------------
# Copyright (c) Merchise Autrement [~º/~] and Contributors
# All rights reserved.
#
# This is free software; you can do what the LICENCE file allows you to.
#
'''Base interfaces.'''
from dataclasses import dataclass


[docs]@dataclass(frozen=True, order=True) class Process: '''Represents a process or node that holds replicated objects. We require (for some CRDTs) that processes are uniquely named and totally ordered across the cluster. So when adding/removing a process you should take measures for not reusing old names. ''' order: int name: str def __init__(self, name: str, order: int) -> None: object.__setattr__(self, 'name', name) object.__setattr__(self, 'order', order) def __repr__(self): return f"Process({self.name!r}, {self.order!r})" def __eq__(self, other) -> bool: if isinstance(other, Process): return self.name == other.name else: return NotImplemented
[docs]class CvRDT: '''Base class for Convergent Replicated Data Types. Basically this documents the expectation of each CvRDT. Subclasses **must** implement the following methods and attributes. ''' def __init__(self, *, process: Process) -> None: self.process = process self.init()
[docs] def init(self) -> None: '''Set the initial state of a newly create CRDT.'''
[docs] def merge(self, other: 'CvRDT') -> None: '''Update the CvRDT to account for the another replica's state. ''' raise NotImplementedError
@property def value(self): '''The current value that is managed by this CRDT. This could be any type of value. But you *must* never assume changes to the value return will be of any effect. Each CRDT implements methods to properly update its value. This is a read-only property. ''' raise NotImplementedError
[docs] def reset(self) -> None: '''Reset the internal state of value, usually to the initial state. ''' self.init()
[docs] def __le__(self, other): '''Compares two replicas for '<=' in the semilattice. This is **NOT** a relation of the `value`:any:. ''' return NotImplemented
[docs] def __eq__(self, other) -> bool: '''Compares two replicas for '==' in the semilattice. This is **NOT** a relation of the `value`:any:. ''' return NotImplemented
[docs]def get_state(crdt: CvRDT) -> bytes: '''Dumps the crdt in a way that is amenable for transmission/storage. ''' import pickle return pickle.dumps(crdt)
[docs]def from_state(state: bytes) -> CvRDT: '''Reconstruct the CRDT from its dumped state. `state` should be the result of calling `get_state`:func:. The following property should always hold:: assert crdt == from_state(get_state(crdt)) ''' import pickle res = pickle.loads(state) if not isinstance(res, CvRDT): raise ValueError('Invalid state') else: return res