@@ -27,7 +27,8 @@ static void apply_concurrent_changes(EState *estate, ModifyTableState *mtstate,
27
27
Relation ident_index ,
28
28
TupleTableSlot * slot_dst_ind ,
29
29
partitions_hash * partitions ,
30
- TupleConversionMapExt * conv_map );
30
+ TupleConversionMapExt * conv_map ,
31
+ struct timeval * must_complete );
31
32
static void apply_insert (HeapTuple tup , TupleTableSlot * slot ,
32
33
EState * estate , ModifyTableState * mtstate ,
33
34
struct PartitionTupleRouting * proute ,
@@ -106,6 +107,20 @@ pg_rewrite_process_concurrent_changes(EState *estate,
106
107
partitions && proute ));
107
108
108
109
dstate = (DecodingOutputState * ) ctx -> output_writer_private ;
110
+
111
+ /*
112
+ * If some changes could not be applied due to time constraint, make sure
113
+ * the tuplestore is empty before we insert new tuples into it.
114
+ */
115
+ if (dstate -> nchanges > 0 )
116
+ apply_concurrent_changes (estate , mtstate , proute ,
117
+ dstate , ident_key , ident_key_nentries ,
118
+ ident_index , slot_dst_ind ,
119
+ partitions , conv_map , must_complete );
120
+ /* Ran out of time? */
121
+ if (dstate -> nchanges > 0 )
122
+ return false;
123
+
109
124
done = false;
110
125
while (!done )
111
126
{
@@ -129,7 +144,10 @@ pg_rewrite_process_concurrent_changes(EState *estate,
129
144
apply_concurrent_changes (estate , mtstate , proute ,
130
145
dstate , ident_key , ident_key_nentries ,
131
146
ident_index , slot_dst_ind ,
132
- partitions , conv_map );
147
+ partitions , conv_map , must_complete );
148
+ /* Ran out of time? */
149
+ if (dstate -> nchanges > 0 )
150
+ return false;
133
151
}
134
152
135
153
return true;
@@ -233,7 +251,8 @@ apply_concurrent_changes(EState *estate, ModifyTableState *mtstate,
233
251
Relation ident_index ,
234
252
TupleTableSlot * slot_dst_ind ,
235
253
partitions_hash * partitions ,
236
- TupleConversionMapExt * conv_map )
254
+ TupleConversionMapExt * conv_map ,
255
+ struct timeval * must_complete )
237
256
{
238
257
BulkInsertState bistate = NULL ;
239
258
HeapTuple tup_old = NULL ;
@@ -272,6 +291,9 @@ apply_concurrent_changes(EState *estate, ModifyTableState *mtstate,
272
291
bool isnull [1 ];
273
292
Datum values [1 ];
274
293
294
+ Assert (dstate -> nchanges > 0 );
295
+ dstate -> nchanges -- ;
296
+
275
297
/* Get the change from the single-column tuple. */
276
298
tup_change = ExecFetchSlotHeapTuple (dstate -> tsslot , false, & shouldFree );
277
299
heap_deform_tuple (tup_change , dstate -> tupdesc_change , values , isnull );
@@ -320,10 +342,22 @@ apply_concurrent_changes(EState *estate, ModifyTableState *mtstate,
320
342
/* TTSOpsMinimalTuple has .get_heap_tuple==NULL. */
321
343
Assert (shouldFree );
322
344
pfree (tup_change );
345
+
346
+ /*
347
+ * If there is a limit on the time of completion, check it
348
+ * now. However, make sure the loop does not break if tup_old was set
349
+ * in the previous iteration. In such a case we could not resume the
350
+ * processing in the next call.
351
+ */
352
+ if (must_complete && tup_old == NULL &&
353
+ processing_time_elapsed (must_complete ))
354
+ /* The next call will process the remaining changes. */
355
+ break ;
323
356
}
324
357
325
- tuplestore_clear (dstate -> tstore );
326
- dstate -> nchanges = 0 ;
358
+ /* If we could not apply all the changes, the next call will do. */
359
+ if (dstate -> nchanges == 0 )
360
+ tuplestore_clear (dstate -> tstore );
327
361
328
362
PopActiveSnapshot ();
329
363
0 commit comments