Ketika kegagalan sistem terjadi, kita harus melihat ke log terlebih dahulu untuk memutuskan transaksi mana yang harus dilakukan redo atau undo. Oleh karena itu kita harus mencari ke seluruh log sebelum dapat memutuskan untuk melakukan redo atau undo. Hal ini tentunya mempunyai kekurangan:
Proses pencarian akan memakan waktu yang cukup lama.
Seandainya transaksi tersebut harus dilakukan redo, berarti data tersebut harus dimodifikasi dengan nilai yang sebenarnya telah di- update. Meskipun hal tersebut tidak berdampak buruk, tetapi proses pemulihan akan memakan waktu yang lebih lama.
Untuk mengatasi kekurangan tersebut, kita dapat menggunakan sebuah konsep checkpoint. Selama transaksi dijalankan, sistem membuat write-ahead log dan secara periodik menjalankan checkpoint yang dilakukan pada saat:
Seluruh catatan dalam log yang sedang berada di volatile storage dipindahkan ke stable storage.
Seluruh data yang dimodifikasi yang berada di volatile storage dipindahkan ke stable storage.
Log yang menyimpan operasi checkpoint dipindahkan ke stable storage.
Ketika kegagalan terjadi routine pemulihan memeriksa log untuk memutuskan transaksi mana yang terakhir kali melakukan operasi write dan di mana operasi checkpoint terjadi. Dengan menggunakan pencarian mundur dan berhasil menemukan checkpoint dan menemukan catatan operasi start, berarti kita telah menemukan bagian dari transaksi yang akan kita periksa untuk selanjutnya dilakukan redo atau undo. Dengan kata lain, kita tidak harus memeriksa keseluruhan log pada transaksi tersebut. Proses pemulihan dapat dilakukan dengan kondisi:
Jika pada bagian transaksi tersebut ditemukan operasi commit, maka dilakukan redo.
Jika pada bagian transaksi tersebut tidak ditemukan catatan mengenai operasi commit, maka dilakukan undo.
Sebelumnya telah dijelaskan mengenai kasus dimana hanya ada satu buah transaksi yang dapat dieksekusi pada suatu waktu. Sekarang, kita beralih pada kasus dimana ada beberapa transaksi yang harus dieksekusi secara bersamaan. Oleh karena setiap transaksi yang dilakukan bersifat atomik, maka hasil dari eksekusi akhir harus sama dengan hasil eksekusi bila transaksi-transaksi tersebut dijalankan secara berurutan. Meskipun, cara demikian akan memastikan keatomikan dari setiap transaksi, tetapi cara demikian sangat tidak efisien karena adanya pembatasan transaksi-transaksi ketika suatu transaksi dilaksanakan.
Penjadwalan (schedule) merupakan urutan pengeksekusian transaksi-transaksi. Misalkan ada dua buah transaksi T0 dan T1, dimana kedua transaksi ini dieksekusi secara atomik dengan urutan T0 diikuti dengan T1. Sebuah penjadwalan dimana setiap transaksi dieksekusi secara atomik sesuai dengan urutan yang ada disebut penjadwalan serial. Dengan demikian, bila ada n transaksi akan ada n! penjadwalan yang valid.
Tabel 21.1. Contoh Penjadwalan Serial: Penjadwalan T0 diikuti T1
| T0 | T1 |
|---|---|
| Read (A) | |
| Write (A) | |
| Read (B) | |
| Write (B) | |
| Read (A) | |
| Write (A) | |
| Read (B) | |
| Write (B) |
Pada kasus dimana terjadi overlapping (ada transaksi yang dijalankan ketika transaksi lain sedang berjalan) dalam pengeksekusian transaksi-transaksi yang ada, maka penjadwalan tersebut disebut penjadwalan non-serial. Penjadwalan demikian tidak selalu menghasilkan hasil eksekusi yang salah (bisa benar bila hasilnya sama dengan hasil penjadwalan serial). Penjadwalan non-serial yang menghasilkan eksekusi yang benar disebut conflict serializable. Untuk memeriksa sifat serializable dari sebuah penjadwalan, harus diperiksa apakah terdapat konflik antara dua operasi pada transaksi yang berbeda. Konflik terjadi bila:
Ada dua operasi Oi dan Oj pada penjadwalan S dimana keduanya mengakses data yang sama, dan
Setidaknya ada satu operasi yang melakukan
write()
Tabel 21.2. Contoh Penjadwalan Non-Serial ( Concurrent Serializable Schedule)
| T0 | T1 |
|---|---|
| Read (A) | |
| Write (A) | |
| Read (A) | |
| Write (A) | |
| Read (B) | |
| Write (B) | |
| Read (B) | |
| Write (B) |
Pada contoh tersebut,
write(A) pada T0 mengalami konflik dengan
read(A) pada T1 karena keduanya mengakses
data yang sama (A) dan terdapat operasi
write(A). Namun,
write(A) pada T1 tidak mengalami konflik
dengan
read(B) pada T0, karena walaupun ada operasi
write(A) tetapi keduanya mengakses data yang
berbeda. Dalam kasus dimana tidak terjadi konflik antar dua
operasi, maka dapat dilakukan
swapping sehingga terbentuk
penjadwalan baru S' yang urutannya sama dengan penjadwalan
serial. Pada contoh tersebut
swapping yang dapat dilakukan
adalah:
Swap
write(A) pada T1 dengan
read(B) pada T0
Swap
read(B) pada T0 dengan
read(A) pada T1
Swap
write(B) pada T0 dengan
write(A) pada T1
Swap
write(B) pada T0 dengan
read(A) pada T1
Maka, akan didapat penjadwalan baru S' yang merupakan penjadwalan serial. Penjadwalan demikian dinamakan conflict serializable, sedangkan proses penyusunan penjadwalan baru yang serial disebut serialisasi.