mirror of
https://github.com/OpenSelena/omniget.git
synced 2026-11-04 08:10:56 +00:00
Fecha o que ficou aberto na #217. Aquela PR entregava o modulo sem ligar nada; o bloqueio declarado era "mudar todos os call sites e decidir a migracao". Nenhum call site mudou. A API publica do recovery.rs continua igual (init_from_disk, persist, remove, list, clear_all) e so o armazenamento por baixo trocou. Era o caminho mais seguro e nao tinha sido tentado. O formato anterior reescrevia o arquivo inteiro a cada mudanca, entao um crash no meio da escrita podia levar a fila toda. Agora anexa uma linha com fsync por registro: um crash so pode corromper o ultimo, e o decode_log descarta a linha truncada e mantem o resto. Verificado com SIGKILL de verdade pelo scripts/wal-kill9.py: 202 registros integros, exatamente 1 truncado. Achado que so apareceu ao ligar: o Enqueued do WAL nao tinha `referer`, que existe no RecoveryItem desde sempre. Migrar como estava teria descartado o campo em silencio, e o download so falharia depois, no site que exige o header. Campo adicionado em 6 pontos, com teste que reprova se ele parar de propagar. A migracao do recovery.json roda uma vez, ordena por id (o JSON nao guardava posicao, e inventar ordem embaralharia a fila de quem atualiza) e renomeia o original para .json.migrated em vez de apagar. A producao chama a mesma funcao que o teste exercita. Na primeira versao o json_para_registros era usado so no teste e o codigo real reparseava por fora — o portao de clippy pegou como dead_code, e o teste estaria provando algo que ninguem executa. 609 testes, 0 falhando. Clippy 92, nenhum novo.
36 lines
1.5 KiB
Python
36 lines
1.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Gera um WAL cortado por um SIGKILL de verdade.
|
|
|
|
Nao e simulacao: sobe um processo filho que escreve o log com fsync a cada
|
|
registro, e o mata com SIGKILL exatamente enquanto o ultimo registro esta pela
|
|
metade. O arquivo resultante e o que o kernel deixou.
|
|
|
|
Existe para produzir a fixture do teste `recupera_a_fila_de_um_arquivo_cortado_
|
|
por_kill9_real` em src-tauri/src/core/queue_wal.rs, e para poder refaze-la
|
|
quando o formato do registro mudar.
|
|
|
|
python3 scripts/wal-kill9.py
|
|
|
|
Imprime o caminho do WAL gerado. Resultado esperado: N registros integros e
|
|
exatamente 1 truncado.
|
|
"""
|
|
import json, os, subprocess, sys, tempfile, signal, time
|
|
d = tempfile.mkdtemp(prefix="omniget-wal-")
|
|
wal = os.path.join(d, "queue.wal")
|
|
child = f'''
|
|
import json, os, sys, time
|
|
f = open({wal!r}, "ab", buffering=0)
|
|
for i in range(200):
|
|
rec = {{"op":"enqueued","id":i,"url":f"https://example.com/{{i}}","title":f"v{{i}}",
|
|
"platform":"youtube","output_dir":"/downloads","position":i}}
|
|
f.write((json.dumps(rec)+"\\n").encode()); os.fsync(f.fileno())
|
|
f.write(json.dumps({{"op":"started","id":5}}).encode()+b"\\n"); os.fsync(f.fileno())
|
|
f.write(json.dumps({{"op":"completed","id":7,"file_path":"/x.mp4"}}).encode()+b"\\n"); os.fsync(f.fileno())
|
|
sys.stdout.write("READY\\n"); sys.stdout.flush()
|
|
f.write(b'{{"op":"progress","id":5,"perc'); os.fsync(f.fileno())
|
|
time.sleep(30)
|
|
'''
|
|
p = subprocess.Popen([sys.executable,"-c",child], stdout=subprocess.PIPE)
|
|
p.stdout.readline(); time.sleep(0.3); os.kill(p.pid, signal.SIGKILL); p.wait()
|
|
print(wal)
|