Files
chia-blockchain/chia/full_node/lock_queue.py
T
8a028c3594 Ms.mempool locking (#9050)
* Prority locking to consensus

* Remove pstats

* Linting

* Do some stuff outside of lock

* Fix startup

* Add log timings

* Try some different locking

* Add limit

* catch excp

* CLVM inside lock

* Try using a semaphore instead

* use events for lock queue

* test

* Add logging for message types

* type

* remove seed

* check new peak waiters

* correct FullNodeAPI self.full_node.new_peak._waiters typo

* correct logging string typos

* only warn about new_peak Waiters if there is at least 1

* remove no-longer-accepted parameter to FullNode.peak_post_processing()

* only warn about respond_transaction Waiters if there is at least 1

* lint

* Change some constants

* Small fix and logging changes

* Put message types outside

* Change some log levels so we can test with info

* More logging

* Increase rate limits but decrease paralelism

* tweaks

* Log dropped tx

* Fix pool rpc test

* Test fixes

* Mempool optimization

* Remove from seen if fails

* Increase queue sizes

* Message types info

* More test and logging

* Small changes to networking just in case

* Decrease logging

* Decrease logging even further

* Decrease logging even further even further

* Decrease logging 3

* Transaction queue

* Don't cancel tasks or close connection

* Cancel tasks on disconnect (for shutdown purposed)

* Fix typo

* Catch cancelled

* Do multiple at a time

* More accurate farmer response time

* More efficiently create tasks

* Increase queue size and priority by fee

* Revert priority

* Don't re-request too many times for dropped TX

* Handle cancelled error so we don't go into a bad state

* Catch cancelled in syncing tasks

* Reduce new_peak_sem to improve performance

* Less bytes conversion

* Missing file, and 2 workers for CLVM

* Validate BLS in a new thread

* tests

* Change semaphore constants

* correct a cancellation triggered exception and assertion

* Fix send_transaction, dont use BaseException, fix tests

* Fix more tests

* only log transaction handler cancellation in debug

* typing in log

* move unfinished validation to diff proc

* it is asyncio.CancelledError

* Add a test for bad signature

* Fix more tests, reduce logging, lint

* One more lint

* blockchain tests, pass bytes directly, single call

* Try to fix rl_wallet failures

* Fix mempool test

* catch everything

* Don't test RL wallet

* Fix more tests and return error code

* Improve error handling in multiprocess

* Add pre-validation time

* Add pre-validation time in logs, and revert pytest.ini changes

* Add log correctly

* Ms.bls cache experiment (#9115)

* Logging for cache

* Less logging

* Return to original plan

* Clean up

* Remove coment

* Remove log

* formalize LockQueue shutdown

* Comments

* Fix blockchain test

* Improve cache

* Remove logs

* Fix sign_coin_spends

* Fix pool wallet

Co-authored-by: Kyle Altendorf <sda@fstab.net>
Co-authored-by: Yostra <straya@chia.net>
2021-11-04 09:29:05 -07:00

86 lines
2.6 KiB
Python

import asyncio
import dataclasses
import logging
import traceback
from typing import Awaitable, Callable
log = logging.getLogger(__name__)
@dataclasses.dataclass(frozen=True, order=True)
class PrioritizedCallable:
priority: int
af: Callable[[], Awaitable[object]] = dataclasses.field(compare=False)
class LockQueue:
"""
The purpose of this class is to be able to control access to a lock, and give priority to certain clients
(LockClients). To use it, create a lock and clients:
```
my_lock = LockQueue(asyncio.Lock())
client_a = LockClient(0, my_lock)
client_b = LockClient(1, my_lock)
async with client_a:
...
```
The clients can be used like normal async locks, but the higher priority (lower number) will always go first.
Must be created under an asyncio running loop, and close and await_closed should be called.
"""
def __init__(self, inner_lock: asyncio.Lock):
self._inner_lock: asyncio.Lock = inner_lock
self._task_queue: asyncio.PriorityQueue = asyncio.PriorityQueue()
self._run_task = asyncio.create_task(self._run())
self._release_event = asyncio.Event()
async def put(self, priority: int, callback: Callable[[], Awaitable[object]]):
await self._task_queue.put(PrioritizedCallable(priority=priority, af=callback))
async def acquire(self):
await self._inner_lock.acquire()
def release(self):
self._inner_lock.release()
self._release_event.set()
async def _run(self):
try:
while True:
prioritized_callback = await self._task_queue.get()
self._release_event = asyncio.Event()
await self.acquire()
await prioritized_callback.af()
await self._release_event.wait()
except asyncio.CancelledError:
error_stack = traceback.format_exc()
log.debug(f"LockQueue._run() cancelled: {error_stack}")
def close(self):
self._run_task.cancel()
async def await_closed(self):
await self._run_task
class LockClient:
def __init__(self, priority: int, queue: LockQueue):
self._priority = priority
self._queue = queue
async def __aenter__(self):
called: asyncio.Event = asyncio.Event()
# Use a parameter default to avoid a closure
async def callback(called=called) -> None:
called.set()
await self._queue.put(priority=self._priority, callback=callback)
await called.wait()
async def __aexit__(self, exc_type, exc, tb):
self._queue.release()