1use std::path::PathBuf;
9use std::sync::Arc;
10use std::sync::Mutex;
11
12use crate::lock::ScopedDirLock;
13use crate::log::LogMetadata;
14use crate::log::META_FILE;
15use crate::utils;
16
17#[derive(Clone, Debug)]
21pub enum GenericPath {
22 Filesystem(PathBuf),
24
25 SharedMeta {
28 path: Box<GenericPath>,
29 meta: Arc<Mutex<LogMetadata>>,
30 },
31
32 Nothing,
34}
35
36impl From<&std::path::Path> for GenericPath {
37 fn from(path: &std::path::Path) -> Self {
38 Self::Filesystem(path.to_path_buf())
39 }
40}
41
42impl From<&str> for GenericPath {
43 fn from(path: &str) -> Self {
44 Self::Filesystem(std::path::Path::new(path).to_path_buf())
45 }
46}
47
48impl From<PathBuf> for GenericPath {
49 fn from(path: PathBuf) -> Self {
50 Self::Filesystem(path)
51 }
52}
53
54impl From<&PathBuf> for GenericPath {
55 fn from(path: &PathBuf) -> Self {
56 Self::Filesystem(path.clone())
57 }
58}
59
60impl From<()> for GenericPath {
61 fn from(_path: ()) -> Self {
62 Self::Nothing
63 }
64}
65
66impl GenericPath {
67 pub fn as_opt_path(&self) -> Option<&std::path::Path> {
69 match self {
70 GenericPath::Filesystem(path) => Some(path),
71 GenericPath::SharedMeta { path, .. } => path.as_opt_path(),
72 GenericPath::Nothing => None,
73 }
74 }
75
76 pub(crate) fn mkdir(&self) -> crate::Result<()> {
77 if let Some(dir) = self.as_opt_path() {
78 utils::mkdir_p(dir)
79 } else {
80 Ok(())
81 }
82 }
83
84 pub(crate) fn lock(&self) -> crate::Result<ScopedDirLock> {
85 if let Some(dir) = self.as_opt_path() {
86 Ok(ScopedDirLock::new(dir)?)
87 } else {
88 Err(crate::Error::programming(
89 "read_meta() does not support GenericPath::Nothing",
90 ))
91 }
92 }
93
94 pub(crate) fn read_meta(&self) -> crate::Result<LogMetadata> {
95 match self {
96 GenericPath::Filesystem(dir) => {
97 let meta_path = dir.join(META_FILE);
98 LogMetadata::read_file(meta_path)
99 }
100 GenericPath::SharedMeta { meta, path } => {
101 let meta = meta.lock().unwrap();
102 if let GenericPath::Filesystem(dir) = path.as_ref() {
103 let meta_path = dir.join(META_FILE);
104 if let Ok(on_disk_meta) = LogMetadata::read_file(meta_path) {
105 if meta.is_compatible_with(&on_disk_meta) {
109 return Ok(on_disk_meta);
110 }
111 }
112 }
113 Ok(meta.clone())
114 }
115 GenericPath::Nothing => Err(crate::Error::programming(
116 "read_meta() does not support GenericPath::Nothing",
117 )),
118 }
119 }
120
121 pub(crate) fn write_meta(&self, meta: &LogMetadata, fsync: bool) -> crate::Result<()> {
122 match self {
123 GenericPath::Filesystem(dir) => {
124 let meta_path = dir.join(META_FILE);
125 meta.write_file(meta_path, fsync)?;
126 Ok(())
127 }
128 GenericPath::SharedMeta {
129 meta: shared_meta,
130 path,
131 } => {
132 if let GenericPath::Filesystem(dir) = path.as_ref() {
136 let meta_path = dir.join(META_FILE);
137 meta.write_file(meta_path, fsync)?;
138 }
139 let mut shared_meta = shared_meta.lock().unwrap();
140 *shared_meta = meta.clone();
141 Ok(())
142 }
143 GenericPath::Nothing => Err(crate::Error::programming(
144 "write_meta() does not support GenericPath::Nothing",
145 )),
146 }
147 }
148}