Skip to main content

linkrs_core/
session_stats.rs

1//! Session Statistics Module
2//!
3//! Provides session-level statistics such as the number of rows affected by query execution,
4//! last insertion ID, etc.
5
6use std::sync::atomic::{AtomicU64, Ordering};
7
8/// Session-level change statistics
9///
10/// Records the execution of queries in the session, including:
11/// - Number of rows affected by the last operation
12/// - Total session changes
13/// - Vertex ID of the last inserted vertex
14/// - Last inserted edge ID
15#[derive(Debug)]
16pub struct SessionStatistics {
17    /// Number of rows affected by the last operation
18    last_changes: AtomicU64,
19    /// Total number of session changes
20    total_changes: AtomicU64,
21    /// ID of the last vertex inserted
22    last_insert_vertex_id: AtomicU64,
23    /// Last inserted edge ID
24    last_insert_edge_id: AtomicU64,
25    /// Whether there is a vertex ID (0 means invalid)
26    has_vertex_id: AtomicU64,
27    /// Whether there is an edge ID (0 means invalid)
28    has_edge_id: AtomicU64,
29}
30
31impl SessionStatistics {
32    /// Creating a new statistics instance
33    pub fn new() -> Self {
34        Self {
35            last_changes: AtomicU64::new(0),
36            total_changes: AtomicU64::new(0),
37            last_insert_vertex_id: AtomicU64::new(0),
38            last_insert_edge_id: AtomicU64::new(0),
39            has_vertex_id: AtomicU64::new(0),
40            has_edge_id: AtomicU64::new(0),
41        }
42    }
43
44    /// Record the number of lines changed
45    ///
46    /// # Parameters
47    /// - `count` - number of lines affected
48    pub fn record_changes(&self, count: u64) {
49        self.last_changes.store(count, Ordering::SeqCst);
50        self.total_changes.fetch_add(count, Ordering::SeqCst);
51    }
52
53    /// Record Vertex Insertion
54    ///
55    /// # Parameters
56    /// - `id` - the ID of the inserted vertex
57    pub fn record_vertex_insert(&self, id: u64) {
58        if id > 0 {
59            self.last_insert_vertex_id.store(id, Ordering::SeqCst);
60            self.has_vertex_id.store(1, Ordering::SeqCst);
61            self.last_changes.store(1, Ordering::SeqCst);
62            self.total_changes.fetch_add(1, Ordering::SeqCst);
63        }
64    }
65
66    /// Record edge insertion
67    ///
68    /// # Parameters
69    /// - `id` - the ID of the inserted edge
70    pub fn record_edge_insert(&self, id: u64) {
71        if id > 0 {
72            self.last_insert_edge_id.store(id, Ordering::SeqCst);
73            self.has_edge_id.store(1, Ordering::SeqCst);
74            self.last_changes.store(1, Ordering::SeqCst);
75            self.total_changes.fetch_add(1, Ordering::SeqCst);
76        }
77    }
78
79    /// Get the number of rows affected by the last operation
80    pub fn last_changes(&self) -> u64 {
81        self.last_changes.load(Ordering::SeqCst)
82    }
83
84    /// Getting the number of total session changes
85    pub fn total_changes(&self) -> u64 {
86        self.total_changes.load(Ordering::SeqCst)
87    }
88
89    /// Get the ID of the last inserted vertex
90    ///
91    /// Returns None for no records
92    pub fn last_insert_vertex_id(&self) -> Option<u64> {
93        if self.has_vertex_id.load(Ordering::SeqCst) != 0 {
94            Some(self.last_insert_vertex_id.load(Ordering::SeqCst))
95        } else {
96            None
97        }
98    }
99
100    /// Get the last inserted edge ID
101    ///
102    /// Returns None if no records were found
103    pub fn last_insert_edge_id(&self) -> Option<u64> {
104        if self.has_edge_id.load(Ordering::SeqCst) != 0 {
105            Some(self.last_insert_edge_id.load(Ordering::SeqCst))
106        } else {
107            None
108        }
109    }
110
111    /// Reset last change record
112    ///
113    /// Usually called before executing a new query
114    pub fn reset_last(&self) {
115        self.last_changes.store(0, Ordering::SeqCst);
116        self.has_vertex_id.store(0, Ordering::SeqCst);
117        self.has_edge_id.store(0, Ordering::SeqCst);
118    }
119
120    /// Reset all statistics
121    pub fn reset_all(&self) {
122        self.last_changes.store(0, Ordering::SeqCst);
123        self.total_changes.store(0, Ordering::SeqCst);
124        self.last_insert_vertex_id.store(0, Ordering::SeqCst);
125        self.last_insert_edge_id.store(0, Ordering::SeqCst);
126        self.has_vertex_id.store(0, Ordering::SeqCst);
127        self.has_edge_id.store(0, Ordering::SeqCst);
128    }
129}
130
131impl Default for SessionStatistics {
132    fn default() -> Self {
133        Self::new()
134    }
135}
136
137impl Clone for SessionStatistics {
138    fn clone(&self) -> Self {
139        Self {
140            last_changes: AtomicU64::new(self.last_changes.load(Ordering::SeqCst)),
141            total_changes: AtomicU64::new(self.total_changes.load(Ordering::SeqCst)),
142            last_insert_vertex_id: AtomicU64::new(
143                self.last_insert_vertex_id.load(Ordering::SeqCst),
144            ),
145            last_insert_edge_id: AtomicU64::new(self.last_insert_edge_id.load(Ordering::SeqCst)),
146            has_vertex_id: AtomicU64::new(self.has_vertex_id.load(Ordering::SeqCst)),
147            has_edge_id: AtomicU64::new(self.has_edge_id.load(Ordering::SeqCst)),
148        }
149    }
150}
151
152#[cfg(test)]
153mod tests {
154    use super::*;
155
156    #[test]
157    fn test_session_statistics_basic() {
158        let stats = SessionStatistics::new();
159
160        assert_eq!(stats.last_changes(), 0);
161        assert_eq!(stats.total_changes(), 0);
162        assert_eq!(stats.last_insert_vertex_id(), None);
163        assert_eq!(stats.last_insert_edge_id(), None);
164    }
165
166    #[test]
167    fn test_record_changes() {
168        let stats = SessionStatistics::new();
169
170        stats.record_changes(5);
171        assert_eq!(stats.last_changes(), 5);
172        assert_eq!(stats.total_changes(), 5);
173
174        stats.record_changes(3);
175        assert_eq!(stats.last_changes(), 3);
176        assert_eq!(stats.total_changes(), 8);
177    }
178
179    #[test]
180    fn test_record_vertex_insert() {
181        let stats = SessionStatistics::new();
182
183        stats.record_vertex_insert(100);
184        assert_eq!(stats.last_insert_vertex_id(), Some(100));
185        assert_eq!(stats.last_changes(), 1);
186        assert_eq!(stats.total_changes(), 1);
187
188        stats.record_vertex_insert(0);
189        assert_eq!(stats.last_insert_vertex_id(), Some(100));
190    }
191
192    #[test]
193    fn test_record_edge_insert() {
194        let stats = SessionStatistics::new();
195
196        stats.record_edge_insert(200);
197        assert_eq!(stats.last_insert_edge_id(), Some(200));
198        assert_eq!(stats.last_changes(), 1);
199        assert_eq!(stats.total_changes(), 1);
200    }
201
202    #[test]
203    fn test_reset() {
204        let stats = SessionStatistics::new();
205
206        stats.record_changes(5);
207        stats.record_vertex_insert(100);
208
209        stats.reset_last();
210        assert_eq!(stats.last_changes(), 0);
211        assert_eq!(stats.last_insert_vertex_id(), None);
212        assert_eq!(stats.total_changes(), 6);
213
214        stats.reset_all();
215        assert_eq!(stats.total_changes(), 0);
216    }
217}