1mod source;
4mod worker;
5
6use std::collections::{BTreeMap, BTreeSet};
7use std::io;
8use std::ops::Range;
9use std::sync::mpsc::{self, Receiver, Sender, TryRecvError};
10use std::sync::Arc;
11use std::thread;
12
13use arrow_schema::SchemaRef;
14use densa_grid::{CellStyle, CellText, Column, GridModel, Palette, SortOrder, CELL_BYTES};
15
16pub use source::{FetchError, PageError, PageOptions, PageQuery, PageSource, SortKey};
17use worker::{Ask, Fetched, Got, Wanted, Worker};
18
19use crate::reader::{Format, Reader};
20use crate::table::{
21 columns_of, new_formats, size_column, widen_column, write_value, CellState, TableError,
22};
23
24#[derive(Debug)]
27struct Page {
28 epoch: u64,
29 rows: usize,
30 readers: Vec<Reader>,
31}
32
33#[derive(Debug)]
49pub struct PagedModel {
50 schema: SchemaRef,
51 options: PageOptions,
52 formats: Vec<Format>,
53 sized: bool,
55 columns: Vec<Column>,
56 columns_revision: u64,
57 sortable: Vec<bool>,
59 pages: BTreeMap<u64, Page>,
60 asked: BTreeSet<u64>,
62 failed: BTreeSet<u64>,
64 rows: Option<u64>,
66 counted: bool,
68 counting: bool,
70 count_epoch: u64,
73 query: PageQuery,
74 sort: Option<(usize, SortOrder)>,
75 epoch: u64,
77 error: Option<FetchError>,
78 stopped: Option<FetchError>,
80 want: Range<u64>,
82 wanted: Arc<Wanted>,
83 asks: Sender<Ask>,
84 gots: Receiver<Got>,
85}
86
87impl PagedModel {
88 pub fn new(
99 schema: SchemaRef,
100 source: impl PageSource,
101 wake: impl Fn() + Send + 'static,
102 ) -> io::Result<Self> {
103 Self::with_options(schema, source, wake, PageOptions::default())
104 }
105
106 pub fn with_options(
111 schema: SchemaRef,
112 source: impl PageSource,
113 wake: impl Fn() + Send + 'static,
114 options: PageOptions,
115 ) -> io::Result<Self> {
116 let options = PageOptions {
117 page_rows: options.page_rows.max(1),
118 pages_kept: options.pages_kept.max(1),
119 };
120 let sortable = schema
121 .fields()
122 .iter()
123 .map(|field| source.can_sort(field.name()))
124 .collect();
125 let (asks, asked) = mpsc::channel();
126 let (sent, gots) = mpsc::channel();
127 let wanted = Arc::new(Wanted::default());
128 let worker = Worker {
129 source,
130 schema: schema.clone(),
131 page_rows: options.page_rows,
132 asks: asked,
133 gots: sent,
134 wanted: Arc::clone(&wanted),
135 wake: Box::new(wake),
136 };
137 thread::Builder::new()
138 .name("densa-pages".to_owned())
139 .spawn(move || worker.serve())?;
140 let formats = new_formats(&schema);
141 let columns = columns_of(&schema, &formats);
142 let mut model = Self {
143 schema,
144 options,
145 formats,
146 sized: false,
147 columns,
148 columns_revision: 0,
149 sortable,
150 pages: BTreeMap::new(),
151 asked: BTreeSet::new(),
152 failed: BTreeSet::new(),
153 rows: None,
154 counted: false,
155 counting: false,
156 count_epoch: 0,
157 query: PageQuery::new(),
158 sort: None,
159 epoch: 0,
160 error: None,
161 stopped: None,
162 want: 0..0,
163 wanted,
164 asks,
165 gots,
166 };
167 model.ask(true);
168 Ok(model)
169 }
170
171 pub fn schema(&self) -> &SchemaRef {
173 &self.schema
174 }
175
176 pub fn row_count(&self) -> Option<u64> {
179 self.rows
180 }
181
182 pub fn error(&self) -> Option<&FetchError> {
186 self.stopped.as_ref().or(self.error.as_ref())
187 }
188
189 pub fn is_fetched(&self, row: usize) -> bool {
192 self.pages
193 .get(&self.page_of(row))
194 .is_some_and(|page| page.epoch == self.epoch)
195 }
196
197 pub fn pages_held(&self) -> usize {
199 self.pages.len()
200 }
201
202 pub fn page_rows(&self) -> usize {
204 self.options.page_rows
205 }
206
207 pub fn retry(&mut self) {
210 self.failed.clear();
211 self.error = None;
212 if !self.counted && !self.counting {
213 self.ask(true);
214 }
215 }
216
217 pub fn refresh(&mut self) {
221 self.ask(true);
222 }
223
224 fn ask(&mut self, count: bool) {
227 self.epoch = self.epoch.wrapping_add(1);
228 self.asked.clear();
229 self.failed.clear();
230 self.error = None;
231 if count {
232 self.counted = false;
233 self.counting = true;
234 self.count_epoch = self.epoch;
235 }
236 let _ = self.asks.send(Ask::Query {
238 epoch: self.epoch,
239 query: self.query.clone(),
240 count,
241 });
242 }
243
244 pub fn set_decimals(
252 &mut self,
253 column: usize,
254 decimals: Option<usize>,
255 ) -> Result<(), TableError> {
256 self.formats
257 .get_mut(column)
258 .ok_or(TableError::NoSuchColumn(column))?
259 .decimals = decimals;
260 self.size_again(column);
261 Ok(())
262 }
263
264 pub fn set_column_chars(&mut self, column: usize, chars: usize) -> Result<(), TableError> {
271 let format = self
272 .formats
273 .get_mut(column)
274 .ok_or(TableError::NoSuchColumn(column))?;
275 format.max_chars = chars.clamp(1, CELL_BYTES);
276 format.width_set = true;
277 self.read_columns();
278 Ok(())
279 }
280
281 fn size_again(&mut self, column: usize) {
283 let (Some(field), Some(format)) = (
284 self.schema.fields().get(column),
285 self.formats.get_mut(column),
286 ) else {
287 return;
288 };
289 let mut held = self
290 .pages
291 .values()
292 .filter_map(|page| page.readers.get(column));
293 if let Some(first) = held.next() {
294 size_column(format, first, field.name());
295 let mut text = CellText::new();
296 for reader in held {
297 widen_column(format, reader, field.data_type(), &mut text);
298 }
299 }
300 self.read_columns();
301 }
302
303 fn read_columns(&mut self) {
305 self.columns = columns_of(&self.schema, &self.formats);
306 self.columns_revision = self.columns_revision.wrapping_add(1);
307 }
308
309 fn page_of(&self, row: usize) -> u64 {
311 (row / self.options.page_rows) as u64
313 }
314
315 fn page_of_row(&self, row: u64) -> u64 {
317 row / self.options.page_rows as u64
319 }
320
321 fn rows_of(&self, pages: Range<u64>) -> Range<u64> {
323 let page_rows = self.options.page_rows as u64;
325 let start = pages.start.saturating_mul(page_rows);
326 let end = pages.end.saturating_mul(page_rows);
327 start..self.rows.map_or(end, |rows| end.min(rows)).max(start)
328 }
329
330 fn take_in(&mut self) {
332 loop {
333 match self.gots.try_recv() {
334 Ok(got) => self.take(got),
335 Err(TryRecvError::Empty) => return,
336 Err(TryRecvError::Disconnected) => {
337 if self.stopped.is_none() {
339 self.stopped = Some(FetchError::Stopped {
340 message: "it ended without saying why".to_owned(),
341 });
342 }
343 return;
344 }
345 }
346 }
347 }
348
349 fn take(&mut self, got: Got) {
351 match got {
352 Got::Count { epoch, rows } if self.is_count(epoch) => {
353 self.rows = Some(rows);
354 self.counted = true;
355 self.counting = false;
356 }
357 Got::Pages {
358 epoch,
359 first,
360 pages,
361 } if epoch == self.epoch => {
362 for (fetched, page) in pages.into_iter().zip(first..) {
363 self.asked.remove(&page);
364 self.take_page(page, fetched);
365 }
366 }
367 Got::Failed {
368 epoch,
369 pages: Some(pages),
370 message,
371 } if epoch == self.epoch => {
372 for page in pages.clone() {
373 self.asked.remove(&page);
374 self.failed.insert(page);
375 }
376 let rows = self.rows_of(pages);
377 self.error = Some(FetchError::Rows { rows, message });
378 }
379 Got::Failed {
380 epoch,
381 pages: None,
382 message,
383 } if self.is_count(epoch) => {
384 self.rows = None;
386 self.counting = false;
387 self.error = Some(FetchError::Count { message });
388 }
389 Got::Skipped { epoch, pages } if epoch == self.epoch => {
390 for page in pages {
391 self.asked.remove(&page);
392 }
393 }
394 Got::Stopped { message } => self.stopped = Some(FetchError::Stopped { message }),
395 _ => {}
397 }
398 }
399
400 fn is_count(&self, epoch: u64) -> bool {
404 epoch.wrapping_sub(self.count_epoch) <= self.epoch.wrapping_sub(self.count_epoch)
405 }
406
407 fn take_page(&mut self, page: u64, fetched: Fetched) {
410 let rows = self.rows_of(page..page + 1);
411 let got = fetched.rows as u64;
413 if got < rows.end - rows.start {
414 self.failed.insert(page);
415 self.error = Some(FetchError::Short { rows, got });
416 return;
417 }
418 self.keep(page, fetched);
419 }
420
421 fn keep(&mut self, page: u64, fetched: Fetched) {
424 let readers: Vec<Reader> = fetched.columns.into_iter().map(Reader::new).collect();
425 let fields = self.schema.fields();
426 let mut text = CellText::new();
427 let mut widened = false;
428 for ((reader, format), field) in readers.iter().zip(&mut self.formats).zip(fields.iter()) {
429 if self.sized {
430 widened |= widen_column(format, reader, field.data_type(), &mut text);
431 } else {
432 size_column(format, reader, field.name());
433 }
434 }
435 if widened || !self.sized {
436 self.sized = true;
437 self.read_columns();
438 }
439 let (epoch, rows) = (self.epoch, fetched.rows);
440 self.pages.insert(
441 page,
442 Page {
443 epoch,
444 rows,
445 readers,
446 },
447 );
448 self.evict();
449 }
450
451 fn evict(&mut self) {
454 while self.pages.len() > self.options.pages_kept {
455 let (Some(&low), Some(&high)) =
456 (self.pages.keys().next(), self.pages.keys().next_back())
457 else {
458 return;
459 };
460 let below = self.want.start.saturating_sub(low);
461 let above = high.saturating_sub(self.want.end.saturating_sub(1));
462 let page = if below >= above { low } else { high };
463 if self.want.contains(&page) {
464 return;
466 }
467 self.pages.remove(&page);
468 }
469 }
470
471 fn ask_pages(&mut self, rows: Range<usize>) {
474 let Some(count) = self.rows.filter(|&n| n > 0 && self.counted) else {
475 return;
476 };
477 if rows.is_empty() {
478 return;
479 }
480 let first = self.page_of(rows.start).saturating_sub(1);
481 let last = (self.page_of(rows.end - 1) + 1).min(self.page_of_row(count - 1));
482 if first > last {
483 return;
484 }
485 self.want = first..last + 1;
486 self.wanted.set(first, last);
487 let mut pages = Vec::new();
489 for page in first..=last {
490 let known = self.pages.get(&page).is_some_and(|p| p.epoch == self.epoch)
491 || self.asked.contains(&page)
492 || self.failed.contains(&page);
493 if !known {
494 pages.push(page);
495 }
496 }
497 if pages.is_empty() {
498 return;
499 }
500 self.asked.extend(pages.iter().copied());
501 let _ = self.asks.send(Ask::Pages {
503 epoch: self.epoch,
504 pages,
505 });
506 }
507
508 fn write(&self, row: usize, column: usize, text: &mut CellText) -> CellState {
510 let local = row % self.options.page_rows;
511 let reader = self
512 .pages
513 .get(&self.page_of(row))
514 .and_then(|page| page.readers.get(column));
515 match (reader, self.formats.get(column)) {
516 (Some(reader), Some(format)) if local < reader.len() => {
517 write_value(reader, local, format, text)
518 }
519 _ => CellState::OutOfRange,
520 }
521 }
522}
523
524impl GridModel for PagedModel {
525 fn columns(&self) -> &[Column] {
526 &self.columns
527 }
528
529 fn rows(&self) -> usize {
530 self.rows
531 .map_or(0, |rows| usize::try_from(rows).unwrap_or(usize::MAX))
532 }
533
534 fn cell(&self, row: usize, column: usize, text: &mut CellText, palette: &Palette) -> CellStyle {
535 let color = match self.write(row, column, text) {
536 CellState::Value => palette.text,
537 _ => palette.dim_text,
538 };
539 CellStyle::new(color)
540 }
541
542 fn prepare(&mut self) {
543 self.take_in();
544 }
545
546 fn showing(&mut self, rows: Range<usize>) {
547 self.ask_pages(rows);
548 }
549
550 fn copy_rows(&self, rows: Range<usize>) -> Vec<Range<usize>> {
552 let mut runs: Vec<Range<usize>> = Vec::new();
553 if rows.is_empty() {
554 return runs;
555 }
556 let pages = self.page_of(rows.start)..=self.page_of(rows.end - 1);
557 for (&page, held) in self.pages.range(pages) {
558 let Some(start) = usize::try_from(page)
559 .ok()
560 .and_then(|page| page.checked_mul(self.options.page_rows))
561 else {
562 continue;
563 };
564 let run = start.max(rows.start)..start.saturating_add(held.rows).min(rows.end);
565 if run.is_empty() {
566 continue;
567 }
568 match runs.last_mut() {
569 Some(last) if last.end == run.start => last.end = run.end,
570 _ => runs.push(run),
571 }
572 }
573 runs
574 }
575
576 fn sort(&mut self, column: usize, order: SortOrder) -> bool {
580 let Some(field) = self.schema.fields().get(column) else {
581 return false;
582 };
583 let named_once = self
584 .schema
585 .column_with_name(field.name())
586 .is_some_and(|(at, _)| at == column);
587 if !named_once || !self.sortable.get(column).copied().unwrap_or(false) {
588 return false;
589 }
590 self.sort = Some((column, order));
591 self.query = PageQuery::new().sorted_by(SortKey::new(field.name().clone(), order));
592 self.pages.clear();
595 self.ask(!self.counted && !self.counting);
596 true
597 }
598
599 fn sort_state(&self) -> Option<(usize, SortOrder)> {
600 self.sort
601 }
602
603 fn columns_revision(&self) -> u64 {
604 self.columns_revision
605 }
606}