1pub mod drivers;
7pub mod ext;
8
9use crate::io_buffers::{IoBuffer, IoVector, IoVectorMut};
10use drivers::CommonStorageHelper;
11use std::any::Any;
12use std::fmt::{Debug, Display};
13use std::future::Future;
14use std::path::{Path, PathBuf};
15use std::pin::Pin;
16use std::sync::Arc;
17use std::{cmp, io};
18
19#[derive(Clone, Debug, Default)]
21pub struct StorageOpenOptions {
22 pub(crate) filename: Option<PathBuf>,
24
25 pub(crate) writable: bool,
27
28 pub(crate) direct: bool,
30
31 #[cfg(target_os = "macos")]
33 pub(crate) relaxed_sync: bool,
34}
35
36#[derive(Clone, Debug)]
38pub struct StorageCreateOptions {
39 pub(crate) open_opts: StorageOpenOptions,
43
44 pub(crate) size: u64,
46
47 pub(crate) prealloc_mode: PreallocateMode,
49
50 pub(crate) overwrite: bool,
52}
53
54pub trait Storage: Debug + Display + Send + Sized + Sync {
56 #[allow(async_fn_in_trait)] async fn open(_opts: StorageOpenOptions) -> io::Result<Self> {
61 Err(io::Error::new(
62 io::ErrorKind::Unsupported,
63 format!(
64 "Cannot open storage objects of type {}",
65 std::any::type_name::<Self>()
66 ),
67 ))
68 }
69
70 #[cfg(feature = "sync-wrappers")]
72 fn open_sync(opts: StorageOpenOptions) -> io::Result<Self> {
73 tokio::runtime::Builder::new_current_thread()
74 .build()?
75 .block_on(Self::open(opts))
76 }
77
78 #[allow(async_fn_in_trait)] async fn create_open(_opts: StorageCreateOptions) -> io::Result<Self> {
85 Err(io::Error::new(
86 io::ErrorKind::Unsupported,
87 format!(
88 "Cannot create storage objects of type {}",
89 std::any::type_name::<Self>()
90 ),
91 ))
92 }
93
94 #[allow(async_fn_in_trait)] async fn create(opts: StorageCreateOptions) -> io::Result<()> {
99 Self::create_open(opts).await?;
100 Ok(())
101 }
102
103 fn mem_align(&self) -> usize {
105 1
106 }
107
108 fn req_align(&self) -> usize {
110 1
111 }
112
113 fn zero_align(&self) -> usize {
117 self.req_align()
118 }
119
120 fn discard_align(&self) -> usize {
124 self.req_align()
125 }
126
127 fn size(&self) -> io::Result<u64>;
129
130 fn resolve_relative_path<P: AsRef<Path>>(&self, _relative: P) -> io::Result<PathBuf> {
140 Err(io::ErrorKind::Unsupported.into())
141 }
142
143 fn get_filename(&self) -> Option<PathBuf> {
148 None
149 }
150
151 #[allow(async_fn_in_trait)] async unsafe fn pure_readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()>;
164
165 #[allow(async_fn_in_trait)] async unsafe fn pure_writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()>;
181
182 #[allow(async_fn_in_trait)] async unsafe fn pure_write_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
200 unsafe { pure_write_full_zeroes(self, offset, length).await }
201 }
202
203 #[allow(async_fn_in_trait)] async unsafe fn pure_write_allocated_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
222 unsafe { pure_write_full_zeroes(self, offset, length).await }
223 }
224
225 #[allow(async_fn_in_trait)] async unsafe fn pure_discard(&self, _offset: u64, _length: u64) -> io::Result<()> {
240 Ok(())
241 }
242
243 #[allow(async_fn_in_trait)] async fn flush(&self) -> io::Result<()>;
252
253 #[allow(async_fn_in_trait)] async fn sync(&self) -> io::Result<()>;
259
260 #[allow(async_fn_in_trait)] async unsafe fn invalidate_cache(&self) -> io::Result<()>;
270
271 fn get_storage_helper(&self) -> &CommonStorageHelper;
274
275 #[allow(async_fn_in_trait)] async fn resize(&self, _new_size: u64, _prealloc_mode: PreallocateMode) -> io::Result<()> {
285 Err(io::ErrorKind::Unsupported.into())
286 }
287}
288
289pub trait DynStorage: Any + Debug + Display + Send + Sync {
303 fn dyn_mem_align(&self) -> usize;
305
306 fn dyn_req_align(&self) -> usize;
308
309 fn dyn_zero_align(&self) -> usize;
311
312 fn dyn_discard_align(&self) -> usize;
314
315 fn dyn_size(&self) -> io::Result<u64>;
317
318 fn dyn_resolve_relative_path(&self, relative: &Path) -> io::Result<PathBuf>;
320
321 fn dyn_get_filename(&self) -> Option<PathBuf>;
323
324 unsafe fn dyn_pure_readv<'a>(
329 &'a self,
330 bufv: IoVectorMut<'a>,
331 offset: u64,
332 ) -> Pin<Box<dyn Future<Output = io::Result<()>> + 'a>>;
333
334 unsafe fn dyn_pure_writev<'a>(
339 &'a self,
340 bufv: IoVector<'a>,
341 offset: u64,
342 ) -> Pin<Box<dyn Future<Output = io::Result<()>> + 'a>>;
343
344 unsafe fn dyn_pure_write_zeroes(
349 &self,
350 offset: u64,
351 length: u64,
352 ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
353
354 unsafe fn dyn_pure_write_allocated_zeroes(
359 &self,
360 offset: u64,
361 length: u64,
362 ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
363
364 unsafe fn dyn_pure_discard(
369 &self,
370 offset: u64,
371 length: u64,
372 ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
373
374 fn dyn_flush(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
376
377 fn dyn_sync(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
379
380 unsafe fn dyn_invalidate_cache(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
385
386 fn dyn_get_storage_helper(&self) -> &CommonStorageHelper;
388
389 fn dyn_resize(
391 &self,
392 new_size: u64,
393 prealloc_mode: PreallocateMode,
394 ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
395}
396
397#[derive(Clone, Copy, Debug, Eq, PartialEq)]
402#[non_exhaustive]
403pub enum PreallocateMode {
404 None,
408
409 Zero,
414
415 Allocate,
419
420 WriteData,
424}
425
426impl<S: Storage> Storage for &S {
427 fn mem_align(&self) -> usize {
428 (*self).mem_align()
429 }
430
431 fn req_align(&self) -> usize {
432 (*self).req_align()
433 }
434
435 fn zero_align(&self) -> usize {
436 (*self).zero_align()
437 }
438
439 fn discard_align(&self) -> usize {
440 (*self).discard_align()
441 }
442
443 fn size(&self) -> io::Result<u64> {
444 (*self).size()
445 }
446
447 fn resolve_relative_path<P: AsRef<Path>>(&self, relative: P) -> io::Result<PathBuf> {
448 (*self).resolve_relative_path(relative)
449 }
450
451 fn get_filename(&self) -> Option<PathBuf> {
452 (*self).get_filename()
453 }
454
455 async unsafe fn pure_readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()> {
456 unsafe { (*self).pure_readv(bufv, offset).await }
457 }
458
459 async unsafe fn pure_writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()> {
460 unsafe { (*self).pure_writev(bufv, offset).await }
461 }
462
463 async unsafe fn pure_write_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
464 unsafe { (*self).pure_write_zeroes(offset, length).await }
465 }
466
467 async unsafe fn pure_write_allocated_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
468 unsafe { (*self).pure_write_allocated_zeroes(offset, length).await }
469 }
470
471 async unsafe fn pure_discard(&self, offset: u64, length: u64) -> io::Result<()> {
472 unsafe { (*self).pure_discard(offset, length).await }
473 }
474
475 async fn flush(&self) -> io::Result<()> {
476 (*self).flush().await
477 }
478
479 async fn sync(&self) -> io::Result<()> {
480 (*self).sync().await
481 }
482
483 async unsafe fn invalidate_cache(&self) -> io::Result<()> {
484 unsafe { (*self).invalidate_cache().await }
485 }
486
487 fn get_storage_helper(&self) -> &CommonStorageHelper {
488 (*self).get_storage_helper()
489 }
490
491 async fn resize(&self, new_size: u64, prealloc_mode: PreallocateMode) -> io::Result<()> {
492 (*self).resize(new_size, prealloc_mode).await
493 }
494}
495
496impl<S: Storage + 'static> DynStorage for S {
497 fn dyn_mem_align(&self) -> usize {
498 <S as Storage>::mem_align(self)
499 }
500
501 fn dyn_req_align(&self) -> usize {
502 <S as Storage>::req_align(self)
503 }
504
505 fn dyn_zero_align(&self) -> usize {
506 <S as Storage>::zero_align(self)
507 }
508
509 fn dyn_discard_align(&self) -> usize {
510 <S as Storage>::discard_align(self)
511 }
512
513 fn dyn_size(&self) -> io::Result<u64> {
514 <S as Storage>::size(self)
515 }
516
517 fn dyn_resolve_relative_path(&self, relative: &Path) -> io::Result<PathBuf> {
518 <S as Storage>::resolve_relative_path(self, relative)
519 }
520
521 fn dyn_get_filename(&self) -> Option<PathBuf> {
522 <S as Storage>::get_filename(self)
523 }
524
525 unsafe fn dyn_pure_readv<'a>(
526 &'a self,
527 bufv: IoVectorMut<'a>,
528 offset: u64,
529 ) -> Pin<Box<dyn Future<Output = io::Result<()>> + 'a>> {
530 Box::pin(unsafe { <S as Storage>::pure_readv(self, bufv, offset) })
531 }
532
533 unsafe fn dyn_pure_writev<'a>(
534 &'a self,
535 bufv: IoVector<'a>,
536 offset: u64,
537 ) -> Pin<Box<dyn Future<Output = io::Result<()>> + 'a>> {
538 Box::pin(unsafe { <S as Storage>::pure_writev(self, bufv, offset) })
539 }
540
541 unsafe fn dyn_pure_write_zeroes(
542 &self,
543 offset: u64,
544 length: u64,
545 ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
546 Box::pin(unsafe { <S as Storage>::pure_write_zeroes(self, offset, length) })
547 }
548
549 unsafe fn dyn_pure_write_allocated_zeroes(
550 &self,
551 offset: u64,
552 length: u64,
553 ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
554 Box::pin(unsafe { <S as Storage>::pure_write_allocated_zeroes(self, offset, length) })
555 }
556
557 unsafe fn dyn_pure_discard(
558 &self,
559 offset: u64,
560 length: u64,
561 ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
562 Box::pin(unsafe { <S as Storage>::pure_discard(self, offset, length) })
563 }
564
565 fn dyn_flush(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
566 Box::pin(<S as Storage>::flush(self))
567 }
568
569 fn dyn_sync(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
570 Box::pin(<S as Storage>::sync(self))
571 }
572
573 unsafe fn dyn_invalidate_cache(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
574 Box::pin(unsafe { <S as Storage>::invalidate_cache(self) })
575 }
576
577 fn dyn_get_storage_helper(&self) -> &CommonStorageHelper {
578 <S as Storage>::get_storage_helper(self)
579 }
580
581 fn dyn_resize(
582 &self,
583 new_size: u64,
584 prealloc_mode: PreallocateMode,
585 ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
586 Box::pin(<S as Storage>::resize(self, new_size, prealloc_mode))
587 }
588}
589
590impl Storage for Box<dyn DynStorage> {
591 async fn open(opts: StorageOpenOptions) -> io::Result<Self> {
592 Ok(Box::new(crate::file::File::open(opts).await?))
596 }
597
598 async fn create_open(opts: StorageCreateOptions) -> io::Result<Self> {
599 Ok(Box::new(crate::file::File::create_open(opts).await?))
601 }
602
603 fn mem_align(&self) -> usize {
604 self.as_ref().dyn_mem_align()
605 }
606
607 fn req_align(&self) -> usize {
608 self.as_ref().dyn_req_align()
609 }
610
611 fn zero_align(&self) -> usize {
612 self.as_ref().dyn_zero_align()
613 }
614
615 fn discard_align(&self) -> usize {
616 self.as_ref().dyn_discard_align()
617 }
618
619 fn size(&self) -> io::Result<u64> {
620 self.as_ref().dyn_size()
621 }
622
623 fn resolve_relative_path<P: AsRef<Path>>(&self, relative: P) -> io::Result<PathBuf> {
624 self.as_ref().dyn_resolve_relative_path(relative.as_ref())
625 }
626
627 fn get_filename(&self) -> Option<PathBuf> {
628 self.as_ref().dyn_get_filename()
629 }
630
631 async unsafe fn pure_readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()> {
632 unsafe { self.as_ref().dyn_pure_readv(bufv, offset).await }
633 }
634
635 async unsafe fn pure_writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()> {
636 unsafe { self.as_ref().dyn_pure_writev(bufv, offset).await }
637 }
638
639 async unsafe fn pure_write_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
640 unsafe { self.as_ref().dyn_pure_write_zeroes(offset, length).await }
641 }
642
643 async unsafe fn pure_write_allocated_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
644 unsafe {
645 self.as_ref()
646 .dyn_pure_write_allocated_zeroes(offset, length)
647 .await
648 }
649 }
650
651 async unsafe fn pure_discard(&self, offset: u64, length: u64) -> io::Result<()> {
652 unsafe { self.as_ref().dyn_pure_discard(offset, length).await }
653 }
654
655 async fn flush(&self) -> io::Result<()> {
656 self.as_ref().dyn_flush().await
657 }
658
659 async fn sync(&self) -> io::Result<()> {
660 self.as_ref().dyn_sync().await
661 }
662
663 async unsafe fn invalidate_cache(&self) -> io::Result<()> {
664 unsafe { self.as_ref().dyn_invalidate_cache().await }
665 }
666
667 fn get_storage_helper(&self) -> &CommonStorageHelper {
668 self.as_ref().dyn_get_storage_helper()
669 }
670
671 async fn resize(&self, new_size: u64, prealloc_mode: PreallocateMode) -> io::Result<()> {
672 self.as_ref().dyn_resize(new_size, prealloc_mode).await
673 }
674}
675
676impl Storage for Arc<dyn DynStorage> {
677 async fn open(opts: StorageOpenOptions) -> io::Result<Self> {
678 Box::<dyn DynStorage>::open(opts).await.map(Into::into)
679 }
680
681 async fn create_open(opts: StorageCreateOptions) -> io::Result<Self> {
682 Box::<dyn DynStorage>::create_open(opts)
683 .await
684 .map(Into::into)
685 }
686
687 fn mem_align(&self) -> usize {
688 self.as_ref().dyn_mem_align()
689 }
690
691 fn req_align(&self) -> usize {
692 self.as_ref().dyn_req_align()
693 }
694
695 fn zero_align(&self) -> usize {
696 self.as_ref().dyn_zero_align()
697 }
698
699 fn discard_align(&self) -> usize {
700 self.as_ref().dyn_discard_align()
701 }
702
703 fn size(&self) -> io::Result<u64> {
704 self.as_ref().dyn_size()
705 }
706
707 fn resolve_relative_path<P: AsRef<Path>>(&self, relative: P) -> io::Result<PathBuf> {
708 self.as_ref().dyn_resolve_relative_path(relative.as_ref())
709 }
710
711 fn get_filename(&self) -> Option<PathBuf> {
712 self.as_ref().dyn_get_filename()
713 }
714
715 async unsafe fn pure_readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()> {
716 unsafe { self.as_ref().dyn_pure_readv(bufv, offset) }.await
717 }
718
719 async unsafe fn pure_writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()> {
720 unsafe { self.as_ref().dyn_pure_writev(bufv, offset) }.await
721 }
722
723 async unsafe fn pure_write_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
724 unsafe { self.as_ref().dyn_pure_write_zeroes(offset, length) }.await
725 }
726
727 async unsafe fn pure_write_allocated_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
728 unsafe {
729 self.as_ref()
730 .dyn_pure_write_allocated_zeroes(offset, length)
731 }
732 .await
733 }
734
735 async unsafe fn pure_discard(&self, offset: u64, length: u64) -> io::Result<()> {
736 unsafe { self.as_ref().dyn_pure_discard(offset, length) }.await
737 }
738
739 async fn flush(&self) -> io::Result<()> {
740 self.as_ref().dyn_flush().await
741 }
742
743 async fn sync(&self) -> io::Result<()> {
744 self.as_ref().dyn_sync().await
745 }
746
747 async unsafe fn invalidate_cache(&self) -> io::Result<()> {
748 unsafe { self.as_ref().dyn_invalidate_cache().await }
749 }
750
751 fn get_storage_helper(&self) -> &CommonStorageHelper {
752 self.as_ref().dyn_get_storage_helper()
753 }
754
755 async fn resize(&self, new_size: u64, prealloc_mode: PreallocateMode) -> io::Result<()> {
756 self.as_ref().dyn_resize(new_size, prealloc_mode).await
757 }
758}
759
760impl StorageOpenOptions {
761 pub fn new() -> Self {
763 StorageOpenOptions::default()
764 }
765
766 pub fn filename<P: AsRef<Path>>(mut self, filename: P) -> Self {
768 self.filename = Some(filename.as_ref().to_owned());
769 self
770 }
771
772 pub fn write(mut self, write: bool) -> Self {
774 self.writable = write;
775 self
776 }
777
778 pub fn direct(mut self, direct: bool) -> Self {
780 self.direct = direct;
781 self
782 }
783
784 #[cfg(target_os = "macos")]
791 pub fn relaxed_sync(mut self, relaxed_sync: bool) -> Self {
792 self.relaxed_sync = relaxed_sync;
793 self
794 }
795
796 pub fn get_filename(&self) -> Option<&Path> {
798 self.filename.as_deref()
799 }
800
801 pub fn get_writable(&self) -> bool {
803 self.writable
804 }
805
806 pub fn get_direct(&self) -> bool {
808 self.direct
809 }
810
811 #[cfg(target_os = "macos")]
813 pub fn get_relaxed_sync(&self) -> bool {
814 self.relaxed_sync
815 }
816}
817
818impl StorageCreateOptions {
819 pub fn new() -> Self {
821 StorageCreateOptions::default()
822 }
823
824 pub fn filename<P: AsRef<Path>>(self, filename: P) -> Self {
826 self.modify_open_opts(|o| o.filename(filename))
827 }
828
829 pub fn size(mut self, size: u64) -> Self {
831 self.size = size;
832 self
833 }
834
835 pub fn preallocate(mut self, prealloc_mode: PreallocateMode) -> Self {
837 self.prealloc_mode = prealloc_mode;
838 self
839 }
840
841 pub fn overwrite(mut self, overwrite: bool) -> Self {
843 self.overwrite = overwrite;
844 self
845 }
846
847 pub fn modify_open_opts<F: FnOnce(StorageOpenOptions) -> StorageOpenOptions>(
849 mut self,
850 f: F,
851 ) -> Self {
852 self.open_opts = f(self.open_opts);
853 self
854 }
855
856 pub fn get_filename(&self) -> Option<&Path> {
858 self.open_opts.filename.as_deref()
859 }
860
861 pub fn get_size(&self) -> u64 {
863 self.size
864 }
865
866 pub fn get_preallocate(&self) -> PreallocateMode {
868 self.prealloc_mode
869 }
870
871 pub fn get_overwrite(&self) -> bool {
873 self.overwrite
874 }
875
876 pub fn get_open_options(self) -> StorageOpenOptions {
878 self.open_opts
879 }
880}
881
882impl Default for StorageCreateOptions {
883 fn default() -> Self {
884 StorageCreateOptions {
885 open_opts: Default::default(),
886 size: 0,
887 prealloc_mode: PreallocateMode::None,
888 overwrite: false,
889 }
890 }
891}
892
893async unsafe fn pure_write_full_zeroes<S: Storage>(
905 storage: S,
906 mut offset: u64,
907 mut length: u64,
908) -> io::Result<()> {
909 let req_align = storage.req_align() as u64;
910 if !(offset | length).is_multiple_of(req_align) {
911 return Err(io::Error::new(
912 io::ErrorKind::InvalidInput,
913 "write_zeroes fallback: offset/length not aligned to request alignment",
914 ));
915 }
916
917 let mem_align = storage.mem_align() as u64;
918 let max_chunk_len = cmp::max(cmp::max(req_align, mem_align), 1048576);
919 let buflen = cmp::min(length, max_chunk_len) as usize;
920 let mut buf = IoBuffer::new(buflen, storage.mem_align())?;
921 buf.as_mut().into_slice().fill(0);
922
923 while length > 0 {
924 let chunk_len = cmp::min(length, max_chunk_len) as usize;
925 unsafe {
926 storage
927 .pure_writev(buf.as_ref_range(0..chunk_len).into(), offset)
928 .await
929 }?;
930 offset += chunk_len as u64;
931 length -= chunk_len as u64;
932 }
933
934 Ok(())
935}