1use super::{
5 EventQuery, EventSnapshot, EventSourcingStats, EventStoreConfig, EventStoreTrait,
6 PersistenceBackend, PersistenceOperation, PersistenceStats, PersistenceStatus, QueryOrder,
7 SnapshotMetadata, StorageMetadata, StoredEvent, TimeRange,
8};
9use crate::{EventMetadata, StreamEvent};
10use anyhow::Result;
11use chrono::{DateTime, Utc};
12use serde::de::DeserializeOwned;
13use std::collections::VecDeque;
14use std::collections::{BTreeMap, HashMap, HashSet};
15use std::path::Path;
16use std::sync::atomic::{AtomicU64, Ordering};
17use std::sync::Arc;
18use std::time::Instant;
19use tokio::io::AsyncWriteExt;
20use tokio::sync::{Mutex, RwLock, Semaphore};
21use tracing::{debug, error, info, warn};
22use uuid::Uuid;
23
24pub struct EventStore {
26 config: EventStoreConfig,
28 memory_events: Arc<RwLock<BTreeMap<u64, StoredEvent>>>,
30 stream_versions: Arc<RwLock<HashMap<String, u64>>>,
32 next_sequence: Arc<AtomicU64>,
34 indexes: Arc<EventIndexes>,
36 snapshots: Arc<RwLock<HashMap<String, Vec<EventSnapshot>>>>,
38 persistence_manager: Arc<PersistenceManager>,
40 stats: Arc<EventSourcingStats>,
42 operation_semaphore: Arc<Semaphore>,
44}
45
46pub struct EventIndexes {
48 by_event_type: RwLock<HashMap<String, Vec<u64>>>,
50 by_timestamp: RwLock<BTreeMap<DateTime<Utc>, Vec<u64>>>,
52 by_source: RwLock<HashMap<String, Vec<u64>>>,
54 by_stream: RwLock<HashMap<String, Vec<u64>>>,
56 custom_indexes: RwLock<HashMap<String, HashMap<String, Vec<u64>>>>,
58}
59
60pub struct PersistenceManager {
62 backend: PersistenceBackend,
64 pending_operations: Arc<Mutex<VecDeque<PersistenceOperation>>>,
66 pub(crate) stats: Arc<PersistenceStats>,
68}
69
70impl EventStore {
71 pub async fn new(config: EventStoreConfig) -> Result<Self> {
78 let persistence_manager =
79 Arc::new(PersistenceManager::new(config.persistence_backend.clone())?);
80
81 let memory_events = Arc::new(RwLock::new(BTreeMap::new()));
82 let stream_versions = Arc::new(RwLock::new(HashMap::new()));
83 let indexes = Arc::new(EventIndexes::new());
84 let snapshots = Arc::new(RwLock::new(HashMap::new()));
85 let next_sequence = Arc::new(AtomicU64::new(1));
86
87 let loaded_events = persistence_manager.load_persisted_events().await?;
90 let mut max_sequence = 0u64;
91 {
92 let mut mem = memory_events.write().await;
93 let mut versions = stream_versions.write().await;
94 for mut event in loaded_events {
95 event.storage_metadata.persistence_status = PersistenceStatus::Persisted;
97 max_sequence = max_sequence.max(event.sequence_number);
98 let version_slot = versions.entry(event.stream_id.clone()).or_insert(0);
99 if event.stream_version > *version_slot {
100 *version_slot = event.stream_version;
101 }
102 indexes.add_event(&event).await?;
103 mem.insert(event.sequence_number, event);
104 }
105 }
106 next_sequence.store(max_sequence + 1, Ordering::SeqCst);
107
108 let loaded_snapshots = persistence_manager.load_persisted_snapshots().await?;
109 {
110 let mut snapshot_map = snapshots.write().await;
111 for snapshot in loaded_snapshots {
112 snapshot_map
113 .entry(snapshot.stream_id.clone())
114 .or_insert_with(Vec::new)
115 .push(snapshot);
116 }
117 for stream_snapshots in snapshot_map.values_mut() {
118 stream_snapshots.sort_by_key(|s| s.stream_version);
119 }
120 }
121
122 Ok(Self {
123 config,
124 memory_events,
125 stream_versions,
126 next_sequence,
127 indexes,
128 snapshots,
129 persistence_manager,
130 stats: Arc::new(EventSourcingStats::default()),
131 operation_semaphore: Arc::new(Semaphore::new(1000)), })
133 }
134
135 pub async fn store_event(&self, stream_id: String, event: StreamEvent) -> Result<StoredEvent> {
137 let _permit = self.operation_semaphore.acquire().await?;
138 let start_time = Instant::now();
139
140 let sequence_number = self.next_sequence.fetch_add(1, Ordering::SeqCst);
142 let stream_version = {
143 let mut versions = self.stream_versions.write().await;
144 let version = versions.get(&stream_id).unwrap_or(&0) + 1;
145 versions.insert(stream_id.clone(), version);
146 version
147 };
148
149 let checksum = self.calculate_checksum(&event)?;
151 let original_size = self.estimate_size(&event);
152 let mut stored_event = StoredEvent {
153 event_id: Uuid::new_v4(),
154 sequence_number,
155 stream_id: stream_id.clone(),
156 stream_version,
157 event_data: event,
158 stored_at: Utc::now(),
159 storage_metadata: StorageMetadata {
160 checksum,
161 compressed_size: None,
162 original_size,
163 storage_location: format!("memory:{sequence_number}"),
164 persistence_status: PersistenceStatus::InMemory,
165 },
166 };
167
168 {
170 let mut memory_events = self.memory_events.write().await;
171 memory_events.insert(sequence_number, stored_event.clone());
172 }
173
174 self.indexes.add_event(&stored_event).await?;
176
177 if self.config.enable_persistence && self.persistence_manager.is_durable() {
180 match self.persistence_manager.persist_event(&stored_event).await {
181 Ok(()) => {
182 stored_event.storage_metadata.persistence_status = PersistenceStatus::Persisted;
183 self.stats
184 .persistence_operations
185 .fetch_add(1, Ordering::Relaxed);
186 let mut memory_events = self.memory_events.write().await;
187 if let Some(entry) = memory_events.get_mut(&sequence_number) {
188 entry.storage_metadata.persistence_status = PersistenceStatus::Persisted;
189 }
190 }
191 Err(e) => {
192 error!(
193 "Failed to persist event {} for stream {}: {}",
194 stored_event.event_id, stream_id, e
195 );
196 stored_event.storage_metadata.persistence_status = PersistenceStatus::Failed {
197 error: e.to_string(),
198 };
199 self.stats.failed_operations.fetch_add(1, Ordering::Relaxed);
200 let mut memory_events = self.memory_events.write().await;
201 if let Some(entry) = memory_events.get_mut(&sequence_number) {
202 entry.storage_metadata.persistence_status = PersistenceStatus::Failed {
203 error: e.to_string(),
204 };
205 }
206 }
207 }
208 }
209
210 {
216 let mut memory_events = self.memory_events.write().await;
217 if memory_events.len() > self.config.max_memory_events {
218 let overflow = memory_events.len() - self.config.max_memory_events;
219 let evictable: Vec<u64> = memory_events
220 .iter()
221 .filter(|(_, event)| self.can_evict(event))
222 .map(|(seq, _)| *seq)
223 .take(overflow)
224 .collect();
225
226 for seq in evictable {
227 memory_events.remove(&seq);
228 }
229 }
230 }
231
232 if self.config.snapshot_config.enable_snapshots
234 && stream_version % self.config.snapshot_config.snapshot_interval as u64 == 0
235 {
236 self.create_snapshot(&stream_id, stream_version).await?;
237 }
238
239 self.stats
241 .total_events_stored
242 .fetch_add(1, Ordering::Relaxed);
243 let store_latency = start_time.elapsed();
244 self.stats
245 .average_store_latency_ms
246 .store(store_latency.as_millis() as u64, Ordering::Relaxed);
247
248 info!(
249 "Stored event {} for stream {} (seq: {}, version: {})",
250 stored_event.event_id, stream_id, sequence_number, stream_version
251 );
252
253 Ok(stored_event)
254 }
255
256 pub async fn query_events(&self, query: EventQuery) -> Result<Vec<StoredEvent>> {
258 let _permit = self.operation_semaphore.acquire().await?;
259 let start_time = Instant::now();
260
261 let candidate_sequences = self.indexes.find_matching_sequences(&query).await?;
262 let mut results = Vec::new();
263
264 let memory_events = self.memory_events.read().await;
265 for &sequence in &candidate_sequences {
266 if let Some(stored_event) = memory_events.get(&sequence) {
267 if self.matches_query(stored_event, &query) {
268 results.push(stored_event.clone());
269
270 if let Some(limit) = query.limit {
271 if results.len() >= limit {
272 break;
273 }
274 }
275 }
276 }
277 }
278
279 self.sort_results(&mut results, &query.order);
281
282 self.stats
284 .total_events_retrieved
285 .fetch_add(results.len() as u64, Ordering::Relaxed);
286 let retrieve_latency = start_time.elapsed();
287 self.stats
288 .average_retrieve_latency_ms
289 .store(retrieve_latency.as_millis() as u64, Ordering::Relaxed);
290
291 debug!(
292 "Query returned {} events in {:?}",
293 results.len(),
294 retrieve_latency
295 );
296
297 Ok(results)
298 }
299
300 pub async fn get_stream_events(
302 &self,
303 stream_id: &str,
304 from_version: Option<u64>,
305 ) -> Result<Vec<StoredEvent>> {
306 let query = EventQuery {
307 stream_id: Some(stream_id.to_string()),
308 event_types: None,
309 time_range: None,
310 sequence_range: None,
311 source: None,
312 custom_filters: HashMap::new(),
313 limit: None,
314 order: QueryOrder::SequenceAsc,
315 };
316
317 let mut events = self.query_events(query).await?;
318
319 if let Some(from_version) = from_version {
320 events.retain(|e| e.stream_version >= from_version);
321 }
322
323 Ok(events)
324 }
325
326 pub async fn replay_from_timestamp(
328 &self,
329 timestamp: DateTime<Utc>,
330 ) -> Result<Vec<StoredEvent>> {
331 let query = EventQuery {
332 stream_id: None,
333 event_types: None,
334 time_range: Some(TimeRange {
335 start: timestamp,
336 end: Utc::now(),
337 }),
338 sequence_range: None,
339 source: None,
340 custom_filters: HashMap::new(),
341 limit: None,
342 order: QueryOrder::SequenceAsc,
343 };
344
345 self.query_events(query).await
346 }
347
348 async fn create_snapshot(&self, stream_id: &str, stream_version: u64) -> Result<EventSnapshot> {
350 let events = self.get_stream_events(stream_id, None).await?;
351
352 let state_data = self.aggregate_events(&events)?;
354 let compressed_data = self.compress_data(&state_data)?;
355
356 let snapshot = EventSnapshot {
357 snapshot_id: Uuid::new_v4(),
358 stream_id: stream_id.to_string(),
359 stream_version,
360 sequence_number: events.last().map(|e| e.sequence_number).unwrap_or(0),
361 created_at: Utc::now(),
362 state_data: compressed_data.clone(),
363 metadata: SnapshotMetadata {
364 compression: Some("gzip".to_string()),
365 original_size: state_data.len(),
366 compressed_size: compressed_data.len(),
367 checksum: self.calculate_data_checksum(&compressed_data)?,
368 },
369 };
370
371 {
373 let mut snapshots = self.snapshots.write().await;
374 let stream_snapshots = snapshots
375 .entry(stream_id.to_string())
376 .or_insert_with(Vec::new);
377 stream_snapshots.push(snapshot.clone());
378
379 if stream_snapshots.len() > self.config.snapshot_config.max_snapshots {
381 stream_snapshots.remove(0);
382 }
383 }
384
385 if self.config.enable_persistence && self.persistence_manager.is_durable() {
388 self.persistence_manager
389 .persist_snapshot(&snapshot)
390 .await
391 .map_err(|e| {
392 anyhow::anyhow!("Failed to persist snapshot for stream {stream_id}: {e}")
393 })?;
394 }
395
396 self.stats.snapshots_created.fetch_add(1, Ordering::Relaxed);
397 info!(
398 "Created snapshot {} for stream {} at version {}",
399 snapshot.snapshot_id, stream_id, stream_version
400 );
401
402 Ok(snapshot)
403 }
404
405 pub async fn get_latest_snapshot(&self, stream_id: &str) -> Result<Option<EventSnapshot>> {
407 let snapshots = self.snapshots.read().await;
408 if let Some(stream_snapshots) = snapshots.get(stream_id) {
409 Ok(stream_snapshots.last().cloned())
410 } else {
411 Ok(None)
412 }
413 }
414
415 pub async fn rebuild_stream_state(&self, stream_id: &str) -> Result<Vec<u8>> {
417 if let Some(snapshot) = self.get_latest_snapshot(stream_id).await? {
419 let events = self
421 .get_stream_events(stream_id, Some(snapshot.stream_version + 1))
422 .await?;
423
424 let mut state = self.decompress_data(&snapshot.state_data)?;
426
427 for event in events {
429 state = self.apply_event_to_state(state, &event.event_data)?;
430 }
431
432 Ok(state)
433 } else {
434 let events = self.get_stream_events(stream_id, None).await?;
436 let aggregated = self.aggregate_events(&events)?;
437 Ok(aggregated)
438 }
439 }
440
441 fn can_evict(&self, event: &StoredEvent) -> bool {
447 if !self.config.enable_persistence || !self.persistence_manager.is_durable() {
448 return true;
449 }
450 matches!(
451 event.storage_metadata.persistence_status,
452 PersistenceStatus::Persisted | PersistenceStatus::Archived
453 )
454 }
455
456 fn matches_query(&self, event: &StoredEvent, query: &EventQuery) -> bool {
458 if let Some(ref stream_id) = query.stream_id {
460 if &event.stream_id != stream_id {
461 return false;
462 }
463 }
464
465 if let Some(ref event_types) = query.event_types {
467 let event_type = format!("{:?}", std::mem::discriminant(&event.event_data));
468 if !event_types.contains(&event_type) {
469 return false;
470 }
471 }
472
473 if let Some(ref time_range) = query.time_range {
475 let event_time = event.event_data.metadata().timestamp;
476 if event_time < time_range.start || event_time > time_range.end {
477 return false;
478 }
479 }
480
481 if let Some(ref seq_range) = query.sequence_range {
483 if event.sequence_number < seq_range.start || event.sequence_number > seq_range.end {
484 return false;
485 }
486 }
487
488 if let Some(ref source) = query.source {
490 if &event.event_data.metadata().source != source {
491 return false;
492 }
493 }
494
495 true
496 }
497
498 fn sort_results(&self, results: &mut [StoredEvent], order: &QueryOrder) {
500 match order {
501 QueryOrder::SequenceAsc => {
502 results.sort_by_key(|e| e.sequence_number);
503 }
504 QueryOrder::SequenceDesc => {
505 results.sort_by_key(|e| std::cmp::Reverse(e.sequence_number));
506 }
507 QueryOrder::TimestampAsc => {
508 results.sort_by_key(|e| e.event_data.metadata().timestamp);
509 }
510 QueryOrder::TimestampDesc => {
511 results.sort_by_key(|e| std::cmp::Reverse(e.event_data.metadata().timestamp));
512 }
513 }
514 }
515
516 fn calculate_checksum(&self, event: &StreamEvent) -> Result<String> {
518 let serialized = serde_json::to_string(event)?;
519 Ok(format!("{:x}", crc32fast::hash(serialized.as_bytes())))
520 }
521
522 fn calculate_data_checksum(&self, data: &[u8]) -> Result<String> {
524 Ok(format!("{:x}", crc32fast::hash(data)))
525 }
526
527 fn estimate_size(&self, event: &StreamEvent) -> usize {
529 serde_json::to_string(event)
530 .map(|s| s.len())
531 .unwrap_or(1024)
532 }
533
534 fn aggregate_events(&self, events: &[StoredEvent]) -> Result<Vec<u8>> {
536 let aggregate = format!("Aggregated {} events", events.len());
538 Ok(aggregate.into_bytes())
539 }
540
541 fn apply_event_to_state(&self, mut state: Vec<u8>, _event: &StreamEvent) -> Result<Vec<u8>> {
543 state.extend_from_slice(b" +event");
545 Ok(state)
546 }
547
548 fn compress_data(&self, data: &[u8]) -> Result<Vec<u8>> {
550 if self.config.enable_compression {
551 oxiarc_deflate::gzip_compress(data, 6)
552 .map_err(|e| anyhow::anyhow!("Gzip compression failed: {e}"))
553 } else {
554 Ok(data.to_vec())
555 }
556 }
557
558 fn decompress_data(&self, data: &[u8]) -> Result<Vec<u8>> {
560 if self.config.enable_compression {
561 oxiarc_deflate::gzip_decompress(data)
562 .map_err(|e| anyhow::anyhow!("Gzip decompression failed: {e}"))
563 } else {
564 Ok(data.to_vec())
565 }
566 }
567
568 pub fn get_stats(&self) -> super::EventSourcingStats {
570 super::EventSourcingStats {
571 total_events_stored: AtomicU64::new(
572 self.stats.total_events_stored.load(Ordering::Relaxed),
573 ),
574 total_events_retrieved: AtomicU64::new(
575 self.stats.total_events_retrieved.load(Ordering::Relaxed),
576 ),
577 snapshots_created: AtomicU64::new(self.stats.snapshots_created.load(Ordering::Relaxed)),
578 events_archived: AtomicU64::new(self.stats.events_archived.load(Ordering::Relaxed)),
579 persistence_operations: AtomicU64::new(
580 self.stats.persistence_operations.load(Ordering::Relaxed),
581 ),
582 failed_operations: AtomicU64::new(self.stats.failed_operations.load(Ordering::Relaxed)),
583 memory_usage_bytes: AtomicU64::new(
584 self.stats.memory_usage_bytes.load(Ordering::Relaxed),
585 ),
586 disk_usage_bytes: AtomicU64::new(self.stats.disk_usage_bytes.load(Ordering::Relaxed)),
587 average_store_latency_ms: AtomicU64::new(
588 self.stats.average_store_latency_ms.load(Ordering::Relaxed),
589 ),
590 average_retrieve_latency_ms: AtomicU64::new(
591 self.stats
592 .average_retrieve_latency_ms
593 .load(Ordering::Relaxed),
594 ),
595 }
596 }
597}
598
599#[async_trait::async_trait]
601impl EventStoreTrait for EventStore {
602 async fn store_event(&self, stream_id: String, event: StreamEvent) -> Result<StoredEvent> {
603 self.store_event(stream_id, event).await
604 }
605
606 async fn query_events(&self, query: EventQuery) -> Result<Vec<StoredEvent>> {
607 self.query_events(query).await
608 }
609
610 async fn get_stream_events(
611 &self,
612 stream_id: &str,
613 from_version: Option<u64>,
614 ) -> Result<Vec<StoredEvent>> {
615 self.get_stream_events(stream_id, from_version).await
616 }
617
618 async fn replay_from_timestamp(&self, timestamp: DateTime<Utc>) -> Result<Vec<StoredEvent>> {
619 self.replay_from_timestamp(timestamp).await
620 }
621
622 async fn get_latest_snapshot(&self, stream_id: &str) -> Result<Option<EventSnapshot>> {
623 self.get_latest_snapshot(stream_id).await
624 }
625
626 async fn rebuild_stream_state(&self, stream_id: &str) -> Result<Vec<u8>> {
627 self.rebuild_stream_state(stream_id).await
628 }
629
630 async fn append_events(
631 &self,
632 aggregate_id: &str,
633 events: &[StreamEvent],
634 _expected_version: Option<u64>,
635 ) -> Result<u64> {
636 let mut last_version = 0u64;
637 for event in events {
638 let stored_event = self
639 .store_event(aggregate_id.to_string(), event.clone())
640 .await?;
641 last_version = stored_event.stream_version;
642 }
643 Ok(last_version)
644 }
645}
646
647impl Default for EventIndexes {
648 fn default() -> Self {
649 Self::new()
650 }
651}
652
653impl EventIndexes {
654 pub fn new() -> Self {
656 Self {
657 by_event_type: RwLock::new(HashMap::new()),
658 by_timestamp: RwLock::new(BTreeMap::new()),
659 by_source: RwLock::new(HashMap::new()),
660 by_stream: RwLock::new(HashMap::new()),
661 custom_indexes: RwLock::new(HashMap::new()),
662 }
663 }
664
665 pub async fn add_event(&self, event: &StoredEvent) -> Result<()> {
667 let sequence = event.sequence_number;
668
669 {
671 let mut by_type = self.by_event_type.write().await;
672 let event_type = format!("{:?}", std::mem::discriminant(&event.event_data));
673 by_type
674 .entry(event_type)
675 .or_insert_with(Vec::new)
676 .push(sequence);
677 }
678
679 {
681 let mut by_timestamp = self.by_timestamp.write().await;
682 let timestamp = event.event_data.metadata().timestamp;
683 by_timestamp
684 .entry(timestamp)
685 .or_insert_with(Vec::new)
686 .push(sequence);
687 }
688
689 {
691 let mut by_source = self.by_source.write().await;
692 let source = &event.event_data.metadata().source;
693 by_source
694 .entry(source.clone())
695 .or_insert_with(Vec::new)
696 .push(sequence);
697 }
698
699 {
701 let mut by_stream = self.by_stream.write().await;
702 by_stream
703 .entry(event.stream_id.clone())
704 .or_insert_with(Vec::new)
705 .push(sequence);
706 }
707
708 Ok(())
709 }
710
711 pub async fn find_matching_sequences(&self, query: &EventQuery) -> Result<Vec<u64>> {
713 let mut candidate_sequences = Vec::new();
714
715 if let Some(ref stream_id) = query.stream_id {
717 let by_stream = self.by_stream.read().await;
718 if let Some(sequences) = by_stream.get(stream_id) {
719 candidate_sequences = sequences.clone();
720 } else {
721 return Ok(Vec::new()); }
723 } else {
724 let by_stream = self.by_stream.read().await;
726 for sequences in by_stream.values() {
727 candidate_sequences.extend(sequences);
728 }
729 }
730
731 if let Some(ref event_types) = query.event_types {
733 let by_type = self.by_event_type.read().await;
734 let mut type_sequences: HashSet<u64> = HashSet::new();
735
736 for event_type in event_types {
737 if let Some(sequences) = by_type.get(event_type) {
738 type_sequences.extend(sequences);
739 }
740 }
741
742 candidate_sequences.retain(|seq| type_sequences.contains(seq));
743 }
744
745 if let Some(ref seq_range) = query.sequence_range {
747 candidate_sequences.retain(|&seq| seq >= seq_range.start && seq <= seq_range.end);
748 }
749
750 candidate_sequences.sort_unstable();
751 Ok(candidate_sequences)
752 }
753}
754
755impl PersistenceManager {
756 pub fn new(backend: PersistenceBackend) -> Result<Self> {
762 if let PersistenceBackend::FileSystem { base_path } = &backend {
763 std::fs::create_dir_all(base_path).map_err(|e| {
764 anyhow::anyhow!(
765 "Failed to create event store persistence directory '{base_path}': {e}"
766 )
767 })?;
768 }
769
770 Ok(Self {
771 backend,
772 pending_operations: Arc::new(Mutex::new(VecDeque::new())),
773 stats: Arc::new(PersistenceStats::default()),
774 })
775 }
776
777 pub fn is_durable(&self) -> bool {
781 matches!(self.backend, PersistenceBackend::FileSystem { .. })
782 }
783
784 pub async fn persist_event(&self, event: &StoredEvent) -> Result<()> {
788 match &self.backend {
789 PersistenceBackend::Memory => Ok(()),
790 PersistenceBackend::FileSystem { base_path } => {
791 let line = serde_json::to_string(event)?;
792 self.append_jsonl(base_path, "events.jsonl", line).await
793 }
794 PersistenceBackend::Database { .. } | PersistenceBackend::ObjectStorage { .. } => {
795 Err(anyhow::anyhow!(
796 "Persistence backend {:?} is not implemented; use FileSystem or Memory",
797 self.backend
798 ))
799 }
800 }
801 }
802
803 pub async fn persist_snapshot(&self, snapshot: &EventSnapshot) -> Result<()> {
806 match &self.backend {
807 PersistenceBackend::Memory => Ok(()),
808 PersistenceBackend::FileSystem { base_path } => {
809 let line = serde_json::to_string(snapshot)?;
810 self.append_jsonl(base_path, "snapshots.jsonl", line).await
811 }
812 PersistenceBackend::Database { .. } | PersistenceBackend::ObjectStorage { .. } => {
813 Err(anyhow::anyhow!(
814 "Persistence backend {:?} is not implemented; use FileSystem or Memory",
815 self.backend
816 ))
817 }
818 }
819 }
820
821 pub async fn load_persisted_events(&self) -> Result<Vec<StoredEvent>> {
823 match &self.backend {
824 PersistenceBackend::FileSystem { base_path } => {
825 let path = Path::new(base_path).join("events.jsonl");
826 Self::read_jsonl(&path).await
827 }
828 _ => Ok(Vec::new()),
829 }
830 }
831
832 pub async fn load_persisted_snapshots(&self) -> Result<Vec<EventSnapshot>> {
834 match &self.backend {
835 PersistenceBackend::FileSystem { base_path } => {
836 let path = Path::new(base_path).join("snapshots.jsonl");
837 Self::read_jsonl(&path).await
838 }
839 _ => Ok(Vec::new()),
840 }
841 }
842
843 async fn append_jsonl(&self, base_path: &str, file_name: &str, line: String) -> Result<()> {
846 let path = Path::new(base_path).join(file_name);
847 let mut file = tokio::fs::OpenOptions::new()
848 .create(true)
849 .append(true)
850 .open(&path)
851 .await
852 .map_err(|e| {
853 anyhow::anyhow!("Failed to open persistence file '{}': {e}", path.display())
854 })?;
855 file.write_all(line.as_bytes()).await.map_err(|e| {
856 anyhow::anyhow!(
857 "Failed to write to persistence file '{}': {e}",
858 path.display()
859 )
860 })?;
861 file.write_all(b"\n").await.map_err(|e| {
862 anyhow::anyhow!(
863 "Failed to write to persistence file '{}': {e}",
864 path.display()
865 )
866 })?;
867 file.flush()
868 .await
869 .map_err(|e| anyhow::anyhow!("Failed to flush '{}': {e}", path.display()))?;
870 file.sync_data()
871 .await
872 .map_err(|e| anyhow::anyhow!("fsync failed for '{}': {e}", path.display()))?;
873
874 self.stats
875 .bytes_written
876 .fetch_add(line.len() as u64 + 1, Ordering::Relaxed);
877 Ok(())
878 }
879
880 async fn read_jsonl<T: DeserializeOwned>(path: &Path) -> Result<Vec<T>> {
883 if !tokio::fs::try_exists(path).await.unwrap_or(false) {
884 return Ok(Vec::new());
885 }
886
887 let content = tokio::fs::read_to_string(path)
888 .await
889 .map_err(|e| anyhow::anyhow!("Failed to read '{}': {e}", path.display()))?;
890
891 let mut items = Vec::new();
892 for (line_no, line) in content.lines().enumerate() {
893 let line = line.trim();
894 if line.is_empty() {
895 continue;
896 }
897 match serde_json::from_str::<T>(line) {
898 Ok(item) => items.push(item),
899 Err(e) => warn!(
900 "Skipping corrupt persisted record at {}:{}: {e}",
901 path.display(),
902 line_no + 1
903 ),
904 }
905 }
906 Ok(items)
907 }
908
909 pub async fn queue_operation(&self, operation: PersistenceOperation) -> Result<()> {
913 let mut queue = self.pending_operations.lock().await;
914 queue.push_back(operation);
915 self.stats.operations_queued.fetch_add(1, Ordering::Relaxed);
916 Ok(())
917 }
918
919 pub async fn process_pending_operations(&self) -> Result<()> {
921 let operations: Vec<PersistenceOperation> = {
922 let mut queue = self.pending_operations.lock().await;
923 queue.drain(..).collect()
924 };
925
926 for operation in operations {
927 match self.execute_operation(operation).await {
928 Ok(_) => {
929 self.stats
930 .operations_completed
931 .fetch_add(1, Ordering::Relaxed);
932 }
933 Err(e) => {
934 self.stats.operations_failed.fetch_add(1, Ordering::Relaxed);
935 error!("Persistence operation failed: {}", e);
936 }
937 }
938 }
939
940 Ok(())
941 }
942
943 async fn execute_operation(&self, operation: PersistenceOperation) -> Result<()> {
945 match &self.backend {
946 PersistenceBackend::Memory => Ok(()),
947 PersistenceBackend::FileSystem { base_path } => {
948 self.execute_filesystem_operation(operation, base_path)
949 .await
950 }
951 PersistenceBackend::Database { .. } | PersistenceBackend::ObjectStorage { .. } => {
952 Err(anyhow::anyhow!(
953 "Persistence backend {:?} is not implemented; use FileSystem or Memory",
954 self.backend
955 ))
956 }
957 }
958 }
959
960 async fn execute_filesystem_operation(
962 &self,
963 operation: PersistenceOperation,
964 base_path: &str,
965 ) -> Result<()> {
966 match operation {
967 PersistenceOperation::StoreEvent(event) => {
968 let line = serde_json::to_string(&*event)?;
969 self.append_jsonl(base_path, "events.jsonl", line).await?;
970 }
971 PersistenceOperation::StoreSnapshot(snapshot) => {
972 let line = serde_json::to_string(&snapshot)?;
973 self.append_jsonl(base_path, "snapshots.jsonl", line)
974 .await?;
975 }
976 PersistenceOperation::ArchiveEvents(events) => {
977 for event in &events {
978 let line = serde_json::to_string(event)?;
979 self.append_jsonl(base_path, "archive.jsonl", line).await?;
980 }
981 }
982 PersistenceOperation::DeleteEvents(sequence_numbers) => {
983 let line = serde_json::to_string(&sequence_numbers)?;
984 self.append_jsonl(base_path, "deletions.jsonl", line)
985 .await?;
986 }
987 }
988 Ok(())
989 }
990}
991
992pub trait EventMetadataAccessor {
994 fn metadata(&self) -> &EventMetadata;
995}
996
997impl EventMetadataAccessor for StreamEvent {
998 fn metadata(&self) -> &EventMetadata {
999 match self {
1000 StreamEvent::TripleAdded { metadata, .. } => metadata,
1001 StreamEvent::TripleRemoved { metadata, .. } => metadata,
1002 StreamEvent::QuadAdded { metadata, .. } => metadata,
1003 StreamEvent::QuadRemoved { metadata, .. } => metadata,
1004 StreamEvent::GraphCreated { metadata, .. } => metadata,
1005 StreamEvent::GraphCleared { metadata, .. } => metadata,
1006 StreamEvent::GraphDeleted { metadata, .. } => metadata,
1007 StreamEvent::SparqlUpdate { metadata, .. } => metadata,
1008 StreamEvent::TransactionBegin { metadata, .. } => metadata,
1009 StreamEvent::TransactionCommit { metadata, .. } => metadata,
1010 StreamEvent::TransactionAbort { metadata, .. } => metadata,
1011 StreamEvent::SchemaChanged { metadata, .. } => metadata,
1012 StreamEvent::Heartbeat { metadata, .. } => metadata,
1013 StreamEvent::QueryResultAdded { metadata, .. } => metadata,
1014 StreamEvent::QueryResultRemoved { metadata, .. } => metadata,
1015 StreamEvent::QueryCompleted { metadata, .. } => metadata,
1016 StreamEvent::ErrorOccurred { metadata, .. } => metadata,
1017 _ => {
1018 use once_cell::sync::Lazy;
1020 static DEFAULT_METADATA: Lazy<EventMetadata> = Lazy::new(EventMetadata::default);
1021 &DEFAULT_METADATA
1022 }
1023 }
1024 }
1025}