1use std::mem;
16use std::sync::Arc;
17use std::sync::atomic::{AtomicU64, Ordering};
18
19use api::v1::{BulkWalEntry, Mutation, OpType, Rows, WalEntry, WriteHint};
20use futures::stream::{FuturesUnordered, StreamExt};
21use snafu::ResultExt;
22use store_api::logstore::LogStore;
23use store_api::logstore::provider::Provider;
24use store_api::storage::{RegionId, SequenceNumber};
25
26use crate::error::{Error, Result, WriteGroupSnafu};
27use crate::memtable::KeyValues;
28use crate::memtable::bulk::part::BulkPart;
29use crate::metrics;
30use crate::region::version::{VersionControlData, VersionControlRef, VersionRef};
31use crate::request::OptionOutputTx;
32use crate::wal::{EntryId, WalWriter};
33
34struct WriteNotify {
36 err: Option<Arc<Error>>,
38 sender: OptionOutputTx,
40 num_rows: usize,
42}
43
44impl WriteNotify {
45 fn new(sender: OptionOutputTx, num_rows: usize) -> WriteNotify {
47 WriteNotify {
48 err: None,
49 sender,
50 num_rows,
51 }
52 }
53
54 fn notify_result(&mut self) {
56 if let Some(err) = &self.err {
57 self.sender
59 .send_mut(Err(err.clone()).context(WriteGroupSnafu));
60 } else {
61 self.sender.send_mut(Ok(self.num_rows));
63 }
64 }
65}
66
67impl Drop for WriteNotify {
68 fn drop(&mut self) {
69 self.notify_result();
70 }
71}
72
73pub(crate) struct RegionWriteCtx {
75 region_id: RegionId,
77 version: VersionRef,
79 version_control: VersionControlRef,
81 next_sequence: SequenceNumber,
85 next_entry_id: EntryId,
87 wal_entry: WalEntry,
92 provider: Provider,
94 notifiers: Vec<WriteNotify>,
98 bulk_notifiers: Vec<WriteNotify>,
100 pub(crate) bulk_parts: Vec<BulkPart>,
102 failed: bool,
104
105 pub(crate) put_num: usize,
108 pub(crate) delete_num: usize,
110 pub(crate) written_bytes: Option<Arc<AtomicU64>>,
112}
113
114impl RegionWriteCtx {
115 pub(crate) fn new(
117 region_id: RegionId,
118 version_control: &VersionControlRef,
119 provider: Provider,
120 written_bytes: Option<Arc<AtomicU64>>,
121 ) -> RegionWriteCtx {
122 let VersionControlData {
123 version,
124 committed_sequence,
125 last_entry_id,
126 ..
127 } = version_control.current();
128
129 RegionWriteCtx {
130 region_id,
131 version,
132 version_control: version_control.clone(),
133 next_sequence: committed_sequence + 1,
134 next_entry_id: last_entry_id + 1,
135 wal_entry: WalEntry::default(),
136 provider,
137 notifiers: Vec::new(),
138 bulk_notifiers: vec![],
139 failed: false,
140 put_num: 0,
141 delete_num: 0,
142 bulk_parts: vec![],
143 written_bytes,
144 }
145 }
146
147 pub(crate) fn push_mutation(
150 &mut self,
151 op_type: i32,
152 rows: Option<Rows>,
153 write_hint: Option<WriteHint>,
154 tx: OptionOutputTx,
155 sequence: Option<SequenceNumber>,
156 ) {
157 if let Some(sequence) = sequence {
158 self.next_sequence = sequence;
159 }
160 let num_rows = rows.as_ref().map(|rows| rows.rows.len()).unwrap_or(0);
161 self.wal_entry.mutations.push(Mutation {
162 op_type,
163 sequence: self.next_sequence,
164 rows,
165 write_hint,
166 });
167
168 let notify = WriteNotify::new(tx, num_rows);
169 self.notifiers.push(notify);
171
172 self.next_sequence += num_rows as u64;
174
175 match OpType::try_from(op_type) {
177 Ok(OpType::Delete) => self.delete_num += num_rows,
178 Ok(OpType::Put) => self.put_num += num_rows,
179 Err(_) => (),
180 }
181 }
182
183 pub(crate) fn add_wal_entry<S: LogStore>(
185 &mut self,
186 wal_writer: &mut WalWriter<S>,
187 ) -> Result<()> {
188 wal_writer.add_entry(
189 self.region_id,
190 self.next_entry_id,
191 &self.wal_entry,
192 &self.provider,
193 )?;
194 self.next_entry_id += 1;
195 Ok(())
196 }
197
198 pub(crate) fn version(&self) -> &VersionRef {
199 &self.version
200 }
201
202 pub(crate) fn skip_wal(&self) -> bool {
204 self.provider == Provider::Noop || self.version.options.skip_wal
205 }
206
207 pub(crate) fn set_error(&mut self, err: Arc<Error>) {
209 for notify in &mut self.notifiers {
211 notify.err = Some(err.clone());
212 }
213 for notify in &mut self.bulk_notifiers {
214 notify.err = Some(err.clone());
215 }
216
217 self.failed = true;
219 }
220
221 pub(crate) fn is_failed(&self) -> bool {
223 self.failed
224 }
225
226 pub(crate) fn set_next_entry_id(&mut self, next_entry_id: EntryId) {
228 self.next_entry_id = next_entry_id
229 }
230
231 #[cfg(test)]
233 pub(crate) fn next_entry_id(&self) -> EntryId {
234 self.next_entry_id
235 }
236
237 pub(crate) async fn write_memtable(&mut self) {
239 debug_assert_eq!(self.notifiers.len(), self.wal_entry.mutations.len());
240
241 if self.failed {
242 return;
243 }
244
245 let mutable_memtable = self.version.memtables.mutable.clone();
246 let prev_memory_usage = if self.written_bytes.is_some() {
247 Some(mutable_memtable.memory_usage())
248 } else {
249 None
250 };
251
252 let mutations = mem::take(&mut self.wal_entry.mutations)
253 .into_iter()
254 .enumerate()
255 .filter_map(|(i, mutation)| {
256 let kvs = KeyValues::new(&self.version.metadata, mutation)?;
257 Some((i, kvs))
258 })
259 .collect::<Vec<_>>();
260
261 if mutations.len() == 1 {
262 if let Err(err) = mutable_memtable.write(&mutations[0].1) {
263 self.notifiers[mutations[0].0].err = Some(Arc::new(err));
264 }
265 } else {
266 let mut tasks = FuturesUnordered::new();
267 for (i, kvs) in mutations {
268 let mutable = mutable_memtable.clone();
269 tasks.push(common_runtime::spawn_blocking_global(move || {
271 (i, mutable.write(&kvs))
272 }));
273 }
274
275 while let Some(result) = tasks.next().await {
276 let (i, result) = result.unwrap();
278 if let Err(err) = result {
279 self.notifiers[i].err = Some(Arc::new(err));
280 }
281 }
282 }
283
284 if let Some(written_bytes) = &self.written_bytes {
285 let new_memory_usage = mutable_memtable.memory_usage();
286 let bytes = new_memory_usage.saturating_sub(prev_memory_usage.unwrap_or_default());
287 written_bytes.fetch_add(bytes as u64, Ordering::Relaxed);
288 }
289 self.version_control
292 .set_sequence_and_entry_id(self.next_sequence - 1, self.next_entry_id - 1);
293 }
294
295 pub(crate) fn push_bulk(
296 &mut self,
297 sender: OptionOutputTx,
298 mut bulk: BulkPart,
299 sequence: Option<SequenceNumber>,
300 ) -> bool {
301 if let Some(sequence) = sequence {
302 self.next_sequence = sequence;
303 }
304 bulk.sequence = self.next_sequence;
305 let entry = match BulkWalEntry::try_from(&bulk) {
306 Ok(entry) => entry,
307 Err(e) => {
308 sender.send(Err(e));
309 return false;
310 }
311 };
312
313 self.bulk_notifiers
314 .push(WriteNotify::new(sender, bulk.num_rows()));
315
316 self.wal_entry.bulk_entries.push(entry);
318 self.next_sequence += bulk.num_rows() as u64;
319 self.bulk_parts.push(bulk);
320 true
321 }
322
323 pub(crate) async fn write_bulk(&mut self) {
324 if self.failed || self.bulk_parts.is_empty() {
325 return;
326 }
327 let _timer = metrics::REGION_WORKER_HANDLE_WRITE_ELAPSED
328 .with_label_values(&["write_bulk"])
329 .start_timer();
330
331 let mutable_memtable = &self.version.memtables.mutable;
332 let prev_memory_usage = if self.written_bytes.is_some() {
333 Some(mutable_memtable.memory_usage())
334 } else {
335 None
336 };
337
338 if self.bulk_parts.len() == 1 {
339 let part = self.bulk_parts.swap_remove(0);
340 let num_rows = part.num_rows();
341 if let Err(e) = self.version.memtables.mutable.write_bulk(part) {
342 self.bulk_notifiers[0].err = Some(Arc::new(e));
343 } else {
344 self.put_num += num_rows;
345 }
346 return;
347 }
348
349 let mut tasks = FuturesUnordered::new();
350 for (i, part) in self.bulk_parts.drain(..).enumerate() {
351 let mutable = mutable_memtable.clone();
352 tasks.push(common_runtime::spawn_blocking_global(move || {
353 let num_rows = part.num_rows();
354 (i, mutable.write_bulk(part), num_rows)
355 }));
356 }
357 while let Some(result) = tasks.next().await {
358 let (i, result, num_rows) = result.unwrap();
360 if let Err(err) = result {
361 self.bulk_notifiers[i].err = Some(Arc::new(err));
362 } else {
363 self.put_num += num_rows;
364 }
365 }
366
367 if let Some(written_bytes) = &self.written_bytes {
368 let new_memory_usage = mutable_memtable.memory_usage();
369 let bytes = new_memory_usage.saturating_sub(prev_memory_usage.unwrap_or_default());
370 written_bytes.fetch_add(bytes as u64, Ordering::Relaxed);
371 }
372 self.version_control
373 .set_sequence_and_entry_id(self.next_sequence - 1, self.next_entry_id - 1);
374 }
375}
376
377#[cfg(test)]
378mod tests {
379 use std::sync::Arc;
380
381 use common_recordbatch::DfRecordBatch;
382 use datatypes::arrow::array::{ArrayRef, TimestampMillisecondArray};
383 use datatypes::arrow::datatypes::{DataType, Field, Schema};
384 use store_api::logstore::provider::Provider;
385 use tokio::sync::oneshot;
386
387 use super::*;
388 use crate::error::UnexpectedSnafu;
389 use crate::memtable::bulk::part::BulkPart;
390 use crate::test_util::version_util::VersionControlBuilder;
391
392 #[test]
393 fn test_set_error_marks_bulk_notifiers_failed() {
394 let builder = VersionControlBuilder::new();
395 let region_id = builder.region_id();
396 let version_control = Arc::new(builder.build());
397 let mut ctx =
398 RegionWriteCtx::new(region_id, &version_control, Provider::noop_provider(), None);
399 let (tx, rx) = oneshot::channel();
400
401 assert!(ctx.push_bulk(OptionOutputTx::from(tx), new_bulk_part(), None));
402 ctx.set_error(Arc::new(
403 UnexpectedSnafu {
404 reason: "wal failed".to_string(),
405 }
406 .build(),
407 ));
408 drop(ctx);
409
410 let result = rx.blocking_recv().unwrap();
411 assert!(result.is_err(), "bulk notifier should report WAL error");
412 }
413
414 fn new_bulk_part() -> BulkPart {
415 let schema = Arc::new(Schema::new(vec![Field::new(
416 "ts",
417 DataType::Timestamp(datatypes::arrow::datatypes::TimeUnit::Millisecond, None),
418 false,
419 )]));
420 let arrays = vec![Arc::new(TimestampMillisecondArray::from(vec![1, 2])) as ArrayRef];
421 let batch = DfRecordBatch::try_new(schema, arrays).unwrap();
422
423 BulkPart {
424 batch,
425 max_timestamp: 2,
426 min_timestamp: 1,
427 sequence: 0,
428 timestamp_index: 0,
429 raw_data: None,
430 }
431 }
432}