Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 3682025

Browse files
committed
Add support for multiple kinds of external toast datums.
To that end, support tags rather than lengths for external datums. As an example of how this can be used, add support or "indirect" tuples which point to some externally allocated memory containing a toast tuple. Similar infrastructure could be used for other purposes, including, perhaps, support for alternative compression algorithms. Andres Freund, reviewed by Hitoshi Harada and myself
1 parent 148326b commit 3682025

File tree

10 files changed

+472
-43
lines changed

10 files changed

+472
-43
lines changed

src/backend/access/heap/tuptoaster.c

+90-20
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,6 @@
4444

4545
#undef TOAST_DEBUG
4646

47-
/* Size of an EXTERNAL datum that contains a standard TOAST pointer */
48-
#define TOAST_POINTER_SIZE (VARHDRSZ_EXTERNAL + sizeof(struct varatt_external))
49-
5047
/*
5148
* Testing whether an externally-stored value is compressed now requires
5249
* comparing extsize (the actual length of the external data) to rawsize
@@ -87,25 +84,47 @@ static struct varlena *toast_fetch_datum_slice(struct varlena * attr,
8784
* heap_tuple_fetch_attr -
8885
*
8986
* Public entry point to get back a toasted value from
90-
* external storage (possibly still in compressed format).
87+
* external source (possibly still in compressed format).
9188
*
9289
* This will return a datum that contains all the data internally, ie, not
93-
* relying on external storage, but it can still be compressed or have a short
94-
* header.
90+
* relying on external storage or memory, but it can still be compressed or
91+
* have a short header.
9592
----------
9693
*/
9794
struct varlena *
9895
heap_tuple_fetch_attr(struct varlena * attr)
9996
{
10097
struct varlena *result;
10198

102-
if (VARATT_IS_EXTERNAL(attr))
99+
if (VARATT_IS_EXTERNAL_ONDISK(attr))
103100
{
104101
/*
105102
* This is an external stored plain value
106103
*/
107104
result = toast_fetch_datum(attr);
108105
}
106+
else if (VARATT_IS_EXTERNAL_INDIRECT(attr))
107+
{
108+
/*
109+
* copy into the caller's memory context. That's not required in all
110+
* cases but sufficient for now since this is mainly used when we need
111+
* to persist a Datum for unusually long time, like in a HOLD cursor.
112+
*/
113+
struct varatt_indirect redirect;
114+
VARATT_EXTERNAL_GET_POINTER(redirect, attr);
115+
attr = (struct varlena *)redirect.pointer;
116+
117+
/* nested indirect Datums aren't allowed */
118+
Assert(!VARATT_IS_EXTERNAL_INDIRECT(attr));
119+
120+
/* doesn't make much sense, but better handle it */
121+
if (VARATT_IS_EXTERNAL_ONDISK(attr))
122+
return heap_tuple_fetch_attr(attr);
123+
124+
/* copy datum verbatim */
125+
result = (struct varlena *) palloc(VARSIZE_ANY(attr));
126+
memcpy(result, attr, VARSIZE_ANY(attr));
127+
}
109128
else
110129
{
111130
/*
@@ -128,7 +147,7 @@ heap_tuple_fetch_attr(struct varlena * attr)
128147
struct varlena *
129148
heap_tuple_untoast_attr(struct varlena * attr)
130149
{
131-
if (VARATT_IS_EXTERNAL(attr))
150+
if (VARATT_IS_EXTERNAL_ONDISK(attr))
132151
{
133152
/*
134153
* This is an externally stored datum --- fetch it back from there
@@ -145,6 +164,17 @@ heap_tuple_untoast_attr(struct varlena * attr)
145164
pfree(tmp);
146165
}
147166
}
167+
else if (VARATT_IS_EXTERNAL_INDIRECT(attr))
168+
{
169+
struct varatt_indirect redirect;
170+
VARATT_EXTERNAL_GET_POINTER(redirect, attr);
171+
attr = (struct varlena *)redirect.pointer;
172+
173+
/* nested indirect Datums aren't allowed */
174+
Assert(!VARATT_IS_EXTERNAL_INDIRECT(attr));
175+
176+
attr = heap_tuple_untoast_attr(attr);
177+
}
148178
else if (VARATT_IS_COMPRESSED(attr))
149179
{
150180
/*
@@ -191,7 +221,7 @@ heap_tuple_untoast_attr_slice(struct varlena * attr,
191221
char *attrdata;
192222
int32 attrsize;
193223

194-
if (VARATT_IS_EXTERNAL(attr))
224+
if (VARATT_IS_EXTERNAL_ONDISK(attr))
195225
{
196226
struct varatt_external toast_pointer;
197227

@@ -204,6 +234,17 @@ heap_tuple_untoast_attr_slice(struct varlena * attr,
204234
/* fetch it back (compressed marker will get set automatically) */
205235
preslice = toast_fetch_datum(attr);
206236
}
237+
else if (VARATT_IS_EXTERNAL_INDIRECT(attr))
238+
{
239+
struct varatt_indirect redirect;
240+
VARATT_EXTERNAL_GET_POINTER(redirect, attr);
241+
242+
/* nested indirect Datums aren't allowed */
243+
Assert(!VARATT_IS_EXTERNAL_INDIRECT(redirect.pointer));
244+
245+
return heap_tuple_untoast_attr_slice(redirect.pointer,
246+
sliceoffset, slicelength);
247+
}
207248
else
208249
preslice = attr;
209250

@@ -267,14 +308,24 @@ toast_raw_datum_size(Datum value)
267308
struct varlena *attr = (struct varlena *) DatumGetPointer(value);
268309
Size result;
269310

270-
if (VARATT_IS_EXTERNAL(attr))
311+
if (VARATT_IS_EXTERNAL_ONDISK(attr))
271312
{
272313
/* va_rawsize is the size of the original datum -- including header */
273314
struct varatt_external toast_pointer;
274315

275316
VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
276317
result = toast_pointer.va_rawsize;
277318
}
319+
else if (VARATT_IS_EXTERNAL_INDIRECT(attr))
320+
{
321+
struct varatt_indirect toast_pointer;
322+
VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
323+
324+
/* nested indirect Datums aren't allowed */
325+
Assert(!VARATT_IS_EXTERNAL_INDIRECT(toast_pointer.pointer));
326+
327+
return toast_raw_datum_size(PointerGetDatum(toast_pointer.pointer));
328+
}
278329
else if (VARATT_IS_COMPRESSED(attr))
279330
{
280331
/* here, va_rawsize is just the payload size */
@@ -308,7 +359,7 @@ toast_datum_size(Datum value)
308359
struct varlena *attr = (struct varlena *) DatumGetPointer(value);
309360
Size result;
310361

311-
if (VARATT_IS_EXTERNAL(attr))
362+
if (VARATT_IS_EXTERNAL_ONDISK(attr))
312363
{
313364
/*
314365
* Attribute is stored externally - return the extsize whether
@@ -320,6 +371,16 @@ toast_datum_size(Datum value)
320371
VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
321372
result = toast_pointer.va_extsize;
322373
}
374+
else if (VARATT_IS_EXTERNAL_INDIRECT(attr))
375+
{
376+
struct varatt_indirect toast_pointer;
377+
VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
378+
379+
/* nested indirect Datums aren't allowed */
380+
Assert(!VARATT_IS_EXTERNAL_INDIRECT(attr));
381+
382+
return toast_datum_size(PointerGetDatum(toast_pointer.pointer));
383+
}
323384
else if (VARATT_IS_SHORT(attr))
324385
{
325386
result = VARSIZE_SHORT(attr);
@@ -387,8 +448,12 @@ toast_delete(Relation rel, HeapTuple oldtup)
387448
{
388449
Datum value = toast_values[i];
389450

390-
if (!toast_isnull[i] && VARATT_IS_EXTERNAL(PointerGetDatum(value)))
451+
if (toast_isnull[i])
452+
continue;
453+
else if (VARATT_IS_EXTERNAL_ONDISK(PointerGetDatum(value)))
391454
toast_delete_datum(rel, value);
455+
else if (VARATT_IS_EXTERNAL_INDIRECT(PointerGetDatum(value)))
456+
elog(ERROR, "attempt to delete tuple containing indirect datums");
392457
}
393458
}
394459
}
@@ -490,13 +555,13 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
490555
new_value = (struct varlena *) DatumGetPointer(toast_values[i]);
491556

492557
/*
493-
* If the old value is an external stored one, check if it has
494-
* changed so we have to delete it later.
558+
* If the old value is stored on disk, check if it has changed so
559+
* we have to delete it later.
495560
*/
496561
if (att[i]->attlen == -1 && !toast_oldisnull[i] &&
497-
VARATT_IS_EXTERNAL(old_value))
562+
VARATT_IS_EXTERNAL_ONDISK(old_value))
498563
{
499-
if (toast_isnull[i] || !VARATT_IS_EXTERNAL(new_value) ||
564+
if (toast_isnull[i] || !VARATT_IS_EXTERNAL_ONDISK(new_value) ||
500565
memcmp((char *) old_value, (char *) new_value,
501566
VARSIZE_EXTERNAL(old_value)) != 0)
502567
{
@@ -1258,6 +1323,8 @@ toast_save_datum(Relation rel, Datum value,
12581323
int32 data_todo;
12591324
Pointer dval = DatumGetPointer(value);
12601325

1326+
Assert(!VARATT_IS_EXTERNAL(value));
1327+
12611328
/*
12621329
* Open the toast relation and its index. We can use the index to check
12631330
* uniqueness of the OID we assign to the toasted item, even though it has
@@ -1341,7 +1408,7 @@ toast_save_datum(Relation rel, Datum value,
13411408
{
13421409
struct varatt_external old_toast_pointer;
13431410

1344-
Assert(VARATT_IS_EXTERNAL(oldexternal));
1411+
Assert(VARATT_IS_EXTERNAL_ONDISK(oldexternal));
13451412
/* Must copy to access aligned fields */
13461413
VARATT_EXTERNAL_GET_POINTER(old_toast_pointer, oldexternal);
13471414
if (old_toast_pointer.va_toastrelid == rel->rd_toastoid)
@@ -1456,7 +1523,7 @@ toast_save_datum(Relation rel, Datum value,
14561523
* Create the TOAST pointer value that we'll return
14571524
*/
14581525
result = (struct varlena *) palloc(TOAST_POINTER_SIZE);
1459-
SET_VARSIZE_EXTERNAL(result, TOAST_POINTER_SIZE);
1526+
SET_VARTAG_EXTERNAL(result, VARTAG_ONDISK);
14601527
memcpy(VARDATA_EXTERNAL(result), &toast_pointer, sizeof(toast_pointer));
14611528

14621529
return PointerGetDatum(result);
@@ -1480,7 +1547,7 @@ toast_delete_datum(Relation rel, Datum value)
14801547
SysScanDesc toastscan;
14811548
HeapTuple toasttup;
14821549

1483-
if (!VARATT_IS_EXTERNAL(attr))
1550+
if (!VARATT_IS_EXTERNAL_ONDISK(attr))
14841551
return;
14851552

14861553
/* Must copy to access aligned fields */
@@ -1608,6 +1675,9 @@ toast_fetch_datum(struct varlena * attr)
16081675
char *chunkdata;
16091676
int32 chunksize;
16101677

1678+
if (VARATT_IS_EXTERNAL_INDIRECT(attr))
1679+
elog(ERROR, "shouldn't be called for indirect tuples");
1680+
16111681
/* Must copy to access aligned fields */
16121682
VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
16131683

@@ -1775,7 +1845,7 @@ toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length)
17751845
int32 chcpystrt;
17761846
int32 chcpyend;
17771847

1778-
Assert(VARATT_IS_EXTERNAL(attr));
1848+
Assert(VARATT_IS_EXTERNAL_ONDISK(attr));
17791849

17801850
/* Must copy to access aligned fields */
17811851
VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);

src/include/access/tuptoaster.h

+5
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@
9494
sizeof(int32) - \
9595
VARHDRSZ)
9696

97+
/* Size of an EXTERNAL datum that contains a standard TOAST pointer */
98+
#define TOAST_POINTER_SIZE (VARHDRSZ_EXTERNAL + sizeof(struct varatt_external))
99+
100+
/* Size of an indirect datum that contains an indirect TOAST pointer */
101+
#define INDIRECT_POINTER_SIZE (VARHDRSZ_EXTERNAL + sizeof(struct varatt_indirect))
97102

98103
/* ----------
99104
* toast_insert_or_update -

0 commit comments

Comments
 (0)