Hi,

> At 2018-05-15 01:49:41, "Tom Lane" <t...@sss.pgh.pa.us> wrote:
> >=?GBK?B?19S8ug==?= <zoulx1...@163.com> writes:
> >> i run test using pg10.0 on my machine, and the program crashed on 
> >> _bt_getbuf.
> >> And i found the following code:
> >> the routine _bt_page_recyclable say maybe the page is all-zero page,
> >> if so then the code run (BTPageOpaque) PageGetSpecialPointer(page);
> >> it will be failed because it access invalid memory.
> >> I don't know whether it is so. Look forward t your reply, thanks.
> >
> >This code's clearly broken, as was discussed before:
> >
> >https://www.postgresql.org/message-id/flat/2628.1474272158%40localhost
> >
> >but nothing was done about it, perhaps partly because we didn't have a
> >reproducible test case.  Do you have one?
> >
> >                     regards, tom lane
> 
> Unfortunately, I don't have a complete test case.

I recently checked about this code and previous discussion and tried to occur a 
crash.
I will describe how to occur a crash in the last of this mail, but I don't know 
whether it is useful because I used gdb to occur a crash, that it is not 
actually a reproducible test case.

As was discussed before, this crash happens when recycling an all-zeroes page 
in an index.
Referring to below comments in code, an all-zeroes page is created when backend 
downs in the split process after extending the index's relation to get a new 
page and before making WAL entries for that.

        bool
        _bt_page_recyclable(Page page)
        {
                BTPageOpaque opaque;

                /*
                 * It's possible to find an all-zeroes page in an index --- for 
example, a
                 * backend might successfully extend the relation one page and 
then crash
                 * before it is able to make a WAL entry for adding the page. 
If we find a
                 * zeroed page then reclaim it.
                 */
                if (PageIsNew(page))
                        return true;
                                ...
                }

After backend down at that time, an extended new page is not initialized since 
a recovery process after a backend down do nothing because of no WAL entry 
about a new page, and it will be recyclable when vacuum runs. 


Considering above conditions, I reproduced a crash as below.
I tested at version in master(11beta1), compiled with --enable-cassert and 
--enable-debug, with hot-standby.

<<method for making recyclable new page>>
(psql) CREATE TABLE mytab (id int, val int);
(psql) CREATE INDEX idx_val ON mytab(val);
(gdb) b nbtinsert.c:1467   (at XLogBeginInsert(); in _bt_split())
(gdb) c
while(breakpoint is not hit){
    (psql) INSERT INTO mytab SELECT t, t FROM generate_series(1, 3000) t;
}
[bash] kill -s SIGKILL (backend pid)
(psql) VACUUM;

<<method for occuring a crash>>
while(crash is not occurred){
    (psql) INSERT INTO mytab SELECT t, t FROM generate_series(1, 3000) t;
}


Yoshikazu Imai


Reply via email to