Files
NODEDC_MISSION_CORE/simulation/ai-polygon/local_state.py
T

103 lines
3.4 KiB
Python

"""Atomic local IPC snapshots; no network access in the simulation process."""
import json
import os
import sqlite3
import time
from pathlib import Path
class StateChannel:
"""Latest-value local IPC using SQLite WAL, available in both Python hosts.
Readers never hold Windows rename/delete locks on a telemetry snapshot.
The durable camera/motion journals remain separate evidence artifacts.
Each process owns its connection; only small control/telemetry JSON enters it.
"""
def __init__(self, directory: Path):
self.connection = sqlite3.connect(directory / "channel.sqlite3", timeout=0.1)
self.connection.execute("PRAGMA journal_mode=WAL")
self.connection.execute("PRAGMA synchronous=NORMAL")
self.connection.execute(
"CREATE TABLE IF NOT EXISTS state (key TEXT PRIMARY KEY, value TEXT NOT NULL)"
)
self.connection.commit()
def write(self, key, value):
encoded = json.dumps(value, allow_nan=False)
with self.connection:
self.connection.execute(
"INSERT INTO state(key,value) VALUES(?,?) "
"ON CONFLICT(key) DO UPDATE SET value=excluded.value",
(key, encoded),
)
def read(self, key, default=None):
row = self.connection.execute("SELECT value FROM state WHERE key=?", (key,)).fetchone()
return default if row is None else json.loads(row[0])
def close(self):
self.connection.close()
def sharing_retry(operation):
# A concurrent Windows reader briefly denies delete/replace sharing. Retry
# only this local file operation, bounded to 14ms; permanent errors surface.
for attempt in range(8):
try:
return operation()
except PermissionError:
if attempt == 7:
raise
time.sleep(0.002)
def write_json(path: Path, value):
temporary = path.with_name(path.name + f".{os.getpid()}.tmp")
temporary.write_text(json.dumps(value, allow_nan=False), encoding="utf-8")
sharing_retry(lambda: os.replace(temporary, path))
def read_json(path: Path, default=None):
try:
return json.loads(sharing_retry(lambda: read_shared_text(path)))
except FileNotFoundError:
return default
def read_shared_text(path: Path):
if os.name != "nt":
return path.read_text(encoding="utf-8")
# Python's normal Windows open does not grant FILE_SHARE_DELETE. An atomic
# writer must remain able to replace a snapshot while a reader holds it.
import ctypes
import msvcrt
from ctypes import wintypes
kernel = ctypes.WinDLL("kernel32", use_last_error=True)
kernel.CreateFileW.argtypes = [
wintypes.LPCWSTR,
wintypes.DWORD,
wintypes.DWORD,
ctypes.c_void_p,
wintypes.DWORD,
wintypes.DWORD,
wintypes.HANDLE,
]
kernel.CreateFileW.restype = wintypes.HANDLE
handle = kernel.CreateFileW(str(path), 0x80000000, 7, None, 3, 0x80, None)
if handle == wintypes.HANDLE(-1).value:
code = ctypes.get_last_error()
if code in (2, 3):
raise FileNotFoundError(str(path))
raise ctypes.WinError(code)
try:
descriptor = msvcrt.open_osfhandle(handle, os.O_RDONLY)
except BaseException:
kernel.CloseHandle.argtypes = [wintypes.HANDLE]
kernel.CloseHandle(handle)
raise
with os.fdopen(descriptor, "r", encoding="utf-8") as stream:
return stream.read()