@@ -413,6 +413,178 @@ impl FileSystem for PseudoFs {
413413 }
414414}
415415
416+ /// Save and restore PseudoFs state.
417+ #[ cfg( feature = "persist" ) ]
418+ pub mod persist {
419+ use std:: collections:: HashMap ;
420+ use std:: io:: { Error as IoError , ErrorKind , Result } ;
421+ use std:: sync:: atomic:: Ordering ;
422+ use std:: sync:: Arc ;
423+
424+ use dbs_snapshot:: Snapshot ;
425+ use versionize:: { VersionMap , Versionize , VersionizeResult } ;
426+ use versionize_derive:: Versionize ;
427+
428+ use super :: { PseudoFs , PseudoInode } ;
429+ use crate :: api:: filesystem:: ROOT_ID ;
430+
431+ #[ derive( Versionize , PartialEq , Debug , Default , Clone ) ]
432+ struct PseudoInodeState {
433+ ino : u64 ,
434+ parent : u64 ,
435+ name : String ,
436+ }
437+
438+ #[ derive( Versionize , PartialEq , Debug , Default ) ]
439+ pub struct PseudoFsState {
440+ next_inode : u64 ,
441+ inodes : Vec < PseudoInodeState > ,
442+ }
443+
444+ impl PseudoFs {
445+ fn get_version_map ( ) -> VersionMap {
446+ let mut vm = VersionMap :: new ( ) ;
447+ vm. set_type_version ( PseudoFsState :: type_id ( ) , 1 ) ;
448+
449+ // more versions for the future
450+
451+ vm
452+ }
453+
454+ /// Saves part of the PseudoFs into a byte array.
455+ /// The upper layer caller can use this method to save
456+ /// and transfer metadata for the reloading in the future.
457+ pub fn save_to_bytes ( & self ) -> Result < Vec < u8 > > {
458+ let mut inodes = Vec :: new ( ) ;
459+ let next_inode = self . next_inode . load ( Ordering :: Relaxed ) ;
460+
461+ let _guard = self . lock . lock ( ) . unwrap ( ) ;
462+ for inode in self . inodes . load ( ) . values ( ) {
463+ if inode. ino == ROOT_ID {
464+ // no need to save the root inode
465+ continue ;
466+ }
467+
468+ inodes. push ( PseudoInodeState {
469+ ino : inode. ino ,
470+ parent : inode. parent ,
471+ name : inode. name . clone ( ) ,
472+ } ) ;
473+ }
474+ let state = PseudoFsState { next_inode, inodes } ;
475+
476+ let vm = PseudoFs :: get_version_map ( ) ;
477+ let target_version = vm. latest_version ( ) ;
478+ let mut s = Snapshot :: new ( vm, target_version) ;
479+ let mut buf = Vec :: new ( ) ;
480+ s. save ( & mut buf, & state) . map_err ( |e| {
481+ IoError :: new (
482+ ErrorKind :: Other ,
483+ format ! ( "Failed to save PseudoFs to bytes: {:?}" , e) ,
484+ )
485+ } ) ?;
486+
487+ Ok ( buf)
488+ }
489+
490+ /// Restores the PseudoFs from a byte array.
491+ pub fn restore_from_bytes ( & self , buf : & mut Vec < u8 > ) -> Result < ( ) > {
492+ let state: PseudoFsState =
493+ Snapshot :: load ( & mut buf. as_slice ( ) , buf. len ( ) , PseudoFs :: get_version_map ( ) )
494+ . map_err ( |e| {
495+ IoError :: new (
496+ ErrorKind :: Other ,
497+ format ! ( "Failed to load PseudoFs from bytes: {:?}" , e) ,
498+ )
499+ } ) ?
500+ . 0 ;
501+ self . restore_from_state ( & state)
502+ }
503+
504+ fn restore_from_state ( & self , state : & PseudoFsState ) -> Result < ( ) > {
505+ // first, reconstruct all the inodes
506+ let mut inode_map = HashMap :: new ( ) ;
507+ let mut state_inodes = state. inodes . clone ( ) ;
508+ for inode in state_inodes. iter ( ) {
509+ let inode = Arc :: new ( PseudoInode :: new (
510+ inode. ino ,
511+ inode. parent ,
512+ inode. name . clone ( ) ,
513+ ) ) ;
514+ inode_map. insert ( inode. ino , inode) ;
515+ }
516+
517+ // insert root inode to make sure the others inodes can find their parents
518+ inode_map. insert ( self . root_inode . ino , self . root_inode . clone ( ) ) ;
519+
520+ // then, connect the inodes
521+ state_inodes. sort_by ( |a, b| a. ino . cmp ( & b. ino ) ) ;
522+ for inode in state_inodes. iter ( ) {
523+ let inode = inode_map
524+ . get ( & inode. ino )
525+ . ok_or_else ( || {
526+ IoError :: new (
527+ ErrorKind :: InvalidData ,
528+ format ! ( "invalid inode {}" , inode. ino) ,
529+ )
530+ } ) ?
531+ . clone ( ) ;
532+ let parent = inode_map. get_mut ( & inode. parent ) . ok_or_else ( || {
533+ IoError :: new (
534+ ErrorKind :: InvalidData ,
535+ format ! (
536+ "invalid parent inode {} for inode {}" ,
537+ inode. parent, inode. ino
538+ ) ,
539+ )
540+ } ) ?;
541+ parent. insert_child ( inode) ;
542+ }
543+ self . inodes . store ( Arc :: new ( inode_map) ) ;
544+
545+ // last, restore next_inode
546+ self . next_inode . store ( state. next_inode , Ordering :: Relaxed ) ;
547+
548+ Ok ( ( ) )
549+ }
550+ }
551+
552+ mod test {
553+
554+ #[ test]
555+ fn save_restore_test ( ) {
556+ use crate :: api:: pseudo_fs:: PseudoFs ;
557+
558+ let fs = & PseudoFs :: new ( ) ;
559+ let paths = vec ! [ "/a" , "/a/b" , "/a/b/c" , "/b" , "/b/a/c" , "/d" ] ;
560+
561+ for path in paths. iter ( ) {
562+ fs. mount ( path) . unwrap ( ) ;
563+ }
564+
565+ // save fs
566+ let mut buf = fs. save_to_bytes ( ) . unwrap ( ) ;
567+
568+ // restore fs
569+ let restored_fs = & PseudoFs :: new ( ) ;
570+ restored_fs. restore_from_bytes ( & mut buf) . unwrap ( ) ;
571+
572+ // check fs and restored_fs
573+ let next_inode = fs. next_inode . load ( std:: sync:: atomic:: Ordering :: Relaxed ) ;
574+ let restored_next_inode = restored_fs
575+ . next_inode
576+ . load ( std:: sync:: atomic:: Ordering :: Relaxed ) ;
577+ assert_eq ! ( next_inode, restored_next_inode) ;
578+
579+ for path in paths. iter ( ) {
580+ let inode = fs. path_walk ( path) . unwrap ( ) ;
581+ let restored_inode = restored_fs. path_walk ( path) . unwrap ( ) ;
582+ assert_eq ! ( inode, restored_inode) ;
583+ }
584+ }
585+ }
586+ }
587+
416588#[ cfg( test) ]
417589mod tests {
418590 use super :: * ;
0 commit comments