Branch Protect Snapshots
When
DATA BRANCH CREATE TABLEorDATA BRANCH CREATE DATABASEcreates a branch, MatrixOne automatically inserts an internal snapshot row intomo_catalog.mo_snapshotswith ansnameprefixed__mo_branch_. This protects the parent table's data from garbage collection while any descendant branch remains alive. Branch snapshots are invisible toSHOW SNAPSHOTS, rejected byDROP SNAPSHOT, and reclaimed automatically when the entire DAG subtree is deleted.
Syntax
No dedicated SQL syntax — branch protect snapshots are created automatically by DATA BRANCH CREATE TABLE and DATA BRANCH CREATE DATABASE. They are internal catalog rows in mo_catalog.mo_snapshots and cannot be created, listed, or dropped directly with snapshot commands (CREATE SNAPSHOT, SHOW SNAPSHOTS, DROP SNAPSHOT).
Arguments
Branch protect snapshots are identified by the following internal naming and classification conventions:
| Attribute | Value | Description |
|---|---|---|
sname |
__mo_branch_<child_table_id> |
Snapshot name; child_table_id is the cluster-unique table identifier of the child branch table, formatted as a decimal string. The __mo_branch_ prefix distinguishes branch protect snapshots from user-created snapshots. |
level |
table |
All branch protect snapshots are table-level |
obj_id |
parent table_id |
References the parent table whose data is pinned by this snapshot |
account_name |
parent account name | The account that owns the parent table |
What They Are
A branch protect snapshot is an internal row in mo_catalog.mo_snapshots that pins the parent table's data at the branch creation timestamp. It is identified by the __mo_branch_ prefix on its sname and is managed entirely by the data branch subsystem.
Key properties:
| Property | Value |
|---|---|
sname |
__mo_branch_<child_table_id> (decimal) |
level |
table |
| Created by | DATA BRANCH CREATE TABLE / DATA BRANCH CREATE DATABASE |
| Visibility | Hidden from SHOW SNAPSHOTS (filtered by sname prefix) |
| Droppable by user | No — DROP SNAPSHOT rejects it |
| Reclaimed by | DATA BRANCH DELETE TABLE / DATA BRANCH DELETE DATABASE / DROP TABLE |
Lifecycle
Creation
When a DATA BRANCH CREATE TABLE or DATA BRANCH CREATE DATABASE statement succeeds, MatrixOne inserts two rows atomically within the same transaction:
- A row in
mo_catalog.mo_branch_metadatatracking the parent-child relationship. - A row in
mo_catalog.mo_snapshotswith the sname prefix__mo_branch_pinning the parent'sclone_ts.
The snapshot name follows the convention __mo_branch_<child_table_id> where child_table_id is a cluster-unique table identifier.
Visibility
Branch protect snapshots are excluded from all user-facing snapshot operations:
SHOW SNAPSHOTSfilters out rows whosesnamehas the__mo_branch_prefix.- Snapshot quota counts ignore
__mo_branch_rows. DROP SNAPSHOTreturns an error when the target is a branch snapshot.
Reclamation
Branch snapshots are reclaimed automatically through a DAG-aware cascade:
- When a branch child table is dropped (via
DATA BRANCH DELETE TABLE,DATA BRANCH DELETE DATABASE, orDROP TABLE), the corresponding metadata row hastable_deletedset totrue. - The reclaim algorithm walks the DAG upward from dropped tables, checking every ancestor's subtree for full deletion.
- When an entire subtree is confirmed deleted (all descendants have
table_deleted=true), the ancestor's branch snapshot is removed frommo_snapshots. - The reclaim is cycle-safe — a corrupted
mo_branch_metadatacycle logs a warning and terminates without deadlock.
Examples
Verifying branch snapshot creation and DROP SNAPSHOT rejection
DROP DATABASE IF EXISTS protect_db1;
CREATE DATABASE protect_db1;
USE protect_db1;
CREATE TABLE t1(a INT PRIMARY KEY, b VARCHAR(10));
INSERT INTO t1 VALUES (1, 'a'), (2, 'b');
DATA BRANCH CREATE TABLE t2 FROM t1;
-- The branch protect snapshot exists with sname prefix __mo_branch_
SET @t2_tid = (
SELECT rel_id FROM mo_catalog.mo_tables
WHERE reldatabase = 'protect_db1' AND relname = 't2'
);
SET @t1_tid = (
SELECT rel_id FROM mo_catalog.mo_tables
WHERE reldatabase = 'protect_db1' AND relname = 't1'
);
SET @t2_sname = CONCAT('__mo_branch_', CAST(@t2_tid AS CHAR));
SELECT COUNT(*) AS branch_rows_total
FROM mo_catalog.mo_snapshots WHERE sname LIKE '__mo_branch_%';
SELECT level, database_name, table_name,
obj_id = @t1_tid AS obj_id_matches_parent
FROM mo_catalog.mo_snapshots
WHERE sname = @t2_sname;
-- SHOW SNAPSHOTS hides __mo_branch_ rows
SELECT COUNT(*) AS branch_rows_in_show
FROM mo_catalog.mo_snapshots
WHERE sname NOT LIKE 'ccpr_%'
AND sname LIKE '__mo_branch_%';
-- DROP SNAPSHOT on a branch protect snapshot is rejected
SET @drop_snap_sql = CONCAT('DROP SNAPSHOT ', @t2_sname);
-- Expected-Success: false
PREPARE drop_snap_stmt FROM @drop_snap_sql;
-- ERROR: internal error: DROP SNAPSHOT is rejected for branch protect snapshots
-- Expected-Success: false
EXECUTE drop_snap_stmt;
-- Expected-Success: false
DEALLOCATE PREPARE drop_snap_stmt;
DROP TABLE t2;
DROP TABLE t1;
DROP DATABASE protect_db1;
Notes
- Branch protect snapshots are an internal mechanism. You do not create, list, or drop them directly. Use
SHOW SNAPSHOTSonly for user snapshots. - If you need to free storage, drop the branch child tables with
DATA BRANCH DELETE TABLEorDATA BRANCH DELETE DATABASE. The associated snapshots are cleaned up automatically. - The
__mo_branch_prefix onsnameis how internal branch snapshots are distinguished from user snapshots. Do not modify these rows directly.