On Wed, Sep 5, 2018 at 12:26 PM Alexander Korotkov
<a.korot...@postgrespro.ru> wrote:
> On Wed, Sep 5, 2018 at 1:45 AM R, Siva <sivas...@amazon.com> wrote:
> > On Tue, Sep 4, 2018 at 09:16 PM, Alexander Korotkov 
> > <a.korot...@postgrespro.ru> wrote:
> > > Do you have a test scenario for reproduction of this issue?  We need
> > > it to ensure that fix is correct.
> >
> > Unfortunately, I do not have a way of reproducing this issue.
> > So far I have tried a workload consisting of inserts (of the
> > same attribute value that is indexed), batch deletes of rows
> > and vacuum interleaved with engine crash/restarts.
>
> Issue reproduction and testing is essential for bug fix.  Remember
> last time you reported GIN bug [1], after issue reproduction it
> appears that we have more things to fix.  I's quite clear for me that
> if segment list contains GIN_SEGMENT_INSERT before GIN_SEGMENT_DELETE,
> then it might lead to wrong behavior in ginRedoRecompress().  But it's
> not yet clear to understand what code patch could lead to such segment
> list... I'll explore code more and probably will come with some idea.

Aha, I've managed to reproduce this.
1. Apply ginRedoRecompress-asserts.patch, which add assertions to
ginRedoRecompress() detecting past opaque writes.
2. Setup streaming replication.
3. Execute following on the master.
create or replace function test () returns void as $$
declare
i int;
begin
FOR i IN 1..1000 LOOP
  insert into test values ('{1}');
end loop;
end
$$ language plpgsql;
create table test (a int[]);
insert into test (select '{}'::int[] from generate_series(1,10000));
insert into test (select '{1}'::int[] from generate_series(1,100000));
create index test_idx on test using gin(a) with (fastupdate = off);
delete from test where a = '{}'::int[];
vacuum test;
select test();

So, since we managed to reproduce this, I'm going to test and review your fix.

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
diff --git a/src/backend/access/gin/ginxlog.c b/src/backend/access/gin/ginxlog.c
index 7a1e94a1d56..301c527cab9 100644
--- a/src/backend/access/gin/ginxlog.c
+++ b/src/backend/access/gin/ginxlog.c
@@ -276,6 +276,7 @@ ginRedoRecompress(Page page, ginxlogRecompressDataLeaf *data)
 				break;
 
 			case GIN_SEGMENT_INSERT:
+				Assert(segptr + newsegsize + szleft < PageGetSpecialPointer(page));
 				/* make room for the new segment */
 				memmove(segptr + newsegsize, segptr, szleft);
 				/* copy the new segment in place */
@@ -285,6 +286,8 @@ ginRedoRecompress(Page page, ginxlogRecompressDataLeaf *data)
 				break;
 
 			case GIN_SEGMENT_REPLACE:
+				Assert(segptr + newsegsize + (szleft - segsize) < PageGetSpecialPointer(page));
+				Assert(segptr + szleft < PageGetSpecialPointer(page));
 				/* shift the segments that follow */
 				memmove(segptr + newsegsize,
 						segptr + segsize,

Reply via email to