Open-source Grok free registration CLI, xai_enroller auth pipeline, local auth service, tests and docs.
170 lines
5.4 KiB
Python
170 lines
5.4 KiB
Python
"""
|
|
Inventory — 唯一库存门面 + PairLease
|
|
|
|
put_t / put_q: 所有权从 Worker 转移到 Inventory
|
|
claim_pair(): 等待完整 T/Q pair,通过 PairLease 原子转移所有权
|
|
内部单锁 + Condition,不做分片,不做无锁。
|
|
"""
|
|
import asyncio
|
|
import time
|
|
from collections import deque
|
|
|
|
from .envelope import ResourceEnvelope
|
|
|
|
|
|
class PairLease:
|
|
"""claim_pair 成功后的 pair 所有权对象。
|
|
|
|
用法:
|
|
async with inventory.claim_pair() as pair:
|
|
t_val, q_val = pair.t.value, pair.q.value
|
|
...
|
|
离开上下文时无论成功/失败/取消,都核销 T/Q 并释放 slot。
|
|
"""
|
|
|
|
__slots__ = ('t', 'q', '_inventory')
|
|
|
|
def __init__(self, t_env, q_env, inventory):
|
|
self.t = t_env
|
|
self.q = q_env
|
|
self._inventory = inventory
|
|
|
|
async def __aenter__(self):
|
|
return self
|
|
|
|
async def __aexit__(self, exc_type, exc, tb):
|
|
# 第一版策略: 无论结果如何,均核销 T/Q
|
|
self.t.release_slot_once(reason='pair_settle')
|
|
self.q.release_slot_once(reason='pair_settle')
|
|
# 通知可能在等待的 claim_pair
|
|
async with self._inventory._lock:
|
|
self._inventory._cond.notify_all()
|
|
return False
|
|
|
|
|
|
class Inventory:
|
|
"""T/Q 库存门面。
|
|
|
|
内部维护两个 deque 和一个 Lock+Condition。
|
|
put_t/put_q 在锁内 O(1) 操作;claim_pair 在锁外等待 Condition。
|
|
"""
|
|
|
|
def __init__(self, metrics=None):
|
|
self._t_buf = deque()
|
|
self._q_buf = deque()
|
|
self._lock = asyncio.Lock()
|
|
self._cond = asyncio.Condition(self._lock)
|
|
self._metrics = metrics
|
|
|
|
# ── 入库 ──
|
|
|
|
async def put_t(self, env: ResourceEnvelope):
|
|
"""将 T envelope 入库。调用前 env 属于 Worker,成功后属于 Inventory。"""
|
|
async with self._lock:
|
|
now = time.time()
|
|
if env.is_expired(now):
|
|
env.discard(reason='expired_on_put')
|
|
if self._metrics:
|
|
self._metrics.t_expired += 1
|
|
return
|
|
self._cleanup_expired(now)
|
|
self._t_buf.append(env)
|
|
if self._metrics:
|
|
self._metrics.t_admitted += 1
|
|
self._cond.notify_all()
|
|
|
|
async def put_q(self, env: ResourceEnvelope):
|
|
"""将 Q envelope 入库。调用前 env 属于 Worker,成功后属于 Inventory。"""
|
|
async with self._lock:
|
|
now = time.time()
|
|
if env.is_expired(now):
|
|
env.discard(reason='expired_on_put')
|
|
if self._metrics:
|
|
self._metrics.q_expired += 1
|
|
return
|
|
self._cleanup_expired(now)
|
|
self._q_buf.append(env)
|
|
if self._metrics:
|
|
self._metrics.q_admitted += 1
|
|
self._cond.notify_all()
|
|
|
|
# ── Claim ──
|
|
|
|
def claim_pair(self):
|
|
"""返回 PairLease 的 async context manager。
|
|
|
|
等待期间可取消,取消不弹出资源。成功后 T/Q 原子弹出并转移给 PairLease。
|
|
"""
|
|
return _PairClaim(self, self._metrics)
|
|
|
|
# ── 内部 ──
|
|
|
|
def _try_pop_pair(self):
|
|
"""在锁内尝试弹出一对未过期的 T/Q。返回 (t_env, q_env) 或 None。"""
|
|
now = time.time()
|
|
# 清理过期
|
|
self._cleanup_expired(now)
|
|
if self._t_buf and self._q_buf:
|
|
t_env = self._t_buf.popleft()
|
|
q_env = self._q_buf.popleft()
|
|
return t_env, q_env
|
|
return None
|
|
|
|
def _cleanup_expired(self, now):
|
|
"""lazy cleanup: 清理已过期的 T/Q 并释放 slot。锁内调用。"""
|
|
self._cleanup_buf(self._t_buf, now, 't_expired')
|
|
self._cleanup_buf(self._q_buf, now, 'q_expired')
|
|
|
|
def _cleanup_buf(self, buf, now, metric_name):
|
|
"""扫描完整库存,保留未过期实体的原始 FIFO 顺序。"""
|
|
kept = deque()
|
|
while buf:
|
|
env = buf.popleft()
|
|
if env.is_expired(now):
|
|
env.discard(reason='expired_in_inventory')
|
|
if self._metrics:
|
|
setattr(self._metrics, metric_name, getattr(self._metrics, metric_name) + 1)
|
|
else:
|
|
kept.append(env)
|
|
buf.extend(kept)
|
|
|
|
@property
|
|
def t_depth(self):
|
|
return len(self._t_buf)
|
|
|
|
@property
|
|
def q_depth(self):
|
|
return len(self._q_buf)
|
|
|
|
|
|
class _PairClaim:
|
|
"""claim_pair() 返回的 async context manager。"""
|
|
|
|
__slots__ = ('_inventory', '_pair', '_metrics')
|
|
|
|
def __init__(self, inventory, metrics):
|
|
self._inventory = inventory
|
|
self._pair = None
|
|
self._metrics = metrics
|
|
|
|
async def __aenter__(self):
|
|
inv = self._inventory
|
|
async with inv._lock:
|
|
# 循环等待直到有 pair 或被取消
|
|
while True:
|
|
pair = inv._try_pop_pair()
|
|
if pair is not None:
|
|
t_env, q_env = pair
|
|
self._pair = PairLease(t_env, q_env, inv)
|
|
if self._metrics:
|
|
self._metrics.pair_claimed += 1
|
|
return self._pair
|
|
# 没有 pair,等待 notify
|
|
await inv._cond.wait()
|
|
|
|
async def __aexit__(self, exc_type, exc, tb):
|
|
if self._pair is not None:
|
|
# PairLease.__aexit__ 处理核销
|
|
return await self._pair.__aexit__(exc_type, exc, tb)
|
|
return False
|