Files
CM95/tools/compare_pbf_trees.py
2026-10-02 18:03:26 +08:00

48 lines
2.0 KiB
Python
Executable File

#!/usr/bin/env python3
from __future__ import annotations
import argparse, hashlib, json
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path
def digest(p: Path):
h=hashlib.sha256()
with p.open("rb") as f:
for b in iter(lambda:f.read(1024*1024),b""):
h.update(b)
return p.stat().st_size,h.hexdigest()
def inventory(root: Path):
return {str(p.relative_to(root)):p for p in root.rglob("*.pbf") if p.is_file()}
def main():
ap=argparse.ArgumentParser()
ap.add_argument("mysql_root")
ap.add_argument("postgres_root")
ap.add_argument("--output",default="logs/mysql_postgresql_pbf_compare.json")
ap.add_argument("--workers",type=int,default=8)
args=ap.parse_args()
mr,pr=Path(args.mysql_root),Path(args.postgres_root)
mi,pi=inventory(mr),inventory(pr)
common=sorted(set(mi)&set(pi))
def one(rel):
ms,mh=digest(mi[rel]); ps,ph=digest(pi[rel])
return rel,ms,mh,ps,ph
identical=0; diffs=[]
with ThreadPoolExecutor(max_workers=args.workers) as ex:
for rel,ms,mh,ps,ph in ex.map(one,common):
if mh==ph and ms==ps: identical+=1
else: diffs.append({"path":rel,"mysql_bytes":ms,"postgres_bytes":ps,"mysql_sha256":mh,"postgres_sha256":ph})
out={
"mysql_root":str(mr.resolve()),"postgres_root":str(pr.resolve()),
"mysql_files":len(mi),"postgres_files":len(pi),"common_files":len(common),
"identical_files":identical,"different_files":len(diffs),
"mysql_only":sorted(set(mi)-set(pi)),"postgres_only":sorted(set(pi)-set(mi)),
"different_examples":diffs[:100],
"result":"PASS" if len(mi)==len(pi)==identical and not diffs else "DIFF",
}
op=Path(args.output);op.parent.mkdir(parents=True,exist_ok=True)
op.write_text(json.dumps(out,ensure_ascii=False,indent=2),encoding="utf-8")
print(json.dumps({k:v for k,v in out.items() if k not in ("mysql_only","postgres_only","different_examples")},ensure_ascii=False,indent=2))
print(f"report={op}")
if __name__=="__main__": main()