@@ -84,7 +84,7 @@ use iroh_io::AsyncSliceReader;
84
84
use redb:: { AccessGuard , DatabaseError , ReadableTable , StorageError } ;
85
85
use serde:: { Deserialize , Serialize } ;
86
86
use smallvec:: SmallVec ;
87
- use tokio:: io:: AsyncWriteExt ;
87
+ use tokio:: { io:: AsyncWriteExt , runtime :: Handle } ;
88
88
use tracing:: trace_span;
89
89
mod tables;
90
90
#[ doc( hidden) ]
@@ -441,6 +441,30 @@ pub(crate) enum ImportSource {
441
441
Memory ( #[ debug( skip) ] Bytes ) ,
442
442
}
443
443
444
+ /// trait which defines the backend persistence layer
445
+ /// for this store. e.g. filesystem, s3 etc
446
+ pub trait Persistence : Clone {
447
+ /// the error type that is returned for the persistence layer
448
+ type Err ;
449
+
450
+ /// return the size of the file in bytes if it can be found/read
451
+ /// otherwise return a [Self::Err]
452
+ fn size ( & self , path : & Path ) -> impl Future < Output = Result < u64 , Self :: Err > > ;
453
+ }
454
+
455
+ /// A persistence layer that writes to the local file system
456
+ #[ derive( Debug , Clone , Copy ) ]
457
+ pub struct FileSystemPersistence ;
458
+
459
+ impl Persistence for FileSystemPersistence {
460
+ type Err = io:: Error ;
461
+
462
+ fn size ( & self , path : & Path ) -> impl Future < Output = Result < u64 , Self :: Err > > {
463
+ let res = std:: fs:: metadata ( path) . map ( |m| m. len ( ) ) ;
464
+ async move { res }
465
+ }
466
+ }
467
+
444
468
impl ImportSource {
445
469
fn content ( & self ) -> MemOrFile < & [ u8 ] , & Path > {
446
470
match self {
@@ -450,10 +474,10 @@ impl ImportSource {
450
474
}
451
475
}
452
476
453
- fn len ( & self ) -> io :: Result < u64 > {
477
+ async fn len < T : Persistence > ( & self , fs : & T ) -> Result < u64 , T :: Err > {
454
478
match self {
455
- Self :: TempFile ( path) => std :: fs :: metadata ( path) . map ( |m| m . len ( ) ) ,
456
- Self :: External ( path) => std :: fs :: metadata ( path) . map ( |m| m . len ( ) ) ,
479
+ Self :: TempFile ( path) => fs . size ( path) . await ,
480
+ Self :: External ( path) => fs . size ( path) . await ,
457
481
Self :: Memory ( data) => Ok ( data. len ( ) as u64 ) ,
458
482
}
459
483
}
@@ -711,7 +735,7 @@ pub(crate) type FilterPredicate<K, V> =
711
735
/// Storage that is using a redb database for small files and files for
712
736
/// large files.
713
737
#[ derive( Debug , Clone ) ]
714
- pub struct Store ( Arc < StoreInner > ) ;
738
+ pub struct Store < T = FileSystemPersistence > ( Arc < StoreInner < T > > ) ;
715
739
716
740
impl Store {
717
741
/// Load or create a new store.
@@ -758,11 +782,12 @@ impl Store {
758
782
}
759
783
760
784
#[ derive( Debug ) ]
761
- struct StoreInner {
785
+ struct StoreInner < T > {
762
786
tx : async_channel:: Sender < ActorMessage > ,
763
787
temp : Arc < RwLock < TempCounterMap > > ,
764
788
handle : Option < std:: thread:: JoinHandle < ( ) > > ,
765
789
path_options : Arc < PathOptions > ,
790
+ fs : T ,
766
791
}
767
792
768
793
impl TagDrop for RwLock < TempCounterMap > {
@@ -777,8 +802,23 @@ impl TagCounter for RwLock<TempCounterMap> {
777
802
}
778
803
}
779
804
780
- impl StoreInner {
805
+ impl StoreInner < FileSystemPersistence > {
781
806
fn new_sync ( path : PathBuf , options : Options , rt : tokio:: runtime:: Handle ) -> io:: Result < Self > {
807
+ Self :: new_sync_with_backend ( path, options, rt, FileSystemPersistence )
808
+ }
809
+ }
810
+
811
+ impl < T > StoreInner < T >
812
+ where
813
+ T : Persistence ,
814
+ OuterError : From < T :: Err > ,
815
+ {
816
+ fn new_sync_with_backend (
817
+ path : PathBuf ,
818
+ options : Options ,
819
+ rt : tokio:: runtime:: Handle ,
820
+ fs : T ,
821
+ ) -> io:: Result < Self > {
782
822
tracing:: trace!(
783
823
"creating data directory: {}" ,
784
824
options. path. data_path. display( )
@@ -811,6 +851,7 @@ impl StoreInner {
811
851
temp,
812
852
handle : Some ( handle) ,
813
853
path_options : Arc :: new ( options. path ) ,
854
+ fs,
814
855
} )
815
856
}
816
857
@@ -977,10 +1018,13 @@ impl StoreInner {
977
1018
. into ( ) ) ;
978
1019
}
979
1020
let parent = target. parent ( ) . ok_or_else ( || {
980
- OuterError :: from ( io:: Error :: new (
981
- io:: ErrorKind :: InvalidInput ,
982
- "target path has no parent directory" ,
983
- ) )
1021
+ OuterError :: Inner (
1022
+ io:: Error :: new (
1023
+ io:: ErrorKind :: InvalidInput ,
1024
+ "target path has no parent directory" ,
1025
+ )
1026
+ . into ( ) ,
1027
+ )
984
1028
} ) ?;
985
1029
std:: fs:: create_dir_all ( parent) ?;
986
1030
let temp_tag = self . temp . temp_tag ( HashAndFormat :: raw ( hash) ) ;
@@ -1069,7 +1113,7 @@ impl StoreInner {
1069
1113
let file = match mode {
1070
1114
ImportMode :: TryReference => ImportSource :: External ( path) ,
1071
1115
ImportMode :: Copy => {
1072
- if std :: fs :: metadata ( & path) ? . len ( ) < 16 * 1024 {
1116
+ if Handle :: current ( ) . block_on ( self . fs . size ( & path) ) ? < 16 * 1024 {
1073
1117
// we don't know if the data will be inlined since we don't
1074
1118
// have the inline options here. But still for such a small file
1075
1119
// it does not seem worth it do to the temp file ceremony.
@@ -1108,7 +1152,7 @@ impl StoreInner {
1108
1152
id : u64 ,
1109
1153
progress : impl ProgressSender < Msg = ImportProgress > + IdGenerator ,
1110
1154
) -> OuterResult < ( TempTag , u64 ) > {
1111
- let data_size = file. len ( ) ?;
1155
+ let data_size = Handle :: current ( ) . block_on ( file. len ( & self . fs ) ) ?;
1112
1156
tracing:: debug!( "finalize_import_sync {:?} {}" , file, data_size) ;
1113
1157
progress. blocking_send ( ImportProgress :: Size {
1114
1158
id,
@@ -1161,7 +1205,7 @@ impl StoreInner {
1161
1205
}
1162
1206
}
1163
1207
1164
- impl Drop for StoreInner {
1208
+ impl < T > Drop for StoreInner < T > {
1165
1209
fn drop ( & mut self ) {
1166
1210
if let Some ( handle) = self . handle . take ( ) {
1167
1211
self . tx
@@ -1217,10 +1261,7 @@ pub(crate) enum ActorError {
1217
1261
1218
1262
impl From < ActorError > for io:: Error {
1219
1263
fn from ( e : ActorError ) -> Self {
1220
- match e {
1221
- ActorError :: Io ( e) => e,
1222
- e => io:: Error :: new ( io:: ErrorKind :: Other , e) ,
1223
- }
1264
+ io:: Error :: new ( io:: ErrorKind :: Other , e)
1224
1265
}
1225
1266
}
1226
1267
0 commit comments