update RevertableOpStack

This commit is contained in:
Jack Robison 2021-07-14 12:56:52 -04:00
parent 677b8cb633
commit b344f17b86
No known key found for this signature in database
GPG key ID: DF25C68FE0239BB2

View file

@ -1,10 +1,10 @@
import struct import struct
from string import printable from string import printable
from collections import OrderedDict, defaultdict from collections import defaultdict
from typing import Tuple, List, Iterable, Callable, Optional from typing import Tuple, Iterable, Callable, Optional
from lbry.wallet.server.db import DB_PREFIXES from lbry.wallet.server.db import DB_PREFIXES
_OP_STRUCT = struct.Struct('>BHH') _OP_STRUCT = struct.Struct('>BLL')
class RevertableOp: class RevertableOp:
@ -30,7 +30,7 @@ class RevertableOp:
Serialize to bytes Serialize to bytes
""" """
return struct.pack( return struct.pack(
f'>BHH{len(self.key)}s{len(self.value)}s', int(self.is_put), len(self.key), len(self.value), self.key, f'>BLL{len(self.key)}s{len(self.value)}s', int(self.is_put), len(self.key), len(self.value), self.key,
self.value self.value
) )
@ -42,23 +42,12 @@ class RevertableOp:
:param packed: bytes containing at least one packed revertable op :param packed: bytes containing at least one packed revertable op
:return: tuple of the deserialized op (a put or a delete) and the remaining serialized bytes :return: tuple of the deserialized op (a put or a delete) and the remaining serialized bytes
""" """
is_put, key_len, val_len = _OP_STRUCT.unpack(packed[:5]) is_put, key_len, val_len = _OP_STRUCT.unpack(packed[:9])
key = packed[5:5 + key_len] key = packed[9:9 + key_len]
value = packed[5 + key_len:5 + key_len + val_len] value = packed[9 + key_len:9 + key_len + val_len]
if is_put == 1: if is_put == 1:
return RevertablePut(key, value), packed[5 + key_len + val_len:] return RevertablePut(key, value), packed[9 + key_len + val_len:]
return RevertableDelete(key, value), packed[5 + key_len + val_len:] return RevertableDelete(key, value), packed[9 + key_len + val_len:]
@classmethod
def unpack_stack(cls, packed: bytes) -> List['RevertableOp']:
"""
Deserialize multiple from bytes
"""
ops = []
while packed:
op, packed = cls.unpack(packed)
ops.append(op)
return ops
def __eq__(self, other: 'RevertableOp') -> bool: def __eq__(self, other: 'RevertableOp') -> bool:
return (self.is_put, self.key, self.value) == (other.is_put, other.key, other.value) return (self.is_put, self.key, self.value) == (other.is_put, other.key, other.value)
@ -134,3 +123,16 @@ class RevertableOpStack:
for key, ops in self._items.items(): for key, ops in self._items.items():
for op in ops: for op in ops:
yield op yield op
def __reversed__(self):
for key, ops in self._items.items():
for op in reversed(ops):
yield op
def get_undo_ops(self) -> bytes:
return b''.join(op.invert().pack() for op in reversed(self))
def apply_packed_undo_ops(self, packed: bytes):
while packed:
op, packed = RevertableOp.unpack(packed)
self.append(op)