Skip to main content

atom_file/
lib.rs

1//! [`AtomicFile`] provides buffered concurrent access to files with async atomic commit.
2//!
3//! [`BasicAtomicFile`] is a non-async alternative.
4//!
5//! [`MultiFileStorage`] is the recommended backing storage for AtomicFile.
6//!
7//! [`FastFileStorage`] is the recommended temporary storage for AtomicFile.
8//!
9//!# Features
10//!
11//! This crate supports the following cargo features:
12//! - `pstd` : Use pstd crate for `BTreeMap` (allocated in `GTemp`).
13//! - `unsafe-optim` : Enable unsafe optimisations in release mode.
14
15#![deny(missing_docs)]
16
17use rustc_hash::FxHashMap as HashMap;
18use std::cell::Cell;
19use std::cmp::min;
20use std::sync::{Mutex, RwLock};
21
22pub use std::sync::Arc;
23
24#[cfg(feature = "pstd")]
25use pstd::{
26    VecA,
27    collections::{BTreeMapA, btree_map::CustomTuning},
28    localalloc::GTemp,
29    veca as gvec,
30};
31
32#[cfg(not(feature = "pstd"))]
33use std::{collections::BTreeMap, vec as gvec, vec::Vec as GVec};
34
35#[cfg(feature = "pstd")]
36type BTreeMap<K, V> = BTreeMapA<K, V, CustomTuning<GTemp>>;
37
38#[cfg(feature = "pstd")]
39type GVec<T> = VecA<T, GTemp>;
40
41/// ```Arc<Vec<u8>>```
42pub type Data = Arc<GVec<u8>>;
43
44/// Based on [BasicAtomicFile] which makes sure that updates are all-or-nothing.
45/// Performs commit asyncronously.
46///
47/// #Example
48///
49/// ```
50/// use atom_file::{AtomicFile,DummyFile,MemFile,BasicStorage};
51/// let mut af = AtomicFile::new(MemFile::new(), DummyFile::new());
52/// af.write( 0, &[1,2,3,4] );
53/// af.commit(4);
54/// af.wait_complete();
55/// ```
56///
57/// Atomic file has two maps of writes. On commit, the latest batch of writes are sent to be written to underlying
58/// storage, and are also applied to the second map in the "CommitFile". The CommitFile map is reset when all
59/// the updates to underlying storage have been applied.
60pub struct AtomicFile {
61    /// New updates are written here.
62    map: WMap,
63    /// Underlying file, with previous updates mapped.
64    cf: Arc<RwLock<CommitFile>>,
65    /// File size.
66    size: u64,
67    /// For sending update maps to be saved.
68    tx: std::sync::mpsc::Sender<(u64, WMap)>,
69    /// Held by update process while it is active.
70    busy: Arc<Mutex<()>>,
71    /// Limit on size of CommitFile map.
72    map_lim: usize,
73}
74
75impl AtomicFile {
76    /// Construct AtomicFile with default limits. stg is the main underlying storage, upd is temporary storage for updates during commit.
77    pub fn new(stg: Box<dyn Storage>, upd: Box<dyn BasicStorage>) -> Box<Self> {
78        Self::new_with_limits(stg, upd, &Limits::default())
79    }
80
81    /// Construct Atomic file with specified limits.
82    pub fn new_with_limits(
83        stg: Box<dyn Storage>,
84        upd: Box<dyn BasicStorage>,
85        lim: &Limits,
86    ) -> Box<Self> {
87        let size = stg.size();
88        let mut baf = BasicAtomicFile::new(stg.clone(), upd, lim);
89
90        let (tx, rx) = std::sync::mpsc::channel::<(u64, WMap)>();
91        let cf = Arc::new(RwLock::new(CommitFile::new(stg, lim.rbuf_mem)));
92        let busy = Arc::new(Mutex::new(())); // Lock held while async save thread is active.
93
94        // Start the thread which does save asyncronously.
95        let (cf1, busy1) = (cf.clone(), busy.clone());
96
97        std::thread::spawn(move || {
98            // Loop that recieves a map of updates and applies it to BasicAtomicFile.
99            while let Ok((size, map)) = rx.recv() {
100                let _lock = busy1.lock();
101                baf.map = map;
102                baf.commit(size);
103                cf1.write().unwrap().done_one();
104            }
105        });
106        Box::new(Self {
107            map: WMap::default(),
108            cf,
109            size,
110            tx,
111            busy,
112            map_lim: lim.map_lim,
113        })
114    }
115}
116
117impl Storage for AtomicFile {
118    fn clone(&self) -> Box<dyn Storage> {
119        panic!()
120    }
121}
122
123impl BasicStorage for AtomicFile {
124    fn commit(&mut self, size: u64) {
125        self.size = size;
126        if self.map.is_empty() {
127            return;
128        }
129        if self.cf.read().unwrap().map.len() > self.map_lim {
130            self.wait_complete();
131        }
132        let map = std::mem::take(&mut self.map);
133        let stop =
134        {
135            let cf = &mut *self.cf.write().unwrap();
136            if cf.stop { true }
137            else
138            {
139                cf.todo += 1;
140                // Apply map of updates to CommitFile.
141                map.to_storage(cf);
142                // Send map of updates to thread to be written to underlying storage.
143                self.tx.send((size, map)).unwrap();
144                false
145            }
146        };
147        if stop {
148            // Program is terminating, loop forever.
149            loop { std::thread::sleep(std::time::Duration::from_millis(100)); }
150        }
151    }
152
153    fn size(&self) -> u64 {
154        self.size
155    }
156
157    fn read(&self, start: u64, data: &mut [u8]) {
158        self.map.read(start, data, &*self.cf.read().unwrap());
159    }
160
161    fn write_data(&mut self, start: u64, data: Data, off: usize, len: usize) {
162        self.map.write(start, data, off, len);
163    }
164
165    fn write(&mut self, start: u64, data: &[u8]) {
166        let len = data.len();
167        let d = Arc::new(data.to_vec());
168        self.write_data(start, d, 0, len);
169    }
170
171    fn wait_complete(&self) {
172       while self.cf.read().unwrap().todo != 0 {
173           std::thread::yield_now();
174           let _x = self.busy.lock();
175       }
176    }   
177
178    fn shutdown(&mut self) {
179        self.cf.write().unwrap().stop = true; // Prevents new commits from being added.
180        self.wait_complete();
181    }       
182}
183
184struct CommitFile {
185    /// Buffered underlying storage.
186    stg: ReadBufStg<256>,
187    /// Map of committed updates.
188    map: WMap,
189    /// Number of outstanding unsaved commits.
190    todo: usize,
191    /// Flag to prevent new commits starting
192    stop: bool,
193}
194
195impl CommitFile {
196    fn new(stg: Box<dyn Storage>, buf_mem: usize) -> Self {
197        Self {
198            stg: ReadBufStg::<256>::new(stg, 50, buf_mem / 256),
199            map: WMap::default(),
200            todo: 0,
201            stop: false,
202        }
203    }
204
205    fn done_one(&mut self) {
206        self.todo -= 1;
207        if self.todo == 0 {
208            self.map = WMap::default();
209            self.stg.reset();
210        }
211    }
212}
213
214impl BasicStorage for CommitFile {
215    fn commit(&mut self, _size: u64) {
216        panic!()
217    }
218
219    fn size(&self) -> u64 {
220        panic!()
221    }
222
223    fn read(&self, start: u64, data: &mut [u8]) {
224        self.map.read(start, data, &self.stg);
225    }
226
227    fn write_data(&mut self, start: u64, data: Data, off: usize, len: usize) {
228        self.map.write(start, data, off, len);
229    }
230
231    fn write(&mut self, _start: u64, _data: &[u8]) {
232        panic!()
233    }
234}
235
236/// Storage interface - BasicStorage is some kind of "file" storage.
237///
238/// read and write methods take a start which is a byte offset in the underlying file.
239pub trait BasicStorage: Send {
240    /// Get the size of the underlying storage.
241    /// Note : this is valid initially and after a commit but is not defined after write is called.
242    fn size(&self) -> u64;
243
244    /// Read data.
245    fn read(&self, start: u64, data: &mut [u8]);
246
247    /// Write byte slice to storage.
248    fn write(&mut self, start: u64, data: &[u8]);
249
250    /// Write byte Vec.
251    fn write_vec(&mut self, start: u64, data: Vec<u8>) {
252        let len = data.len();
253        let d = Arc::new(data);
254        self.write_data(start, d, 0, len);
255    }
256
257    /// Write Data slice.
258    fn write_data(&mut self, start: u64, data: Data, off: usize, len: usize) {
259        self.write(start, &data[off..off + len]);
260    }
261
262    /// Finish write transaction, size is new size of underlying storage.
263    fn commit(&mut self, size: u64);
264
265    /// Write u64.
266    fn write_u64(&mut self, start: u64, value: u64) {
267        self.write(start, &value.to_le_bytes());
268    }
269
270    /// Read u64.
271    fn read_u64(&self, start: u64) -> u64 {
272        let mut bytes = [0; 8];
273        self.read(start, &mut bytes);
274        u64::from_le_bytes(bytes)
275    }
276
277    /// Wait until current writes are complete.
278    fn wait_complete(&self){}
279
280    /// Called on program termination.
281    fn shutdown(&mut self){}
282}
283
284/// BasicStorage with Sync and clone.
285pub trait Storage: BasicStorage + Sync {
286    /// Clone.
287    fn clone(&self) -> Box<dyn Storage>;
288}
289
290/// Simple implementation of [Storage] using `Arc<Mutex<Vec<u8>>`.
291#[derive(Default)]
292pub struct MemFile {
293    v: Arc<Mutex<Vec<u8>>>,
294}
295
296impl MemFile {
297    /// Get a new (boxed) MemFile.
298    pub fn new() -> Box<Self> {
299        Box::default()
300    }
301}
302
303impl Storage for MemFile {
304    fn clone(&self) -> Box<dyn Storage> {
305        Box::new(Self { v: self.v.clone() })
306    }
307}
308
309impl BasicStorage for MemFile {
310    fn size(&self) -> u64 {
311        let v = self.v.lock().unwrap();
312        v.len() as u64
313    }
314
315    fn read(&self, off: u64, bytes: &mut [u8]) {
316        let off = off as usize;
317        let len = bytes.len();
318        let mut v = self.v.lock().unwrap();
319        if off + len > v.len() {
320            v.resize(off + len, 0);
321        }
322        bytes.copy_from_slice(&v[off..off + len]);
323    }
324
325    fn write(&mut self, off: u64, bytes: &[u8]) {
326        let off = off as usize;
327        let len = bytes.len();
328        let mut v = self.v.lock().unwrap();
329        if off + len > v.len() {
330            v.resize(off + len, 0);
331        }
332        v[off..off + len].copy_from_slice(bytes);
333    }
334
335    fn commit(&mut self, size: u64) {
336        let mut v = self.v.lock().unwrap();
337        v.resize(size as usize, 0);
338    }
339}
340
341use std::{fs, fs::OpenOptions, io::Read, io::Seek, io::SeekFrom, io::Write};
342
343struct FileInner {
344    f: fs::File,
345}
346
347impl FileInner {
348    /// Construct from filename.
349    pub fn new(filename: &str) -> Self {
350        Self {
351            f: OpenOptions::new()
352                .read(true)
353                .write(true)
354                .create(true)
355                .truncate(false)
356                .open(filename)
357                .unwrap(),
358        }
359    }
360
361    fn size(&mut self) -> u64 {
362        self.f.seek(SeekFrom::End(0)).unwrap()
363    }
364
365    fn read(&mut self, off: u64, bytes: &mut [u8]) {
366        self.f.seek(SeekFrom::Start(off)).unwrap();
367        let _ = self.f.read(bytes).unwrap();
368    }
369
370    fn write(&mut self, off: u64, bytes: &[u8]) {
371        // The list of operating systems which auto-zero is likely more than this...research is todo.
372        #[cfg(not(any(target_os = "windows", target_os = "linux")))]
373        {
374            let size = self.f.seek(SeekFrom::End(0)).unwrap();
375            if off > size {
376                self.f.set_len(off).unwrap();
377            }
378        }
379        self.f.seek(SeekFrom::Start(off)).unwrap();
380        let _ = self.f.write(bytes).unwrap();
381    }
382
383    fn commit(&mut self, size: u64) {
384        self.f.set_len(size).unwrap();
385        self.f.sync_all().unwrap();
386    }
387}
388
389/// For atomic upd file, if not unix or windows.
390pub struct UpdFileStorage {
391    file: Cell<Option<FileInner>>,
392}
393
394impl UpdFileStorage {
395    /// Construct from filename.
396    pub fn new(filename: &str) -> Box<Self> {
397        Box::new(Self {
398            file: Cell::new(Some(FileInner::new(filename))),
399        })
400    }
401}
402
403impl BasicStorage for UpdFileStorage {
404    fn size(&self) -> u64 {
405        let mut f = self.file.take().unwrap();
406        let result = f.size();
407        self.file.set(Some(f));
408        result
409    }
410    fn read(&self, off: u64, bytes: &mut [u8]) {
411        let mut f = self.file.take().unwrap();
412        f.read(off, bytes);
413        self.file.set(Some(f));
414    }
415
416    fn write(&mut self, off: u64, bytes: &[u8]) {
417        let mut f = self.file.take().unwrap();
418        f.write(off, bytes);
419        self.file.set(Some(f));
420    }
421
422    fn commit(&mut self, size: u64) {
423        let mut f = self.file.take().unwrap();
424        f.commit(size);
425        self.file.set(Some(f));
426    }
427}
428
429/// Simple implementation of [Storage] using [`std::fs::File`].
430pub struct SimpleFileStorage {
431    file: Arc<Mutex<FileInner>>,
432}
433
434impl SimpleFileStorage {
435    /// Construct from filename.
436    pub fn new(filename: &str) -> Box<Self> {
437        Box::new(Self {
438            file: Arc::new(Mutex::new(FileInner::new(filename))),
439        })
440    }
441}
442
443impl Storage for SimpleFileStorage {
444    fn clone(&self) -> Box<dyn Storage> {
445        Box::new(Self {
446            file: self.file.clone(),
447        })
448    }
449}
450
451impl BasicStorage for SimpleFileStorage {
452    fn size(&self) -> u64 {
453        self.file.lock().unwrap().size()
454    }
455
456    fn read(&self, off: u64, bytes: &mut [u8]) {
457        self.file.lock().unwrap().read(off, bytes);
458    }
459
460    fn write(&mut self, off: u64, bytes: &[u8]) {
461        self.file.lock().unwrap().write(off, bytes);
462    }
463
464    fn commit(&mut self, size: u64) {
465        self.file.lock().unwrap().commit(size);
466    }
467}
468
469/// Alternative to SimpleFileStorage that uses multiple [SimpleFileStorage]s to allow parallel reads by different threads.
470pub struct AnyFileStorage {
471    filename: String,
472    files: Arc<Mutex<Vec<FileInner>>>,
473}
474
475impl AnyFileStorage {
476    /// Create new.
477    pub fn new(filename: &str) -> Box<Self> {
478        Box::new(Self {
479            filename: filename.to_owned(),
480            files: Arc::new(Mutex::new(Vec::new())),
481        })
482    }
483
484    fn get_file(&self) -> FileInner {
485        match self.files.lock().unwrap().pop() {
486            Some(f) => f,
487            _ => FileInner::new(&self.filename),
488        }
489    }
490
491    fn put_file(&self, f: FileInner) {
492        self.files.lock().unwrap().push(f);
493    }
494}
495
496impl Storage for AnyFileStorage {
497    fn clone(&self) -> Box<dyn Storage> {
498        Box::new(Self {
499            filename: self.filename.clone(),
500            files: self.files.clone(),
501        })
502    }
503}
504
505impl BasicStorage for AnyFileStorage {
506    fn size(&self) -> u64 {
507        let mut f = self.get_file();
508        let result = f.size();
509        self.put_file(f);
510        result
511    }
512
513    fn read(&self, off: u64, bytes: &mut [u8]) {
514        let mut f = self.get_file();
515        f.read(off, bytes);
516        self.put_file(f);
517    }
518
519    fn write(&mut self, off: u64, bytes: &[u8]) {
520        let mut f = self.get_file();
521        f.write(off, bytes);
522        self.put_file(f);
523    }
524
525    fn commit(&mut self, size: u64) {
526        let mut f = self.get_file();
527        f.commit(size);
528        self.put_file(f);
529    }
530}
531
532/// Dummy Stg that can be used for Atomic upd file if "reliable" atomic commits are not required.
533pub struct DummyFile {}
534impl DummyFile {
535    /// Construct.
536    pub fn new() -> Box<Self> {
537        Box::new(Self {})
538    }
539}
540
541impl Storage for DummyFile {
542    fn clone(&self) -> Box<dyn Storage> {
543        Self::new()
544    }
545}
546
547impl BasicStorage for DummyFile {
548    fn size(&self) -> u64 {
549        0
550    }
551
552    fn read(&self, _off: u64, _bytes: &mut [u8]) {}
553
554    fn write(&mut self, _off: u64, _bytes: &[u8]) {}
555
556    fn commit(&mut self, _size: u64) {}
557}
558
559/// Memory configuration limits for [`AtomicFile`].
560#[non_exhaustive]
561pub struct Limits {
562    /// Limit on size of commit write map, default is 5000.
563    pub map_lim: usize,
564    /// Memory for buffering small reads, default is 0x200000 ( 2MB ).
565    pub rbuf_mem: usize,
566    /// Memory for buffering writes to main storage, default is 0x100000 (1MB).
567    pub swbuf: usize,
568    /// Memory for buffering writes to temporary storage, default is 0x100000 (1MB).
569    pub uwbuf: usize,
570}
571
572impl Default for Limits {
573    fn default() -> Self {
574        Self {
575            map_lim: 5000,
576            rbuf_mem: 0x200000,
577            swbuf: 0x100000,
578            uwbuf: 0x100000,
579        }
580    }
581}
582
583/// Write Buffer.
584struct WriteBuffer {
585    /// Current write index into buf.
586    ix: usize,
587    /// Current file position.
588    pos: u64,
589    /// Underlying storage.
590    pub stg: Box<dyn BasicStorage>,
591    /// Buffer.
592    buf: Vec<u8>,
593}
594
595impl WriteBuffer {
596    /// Construct.
597    pub fn new(stg: Box<dyn BasicStorage>, buf_size: usize) -> Self {
598        Self {
599            ix: 0,
600            pos: u64::MAX,
601            stg,
602            buf: vec![0; buf_size],
603        }
604    }
605
606    /// Write data to specified offset,
607    pub fn write(&mut self, off: u64, data: &[u8]) {
608        if self.pos + self.ix as u64 != off {
609            self.flush(off);
610        }
611        let mut done: usize = 0;
612        let mut todo: usize = data.len();
613        while todo > 0 {
614            let mut n: usize = self.buf.len() - self.ix;
615            if n == 0 {
616                self.flush(off + done as u64);
617                n = self.buf.len();
618            }
619            if n > todo {
620                n = todo;
621            }
622            self.buf[self.ix..self.ix + n].copy_from_slice(&data[done..done + n]);
623            todo -= n;
624            done += n;
625            self.ix += n;
626        }
627    }
628
629    fn flush(&mut self, new_pos: u64) {
630        if self.ix > 0 {
631            self.stg.write(self.pos, &self.buf[0..self.ix]);
632        }
633        self.ix = 0;
634        self.pos = new_pos;
635    }
636
637    /// Commit.
638    pub fn commit(&mut self, size: u64) {
639        self.flush(u64::MAX);
640        self.stg.commit(size);
641    }
642
643    /// Write u64.
644    pub fn write_u64(&mut self, start: u64, value: u64) {
645        self.write(start, &value.to_le_bytes());
646    }
647}
648
649/// ReadBufStg buffers small (up to limit) reads to the underlying storage using multiple buffers. Only supported functions are read and reset.
650///
651/// See implementation of AtomicFile for how this is used in conjunction with WMap.
652///
653/// N is buffer size.
654struct ReadBufStg<const N: usize> {
655    /// Underlying storage.
656    stg: Box<dyn Storage>,
657    /// Buffers.
658    buf: Mutex<ReadBuffer<N>>,
659    /// Read size that is considered small.
660    limit: usize,
661}
662
663impl<const N: usize> Drop for ReadBufStg<N> {
664    fn drop(&mut self) {
665        self.reset();
666    }
667}
668
669impl<const N: usize> ReadBufStg<N> {
670    /// limit is the size of a read that is considered "small", max_buf is the maximum number of buffers used.
671    pub fn new(stg: Box<dyn Storage>, limit: usize, max_buf: usize) -> Self {
672        Self {
673            stg,
674            buf: Mutex::new(ReadBuffer::<N>::new(max_buf)),
675            limit,
676        }
677    }
678
679    /// Clears the buffers.
680    fn reset(&mut self) {
681        self.buf.lock().unwrap().reset();
682    }
683}
684
685impl<const N: usize> BasicStorage for ReadBufStg<N> {
686    /// Read data from storage.
687    fn read(&self, start: u64, data: &mut [u8]) {
688        if data.len() <= self.limit {
689            self.buf.lock().unwrap().read(&*self.stg, start, data);
690        } else {
691            self.stg.read(start, data);
692        }
693    }
694
695    /// Panics.
696    fn size(&self) -> u64 {
697        panic!()
698    }
699
700    /// Panics.
701    fn write(&mut self, _start: u64, _data: &[u8]) {
702        panic!();
703    }
704
705    /// Panics.
706    fn commit(&mut self, _size: u64) {
707        panic!();
708    }
709}
710
711struct ReadBuffer<const N: usize> {
712    /// Maps sector mumbers cached buffers.
713    map: HashMap<u64, Box<[u8; N]>>,
714    /// Maximum number of buffers.
715    max_buf: usize,
716}
717
718impl<const N: usize> ReadBuffer<N> {
719    fn new(max_buf: usize) -> Self {
720        Self {
721            map: HashMap::default(),
722            max_buf,
723        }
724    }
725
726    fn reset(&mut self) {
727        self.map.clear();
728    }
729
730    fn read(&mut self, stg: &dyn BasicStorage, off: u64, data: &mut [u8]) {
731        let mut done = 0;
732        while done < data.len() {
733            let off = off + done as u64;
734            let sector = off / N as u64;
735            let disp = (off % N as u64) as usize;
736            let amount = min(data.len() - done, N - disp);
737
738            let p = self.map.entry(sector).or_insert_with(|| {
739                let mut p: Box<[u8; N]> = vec![0; N].try_into().unwrap();
740                stg.read(sector * N as u64, &mut *p);
741                p
742            });
743            data[done..done + amount].copy_from_slice(&p[disp..disp + amount]);
744            done += amount;
745        }
746        if self.map.len() >= self.max_buf {
747            self.reset();
748        }
749    }
750}
751
752#[derive(Default)]
753/// Slice of Data to be written to storage.
754struct DataSlice {
755    /// Slice data.
756    pub data: Data,
757    /// Start of slice.
758    pub off: usize,
759    /// Length of slice.
760    pub len: usize,
761}
762
763impl DataSlice {
764    /// Get reference to the whole slice.
765    pub fn all(&self) -> &[u8] {
766        &self.data[self.off..self.off + self.len]
767    }
768    /// Get reference to part of slice.
769    pub fn part(&self, off: usize, len: usize) -> &[u8] {
770        &self.data[self.off + off..self.off + off + len]
771    }
772    /// Trim specified amount from start of slice.
773    pub fn trim(&mut self, trim: usize) {
774        self.off += trim;
775        self.len -= trim;
776    }
777    /// Take the data.
778    #[allow(dead_code)]
779    pub fn take(&mut self) -> Data {
780        std::mem::take(&mut self.data)
781    }
782}
783
784#[derive(Default)]
785/// Updateable store based on some underlying storage.
786struct WMap {
787    /// Map of writes. Key is the end of the slice.
788    map: BTreeMap<u64, DataSlice>,
789}
790
791impl WMap {
792    /// Is the map empty?
793    pub fn is_empty(&self) -> bool {
794        self.map.is_empty()
795    }
796
797    /// Number of key-value pairs in the map.
798    pub fn len(&self) -> usize {
799        self.map.len()
800    }
801
802    /// Take the map and convert it to a Vec.
803    pub fn convert_to_vec(&mut self) -> GVec<(u64, DataSlice)> {
804        let map = std::mem::take(&mut self.map);
805        let mut result = GVec::with_capacity(map.len());
806        for (end, v) in map {
807            let start = end - v.len as u64;
808            result.push((start, v));
809        }
810        result
811    }
812
813    /// Write the map into storage.
814    pub fn to_storage(&self, stg: &mut dyn BasicStorage) {
815        for (end, v) in self.map.iter() {
816            let start = end - v.len as u64;
817            stg.write_data(start, v.data.clone(), v.off, v.len);
818        }
819    }
820
821    #[cfg(not(feature = "pstd"))]
822    /// Write to storage, existing writes which overlap with new write need to be trimmed or removed.
823    pub fn write(&mut self, start: u64, data: Data, off: usize, len: usize) {
824        if len != 0 {
825            let (mut insert, mut remove) = (Vec::new(), Vec::new());
826            let end = start + len as u64;
827            for (ee, v) in self.map.range_mut(start + 1..) {
828                let ee = *ee;
829                let es = ee - v.len as u64; // Existing write Start.
830                if es >= end {
831                    // Existing write starts after end of new write, nothing to do.
832                    break;
833                } else if start <= es {
834                    if end < ee {
835                        // New write starts before existing write, but doesn't subsume it. Trim existing write.
836                        v.trim((end - es) as usize);
837                        break;
838                    }
839                    // New write subsumes existing write entirely, remove existing write.
840                    remove.push(ee);
841                } else if end < ee {
842                    // New write starts in middle of existing write, ends before end of existing write,
843                    // put start of existing write in insert list, trim existing write.
844                    insert.push((es, v.data.clone(), v.off, (start - es) as usize));
845                    v.trim((end - es) as usize);
846                    break;
847                } else {
848                    // New write starts in middle of existing write, ends after existing write,
849                    // put start of existing write in insert list, remove existing write.
850                    insert.push((es, v.take(), v.off, (start - es) as usize));
851                    remove.push(ee);
852                }
853            }
854            for end in remove {
855                self.map.remove(&end);
856            }
857            for (start, data, off, len) in insert {
858                self.map
859                    .insert(start + len as u64, DataSlice { data, off, len });
860            }
861            self.map
862                .insert(start + len as u64, DataSlice { data, off, len });
863        }
864    }
865
866    #[cfg(feature = "pstd")]
867    /// Write to storage, existing writes which overlap with new write need to be trimmed or removed.
868    pub fn write(&mut self, start: u64, data: Data, off: usize, len: usize) {
869        if len != 0 {
870            let end = start + len as u64;
871            let mut c = self
872                .map
873                .lower_bound_mut(std::ops::Bound::Excluded(&start))
874                .with_mutable_key();
875            while let Some((eend, v)) = c.next() {
876                let ee = *eend;
877                let es = ee - v.len as u64; // Existing write Start.
878                if es >= end {
879                    // Existing write starts after end of new write, nothing to do.
880                    c.prev();
881                    break;
882                } else if start <= es {
883                    if end < ee {
884                        // New write starts before existing write, but doesn't subsume it. Trim existing write.
885                        v.trim((end - es) as usize);
886                        c.prev();
887                        break;
888                    }
889                    // New write subsumes existing write entirely, remove existing write.
890                    c.remove_prev();
891                } else if end < ee {
892                    // New write starts in middle of existing write, ends before end of existing write,
893                    // trim existing write, insert start of existing write.
894                    let (data, off, len) = (v.data.clone(), v.off, (start - es) as usize);
895                    v.trim((end - es) as usize);
896                    c.prev();
897                    c.insert_before_unchecked(es + len as u64, DataSlice { data, off, len });
898                    break;
899                } else {
900                    // New write starts in middle of existing write, ends after existing write,
901                    // Trim existing write ( modifies key, but this is ok as ordering is not affected ).
902                    v.len = (start - es) as usize;
903                    *eend = es + v.len as u64;
904                }
905            }
906            // Insert the new write.
907            c.insert_after_unchecked(start + len as u64, DataSlice { data, off, len });
908        }
909    }
910
911    /// Read from storage, taking map of existing writes into account. Unwritten ranges are read from underlying storage.
912    pub fn read(&self, start: u64, data: &mut [u8], u: &dyn BasicStorage) {
913        let len = data.len();
914        if len != 0 {
915            let mut done = 0;
916            for (&end, v) in self.map.range(start + 1..) {
917                let es = end - v.len as u64; // Existing write Start.
918                let doff = start + done as u64;
919                if es > doff {
920                    // Read from underlying storage.
921                    let a = min(len - done, (es - doff) as usize);
922                    u.read(doff, &mut data[done..done + a]);
923                    done += a;
924                    if done == len {
925                        return;
926                    }
927                }
928                // Use existing write.
929                let skip = (start + done as u64 - es) as usize;
930                let a = min(len - done, v.len - skip);
931                data[done..done + a].copy_from_slice(v.part(skip, a));
932                done += a;
933                if done == len {
934                    return;
935                }
936            }
937            u.read(start + done as u64, &mut data[done..]);
938        }
939    }
940}
941
942/// Basis for [crate::AtomicFile] ( non-async alternative ). Provides two-phase commit and buffering of writes.
943pub struct BasicAtomicFile {
944    /// The main underlying storage.
945    stg: WriteBuffer,
946    /// Temporary storage for updates during commit.
947    upd: WriteBuffer,
948    /// Map of writes.
949    map: WMap,
950    /// List of writes.
951    list: GVec<(u64, DataSlice)>,
952    size: u64,
953    stop: bool,
954}
955
956impl BasicAtomicFile {
957    /// stg is the main underlying storage, upd is temporary storage for updates during commit.
958    pub fn new(stg: Box<dyn BasicStorage>, upd: Box<dyn BasicStorage>, lim: &Limits) -> Box<Self> {
959        let size = stg.size();
960        let mut result = Box::new(Self {
961            stg: WriteBuffer::new(stg, lim.swbuf),
962            upd: WriteBuffer::new(upd, lim.uwbuf),
963            map: WMap::default(),
964            list: GVec::new(),
965            size,
966            stop: false,
967        });
968        result.init();
969        result
970    }
971
972    /// Apply outstanding updates.
973    fn init(&mut self) {
974        let end = self.upd.stg.read_u64(0);
975        let size = self.upd.stg.read_u64(8);
976        if end == 0 {
977            return;
978        }
979        assert!(end == self.upd.stg.size());
980        let mut pos = 16;
981        while pos < end {
982            let start = self.upd.stg.read_u64(pos);
983            pos += 8;
984            let len = self.upd.stg.read_u64(pos);
985            pos += 8;
986            let mut buf: GVec<u8> = gvec![0; len as usize];
987            self.upd.stg.read(pos, &mut buf);
988            pos += len;
989            self.stg.write(start, &buf);
990        }
991        self.stg.commit(size);
992        self.upd.commit(0);
993    }
994
995    /// Perform the specified phase ( 1 or 2 ) of a two-phase commit.
996    pub fn commit_phase(&mut self, size: u64, phase: u8) {
997        if self.map.is_empty() && self.list.is_empty() {
998            return;
999        }
1000        if phase == 1 {
1001            self.list = self.map.convert_to_vec();
1002
1003            // Write the updates to upd.
1004            // First set the end position to zero.
1005            self.upd.write_u64(0, 0);
1006            self.upd.write_u64(8, size);
1007            self.upd.commit(16); // Not clear if this is necessary.
1008
1009            // Write the update records.
1010            let mut stg_written = false;
1011            let mut pos: u64 = 16;
1012            for (start, v) in self.list.iter() {
1013                let (start, len, data) = (*start, v.len as u64, v.all());
1014                if start >= self.size {
1015                    // Writes beyond current stg size can be written directly.
1016                    stg_written = true;
1017                    self.stg.write(start, data);
1018                } else {
1019                    self.upd.write_u64(pos, start);
1020                    pos += 8;
1021                    self.upd.write_u64(pos, len);
1022                    pos += 8;
1023                    self.upd.write(pos, data);
1024                    pos += len;
1025                }
1026            }
1027            if stg_written {
1028                self.stg.commit(size);
1029            }
1030            self.upd.commit(pos); // Not clear if this is necessary.
1031
1032            // Set the end position.
1033            self.upd.write_u64(0, pos);
1034            self.upd.write_u64(8, size);
1035            self.upd.commit(pos);
1036        } else {
1037            for (start, v) in self.list.iter() {
1038                if *start < self.size {
1039                    // Writes beyond current stg size have already been written.
1040                    self.stg.write(*start, v.all());
1041                }
1042            }
1043            self.list = GVec::new();
1044            self.stg.commit(size);
1045            self.upd.commit(0);
1046        }
1047    }
1048}
1049
1050impl BasicStorage for BasicAtomicFile {
1051    fn commit(&mut self, size: u64) {
1052        if self.stop { return; }
1053        self.commit_phase(size, 1);
1054        self.commit_phase(size, 2);
1055        self.size = size;
1056    }
1057
1058    fn size(&self) -> u64 {
1059        self.size
1060    }
1061
1062    fn read(&self, start: u64, data: &mut [u8]) {
1063        self.map.read(start, data, &*self.stg.stg);
1064    }
1065
1066    fn write_data(&mut self, start: u64, data: Data, off: usize, len: usize) {
1067        self.map.write(start, data, off, len);
1068    }
1069
1070    fn write(&mut self, start: u64, data: &[u8]) {
1071        let len = data.len();
1072        let d = Arc::new(data.to_vec());
1073        self.write_data(start, d, 0, len);
1074    }
1075
1076    fn shutdown(&mut self)
1077    {
1078        self.stop = true;
1079    }
1080}
1081
1082/// Optimized implementation of [Storage] ( unix only ).
1083#[cfg(target_family = "unix")]
1084pub struct UnixFileStorage {
1085    size: Arc<Mutex<u64>>,
1086    f: fs::File,
1087}
1088#[cfg(target_family = "unix")]
1089impl UnixFileStorage {
1090    /// Construct from filename.
1091    pub fn new(filename: &str) -> Box<Self> {
1092        let mut f = OpenOptions::new()
1093            .read(true)
1094            .write(true)
1095            .create(true)
1096            .truncate(false)
1097            .open(filename)
1098            .unwrap();
1099        let size = f.seek(SeekFrom::End(0)).unwrap();
1100        let size = Arc::new(Mutex::new(size));
1101        Box::new(Self { size, f })
1102    }
1103}
1104
1105#[cfg(target_family = "unix")]
1106impl Storage for UnixFileStorage {
1107    fn clone(&self) -> Box<dyn Storage> {
1108        Box::new(Self {
1109            size: self.size.clone(),
1110            f: self.f.try_clone().unwrap(),
1111        })
1112    }
1113}
1114
1115#[cfg(target_family = "unix")]
1116use std::os::unix::fs::FileExt;
1117
1118#[cfg(target_family = "unix")]
1119impl BasicStorage for UnixFileStorage {
1120    fn read(&self, start: u64, data: &mut [u8]) {
1121        let _ = self.f.read_at(data, start);
1122    }
1123
1124    fn write(&mut self, start: u64, data: &[u8]) {
1125        let _ = self.f.write_at(data, start);
1126    }
1127
1128    fn size(&self) -> u64 {
1129        *self.size.lock().unwrap()
1130    }
1131
1132    fn commit(&mut self, size: u64) {
1133        *self.size.lock().unwrap() = size;
1134        self.f.set_len(size).unwrap();
1135        self.f.sync_all().unwrap();
1136    }
1137}
1138
1139/// Optimized implementation of [Storage] ( windows only ).
1140#[cfg(target_family = "windows")]
1141pub struct WindowsFileStorage {
1142    size: Arc<Mutex<u64>>,
1143    f: fs::File,
1144}
1145#[cfg(target_family = "windows")]
1146impl WindowsFileStorage {
1147    /// Construct from filename.
1148    pub fn new(filename: &str) -> Box<Self> {
1149        let mut f = OpenOptions::new()
1150            .read(true)
1151            .write(true)
1152            .create(true)
1153            .truncate(false)
1154            .open(filename)
1155            .unwrap();
1156        let size = f.seek(SeekFrom::End(0)).unwrap();
1157        let size = Arc::new(Mutex::new(size));
1158        Box::new(Self { size, f })
1159    }
1160}
1161
1162#[cfg(target_family = "windows")]
1163impl Storage for WindowsFileStorage {
1164    fn clone(&self) -> Box<dyn Storage> {
1165        Box::new(Self {
1166            size: self.size.clone(),
1167            f: self.f.try_clone().unwrap(),
1168        })
1169    }
1170}
1171
1172#[cfg(target_family = "windows")]
1173use std::os::windows::fs::FileExt;
1174
1175#[cfg(target_family = "windows")]
1176impl BasicStorage for WindowsFileStorage {
1177    fn read(&self, start: u64, data: &mut [u8]) {
1178        let _ = self.f.seek_read(data, start);
1179    }
1180
1181    fn write(&mut self, start: u64, data: &[u8]) {
1182        let _ = self.f.seek_write(data, start);
1183    }
1184
1185    fn size(&self) -> u64 {
1186        *self.size.lock().unwrap()
1187    }
1188
1189    fn commit(&mut self, size: u64) {
1190        *self.size.lock().unwrap() = size;
1191        self.f.set_len(size).unwrap();
1192        self.f.sync_all().unwrap();
1193    }
1194}
1195
1196/// Optimised Storage ( varies according to platform ).
1197#[cfg(target_family = "windows")]
1198pub type MultiFileStorage = WindowsFileStorage;
1199
1200/// Optimised Storage ( varies according to platform ).
1201#[cfg(target_family = "unix")]
1202pub type MultiFileStorage = UnixFileStorage;
1203
1204/// Optimised Storage ( varies according to platform ).
1205#[cfg(not(any(target_family = "unix", target_family = "windows")))]
1206pub type MultiFileStorage = AnyFileStorage;
1207
1208/// Fast Storage for upd file ( varies according to platform ).
1209#[cfg(any(target_family = "windows", target_family = "unix"))]
1210pub type FastFileStorage = MultiFileStorage;
1211
1212/// Fast Storage for upd file ( varies according to platform ).
1213#[cfg(not(any(target_family = "windows", target_family = "unix")))]
1214pub type FastFileStorage = UpdFileStorage;
1215
1216#[cfg(test)]
1217/// Get amount of testing from environment variable TA.
1218fn test_amount() -> usize {
1219    str::parse(&std::env::var("TA").unwrap_or("1".to_string())).unwrap()
1220}
1221
1222#[test]
1223fn test_atomic_file() {
1224    use rand::Rng;
1225    /* Idea of test is to check AtomicFile and MemFile behave the same */
1226
1227    let ta = test_amount();
1228    println!(" Test amount={}", ta);
1229
1230    let mut rng = rand::thread_rng();
1231
1232    for _ in 0..100 {
1233        let mut s1 = AtomicFile::new(MemFile::new(), MemFile::new());
1234        // let mut s1 = BasicAtomicFile::new(MemFile::new(), MemFile::new(), &Limits::default() );
1235        let mut s2 = MemFile::new();
1236
1237        for _ in 0..1000 * ta {
1238            let off: usize = rng.r#gen::<usize>() % 100;
1239            let mut len = 1 + rng.r#gen::<usize>() % 20;
1240            let w: bool = rng.r#gen();
1241            if w {
1242                let mut bytes = Vec::new();
1243                while len > 0 {
1244                    len -= 1;
1245                    let b: u8 = rng.r#gen::<u8>();
1246                    bytes.push(b);
1247                }
1248                s1.write(off as u64, &bytes);
1249                s2.write(off as u64, &bytes);
1250            } else {
1251                let mut b2 = vec![0; len];
1252                let mut b3 = vec![0; len];
1253                s1.read(off as u64, &mut b2);
1254                s2.read(off as u64, &mut b3);
1255                assert!(b2 == b3);
1256            }
1257            if rng.r#gen::<usize>() % 50 == 0 {
1258                s1.commit(200);
1259                s2.commit(200);
1260            }
1261        }
1262    }
1263}