From: Heikki Linnakangas Date: Fri, 24 Jan 2014 08:42:38 +0000 (+0200) Subject: In GIN recompression code, use mmemove rather than memcpy, for vacuum. X-Git-Tag: REL9_4_BETA1~629 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=398cf255ad50db86ca665b75582317d4e795242a;p=thirdparty%2Fpostgresql.git In GIN recompression code, use mmemove rather than memcpy, for vacuum. When vacuuming a data leaf page, any compressed posting lists that are not modified, are copied back to the buffer from a later location in the same buffer rather than from a palloc'd copy. IOW, they are just moved downwards in the same buffer. Because the source and destination addresses can overlap, we must use memmove rather than memcpy. Report and fix by Alexander Korotkov. --- diff --git a/src/backend/access/gin/gindatapage.c b/src/backend/access/gin/gindatapage.c index 8504f4c7afc..ebdacd40c55 100644 --- a/src/backend/access/gin/gindatapage.c +++ b/src/backend/access/gin/gindatapage.c @@ -753,6 +753,13 @@ ginVacuumPostingTreeLeaf(Relation indexrel, Buffer buffer, GinVacuumState *gvs) * *prdata is filled with WAL information about this operation. The caller * is responsible for inserting to the WAL, along with any other information * about the operation that triggered this recompression. + * + * NOTE: The segment pointers can point directly to the same buffer, with + * the limitation that any earlier segment must not overlap with an original, + * later segment. In other words, some segments may point the original buffer + * as long as you don't make any segments larger. Currently, leafRepackItems + * satisies this rule because it rewrites all segments after the first + * modified one, and vacuum can only make segments shorter. */ static void dataPlaceToPageLeafRecompress(Buffer buf, disassembledLeaf *leaf, @@ -798,7 +805,13 @@ dataPlaceToPageLeafRecompress(Buffer buf, disassembledLeaf *leaf, if (!modified) unmodifiedsize += segsize; else - memcpy(ptr, seginfo->seg, segsize); + { + /* + * Use memmove rather than memcpy, in case the segment points + * to the same buffer + */ + memmove(ptr, seginfo->seg, segsize); + } ptr += segsize; newsize += segsize; }