@@ -10,7 +10,7 @@ use std::{
10
10
11
11
use bytes:: Bytes ;
12
12
use ceresdbproto:: storage:: {
13
- storage_service_client:: StorageServiceClient , value, RouteRequest , WriteRequest ,
13
+ storage_service_client:: StorageServiceClient , value, RouteRequest , Value , WriteRequest ,
14
14
WriteResponse as WriteResponsePB , WriteSeriesEntry , WriteTableRequest ,
15
15
} ;
16
16
use cluster:: config:: SchemaConfig ;
@@ -34,7 +34,7 @@ use query_engine::executor::Executor as QueryExecutor;
34
34
use query_frontend:: {
35
35
frontend:: { Context as FrontendContext , Frontend } ,
36
36
plan:: { AlterTableOperation , AlterTablePlan , InsertPlan , Plan } ,
37
- planner:: build_schema_from_write_table_request ,
37
+ planner:: { build_column_schema , try_get_data_type_from_value } ,
38
38
provider:: CatalogMetaProvider ,
39
39
} ;
40
40
use router:: endpoint:: Endpoint ;
@@ -43,7 +43,7 @@ use table_engine::table::TableRef;
43
43
use tonic:: transport:: Channel ;
44
44
45
45
use crate :: {
46
- error:: { ErrNoCause , ErrWithCause , InternalNoCause , Result } ,
46
+ error:: { ErrNoCause , ErrWithCause , Internal , InternalNoCause , Result } ,
47
47
forward:: { ForwardResult , ForwarderRef } ,
48
48
Context , Proxy ,
49
49
} ;
@@ -320,7 +320,7 @@ impl<Q: QueryExecutor + 'static> Proxy<Q> {
320
320
. map ( |endpoint| ( router. table , endpoint. into ( ) ) )
321
321
} )
322
322
. filter ( |router| !self . forwarder . is_local_endpoint ( & router. 1 ) )
323
- . collect :: < HashMap < _ , _ > > ( ) ;
323
+ . collect :: < BTreeMap < _ , _ > > ( ) ;
324
324
325
325
// No table need to be forwarded.
326
326
if forwarded_table_routes. is_empty ( ) {
@@ -477,14 +477,6 @@ impl<Q: QueryExecutor + 'static> Proxy<Q> {
477
477
code : StatusCode :: BAD_REQUEST ,
478
478
} ) ?;
479
479
let schema = req_ctx. database ;
480
- let schema_config = self
481
- . schema_config_provider
482
- . schema_config ( & schema)
483
- . box_err ( )
484
- . with_context ( || ErrWithCause {
485
- code : StatusCode :: INTERNAL_SERVER_ERROR ,
486
- msg : format ! ( "Fail to fetch schema config, schema_name:{schema}" ) ,
487
- } ) ?;
488
480
489
481
debug ! (
490
482
"Local write begin, catalog:{catalog}, schema:{schema}, request_id:{request_id}, first_table:{:?}, num_tables:{}" ,
@@ -503,7 +495,7 @@ impl<Q: QueryExecutor + 'static> Proxy<Q> {
503
495
} ;
504
496
505
497
let plan_vec = self
506
- . write_request_to_insert_plan ( req. table_requests , schema_config , write_context)
498
+ . write_request_to_insert_plan ( req. table_requests , write_context)
507
499
. await ?;
508
500
509
501
let mut success = 0 ;
@@ -522,7 +514,6 @@ impl<Q: QueryExecutor + 'static> Proxy<Q> {
522
514
async fn write_request_to_insert_plan (
523
515
& self ,
524
516
table_requests : Vec < WriteTableRequest > ,
525
- schema_config : Option < & SchemaConfig > ,
526
517
write_context : WriteContext ,
527
518
) -> Result < Vec < InsertPlan > > {
528
519
let mut plan_vec = Vec :: with_capacity ( table_requests. len ( ) ) ;
@@ -534,7 +525,6 @@ impl<Q: QueryExecutor + 'static> Proxy<Q> {
534
525
deadline,
535
526
auto_create_table,
536
527
} = write_context;
537
- let schema_config = schema_config. cloned ( ) . unwrap_or_default ( ) ;
538
528
for write_table_req in table_requests {
539
529
let table_name = & write_table_req. table ;
540
530
self . maybe_open_partition_table_if_not_exist ( & catalog, & schema, table_name)
@@ -555,7 +545,7 @@ impl<Q: QueryExecutor + 'static> Proxy<Q> {
555
545
// * Currently, the decision to add columns is made at the request level, not at
556
546
// the row level, so the cost is relatively small.
557
547
let table_schema = table. schema ( ) ;
558
- let columns = find_new_columns ( & table_schema, & schema_config , & write_table_req) ?;
548
+ let columns = find_new_columns ( & table_schema, & write_table_req) ?;
559
549
if !columns. is_empty ( ) {
560
550
self . execute_add_columns_plan (
561
551
request_id,
@@ -668,32 +658,95 @@ impl<Q: QueryExecutor + 'static> Proxy<Q> {
668
658
669
659
fn find_new_columns (
670
660
schema : & Schema ,
671
- schema_config : & SchemaConfig ,
672
- write_req : & WriteTableRequest ,
661
+ write_table_req : & WriteTableRequest ,
673
662
) -> Result < Vec < ColumnSchema > > {
674
- let new_schema = build_schema_from_write_table_request ( schema_config, write_req)
663
+ let WriteTableRequest {
664
+ table,
665
+ field_names,
666
+ tag_names,
667
+ entries : write_entries,
668
+ } = write_table_req;
669
+
670
+ let mut columns: BTreeMap < _ , ColumnSchema > = BTreeMap :: new ( ) ;
671
+ for write_entry in write_entries {
672
+ // parse tags
673
+ for tag in & write_entry. tags {
674
+ let name_index = tag. name_index as usize ;
675
+ ensure ! (
676
+ name_index < tag_names. len( ) ,
677
+ InternalNoCause {
678
+ msg: format!(
679
+ "Tag {tag:?} is not found in tag_names:{tag_names:?}, table:{table}" ,
680
+ ) ,
681
+ }
682
+ ) ;
683
+
684
+ let tag_name = & tag_names[ name_index] ;
685
+
686
+ build_column ( & mut columns, schema, tag_name, & tag. value , true ) ?;
687
+ }
688
+
689
+ // parse fields
690
+ for field_group in & write_entry. field_groups {
691
+ for field in & field_group. fields {
692
+ let field_index = field. name_index as usize ;
693
+ ensure ! (
694
+ field_index < field_names. len( ) ,
695
+ InternalNoCause {
696
+ msg: format!(
697
+ "Field {field:?} is not found in field_names:{field_names:?}, table:{table}" ,
698
+ ) ,
699
+ }
700
+ ) ;
701
+ if ( field. name_index as usize ) < field_names. len ( ) {
702
+ let field_name = & field_names[ field. name_index as usize ] ;
703
+ build_column ( & mut columns, schema, field_name, & field. value , false ) ?;
704
+ }
705
+ }
706
+ }
707
+ }
708
+
709
+ Ok ( columns. into_iter ( ) . map ( |v| v. 1 ) . collect ( ) )
710
+ }
711
+
712
+ fn build_column < ' a > (
713
+ columns : & mut BTreeMap < & ' a str , ColumnSchema > ,
714
+ schema : & Schema ,
715
+ name : & ' a str ,
716
+ value : & Option < Value > ,
717
+ is_tag : bool ,
718
+ ) -> Result < ( ) > {
719
+ // Skip adding columns, the following cases:
720
+ // 1. Field already exists.
721
+ // 2. The new column has been added.
722
+ if schema. index_of ( name) . is_some ( ) || columns. get ( name) . is_some ( ) {
723
+ return Ok ( ( ) ) ;
724
+ }
725
+
726
+ let column_value = value
727
+ . as_ref ( )
728
+ . with_context ( || InternalNoCause {
729
+ msg : format ! ( "Field value is needed, field:{name}" ) ,
730
+ } ) ?
731
+ . value
732
+ . as_ref ( )
733
+ . with_context ( || InternalNoCause {
734
+ msg : format ! ( "Field value type is not supported, field:{name}" ) ,
735
+ } ) ?;
736
+
737
+ let data_type = try_get_data_type_from_value ( column_value)
675
738
. box_err ( )
676
- . context ( ErrWithCause {
677
- code : StatusCode :: INTERNAL_SERVER_ERROR ,
678
- msg : "Build schema from write table request failed" ,
739
+ . context ( Internal {
740
+ msg : "Failed to get data type" ,
679
741
} ) ?;
680
742
681
- let columns = new_schema. columns ( ) ;
682
- let old_columns = schema. columns ( ) ;
683
-
684
- // find new columns:
685
- // 1. timestamp column can't be a new column;
686
- // 2. column not in old schema is a new column.
687
- let new_columns = columns
688
- . iter ( )
689
- . enumerate ( )
690
- . filter ( |( idx, column) | {
691
- * idx != new_schema. timestamp_index ( )
692
- && !old_columns. iter ( ) . any ( |c| c. name == column. name )
693
- } )
694
- . map ( |( _, column) | column. clone ( ) )
695
- . collect ( ) ;
696
- Ok ( new_columns)
743
+ let column_schema = build_column_schema ( name, data_type, is_tag)
744
+ . box_err ( )
745
+ . context ( Internal {
746
+ msg : "Failed to build column schema" ,
747
+ } ) ?;
748
+ columns. insert ( name, column_schema) ;
749
+ Ok ( ( ) )
697
750
}
698
751
699
752
fn write_table_request_to_insert_plan (
@@ -802,7 +855,7 @@ fn write_entry_to_rows(
802
855
}
803
856
804
857
// Fill fields.
805
- let mut field_name_index: HashMap < String , usize > = HashMap :: new ( ) ;
858
+ let mut field_name_index: BTreeMap < String , usize > = BTreeMap :: new ( ) ;
806
859
for ( i, field_group) in write_series_entry. field_groups . into_iter ( ) . enumerate ( ) {
807
860
// timestamp
808
861
let timestamp_index_in_schema = schema. timestamp_index ( ) ;
0 commit comments