rust/hg-core/src/revlog/index.rs
changeset 51234 59183a19954e
parent 51233 ca81cd96000a
child 51235 456e0fe702e8
equal deleted inserted replaced
51233:ca81cd96000a 51234:59183a19954e
   259     /// Offsets of starts of index blocks.
   259     /// Offsets of starts of index blocks.
   260     /// Only needed when the index is interleaved with data.
   260     /// Only needed when the index is interleaved with data.
   261     offsets: RwLock<Option<Vec<usize>>>,
   261     offsets: RwLock<Option<Vec<usize>>>,
   262     uses_generaldelta: bool,
   262     uses_generaldelta: bool,
   263     is_inline: bool,
   263     is_inline: bool,
   264     /// Cache of the head revisions in this index, kept in sync. Should
   264     /// Cache of (head_revisions, filtered_revisions)
       
   265     ///
       
   266     /// The head revisions in this index, kept in sync. Should
   265     /// be accessed via the [`Self::head_revs`] method.
   267     /// be accessed via the [`Self::head_revs`] method.
   266     head_revs: Vec<Revision>,
   268     /// The last filtered revisions in this index, used to make sure
   267     /// Cache of the last filtered revisions in this index, used to make sure
       
   268     /// we haven't changed filters when returning the cached `head_revs`.
   269     /// we haven't changed filters when returning the cached `head_revs`.
   269     filtered_revs: HashSet<Revision>,
   270     head_revs: RwLock<(Vec<Revision>, HashSet<Revision>)>,
   270 }
   271 }
   271 
   272 
   272 impl Debug for Index {
   273 impl Debug for Index {
   273     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
   274     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
   274         f.debug_struct("Index")
   275         f.debug_struct("Index")
   364                 Ok(Self {
   365                 Ok(Self {
   365                     bytes: IndexData::new(bytes),
   366                     bytes: IndexData::new(bytes),
   366                     offsets: RwLock::new(Some(offsets)),
   367                     offsets: RwLock::new(Some(offsets)),
   367                     uses_generaldelta,
   368                     uses_generaldelta,
   368                     is_inline: true,
   369                     is_inline: true,
   369                     head_revs: vec![],
   370                     head_revs: RwLock::new((vec![], HashSet::new())),
   370                     filtered_revs: HashSet::new(),
       
   371                 })
   371                 })
   372             } else {
   372             } else {
   373                 Err(HgError::corrupted("unexpected inline revlog length"))
   373                 Err(HgError::corrupted("unexpected inline revlog length"))
   374             }
   374             }
   375         } else {
   375         } else {
   376             Ok(Self {
   376             Ok(Self {
   377                 bytes: IndexData::new(bytes),
   377                 bytes: IndexData::new(bytes),
   378                 offsets: RwLock::new(None),
   378                 offsets: RwLock::new(None),
   379                 uses_generaldelta,
   379                 uses_generaldelta,
   380                 is_inline: false,
   380                 is_inline: false,
   381                 head_revs: vec![],
   381                 head_revs: RwLock::new((vec![], HashSet::new())),
   382                 filtered_revs: HashSet::new(),
       
   383             })
   382             })
   384         }
   383         }
   385     }
   384     }
   386 
   385 
   387     pub fn uses_generaldelta(&self) -> bool {
   386     pub fn uses_generaldelta(&self) -> bool {
   530             offset_override: Some(0),
   529             offset_override: Some(0),
   531         }
   530         }
   532     }
   531     }
   533 
   532 
   534     /// Return the head revisions of this index
   533     /// Return the head revisions of this index
   535     pub fn head_revs(&mut self) -> Result<Vec<Revision>, GraphError> {
   534     pub fn head_revs(&self) -> Result<Vec<Revision>, GraphError> {
   536         self.head_revs_filtered(&HashSet::new())
   535         self.head_revs_filtered(&HashSet::new())
   537     }
   536     }
   538 
   537 
   539     /// Return the head revisions of this index
   538     /// Return the head revisions of this index
   540     pub fn head_revs_filtered(
   539     pub fn head_revs_filtered(
   541         &mut self,
   540         &self,
   542         filtered_revs: &HashSet<Revision>,
   541         filtered_revs: &HashSet<Revision>,
   543     ) -> Result<Vec<Revision>, GraphError> {
   542     ) -> Result<Vec<Revision>, GraphError> {
   544         if !self.head_revs.is_empty() && filtered_revs == &self.filtered_revs {
   543         {
   545             return Ok(self.head_revs.to_owned());
   544             let guard = self
       
   545                 .head_revs
       
   546                 .read()
       
   547                 .expect("RwLock on Index.head_revs should not be poisoned");
       
   548             let self_head_revs = &guard.0;
       
   549             let self_filtered_revs = &guard.1;
       
   550             if !self_head_revs.is_empty()
       
   551                 && filtered_revs == self_filtered_revs
       
   552             {
       
   553                 return Ok(self_head_revs.to_owned());
       
   554             }
   546         }
   555         }
   547         let mut revs: HashSet<Revision, RandomState> =
   556         let mut revs: HashSet<Revision, RandomState> =
   548             if filtered_revs.is_empty() {
   557             if filtered_revs.is_empty() {
   549                 (0..self.len())
   558                 (0..self.len())
   550                     .into_iter()
   559                     .into_iter()
   568             revs.insert(NULL_REVISION);
   577             revs.insert(NULL_REVISION);
   569         }
   578         }
   570         let mut as_vec: Vec<Revision> =
   579         let mut as_vec: Vec<Revision> =
   571             revs.into_iter().map(Into::into).collect();
   580             revs.into_iter().map(Into::into).collect();
   572         as_vec.sort_unstable();
   581         as_vec.sort_unstable();
   573         self.head_revs = as_vec.to_owned();
   582         *self
   574         self.filtered_revs = filtered_revs.to_owned();
   583             .head_revs
       
   584             .write()
       
   585             .expect("RwLock on Index.head_revs should not be poisoned") =
       
   586             (as_vec.to_owned(), filtered_revs.to_owned());
   575         Ok(as_vec)
   587         Ok(as_vec)
   576     }
   588     }
   577 
   589 
   578     /// Obtain the delta chain for a revision.
   590     /// Obtain the delta chain for a revision.
   579     ///
   591     ///
   649             cache.insert_for(base.0, rev)?;
   661             cache.insert_for(base.0, rev)?;
   650         }
   662         }
   651         Ok(())
   663         Ok(())
   652     }
   664     }
   653 
   665 
       
   666     fn clear_head_revs(&self) {
       
   667         self.head_revs
       
   668             .write()
       
   669             .expect("RwLock on Index.head_revs should not be poisoined")
       
   670             .0
       
   671             .clear()
       
   672     }
       
   673 
   654     /// TODO move this to the trait probably, along with other things
   674     /// TODO move this to the trait probably, along with other things
   655     pub fn append(
   675     pub fn append(
   656         &mut self,
   676         &mut self,
   657         revision_data: RevisionDataParams,
   677         revision_data: RevisionDataParams,
   658     ) -> Result<(), RevlogError> {
   678     ) -> Result<(), RevlogError> {
   660         let new_offset = self.bytes.len();
   680         let new_offset = self.bytes.len();
   661         if let Some(offsets) = &mut *self.get_offsets_mut() {
   681         if let Some(offsets) = &mut *self.get_offsets_mut() {
   662             offsets.push(new_offset)
   682             offsets.push(new_offset)
   663         }
   683         }
   664         self.bytes.added.extend(revision_data.into_v1().as_bytes());
   684         self.bytes.added.extend(revision_data.into_v1().as_bytes());
   665         self.head_revs.clear();
   685         self.clear_head_revs();
   666         Ok(())
   686         Ok(())
   667     }
   687     }
   668 
   688 
   669     pub fn pack_header(&self, header: i32) -> [u8; 4] {
   689     pub fn pack_header(&self, header: i32) -> [u8; 4] {
   670         header.to_be_bytes()
   690         header.to_be_bytes()
   674         let offsets = self.get_offsets().clone();
   694         let offsets = self.get_offsets().clone();
   675         self.bytes.remove(rev, offsets.as_deref())?;
   695         self.bytes.remove(rev, offsets.as_deref())?;
   676         if let Some(offsets) = &mut *self.get_offsets_mut() {
   696         if let Some(offsets) = &mut *self.get_offsets_mut() {
   677             offsets.truncate(rev.0 as usize)
   697             offsets.truncate(rev.0 as usize)
   678         }
   698         }
   679         self.head_revs.clear();
   699         self.clear_head_revs();
   680         Ok(())
   700         Ok(())
   681     }
   701     }
   682 
   702 
   683     pub fn clear_caches(&mut self) {
   703     pub fn clear_caches(&self) {
   684         // We need to get the 'inline' value from Python at init and use this
   704         // We need to get the 'inline' value from Python at init and use this
   685         // instead of offsets to determine whether we're inline since we might
   705         // instead of offsets to determine whether we're inline since we might
   686         // clear caches. This implies re-populating the offsets on-demand.
   706         // clear caches. This implies re-populating the offsets on-demand.
   687         self.offsets = RwLock::new(None);
   707         *self
   688         self.head_revs.clear();
   708             .offsets
       
   709             .write()
       
   710             .expect("RwLock on Index.offsets should not be poisoed") = None;
       
   711         self.clear_head_revs();
   689     }
   712     }
   690 
   713 
   691     /// Unchecked version of `is_snapshot`.
   714     /// Unchecked version of `is_snapshot`.
   692     /// Assumes the caller checked that `rev` is within a valid revision range.
   715     /// Assumes the caller checked that `rev` is within a valid revision range.
   693     pub fn is_snapshot_unchecked(
   716     pub fn is_snapshot_unchecked(