VulCode
Blog

Sonic: TRIGGER backup działa, gdy magazyn jest w użyciu

Kopia zapasowa w wyszukiwarce Sonic zawodziła tuż po zapisie danych, bo RocksDB nie otwiera bazy, która jest już otwarta w tym samym procesie. Teraz backup korzysta z otwartego magazynu.

DualFroz - VulCode CEODualFroz - VulCode CEO1 min czytania
Sonic: TRIGGER backup działa, gdy magazyn jest w użyciu - DualFroz - VulCode CEO
Tytuł zmiany w repozytorium
fix(core): Make `TRIGGER backup` work while stores are in use
Scalono
5.10.2026
Opisano tutaj
6.10.2026

Wpis powstał 1 dzień po scaleniu zmiany.

Sonic
Technologie:RustRocksDB

Co nie działało

Sonic to szybki backend wyszukiwania napisany w Rust, który autorzy opisują jako alternatywę dla Elasticsearch działającą na kilku megabajtach pamięci. Indeks trzyma w RocksDB (magazyn KV) i w plikach FST. Komenda TRIGGER backup miała robić kopię obu, ale zawodziła w dwóch sytuacjach opisanych w zgłoszeniu #274.

Pierwsza: kopia zaraz po zapisie danych komendą PUSH. Zapis otwiera bazę RocksDB i zostawia ją otwartą w puli magazynów, a kod kopii próbował otworzyć ją drugi raz. RocksDB na to nie pozwala, bo plik LOCK jest już zajęty. Druga: świeży serwer, na którym nic jeszcze nie zapisano, więc katalogi magazynów w ogóle nie istniały.

Co zmieniliśmy

Jeśli magazyn jest już otwarty w puli, kopia powstaje z tej instancji. Przed kopią dane są zrzucane z pamięci na dysk, bo bufory w pamięci mogą trzymać zapisy, których nie ma jeszcze w plikach:

rust
match pooled_store {
    Some(store) => kv_backup_engine.create_new_backup_flush(&store.database, true),
    None => {
        let origin_kv = self.open(store_id, |_| {})?;
        kv_backup_engine.create_new_backup(&origin_kv)
    }
}

Gdy katalog magazynu KV albo FST jeszcze nie istnieje, kopia po prostu go pomija zamiast zwracać błąd.

Jak to sprawdziliśmy

Test trigger_backup był wcześniej wyłączony z adnotacją, że klient go nie obsługuje, a w środku miał todo!(). Napisaliśmy go od nowa: kopia na pustym serwerze, potem PUSH, potem kopia przy otwartym magazynie i sprawdzenie, że w katalogu kopii jest dokładnie jeden niepusty backup KV.

Efekt

Zmianę scalono 5 października 2026. Tego samego dnia przyjęto też naszą drugą poprawkę (#432): od jednej z wcześniejszych zmian pętla po kubełkach FST sprawdzała zły wpis, więc backup zgłaszał sukces, ale nie zapisywał plików FST, a odtwarzanie niczego nie odtwarzało.

Te same wywołania przed zmianą i po niej

Przypadki z wpisu i z testu w pull requeście #430: co powinno wyjść, co wychodziło przed poprawką i co wychodzi teraz.

KomendaPowinno daćPrzed zmianąPo zmianieWynik
KomendaTRIGGER backupświeży serwer, nic jeszcze nie zapisano
Powinno daćkopia bez błędu
Przed zmianąbłąd: katalogi magazynów nie istnieją
Po zmianiebrakujący katalog KV albo FST jest pomijany
Zgodne z oczekiwanym
KomendaPUSH, TRIGGER backupmagazyn RocksDB otwarty w puli po zapisie
Powinno daćkopia otwartego magazynu
Przed zmianąRocksDB odmawia drugiego otwarcia, plik LOCK jest zajęty
Po zmianiekopia z instancji w puli, po zrzuceniu buforów na dysk
Zgodne z oczekiwanym

2 z 2 przypadków zgodnych z oczekiwanym

Co sprawdza test

Kopia na pustym serwerze, PUSH, kopia przy otwartym magazynie i dokładnie jeden niepusty backup KV w katalogu kopii.

Tego samego dnia

Przyjęto też naszą poprawkę #432: backup zgłaszał sukces, ale nie zapisywał plików FST.

Czego nas to nauczyło

Kopia zapasowa robiona w trakcie pracy musi brać spójny stan, a nie blokować magazyn albo czytać go w połowie zapisu. To ta sama zasada, którą stosujemy w kopiach danych klientów.

Pytania o zmianę #430

Gdzie jest zmiana, jak ją sprawdziliśmy i kto ją przyjął.