Fast path for external importers (e.g. git-import) that already have pre-built `RecordedFile`s and just need globalization + assembly + hashing. Returns `(Change, Hash)`.
(
&self,
header: ChangeHeader,
recorded_files: &[atomic_core::record::workflow::RecordedFile],
)
| 862 | /// |
| 863 | /// Returns `(Change, Hash)`. |
| 864 | pub fn assemble_and_hash( |
| 865 | &self, |
| 866 | header: ChangeHeader, |
| 867 | recorded_files: &[atomic_core::record::workflow::RecordedFile], |
| 868 | ) -> Result<(Change, Hash), RecordError> { |
| 869 | use atomic_core::record::workflow::assemble_change; |
| 870 | use atomic_core::record::workflow::assembly::AssemblyOptions; |
| 871 | |
| 872 | let overall_start = std::time::Instant::now(); |
| 873 | |
| 874 | let txn = self |
| 875 | .pristine |
| 876 | .read_txn() |
| 877 | .map_err(|e| RecordError::Database(e.to_string()))?; |
| 878 | |
| 879 | // Use a bare transaction — no ViewGraph filter needed. |
| 880 | // |
| 881 | // This method is the fast path for git import, where every change |
| 882 | // is written to a shared view and all edges land in the global |
| 883 | // GRAPH table. A bare ReadTxn sees every edge directly. |
| 884 | // |
| 885 | // Wrapping in ViewGraph + collect_visible_change_ids would scan |
| 886 | // the entire view change log on every call (O(N) per commit, |
| 887 | // O(N²) total for N commits), which makes large imports |
| 888 | // progressively slower. |
| 889 | let assembly_options = AssemblyOptions::default(); |
| 890 | |
| 891 | let assembly_result = assemble_change(&txn, recorded_files, header, &assembly_options)?; |
| 892 | |
| 893 | let change = assembly_result.into_change(); |
| 894 | log::debug!( |
| 895 | "assemble_and_hash: assembly complete, content_size={} hunks={}", |
| 896 | change.contents.len(), |
| 897 | change.hunks().len(), |
| 898 | ); |
| 899 | |
| 900 | let step = std::time::Instant::now(); |
| 901 | let mut v3_bytes = Vec::new(); |
| 902 | let hash = change |
| 903 | .serialize(&mut v3_bytes) |
| 904 | .map_err(|e| RecordError::ChangeStore(e.to_string()))?; |
| 905 | let serialize_ms = step.elapsed().as_millis(); |
| 906 | |
| 907 | let step = std::time::Instant::now(); |
| 908 | let (final_change, _) = Change::deserialize(&mut v3_bytes.as_slice()) |
| 909 | .map_err(|e| RecordError::ChangeStore(e.to_string()))?; |
| 910 | let deserialize_ms = step.elapsed().as_millis(); |
| 911 | |
| 912 | let total_ms = overall_start.elapsed().as_millis(); |
| 913 | if serialize_ms + deserialize_ms > 100 { |
| 914 | log::warn!( |
| 915 | "assemble_and_hash: serialize={}ms ({} bytes) deserialize={}ms total={}ms", |
| 916 | serialize_ms, |
| 917 | v3_bytes.len(), |
| 918 | deserialize_ms, |
| 919 | total_ms, |
| 920 | ); |
| 921 | } else { |
nothing calls this directly
no test coverage detected