rust/hg-core/src/dirstate_tree/dirstate_map.rs
changeset 49130 3926bfef28e4
parent 49129 74c996f84958
child 49131 fcf6f943a142
equal deleted inserted replaced
49129:74c996f84958 49130:3926bfef28e4
   476 
   476 
   477         let parents = parse_dirstate_entries(
   477         let parents = parse_dirstate_entries(
   478             map.on_disk,
   478             map.on_disk,
   479             |path, entry, copy_source| {
   479             |path, entry, copy_source| {
   480                 let tracked = entry.state().is_tracked();
   480                 let tracked = entry.state().is_tracked();
   481                 let node = Self::get_or_insert_node(
   481                 let node = Self::get_or_insert_node_inner(
   482                     map.on_disk,
   482                     map.on_disk,
   483                     &mut map.unreachable_bytes,
   483                     &mut map.unreachable_bytes,
   484                     &mut map.root,
   484                     &mut map.root,
   485                     path,
   485                     path,
   486                     WithBasename::to_cow_borrowed,
   486                     WithBasename::to_cow_borrowed,
   572                 return Ok(None);
   572                 return Ok(None);
   573             }
   573             }
   574         }
   574         }
   575     }
   575     }
   576 
   576 
       
   577     /// Get a mutable reference to the node at `path`, creating it if it does
       
   578     /// not exist.
       
   579     ///
       
   580     /// `each_ancestor` is a callback that is called for each ancestor node
       
   581     /// when descending the tree. It is used to keep the different counters
       
   582     /// of the `DirstateMap` up-to-date.
   577     fn get_or_insert_node<'tree, 'path>(
   583     fn get_or_insert_node<'tree, 'path>(
       
   584         &'tree mut self,
       
   585         path: &'path HgPath,
       
   586         each_ancestor: impl FnMut(&mut Node),
       
   587     ) -> Result<&'tree mut Node<'on_disk>, DirstateV2ParseError> {
       
   588         Self::get_or_insert_node_inner(
       
   589             self.on_disk,
       
   590             &mut self.unreachable_bytes,
       
   591             &mut self.root,
       
   592             path,
       
   593             WithBasename::to_cow_owned,
       
   594             each_ancestor,
       
   595         )
       
   596     }
       
   597 
       
   598     /// Lower-level version of `get_or_insert_node_inner`, which is used when
       
   599     /// parsing disk data to remove allocations for new nodes.
       
   600     fn get_or_insert_node_inner<'tree, 'path>(
   578         on_disk: &'on_disk [u8],
   601         on_disk: &'on_disk [u8],
   579         unreachable_bytes: &mut u32,
   602         unreachable_bytes: &mut u32,
   580         root: &'tree mut ChildNodes<'on_disk>,
   603         root: &'tree mut ChildNodes<'on_disk>,
   581         path: &'path HgPath,
   604         path: &'path HgPath,
   582         to_cow: impl Fn(
   605         to_cow: impl Fn(
   618     ) -> Result<(), DirstateError> {
   641     ) -> Result<(), DirstateError> {
   619         let (had_entry, was_tracked) = match old_entry_opt {
   642         let (had_entry, was_tracked) = match old_entry_opt {
   620             Some(old_entry) => (true, old_entry.tracked()),
   643             Some(old_entry) => (true, old_entry.tracked()),
   621             None => (false, false),
   644             None => (false, false),
   622         };
   645         };
   623         let node = Self::get_or_insert_node(
   646         let node = self.get_or_insert_node(filename, |ancestor| {
   624             self.on_disk,
   647             if !had_entry {
   625             &mut self.unreachable_bytes,
   648                 ancestor.descendants_with_entry_count += 1;
   626             &mut self.root,
   649             }
   627             filename,
   650             if was_tracked {
   628             WithBasename::to_cow_owned,
   651                 if !wc_tracked {
   629             |ancestor| {
   652                     ancestor.tracked_descendants_count = ancestor
   630                 if !had_entry {
   653                         .tracked_descendants_count
   631                     ancestor.descendants_with_entry_count += 1;
   654                         .checked_sub(1)
       
   655                         .expect("tracked count to be >= 0");
   632                 }
   656                 }
   633                 if was_tracked {
   657             } else {
   634                     if !wc_tracked {
   658                 if wc_tracked {
   635                         ancestor.tracked_descendants_count = ancestor
   659                     ancestor.tracked_descendants_count += 1;
   636                             .tracked_descendants_count
       
   637                             .checked_sub(1)
       
   638                             .expect("tracked count to be >= 0");
       
   639                     }
       
   640                 } else {
       
   641                     if wc_tracked {
       
   642                         ancestor.tracked_descendants_count += 1;
       
   643                     }
       
   644                 }
   660                 }
   645             },
   661             }
   646         )?;
   662         })?;
   647 
   663 
   648         let v2_data = if let Some(parent_file_data) = parent_file_data_opt {
   664         let v2_data = if let Some(parent_file_data) = parent_file_data_opt {
   649             DirstateV2Data {
   665             DirstateV2Data {
   650                 wc_tracked,
   666                 wc_tracked,
   651                 p1_tracked,
   667                 p1_tracked,
   664                 p1_tracked,
   680                 p1_tracked,
   665                 p2_info,
   681                 p2_info,
   666                 ..Default::default()
   682                 ..Default::default()
   667             }
   683             }
   668         };
   684         };
       
   685         node.data = NodeData::Entry(DirstateEntry::from_v2_data(v2_data));
   669         if !had_entry {
   686         if !had_entry {
   670             self.nodes_with_entry_count += 1;
   687             self.nodes_with_entry_count += 1;
   671         }
   688         }
   672         node.data = NodeData::Entry(DirstateEntry::from_v2_data(v2_data));
       
   673         Ok(())
   689         Ok(())
   674     }
   690     }
   675 
   691 
   676     fn set_tracked(
   692     fn set_tracked(
   677         &mut self,
   693         &mut self,
   681         let was_tracked = old_entry_opt.map_or(false, |e| e.tracked());
   697         let was_tracked = old_entry_opt.map_or(false, |e| e.tracked());
   682         let had_entry = old_entry_opt.is_some();
   698         let had_entry = old_entry_opt.is_some();
   683         let tracked_count_increment = if was_tracked { 0 } else { 1 };
   699         let tracked_count_increment = if was_tracked { 0 } else { 1 };
   684         let mut new = false;
   700         let mut new = false;
   685 
   701 
   686         let node = Self::get_or_insert_node(
   702         let node = self.get_or_insert_node(filename, |ancestor| {
   687             self.on_disk,
   703             if !had_entry {
   688             &mut self.unreachable_bytes,
   704                 ancestor.descendants_with_entry_count += 1;
   689             &mut self.root,
   705             }
   690             filename,
   706 
   691             WithBasename::to_cow_owned,
   707             ancestor.tracked_descendants_count += tracked_count_increment;
   692             |ancestor| {
   708         })?;
   693                 if !had_entry {
   709         if let Some(old_entry) = old_entry_opt {
   694                     ancestor.descendants_with_entry_count += 1;
       
   695                 }
       
   696 
       
   697                 ancestor.tracked_descendants_count += tracked_count_increment;
       
   698             },
       
   699         )?;
       
   700         let new_entry = if let Some(old_entry) = old_entry_opt {
       
   701             let mut e = old_entry.clone();
   710             let mut e = old_entry.clone();
   702             if e.tracked() {
   711             if e.tracked() {
   703                 // XXX
   712                 // XXX
   704                 // This is probably overkill for more case, but we need this to
   713                 // This is probably overkill for more case, but we need this to
   705                 // fully replace the `normallookup` call with `set_tracked`
   714                 // fully replace the `normallookup` call with `set_tracked`
   707                 e.set_possibly_dirty();
   716                 e.set_possibly_dirty();
   708             } else {
   717             } else {
   709                 new = true;
   718                 new = true;
   710                 e.set_tracked();
   719                 e.set_tracked();
   711             }
   720             }
   712             e
   721             node.data = NodeData::Entry(e)
   713         } else {
   722         } else {
       
   723             node.data = NodeData::Entry(DirstateEntry::new_tracked());
   714             self.nodes_with_entry_count += 1;
   724             self.nodes_with_entry_count += 1;
   715             new = true;
   725             new = true;
   716             DirstateEntry::new_tracked()
       
   717         };
   726         };
   718         node.data = NodeData::Entry(new_entry);
       
   719         Ok(new)
   727         Ok(new)
   720     }
   728     }
   721 
   729 
   722     /// It is the responsibility of the caller to know that there was an entry
   730     /// It is the responsibility of the caller to know that there was an entry
   723     /// there before. Does not handle the removal of copy source
   731     /// there before. Does not handle the removal of copy source
   724     fn set_untracked(
   732     fn set_untracked(
   725         &mut self,
   733         &mut self,
   726         filename: &HgPath,
   734         filename: &HgPath,
   727         old_entry: DirstateEntry,
   735         old_entry: DirstateEntry,
   728     ) -> Result<(), DirstateV2ParseError> {
   736     ) -> Result<(), DirstateV2ParseError> {
   729         let node = Self::get_or_insert_node(
   737         let node = self.get_or_insert_node(filename, |ancestor| {
   730             self.on_disk,
   738             ancestor.tracked_descendants_count = ancestor
   731             &mut self.unreachable_bytes,
   739                 .tracked_descendants_count
   732             &mut self.root,
   740                 .checked_sub(1)
   733             filename,
   741                 .expect("tracked_descendants_count should be >= 0");
   734             WithBasename::to_cow_owned,
   742         })?;
   735             |ancestor| {
       
   736                 ancestor.tracked_descendants_count = ancestor
       
   737                     .tracked_descendants_count
       
   738                     .checked_sub(1)
       
   739                     .expect("tracked_descendants_count should be >= 0");
       
   740             },
       
   741         )?;
       
   742         let mut new_entry = old_entry.clone();
   743         let mut new_entry = old_entry.clone();
   743         new_entry.set_untracked();
   744         new_entry.set_untracked();
   744         node.data = NodeData::Entry(new_entry);
   745         node.data = NodeData::Entry(new_entry);
   745         Ok(())
   746         Ok(())
   746     }
   747     }
   751         old_entry: DirstateEntry,
   752         old_entry: DirstateEntry,
   752         mode: u32,
   753         mode: u32,
   753         size: u32,
   754         size: u32,
   754         mtime: TruncatedTimestamp,
   755         mtime: TruncatedTimestamp,
   755     ) -> Result<(), DirstateError> {
   756     ) -> Result<(), DirstateError> {
   756         let node = Self::get_or_insert_node(
   757         let node = self.get_or_insert_node(filename, |ancestor| {
   757             self.on_disk,
   758             if !old_entry.tracked() {
   758             &mut self.unreachable_bytes,
   759                 ancestor.tracked_descendants_count += 1;
   759             &mut self.root,
   760             }
   760             filename,
   761         })?;
   761             WithBasename::to_cow_owned,
       
   762             |ancestor| {
       
   763                 if !old_entry.tracked() {
       
   764                     ancestor.tracked_descendants_count += 1;
       
   765                 }
       
   766             },
       
   767         )?;
       
   768         let mut new_entry = old_entry.clone();
   762         let mut new_entry = old_entry.clone();
   769         new_entry.set_clean(mode, size, mtime);
   763         new_entry.set_clean(mode, size, mtime);
   770         node.data = NodeData::Entry(new_entry);
   764         node.data = NodeData::Entry(new_entry);
   771         Ok(())
   765         Ok(())
   772     }
   766     }
   773 
   767 
   774     fn set_possibly_dirty(
   768     fn set_possibly_dirty(
   775         &mut self,
   769         &mut self,
   776         filename: &HgPath,
   770         filename: &HgPath,
   777     ) -> Result<(), DirstateError> {
   771     ) -> Result<(), DirstateError> {
   778         let node = Self::get_or_insert_node(
   772         let node = self.get_or_insert_node(filename, |_ancestor| {})?;
   779             self.on_disk,
       
   780             &mut self.unreachable_bytes,
       
   781             &mut self.root,
       
   782             filename,
       
   783             WithBasename::to_cow_owned,
       
   784             |_ancestor| {},
       
   785         )?;
       
   786         let entry = node.data.as_entry_mut().expect("entry should exist");
   773         let entry = node.data.as_entry_mut().expect("entry should exist");
   787         entry.set_possibly_dirty();
   774         entry.set_possibly_dirty();
   788         node.data = NodeData::Entry(*entry);
   775         node.data = NodeData::Entry(*entry);
   789         Ok(())
   776         Ok(())
   790     }
   777     }
  1322         &mut self,
  1309         &mut self,
  1323         key: &HgPath,
  1310         key: &HgPath,
  1324         value: &HgPath,
  1311         value: &HgPath,
  1325     ) -> Result<Option<HgPathBuf>, DirstateV2ParseError> {
  1312     ) -> Result<Option<HgPathBuf>, DirstateV2ParseError> {
  1326         self.with_dmap_mut(|map| {
  1313         self.with_dmap_mut(|map| {
  1327             let node = DirstateMap::get_or_insert_node(
  1314             let node = map.get_or_insert_node(&key, |_ancestor| {})?;
  1328                 map.on_disk,
  1315             let had_copy_source = node.copy_source.is_none();
  1329                 &mut map.unreachable_bytes,
  1316             let old = node
  1330                 &mut map.root,
       
  1331                 &key,
       
  1332                 WithBasename::to_cow_owned,
       
  1333                 |_ancestor| {},
       
  1334             )?;
       
  1335             if node.copy_source.is_none() {
       
  1336                 map.nodes_with_copy_source_count += 1
       
  1337             }
       
  1338             Ok(node
       
  1339                 .copy_source
  1317                 .copy_source
  1340                 .replace(value.to_owned().into())
  1318                 .replace(value.to_owned().into())
  1341                 .map(Cow::into_owned))
  1319                 .map(Cow::into_owned);
       
  1320             if had_copy_source {
       
  1321                 map.nodes_with_copy_source_count += 1
       
  1322             }
       
  1323             Ok(old)
  1342         })
  1324         })
  1343     }
  1325     }
  1344 
  1326 
  1345     pub fn len(&self) -> usize {
  1327     pub fn len(&self) -> usize {
  1346         let map = self.get_map();
  1328         let map = self.get_map();
  1422                 files_with_p2_info.push(path.to_owned())
  1404                 files_with_p2_info.push(path.to_owned())
  1423             }
  1405             }
  1424         }
  1406         }
  1425         self.with_dmap_mut(|map| {
  1407         self.with_dmap_mut(|map| {
  1426             for path in files_with_p2_info.iter() {
  1408             for path in files_with_p2_info.iter() {
  1427                 let node = DirstateMap::get_or_insert_node(
  1409                 let node = map.get_or_insert_node(path, |_| {})?;
  1428                     map.on_disk,
       
  1429                     &mut map.unreachable_bytes,
       
  1430                     &mut map.root,
       
  1431                     path,
       
  1432                     WithBasename::to_cow_owned,
       
  1433                     |_| {},
       
  1434                 )?;
       
  1435                 let entry =
  1410                 let entry =
  1436                     node.data.as_entry_mut().expect("entry should exist");
  1411                     node.data.as_entry_mut().expect("entry should exist");
  1437                 entry.drop_merge_data();
  1412                 entry.drop_merge_data();
  1438                 if let Some(source) = node.copy_source.take().as_deref() {
  1413                 if let Some(source) = node.copy_source.take().as_deref() {
  1439                     copies.push((path.to_owned(), source.to_owned()));
  1414                     copies.push((path.to_owned(), source.to_owned()));