chronaxis.execution.history
源码基线:8904c2f744951857659abd40aaa3535d57faf53c
1"""估算现役来源/表达式元数据和未完成批协议状态,不保存或回放历史。23保留现有内部导入路径;费用公式与异常边界不因旧历史仓退出而改变。4"""5from collections.abc import Mapping6from dataclasses import fields, is_dataclass7from enum import Enum8from sys import getsizeof9from ..extensions import ExtensionRegistry, FunctionSpec, ReductionSpec, TransformSpec10from ..core.binding import SignalDefinition11from ..core.expression import ExprNode12from ..results.errors import ResultFormatError13from ..sources.protocol import BatchValidator1415def _metadata_bytes(value, depth: int = 0) -> int:16 """估算已校验来源/请求的冻结元数据,不改变结果层封闭类型注册。1718 参数: value为typed描述树,depth为普通容器的递归深度。返回: 基础bytes。19 异常: ResultFormatError为普通元数据超过32层、存在环或未支持结构。20 已编译表达式的子节点用显式栈遍历,不把每层args元组算作额外数据协议层级。21 费用仍按每个引用位置累计,缓存只避免重新遍历相同子树,不减少预算费用。22 """23 return _metadata_cost(value, depth, set(), {})242526def _metadata_cost(value, depth, active, expression_costs):27 """按原费用公式估算一个元数据位置,并检测当前容器路径上的环。2829 参数: value为元数据、depth为普通嵌套层级、active为当前路径身份集合,30 expression_costs为本次调用的表达式子树费用缓存。31 返回: 此引用位置的完整费用。异常: 深度、环或未知结构的ResultFormatError。32 副作用: 临时登记当前路径;返回或异常时移除,不修改调用方元数据。33 """34 # 仅计数,不执行序列化或调用任意对象方法;所有描述先经typed模型检查。35 if depth > 32:36 raise ResultFormatError('历史元数据超过32层')37 # 已注册的宿主实现由调用方持有,本次计划仅借不可变描述/身份。不遍历或38 # 序列化任意Python回调;实际被请求的状态和工作区在其生命周期单独预约。39 if type(value) in (ExtensionRegistry,FunctionSpec,ReductionSpec,TransformSpec):40 return 25641 if type(value) is ExprNode:42 return _expression_metadata_cost(value, depth, active, expression_costs)43 container = is_dataclass(value) and not isinstance(value, type) or isinstance(value, Mapping) or type(value) is tuple44 if container:45 identity = id(value)46 if identity in active:47 raise ResultFormatError('历史元数据存在循环引用')48 active.add(identity)49 try:50 if type(value) is SignalDefinition:51 # 四个默认字段仍只收引用槽;实际非默认声明继续按完整字段计费。52 shared_defaults={'input_dtype','code_dtype','capture_code','config_version'}53 return getsizeof(value)+sum(16 if f.name in shared_defaults and getattr(value,f.name) is f.default54 else 256+_metadata_cost(getattr(value,f.name),depth+1,active,expression_costs) for f in fields(value))55 if is_dataclass(value) and not isinstance(value, type):56 return getsizeof(value) + sum(256 + _metadata_cost(getattr(value, field.name), depth + 1,57 active, expression_costs) for field in fields(value))58 if isinstance(value, Mapping):59 return getsizeof(value) + sum(128 + _metadata_cost(key, depth + 1, active, expression_costs)60 + _metadata_cost(item, depth + 1, active, expression_costs) for key, item in value.items())61 return getsizeof(value) + sum(32 + _metadata_cost(item, depth + 1, active, expression_costs) for item in value)62 finally:63 active.remove(identity)64 if isinstance(value, Enum):65 return 51266 # 已校验查表节点的冻结字节列按真实长度计入固定元数据成本。67 if value is None or type(value) in (str, int, bool, float, bytes):68 return getsizeof(value) + 6469 raise ResultFormatError('历史元数据类型无法估算')707172def _expression_metadata_cost(root, depth, active, costs):73 """非递归估算已编译表达式,同时保留原节点、字段和重复引用槽费用。7475 参数: root为ExprNode;depth为表达式之外的普通容器深度;active为当前路径;76 costs缓存本次调用同一节点及普通深度下的完整费用。77 返回: 根的完整费用,重复子树每出现一次仍收一次原费用。78 异常: 子节点不是ExprNode、args不是tuple、环或字段结构错误的ResultFormatError。79 副作用: 缓存只活到本次_metadata_bytes返回,不持有样本或跨任务状态。80 """81 pending = [(root, False)]82 entered = []83 try:84 while pending:85 node, complete = pending.pop()86 identity = id(node)87 key = identity, depth88 if complete:89 total = getsizeof(node)90 for field in fields(node):91 if field.name == 'args':92 # 子树费用可复用,但每个参数槽的32字节和完整子树费用都保留。93 total += 256 + getsizeof(node.args) + sum(32 + costs[(id(child), depth)][1]94 for child in node.args)95 else:96 # 非子树字段仍走普通元数据检查,不让表达式包装绕过32层限制。97 total += 256 + _metadata_cost(getattr(node, field.name), depth + 1, active, costs)98 costs[key] = node, total99 active.remove(identity)100 continue101 if identity in active:102 raise ResultFormatError('历史元数据存在循环引用')103 cached = costs.get(key)104 if cached is not None and cached[0] is node:105 continue106 if type(node) is not ExprNode or type(node.args) is not tuple or any(type(child) is not ExprNode for child in node.args):107 raise ResultFormatError('历史表达式元数据结构无法估算')108 active.add(identity)109 entered.append(identity)110 pending.append((node, True))111 pending.extend((child, False) for child in reversed(node.args))112 return costs[(id(root), depth)][1]113 finally:114 # 失败后的异常栈不能把这次路径登记带进其他元数据位置。115 active.difference_update(entered)116117118def _pending_bytes(validator: BatchValidator) -> int:119 """估算当前组去重状态,不保留历史所有sequence。120121 参数: validator为一个来源协议状态。返回: 保守bytes。122 异常: 已校验状态不主动抛错。123 """124 # set每身份计256bytes,覆盖槽位、整数与局部复制;列固定项单独计。125 return sum(512 + len(sequences) * 256 for _, sequences in validator.pending.values())126