rust/hg-core/src/revlog/index.rs
changeset 51445 d2858d97af6c
parent 51425 7c6d0b9dde37
--- a/rust/hg-core/src/revlog/index.rs	Mon Feb 26 13:41:02 2024 +0100
+++ b/rust/hg-core/src/revlog/index.rs	Mon Feb 26 12:59:57 2024 +0100
@@ -18,11 +18,12 @@
 };
 
 pub const INDEX_ENTRY_SIZE: usize = 64;
+pub const INDEX_HEADER_SIZE: usize = 4;
 pub const COMPRESSION_MODE_INLINE: u8 = 2;
 
 #[derive(Debug)]
 pub struct IndexHeader {
-    pub(super) header_bytes: [u8; 4],
+    pub(super) header_bytes: [u8; INDEX_HEADER_SIZE],
 }
 
 #[derive(Copy, Clone)]
@@ -92,14 +93,21 @@
     truncation: Option<usize>,
     /// Bytes that were added after reading the index
     added: Vec<u8>,
+    first_entry: [u8; INDEX_ENTRY_SIZE],
 }
 
 impl IndexData {
     pub fn new(bytes: Box<dyn Deref<Target = [u8]> + Send + Sync>) -> Self {
+        let mut first_entry = [0; INDEX_ENTRY_SIZE];
+        if bytes.len() >= INDEX_ENTRY_SIZE {
+            first_entry[INDEX_HEADER_SIZE..]
+                .copy_from_slice(&bytes[INDEX_HEADER_SIZE..INDEX_ENTRY_SIZE])
+        }
         Self {
             bytes,
             truncation: None,
             added: vec![],
+            first_entry,
         }
     }
 
@@ -356,7 +364,6 @@
                 let end = offset + INDEX_ENTRY_SIZE;
                 let entry = IndexEntry {
                     bytes: &bytes[offset..end],
-                    offset_override: None,
                 };
 
                 offset += INDEX_ENTRY_SIZE + entry.compressed_len() as usize;
@@ -449,11 +456,17 @@
         if rev == NULL_REVISION {
             return None;
         }
-        Some(if self.is_inline() {
-            self.get_entry_inline(rev)
+        if rev.0 == 0 {
+            Some(IndexEntry {
+                bytes: &self.bytes.first_entry[..],
+            })
         } else {
-            self.get_entry_separated(rev)
-        })
+            Some(if self.is_inline() {
+                self.get_entry_inline(rev)
+            } else {
+                self.get_entry_separated(rev)
+            })
+        }
     }
 
     /// Return the binary content of the index entry for the given revision
@@ -512,13 +525,7 @@
         let end = start + INDEX_ENTRY_SIZE;
         let bytes = &self.bytes[start..end];
 
-        // See IndexEntry for an explanation of this override.
-        let offset_override = Some(end);
-
-        IndexEntry {
-            bytes,
-            offset_override,
-        }
+        IndexEntry { bytes }
     }
 
     fn get_entry_separated(&self, rev: Revision) -> IndexEntry {
@@ -526,20 +533,12 @@
         let end = start + INDEX_ENTRY_SIZE;
         let bytes = &self.bytes[start..end];
 
-        // Override the offset of the first revision as its bytes are used
-        // for the index's metadata (saving space because it is always 0)
-        let offset_override = if rev == Revision(0) { Some(0) } else { None };
-
-        IndexEntry {
-            bytes,
-            offset_override,
-        }
+        IndexEntry { bytes }
     }
 
     fn null_entry(&self) -> IndexEntry {
         IndexEntry {
             bytes: &[0; INDEX_ENTRY_SIZE],
-            offset_override: Some(0),
         }
     }
 
@@ -755,13 +754,20 @@
         revision_data: RevisionDataParams,
     ) -> Result<(), RevlogError> {
         revision_data.validate()?;
+        let entry_v1 = revision_data.into_v1();
+        let entry_bytes = entry_v1.as_bytes();
+        if self.bytes.len() == 0 {
+            self.bytes.first_entry[INDEX_HEADER_SIZE..].copy_from_slice(
+                &entry_bytes[INDEX_HEADER_SIZE..INDEX_ENTRY_SIZE],
+            )
+        }
         if self.is_inline() {
             let new_offset = self.bytes.len();
             if let Some(offsets) = &mut *self.get_offsets_mut() {
                 offsets.push(new_offset)
             }
         }
-        self.bytes.added.extend(revision_data.into_v1().as_bytes());
+        self.bytes.added.extend(entry_bytes);
         self.clear_head_revs();
         Ok(())
     }
@@ -1654,7 +1660,6 @@
         let end = offset + INDEX_ENTRY_SIZE;
         let entry = IndexEntry {
             bytes: &bytes[offset..end],
-            offset_override: None,
         };
 
         offset += INDEX_ENTRY_SIZE + entry.compressed_len() as usize;
@@ -1678,29 +1683,14 @@
 #[derive(Debug)]
 pub struct IndexEntry<'a> {
     bytes: &'a [u8],
-    /// Allows to override the offset value of the entry.
-    ///
-    /// For interleaved index and data, the offset stored in the index
-    /// corresponds to the separated data offset.
-    /// It has to be overridden with the actual offset in the interleaved
-    /// index which is just after the index block.
-    ///
-    /// For separated index and data, the offset stored in the first index
-    /// entry is mixed with the index headers.
-    /// It has to be overridden with 0.
-    offset_override: Option<usize>,
 }
 
 impl<'a> IndexEntry<'a> {
     /// Return the offset of the data.
     pub fn offset(&self) -> usize {
-        if let Some(offset_override) = self.offset_override {
-            offset_override
-        } else {
-            let mut bytes = [0; 8];
-            bytes[2..8].copy_from_slice(&self.bytes[0..=5]);
-            BigEndian::read_u64(&bytes[..]) as usize
-        }
+        let mut bytes = [0; 8];
+        bytes[2..8].copy_from_slice(&self.bytes[0..=5]);
+        BigEndian::read_u64(&bytes[..]) as usize
     }
     pub fn raw_offset(&self) -> u64 {
         BigEndian::read_u64(&self.bytes[0..8])
@@ -1956,32 +1946,15 @@
     #[test]
     fn test_offset() {
         let bytes = IndexEntryBuilder::new().with_offset(1).build();
-        let entry = IndexEntry {
-            bytes: &bytes,
-            offset_override: None,
-        };
+        let entry = IndexEntry { bytes: &bytes };
 
         assert_eq!(entry.offset(), 1)
     }
 
     #[test]
-    fn test_with_overridden_offset() {
-        let bytes = IndexEntryBuilder::new().with_offset(1).build();
-        let entry = IndexEntry {
-            bytes: &bytes,
-            offset_override: Some(2),
-        };
-
-        assert_eq!(entry.offset(), 2)
-    }
-
-    #[test]
     fn test_compressed_len() {
         let bytes = IndexEntryBuilder::new().with_compressed_len(1).build();
-        let entry = IndexEntry {
-            bytes: &bytes,
-            offset_override: None,
-        };
+        let entry = IndexEntry { bytes: &bytes };
 
         assert_eq!(entry.compressed_len(), 1)
     }
@@ -1989,10 +1962,7 @@
     #[test]
     fn test_uncompressed_len() {
         let bytes = IndexEntryBuilder::new().with_uncompressed_len(1).build();
-        let entry = IndexEntry {
-            bytes: &bytes,
-            offset_override: None,
-        };
+        let entry = IndexEntry { bytes: &bytes };
 
         assert_eq!(entry.uncompressed_len(), 1)
     }
@@ -2002,10 +1972,7 @@
         let bytes = IndexEntryBuilder::new()
             .with_base_revision_or_base_of_delta_chain(Revision(1))
             .build();
-        let entry = IndexEntry {
-            bytes: &bytes,
-            offset_override: None,
-        };
+        let entry = IndexEntry { bytes: &bytes };
 
         assert_eq!(entry.base_revision_or_base_of_delta_chain(), 1.into())
     }
@@ -2016,10 +1983,7 @@
             .with_link_revision(Revision(123))
             .build();
 
-        let entry = IndexEntry {
-            bytes: &bytes,
-            offset_override: None,
-        };
+        let entry = IndexEntry { bytes: &bytes };
 
         assert_eq!(entry.link_revision(), 123.into());
     }
@@ -2028,10 +1992,7 @@
     fn p1_test() {
         let bytes = IndexEntryBuilder::new().with_p1(Revision(123)).build();
 
-        let entry = IndexEntry {
-            bytes: &bytes,
-            offset_override: None,
-        };
+        let entry = IndexEntry { bytes: &bytes };
 
         assert_eq!(entry.p1(), 123.into());
     }
@@ -2040,10 +2001,7 @@
     fn p2_test() {
         let bytes = IndexEntryBuilder::new().with_p2(Revision(123)).build();
 
-        let entry = IndexEntry {
-            bytes: &bytes,
-            offset_override: None,
-        };
+        let entry = IndexEntry { bytes: &bytes };
 
         assert_eq!(entry.p2(), 123.into());
     }
@@ -2054,10 +2012,7 @@
             .unwrap();
         let bytes = IndexEntryBuilder::new().with_node(node).build();
 
-        let entry = IndexEntry {
-            bytes: &bytes,
-            offset_override: None,
-        };
+        let entry = IndexEntry { bytes: &bytes };
 
         assert_eq!(*entry.hash(), node);
     }