Zapisywanie na początku pliku czegoś, co znasz tylko na końcu

9

Tło: Piszę kod C mikrokontrolera, aby zapisać plik EBML. EBML jest jak binarny XML z zagnieżdżonymi elementami, ale zamiast znaczników początkowego i końcowego istnieje identyfikator początkowy, długość, a następnie dane. Piszę to w zewnętrznej pamięci Flash w aplikacji o niskiej mocy, więc chciałbym ograniczyć dostęp do lampy błyskowej do minimum. Pamięć jest również ograniczona, ponieważ nic nigdy nie jest łatwe.

Kiedy mogę zachować cały element EBML w pamięci, wtedy generowanie go jest łatwe, ponieważ mogę wrócić i wypełnić długość każdego elementu po tym, jak wiem, jaka jest ta długość. Problem polega na tym, co zrobić, gdy nie mogę utrzymać całego elementu w pamięci. Opcje, które widzę to:

  • Napisz, co wiem, a następnie wróć i dodaj długości (najłatwiej, ale dodaje więcej dostępu flash niż chcę)
  • Oblicz długość każdego elementu, zanim zacznę go pisać (stosunkowo łatwo, ale dużo czasu procesora)
  • Przełączaj tryby, gdy moja pamięć się zapełni, aby kontynuować dane, ale tylko w celu obliczenia długości elementów już zarezerwowanych w pamięci. Następnie napisz, co mam w pamięci, i wróć i kontynuuj przetwarzanie danych od miejsca, w którym przestałem. (Moja ulubiona jak dotąd opcja)
  • Podaj elementom maksymalną lub najgorszą długość przypadku, gdy trzeba je napisać, a ich ostateczna długość nie jest jeszcze znana. (Łatwiej niż powyżej, ale może spowodować pożar i marnować miejsce)

Pytanie: Wydaje się, że powinien to być dość powszechny problem, o którym ludzie myśleli. Wiem, że może się to zdarzyć również podczas tworzenia niektórych pakietów danych. Czy brakuje mi lepszej / bardziej powszechnej / bardziej akceptowanej techniki? A może tylko niektóre terminy dotyczące problemu, który mogę wyszukać?

pscheidler
źródło
1
/ sccs działa w ten sposób: zapisuje sumę kontrolną wszystkich bajtów na początku pliku po zakończeniu pisania. Działa świetnie na systemach Unix, które mogą wykonywać potrzebne operacje na plikach atomowo (np. Solaris) i powoduje dziwne sporadyczne problemy na systemach Unix, które nie mogą tego zrobić, np. Linux
gnat

Odpowiedzi:

2

Jeśli nie wiesz, jak długo będzie trwała ładowność, rzadko jest to powodem do zmartwień, nawet jeśli nie pamiętasz pozycji i zapełnisz ją później:

Po prostu zanotuj „nieznany rozmiar”.

Ta funkcja zależy od ładunku składającego się z elementów EBML i następującego elementu, który nie jest prawidłowym elementem potomnym.

Jeśli chcesz, możesz później kanonizować wynikowy EBML offline w dogodny dla siebie sposób, w dowolny sposób, na przykład „bez nieznanych rozmiarów, minimalny rozmiar” lub „minimalny rozmiar, unikaj nieznanych rozmiarów”.


Szczegółowe informacje można znaleźć w wersji roboczej EBML RFC na stronie matroska.org.

Deduplikator
źródło
To jest świetne! Jest to coś, czego nie byłem świadomy i pozwala uniknąć podstawowego problemu, ale nadal chciałbym uzyskać wskazówki na temat dobrego sposobu rozwiązania podstawowego problemu. Wydaje się, że użycie elementu o nieznanym rozmiarze może ograniczyć przyszłą kompatybilność, ponieważ stare oprogramowanie przedwcześnie wychodzi z nowych elementów.
pscheidler,
Potrzebujesz odpowiedniego DTD lub nie możesz tak naprawdę dekodować EBML. Cóż, jeśli wszystkie nieznane elementy mają wymiary, możesz je pominąć, ale czy to wystarczy? Wystarczy przetworzyć dowolny EBML, który chcesz przechowywać offline, jeśli jest.
Deduplicator,
Używamy własnego schematu, który się rozszerzy. Został zaprojektowany ze świadomością, że starsze oprogramowanie może ostatecznie pomijać niektóre dane. Ale to świetna funkcja EBML, o której nie wiedziałam, więc akceptuję odpowiedź.
pscheidler,
0

Jeśli pojedynczy element ze stałą liczbą podelementów jest zbyt duży, być może powinieneś spróbować podzielić go na schemat. Nie znam tego formatu, ale najprawdopodobniej możesz zdefiniować w nim maksymalną długość.

W przypadku sekwencji można spróbować zdefiniować maksymalną liczbę podelementów i „strumień” pozostały w następnym pliku

Dla elementów potencjalnie przekraczających maksymalny rozmiar pamięci przygotuj stos zawierający pary: położenie zarezerwowanej długości elementu i licznik długości. Po popie zapisz bieżący licznik w bieżącym znaczniku i dodaj jego wartość do następnego licznika.

Ogólnie staraj się minimalizować liczbę zbyt dużych elementów

Whoot
źródło
Cóż, prawdopodobnie mógłby to zrobić dla własnych elementów EBML, ale to nadal nie pomaga mu w przypadku elementu nadrzędnego.
Deduplicator
Twój pomysł zadziałałby, ale wolałbym stworzyć system, który może obsługiwać duże elementy, zamiast ograniczać schemat tak, aby omijał duże elementy.
pscheidler,
To rozwiązanie będzie działać również w przypadku dużych elementów, po prostu zachowaj ostrożność przy stosie. A jeśli chodzi o schemat ... pomyśl o nim jako o języku, z którego korzystają twoje aplikacje, jeśli nie możesz sobie poradzić ze złożonym, to drugi powinien się dostosować lub wymagany jest tłumacz. Wielu programistów (przynajmniej C / C ++, których znam) ma tendencję do unikania zmian w schemacie / projekcie, jakby to był pożar, który później skutkuje złym systemem. Jeśli inny komponent nie jest w stanie wyregulować, być może jest on źle rozłożony / zaprojektowany. Jeśli istnieją inne powody, aby się nie zmieniać, prawdopodobnie powinieneś rozważyć użycie innego sprzętu
Whoot
0

KISS i YAGNI.
Wybierz opcję 1, a jeśli stanie się to prawdziwym problemem - tylko wtedy powtórz ją.

Przynajmniej dla podobnych przypadków użycia z podobnymi formatami binarnymi, gdy tylko kilka wartości musiało być wypełnionych w taki sposób, jest to najprostsze / najłatwiejsze / najlepsze rozwiązanie. Jeśli musisz to zrobić na każdym fragmencie danych - może to być wada w architekturze.

Kromster
źródło