00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "postgres.h"
00021
00022 #include "access/visibilitymap.h"
00023 #include "access/xact.h"
00024 #include "access/xlogutils.h"
00025 #include "catalog/catalog.h"
00026 #include "catalog/storage.h"
00027 #include "catalog/storage_xlog.h"
00028 #include "storage/freespace.h"
00029 #include "storage/smgr.h"
00030 #include "utils/memutils.h"
00031 #include "utils/rel.h"
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 typedef struct PendingRelDelete
00054 {
00055 RelFileNode relnode;
00056 BackendId backend;
00057 bool atCommit;
00058 int nestLevel;
00059 struct PendingRelDelete *next;
00060 } PendingRelDelete;
00061
00062 static PendingRelDelete *pendingDeletes = NULL;
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075 void
00076 RelationCreateStorage(RelFileNode rnode, char relpersistence)
00077 {
00078 PendingRelDelete *pending;
00079 SMgrRelation srel;
00080 BackendId backend;
00081 bool needs_wal;
00082
00083 switch (relpersistence)
00084 {
00085 case RELPERSISTENCE_TEMP:
00086 backend = MyBackendId;
00087 needs_wal = false;
00088 break;
00089 case RELPERSISTENCE_UNLOGGED:
00090 backend = InvalidBackendId;
00091 needs_wal = false;
00092 break;
00093 case RELPERSISTENCE_PERMANENT:
00094 backend = InvalidBackendId;
00095 needs_wal = true;
00096 break;
00097 default:
00098 elog(ERROR, "invalid relpersistence: %c", relpersistence);
00099 return;
00100 }
00101
00102 srel = smgropen(rnode, backend);
00103 smgrcreate(srel, MAIN_FORKNUM, false);
00104
00105 if (needs_wal)
00106 log_smgrcreate(&srel->smgr_rnode.node, MAIN_FORKNUM);
00107
00108
00109 pending = (PendingRelDelete *)
00110 MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
00111 pending->relnode = rnode;
00112 pending->backend = backend;
00113 pending->atCommit = false;
00114 pending->nestLevel = GetCurrentTransactionNestLevel();
00115 pending->next = pendingDeletes;
00116 pendingDeletes = pending;
00117 }
00118
00119
00120
00121
00122 void
00123 log_smgrcreate(RelFileNode *rnode, ForkNumber forkNum)
00124 {
00125 xl_smgr_create xlrec;
00126 XLogRecData rdata;
00127
00128
00129
00130
00131 xlrec.rnode = *rnode;
00132 xlrec.forkNum = forkNum;
00133
00134 rdata.data = (char *) &xlrec;
00135 rdata.len = sizeof(xlrec);
00136 rdata.buffer = InvalidBuffer;
00137 rdata.next = NULL;
00138
00139 XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE, &rdata);
00140 }
00141
00142
00143
00144
00145
00146 void
00147 RelationDropStorage(Relation rel)
00148 {
00149 PendingRelDelete *pending;
00150
00151
00152 pending = (PendingRelDelete *)
00153 MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
00154 pending->relnode = rel->rd_node;
00155 pending->backend = rel->rd_backend;
00156 pending->atCommit = true;
00157 pending->nestLevel = GetCurrentTransactionNestLevel();
00158 pending->next = pendingDeletes;
00159 pendingDeletes = pending;
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171 RelationCloseSmgr(rel);
00172 }
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191 void
00192 RelationPreserveStorage(RelFileNode rnode, bool atCommit)
00193 {
00194 PendingRelDelete *pending;
00195 PendingRelDelete *prev;
00196 PendingRelDelete *next;
00197
00198 prev = NULL;
00199 for (pending = pendingDeletes; pending != NULL; pending = next)
00200 {
00201 next = pending->next;
00202 if (RelFileNodeEquals(rnode, pending->relnode)
00203 && pending->atCommit == atCommit)
00204 {
00205
00206 if (prev)
00207 prev->next = next;
00208 else
00209 pendingDeletes = next;
00210 pfree(pending);
00211
00212 }
00213 else
00214 {
00215
00216 prev = pending;
00217 }
00218 }
00219 }
00220
00221
00222
00223
00224
00225
00226
00227
00228 void
00229 RelationTruncate(Relation rel, BlockNumber nblocks)
00230 {
00231 bool fsm;
00232 bool vm;
00233
00234
00235 RelationOpenSmgr(rel);
00236
00237
00238
00239
00240 rel->rd_smgr->smgr_targblock = InvalidBlockNumber;
00241 rel->rd_smgr->smgr_fsm_nblocks = InvalidBlockNumber;
00242 rel->rd_smgr->smgr_vm_nblocks = InvalidBlockNumber;
00243
00244
00245 fsm = smgrexists(rel->rd_smgr, FSM_FORKNUM);
00246 if (fsm)
00247 FreeSpaceMapTruncateRel(rel, nblocks);
00248
00249
00250 vm = smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM);
00251 if (vm)
00252 visibilitymap_truncate(rel, nblocks);
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263 if (RelationNeedsWAL(rel))
00264 {
00265
00266
00267
00268 XLogRecPtr lsn;
00269 XLogRecData rdata;
00270 xl_smgr_truncate xlrec;
00271
00272 xlrec.blkno = nblocks;
00273 xlrec.rnode = rel->rd_node;
00274
00275 rdata.data = (char *) &xlrec;
00276 rdata.len = sizeof(xlrec);
00277 rdata.buffer = InvalidBuffer;
00278 rdata.next = NULL;
00279
00280 lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_TRUNCATE, &rdata);
00281
00282
00283
00284
00285
00286
00287
00288
00289 if (fsm || vm)
00290 XLogFlush(lsn);
00291 }
00292
00293
00294 smgrtruncate(rel->rd_smgr, MAIN_FORKNUM, nblocks);
00295 }
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308 void
00309 smgrDoPendingDeletes(bool isCommit)
00310 {
00311 int nestLevel = GetCurrentTransactionNestLevel();
00312 PendingRelDelete *pending;
00313 PendingRelDelete *prev;
00314 PendingRelDelete *next;
00315 int nrels = 0,
00316 i = 0,
00317 maxrels = 8;
00318 SMgrRelation *srels = palloc(maxrels * sizeof(SMgrRelation));
00319
00320 prev = NULL;
00321 for (pending = pendingDeletes; pending != NULL; pending = next)
00322 {
00323 next = pending->next;
00324 if (pending->nestLevel < nestLevel)
00325 {
00326
00327 prev = pending;
00328 }
00329 else
00330 {
00331
00332 if (prev)
00333 prev->next = next;
00334 else
00335 pendingDeletes = next;
00336
00337 if (pending->atCommit == isCommit)
00338 {
00339 SMgrRelation srel;
00340
00341 srel = smgropen(pending->relnode, pending->backend);
00342
00343
00344 if (maxrels <= nrels)
00345 {
00346 maxrels *= 2;
00347 srels = repalloc(srels, sizeof(SMgrRelation) * maxrels);
00348 }
00349
00350 srels[nrels++] = srel;
00351 }
00352
00353 pfree(pending);
00354
00355 }
00356 }
00357
00358 if (nrels > 0)
00359 {
00360 smgrdounlinkall(srels, nrels, false);
00361
00362 for (i = 0; i < nrels; i++)
00363 smgrclose(srels[i]);
00364 }
00365
00366 pfree(srels);
00367
00368 }
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387 int
00388 smgrGetPendingDeletes(bool forCommit, RelFileNode **ptr)
00389 {
00390 int nestLevel = GetCurrentTransactionNestLevel();
00391 int nrels;
00392 RelFileNode *rptr;
00393 PendingRelDelete *pending;
00394
00395 nrels = 0;
00396 for (pending = pendingDeletes; pending != NULL; pending = pending->next)
00397 {
00398 if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit
00399 && pending->backend == InvalidBackendId)
00400 nrels++;
00401 }
00402 if (nrels == 0)
00403 {
00404 *ptr = NULL;
00405 return 0;
00406 }
00407 rptr = (RelFileNode *) palloc(nrels * sizeof(RelFileNode));
00408 *ptr = rptr;
00409 for (pending = pendingDeletes; pending != NULL; pending = pending->next)
00410 {
00411 if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit
00412 && pending->backend == InvalidBackendId)
00413 {
00414 *rptr = pending->relnode;
00415 rptr++;
00416 }
00417 }
00418 return nrels;
00419 }
00420
00421
00422
00423
00424
00425
00426
00427
00428 void
00429 PostPrepare_smgr(void)
00430 {
00431 PendingRelDelete *pending;
00432 PendingRelDelete *next;
00433
00434 for (pending = pendingDeletes; pending != NULL; pending = next)
00435 {
00436 next = pending->next;
00437 pendingDeletes = next;
00438
00439 pfree(pending);
00440 }
00441 }
00442
00443
00444
00445
00446
00447
00448
00449 void
00450 AtSubCommit_smgr(void)
00451 {
00452 int nestLevel = GetCurrentTransactionNestLevel();
00453 PendingRelDelete *pending;
00454
00455 for (pending = pendingDeletes; pending != NULL; pending = pending->next)
00456 {
00457 if (pending->nestLevel >= nestLevel)
00458 pending->nestLevel = nestLevel - 1;
00459 }
00460 }
00461
00462
00463
00464
00465
00466
00467
00468
00469 void
00470 AtSubAbort_smgr(void)
00471 {
00472 smgrDoPendingDeletes(false);
00473 }
00474
00475 void
00476 smgr_redo(XLogRecPtr lsn, XLogRecord *record)
00477 {
00478 uint8 info = record->xl_info & ~XLR_INFO_MASK;
00479
00480
00481 Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));
00482
00483 if (info == XLOG_SMGR_CREATE)
00484 {
00485 xl_smgr_create *xlrec = (xl_smgr_create *) XLogRecGetData(record);
00486 SMgrRelation reln;
00487
00488 reln = smgropen(xlrec->rnode, InvalidBackendId);
00489 smgrcreate(reln, xlrec->forkNum, true);
00490 }
00491 else if (info == XLOG_SMGR_TRUNCATE)
00492 {
00493 xl_smgr_truncate *xlrec = (xl_smgr_truncate *) XLogRecGetData(record);
00494 SMgrRelation reln;
00495 Relation rel;
00496
00497 reln = smgropen(xlrec->rnode, InvalidBackendId);
00498
00499
00500
00501
00502
00503
00504
00505 smgrcreate(reln, MAIN_FORKNUM, true);
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523 XLogFlush(lsn);
00524
00525 smgrtruncate(reln, MAIN_FORKNUM, xlrec->blkno);
00526
00527
00528 XLogTruncateRelation(xlrec->rnode, MAIN_FORKNUM, xlrec->blkno);
00529
00530
00531 rel = CreateFakeRelcacheEntry(xlrec->rnode);
00532
00533 if (smgrexists(reln, FSM_FORKNUM))
00534 FreeSpaceMapTruncateRel(rel, xlrec->blkno);
00535 if (smgrexists(reln, VISIBILITYMAP_FORKNUM))
00536 visibilitymap_truncate(rel, xlrec->blkno);
00537
00538 FreeFakeRelcacheEntry(rel);
00539 }
00540 else
00541 elog(PANIC, "smgr_redo: unknown op code %u", info);
00542 }