Write a recorded change to the repository. This method inserts a change that was just recorded, updating both the graph and the tree tables. It's the integration point between recording and inserting. Unlike `insert_change`, this method: - Takes the change directly (doesn't load from store) - Updates tree tables for FileAdd hunks - Assigns new inodes to added files # Arguments `outcome` - The
(
&self,
outcome: &RecordOutcome,
mut options: InsertOptions,
)
| 1981 | /// println!("Inserted with state: {}", apply_outcome.new_state.to_base32()); |
| 1982 | /// ``` |
| 1983 | pub fn write_recorded( |
| 1984 | &self, |
| 1985 | outcome: &RecordOutcome, |
| 1986 | mut options: InsertOptions, |
| 1987 | ) -> Result<InsertOutcome, RepositoryError> { |
| 1988 | let trace_record = std::env::var_os("ATOMIC_TRACE_RECORD").is_some(); |
| 1989 | let change = outcome.change(); |
| 1990 | let hash = outcome.hash(); |
| 1991 | |
| 1992 | // A freshly-recorded change is applied to the view it was recorded on. |
| 1993 | // Its dependency closure is complete by construction, so it cannot |
| 1994 | // produce zombie or missing-context conflicts. Disable conflict |
| 1995 | // detection to skip the per-hunk zombie/deleted-context graph scans |
| 1996 | // (the dominant apply cost on large changes); the graph written is |
| 1997 | // identical, only the (empty) conflict report is skipped. |
| 1998 | options.track_conflicts = false; |
| 1999 | |
| 2000 | // Get write transaction |
| 2001 | let mut txn = self |
| 2002 | .pristine |
| 2003 | .write_txn() |
| 2004 | .map_err(|e| RepositoryError::Database(e.to_string()))?; |
| 2005 | |
| 2006 | // Register the change to get an internal ID |
| 2007 | let change_id = txn |
| 2008 | .register_change(hash) |
| 2009 | .map_err(|e| RepositoryError::Database(e.to_string()))?; |
| 2010 | txn.put_change_deps(change_id, change.dependencies()) |
| 2011 | .map_err(|e| RepositoryError::Database(e.to_string()))?; |
| 2012 | |
| 2013 | // Determine which view to use |
| 2014 | let view_name = options.view.as_deref().unwrap_or(&self.current_view); |
| 2015 | |
| 2016 | // Before applying atoms, set up tree entries for FileAdd hunks. |
| 2017 | // This creates the inode→position and path→inode mappings needed |
| 2018 | // for the graph operations. |
| 2019 | // |
| 2020 | // Note: put_tree creates both TREE and REV_TREE entries. |
| 2021 | // put_inode creates both INODES and REV_INODES entries. |
| 2022 | for graph_op in change.hunks() { |
| 2023 | match graph_op { |
| 2024 | GraphOp::FileAdd { |
| 2025 | add_inode, path, .. |
| 2026 | } => { |
| 2027 | // Allocate a new inode for this file |
| 2028 | let new_inode = txn |
| 2029 | .alloc_inode() |
| 2030 | .map_err(|e| RepositoryError::Database(e.to_string()))?; |
| 2031 | |
| 2032 | // The inode span position is relative to this change. |
| 2033 | // Since add_inode.start is a ChangePosition within this change's content, |
| 2034 | // we create an internal position using the change_id we just registered. |
| 2035 | let inode_position = Position::new(change_id, add_inode.start); |
| 2036 | |
| 2037 | // Add to tree tables: |
| 2038 | // - put_tree: path ↔ inode (TREE and REV_TREE) |
| 2039 | // - put_inode: inode ↔ position (INODES and REV_INODES) |
| 2040 | txn.put_tree(path, new_inode) |