1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
//! Core data types for OpenData Log.
//!
//! This module defines the fundamental data structures used throughout the
//! log API, including records for writing and entries for reading.
use Bytes;
/// Unique identifier for a segment.
///
/// Segment IDs are monotonically increasing integers assigned when segments
/// are created. Use with [`LogRead::list_keys`](crate::LogRead::list_keys)
/// to query keys within specific segments.
pub type SegmentId = u32;
/// Global sequence number for log entries.
///
/// Sequence numbers are monotonically increasing integers assigned to each
/// entry at append time. They provide a total ordering across all keys in
/// the log.
pub type Sequence = u64;
/// A segment of the log.
///
/// Segments partition the log into coarse-grained chunks based on time or
/// other policies. Each segment has a unique identifier and tracks the
/// starting sequence number for entries it contains.
///
/// Segments are the natural boundary for attaching metadata such as key
/// listings. See [`LogRead::list_segments`](crate::LogRead::list_segments)
/// for querying segments.
///
/// # Example
///
/// ```no_run
/// # use log::{LogDb, LogRead, Config};
/// # use common::StorageConfig;
/// # #[tokio::main]
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// # let config = Config { storage: StorageConfig::InMemory, ..Default::default() };
/// # let log = LogDb::open(config).await?;
/// let segments = log.list_segments(..).await?;
/// for segment in segments {
/// println!(
/// "segment {}: start_seq={}, created at {}",
/// segment.id, segment.start_seq, segment.start_time_ms
/// );
/// }
/// # Ok(())
/// # }
/// ```
/// A record to be appended to the log.
///
/// Records are the unit of data written to the log. Each record consists of
/// a key identifying the log stream and a value containing the payload.
///
/// # Key Selection
///
/// Keys determine how data is organized in the log. Each unique key represents
/// an independent log stream with its own sequence of entries. Choose keys based
/// on your access patterns:
///
/// - Use a single key for a simple append-only log
/// - Use entity IDs as keys for per-entity event streams
/// - Use composite keys (e.g., `tenant:entity`) for multi-tenant scenarios
///
/// # Example
///
/// ```
/// use bytes::Bytes;
/// use log::Record;
///
/// let record = Record {
/// key: Bytes::from("orders"),
/// value: Bytes::from(r#"{"id": "123", "amount": 99.99}"#),
/// };
/// ```
/// Output of an append operation.
///
/// Contains metadata about the appended records, including the starting
/// sequence number assigned to the first record in the batch.
///
/// # Example
///
/// ```no_run
/// # use log::{LogDb, Config, Record};
/// # use bytes::Bytes;
/// # use common::StorageConfig;
/// # #[tokio::main]
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// # let config = Config { storage: StorageConfig::InMemory, ..Default::default() };
/// # let log = LogDb::open(config).await?;
/// # let records = vec![Record { key: Bytes::from("k"), value: Bytes::from("v") }];
/// let result = log.try_append(records).await?;
/// println!("Appended starting at sequence {}", result.start_sequence);
/// # Ok(())
/// # }
/// ```
/// An entry read from the log.
///
/// Log entries are returned by [`LogIterator`](crate::LogIterator) and contain
/// the original record data along with metadata assigned at append time.
///
/// # Sequence Numbers
///
/// Each entry has a globally unique sequence number assigned when it was
/// appended. Within a single key's log, entries are ordered by sequence
/// number, but the numbers are not contiguous—other keys' appends are
/// interleaved in the global sequence.
///
/// # Example
///
/// ```no_run
/// # use log::{LogDb, LogRead, Config};
/// # use bytes::Bytes;
/// # use common::StorageConfig;
/// # #[tokio::main]
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// # let config = Config { storage: StorageConfig::InMemory, ..Default::default() };
/// # let log = LogDb::open(config).await?;
/// # let key = Bytes::from("orders");
/// let mut iter = log.scan(key, ..).await?;
/// while let Some(entry) = iter.next().await? {
/// println!(
/// "key={:?}, seq={}, value={:?}",
/// entry.key, entry.sequence, entry.value
/// );
/// }
/// # Ok(())
/// # }
/// ```