|
18 | 18 |
|
19 | 19 | use std::sync::Arc; |
20 | 20 |
|
21 | | -use chrono::{DateTime, NaiveDateTime, NaiveTime, Utc}; |
| 21 | +use chrono::{DateTime, Local, NaiveDateTime, NaiveTime, Utc}; |
22 | 22 | use relative_path::RelativePathBuf; |
23 | 23 |
|
24 | 24 | use crate::{ |
@@ -69,33 +69,33 @@ impl ManifestFile for manifest::File { |
69 | 69 | } |
70 | 70 | } |
71 | 71 |
|
| 72 | +fn get_file_bounds(file: &manifest::File) -> (DateTime<Utc>, DateTime<Utc>) { |
| 73 | + match file |
| 74 | + .columns() |
| 75 | + .iter() |
| 76 | + .find(|col| col.name == "p_timestamp") |
| 77 | + .unwrap() |
| 78 | + .stats |
| 79 | + .clone() |
| 80 | + .unwrap() |
| 81 | + { |
| 82 | + column::TypedStatistics::Int(stats) => ( |
| 83 | + NaiveDateTime::from_timestamp_millis(stats.min) |
| 84 | + .unwrap() |
| 85 | + .and_utc(), |
| 86 | + NaiveDateTime::from_timestamp_millis(stats.max) |
| 87 | + .unwrap() |
| 88 | + .and_utc(), |
| 89 | + ), |
| 90 | + _ => unreachable!(), |
| 91 | + } |
| 92 | +} |
| 93 | + |
72 | 94 | pub async fn update_snapshot( |
73 | 95 | storage: Arc<dyn ObjectStorage + Send>, |
74 | 96 | stream_name: &str, |
75 | 97 | change: manifest::File, |
76 | 98 | ) -> Result<(), ObjectStorageError> { |
77 | | - fn get_file_bounds(file: &manifest::File) -> (DateTime<Utc>, DateTime<Utc>) { |
78 | | - match file |
79 | | - .columns() |
80 | | - .iter() |
81 | | - .find(|col| col.name == "p_timestamp") |
82 | | - .unwrap() |
83 | | - .stats |
84 | | - .clone() |
85 | | - .unwrap() |
86 | | - { |
87 | | - column::TypedStatistics::Int(stats) => ( |
88 | | - NaiveDateTime::from_timestamp_millis(stats.min) |
89 | | - .unwrap() |
90 | | - .and_utc(), |
91 | | - NaiveDateTime::from_timestamp_millis(stats.min) |
92 | | - .unwrap() |
93 | | - .and_utc(), |
94 | | - ), |
95 | | - _ => unreachable!(), |
96 | | - } |
97 | | - } |
98 | | - |
99 | 99 | // get current snapshot |
100 | 100 | let mut meta = storage.get_snapshot(stream_name).await?; |
101 | 101 | let manifests = &mut meta.manifest_list; |
@@ -154,6 +154,58 @@ pub async fn update_snapshot( |
154 | 154 | Ok(()) |
155 | 155 | } |
156 | 156 |
|
| 157 | +pub async fn remove_manifest_from_snapshot( |
| 158 | + storage: Arc<dyn ObjectStorage + Send>, |
| 159 | + stream_name: &str, |
| 160 | + dates: Vec<String>, |
| 161 | +) -> Result<(), ObjectStorageError> { |
| 162 | + // get current snapshot |
| 163 | + let mut meta = storage.get_snapshot(stream_name).await?; |
| 164 | + let manifests = &mut meta.manifest_list; |
| 165 | + |
| 166 | + // Filter out items whose manifest_path contains any of the dates_to_delete |
| 167 | + manifests.retain(|item| !dates.iter().any(|date| item.manifest_path.contains(date))); |
| 168 | + |
| 169 | + storage.put_snapshot(stream_name, meta).await?; |
| 170 | + Ok(()) |
| 171 | +} |
| 172 | + |
| 173 | +pub async fn get_first_event( |
| 174 | + storage: Arc<dyn ObjectStorage + Send>, |
| 175 | + stream_name: &str, |
| 176 | +) -> Result<Option<String>, ObjectStorageError> { |
| 177 | + // get current snapshot |
| 178 | + let mut meta = storage.get_snapshot(stream_name).await?; |
| 179 | + let manifests = &mut meta.manifest_list; |
| 180 | + |
| 181 | + if manifests.is_empty() { |
| 182 | + log::info!("No manifest found for stream {stream_name}"); |
| 183 | + return Err(ObjectStorageError::Custom("No manifest found".to_string())); |
| 184 | + } |
| 185 | + |
| 186 | + let manifest = &manifests[0]; |
| 187 | + |
| 188 | + let path = partition_path( |
| 189 | + stream_name, |
| 190 | + manifest.time_lower_bound, |
| 191 | + manifest.time_upper_bound, |
| 192 | + ); |
| 193 | + let Some(manifest) = storage.get_manifest(&path).await? else { |
| 194 | + return Err(ObjectStorageError::UnhandledError( |
| 195 | + "Manifest found in snapshot but not in object-storage" |
| 196 | + .to_string() |
| 197 | + .into(), |
| 198 | + )); |
| 199 | + }; |
| 200 | + |
| 201 | + if let Some(first_event) = manifest.files.first() { |
| 202 | + let (lower_bound, _) = get_file_bounds(first_event); |
| 203 | + let first_event_at = lower_bound.with_timezone(&Local).to_rfc3339(); |
| 204 | + return Ok(Some(first_event_at)); |
| 205 | + } |
| 206 | + Ok(None) |
| 207 | +} |
| 208 | + |
157 | 209 | /// Partition the path to which this manifest belongs. |
158 | 210 | /// Useful when uploading the manifest file. |
159 | 211 | fn partition_path( |
|
0 commit comments