Upgrades¶
Upgrading RockLake involves replacing the binary (or container image) with a newer version and, in some cases, migrating the catalog's internal format. Because RockLake stores all state in SlateDB on object storage, upgrades are simpler than traditional database upgrades — there is no local data directory to migrate, no WAL to replay, and no cluster coordination to manage.
This page covers version compatibility guarantees, the upgrade procedure for every deployment model, format migrations, rollback strategies, and best practices for zero-downtime upgrades.
Version Compatibility¶
Semantic Versioning¶
RockLake follows semantic versioning (MAJOR.MINOR.PATCH):
- PATCH (0.8.0 → 0.8.1): Bug fixes only. No format changes. Drop-in replacement.
- MINOR (0.8.x → 0.9.0): New features, possibly new configuration options. May include a format migration (documented in release notes).
- MAJOR (0.x → 1.0): Breaking changes to CLI, configuration, or wire protocol. Will include format migration.
Format Versions¶
The catalog format version is a single integer stored as a system key (sys/format_version). It determines binary compatibility:
| Format Version | Introduced In | Description |
|---|---|---|
| 1 | 0.1.0 | Initial format: protobuf values, tag-prefixed keys |
Compatibility Rules:
- A binary that supports format version N can read/write catalogs at format version N
- A binary that supports format version N+1 can read catalogs at format version N (backward compatible)
- A binary that only supports format version N CANNOT read catalogs at format version N+1 (forward incompatible)
Once a format migration is applied, you cannot downgrade the binary below the version that introduced the new format (without restoring from backup).
Wire Protocol Compatibility¶
The PostgreSQL wire protocol interface maintains backward compatibility within a major version:
- DuckDB clients built for RockLake 0.7.x will work with RockLake 0.8.x
- New protocol features are additive (new message types, new columns in results)
- Breaking wire protocol changes are reserved for major version bumps
Pre-Upgrade Checklist¶
Before upgrading, complete these steps:
# 1. Check current version and catalog state
rocklake --version
rocklake inspect --catalog s3://bucket/catalog/
# 2. Read the release notes for the target version
# Pay attention to: format migrations, breaking changes, deprecations
# 3. Take a backup (critical for format migrations)
rocklake export --catalog s3://bucket/catalog/ --output pre-upgrade-backup.ndjson
# 4. Verify the backup
wc -l pre-upgrade-backup.ndjson
# Should match expected row count from inspect
# 5. Check disk space / storage quota (for migration overhead)
aws s3 ls s3://bucket/catalog/ --recursive --summarize | tail -2
Upgrade Procedures¶
Binary Installation¶
# 1. Stop RockLake
systemctl stop rocklake
# or: kill $(pgrep rocklake)
# 2. Replace the binary
mv /usr/local/bin/rocklake /usr/local/bin/rocklake.old
curl -L https://github.com/rocklake/rocklake/releases/download/v0.9.0/rocklake-$(uname -m)-unknown-linux-gnu -o /usr/local/bin/rocklake
chmod +x /usr/local/bin/rocklake
# 3. Start the new version
systemctl start rocklake
# or: rocklake serve --catalog s3://bucket/catalog/
# 4. Verify
rocklake --version
rocklake inspect --catalog s3://bucket/catalog/
Docker¶
# 1. Pull the new image
docker pull ghcr.io/rocklake/rocklake:0.9.0
# 2. Stop the old container
docker stop rocklake
# 3. Start with the new image
docker run -d --name rocklake-new \
-p 5432:5432 \
-e ROCKLAKE_STORAGE=s3://bucket/catalog/ \
-e AWS_REGION=us-east-1 \
ghcr.io/rocklake/rocklake:0.9.0 \
serve
# 4. Verify
docker logs rocklake-new | head -20
# 5. Remove old container
docker rm rocklake
docker rename rocklake-new rocklake
Kubernetes¶
# Update the image tag in your deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: rocklake
spec:
replicas: 1
strategy:
type: Recreate # Ensures old pod dies before new one starts
template:
spec:
containers:
- name: rocklake
image: ghcr.io/rocklake/rocklake:0.9.0 # Updated
# Apply the update
kubectl apply -f rocklake-deployment.yaml
# Watch the rollout
kubectl rollout status deployment/rocklake
# Verify
kubectl exec deployment/rocklake -- rocklake --version
kubectl exec deployment/rocklake -- rocklake inspect --catalog s3://bucket/catalog/
Fly.io¶
# Update fly.toml with new image or rebuild
fly deploy --image ghcr.io/rocklake/rocklake:0.9.0
# Verify
fly ssh console -C "rocklake --version"
fly ssh console -C "rocklake inspect --catalog s3://bucket/catalog/"
Format Migrations¶
When a new version introduces a format change, the migration is handled as follows:
Automatic Migration (Default)¶
Most format migrations are automatic. On first startup with the new binary:
- RockLake detects the old format version
- It reads all catalog data
- It rewrites data in the new format
- It updates
sys/format_version - Normal operation resumes
The migration is atomic — if it fails midway, the catalog remains at the old format version and can be retried.
Manual Migration (Rare)¶
For complex migrations (announced in release notes):
# Run the migration tool explicitly
rocklake migrate --catalog s3://bucket/catalog/ --target-version 2
# Verify
rocklake inspect --catalog s3://bucket/catalog/
Migration Duration¶
| Catalog Size | Typical Migration Time |
|---|---|
| Small (< 100 tables) | < 5 seconds |
| Medium (100–1,000 tables) | 5–30 seconds |
| Large (1,000–10,000 tables) | 30 seconds – 5 minutes |
| Very large (10,000+ tables) | 5–30 minutes |
During migration, the catalog is unavailable for reads and writes. Plan accordingly.
Rollback Strategies¶
No Format Migration (Simple Rollback)¶
If the new version has the same format version as the old one:
# Simply replace the binary with the old version
systemctl stop rocklake
mv /usr/local/bin/rocklake.old /usr/local/bin/rocklake
systemctl start rocklake
After Format Migration (Backup Restore)¶
If a format migration was applied, you cannot simply use the old binary (it will refuse with FormatVersionMismatch). Your options:
-
Restore from NDJSON backup (recommended):
-
Object storage versioning (advanced): If bucket versioning is enabled, restore the previous versions of all objects under the catalog prefix. This restores the raw SlateDB state.
-
Continue forward (pragmatic): Often, fixing the issue in the new version (configuration change, bug workaround) is simpler than rolling back.
Zero-Downtime Upgrades¶
Because RockLake uses a single-writer architecture, true zero-downtime upgrades require careful orchestration:
Strategy: Quick Restart¶
For most deployments, the simplest approach:
- Stop the old instance
- Start the new instance
- Total downtime: 2–10 seconds (startup time)
DuckDB clients will receive connection errors during the gap and should retry.
Strategy: Writer Handoff¶
For environments requiring minimal disruption:
- Start the new instance pointing at the same catalog
- The new instance claims the writer epoch (fences the old instance)
- The old instance becomes read-only (existing queries complete)
- Terminate the old instance after a grace period
# Start new instance on a different port
rocklake serve --catalog s3://bucket/catalog/ --bind 0.0.0.0:5433
# Verify it claimed the epoch
rocklake inspect --catalog s3://bucket/catalog/ --format json | jq '.writer_epoch'
# Update load balancer to point to new port
# ...
# Stop old instance after drain period
kill $(pgrep -f "rocklake.*5432")
Strategy: Blue-Green with DNS¶
For production environments with DNS-based routing:
- Deploy new version to "green" environment
- New instance claims the catalog (fences blue)
- Switch DNS from blue to green
- Terminate blue after TTL expires
Upgrade Testing¶
Before upgrading production, test in a staging environment:
# Copy production catalog to staging
rocklake export --catalog s3://prod-bucket/catalog/ --output prod-snapshot.ndjson
rocklake import --catalog s3://staging-bucket/catalog/ --input prod-snapshot.ndjson
# Upgrade staging
# ... (follow upgrade procedure)
# Run integration tests against staging
rocklake verify --catalog s3://staging-bucket/catalog/
# Run your application's test suite
Post-Upgrade Verification¶
After any upgrade, run through this verification checklist:
Immediate Checks (First 5 Minutes)¶
# 1. Version confirmation
rocklake --version
# Expected: the target version
# 2. Catalog health
rocklake inspect --catalog s3://bucket/catalog/
# Expected: all entity counts match pre-upgrade values
# 3. Verify connectivity
duckdb -c "ATTACH 'ducklake:postgresql://localhost:5432/rocklake' AS lake; SELECT count(*) FROM lake.information_schema.tables;"
# Expected: same table count as before
# 4. Check logs for errors
journalctl -u rocklake --since "5 minutes ago" | grep -i error
# Expected: no errors
Extended Verification (First Hour)¶
- Monitor latency metrics — are query response times normal?
- Check that scheduled jobs (GC, backups) still trigger successfully
- Verify that DuckDB clients reconnect without intervention
- Watch for any deprecation warnings in logs that may need configuration changes
Load Testing After Format Migration¶
After a format migration, run a representative workload to confirm performance characteristics have not regressed:
# Run the benchmark suite against the migrated catalog
rocklake bench --catalog s3://bucket/catalog/ --operations 1000
# Compare with baseline
# Look for: point-read latency, prefix scan throughput, write batch commit time
Common Upgrade Issues¶
Binary Refuses to Start After Upgrade¶
Symptom: Error: FormatVersionMismatch { expected: 2, found: 1 }
This means the new binary requires a format version higher than what exists on disk, and automatic migration did not run. Explicitly trigger migration:
DuckDB Clients Get "Connection Refused" After Upgrade¶
Symptom: DuckDB ATTACH fails with connection errors.
Check that the new instance is listening on the expected port. Configuration file format may have changed between versions — verify bind address in logs:
Performance Regression After Upgrade¶
Symptom: Query latency increased significantly after upgrade.
Common causes:
- Compaction pending: Format migration writes new SST files. Wait for SlateDB compaction to optimize the layout.
- Cache cold: The new process starts with an empty block cache. Performance normalizes after warming.
- New feature overhead: Check if new default-enabled features (additional statistics, telemetry) can be disabled if not needed.
Writer Epoch Keeps Incrementing¶
Symptom: rocklake inspect shows rapidly increasing writer epoch.
This indicates multiple instances are competing for the writer lease — typically caused by the old deployment not being fully terminated before the new one starts. Ensure only one writer instance is running:
Version History¶
| Version | Format | Notable Changes |
|---|---|---|
| 0.8.0 | 1 | Initial stable release |
| 0.7.0 | 1 | Performance improvements, new CLI commands |
| 0.6.0 | 1 | GC and excision support |
| 0.5.0 | 1 | Writer fencing, epoch-based lease |
Further Reading¶
- Configuration — Configuration options that may change between versions
- Backup & Restore — Pre-upgrade backup procedures
- Verify & Repair — Post-upgrade integrity verification
- Troubleshooting — Diagnosing upgrade-related issues