@@ -27,6 +27,7 @@ use crate::option::{Mode, CONFIG};
2727use crate :: stats:: {
2828 event_labels_date, get_current_stats, storage_size_labels_date, update_deleted_stats,
2929} ;
30+ use crate :: storage:: object_storage:: get_stream_meta_from_storage;
3031use crate :: {
3132 catalog:: manifest:: Manifest ,
3233 event:: DEFAULT_TIMESTAMP_KEY ,
@@ -280,7 +281,9 @@ async fn create_manifest(
280281 }
281282 } ;
282283 first_event_at = Some ( lower_bound. with_timezone ( & Local ) . to_rfc3339 ( ) ) ;
283- if let Err ( err) = STREAM_INFO . set_first_event_at ( stream_name, first_event_at. clone ( ) ) {
284+ if let Err ( err) =
285+ STREAM_INFO . set_first_event_at ( stream_name, first_event_at. as_ref ( ) . unwrap ( ) )
286+ {
284287 error ! (
285288 "Failed to update first_event_at in streaminfo for stream {:?} {err:?}" ,
286289 stream_name
@@ -331,8 +334,8 @@ pub async fn remove_manifest_from_snapshot(
331334 let manifests = & mut meta. snapshot . manifest_list ;
332335 // Filter out items whose manifest_path contains any of the dates_to_delete
333336 manifests. retain ( |item| !dates. iter ( ) . any ( |date| item. manifest_path . contains ( date) ) ) ;
337+ STREAM_INFO . reset_first_event_at ( stream_name) ?;
334338 meta. first_event_at = None ;
335- STREAM_INFO . set_first_event_at ( stream_name, None ) ?;
336339 storage. put_snapshot ( stream_name, meta. snapshot ) . await ?;
337340 }
338341 match CONFIG . options . mode {
@@ -392,7 +395,7 @@ pub async fn get_first_event(
392395 first_event_at = lower_bound. with_timezone ( & Local ) . to_rfc3339 ( ) ;
393396 meta. first_event_at = Some ( first_event_at. clone ( ) ) ;
394397 storage. put_stream_manifest ( stream_name, & meta) . await ?;
395- STREAM_INFO . set_first_event_at ( stream_name, Some ( first_event_at. clone ( ) ) ) ?;
398+ STREAM_INFO . set_first_event_at ( stream_name, & first_event_at) ?;
396399 }
397400 }
398401 }
@@ -435,6 +438,58 @@ pub async fn get_first_event(
435438 Ok ( Some ( first_event_at) )
436439}
437440
441+ /// Retrieves the earliest first-event-at from the storage for the specified stream.
442+ ///
443+ /// This function fetches the object-store format from all the stream.json files for the given stream from the storage,
444+ /// extracts the `first_event_at` timestamps, and returns the earliest `first_event_at`.
445+ ///
446+ /// # Arguments
447+ ///
448+ /// * `stream_name` - The name of the stream for which `first_event_at` is to be retrieved.
449+ ///
450+ /// # Returns
451+ ///
452+ /// * `Result<Option<String>, ObjectStorageError>` - Returns `Ok(Some(String))` with the earliest
453+ /// first event timestamp if found, `Ok(None)` if no timestamps are found, or an `ObjectStorageError`
454+ /// if an error occurs.
455+ ///
456+ /// # Errors
457+ ///
458+ /// This function will return an error if:
459+ /// * The stream metadata cannot be retrieved from the storage.
460+ ///
461+ /// # Examples
462+ /// ```ignore
463+ /// ```rust
464+ /// let result = get_first_event_from_storage("my_stream").await;
465+ /// match result {
466+ /// Ok(Some(first_event)) => println!("first-event-at: {}", first_event),
467+ /// Ok(None) => println!("first-event-at not found"),
468+ /// Err(e) => eprintln!("Error retrieving first-event-at from storage: {}", e),
469+ /// }
470+ /// ```
471+ pub async fn get_first_event_from_storage (
472+ stream_name : & str ,
473+ ) -> Result < Option < String > , ObjectStorageError > {
474+ let mut all_first_events = vec ! [ ] ;
475+ let stream_metas = get_stream_meta_from_storage ( stream_name) . await ;
476+ if let Ok ( stream_metas) = stream_metas {
477+ for stream_meta in stream_metas. iter ( ) {
478+ if let Some ( first_event) = & stream_meta. first_event_at {
479+ let first_event = DateTime :: parse_from_rfc3339 ( first_event) . unwrap ( ) ;
480+ let first_event = first_event. with_timezone ( & Utc ) ;
481+ all_first_events. push ( first_event) ;
482+ }
483+ }
484+ }
485+
486+ if all_first_events. is_empty ( ) {
487+ return Ok ( None ) ;
488+ }
489+ let first_event_at = all_first_events. iter ( ) . min ( ) . unwrap ( ) . to_rfc3339 ( ) ;
490+ Ok ( Some ( first_event_at) )
491+ }
492+
438493/// Partition the path to which this manifest belongs.
439494/// Useful when uploading the manifest file.
440495pub fn partition_path (
0 commit comments