~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/backend/storage/smgr/smgr.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * smgr.c
 
4
 *        public interface routines to storage manager switch.
 
5
 *
 
6
 *        All file system operations in POSTGRES dispatch through these
 
7
 *        routines.
 
8
 *
 
9
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
 
10
 * Portions Copyright (c) 1994, Regents of the University of California
 
11
 *
 
12
 *
 
13
 * IDENTIFICATION
 
14
 *        $PostgreSQL: pgsql/src/backend/storage/smgr/smgr.c,v 1.85 2005-01-10 20:02:22 tgl Exp $
 
15
 *
 
16
 *-------------------------------------------------------------------------
 
17
 */
 
18
#include "postgres.h"
 
19
 
 
20
#include "access/xact.h"
 
21
#include "commands/tablespace.h"
 
22
#include "storage/bufmgr.h"
 
23
#include "storage/freespace.h"
 
24
#include "storage/ipc.h"
 
25
#include "storage/smgr.h"
 
26
#include "utils/hsearch.h"
 
27
#include "utils/memutils.h"
 
28
 
 
29
 
 
30
/*
 
31
 * This struct of function pointers defines the API between smgr.c and
 
32
 * any individual storage manager module.  Note that smgr subfunctions are
 
33
 * generally expected to return TRUE on success, FALSE on error.  (For
 
34
 * nblocks and truncate we instead say that returning InvalidBlockNumber
 
35
 * indicates an error.)
 
36
 */
 
37
typedef struct f_smgr
 
38
{
 
39
        bool            (*smgr_init) (void);    /* may be NULL */
 
40
        bool            (*smgr_shutdown) (void);                /* may be NULL */
 
41
        bool            (*smgr_close) (SMgrRelation reln);
 
42
        bool            (*smgr_create) (SMgrRelation reln, bool isRedo);
 
43
        bool            (*smgr_unlink) (RelFileNode rnode, bool isRedo);
 
44
        bool            (*smgr_extend) (SMgrRelation reln, BlockNumber blocknum,
 
45
                                                                                        char *buffer, bool isTemp);
 
46
        bool            (*smgr_read) (SMgrRelation reln, BlockNumber blocknum,
 
47
                                                                                  char *buffer);
 
48
        bool            (*smgr_write) (SMgrRelation reln, BlockNumber blocknum,
 
49
                                                                                   char *buffer, bool isTemp);
 
50
        BlockNumber (*smgr_nblocks) (SMgrRelation reln);
 
51
        BlockNumber (*smgr_truncate) (SMgrRelation reln, BlockNumber nblocks,
 
52
                                                                                          bool isTemp);
 
53
        bool            (*smgr_immedsync) (SMgrRelation reln);
 
54
        bool            (*smgr_commit) (void);  /* may be NULL */
 
55
        bool            (*smgr_abort) (void);   /* may be NULL */
 
56
        bool            (*smgr_sync) (void);    /* may be NULL */
 
57
} f_smgr;
 
58
 
 
59
 
 
60
static const f_smgr smgrsw[] = {
 
61
        /* magnetic disk */
 
62
        {mdinit, NULL, mdclose, mdcreate, mdunlink, mdextend,
 
63
                mdread, mdwrite, mdnblocks, mdtruncate, mdimmedsync,
 
64
                NULL, NULL, mdsync
 
65
        }
 
66
};
 
67
 
 
68
static const int NSmgr = lengthof(smgrsw);
 
69
 
 
70
 
 
71
/*
 
72
 * Each backend has a hashtable that stores all extant SMgrRelation objects.
 
73
 */
 
74
static HTAB *SMgrRelationHash = NULL;
 
75
 
 
76
/*
 
77
 * We keep a list of all relations (represented as RelFileNode values)
 
78
 * that have been created or deleted in the current transaction.  When
 
79
 * a relation is created, we create the physical file immediately, but
 
80
 * remember it so that we can delete the file again if the current
 
81
 * transaction is aborted.      Conversely, a deletion request is NOT
 
82
 * executed immediately, but is just entered in the list.  When and if
 
83
 * the transaction commits, we can delete the physical file.
 
84
 *
 
85
 * To handle subtransactions, every entry is marked with its transaction
 
86
 * nesting level.  At subtransaction commit, we reassign the subtransaction's
 
87
 * entries to the parent nesting level.  At subtransaction abort, we can
 
88
 * immediately execute the abort-time actions for all entries of the current
 
89
 * nesting level.
 
90
 *
 
91
 * NOTE: the list is kept in TopMemoryContext to be sure it won't disappear
 
92
 * unbetimes.  It'd probably be OK to keep it in TopTransactionContext,
 
93
 * but I'm being paranoid.
 
94
 */
 
95
 
 
96
typedef struct PendingRelDelete
 
97
{
 
98
        RelFileNode relnode;            /* relation that may need to be deleted */
 
99
        int                     which;                  /* which storage manager? */
 
100
        bool            isTemp;                 /* is it a temporary relation? */
 
101
        bool            atCommit;               /* T=delete at commit; F=delete at abort */
 
102
        int                     nestLevel;              /* xact nesting level of request */
 
103
        struct PendingRelDelete *next;          /* linked-list link */
 
104
} PendingRelDelete;
 
105
 
 
106
static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */
 
107
 
 
108
 
 
109
/*
 
110
 * Declarations for smgr-related XLOG records
 
111
 *
 
112
 * Note: we log file creation and truncation here, but logging of deletion
 
113
 * actions is handled by xact.c, because it is part of transaction commit.
 
114
 */
 
115
 
 
116
/* XLOG gives us high 4 bits */
 
117
#define XLOG_SMGR_CREATE        0x10
 
118
#define XLOG_SMGR_TRUNCATE      0x20
 
119
 
 
120
typedef struct xl_smgr_create
 
121
{
 
122
        RelFileNode rnode;
 
123
} xl_smgr_create;
 
124
 
 
125
typedef struct xl_smgr_truncate
 
126
{
 
127
        BlockNumber blkno;
 
128
        RelFileNode rnode;
 
129
} xl_smgr_truncate;
 
130
 
 
131
 
 
132
/* local function prototypes */
 
133
static void smgrshutdown(int code, Datum arg);
 
134
static void smgr_internal_unlink(RelFileNode rnode, int which,
 
135
                                         bool isTemp, bool isRedo);
 
136
 
 
137
 
 
138
/*
 
139
 *      smgrinit(), smgrshutdown() -- Initialize or shut down all storage
 
140
 *                                                                managers.
 
141
 *
 
142
 * Note: in the normal multiprocess scenario with a postmaster, these are
 
143
 * called at postmaster start and stop, not per-backend.
 
144
 */
 
145
void
 
146
smgrinit(void)
 
147
{
 
148
        int                     i;
 
149
 
 
150
        for (i = 0; i < NSmgr; i++)
 
151
        {
 
152
                if (smgrsw[i].smgr_init)
 
153
                {
 
154
                        if (!(*(smgrsw[i].smgr_init)) ())
 
155
                                elog(FATAL, "smgr initialization failed on %s: %m",
 
156
                                         DatumGetCString(DirectFunctionCall1(smgrout,
 
157
                                                                                                         Int16GetDatum(i))));
 
158
                }
 
159
        }
 
160
 
 
161
        /* register the shutdown proc */
 
162
        on_proc_exit(smgrshutdown, 0);
 
163
}
 
164
 
 
165
static void
 
166
smgrshutdown(int code, Datum arg)
 
167
{
 
168
        int                     i;
 
169
 
 
170
        for (i = 0; i < NSmgr; i++)
 
171
        {
 
172
                if (smgrsw[i].smgr_shutdown)
 
173
                {
 
174
                        if (!(*(smgrsw[i].smgr_shutdown)) ())
 
175
                                elog(FATAL, "smgr shutdown failed on %s: %m",
 
176
                                         DatumGetCString(DirectFunctionCall1(smgrout,
 
177
                                                                                                         Int16GetDatum(i))));
 
178
                }
 
179
        }
 
180
}
 
181
 
 
182
/*
 
183
 *      smgropen() -- Return an SMgrRelation object, creating it if need be.
 
184
 *
 
185
 *              This does not attempt to actually open the object.
 
186
 */
 
187
SMgrRelation
 
188
smgropen(RelFileNode rnode)
 
189
{
 
190
        SMgrRelation reln;
 
191
        bool            found;
 
192
 
 
193
        if (SMgrRelationHash == NULL)
 
194
        {
 
195
                /* First time through: initialize the hash table */
 
196
                HASHCTL         ctl;
 
197
 
 
198
                MemSet(&ctl, 0, sizeof(ctl));
 
199
                ctl.keysize = sizeof(RelFileNode);
 
200
                ctl.entrysize = sizeof(SMgrRelationData);
 
201
                ctl.hash = tag_hash;
 
202
                SMgrRelationHash = hash_create("smgr relation table", 400,
 
203
                                                                           &ctl, HASH_ELEM | HASH_FUNCTION);
 
204
        }
 
205
 
 
206
        /* Look up or create an entry */
 
207
        reln = (SMgrRelation) hash_search(SMgrRelationHash,
 
208
                                                                          (void *) &rnode,
 
209
                                                                          HASH_ENTER, &found);
 
210
        if (reln == NULL)
 
211
                ereport(ERROR,
 
212
                                (errcode(ERRCODE_OUT_OF_MEMORY),
 
213
                                 errmsg("out of memory")));
 
214
 
 
215
        /* Initialize it if not present before */
 
216
        if (!found)
 
217
        {
 
218
                /* hash_search already filled in the lookup key */
 
219
                reln->smgr_owner = NULL;
 
220
                reln->smgr_which = 0;   /* we only have md.c at present */
 
221
                reln->md_fd = NULL;             /* mark it not open */
 
222
        }
 
223
 
 
224
        return reln;
 
225
}
 
226
 
 
227
/*
 
228
 * smgrsetowner() -- Establish a long-lived reference to an SMgrRelation object
 
229
 *
 
230
 * There can be only one owner at a time; this is sufficient since currently
 
231
 * the only such owners exist in the relcache.
 
232
 */
 
233
void
 
234
smgrsetowner(SMgrRelation *owner, SMgrRelation reln)
 
235
{
 
236
        /*
 
237
         * First, unhook any old owner.  (Normally there shouldn't be any, but
 
238
         * it seems possible that this can happen during swap_relation_files()
 
239
         * depending on the order of processing.  It's ok to close the old
 
240
         * relcache entry early in that case.)
 
241
         */
 
242
        if (reln->smgr_owner)
 
243
                *(reln->smgr_owner) = NULL;
 
244
 
 
245
        /* Now establish the ownership relationship. */
 
246
        reln->smgr_owner = owner;
 
247
        *owner = reln;
 
248
}
 
249
 
 
250
/*
 
251
 *      smgrclose() -- Close and delete an SMgrRelation object.
 
252
 */
 
253
void
 
254
smgrclose(SMgrRelation reln)
 
255
{
 
256
        SMgrRelation *owner;
 
257
 
 
258
        if (!(*(smgrsw[reln->smgr_which].smgr_close)) (reln))
 
259
                ereport(ERROR,
 
260
                                (errcode_for_file_access(),
 
261
                                 errmsg("could not close relation %u/%u/%u: %m",
 
262
                                                reln->smgr_rnode.spcNode,
 
263
                                                reln->smgr_rnode.dbNode,
 
264
                                                reln->smgr_rnode.relNode)));
 
265
 
 
266
        owner = reln->smgr_owner;
 
267
 
 
268
        if (hash_search(SMgrRelationHash,
 
269
                                        (void *) &(reln->smgr_rnode),
 
270
                                        HASH_REMOVE, NULL) == NULL)
 
271
                elog(ERROR, "SMgrRelation hashtable corrupted");
 
272
 
 
273
        /*
 
274
         * Unhook the owner pointer, if any.  We do this last since in the
 
275
         * remote possibility of failure above, the SMgrRelation object will still
 
276
         * exist.
 
277
         */
 
278
        if (owner)
 
279
                *owner = NULL;
 
280
}
 
281
 
 
282
/*
 
283
 *      smgrcloseall() -- Close all existing SMgrRelation objects.
 
284
 */
 
285
void
 
286
smgrcloseall(void)
 
287
{
 
288
        HASH_SEQ_STATUS status;
 
289
        SMgrRelation reln;
 
290
 
 
291
        /* Nothing to do if hashtable not set up */
 
292
        if (SMgrRelationHash == NULL)
 
293
                return;
 
294
 
 
295
        hash_seq_init(&status, SMgrRelationHash);
 
296
 
 
297
        while ((reln = (SMgrRelation) hash_seq_search(&status)) != NULL)
 
298
                smgrclose(reln);
 
299
}
 
300
 
 
301
/*
 
302
 *      smgrclosenode() -- Close SMgrRelation object for given RelFileNode,
 
303
 *                                         if one exists.
 
304
 *
 
305
 * This has the same effects as smgrclose(smgropen(rnode)), but it avoids
 
306
 * uselessly creating a hashtable entry only to drop it again when no
 
307
 * such entry exists already.
 
308
 */
 
309
void
 
310
smgrclosenode(RelFileNode rnode)
 
311
{
 
312
        SMgrRelation reln;
 
313
 
 
314
        /* Nothing to do if hashtable not set up */
 
315
        if (SMgrRelationHash == NULL)
 
316
                return;
 
317
 
 
318
        reln = (SMgrRelation) hash_search(SMgrRelationHash,
 
319
                                                                          (void *) &rnode,
 
320
                                                                          HASH_FIND, NULL);
 
321
        if (reln != NULL)
 
322
                smgrclose(reln);
 
323
}
 
324
 
 
325
/*
 
326
 *      smgrcreate() -- Create a new relation.
 
327
 *
 
328
 *              Given an already-created (but presumably unused) SMgrRelation,
 
329
 *              cause the underlying disk file or other storage to be created.
 
330
 *
 
331
 *              If isRedo is true, it is okay for the underlying file to exist
 
332
 *              already because we are in a WAL replay sequence.  In this case
 
333
 *              we should make no PendingRelDelete entry; the WAL sequence will
 
334
 *              tell whether to drop the file.
 
335
 */
 
336
void
 
337
smgrcreate(SMgrRelation reln, bool isTemp, bool isRedo)
 
338
{
 
339
        XLogRecPtr      lsn;
 
340
        XLogRecData rdata;
 
341
        xl_smgr_create xlrec;
 
342
        PendingRelDelete *pending;
 
343
 
 
344
        /*
 
345
         * We may be using the target table space for the first time in this
 
346
         * database, so create a per-database subdirectory if needed.
 
347
         *
 
348
         * XXX this is a fairly ugly violation of module layering, but this seems
 
349
         * to be the best place to put the check.  Maybe
 
350
         * TablespaceCreateDbspace should be here and not in
 
351
         * commands/tablespace.c?  But that would imply importing a lot of
 
352
         * stuff that smgr.c oughtn't know, either.
 
353
         */
 
354
        TablespaceCreateDbspace(reln->smgr_rnode.spcNode,
 
355
                                                        reln->smgr_rnode.dbNode,
 
356
                                                        isRedo);
 
357
 
 
358
        if (!(*(smgrsw[reln->smgr_which].smgr_create)) (reln, isRedo))
 
359
                ereport(ERROR,
 
360
                                (errcode_for_file_access(),
 
361
                                 errmsg("could not create relation %u/%u/%u: %m",
 
362
                                                reln->smgr_rnode.spcNode,
 
363
                                                reln->smgr_rnode.dbNode,
 
364
                                                reln->smgr_rnode.relNode)));
 
365
 
 
366
        if (isRedo)
 
367
                return;
 
368
 
 
369
        /*
 
370
         * Make a non-transactional XLOG entry showing the file creation. It's
 
371
         * non-transactional because we should replay it whether the
 
372
         * transaction commits or not; if not, the file will be dropped at
 
373
         * abort time.
 
374
         */
 
375
        xlrec.rnode = reln->smgr_rnode;
 
376
 
 
377
        rdata.buffer = InvalidBuffer;
 
378
        rdata.data = (char *) &xlrec;
 
379
        rdata.len = sizeof(xlrec);
 
380
        rdata.next = NULL;
 
381
 
 
382
        lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE | XLOG_NO_TRAN, &rdata);
 
383
 
 
384
        /* Add the relation to the list of stuff to delete at abort */
 
385
        pending = (PendingRelDelete *)
 
386
                MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
 
387
        pending->relnode = reln->smgr_rnode;
 
388
        pending->which = reln->smgr_which;
 
389
        pending->isTemp = isTemp;
 
390
        pending->atCommit = false;      /* delete if abort */
 
391
        pending->nestLevel = GetCurrentTransactionNestLevel();
 
392
        pending->next = pendingDeletes;
 
393
        pendingDeletes = pending;
 
394
}
 
395
 
 
396
/*
 
397
 *      smgrscheduleunlink() -- Schedule unlinking a relation at xact commit.
 
398
 *
 
399
 *              The relation is marked to be removed from the store if we
 
400
 *              successfully commit the current transaction.
 
401
 *
 
402
 * This also implies smgrclose() on the SMgrRelation object.
 
403
 */
 
404
void
 
405
smgrscheduleunlink(SMgrRelation reln, bool isTemp)
 
406
{
 
407
        PendingRelDelete *pending;
 
408
 
 
409
        /* Add the relation to the list of stuff to delete at commit */
 
410
        pending = (PendingRelDelete *)
 
411
                MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
 
412
        pending->relnode = reln->smgr_rnode;
 
413
        pending->which = reln->smgr_which;
 
414
        pending->isTemp = isTemp;
 
415
        pending->atCommit = true;       /* delete if commit */
 
416
        pending->nestLevel = GetCurrentTransactionNestLevel();
 
417
        pending->next = pendingDeletes;
 
418
        pendingDeletes = pending;
 
419
 
 
420
        /*
 
421
         * NOTE: if the relation was created in this transaction, it will now
 
422
         * be present in the pending-delete list twice, once with atCommit
 
423
         * true and once with atCommit false.  Hence, it will be physically
 
424
         * deleted at end of xact in either case (and the other entry will be
 
425
         * ignored by smgrDoPendingDeletes, so no error will occur).  We could
 
426
         * instead remove the existing list entry and delete the physical file
 
427
         * immediately, but for now I'll keep the logic simple.
 
428
         */
 
429
 
 
430
        /* Now close the file and throw away the hashtable entry */
 
431
        smgrclose(reln);
 
432
}
 
433
 
 
434
/*
 
435
 *      smgrdounlink() -- Immediately unlink a relation.
 
436
 *
 
437
 *              The relation is removed from the store.  This should not be used
 
438
 *              during transactional operations, since it can't be undone.
 
439
 *
 
440
 *              If isRedo is true, it is okay for the underlying file to be gone
 
441
 *              already.  (In practice isRedo will always be true.)
 
442
 *
 
443
 * This also implies smgrclose() on the SMgrRelation object.
 
444
 */
 
445
void
 
446
smgrdounlink(SMgrRelation reln, bool isTemp, bool isRedo)
 
447
{
 
448
        RelFileNode rnode = reln->smgr_rnode;
 
449
        int                     which = reln->smgr_which;
 
450
 
 
451
        /* Close the file and throw away the hashtable entry */
 
452
        smgrclose(reln);
 
453
 
 
454
        smgr_internal_unlink(rnode, which, isTemp, isRedo);
 
455
}
 
456
 
 
457
/*
 
458
 * Shared subroutine that actually does the unlink ...
 
459
 */
 
460
static void
 
461
smgr_internal_unlink(RelFileNode rnode, int which, bool isTemp, bool isRedo)
 
462
{
 
463
        /*
 
464
         * Get rid of any leftover buffers for the rel (shouldn't be any in
 
465
         * the commit case, but there can be in the abort case).
 
466
         */
 
467
        DropRelFileNodeBuffers(rnode, isTemp, 0);
 
468
 
 
469
        /*
 
470
         * Tell the free space map to forget this relation.  It won't be
 
471
         * accessed any more anyway, but we may as well recycle the map space
 
472
         * quickly.
 
473
         */
 
474
        FreeSpaceMapForgetRel(&rnode);
 
475
 
 
476
        /*
 
477
         * And delete the physical files.
 
478
         *
 
479
         * Note: we treat deletion failure as a WARNING, not an error, because
 
480
         * we've already decided to commit or abort the current xact.
 
481
         */
 
482
        if (!(*(smgrsw[which].smgr_unlink)) (rnode, isRedo))
 
483
                ereport(WARNING,
 
484
                                (errcode_for_file_access(),
 
485
                                 errmsg("could not remove relation %u/%u/%u: %m",
 
486
                                                rnode.spcNode,
 
487
                                                rnode.dbNode,
 
488
                                                rnode.relNode)));
 
489
}
 
490
 
 
491
/*
 
492
 *      smgrextend() -- Add a new block to a file.
 
493
 *
 
494
 *              The semantics are basically the same as smgrwrite(): write at the
 
495
 *              specified position.  However, we are expecting to extend the
 
496
 *              relation (ie, blocknum is the current EOF), and so in case of
 
497
 *              failure we clean up by truncating.
 
498
 */
 
499
void
 
500
smgrextend(SMgrRelation reln, BlockNumber blocknum, char *buffer, bool isTemp)
 
501
{
 
502
        if (!(*(smgrsw[reln->smgr_which].smgr_extend)) (reln, blocknum, buffer,
 
503
                                                                                                        isTemp))
 
504
                ereport(ERROR,
 
505
                                (errcode_for_file_access(),
 
506
                                 errmsg("could not extend relation %u/%u/%u: %m",
 
507
                                                reln->smgr_rnode.spcNode,
 
508
                                                reln->smgr_rnode.dbNode,
 
509
                                                reln->smgr_rnode.relNode),
 
510
                                 errhint("Check free disk space.")));
 
511
}
 
512
 
 
513
/*
 
514
 *      smgrread() -- read a particular block from a relation into the supplied
 
515
 *                                buffer.
 
516
 *
 
517
 *              This routine is called from the buffer manager in order to
 
518
 *              instantiate pages in the shared buffer cache.  All storage managers
 
519
 *              return pages in the format that POSTGRES expects.
 
520
 */
 
521
void
 
522
smgrread(SMgrRelation reln, BlockNumber blocknum, char *buffer)
 
523
{
 
524
        if (!(*(smgrsw[reln->smgr_which].smgr_read)) (reln, blocknum, buffer))
 
525
                ereport(ERROR,
 
526
                                (errcode_for_file_access(),
 
527
                           errmsg("could not read block %u of relation %u/%u/%u: %m",
 
528
                                          blocknum,
 
529
                                          reln->smgr_rnode.spcNode,
 
530
                                          reln->smgr_rnode.dbNode,
 
531
                                          reln->smgr_rnode.relNode)));
 
532
}
 
533
 
 
534
/*
 
535
 *      smgrwrite() -- Write the supplied buffer out.
 
536
 *
 
537
 *              This is not a synchronous write -- the block is not necessarily
 
538
 *              on disk at return, only dumped out to the kernel.  However,
 
539
 *              provisions will be made to fsync the write before the next checkpoint.
 
540
 *
 
541
 *              isTemp indicates that the relation is a temp table (ie, is managed
 
542
 *              by the local-buffer manager).  In this case no provisions need be
 
543
 *              made to fsync the write before checkpointing.
 
544
 */
 
545
void
 
546
smgrwrite(SMgrRelation reln, BlockNumber blocknum, char *buffer, bool isTemp)
 
547
{
 
548
        if (!(*(smgrsw[reln->smgr_which].smgr_write)) (reln, blocknum, buffer,
 
549
                                                                                                   isTemp))
 
550
                ereport(ERROR,
 
551
                                (errcode_for_file_access(),
 
552
                          errmsg("could not write block %u of relation %u/%u/%u: %m",
 
553
                                         blocknum,
 
554
                                         reln->smgr_rnode.spcNode,
 
555
                                         reln->smgr_rnode.dbNode,
 
556
                                         reln->smgr_rnode.relNode)));
 
557
}
 
558
 
 
559
/*
 
560
 *      smgrnblocks() -- Calculate the number of blocks in the
 
561
 *                                       supplied relation.
 
562
 *
 
563
 *              Returns the number of blocks on success, aborts the current
 
564
 *              transaction on failure.
 
565
 */
 
566
BlockNumber
 
567
smgrnblocks(SMgrRelation reln)
 
568
{
 
569
        BlockNumber nblocks;
 
570
 
 
571
        nblocks = (*(smgrsw[reln->smgr_which].smgr_nblocks)) (reln);
 
572
 
 
573
        /*
 
574
         * NOTE: if a relation ever did grow to 2^32-1 blocks, this code would
 
575
         * fail --- but that's a good thing, because it would stop us from
 
576
         * extending the rel another block and having a block whose number
 
577
         * actually is InvalidBlockNumber.
 
578
         */
 
579
        if (nblocks == InvalidBlockNumber)
 
580
                ereport(ERROR,
 
581
                                (errcode_for_file_access(),
 
582
                                 errmsg("could not count blocks of relation %u/%u/%u: %m",
 
583
                                                reln->smgr_rnode.spcNode,
 
584
                                                reln->smgr_rnode.dbNode,
 
585
                                                reln->smgr_rnode.relNode)));
 
586
 
 
587
        return nblocks;
 
588
}
 
589
 
 
590
/*
 
591
 *      smgrtruncate() -- Truncate supplied relation to the specified number
 
592
 *                                        of blocks
 
593
 *
 
594
 *              Returns the number of blocks on success, aborts the current
 
595
 *              transaction on failure.
 
596
 */
 
597
BlockNumber
 
598
smgrtruncate(SMgrRelation reln, BlockNumber nblocks, bool isTemp)
 
599
{
 
600
        BlockNumber newblks;
 
601
 
 
602
        /*
 
603
         * Tell the free space map to forget anything it may have stored for
 
604
         * the about-to-be-deleted blocks.      We want to be sure it won't return
 
605
         * bogus block numbers later on.
 
606
         */
 
607
        FreeSpaceMapTruncateRel(&reln->smgr_rnode, nblocks);
 
608
 
 
609
        /* Do the truncation */
 
610
        newblks = (*(smgrsw[reln->smgr_which].smgr_truncate)) (reln, nblocks,
 
611
                                                                                                                   isTemp);
 
612
        if (newblks == InvalidBlockNumber)
 
613
                ereport(ERROR,
 
614
                                (errcode_for_file_access(),
 
615
                  errmsg("could not truncate relation %u/%u/%u to %u blocks: %m",
 
616
                                 reln->smgr_rnode.spcNode,
 
617
                                 reln->smgr_rnode.dbNode,
 
618
                                 reln->smgr_rnode.relNode,
 
619
                                 nblocks)));
 
620
 
 
621
        if (!isTemp)
 
622
        {
 
623
                /*
 
624
                 * Make a non-transactional XLOG entry showing the file
 
625
                 * truncation. It's non-transactional because we should replay it
 
626
                 * whether the transaction commits or not; the underlying file
 
627
                 * change is certainly not reversible.
 
628
                 */
 
629
                XLogRecPtr      lsn;
 
630
                XLogRecData rdata;
 
631
                xl_smgr_truncate xlrec;
 
632
 
 
633
                xlrec.blkno = newblks;
 
634
                xlrec.rnode = reln->smgr_rnode;
 
635
 
 
636
                rdata.buffer = InvalidBuffer;
 
637
                rdata.data = (char *) &xlrec;
 
638
                rdata.len = sizeof(xlrec);
 
639
                rdata.next = NULL;
 
640
 
 
641
                lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_TRUNCATE | XLOG_NO_TRAN,
 
642
                                                 &rdata);
 
643
        }
 
644
 
 
645
        return newblks;
 
646
}
 
647
 
 
648
/*
 
649
 *      smgrimmedsync() -- Force the specified relation to stable storage.
 
650
 *
 
651
 *              Synchronously force all of the specified relation down to disk.
 
652
 *
 
653
 *              This is useful for building completely new relations (eg, new
 
654
 *              indexes).  Instead of incrementally WAL-logging the index build
 
655
 *              steps, we can just write completed index pages to disk with smgrwrite
 
656
 *              or smgrextend, and then fsync the completed index file before
 
657
 *              committing the transaction.  (This is sufficient for purposes of
 
658
 *              crash recovery, since it effectively duplicates forcing a checkpoint
 
659
 *              for the completed index.  But it is *not* sufficient if one wishes
 
660
 *              to use the WAL log for PITR or replication purposes: in that case
 
661
 *              we have to make WAL entries as well.)
 
662
 *
 
663
 *              The preceding writes should specify isTemp = true to avoid
 
664
 *              duplicative fsyncs.
 
665
 */
 
666
void
 
667
smgrimmedsync(SMgrRelation reln)
 
668
{
 
669
        if (!(*(smgrsw[reln->smgr_which].smgr_immedsync)) (reln))
 
670
                ereport(ERROR,
 
671
                                (errcode_for_file_access(),
 
672
                                 errmsg("could not sync relation %u/%u/%u: %m",
 
673
                                                reln->smgr_rnode.spcNode,
 
674
                                                reln->smgr_rnode.dbNode,
 
675
                                                reln->smgr_rnode.relNode)));
 
676
}
 
677
 
 
678
/*
 
679
 *      smgrDoPendingDeletes() -- Take care of relation deletes at end of xact.
 
680
 *
 
681
 * This also runs when aborting a subxact; we want to clean up a failed
 
682
 * subxact immediately.
 
683
 */
 
684
void
 
685
smgrDoPendingDeletes(bool isCommit)
 
686
{
 
687
        int                     nestLevel = GetCurrentTransactionNestLevel();
 
688
        PendingRelDelete *pending;
 
689
        PendingRelDelete *prev;
 
690
        PendingRelDelete *next;
 
691
 
 
692
        prev = NULL;
 
693
        for (pending = pendingDeletes; pending != NULL; pending = next)
 
694
        {
 
695
                next = pending->next;
 
696
                if (pending->nestLevel < nestLevel)
 
697
                {
 
698
                        /* outer-level entries should not be processed yet */
 
699
                        prev = pending;
 
700
                }
 
701
                else
 
702
                {
 
703
                        /* unlink list entry first, so we don't retry on failure */
 
704
                        if (prev)
 
705
                                prev->next = next;
 
706
                        else
 
707
                                pendingDeletes = next;
 
708
                        /* do deletion if called for */
 
709
                        if (pending->atCommit == isCommit)
 
710
                                smgr_internal_unlink(pending->relnode,
 
711
                                                                         pending->which,
 
712
                                                                         pending->isTemp,
 
713
                                                                         false);
 
714
                        /* must explicitly free the list entry */
 
715
                        pfree(pending);
 
716
                        /* prev does not change */
 
717
                }
 
718
        }
 
719
}
 
720
 
 
721
/*
 
722
 * smgrGetPendingDeletes() -- Get a list of relations to be deleted.
 
723
 *
 
724
 * The return value is the number of relations scheduled for termination.
 
725
 * *ptr is set to point to a freshly-palloc'd array of RelFileNodes.
 
726
 * If there are no relations to be deleted, *ptr is set to NULL.
 
727
 *
 
728
 * Note that the list does not include anything scheduled for termination
 
729
 * by upper-level transactions.
 
730
 */
 
731
int
 
732
smgrGetPendingDeletes(bool forCommit, RelFileNode **ptr)
 
733
{
 
734
        int                     nestLevel = GetCurrentTransactionNestLevel();
 
735
        int                     nrels;
 
736
        RelFileNode *rptr;
 
737
        PendingRelDelete *pending;
 
738
 
 
739
        nrels = 0;
 
740
        for (pending = pendingDeletes; pending != NULL; pending = pending->next)
 
741
        {
 
742
                if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit)
 
743
                        nrels++;
 
744
        }
 
745
        if (nrels == 0)
 
746
        {
 
747
                *ptr = NULL;
 
748
                return 0;
 
749
        }
 
750
        rptr = (RelFileNode *) palloc(nrels * sizeof(RelFileNode));
 
751
        *ptr = rptr;
 
752
        for (pending = pendingDeletes; pending != NULL; pending = pending->next)
 
753
        {
 
754
                if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit)
 
755
                        *rptr++ = pending->relnode;
 
756
        }
 
757
        return nrels;
 
758
}
 
759
 
 
760
/*
 
761
 * AtSubCommit_smgr() --- Take care of subtransaction commit.
 
762
 *
 
763
 * Reassign all items in the pending-deletes list to the parent transaction.
 
764
 */
 
765
void
 
766
AtSubCommit_smgr(void)
 
767
{
 
768
        int                     nestLevel = GetCurrentTransactionNestLevel();
 
769
        PendingRelDelete *pending;
 
770
 
 
771
        for (pending = pendingDeletes; pending != NULL; pending = pending->next)
 
772
        {
 
773
                if (pending->nestLevel >= nestLevel)
 
774
                        pending->nestLevel = nestLevel - 1;
 
775
        }
 
776
}
 
777
 
 
778
/*
 
779
 * AtSubAbort_smgr() --- Take care of subtransaction abort.
 
780
 *
 
781
 * Delete created relations and forget about deleted relations.
 
782
 * We can execute these operations immediately because we know this
 
783
 * subtransaction will not commit.
 
784
 */
 
785
void
 
786
AtSubAbort_smgr(void)
 
787
{
 
788
        smgrDoPendingDeletes(false);
 
789
}
 
790
 
 
791
/*
 
792
 *      smgrcommit() -- Prepare to commit changes made during the current
 
793
 *                                      transaction.
 
794
 *
 
795
 *              This is called before we actually commit.
 
796
 */
 
797
void
 
798
smgrcommit(void)
 
799
{
 
800
        int                     i;
 
801
 
 
802
        for (i = 0; i < NSmgr; i++)
 
803
        {
 
804
                if (smgrsw[i].smgr_commit)
 
805
                {
 
806
                        if (!(*(smgrsw[i].smgr_commit)) ())
 
807
                                elog(ERROR, "transaction commit failed on %s: %m",
 
808
                                         DatumGetCString(DirectFunctionCall1(smgrout,
 
809
                                                                                                         Int16GetDatum(i))));
 
810
                }
 
811
        }
 
812
}
 
813
 
 
814
/*
 
815
 *      smgrabort() -- Clean up after transaction abort.
 
816
 */
 
817
void
 
818
smgrabort(void)
 
819
{
 
820
        int                     i;
 
821
 
 
822
        for (i = 0; i < NSmgr; i++)
 
823
        {
 
824
                if (smgrsw[i].smgr_abort)
 
825
                {
 
826
                        if (!(*(smgrsw[i].smgr_abort)) ())
 
827
                                elog(ERROR, "transaction abort failed on %s: %m",
 
828
                                         DatumGetCString(DirectFunctionCall1(smgrout,
 
829
                                                                                                         Int16GetDatum(i))));
 
830
                }
 
831
        }
 
832
}
 
833
 
 
834
/*
 
835
 *      smgrsync() -- Sync files to disk at checkpoint time.
 
836
 */
 
837
void
 
838
smgrsync(void)
 
839
{
 
840
        int                     i;
 
841
 
 
842
        for (i = 0; i < NSmgr; i++)
 
843
        {
 
844
                if (smgrsw[i].smgr_sync)
 
845
                {
 
846
                        if (!(*(smgrsw[i].smgr_sync)) ())
 
847
                                elog(ERROR, "storage sync failed on %s: %m",
 
848
                                         DatumGetCString(DirectFunctionCall1(smgrout,
 
849
                                                                                                         Int16GetDatum(i))));
 
850
                }
 
851
        }
 
852
}
 
853
 
 
854
 
 
855
void
 
856
smgr_redo(XLogRecPtr lsn, XLogRecord *record)
 
857
{
 
858
        uint8           info = record->xl_info & ~XLR_INFO_MASK;
 
859
 
 
860
        if (info == XLOG_SMGR_CREATE)
 
861
        {
 
862
                xl_smgr_create *xlrec = (xl_smgr_create *) XLogRecGetData(record);
 
863
                SMgrRelation reln;
 
864
 
 
865
                reln = smgropen(xlrec->rnode);
 
866
                smgrcreate(reln, false, true);
 
867
        }
 
868
        else if (info == XLOG_SMGR_TRUNCATE)
 
869
        {
 
870
                xl_smgr_truncate *xlrec = (xl_smgr_truncate *) XLogRecGetData(record);
 
871
                SMgrRelation reln;
 
872
                BlockNumber newblks;
 
873
 
 
874
                reln = smgropen(xlrec->rnode);
 
875
 
 
876
                /*
 
877
                 * First, force bufmgr to drop any buffers it has for the to-be-
 
878
                 * truncated blocks.  We must do this, else subsequent
 
879
                 * XLogReadBuffer operations will not re-extend the file properly.
 
880
                 */
 
881
                DropRelFileNodeBuffers(xlrec->rnode, false, xlrec->blkno);
 
882
 
 
883
                /* Can't use smgrtruncate because it would try to xlog */
 
884
 
 
885
                /*
 
886
                 * Tell the free space map to forget anything it may have stored
 
887
                 * for the about-to-be-deleted blocks.  We want to be sure it
 
888
                 * won't return bogus block numbers later on.
 
889
                 */
 
890
                FreeSpaceMapTruncateRel(&reln->smgr_rnode, xlrec->blkno);
 
891
 
 
892
                /* Do the truncation */
 
893
                newblks = (*(smgrsw[reln->smgr_which].smgr_truncate)) (reln,
 
894
                                                                                                                        xlrec->blkno,
 
895
                                                                                                                           false);
 
896
                if (newblks == InvalidBlockNumber)
 
897
                        ereport(WARNING,
 
898
                                        (errcode_for_file_access(),
 
899
                                         errmsg("could not truncate relation %u/%u/%u to %u blocks: %m",
 
900
                                                        reln->smgr_rnode.spcNode,
 
901
                                                        reln->smgr_rnode.dbNode,
 
902
                                                        reln->smgr_rnode.relNode,
 
903
                                                        xlrec->blkno)));
 
904
        }
 
905
        else
 
906
                elog(PANIC, "smgr_redo: unknown op code %u", info);
 
907
}
 
908
 
 
909
void
 
910
smgr_undo(XLogRecPtr lsn, XLogRecord *record)
 
911
{
 
912
        /* Since we have no transactional WAL entries, should never undo */
 
913
        elog(PANIC, "smgr_undo: cannot undo");
 
914
}
 
915
 
 
916
void
 
917
smgr_desc(char *buf, uint8 xl_info, char *rec)
 
918
{
 
919
        uint8           info = xl_info & ~XLR_INFO_MASK;
 
920
 
 
921
        if (info == XLOG_SMGR_CREATE)
 
922
        {
 
923
                xl_smgr_create *xlrec = (xl_smgr_create *) rec;
 
924
 
 
925
                sprintf(buf + strlen(buf), "file create: %u/%u/%u",
 
926
                                xlrec->rnode.spcNode, xlrec->rnode.dbNode,
 
927
                                xlrec->rnode.relNode);
 
928
        }
 
929
        else if (info == XLOG_SMGR_TRUNCATE)
 
930
        {
 
931
                xl_smgr_truncate *xlrec = (xl_smgr_truncate *) rec;
 
932
 
 
933
                sprintf(buf + strlen(buf), "file truncate: %u/%u/%u to %u blocks",
 
934
                                xlrec->rnode.spcNode, xlrec->rnode.dbNode,
 
935
                                xlrec->rnode.relNode, xlrec->blkno);
 
936
        }
 
937
        else
 
938
                strcat(buf, "UNKNOWN");
 
939
}