mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-01-05 21:02:58 +00:00
feat: Adds RegionScanner trait (#3948)
* feat: define region scanner * feat: single partition scanner * feat: use single partition scanner * feat: implement ExecutionPlan wip * feat: mito engine returns single partition scanner * feat: implement DisplayAs for region server * feat: dummy table provider use handle_partitioned_query() * test: update sqlness test * feat: table provider use ReadFromRegion * refactor: remove StreamScanAdapter * chore: update lock * style: fix clippy * refactor: remove handle_query from the RegionEngine trait * chore: address CR comments * refactor: rename methods * refactor: rename ReadFromRegion to RegionScanExec
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -10169,6 +10169,7 @@ dependencies = [
|
||||
"common-query",
|
||||
"common-recordbatch",
|
||||
"common-wal",
|
||||
"datafusion-physical-plan 37.0.0",
|
||||
"datatypes",
|
||||
"derive_builder 0.12.0",
|
||||
"futures",
|
||||
|
||||
@@ -110,6 +110,7 @@ datafusion-expr = { git = "https://github.com/apache/arrow-datafusion.git", rev
|
||||
datafusion-functions = { git = "https://github.com/apache/arrow-datafusion.git", rev = "34eda15b73a9e278af8844b30ed2f1c21c10359c" }
|
||||
datafusion-optimizer = { git = "https://github.com/apache/arrow-datafusion.git", rev = "34eda15b73a9e278af8844b30ed2f1c21c10359c" }
|
||||
datafusion-physical-expr = { git = "https://github.com/apache/arrow-datafusion.git", rev = "34eda15b73a9e278af8844b30ed2f1c21c10359c" }
|
||||
datafusion-physical-plan = { git = "https://github.com/apache/arrow-datafusion.git", rev = "34eda15b73a9e278af8844b30ed2f1c21c10359c" }
|
||||
datafusion-sql = { git = "https://github.com/apache/arrow-datafusion.git", rev = "34eda15b73a9e278af8844b30ed2f1c21c10359c" }
|
||||
datafusion-substrait = { git = "https://github.com/apache/arrow-datafusion.git", rev = "34eda15b73a9e278af8844b30ed2f1c21c10359c" }
|
||||
derive_builder = "0.12"
|
||||
|
||||
@@ -23,7 +23,6 @@ use common_function::function::FunctionRef;
|
||||
use common_function::scalars::aggregate::AggregateFunctionMetaRef;
|
||||
use common_query::prelude::ScalarUdf;
|
||||
use common_query::Output;
|
||||
use common_recordbatch::SendableRecordBatchStream;
|
||||
use common_runtime::Runtime;
|
||||
use query::dataframe::DataFrame;
|
||||
use query::plan::LogicalPlan;
|
||||
@@ -32,7 +31,7 @@ use query::query_engine::DescribeResult;
|
||||
use query::{QueryEngine, QueryEngineContext};
|
||||
use session::context::QueryContextRef;
|
||||
use store_api::metadata::RegionMetadataRef;
|
||||
use store_api::region_engine::{RegionEngine, RegionRole, SetReadonlyResponse};
|
||||
use store_api::region_engine::{RegionEngine, RegionRole, RegionScannerRef, SetReadonlyResponse};
|
||||
use store_api::region_request::{AffectedRows, RegionRequest};
|
||||
use store_api::storage::{RegionId, ScanRequest};
|
||||
use table::TableRef;
|
||||
@@ -193,7 +192,7 @@ impl RegionEngine for MockRegionEngine {
|
||||
&self,
|
||||
_region_id: RegionId,
|
||||
_request: ScanRequest,
|
||||
) -> Result<SendableRecordBatchStream, BoxedError> {
|
||||
) -> Result<RegionScannerRef, BoxedError> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,9 @@ use common_telemetry::{error, info};
|
||||
use object_store::ObjectStore;
|
||||
use snafu::{ensure, OptionExt};
|
||||
use store_api::metadata::RegionMetadataRef;
|
||||
use store_api::region_engine::{RegionEngine, RegionRole, SetReadonlyResponse};
|
||||
use store_api::region_engine::{
|
||||
RegionEngine, RegionRole, RegionScannerRef, SetReadonlyResponse, SinglePartitionScanner,
|
||||
};
|
||||
use store_api::region_request::{
|
||||
AffectedRows, RegionCloseRequest, RegionCreateRequest, RegionDropRequest, RegionOpenRequest,
|
||||
RegionRequest,
|
||||
@@ -49,6 +51,20 @@ impl FileRegionEngine {
|
||||
inner: Arc::new(EngineInner::new(object_store)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_query(
|
||||
&self,
|
||||
region_id: RegionId,
|
||||
request: ScanRequest,
|
||||
) -> Result<SendableRecordBatchStream, BoxedError> {
|
||||
self.inner
|
||||
.get_region(region_id)
|
||||
.await
|
||||
.context(RegionNotFoundSnafu { region_id })
|
||||
.map_err(BoxedError::new)?
|
||||
.query(request)
|
||||
.map_err(BoxedError::new)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -72,14 +88,10 @@ impl RegionEngine for FileRegionEngine {
|
||||
&self,
|
||||
region_id: RegionId,
|
||||
request: ScanRequest,
|
||||
) -> Result<SendableRecordBatchStream, BoxedError> {
|
||||
self.inner
|
||||
.get_region(region_id)
|
||||
.await
|
||||
.context(RegionNotFoundSnafu { region_id })
|
||||
.map_err(BoxedError::new)?
|
||||
.query(request)
|
||||
.map_err(BoxedError::new)
|
||||
) -> Result<RegionScannerRef, BoxedError> {
|
||||
let stream = self.handle_query(region_id, request).await?;
|
||||
let scanner = Arc::new(SinglePartitionScanner::new(stream));
|
||||
Ok(scanner)
|
||||
}
|
||||
|
||||
async fn get_metadata(&self, region_id: RegionId) -> Result<RegionMetadataRef, BoxedError> {
|
||||
|
||||
@@ -35,7 +35,9 @@ use common_recordbatch::SendableRecordBatchStream;
|
||||
use mito2::engine::MitoEngine;
|
||||
use store_api::metadata::RegionMetadataRef;
|
||||
use store_api::metric_engine_consts::METRIC_ENGINE_NAME;
|
||||
use store_api::region_engine::{RegionEngine, RegionRole, SetReadonlyResponse};
|
||||
use store_api::region_engine::{
|
||||
RegionEngine, RegionRole, RegionScannerRef, SetReadonlyResponse, SinglePartitionScanner,
|
||||
};
|
||||
use store_api::region_request::RegionRequest;
|
||||
use store_api::storage::{RegionId, ScanRequest};
|
||||
|
||||
@@ -155,16 +157,14 @@ impl RegionEngine for MetricEngine {
|
||||
})
|
||||
}
|
||||
|
||||
/// Handles substrait query and return a stream of record batches
|
||||
async fn handle_query(
|
||||
&self,
|
||||
region_id: RegionId,
|
||||
request: ScanRequest,
|
||||
) -> Result<SendableRecordBatchStream, BoxedError> {
|
||||
self.inner
|
||||
.read_region(region_id, request)
|
||||
.await
|
||||
.map_err(BoxedError::new)
|
||||
) -> Result<RegionScannerRef, BoxedError> {
|
||||
let stream = self.handle_query(region_id, request).await?;
|
||||
let scanner = Arc::new(SinglePartitionScanner::new(stream));
|
||||
Ok(scanner)
|
||||
}
|
||||
|
||||
/// Retrieves region's metadata.
|
||||
@@ -251,6 +251,18 @@ impl MetricEngine {
|
||||
.logical_regions(physical_region_id)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Handles substrait query and return a stream of record batches
|
||||
async fn handle_query(
|
||||
&self,
|
||||
region_id: RegionId,
|
||||
request: ScanRequest,
|
||||
) -> Result<SendableRecordBatchStream, BoxedError> {
|
||||
self.inner
|
||||
.read_region(region_id, request)
|
||||
.await
|
||||
.map_err(BoxedError::new)
|
||||
}
|
||||
}
|
||||
|
||||
struct MetricEngineInner {
|
||||
|
||||
@@ -62,7 +62,7 @@ impl MetricEngineInner {
|
||||
.start_timer();
|
||||
|
||||
self.mito
|
||||
.handle_query(region_id, request)
|
||||
.scan_to_stream(region_id, request)
|
||||
.await
|
||||
.context(MitoReadOperationSnafu)
|
||||
}
|
||||
@@ -82,7 +82,7 @@ impl MetricEngineInner {
|
||||
.transform_request(physical_region_id, logical_region_id, request)
|
||||
.await?;
|
||||
self.mito
|
||||
.handle_query(data_region_id, request)
|
||||
.scan_to_stream(data_region_id, request)
|
||||
.await
|
||||
.context(MitoReadOperationSnafu)
|
||||
}
|
||||
|
||||
@@ -300,7 +300,7 @@ impl MetadataRegion {
|
||||
let scan_req = Self::build_read_request(key);
|
||||
let record_batch_stream = self
|
||||
.mito
|
||||
.handle_query(region_id, scan_req)
|
||||
.scan_to_stream(region_id, scan_req)
|
||||
.await
|
||||
.context(MitoReadOperationSnafu)?;
|
||||
let scan_result = collect(record_batch_stream)
|
||||
@@ -317,7 +317,7 @@ impl MetadataRegion {
|
||||
let scan_req = Self::build_read_request(key);
|
||||
let record_batch_stream = self
|
||||
.mito
|
||||
.handle_query(region_id, scan_req)
|
||||
.scan_to_stream(region_id, scan_req)
|
||||
.await
|
||||
.context(MitoReadOperationSnafu)?;
|
||||
let scan_result = collect(record_batch_stream)
|
||||
@@ -351,7 +351,7 @@ impl MetadataRegion {
|
||||
};
|
||||
let record_batch_stream = self
|
||||
.mito
|
||||
.handle_query(region_id, scan_req)
|
||||
.scan_to_stream(region_id, scan_req)
|
||||
.await
|
||||
.context(MitoReadOperationSnafu)?;
|
||||
let scan_result = collect(record_batch_stream)
|
||||
@@ -590,7 +590,7 @@ mod test {
|
||||
let scan_req = MetadataRegion::build_read_request("test_key");
|
||||
let record_batch_stream = metadata_region
|
||||
.mito
|
||||
.handle_query(region_id, scan_req)
|
||||
.scan_to_stream(region_id, scan_req)
|
||||
.await
|
||||
.unwrap();
|
||||
let scan_result = collect(record_batch_stream).await.unwrap();
|
||||
|
||||
@@ -62,7 +62,7 @@ use object_store::manager::ObjectStoreManagerRef;
|
||||
use snafu::{ensure, OptionExt, ResultExt};
|
||||
use store_api::logstore::LogStore;
|
||||
use store_api::metadata::RegionMetadataRef;
|
||||
use store_api::region_engine::{RegionEngine, RegionRole, SetReadonlyResponse};
|
||||
use store_api::region_engine::{RegionEngine, RegionRole, RegionScannerRef, SetReadonlyResponse};
|
||||
use store_api::region_request::{AffectedRows, RegionRequest};
|
||||
use store_api::storage::{RegionId, ScanRequest};
|
||||
use tokio::sync::oneshot;
|
||||
@@ -115,11 +115,35 @@ impl MitoEngine {
|
||||
Ok(region.region_usage().await)
|
||||
}
|
||||
|
||||
/// Handle substrait query and return a stream of record batches
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub async fn scan_to_stream(
|
||||
&self,
|
||||
region_id: RegionId,
|
||||
request: ScanRequest,
|
||||
) -> std::result::Result<SendableRecordBatchStream, BoxedError> {
|
||||
self.scanner(region_id, request)
|
||||
.map_err(BoxedError::new)?
|
||||
.scan()
|
||||
.await
|
||||
.map_err(BoxedError::new)
|
||||
}
|
||||
|
||||
/// Returns a scanner to scan for `request`.
|
||||
fn scanner(&self, region_id: RegionId, request: ScanRequest) -> Result<Scanner> {
|
||||
self.scan_region(region_id, request)?.scanner()
|
||||
}
|
||||
|
||||
/// Returns a region scanner to scan the region for `request`.
|
||||
async fn region_scanner(
|
||||
&self,
|
||||
region_id: RegionId,
|
||||
request: ScanRequest,
|
||||
) -> Result<RegionScannerRef> {
|
||||
let scanner = self.scanner(region_id, request)?;
|
||||
scanner.region_scanner().await
|
||||
}
|
||||
|
||||
/// Scans a region.
|
||||
fn scan_region(&self, region_id: RegionId, request: ScanRequest) -> Result<ScanRegion> {
|
||||
self.inner.handle_query(region_id, request)
|
||||
@@ -312,16 +336,13 @@ impl RegionEngine for MitoEngine {
|
||||
.map_err(BoxedError::new)
|
||||
}
|
||||
|
||||
/// Handle substrait query and return a stream of record batches
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn handle_query(
|
||||
&self,
|
||||
region_id: RegionId,
|
||||
request: ScanRequest,
|
||||
) -> std::result::Result<SendableRecordBatchStream, BoxedError> {
|
||||
self.scanner(region_id, request)
|
||||
.map_err(BoxedError::new)?
|
||||
.scan()
|
||||
) -> Result<RegionScannerRef, BoxedError> {
|
||||
self.region_scanner(region_id, request)
|
||||
.await
|
||||
.map_err(BoxedError::new)
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ async fn test_put_after_alter() {
|
||||
| | b | 2.0 | 1970-01-01T00:00:02 |
|
||||
+-------+-------+---------+---------------------+";
|
||||
let request = ScanRequest::default();
|
||||
let stream = engine.handle_query(region_id, request).await.unwrap();
|
||||
let stream = engine.scan_to_stream(region_id, request).await.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
assert_eq!(expected, batches.pretty_print().unwrap());
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ async fn test_append_mode_write_query() {
|
||||
put_rows(&engine, region_id, rows).await;
|
||||
|
||||
let request = ScanRequest::default();
|
||||
let stream = engine.handle_query(region_id, request).await.unwrap();
|
||||
let stream = engine.scan_to_stream(region_id, request).await.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
let expected = "\
|
||||
+-------+---------+---------------------+
|
||||
@@ -183,7 +183,7 @@ async fn test_append_mode_compaction() {
|
||||
// Reopens the region.
|
||||
reopen_region(&engine, region_id, region_dir, false, region_opts).await;
|
||||
let stream = engine
|
||||
.handle_query(region_id, ScanRequest::default())
|
||||
.scan_to_stream(region_id, ScanRequest::default())
|
||||
.await
|
||||
.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
|
||||
@@ -128,7 +128,7 @@ async fn test_region_replay() {
|
||||
assert_eq!(0, result.affected_rows);
|
||||
|
||||
let request = ScanRequest::default();
|
||||
let stream = engine.handle_query(region_id, request).await.unwrap();
|
||||
let stream = engine.scan_to_stream(region_id, request).await.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
assert_eq!(42, batches.iter().map(|b| b.num_rows()).sum::<usize>());
|
||||
|
||||
@@ -166,7 +166,7 @@ async fn test_write_query_region() {
|
||||
put_rows(&engine, region_id, rows).await;
|
||||
|
||||
let request = ScanRequest::default();
|
||||
let stream = engine.handle_query(region_id, request).await.unwrap();
|
||||
let stream = engine.scan_to_stream(region_id, request).await.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
let expected = "\
|
||||
+-------+---------+---------------------+
|
||||
@@ -227,7 +227,7 @@ async fn test_different_order() {
|
||||
put_rows(&engine, region_id, rows).await;
|
||||
|
||||
let request = ScanRequest::default();
|
||||
let stream = engine.handle_query(region_id, request).await.unwrap();
|
||||
let stream = engine.scan_to_stream(region_id, request).await.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
let expected = "\
|
||||
+-------+-------+---------+---------+---------------------+
|
||||
@@ -289,7 +289,7 @@ async fn test_different_order_and_type() {
|
||||
put_rows(&engine, region_id, rows).await;
|
||||
|
||||
let request = ScanRequest::default();
|
||||
let stream = engine.handle_query(region_id, request).await.unwrap();
|
||||
let stream = engine.scan_to_stream(region_id, request).await.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
let expected = "\
|
||||
+-------+-------+---------+---------+---------------------+
|
||||
@@ -341,7 +341,7 @@ async fn test_put_delete() {
|
||||
delete_rows(&engine, region_id, rows).await;
|
||||
|
||||
let request = ScanRequest::default();
|
||||
let stream = engine.handle_query(region_id, request).await.unwrap();
|
||||
let stream = engine.scan_to_stream(region_id, request).await.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
let expected = "\
|
||||
+-------+---------+---------------------+
|
||||
@@ -383,7 +383,7 @@ async fn test_delete_not_null_fields() {
|
||||
delete_rows(&engine, region_id, rows).await;
|
||||
|
||||
let request = ScanRequest::default();
|
||||
let stream = engine.handle_query(region_id, request).await.unwrap();
|
||||
let stream = engine.scan_to_stream(region_id, request).await.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
let expected = "\
|
||||
+-------+---------+---------------------+
|
||||
@@ -398,7 +398,7 @@ async fn test_delete_not_null_fields() {
|
||||
// Reopen and scan again.
|
||||
reopen_region(&engine, region_id, region_dir, false, HashMap::new()).await;
|
||||
let request = ScanRequest::default();
|
||||
let stream = engine.handle_query(region_id, request).await.unwrap();
|
||||
let stream = engine.scan_to_stream(region_id, request).await.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
assert_eq!(expected, batches.pretty_print().unwrap());
|
||||
}
|
||||
@@ -447,7 +447,7 @@ async fn test_put_overwrite() {
|
||||
put_rows(&engine, region_id, rows).await;
|
||||
|
||||
let request = ScanRequest::default();
|
||||
let stream = engine.handle_query(region_id, request).await.unwrap();
|
||||
let stream = engine.scan_to_stream(region_id, request).await.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
let expected = "\
|
||||
+-------+---------+---------------------+
|
||||
@@ -688,7 +688,7 @@ async fn test_cache_null_primary_key() {
|
||||
put_rows(&engine, region_id, rows).await;
|
||||
|
||||
let request = ScanRequest::default();
|
||||
let stream = engine.handle_query(region_id, request).await.unwrap();
|
||||
let stream = engine.scan_to_stream(region_id, request).await.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
let expected = "\
|
||||
+-------+-------+---------+---------------------+
|
||||
|
||||
@@ -104,7 +104,7 @@ async fn test_catchup_with_last_entry_id() {
|
||||
// Scans
|
||||
let request = ScanRequest::default();
|
||||
let stream = follower_engine
|
||||
.handle_query(region_id, request)
|
||||
.scan_to_stream(region_id, request)
|
||||
.await
|
||||
.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
@@ -264,7 +264,7 @@ async fn test_catchup_without_last_entry_id() {
|
||||
|
||||
let request = ScanRequest::default();
|
||||
let stream = follower_engine
|
||||
.handle_query(region_id, request)
|
||||
.scan_to_stream(region_id, request)
|
||||
.await
|
||||
.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
@@ -367,7 +367,7 @@ async fn test_catchup_with_manifest_update() {
|
||||
|
||||
let request = ScanRequest::default();
|
||||
let stream = follower_engine
|
||||
.handle_query(region_id, request)
|
||||
.scan_to_stream(region_id, request)
|
||||
.await
|
||||
.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
|
||||
@@ -231,7 +231,7 @@ async fn test_engine_create_with_memtable_opts() {
|
||||
put_rows(&engine, region_id, rows).await;
|
||||
|
||||
let request = ScanRequest::default();
|
||||
let stream = engine.handle_query(region_id, request).await.unwrap();
|
||||
let stream = engine.scan_to_stream(region_id, request).await.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
let expected = "\
|
||||
+-------+---------+---------------------+
|
||||
|
||||
@@ -69,7 +69,7 @@ async fn test_scan_without_filtering_deleted() {
|
||||
|
||||
// scan
|
||||
let request = ScanRequest::default();
|
||||
let stream = engine.handle_query(region_id, request).await.unwrap();
|
||||
let stream = engine.scan_to_stream(region_id, request).await.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
let expected = "\
|
||||
+-------+---------+---------------------+
|
||||
|
||||
@@ -276,7 +276,7 @@ async fn test_open_region_skip_wal_replay() {
|
||||
.unwrap();
|
||||
|
||||
let request = ScanRequest::default();
|
||||
let stream = engine.handle_query(region_id, request).await.unwrap();
|
||||
let stream = engine.scan_to_stream(region_id, request).await.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
let expected = "\
|
||||
+-------+---------+---------------------+
|
||||
@@ -305,7 +305,7 @@ async fn test_open_region_skip_wal_replay() {
|
||||
.unwrap();
|
||||
|
||||
let request = ScanRequest::default();
|
||||
let stream = engine.handle_query(region_id, request).await.unwrap();
|
||||
let stream = engine.scan_to_stream(region_id, request).await.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
let expected = "\
|
||||
+-------+---------+---------------------+
|
||||
|
||||
@@ -57,7 +57,7 @@ async fn scan_in_parallel(
|
||||
.unwrap();
|
||||
|
||||
let request = ScanRequest::default();
|
||||
let stream = engine.handle_query(region_id, request).await.unwrap();
|
||||
let stream = engine.scan_to_stream(region_id, request).await.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
let expected = "\
|
||||
+-------+---------+---------------------+
|
||||
|
||||
@@ -79,7 +79,7 @@ async fn test_scan_projection() {
|
||||
output_ordering: None,
|
||||
limit: None,
|
||||
};
|
||||
let stream = engine.handle_query(region_id, request).await.unwrap();
|
||||
let stream = engine.scan_to_stream(region_id, request).await.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
let expected = "\
|
||||
+-------+---------+---------------------+
|
||||
|
||||
@@ -53,7 +53,7 @@ async fn check_prune_row_groups(expr: DfExpr, expected: &str) {
|
||||
flush_region(&engine, region_id, Some(5)).await;
|
||||
|
||||
let stream = engine
|
||||
.handle_query(
|
||||
.scan_to_stream(
|
||||
region_id,
|
||||
ScanRequest {
|
||||
filters: vec![Expr::from(expr)],
|
||||
@@ -186,7 +186,7 @@ async fn test_prune_memtable() {
|
||||
.await;
|
||||
|
||||
let stream = engine
|
||||
.handle_query(
|
||||
.scan_to_stream(
|
||||
region_id,
|
||||
ScanRequest {
|
||||
filters: vec![time_range_expr(0, 20)],
|
||||
@@ -238,7 +238,7 @@ async fn test_prune_memtable_complex_expr() {
|
||||
let filters = vec![time_range_expr(4, 7), Expr::from(col("tag_0").lt(lit("6")))];
|
||||
|
||||
let stream = engine
|
||||
.handle_query(
|
||||
.scan_to_stream(
|
||||
region_id,
|
||||
ScanRequest {
|
||||
filters,
|
||||
|
||||
@@ -55,7 +55,7 @@ async fn test_engine_truncate_region_basic() {
|
||||
|
||||
// Scan the region.
|
||||
let request = ScanRequest::default();
|
||||
let stream = engine.handle_query(region_id, request).await.unwrap();
|
||||
let stream = engine.scan_to_stream(region_id, request).await.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
let expected = "\
|
||||
+-------+---------+---------------------+
|
||||
@@ -75,7 +75,7 @@ async fn test_engine_truncate_region_basic() {
|
||||
|
||||
// Scan the region.
|
||||
let request = ScanRequest::default();
|
||||
let stream = engine.handle_query(region_id, request).await.unwrap();
|
||||
let stream = engine.scan_to_stream(region_id, request).await.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
let expected = "++\n++";
|
||||
assert_eq!(expected, batches.pretty_print().unwrap());
|
||||
@@ -104,7 +104,7 @@ async fn test_engine_put_data_after_truncate() {
|
||||
|
||||
// Scan the region
|
||||
let request = ScanRequest::default();
|
||||
let stream = engine.handle_query(region_id, request).await.unwrap();
|
||||
let stream = engine.scan_to_stream(region_id, request).await.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
let expected = "\
|
||||
+-------+---------+---------------------+
|
||||
@@ -131,7 +131,7 @@ async fn test_engine_put_data_after_truncate() {
|
||||
|
||||
// Scan the region.
|
||||
let request = ScanRequest::default();
|
||||
let stream = engine.handle_query(region_id, request).await.unwrap();
|
||||
let stream = engine.scan_to_stream(region_id, request).await.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
let expected = "\
|
||||
+-------+---------+---------------------+
|
||||
@@ -261,7 +261,7 @@ async fn test_engine_truncate_reopen() {
|
||||
|
||||
// Scan the region.
|
||||
let request = ScanRequest::default();
|
||||
let stream = engine.handle_query(region_id, request).await.unwrap();
|
||||
let stream = engine.scan_to_stream(region_id, request).await.unwrap();
|
||||
let batches = RecordBatches::try_collect(stream).await.unwrap();
|
||||
let expected = "++\n++";
|
||||
assert_eq!(expected, batches.pretty_print().unwrap());
|
||||
|
||||
@@ -20,6 +20,7 @@ use std::time::Instant;
|
||||
use common_recordbatch::SendableRecordBatchStream;
|
||||
use common_telemetry::{debug, error, warn};
|
||||
use common_time::range::TimestampRange;
|
||||
use store_api::region_engine::{RegionScannerRef, SinglePartitionScanner};
|
||||
use store_api::storage::ScanRequest;
|
||||
use table::predicate::{Predicate, TimeRangePredicateBuilder};
|
||||
use tokio::sync::{mpsc, Semaphore};
|
||||
@@ -57,6 +58,14 @@ impl Scanner {
|
||||
Scanner::Unordered(unordered_scan) => unordered_scan.build_stream().await,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a [RegionScanner] to scan the region.
|
||||
pub(crate) async fn region_scanner(&self) -> Result<RegionScannerRef> {
|
||||
let stream = self.scan().await?;
|
||||
let scanner = SinglePartitionScanner::new(stream);
|
||||
|
||||
Ok(Arc::new(scanner))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -198,6 +198,14 @@ impl UnorderedScan {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl UnorderedScan {
|
||||
/// Returns the input.
|
||||
pub(crate) fn input(&self) -> &ScanInput {
|
||||
&self.input
|
||||
}
|
||||
}
|
||||
|
||||
/// Metrics for [UnorderedScan].
|
||||
#[derive(Debug, Default)]
|
||||
struct Metrics {
|
||||
@@ -216,11 +224,3 @@ struct Metrics {
|
||||
/// Number of rows returned.
|
||||
num_rows: usize,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl UnorderedScan {
|
||||
/// Returns the input.
|
||||
pub(crate) fn input(&self) -> &ScanInput {
|
||||
&self.input
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ use snafu::ResultExt;
|
||||
use store_api::metadata::RegionMetadataRef;
|
||||
use store_api::region_engine::RegionEngineRef;
|
||||
use store_api::storage::{RegionId, ScanRequest};
|
||||
use table::table::scan::StreamScanAdapter;
|
||||
use table::table::scan::RegionScanExec;
|
||||
|
||||
use crate::error::{GetRegionMetadataSnafu, Result};
|
||||
|
||||
@@ -168,12 +168,12 @@ impl TableProvider for DummyTableProvider {
|
||||
.collect();
|
||||
request.limit = limit;
|
||||
|
||||
let stream = self
|
||||
let scanner = self
|
||||
.engine
|
||||
.handle_query(self.region_id, request)
|
||||
.await
|
||||
.map_err(|e| DataFusionError::External(Box::new(e)))?;
|
||||
Ok(Arc::new(StreamScanAdapter::new(stream)))
|
||||
Ok(Arc::new(RegionScanExec::new(scanner)))
|
||||
}
|
||||
|
||||
fn supports_filters_pushdown(
|
||||
|
||||
@@ -23,12 +23,11 @@ use api::v1::SemanticType;
|
||||
use async_trait::async_trait;
|
||||
use common_error::ext::{BoxedError, PlainError};
|
||||
use common_error::status_code::StatusCode;
|
||||
use common_recordbatch::SendableRecordBatchStream;
|
||||
use datatypes::schema::ColumnSchema;
|
||||
use store_api::metadata::{
|
||||
ColumnMetadata, RegionMetadata, RegionMetadataBuilder, RegionMetadataRef,
|
||||
};
|
||||
use store_api::region_engine::{RegionEngine, RegionRole, SetReadonlyResponse};
|
||||
use store_api::region_engine::{RegionEngine, RegionRole, RegionScannerRef, SetReadonlyResponse};
|
||||
use store_api::region_request::RegionRequest;
|
||||
use store_api::storage::{ConcreteDataType, RegionId, ScanRequest};
|
||||
|
||||
@@ -67,7 +66,7 @@ impl RegionEngine for MetaRegionEngine {
|
||||
&self,
|
||||
_region_id: RegionId,
|
||||
_request: ScanRequest,
|
||||
) -> Result<SendableRecordBatchStream, BoxedError> {
|
||||
) -> Result<RegionScannerRef, BoxedError> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ common-macro.workspace = true
|
||||
common-query.workspace = true
|
||||
common-recordbatch.workspace = true
|
||||
common-wal.workspace = true
|
||||
datafusion-physical-plan.workspace = true
|
||||
datatypes.workspace = true
|
||||
derive_builder.workspace = true
|
||||
futures.workspace = true
|
||||
|
||||
@@ -15,15 +15,19 @@
|
||||
//! Region Engine's definition
|
||||
|
||||
use std::any::Any;
|
||||
use std::fmt::Display;
|
||||
use std::sync::Arc;
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use api::greptime_proto::v1::meta::{GrantedRegion as PbGrantedRegion, RegionRole as PbRegionRole};
|
||||
use api::region::RegionResponse;
|
||||
use async_trait::async_trait;
|
||||
use common_error::ext::BoxedError;
|
||||
use common_query::error::ExecuteRepeatedlySnafu;
|
||||
use common_recordbatch::SendableRecordBatchStream;
|
||||
use datafusion_physical_plan::{DisplayAs, DisplayFormatType};
|
||||
use datatypes::schema::SchemaRef;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use snafu::OptionExt;
|
||||
|
||||
use crate::logstore::entry;
|
||||
use crate::metadata::RegionMetadataRef;
|
||||
@@ -120,6 +124,57 @@ impl From<PbRegionRole> for RegionRole {
|
||||
}
|
||||
}
|
||||
|
||||
/// Output partition properties of the [RegionScanner].
|
||||
#[derive(Debug)]
|
||||
pub enum ScannerPartitioning {
|
||||
/// Unknown partitioning scheme with a known number of partitions
|
||||
Unknown(usize),
|
||||
}
|
||||
|
||||
impl ScannerPartitioning {
|
||||
/// Returns the number of partitions.
|
||||
pub fn num_partitions(&self) -> usize {
|
||||
match self {
|
||||
ScannerPartitioning::Unknown(num_partitions) => *num_partitions,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Properties of the [RegionScanner].
|
||||
#[derive(Debug)]
|
||||
pub struct ScannerProperties {
|
||||
/// Partitions to scan.
|
||||
partitioning: ScannerPartitioning,
|
||||
}
|
||||
|
||||
impl ScannerProperties {
|
||||
/// Creates a new [ScannerProperties] with the given partitioning.
|
||||
pub fn new(partitioning: ScannerPartitioning) -> Self {
|
||||
Self { partitioning }
|
||||
}
|
||||
|
||||
/// Returns properties of partitions to scan.
|
||||
pub fn partitioning(&self) -> &ScannerPartitioning {
|
||||
&self.partitioning
|
||||
}
|
||||
}
|
||||
|
||||
/// A scanner that provides a way to scan the region concurrently.
|
||||
/// The scanner splits the region into partitions so that each partition can be scanned concurrently.
|
||||
/// You can use this trait to implement an [ExecutionPlan](datafusion_physical_plan::ExecutionPlan).
|
||||
pub trait RegionScanner: Debug + DisplayAs + Send + Sync {
|
||||
/// Returns the properties of the scanner.
|
||||
fn properties(&self) -> &ScannerProperties;
|
||||
|
||||
/// Returns the schema of the record batches.
|
||||
fn schema(&self) -> SchemaRef;
|
||||
|
||||
/// Scans the partition and returns a stream of record batches.
|
||||
fn scan_partition(&self, partition: usize) -> Result<SendableRecordBatchStream, BoxedError>;
|
||||
}
|
||||
|
||||
pub type RegionScannerRef = Arc<dyn RegionScanner>;
|
||||
|
||||
#[async_trait]
|
||||
pub trait RegionEngine: Send + Sync {
|
||||
/// Name of this engine
|
||||
@@ -132,12 +187,12 @@ pub trait RegionEngine: Send + Sync {
|
||||
request: RegionRequest,
|
||||
) -> Result<RegionResponse, BoxedError>;
|
||||
|
||||
/// Handles substrait query and return a stream of record batches
|
||||
/// Handles query and return a scanner that can be used to scan the region concurrently.
|
||||
async fn handle_query(
|
||||
&self,
|
||||
region_id: RegionId,
|
||||
request: ScanRequest,
|
||||
) -> Result<SendableRecordBatchStream, BoxedError>;
|
||||
) -> Result<RegionScannerRef, BoxedError>;
|
||||
|
||||
/// Retrieves region's metadata.
|
||||
async fn get_metadata(&self, region_id: RegionId) -> Result<RegionMetadataRef, BoxedError>;
|
||||
@@ -172,3 +227,52 @@ pub trait RegionEngine: Send + Sync {
|
||||
}
|
||||
|
||||
pub type RegionEngineRef = Arc<dyn RegionEngine>;
|
||||
|
||||
/// A [RegionScanner] that only scans a single partition.
|
||||
pub struct SinglePartitionScanner {
|
||||
stream: Mutex<Option<SendableRecordBatchStream>>,
|
||||
schema: SchemaRef,
|
||||
properties: ScannerProperties,
|
||||
}
|
||||
|
||||
impl SinglePartitionScanner {
|
||||
/// Creates a new [SinglePartitionScanner] with the given stream.
|
||||
pub fn new(stream: SendableRecordBatchStream) -> Self {
|
||||
let schema = stream.schema();
|
||||
Self {
|
||||
stream: Mutex::new(Some(stream)),
|
||||
schema,
|
||||
properties: ScannerProperties::new(ScannerPartitioning::Unknown(1)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for SinglePartitionScanner {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "SinglePartitionScanner: <SendableRecordBatchStream>")
|
||||
}
|
||||
}
|
||||
|
||||
impl RegionScanner for SinglePartitionScanner {
|
||||
fn properties(&self) -> &ScannerProperties {
|
||||
&self.properties
|
||||
}
|
||||
|
||||
fn schema(&self) -> SchemaRef {
|
||||
self.schema.clone()
|
||||
}
|
||||
|
||||
fn scan_partition(&self, _partition: usize) -> Result<SendableRecordBatchStream, BoxedError> {
|
||||
let mut stream = self.stream.lock().unwrap();
|
||||
stream
|
||||
.take()
|
||||
.context(ExecuteRepeatedlySnafu)
|
||||
.map_err(BoxedError::new)
|
||||
}
|
||||
}
|
||||
|
||||
impl DisplayAs for SinglePartitionScanner {
|
||||
fn fmt_as(&self, _t: DisplayFormatType, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,9 +26,10 @@ use datafusion_expr::expr::Expr as DfExpr;
|
||||
use datafusion_expr::TableProviderFilterPushDown as DfTableProviderFilterPushDown;
|
||||
use datafusion_physical_expr::expressions::Column;
|
||||
use datafusion_physical_expr::PhysicalSortExpr;
|
||||
use store_api::region_engine::SinglePartitionScanner;
|
||||
use store_api::storage::ScanRequest;
|
||||
|
||||
use crate::table::scan::StreamScanAdapter;
|
||||
use crate::table::scan::RegionScanExec;
|
||||
use crate::table::{TableRef, TableType};
|
||||
|
||||
/// Adapt greptime's [TableRef] to DataFusion's [TableProvider].
|
||||
@@ -110,11 +111,12 @@ impl TableProvider for DfTableProviderAdapter {
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
|
||||
let mut stream_adapter = StreamScanAdapter::new(stream);
|
||||
let scanner = Arc::new(SinglePartitionScanner::new(stream));
|
||||
let mut plan = RegionScanExec::new(scanner);
|
||||
if let Some(sort_expr) = sort_expr {
|
||||
stream_adapter = stream_adapter.with_output_ordering(sort_expr);
|
||||
plan = plan.with_output_ordering(sort_expr);
|
||||
}
|
||||
Ok(Arc::new(stream_adapter))
|
||||
Ok(Arc::new(plan))
|
||||
}
|
||||
|
||||
fn supports_filters_pushdown(
|
||||
|
||||
@@ -13,12 +13,10 @@
|
||||
// limitations under the License.
|
||||
|
||||
use std::any::Any;
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::pin::Pin;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::Arc;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use common_query::error::ExecuteRepeatedlySnafu;
|
||||
use common_recordbatch::{DfRecordBatch, DfSendableRecordBatchStream, SendableRecordBatchStream};
|
||||
use common_telemetry::tracing::Span;
|
||||
use common_telemetry::tracing_context::TracingContext;
|
||||
@@ -32,59 +30,54 @@ use datafusion::physical_plan::{
|
||||
use datafusion_common::DataFusionError;
|
||||
use datafusion_physical_expr::{EquivalenceProperties, Partitioning, PhysicalSortExpr};
|
||||
use datatypes::arrow::datatypes::SchemaRef as ArrowSchemaRef;
|
||||
use datatypes::schema::SchemaRef;
|
||||
use futures::{Stream, StreamExt};
|
||||
use snafu::OptionExt;
|
||||
use store_api::region_engine::RegionScannerRef;
|
||||
|
||||
use crate::table::metrics::MemoryUsageMetrics;
|
||||
|
||||
/// Adapt greptime's [SendableRecordBatchStream] to [ExecutionPlan].
|
||||
pub struct StreamScanAdapter {
|
||||
stream: Mutex<Option<SendableRecordBatchStream>>,
|
||||
schema: SchemaRef,
|
||||
/// A plan to read multiple partitions from a region of a table.
|
||||
#[derive(Debug)]
|
||||
pub struct RegionScanExec {
|
||||
scanner: RegionScannerRef,
|
||||
arrow_schema: ArrowSchemaRef,
|
||||
/// The expected output ordering for the plan.
|
||||
output_ordering: Option<Vec<PhysicalSortExpr>>,
|
||||
metric: ExecutionPlanMetricsSet,
|
||||
properties: PlanProperties,
|
||||
}
|
||||
|
||||
impl Debug for StreamScanAdapter {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("StreamScanAdapter")
|
||||
.field("stream", &"<SendableRecordBatchStream>")
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl StreamScanAdapter {
|
||||
pub fn new(stream: SendableRecordBatchStream) -> Self {
|
||||
let schema = stream.schema();
|
||||
impl RegionScanExec {
|
||||
pub fn new(scanner: RegionScannerRef) -> Self {
|
||||
let arrow_schema = scanner.schema().arrow_schema().clone();
|
||||
let scanner_props = scanner.properties();
|
||||
let properties = PlanProperties::new(
|
||||
EquivalenceProperties::new(schema.arrow_schema().clone()),
|
||||
Partitioning::UnknownPartitioning(1),
|
||||
EquivalenceProperties::new(arrow_schema.clone()),
|
||||
Partitioning::UnknownPartitioning(scanner_props.partitioning().num_partitions()),
|
||||
ExecutionMode::Bounded,
|
||||
);
|
||||
Self {
|
||||
stream: Mutex::new(Some(stream)),
|
||||
schema,
|
||||
scanner,
|
||||
arrow_schema,
|
||||
output_ordering: None,
|
||||
metric: ExecutionPlanMetricsSet::new(),
|
||||
properties,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the expected output ordering for the plan.
|
||||
pub fn with_output_ordering(mut self, output_ordering: Vec<PhysicalSortExpr>) -> Self {
|
||||
self.output_ordering = Some(output_ordering);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl ExecutionPlan for StreamScanAdapter {
|
||||
impl ExecutionPlan for RegionScanExec {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn schema(&self) -> ArrowSchemaRef {
|
||||
self.schema.arrow_schema().clone()
|
||||
self.arrow_schema.clone()
|
||||
}
|
||||
|
||||
fn properties(&self) -> &PlanProperties {
|
||||
@@ -98,7 +91,7 @@ impl ExecutionPlan for StreamScanAdapter {
|
||||
fn with_new_children(
|
||||
self: Arc<Self>,
|
||||
_children: Vec<Arc<dyn ExecutionPlan>>,
|
||||
) -> DfResult<Arc<dyn ExecutionPlan>> {
|
||||
) -> datafusion_common::Result<Arc<dyn ExecutionPlan>> {
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
@@ -106,12 +99,15 @@ impl ExecutionPlan for StreamScanAdapter {
|
||||
&self,
|
||||
partition: usize,
|
||||
context: Arc<TaskContext>,
|
||||
) -> DfResult<DfSendableRecordBatchStream> {
|
||||
) -> datafusion_common::Result<DfSendableRecordBatchStream> {
|
||||
let tracing_context = TracingContext::from_json(context.session_id().as_str());
|
||||
let span = tracing_context.attach(common_telemetry::tracing::info_span!("stream_adapter"));
|
||||
let span =
|
||||
tracing_context.attach(common_telemetry::tracing::info_span!("read_from_region"));
|
||||
|
||||
let mut stream = self.stream.lock().unwrap();
|
||||
let stream = stream.take().context(ExecuteRepeatedlySnafu)?;
|
||||
let stream = self
|
||||
.scanner
|
||||
.scan_partition(partition)
|
||||
.map_err(|e| DataFusionError::External(Box::new(e)))?;
|
||||
let mem_usage_metrics = MemoryUsageMetrics::new(&self.metric, partition);
|
||||
Ok(Box::pin(StreamWithMetricWrapper {
|
||||
stream,
|
||||
@@ -125,9 +121,10 @@ impl ExecutionPlan for StreamScanAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
impl DisplayAs for StreamScanAdapter {
|
||||
fn fmt_as(&self, _t: DisplayFormatType, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
impl DisplayAs for RegionScanExec {
|
||||
fn fmt_as(&self, _t: DisplayFormatType, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
// The scanner contains all information needed to display the plan.
|
||||
write!(f, "{:?}", self.scanner)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,12 +174,15 @@ impl DfRecordBatchStream for StreamWithMetricWrapper {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::sync::Arc;
|
||||
|
||||
use common_recordbatch::{RecordBatch, RecordBatches};
|
||||
use datafusion::prelude::SessionContext;
|
||||
use datatypes::data_type::ConcreteDataType;
|
||||
use datatypes::schema::{ColumnSchema, Schema};
|
||||
use datatypes::schema::{ColumnSchema, Schema, SchemaRef};
|
||||
use datatypes::vectors::Int32Vector;
|
||||
use futures::TryStreamExt;
|
||||
use store_api::region_engine::SinglePartitionScanner;
|
||||
|
||||
use super::*;
|
||||
|
||||
@@ -210,9 +210,10 @@ mod test {
|
||||
RecordBatches::try_new(schema.clone(), vec![batch1.clone(), batch2.clone()]).unwrap();
|
||||
let stream = recordbatches.as_stream();
|
||||
|
||||
let scan = StreamScanAdapter::new(stream);
|
||||
let scanner = Arc::new(SinglePartitionScanner::new(stream));
|
||||
let plan = RegionScanExec::new(scanner);
|
||||
let actual: SchemaRef = Arc::new(
|
||||
scan.properties
|
||||
plan.properties
|
||||
.eq_properties
|
||||
.schema()
|
||||
.clone()
|
||||
@@ -221,12 +222,12 @@ mod test {
|
||||
);
|
||||
assert_eq!(actual, schema);
|
||||
|
||||
let stream = scan.execute(0, ctx.task_ctx()).unwrap();
|
||||
let stream = plan.execute(0, ctx.task_ctx()).unwrap();
|
||||
let recordbatches = stream.try_collect::<Vec<_>>().await.unwrap();
|
||||
assert_eq!(batch1.df_record_batch(), &recordbatches[0]);
|
||||
assert_eq!(batch2.df_record_batch(), &recordbatches[1]);
|
||||
|
||||
let result = scan.execute(0, ctx.task_ctx());
|
||||
let result = plan.execute(0, ctx.task_ctx());
|
||||
assert!(result.is_err());
|
||||
match result {
|
||||
Err(e) => assert!(e
|
||||
|
||||
@@ -35,7 +35,7 @@ explain analyze SELECT count(*) FROM system_metrics;
|
||||
|_|_|_CoalescePartitionsExec REDACTED
|
||||
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[COUNT(greptime.public.system_REDACTED
|
||||
|_|_|_RepartitionExec: partitioning=REDACTED
|
||||
|_|_|_StreamScanAdapter { stream: "<SendableRecordBatchStream>" } REDACTED
|
||||
|_|_|_SinglePartitionScanner: <SendableRecordBatchStream> REDACTED
|
||||
|_|_|_|
|
||||
|_|_| Total rows: 1_|
|
||||
+-+-+-+
|
||||
|
||||
@@ -1,61 +1,61 @@
|
||||
-- SQLNESS REPLACE (peers.*) REDACTED
|
||||
explain select * from numbers;
|
||||
|
||||
+---------------+-------------------------------------------------------------+
|
||||
| plan_type | plan |
|
||||
+---------------+-------------------------------------------------------------+
|
||||
| logical_plan | MergeScan [is_placeholder=false] |
|
||||
| physical_plan | StreamScanAdapter { stream: "<SendableRecordBatchStream>" } |
|
||||
| | |
|
||||
+---------------+-------------------------------------------------------------+
|
||||
+---------------+-----------------------------------------------------+
|
||||
| plan_type | plan |
|
||||
+---------------+-----------------------------------------------------+
|
||||
| logical_plan | MergeScan [is_placeholder=false] |
|
||||
| physical_plan | SinglePartitionScanner: <SendableRecordBatchStream> |
|
||||
| | |
|
||||
+---------------+-----------------------------------------------------+
|
||||
|
||||
-- SQLNESS REPLACE (peers.*) REDACTED
|
||||
explain select * from numbers order by number desc;
|
||||
|
||||
+---------------+---------------------------------------------------------------+
|
||||
| plan_type | plan |
|
||||
+---------------+---------------------------------------------------------------+
|
||||
| logical_plan | MergeScan [is_placeholder=false] |
|
||||
| physical_plan | SortExec: expr=[number@0 DESC] |
|
||||
| | StreamScanAdapter { stream: "<SendableRecordBatchStream>" } |
|
||||
| | |
|
||||
+---------------+---------------------------------------------------------------+
|
||||
+---------------+-------------------------------------------------------+
|
||||
| plan_type | plan |
|
||||
+---------------+-------------------------------------------------------+
|
||||
| logical_plan | MergeScan [is_placeholder=false] |
|
||||
| physical_plan | SortExec: expr=[number@0 DESC] |
|
||||
| | SinglePartitionScanner: <SendableRecordBatchStream> |
|
||||
| | |
|
||||
+---------------+-------------------------------------------------------+
|
||||
|
||||
-- SQLNESS REPLACE (peers.*) REDACTED
|
||||
explain select * from numbers order by number asc;
|
||||
|
||||
+---------------+---------------------------------------------------------------+
|
||||
| plan_type | plan |
|
||||
+---------------+---------------------------------------------------------------+
|
||||
| logical_plan | MergeScan [is_placeholder=false] |
|
||||
| physical_plan | SortExec: expr=[number@0 ASC NULLS LAST] |
|
||||
| | StreamScanAdapter { stream: "<SendableRecordBatchStream>" } |
|
||||
| | |
|
||||
+---------------+---------------------------------------------------------------+
|
||||
+---------------+-------------------------------------------------------+
|
||||
| plan_type | plan |
|
||||
+---------------+-------------------------------------------------------+
|
||||
| logical_plan | MergeScan [is_placeholder=false] |
|
||||
| physical_plan | SortExec: expr=[number@0 ASC NULLS LAST] |
|
||||
| | SinglePartitionScanner: <SendableRecordBatchStream> |
|
||||
| | |
|
||||
+---------------+-------------------------------------------------------+
|
||||
|
||||
-- SQLNESS REPLACE (peers.*) REDACTED
|
||||
explain select * from numbers order by number desc limit 10;
|
||||
|
||||
+---------------+-----------------------------------------------------------------+
|
||||
| plan_type | plan |
|
||||
+---------------+-----------------------------------------------------------------+
|
||||
| logical_plan | MergeScan [is_placeholder=false] |
|
||||
| physical_plan | GlobalLimitExec: skip=0, fetch=10 |
|
||||
| | SortExec: TopK(fetch=10), expr=[number@0 DESC] |
|
||||
| | StreamScanAdapter { stream: "<SendableRecordBatchStream>" } |
|
||||
| | |
|
||||
+---------------+-----------------------------------------------------------------+
|
||||
+---------------+---------------------------------------------------------+
|
||||
| plan_type | plan |
|
||||
+---------------+---------------------------------------------------------+
|
||||
| logical_plan | MergeScan [is_placeholder=false] |
|
||||
| physical_plan | GlobalLimitExec: skip=0, fetch=10 |
|
||||
| | SortExec: TopK(fetch=10), expr=[number@0 DESC] |
|
||||
| | SinglePartitionScanner: <SendableRecordBatchStream> |
|
||||
| | |
|
||||
+---------------+---------------------------------------------------------+
|
||||
|
||||
-- SQLNESS REPLACE (peers.*) REDACTED
|
||||
explain select * from numbers order by number asc limit 10;
|
||||
|
||||
+---------------+-----------------------------------------------------------------+
|
||||
| plan_type | plan |
|
||||
+---------------+-----------------------------------------------------------------+
|
||||
| logical_plan | MergeScan [is_placeholder=false] |
|
||||
| physical_plan | GlobalLimitExec: skip=0, fetch=10 |
|
||||
| | SortExec: TopK(fetch=10), expr=[number@0 ASC NULLS LAST] |
|
||||
| | StreamScanAdapter { stream: "<SendableRecordBatchStream>" } |
|
||||
| | |
|
||||
+---------------+-----------------------------------------------------------------+
|
||||
+---------------+------------------------------------------------------------+
|
||||
| plan_type | plan |
|
||||
+---------------+------------------------------------------------------------+
|
||||
| logical_plan | MergeScan [is_placeholder=false] |
|
||||
| physical_plan | GlobalLimitExec: skip=0, fetch=10 |
|
||||
| | SortExec: TopK(fetch=10), expr=[number@0 ASC NULLS LAST] |
|
||||
| | SinglePartitionScanner: <SendableRecordBatchStream> |
|
||||
| | |
|
||||
+---------------+------------------------------------------------------------+
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ EXPLAIN ANALYZE SELECT ts, host, min(val) RANGE '5s' FROM host ALIGN '5s';
|
||||
| 0_| 0_|_RangeSelectExec: range_expr=[MIN(host.val) RANGE 5s], align=5000ms, align_to=0ms, align_by=[host@1], time_index=ts REDACTED
|
||||
|_|_|_MergeScanExec: REDACTED
|
||||
|_|_|_|
|
||||
| 1_| 0_|_StreamScanAdapter { stream: "<SendableRecordBatchStream>" } REDACTED
|
||||
| 1_| 0_|_SinglePartitionScanner: <SendableRecordBatchStream> REDACTED
|
||||
|_|_|_|
|
||||
|_|_| Total rows: 10_|
|
||||
+-+-+-+
|
||||
|
||||
@@ -30,7 +30,7 @@ TQL ANALYZE (0, 10, '5s') test;
|
||||
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|
||||
|_|_|_FilterExec: j@1 >= -300000 AND j@1 <= 310000 REDACTED
|
||||
|_|_|_RepartitionExec: partitioning=REDACTED
|
||||
|_|_|_StreamScanAdapter { stream: "<SendableRecordBatchStream>" } REDACTED
|
||||
|_|_|_SinglePartitionScanner: <SendableRecordBatchStream> REDACTED
|
||||
|_|_|_|
|
||||
|_|_| Total rows: 4_|
|
||||
+-+-+-+
|
||||
@@ -59,7 +59,7 @@ TQL ANALYZE (0, 10, '1s', '2s') test;
|
||||
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|
||||
|_|_|_FilterExec: j@1 >= -2000 AND j@1 <= 12000 REDACTED
|
||||
|_|_|_RepartitionExec: partitioning=REDACTED
|
||||
|_|_|_StreamScanAdapter { stream: "<SendableRecordBatchStream>" } REDACTED
|
||||
|_|_|_SinglePartitionScanner: <SendableRecordBatchStream> REDACTED
|
||||
|_|_|_|
|
||||
|_|_| Total rows: 4_|
|
||||
+-+-+-+
|
||||
@@ -87,7 +87,7 @@ TQL ANALYZE ('1970-01-01T00:00:00'::timestamp, '1970-01-01T00:00:00'::timestamp
|
||||
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|
||||
|_|_|_FilterExec: j@1 >= -300000 AND j@1 <= 310000 REDACTED
|
||||
|_|_|_RepartitionExec: partitioning=REDACTED
|
||||
|_|_|_StreamScanAdapter { stream: "<SendableRecordBatchStream>" } REDACTED
|
||||
|_|_|_SinglePartitionScanner: <SendableRecordBatchStream> REDACTED
|
||||
|_|_|_|
|
||||
|_|_| Total rows: 4_|
|
||||
+-+-+-+
|
||||
@@ -117,7 +117,7 @@ TQL ANALYZE VERBOSE (0, 10, '5s') test;
|
||||
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|
||||
|_|_|_FilterExec: j@1 >= -300000 AND j@1 <= 310000 REDACTED
|
||||
|_|_|_RepartitionExec: partitioning=REDACTED
|
||||
|_|_|_StreamScanAdapter { stream: "<SendableRecordBatchStream>" } REDACTED
|
||||
|_|_|_SinglePartitionScanner: <SendableRecordBatchStream> REDACTED
|
||||
|_|_|_|
|
||||
|_|_| Total rows: 4_|
|
||||
+-+-+-+
|
||||
|
||||
@@ -1,56 +1,56 @@
|
||||
explain select * from numbers;
|
||||
|
||||
+---------------+-------------------------------------------------------------+
|
||||
| plan_type | plan |
|
||||
+---------------+-------------------------------------------------------------+
|
||||
| logical_plan | MergeScan [is_placeholder=false] |
|
||||
| physical_plan | StreamScanAdapter { stream: "<SendableRecordBatchStream>" } |
|
||||
| | |
|
||||
+---------------+-------------------------------------------------------------+
|
||||
+---------------+-----------------------------------------------------+
|
||||
| plan_type | plan |
|
||||
+---------------+-----------------------------------------------------+
|
||||
| logical_plan | MergeScan [is_placeholder=false] |
|
||||
| physical_plan | SinglePartitionScanner: <SendableRecordBatchStream> |
|
||||
| | |
|
||||
+---------------+-----------------------------------------------------+
|
||||
|
||||
explain select * from numbers order by number desc;
|
||||
|
||||
+---------------+---------------------------------------------------------------+
|
||||
| plan_type | plan |
|
||||
+---------------+---------------------------------------------------------------+
|
||||
| logical_plan | MergeScan [is_placeholder=false] |
|
||||
| physical_plan | SortExec: expr=[number@0 DESC] |
|
||||
| | StreamScanAdapter { stream: "<SendableRecordBatchStream>" } |
|
||||
| | |
|
||||
+---------------+---------------------------------------------------------------+
|
||||
+---------------+-------------------------------------------------------+
|
||||
| plan_type | plan |
|
||||
+---------------+-------------------------------------------------------+
|
||||
| logical_plan | MergeScan [is_placeholder=false] |
|
||||
| physical_plan | SortExec: expr=[number@0 DESC] |
|
||||
| | SinglePartitionScanner: <SendableRecordBatchStream> |
|
||||
| | |
|
||||
+---------------+-------------------------------------------------------+
|
||||
|
||||
explain select * from numbers order by number asc;
|
||||
|
||||
+---------------+---------------------------------------------------------------+
|
||||
| plan_type | plan |
|
||||
+---------------+---------------------------------------------------------------+
|
||||
| logical_plan | MergeScan [is_placeholder=false] |
|
||||
| physical_plan | SortExec: expr=[number@0 ASC NULLS LAST] |
|
||||
| | StreamScanAdapter { stream: "<SendableRecordBatchStream>" } |
|
||||
| | |
|
||||
+---------------+---------------------------------------------------------------+
|
||||
+---------------+-------------------------------------------------------+
|
||||
| plan_type | plan |
|
||||
+---------------+-------------------------------------------------------+
|
||||
| logical_plan | MergeScan [is_placeholder=false] |
|
||||
| physical_plan | SortExec: expr=[number@0 ASC NULLS LAST] |
|
||||
| | SinglePartitionScanner: <SendableRecordBatchStream> |
|
||||
| | |
|
||||
+---------------+-------------------------------------------------------+
|
||||
|
||||
explain select * from numbers order by number desc limit 10;
|
||||
|
||||
+---------------+-----------------------------------------------------------------+
|
||||
| plan_type | plan |
|
||||
+---------------+-----------------------------------------------------------------+
|
||||
| logical_plan | MergeScan [is_placeholder=false] |
|
||||
| physical_plan | GlobalLimitExec: skip=0, fetch=10 |
|
||||
| | SortExec: TopK(fetch=10), expr=[number@0 DESC] |
|
||||
| | StreamScanAdapter { stream: "<SendableRecordBatchStream>" } |
|
||||
| | |
|
||||
+---------------+-----------------------------------------------------------------+
|
||||
+---------------+---------------------------------------------------------+
|
||||
| plan_type | plan |
|
||||
+---------------+---------------------------------------------------------+
|
||||
| logical_plan | MergeScan [is_placeholder=false] |
|
||||
| physical_plan | GlobalLimitExec: skip=0, fetch=10 |
|
||||
| | SortExec: TopK(fetch=10), expr=[number@0 DESC] |
|
||||
| | SinglePartitionScanner: <SendableRecordBatchStream> |
|
||||
| | |
|
||||
+---------------+---------------------------------------------------------+
|
||||
|
||||
explain select * from numbers order by number asc limit 10;
|
||||
|
||||
+---------------+-----------------------------------------------------------------+
|
||||
| plan_type | plan |
|
||||
+---------------+-----------------------------------------------------------------+
|
||||
| logical_plan | MergeScan [is_placeholder=false] |
|
||||
| physical_plan | GlobalLimitExec: skip=0, fetch=10 |
|
||||
| | SortExec: TopK(fetch=10), expr=[number@0 ASC NULLS LAST] |
|
||||
| | StreamScanAdapter { stream: "<SendableRecordBatchStream>" } |
|
||||
| | |
|
||||
+---------------+-----------------------------------------------------------------+
|
||||
+---------------+------------------------------------------------------------+
|
||||
| plan_type | plan |
|
||||
+---------------+------------------------------------------------------------+
|
||||
| logical_plan | MergeScan [is_placeholder=false] |
|
||||
| physical_plan | GlobalLimitExec: skip=0, fetch=10 |
|
||||
| | SortExec: TopK(fetch=10), expr=[number@0 ASC NULLS LAST] |
|
||||
| | SinglePartitionScanner: <SendableRecordBatchStream> |
|
||||
| | |
|
||||
+---------------+------------------------------------------------------------+
|
||||
|
||||
|
||||
Reference in New Issue
Block a user