g1t/services/repos/migrations/0014_namespace_moves.sql
Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| Repositories shard across git store namespaces, move between them, and can keep to the EU; a namespace can be served read-only from the self-hosted git store, rebuilt from the nightly backups (#20, #25) | 1 | -- Moving a repository from one git store namespace to another |
| 2 | -- (src/moves.rs; docs/ARTIFACTS.md, R7). Additive; nothing is backfilled, | |
| 3 | -- and nothing moves until an operator asks. | |
| 4 | -- | |
| 5 | -- writes_paused_until: milliseconds since the epoch. Until then nothing | |
| 6 | -- writes to the repository: pushes wait up to 20 seconds for it to pass, | |
| 7 | -- then are told to try again; merges, commits from the web and handed-out | |
| 8 | -- push credentials the same. Set while a move copies the repository and | |
| 9 | -- its pull requests' working copies, cleared when it ends either way, and | |
| 10 | -- it passes on its own should a move die half way. | |
| 11 | -- writes_paused_for: why, in words (`moving to g1t-us-1`). | |
| 12 | ALTER TABLE repos ADD COLUMN writes_paused_until INTEGER; | |
| 13 | ALTER TABLE repos ADD COLUMN writes_paused_for TEXT; | |
| 14 | ||
| 15 | -- One row per move asked for. The hourly sweep (`23 * * * *`) runs the | |
| 16 | -- queued ones, oldest first, one at a time. | |
| 17 | -- | |
| 18 | -- status: queued | moving | moved | failed | cleaned | diverged. | |
| 19 | -- moved: the repository reads and writes in its new namespace; the copy | |
| 20 | -- in the old one is kept MOVE_KEEP_DAYS (7) in case of a rollback, then | |
| 21 | -- deleted (cleaned). diverged: the old copy's refs changed after the | |
| 22 | -- move (a push that slipped past the pause), so it is kept and an | |
| 23 | -- operator reconciles it. | |
| 24 | -- to_namespace: where it goes. | |
| 25 | -- requested_by: who asked, in words. | |
| 26 | -- note: the last thing that happened (why it waits, why it failed). | |
| 27 | CREATE TABLE repo_moves ( | |
| 28 | id TEXT PRIMARY KEY, | |
| 29 | repo_id TEXT NOT NULL, | |
| 30 | to_namespace TEXT NOT NULL, | |
| 31 | status TEXT NOT NULL DEFAULT 'queued', | |
| 32 | requested_by TEXT, | |
| 33 | queued_ms INTEGER NOT NULL, | |
| 34 | started_ms INTEGER, | |
| 35 | finished_ms INTEGER, | |
| 36 | cleaned_ms INTEGER, | |
| 37 | attempts INTEGER NOT NULL DEFAULT 0, | |
| 38 | note TEXT | |
| 39 | ); | |
| 40 | CREATE INDEX repo_moves_queue ON repo_moves (status, queued_ms); | |
| 41 | -- At most one move in hand per repository. | |
| 42 | CREATE UNIQUE INDEX repo_moves_active ON repo_moves (repo_id) WHERE status IN ('queued', 'moving'); | |
| 43 | ||
| 44 | -- What each move copied: the repository and each of its pull requests' | |
| 45 | -- working copies, from one key to another, with every ref as copied. | |
| 46 | -- | |
| 47 | -- name: the key's name without its namespace. A name with a copy not yet | |
| 48 | -- cleaned stays taken (registry.rs `claim_store_key`), so a new | |
| 49 | -- repository never adopts an old copy left behind. | |
| 50 | -- refs: JSON object, ref name to object, as copied; the old copy is | |
| 51 | -- deleted only while it still says the same. | |
| 52 | CREATE TABLE repo_move_copies ( | |
| 53 | move_id TEXT NOT NULL, | |
| 54 | repo_id TEXT NOT NULL, | |
| 55 | from_key TEXT NOT NULL, | |
| 56 | to_key TEXT NOT NULL, | |
| 57 | name TEXT NOT NULL, | |
| 58 | refs TEXT NOT NULL DEFAULT '{}', | |
| 59 | cleaned_ms INTEGER, | |
| 60 | PRIMARY KEY (move_id, repo_id) | |
| 61 | ); | |
| 62 | CREATE INDEX repo_move_copies_name ON repo_move_copies (name) WHERE cleaned_ms IS NULL; |