doc strings
This commit is contained in:
parent
05e5d24c5e
commit
22b43a2b01
1 changed files with 24 additions and 0 deletions
|
@ -83,11 +83,26 @@ class OpStackIntegrity(Exception):
|
||||||
|
|
||||||
class RevertableOpStack:
|
class RevertableOpStack:
|
||||||
def __init__(self, get_fn: Callable[[bytes], Optional[bytes]], unsafe_prefixes=None):
|
def __init__(self, get_fn: Callable[[bytes], Optional[bytes]], unsafe_prefixes=None):
|
||||||
|
"""
|
||||||
|
This represents a sequence of revertable puts and deletes to a key-value database that checks for integrity
|
||||||
|
violations when applying the puts and deletes. The integrity checks assure that keys that do not exist
|
||||||
|
are not deleted, and that when keys are deleted the current value is correctly known so that the delete
|
||||||
|
may be undone. When putting values, the integrity checks assure that existing values are not overwritten
|
||||||
|
without first being deleted. Updates are performed by applying a delete op for the old value and a put op
|
||||||
|
for the new value.
|
||||||
|
|
||||||
|
:param get_fn: getter function from an object implementing `KeyValueStorage`
|
||||||
|
:param unsafe_prefixes: optional set of prefixes to ignore integrity errors for, violations are still logged
|
||||||
|
"""
|
||||||
self._get = get_fn
|
self._get = get_fn
|
||||||
self._items = defaultdict(list)
|
self._items = defaultdict(list)
|
||||||
self._unsafe_prefixes = unsafe_prefixes or set()
|
self._unsafe_prefixes = unsafe_prefixes or set()
|
||||||
|
|
||||||
def append_op(self, op: RevertableOp):
|
def append_op(self, op: RevertableOp):
|
||||||
|
"""
|
||||||
|
Apply a put or delete op, checking that it introduces no integrity errors
|
||||||
|
"""
|
||||||
|
|
||||||
inverted = op.invert()
|
inverted = op.invert()
|
||||||
if self._items[op.key] and inverted == self._items[op.key][-1]:
|
if self._items[op.key] and inverted == self._items[op.key][-1]:
|
||||||
self._items[op.key].pop() # if the new op is the inverse of the last op, we can safely null both
|
self._items[op.key].pop() # if the new op is the inverse of the last op, we can safely null both
|
||||||
|
@ -119,6 +134,9 @@ class RevertableOpStack:
|
||||||
self._items[op.key].append(op)
|
self._items[op.key].append(op)
|
||||||
|
|
||||||
def extend_ops(self, ops: Iterable[RevertableOp]):
|
def extend_ops(self, ops: Iterable[RevertableOp]):
|
||||||
|
"""
|
||||||
|
Apply a sequence of put or delete ops, checking that they introduce no integrity errors
|
||||||
|
"""
|
||||||
for op in ops:
|
for op in ops:
|
||||||
self.append_op(op)
|
self.append_op(op)
|
||||||
|
|
||||||
|
@ -139,9 +157,15 @@ class RevertableOpStack:
|
||||||
yield op
|
yield op
|
||||||
|
|
||||||
def get_undo_ops(self) -> bytes:
|
def get_undo_ops(self) -> bytes:
|
||||||
|
"""
|
||||||
|
Get the serialized bytes to undo all of the changes made by the pending ops
|
||||||
|
"""
|
||||||
return b''.join(op.invert().pack() for op in reversed(self))
|
return b''.join(op.invert().pack() for op in reversed(self))
|
||||||
|
|
||||||
def apply_packed_undo_ops(self, packed: bytes):
|
def apply_packed_undo_ops(self, packed: bytes):
|
||||||
|
"""
|
||||||
|
Unpack and apply a sequence of undo ops from serialized undo bytes
|
||||||
|
"""
|
||||||
while packed:
|
while packed:
|
||||||
op, packed = RevertableOp.unpack(packed)
|
op, packed = RevertableOp.unpack(packed)
|
||||||
self.append_op(op)
|
self.append_op(op)
|
||||||
|
|
Loading…
Reference in a new issue