Valid XHTML 1.0! Valid CSS!

Lokalne systemy plików

Przemysław K. Rekucki

1. Wstęp

Tematem nimniejszego dokumentu są lokalne systemy plików. W dalszej części będziemy po kolei opisywać różne znane systemy plików. Nasze opisy nie dostarczą dość informacji, by napisać własną implementację, a jedynie by zrozumieć główne rozwiązania danego systemu. Pozwoli nam to ocenić różnice danych systemów, ich wady i zalety.

1.1. Zagadnienia związane z systemami plików

Przed twórcą systemu plików stoi wiele wyzwań:

Dwa pierwsze punkty dotyczą dodatkowych danych jakie będzą obsługiwane w danym systemie plików. Część z nich jest niezbędna samej implementacji, na przykład parametry dysku czy wielkości jednostek alokacji. Większość jednak potrzebna jest użytkownikowi. Słabości tej części są przyczynami wielu komplikacji w przyszłości. Przykładem może być problem z dostarczeniem długich do nazw plików w systemie „Windows 95” , lub brak list praw dostępu w „ext2”

W ewolucji systemów pliów daje się zauważyć zmiane warzności poszczgólnych cech systemu dla projektanta. Początkowo od wygody urzytkownika warzniejsza była prostota implementacji. Systemy optymalizowano by dostarczały jak najwięcej przestrzeni dla danych często kosztem wydajności. Z czasem jak nośniki stawały się tańsze daje się zauwarzyć wzrost nakładów na wydajność. Dopiero ostatnio twórcy są gotowi rezygnować z wydajność na korzyść bezpieczeństwa.

Z przedstawionych powyrzej zwgledów ocena jakości systemu pliku nie może być jednoznaczna. Jak zobaczymy dalej mniej wydajne systemy będą zwykle miały albo mniejszą fragmentacje wewnętrzna albo większe bezpieczeństwo.

1.2. Pojęcia

Dalej bedziemy posługiwać się następującymi pojęciami:

blok dyskowy
Jednostka transmisji z urządzeniem blokowym
klaster
Grupa bloków dyskowych używana jako jednostka alkocji

2. Filesytem FAT

„FAT” był jedynym systemem plików w systemie „DOS” . Podobno początkowo nie posiadał nawet podkatalogów. W miarę współczesny wygląd uzyskał dopiero w „DOS 2.0” .

2.1. Organizacja dysku

Dysk w systemie „DOS” podzielony jest na partycje. Przykład takiego podzału widać na rysunku 2.1.1. Pierwszy sektor dysku nazywa się „Master Boot Sector” w skrócie „MBR” . Pod koniec tego sektora znajduje się opis podziału dysku na strefy, tak zwana tablica partycji. Budowę tablicy partycji przedstawia tabela 2.1.2

image: pics/part.gif
Rysunek 2.1.1: Podział na strefy
Wielkość Bajty Zawartość
1 0 Znacznik aktywności strefy. (0x00 = nieaktywna, 0x80 = aktywna)
1 1 Początek strefy: numer głowicy
2 2-3 Początek strefy: numer cylindra i sektora. Numer sektora koduje pierwsze 5 bitów.
1 4 Rodzaj strefy. Kodowany jest tu rodzaj systemy plików. Dla DOS są to:
0x01 12-bitowy FAT
0x04 16-bitowy FAT dla dysku mniejszego 32MB
0x05 strefa rozszerzona
0x06 16-bitowy FAT dla dużego dysku.
1 5 Koniec strefy: numer głowicy.
2 6-7 Koniec strefy: numer cylindra i sektora. Numer sektora koduje pierwsze 5 bitów.
4 8-11 Początek strefy: adres liniowy liczony w sektorach od początku danego dysku logicznego.
4 12-15 Wielkość partycji w sektorach.
Tabela 2.1.2: Zawartość rekordu opisu strefy

Strefa rozszerzona definiuje dysk logiczny. Strefa taka ma strukturę dokładnie taką samą jak dysk i posiada własną tablicę partycji.

Strefa z systemem plików zamiast tablicy partycji posiada rekord ładujacy, którego zawartość opisuje parametry dysku i strefy. (patrz tabela 2.1.3). Bajty 11-23 definują bloki parametrów BIOS (BPB).

Wielkość Bajty Zawartość
3 0-2 Instrukcja skoku do początku programu ładującego
8 3-10 Nazwa systemu (w ASCII)
2 11-12 Wielkość sektorów w bajtach
1 13 Liczba sektorów w jednostce alokacji JAP
2 14-15 Liczba sektorów zarezerwowanych na początku dysku. Jest przesunięciem tablicy FAT w sektorach od początku dysku logicznego (zwykle 1).
1 16 Liczba kopii FAT
2 17-18 Maksymalna liczba plików w katalogu głównym
2 19-20 Całkowita liczba sektorów na dysku
1 21 Bajt identyfikacji nośnika
2 22-23 Liczba sektorów zajętych przez FAT
2 24-25 Liczba sektorów na ścieżce
2 26-27 Liczba głowic dysku
2 28-29 Liczba sektorów ukrytych
Tabela 2.1.3: Informacje wpisane w rekordzie ładującym

2.2. Tablica rozmieszczenia plików

Jednostką alokacji jest klaster, który składa się z całkowitej liczby bloków dyskowych.

„File Allocation Table” jest strukturą opisującą zarówno kolejność klastrów w plikach, jak i wolne klastry. Początkowo była to tablica liczb 12-bitowych, czyli dwa elementy mieściły się w dwóch bajtach. Później wraz ze wzrostem rozmiarów dysków wprowadzono tam liczby 16- i 32-bitowe.

Libczba znajdująca się w tablicy FAT12 miała następujące znaczenie:

0x000 Indeks w tablicy jest numerem wolnego klastra
0xFF7 Dany klaster jest uszkodzony i nie powinien być alokowany
0xFF8-0xFFF Oznacza że dany klaster jest ostatnim klastrem pliku do którego należy
inny Jest numerem następnego klastra pliku, do którego należy nasz blok.

W wersji 16-bitowej 0x000 stało się 0x0000, 0xFF7 stało się 0xFFF7, idt. Analogicznie dla wersji 32-bitowej 0x000 stało się 0x00000000, 0xFF7 stało się 0xFFFFFFF7, 0xFF8 przeszło na 0xFFFFFFF8, itd.

Na rysunku 2.2.1 pokazany jest fragment przykładowego FAT. Zostały tam zaznaczone wpisy pliku zaczynającego się od klastra 0x025, a kończącego się na klastrze 0x023.

image: pics/fat1.gif
Rysunek 2.2.1: Fragment FAT

Fakty:

2.3. Katalog

Katalog jest zwykłą tablicą rekordów zgodnych z tabelką. 2.3.1

Wielkość Bajty Zawartość
8 0-7 Nazwa pliku
3 8-10 Rozszerzenie pliku
1 11 Atrybuty
10 12-21 Zarezerwowane
2 22-23 Czas utworzenia lub aktualizacji pliku
2 24-25 Data utworzenia lub aktualizacji pliku
2 26-27 Numer pierwszego klastra (JAP)
4 28-31 Wielkość
Tabela 2.3.1: Wpis w katalogu

Bity atrybutów:

0
Plik tylko do odczytu (readonly)
1
Plik ukryty (hidden)
2
Plik systemowy
3
Etykieta dysku
4
Podkatalog
5
Plik archiwizowalny
6,7
Nie wykorzystywane

Pierwszy znak nazwy pliku ma szczególne znaczenie:

0x00
Wpis pusty
0xE5
Wpis skasowanego rekordu może być nadpisany przy tworzeniu nowego pliku
0x05
Jako że 0xE5 jest dopuszczalnym znakiem nazwy pliku, to nie może wystąpić jawnie -- zamiast tego umieszczany jest kod 0x05
0x2E
Jest to znak kropki, jeśli następnym bajtem jest też kropka, to jest to wpis wskaźnika do katalogu rodzica. Dla katologu głównego adres ten jest równy 0.

Wraz z pojawieniem się „Windows 95” , FAT zyskał długie nazwy plików. Odbyło się to przy zachowaniu kompatybilności z systemem DOS. Wykorzystano fakt, że nie wyświetla się wpisów etykiet dysku z wyjątkiem pierwszego takiego wpisu w katalogu głównym.

Własności wpisu długiej nazwy:

Wielkość Bajty Zawartość
1 0 ID
10 1-10 5 pierwszych znaków
1 11 Atrybuty = 0xFF
1 12 Zarezerwowane
1 13 Suma kontrolna krótkiej nazwy, której dotyczy ten opis. Jeśli program nie znający długich nazw dokona zmian, powinno to być wykryte. Nieaktualne wpisy powinny wtedy zostać anulowane.
12 14-25 6 liter
2 26-27 Numer JAP. Powinno być 0
4 28-31 2 litery
Tabela 2.3.2: Wpis długiej nazwy

Jak widać w rekordzie może być maksymalnie 13 liter. Nie używane litery ustawia się na 0.

Dodatkowych wyjaśnień wymaga pole „ID” .

3. Od SytemV do Ext3

3.1. SystemV

Budowa dysku jest bardzo prosta:

Blok ładujący Superblok Bloki i-węzłów Bloki danych
Tabela 3.1.1: Struktura dysku SystemV

Bloki i-węzłów to tablica stałej wielkości rekordów opisujących i-węzeł. Przestrzeń ta ma stałą wielkość, czyli dana jest z góry określona maksymalna liczba plików. Ta zła własność została zachowana i chrakteryzuje również system „ext3” .

Alokacja i-węzłów

Jest bardzo prosta. Korzysta się tu ze zoptymalizowanego przeszukiwania liniowego. Ulepszenie polega na tym, że w superbloku znajduje się tablica numerów wolnych i-węzłów.

image: pics/inode1.gif
Początkowo lista jest wypełniona. Na alokację czeka węzeł 105.


image: pics/inode2.gif
Przydzielono węzeł 105. Teraz na alokację czeka węzeł 106.


image: pics/inode3.gif
Stan po kilku alokacjach.


image: pics/inode4.gif
Zwolniono węzeł o numerze 106. Ponieważ jego numer jest mniejszy od 122, to ostatni wyraz listy zostaje ustawiony na 106.


image: pics/inode4.gif
Zwolniono węzeł o numerze 115. Ponieważ jego numer jest większy od 106, to nic sie nie dzieje.


image: pics/inode5.gif
Zaalokowano węzeł (120)


image: pics/inode6.gif
Zaalokowano węzeł (121)


image: pics/inode7.gif
Zaalokowano węzeł (106). Wykonano operację refill zaczynając poszukiwania wolnych węzłów od węzła (107).


Rysunek 3.1.1: Działanie alokatora i-węzłów

Zastosowany algorytm był wystarczająco wydajny. Alokacje i-węzłów są stosunkowo rzadkie w porównaniu z alokacjami bloków dyskowych. Kosztowna operacja uzupełniania listy wykonywana jest rzadko i w praktyce wykonuje się szybciej niż w pesymistycznym przypadku, ponieważ węzły alokowane w tym samym czasie zazwyczaj są również zwalniane w bliskich odcinkach czasu.

Alokacja bloków

Do zarządzania wolnymi blokami używa się list wolnych bloków. Początek listy znajduje się w superbloku. Każdy węzeł listy zawiera tablice wolnych bloków ze wskaźnikiem na wolny blok zawierający następny węzeł.

image: pics/blok1.gif
Rysunek 3.1.1: Przykładowa lista wolnych bloków

Na przedstawionym przykładzie kolejne alokacje będą dawać bloki: 420, 508, ..., 165, 205, 101, 100, ...

Alokacja bloku 100 przebiega w spoób wyjątkowy, ponieważ blok ten jest następnikiem superbloku w liście i nie może być on natychmiastowo użyty. Najpierw jego zawartość zostaje przekopiowana w miejsce pustej tablicy w superbloku (patrz rysunek).

image: pics/blok2.gif
Rysunek 3.1.2: Stan po alokacji bloku 100

Zwalnianie bloku polega na dopisaniu bloku na koniec tablicy znajdującej się w superbloku. Jeśli tablica jest pełna i nastąpi zwolnienie bloku, powiedzmy numer 291, to zawartość superbloku zostanie skopiowana do bloku 291, a tablica wolnych bloków będzie posiadać teraz tylko jeden wpis 291.

image: pics/blok3.gif
Rysunek 3.1.3: Stan po dealokacji bloku 291

Alokator ten jest stosunkowo szybki, ma jednak bardzo poważną wadę: bloki w liście nie są ułożone w żaden rozsądny sposób, przez co pliki ulegają wysokiej fragmentacji.

Struktura i-węzła

Adresowanie bloków w i-węźle przebiega przez strukture teblicową.

Standardowe bloki miały po 1kb.

3.2. Minix

„Linux” pisany był pod systemem „Minix” i początkowo jako swój system plików używał systemu z Minix-a. System ten jest podobny do SystemV. Podobnie jak on, ma z góry ustaloną liczbę i-węzłów. Dodatkowo nie posiada bloków potrójnie pośrednich, ponieważ bloki numerowane są liczbami 16-bitowymi, dzieki czemu w bloku pośrednim mieści się 512 adesów. Pozwala to zmniejszyć liczbę bloków adresujących.

Blok ładujący Superblok Bitmapa i-węzłow Bloki i-węzłów Bitmapa bloków Bloki danych
Tabela 3.2.1: Struktura dysku Minix

Wprowadzanie map bitowych przyśpiesza alokację, ponieważ mapy są dostatecznie małe, by móc przechowywać je w pamięci. Mapy ułatwiają również walkę z fragmentacją.

Wpisy katalogowe były stałej wiekości, ustalonej z góry i zapisanej w superbloku.

Własności:

Implementacja Minix-a z jądra 1.0 rozpatrywała adresowanie takie, jak przy SystemV (32-bitowe adresowanie z odwołaniem potrójnie pośrednim).

3.3. ext2

Ograniczenia Minix-a spowodowały, że rozpoczęto prace nad jego modyfikacjami. Jedną z nich, choć nie jedyną, była implementacja systemu „ext2” , który rozwiązuje większość problemów z Minix-a. Posiada zmienną wielkość wpisu w strukturze katalogu, dzięki czemu nie występuje problem z długimi nazwami. Jedynym ograniczeniem jest to, że wpis musi się mieścić w pojedyńczym bloku dyskowym.

Blok ładujący Grupa 1 Grupa 2 ........ Grupa n
Tabela 3.3.1: Struktura dysku Ext2
Super blok opis grupy mapa bloków mapa i-węzłow i-węzły bloki
Tabela 3.3.2: Struktura Grupy

W opisie grupy znajdują się informacje o pozycjach dyskowych pozostałych elementów grupy.

Większość informacji o tym systemie plików była podana na wykładzie, dlatego nie będę tu przedstawiać więcej detali. Zamiast tego omówię niektóre rozszerzenia tego systemu.

Indeksy katalogów

Standardowa implementacja ext2 używa katalogów w postaci niezindeksowanej. Przez co koszt n wstawień do katalogu wynosi O(n^2)

Rozpoczęto, i zadaje się że nadal trwa, wiele projektów których celem jest dodanie B-drzew do ext2. Z dostępnych rozwiązań interesująca wydaje się implementacja indeksowanych katalogów wykonana przez Daniela Phillipsa.

HTree

image: pics/htree1.gif
Rysunek 3.3.1: Schemat struktury HTree

Operacja wyszukiwania:

W praktyce kolizje zdarzają się wyjątkowo rzadko.

Operacja dodawania nazwy jest stosunkowo prosta. Najpierw znajduje się blok, w którym nazwa mogła by występować, zgodnie z tym co jest napisane powyżej. Jeśli w bloku jest wolne miejsce, to można od razu dodać nowy wpis.

Jeśli brakuje miejsca, trzeba wykonać podział bloku tak, jak ma to miejsce przy zwykłych B-drzewach.

Journaling

ext2 z journalingiem nazywany jest ext3. W przciwieństwie do innych implementacji systemu plików z tranzakcjami oprócz journalingu metadanych posiada on możliwość logowania zmian bloków.

Szczegóły tego rozszerzenia są omówione w następnym rozdziale.

4. EXT3 i JBD

W rozdziale tym zostanie omówiona architektura systemu plików „ext3” . Zostaną omówione co ciekawsze detale szegóły z implementacji, których celem będzie nauczenie metod stosowania i implementacji „journalingu” we własnych aplikacjach.

4.1. Własności transakcji

Dyskusje zaczniemy od tego czym są transakcje. Sama koncepcja pochodzi z baz danych, w których ważne okazało się zachowanie spójności danych w trakcie złożonych operacji.

Często jako przykład użyteczności transakcji podaje się system bankowy. Na rysunku 4.1.1 podany został bardzo prosty przykład sytuacji gdy brak synchronizacji prowadzi do błędów.

Wpłata $10 na konto x1 Wpłata $5 na konto x2
x1 := <zawartość konta $500> $500
x2 := <zawartość konta $500> $500
x1 := x1 + $10 $510
x2 := x2 + $5 $505
<konto> := x2 $505
<konto> := x1 $510
Rysunek 4.1.1: Przykład konfliktu równoczesna wpłata na to samo konto

Podstawowe własności transakcji to:

Atomowość
Transakcja wykonuje się w całości lub wcale.
Spójność
Po wykonaniu stan systemu spełnia więzy spójności. Dane tworzą poprawną całość.
Izolacja
Inne wykonywane transakcje nie mają wpływu na siebie.
Trwałość
Zatwierdzona transakcja zostanie wykonana na trwałe i jej wynik nie zostanie utracony.

Systemy plików są bardzo szczególnym rodzajem baz danych. Transakcje wykonywane w typowych systemach plików są łatwiejsze w implementacji niż w ogólnym bazodanowym przypadku.

Od systemu z transakcjami oczekujemy że po nagłej awarii i ponownym uruchomieniu system znajdzie się poprawnym z punktu widzenia jego budowy stanie. Oczekujemy że każda rozpoczęta transakcja albo będzie całkowicie zakończona albo całkowicie anulowana.

Na przykład gdy kasujemy plik mogą być wykonywane następujące operacje:

  1. Szuka się wpisu pliku w strukturze katalogowej
  2. Pobiera się numer i-węzła we wpisie.
  3. Z bloku z wpisem usuwa się znaleziony rekord
  4. Odczytuje się blok z opisem i-węzła. Zmniejszamy i sprawdzamy licznik referencji.
  5. Jeśli licznik referencji w i-węźle jest 0 oraz żaden proces nie ma do niego referencji (dodatkowy licznik z VFS). To zwalniamy zaalokowane bloki. Wymaga to szeregu odczytów struktury indeksowej i modyfikacji szeregu bloków w mapie bitowej wolnych bloków.

Teraz jeśli awaria nastąpi w punkcie 4 zanim zapiszemy blok ze zmniejszonym licznikiem. Na dysku będą znajdować się zaalokowane bloki do których nie będzie żadnej referencji. By móc stwierdzić że wartość licznika i i-węźle jest fałszywa trzeba przejrzeć wszystkie wpisy katalogowe. Gdyby awaria nastąpiła nastąpiła podczas zwalniania bloków, to by dokończyć tą operacje trzeba przejrzeć wszystkie struktury indeksowe. Tym samym widać że w standardowym systemie plików start systemu po awarii łączy się z pełną rekonstrukcją wszystkich metadanych.

Głównym celem wprowadzenia journalingu jest uzyskanie atomowości tego typu operacji.

4.2. Transakcja w systemach plików

Systemy plików charakteryzują następujące własności:

W systemie „ext3” podstawową operacją jest zapis bloku. Pojedyncza transakcje jest tu sekwencją operacji zapisu określonych danych w określonym miejscu. Takie podejście powoduje że:

Ostatni punkt jest bardzo ważną i wydajną optymalizacją.

4.3. JBD

Obsługa journalingu została wyjęta do oddzielnego modułu Journaling Block Device (JBD).

Pojęcia

Punkt kontrolny
Tranaskcje są łączone w grupy. Zmknięcie grupy nazywany punktem kontrolnym
Deskryptor punktu kontrolnego
Opis, w logu, operacji jakie należy wykonać by system plików osiągnoł punkt kontrolny. By wykonać te operacje trzeba jeszcze mieć zawartość bloków danych.

Typy danych

journal_t
Opisuje całkowity stan danego logu. Zarządza rozmieszczeniem deskryptorów transakcji w logu, oraz synchronizacją z dyskiem.
handle_t
Znacznik tworzonej transakcji. Operacje wykonywane zostaną wykonane w całości lub wcale. Mogą się one wykonać tylko wtedy gdy operacje starszych znaczników też zostały wykonane.

Funkcje

journal_t * journal_init_dev(kdev_t dev, kdev_t fs_dev, int start, int len, int bsize);
journal_t * journal_init_inode (struct inode *);

Funkcje te zakładają log odpowiednio na: spójnym obszarze urządzenia blokowego, w podanym i-węźle

int journal_flush (journal_t *);

Zapisuje wszystkie dane do logu i na dysk. Używane przy przemontowywaniu w tryb tylko do odczytu.

void journal_lock_updates (journal_t *);

Blokuje wszystkie przyszłe tranzakcje w chwili rozpoczęcia. Blokuje do chwili aż aktualnie trwające tranzakcje się nie zakończą.

void journal_unlock_updates (journal_t *);

Zdejmuje blokadę na nowe tranzakcje

int journal_create(journal_t *);

Tworzy nowy log.

int journal_load(journal_t *journal);

Inicjuje struktury danych dla istniejącego już logu

void journal_destroy(journal_t *);

Zwalnia strukturę. Przeciwieństwo „init”

int journal_recover(journal_t *journal);

Wznawia log po awarii. Najpierw znajduje się deskryptor transakcji o najnowszym numerze. Następnie

handle_t *journal_start(journal_t *, int nblocks);
handle_t *journal_try_start(journal_t *, int nblocks)

Rozpoczyna nową tranzakcje. Wartość „nblocks” określa ile maksymalnie bloków będzie modyfikować. Funkcja „journal_start” czeka aż w logu będzie dostatecznie dużo wolnego miejsca

int journal_restart (handle_t *, int nblocks);

Pozwala w tym samym znaczniku otworzyć nową tranzakcje

int journal_extend (handle_t *, int nblocks);

Próbuje zwiększyć maksymalną liczbe modyfikowanych bloków. Ponieważ nie ma anulowania transakcji trzeba sobie poradzić nawet wtedy gdyby zwiększenie byłoby niemożliwe

int journal_get_write_access (handle_t *, struct buffer_head *);

Poinformowanie że będziemy pisać do danego bufora. Zgodnie z tym co było mówione jeśli ta tranzakcje łączona jest z inną nie trzeba nic robić. Natomiast jeśli rozpoczęto zapis lub realizacje transakcji z użyciem danego bufora to trzeba wykonać kopie roboczą.

int journal_get_create_access (handle_t *, struct buffer_head *);

Poinformowanie o dostępie do nowego bloku. Sprawdza się czy bufor jest używany przez inną tranzakcje (to się nie powinno zdarzyć).

int journal_get_undo_access (handle_t *, struct buffer_head *);

Poinformowanie o zwolnieniu bufora. Dzieki temu nie trzba trzymać jego kopii.

int journal_dirty_data (handle_t *, struct buffer_head *, int async);

Dodanie do transakcji operacji modyfikacji bloku. Podczas zapisu bufor zostanie umieszczony w logu. „Linux” pozwala na efektywne zpisywanie bufora w innym miejscu niż docelowe. Robi się to tworząć nowy nagłówek bufora z innym adresem ale tym samym wskaźnikiem do danych.

int journal_dirty_metadata (handle_t *, struct buffer_head *);

To co wyżej tylko dla metadanych. „ext3” może pracować w różnych trybach. Journaling danych jest opcjonalny, efektywniej jest zapisywać tylko metadane. Jest ich mniej więc tranzakcje na nich lepiej się łączą w gupy.

int journal_stop(handle_t *);

Zamknięcie tranzakcji. Nie jest ona wykonywana natychmiast (może że jest ustawiony tryb synchroniczny), przez co może być łączona z kolejną.

Algorytm journal_commit_transation

Celem jest zsynchronizowanie listy operacji z logiem. Funkcja wołana jest z demona synchronizującego „kjournald”

  1. Blokujemy otwieranie nowych transakcji
  2. Czekamy na zakończenie trwających transakcji
  3. Synchronizujeny super blok logu. Zapisując nowy numer ostatniej transakcji, oraz kod błędu zapamientany w journal_t.
  4. Kasujemy bufory zapisanych punktów kontrolnych.
  5. Zapisujemy bloki danych
  6. Zapisujemy metadane logu
  7. Zapisujemy znacznik końca transakcji

Później funkcja „log_do_checkpoint” może nas doprowadzić do stanu w którym bufory znajdą się we właściwych miejscach. Działanie polega na wykonywani operacji z listy.

Etapy zapisywania danych

By zakończyć transakcje trzeba przejść następujące etapy:

  1. Zamykamy tranzakcje od tego momentu wszystkie operacje są w nowej tranzakcji.
  2. Wątek zapisu do logu sprowadza transakcje na dysk.
  3. Czekamy aż czekające na wykonanie zmiany zostaną zapisane w logu.
  4. Zapisujemy nowe wartości nagłówków logu
  5. Następnie gdy bloki są synchronizowane z właściwymi miejscami na dysku (dopiero gdy jest to konieczne). Nagrane bloki są zanaczane jako wolne. Gdy cały checkpoint zostanie osiągnięty to zajmowane przez niego miejsce w logu może być zwolnione

4.4. Podsumowanie