What a branch is here
A branch is a real environment: its own Postgres container, its own bucket, its own app containers, its own managed databases, all keyed by the ref (<project>-<branch>) and all on their
own hostnames. Nothing is shared with the source branch after the fork.
Where the data lives
Under the data directory,/var/lib/instacloud on a server and ~/.insta-oss on a laptop:
How a clone works
insta branch create feat --from main does this to the Postgres service:
- Check that the source is at rest. A database here sleeps when nothing is using it, so the parent of a branch is normally stopped, and a stopped data directory is one nothing is writing.
- Copy the data directory with a reflink copy. The filesystem shares the blocks and only divergent writes allocate anything, so this is a metadata operation: sub-second whether the database is 100 MB or 100 GB.
- Start the new container on the copy. Postgres runs its normal crash recovery, which is what it does after any unclean stop, and comes up with the data as of the moment the source stopped.
pg_basebackup instead, and so is any source on a filesystem
without reflink support. Same result, but the time is proportional to the size of the database.
Copying a live data directory file by file is not safe at any speed: the server keeps writing
through the copy, so the result would be assembled out of several different moments and might not
recover at all. Postgres allows a file-level copy only against a stopped server, an atomic
filesystem snapshot, or its own backup protocol, so an always-on database always streams. The
install page has the reflink check and how to get one.
Either way, insta agent events records what happened:
db.method is reflink or basebackup, and it is the fastest way to confirm that reflinks are
actually working on your box.
INSTA_OSS_FORK decides which of the two is allowed: auto (the default) reflinks when it can and
streams when it cannot, reflink refuses the fork rather than falling back, and basebackup
always streams. Set it to reflink on a box where a silent fall back to a copy proportional to the
database would be worse than an error. reflink refuses a fork of a running database too: the
safety rule is not something a setting turns off, so stop the source or let it sleep first.
Volumes fork too
Every compute volume is reflink-copied along with the database, so a branch starts with the files its source had. Unlike the database, a volume is copied whether or not its app is running. The database has a consistent alternative for the live case (pg_basebackup streams it), and an inconsistent copy of
a database does not survive its own crash recovery. A volume has neither: nothing can stream an
arbitrary application’s files consistently, so the choice is between copying a live directory and
failing every branch create of an app that is awake. InstaCloud OSS copies. What the branch gets is
each file as it stood when the walk reached it, which is many moments of the tree and not one: a
crash or a power cut freezes a single instant, and this does not, so an invariant that spans two
files (a log and the record it describes, a rename and the index entry for it) can land broken in
a way no crash would produce. An app that only appends, or that fsyncs a single file, is fine; one
whose consistency spans files is not. If a group writes data that cannot take that, stop it first
with insta compute stop <group>, or let the idle sweep put it to sleep, and then create the
branch.
This is a difference from the hosted platform, where a new branch gets an empty volume. Here the
volume is forked, because forking files is what the local filesystem is good at.
Buckets
Objects are copied withrclone sync into the new bucket for the branch. This is a real copy, so
it is proportional to how much you have stored.
Managed databases
Redis, MySQL and MongoDB services start empty on a new branch, the same as on the hosted platform. They are caches and side stores, and a copy is rarely what you want.A new branch sleeps
Every service of a new branch is created and then left asleep: the app containers are created and not started, and the databases are provisioned, readied, and then stopped. The first request to the branch wakes what it needs. Always-on services are the exception and stay up. That is what makes it cheap to leave ten branches lying around. See sleep and wake.Upgrading from an older install
Installs before the fork model kept Postgres data in named Docker volumes, which cannot be reflinked. The first boot after the upgrade moves that data intopg/<ref>/<id>/ for you, one
service at a time, and logs each move. Nothing to run by hand.