comparison rust/hg-core/src/revlog/inner_revlog.rs @ 52308:7756494c5ecd

rust-inner-revlog: cache the compressor The `compress` function is unlikely to be used in highly contended situations, and creating a compressor has some overhead, on top of losing out on some potential advantages of longer-running optimizations from the compressor.
author Raphaël Gomès <rgomes@octobus.net>
date Mon, 04 Nov 2024 12:10:22 +0100
parents 7ffc71552662
children f69a3f55fa9b
comparison
equal deleted inserted replaced
52307:22d24f6d6411 52308:7756494c5ecd
50 /// Data config that applies to this revlog 50 /// Data config that applies to this revlog
51 data_config: RevlogDataConfig, 51 data_config: RevlogDataConfig,
52 /// Delta config that applies to this revlog 52 /// Delta config that applies to this revlog
53 delta_config: RevlogDeltaConfig, 53 delta_config: RevlogDeltaConfig,
54 /// Feature config that applies to this revlog 54 /// Feature config that applies to this revlog
55 #[allow(unused)]
55 feature_config: RevlogFeatureConfig, 56 feature_config: RevlogFeatureConfig,
56 /// A view into this revlog's data file 57 /// A view into this revlog's data file
57 segment_file: RandomAccessFile, 58 segment_file: RandomAccessFile,
58 /// A cache of uncompressed chunks that have previously been restored. 59 /// A cache of uncompressed chunks that have previously been restored.
59 /// Its eviction policy is defined in [`Self::new`]. 60 /// Its eviction policy is defined in [`Self::new`].
69 /// Whether this revlog is inline. XXX why duplicate from `index`? 70 /// Whether this revlog is inline. XXX why duplicate from `index`?
70 pub inline: bool, 71 pub inline: bool,
71 /// A cache of the last revision, which is usually accessed multiple 72 /// A cache of the last revision, which is usually accessed multiple
72 /// times. 73 /// times.
73 pub last_revision_cache: Mutex<Option<SingleRevisionCache>>, 74 pub last_revision_cache: Mutex<Option<SingleRevisionCache>>,
75 /// The [`Compressor`] that this revlog uses by default to compress data.
76 /// This does not mean that this revlog uses this compressor for reading
77 /// data, as different revisions may have different compression modes.
78 compressor: Mutex<Box<dyn Compressor + Send>>,
74 } 79 }
75 80
76 impl InnerRevlog { 81 impl InnerRevlog {
77 pub fn new( 82 pub fn new(
78 vfs: Box<dyn Vfs>, 83 vfs: Box<dyn Vfs>,
115 original_index_file: None, 120 original_index_file: None,
116 writing_handles: None, 121 writing_handles: None,
117 delayed_buffer: None, 122 delayed_buffer: None,
118 inline, 123 inline,
119 last_revision_cache: Mutex::new(None), 124 last_revision_cache: Mutex::new(None),
125 compressor: Mutex::new(match feature_config.compression_engine {
126 CompressionConfig::Zlib { level } => {
127 Box::new(ZlibCompressor::new(level))
128 }
129 CompressionConfig::Zstd { level, threads } => {
130 Box::new(ZstdCompressor::new(level, threads))
131 }
132 CompressionConfig::None => Box::new(NoneCompressor),
133 }),
120 } 134 }
121 } 135 }
122 136
123 /// Return number of entries of the revlog index 137 /// Return number of entries of the revlog index
124 pub fn len(&self) -> usize { 138 pub fn len(&self) -> usize {
284 stop_rev, 298 stop_rev,
285 self.delta_config.general_delta.into(), 299 self.delta_config.general_delta.into(),
286 ) 300 )
287 } 301 }
288 302
289 fn compressor(&self) -> Result<Box<dyn Compressor>, HgError> {
290 // TODO cache the compressor?
291 Ok(match self.feature_config.compression_engine {
292 CompressionConfig::Zlib { level } => {
293 Box::new(ZlibCompressor::new(level))
294 }
295 CompressionConfig::Zstd { level, threads } => {
296 Box::new(ZstdCompressor::new(level, threads))
297 }
298 CompressionConfig::None => Box::new(NoneCompressor),
299 })
300 }
301
302 /// Generate a possibly-compressed representation of data. 303 /// Generate a possibly-compressed representation of data.
303 /// Returns `None` if the data was not compressed. 304 /// Returns `None` if the data was not compressed.
304 pub fn compress<'data>( 305 pub fn compress<'data>(
305 &self, 306 &self,
306 data: &'data [u8], 307 data: &'data [u8],
307 ) -> Result<Option<Cow<'data, [u8]>>, RevlogError> { 308 ) -> Result<Option<Cow<'data, [u8]>>, RevlogError> {
308 if data.is_empty() { 309 if data.is_empty() {
309 return Ok(Some(data.into())); 310 return Ok(Some(data.into()));
310 } 311 }
311 let res = self.compressor()?.compress(data)?; 312 let res = self.compressor.lock().unwrap().compress(data)?;
312 if let Some(compressed) = res { 313 if let Some(compressed) = res {
313 // The revlog compressor added the header in the returned data. 314 // The revlog compressor added the header in the returned data.
314 return Ok(Some(compressed.into())); 315 return Ok(Some(compressed.into()));
315 } 316 }
316 317