1+ //! High-performance, multi-threaded backy image restore library.
2+ //!
3+ //! `backy_extract` reads an backup revision from a
4+ //! [backy](https://bitbucket.org/flyingcircus/backy) *chunked v2* data store, decompresses it on
5+ //! the fly and writes it to a restore target using pluggable writeout modules.
6+
17mod backend;
28mod chunkvec;
39#[ cfg( test) ]
410mod test_helper;
511mod writeout;
612
713use self :: backend:: Backend ;
8- use self :: chunkvec:: { ChunkVec , Data } ;
14+ use self :: chunkvec:: { ChunkVec } ;
915pub use self :: writeout:: { RandomAccess , Stream } ;
10- use self :: writeout:: { WriteOut , WriteOutBuilder } ;
1116
1217use console:: { style, StyledObject } ;
13- use crossbeam:: channel:: { bounded, unbounded, Receiver } ;
18+ use crossbeam:: channel:: { bounded, unbounded, Sender , Receiver } ;
1419use crossbeam:: thread;
1520use failure:: { Fail , Fallible , ResultExt } ;
1621use fs2:: FileExt ;
@@ -19,18 +24,60 @@ use lazy_static::lazy_static;
1924use memmap:: MmapMut ;
2025use num_cpus;
2126use smallvec:: SmallVec ;
27+ use std:: fmt:: Debug ;
2228use std:: fs:: { self , File } ;
2329use std:: path:: { Path , PathBuf } ;
2430use std:: time:: Instant ;
2531
26- // Size of an uncompressed Chunk in the backy store.
32+ /// Size of an uncompressed Chunk in the backy store as 2's exponent .
2733// This value must be a u32 because it is encoded as 32 bit uint the chunk file header.
2834pub const CHUNKSZ_LOG : usize = 22 ; // 4 MiB
2935
3036lazy_static ! {
3137 static ref ZERO_CHUNK : MmapMut = MmapMut :: map_anon( 1 << CHUNKSZ_LOG ) . expect( "mmap" ) ;
3238}
3339
40+ /// WriteOut factory.
41+ ///
42+ /// We use the factory approach to have only the minimum of parameters to the
43+ /// user-facing constructor. Further parameters from the Exctractor are supplied internally by
44+ /// invoking `build` to get the final WriteOut object.
45+ pub trait WriteOutBuilder {
46+ type Impl : WriteOut + Sync + Send ;
47+ fn build ( self , total_size : u64 , threads : u8 ) -> Self :: Impl ;
48+ }
49+
50+ /// Abstract writeout (restore) plugin.
51+ ///
52+ /// A concrete writer is instantiated via `WriteOutBuilder.build()`.
53+ pub trait WriteOut : Debug {
54+ /// Gets an unordered stream of `Chunk`s which must be written to the restore target according
55+ /// to the chunks' sequence numbers. Writer must send the number of bytes written to the
56+ /// `progress` channel to indicate restore progress in real time.
57+ fn receive ( self , chunks : Receiver < Chunk > , progress : Sender < usize > ) -> Fallible < ( ) > ;
58+
59+ /// Short idenfication for user display. Should contain plugin type and file name.
60+ fn name ( & self ) -> String ;
61+ }
62+
63+ /// Transport of a single image data chunk.
64+ ///
65+ /// A chunk needs to be placed into all logical positions that are listed in the `seqs` attribute.
66+ /// Each seq starts at offset (seq << CHUNKSZ_LOG) bytes in the restored image.
67+ #[ derive( Debug , Clone , PartialEq , Eq , PartialOrd , Ord ) ]
68+ pub struct Chunk {
69+ pub data : Data ,
70+ pub seqs : SmallVec < [ usize ; 4 ] > ,
71+ }
72+
73+ /// Block of uncompressed image contents of length (1 << CHUNKSZ_LOG).
74+ #[ derive( Debug , Clone , PartialEq , Eq , PartialOrd , Ord ) ]
75+ pub enum Data {
76+ Some ( Vec < u8 > ) ,
77+ /// Shortcut if the whole block consists only of zeros.
78+ Zero ,
79+ }
80+
3481// Converts file position/size into chunk sequence number
3582fn pos2chunk ( pos : u64 ) -> usize {
3683 ( pos >> CHUNKSZ_LOG ) as usize
@@ -41,12 +88,6 @@ fn chunk2pos(seq: usize) -> u64 {
4188 ( seq as u64 ) << CHUNKSZ_LOG
4289}
4390
44- #[ derive( Debug , Clone , PartialEq , Eq , PartialOrd , Ord ) ]
45- pub struct Chunk {
46- data : Data ,
47- seqs : SmallVec < [ usize ; 4 ] > ,
48- }
49-
5091fn purgelock ( basedir : & Path ) -> Fallible < File > {
5192 let f = File :: create ( basedir. join ( ".purge" ) ) ?;
5293 f. try_lock_exclusive ( ) ?;
@@ -94,10 +135,6 @@ impl Extractor {
94135 } )
95136 }
96137
97- fn default_threads ( ) -> u8 {
98- ( num_cpus:: get ( ) / 2 ) . max ( 1 ) . min ( 60 ) as u8
99- }
100-
101138 /// Sets number of decompression threads. Heuristics apply in this method is never called.
102139 pub fn threads ( & mut self , n : u8 ) -> & mut Self {
103140 if n > 0 {
@@ -106,6 +143,10 @@ impl Extractor {
106143 self
107144 }
108145
146+ fn default_threads ( ) -> u8 {
147+ ( num_cpus:: get ( ) / 2 ) . max ( 1 ) . min ( 60 ) as u8
148+ }
149+
109150 /// Enables/disables a nice progress bar on stderr while restoring.
110151 pub fn progress ( & mut self , show : bool ) -> & mut Self {
111152 self . progress = if show {
0 commit comments