from nullptr.models import * from os.path import isfile, dirname, isdir import os from os.path import basename import json from .util import * from time import time import pickle from struct import unpack, pack from functools import partial class ChunkHeader: def __init__(self): self.in_use = True self.size = 0 self.used = 0 @classmethod def parse(cls, fil): d = fil.read(16) if len(d) < 16: return None # print(d) o = cls() d, o.used = unpack(' 0: # read chunk hdr self.fil.seek(obj.file_offset) hdr = ChunkHeader.parse(self.fil) csize = hdr.size # if the chunk is too small if csize < osize: # free the chunk hdr.in_use = False # force a new chunk obj.file_offset = 0 else: # if it is big enough, update the used field hdr.used = osize self.fil.seek(obj.file_offset) hdr.write(self.fil) if obj.file_offset == 0: obj.file_offset, hdr = self.allocate_chunk(osize) self.fil.write(data) slack = b'\x00' * (hdr.size - hdr.used) self.fil.write(slack) def hold(self, obj): typ = type(obj) symbol = obj.symbol obj.store = self self.data[typ][symbol] = obj if hasattr(typ, 'system'): system_str = obj.system.symbol if system_str not in self.system_members: self.system_members[system_str] = set() self.system_members[system_str].add(obj) def create(self, typ, symbol): obj = typ(symbol, self) self.hold(obj) self.dirty(obj) return obj def get(self, typ, symbol, create=False): if type(typ) == str and typ in self.model_names: typ = self.model_names[typ] symbol = symbol.upper() if typ not in self.data: return None if symbol not in self.data[typ]: if create: return self.create(typ, symbol) else: return None return self.data[typ][symbol] def getter(self, typ, create=False): if type(typ) == str and typ in self.model_names: typ = self.model_names[typ] return partial(self.get, typ=typ, create=create) def update(self, typ, data, symbol=None): if type(typ) == str and typ in self.model_names: typ = self.model_names[typ] if symbol is None: symbol = mg(data, typ.identifier) obj = self.get(typ, symbol, True) obj.update(data) return obj def update_list(self, typ, lst): return [self.update(typ, d) for d in lst] def all(self, typ): if type(typ) == str and typ in self.model_names: typ = self.model_names[typ] for m in self.data[typ].values(): yield m def all_members(self, system, typ=None): if type(typ) == str and typ in self.model_names: typ = self.model_names[typ] if type(system) == System: system = system.symbol if 'system' not in self.system_members: return print('typ', typ) for m in self.system_members[system]: if typ is None or type(m) == typ: yield m def cleanup(self): if time() < self.last_cleanup + self.cleanup_interval: return start_time = time() expired = list() for t in self.data: for o in self.all(t): if o.is_expired(): expired.append(o) for o in expired: # TODO del self.data[type(o)][o.symbol] dur = time() - start_time # print(f'cleaned {len(expired)} in {dur:.03f} seconds') def flush(self): self.cleanup() it = 0 start_time = time() for obj in self.dirty_objects: it += 1 self.store(obj) self.fil.flush() self.dirty_objects = set() dur = time() - start_time # print(f'flush done {it} items {dur:.2f}')