rust/hg-core/src/revlog/revlog.rs
changeset 48541 f2f57724d4eb
parent 48540 20d0d896183e
child 48542 35c47015b9b7
equal deleted inserted replaced
48540:20d0d896183e 48541:f2f57724d4eb
   182     ///
   182     ///
   183     /// All entries required to build the final data out of deltas will be
   183     /// All entries required to build the final data out of deltas will be
   184     /// retrieved as needed, and the deltas will be applied to the inital
   184     /// retrieved as needed, and the deltas will be applied to the inital
   185     /// snapshot to rebuild the final data.
   185     /// snapshot to rebuild the final data.
   186     #[timed]
   186     #[timed]
   187     pub fn get_rev_data(&self, rev: Revision) -> Result<Vec<u8>, RevlogError> {
   187     pub fn get_rev_data(
       
   188         &self,
       
   189         rev: Revision,
       
   190     ) -> Result<Cow<[u8]>, RevlogError> {
   188         if rev == NULL_REVISION {
   191         if rev == NULL_REVISION {
   189             return Ok(vec![]);
   192             return Ok(Cow::Borrowed(&[]));
   190         };
   193         };
   191         // Todo return -> Cow
   194         self.get_entry(rev)?.data()
   192         let mut entry = self.get_entry(rev)?;
       
   193         let mut delta_chain = vec![];
       
   194 
       
   195         // The meaning of `base_rev_or_base_of_delta_chain` depends on
       
   196         // generaldelta. See the doc on `ENTRY_DELTA_BASE` in
       
   197         // `mercurial/revlogutils/constants.py` and the code in
       
   198         // [_chaininfo] and in [index_deltachain].
       
   199         let uses_generaldelta = self.index.uses_generaldelta();
       
   200         while let Some(base_rev) = entry.base_rev_or_base_of_delta_chain {
       
   201             let base_rev = if uses_generaldelta {
       
   202                 base_rev
       
   203             } else {
       
   204                 entry.rev - 1
       
   205             };
       
   206             delta_chain.push(entry);
       
   207             entry = self.get_entry_internal(base_rev)?;
       
   208         }
       
   209 
       
   210         // TODO do not look twice in the index
       
   211         let index_entry = self
       
   212             .index
       
   213             .get_entry(rev)
       
   214             .ok_or(RevlogError::InvalidRevision)?;
       
   215 
       
   216         let data: Vec<u8> = if delta_chain.is_empty() {
       
   217             entry.data_chunk()?.into()
       
   218         } else {
       
   219             Revlog::build_data_from_deltas(entry, &delta_chain)?
       
   220         };
       
   221 
       
   222         if self.check_hash(
       
   223             index_entry.p1(),
       
   224             index_entry.p2(),
       
   225             index_entry.hash().as_bytes(),
       
   226             &data,
       
   227         ) {
       
   228             Ok(data)
       
   229         } else {
       
   230             Err(RevlogError::corrupted())
       
   231         }
       
   232     }
   195     }
   233 
   196 
   234     /// Check the hash of some given data against the recorded hash.
   197     /// Check the hash of some given data against the recorded hash.
   235     pub fn check_hash(
   198     pub fn check_hash(
   236         &self,
   199         &self,
   294             self.index.data(start, end)
   257             self.index.data(start, end)
   295         } else {
   258         } else {
   296             &self.data()[start..end]
   259             &self.data()[start..end]
   297         };
   260         };
   298         let entry = RevlogEntry {
   261         let entry = RevlogEntry {
       
   262             revlog: self,
   299             rev,
   263             rev,
   300             bytes: data,
   264             bytes: data,
   301             compressed_len: index_entry.compressed_len(),
   265             compressed_len: index_entry.compressed_len(),
   302             uncompressed_len: index_entry.uncompressed_len(),
   266             uncompressed_len: index_entry.uncompressed_len(),
   303             base_rev_or_base_of_delta_chain: if index_entry
   267             base_rev_or_base_of_delta_chain: if index_entry
   322     }
   286     }
   323 }
   287 }
   324 
   288 
   325 /// The revlog entry's bytes and the necessary informations to extract
   289 /// The revlog entry's bytes and the necessary informations to extract
   326 /// the entry's data.
   290 /// the entry's data.
   327 #[derive(Debug)]
   291 #[derive(Clone)]
   328 pub struct RevlogEntry<'a> {
   292 pub struct RevlogEntry<'a> {
       
   293     revlog: &'a Revlog,
   329     rev: Revision,
   294     rev: Revision,
   330     bytes: &'a [u8],
   295     bytes: &'a [u8],
   331     compressed_len: usize,
   296     compressed_len: usize,
   332     uncompressed_len: usize,
   297     uncompressed_len: usize,
   333     base_rev_or_base_of_delta_chain: Option<Revision>,
   298     base_rev_or_base_of_delta_chain: Option<Revision>,
   336 impl<'a> RevlogEntry<'a> {
   301 impl<'a> RevlogEntry<'a> {
   337     pub fn revision(&self) -> Revision {
   302     pub fn revision(&self) -> Revision {
   338         self.rev
   303         self.rev
   339     }
   304     }
   340 
   305 
       
   306     /// The data for this entry, after resolving deltas if any.
       
   307     pub fn data(&self) -> Result<Cow<'a, [u8]>, RevlogError> {
       
   308         let mut entry = self.clone();
       
   309         let mut delta_chain = vec![];
       
   310 
       
   311         // The meaning of `base_rev_or_base_of_delta_chain` depends on
       
   312         // generaldelta. See the doc on `ENTRY_DELTA_BASE` in
       
   313         // `mercurial/revlogutils/constants.py` and the code in
       
   314         // [_chaininfo] and in [index_deltachain].
       
   315         let uses_generaldelta = self.revlog.index.uses_generaldelta();
       
   316         while let Some(base_rev) = entry.base_rev_or_base_of_delta_chain {
       
   317             let base_rev = if uses_generaldelta {
       
   318                 base_rev
       
   319             } else {
       
   320                 entry.rev - 1
       
   321             };
       
   322             delta_chain.push(entry);
       
   323             entry = self.revlog.get_entry_internal(base_rev)?;
       
   324         }
       
   325 
       
   326         // TODO do not look twice in the index
       
   327         let index_entry = self
       
   328             .revlog
       
   329             .index
       
   330             .get_entry(self.rev)
       
   331             .ok_or(RevlogError::InvalidRevision)?;
       
   332 
       
   333         let data = if delta_chain.is_empty() {
       
   334             entry.data_chunk()?
       
   335         } else {
       
   336             Revlog::build_data_from_deltas(entry, &delta_chain)?.into()
       
   337         };
       
   338 
       
   339         if self.revlog.check_hash(
       
   340             index_entry.p1(),
       
   341             index_entry.p2(),
       
   342             index_entry.hash().as_bytes(),
       
   343             &data,
       
   344         ) {
       
   345             Ok(data)
       
   346         } else {
       
   347             Err(RevlogError::corrupted())
       
   348         }
       
   349     }
       
   350 
   341     /// Extract the data contained in the entry.
   351     /// Extract the data contained in the entry.
   342     /// This may be a delta. (See `is_delta`.)
   352     /// This may be a delta. (See `is_delta`.)
   343     fn data_chunk(&self) -> Result<Cow<'_, [u8]>, RevlogError> {
   353     fn data_chunk(&self) -> Result<Cow<'a, [u8]>, RevlogError> {
   344         if self.bytes.is_empty() {
   354         if self.bytes.is_empty() {
   345             return Ok(Cow::Borrowed(&[]));
   355             return Ok(Cow::Borrowed(&[]));
   346         }
   356         }
   347         match self.bytes[0] {
   357         match self.bytes[0] {
   348             // Revision data is the entirety of the entry, including this
   358             // Revision data is the entirety of the entry, including this