|
1 | 1 | use crate::{ |
2 | 2 | hash, loose, pack, |
3 | | - pack::index::write::types::{Cache, EntrySlice, Mode, ObjectKind}, |
| 3 | + pack::index::write::types::{EntrySlice, ObjectKind}, |
4 | 4 | pack::index::write::Error, |
5 | 5 | zlib, |
6 | 6 | }; |
7 | 7 | use git_features::progress::Progress; |
8 | 8 | use git_object::{owned, HashKind}; |
9 | | -use std::{cell::RefCell, io}; |
| 9 | +use std::{cell::RefCell, collections::BTreeMap, io}; |
10 | 10 |
|
11 | 11 | pub(crate) fn apply_deltas<F, P>( |
12 | | - mut nodes: Vec<pack::tree::Node<pack::index::write::types::TreeEntry>>, |
| 12 | + nodes: Vec<pack::tree::Node<pack::index::write::types::TreeEntry>>, |
13 | 13 | (bytes_buf, progress): &mut (Vec<u8>, P), |
14 | | - mode: Mode, |
15 | 14 | resolve: F, |
16 | 15 | hash_kind: HashKind, |
17 | 16 | ) -> Result<usize, Error> |
18 | 17 | where |
19 | 18 | F: for<'r> Fn(EntrySlice, &'r mut Vec<u8>) -> Option<()> + Send + Sync, |
20 | 19 | P: Progress, |
21 | 20 | { |
| 21 | + let mut decompressed_bytes_by_pack_offset = BTreeMap::new(); |
22 | 22 | let bytes_buf = RefCell::new(bytes_buf); |
23 | 23 | let mut num_objects = 0; |
24 | | - let decompress_from_cache = |cache: Cache, pack_offset: u64, entry_size: usize| -> Result<Vec<u8>, Error> { |
25 | | - Ok(match cache { |
26 | | - Cache::Unset => { |
27 | | - let mut bytes_buf = bytes_buf.borrow_mut(); |
28 | | - bytes_buf.resize(entry_size, 0); |
29 | | - match mode { |
30 | | - Mode::ResolveDeltas | Mode::ResolveBasesAndDeltas => { |
31 | | - resolve(pack_offset..pack_offset + entry_size as u64, &mut bytes_buf) |
32 | | - .ok_or_else(|| Error::ConsumeResolveFailed(pack_offset))?; |
33 | | - let entry = pack::data::Entry::from_bytes(&bytes_buf, pack_offset); |
34 | | - decompress_all_at_once( |
35 | | - &bytes_buf[entry.header_size() as usize..], |
36 | | - entry.decompressed_size as usize, |
37 | | - )? |
38 | | - } |
39 | | - Mode::InMemory => unreachable!("BUG: If there is no cache, we always need a resolver"), |
40 | | - } |
41 | | - } |
42 | | - Cache::Decompressed(bytes) => bytes, |
43 | | - }) |
| 24 | + let decompress_from_resolver = |pack_offset: u64, entry_size: usize| -> Result<Vec<u8>, Error> { |
| 25 | + let mut bytes_buf = bytes_buf.borrow_mut(); |
| 26 | + bytes_buf.resize(entry_size, 0); |
| 27 | + resolve(pack_offset..pack_offset + entry_size as u64, &mut bytes_buf) |
| 28 | + .ok_or_else(|| Error::ConsumeResolveFailed(pack_offset))?; |
| 29 | + let entry = pack::data::Entry::from_bytes(&bytes_buf, pack_offset); |
| 30 | + decompress_all_at_once( |
| 31 | + &bytes_buf[entry.header_size() as usize..], |
| 32 | + entry.decompressed_size as usize, |
| 33 | + ) |
44 | 34 | }; |
45 | 35 |
|
46 | 36 | // Traverse the tree breadth first and loose the data produced for the base as it won't be needed anymore. |
47 | 37 | progress.init(None, Some("objects")); |
48 | 38 |
|
49 | 39 | // each node is a base, and its children always start out as deltas which become a base after applying them. |
50 | 40 | // These will be pushed onto our stack until all are processed |
51 | | - while let Some(mut base) = nodes.pop() { |
52 | | - let base_bytes = decompress_from_cache( |
53 | | - std::mem::take(&mut base.data.cache), |
54 | | - base.data.pack_offset, |
55 | | - base.data.entry_len, |
56 | | - )?; |
| 41 | + let root_level = 0; |
| 42 | + let mut nodes: Vec<_> = nodes.into_iter().map(|n| (root_level, n)).collect(); |
| 43 | + while let Some((level, mut base)) = nodes.pop() { |
| 44 | + let base_bytes = if level == root_level { |
| 45 | + decompress_from_resolver(base.data.pack_offset, base.data.entry_len)? |
| 46 | + } else { |
| 47 | + decompressed_bytes_by_pack_offset |
| 48 | + .remove(&base.data.pack_offset) |
| 49 | + .expect("we store the resolved delta buffer when done") |
| 50 | + }; |
57 | 51 | let base_kind = base.data.kind.to_kind().expect("base object as source of iteration"); |
58 | 52 | let id = compute_hash(base_kind, &base_bytes, hash_kind); |
59 | 53 | num_objects += 1; |
60 | 54 |
|
61 | 55 | base.data.id = id; |
62 | 56 | for mut child in base.store_changes_then_into_child_iter() { |
63 | | - let delta_bytes = decompress_from_cache( |
64 | | - std::mem::take(&mut child.data.cache), |
65 | | - child.data.pack_offset, |
66 | | - child.data.entry_len, |
67 | | - )?; |
| 57 | + let delta_bytes = decompress_from_resolver(child.data.pack_offset, child.data.entry_len)?; |
68 | 58 | let (base_size, consumed) = pack::data::decode::delta_header_size_ofs(&delta_bytes); |
69 | 59 | let mut header_ofs = consumed; |
70 | 60 | assert_eq!( |
|
79 | 69 | fully_resolved_delta_bytes.resize(result_size as usize, 0); |
80 | 70 | pack::data::decode::apply_delta(&base_bytes, &mut fully_resolved_delta_bytes, &delta_bytes[header_ofs..]); |
81 | 71 |
|
82 | | - child.data.cache = Cache::Decompressed(fully_resolved_delta_bytes.to_owned()); |
| 72 | + decompressed_bytes_by_pack_offset.insert(child.data.pack_offset, fully_resolved_delta_bytes.to_owned()); |
83 | 73 | child.data.kind = ObjectKind::Base(base_kind); |
84 | | - nodes.push(child); |
| 74 | + nodes.push((level + 1, child)); |
85 | 75 | } |
86 | 76 | } |
87 | 77 |
|
|
0 commit comments