Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite9fd041

Browse files
committed
Move heap-specific detoasting logic into a separate function.
The new function, heap_fetch_toast_slice, is shared betweentoast_fetch_datum_slice and toast_fetch_datum, and does all thework of scanning the TOAST table, fetching chunks, and storingthem into the space allocated for the result varlena.As an incidental side effect, this allows toast_fetch_datum_sliceto perform the scan with only a single scankey if all chunks arebeing fetched, which might have some tiny performance benefit.Discussion:http://postgr.es/m/CA+TgmobBzxwFojJ0zV0Own3dr09y43hp+OzU2VW+nos4PMXWEg@mail.gmail.com
1 parentbf7427b commite9fd041

File tree

1 file changed

+71
-173
lines changed

1 file changed

+71
-173
lines changed

‎src/backend/access/common/detoast.c

Lines changed: 71 additions & 173 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ static struct varlena *toast_fetch_datum(struct varlena *attr);
2727
staticstructvarlena*toast_fetch_datum_slice(structvarlena*attr,
2828
int32sliceoffset,
2929
int32slicelength);
30+
staticvoidheap_fetch_toast_slice(Relationtoastrel,Oidvalueid,
31+
int32attrsize,int32sliceoffset,
32+
int32slicelength,structvarlena*result);
3033
staticstructvarlena*toast_decompress_datum(structvarlena*attr);
3134
staticstructvarlena*toast_decompress_datum_slice(structvarlena*attr,int32slicelength);
3235

@@ -325,19 +328,9 @@ static struct varlena *
325328
toast_fetch_datum(structvarlena*attr)
326329
{
327330
Relationtoastrel;
328-
Relation*toastidxs;
329-
ScanKeyDatatoastkey;
330-
SysScanDesctoastscan;
331-
HeapTuplettup;
332-
TupleDesctoasttupDesc;
333331
structvarlena*result;
334332
structvaratt_externaltoast_pointer;
335333
int32attrsize;
336-
int32expectedchunk;
337-
int32totalchunks;
338-
intnum_indexes;
339-
intvalidIndex;
340-
SnapshotDataSnapshotToast;
341334

342335
if (!VARATT_IS_EXTERNAL_ONDISK(attr))
343336
elog(ERROR,"toast_fetch_datum shouldn't be called for non-ondisk datums");
@@ -346,7 +339,6 @@ toast_fetch_datum(struct varlena *attr)
346339
VARATT_EXTERNAL_GET_POINTER(toast_pointer,attr);
347340

348341
attrsize=toast_pointer.va_extsize;
349-
totalchunks= ((attrsize-1) /TOAST_MAX_CHUNK_SIZE)+1;
350342

351343
result= (structvarlena*)palloc(attrsize+VARHDRSZ);
352344

@@ -355,130 +347,19 @@ toast_fetch_datum(struct varlena *attr)
355347
else
356348
SET_VARSIZE(result,attrsize+VARHDRSZ);
357349

350+
if (attrsize==0)
351+
returnresult;/* Probably shouldn't happen, but just in case. */
352+
358353
/*
359354
* Open the toast relation and its indexes
360355
*/
361356
toastrel=table_open(toast_pointer.va_toastrelid,AccessShareLock);
362-
toasttupDesc=toastrel->rd_att;
363-
364-
/* Look for the valid index of the toast relation */
365-
validIndex=toast_open_indexes(toastrel,
366-
AccessShareLock,
367-
&toastidxs,
368-
&num_indexes);
369357

370-
/*
371-
* Setup a scan key to fetch from the index by va_valueid
372-
*/
373-
ScanKeyInit(&toastkey,
374-
(AttrNumber)1,
375-
BTEqualStrategyNumber,F_OIDEQ,
376-
ObjectIdGetDatum(toast_pointer.va_valueid));
358+
/* Fetch all chunks */
359+
heap_fetch_toast_slice(toastrel,toast_pointer.va_valueid,attrsize,0,
360+
attrsize,result);
377361

378-
/*
379-
* Read the chunks by index
380-
*
381-
* Note that because the index is actually on (valueid, chunkidx) we will
382-
* see the chunks in chunkidx order, even though we didn't explicitly ask
383-
* for it.
384-
*/
385-
expectedchunk=0;
386-
387-
init_toast_snapshot(&SnapshotToast);
388-
toastscan=systable_beginscan_ordered(toastrel,toastidxs[validIndex],
389-
&SnapshotToast,1,&toastkey);
390-
while ((ttup=systable_getnext_ordered(toastscan,ForwardScanDirection))!=NULL)
391-
{
392-
int32curchunk;
393-
Pointerchunk;
394-
boolisnull;
395-
char*chunkdata;
396-
int32chunksize;
397-
int32expected_size;
398-
399-
/*
400-
* Have a chunk, extract the sequence number and the data
401-
*/
402-
curchunk=DatumGetInt32(fastgetattr(ttup,2,toasttupDesc,&isnull));
403-
Assert(!isnull);
404-
chunk=DatumGetPointer(fastgetattr(ttup,3,toasttupDesc,&isnull));
405-
Assert(!isnull);
406-
if (!VARATT_IS_EXTENDED(chunk))
407-
{
408-
chunksize=VARSIZE(chunk)-VARHDRSZ;
409-
chunkdata=VARDATA(chunk);
410-
}
411-
elseif (VARATT_IS_SHORT(chunk))
412-
{
413-
/* could happen due to heap_form_tuple doing its thing */
414-
chunksize=VARSIZE_SHORT(chunk)-VARHDRSZ_SHORT;
415-
chunkdata=VARDATA_SHORT(chunk);
416-
}
417-
else
418-
{
419-
/* should never happen */
420-
elog(ERROR,"found toasted toast chunk for toast value %u in %s",
421-
toast_pointer.va_valueid,
422-
RelationGetRelationName(toastrel));
423-
chunksize=0;/* keep compiler quiet */
424-
chunkdata=NULL;
425-
}
426-
427-
/*
428-
* Some checks on the data we've found
429-
*/
430-
if (curchunk!=expectedchunk)
431-
ereport(ERROR,
432-
(errcode(ERRCODE_DATA_CORRUPTED),
433-
errmsg_internal("unexpected chunk number %d (expected %d) for toast value %u in %s",
434-
curchunk,expectedchunk,
435-
toast_pointer.va_valueid,
436-
RelationGetRelationName(toastrel))));
437-
if (curchunk>totalchunks-1)
438-
ereport(ERROR,
439-
(errcode(ERRCODE_DATA_CORRUPTED),
440-
errmsg_internal("unexpected chunk number %d (out of range %d..%d) for toast value %u in %s",
441-
curchunk,
442-
0,totalchunks-1,
443-
toast_pointer.va_valueid,
444-
RelationGetRelationName(toastrel))));
445-
expected_size=curchunk<totalchunks-1 ?TOAST_MAX_CHUNK_SIZE
446-
:attrsize- ((totalchunks-1)*TOAST_MAX_CHUNK_SIZE);
447-
if (chunksize!=expected_size)
448-
ereport(ERROR,
449-
(errcode(ERRCODE_DATA_CORRUPTED),
450-
errmsg_internal("unexpected chunk size %d (expected %d) in chunk %d of %d for toast value %u in %s",
451-
chunksize,expected_size,
452-
curchunk,totalchunks,
453-
toast_pointer.va_valueid,
454-
RelationGetRelationName(toastrel))));
455-
456-
/*
457-
* Copy the data into proper place in our result
458-
*/
459-
memcpy(VARDATA(result)+curchunk*TOAST_MAX_CHUNK_SIZE,
460-
chunkdata,
461-
chunksize);
462-
463-
expectedchunk++;
464-
}
465-
466-
/*
467-
* Final checks that we successfully fetched the datum
468-
*/
469-
if (expectedchunk!=totalchunks)
470-
ereport(ERROR,
471-
(errcode(ERRCODE_DATA_CORRUPTED),
472-
errmsg_internal("missing chunk number %d for toast value %u in %s",
473-
expectedchunk,
474-
toast_pointer.va_valueid,
475-
RelationGetRelationName(toastrel))));
476-
477-
/*
478-
* End scan and close relations
479-
*/
480-
systable_endscan_ordered(toastscan);
481-
toast_close_indexes(toastidxs,num_indexes,AccessShareLock);
362+
/* Close toast table */
482363
table_close(toastrel,AccessShareLock);
483364

484365
returnresult;
@@ -500,22 +381,9 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset,
500381
int32slicelength)
501382
{
502383
Relationtoastrel;
503-
Relation*toastidxs;
504-
ScanKeyDatatoastkey[3];
505-
intnscankeys;
506-
SysScanDesctoastscan;
507-
HeapTuplettup;
508-
TupleDesctoasttupDesc;
509384
structvarlena*result;
510385
structvaratt_externaltoast_pointer;
511386
int32attrsize;
512-
int32expectedchunk;
513-
intstartchunk;
514-
intendchunk;
515-
inttotalchunks;
516-
intnum_indexes;
517-
intvalidIndex;
518-
SnapshotDataSnapshotToast;
519387

520388
if (!VARATT_IS_EXTERNAL_ONDISK(attr))
521389
elog(ERROR,"toast_fetch_datum_slice shouldn't be called for non-ondisk datums");
@@ -531,7 +399,6 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset,
531399
Assert(!VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer)||0==sliceoffset);
532400

533401
attrsize=toast_pointer.va_extsize;
534-
totalchunks= ((attrsize-1) /TOAST_MAX_CHUNK_SIZE)+1;
535402

536403
if (sliceoffset >=attrsize)
537404
{
@@ -560,35 +427,74 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset,
560427
if (slicelength==0)
561428
returnresult;/* Can save a lot of work at this point! */
562429

563-
startchunk=sliceoffset /TOAST_MAX_CHUNK_SIZE;
564-
endchunk= (sliceoffset+slicelength-1) /TOAST_MAX_CHUNK_SIZE;
565-
Assert(endchunk<totalchunks);
566-
567-
/*
568-
* Open the toast relation and its indexes
569-
*/
430+
/* Open the toast relation */
570431
toastrel=table_open(toast_pointer.va_toastrelid,AccessShareLock);
571-
toasttupDesc=toastrel->rd_att;
432+
433+
/* Fetch all chunks */
434+
heap_fetch_toast_slice(toastrel,toast_pointer.va_valueid,attrsize,
435+
sliceoffset,slicelength,result);
436+
437+
/* Close toast table */
438+
table_close(toastrel,AccessShareLock);
439+
440+
returnresult;
441+
}
442+
443+
/*
444+
* Fetch a TOAST slice from a heap table.
445+
*
446+
* toastrel is the relation from which chunks are to be fetched.
447+
* valueid identifies the TOAST value from which chunks are being fetched.
448+
* attrsize is the total size of the TOAST value.
449+
* sliceoffset is the byte offset within the TOAST value from which to fetch.
450+
* slicelength is the number of bytes to be fetched from the TOAST value.
451+
* result is the varlena into which the results should be written.
452+
*/
453+
staticvoid
454+
heap_fetch_toast_slice(Relationtoastrel,Oidvalueid,int32attrsize,
455+
int32sliceoffset,int32slicelength,
456+
structvarlena*result)
457+
{
458+
Relation*toastidxs;
459+
ScanKeyDatatoastkey[3];
460+
TupleDesctoasttupDesc=toastrel->rd_att;
461+
intnscankeys;
462+
SysScanDesctoastscan;
463+
HeapTuplettup;
464+
int32expectedchunk;
465+
int32totalchunks= ((attrsize-1) /TOAST_MAX_CHUNK_SIZE)+1;
466+
intstartchunk;
467+
intendchunk;
468+
intnum_indexes;
469+
intvalidIndex;
470+
SnapshotDataSnapshotToast;
572471

573472
/* Look for the valid index of toast relation */
574473
validIndex=toast_open_indexes(toastrel,
575474
AccessShareLock,
576475
&toastidxs,
577476
&num_indexes);
578477

478+
startchunk=sliceoffset /TOAST_MAX_CHUNK_SIZE;
479+
endchunk= (sliceoffset+slicelength-1) /TOAST_MAX_CHUNK_SIZE;
480+
Assert(endchunk <=totalchunks);
481+
579482
/*
580483
* Setup a scan key to fetch from the index. This is either two keys or
581484
* three depending on the number of chunks.
582485
*/
583486
ScanKeyInit(&toastkey[0],
584487
(AttrNumber)1,
585488
BTEqualStrategyNumber,F_OIDEQ,
586-
ObjectIdGetDatum(toast_pointer.va_valueid));
489+
ObjectIdGetDatum(valueid));
587490

588491
/*
589-
* Use equality condition for one chunk, a range condition otherwise:
492+
* No additional condition if fetching all chunks. Otherwise, use an
493+
* equality condition for one chunk, and a range condition otherwise.
590494
*/
591-
if (startchunk==endchunk)
495+
if (startchunk==0&&endchunk==totalchunks-1)
496+
nscankeys=1;
497+
elseif (startchunk==endchunk)
592498
{
593499
ScanKeyInit(&toastkey[1],
594500
(AttrNumber)2,
@@ -609,15 +515,17 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset,
609515
nscankeys=3;
610516
}
611517

518+
/* Prepare for scan */
519+
init_toast_snapshot(&SnapshotToast);
520+
toastscan=systable_beginscan_ordered(toastrel,toastidxs[validIndex],
521+
&SnapshotToast,nscankeys,toastkey);
522+
612523
/*
613524
* Read the chunks by index
614525
*
615526
* The index is on (valueid, chunkidx) so they will come in order
616527
*/
617-
init_toast_snapshot(&SnapshotToast);
618528
expectedchunk=startchunk;
619-
toastscan=systable_beginscan_ordered(toastrel,toastidxs[validIndex],
620-
&SnapshotToast,nscankeys,toastkey);
621529
while ((ttup=systable_getnext_ordered(toastscan,ForwardScanDirection))!=NULL)
622530
{
623531
int32curchunk;
@@ -651,8 +559,7 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset,
651559
{
652560
/* should never happen */
653561
elog(ERROR,"found toasted toast chunk for toast value %u in %s",
654-
toast_pointer.va_valueid,
655-
RelationGetRelationName(toastrel));
562+
valueid,RelationGetRelationName(toastrel));
656563
chunksize=0;/* keep compiler quiet */
657564
chunkdata=NULL;
658565
}
@@ -664,16 +571,14 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset,
664571
ereport(ERROR,
665572
(errcode(ERRCODE_DATA_CORRUPTED),
666573
errmsg_internal("unexpected chunk number %d (expected %d) for toast value %u in %s",
667-
curchunk,expectedchunk,
668-
toast_pointer.va_valueid,
574+
curchunk,expectedchunk,valueid,
669575
RelationGetRelationName(toastrel))));
670576
if (curchunk>endchunk)
671577
ereport(ERROR,
672578
(errcode(ERRCODE_DATA_CORRUPTED),
673579
errmsg_internal("unexpected chunk number %d (out of range %d..%d) for toast value %u in %s",
674580
curchunk,
675-
startchunk,endchunk,
676-
toast_pointer.va_valueid,
581+
startchunk,endchunk,valueid,
677582
RelationGetRelationName(toastrel))));
678583
expected_size=curchunk<totalchunks-1 ?TOAST_MAX_CHUNK_SIZE
679584
:attrsize- ((totalchunks-1)*TOAST_MAX_CHUNK_SIZE);
@@ -682,8 +587,7 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset,
682587
(errcode(ERRCODE_DATA_CORRUPTED),
683588
errmsg_internal("unexpected chunk size %d (expected %d) in chunk %d of %d for toast value %u in %s",
684589
chunksize,expected_size,
685-
curchunk,totalchunks,
686-
toast_pointer.va_valueid,
590+
curchunk,totalchunks,valueid,
687591
RelationGetRelationName(toastrel))));
688592

689593
/*
@@ -711,18 +615,12 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset,
711615
ereport(ERROR,
712616
(errcode(ERRCODE_DATA_CORRUPTED),
713617
errmsg_internal("missing chunk number %d for toast value %u in %s",
714-
expectedchunk,
715-
toast_pointer.va_valueid,
618+
expectedchunk,valueid,
716619
RelationGetRelationName(toastrel))));
717620

718-
/*
719-
* End scan and close relations
720-
*/
621+
/* End scan and close indexes. */
721622
systable_endscan_ordered(toastscan);
722623
toast_close_indexes(toastidxs,num_indexes,AccessShareLock);
723-
table_close(toastrel,AccessShareLock);
724-
725-
returnresult;
726624
}
727625

728626
/* ----------

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp