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

Commit 30b4e0d

Browse files
author
Nikita Malakhov
committed
Default Toaster using Custom TOAST Pointers
Default Toaster changed to use Custom TOAST Pointes instead of External to make it fully compliant to TOAST API. Backward compatibility is preserved by allowing Default Toaster to read old (External) TOAST Pointers, but save TOASTed data as new Custom TOAST Pointer. Author: Teodor Sigaev <teodor@sigaev.ru> Author: Oleg Bartunov <obartunov@postgrespro.ru> Author: Nikita Glukhov <n.gluhov@postgrespro.ru> Author: Nikita Malakhov <n.malakhov@postgrespro.ru>
1 parent d49ffdc commit 30b4e0d

File tree

4 files changed

+209
-40
lines changed

4 files changed

+209
-40
lines changed

src/backend/access/common/heaptuple.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,9 @@ fill_val(Form_pg_attribute att,
243243
{
244244
*infomask |= HEAP_HASEXTERNAL;
245245
/* no alignment, since it's short by definition */
246+
if (VARATT_IS_CUSTOM(val))
247+
data = (char *) att_align_nominal(data,
248+
att->attalign);
246249
data_length = VARSIZE_EXTERNAL(val);
247250
memcpy(data, val, data_length);
248251
}

src/backend/access/common/toast_internals.c

Lines changed: 108 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "access/heaptoast.h"
2020
#include "access/table.h"
2121
#include "access/toast_internals.h"
22+
#include "access/generic_toaster.h"
2223
#include "catalog/toasting.h"
2324
#include "access/xact.h"
2425
#include "catalog/catalog.h"
@@ -165,9 +166,22 @@ toast_save_datum_ext(Relation rel, Oid toasterid, Datum value,
165166
{
166167
struct varatt_external old_toast_pointer;
167168

168-
Assert(VARATT_IS_EXTERNAL_ONDISK(oldexternal));
169+
/* New case - Generic TOAST working with Custom pointer */
170+
if(VARATT_IS_CUSTOM(oldexternal))
171+
{
172+
ExternalToastData data;
173+
VARATT_CUSTOM_GET_EXTERNAL_DATA(PointerGetDatum(oldexternal), data);
174+
old_toast_pointer.va_toastrelid = get_uint32align16(&data.va_toastrelid);
175+
old_toast_pointer.va_valueid = get_uint32align16(&data.va_valueid);
176+
}
177+
else
178+
{
179+
Assert(VARATT_IS_EXTERNAL_ONDISK(oldexternal));
180+
VARATT_EXTERNAL_GET_POINTER(old_toast_pointer, oldexternal);
181+
}
169182
/* Must copy to access aligned fields */
170-
VARATT_EXTERNAL_GET_POINTER(old_toast_pointer, oldexternal);
183+
/* VARATT_EXTERNAL_GET_POINTER(old_toast_pointer, oldexternal); */
184+
/* XXX if (old_toast_pointer.va_toastrelid == rel->rd_toastoid) */
171185
if (old_toast_pointer.va_toastrelid == real_toastrelid)
172186
{
173187
/* This value came from the old toast table; reuse its OID */
@@ -265,17 +279,34 @@ toast_delete_datum(Datum value, bool is_speculative)
265279
int num_indexes;
266280
int validIndex;
267281
SnapshotData SnapshotToast;
282+
ExternalToastData data;
283+
Oid va_toastrelid;
284+
Oid va_valueid;
268285

269-
if (!VARATT_IS_EXTERNAL_ONDISK(attr))
286+
if (!VARATT_IS_EXTERNAL_ONDISK(attr) && !VARATT_IS_CUSTOM(attr))
270287
return;
271288

272289
/* Must copy to access aligned fields */
273-
VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
290+
if(VARATT_IS_CUSTOM(attr))
291+
{
292+
/* process custom Toast Pointer */
293+
VARATT_CUSTOM_GET_EXTERNAL_DATA(attr, data);
294+
295+
va_toastrelid = get_uint32align16(&data.va_toastrelid);
296+
va_valueid = get_uint32align16(&data.va_valueid);
297+
}
298+
else
299+
{
300+
VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
301+
302+
va_toastrelid = toast_pointer.va_toastrelid;
303+
va_valueid = toast_pointer.va_valueid;
304+
}
274305

275306
/*
276307
* Open the toast relation and its indexes
277308
*/
278-
toastrel = table_open(toast_pointer.va_toastrelid, RowExclusiveLock);
309+
toastrel = table_open(va_toastrelid, RowExclusiveLock);
279310

280311
/* Fetch valid relation used for process */
281312
validIndex = toast_open_indexes(toastrel,
@@ -289,7 +320,7 @@ toast_delete_datum(Datum value, bool is_speculative)
289320
ScanKeyInit(&toastkey,
290321
(AttrNumber) 1,
291322
BTEqualStrategyNumber, F_OIDEQ,
292-
ObjectIdGetDatum(toast_pointer.va_valueid));
323+
ObjectIdGetDatum(va_valueid));
293324

294325
/*
295326
* Find all the chunks. (We don't actually care whether we see them in
@@ -405,19 +436,43 @@ toast_fetch_datum(struct varlena *attr)
405436
Relation toastrel;
406437
struct varlena *result;
407438
struct varatt_external toast_pointer;
439+
ExternalToastData data;
440+
Oid va_toastrelid;
441+
Oid va_valueid;
408442
int32 attrsize;
443+
bool is_compressed = false;
409444

410-
if (!VARATT_IS_EXTERNAL_ONDISK(attr))
411-
elog(ERROR, "toast_fetch_datum shouldn't be called for non-ondisk datums");
445+
if (!VARATT_IS_EXTERNAL_ONDISK(attr) && !VARATT_IS_CUSTOM(attr))
446+
elog(ERROR, "toast_fetch_datum_slice shouldn't be called for non-ondisk or non-custom datums");
412447

413448
/* Must copy to access aligned fields */
414-
VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
449+
if(VARATT_IS_CUSTOM(attr))
450+
{
451+
/* process custom Toast Pointer */
452+
VARATT_CUSTOM_GET_EXTERNAL_DATA(attr, data);
453+
454+
attrsize = get_uint32align16(&data.va_extinfo);
455+
va_toastrelid = get_uint32align16(&data.va_toastrelid);
456+
va_valueid = get_uint32align16(&data.va_valueid);
457+
458+
if (VARATT_CUSTOM_EXTERNAL_IS_COMPRESSED(attr, attrsize))
459+
is_compressed = true;
460+
}
461+
else
462+
{
463+
VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
415464

416-
attrsize = VARATT_EXTERNAL_GET_EXTSIZE(toast_pointer);
465+
va_toastrelid = toast_pointer.va_toastrelid;
466+
va_valueid = toast_pointer.va_valueid;
467+
468+
attrsize = VARATT_EXTERNAL_GET_EXTSIZE(toast_pointer);
469+
if (VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer))
470+
is_compressed = true;
471+
}
417472

418473
result = (struct varlena *) palloc(attrsize + VARHDRSZ);
419474

420-
if (VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer))
475+
if (is_compressed)
421476
SET_VARSIZE_COMPRESSED(result, attrsize + VARHDRSZ);
422477
else
423478
SET_VARSIZE(result, attrsize + VARHDRSZ);
@@ -429,10 +484,10 @@ toast_fetch_datum(struct varlena *attr)
429484
/*
430485
* Open the toast relation and its indexes
431486
*/
432-
toastrel = table_open(toast_pointer.va_toastrelid, AccessShareLock);
487+
toastrel = table_open(va_toastrelid, AccessShareLock);
433488

434489
/* Fetch all chunks */
435-
toast_fetch_toast_slice(toastrel, toast_pointer.va_valueid,
490+
toast_fetch_toast_slice(toastrel, va_valueid,
436491
attr, attrsize, 0, attrsize, result, 0,
437492
NULL, NULL);
438493

@@ -460,22 +515,47 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset,
460515
Relation toastrel;
461516
struct varlena *result;
462517
struct varatt_external toast_pointer;
518+
ExternalToastData data;
519+
Oid va_toastrelid;
520+
Oid va_valueid;
463521
int32 attrsize;
522+
bool is_compressed = false;
464523

465-
if (!VARATT_IS_EXTERNAL_ONDISK(attr))
466-
elog(ERROR, "toast_fetch_datum_slice shouldn't be called for non-ondisk datums");
524+
if (!(VARATT_IS_EXTERNAL_ONDISK(attr) || VARATT_IS_CUSTOM(attr)))
525+
elog(ERROR, "toast_fetch_datum_slice shouldn't be called for non-ondisk or non-custom datums");
467526

468527
/* Must copy to access aligned fields */
469-
VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
528+
if(VARATT_IS_CUSTOM(attr))
529+
{
530+
/* process custom Toast Pointer */
531+
VARATT_CUSTOM_GET_EXTERNAL_DATA(attr, data);
470532

471-
/*
472-
* It's nonsense to fetch slices of a compressed datum unless when it's a
473-
* prefix -- this isn't lo_* we can't return a compressed datum which is
474-
* meaningful to toast later.
475-
*/
476-
Assert(!VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer) || 0 == sliceoffset);
533+
attrsize = get_uint32align16(&data.va_extinfo);
534+
va_toastrelid = get_uint32align16(&data.va_toastrelid);
535+
va_valueid = get_uint32align16(&data.va_valueid);
536+
537+
if (VARATT_CUSTOM_EXTERNAL_IS_COMPRESSED(attr, attrsize) && slicelength > 0)
538+
is_compressed = true;
539+
}
540+
else
541+
{
542+
VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
543+
544+
va_toastrelid = toast_pointer.va_toastrelid;
545+
va_valueid = toast_pointer.va_valueid;
546+
547+
/*
548+
* It's nonsense to fetch slices of a compressed datum unless when it's a
549+
* prefix -- this isn't lo_* we can't return a compressed datum which is
550+
* meaningful to toast later.
551+
*/
552+
Assert(!VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer) || 0 == sliceoffset);
553+
554+
attrsize = VARATT_EXTERNAL_GET_EXTSIZE(toast_pointer);
555+
if (VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer) && slicelength > 0)
556+
is_compressed = true;
557+
}
477558

478-
attrsize = VARATT_EXTERNAL_GET_EXTSIZE(toast_pointer);
479559

480560
if (sliceoffset >= attrsize)
481561
{
@@ -488,7 +568,8 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset,
488568
* space required by va_tcinfo, which is stored at the beginning as an
489569
* int32 value.
490570
*/
491-
if (VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer) && slicelength > 0)
571+
/* if (VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer) && slicelength > 0) */
572+
if(is_compressed)
492573
slicelength = slicelength + sizeof(int32);
493574

494575
/*
@@ -501,7 +582,7 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset,
501582

502583
result = (struct varlena *) palloc(slicelength + VARHDRSZ);
503584

504-
if (VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer))
585+
if(is_compressed)
505586
SET_VARSIZE_COMPRESSED(result, slicelength + VARHDRSZ);
506587
else
507588
SET_VARSIZE(result, slicelength + VARHDRSZ);
@@ -510,10 +591,10 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset,
510591
return result; /* Can save a lot of work at this point! */
511592

512593
/* Open the toast relation */
513-
toastrel = table_open(toast_pointer.va_toastrelid, AccessShareLock);
594+
toastrel = table_open(va_toastrelid, AccessShareLock);
514595

515596
/* Fetch all chunks */
516-
toast_fetch_toast_slice(toastrel, toast_pointer.va_valueid,
597+
toast_fetch_toast_slice(toastrel, va_valueid,
517598
attr, attrsize, sliceoffset, slicelength,
518599
result, 0, NULL, NULL);
519600

src/backend/access/toast/generic_toaster.c

Lines changed: 72 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,40 @@
5050
#include "access/genam.h"
5151
#include "access/toast_helper.h"
5252
#include "utils/fmgroids.h"
53+
#include "utils/memutils.h"
5354
#include "access/generic_toaster.h"
5455
#include "access/toast_compression.h"
5556
#include "replication/reorderbuffer.h"
5657

5758
/*
5859
* Callback function signatures --- see toaster.sgml for more info.
5960
*/
61+
static struct varlena *
62+
generic_toast_make_pointer(Oid toasterid, struct varatt_external *ptr)
63+
{
64+
Size size = VARATT_CUSTOM_EXTERNAL_SIZE;
65+
struct varlena *result = palloc(size);
66+
ExternalToastData result_data;
67+
68+
SET_VARTAG_EXTERNAL(result, VARTAG_CUSTOM);
69+
70+
if (ptr->va_rawsize > MaxAllocSize)
71+
ereport(ERROR,
72+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
73+
errmsg("atribute length too large")));
74+
75+
VARATT_CUSTOM_SET_TOASTERID(result, toasterid);
76+
VARATT_CUSTOM_SET_DATA_RAW_SIZE(result, ptr->va_rawsize);
77+
VARATT_CUSTOM_SET_DATA_SIZE(result, VARATT_CUSTOM_EXTERNAL_HDRSZ);
78+
79+
set_uint32align16(&result_data.va_extinfo, VARATT_EXTERNAL_GET_EXTSIZE(*ptr)); //->va_extinfo);
80+
set_uint32align16(&result_data.va_toastrelid, ptr->va_toastrelid);
81+
set_uint32align16(&result_data.va_valueid, ptr->va_valueid);
82+
83+
memcpy(VARATT_CUSTOM_GET_DATA(result), &result_data, VARATT_CUSTOM_EXTERNAL_HDRSZ);
84+
85+
return result;
86+
}
6087

6188
/*
6289
* Init function. Creates Toast table for Toasted data storage
@@ -78,14 +105,25 @@ static Datum
78105
generic_toast(Relation toast_rel, Oid toasterid, Datum value, Datum oldvalue,
79106
int max_inline_size, int options)
80107
{
81-
Datum result;
108+
Datum detoasted_newval;
109+
Datum toasted_newval;
110+
struct varatt_external toast_ptr;
82111

83112
Assert(toast_rel != NULL);
113+
detoasted_newval = PointerGetDatum(detoast_attr((struct varlena *) value));
114+
toasted_newval = toast_save_datum_ext(toast_rel, toasterid, detoasted_newval,
115+
(struct varlena *) DatumGetPointer(oldvalue), options,
116+
NULL, 0);
84117

85-
result = toast_save_datum(toast_rel, toasterid, value,
86-
(struct varlena *) DatumGetPointer(oldvalue),
87-
options);
88-
return result;
118+
/*
119+
* Custom Toast Pointers differ from regular, this assertion will fail for Custom
120+
* Assert(VARATT_IS_EXTERNAL_ONDISK(toasted_newval));
121+
*/
122+
VARATT_EXTERNAL_GET_POINTER(toast_ptr, DatumGetPointer(toasted_newval));
123+
124+
pfree(DatumGetPointer(toasted_newval));
125+
126+
return PointerGetDatum(generic_toast_make_pointer(toasterid, &toast_ptr));
89127
}
90128

91129
/*
@@ -96,21 +134,31 @@ static Datum
96134
generic_detoast(Datum toast_ptr, int offset, int length)
97135
{
98136
struct varlena *result = 0;
99-
struct varlena *tvalue = (struct varlena*)DatumGetPointer(toast_ptr);
100137
struct varatt_external toast_pointer;
138+
ExternalToastData data;
139+
int32 toasted_size;
140+
struct varlena *tvalue = (struct varlena*)DatumGetPointer(toast_ptr);;
101141

102-
VARATT_EXTERNAL_GET_POINTER(toast_pointer, tvalue);
142+
if( VARATT_IS_CUSTOM( tvalue ) )
143+
{
144+
VARATT_CUSTOM_GET_EXTERNAL_DATA(toast_ptr, data);
145+
toasted_size = get_uint32align16(&data.va_extinfo);
146+
}
147+
else
148+
{
149+
VARATT_EXTERNAL_GET_POINTER(toast_pointer, tvalue);
150+
toasted_size = VARATT_EXTERNAL_GET_EXTSIZE(toast_pointer);
151+
}
103152
if(offset == 0
104-
&& (length < 0 || length >= VARATT_EXTERNAL_GET_EXTSIZE(toast_pointer)))
153+
&& (length < 0 || length >= toasted_size))
105154
{
106155
result = toast_fetch_datum(tvalue);
107156
}
108157
else
109158
{
110159
result = toast_fetch_datum_slice(tvalue,
111-
offset, length);
160+
offset, length);
112161
}
113-
114162
return PointerGetDatum(result);
115163
}
116164

@@ -163,11 +211,22 @@ DetoastIterator
163211
create_detoast_iterator(struct varlena *attr)
164212
{
165213
struct varatt_external toast_pointer;
214+
ExternalToastData data;
166215
DetoastIterator iter;
167-
if (VARATT_IS_EXTERNAL_ONDISK(attr))
216+
217+
if (VARATT_IS_EXTERNAL_ONDISK(attr) || VARATT_IS_CUSTOM( attr ))
168218
{
169219
FetchDatumIterator fetch_iter;
170220

221+
if(VARATT_IS_CUSTOM( attr ))
222+
{
223+
VARATT_CUSTOM_GET_EXTERNAL_DATA(PointerGetDatum(attr), data);
224+
toast_pointer.va_extinfo = get_uint32align16(&data.va_extinfo);
225+
toast_pointer.va_toastrelid = get_uint32align16(&data.va_toastrelid);
226+
toast_pointer.va_valueid = get_uint32align16(&data.va_valueid);
227+
toast_pointer.va_rawsize = get_uint32align16(&data.va_extinfo) + VARATT_CUSTOM_EXTERNAL_HDRSZ;
228+
}
229+
171230
iter = (DetoastIterator) palloc0(sizeof(DetoastIteratorData));
172231
iter->done = false;
173232
iter->nrefs = 1;
@@ -176,7 +235,7 @@ create_detoast_iterator(struct varlena *attr)
176235
/* This is an externally stored datum --- initialize fetch datum iterator */
177236
iter->fetch_datum_iterator = fetch_iter = create_fetch_datum_iterator(attr);
178237
VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
179-
if (VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer))
238+
if (!VARATT_IS_CUSTOM( attr ) && VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer))
180239
{
181240
iter->compressed = true;
182241
iter->compression_method = VARATT_EXTERNAL_GET_COMPRESS_METHOD(toast_pointer);
@@ -619,7 +678,7 @@ generic_toaster_vtable(Datum toast_ptr)
619678

620679
struct varlena *
621680
generic_toaster_reconstruct(Relation toastrel, struct varlena *varlena,
622-
HTAB *toast_hash)
681+
HTAB *toast_hash)
623682
{
624683
struct varatt_external toast_pointer;
625684
struct varlena *reconstructed;

0 commit comments

Comments
 (0)