Line data Source code
1 : /*-------------------------------------------------------------------------
2 : * relpath.c
3 : * Shared frontend/backend code to compute pathnames of relation files
4 : *
5 : * This module also contains some logic associated with fork names.
6 : *
7 : * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
8 : * Portions Copyright (c) 1994, Regents of the University of California
9 : *
10 : * IDENTIFICATION
11 : * src/common/relpath.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : #ifndef FRONTEND
16 : #include "postgres.h"
17 : #else
18 : #include "postgres_fe.h"
19 : #endif
20 :
21 : #include "catalog/catalog.h"
22 : #include "catalog/pg_tablespace.h"
23 : #include "common/relpath.h"
24 : #include "storage/backendid.h"
25 :
26 :
27 : /*
28 : * Lookup table of fork name by fork number.
29 : *
30 : * If you add a new entry, remember to update the errhint in
31 : * forkname_to_number() below, and update the SGML documentation for
32 : * pg_relation_size().
33 : */
34 : const char *const forkNames[] = {
35 : "main", /* MAIN_FORKNUM */
36 : "fsm", /* FSM_FORKNUM */
37 : "vm", /* VISIBILITYMAP_FORKNUM */
38 : "init" /* INIT_FORKNUM */
39 : };
40 :
41 : /*
42 : * forkname_to_number - look up fork number by name
43 : *
44 : * In backend, we throw an error for no match; in frontend, we just
45 : * return InvalidForkNumber.
46 : */
47 : ForkNumber
48 0 : forkname_to_number(const char *forkName)
49 : {
50 : ForkNumber forkNum;
51 :
52 0 : for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
53 0 : if (strcmp(forkNames[forkNum], forkName) == 0)
54 0 : return forkNum;
55 :
56 : #ifndef FRONTEND
57 0 : ereport(ERROR,
58 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
59 : errmsg("invalid fork name"),
60 : errhint("Valid fork names are \"main\", \"fsm\", "
61 : "\"vm\", and \"init\".")));
62 : #endif
63 :
64 : return InvalidForkNumber;
65 : }
66 :
67 : /*
68 : * forkname_chars
69 : * We use this to figure out whether a filename could be a relation
70 : * fork (as opposed to an oddly named stray file that somehow ended
71 : * up in the database directory). If the passed string begins with
72 : * a fork name (other than the main fork name), we return its length,
73 : * and set *fork (if not NULL) to the fork number. If not, we return 0.
74 : *
75 : * Note that the present coding assumes that there are no fork names which
76 : * are prefixes of other fork names.
77 : */
78 : int
79 0 : forkname_chars(const char *str, ForkNumber *fork)
80 : {
81 : ForkNumber forkNum;
82 :
83 0 : for (forkNum = 1; forkNum <= MAX_FORKNUM; forkNum++)
84 : {
85 0 : int len = strlen(forkNames[forkNum]);
86 :
87 0 : if (strncmp(forkNames[forkNum], str, len) == 0)
88 : {
89 0 : if (fork)
90 0 : *fork = forkNum;
91 0 : return len;
92 : }
93 : }
94 0 : if (fork)
95 0 : *fork = InvalidForkNumber;
96 0 : return 0;
97 : }
98 :
99 :
100 : /*
101 : * GetDatabasePath - construct path to a database directory
102 : *
103 : * Result is a palloc'd string.
104 : *
105 : * XXX this must agree with GetRelationPath()!
106 : */
107 : char *
108 4759 : GetDatabasePath(Oid dbNode, Oid spcNode)
109 : {
110 4759 : if (spcNode == GLOBALTABLESPACE_OID)
111 : {
112 : /* Shared system relations live in {datadir}/global */
113 0 : Assert(dbNode == 0);
114 0 : return pstrdup("global");
115 : }
116 4759 : else if (spcNode == DEFAULTTABLESPACE_OID)
117 : {
118 : /* The default tablespace is {datadir}/base */
119 4740 : return psprintf("base/%u", dbNode);
120 : }
121 : else
122 : {
123 : /* All other tablespaces are accessed via symlinks */
124 19 : return psprintf("pg_tblspc/%u/%s/%u",
125 : spcNode, TABLESPACE_VERSION_DIRECTORY, dbNode);
126 : }
127 : }
128 :
129 : /*
130 : * GetRelationPath - construct path to a relation's file
131 : *
132 : * Result is a palloc'd string.
133 : *
134 : * Note: ideally, backendId would be declared as type BackendId, but relpath.h
135 : * would have to include a backend-only header to do that; doesn't seem worth
136 : * the trouble considering BackendId is just int anyway.
137 : */
138 : char *
139 45642 : GetRelationPath(Oid dbNode, Oid spcNode, Oid relNode,
140 : int backendId, ForkNumber forkNumber)
141 : {
142 : char *path;
143 :
144 45642 : if (spcNode == GLOBALTABLESPACE_OID)
145 : {
146 : /* Shared system relations live in {datadir}/global */
147 931 : Assert(dbNode == 0);
148 931 : Assert(backendId == InvalidBackendId);
149 931 : if (forkNumber != MAIN_FORKNUM)
150 394 : path = psprintf("global/%u_%s",
151 : relNode, forkNames[forkNumber]);
152 : else
153 537 : path = psprintf("global/%u", relNode);
154 : }
155 44711 : else if (spcNode == DEFAULTTABLESPACE_OID)
156 : {
157 : /* The default tablespace is {datadir}/base */
158 44502 : if (backendId == InvalidBackendId)
159 : {
160 39322 : if (forkNumber != MAIN_FORKNUM)
161 17419 : path = psprintf("base/%u/%u_%s",
162 : dbNode, relNode,
163 : forkNames[forkNumber]);
164 : else
165 21903 : path = psprintf("base/%u/%u",
166 : dbNode, relNode);
167 : }
168 : else
169 : {
170 5180 : if (forkNumber != MAIN_FORKNUM)
171 2445 : path = psprintf("base/%u/t%d_%u_%s",
172 : dbNode, backendId, relNode,
173 : forkNames[forkNumber]);
174 : else
175 2735 : path = psprintf("base/%u/t%d_%u",
176 : dbNode, backendId, relNode);
177 : }
178 : }
179 : else
180 : {
181 : /* All other tablespaces are accessed via symlinks */
182 209 : if (backendId == InvalidBackendId)
183 : {
184 209 : if (forkNumber != MAIN_FORKNUM)
185 91 : path = psprintf("pg_tblspc/%u/%s/%u/%u_%s",
186 : spcNode, TABLESPACE_VERSION_DIRECTORY,
187 : dbNode, relNode,
188 : forkNames[forkNumber]);
189 : else
190 118 : path = psprintf("pg_tblspc/%u/%s/%u/%u",
191 : spcNode, TABLESPACE_VERSION_DIRECTORY,
192 : dbNode, relNode);
193 : }
194 : else
195 : {
196 0 : if (forkNumber != MAIN_FORKNUM)
197 0 : path = psprintf("pg_tblspc/%u/%s/%u/t%d_%u_%s",
198 : spcNode, TABLESPACE_VERSION_DIRECTORY,
199 : dbNode, backendId, relNode,
200 : forkNames[forkNumber]);
201 : else
202 0 : path = psprintf("pg_tblspc/%u/%s/%u/t%d_%u",
203 : spcNode, TABLESPACE_VERSION_DIRECTORY,
204 : dbNode, backendId, relNode);
205 : }
206 : }
207 45642 : return path;
208 : }
|