Deployment
Upgrading to LMDB 1.0
The storage engine moved from LMDB 0.9 to 1.0; detecting and migrating 0.9 files, rolling upgrades and rollback
#Upgrading to LMDB 1.0
Since phoenixml main ee0c056, the storage engine uses LightningDB 0.23.1 (LMDB 1.0.1). LMDB 0.9
and 1.0 files can't read each other. The engine has had no public release on LMDB 0.9, so this
affects only databases created with earlier internal builds.
#What changes
-
0.9 files are detected and refused before LMDB opens them. That covers a database, a Raft log, a backup file, a restore stream and a cluster snapshot. The engine throws
PhoenixmlDb.Storage.Lmdb.LmdbMigrationRequiredException(propertiesPathandFound), whose message names the command to run and ends "The file was not opened or changed."LmdbFileFormatDetector.Detect(path)reports a file's format (LmdbFileFormatKind). -
Linux needs glibc 2.38 or later. Debian 12 (glibc 2.36) does not meet it. Ubuntu 22.04, RHEL 9 and Amazon Linux 2023 ship older glibc versions than 2.38 and do not meet it either.
-
LightningDB 0.23.1 includes no native libraries for browser WebAssembly or iOS (arm).
-
Restores are staged. Every restore path writes
data.mdb.restore.tmp, flushes it and checks its format before replacing anything. A restore needs a stopped database and throwsInvalidOperationExceptionif the database is open in this or another process. -
Keys are limited to 511 bytes on every platform; a longer key is refused with
LightningExceptionMDB_BAD_VALSIZE(LMDB 1.0's own limit is larger and depends on the page size). Values in duplicate-sorted databases are limited to 511 bytes too. -
For code that uses
LmdbStorageEnginedirectly: LMDB 1.0 refuses an empty value in a duplicate-sorted database.
#Migrating a 0.9 database
Use the PhoenixmlDb.Migrate tool. It isn't yet published as a package. Stop the database first:
nothing may have the directory open, in any process, or the tool refuses.
PhoenixmlDb.Migrate <envDir> [--export-tool <path>] [--export-timeout <seconds>] [--map-size <bytes>]
PhoenixmlDb.Migrate --backup <in.mdb> <out.mdb> [same options]
PhoenixmlDb.Migrate --version
<envDir> is a database or Raft log directory, migrated in place. --backup converts one backup
file into a new file: <out.mdb> must not exist, and the input is not modified. The tool starts
PhoenixmlDb.Migrate.Export from the export folder beside it; --export-tool names another
path. --export-timeout defaults to 3600 seconds.
The tool exports the 0.9 data through a separate process (PhoenixmlDb.Migrate.Export), writes a
new 1.0 file, reads every database back, and compares each one's entry count and SHA-256 with the
original. Only then is the original data.mdb renamed to data.mdb.v09; it's never modified. The
new file's map size defaults to twice the data in use (at least 1 MiB); --map-size overrides it.
Run the tool as the user the database runs as, since the new file belongs to whoever runs it.
|
Exit code |
Meaning |
|---|---|
|
0 |
Migrated, or an interrupted migration was completed |
|
1 |
Failed (an LMDB or I/O error, or a map size that's too small); the original wasn't replaced |
|
2 |
Bad arguments |
|
3 |
Nothing to migrate: already LMDB 1.0, no data file, or not an LMDB file |
|
4 |
Refused: the database is open, |
|
5 |
Verification failed; the original wasn't replaced |
|
6 |
The export tool is missing, failed or timed out |
|
7 |
The data holds an entry LMDB 1.0 can't store (the message names it) |
Verification proves the copy equals what LMDB 0.9 read. LMDB 0.9 keeps no checksums, so it can't prove the original was undamaged.
#Embedded applications and single servers
Stop the application or server, run PhoenixmlDb.Migrate on the data directory, then start the new
version. Migrate any backups you might restore with --backup.
Embedded application
-
Stop the application. Take a backup of the database directory if you want one beyond
data.mdb.v09. -
Run
PhoenixmlDb.Migrate <database directory>(the directory that holdsdata.mdb). Expect exit 0. -
Start the application on the new build.
-
Keep
data.mdb.v09until you are satisfied, then delete it.
Single server
-
Stop the server.
-
Run
PhoenixmlDb.Migrate <data directory>. If the server has a Raft log directory (PhoenixmlDb:Raft:LogPath), runPhoenixmlDb.Migrate <raft log directory>as well. -
Start the server on the new build, on a host with glibc 2.38 or newer.
Backup files. A backup written in the 0.9 format is refused on restore; nothing is restored,
and neither the backup nor the database changes. Convert it with
PhoenixmlDb.Migrate --backup <in.mdb> <out.mdb>, then restore the result.
Interrupted run. Run the tool again: it finishes the migration, or puts the original back, or says why it can do neither (exit 4). The engine refuses to open a directory in that state and says to run the tool again.
#A Raft cluster, one node at a time
Cluster nodes are designed to be upgraded one at a time: the bytes the nodes exchange are the same in both versions. A cluster with nodes on both versions has not been tested. For each node: stop it, migrate its database directory and its Raft log directory, then start it on the new version. A snapshot sent by a node still on LMDB 0.9 is refused, so finish the upgrade before a lagging node needs a snapshot.
The Raft log format carries no version number. A command type added by a newer build is not known to an older build.
#Rolling back
Stop the database, remove the new data.mdb, rename data.mdb.v09 to data.mdb, and run the
previous version. Removing lock.mdb too is harmless but not needed. Anything written after the
migration is not in data.mdb.v09. A migrated directory also keeps
.phoenixml-migrate.lock, the tool's guard against two migrations at once; it can stay or go.
#Known limits
-
Windows is not tested. On Windows LMDB sets the size of
data.mdbto the map size when it creates the file; use--map-sizewith the migration tool to choose it. -
Only the linux-x64 build of the tool has been run.
-
There's no up-front disk-space check. The export needs a little over twice the data, plus the new file; running out of space fails with the original untouched.
#Events
Migration and restore log storage events 1015–1021; see Logging and Telemetry.