Received: from magus.postgresql.org (magus.postgresql.org [87.238.57.229]) by mail.postgresql.org (Postfix) with ESMTP id 9592610EE895 for ; Tue, 7 Aug 2012 23:39:15 -0300 (ADT) Received: from mail-pb0-f46.google.com ([209.85.160.46]) by magus.postgresql.org with esmtp (Exim 4.72) (envelope-from ) id 1SywAy-0003lu-Jd for pgsql-admin@postgresql.org; Wed, 08 Aug 2012 02:39:14 +0000 Received: by pbbrr13 with SMTP id rr13so663082pbb.19 for ; Tue, 07 Aug 2012 19:38:58 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=message-id:date:from:user-agent:mime-version:to:cc:subject :references:in-reply-to:content-type:x-gm-message-state; bh=MinEykZl8zf7yyHdfG3siUWS8ZJGI/+zUxClq3lDU0Y=; b=KCAdgLZiEb8tBolyiBnmGcevxwiXWmNQAXyDKwS1hJilXxppkP8rsh1SGF3pT5bJ/U 1QpqTYZ+nPUEZ7oVD1yPrYWxkQUuwW+Sjqpzb5f7q3DnooqGg5buCc1BUdrlXjOqwm5W cubdeIBWL4hCaNyju6PE5aiY75JW4LZO5ohEx1Kf0aUoUQ7VSJQcbMn4f3s3h6BXR50z Y/xbn2MoaR+y7/vg/pz/DDcT3yeM4uROo9scWtfSCVd9Ucx8StX/9z+adNhz2cClW3qX XhMxXsFav/1tuLxau9vurazFnNhFV6PGpwzd7ywcYpxS7q17wk1M4ONv4Y3GjRQZkH4J b1AQ== Received: by 10.68.190.168 with SMTP id gr8mr32378712pbc.157.1344393537962; Tue, 07 Aug 2012 19:38:57 -0700 (PDT) Received: from ayaki.localdomain (office1.postnewspapers.com.au. [150.101.171.128]) by mx.google.com with ESMTPS id wn1sm5008999pbc.57.2012.08.07.19.38.54 (version=SSLv3 cipher=OTHER); Tue, 07 Aug 2012 19:38:56 -0700 (PDT) Message-ID: <5021D13C.40809@ringerc.id.au> Date: Wed, 08 Aug 2012 10:38:52 +0800 From: Craig Ringer User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:14.0) Gecko/20120717 Thunderbird/14.0 MIME-Version: 1.0 To: Stephen Frost CC: Terry Schmitt , pgsql-admin@postgresql.org Subject: Re: Data corruption after SAN snapshot References: <5021BCA6.7030000@ringerc.id.au> <20120808013931.GO1267@tamriel.snowman.net> In-Reply-To: <20120808013931.GO1267@tamriel.snowman.net> Content-Type: multipart/alternative; boundary="------------070307030300040309040205" X-Gm-Message-State: ALoCoQl7vhMDkiY7Nq38voFAN9SjN2+dOSj18Wy5uj4/w0hkL41p45MvGYw+TDqXoPZhW8/xCtwY X-Pg-Spam-Score: -1.9 (-) X-Archive-Number: 201208/50 X-Sequence-Number: 39871 This is a multi-part message in MIME format. --------------070307030300040309040205 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit On 08/08/2012 09:39 AM, Stephen Frost wrote: > Terry, > > * Terry Schmitt (tschmitt@schmittworks.com) wrote: >> So far, executing pg_dumpall >> seems to be fairly reliable for finding the corrupt objects after my >> initial data load, but unfortunately much of the corruption has been with >> indexes which pgdump will not expose. > Shouldn't be too hard to write a script that'll do a query against each > table using an ORDER BY that matches each index, at least for 'simple' > indexes, which'll typically cause an in-order index traversal. > I'd really like a "VERIFY" command for PostgreSQL, though a proper one isn't really possible without block checksums. I'm currently working on a virtual plug pull tool that uses VMs to simulate abrupt crashes of the machine PostgreSQL is running on. One of the bigger challenges is that Pg doesn't offer any reliable way to detect even simple corruption. Maybe a pg_read_relation(oid) that simply reads all blocks in an index or table would help. It could live in the `adminpack' module ( http://www.postgresql.org/docs/9.1/static/adminpack.html) or `pageinspect' module ( http://www.postgresql.org/docs/9.1/static/pageinspect.html). It turns out I can use the pageinspect functions to do a rough kind of verify, but it's pretty slow and inconvenient. Eg: WITH pages(page) AS ( SELECT get_raw_page('tablename'::text, pageno) FROM generate_series(0, (SELECT relpages FROM pg_class WHERE relname = 'tablename')-1) AS pageno ) SELECT page_header(page), heap_page_items(page) FROM pages; takes 90ms when a 'SELECT * FROM tablename' takes 6.2ms . On a bigger table, the query takes 3939.912 vs 125.135ms for a table scan. Of course, pageinspect is mostly interesting for indexes, where I'd do: create or replace function scan_index(indexname text) returns setof record as $$ SELECT page_header(get_raw_page($1, 0)); WITH pagenumbers(pageno) AS ( SELECT generate_series(1, (SELECT relpages FROM pg_class WHERE relname = $1)-1) ) SELECT bt_page_items($1, pageno) FROM pagenumbers; $$ language sql volatile; SELECT scan_index('some_idx'); ... but that's getting really quite slow and still hasn't touched the free space map or visibility map. Of course, these checks prove nothing about subtle corruption or incorrect contents, they only make sure Pg can read them and they look vaguely sane. It doesn't do any kind of consistency checking between index and table. -- Craig Ringer --------------070307030300040309040205 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit
On 08/08/2012 09:39 AM, Stephen Frost wrote:
Terry,

* Terry Schmitt (tschmitt@schmittworks.com) wrote:
So far, executing pg_dumpall
seems to be fairly reliable for finding the corrupt objects after my
initial data load, but unfortunately much of the corruption has been with
indexes which pgdump will not expose.
Shouldn't be too hard to write a script that'll do a query against each
table using an ORDER BY that matches each index, at least for 'simple'
indexes, which'll typically cause an in-order index traversal.

I'd really like a "VERIFY" command for PostgreSQL, though a proper one isn't really possible without block checksums.

I'm currently working on a virtual plug pull tool that uses VMs to simulate abrupt crashes of the machine PostgreSQL is running on. One of the bigger challenges is that Pg doesn't offer any reliable way to detect even simple corruption.

Maybe a pg_read_relation(oid) that simply reads all blocks in an index or table would help. It could live in the `adminpack' module ( http://www.postgresql.org/docs/9.1/static/adminpack.html) or `pageinspect' module ( http://www.postgresql.org/docs/9.1/static/pageinspect.html).


It turns out I can use the pageinspect functions to do a rough kind of verify, but it's pretty slow and inconvenient. Eg:

WITH pages(page) AS (
    SELECT get_raw_page('tablename'::text, pageno)
    FROM generate_series(0, (SELECT relpages FROM pg_class WHERE relname = 'tablename')-1) AS pageno
)
SELECT page_header(page), heap_page_items(page) FROM pages;

takes 90ms when a 'SELECT * FROM tablename' takes 6.2ms . On a bigger table, the query takes 3939.912 vs 125.135ms for a table scan.

Of course, pageinspect is mostly interesting for indexes, where I'd do:

create or replace function scan_index(indexname text) returns setof record as $$
SELECT page_header(get_raw_page($1, 0));
WITH pagenumbers(pageno) AS (
    SELECT generate_series(1, (SELECT relpages FROM pg_class WHERE relname = $1)-1)
)
SELECT bt_page_items($1, pageno) FROM pagenumbers;
$$ language sql volatile;

SELECT scan_index('some_idx');

... but that's getting really quite slow and still hasn't touched the free space map or visibility map.

Of course, these checks prove nothing about subtle corruption or incorrect contents, they only make sure Pg can read them and they look vaguely sane. It doesn't do any kind of consistency checking between index and table.

--
Craig Ringer
--------------070307030300040309040205--