annotate rust/hg-core/src/revlog/file_io.rs @ 52280:f4aede0f01af

rust-manifest: use `memchr` crate for all byte-finding needs While writing a very dumb manifest diffing algorithm for a proof-of-concept I saw that `Manifest::find_by_path` was much slower than I was expecting. It turns out that the Rust stdlib uses slow (all is relative) code when searching for byte positions for reasons ranging from portability, SIMD API stability, nobody doing the work, etc. `memch` is much faster for these purposes, so let's use it. I was measuring ~670ms of profile time in `find_by_path`, after this patch it went down to ~230ms.
author Rapha?l Gom?s <rgomes@octobus.net>
date Tue, 12 Nov 2024 23:20:04 +0100
parents 8d35941689af
children 645d247d4c75
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
52155
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
1 //! Helpers for revlog file reading and writing.
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
2
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
3 use std::{
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
4 cell::RefCell,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
5 io::{Read, Seek, SeekFrom, Write},
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
6 path::{Path, PathBuf},
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
7 sync::{Arc, Mutex},
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
8 };
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
9
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
10 use crate::{
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
11 errors::{HgError, IoResultExt},
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
12 vfs::{Vfs, VfsFile},
52155
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
13 };
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
14
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
15 /// Wraps accessing arbitrary chunks of data within a file and reusing handles.
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
16 /// This is currently useful for accessing a revlog's data file, only reading
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
17 /// the ranges that are currently relevant, like a sort of basic and manual
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
18 /// file-based mmap.
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
19 ///
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
20 /// XXX should this just be replaced with `mmap` + `madvise` ranges?
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
21 /// The upcoming `UncompressedChunkCache` will make up for most of the slowness
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
22 /// of re-reading the same chunks, so this might not be as useful. Aside from
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
23 /// the major benefit of having less code to take care of, using `mmap` will
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
24 /// allow multiple processes to share the same pages, especially for the
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
25 /// changelog and manifest, which would make a difference in server contexts.
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
26 pub struct RandomAccessFile {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
27 /// The current store VFS to pass it to [`FileHandle`]
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
28 vfs: Box<dyn Vfs>,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
29 /// Filename of the open file, relative to the vfs root
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
30 pub filename: PathBuf,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
31 /// The current read-only handle on the file, if any
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
32 pub reading_handle: RefCell<Option<FileHandle>>,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
33 /// The current read-write handle on the file, if any
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
34 pub writing_handle: RefCell<Option<FileHandle>>,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
35 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
36
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
37 impl RandomAccessFile {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
38 /// Wrap a file for random access
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
39 pub fn new(vfs: Box<dyn Vfs>, filename: PathBuf) -> Self {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
40 assert!(filename.is_relative());
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
41 Self {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
42 vfs,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
43 filename,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
44 reading_handle: RefCell::new(None),
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
45 writing_handle: RefCell::new(None),
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
46 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
47 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
48
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
49 /// Read a chunk of bytes from the file.
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
50 pub fn read_chunk(
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
51 &self,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
52 offset: usize,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
53 length: usize,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
54 ) -> Result<Vec<u8>, HgError> {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
55 let mut handle = self.get_read_handle()?;
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
56 handle
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
57 .seek(SeekFrom::Start(offset as u64))
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
58 .when_reading_file(&self.filename)?;
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
59 handle.read_exact(length).when_reading_file(&self.filename)
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
60 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
61
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
62 /// `pub` only for hg-cpython
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
63 #[doc(hidden)]
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
64 pub fn get_read_handle(&self) -> Result<FileHandle, HgError> {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
65 if let Some(handle) = &*self.writing_handle.borrow() {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
66 // Use a file handle being actively used for writes, if available.
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
67 // There is some danger to doing this because reads will seek the
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
68 // file.
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
69 // However, [`Revlog::write_entry`] performs a `SeekFrom::End(0)`
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
70 // before all writes, so we should be safe.
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
71 return Ok(handle.clone());
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
72 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
73 if let Some(handle) = &*self.reading_handle.borrow() {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
74 return Ok(handle.clone());
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
75 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
76 // early returns done to work around borrowck being overzealous
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
77 // See https://github.com/rust-lang/rust/issues/103108
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
78 let new_handle = FileHandle::new(
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
79 dyn_clone::clone_box(&*self.vfs),
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
80 &self.filename,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
81 false,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
82 false,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
83 )?;
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
84 *self.reading_handle.borrow_mut() = Some(new_handle.clone());
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
85 Ok(new_handle)
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
86 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
87
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
88 /// `pub` only for hg-cpython
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
89 #[doc(hidden)]
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
90 pub fn exit_reading_context(&self) {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
91 self.reading_handle.take();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
92 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
93
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
94 // Returns whether this file currently open
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
95 pub fn is_open(&self) -> bool {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
96 self.reading_handle.borrow().is_some()
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
97 || self.writing_handle.borrow().is_some()
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
98 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
99 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
100
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
101 /// A buffer that holds new changelog index data that needs to be written
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
102 /// after the manifest and filelogs so that the repo is updated atomically to
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
103 /// external processes.
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
104 #[derive(Clone, Debug, Default)]
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
105 pub struct DelayedBuffer {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
106 // The actual in-memory bytes storing the delayed writes
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
107 pub(super) buffer: Vec<u8>,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
108 /// The current offset into the virtual file composed of file + buffer
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
109 offset: u64,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
110 /// The size of the file at the time of opening
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
111 file_size: u64,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
112 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
113
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
114 impl DelayedBuffer {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
115 /// Returns the length of the full data (on-disk + buffer length).
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
116 pub fn len(&self) -> u64 {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
117 self.buffer.len() as u64 + self.file_size
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
118 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
119
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
120 pub fn is_empty(&self) -> bool {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
121 self.len() == 0
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
122 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
123 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
124
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
125 /// Holds an open [`VfsFile`] and the related data. This can be used for
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
126 /// reading and writing. Writes can be delayed to a buffer before touching
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
127 /// the disk, if relevant (in the changelog case), but reads are transparent.
52155
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
128 pub struct FileHandle {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
129 /// The actual open file
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
130 pub file: VfsFile,
52155
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
131 /// The VFS with which the file was opened
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
132 vfs: Box<dyn Vfs>,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
133 /// Filename of the open file, relative to the repo root
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
134 filename: PathBuf,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
135 /// Buffer of delayed entry writes to the changelog index. This points
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
136 /// back to the buffer inside the revlog this handle refers to.
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
137 delayed_buffer: Option<Arc<Mutex<DelayedBuffer>>>,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
138 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
139
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
140 impl std::fmt::Debug for FileHandle {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
141 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
142 f.debug_struct("FileHandle")
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
143 .field("filename", &self.filename)
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
144 .field("delayed_buffer", &self.delayed_buffer)
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
145 .field("file", &self.file)
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
146 .finish()
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
147 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
148 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
149
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
150 impl Clone for FileHandle {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
151 fn clone(&self) -> Self {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
152 Self {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
153 vfs: dyn_clone::clone_box(&*self.vfs),
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
154 filename: self.filename.clone(),
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
155 delayed_buffer: self.delayed_buffer.clone(),
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
156 // This can only fail if the OS doesn't have the file handle
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
157 // anymore, so we're not going to do anything useful anyway.
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
158 file: self.file.try_clone().expect("couldn't clone file handle"),
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
159 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
160 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
161 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
162
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
163 impl FileHandle {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
164 /// Get a (read or write) file handle to `filename`. Only creates the file
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
165 /// if `create` is `true`.
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
166 pub fn new(
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
167 vfs: Box<dyn Vfs>,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
168 filename: impl AsRef<Path>,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
169 create: bool,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
170 write: bool,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
171 ) -> Result<Self, HgError> {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
172 let file = if create {
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
173 vfs.create(filename.as_ref(), false)?
52155
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
174 } else if write {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
175 vfs.open(filename.as_ref())?
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
176 } else {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
177 vfs.open_read(filename.as_ref())?
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
178 };
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
179 Ok(Self {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
180 vfs,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
181 filename: filename.as_ref().to_owned(),
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
182 delayed_buffer: None,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
183 file,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
184 })
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
185 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
186
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
187 /// Get a file handle to `filename`, but writes go to a [`DelayedBuffer`].
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
188 pub fn new_delayed(
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
189 vfs: Box<dyn Vfs>,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
190 filename: impl AsRef<Path>,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
191 create: bool,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
192 delayed_buffer: Arc<Mutex<DelayedBuffer>>,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
193 ) -> Result<Self, HgError> {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
194 let mut file = if create {
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
195 vfs.create(filename.as_ref(), false)?
52155
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
196 } else {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
197 vfs.open(filename.as_ref())?
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
198 };
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
199 let size = vfs.file_size(&file)?;
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
200 let offset = file
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
201 .stream_position()
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
202 .when_reading_file(filename.as_ref())?;
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
203
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
204 {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
205 let mut buf = delayed_buffer.lock().unwrap();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
206 buf.file_size = size;
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
207 buf.offset = offset;
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
208 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
209
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
210 Ok(Self {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
211 vfs,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
212 filename: filename.as_ref().to_owned(),
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
213 delayed_buffer: Some(delayed_buffer),
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
214 file,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
215 })
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
216 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
217
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
218 /// Wrap an existing [`VfsFile`]
52155
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
219 pub fn from_file(
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
220 file: VfsFile,
52155
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
221 vfs: Box<dyn Vfs>,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
222 filename: impl AsRef<Path>,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
223 ) -> Self {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
224 Self {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
225 vfs,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
226 filename: filename.as_ref().to_owned(),
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
227 delayed_buffer: None,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
228 file,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
229 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
230 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
231
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
232 /// Wrap an existing [`VfsFile`], but writes go to a [`DelayedBuffer`].
52155
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
233 pub fn from_file_delayed(
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
234 mut file: VfsFile,
52155
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
235 vfs: Box<dyn Vfs>,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
236 filename: impl AsRef<Path>,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
237 delayed_buffer: Arc<Mutex<DelayedBuffer>>,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
238 ) -> Result<Self, HgError> {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
239 let size = vfs.file_size(&file)?;
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
240 let offset = file
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
241 .stream_position()
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
242 .when_reading_file(filename.as_ref())?;
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
243
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
244 {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
245 let mut buf = delayed_buffer.lock().unwrap();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
246 buf.file_size = size;
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
247 buf.offset = offset;
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
248 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
249
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
250 Ok(Self {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
251 vfs,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
252 filename: filename.as_ref().to_owned(),
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
253 delayed_buffer: Some(delayed_buffer),
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
254 file,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
255 })
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
256 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
257
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
258 /// Move the position of the handle to `pos`,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
259 /// spanning the [`DelayedBuffer`] if defined. Will return an error if
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
260 /// an invalid seek position is asked, or for any standard io error.
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
261 pub fn seek(&mut self, pos: SeekFrom) -> Result<u64, std::io::Error> {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
262 if let Some(delay_buf) = &self.delayed_buffer {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
263 let mut delay_buf = delay_buf.lock().unwrap();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
264 // Virtual file offset spans real file and data
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
265 match pos {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
266 SeekFrom::Start(offset) => delay_buf.offset = offset,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
267 SeekFrom::End(offset) => {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
268 delay_buf.offset =
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
269 delay_buf.len().saturating_add_signed(offset)
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
270 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
271 SeekFrom::Current(offset) => {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
272 delay_buf.offset =
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
273 delay_buf.offset.saturating_add_signed(offset);
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
274 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
275 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
276 if delay_buf.offset < delay_buf.file_size {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
277 self.file.seek(pos)
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
278 } else {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
279 Ok(delay_buf.offset)
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
280 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
281 } else {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
282 self.file.seek(pos)
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
283 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
284 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
285
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
286 /// Read exactly `length` bytes from the current position.
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
287 /// Errors are the same as [`std::io::Read::read_exact`].
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
288 pub fn read_exact(
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
289 &mut self,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
290 length: usize,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
291 ) -> Result<Vec<u8>, std::io::Error> {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
292 if let Some(delay_buf) = self.delayed_buffer.as_mut() {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
293 let mut delay_buf = delay_buf.lock().unwrap();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
294 let mut buf = vec![0; length];
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
295 let offset: isize =
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
296 delay_buf.offset.try_into().expect("buffer too large");
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
297 let file_size: isize =
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
298 delay_buf.file_size.try_into().expect("file too large");
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
299 let span: isize = offset - file_size;
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
300 let length = length.try_into().expect("too large of a length");
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
301 let absolute_span: u64 =
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
302 span.unsigned_abs().try_into().expect("length too large");
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
303 if span < 0 {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
304 if length <= absolute_span {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
305 // We're only in the file
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
306 self.file.read_exact(&mut buf)?;
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
307 } else {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
308 // We're spanning file and buffer
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
309 self.file
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
310 .read_exact(&mut buf[..absolute_span as usize])?;
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
311 delay_buf
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
312 .buffer
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
313 .take(length - absolute_span)
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
314 .read_exact(&mut buf[absolute_span as usize..])?;
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
315 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
316 } else {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
317 // We're only in the buffer
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
318 delay_buf.buffer[absolute_span as usize..]
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
319 .take(length)
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
320 .read_exact(&mut buf)?;
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
321 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
322 delay_buf.offset += length;
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
323 Ok(buf.to_owned())
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
324 } else {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
325 let mut buf = vec![0; length];
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
326 self.file.read_exact(&mut buf)?;
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
327 Ok(buf)
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
328 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
329 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
330
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
331 /// Flush the in-memory changes to disk. This does *not* write the
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
332 /// delayed buffer, only the pending file changes.
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
333 pub fn flush(&mut self) -> Result<(), HgError> {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
334 self.file.flush().when_writing_file(&self.filename)
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
335 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
336
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
337 /// Return the current position in the file
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
338 pub fn position(&mut self) -> Result<u64, HgError> {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
339 self.file
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
340 .stream_position()
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
341 .when_reading_file(&self.filename)
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
342 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
343
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
344 /// Append `data` to the file, or to the [`DelayedBuffer`], if any.
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
345 pub fn write_all(&mut self, data: &[u8]) -> Result<(), HgError> {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
346 if let Some(buf) = &mut self.delayed_buffer {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
347 let mut delayed_buffer = buf.lock().expect("propagate the panic");
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
348 assert_eq!(delayed_buffer.offset, delayed_buffer.len());
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
349 delayed_buffer.buffer.extend_from_slice(data);
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
350 delayed_buffer.offset += data.len() as u64;
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
351 Ok(())
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
352 } else {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
353 self.file
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
354 .write_all(data)
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
355 .when_writing_file(&self.filename)?;
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
356 Ok(())
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
357 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
358 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
359 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
360
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
361 /// Write handles to a given revlog (index + maybe data)
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
362 #[derive(Debug)]
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
363 pub struct WriteHandles {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
364 /// Handle to the index file
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
365 pub index_handle: FileHandle,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
366 /// Handle to the data file, if the revlog is non-inline
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
367 pub data_handle: Option<FileHandle>,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
368 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
369
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
370 #[cfg(test)]
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
371 mod tests {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
372 use std::io::ErrorKind;
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
373
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
374 use crate::vfs::VfsImpl;
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
375
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
376 use super::*;
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
377
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
378 #[test]
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
379 fn test_random_access_file() {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
380 let base = tempfile::tempdir().unwrap().into_path();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
381 let filename = Path::new("a");
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
382 let file_path = base.join(filename);
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
383 let raf = RandomAccessFile::new(
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
384 Box::new(VfsImpl::new(base.clone(), true)),
52155
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
385 filename.to_owned(),
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
386 );
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
387
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
388 assert!(!raf.is_open());
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
389 assert_eq!(&raf.filename, &filename);
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
390 // Should fail to read a non-existing file
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
391 match raf.get_read_handle().unwrap_err() {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
392 HgError::IoError { error, .. } => match error.kind() {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
393 std::io::ErrorKind::NotFound => {}
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
394 _ => panic!("should be not found"),
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
395 },
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
396 e => panic!("{}", e.to_string()),
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
397 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
398
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
399 std::fs::write(file_path, b"1234567890").unwrap();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
400
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
401 // Should be able to open an existing file
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
402 let mut handle = raf.get_read_handle().unwrap();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
403 assert!(raf.is_open());
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
404 assert_eq!(handle.read_exact(10).unwrap(), b"1234567890".to_vec());
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
405 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
406
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
407 #[test]
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
408 fn test_file_handle() {
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
409 let base = tempfile::tempdir().unwrap().into_path();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
410 let filename = base.join("a");
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
411 // No `create` should fail
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
412 FileHandle::new(
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
413 Box::new(VfsImpl::new(base.clone(), false)),
52155
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
414 &filename,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
415 false,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
416 false,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
417 )
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
418 .unwrap_err();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
419 std::fs::write(&filename, b"1234567890").unwrap();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
420
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
421 let mut read_handle = FileHandle::new(
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
422 Box::new(VfsImpl::new(base.clone(), true)),
52155
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
423 &filename,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
424 false,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
425 false,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
426 )
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
427 .unwrap();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
428 assert_eq!(&read_handle.filename, &filename);
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
429 assert_eq!(read_handle.position().unwrap(), 0);
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
430
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
431 // Writing to an explicit read handle should fail
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
432 read_handle.write_all(b"some data").unwrap_err();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
433
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
434 // reading exactly n bytes should work
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
435 assert_eq!(read_handle.read_exact(3).unwrap(), b"123".to_vec());
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
436 // and the position should be remembered
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
437 assert_eq!(read_handle.read_exact(2).unwrap(), b"45".to_vec());
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
438
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
439 // Seeking should work
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
440 let position = read_handle.position().unwrap();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
441 read_handle.seek(SeekFrom::Current(-2)).unwrap();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
442 assert_eq!(position - 2, read_handle.position().unwrap());
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
443
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
444 // Seeking too much data should fail
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
445 read_handle.read_exact(1000).unwrap_err();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
446
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
447 // Open a write handle
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
448 let mut handle = FileHandle::new(
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
449 Box::new(VfsImpl::new(base.clone(), false)),
52155
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
450 &filename,
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
451 false,
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
452 true,
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
453 )
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
454 .unwrap();
52155
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
455
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
456 // Now writing should succeed
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
457 handle.write_all(b"new data").unwrap();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
458 // Opening or writing does not seek, so we should be at the start
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
459 assert_eq!(handle.position().unwrap(), 8);
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
460 // We can still read
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
461 assert_eq!(handle.read_exact(2).unwrap(), b"90".to_vec());
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
462
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
463 let mut read_handle = FileHandle::new(
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
464 Box::new(VfsImpl::new(base.clone(), true)),
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
465 &filename,
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
466 false,
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
467 false,
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
468 )
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
469 .unwrap();
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
470 read_handle.seek(SeekFrom::Start(0)).unwrap();
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
471 // On-disk file contents should be changed
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
472 assert_eq!(
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
473 &read_handle.read_exact(10).unwrap(),
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
474 &b"new data90".to_vec(),
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
475 );
52155
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
476 // Flushing doesn't do anything unexpected
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
477 handle.flush().unwrap();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
478
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
479 let delayed_buffer = Arc::new(Mutex::new(DelayedBuffer::default()));
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
480 let mut handle = FileHandle::new_delayed(
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
481 Box::new(VfsImpl::new(base.clone(), false)),
52155
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
482 &filename,
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52155
diff changeset
483 false,
52155
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
484 delayed_buffer,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
485 )
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
486 .unwrap();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
487
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
488 assert_eq!(
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
489 handle
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
490 .delayed_buffer
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
491 .as_ref()
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
492 .unwrap()
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
493 .lock()
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
494 .unwrap()
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
495 .file_size,
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
496 10
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
497 );
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
498 handle.seek(SeekFrom::End(0)).unwrap();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
499 handle.write_all(b"should go to buffer").unwrap();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
500 assert_eq!(
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
501 handle
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
502 .delayed_buffer
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
503 .as_ref()
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
504 .unwrap()
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
505 .lock()
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
506 .unwrap()
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
507 .len(),
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
508 29
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
509 );
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
510 read_handle.seek(SeekFrom::Start(0)).unwrap();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
511 // On-disk file contents should be unchanged
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
512 assert_eq!(
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
513 read_handle.read_exact(10).unwrap(),
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
514 b"new data90".to_vec(),
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
515 );
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
516
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
517 assert_eq!(
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
518 read_handle.read_exact(1).unwrap_err().kind(),
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
519 ErrorKind::UnexpectedEof
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
520 );
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
521
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
522 handle.flush().unwrap();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
523 // On-disk file contents should still be unchanged after a flush
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
524 assert_eq!(
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
525 read_handle.read_exact(1).unwrap_err().kind(),
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
526 ErrorKind::UnexpectedEof
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
527 );
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
528
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
529 // Read from the buffer only
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
530 handle.seek(SeekFrom::End(-1)).unwrap();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
531 assert_eq!(handle.read_exact(1).unwrap(), b"r".to_vec());
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
532
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
533 // Read from an overlapping section of file and buffer
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
534 handle.seek(SeekFrom::Start(6)).unwrap();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
535 assert_eq!(
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
536 handle.read_exact(20).unwrap(),
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
537 b"ta90should go to buf".to_vec()
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
538 );
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
539
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
540 // Read from file only
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
541 handle.seek(SeekFrom::Start(0)).unwrap();
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
542 assert_eq!(handle.read_exact(8).unwrap(), b"new data".to_vec());
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
543 }
426696af24d3 rust-revlog: add file IO helpers
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
544 }