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 1iuNf9-0002fk-QR for pgsql-hackers@arkaria.postgresql.org; Wed, 22 Jan 2020 21:35:48 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1iuNf6-00073N-Qz for pgsql-hackers@arkaria.postgresql.org; Wed, 22 Jan 2020 21:35:44 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from <9erthalion6@gmail.com>) id 1iuNf6-00073G-Cf for pgsql-hackers@lists.postgresql.org; Wed, 22 Jan 2020 21:35:44 +0000 Received: from mail-wr1-x444.google.com ([2a00:1450:4864:20::444]) by makus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from <9erthalion6@gmail.com>) id 1iuNf3-0003zy-VK for pgsql-hackers@postgresql.org; Wed, 22 Jan 2020 21:35:43 +0000 Received: by mail-wr1-x444.google.com with SMTP id b6so765639wrq.0 for ; Wed, 22 Jan 2020 13:35:41 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to; bh=7KmxDUQgnpRSRjO4qIOGqcixBuCBxKPzcEtT6A/eE2E=; b=schbDdZh9Q8RdSZ+ZX54+/x8h1UDhK+VuRqB7Uqp7J3GTSMEewrGM77roLOBLhBbwz 6s91Vgf5gXC+B/6K+Q3MM8AYyLSDPWOJGBwtYGuE/kUQ6H2UpvfZh2mgYHZhc0yrpc9e 17tcNCVEEcAdYb/6puwMnmlSLy5VLUOP1Pr78oZ4p7U6oYvoA67ct10NakVXqeqrQ6dA pripsAcgxbmrTy6DAyxxEWHXzjwOKBXJQ4U+g3J1AXhUUUTMdIT05nazcSjLfQr+0Hgb iPvAL8hVtcV2pi+O2/Ri3U+05g8t40eOJKGmTqb1YX4NCLwdXDolf+geXrZNCjl4wOO2 C2Sg== 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=7KmxDUQgnpRSRjO4qIOGqcixBuCBxKPzcEtT6A/eE2E=; b=uZIFOw77p1LetV18vGB00VykWOcMbEmVhdinW9UHnaZycy6Biwd9gGIGfPOXRSP/Er zHqaqe39FgMKVvNHNG0sL7mv2qQ+3OZSB06qWZy2DOrNm+3OUkGe9Nvrv2u9/DFzAFm4 sNe0tJrTjeB5mYxH4Zrx01A1zmjSVnXQoeyRY2Z7ydBK9pcMpis2ciHF5Utk/3f26W+7 QLOMNkJrFOKppLgVPzNGaArjufQhRPdN8I/eW0h8VgnZTteHTDnk4NWtuMOzw6p8buRc i1WIo/vcmiF2NyLBBF/rseU+ppwPrs8HiGPzWFZ7fHL6iPshYilGelzhW30JslBsprf0 p8FA== X-Gm-Message-State: APjAAAXR7+DlNMbOQ8T82Q2fvHPkZuqmHIal0b7QjiceXBX7YeVEKSna AoW3E2lLIOV/UozWJayntxI= X-Google-Smtp-Source: APXvYqyINqNZe+upnijWXGcJX5ghq15fu3uA0E+HnwSd+m1IrKXRAHZsW2Sybqu/HeE2ZDpbVfNONw== X-Received: by 2002:a5d:4acb:: with SMTP id y11mr13536935wrs.106.1579728939512; Wed, 22 Jan 2020 13:35:39 -0800 (PST) Received: from localhost (dslb-094-222-004-201.094.222.pools.vodafone-ip.de. [94.222.4.201]) by smtp.gmail.com with ESMTPSA id b68sm5834397wme.6.2020.01.22.13.35.37 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 22 Jan 2020 13:35:38 -0800 (PST) Date: Wed, 22 Jan 2020 22:36:03 +0100 From: Dmitry Dolgov <9erthalion6@gmail.com> To: Floris Van Nee Cc: Peter Geoghegan , Jesper Pedersen , David Rowley , Tomas Vondra , Kyotaro Horiguchi , Alvaro Herrera , Thomas Munro , James Coleman , Rafia Sabih , Jeff Janes , Bhushan Uparkar , PostgreSQL-development , Alexander Korotkov Subject: Re: Index Skip Scan Message-ID: <20200122213603.ndlm6t4ryivdwxs7@localhost> References: <1e59d800b38141c5af2ad3a64cf9758e@opammb0562.comp.optiver.com> <802e46fa-dc2c-4c32-e55b-884e04aa7f12@redhat.com> <20200121160942.eu4bvbu46nt223ug@localhost> <20200122160441.ograupmzyytde2mi@localhost> <1579713885361.64964@Optiver.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <1579713885361.64964@Optiver.com> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk > On Wed, Jan 22, 2020 at 05:24:43PM +0000, Floris Van Nee wrote: > > > > Anyone please correct me if I'm wrong, but I think one case where the current patch relies on some data from the page it has locked before it in checking this hi/lo key. I think it's possible for the following sequence to happen. Suppose we have a very simple one leaf-page btree containing four elements: leaf page 1 = [2,4,6,8] > > > We do a backwards index skip scan on this and have just returned our first tuple (8). The buffer is left pinned but unlocked. Now, someone else comes in and inserts a tuple (value 5) into this page, but suppose the page happens to be full. So a page split occurs. As far as I know, a page split could happen at any random element in the page. One of the situations we could be left with is: > > > Leaf page 1 = [2,4] > > > Leaf page 2 = [5,6,8] > > > However, our scan is still pointing to leaf page 1. > > > In case if we just returned a tuple, the next action would be either > >> check the next page for another key or search down to the tree. Maybe > > But it won't look at the 'next page for another key', but rather at the 'same page or another key', right? In the _bt_scankey_within_page shortcut we're taking, there's no stepping to a next page involved. It just locks the page again that it previously also locked. Yep, it would look only on the same page. Not sure what do you mean by "another key", if the current key is not found within the current page at the first stage, we restart from the root. > > I'm missing something in your scenario, but the latter will land us on a > > required page (we do not point to any leaf here), and before the former > > there is a check for high/low key. Is there anything else missing? > > Let me try to clarify. After we return the first tuple, so->currPos.buf is pointing to page=1 in my example (it's the only page after all). We've returned item=8. Then the split happens and the items get rearranged as in my example. We're still pointing with so->currPos.buf to page=1, but the page now contains [2,4]. The split happened to the right, so there's a page=2 with [5,6,8], however the ongoing index scan is unaware of that. > Now _bt_skip gets called to fetch the next tuple. It starts by checking _bt_scankey_within_page(scan, so->skipScanKey, so->currPos.buf, dir), the result of which will be 'true': we're comparing the skip key to the low key of the page. So it thinks the next key can be found on the current page. It locks the page and does a _binsrch, finding item=4 to be returned. > > The problem here is that _bt_scankey_within_page mistakenly returns true, thereby limiting the search to just the page that it's pointing to already. > It may be fine to just fix this function to return the proper value (I guess it'd also need to look at the high key in this example). It could also be fixed by not looking at the lo/hi key of the page, but to use the local tuple buffer instead. We already did a _read_page once, so if we have any matching tuples on that specific page, we have them locally in the buffer already. That way we never need to lock the same page twice. Oh, that's what you mean. Yes, I was somehow tricked by the name of this function and didn't notice that it checks only one boundary, so in case of backward scan it returns wrong result. I think in the situation you've describe it would actually not find any item on the current page and restart from the root, but nevertheless we need to check for both keys in _bt_scankey_within_page.