evict entries continuously from seen_unfinished_blocks (#17207)

remove entries from the seen-unfinished-blocks cache continuously, rather than emptying it periodically
This commit is contained in:
Arvid Norberg 2024-01-05 21:23:03 +01:00 committed by GitHub
parent c7c4c6b4b7
commit 41b9d02669
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 17 additions and 9 deletions

View File

@ -1598,7 +1598,6 @@ class FullNode:
if record.height % 1000 == 0:
# Occasionally clear data in full node store to keep memory usage small
self.full_node_store.clear_seen_unfinished_blocks()
self.full_node_store.clear_old_cache_entries()
if self.sync_store.get_sync_mode() is False:

View File

@ -45,8 +45,11 @@ class FullNodeStore:
candidate_blocks: Dict[bytes32, Tuple[uint32, UnfinishedBlock]]
candidate_backup_blocks: Dict[bytes32, Tuple[uint32, UnfinishedBlock]]
# Header hashes of unfinished blocks that we have seen recently
seen_unfinished_blocks: Set[bytes32]
# Block hashes of unfinished blocks that we have seen recently. This is
# effectively a Set[bytes32] but in order to evict the oldest items first,
# we use a Dict that preserves insertion order, and remove from the
# beginning
seen_unfinished_blocks: Dict[bytes32, None]
# Unfinished blocks, keyed from reward hash
unfinished_blocks: Dict[bytes32, Tuple[uint32, UnfinishedBlock, PreValidationResult]]
@ -86,10 +89,12 @@ class FullNodeStore:
serialized_wp_message: Optional[Message]
serialized_wp_message_tip: Optional[bytes32]
max_seen_unfinished_blocks: int
def __init__(self, constants: ConsensusConstants):
self.candidate_blocks = {}
self.candidate_backup_blocks = {}
self.seen_unfinished_blocks = set()
self.seen_unfinished_blocks = {}
self.unfinished_blocks = {}
self.finished_sub_slots = []
self.future_eos_cache = {}
@ -108,6 +113,7 @@ class FullNodeStore:
self.tx_fetch_tasks = {}
self.serialized_wp_message = None
self.serialized_wp_message_tip = None
self.max_seen_unfinished_blocks = 1000
def add_candidate_block(
self, quality_string: bytes32, height: uint32, unfinished_block: UnfinishedBlock, backup: bool = False
@ -148,12 +154,13 @@ class FullNodeStore:
def seen_unfinished_block(self, object_hash: bytes32) -> bool:
if object_hash in self.seen_unfinished_blocks:
return True
self.seen_unfinished_blocks.add(object_hash)
self.seen_unfinished_blocks[object_hash] = None
if len(self.seen_unfinished_blocks) > self.max_seen_unfinished_blocks:
# remove the least recently added hash
to_remove = next(iter(self.seen_unfinished_blocks))
del self.seen_unfinished_blocks[to_remove]
return False
def clear_seen_unfinished_blocks(self) -> None:
self.seen_unfinished_blocks.clear()
def add_unfinished_block(
self, height: uint32, unfinished_block: UnfinishedBlock, result: PreValidationResult
) -> None:

View File

@ -114,7 +114,9 @@ async def test_basic_store(
h_hash_1 = bytes32.random(seeded_random)
assert not store.seen_unfinished_block(h_hash_1)
assert store.seen_unfinished_block(h_hash_1)
store.clear_seen_unfinished_blocks()
# this will crowd out h_hash_1
for _ in range(store.max_seen_unfinished_blocks):
store.seen_unfinished_block(bytes32.random(seeded_random))
assert not store.seen_unfinished_block(h_hash_1)
# Add/get unfinished block