π What Is a Log?
A log is a sequence of records stored on a stable storage (disk) that keeps track of:
Transaction start
Data items modified
Old and new values
Transaction commit or abort
Log-Based Recovery Methods are essential techniques in DBMS for maintaining Atomicity and Durabilityβtwo key ACID properties of transactions. These methods use a log file to track all the changes made by transactions, ensuring that the database can recover from crashes or failures.
π§Ύ Format of Log Records:

π Two Main Log-Based Recovery Methods:
1. Deferred Update (Deferred Write)
β Updates are made to the database only after the transaction commits.
β If the transaction fails or the system crashes before commit, no change is made to the DB.
π§ Steps:
On
START, log the event:<START T1>On update, log only:
<T1, X, old, new>On
COMMIT, apply the updates to DB and write<COMMIT T1>
π Recovery:
Redo transactions that have <COMMIT>
Ignore transactions without <COMMIT>
β Pros:
Simple recovery β no need to undo
Ideal for systems that commit infrequently
β Cons:
Delayed performance due to postponed writes
2. Immediate Update
β Updates are made to the database before the transaction commits.
β So if a crash occurs, we may need to UNDO the changes.
π§ Steps:
On
START, log:<START T1>On update, log:
<T1, X, old, new>and apply change to DBOn
COMMIT, log:<COMMIT T1>
π Recovery:
UNDO uncommitted transactions (using old values)
REDO committed transactions (using new values)
β Pros:
Faster writes
Suitable for real-time updates
β Cons:
Complex recovery β need both UNDO and REDO operations
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Deferred vs Immediate Update β Try It Yourself</title>
<style>
.infographic-recoverymethods {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--good: #16a34a;
--good-soft: #dcfce7;
--bad: #dc2626;
--bad-soft: #fee2e2;
--warn: #b45309;
--warn-soft: #fef3c7;
--on-accent: #ffffff;
--display-font: Georgia, 'Iowan Old Style', serif;
--body-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--mono-font: 'SF Mono', Consolas, monospace;
background: var(--paper);
color: var(--ink);
font-family: var(--body-font);
max-width: 800px;
margin: 0 auto;
box-sizing: border-box;
overflow-x: hidden;
}
.infographic-recoverymethods[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
--good: #4ade80;
--good-soft: #123420;
--bad: #f87171;
--bad-soft: #3a1414;
--warn: #fbbf24;
--warn-soft: #3a2f0e;
--on-accent: #101418;
}
.infographic-recoverymethods * { box-sizing: border-box; }
.rm-head { text-align: center; margin-bottom: 0.25rem; }
.rm-head h2 { font-family: var(--display-font); font-size: 1.8rem; margin: 0 0 0.5rem; }
.rm-head p { color: var(--ink-soft); font-size: 0.95rem; margin: 0 auto; max-width: 600px; line-height: 1.55; }
.rm-tabs { display: flex; gap: 0.5rem; margin-top: 1.5rem; flex-wrap: wrap; justify-content: center; }
.rm-tab-btn { font: inherit; font-size: 0.85rem; background: var(--paper-alt); color: var(--ink-soft); border: 1px solid var(--line); border-radius: 999px; padding: 0.5rem 1rem; cursor: pointer; }
.rm-tab-btn.is-active { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.rm-panel { display: none; background: var(--paper-alt); border: 1px solid var(--line); border-radius: 10px; padding: 1.25rem; margin-top: 1rem; }
.rm-panel.is-active { display: block; animation: rm-fade-in 0.35s ease; }
@keyframes rm-fade-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
.rm-panel-title { font-family: var(--display-font); font-size: 1.1rem; margin: 0 0 0.4rem; }
.rm-panel-desc { font-size: 0.85rem; color: var(--ink-soft); line-height: 1.5; margin: 0 0 0.9rem; }
.rm-chip-row { display: flex; gap: 0.5rem; flex-wrap: wrap; margin: 0 0 1rem; }
.rm-chip { font-size: 0.72rem; background: var(--paper); border: 1px solid var(--line); border-radius: 999px; padding: 0.25rem 0.6rem; color: var(--ink-soft); }
.rm-chip.is-good { color: var(--good); border-color: var(--good); }
.rm-chip.is-bad { color: var(--bad); border-color: var(--bad); }
.rm-state-row { display: flex; gap: 1rem; flex-wrap: wrap; margin-bottom: 1rem; }
.rm-state-box { flex: 1 1 140px; background: var(--paper); border: 1px solid var(--line); border-radius: 8px; padding: 0.8rem; text-align: center; }
.rm-state-label { font-size: 0.72rem; color: var(--ink-soft); text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 0.3rem; }
.rm-state-value { font-size: 1.4rem; font-weight: 700; font-family: var(--mono-font); color: var(--accent); transition: color 0.3s; }
.rm-state-value.is-changing { color: var(--warn); }
.rm-log-scroll { overflow-x: auto; }
.rm-log { background: var(--ink); color: #d4e2ff; border-radius: 8px; padding: 0.8rem 1rem; font-family: var(--mono-font); font-size: 0.8rem; line-height: 1.7; min-height: 2.5rem; display: inline-block; min-width: 100%; }
.infographic-recoverymethods[data-theme="dark"] .rm-log { background: #05070a; }
.rm-log-line { opacity: 0; animation: rm-line-in 0.3s ease forwards; }
@keyframes rm-line-in { to { opacity: 1; } }
.rm-log-placeholder { color: #7c8aa8; font-style: italic; }
.rm-log-commit { color: #86efac; }
.rm-log-crash { color: #fca5a5; }
.rm-run-row { display: flex; justify-content: center; gap: 0.5rem; margin-top: 1rem; flex-wrap: wrap; }
.rm-run-btn { font: inherit; font-size: 0.82rem; background: var(--accent); color: var(--on-accent); border: none; border-radius: 7px; padding: 0.55rem 1rem; cursor: pointer; }
.rm-run-btn:hover { opacity: 0.9; }
.rm-run-btn:disabled { opacity: 0.45; cursor: not-allowed; }
.rm-run-btn.is-danger { background: var(--bad); }
.rm-run-btn.is-good { background: var(--good); }
.rm-run-btn.is-secondary { background: var(--paper); color: var(--ink); border: 1px solid var(--line); }
.rm-msg { margin-top: 0.9rem; padding: 0.65rem 0.85rem; border-radius: 8px; font-size: 0.83rem; line-height: 1.5; display: none; }
.rm-msg.is-visible { display: block; }
.rm-msg.st-good { background: var(--good-soft); color: var(--good); }
.rm-msg.st-bad { background: var(--bad-soft); color: var(--bad); }
.rm-msg.st-warn { background: var(--warn-soft); color: var(--warn); }
@media (prefers-reduced-motion: reduce) {
.infographic-recoverymethods *, .infographic-recoverymethods *::before, .infographic-recoverymethods *::after {
transition-duration: 0.001ms !important; animation-duration: 0.001ms !important;
}
}
</style>
</head>
<body>
<div class="infographic-recoverymethods" id="recoverymethods">
<div class="rm-head">
<h2>Log-Based Recovery: Deferred vs Immediate Update</h2>
<p>Same transaction β update X from 10 to 20 β handled two different ways. Try crashing before commit in each and see what recovery actually has to do.</p>
</div>
<div class="rm-tabs">
<button class="rm-tab-btn is-active" data-tab="deferred" type="button">π Deferred Update</button>
<button class="rm-tab-btn" data-tab="immediate" type="button">β‘ Immediate Update</button>
</div>
<!-- TAB 1: Deferred Update -->
<div class="rm-panel is-active" id="panel-deferred">
<p class="rm-panel-title">Deferred Update</p>
<p class="rm-panel-desc">Updates are written to the log immediately, but only applied to the actual database after COMMIT.</p>
<div class="rm-chip-row">
<span class="rm-chip is-good">β
Simple recovery β no UNDO needed</span>
<span class="rm-chip is-bad">β Writes are delayed</span>
</div>
<div class="rm-state-row">
<div class="rm-state-box"><div class="rm-state-label">Database value of X</div><div class="rm-state-value" id="defDbValue">10</div></div>
</div>
<div class="rm-log-scroll">
<div class="rm-log" id="defLog"><span class="rm-log-placeholder">Click START to begin the transaction...</span></div>
</div>
<div class="rm-run-row">
<button class="rm-run-btn" id="defStartBtn" type="button">βΆ START T1</button>
<button class="rm-run-btn" id="defUpdateBtn" type="button" disabled>βΆ Update X: 10 β 20</button>
<button class="rm-run-btn is-good" id="defCommitBtn" type="button" disabled>βοΈ COMMIT T1</button>
<button class="rm-run-btn is-danger" id="defCrashBtn" type="button" disabled>π₯ Crash now</button>
<button class="rm-run-btn is-secondary" id="defReset" type="button">βΊ Reset</button>
</div>
<p class="rm-msg" id="defMsg"></p>
</div>
<!-- TAB 2: Immediate Update -->
<div class="rm-panel" id="panel-immediate">
<p class="rm-panel-title">Immediate Update</p>
<p class="rm-panel-desc">Updates are applied to the actual database as soon as they happen β before the transaction has committed.</p>
<div class="rm-chip-row">
<span class="rm-chip is-good">β
Faster writes</span>
<span class="rm-chip is-bad">β Recovery needs UNDO and REDO</span>
</div>
<div class="rm-state-row">
<div class="rm-state-box"><div class="rm-state-label">Database value of X</div><div class="rm-state-value" id="immDbValue">10</div></div>
</div>
<div class="rm-log-scroll">
<div class="rm-log" id="immLog"><span class="rm-log-placeholder">Click START to begin the transaction...</span></div>
</div>
<div class="rm-run-row">
<button class="rm-run-btn" id="immStartBtn" type="button">βΆ START T1</button>
<button class="rm-run-btn" id="immUpdateBtn" type="button" disabled>βΆ Update X: 10 β 20 (apply now)</button>
<button class="rm-run-btn is-good" id="immCommitBtn" type="button" disabled>βοΈ COMMIT T1</button>
<button class="rm-run-btn is-danger" id="immCrashBtn" type="button" disabled>π₯ Crash now</button>
<button class="rm-run-btn is-secondary" id="immReset" type="button">βΊ Reset</button>
</div>
<p class="rm-msg" id="immMsg"></p>
</div>
</div>
<script>
(function () {
const wrapper = document.getElementById('recoverymethods');
const bodyAttr = document.body.getAttribute('data-darkmode');
let dark;
if (bodyAttr === 'true') {
dark = true;
} else if (bodyAttr === 'false') {
dark = false;
} else {
const match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
})();
/* tabs */
(function () {
document.querySelectorAll('.rm-tab-btn').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.rm-tab-btn').forEach(b => b.classList.remove('is-active'));
document.querySelectorAll('.rm-panel').forEach(p => p.classList.remove('is-active'));
btn.classList.add('is-active');
document.getElementById('panel-' + btn.dataset.tab).classList.add('is-active');
});
});
})();
function appendLog(logEl, html) {
if (logEl.querySelector('.rm-log-placeholder')) logEl.innerHTML = '';
const line = document.createElement('div');
line.className = 'rm-log-line';
line.innerHTML = html;
logEl.appendChild(line);
}
function showMsg(id, text, kind) {
const el = document.getElementById(id);
el.textContent = text;
el.className = 'rm-msg is-visible st-' + kind;
}
/* TAB 1: Deferred Update */
(function () {
const log = document.getElementById('defLog');
const dbValueEl = document.getElementById('defDbValue');
const startBtn = document.getElementById('defStartBtn');
const updateBtn = document.getElementById('defUpdateBtn');
const commitBtn = document.getElementById('defCommitBtn');
const crashBtn = document.getElementById('defCrashBtn');
startBtn.addEventListener('click', () => {
startBtn.disabled = true;
appendLog(log, '<START T1>');
updateBtn.disabled = false;
crashBtn.disabled = false;
});
updateBtn.addEventListener('click', () => {
updateBtn.disabled = true;
appendLog(log, '<T1, X, 10, 20> <span style="color:#9a968c;">β logged only, DB untouched</span>');
commitBtn.disabled = false;
showMsg('defMsg', 'The change exists only in the log right now β X in the actual database is still 10.', 'warn');
});
commitBtn.addEventListener('click', () => {
commitBtn.disabled = true;
crashBtn.disabled = true;
appendLog(log, '<span class="rm-log-commit"><COMMIT T1></span>');
dbValueEl.textContent = '20';
dbValueEl.classList.add('is-changing');
setTimeout(() => dbValueEl.classList.remove('is-changing'), 600);
showMsg('defMsg', 'βοΈ Only now, at COMMIT, does the database actually get updated to 20.', 'good');
});
crashBtn.addEventListener('click', () => {
crashBtn.disabled = true;
updateBtn.disabled = true;
commitBtn.disabled = true;
appendLog(log, '<span class="rm-log-crash">π₯ CRASH</span>');
showMsg('defMsg', 'π Recovery scans the log: no <COMMIT T1> found, so T1 is ignored entirely. Since the database was never touched, there is nothing to undo β X is still safely 10.', 'bad');
});
document.getElementById('defReset').addEventListener('click', () => {
log.innerHTML = '<span class="rm-log-placeholder">Click START to begin the transaction...</span>';
dbValueEl.textContent = '10';
startBtn.disabled = false;
updateBtn.disabled = true;
commitBtn.disabled = true;
crashBtn.disabled = true;
document.getElementById('defMsg').classList.remove('is-visible');
});
})();
/* TAB 2: Immediate Update */
(function () {
const log = document.getElementById('immLog');
const dbValueEl = document.getElementById('immDbValue');
const startBtn = document.getElementById('immStartBtn');
const updateBtn = document.getElementById('immUpdateBtn');
const commitBtn = document.getElementById('immCommitBtn');
const crashBtn = document.getElementById('immCrashBtn');
startBtn.addEventListener('click', () => {
startBtn.disabled = true;
appendLog(log, '<START T1>');
updateBtn.disabled = false;
crashBtn.disabled = false;
});
updateBtn.addEventListener('click', () => {
updateBtn.disabled = true;
appendLog(log, '<T1, X, 10, 20> <span style="color:#9a968c;">β logged AND applied to DB</span>');
dbValueEl.textContent = '20';
dbValueEl.classList.add('is-changing');
setTimeout(() => dbValueEl.classList.remove('is-changing'), 600);
commitBtn.disabled = false;
showMsg('immMsg', 'β οΈ The database is already showing 20 β but T1 hasn\u2019t committed yet. If something goes wrong now, this change has to be undone.', 'warn');
});
commitBtn.addEventListener('click', () => {
commitBtn.disabled = true;
crashBtn.disabled = true;
appendLog(log, '<span class="rm-log-commit"><COMMIT T1></span>');
showMsg('immMsg', 'βοΈ Now that T1 has committed, 20 is permanent. A crash from here on would just REDO using the logged new value β no undo needed.', 'good');
});
crashBtn.addEventListener('click', () => {
crashBtn.disabled = true;
updateBtn.disabled = true;
commitBtn.disabled = true;
appendLog(log, '<span class="rm-log-crash">π₯ CRASH</span>');
const wasUpdated = dbValueEl.textContent === '20';
if (wasUpdated) {
showMsg('immMsg', 'π Recovery scans the log: no <COMMIT T1> found, but the DB was already changed to 20. It must UNDO using the old value (10) from the log entry.', 'bad');
setTimeout(() => {
dbValueEl.textContent = '10';
dbValueEl.classList.add('is-changing');
setTimeout(() => dbValueEl.classList.remove('is-changing'), 600);
}, 900);
} else {
showMsg('immMsg', 'π Recovery scans the log: no <COMMIT T1> found, and the update hadn\u2019t even been applied yet β nothing to undo.', 'bad');
}
});
document.getElementById('immReset').addEventListener('click', () => {
log.innerHTML = '<span class="rm-log-placeholder">Click START to begin the transaction...</span>';
dbValueEl.textContent = '10';
startBtn.disabled = false;
updateBtn.disabled = true;
commitBtn.disabled = true;
crashBtn.disabled = true;
document.getElementById('immMsg').classList.remove('is-visible');
});
})();
</script>
</body>
</html>.demo {
font-family: system-ui, sans-serif;
padding: 16px;
}
.demo h1 {
color: #2563eb;
margin: 0 0 8px;
}
.demo p {
color: #4b5563;
margin: 0;
}document.querySelector('.demo h1')?.addEventListener('click', () => {
alert('Hello from live preview!');
});π§ Summary Table:
Feature | Deferred Update | Immediate Update |
|---|---|---|
When DB is updated | After COMMIT | Before COMMIT |
Log Required | REDO only | UNDO + REDO |
Recovery Complexity | Simple | Complex |
Speed | Slower | Faster |
Failure Before Commit | No effect (nothing written) | Must UNDO |
π§° Types of Recovery Operations
Operation | Purpose |
|---|---|
UNDO | Reverse changes made by uncommitted transactions |
REDO | Reapply changes made by committed transactions |
π‘ Bonus Tip: Write-Ahead Logging (WAL)
Before applying any changes to the database, the log must be written to disk first. This ensures that:
If a failure occurs, the log is there to recover from.
Maintains data integrity.