patternModeratepending
Pattern: Write-Ahead Log (WAL) for crash recovery
Viewed 0 times
WALwrite-ahead-logcrash-recoverydurabilityappend-onlyfsync
Problem
If a system crashes mid-write, data can be corrupted or lost. Need a way to recover to a consistent state.
Solution
Write changes to an append-only log before applying them:
# WAL concept:
# 1. Write the INTENTION to a log file (fsync)
# 2. Apply the change to the actual data
# 3. Mark the log entry as applied
#
# On crash recovery:
# - Read uncommitted log entries
# - Re-apply (or roll back) as needed
class SimpleWAL:
def __init__(self, log_path, data_path):
self.log = open(log_path, 'ab') # Append-only
self.data_path = data_path
def write(self, key, value):
# Step 1: Write to log
entry = json.dumps({'op': 'SET', 'key': key, 'value': value, 'ts': time.time()})
self.log.write(entry.encode() + b'\n')
self.log.flush()
os.fsync(self.log.fileno()) # Ensure on disk
# Step 2: Apply to data store
self._apply(key, value)
# Step 3: Mark as committed (write checkpoint)
self._checkpoint()
def recover(self):
# On startup: replay uncommitted entries
for entry in self._read_uncommitted():
self._apply(entry['key'], entry['value'])
Used by: PostgreSQL, SQLite (WAL mode), Redis (AOF),
Kafka (commit log), LevelDB/RocksDB
# WAL concept:
# 1. Write the INTENTION to a log file (fsync)
# 2. Apply the change to the actual data
# 3. Mark the log entry as applied
#
# On crash recovery:
# - Read uncommitted log entries
# - Re-apply (or roll back) as needed
class SimpleWAL:
def __init__(self, log_path, data_path):
self.log = open(log_path, 'ab') # Append-only
self.data_path = data_path
def write(self, key, value):
# Step 1: Write to log
entry = json.dumps({'op': 'SET', 'key': key, 'value': value, 'ts': time.time()})
self.log.write(entry.encode() + b'\n')
self.log.flush()
os.fsync(self.log.fileno()) # Ensure on disk
# Step 2: Apply to data store
self._apply(key, value)
# Step 3: Mark as committed (write checkpoint)
self._checkpoint()
def recover(self):
# On startup: replay uncommitted entries
for entry in self._read_uncommitted():
self._apply(entry['key'], entry['value'])
Used by: PostgreSQL, SQLite (WAL mode), Redis (AOF),
Kafka (commit log), LevelDB/RocksDB
Why
Sequential writes to an append-only log are fast and durable. The WAL ensures no committed data is lost, even on crashes.
Revisions (0)
No revisions yet.