Archiv: je Version quellen.tar und arbeit.tar statt einzelner Dateien – SMB schafft 25 Dateien/s, am Stück 90 MB/s

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
team3andClaude Fable 5.1 committed 2026-10-14 16:14:49 +02:00
1 parent 7ba08b68e0
commit 54d1d6a8da
3 files changed
+26 -26

No files matched your search

+20 -21
View File
@@ -1,9 +1,12 @@
"""Quellen und Arbeitsdateien fertiger Versionen ins Archiv verschieben (config.ARCHIV, auf dem Server eine Storage Box).
Nichts liest danach noch daraus: neue Versionen recherchieren neu, fertige Läufe setzen nie fort. QUELLEN.md bleibt im Speicher,
die Buchansicht zeigt sie. Erst kopieren, dann löschen – ein Abbruch lässt den Speicher vollständig, der nächste Start holt nach."""
"""Quellen und Arbeitsdateien fertiger Versionen als tar ins Archiv (config.ARCHIV, auf dem Server die Storage Box).
Je Version quellen.tar (ohne QUELLEN.md, die bleibt im Speicher und steht in der Buchansicht) und arbeit.tar. Ein tar statt
einzelner Dateien, weil SMB je Datei mehrere Round-Trips braucht (25 Dateien/s), am Stück aber 90 MB/s schafft.
Nichts liest danach noch daraus: neue Versionen recherchieren neu, fertige Läufe setzen nie fort.
Erst packen, dann löschen – ein Abbruch lässt den Speicher vollständig, der nächste Start holt nach."""
import asyncio
import logging
import shutil
import subprocess
from pathlib import Path
from . import config, state
@@ -25,32 +28,28 @@ def _eintraege(d: Path) -> list[Path]:
def auslagern(key: str) -> None:
"""Verschiebt quellen/ (außer QUELLEN.md) und arbeit/ nach ARCHIV/<key>/. Blockiert – im Thread aufrufen."""
"""Packt quellen/ (außer QUELLEN.md) und arbeit/ nach ARCHIV/<key>/<ordner>.tar und löscht sie. Blockiert – im Thread aufrufen."""
v = state.verzeichnis(key)
ziel = config.ARCHIV / key
ziel.mkdir(parents=True, exist_ok=True)
for u in ORDNER:
for p in _eintraege(v / u):
_kopieren(p, config.ARCHIV / key / u / p.name)
eintraege = _eintraege(v / u)
if not eintraege:
continue
tmp = ziel / f"{u}.tar.tmp"
r = subprocess.run(["tar", "-cf", str(tmp), "-C", str(v / u), *[p.name for p in eintraege]], capture_output=True, text=True)
if r.returncode:
raise OSError(f"tar {u}/ von {key}: {r.stderr.strip()[-300:]}")
tmp.replace(ziel / f"{u}.tar")
for p in eintraege:
if p.is_dir() and not p.is_symlink():
shutil.rmtree(p)
else:
p.unlink()
def _kopieren(quelle: Path, ziel: Path) -> None:
"""Ohne Rechte, Zeiten und Symlinks: CIFS kennt beides nicht. Links in Klonen entfallen."""
if quelle.is_symlink():
return
if quelle.is_dir():
ziel.mkdir(parents=True, exist_ok=True)
for k in quelle.iterdir():
_kopieren(k, ziel / k.name)
elif quelle.is_file():
ziel.parent.mkdir(parents=True, exist_ok=True)
shutil.copyfile(quelle, ziel)
async def _auslagern(key: str) -> None:
state.ereignis(key, "archiv", "start", f"Quellen und Arbeitsdateien nach {config.ARCHIV / key}")
state.ereignis(key, "archiv", "start", f"Quellen und Arbeitsdateien als tar nach {config.ARCHIV / key}")
try:
await asyncio.to_thread(auslagern, key)
state.ereignis(key, "archiv", "ende", "ausgelagert")
@@ -69,7 +68,7 @@ def anstossen(key: str) -> None:
async def nachholen() -> None:
"""Beim Start: alle fertigen Versionen mit Restbestand, nacheinander (Bestand und abgebrochene Kopien)."""
"""Beim Start: alle fertigen Versionen mit Restbestand, nacheinander (Bestand und abgebrochene Läufe)."""
if not config.ARCHIV:
return
for t in state.themen():