Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtp (Exim 4.80) (envelope-from ) id 1ZHBrt-0000h9-Oj for pgsql-hackers@arkaria.postgresql.org; Mon, 20 Jul 2015 14:16:33 +0000 Received: from localhost ([127.0.0.1] helo=postgresql.org) by malur.postgresql.org with smtp (Exim 4.84) (envelope-from ) id 1ZHBrt-0004Or-4G for pgsql-hackers@arkaria.postgresql.org; Mon, 20 Jul 2015 14:16:33 +0000 Received: from makus.postgresql.org ([2001:4800:1501:1::229]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA384:256) (Exim 4.84) (envelope-from ) id 1ZHBqc-0002wo-Ai for pgsql-hackers@postgresql.org; Mon, 20 Jul 2015 14:15:14 +0000 Received: from mail-wg0-x22b.google.com ([2a00:1450:400c:c00::22b]) by makus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.84) (envelope-from ) id 1ZHBqU-000713-Mm for pgsql-hackers@postgresql.org; Mon, 20 Jul 2015 14:15:12 +0000 Received: by wgav7 with SMTP id v7so66276416wga.2 for ; Mon, 20 Jul 2015 07:15:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:message-id:date:from:reply-to:user-agent:mime-version:to :subject:references:in-reply-to:content-type :content-transfer-encoding; bh=KJeLupFiPTM54KAh30+VR+4voQ3FzUKxrDqCLYVlSds=; b=pf9FVVZZ4rfDFRP5xzyv7UC0AwZd4230Ib9csCFveERt1DPq1QvbSgRv2PjeY5e8ow Ufbd5Joipx7WH579ufGpkIJW9bftDMJQNzeYJL0ilsjKzFrUJC9/v9mI+aD9x+0/6Y/b x8qz9oR0NJ37Gzk2DGjBTTGJzu1qrbDFFBgXR0695ijrbwgMYdedqOdQo5VYafEHB3NC Bfo1A+lTgexrlwHbbvZbaggCE6V4rh4fdxOb5AyPNPaot2BJlhLlz9JBh5tL6piptNmg CyW/QrgJZlul2VAZZtNKEIaPD649P/8CXuGzb6QQ4JDwuIw5jqu86D7HId1MEOqFUQCS K2kw== X-Received: by 10.194.21.70 with SMTP id t6mr61458194wje.74.1437401705082; Mon, 20 Jul 2015 07:15:05 -0700 (PDT) Received: from [192.168.1.105] (dsl-hkibrasgw1-58c38f-82.dhcp.inet.fi. [88.195.143.82]) by smtp.gmail.com with ESMTPSA id h9sm32220283wjx.20.2015.07.20.07.15.03 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 20 Jul 2015 07:15:04 -0700 (PDT) Message-ID: <55AD0266.4050300@iki.fi> Date: Mon, 20 Jul 2015 17:15:02 +0300 From: Heikki Linnakangas Reply-To: hlinnaka@iki.fi User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Icedove/31.7.0 MIME-Version: 1.0 To: pgsql-hackers , Alvaro Herrera Subject: Re: All-zero page in GIN index causes assertion failure References: <55ACADCD.6020206@iki.fi> In-Reply-To: <55ACADCD.6020206@iki.fi> Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit X-Pg-Spam-Score: -2.4 (--) List-Archive: List-Help: List-ID: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: X-Mailing-List: pgsql-hackers Precedence: bulk Sender: pgsql-hackers-owner@postgresql.org On 07/20/2015 11:14 AM, Heikki Linnakangas wrote: > ISTM ginvacuumcleanup should check for PageIsNew, and put the page to > the FSM. That's what btvacuumpage() gistvacuumcleanup() do. > spgvacuumpage() seems to also check for PageIsNew(), but it seems broken > in a different way: it initializes the page and marks the page as dirty, > but it is not WAL-logged. That is a problem at least if checksums are > enabled: if you crash you might have a torn page on disk, with invalid > checksum. Looking closer, heap vacuum does a similar thing, but there are two mitigating factors that make it safe in practice, I think: 1. An empty heap page is all-zeroes except for the small page header in the beginning of the page. For a torn page to matter, the page would need to be torn in the header, but we rely elsewhere (control file) anyway that a 512-byte sector update is atomic, so that shouldn't happen. Note that this hinges on the fact that there is no special area on heap pages, so you cannot rely on this for index pages. 2. The redo of the first insert/update on a heap page will always re-initialize the page, even when full-page-writes are disabled. This is the XLOG_HEAP_INIT_PAGE optimization. So it's not just an optimization, it's required for correctness. Heap update can also leave behind a page in the buffer cache that's been initialized by RelationGetBufferForTuple but not yet WAL-logged. However, it doesn't mark the buffer dirty, so the torn-page problem cannot happen because the page will not be flushed to disk if nothing else touches it. The XLOG_HEAP_INIT_PAGE optimization is needed in that case too, however. B-tree, GiST, and SP-GiST's relation extension work similarly, but they have other mitigating factors. If a newly-initialized B-tree page is left behind in the relation, it won't be reused for anything, and vacuum will ignore it (by accident, I think; there is no explicit comment on what will happen to such pages, but it will be treated like an internal page and ignored). Eventually the buffer will be evicted from cache, and because it's not marked as dirty, it will not be flushed to disk, and will later be read back as all-zeros and vacuum will recycle it. BRIN update is not quite right, however. brin_getinsertbuffer() can initialize a page, but the caller might bail out without using the page and WAL-logging the change. If that happens, the next update that uses the same page will WAL-log the change but it will not use the XLOG_BRIN_INIT_PAGE option, and redo will not initialize the page. Redo will fail. BTW, shouldn't there be a step in BRIN vacuum that scans all the BRIN pages? If an empty page is missing from the FSM for any reason, there's nothing to add it there. This is all very subtle. The whole business of leaving behind an already-initialized page in the buffer cache, without marking the buffer as dirty, is pretty ugly. I wish we had a more robust pattern to handle all-zero pages and relation extension. Thoughts? As a minimal backpatchable fix, I think we should add the check in ginvacuumpage() to initialize any all-zeros pages it encounters. That needs to be WAL-logged, and WAL-logging needs to be added to the page initialization in spgvacuumpage too. - Heikki -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers