Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1intrt-0003z1-71 for pgsql-hackers@arkaria.postgresql.org; Sun, 05 Jan 2020 00:34:09 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1intrq-0006BM-Ew for pgsql-hackers@arkaria.postgresql.org; Sun, 05 Jan 2020 00:34:06 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1intrq-0006BF-2q for pgsql-hackers@lists.postgresql.org; Sun, 05 Jan 2020 00:34:06 +0000 Received: from mail-wm1-x342.google.com ([2a00:1450:4864:20::342]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1intri-0002ah-9w for pgsql-hackers@postgresql.org; Sun, 05 Jan 2020 00:34:05 +0000 Received: by mail-wm1-x342.google.com with SMTP id p9so11559631wmc.2 for ; Sat, 04 Jan 2020 16:33:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=2ndquadrant-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to; bh=UuOoJr9uUFBtcDIRgwOCtE8heRffoPZdHp3lFQWZhMw=; b=fbbE+IrTEN9JthpPv+OuWpkseZLChc1VjRJ401UPhLZZ7w6khpc8isCTDG7VLp7aYc BNYBFCXEVCMtN3uK4KjySdZ183Ij9J1TxsJvWkC5k10siSnvlTPTszIhNLbNpfpgo/od R+KKu0yWj1xKxKIPlybz/1qD5Y8RhJ00sRSuJpaR6AXf3FRkoRmQanGfhXLSafNqKG61 oV580TsAVXdtZFvFgn1kMJnQ4dS4ogpG7wLGYz1l7WwCH7wPqVIHOtcGc008mNjO8n+x bw6zrXWPaofaL9cTA/oQ8QPQYT/n24yZpMcx2F2zQ55AxXSCqGBeQCUB+FsW7R1H75/B 3x0g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to; bh=UuOoJr9uUFBtcDIRgwOCtE8heRffoPZdHp3lFQWZhMw=; b=NSnCnsO/JmFgv2VCg75T+Xc8lULDXUUgiED21qXR2WMEwIKfeQzYiyTVb5JWbnDWab Bwb+qDBVVdzZXWop0FJ5IplFcNkXRAl3QWOxGiBjAH2OzB8sxzjI4byfhtUPINrSDhYT vC9FoseWF6FdwYayDwQOzL9yofqOgo8X2zohRk9V6hCe24mYR0yrWDWcWrjOZG5r0vu2 +PSRGA7ccooiESM19lEnsojXHWfOjZKBNyr3A9kz83RGpnGmO/WgNUmPJm8CV/4WSQzT GIpS9xzvlULkOAmzfMaxE1OY+6fZ6KKrPfyBSQIDRpdBSPu4bUdSNj4xDhv9V8zDuPBg wacA== X-Gm-Message-State: APjAAAUtHP5XD+7r14uYZrwTsIVbj/nB3CTyqWgiUGWo7qYwoFXWTUDN gS7aHaGpD7FaRNHFpm5ks3h3de3Tgjk= X-Google-Smtp-Source: APXvYqyTvynX0nsv8l9YjEk3rtdr2jssZN7WraxahVGbdTBuqXHVXqdnwO+mcDysySBGjFQ+l2HQDw== X-Received: by 2002:a1c:6755:: with SMTP id b82mr26299607wmc.126.1578184437239; Sat, 04 Jan 2020 16:33:57 -0800 (PST) Received: from localhost (ip-86-49-253-92.net.upcbroadband.cz. [86.49.253.92]) by smtp.gmail.com with ESMTPSA id s19sm17335306wmj.33.2020.01.04.16.33.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 04 Jan 2020 16:33:56 -0800 (PST) Date: Sun, 5 Jan 2020 01:33:55 +0100 From: Tomas Vondra To: Noah Misch Cc: pgsql-hackers@postgresql.org Subject: Re: Spurious "apparent wraparound" via SimpleLruTruncate() rounding Message-ID: <20200105003355.n2atv7thx7dqiqbt@development> References: <20190202083822.GC32531@gust.leadboat.com> <20190214072623.GA1139206@rfd.leadboat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Disposition: inline In-Reply-To: <20190214072623.GA1139206@rfd.leadboat.com> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk On Wed, Feb 13, 2019 at 11:26:23PM -0800, Noah Misch wrote: >On Sat, Feb 02, 2019 at 03:38:22AM -0500, Noah Misch wrote: >> The main consequence is the false alarm. > >That conclusion was incorrect. On further study, I was able to reproduce data >loss via either of two weaknesses in the "apparent wraparound" test: > >1. The result of the test is valid only until we release the SLRU ControlLock, > which we do before SlruScanDirCbDeleteCutoff() uses the cutoff to evaluate > segments for deletion. Once we release that lock, latest_page_number can > advance. This creates a TOCTOU race condition, allowing excess deletion: > > [local] test=# table trunc_clog_concurrency ; > ERROR: could not access status of transaction 2149484247 > DETAIL: Could not open file "pg_xact/0801": No such file or directory. > >2. By the time the "apparent wraparound" test fires, we've already WAL-logged > the truncation. clog_redo() suppresses the "apparent wraparound" test, > then deletes too much. Startup then fails: > > 881997 2019-02-10 02:53:32.105 GMT FATAL: could not access status of transaction 708112327 > 881997 2019-02-10 02:53:32.105 GMT DETAIL: Could not open file "pg_xact/02A3": No such file or directory. > 881855 2019-02-10 02:53:32.107 GMT LOG: startup process (PID 881997) exited with exit code 1 > > >Fixes are available: > >a. Fix the rounding in SimpleLruTruncate(). (The patch I posted upthread is > wrong; I will correct it in a separate message.) > >b. Arrange so only one backend runs vac_truncate_clog() at a time. Other than > AsyncCtl, every SLRU truncation appears in vac_truncate_clog(), in a > checkpoint, or in the startup process. Hence, also arrange for only one > backend to call SimpleLruTruncate(AsyncCtl) at a time. > >c. Test "apparent wraparound" before writing WAL, and don't WAL-log > truncations that "apparent wraparound" forces us to skip. > >d. Hold the ControlLock for the entirety of SimpleLruTruncate(). This removes > the TOCTOU race condition, but TransactionIdDidCommit() and other key > operations would be waiting behind filesystem I/O. > >e. Have the SLRU track a "low cutoff" for an ongoing truncation. Initially, > the low cutoff is the page furthest in the past relative to cutoffPage (the > "high cutoff"). If SimpleLruZeroPage() wishes to use a page in the > truncation range, it would acquire an LWLock and increment the low cutoff. > Before unlinking any segment, SlruScanDirCbDeleteCutoff() would take the > same LWLock and recheck the segment against the latest low cutoff. > >With both (a) and (b), the only way I'd know to reach the "apparent >wraparound" message is to restart in single-user mode and burn XIDs to the >point of bona fide wraparound. Hence, I propose to back-patch (a) and (b), >and I propose (c) for HEAD only. I don't want (d), which threatens >performance too much. I would rather not have (e), because I expect it's more >complex than (b) and fixes strictly less than (b) fixes. > >Can you see a way to improve on that plan? Can you see other bugs of this >nature that this plan does not fix? > Seems reasonable, although I wonder how much more expensive would just doing (d) be. It seems by far the least complex solution, and it moves "just" the SlruScanDirectory() call before the lock. It's true it adds I/O requests, OTOH it's just unlink() without fsync() and I'd expect the number of files to be relatively low. Plus we already do SimpleLruWaitIO and SlruInternalWritePage in the loop. BTW isn't that an issue that SlruInternalDeleteSegment does not do any fsync calls after unlinking the segments? If the system crashes/reboots before this becomes persistent (i.e. some of the segments reappear, won't that cause a problem)? It's a bit unfortunate that a patch for a data corruption / loss issue (even if a low-probability one) fell through multiple commitfests. regards -- Tomas Vondra http://www.2ndQuadrant.com PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services