@@ -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 ,
@@ -279,7 +280,9 @@ async fn create_manifest(
279280 }
280281 } ;
281282 first_event_at = Some ( lower_bound. with_timezone ( & Local ) . to_rfc3339 ( ) ) ;
282- if let Err ( err) = STREAM_INFO . set_first_event_at ( stream_name, first_event_at. clone ( ) ) {
283+ if let Err ( err) =
284+ STREAM_INFO . set_first_event_at ( stream_name, first_event_at. as_ref ( ) . unwrap ( ) )
285+ {
283286 error ! (
284287 "Failed to update first_event_at in streaminfo for stream {:?} {err:?}" ,
285288 stream_name
@@ -330,8 +333,8 @@ pub async fn remove_manifest_from_snapshot(
330333 let manifests = & mut meta. snapshot . manifest_list ;
331334 // Filter out items whose manifest_path contains any of the dates_to_delete
332335 manifests. retain ( |item| !dates. iter ( ) . any ( |date| item. manifest_path . contains ( date) ) ) ;
336+ STREAM_INFO . reset_first_event_at ( stream_name) ?;
333337 meta. first_event_at = None ;
334- STREAM_INFO . set_first_event_at ( stream_name, None ) ?;
335338 storage. put_snapshot ( stream_name, meta. snapshot ) . await ?;
336339 }
337340 match CONFIG . options . mode {
@@ -391,7 +394,7 @@ pub async fn get_first_event(
391394 first_event_at = lower_bound. with_timezone ( & Local ) . to_rfc3339 ( ) ;
392395 meta. first_event_at = Some ( first_event_at. clone ( ) ) ;
393396 storage. put_stream_manifest ( stream_name, & meta) . await ?;
394- STREAM_INFO . set_first_event_at ( stream_name, Some ( first_event_at. clone ( ) ) ) ?;
397+ STREAM_INFO . set_first_event_at ( stream_name, & first_event_at) ?;
395398 }
396399 }
397400 }
@@ -432,6 +435,58 @@ pub async fn get_first_event(
432435 Ok ( Some ( first_event_at) )
433436}
434437
438+ /// Retrieves the earliest first-event-at from the storage for the specified stream.
439+ ///
440+ /// This function fetches the object-store format from all the stream.json files for the given stream from the storage,
441+ /// extracts the `first_event_at` timestamps, and returns the earliest `first_event_at`.
442+ ///
443+ /// # Arguments
444+ ///
445+ /// * `stream_name` - The name of the stream for which `first_event_at` is to be retrieved.
446+ ///
447+ /// # Returns
448+ ///
449+ /// * `Result<Option<String>, ObjectStorageError>` - Returns `Ok(Some(String))` with the earliest
450+ /// first event timestamp if found, `Ok(None)` if no timestamps are found, or an `ObjectStorageError`
451+ /// if an error occurs.
452+ ///
453+ /// # Errors
454+ ///
455+ /// This function will return an error if:
456+ /// * The stream metadata cannot be retrieved from the storage.
457+ ///
458+ /// # Examples
459+ /// ```ignore
460+ /// ```rust
461+ /// let result = get_first_event_from_storage("my_stream").await;
462+ /// match result {
463+ /// Ok(Some(first_event)) => println!("first-event-at: {}", first_event),
464+ /// Ok(None) => println!("first-event-at not found"),
465+ /// Err(e) => eprintln!("Error retrieving first-event-at from storage: {}", e),
466+ /// }
467+ /// ```
468+ pub async fn get_first_event_from_storage (
469+ stream_name : & str ,
470+ ) -> Result < Option < String > , ObjectStorageError > {
471+ let mut all_first_events = vec ! [ ] ;
472+ let stream_metas = get_stream_meta_from_storage ( stream_name) . await ;
473+ if let Ok ( stream_metas) = stream_metas {
474+ for stream_meta in stream_metas. iter ( ) {
475+ if let Some ( first_event) = & stream_meta. first_event_at {
476+ let first_event = DateTime :: parse_from_rfc3339 ( first_event) . unwrap ( ) ;
477+ let first_event = first_event. with_timezone ( & Utc ) ;
478+ all_first_events. push ( first_event) ;
479+ }
480+ }
481+ }
482+
483+ if all_first_events. is_empty ( ) {
484+ return Ok ( None ) ;
485+ }
486+ let first_event_at = all_first_events. iter ( ) . min ( ) . unwrap ( ) . to_rfc3339 ( ) ;
487+ Ok ( Some ( first_event_at) )
488+ }
489+
435490/// Partition the path to which this manifest belongs.
436491/// Useful when uploading the manifest file.
437492pub fn partition_path (
0 commit comments