@@ -24,6 +24,7 @@ mod sort_order;
24
24
use std:: cmp:: Ordering ;
25
25
use std:: collections:: HashMap ;
26
26
use std:: mem:: discriminant;
27
+ use std:: sync:: Arc ;
27
28
28
29
use uuid:: Uuid ;
29
30
@@ -37,7 +38,8 @@ use crate::{Catalog, Error, ErrorKind, TableCommit, TableRequirement, TableUpdat
37
38
38
39
/// Table transaction.
39
40
pub struct Transaction < ' a > {
40
- table : & ' a Table ,
41
+ base_table : & ' a Table ,
42
+ current_table : Table ,
41
43
updates : Vec < TableUpdate > ,
42
44
requirements : Vec < TableRequirement > ,
43
45
}
@@ -46,38 +48,60 @@ impl<'a> Transaction<'a> {
46
48
/// Creates a new transaction.
47
49
pub fn new ( table : & ' a Table ) -> Self {
48
50
Self {
49
- table,
51
+ base_table : table,
52
+ current_table : table. clone ( ) ,
50
53
updates : vec ! [ ] ,
51
54
requirements : vec ! [ ] ,
52
55
}
53
56
}
54
57
55
- fn append_updates ( & mut self , updates : Vec < TableUpdate > ) -> Result < ( ) > {
56
- for update in & updates {
57
- for up in & self . updates {
58
- if discriminant ( up) == discriminant ( update) {
59
- return Err ( Error :: new (
60
- ErrorKind :: DataInvalid ,
61
- format ! (
62
- "Cannot apply update with same type at same time: {:?}" ,
63
- update
64
- ) ,
65
- ) ) ;
66
- }
67
- }
58
+ fn update_table_metadata ( & mut self , updates : & [ TableUpdate ] ) -> Result < ( ) > {
59
+ let mut metadata_builder = self . current_table . metadata ( ) . clone ( ) . into_builder ( None ) ;
60
+ for update in updates {
61
+ metadata_builder = update. clone ( ) . apply ( metadata_builder) ?;
68
62
}
69
- self . updates . extend ( updates) ;
63
+
64
+ self . current_table
65
+ . with_metadata ( Arc :: new ( metadata_builder. build ( ) ?. metadata ) ) ;
66
+
70
67
Ok ( ( ) )
71
68
}
72
69
73
- fn append_requirements ( & mut self , requirements : Vec < TableRequirement > ) -> Result < ( ) > {
74
- self . requirements . extend ( requirements) ;
70
+ fn apply (
71
+ & mut self ,
72
+ updates : Vec < TableUpdate > ,
73
+ requirements : Vec < TableRequirement > ,
74
+ ) -> Result < ( ) > {
75
+ for requirement in & requirements {
76
+ requirement. check ( Some ( self . current_table . metadata ( ) ) ) ?;
77
+ }
78
+
79
+ self . update_table_metadata ( & updates) ?;
80
+
81
+ self . updates . extend ( updates) ;
82
+
83
+ // For the requirements, it does not make sense to add a requirement more than once
84
+ // For example, you cannot assert that the current schema has two different IDs
85
+ for new_requirement in requirements {
86
+ if self
87
+ . requirements
88
+ . iter ( )
89
+ . map ( discriminant)
90
+ . all ( |d| d != discriminant ( & new_requirement) )
91
+ {
92
+ self . requirements . push ( new_requirement) ;
93
+ }
94
+ }
95
+
96
+ // # TODO
97
+ // Support auto commit later.
98
+
75
99
Ok ( ( ) )
76
100
}
77
101
78
102
/// Sets table to a new version.
79
103
pub fn upgrade_table_version ( mut self , format_version : FormatVersion ) -> Result < Self > {
80
- let current_version = self . table . metadata ( ) . format_version ( ) ;
104
+ let current_version = self . current_table . metadata ( ) . format_version ( ) ;
81
105
match current_version. cmp ( & format_version) {
82
106
Ordering :: Greater => {
83
107
return Err ( Error :: new (
@@ -89,7 +113,7 @@ impl<'a> Transaction<'a> {
89
113
) ) ;
90
114
}
91
115
Ordering :: Less => {
92
- self . append_updates ( vec ! [ UpgradeFormatVersion { format_version } ] ) ?;
116
+ self . apply ( vec ! [ UpgradeFormatVersion { format_version } ] , vec ! [ ] ) ?;
93
117
}
94
118
Ordering :: Equal => {
95
119
// Do nothing.
@@ -100,7 +124,7 @@ impl<'a> Transaction<'a> {
100
124
101
125
/// Update table's property.
102
126
pub fn set_properties ( mut self , props : HashMap < String , String > ) -> Result < Self > {
103
- self . append_updates ( vec ! [ TableUpdate :: SetProperties { updates: props } ] ) ?;
127
+ self . apply ( vec ! [ TableUpdate :: SetProperties { updates: props } ] , vec ! [ ] ) ?;
104
128
Ok ( self )
105
129
}
106
130
@@ -116,7 +140,7 @@ impl<'a> Transaction<'a> {
116
140
} ;
117
141
let mut snapshot_id = generate_random_id ( ) ;
118
142
while self
119
- . table
143
+ . current_table
120
144
. metadata ( )
121
145
. snapshots ( )
122
146
. any ( |s| s. snapshot_id ( ) == snapshot_id)
@@ -152,14 +176,17 @@ impl<'a> Transaction<'a> {
152
176
153
177
/// Remove properties in table.
154
178
pub fn remove_properties ( mut self , keys : Vec < String > ) -> Result < Self > {
155
- self . append_updates ( vec ! [ TableUpdate :: RemoveProperties { removals: keys } ] ) ?;
179
+ self . apply (
180
+ vec ! [ TableUpdate :: RemoveProperties { removals: keys } ] ,
181
+ vec ! [ ] ,
182
+ ) ?;
156
183
Ok ( self )
157
184
}
158
185
159
186
/// Commit transaction.
160
187
pub async fn commit ( self , catalog : & dyn Catalog ) -> Result < Table > {
161
188
let table_commit = TableCommit :: builder ( )
162
- . ident ( self . table . identifier ( ) . clone ( ) )
189
+ . ident ( self . base_table . identifier ( ) . clone ( ) )
163
190
. updates ( self . updates )
164
191
. requirements ( self . requirements )
165
192
. build ( ) ;
@@ -308,19 +335,21 @@ mod tests {
308
335
) ;
309
336
}
310
337
311
- #[ test]
312
- fn test_do_same_update_in_same_transaction ( ) {
313
- let table = make_v2_table ( ) ;
338
+ #[ tokio :: test]
339
+ async fn test_transaction_apply_upgrade ( ) {
340
+ let table = make_v1_table ( ) ;
314
341
let tx = Transaction :: new ( & table) ;
315
- let tx = tx
316
- . remove_properties ( vec ! [ "a" . to_string ( ) , "b" . to_string ( ) ] )
317
- . unwrap ( ) ;
318
-
319
- let tx = tx . remove_properties ( vec ! [ "c" . to_string ( ) , "d" . to_string ( ) ] ) ;
320
-
321
- assert ! (
322
- tx . is_err ( ) ,
323
- "Should not allow to do same kinds update in same transaction"
342
+ // Upgrade v1 to v1, do nothing.
343
+ let tx = tx . upgrade_table_version ( FormatVersion :: V1 ) . unwrap ( ) ;
344
+ // Upgrade v1 to v2, success.
345
+ let tx = tx . upgrade_table_version ( FormatVersion :: V2 ) . unwrap ( ) ;
346
+ assert_eq ! (
347
+ vec! [ TableUpdate :: UpgradeFormatVersion {
348
+ format_version : FormatVersion :: V2
349
+ } ] ,
350
+ tx . updates
324
351
) ;
352
+ // Upgrade v2 to v1, return error.
353
+ assert ! ( tx. upgrade_table_version( FormatVersion :: V1 ) . is_err( ) ) ;
325
354
}
326
355
}
0 commit comments