@@ -69,6 +69,8 @@ use databend_common_meta_app::schema::ListDroppedTableResp;
69
69
use databend_common_meta_app:: schema:: ListTableReq ;
70
70
use databend_common_meta_app:: schema:: RenameTableReply ;
71
71
use databend_common_meta_app:: schema:: RenameTableReq ;
72
+ use databend_common_meta_app:: schema:: SwapTableReply ;
73
+ use databend_common_meta_app:: schema:: SwapTableReq ;
72
74
use databend_common_meta_app:: schema:: TableCopiedFileNameIdent ;
73
75
use databend_common_meta_app:: schema:: TableId ;
74
76
use databend_common_meta_app:: schema:: TableIdHistoryIdent ;
@@ -712,6 +714,192 @@ where
712
714
}
713
715
}
714
716
717
+ #[ logcall:: logcall]
718
+ #[ fastrace:: trace]
719
+ async fn swap_table ( & self , req : SwapTableReq ) -> Result < SwapTableReply , KVAppError > {
720
+ debug ! ( req : ? =( & req) ; "SchemaApi: {}" , func_name!( ) ) ;
721
+
722
+ let mut trials = txn_backoff ( None , func_name ! ( ) ) ;
723
+ loop {
724
+ trials. next ( ) . unwrap ( ) ?. await ;
725
+
726
+ // Get databases
727
+ let tenant_dbname_left = req. origin_table . db_name_ident ( ) ;
728
+
729
+ let ( seq_db_id_left, db_meta_left) =
730
+ get_db_or_err ( self , & tenant_dbname_left, "swap_table: tenant_dbname_left" ) . await ?;
731
+
732
+ let dbid_tbname_left = DBIdTableName {
733
+ db_id : * seq_db_id_left. data ,
734
+ table_name : req. origin_table . table_name . clone ( ) ,
735
+ } ;
736
+
737
+ let ( tb_id_seq_left, table_id_left) = get_u64_value ( self , & dbid_tbname_left) . await ?;
738
+ if req. if_exists && tb_id_seq_left == 0 {
739
+ return Ok ( SwapTableReply { } ) ;
740
+ }
741
+ assert_table_exist (
742
+ tb_id_seq_left,
743
+ & req. origin_table ,
744
+ "swap_table: origin_table" ,
745
+ ) ?;
746
+
747
+ let dbid_tbname_right = DBIdTableName {
748
+ db_id : * seq_db_id_left. data ,
749
+ table_name : req. target_table_name . clone ( ) ,
750
+ } ;
751
+
752
+ let ( tb_id_seq_right, table_id_right) = get_u64_value ( self , & dbid_tbname_right) . await ?;
753
+ if req. if_exists && tb_id_seq_right == 0 {
754
+ return Ok ( SwapTableReply { } ) ;
755
+ }
756
+ assert_table_exist (
757
+ tb_id_seq_right,
758
+ & TableNameIdent {
759
+ tenant : req. origin_table . tenant . clone ( ) ,
760
+ db_name : req. origin_table . db_name . clone ( ) ,
761
+ table_name : req. target_table_name . clone ( ) ,
762
+ } ,
763
+ "swap_table: target_table" ,
764
+ ) ?;
765
+
766
+ // Get table id lists
767
+ let dbid_tbname_idlist_left = TableIdHistoryIdent {
768
+ database_id : * seq_db_id_left. data ,
769
+ table_name : req. origin_table . table_name . clone ( ) ,
770
+ } ;
771
+ let dbid_tbname_idlist_right = TableIdHistoryIdent {
772
+ database_id : * seq_db_id_left. data ,
773
+ table_name : req. target_table_name . clone ( ) ,
774
+ } ;
775
+
776
+ let seq_table_history_left = self . get_pb ( & dbid_tbname_idlist_left) . await ?;
777
+ let seq_table_history_right = self . get_pb ( & dbid_tbname_idlist_right) . await ?;
778
+
779
+ let tb_id_list_seq_left = seq_table_history_left. seq ( ) ;
780
+ let tb_id_list_seq_right = seq_table_history_right. seq ( ) ;
781
+
782
+ let mut tb_id_list_left = seq_table_history_left
783
+ . into_value ( )
784
+ . unwrap_or_else ( || TableIdList :: new_with_ids ( [ table_id_left] ) ) ;
785
+ let mut tb_id_list_right = seq_table_history_right
786
+ . into_value ( )
787
+ . unwrap_or_else ( || TableIdList :: new_with_ids ( [ table_id_right] ) ) ;
788
+
789
+ // Validate table IDs in history lists
790
+ {
791
+ let last_left = tb_id_list_left. last ( ) . copied ( ) ;
792
+ if Some ( table_id_left) != last_left {
793
+ let err_message = format ! (
794
+ "swap_table {:?} but last table id conflict, id list last: {:?}, current: {}" ,
795
+ req. origin_table, last_left, table_id_left
796
+ ) ;
797
+ error ! ( "{}" , err_message) ;
798
+ return Err ( KVAppError :: AppError ( AppError :: UnknownTable (
799
+ UnknownTable :: new ( & req. origin_table . table_name , err_message) ,
800
+ ) ) ) ;
801
+ }
802
+
803
+ let last_right = tb_id_list_right. last ( ) . copied ( ) ;
804
+ if Some ( table_id_right) != last_right {
805
+ let err_message = format ! (
806
+ "swap_table {:?} but last table id conflict, id list last: {:?}, current: {}" ,
807
+ req. target_table_name, last_right, table_id_right
808
+ ) ;
809
+ error ! ( "{}" , err_message) ;
810
+ return Err ( KVAppError :: AppError ( AppError :: UnknownTable (
811
+ UnknownTable :: new ( & req. target_table_name , err_message) ,
812
+ ) ) ) ;
813
+ }
814
+ }
815
+
816
+ // Get table id to name mappings
817
+ let table_id_to_name_key_left = TableIdToName {
818
+ table_id : table_id_left,
819
+ } ;
820
+ let table_id_to_name_key_right = TableIdToName {
821
+ table_id : table_id_right,
822
+ } ;
823
+ let table_id_to_name_seq_left = self . get_seq ( & table_id_to_name_key_left) . await ?;
824
+ let table_id_to_name_seq_right = self . get_seq ( & table_id_to_name_key_right) . await ?;
825
+
826
+ // Prepare new mappings after swap
827
+ let db_id_table_name_left = DBIdTableName {
828
+ db_id : * seq_db_id_left. data ,
829
+ table_name : req. origin_table . table_name . clone ( ) ,
830
+ } ;
831
+ let db_id_table_name_right = DBIdTableName {
832
+ db_id : * seq_db_id_left. data ,
833
+ table_name : req. target_table_name . clone ( ) ,
834
+ } ;
835
+
836
+ {
837
+ // Update history lists: remove current table IDs
838
+ tb_id_list_left. pop ( ) ;
839
+ tb_id_list_right. pop ( ) ;
840
+ // Add swapped table IDs
841
+ tb_id_list_left. append ( table_id_right) ;
842
+ tb_id_list_right. append ( table_id_left) ;
843
+
844
+ let txn = TxnRequest :: new (
845
+ vec ! [
846
+ // Ensure databases haven't changed
847
+ txn_cond_seq( & seq_db_id_left. data, Eq , db_meta_left. seq) ,
848
+ // Ensure table name->table_id mappings haven't changed
849
+ txn_cond_seq( & dbid_tbname_left, Eq , tb_id_seq_left) ,
850
+ txn_cond_seq( & dbid_tbname_right, Eq , tb_id_seq_right) ,
851
+ // Ensure table history lists haven't changed
852
+ txn_cond_seq( & dbid_tbname_idlist_left, Eq , tb_id_list_seq_left) ,
853
+ txn_cond_seq( & dbid_tbname_idlist_right, Eq , tb_id_list_seq_right) ,
854
+ // Ensure table_id->name mappings haven't changed
855
+ txn_cond_seq( & table_id_to_name_key_left, Eq , table_id_to_name_seq_left) ,
856
+ txn_cond_seq( & table_id_to_name_key_right, Eq , table_id_to_name_seq_right) ,
857
+ ] ,
858
+ vec ! [
859
+ // Swap table name->table_id mappings
860
+ txn_op_put( & dbid_tbname_left, serialize_u64( table_id_right) ?) , /* origin_table_name -> target_table_id */
861
+ txn_op_put( & dbid_tbname_right, serialize_u64( table_id_left) ?) , /* target_table_name -> origin_table_id */
862
+ // Update database metadata sequences
863
+ txn_op_put( & seq_db_id_left. data, serialize_struct( & * db_meta_left) ?) ,
864
+ // Update table history lists
865
+ txn_op_put(
866
+ & dbid_tbname_idlist_left,
867
+ serialize_struct( & tb_id_list_left) ?,
868
+ ) ,
869
+ txn_op_put(
870
+ & dbid_tbname_idlist_right,
871
+ serialize_struct( & tb_id_list_right) ?,
872
+ ) ,
873
+ // Update table_id->name mappings
874
+ txn_op_put(
875
+ & table_id_to_name_key_left,
876
+ serialize_struct( & db_id_table_name_right) ?,
877
+ ) , // origin_table_id -> target_table_name
878
+ txn_op_put(
879
+ & table_id_to_name_key_right,
880
+ serialize_struct( & db_id_table_name_left) ?,
881
+ ) , // target_table_id -> origin_table_name
882
+ ] ,
883
+ ) ;
884
+
885
+ let ( succ, _responses) = send_txn ( self , txn) . await ?;
886
+
887
+ debug ! (
888
+ origin_table : ? =( & req. origin_table) ,
889
+ target_table_name : ? =( & req. target_table_name) ,
890
+ table_id_left : ? =( & table_id_left) ,
891
+ table_id_right : ? =( & table_id_right) ,
892
+ succ = succ;
893
+ "swap_table"
894
+ ) ;
895
+
896
+ if succ {
897
+ return Ok ( SwapTableReply { } ) ;
898
+ }
899
+ }
900
+ }
901
+ }
902
+
715
903
#[ logcall:: logcall]
716
904
#[ fastrace:: trace]
717
905
async fn truncate_table (
0 commit comments