""" Zinc shared memory IPC layer for MALKHUT. Uses the real Zinc shared memory adapter (POSIX SHM via /dev/shm/zinc_*), NOT the file-based transport. This is the lock-free, zero-copy IPC path. Regions (all use UVZINC01 seqlock framing for torn-read safety): malkhut_book_state — canonical order book snapshot malkhut_account_state — account/position snapshot malkhut_fulfilment_out — planner output: action + distribution malkhut_risk_gate — risk gate decisions Writer: data feed / CWM Readers: planner, risk gate, other systems """ from __future__ import annotations import json import struct import time from dataclasses import dataclass from typing import Any, Mapping, Optional # Zinc shared memory adapter (POSIX SHM, not file transport) import sys _ZINC_PATH = "/mnt/dolphinng5_predict/zinc/adapters/python" if _ZINC_PATH not in sys.path: sys.path.insert(0, _ZINC_PATH) from zinc import SharedRegion # UVZINC01 envelope: 8-byte magic + 8-byte seq + 8-byte json_size _MAGIC = b"UVZINC01" _HDR_FMT = "<8sQQ" # magic(8) + seq(u64) + json_size(u64) _HDR_SIZE = struct.calcsize(_HDR_FMT) DEFAULT_REGION_SIZE = 4 << 20 # 4 MiB per region def _encode_payload(data: Mapping[str, Any], seq: int) -> bytes: """Encode data into UVZINC01 envelope.""" body = json.dumps(data, separators=(",", ":")).encode("utf-8") header = struct.pack(_HDR_FMT, _MAGIC, seq, len(body)) return header + body def _decode_payload(buf: memoryview) -> tuple[dict, int]: """Decode UVZINC01 envelope. Returns (data, seq). Raises on torn frame.""" if len(buf) < _HDR_SIZE: raise ValueError("buffer too small for header") magic, seq, json_size = struct.unpack_from(_HDR_FMT, buf) if magic != _MAGIC: raise ValueError(f"bad magic: {magic!r}, expected {_MAGIC!r}") end = _HDR_SIZE + json_size if end > len(buf): raise ValueError(f"json_size={json_size} exceeds buffer") body = bytes(buf[_HDR_SIZE:end]) data = json.loads(body) return data, seq class SharedRegionWriter: """Lock-free writer to a Zinc shared memory region.""" def __init__(self, region_name: str, capacity: int = DEFAULT_REGION_SIZE) -> None: self.region_name = region_name self.capacity = capacity try: self._region = SharedRegion.create(region_name, capacity) except FileExistsError: self._region = SharedRegion.open(region_name) self._seq = 0 def write(self, data: Mapping[str, Any]) -> None: self._seq += 1 payload = _encode_payload(data, self._seq) if len(payload) > self.capacity: raise ValueError(f"payload {len(payload)} > capacity {self.capacity}") buf = self._region.as_buffer() buf[:len(payload)] = payload self._region.notify() def close(self) -> None: self._region.close() class SharedRegionReader: """Lock-free reader from a Zinc shared memory region.""" def __init__(self, region_name: str) -> None: self.region_name = region_name self._region = SharedRegion.open(region_name) def read(self, timeout_ms: int = 100) -> tuple[dict, int]: """Read current data. Returns (data, seq). Blocks up to timeout_ms.""" self._region.wait(timeout_ms) buf = self._region.as_buffer() return _decode_payload(buf) def close(self) -> None: self._region.close() class MalkhutZincPlane: """ MALKHUT shared memory plane. Creates dedicated Zinc regions for book state, account state, fulfilment output, and risk gate decisions. """ def __init__(self, prefix: str = "malkhut", capacity: int = DEFAULT_REGION_SIZE) -> None: self.prefix = prefix self._writers: dict[str, SharedRegionWriter] = {} self._readers: dict[str, SharedRegionReader] = {} self._seq: dict[str, int] = {} def _region_name(self, kind: str) -> str: return f"{self.prefix}_{kind}" def writer(self, kind: str) -> SharedRegionWriter: if kind not in self._writers: name = self._region_name(kind) self._writers[kind] = SharedRegionWriter(name, DEFAULT_REGION_SIZE) self._seq[kind] = 0 return self._writers[kind] def reader(self, kind: str) -> SharedRegionReader: if kind not in self._readers: name = self._region_name(kind) self._readers[kind] = SharedRegionReader(name) return self._readers[kind] def publish_book(self, data: Mapping[str, Any]) -> None: self.writer("book_state").write(data) def read_book(self, timeout_ms: int = 100) -> tuple[dict, int]: return self.reader("book_state").read(timeout_ms) def publish_account(self, data: Mapping[str, Any]) -> None: self.writer("account_state").write(data) def read_account(self, timeout_ms: int = 100) -> tuple[dict, int]: return self.reader("account_state").read(timeout_ms) def publish_fulfilment(self, data: Mapping[str, Any]) -> None: self.writer("fulfilment_out").write(data) def read_fulfilment(self, timeout_ms: int = 100) -> tuple[dict, int]: return self.reader("fulfilment_out").read(timeout_ms) def publish_risk(self, data: Mapping[str, Any]) -> None: self.writer("risk_gate").write(data) def read_risk(self, timeout_ms: int = 100) -> tuple[dict, int]: return self.reader("risk_gate").read(timeout_ms) def close_all(self) -> None: for w in self._writers.values(): w.close() for r in self._readers.values(): r.close()