use std::io::{self, Read, Write};
pub const HEADER_LEN: usize = 8; // 4-byte length + 4-byte crc
#[derive(Debug)]
pub enum DecodeError {
UnexpectedEof,
ChecksumMismatch,
Io(io::Error),
}
impl From<io::Error> for DecodeError {
fn from(e: io::Error) -> Self {
DecodeError::Io(e)
}
}
pub struct Record;
impl Record {
pub fn encode<W: Write>(w: &mut W, payload: &[u8]) -> io::Result<usize> {
let crc = crc32fast::hash(payload);
w.write_all(&(payload.len() as u32).to_le_bytes())?;
w.write_all(&crc.to_le_bytes())?;
w.write_all(payload)?;
Ok(HEADER_LEN + payload.len())
}
pub fn decode<R: Read>(r: &mut R) -> Result<Vec<u8>, DecodeError> {
let mut header = [0u8; HEADER_LEN];
match r.read_exact(&mut header) {
Ok(()) => {}
Err(ref e) if e.kind() == io::ErrorKind::UnexpectedEof => {
return Err(DecodeError::UnexpectedEof)
}
Err(e) => return Err(DecodeError::Io(e)),
}
let len = u32::from_le_bytes(header[0..4].try_into().unwrap()) as usize;
let want_crc = u32::from_le_bytes(header[4..8].try_into().unwrap());
let mut payload = vec![0u8; len];
r.read_exact(&mut payload).map_err(|e| {
if e.kind() == io::ErrorKind::UnexpectedEof {
DecodeError::UnexpectedEof
} else {
DecodeError::Io(e)
}
})?;
if crc32fast::hash(&payload) != want_crc {
return Err(DecodeError::ChecksumMismatch);
}
Ok(payload)
}
}
use std::fs::{File, OpenOptions};
use std::io::{self, BufWriter, Write};
use std::path::{Path, PathBuf};
use serde::{Deserialize, Serialize};
use crate::record::Record;
#[derive(Debug, Serialize, Deserialize)]
pub enum Entry {
Set { key: String, value: Vec<u8> },
Delete { key: String },
}
pub struct Wal {
path: PathBuf,
writer: BufWriter<File>,
}
impl Wal {
pub fn append(&mut self, entry: &Entry) -> io::Result<()> {
let payload = bincode::serialize(entry)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
Record::encode(&mut self.writer, &payload)?;
self.writer.flush()?;
// Force bytes to stable storage before returning to the caller.
self.writer.get_ref().sync_data()?;
Ok(())
}
pub fn path(&self) -> &Path {
&self.path
}
fn from_file(path: PathBuf, file: File) -> Self {
Wal {
path,
writer: BufWriter::new(file),
}
}
pub(crate) fn open_append(path: &Path) -> io::Result<File> {
OpenOptions::new().create(true).append(true).open(path)
}
}
use std::fs::{File, OpenOptions};
use std::io::{self, BufReader, Seek, SeekFrom};
use std::path::PathBuf;
use crate::record::{DecodeError, Record};
use crate::wal::{Entry, Wal};
impl Wal {
pub fn open<F>(path: PathBuf, mut apply: F) -> io::Result<Wal>
where
F: FnMut(Entry),
{
let read_file = OpenOptions::new().read(true).open(&path).or_else(|e| {
if e.kind() == io::ErrorKind::NotFound {
File::create(&path)
} else {
Err(e)
}
})?;
let mut reader = BufReader::new(read_file);
let mut good_offset: u64 = 0;
loop {
match Record::decode(&mut reader) {
Ok(payload) => match bincode::deserialize::<Entry>(&payload) {
Ok(entry) => {
apply(entry);
good_offset = reader.stream_position()?;
}
Err(_) => break, // undecodable record: stop and drop tail
},
Err(DecodeError::UnexpectedEof) | Err(DecodeError::ChecksumMismatch) => break,
Err(DecodeError::Io(e)) => return Err(e),
}
}
let append_file = Wal::open_append(&path)?;
// Discard any torn trailing bytes left by a crash mid-append.
append_file.set_len(good_offset)?;
append_file.seek(SeekFrom::End(0)).ok();
Ok(Wal::from_file(path, append_file))
}
}
A write-ahead log (WAL) is the standard technique for making state changes durable and recoverable: every mutation is first appended to an on-disk log, flushed, and only then applied to in-memory or on-disk structures. If the process crashes, the log is replayed on startup to reconstruct the last committed state. The key properties are that appends are sequential (fast), each record is self-describing, and corruption from a partial write is detectable rather than silently loaded.
The record format tab defines the on-disk framing. Each record is a length prefix, a crc32 checksum, and the payload bytes. Record::encode computes the checksum over the payload with crc32fast and writes everything little-endian; Record::decode reads the frame back and returns DecodeError::ChecksumMismatch when the stored CRC does not match the recomputed one. Framing every entry with its own length and CRC is what makes recovery robust: a torn tail from a crash mid-write is caught by a short read or a bad checksum and treated as end-of-log rather than propagated as bad data.
The Wal writer tab wraps a file opened in append mode. append serializes the entry, encodes a Record, writes it, and calls sync_data so the bytes reach stable storage before the caller proceeds. That fsync is the whole point — without it the OS page cache can lose the write on power failure, defeating the log. The trade-off is latency, which is why real systems batch appends and amortize one fsync across many records; this implementation flushes per append for clarity.
The replay on startup tab shows recovery. Wal::open reads records sequentially through Record::decode and folds each decoded Entry into caller state via a closure. Crucially, when it hits an UnexpectedEof or ChecksumMismatch, it stops cleanly and truncates the file to the last known-good offset, discarding the partial trailing record. This tolerate-torn-tail behavior is what lets a WAL survive a crash during a write.
Developers reach for this pattern whenever an in-memory structure must survive restarts — key-value stores, queues, ledgers. Pitfalls include forgetting fsync, not versioning the record format, and assuming a clean read means a clean disk; the per-record CRC guards against the last of these.
Related snips
class PostSerializer < ActiveModel::Serializer
attributes :id, :title, :excerpt, :body, :published_at, :views, :likes_count, :comments_count
attribute :can_edit, if: :current_user_can_edit?
belongs_to :author, serializer: UserSummarySerializer
Serializers with ActiveModel::Serializers
class PostsController < ApplicationController
def index
posts = Post.for_feed.page(params[:page]).per(25)
render json: {
data: posts.map { |post| PostSerializer.new(post).as_json },
N+1 Proof Serialization with preloaded associations
-- Logical backup with pg_dump
-- Single database
-- pg_dump -h localhost -U postgres -d mydb -F c -f mydb_backup.dump
-- All databases
-- pg_dumpall -h localhost -U postgres -f all_databases.sql
Database backup and recovery strategies
package com.example.demo.controller;
import com.example.demo.dto.FileMetadata;
import com.example.demo.service.FileStorageService;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
File upload and download handling
# Headless Service for stable DNS
apiVersion: v1
kind: Service
metadata:
name: postgres
namespace: production
Kubernetes StatefulSets for stateful workloads
class NotifyFollowersJob
include Sidekiq::Job
sidekiq_options queue: :notifications, retry: 5
def perform(post_id, actor_id)
Safer Background Job Arguments (Serialize IDs only)
Share this code
Here's the card — post it anywhere.