@@ -30,7 +30,8 @@ use crate::io::OutputFile;
30
30
use crate :: spec:: {
31
31
DataFile , DataFileFormat , FormatVersion , ManifestEntry , ManifestFile , ManifestListWriter ,
32
32
ManifestWriterBuilder , NullOrder , Operation , Snapshot , SnapshotReference , SnapshotRetention ,
33
- SortDirection , SortField , SortOrder , Struct , StructType , Summary , Transform , MAIN_BRANCH ,
33
+ SortDirection , SortField , SortOrder , Struct , StructType , Summary , TableMetadata , Transform ,
34
+ MAIN_BRANCH ,
34
35
} ;
35
36
use crate :: table:: Table ;
36
37
use crate :: TableUpdate :: UpgradeFormatVersion ;
@@ -40,7 +41,8 @@ const META_ROOT_PATH: &str = "metadata";
40
41
41
42
/// Table transaction.
42
43
pub struct Transaction < ' a > {
43
- table : & ' a Table ,
44
+ base_table : & ' a Table ,
45
+ current_metadata : TableMetadata ,
44
46
updates : Vec < TableUpdate > ,
45
47
requirements : Vec < TableRequirement > ,
46
48
}
@@ -49,38 +51,59 @@ impl<'a> Transaction<'a> {
49
51
/// Creates a new transaction.
50
52
pub fn new ( table : & ' a Table ) -> Self {
51
53
Self {
52
- table,
54
+ base_table : table,
55
+ current_metadata : table. metadata ( ) . clone ( ) ,
53
56
updates : vec ! [ ] ,
54
57
requirements : vec ! [ ] ,
55
58
}
56
59
}
57
60
58
- fn append_updates ( & mut self , updates : Vec < TableUpdate > ) -> Result < ( ) > {
59
- for update in & updates {
60
- for up in & self . updates {
61
- if discriminant ( up) == discriminant ( update) {
62
- return Err ( Error :: new (
63
- ErrorKind :: DataInvalid ,
64
- format ! (
65
- "Cannot apply update with same type at same time: {:?}" ,
66
- update
67
- ) ,
68
- ) ) ;
69
- }
70
- }
61
+ fn update_table_metadata ( & mut self , updates : & [ TableUpdate ] ) -> Result < ( ) > {
62
+ let mut metadata_builder = self . current_metadata . clone ( ) . into_builder ( None ) ;
63
+ for update in updates {
64
+ metadata_builder = update. clone ( ) . apply ( metadata_builder) ?;
71
65
}
72
- self . updates . extend ( updates) ;
66
+
67
+ self . current_metadata = metadata_builder. build ( ) ?. metadata ;
68
+
73
69
Ok ( ( ) )
74
70
}
75
71
76
- fn append_requirements ( & mut self , requirements : Vec < TableRequirement > ) -> Result < ( ) > {
77
- self . requirements . extend ( requirements) ;
72
+ fn apply (
73
+ & mut self ,
74
+ updates : Vec < TableUpdate > ,
75
+ requirements : Vec < TableRequirement > ,
76
+ ) -> Result < ( ) > {
77
+ for requirment in & requirements {
78
+ requirment. check ( Some ( & self . current_metadata ) ) ?;
79
+ }
80
+
81
+ self . update_table_metadata ( & updates) ?;
82
+
83
+ self . updates . extend ( updates) ;
84
+
85
+ // For the requirements, it does not make sense to add a requirement more than once
86
+ // For example, you cannot assert that the current schema has two different IDs
87
+ for new_requirment in requirements {
88
+ if self
89
+ . requirements
90
+ . iter ( )
91
+ . map ( discriminant)
92
+ . all ( |d| d != discriminant ( & new_requirment) )
93
+ {
94
+ self . requirements . push ( new_requirment) ;
95
+ }
96
+ }
97
+
98
+ // # TODO
99
+ // Support auto commit later.
100
+
78
101
Ok ( ( ) )
79
102
}
80
103
81
104
/// Sets table to a new version.
82
105
pub fn upgrade_table_version ( mut self , format_version : FormatVersion ) -> Result < Self > {
83
- let current_version = self . table . metadata ( ) . format_version ( ) ;
106
+ let current_version = self . current_metadata . format_version ( ) ;
84
107
match current_version. cmp ( & format_version) {
85
108
Ordering :: Greater => {
86
109
return Err ( Error :: new (
@@ -92,7 +115,7 @@ impl<'a> Transaction<'a> {
92
115
) ) ;
93
116
}
94
117
Ordering :: Less => {
95
- self . append_updates ( vec ! [ UpgradeFormatVersion { format_version } ] ) ?;
118
+ self . apply ( vec ! [ UpgradeFormatVersion { format_version } ] , vec ! [ ] ) ?;
96
119
}
97
120
Ordering :: Equal => {
98
121
// Do nothing.
@@ -103,7 +126,7 @@ impl<'a> Transaction<'a> {
103
126
104
127
/// Update table's property.
105
128
pub fn set_properties ( mut self , props : HashMap < String , String > ) -> Result < Self > {
106
- self . append_updates ( vec ! [ TableUpdate :: SetProperties { updates: props } ] ) ?;
129
+ self . apply ( vec ! [ TableUpdate :: SetProperties { updates: props } ] , vec ! [ ] ) ?;
107
130
Ok ( self )
108
131
}
109
132
@@ -119,8 +142,7 @@ impl<'a> Transaction<'a> {
119
142
} ;
120
143
let mut snapshot_id = generate_random_id ( ) ;
121
144
while self
122
- . table
123
- . metadata ( )
145
+ . current_metadata
124
146
. snapshots ( )
125
147
. any ( |s| s. snapshot_id ( ) == snapshot_id)
126
148
{
@@ -155,14 +177,17 @@ impl<'a> Transaction<'a> {
155
177
156
178
/// Remove properties in table.
157
179
pub fn remove_properties ( mut self , keys : Vec < String > ) -> Result < Self > {
158
- self . append_updates ( vec ! [ TableUpdate :: RemoveProperties { removals: keys } ] ) ?;
180
+ self . apply (
181
+ vec ! [ TableUpdate :: RemoveProperties { removals: keys } ] ,
182
+ vec ! [ ] ,
183
+ ) ?;
159
184
Ok ( self )
160
185
}
161
186
162
187
/// Commit transaction.
163
188
pub async fn commit ( self , catalog : & impl Catalog ) -> Result < Table > {
164
189
let table_commit = TableCommit :: builder ( )
165
- . ident ( self . table . identifier ( ) . clone ( ) )
190
+ . ident ( self . base_table . identifier ( ) . clone ( ) )
166
191
. updates ( self . updates )
167
192
. requirements ( self . requirements )
168
193
. build ( ) ;
@@ -231,14 +256,14 @@ impl SnapshotProduceOperation for FastAppendOperation {
231
256
& self ,
232
257
snapshot_produce : & SnapshotProduceAction < ' _ > ,
233
258
) -> Result < Vec < ManifestFile > > {
234
- let Some ( snapshot) = snapshot_produce. tx . table . metadata ( ) . current_snapshot ( ) else {
259
+ let Some ( snapshot) = snapshot_produce. tx . current_metadata . current_snapshot ( ) else {
235
260
return Ok ( vec ! [ ] ) ;
236
261
} ;
237
262
238
263
let manifest_list = snapshot
239
264
. load_manifest_list (
240
- snapshot_produce. tx . table . file_io ( ) ,
241
- & snapshot_produce. tx . table . metadata_ref ( ) ,
265
+ snapshot_produce. tx . base_table . file_io ( ) ,
266
+ & snapshot_produce. tx . current_metadata ,
242
267
)
243
268
. await ?;
244
269
@@ -355,7 +380,7 @@ impl<'a> SnapshotProduceAction<'a> {
355
380
}
356
381
Self :: validate_partition_value (
357
382
data_file. partition ( ) ,
358
- self . tx . table . metadata ( ) . default_partition_type ( ) ,
383
+ self . tx . current_metadata . default_partition_type ( ) ,
359
384
) ?;
360
385
}
361
386
self . added_data_files . extend ( data_files) ;
@@ -365,24 +390,25 @@ impl<'a> SnapshotProduceAction<'a> {
365
390
fn new_manifest_output ( & mut self ) -> Result < OutputFile > {
366
391
let new_manifest_path = format ! (
367
392
"{}/{}/{}-m{}.{}" ,
368
- self . tx. table . metadata ( ) . location( ) ,
393
+ self . tx. current_metadata . location( ) ,
369
394
META_ROOT_PATH ,
370
395
self . commit_uuid,
371
396
self . manifest_counter. next( ) . unwrap( ) ,
372
397
DataFileFormat :: Avro
373
398
) ;
374
- self . tx . table . file_io ( ) . new_output ( new_manifest_path)
399
+ self . tx . base_table . file_io ( ) . new_output ( new_manifest_path)
375
400
}
376
401
377
402
// Write manifest file for added data files and return the ManifestFile for ManifestList.
378
403
async fn write_added_manifest ( & mut self ) -> Result < ManifestFile > {
379
404
let added_data_files = std:: mem:: take ( & mut self . added_data_files ) ;
380
405
let snapshot_id = self . snapshot_id ;
406
+ let format_version = self . tx . current_metadata . format_version ( ) ;
381
407
let manifest_entries = added_data_files. into_iter ( ) . map ( |data_file| {
382
408
let builder = ManifestEntry :: builder ( )
383
409
. status ( crate :: spec:: ManifestStatus :: Added )
384
410
. data_file ( data_file) ;
385
- if self . tx . table . metadata ( ) . format_version ( ) == FormatVersion :: V1 {
411
+ if format_version == FormatVersion :: V1 {
386
412
builder. snapshot_id ( snapshot_id) . build ( )
387
413
} else {
388
414
// For format version > 1, we set the snapshot id at the inherited time to avoid rewrite the manifest file when
@@ -395,15 +421,14 @@ impl<'a> SnapshotProduceAction<'a> {
395
421
self . new_manifest_output ( ) ?,
396
422
Some ( self . snapshot_id ) ,
397
423
self . key_metadata . clone ( ) ,
398
- self . tx . table . metadata ( ) . current_schema ( ) . clone ( ) ,
424
+ self . tx . current_metadata . current_schema ( ) . clone ( ) ,
399
425
self . tx
400
- . table
401
- . metadata ( )
426
+ . current_metadata
402
427
. default_partition_spec ( )
403
428
. as_ref ( )
404
429
. clone ( ) ,
405
430
) ;
406
- if self . tx . table . metadata ( ) . format_version ( ) == FormatVersion :: V1 {
431
+ if self . tx . current_metadata . format_version ( ) == FormatVersion :: V1 {
407
432
builder. build_v1 ( )
408
433
} else {
409
434
builder. build_v2_data ( )
@@ -443,7 +468,7 @@ impl<'a> SnapshotProduceAction<'a> {
443
468
fn generate_manifest_list_file_path ( & self , attempt : i64 ) -> String {
444
469
format ! (
445
470
"{}/{}/snap-{}-{}-{}.{}" ,
446
- self . tx. table . metadata ( ) . location( ) ,
471
+ self . tx. current_metadata . location( ) ,
447
472
META_ROOT_PATH ,
448
473
self . snapshot_id,
449
474
attempt,
@@ -461,28 +486,28 @@ impl<'a> SnapshotProduceAction<'a> {
461
486
let new_manifests = self
462
487
. manifest_file ( & snapshot_produce_operation, & process)
463
488
. await ?;
464
- let next_seq_num = self . tx . table . metadata ( ) . next_sequence_number ( ) ;
489
+ let next_seq_num = self . tx . current_metadata . next_sequence_number ( ) ;
465
490
466
491
let summary = self . summary ( & snapshot_produce_operation) ;
467
492
468
493
let manifest_list_path = self . generate_manifest_list_file_path ( 0 ) ;
469
494
470
- let mut manifest_list_writer = match self . tx . table . metadata ( ) . format_version ( ) {
495
+ let mut manifest_list_writer = match self . tx . current_metadata . format_version ( ) {
471
496
FormatVersion :: V1 => ManifestListWriter :: v1 (
472
497
self . tx
473
- . table
498
+ . base_table
474
499
. file_io ( )
475
500
. new_output ( manifest_list_path. clone ( ) ) ?,
476
501
self . snapshot_id ,
477
- self . tx . table . metadata ( ) . current_snapshot_id ( ) ,
502
+ self . tx . current_metadata . current_snapshot_id ( ) ,
478
503
) ,
479
504
FormatVersion :: V2 => ManifestListWriter :: v2 (
480
505
self . tx
481
- . table
506
+ . base_table
482
507
. file_io ( )
483
508
. new_output ( manifest_list_path. clone ( ) ) ?,
484
509
self . snapshot_id ,
485
- self . tx . table . metadata ( ) . current_snapshot_id ( ) ,
510
+ self . tx . current_metadata . current_snapshot_id ( ) ,
486
511
next_seq_num,
487
512
) ,
488
513
} ;
@@ -493,34 +518,36 @@ impl<'a> SnapshotProduceAction<'a> {
493
518
let new_snapshot = Snapshot :: builder ( )
494
519
. with_manifest_list ( manifest_list_path)
495
520
. with_snapshot_id ( self . snapshot_id )
496
- . with_parent_snapshot_id ( self . tx . table . metadata ( ) . current_snapshot_id ( ) )
521
+ . with_parent_snapshot_id ( self . tx . current_metadata . current_snapshot_id ( ) )
497
522
. with_sequence_number ( next_seq_num)
498
523
. with_summary ( summary)
499
- . with_schema_id ( self . tx . table . metadata ( ) . current_schema_id ( ) )
524
+ . with_schema_id ( self . tx . current_metadata . current_schema_id ( ) )
500
525
. with_timestamp_ms ( commit_ts)
501
526
. build ( ) ;
502
527
503
- self . tx . append_updates ( vec ! [
504
- TableUpdate :: AddSnapshot {
505
- snapshot: new_snapshot,
506
- } ,
507
- TableUpdate :: SetSnapshotRef {
508
- ref_name: MAIN_BRANCH . to_string( ) ,
509
- reference: SnapshotReference :: new(
510
- self . snapshot_id,
511
- SnapshotRetention :: branch( None , None , None ) ,
512
- ) ,
513
- } ,
514
- ] ) ?;
515
- self . tx . append_requirements ( vec ! [
516
- TableRequirement :: UuidMatch {
517
- uuid: self . tx. table. metadata( ) . uuid( ) ,
518
- } ,
519
- TableRequirement :: RefSnapshotIdMatch {
520
- r#ref: MAIN_BRANCH . to_string( ) ,
521
- snapshot_id: self . tx. table. metadata( ) . current_snapshot_id( ) ,
522
- } ,
523
- ] ) ?;
528
+ self . tx . apply (
529
+ vec ! [
530
+ TableUpdate :: AddSnapshot {
531
+ snapshot: new_snapshot. clone( ) ,
532
+ } ,
533
+ TableUpdate :: SetSnapshotRef {
534
+ ref_name: MAIN_BRANCH . to_string( ) ,
535
+ reference: SnapshotReference :: new(
536
+ self . snapshot_id,
537
+ SnapshotRetention :: branch( None , None , None ) ,
538
+ ) ,
539
+ } ,
540
+ ] ,
541
+ vec ! [
542
+ TableRequirement :: UuidMatch {
543
+ uuid: self . tx. current_metadata. uuid( ) ,
544
+ } ,
545
+ TableRequirement :: RefSnapshotIdMatch {
546
+ r#ref: MAIN_BRANCH . to_string( ) ,
547
+ snapshot_id: self . tx. current_metadata. current_snapshot_id( ) ,
548
+ } ,
549
+ ] ,
550
+ ) ?;
524
551
Ok ( self . tx )
525
552
}
526
553
}
@@ -557,15 +584,14 @@ impl<'a> ReplaceSortOrderAction<'a> {
557
584
558
585
let requirements = vec ! [
559
586
TableRequirement :: CurrentSchemaIdMatch {
560
- current_schema_id: self . tx. table . metadata ( ) . current_schema( ) . schema_id( ) ,
587
+ current_schema_id: self . tx. current_metadata . current_schema( ) . schema_id( ) ,
561
588
} ,
562
589
TableRequirement :: DefaultSortOrderIdMatch {
563
- default_sort_order_id: self . tx. table . metadata ( ) . default_sort_order( ) . order_id,
590
+ default_sort_order_id: self . tx. current_metadata . default_sort_order( ) . order_id,
564
591
} ,
565
592
] ;
566
593
567
- self . tx . append_requirements ( requirements) ?;
568
- self . tx . append_updates ( updates) ?;
594
+ self . tx . apply ( updates, requirements) ?;
569
595
Ok ( self . tx )
570
596
}
571
597
@@ -577,8 +603,7 @@ impl<'a> ReplaceSortOrderAction<'a> {
577
603
) -> Result < Self > {
578
604
let field_id = self
579
605
. tx
580
- . table
581
- . metadata ( )
606
+ . current_metadata
582
607
. current_schema ( )
583
608
. field_id_by_name ( name)
584
609
. ok_or_else ( || {
@@ -806,14 +831,15 @@ mod tests {
806
831
assert ! (
807
832
matches!( ( & tx. updates[ 0 ] , & tx. updates[ 1 ] ) , ( TableUpdate :: AddSnapshot { snapshot } , TableUpdate :: SetSnapshotRef { reference, ref_name } ) if snapshot. snapshot_id( ) == reference. snapshot_id && ref_name == MAIN_BRANCH )
808
833
) ;
834
+ // requriments is based on original table metadata
809
835
assert_eq ! (
810
836
vec![
811
837
TableRequirement :: UuidMatch {
812
- uuid: tx . table. metadata( ) . uuid( )
838
+ uuid: table. metadata( ) . uuid( )
813
839
} ,
814
840
TableRequirement :: RefSnapshotIdMatch {
815
841
r#ref: MAIN_BRANCH . to_string( ) ,
816
- snapshot_id: tx . table. metadata( ) . current_snapshot_id
842
+ snapshot_id: table. metadata( ) . current_snapshot_id( )
817
843
}
818
844
] ,
819
845
tx. requirements
@@ -853,20 +879,4 @@ mod tests {
853
879
) ;
854
880
assert_eq ! ( data_file, * manifest. entries( ) [ 0 ] . data_file( ) ) ;
855
881
}
856
-
857
- #[ test]
858
- fn test_do_same_update_in_same_transaction ( ) {
859
- let table = make_v2_table ( ) ;
860
- let tx = Transaction :: new ( & table) ;
861
- let tx = tx
862
- . remove_properties ( vec ! [ "a" . to_string( ) , "b" . to_string( ) ] )
863
- . unwrap ( ) ;
864
-
865
- let tx = tx. remove_properties ( vec ! [ "c" . to_string( ) , "d" . to_string( ) ] ) ;
866
-
867
- assert ! (
868
- tx. is_err( ) ,
869
- "Should not allow to do same kinds update in same transaction"
870
- ) ;
871
- }
872
882
}
0 commit comments