monitor sort
This commit is contained in:
1 parent
339f66b648
commit
a7ca0e0d98
2 files changed
+27
-5
No files matched your search
@@ -11,8 +11,10 @@ from tqdm import tqdm
|
|||||||
from collectionparser.utils import create_dir_for_file, find_files
|
from collectionparser.utils import create_dir_for_file, find_files
|
||||||
|
|
||||||
# ponytail: buckets under this size sort byte-exactly in RAM; larger buckets
|
# ponytail: buckets under this size sort byte-exactly in RAM; larger buckets
|
||||||
# shell out to `sort -u`, which spills to disk.
|
# shell out to `sort -u`. 64 MB covers almost every bucket, so the final dedup
|
||||||
_IN_MEMORY_SORT_LIMIT = 8 * 1024 * 1024
|
# rarely spawns a process; a single bucket's sort is one file, so memory stays
|
||||||
|
# bounded. Lower this if bucket files can be huge.
|
||||||
|
_IN_MEMORY_SORT_LIMIT = 64 * 1024 * 1024
|
||||||
|
|
||||||
|
|
||||||
class API:
|
class API:
|
||||||
@@ -80,9 +82,13 @@ def sort_unique(src, dst) -> None:
|
|||||||
Path(dst).write_bytes(b"\n".join(lines) + b"\n" if lines else b"")
|
Path(dst).write_bytes(b"\n".join(lines) + b"\n" if lines else b"")
|
||||||
else:
|
else:
|
||||||
tmp = f"{dst}.tmp"
|
tmp = f"{dst}.tmp"
|
||||||
|
# Parallel sort, but memory-bounded: `-S` caps the sort buffer and
|
||||||
|
# `--parallel 4` bounds the threads. A large `-S` here can OOM and get
|
||||||
|
# the sort SIGKILLed. ponytail: ceiling ~1 GB + per-thread buffers;
|
||||||
|
# raise `-S`/`--parallel` only if the box has RAM to spare.
|
||||||
with open(tmp, "wb") as writer:
|
with open(tmp, "wb") as writer:
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
["sort", "-u", str(src)],
|
["sort", "-S", "1G", "--parallel", "4", "-u", str(src)],
|
||||||
stdout=writer,
|
stdout=writer,
|
||||||
check=True,
|
check=True,
|
||||||
env={**os.environ, "LC_ALL": "C"},
|
env={**os.environ, "LC_ALL": "C"},
|
||||||
|
|||||||
@@ -246,8 +246,14 @@ def build(
|
|||||||
dataset.mkdir(parents=True, exist_ok=True)
|
dataset.mkdir(parents=True, exist_ok=True)
|
||||||
scratch.mkdir(parents=True, exist_ok=True)
|
scratch.mkdir(parents=True, exist_ok=True)
|
||||||
os.environ["TMPDIR"] = str(scratch) # `sort -u` spills here, not into the dataset
|
os.environ["TMPDIR"] = str(scratch) # `sort -u` spills here, not into the dataset
|
||||||
for stale in scratch.glob("extract_*"):
|
# Leftovers from a crashed run: extraction dirs, and `sort` run/temp files.
|
||||||
|
# Only scratch is touched, never the source or dataset.
|
||||||
|
for pattern in ("extract_*", "sort*", "*.tmp"):
|
||||||
|
for stale in scratch.glob(pattern):
|
||||||
|
if stale.is_dir():
|
||||||
shutil.rmtree(stale, ignore_errors=True)
|
shutil.rmtree(stale, ignore_errors=True)
|
||||||
|
else:
|
||||||
|
stale.unlink(missing_ok=True)
|
||||||
|
|
||||||
if extract and not _which("7z", "7za", "unrar"):
|
if extract and not _which("7z", "7za", "unrar"):
|
||||||
print(
|
print(
|
||||||
@@ -316,15 +322,25 @@ def build(
|
|||||||
pending = [f for f in inputs if str(f) not in parsed]
|
pending = [f for f in inputs if str(f) not in parsed]
|
||||||
|
|
||||||
t0 = time.time()
|
t0 = time.time()
|
||||||
|
pairs: int | None = None
|
||||||
|
rejects: int | None = None
|
||||||
if pending:
|
if pending:
|
||||||
parse_files(
|
pairs, rejects = parse_files(
|
||||||
pending,
|
pending,
|
||||||
str(success),
|
str(success),
|
||||||
str(failure),
|
str(failure),
|
||||||
progress_filename=str(progress_path),
|
progress_filename=str(progress_path),
|
||||||
hashes_filename=str(hashes),
|
hashes_filename=str(hashes),
|
||||||
)
|
)
|
||||||
|
# Remember the counts so a later resume skips the full re-read.
|
||||||
|
state.setdefault("counts", {})[str(index)] = [pairs, rejects]
|
||||||
|
save()
|
||||||
if success.exists():
|
if success.exists():
|
||||||
|
if pairs is None:
|
||||||
|
saved = (state.get("counts") or {}).get(str(index))
|
||||||
|
if saved:
|
||||||
|
pairs, rejects = saved
|
||||||
|
else: # ponytail: only pre-count-state runs need this full read
|
||||||
pairs = _count_lines(success)
|
pairs = _count_lines(success)
|
||||||
rejects = _count_lines(failure) if failure.exists() else 0
|
rejects = _count_lines(failure) if failure.exists() else 0
|
||||||
sort_unique(success, success)
|
sort_unique(success, success)
|
||||||
|
|||||||
Reference in new issue
Block a user