1use crate::backend::{
2 LineCounter, Output, SequentialDecoder, SequentialItem, decode_source,
3 decode_source_with_index, validate_initial_stream,
4};
5use crate::config::Config;
6use crate::gzip::StreamCursor;
7use crate::index::{DeflateIndex, IndexCollector, IndexOptions};
8use crate::indexed_parallel::IndexedPlan;
9use crate::runtime::{AuxiliaryKind, RuntimeState};
10use crate::{
11 DecodeError, DecodeReport, DecoderHandle, DecoderStats, IndexedDecodeReport, IndexingError,
12 ReadAt, WorkerLimitError,
13};
14use std::io::{self, IoSliceMut, Read};
15use std::sync::Arc;
16use std::sync::atomic::{AtomicBool, Ordering};
17use std::sync::mpsc::{self, Receiver, SyncSender, TrySendError};
18use std::thread::{self, JoinHandle};
19use std::time::Duration;
20
21enum Message {
22 Data(Vec<u8>),
23 Finished(Completion),
24 Failed(Failure),
25}
26
27enum Completion {
28 Decode(DecodeReport),
29 Indexed(IndexedDecodeReport),
30}
31
32enum Failure {
33 Decode(DecodeError),
34 Indexing(IndexingError),
35}
36
37struct ChannelOutput {
38 sender: SyncSender<Message>,
39 cancelled: Arc<AtomicBool>,
40 runtime: Arc<RuntimeState>,
41}
42
43impl ChannelOutput {
44 fn send(&self, mut message: Message) -> Result<(), DecodeError> {
45 let mut observed_full = false;
46 loop {
47 if self.cancelled.load(Ordering::Relaxed) {
48 return Err(DecodeError::Cancelled);
49 }
50 match self.sender.try_send(message) {
51 Ok(()) => {
52 if !observed_full {
53 self.runtime.set_consumer_blocked(false);
54 }
55 return Ok(());
56 }
57 Err(TrySendError::Disconnected(_)) => return Err(DecodeError::Cancelled),
58 Err(TrySendError::Full(returned)) => {
59 observed_full = true;
60 self.runtime.set_consumer_blocked(true);
61 message = returned;
62 thread::park_timeout(Duration::from_millis(1));
63 }
64 }
65 }
66 }
67}
68
69impl Output for ChannelOutput {
70 fn emit(&mut self, chunk: Vec<u8>) -> Result<(), DecodeError> {
71 let byte_count = chunk.len();
72 self.send(Message::Data(chunk))?;
73 self.runtime.add_decompressed_bytes(byte_count);
74 Ok(())
75 }
76}
77
78enum Terminal {
79 Open,
80 Finished(Completion),
81 Failed(Failure),
82}
83
84#[must_use]
100pub struct DecoderReader {
101 mode: ReaderMode,
102 cancelled: Arc<AtomicBool>,
103 handle: DecoderHandle,
104 current: Vec<u8>,
105 current_offset: usize,
106 terminal: Terminal,
107}
108
109enum ReaderMode {
110 Coordinator {
111 receiver: Option<Receiver<Message>>,
112 worker: Option<JoinHandle<()>>,
113 },
114 Streaming {
115 decoder: Box<SequentialDecoder<StreamCursor<Box<dyn Read + Send>>>>,
116 collector: Option<Arc<IndexCollector>>,
117 line_counter: LineCounter,
118 },
119}
120
121fn spawn_coordinator<F>(
125 decode: F,
126 in_flight_chunks: usize,
127 configured_workers: usize,
128) -> Result<DecoderReader, DecodeError>
129where
130 F: FnOnce(
131 &AtomicBool,
132 &mut ChannelOutput,
133 &Arc<RuntimeState>,
134 ) -> Result<Completion, IndexingError>
135 + Send
136 + 'static,
137{
138 let (sender, receiver) = mpsc::sync_channel(in_flight_chunks);
139 let cancelled = Arc::new(AtomicBool::new(false));
140 let runtime = RuntimeState::new(configured_workers);
141 let handle = DecoderHandle::new(Arc::clone(&runtime));
142 let worker_cancelled = Arc::clone(&cancelled);
143 let worker_runtime = Arc::clone(&runtime);
144 let worker = thread::Builder::new()
145 .name("rapidgzip-coordinator".to_owned())
146 .spawn(move || {
147 let _registration = worker_runtime.register_auxiliary(AuxiliaryKind::Coordinator);
148 let mut output = ChannelOutput {
149 sender,
150 cancelled: Arc::clone(&worker_cancelled),
151 runtime: Arc::clone(&worker_runtime),
152 };
153 let terminal = match decode(&worker_cancelled, &mut output, &worker_runtime) {
154 Ok(completion) => {
155 worker_runtime.set_member_count(match &completion {
156 Completion::Decode(report) => report.member_count,
157 Completion::Indexed(report) => report.decode.member_count,
158 });
159 Message::Finished(completion)
160 }
161 Err(IndexingError::Decode(DecodeError::Cancelled))
162 if worker_cancelled.load(Ordering::Relaxed) =>
163 {
164 return;
165 }
166 Err(IndexingError::Decode(error)) => Message::Failed(Failure::Decode(error)),
167 Err(error) => Message::Failed(Failure::Indexing(error)),
168 };
169 let _ = output.send(terminal);
170 })
171 .map_err(DecodeError::output_io)?;
172
173 Ok(DecoderReader {
174 mode: ReaderMode::Coordinator {
175 receiver: Some(receiver),
176 worker: Some(worker),
177 },
178 cancelled,
179 handle,
180 current: Vec::new(),
181 current_offset: 0,
182 terminal: Terminal::Open,
183 })
184}
185
186pub(crate) fn spawn<R>(source: R, config: Config) -> Result<DecoderReader, DecodeError>
187where
188 R: ReadAt + 'static,
189{
190 let in_flight_chunks = config.in_flight_chunks;
191 let configured_workers = config.decoder_threads;
192 spawn_coordinator(
193 move |cancelled, output, runtime| {
194 decode_source(&source, &config, cancelled, output, runtime)
195 .map(Completion::Decode)
196 .map_err(IndexingError::from)
197 },
198 in_flight_chunks,
199 configured_workers,
200 )
201}
202
203pub(crate) fn spawn_indexed<R>(
204 source: R,
205 config: Config,
206 options: IndexOptions,
207) -> Result<IndexingDecoderReader, DecodeError>
208where
209 R: ReadAt + 'static,
210{
211 let in_flight_chunks = config.in_flight_chunks;
212 let configured_workers = config.decoder_threads;
213 spawn_coordinator(
214 move |cancelled, output, runtime| {
215 decode_source_with_index(&source, &config, cancelled, output, runtime, options)
216 .map(Completion::Indexed)
217 },
218 in_flight_chunks,
219 configured_workers,
220 )
221 .map(|inner| IndexingDecoderReader { inner })
222}
223
224pub(crate) fn spawn_from_index<R>(
225 source: R,
226 config: Config,
227 index: Arc<DeflateIndex>,
228 plan: IndexedPlan,
229) -> Result<DecoderReader, DecodeError>
230where
231 R: ReadAt + 'static,
232{
233 let in_flight_chunks = config.in_flight_chunks;
234 let configured_workers = config.decoder_threads;
235 spawn_coordinator(
236 move |cancelled, output, runtime| {
237 crate::indexed_parallel::decode(
238 &source, &config, cancelled, output, &index, &plan, runtime,
239 )
240 .map(Completion::Decode)
241 .map_err(IndexingError::from)
242 },
243 in_flight_chunks,
244 configured_workers,
245 )
246}
247
248pub(crate) fn spawn_stream<R>(source: R, config: Config) -> Result<DecoderReader, DecodeError>
254where
255 R: Read + Send + 'static,
256{
257 let source: Box<dyn Read + Send> = Box::new(source);
258 let mut cursor = StreamCursor::new(source, config.input_page_size);
259 validate_initial_stream(&mut cursor, &config)?;
260 let runtime = RuntimeState::new(config.decoder_threads);
261 let handle = DecoderHandle::new(Arc::clone(&runtime));
262 let decoder = SequentialDecoder::new(
263 cursor,
264 &config,
265 0,
266 0,
267 config.decoder_threads,
268 &runtime,
269 None,
270 );
271 Ok(DecoderReader {
272 mode: ReaderMode::Streaming {
273 decoder: Box::new(decoder),
274 collector: None,
275 line_counter: LineCounter::new(config.count_lines),
276 },
277 cancelled: Arc::new(AtomicBool::new(false)),
278 handle,
279 current: Vec::new(),
280 current_offset: 0,
281 terminal: Terminal::Open,
282 })
283}
284
285pub(crate) fn spawn_stream_indexed<R>(
286 source: R,
287 config: Config,
288 options: IndexOptions,
289) -> Result<IndexingDecoderReader, DecodeError>
290where
291 R: Read + Send + 'static,
292{
293 let source: Box<dyn Read + Send> = Box::new(source);
294 let mut cursor = StreamCursor::new(source, config.input_page_size);
295 validate_initial_stream(&mut cursor, &config)?;
296 let runtime = RuntimeState::new(config.decoder_threads);
297 let handle = DecoderHandle::new(Arc::clone(&runtime));
298 let collector = IndexCollector::new(options, config.count_lines);
299 let decoder = SequentialDecoder::new(
300 cursor,
301 &config,
302 0,
303 0,
304 config.decoder_threads,
305 &runtime,
306 Some(&collector),
307 );
308 Ok(IndexingDecoderReader {
309 inner: DecoderReader {
310 mode: ReaderMode::Streaming {
311 decoder: Box::new(decoder),
312 collector: Some(collector),
313 line_counter: LineCounter::new(config.count_lines),
314 },
315 cancelled: Arc::new(AtomicBool::new(false)),
316 handle,
317 current: Vec::new(),
318 current_offset: 0,
319 terminal: Terminal::Open,
320 },
321 })
322}
323
324impl DecoderReader {
325 pub fn handle(&self) -> DecoderHandle {
330 self.handle.clone()
331 }
332
333 pub fn stats(&self) -> DecoderStats {
335 self.handle.stats()
336 }
337
338 pub fn set_worker_limit(&self, workers: usize) -> Result<(), WorkerLimitError> {
349 self.handle.set_worker_limit(workers)
350 }
351
352 pub const fn report(&self) -> Option<&DecodeReport> {
356 match &self.terminal {
357 Terminal::Finished(Completion::Decode(report)) => Some(report),
358 Terminal::Finished(Completion::Indexed(report)) => Some(&report.decode),
359 Terminal::Open | Terminal::Failed(_) => None,
360 }
361 }
362
363 fn join_worker(&mut self) -> Result<(), DecodeError> {
364 let worker = match &mut self.mode {
365 ReaderMode::Coordinator { worker, .. } => worker.take(),
366 ReaderMode::Streaming { .. } => None,
367 };
368 if let Some(worker) = worker {
369 if worker.join().is_err() {
370 return Err(DecodeError::WorkerPanicked);
371 }
372 }
373 Ok(())
374 }
375
376 fn receive(&mut self) {
377 let mut reusable = std::mem::take(&mut self.current);
378 reusable.clear();
379 let message = match &mut self.mode {
380 ReaderMode::Coordinator { receiver, .. } => receiver
381 .as_ref()
382 .expect("receiver remains present until shutdown")
383 .recv()
384 .ok(),
385 ReaderMode::Streaming {
386 decoder,
387 collector,
388 line_counter,
389 } => {
390 let runtime = Arc::clone(&self.handle.state);
391 let result = {
392 let _busy = runtime.begin_task();
393 decoder.next_chunk(&self.cancelled, reusable)
394 };
395 match result {
396 Ok(SequentialItem::Chunk(data)) => {
397 line_counter.note_output(&data, collector.as_deref());
398 runtime.add_decompressed_bytes(data.len());
399 Some(Message::Data(data))
400 }
401 Ok(SequentialItem::Finished(report)) => {
402 let report = line_counter.finish_report(report);
403 if let Some(collector) = collector {
404 match collector.finish(
405 report.compressed_bytes,
406 report.decompressed_bytes,
407 report.line_count,
408 ) {
409 Ok(index) => Some(Message::Finished(Completion::Indexed(
410 IndexedDecodeReport {
411 decode: report,
412 index,
413 },
414 ))),
415 Err(error) => Some(Message::Failed(Failure::Indexing(
416 IndexingError::Index(error),
417 ))),
418 }
419 } else {
420 Some(Message::Finished(Completion::Decode(report)))
421 }
422 }
423 Err(error) => Some(Message::Failed(Failure::Decode(error))),
424 }
425 }
426 };
427 match message {
428 Some(Message::Data(data)) => {
429 self.current = data;
430 self.current_offset = 0;
431 }
432 Some(Message::Finished(completion)) => {
433 self.handle.state.mark_terminal();
434 let terminal = match self.join_worker() {
435 Ok(()) => Terminal::Finished(completion),
436 Err(error) => Terminal::Failed(Failure::Decode(error)),
437 };
438 self.terminal = terminal;
439 }
440 Some(Message::Failed(error)) => {
441 self.handle.state.mark_terminal();
442 let terminal = match self.join_worker() {
443 Ok(()) => Terminal::Failed(error),
444 Err(join_error) => Terminal::Failed(Failure::Decode(join_error)),
445 };
446 self.terminal = terminal;
447 }
448 None => {
449 self.handle.state.mark_terminal();
450 let error = self
451 .join_worker()
452 .err()
453 .unwrap_or(DecodeError::WorkerPanicked);
454 self.terminal = Terminal::Failed(Failure::Decode(error));
455 }
456 }
457 }
458
459 pub fn finish(mut self) -> Result<DecodeReport, DecodeError> {
466 self.current.clear();
467 loop {
468 match &self.terminal {
469 Terminal::Finished(Completion::Decode(report)) => return Ok(*report),
470 Terminal::Finished(Completion::Indexed(report)) => return Ok(report.decode),
471 Terminal::Failed(Failure::Decode(error)) => return Err(error.clone()),
472 Terminal::Failed(Failure::Indexing(IndexingError::Decode(error))) => {
473 return Err(error.clone());
474 }
475 Terminal::Failed(Failure::Indexing(IndexingError::Index(_))) => {
476 return Err(DecodeError::WorkerPanicked);
477 }
478 Terminal::Open => self.receive(),
479 }
480 self.current.clear();
481 }
482 }
483
484 fn finish_indexed(mut self) -> Result<IndexedDecodeReport, IndexingError> {
485 self.current.clear();
486 while matches!(self.terminal, Terminal::Open) {
487 self.receive();
488 self.current.clear();
489 }
490 match std::mem::replace(&mut self.terminal, Terminal::Open) {
491 Terminal::Finished(Completion::Indexed(report)) => Ok(report),
492 Terminal::Finished(Completion::Decode(_)) | Terminal::Open => {
493 Err(IndexingError::Decode(DecodeError::WorkerPanicked))
494 }
495 Terminal::Failed(Failure::Decode(error)) => Err(IndexingError::Decode(error)),
496 Terminal::Failed(Failure::Indexing(error)) => Err(error),
497 }
498 }
499}
500
501#[must_use]
513pub struct IndexingDecoderReader {
514 inner: DecoderReader,
515}
516
517impl IndexingDecoderReader {
518 pub fn handle(&self) -> DecoderHandle {
520 self.inner.handle()
521 }
522
523 pub fn stats(&self) -> DecoderStats {
525 self.inner.stats()
526 }
527
528 pub fn set_worker_limit(&self, workers: usize) -> Result<(), WorkerLimitError> {
535 self.inner.set_worker_limit(workers)
536 }
537
538 #[must_use]
542 pub const fn report(&self) -> Option<&IndexedDecodeReport> {
543 match &self.inner.terminal {
544 Terminal::Finished(Completion::Indexed(report)) => Some(report),
545 Terminal::Open | Terminal::Finished(Completion::Decode(_)) | Terminal::Failed(_) => {
546 None
547 }
548 }
549 }
550
551 pub fn finish(self) -> Result<IndexedDecodeReport, IndexingError> {
559 self.inner.finish_indexed()
560 }
561}
562
563impl Read for IndexingDecoderReader {
564 fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
565 self.inner.read(output)
566 }
567
568 fn read_vectored(&mut self, buffers: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
569 self.inner.read_vectored(buffers)
570 }
571}
572
573impl Read for DecoderReader {
574 fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
575 if output.is_empty() {
576 return Ok(0);
577 }
578
579 loop {
580 if self.current_offset < self.current.len() {
581 let count = output
582 .len()
583 .min(self.current.len().saturating_sub(self.current_offset));
584 output[..count].copy_from_slice(
585 &self.current[self.current_offset..self.current_offset + count],
586 );
587 self.current_offset += count;
588 if self.current_offset == self.current.len() {
589 self.current.clear();
590 self.current_offset = 0;
591 }
592 self.handle.state.add_consumed_bytes(count);
593 return Ok(count);
594 }
595
596 match &self.terminal {
597 Terminal::Finished(_) => return Ok(0),
598 Terminal::Failed(Failure::Decode(error)) => return Err(error.to_io_error()),
599 Terminal::Failed(Failure::Indexing(error)) => return Err(error.to_io_error()),
600 Terminal::Open => self.receive(),
601 }
602 }
603 }
604
605 fn read_vectored(&mut self, buffers: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
606 let mut total = 0;
607 for buffer in buffers {
608 if buffer.is_empty() {
609 continue;
610 }
611 match self.read(buffer) {
612 Ok(0) => break,
613 Ok(read) => {
614 total += read;
615 if read < buffer.len() {
616 break;
617 }
618 }
619 Err(_) if total > 0 => break,
620 Err(error) => return Err(error),
621 }
622 }
623 Ok(total)
624 }
625}
626
627impl Drop for DecoderReader {
628 fn drop(&mut self) {
629 self.cancelled.store(true, Ordering::Relaxed);
630 self.handle.state.mark_terminal();
631 if let ReaderMode::Coordinator { receiver, .. } = &mut self.mode {
632 receiver.take();
633 let _ = self.join_worker();
634 }
635 }
636}
637
638#[cfg(test)]
639mod tests {
640 use super::{DecoderReader, IndexingDecoderReader};
641 use std::io::Read;
642
643 fn assert_traits<T: Read + Send + Unpin>() {}
644
645 #[test]
646 fn decoder_reader_is_read_send_and_unpin() {
647 assert_traits::<DecoderReader>();
648 assert_traits::<IndexingDecoderReader>();
649 }
650}