Stream all ops for `array` with `hlc >= from_hlc` as batched delta frames, advancing the subscriber cursor after each batch.
(&self, session_id: &str, array: &str, from_hlc: Hlc)
| 152 | /// Stream all ops for `array` with `hlc >= from_hlc` as batched delta |
| 153 | /// frames, advancing the subscriber cursor after each batch. |
| 154 | fn stream_ops(&self, session_id: &str, array: &str, from_hlc: Hlc) -> crate::Result<()> { |
| 155 | // scan_from returns all ops with hlc >= from_hlc across all arrays; |
| 156 | // we filter to the target array here. |
| 157 | let ops_all = self |
| 158 | .op_log |
| 159 | .scan_from(from_hlc) |
| 160 | .map_err(|e| crate::Error::Storage { |
| 161 | engine: "array_sync".into(), |
| 162 | detail: format!("catchup_server scan_from: {e}"), |
| 163 | })?; |
| 164 | |
| 165 | let mut batch_payloads: Vec<Vec<u8>> = Vec::with_capacity(BATCH_SIZE); |
| 166 | let mut last_hlc = from_hlc; |
| 167 | |
| 168 | for op_result in ops_all { |
| 169 | let op = op_result.map_err(|e| crate::Error::Storage { |
| 170 | engine: "array_sync".into(), |
| 171 | detail: format!("catchup_server scan_from iter: {e}"), |
| 172 | })?; |
| 173 | if op.header.array != array { |
| 174 | continue; |
| 175 | } |
| 176 | |
| 177 | match op_codec::encode_op(&op) { |
| 178 | Ok(payload) => { |
| 179 | last_hlc = op.header.hlc; |
| 180 | batch_payloads.push(payload); |
| 181 | } |
| 182 | Err(e) => { |
| 183 | warn!( |
| 184 | session = %session_id, |
| 185 | array = %array, |
| 186 | error = %e, |
| 187 | "catchup_server: encode_op failed — skipping op" |
| 188 | ); |
| 189 | continue; |
| 190 | } |
| 191 | } |
| 192 | |
| 193 | if batch_payloads.len() >= BATCH_SIZE { |
| 194 | let batch = ArrayDeltaBatchMsg { |
| 195 | array: array.to_owned(), |
| 196 | op_payloads: std::mem::take(&mut batch_payloads), |
| 197 | }; |
| 198 | self.send_frame(session_id, SyncMessageType::ArrayDeltaBatch, &batch); |
| 199 | self.cursors.mark_sent(session_id, array, last_hlc); |
| 200 | debug!( |
| 201 | session = %session_id, |
| 202 | array = %array, |
| 203 | last_hlc = ?last_hlc, |
| 204 | "catchup_server: flushed batch" |
| 205 | ); |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | // Flush any remaining ops. |
| 210 | if !batch_payloads.is_empty() { |
| 211 | let batch = ArrayDeltaBatchMsg { |