""" Simulates 100 resourcePolicy records (no filesystem required) with the 10 extra lookup_service fields and estimates the in-memory size of PolicyMetadataDatabase. Usage: python estimate_policy_db_size_simulated.py [--count N] [POLICIES_DIR] """ import argparse import sys WORKSTATION_ROLES_KEY = "workstation_roles" ACCOUNT_FEATURE_CONTROLS_KEY = "account_feature_controls" EXTRA_FIELDS: dict[str, object] = { "lookup_service_01": False, "lookup_service_02": False, "lookup_service_03": False, "lookup_service_04": False, "lookup_service_05": False, "lookup_service_06": False, "lookup_service_07": False, "lookup_service_08": False, "lookup_service_09": False, "lookup_service_10": False, } def simulate_records(count: int) -> list[dict]: """Generate `count` synthetic resourcePolicy records.""" records = [] for i in range(1, count + 1): # Alternate which policies need workstation_roles / feature_controls # so the simulation reflects realistic variety. derived_roles = [WORKSTATION_ROLES_KEY] if i % 3 == 0 else [] variables_import = [ACCOUNT_FEATURE_CONTROLS_KEY] if i % 5 == 0 else [] record = { "resource_type": f"resource_type_{i:03d}", "requires_workstation_roles": WORKSTATION_ROLES_KEY in derived_roles, "requires_account_feature_controls": ACCOUNT_FEATURE_CONTROLS_KEY in variables_import, } for field, default in EXTRA_FIELDS.items(): record[field] = list(default) if isinstance(default, list) else default records.append(record) return records def estimate_size(records: list[dict]) -> None: def deep_sizeof(obj, seen=None): if seen is None: seen = set() obj_id = id(obj) if obj_id in seen: return 0 seen.add(obj_id) size = sys.getsizeof(obj) if isinstance(obj, dict): size += sum(deep_sizeof(k, seen) + deep_sizeof(v, seen) for k, v in obj.items()) elif isinstance(obj, (list, tuple, set, frozenset)): size += sum(deep_sizeof(item, seen) for item in obj) return size # Simulate PolicyMetadataDatabase._policies: resource_type -> record dict. db: dict[str, dict] = {r["resource_type"]: r for r in records} total = deep_sizeof(db) per_record = total / len(db) if db else 0 print(f"\n{'='*65}") print(f" Resource policies simulated: {len(records)}") print(f" Resource types in DB: {len(db)}") print(f" Fields per record: {3 + len(EXTRA_FIELDS)} (3 original + {len(EXTRA_FIELDS)} extra)") print(f" Needs workstation_roles: {sum(r['requires_workstation_roles'] for r in records)}") print(f" Needs feature_controls: {sum(r['requires_account_feature_controls'] for r in records)}") print(f"{'='*65}") print(f" Estimated DB size: {total:,} bytes ({total / 1024:.2f} KB)") print(f" Avg size per record: {per_record:,.1f} bytes") print(f"{'='*65}\n") print("Extra fields on each record:") for field, default in EXTRA_FIELDS.items(): print(f" {field:<30} (default: {default!r})") print(f"\nPer-resource breakdown:") print(f" {'Resource type':<35} {'WS roles':>8} {'Feat ctrl':>9}") print(f" {'-'*35} {'-'*8} {'-'*9}") for r in records: ws = "yes" if r["requires_workstation_roles"] else "no" fc = "yes" if r["requires_account_feature_controls"] else "no" print(f" {r['resource_type']:<35} {ws:>8} {fc:>9}") if __name__ == "__main__": parser = argparse.ArgumentParser( description="Simulate N resourcePolicy records and estimate in-memory DB size." ) parser.add_argument( "--count", type=int, default=100, help="Number of resourcePolicy records to simulate (default: 100)", ) args = parser.parse_args() records = simulate_records(args.count) estimate_size(records)