Skip to main content

risingwave_frontend/session/
cursor_manager.rs

1// Copyright 2024 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use core::mem;
16use core::time::Duration;
17use std::collections::{HashMap, HashSet, VecDeque};
18use std::fmt::{Display, Formatter};
19use std::sync::Arc;
20use std::time::Instant;
21
22use anyhow::anyhow;
23use bytes::Bytes;
24use futures::StreamExt;
25use itertools::Itertools;
26use pgwire::pg_field_descriptor::PgFieldDescriptor;
27use pgwire::pg_response::StatementType;
28use pgwire::types::{Format, Row};
29use risingwave_batch::task::{ShutdownSender, ShutdownToken};
30use risingwave_common::catalog::{ColumnCatalog, Field};
31use risingwave_common::error::BoxedError;
32use risingwave_common::session_config::QueryMode;
33use risingwave_common::types::{DataType, ScalarImpl, StructType, StructValue};
34use risingwave_common::util::iter_util::ZipEqFast;
35use risingwave_hummock_sdk::HummockVersionId;
36
37use super::SessionImpl;
38use crate::catalog::TableId;
39use crate::catalog::subscription_catalog::SubscriptionCatalog;
40use crate::error::{ErrorCode, Result};
41use crate::expr::{ExprType, FunctionCall, InputRef, Literal};
42use crate::handler::HandlerArgs;
43use crate::handler::declare_cursor::create_chunk_stream_for_cursor;
44use crate::handler::query::{RwBatchQueryPlanResult, gen_batch_plan_fragmenter};
45use crate::handler::util::{
46    DataChunkToRowSetAdapter, StaticSessionData, convert_logstore_u64_to_unix_millis,
47    pg_value_format, to_pg_field,
48};
49use crate::monitor::{CursorMetrics, PeriodicCursorMetrics};
50use crate::optimizer::PlanRoot;
51use crate::optimizer::plan_node::{BatchFilter, BatchLogSeqScan, BatchSeqScan, generic};
52use crate::optimizer::property::{Order, RequiredDist};
53use crate::scheduler::{DistributedQueryStream, LocalQueryStream, ReadSnapshot, SchedulerError};
54use crate::utils::Condition;
55use crate::{OptimizerContext, OptimizerContextRef, PgResponseStream, TableCatalog};
56
57pub enum CursorDataChunkStream {
58    LocalDataChunk(Option<LocalQueryStream>),
59    DistributedDataChunk(Option<DistributedQueryStream>),
60    PgResponse(PgResponseStream),
61}
62
63pub struct FetchCursorCancelHandle {
64    cancel_tx: ShutdownSender,
65    cancel_rx: ShutdownToken,
66}
67
68impl FetchCursorCancelHandle {
69    pub fn new() -> Self {
70        let (cancel_tx, cancel_rx) = ShutdownToken::new();
71        Self {
72            cancel_tx,
73            cancel_rx,
74        }
75    }
76
77    fn register(&self, session: &SessionImpl) {
78        session.set_cancel_query_flag(self.cancel_tx.clone());
79    }
80
81    async fn cancelled(&mut self) {
82        self.cancel_rx.cancelled().await;
83    }
84
85    fn is_cancelled(&self) -> bool {
86        self.cancel_rx.is_cancelled()
87    }
88}
89
90impl CursorDataChunkStream {
91    pub fn init_row_stream(
92        &mut self,
93        fields: &Vec<Field>,
94        formats: &Vec<Format>,
95        session: Arc<SessionImpl>,
96    ) {
97        let columns_type = fields.iter().map(|f| f.data_type()).collect();
98        match self {
99            CursorDataChunkStream::LocalDataChunk(data_chunk) => {
100                let data_chunk = mem::take(data_chunk).unwrap();
101                let row_stream = PgResponseStream::LocalQuery(DataChunkToRowSetAdapter::new(
102                    data_chunk,
103                    columns_type,
104                    formats.clone(),
105                    session,
106                ));
107                *self = CursorDataChunkStream::PgResponse(row_stream);
108            }
109            CursorDataChunkStream::DistributedDataChunk(data_chunk) => {
110                let data_chunk = mem::take(data_chunk).unwrap();
111                let row_stream = PgResponseStream::DistributedQuery(DataChunkToRowSetAdapter::new(
112                    data_chunk,
113                    columns_type,
114                    formats.clone(),
115                    session,
116                ));
117                *self = CursorDataChunkStream::PgResponse(row_stream);
118            }
119            _ => {}
120        }
121    }
122
123    pub async fn next(&mut self) -> Result<Option<std::result::Result<Vec<Row>, BoxedError>>> {
124        match self {
125            CursorDataChunkStream::PgResponse(row_stream) => Ok(row_stream.next().await),
126            _ => Err(ErrorCode::InternalError(
127                "Only 'CursorDataChunkStream' can call next and return rows".to_owned(),
128            )
129            .into()),
130        }
131    }
132}
133pub enum Cursor {
134    Subscription(SubscriptionCursor),
135    Query(QueryCursor),
136}
137impl Cursor {
138    pub async fn next(
139        &mut self,
140        count: u32,
141        handler_args: HandlerArgs,
142        formats: &Vec<Format>,
143        timeout_seconds: Option<u64>,
144        cancel_handle: &mut FetchCursorCancelHandle,
145    ) -> Result<(Vec<Row>, Vec<PgFieldDescriptor>)> {
146        match self {
147            Cursor::Subscription(cursor) => cursor
148                .next(count, handler_args, formats, timeout_seconds, cancel_handle)
149                .await
150                .inspect_err(|_| cursor.cursor_metrics.subscription_cursor_error_count.inc()),
151            Cursor::Query(cursor) => {
152                cursor
153                    .next(count, formats, handler_args, timeout_seconds)
154                    .await
155            }
156        }
157    }
158
159    pub fn get_fields(&mut self) -> Vec<Field> {
160        match self {
161            Cursor::Subscription(cursor) => cursor.fields_manager.get_output_fields(),
162            Cursor::Query(cursor) => cursor.fields.clone(),
163        }
164    }
165}
166
167pub struct QueryCursor {
168    chunk_stream: CursorDataChunkStream,
169    fields: Vec<Field>,
170    remaining_rows: VecDeque<Row>,
171}
172
173impl QueryCursor {
174    pub fn new(chunk_stream: CursorDataChunkStream, fields: Vec<Field>) -> Result<Self> {
175        Ok(Self {
176            chunk_stream,
177            fields,
178            remaining_rows: VecDeque::<Row>::new(),
179        })
180    }
181
182    pub async fn next_once(&mut self) -> Result<Option<Row>> {
183        while self.remaining_rows.is_empty() {
184            let rows = self.chunk_stream.next().await?;
185            let rows = match rows {
186                None => return Ok(None),
187                Some(row) => row?,
188            };
189            self.remaining_rows = rows.into_iter().collect();
190        }
191        let row = self.remaining_rows.pop_front().unwrap();
192        Ok(Some(row))
193    }
194
195    pub async fn next(
196        &mut self,
197        count: u32,
198        formats: &Vec<Format>,
199        handler_args: HandlerArgs,
200        timeout_seconds: Option<u64>,
201    ) -> Result<(Vec<Row>, Vec<PgFieldDescriptor>)> {
202        // `FETCH NEXT` is equivalent to `FETCH 1`.
203        // min with 100 to avoid allocating too many memory at once.
204        let timeout_instant = timeout_seconds.map(|s| Instant::now() + Duration::from_secs(s));
205        let session = handler_args.session;
206        let mut ans = Vec::with_capacity(std::cmp::min(100, count) as usize);
207        let mut cur = 0;
208        let desc = self.fields.iter().map(to_pg_field).collect();
209        self.chunk_stream
210            .init_row_stream(&self.fields, formats, session);
211        while cur < count
212            && let Some(row) = self.next_once().await?
213        {
214            cur += 1;
215            ans.push(row);
216            if let Some(timeout_instant) = timeout_instant
217                && Instant::now() > timeout_instant
218            {
219                break;
220            }
221        }
222        Ok((ans, desc))
223    }
224}
225
226enum State {
227    InitLogStoreQuery {
228        // The rw_timestamp used to initiate the query to read from subscription logstore.
229        seek_timestamp: u64,
230
231        // If specified, the expected_timestamp must be an exact match for the next rw_timestamp.
232        expected_timestamp: Option<u64>,
233    },
234    Fetch {
235        // Whether the query is reading from snapshot
236        // true: read from the upstream table snapshot
237        // false: read from subscription logstore
238        from_snapshot: bool,
239
240        // The rw_timestamp used to initiate the query to read from subscription logstore.
241        rw_timestamp: u64,
242
243        // The row stream to from the batch query read.
244        // It is returned from the batch execution.
245        chunk_stream: CursorDataChunkStream,
246
247        // A cache to store the remaining rows from the row stream.
248        remaining_rows: VecDeque<Row>,
249
250        expected_timestamp: Option<u64>,
251
252        init_query_timer: Instant,
253    },
254    Invalid,
255}
256
257impl Display for State {
258    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
259        match self {
260            State::InitLogStoreQuery {
261                seek_timestamp,
262                expected_timestamp,
263            } => write!(
264                f,
265                "InitLogStoreQuery {{ seek_timestamp: {}, expected_timestamp: {:?} }}",
266                seek_timestamp, expected_timestamp
267            ),
268            State::Fetch {
269                from_snapshot,
270                rw_timestamp,
271                expected_timestamp,
272                remaining_rows,
273                init_query_timer,
274                ..
275            } => write!(
276                f,
277                "Fetch {{ from_snapshot: {}, rw_timestamp: {}, expected_timestamp: {:?}, cached rows: {}, query init at {}ms before }}",
278                from_snapshot,
279                rw_timestamp,
280                expected_timestamp,
281                remaining_rows.len(),
282                init_query_timer.elapsed().as_millis()
283            ),
284            State::Invalid => write!(f, "Invalid"),
285        }
286    }
287}
288
289struct FieldsManager {
290    columns_catalog: Vec<ColumnCatalog>,
291    // All row fields, including hidden pk, op, rw_timestamp and all non-hidden columns in the upstream table.
292    row_fields: Vec<Field>,
293    // Row output column indices based on `row_fields`.
294    row_output_col_indices: Vec<usize>,
295    // Row pk indices based on `row_fields`.
296    row_pk_indices: Vec<usize>,
297    // Stream chunk row indices based on `row_fields`.
298    stream_chunk_row_indices: Vec<usize>,
299    // The op index based on `row_fields`.
300    op_index: usize,
301}
302
303impl FieldsManager {
304    // pub const OP_FIELD: Field = Field::with_name(DataType::Varchar, "op".to_owned());
305    // pub const RW_TIMESTAMP_FIELD: Field = Field::with_name(DataType::Int64, "rw_timestamp".to_owned());
306
307    pub fn new(catalog: &TableCatalog) -> Self {
308        let mut row_fields = Vec::new();
309        let mut row_output_col_indices = Vec::new();
310        let mut row_pk_indices = Vec::new();
311        let mut stream_chunk_row_indices = Vec::new();
312        let mut output_idx = 0_usize;
313        let pk_set: HashSet<usize> = catalog
314            .pk
315            .iter()
316            .map(|col_order| col_order.column_index)
317            .collect();
318
319        for (index, v) in catalog.columns.iter().enumerate() {
320            if pk_set.contains(&index) {
321                row_pk_indices.push(output_idx);
322                stream_chunk_row_indices.push(output_idx);
323                row_fields.push(Field::with_name(v.data_type().clone(), v.name()));
324                if !v.is_hidden {
325                    row_output_col_indices.push(output_idx);
326                }
327                output_idx += 1;
328            } else if !v.is_hidden {
329                row_output_col_indices.push(output_idx);
330                stream_chunk_row_indices.push(output_idx);
331                row_fields.push(Field::with_name(v.data_type().clone(), v.name()));
332                output_idx += 1;
333            }
334        }
335
336        row_fields.push(Field::with_name(DataType::Varchar, "op".to_owned()));
337        row_output_col_indices.push(output_idx);
338        let op_index = output_idx;
339        output_idx += 1;
340        row_fields.push(Field::with_name(DataType::Int64, "rw_timestamp".to_owned()));
341        row_output_col_indices.push(output_idx);
342        Self {
343            columns_catalog: catalog.columns.clone(),
344            row_fields,
345            row_output_col_indices,
346            row_pk_indices,
347            stream_chunk_row_indices,
348            op_index,
349        }
350    }
351
352    pub fn try_refill_fields(&mut self, catalog: &TableCatalog) -> bool {
353        if self.columns_catalog.ne(&catalog.columns) {
354            *self = Self::new(catalog);
355            true
356        } else {
357            false
358        }
359    }
360
361    pub fn process_output_desc_row(&self, mut rows: Vec<Row>) -> (Vec<Row>, Option<Row>) {
362        let last_row = rows.last_mut().map(|row| {
363            let mut row = row.clone();
364            row.project(&self.row_pk_indices)
365        });
366        let rows = rows
367            .iter_mut()
368            .map(|row| row.project(&self.row_output_col_indices))
369            .collect();
370        (rows, last_row)
371    }
372
373    pub fn get_output_fields(&self) -> Vec<Field> {
374        self.row_output_col_indices
375            .iter()
376            .map(|&idx| self.row_fields[idx].clone())
377            .collect()
378    }
379
380    // In the beginning (declare cur), we will give it an empty formats,
381    // this formats is not a real, when we fetch, We fill it with the formats returned from the pg client.
382    pub fn get_row_stream_fields_and_formats(
383        &self,
384        formats: &Vec<Format>,
385        from_snapshot: bool,
386    ) -> (Vec<Field>, Vec<Format>) {
387        let mut fields = Vec::new();
388        let need_format = !(formats.is_empty() || formats.len() == 1);
389        let mut new_formats = formats.clone();
390        let stream_chunk_row_indices_iter = if from_snapshot {
391            self.stream_chunk_row_indices.iter().chain(None)
392        } else {
393            self.stream_chunk_row_indices
394                .iter()
395                .chain(Some(&self.op_index))
396        };
397        for index in stream_chunk_row_indices_iter {
398            fields.push(self.row_fields[*index].clone());
399            if need_format && !self.row_output_col_indices.contains(index) {
400                new_formats.insert(*index, Format::Text);
401            }
402        }
403        (fields, new_formats)
404    }
405}
406
407pub struct SubscriptionCursor {
408    cursor_name: String,
409    subscription: Arc<SubscriptionCatalog>,
410    dependent_table_id: TableId,
411    cursor_need_drop_time: Instant,
412    state: State,
413    // fields will be set in the table's catalog when the cursor is created,
414    // and will be reset each time it is created chunk_stream, this is to avoid changes in the catalog due to alter.
415    fields_manager: FieldsManager,
416    cursor_metrics: Arc<CursorMetrics>,
417    last_fetch: Instant,
418    seek_pk_row: Option<Row>,
419}
420
421impl SubscriptionCursor {
422    pub async fn new(
423        cursor_name: String,
424        start_timestamp: Option<u64>,
425        subscription: Arc<SubscriptionCatalog>,
426        dependent_table_id: TableId,
427        handler_args: &HandlerArgs,
428        cursor_metrics: Arc<CursorMetrics>,
429    ) -> Result<Self> {
430        let (state, fields_manager) = if let Some(start_timestamp) = start_timestamp {
431            let table_catalog = handler_args.session.get_table_by_id(dependent_table_id)?;
432            (
433                State::InitLogStoreQuery {
434                    seek_timestamp: start_timestamp,
435                    expected_timestamp: None,
436                },
437                FieldsManager::new(&table_catalog),
438            )
439        } else {
440            // The query stream needs to initiated on cursor creation to make sure
441            // future fetch on the cursor starts from the snapshot when the cursor is declared.
442            //
443            // TODO: is this the right behavior? Should we delay the query stream initiation till the first fetch?
444            let (chunk_stream, init_query_timer, table_catalog) =
445                Self::initiate_query(None, dependent_table_id, handler_args.clone(), None).await?;
446            let pinned_epoch = match handler_args.session.get_pinned_snapshot().ok_or_else(
447                || ErrorCode::InternalError("Fetch Cursor can't find snapshot epoch".to_owned()),
448            )? {
449                ReadSnapshot::FrontendPinned { snapshot, .. } => {
450                    snapshot
451                        .version()
452                        .state_table_info
453                        .info()
454                        .get(&dependent_table_id)
455                        .ok_or_else(|| {
456                            anyhow!("dependent_table_id {dependent_table_id} not exists")
457                        })?
458                        .committed_epoch
459                }
460                ReadSnapshot::Other(_) => {
461                    return Err(ErrorCode::InternalError("Fetch Cursor can't start from specified query epoch. May run `set query_epoch = 0;`".to_owned()).into());
462                }
463                ReadSnapshot::ReadUncommitted => {
464                    return Err(ErrorCode::InternalError(
465                        "Fetch Cursor don't support read uncommitted".to_owned(),
466                    )
467                    .into());
468                }
469            };
470            let start_timestamp = pinned_epoch;
471
472            (
473                State::Fetch {
474                    from_snapshot: true,
475                    rw_timestamp: start_timestamp,
476                    chunk_stream,
477                    remaining_rows: VecDeque::new(),
478                    expected_timestamp: None,
479                    init_query_timer,
480                },
481                FieldsManager::new(&table_catalog),
482            )
483        };
484
485        let cursor_need_drop_time =
486            Instant::now() + Duration::from_secs(subscription.retention_seconds);
487        Ok(Self {
488            cursor_name,
489            subscription,
490            dependent_table_id,
491            cursor_need_drop_time,
492            state,
493            fields_manager,
494            cursor_metrics,
495            last_fetch: Instant::now(),
496            seek_pk_row: None,
497        })
498    }
499
500    async fn next_row(
501        &mut self,
502        handler_args: &HandlerArgs,
503        formats: &Vec<Format>,
504    ) -> Result<Option<Row>> {
505        loop {
506            match &mut self.state {
507                State::InitLogStoreQuery {
508                    seek_timestamp,
509                    expected_timestamp,
510                } => {
511                    let from_snapshot = false;
512
513                    // Initiate a new batch query to continue fetching
514                    match Self::get_next_rw_timestamp(
515                        *seek_timestamp,
516                        self.dependent_table_id,
517                        *expected_timestamp,
518                        handler_args.clone(),
519                        &self.subscription,
520                    )
521                    .await
522                    {
523                        Ok((Some(rw_timestamp), expected_timestamp)) => {
524                            let (mut chunk_stream, init_query_timer, catalog) =
525                                Self::initiate_query(
526                                    Some(rw_timestamp),
527                                    self.dependent_table_id,
528                                    handler_args.clone(),
529                                    None,
530                                )
531                                .await?;
532                            let table_schema_changed =
533                                self.fields_manager.try_refill_fields(&catalog);
534                            let (fields, formats) = self
535                                .fields_manager
536                                .get_row_stream_fields_and_formats(formats, from_snapshot);
537                            chunk_stream.init_row_stream(
538                                &fields,
539                                &formats,
540                                handler_args.session.clone(),
541                            );
542
543                            self.cursor_need_drop_time = Instant::now()
544                                + Duration::from_secs(self.subscription.retention_seconds);
545                            let mut remaining_rows = VecDeque::new();
546                            Self::try_refill_remaining_rows(&mut chunk_stream, &mut remaining_rows)
547                                .await?;
548                            // Transition to the Fetch state
549                            self.state = State::Fetch {
550                                from_snapshot,
551                                rw_timestamp,
552                                chunk_stream,
553                                remaining_rows,
554                                expected_timestamp,
555                                init_query_timer,
556                            };
557                            if table_schema_changed {
558                                return Ok(None);
559                            }
560                        }
561                        Ok((None, _)) => return Ok(None),
562                        Err(e) => {
563                            self.state = State::Invalid;
564                            return Err(e);
565                        }
566                    }
567                }
568                State::Fetch {
569                    from_snapshot,
570                    rw_timestamp,
571                    chunk_stream,
572                    remaining_rows,
573                    expected_timestamp,
574                    init_query_timer,
575                } => {
576                    let session_data = StaticSessionData {
577                        timezone: handler_args.session.config().timezone(),
578                    };
579                    let from_snapshot = *from_snapshot;
580                    let rw_timestamp = *rw_timestamp;
581
582                    // Try refill remaining rows
583                    Self::try_refill_remaining_rows(chunk_stream, remaining_rows).await?;
584
585                    if let Some(row) = remaining_rows.pop_front() {
586                        // 1. Fetch the next row
587                        if from_snapshot {
588                            return Ok(Some(Self::build_row(
589                                row.take(),
590                                None,
591                                formats,
592                                &session_data,
593                            )?));
594                        } else {
595                            return Ok(Some(Self::build_row(
596                                row.take(),
597                                Some(rw_timestamp),
598                                formats,
599                                &session_data,
600                            )?));
601                        }
602                    } else {
603                        self.cursor_metrics
604                            .subscription_cursor_query_duration
605                            .with_label_values(&[&self.subscription.name])
606                            .observe(init_query_timer.elapsed().as_millis() as _);
607                        // 2. Reach EOF for the current query.
608                        if let Some(expected_timestamp) = expected_timestamp {
609                            self.state = State::InitLogStoreQuery {
610                                seek_timestamp: *expected_timestamp,
611                                expected_timestamp: Some(*expected_timestamp),
612                            };
613                        } else {
614                            self.state = State::InitLogStoreQuery {
615                                seek_timestamp: rw_timestamp + 1,
616                                expected_timestamp: None,
617                            };
618                        }
619                    }
620                }
621                State::Invalid => {
622                    // TODO: auto close invalid cursor?
623                    return Err(ErrorCode::InternalError(
624                        "Cursor is in invalid state. Please close and re-create the cursor."
625                            .to_owned(),
626                    )
627                    .into());
628                }
629            }
630        }
631    }
632
633    pub async fn next(
634        &mut self,
635        count: u32,
636        handler_args: HandlerArgs,
637        formats: &Vec<Format>,
638        timeout_seconds: Option<u64>,
639        cancel_handle: &mut FetchCursorCancelHandle,
640    ) -> Result<(Vec<Row>, Vec<PgFieldDescriptor>)> {
641        let timeout_instant = timeout_seconds.map(|s| Instant::now() + Duration::from_secs(s));
642        if Instant::now() > self.cursor_need_drop_time {
643            return Err(ErrorCode::InternalError(
644                "The cursor has exceeded its maximum lifetime, please recreate it (close then declare cursor).".to_owned(),
645            )
646            .into());
647        }
648
649        let session = &handler_args.session;
650        let mut ans = Vec::with_capacity(std::cmp::min(100, count) as usize);
651        let mut cur = 0;
652        if let State::Fetch {
653            from_snapshot,
654            chunk_stream,
655            ..
656        } = &mut self.state
657        {
658            let (fields, fotmats) = self
659                .fields_manager
660                .get_row_stream_fields_and_formats(formats, *from_snapshot);
661            chunk_stream.init_row_stream(&fields, &fotmats, session.clone());
662        }
663        while cur < count {
664            if cancel_handle.is_cancelled() {
665                return Err(SchedulerError::QueryCancelled("Cancelled by user".to_owned()).into());
666            }
667            let fetch_cursor_timer = Instant::now();
668            let row = self.next_row(&handler_args, formats).await?;
669            self.cursor_metrics
670                .subscription_cursor_fetch_duration
671                .with_label_values(&[&self.subscription.name])
672                .observe(fetch_cursor_timer.elapsed().as_millis() as _);
673            match row {
674                Some(row) => {
675                    cur += 1;
676                    ans.push(row);
677                }
678                None => {
679                    let timeout_seconds = timeout_seconds.unwrap_or(0);
680                    if cur > 0 || timeout_seconds == 0 {
681                        break;
682                    }
683                    let State::InitLogStoreQuery { seek_timestamp, .. } = &self.state else {
684                        // Triggered when previous next_row returns None while self.state is State::Fetch.
685                        continue;
686                    };
687                    // This is the only point where subscription cursor fetch waits without an
688                    // inner query. Register the FETCH-level cancel token so CancelRequest can
689                    // interrupt this wait. The token also marks the whole FETCH as cancelled, so
690                    // we won't start another inner query after a cancellation.
691                    cancel_handle.register(session);
692                    let timeout = tokio::time::sleep(Duration::from_secs(timeout_seconds));
693                    tokio::pin!(timeout);
694                    tokio::select! {
695                        biased;
696                        _ = cancel_handle.cancelled() => {
697                            return Err(SchedulerError::QueryCancelled(
698                                "Cancelled by user".to_owned(),
699                            )
700                            .into());
701                        }
702                        result = session
703                            .env
704                            .hummock_snapshot_manager()
705                            .wait_table_change_log_notification(
706                                self.dependent_table_id,
707                                *seek_timestamp,
708                            ) => {
709                            result?;
710                        }
711                        _ = &mut timeout => {
712                            tracing::debug!("Cursor wait next epoch timeout");
713                            break;
714                        }
715                    }
716                    if cancel_handle.is_cancelled() {
717                        return Err(
718                            SchedulerError::QueryCancelled("Cancelled by user".to_owned()).into(),
719                        );
720                    }
721                }
722            }
723            // Timeout, return with current value
724            if let Some(timeout_instant) = timeout_instant
725                && Instant::now() > timeout_instant
726            {
727                break;
728            }
729        }
730        self.last_fetch = Instant::now();
731        let (rows, seek_pk_row) = self.fields_manager.process_output_desc_row(ans);
732        if let Some(seek_pk_row) = seek_pk_row {
733            self.seek_pk_row = Some(seek_pk_row);
734        }
735        let desc = self
736            .fields_manager
737            .get_output_fields()
738            .iter()
739            .map(to_pg_field)
740            .collect();
741
742        Ok((rows, desc))
743    }
744
745    async fn get_next_rw_timestamp(
746        seek_timestamp: u64,
747        table_id: TableId,
748        expected_timestamp: Option<u64>,
749        handler_args: HandlerArgs,
750        dependent_subscription: &SubscriptionCatalog,
751    ) -> Result<(Option<u64>, Option<u64>)> {
752        let session = handler_args.session;
753        // Test subscription existence
754        session.get_subscription_by_schema_id_name(
755            dependent_subscription.schema_id,
756            &dependent_subscription.name,
757        )?;
758
759        // The epoch here must be pulled every time, otherwise there will be cache consistency issues
760        let Some(new_epochs) = session
761            .list_change_log_epochs(table_id, seek_timestamp, 2)
762            .await?
763        else {
764            return Ok((None, None));
765        };
766        if let Some(expected_timestamp) = expected_timestamp
767            && (new_epochs.is_empty() || &expected_timestamp != new_epochs.first().unwrap())
768        {
769            return Err(ErrorCode::CatalogError(
770                format!(
771                    " No data found for rw_timestamp {:?}, data may have been recycled, please recreate cursor",
772                    convert_logstore_u64_to_unix_millis(expected_timestamp)
773                )
774                .into(),
775            )
776            .into());
777        }
778        Ok((new_epochs.get(0).cloned(), new_epochs.get(1).cloned()))
779    }
780
781    pub fn gen_batch_plan_result(
782        &self,
783        handler_args: HandlerArgs,
784    ) -> Result<RwBatchQueryPlanResult> {
785        match self.state {
786            // Only used to return generated plans, so rw_timestamp are meaningless
787            State::InitLogStoreQuery { .. } => Self::init_batch_plan_for_subscription_cursor(
788                Some(0),
789                self.dependent_table_id,
790                handler_args,
791                self.seek_pk_row.clone(),
792            ),
793            State::Fetch {
794                from_snapshot,
795                rw_timestamp,
796                ..
797            } => {
798                if from_snapshot {
799                    Self::init_batch_plan_for_subscription_cursor(
800                        None,
801                        self.dependent_table_id,
802                        handler_args,
803                        self.seek_pk_row.clone(),
804                    )
805                } else {
806                    Self::init_batch_plan_for_subscription_cursor(
807                        Some(rw_timestamp),
808                        self.dependent_table_id,
809                        handler_args,
810                        self.seek_pk_row.clone(),
811                    )
812                }
813            }
814            State::Invalid => Err(ErrorCode::InternalError(
815                "Cursor is in invalid state. Please close and re-create the cursor.".to_owned(),
816            )
817            .into()),
818        }
819    }
820
821    fn init_batch_plan_for_subscription_cursor(
822        rw_timestamp: Option<u64>,
823        dependent_table_id: TableId,
824        handler_args: HandlerArgs,
825        seek_pk_row: Option<Row>,
826    ) -> Result<RwBatchQueryPlanResult> {
827        let session = handler_args.clone().session;
828        let table_catalog = session.get_table_by_id(dependent_table_id)?;
829        let context = OptimizerContext::from_handler_args(handler_args);
830        let version_id = {
831            let version = session.env.hummock_snapshot_manager.acquire();
832            let version = version.version();
833            if !version
834                .state_table_info
835                .info()
836                .contains_key(&dependent_table_id)
837            {
838                return Err(anyhow!("table id {dependent_table_id} has been dropped").into());
839            }
840            version.id
841        };
842        Self::create_batch_plan_for_cursor(
843            table_catalog,
844            &session,
845            context.into(),
846            rw_timestamp.map(|rw_timestamp| (rw_timestamp, rw_timestamp)),
847            version_id,
848            seek_pk_row,
849        )
850    }
851
852    async fn initiate_query(
853        rw_timestamp: Option<u64>,
854        dependent_table_id: TableId,
855        handler_args: HandlerArgs,
856        seek_pk_row: Option<Row>,
857    ) -> Result<(CursorDataChunkStream, Instant, Arc<TableCatalog>)> {
858        let init_query_timer = Instant::now();
859        let session = handler_args.clone().session;
860        let table_catalog = session.get_table_by_id(dependent_table_id)?;
861        let plan_result = Self::init_batch_plan_for_subscription_cursor(
862            rw_timestamp,
863            dependent_table_id,
864            handler_args.clone(),
865            seek_pk_row,
866        )?;
867        let plan_fragmenter_result = gen_batch_plan_fragmenter(&handler_args.session, plan_result)?;
868        let (chunk_stream, _) =
869            create_chunk_stream_for_cursor(handler_args.session, plan_fragmenter_result).await?;
870        Ok((chunk_stream, init_query_timer, table_catalog))
871    }
872
873    async fn try_refill_remaining_rows(
874        chunk_stream: &mut CursorDataChunkStream,
875        remaining_rows: &mut VecDeque<Row>,
876    ) -> Result<()> {
877        if remaining_rows.is_empty()
878            && let Some(row_set) = chunk_stream.next().await?
879        {
880            remaining_rows.extend(row_set?);
881        }
882        Ok(())
883    }
884
885    pub fn build_row(
886        mut row: Vec<Option<Bytes>>,
887        rw_timestamp: Option<u64>,
888        formats: &Vec<Format>,
889        session_data: &StaticSessionData,
890    ) -> Result<Row> {
891        let row_len = row.len();
892        let new_row = if let Some(rw_timestamp) = rw_timestamp {
893            let rw_timestamp_formats = formats.get(row_len).unwrap_or(&Format::Text);
894            let rw_timestamp = convert_logstore_u64_to_unix_millis(rw_timestamp);
895            let rw_timestamp = pg_value_format(
896                &DataType::Int64,
897                risingwave_common::types::ScalarRefImpl::Int64(rw_timestamp as i64),
898                *rw_timestamp_formats,
899                session_data,
900            )?;
901            vec![Some(rw_timestamp)]
902        } else {
903            let op_formats = formats.get(row_len).unwrap_or(&Format::Text);
904            let op = pg_value_format(
905                &DataType::Varchar,
906                risingwave_common::types::ScalarRefImpl::Utf8("Insert"),
907                *op_formats,
908                session_data,
909            )?;
910            vec![Some(op), None]
911        };
912        row.extend(new_row);
913        Ok(Row::new(row))
914    }
915
916    pub fn build_desc(mut descs: Vec<Field>, from_snapshot: bool) -> Vec<Field> {
917        if from_snapshot {
918            descs.push(Field::with_name(DataType::Varchar, "op"));
919        }
920        descs.push(Field::with_name(DataType::Int64, "rw_timestamp"));
921        descs
922    }
923
924    pub fn create_batch_plan_for_cursor(
925        table_catalog: Arc<TableCatalog>,
926        session: &SessionImpl,
927        context: OptimizerContextRef,
928        epoch_range: Option<(u64, u64)>,
929        version_id: HummockVersionId,
930        seek_pk_rows: Option<Row>,
931    ) -> Result<RwBatchQueryPlanResult> {
932        // pk + all column without hidden
933        let output_col_idx = table_catalog
934            .columns
935            .iter()
936            .enumerate()
937            .filter_map(|(index, v)| {
938                if !v.is_hidden || table_catalog.pk.iter().any(|pk| pk.column_index == index) {
939                    Some(index)
940                } else {
941                    None
942                }
943            })
944            .collect::<Vec<_>>();
945        let max_split_range_gap = context.session_ctx().config().max_split_range_gap() as u64;
946        let pks = table_catalog.pk();
947        let pks = pks
948            .iter()
949            .map(|f| {
950                let pk = table_catalog.columns.get(f.column_index).unwrap();
951                (pk.data_type(), f.column_index)
952            })
953            .collect_vec();
954        let (scan, predicate) = if let Some(seek_pk_rows) = seek_pk_rows {
955            let mut pk_rows = vec![];
956            let mut values = vec![];
957            for (seek_pk, (data_type, column_index)) in
958                seek_pk_rows.take().into_iter().zip_eq_fast(pks.into_iter())
959            {
960                if let Some(seek_pk) = seek_pk {
961                    pk_rows.push(InputRef {
962                        index: column_index,
963                        data_type: data_type.clone(),
964                    });
965                    let value_string = String::from_utf8(seek_pk.clone().into()).unwrap();
966                    let value_data = ScalarImpl::from_text(&value_string, data_type).unwrap();
967                    values.push((Some(value_data), data_type.clone()));
968                }
969            }
970            if pk_rows.is_empty() {
971                (None, None)
972            } else {
973                let (right_data, right_types): (Vec<_>, Vec<_>) = values.into_iter().unzip();
974                let right_data = ScalarImpl::Struct(StructValue::new(right_data));
975                let right_type = DataType::Struct(StructType::row_expr_type(right_types));
976                let left = FunctionCall::new_unchecked(
977                    ExprType::Row,
978                    pk_rows.into_iter().map(|pk| pk.into()).collect(),
979                    right_type.clone(),
980                );
981                let right = Literal::new(Some(right_data), right_type);
982                let (scan, predicate) = Condition {
983                    conjunctions: vec![
984                        FunctionCall::new(ExprType::GreaterThan, vec![left.into(), right.into()])?
985                            .into(),
986                    ],
987                }
988                .split_to_scan_ranges(&table_catalog, max_split_range_gap)?;
989                if scan.len() > 1 {
990                    return Err(ErrorCode::InternalError(
991                        "Seek pk row should only generate one scan range".to_owned(),
992                    )
993                    .into());
994                }
995                (scan.first().cloned(), Some(predicate))
996            }
997        } else {
998            (None, None)
999        };
1000
1001        let (seq_scan, out_fields, out_names) = if let Some(epoch_range) = epoch_range {
1002            let core = generic::LogScan::new(
1003                table_catalog.name.clone(),
1004                output_col_idx,
1005                table_catalog.clone(),
1006                context,
1007                epoch_range,
1008                version_id,
1009            );
1010            let batch_log_seq_scan = BatchLogSeqScan::new(core, scan);
1011            let out_fields = batch_log_seq_scan.core().out_fields();
1012            let out_names = batch_log_seq_scan.core().column_names();
1013            (batch_log_seq_scan.into(), out_fields, out_names)
1014        } else {
1015            let core = generic::TableScan::new(
1016                output_col_idx,
1017                table_catalog.clone(),
1018                vec![],
1019                vec![],
1020                context,
1021                Condition {
1022                    conjunctions: vec![],
1023                },
1024                None,
1025            );
1026            let scans = match scan {
1027                Some(scan) => vec![scan],
1028                None => vec![],
1029            };
1030            let table_scan = BatchSeqScan::new(core, scans, None);
1031            let out_fields = table_scan.core().out_fields();
1032            let out_names = table_scan.core().column_names();
1033            (table_scan.into(), out_fields, out_names)
1034        };
1035
1036        let plan = if let Some(predicate) = predicate
1037            && !predicate.always_true()
1038        {
1039            BatchFilter::new(generic::Filter::new(predicate, seq_scan)).into()
1040        } else {
1041            seq_scan
1042        };
1043
1044        // order by pk, so don't need to sort
1045        let order = Order::new(table_catalog.pk().to_vec());
1046
1047        // Here we just need a plan_root to call the method, only out_fields and out_names will be used
1048        let plan_root = PlanRoot::new_with_batch_plan(
1049            plan,
1050            RequiredDist::single(),
1051            order,
1052            out_fields,
1053            out_names,
1054        );
1055        let schema = plan_root.schema();
1056        let (batch_log_seq_scan, query_mode) = match session.config().query_mode() {
1057            QueryMode::Auto | QueryMode::Local => {
1058                (plan_root.gen_batch_local_plan()?, QueryMode::Local)
1059            }
1060            QueryMode::Distributed => (
1061                plan_root.gen_batch_distributed_plan()?,
1062                QueryMode::Distributed,
1063            ),
1064        };
1065        Ok(RwBatchQueryPlanResult {
1066            plan: batch_log_seq_scan,
1067            query_mode,
1068            schema,
1069            stmt_type: StatementType::SELECT,
1070            dependent_relations: vec![],
1071            dependent_secrets: vec![],
1072        })
1073    }
1074
1075    pub fn idle_duration(&self) -> Duration {
1076        self.last_fetch.elapsed()
1077    }
1078
1079    pub fn subscription_name(&self) -> &str {
1080        self.subscription.name.as_str()
1081    }
1082
1083    pub fn state_info_string(&self) -> String {
1084        format!("{}", self.state)
1085    }
1086}
1087
1088pub struct CursorManager {
1089    cursor_map: tokio::sync::Mutex<HashMap<String, Cursor>>,
1090    cursor_metrics: Arc<CursorMetrics>,
1091}
1092
1093impl CursorManager {
1094    pub fn new(cursor_metrics: Arc<CursorMetrics>) -> Self {
1095        Self {
1096            cursor_map: tokio::sync::Mutex::new(HashMap::new()),
1097            cursor_metrics,
1098        }
1099    }
1100
1101    pub async fn add_subscription_cursor(
1102        &self,
1103        cursor_name: String,
1104        start_timestamp: Option<u64>,
1105        dependent_table_id: TableId,
1106        subscription: Arc<SubscriptionCatalog>,
1107        handler_args: &HandlerArgs,
1108    ) -> Result<()> {
1109        let create_cursor_timer = Instant::now();
1110        let subscription_name = subscription.name.clone();
1111        let cursor = SubscriptionCursor::new(
1112            cursor_name,
1113            start_timestamp,
1114            subscription,
1115            dependent_table_id,
1116            handler_args,
1117            self.cursor_metrics.clone(),
1118        )
1119        .await?;
1120        let mut cursor_map = self.cursor_map.lock().await;
1121        self.cursor_metrics
1122            .subscription_cursor_declare_duration
1123            .with_label_values(&[&subscription_name])
1124            .observe(create_cursor_timer.elapsed().as_millis() as _);
1125
1126        cursor_map.retain(|_, v| {
1127            if let Cursor::Subscription(cursor) = v
1128                && matches!(cursor.state, State::Invalid)
1129            {
1130                false
1131            } else {
1132                true
1133            }
1134        });
1135
1136        cursor_map
1137            .try_insert(cursor.cursor_name.clone(), Cursor::Subscription(cursor))
1138            .map_err(|error| {
1139                ErrorCode::CatalogError(
1140                    format!("cursor `{}` already exists", error.entry.key()).into(),
1141                )
1142            })?;
1143        Ok(())
1144    }
1145
1146    pub async fn add_query_cursor(
1147        &self,
1148        cursor_name: String,
1149        chunk_stream: CursorDataChunkStream,
1150        fields: Vec<Field>,
1151    ) -> Result<()> {
1152        let cursor = QueryCursor::new(chunk_stream, fields)?;
1153        self.cursor_map
1154            .lock()
1155            .await
1156            .try_insert(cursor_name, Cursor::Query(cursor))
1157            .map_err(|error| {
1158                ErrorCode::CatalogError(
1159                    format!("cursor `{}` already exists", error.entry.key()).into(),
1160                )
1161            })?;
1162
1163        Ok(())
1164    }
1165
1166    pub async fn remove_cursor(&self, cursor_name: &str) -> Result<()> {
1167        self.cursor_map
1168            .lock()
1169            .await
1170            .remove(cursor_name)
1171            .ok_or_else(|| {
1172                ErrorCode::CatalogError(format!("cursor `{}` don't exists", cursor_name).into())
1173            })?;
1174        Ok(())
1175    }
1176
1177    pub async fn remove_all_cursor(&self) {
1178        self.cursor_map.lock().await.clear();
1179    }
1180
1181    pub async fn remove_all_query_cursor(&self) {
1182        self.cursor_map
1183            .lock()
1184            .await
1185            .retain(|_, v| matches!(v, Cursor::Subscription(_)));
1186    }
1187
1188    pub async fn get_rows_with_cursor(
1189        &self,
1190        cursor_name: &str,
1191        count: u32,
1192        handler_args: HandlerArgs,
1193        formats: &Vec<Format>,
1194        timeout_seconds: Option<u64>,
1195        cancel_handle: &mut FetchCursorCancelHandle,
1196    ) -> Result<(Vec<Row>, Vec<PgFieldDescriptor>)> {
1197        if let Some(cursor) = self.cursor_map.lock().await.get_mut(cursor_name) {
1198            cursor
1199                .next(count, handler_args, formats, timeout_seconds, cancel_handle)
1200                .await
1201        } else {
1202            Err(ErrorCode::InternalError(format!("Cannot find cursor `{}`", cursor_name)).into())
1203        }
1204    }
1205
1206    pub async fn get_fields_with_cursor(&self, cursor_name: &str) -> Result<Vec<Field>> {
1207        if let Some(cursor) = self.cursor_map.lock().await.get_mut(cursor_name) {
1208            Ok(cursor.get_fields())
1209        } else {
1210            Err(ErrorCode::InternalError(format!("Cannot find cursor `{}`", cursor_name)).into())
1211        }
1212    }
1213
1214    pub async fn get_periodic_cursor_metrics(&self) -> PeriodicCursorMetrics {
1215        let mut subscription_cursor_nums = 0;
1216        let mut invalid_subscription_cursor_nums = 0;
1217        let mut subscription_cursor_last_fetch_duration = HashMap::new();
1218        for cursor in self.cursor_map.lock().await.values() {
1219            if let Cursor::Subscription(subscription_cursor) = cursor {
1220                subscription_cursor_nums += 1;
1221                if matches!(subscription_cursor.state, State::Invalid) {
1222                    invalid_subscription_cursor_nums += 1;
1223                } else {
1224                    let fetch_duration =
1225                        subscription_cursor.last_fetch.elapsed().as_millis() as f64;
1226                    subscription_cursor_last_fetch_duration.insert(
1227                        subscription_cursor.subscription.name.clone(),
1228                        fetch_duration,
1229                    );
1230                }
1231            }
1232        }
1233        PeriodicCursorMetrics {
1234            subscription_cursor_nums,
1235            invalid_subscription_cursor_nums,
1236            subscription_cursor_last_fetch_duration,
1237        }
1238    }
1239
1240    pub async fn iter_query_cursors(&self, mut f: impl FnMut(&String, &QueryCursor)) {
1241        self.cursor_map
1242            .lock()
1243            .await
1244            .iter()
1245            .for_each(|(cursor_name, cursor)| {
1246                if let Cursor::Query(cursor) = cursor {
1247                    f(cursor_name, cursor)
1248                }
1249            });
1250    }
1251
1252    pub async fn iter_subscription_cursors(&self, mut f: impl FnMut(&String, &SubscriptionCursor)) {
1253        self.cursor_map
1254            .lock()
1255            .await
1256            .iter()
1257            .for_each(|(cursor_name, cursor)| {
1258                if let Cursor::Subscription(cursor) = cursor {
1259                    f(cursor_name, cursor)
1260                }
1261            });
1262    }
1263
1264    pub async fn gen_batch_plan_with_subscription_cursor(
1265        &self,
1266        cursor_name: &str,
1267        handler_args: HandlerArgs,
1268    ) -> Result<RwBatchQueryPlanResult> {
1269        match self.cursor_map.lock().await.get(cursor_name).ok_or_else(|| {
1270            ErrorCode::InternalError(format!("Cannot find cursor `{}`", cursor_name))
1271        })? {
1272            Cursor::Subscription(cursor) => {
1273                cursor.gen_batch_plan_result(handler_args.clone())
1274            },
1275            Cursor::Query(_) => Err(ErrorCode::InternalError("The plan of the cursor is the same as the query statement of the as when it was created.".to_owned()).into()),
1276        }
1277    }
1278}