Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kyBK0-0003VS-Sb for pgsql-hackers@arkaria.postgresql.org; Sat, 09 Jan 2021 10:18:13 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1kyBJx-0006ec-6b for pgsql-hackers@arkaria.postgresql.org; Sat, 09 Jan 2021 10:18:09 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kyBJw-0006eV-Nr for pgsql-hackers@lists.postgresql.org; Sat, 09 Jan 2021 10:18:08 +0000 Received: from mail-pg1-x52e.google.com ([2607:f8b0:4864:20::52e]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1kyBJt-0001Lf-Ow for pgsql-hackers@postgresql.org; Sat, 09 Jan 2021 10:18:08 +0000 Received: by mail-pg1-x52e.google.com with SMTP id z21so9297181pgj.4 for ; Sat, 09 Jan 2021 02:18:05 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=leadboat.com; s=google; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=tm90nb5EWHhNtZ2iwm4f+6Zm43KgrIHJu/ZAEHW+Y9c=; b=a9t+CJwyw0KtQO+HDSvdNgAJ1WN+Gh/2JT9g1l5CNvF1+ZlndIerCF9rg8KzP45IAN aiND24+XjaSjZ20z3B7p/Cw7mNNYjEPFwAaGvDjU5i2KsIkHVfmiLov79dbnJOv4oYlt ScGSXDKXOqO2CJpzXdj0mNfAFlO/1gPJe/Gio= 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:user-agent; bh=tm90nb5EWHhNtZ2iwm4f+6Zm43KgrIHJu/ZAEHW+Y9c=; b=C0Zc7eAhM3Jdh5F9VFTSHrR+9fTCZxb5MWVID0Ong0WLq4YmhgGYn8sNAaLehS+72V RC5ev8SKc+SUkeET9k1D2o1VDX/nVtqWpNr7vY9aSWOOqjuwCgGDu+G9oQYpytUVQ6eR 0p1shbPHT0DsGKzNmNKcdRdaufjPgZHPywApozjyHXMNqCAACkqfEAcOdVV9tcGTwsiO dExXjFZtDnqxmc0ssRUNCxpm4FfOISCK9atTP4/RH1cO4FDeGrW1K6xcDk6TAvkFtuWS U4gN+XjtE6g+yXL5GPi3GbIpvXnGl+YHGgOJn2jcroWqVvBZLKkXWfsA62Wa04CRGon8 NG+Q== X-Gm-Message-State: AOAM531e5wTxktP6Te5qlxnIhVeJTvqm7DO2JrL4H9GGmfn9mMRUTUkd 4aXE4gT9TEM+YMR20i3nTb0YsQ== X-Google-Smtp-Source: ABdhPJyTEA8ZOxWMIHmxUjOFnYTTl2VfUd0a4QJXUXQN98zTn5jBEX8b4Le78GuQY6Pvg1LUvWkTIg== X-Received: by 2002:a65:6859:: with SMTP id q25mr6074835pgt.57.1610187483322; Sat, 09 Jan 2021 02:18:03 -0800 (PST) Received: from rfd.leadboat.com ([2600:1702:a20:5750::46]) by smtp.gmail.com with ESMTPSA id u24sm7742221pjx.56.2021.01.09.02.18.01 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 09 Jan 2021 02:18:02 -0800 (PST) Date: Sat, 9 Jan 2021 02:17:59 -0800 From: Noah Misch To: Andrey Borodin Cc: Tom Lane , Tomas Vondra , pgsql-hackers@postgresql.org Subject: Re: Spurious "apparent wraparound" via SimpleLruTruncate() rounding Message-ID: <20210109101759.GA122398@rfd.leadboat.com> References: <13116.1585168951@sss.pgh.pa.us> <20200330052809.GB2324620@rfd.leadboat.com> <1959.1586198769@sss.pgh.pa.us> <20200407041847.GA519993@rfd.leadboat.com> <20200525070033.GA1591335@rfd.leadboat.com> <20200830053433.GA3275593@rfd.leadboat.com> <20201029040159.GA3803708@rfd.leadboat.com> <20201109045319.GA459206@rfd.leadboat.com> <23599722-1EFF-4B71-A77C-67141882EFAE@yandex-team.ru> <561A2AF4-E745-4043-B5FC-9537AEE55701@yandex-team.ru> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <561A2AF4-E745-4043-B5FC-9537AEE55701@yandex-team.ru> User-Agent: Mutt/1.5.24 (2015-08-30) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk On Wed, Jan 06, 2021 at 11:28:36AM +0500, Andrey Borodin wrote: > First patch fixes a bug with possible SLRU truncation around wrapping point too early. > Basic idea of the patch is "If we want to delete a range we must be eligible to delete it's beginning and ending". > So to test if page is deletable it tests that first and last xids(or other SLRU's unit) are of no interest. To test if a segment is deletable it tests if first and last pages can be deleted. Yes. > I'm a little suspicious of implementation of *PagePrecedes(int page1, int page2) functions. Consider following example from the patch: > > static bool > CommitTsPagePrecedes(int page1, int page2) > { > TransactionId xid1; > TransactionId xid2; > > xid1 = ((TransactionId) page1) * COMMIT_TS_XACTS_PER_PAGE; > xid1 += FirstNormalTransactionId + 1; > xid2 = ((TransactionId) page2) * COMMIT_TS_XACTS_PER_PAGE; > xid2 += FirstNormalTransactionId + 1; > > return (TransactionIdPrecedes(xid1, xid2) && > TransactionIdPrecedes(xid1, xid2 + COMMIT_TS_XACTS_PER_PAGE - 1)); > } > > We are adding FirstNormalTransactionId to xids to avoid them being special xids. > We add COMMIT_TS_XACTS_PER_PAGE - 1 to xid2 to shift it to the end of the page. But due to += FirstNormalTransactionId we shift slightly behind page boundaries and risk that xid2 + COMMIT_TS_XACTS_PER_PAGE - 1 can become FrozenTransactionId (FirstNormalTransactionId - 1). Thus we add +1 to all values in scope. While the logic is correct, coding is difficult. Maybe we could just use Right. The overall objective is to compare the first XID of page1 to the first and last XIDs of page2. The FirstNormalTransactionId+1 addend operates at a lower level. It just makes TransactionIdPrecedes() behave like NormalTransactionIdPrecedes() without the latter's assertion. > page1_first_normal_xid = ((TransactionId) page1) * CLOG_XACTS_PER_PAGE + FirstNormalTransactionId; > page2_first_normal_xid = ((TransactionId) page2) * CLOG_XACTS_PER_PAGE + FirstNormalTransactionId; > page2_last_xid = ((TransactionId) page2) * CLOG_XACTS_PER_PAGE + CLOG_XACTS_PER_PAGE - 1; > But I'm not insisting on this. I see your point, but I doubt using different addends on different operands makes this easier to understand. If anything, I'd lean toward adding more explicit abstraction between "the XID we intend to test" and "the XID we're using to fool some general-purpose API". > Following comment is not correct for 1Kb and 4Kb pages > + * At every supported BLCKSZ, (1 << 31) % COMMIT_TS_XACTS_PER_PAGE == 128. Fixed, thanks. > All above notes are not blocking the fix, I just wanted to let committer know about this. I think that it's very important to have this bug fixed. > > Second patch converts binary *PagePreceeds() functions to *PageDiff()s and adds logic to avoid deleting pages in suspicious cases. This logic depends on the scale of returned by diff value: it expects that overflow happens between INT_MIN\INT_MAX. This it prevents page deletion if page_diff <= INT_MIN / 2 (too far from current cleaning point; and in normal cases, of cause). > > It must be comparison here, not equality test. > - ctl->PagePrecedes(segpage, trunc->earliestExistingPage)) > + ctl->PageDiff(segpage, trunc->earliestExistingPage)) That's bad. Fixed, thanks. > This > int diff_max = ((QUEUE_MAX_PAGE + 1) / 2) - 1, > seems to be functional equivalent of > int diff_max = ((QUEUE_MAX_PAGE - 1) / 2), Do you think one conveys the concept better than the other? > AFAICS the overall purpose of the 2nd patch is to help corrupted by other bugs clusters avoid deleting SLRU segments. Yes. > I'm a little bit afraid that this kind of patch can hide bugs (while potentially saving some users data). Besides this patch seems like a useful precaution. Maybe we could emit scary warnings if SLRU segments do not stack into continuous range? Scary warnings are good for an observation that implies a bug, but the slru-truncate-t-insurance patch causes such an outcome in non-bug cases where it doesn't happen today. In other words, discontinuous ranges of SLRU segments would be even more common after that patch. For example, it would happen anytime oldestXID advances by more than ~1B at a time. Thanks, nm