1 | /*------------------------------------------------------------------------- |
2 | * |
3 | * tuptoaster.h |
4 | * POSTGRES definitions for external and compressed storage |
5 | * of variable size attributes. |
6 | * |
7 | * Copyright (c) 2000-2019, PostgreSQL Global Development Group |
8 | * |
9 | * src/include/access/tuptoaster.h |
10 | * |
11 | *------------------------------------------------------------------------- |
12 | */ |
13 | #ifndef TUPTOASTER_H |
14 | #define TUPTOASTER_H |
15 | |
16 | #include "access/htup_details.h" |
17 | #include "storage/lockdefs.h" |
18 | #include "utils/relcache.h" |
19 | |
20 | /* |
21 | * This enables de-toasting of index entries. Needed until VACUUM is |
22 | * smart enough to rebuild indexes from scratch. |
23 | */ |
24 | #define TOAST_INDEX_HACK |
25 | |
26 | |
27 | /* |
28 | * Find the maximum size of a tuple if there are to be N tuples per page. |
29 | */ |
30 | #define MaximumBytesPerTuple(tuplesPerPage) \ |
31 | MAXALIGN_DOWN((BLCKSZ - \ |
32 | MAXALIGN(SizeOfPageHeaderData + (tuplesPerPage) * sizeof(ItemIdData))) \ |
33 | / (tuplesPerPage)) |
34 | |
35 | /* |
36 | * These symbols control toaster activation. If a tuple is larger than |
37 | * TOAST_TUPLE_THRESHOLD, we will try to toast it down to no more than |
38 | * TOAST_TUPLE_TARGET bytes through compressing compressible fields and |
39 | * moving EXTENDED and EXTERNAL data out-of-line. |
40 | * |
41 | * The numbers need not be the same, though they currently are. It doesn't |
42 | * make sense for TARGET to exceed THRESHOLD, but it could be useful to make |
43 | * it be smaller. |
44 | * |
45 | * Currently we choose both values to match the largest tuple size for which |
46 | * TOAST_TUPLES_PER_PAGE tuples can fit on a heap page. |
47 | * |
48 | * XXX while these can be modified without initdb, some thought needs to be |
49 | * given to needs_toast_table() in toasting.c before unleashing random |
50 | * changes. Also see LOBLKSIZE in large_object.h, which can *not* be |
51 | * changed without initdb. |
52 | */ |
53 | #define TOAST_TUPLES_PER_PAGE 4 |
54 | |
55 | #define TOAST_TUPLE_THRESHOLD MaximumBytesPerTuple(TOAST_TUPLES_PER_PAGE) |
56 | |
57 | #define TOAST_TUPLE_TARGET TOAST_TUPLE_THRESHOLD |
58 | |
59 | /* |
60 | * The code will also consider moving MAIN data out-of-line, but only as a |
61 | * last resort if the previous steps haven't reached the target tuple size. |
62 | * In this phase we use a different target size, currently equal to the |
63 | * largest tuple that will fit on a heap page. This is reasonable since |
64 | * the user has told us to keep the data in-line if at all possible. |
65 | */ |
66 | #define TOAST_TUPLES_PER_PAGE_MAIN 1 |
67 | |
68 | #define TOAST_TUPLE_TARGET_MAIN MaximumBytesPerTuple(TOAST_TUPLES_PER_PAGE_MAIN) |
69 | |
70 | /* |
71 | * If an index value is larger than TOAST_INDEX_TARGET, we will try to |
72 | * compress it (we can't move it out-of-line, however). Note that this |
73 | * number is per-datum, not per-tuple, for simplicity in index_form_tuple(). |
74 | */ |
75 | #define TOAST_INDEX_TARGET (MaxHeapTupleSize / 16) |
76 | |
77 | /* |
78 | * When we store an oversize datum externally, we divide it into chunks |
79 | * containing at most TOAST_MAX_CHUNK_SIZE data bytes. This number *must* |
80 | * be small enough that the completed toast-table tuple (including the |
81 | * ID and sequence fields and all overhead) will fit on a page. |
82 | * The coding here sets the size on the theory that we want to fit |
83 | * EXTERN_TUPLES_PER_PAGE tuples of maximum size onto a page. |
84 | * |
85 | * NB: Changing TOAST_MAX_CHUNK_SIZE requires an initdb. |
86 | */ |
87 | #define EXTERN_TUPLES_PER_PAGE 4 /* tweak only this */ |
88 | |
89 | #define EXTERN_TUPLE_MAX_SIZE MaximumBytesPerTuple(EXTERN_TUPLES_PER_PAGE) |
90 | |
91 | #define TOAST_MAX_CHUNK_SIZE \ |
92 | (EXTERN_TUPLE_MAX_SIZE - \ |
93 | MAXALIGN(SizeofHeapTupleHeader) - \ |
94 | sizeof(Oid) - \ |
95 | sizeof(int32) - \ |
96 | VARHDRSZ) |
97 | |
98 | /* Size of an EXTERNAL datum that contains a standard TOAST pointer */ |
99 | #define TOAST_POINTER_SIZE (VARHDRSZ_EXTERNAL + sizeof(varatt_external)) |
100 | |
101 | /* Size of an EXTERNAL datum that contains an indirection pointer */ |
102 | #define INDIRECT_POINTER_SIZE (VARHDRSZ_EXTERNAL + sizeof(varatt_indirect)) |
103 | |
104 | /* |
105 | * Testing whether an externally-stored value is compressed now requires |
106 | * comparing extsize (the actual length of the external data) to rawsize |
107 | * (the original uncompressed datum's size). The latter includes VARHDRSZ |
108 | * overhead, the former doesn't. We never use compression unless it actually |
109 | * saves space, so we expect either equality or less-than. |
110 | */ |
111 | #define VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer) \ |
112 | ((toast_pointer).va_extsize < (toast_pointer).va_rawsize - VARHDRSZ) |
113 | |
114 | /* |
115 | * Macro to fetch the possibly-unaligned contents of an EXTERNAL datum |
116 | * into a local "struct varatt_external" toast pointer. This should be |
117 | * just a memcpy, but some versions of gcc seem to produce broken code |
118 | * that assumes the datum contents are aligned. Introducing an explicit |
119 | * intermediate "varattrib_1b_e *" variable seems to fix it. |
120 | */ |
121 | #define VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr) \ |
122 | do { \ |
123 | varattrib_1b_e *attre = (varattrib_1b_e *) (attr); \ |
124 | Assert(VARATT_IS_EXTERNAL(attre)); \ |
125 | Assert(VARSIZE_EXTERNAL(attre) == sizeof(toast_pointer) + VARHDRSZ_EXTERNAL); \ |
126 | memcpy(&(toast_pointer), VARDATA_EXTERNAL(attre), sizeof(toast_pointer)); \ |
127 | } while (0) |
128 | |
129 | /* ---------- |
130 | * toast_insert_or_update - |
131 | * |
132 | * Called by heap_insert() and heap_update(). |
133 | * ---------- |
134 | */ |
135 | extern HeapTuple toast_insert_or_update(Relation rel, |
136 | HeapTuple newtup, HeapTuple oldtup, |
137 | int options); |
138 | |
139 | /* ---------- |
140 | * toast_delete - |
141 | * |
142 | * Called by heap_delete(). |
143 | * ---------- |
144 | */ |
145 | extern void toast_delete(Relation rel, HeapTuple oldtup, bool is_speculative); |
146 | |
147 | /* ---------- |
148 | * heap_tuple_fetch_attr() - |
149 | * |
150 | * Fetches an external stored attribute from the toast |
151 | * relation. Does NOT decompress it, if stored external |
152 | * in compressed format. |
153 | * ---------- |
154 | */ |
155 | extern struct varlena *heap_tuple_fetch_attr(struct varlena *attr); |
156 | |
157 | /* ---------- |
158 | * heap_tuple_untoast_attr() - |
159 | * |
160 | * Fully detoasts one attribute, fetching and/or decompressing |
161 | * it as needed. |
162 | * ---------- |
163 | */ |
164 | extern struct varlena *heap_tuple_untoast_attr(struct varlena *attr); |
165 | |
166 | /* ---------- |
167 | * heap_tuple_untoast_attr_slice() - |
168 | * |
169 | * Fetches only the specified portion of an attribute. |
170 | * (Handles all cases for attribute storage) |
171 | * ---------- |
172 | */ |
173 | extern struct varlena *heap_tuple_untoast_attr_slice(struct varlena *attr, |
174 | int32 sliceoffset, |
175 | int32 slicelength); |
176 | |
177 | /* ---------- |
178 | * toast_flatten_tuple - |
179 | * |
180 | * "Flatten" a tuple to contain no out-of-line toasted fields. |
181 | * (This does not eliminate compressed or short-header datums.) |
182 | * ---------- |
183 | */ |
184 | extern HeapTuple toast_flatten_tuple(HeapTuple tup, TupleDesc tupleDesc); |
185 | |
186 | /* ---------- |
187 | * toast_flatten_tuple_to_datum - |
188 | * |
189 | * "Flatten" a tuple containing out-of-line toasted fields into a Datum. |
190 | * ---------- |
191 | */ |
192 | extern Datum toast_flatten_tuple_to_datum(HeapTupleHeader tup, |
193 | uint32 tup_len, |
194 | TupleDesc tupleDesc); |
195 | |
196 | /* ---------- |
197 | * toast_build_flattened_tuple - |
198 | * |
199 | * Build a tuple containing no out-of-line toasted fields. |
200 | * (This does not eliminate compressed or short-header datums.) |
201 | * ---------- |
202 | */ |
203 | extern HeapTuple toast_build_flattened_tuple(TupleDesc tupleDesc, |
204 | Datum *values, |
205 | bool *isnull); |
206 | |
207 | /* ---------- |
208 | * toast_compress_datum - |
209 | * |
210 | * Create a compressed version of a varlena datum, if possible |
211 | * ---------- |
212 | */ |
213 | extern Datum toast_compress_datum(Datum value); |
214 | |
215 | /* ---------- |
216 | * toast_raw_datum_size - |
217 | * |
218 | * Return the raw (detoasted) size of a varlena datum |
219 | * ---------- |
220 | */ |
221 | extern Size toast_raw_datum_size(Datum value); |
222 | |
223 | /* ---------- |
224 | * toast_datum_size - |
225 | * |
226 | * Return the storage size of a varlena datum |
227 | * ---------- |
228 | */ |
229 | extern Size toast_datum_size(Datum value); |
230 | |
231 | /* ---------- |
232 | * toast_get_valid_index - |
233 | * |
234 | * Return OID of valid index associated to a toast relation |
235 | * ---------- |
236 | */ |
237 | extern Oid toast_get_valid_index(Oid toastoid, LOCKMODE lock); |
238 | |
239 | #endif /* TUPTOASTER_H */ |
240 | |