@@ -114,19 +114,13 @@ typedef struct _outputContext
114
114
115
115
static const char * modulename = gettext_noop ("archiver" );
116
116
117
- /* index array created by fix_dependencies -- only used in parallel restore */
118
- static TocEntry * * tocsByDumpId ; /* index by dumpId - 1 */
119
- static DumpId maxDumpId ; /* length of above array */
120
-
121
117
122
118
static ArchiveHandle * _allocAH (const char * FileSpec , const ArchiveFormat fmt ,
123
119
const int compression , ArchiveMode mode );
124
120
static void _getObjectDescription (PQExpBuffer buf , TocEntry * te ,
125
121
ArchiveHandle * AH );
126
122
static void _printTocEntry (ArchiveHandle * AH , TocEntry * te , RestoreOptions * ropt , bool isData , bool acl_pass );
127
123
static char * replace_line_endings (const char * str );
128
-
129
-
130
124
static void _doSetFixedOutputState (ArchiveHandle * AH );
131
125
static void _doSetSessionAuth (ArchiveHandle * AH , const char * user );
132
126
static void _doSetWithOids (ArchiveHandle * AH , const bool withOids );
@@ -141,6 +135,7 @@ static teReqs _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include
141
135
static bool _tocEntryIsACL (TocEntry * te );
142
136
static void _disableTriggersIfNecessary (ArchiveHandle * AH , TocEntry * te , RestoreOptions * ropt );
143
137
static void _enableTriggersIfNecessary (ArchiveHandle * AH , TocEntry * te , RestoreOptions * ropt );
138
+ static void buildTocEntryArrays (ArchiveHandle * AH );
144
139
static TocEntry * getTocEntryByDumpId (ArchiveHandle * AH , DumpId id );
145
140
static void _moveBefore (ArchiveHandle * AH , TocEntry * pos , TocEntry * te );
146
141
static int _discoverArchiveFormat (ArchiveHandle * AH );
@@ -171,9 +166,8 @@ static void mark_work_done(ArchiveHandle *AH, TocEntry *ready_list,
171
166
ParallelSlot * slots , int n_slots );
172
167
static void fix_dependencies (ArchiveHandle * AH );
173
168
static bool has_lock_conflicts (TocEntry * te1 , TocEntry * te2 );
174
- static void repoint_table_dependencies (ArchiveHandle * AH ,
175
- DumpId tableId , DumpId tableDataId );
176
- static void identify_locking_dependencies (TocEntry * te );
169
+ static void repoint_table_dependencies (ArchiveHandle * AH );
170
+ static void identify_locking_dependencies (ArchiveHandle * AH , TocEntry * te );
177
171
static void reduce_dependencies (ArchiveHandle * AH , TocEntry * te ,
178
172
TocEntry * ready_list );
179
173
static void mark_create_done (ArchiveHandle * AH , TocEntry * te );
@@ -305,6 +299,13 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
305
299
}
306
300
#endif
307
301
302
+ /*
303
+ * Prepare index arrays, so we can assume we have them throughout restore.
304
+ * It's possible we already did this, though.
305
+ */
306
+ if (AH -> tocsByDumpId == NULL )
307
+ buildTocEntryArrays (AH );
308
+
308
309
/*
309
310
* If we're using a DB connection, then connect it.
310
311
*/
@@ -1524,16 +1525,68 @@ _moveBefore(ArchiveHandle *AH, TocEntry *pos, TocEntry *te)
1524
1525
pos -> prev = te ;
1525
1526
}
1526
1527
1527
- static TocEntry *
1528
- getTocEntryByDumpId (ArchiveHandle * AH , DumpId id )
1528
+ /*
1529
+ * Build index arrays for the TOC list
1530
+ *
1531
+ * This should be invoked only after we have created or read in all the TOC
1532
+ * items.
1533
+ *
1534
+ * The arrays are indexed by dump ID (so entry zero is unused). Note that the
1535
+ * array entries run only up to maxDumpId. We might see dependency dump IDs
1536
+ * beyond that (if the dump was partial); so always check the array bound
1537
+ * before trying to touch an array entry.
1538
+ */
1539
+ static void
1540
+ buildTocEntryArrays (ArchiveHandle * AH )
1529
1541
{
1542
+ DumpId maxDumpId = AH -> maxDumpId ;
1530
1543
TocEntry * te ;
1531
1544
1545
+ AH -> tocsByDumpId = (TocEntry * * ) pg_calloc (maxDumpId + 1 , sizeof (TocEntry * ));
1546
+ AH -> tableDataId = (DumpId * ) pg_calloc (maxDumpId + 1 , sizeof (DumpId ));
1547
+
1532
1548
for (te = AH -> toc -> next ; te != AH -> toc ; te = te -> next )
1533
1549
{
1534
- if (te -> dumpId == id )
1535
- return te ;
1550
+ /* this check is purely paranoia, maxDumpId should be correct */
1551
+ if (te -> dumpId <= 0 || te -> dumpId > maxDumpId )
1552
+ exit_horribly (modulename , "bad dumpId" );
1553
+
1554
+ /* tocsByDumpId indexes all TOCs by their dump ID */
1555
+ AH -> tocsByDumpId [te -> dumpId ] = te ;
1556
+
1557
+ /*
1558
+ * tableDataId provides the TABLE DATA item's dump ID for each TABLE
1559
+ * TOC entry that has a DATA item. We compute this by reversing the
1560
+ * TABLE DATA item's dependency, knowing that a TABLE DATA item has
1561
+ * just one dependency and it is the TABLE item.
1562
+ */
1563
+ if (strcmp (te -> desc , "TABLE DATA" ) == 0 && te -> nDeps > 0 )
1564
+ {
1565
+ DumpId tableId = te -> dependencies [0 ];
1566
+
1567
+ /*
1568
+ * The TABLE item might not have been in the archive, if this was
1569
+ * a data-only dump; but its dump ID should be less than its data
1570
+ * item's dump ID, so there should be a place for it in the array.
1571
+ */
1572
+ if (tableId <= 0 || tableId > maxDumpId )
1573
+ exit_horribly (modulename , "bad table dumpId for TABLE DATA item" );
1574
+
1575
+ AH -> tableDataId [tableId ] = te -> dumpId ;
1576
+ }
1536
1577
}
1578
+ }
1579
+
1580
+ static TocEntry *
1581
+ getTocEntryByDumpId (ArchiveHandle * AH , DumpId id )
1582
+ {
1583
+ /* build index arrays if we didn't already */
1584
+ if (AH -> tocsByDumpId == NULL )
1585
+ buildTocEntryArrays (AH );
1586
+
1587
+ if (id > 0 && id <= AH -> maxDumpId )
1588
+ return AH -> tocsByDumpId [id ];
1589
+
1537
1590
return NULL ;
1538
1591
}
1539
1592
@@ -3978,9 +4031,8 @@ mark_work_done(ArchiveHandle *AH, TocEntry *ready_list,
3978
4031
* This function takes care of fixing up some missing or badly designed
3979
4032
* dependencies, and then prepares subsidiary data structures that will be
3980
4033
* used in the main parallel-restore logic, including:
3981
- * 1. We build the tocsByDumpId[] index array.
3982
- * 2. We build the revDeps[] arrays of incoming dependency dumpIds.
3983
- * 3. We set up depCount fields that are the number of as-yet-unprocessed
4034
+ * 1. We build the revDeps[] arrays of incoming dependency dumpIds.
4035
+ * 2. We set up depCount fields that are the number of as-yet-unprocessed
3984
4036
* dependencies for each TOC entry.
3985
4037
*
3986
4038
* We also identify locking dependencies so that we can avoid trying to
@@ -3993,22 +4045,11 @@ fix_dependencies(ArchiveHandle *AH)
3993
4045
int i ;
3994
4046
3995
4047
/*
3996
- * It is convenient to have an array that indexes the TOC entries by dump
3997
- * ID, rather than searching the TOC list repeatedly. Entries for dump
3998
- * IDs not present in the TOC will be NULL.
3999
- *
4000
- * NOTE: because maxDumpId is just the highest dump ID defined in the
4001
- * archive, there might be dependencies for IDs > maxDumpId. All uses of
4002
- * this array must guard against out-of-range dependency numbers.
4003
- *
4004
- * Also, initialize the depCount/revDeps/nRevDeps fields, and make sure
4005
- * the TOC items are marked as not being in any parallel-processing list.
4048
+ * Initialize the depCount/revDeps/nRevDeps fields, and make sure the TOC
4049
+ * items are marked as not being in any parallel-processing list.
4006
4050
*/
4007
- maxDumpId = AH -> maxDumpId ;
4008
- tocsByDumpId = (TocEntry * * ) pg_calloc (maxDumpId , sizeof (TocEntry * ));
4009
4051
for (te = AH -> toc -> next ; te != AH -> toc ; te = te -> next )
4010
4052
{
4011
- tocsByDumpId [te -> dumpId - 1 ] = te ;
4012
4053
te -> depCount = te -> nDeps ;
4013
4054
te -> revDeps = NULL ;
4014
4055
te -> nRevDeps = 0 ;
@@ -4019,34 +4060,9 @@ fix_dependencies(ArchiveHandle *AH)
4019
4060
/*
4020
4061
* POST_DATA items that are shown as depending on a table need to be
4021
4062
* re-pointed to depend on that table's data, instead. This ensures they
4022
- * won't get scheduled until the data has been loaded. We handle this by
4023
- * first finding TABLE/TABLE DATA pairs and then scanning all the
4024
- * dependencies.
4025
- *
4026
- * Note: currently, a TABLE DATA should always have exactly one
4027
- * dependency, on its TABLE item. So we don't bother to search, but look
4028
- * just at the first dependency. We do trouble to make sure that it's a
4029
- * TABLE, if possible. However, if the dependency isn't in the archive
4030
- * then just assume it was a TABLE; this is to cover cases where the table
4031
- * was suppressed but we have the data and some dependent post-data items.
4032
- *
4033
- * XXX this is O(N^2) if there are a lot of tables. We ought to fix
4034
- * pg_dump to produce correctly-linked dependencies in the first place.
4063
+ * won't get scheduled until the data has been loaded.
4035
4064
*/
4036
- for (te = AH -> toc -> next ; te != AH -> toc ; te = te -> next )
4037
- {
4038
- if (strcmp (te -> desc , "TABLE DATA" ) == 0 && te -> nDeps > 0 )
4039
- {
4040
- DumpId tableId = te -> dependencies [0 ];
4041
-
4042
- if (tableId > maxDumpId ||
4043
- tocsByDumpId [tableId - 1 ] == NULL ||
4044
- strcmp (tocsByDumpId [tableId - 1 ]-> desc , "TABLE" ) == 0 )
4045
- {
4046
- repoint_table_dependencies (AH , tableId , te -> dumpId );
4047
- }
4048
- }
4049
- }
4065
+ repoint_table_dependencies (AH );
4050
4066
4051
4067
/*
4052
4068
* Pre-8.4 versions of pg_dump neglected to set up a dependency from BLOB
@@ -4093,8 +4109,8 @@ fix_dependencies(ArchiveHandle *AH)
4093
4109
{
4094
4110
DumpId depid = te -> dependencies [i ];
4095
4111
4096
- if (depid <= maxDumpId && tocsByDumpId [depid - 1 ] != NULL )
4097
- tocsByDumpId [depid - 1 ]-> nRevDeps ++ ;
4112
+ if (depid <= AH -> maxDumpId && AH -> tocsByDumpId [depid ] != NULL )
4113
+ AH -> tocsByDumpId [depid ]-> nRevDeps ++ ;
4098
4114
else
4099
4115
te -> depCount -- ;
4100
4116
}
@@ -4121,9 +4137,9 @@ fix_dependencies(ArchiveHandle *AH)
4121
4137
{
4122
4138
DumpId depid = te -> dependencies [i ];
4123
4139
4124
- if (depid <= maxDumpId && tocsByDumpId [depid - 1 ] != NULL )
4140
+ if (depid <= AH -> maxDumpId && AH -> tocsByDumpId [depid ] != NULL )
4125
4141
{
4126
- TocEntry * otherte = tocsByDumpId [depid - 1 ];
4142
+ TocEntry * otherte = AH -> tocsByDumpId [depid ];
4127
4143
4128
4144
otherte -> revDeps [otherte -> nRevDeps ++ ] = te -> dumpId ;
4129
4145
}
@@ -4137,32 +4153,34 @@ fix_dependencies(ArchiveHandle *AH)
4137
4153
{
4138
4154
te -> lockDeps = NULL ;
4139
4155
te -> nLockDeps = 0 ;
4140
- identify_locking_dependencies (te );
4156
+ identify_locking_dependencies (AH , te );
4141
4157
}
4142
4158
}
4143
4159
4144
4160
/*
4145
- * Change dependencies on tableId to depend on tableDataId instead,
4161
+ * Change dependencies on table items to depend on table data items instead,
4146
4162
* but only in POST_DATA items.
4147
4163
*/
4148
4164
static void
4149
- repoint_table_dependencies (ArchiveHandle * AH ,
4150
- DumpId tableId , DumpId tableDataId )
4165
+ repoint_table_dependencies (ArchiveHandle * AH )
4151
4166
{
4152
4167
TocEntry * te ;
4153
4168
int i ;
4169
+ DumpId olddep ;
4154
4170
4155
4171
for (te = AH -> toc -> next ; te != AH -> toc ; te = te -> next )
4156
4172
{
4157
4173
if (te -> section != SECTION_POST_DATA )
4158
4174
continue ;
4159
4175
for (i = 0 ; i < te -> nDeps ; i ++ )
4160
4176
{
4161
- if (te -> dependencies [i ] == tableId )
4177
+ olddep = te -> dependencies [i ];
4178
+ if (olddep <= AH -> maxDumpId &&
4179
+ AH -> tableDataId [olddep ] != 0 )
4162
4180
{
4163
- te -> dependencies [i ] = tableDataId ;
4181
+ te -> dependencies [i ] = AH -> tableDataId [ olddep ] ;
4164
4182
ahlog (AH , 2 , "transferring dependency %d -> %d to %d\n" ,
4165
- te -> dumpId , tableId , tableDataId );
4183
+ te -> dumpId , olddep , AH -> tableDataId [ olddep ] );
4166
4184
}
4167
4185
}
4168
4186
}
@@ -4174,7 +4192,7 @@ repoint_table_dependencies(ArchiveHandle *AH,
4174
4192
* itself). Record their dump IDs in the entry's lockDeps[] array.
4175
4193
*/
4176
4194
static void
4177
- identify_locking_dependencies (TocEntry * te )
4195
+ identify_locking_dependencies (ArchiveHandle * AH , TocEntry * te )
4178
4196
{
4179
4197
DumpId * lockids ;
4180
4198
int nlockids ;
@@ -4205,8 +4223,8 @@ identify_locking_dependencies(TocEntry *te)
4205
4223
{
4206
4224
DumpId depid = te -> dependencies [i ];
4207
4225
4208
- if (depid <= maxDumpId && tocsByDumpId [depid - 1 ] &&
4209
- strcmp (tocsByDumpId [depid - 1 ]-> desc , "TABLE DATA" ) == 0 )
4226
+ if (depid <= AH -> maxDumpId && AH -> tocsByDumpId [depid ] != NULL &&
4227
+ strcmp (AH -> tocsByDumpId [depid ]-> desc , "TABLE DATA" ) == 0 )
4210
4228
lockids [nlockids ++ ] = depid ;
4211
4229
}
4212
4230
@@ -4234,7 +4252,7 @@ reduce_dependencies(ArchiveHandle *AH, TocEntry *te, TocEntry *ready_list)
4234
4252
4235
4253
for (i = 0 ; i < te -> nRevDeps ; i ++ )
4236
4254
{
4237
- TocEntry * otherte = tocsByDumpId [te -> revDeps [i ] - 1 ];
4255
+ TocEntry * otherte = AH -> tocsByDumpId [te -> revDeps [i ]];
4238
4256
4239
4257
otherte -> depCount -- ;
4240
4258
if (otherte -> depCount == 0 && otherte -> par_prev != NULL )
@@ -4254,18 +4272,11 @@ reduce_dependencies(ArchiveHandle *AH, TocEntry *te, TocEntry *ready_list)
4254
4272
static void
4255
4273
mark_create_done (ArchiveHandle * AH , TocEntry * te )
4256
4274
{
4257
- TocEntry * tes ;
4258
-
4259
- for (tes = AH -> toc -> next ; tes != AH -> toc ; tes = tes -> next )
4275
+ if (AH -> tableDataId [te -> dumpId ] != 0 )
4260
4276
{
4261
- if (strcmp (tes -> desc , "TABLE DATA" ) == 0 &&
4262
- strcmp (tes -> tag , te -> tag ) == 0 &&
4263
- strcmp (tes -> namespace ? tes -> namespace : "" ,
4264
- te -> namespace ? te -> namespace : "" ) == 0 )
4265
- {
4266
- tes -> created = true;
4267
- break ;
4268
- }
4277
+ TocEntry * ted = AH -> tocsByDumpId [AH -> tableDataId [te -> dumpId ]];
4278
+
4279
+ ted -> created = true;
4269
4280
}
4270
4281
}
4271
4282
@@ -4277,22 +4288,14 @@ static void
4277
4288
inhibit_data_for_failed_table (ArchiveHandle * AH , TocEntry * te )
4278
4289
{
4279
4290
RestoreOptions * ropt = AH -> ropt ;
4280
- TocEntry * tes ;
4281
4291
4282
4292
ahlog (AH , 1 , "table \"%s\" could not be created, will not restore its data\n" ,
4283
4293
te -> tag );
4284
4294
4285
- for ( tes = AH -> toc -> next ; tes != AH -> toc ; tes = tes -> next )
4295
+ if ( AH -> tableDataId [ te -> dumpId ] != 0 )
4286
4296
{
4287
- if (strcmp (tes -> desc , "TABLE DATA" ) == 0 &&
4288
- strcmp (tes -> tag , te -> tag ) == 0 &&
4289
- strcmp (tes -> namespace ? tes -> namespace : "" ,
4290
- te -> namespace ? te -> namespace : "" ) == 0 )
4291
- {
4292
- /* mark it unwanted; we assume idWanted array already exists */
4293
- ropt -> idWanted [tes -> dumpId - 1 ] = false;
4294
- break ;
4295
- }
4297
+ /* mark it unwanted; we assume idWanted array already exists */
4298
+ ropt -> idWanted [AH -> tableDataId [te -> dumpId ] - 1 ] = false;
4296
4299
}
4297
4300
}
4298
4301
0 commit comments