1
1
# ##############################################################################
2
2
# Test of proper transaction isolation.
3
- # Based on Martin Kleppmann tests, https://github.com/ept/hermitage
3
+ # Based on Martin Kleppmann's tests set , https://github.com/ept/hermitage
4
4
# ##############################################################################
5
5
6
6
use strict;
7
7
use warnings;
8
8
use PostgresNode;
9
9
use TestLib;
10
- use Test::More tests => 2 ;
10
+ use Test::More tests => 7 ;
11
11
use DBI;
12
12
use DBD::Pg ' :async' ;
13
13
@@ -16,7 +16,7 @@ sub query_row
16
16
my ($dbi , $sql , @keys ) = @_ ;
17
17
my $sth = $dbi -> prepare($sql ) || die ;
18
18
$sth -> execute(@keys ) || die ;
19
- my $ret = $sth -> fetchrow_array;
19
+ my $ret = $sth -> fetchrow_array || undef ;
20
20
print " query_row('$sql ') -> $ret \n " ;
21
21
return $ret ;
22
22
}
@@ -81,11 +81,13 @@ sub PostgresNode::psql_fails {
81
81
$node2 -> psql(' postgres' , " create table t(id int primary key, v int)" );
82
82
$node2 -> psql(' postgres' , " insert into t values(2, 20)" );
83
83
84
- # we need two connections to each node (run two simultameous global tx)
84
+ # we will run up to three simultaneous tx, so six connections
85
85
my $conn1a = DBI-> connect (' DBI:Pg:' . $node1 -> connstr(' postgres' ));
86
86
my $conn2a = DBI-> connect (' DBI:Pg:' . $node2 -> connstr(' postgres' ));
87
87
my $conn1b = DBI-> connect (' DBI:Pg:' . $node1 -> connstr(' postgres' ));
88
88
my $conn2b = DBI-> connect (' DBI:Pg:' . $node2 -> connstr(' postgres' ));
89
+ my $conn1c = DBI-> connect (' DBI:Pg:' . $node1 -> connstr(' postgres' ));
90
+ my $conn2c = DBI-> connect (' DBI:Pg:' . $node2 -> connstr(' postgres' ));
89
91
90
92
sub count_total
91
93
{
@@ -135,6 +137,12 @@ sub commit_global
135
137
query_exec($c2 , " commit prepared '$gtid '" );
136
138
}
137
139
140
+ # deadlock check!
141
+
142
+ # simple for share/update (examples in pg isolation tests)
143
+
144
+
145
+
138
146
# ##############################################################################
139
147
# Sanity check for dirty reads
140
148
# ##############################################################################
@@ -152,7 +160,7 @@ sub commit_global
152
160
is($intermediate_total , 30, " Check for absence of dirty reads" );
153
161
154
162
# ##############################################################################
155
- # G0
163
+ # G0: Write Cycles
156
164
# ##############################################################################
157
165
158
166
my $fail = 0;
@@ -188,7 +196,159 @@ sub commit_global
188
196
189
197
$fail = 1 if $v1 != 12 or $v2 != 22;
190
198
191
- is($fail , 0, " Global transactions prevents Write Cycles (G0)" );
199
+ is($fail , 0, " Write Cycles (G0)" );
200
+
201
+ # ##############################################################################
202
+ # G1b: Intermediate Reads
203
+ # ##############################################################################
204
+
205
+ $fail = 0;
206
+ $node1 -> psql(' postgres' , " update t set v = 10 where id = 1" );
207
+ $node2 -> psql(' postgres' , " update t set v = 20 where id = 2" );
208
+
209
+ start_global(" G1b-a" , $conn1a , $conn2a );
210
+ start_global(" G1b-b" , $conn1b , $conn2b );
211
+
212
+ query_exec($conn1a , " update t set v = 101 where id = 1" );
213
+
214
+ $v1 = query_row($conn1b , " select v from t where id = 1" );
215
+ $fail = 1 if $v1 != 10;
216
+
217
+ query_exec($conn1a , " update t set v = 11 where id = 1" );
218
+ commit_global(" G1b-a" , $conn1a , $conn2a );
219
+
220
+ $v1 = query_row($conn1b , " select v from t where id = 1" );
221
+ $fail = 1 if $v1 == 101;
222
+
223
+ if ($v1 != 11) {
224
+ print " WARNIG: behavior is stricter than in usual read commited\n "
225
+ }
226
+
227
+ commit_global(" G1b-b" , $conn1b , $conn2b );
228
+
229
+ is($fail , 0, " Intermediate Reads (G1b)" );
230
+
231
+
232
+ # ##############################################################################
233
+ # G1c: Circular Information Flow
234
+ # ##############################################################################
235
+
236
+ $fail = 0;
237
+ $node1 -> psql(' postgres' , " update t set v = 10 where id = 1" );
238
+ $node2 -> psql(' postgres' , " update t set v = 20 where id = 2" );
239
+
240
+ start_global(" G1c-a" , $conn1a , $conn2a );
241
+ start_global(" G1c-b" , $conn1b , $conn2b );
242
+
243
+ query_exec($conn1a , " update t set v = 11 where id = 1" );
244
+ query_exec($conn2b , " update t set v = 22 where id = 2" );
245
+
246
+ $v2 = query_row($conn2a , " select v from t where id = 2" );
247
+ $v1 = query_row($conn1b , " select v from t where id = 1" );
248
+
249
+ $fail = 1 if $v1 != 10 or $v2 != 20;
250
+
251
+ commit_global(" G1c-a" , $conn1a , $conn2a );
252
+ commit_global(" G1c-b" , $conn1b , $conn2b );
253
+
254
+ is($fail , 0, " Circular Information Flow (G1c)" );
255
+
256
+
257
+ # ##############################################################################
258
+ # OTV: Observed Transaction Vanishes
259
+ # ##############################################################################
260
+
261
+ $fail = 0;
262
+ $node1 -> psql(' postgres' , " update t set v = 10 where id = 1" );
263
+ $node2 -> psql(' postgres' , " update t set v = 20 where id = 2" );
264
+
265
+ start_global(" OTV-a" , $conn1a , $conn2a );
266
+ start_global(" OTV-b" , $conn1b , $conn2b );
267
+ start_global(" OTV-c" , $conn1c , $conn2c );
268
+
269
+ query_exec($conn1a , " update t set v = 11 where id = 1" );
270
+ query_exec($conn2a , " update t set v = 19 where id = 2" );
271
+
272
+ query_exec_async($conn1b , " update t set v = 12 where id = 1" );
273
+ $fail = 1 if $conn1b -> pg_ready != 0; # blocks
274
+ commit_global(" OTV-a" , $conn1a , $conn2a );
275
+ $conn1b -> pg_result; # wait for unblock
276
+
277
+ $v1 = query_row($conn1c , " select v from t where id = 1" );
278
+ $fail = 1 if $v1 != 11;
279
+
280
+ query_exec($conn2b , " update t set v = 18 where id = 2" );
281
+
282
+ $v2 = query_row($conn2c , " select v from t where id = 2" );
283
+ $fail = 1 if $v2 != 19;
284
+
285
+ commit_global(" OTV-b" , $conn1b , $conn2b );
286
+
287
+ $v2 = query_row($conn2c , " select v from t where id = 2" );
288
+ $v1 = query_row($conn1c , " select v from t where id = 1" );
289
+ $fail = 1 if $v2 != 18 or $v1 != 12;
290
+
291
+ commit_global(" OTV-c" , $conn1c , $conn2c );
292
+
293
+ is($fail , 0, " Observed Transaction Vanishes (OTV)" );
294
+
295
+
296
+ # ##############################################################################
297
+ # PMP: Predicate-Many-Preceders
298
+ # ##############################################################################
299
+
300
+ $fail = 0;
301
+ $node1 -> psql(' postgres' , " delete from t" );
302
+ $node2 -> psql(' postgres' , " delete from t" );
303
+ $node1 -> psql(' postgres' , " insert into t values(1, 10)" );
304
+ $node2 -> psql(' postgres' , " insert into t values(2, 20)" );
305
+
306
+ start_global(" PMP-a" , $conn1a , $conn2a );
307
+ start_global(" PMP-b" , $conn1b , $conn2b );
308
+
309
+ my $v3 = query_row($conn1a , " select v from t where v = 30" ); # should run everywhere!
310
+
311
+ query_exec($conn1b , " update t set v = 18 where id = 3" ); # try place on second node?
312
+ commit_global(" PMP-b" , $conn1b , $conn2b );
313
+
314
+ $v3 = query_row($conn1a , " select v from t where v % 3 = 0" );
315
+ $fail = 1 if defined $v3 ;
316
+
317
+ commit_global(" PMP-a" , $conn1a , $conn2a );
318
+
319
+ is($fail , 0, " Predicate-Many-Preceders (PMP)" );
320
+
321
+
322
+
323
+ # ##############################################################################
324
+ # PMP: Predicate-Many-Preceders for write predicates
325
+ # ##############################################################################
326
+
327
+ $fail = 0;
328
+ $node1 -> psql(' postgres' , " delete from t" );
329
+ $node2 -> psql(' postgres' , " delete from t" );
330
+ $node1 -> psql(' postgres' , " insert into t values(1, 10)" );
331
+ $node2 -> psql(' postgres' , " insert into t values(2, 20)" );
332
+
333
+ start_global(" PMPwp-a" , $conn1a , $conn2a );
334
+ start_global(" PMPwp-b" , $conn1b , $conn2b );
335
+
336
+ query_exec($conn1a , " update t set v = v + 10" );
337
+ query_exec($conn2a , " update t set v = v + 10" );
338
+
339
+ query_exec_async($conn1b , " delete from t where v = 20" );
340
+ query_exec_async($conn2b , " delete from t where v = 20" );
341
+ commit_global(" PMPwp-a" , $conn1a , $conn2a );
342
+ $conn1b -> pg_result;
343
+ $conn2b -> pg_result;
344
+
345
+ query_row($conn1a , " select v from t where v = 20" );
346
+ query_row($conn2a , " select v from t where v = 20" );
347
+
348
+ commit_global(" PMPwp-b" , $conn1b , $conn2b );
349
+
350
+ is($fail , 0, " Predicate-Many-Preceders for write predicates (PMPwp)" );
351
+
192
352
193
353
194
354
0 commit comments