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 1lALbF-0006XC-6u for pgsql-hackers@arkaria.postgresql.org; Thu, 11 Feb 2021 23:42:17 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1lALbE-0006vM-2S for pgsql-hackers@arkaria.postgresql.org; Thu, 11 Feb 2021 23:42:16 +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 1lALbD-0006vE-MH for pgsql-hackers@lists.postgresql.org; Thu, 11 Feb 2021 23:42:15 +0000 Received: from mail-ej1-x631.google.com ([2a00:1450:4864:20::631]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1lALb8-00073X-HN for pgsql-hackers@postgresql.org; Thu, 11 Feb 2021 23:42:14 +0000 Received: by mail-ej1-x631.google.com with SMTP id bl23so12783238ejb.5 for ; Thu, 11 Feb 2021 15:42:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=enterprisedb-com.20150623.gappssmtp.com; s=20150623; h=subject:to:cc:references:from:message-id:date:user-agent :mime-version:in-reply-to:content-language:content-transfer-encoding; bh=+PzgjMm9a8o4cJXSjQ/gL2iZvURGjuY8pzT/uPkgWI8=; b=wYxaFy5IrAcji37umjHQIjYs95r98N9t6K4hnnbpyDhgoXrIOY+ZH+QaX2VflDoy1L aleLDI54mEvQgqRSZWF80TL4ZiRkHKNFOqlqNXoy0HhDAFn45qTUXI1WCEPurPa29okA MAsaAM7HCuUSvB9kUPdXs9T/I82/KlFJcWcF2X3OOKuT0jFik+NdJUqDzVMlyYL3rqDj KVXLHDI90LT2zB68OBXe4Qo+rRaDu3uHDjL6aGuiIV1iIuVAJ9N7Jn2+YzXpFcmAKcz6 eAJwAsQNR08+y+4g2+MOKYO1uHuhHX848uacQNDwCNEwCL0o77YQnlZLmVYhmxt2Z0rJ +MDQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:cc:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=+PzgjMm9a8o4cJXSjQ/gL2iZvURGjuY8pzT/uPkgWI8=; b=cJ7/WPvlbAlDnE+J2x4GN0Wt1r4bS6/Ml7JNNUDbEZ/hWwGFUV/Yn82nNItz2MPxUE XF4LJKlbJMWOSDTUtRVgV3qIER16KePVRj6Yc4u0U/Xum/AR3qbVjpxbt9S8TDHkaV50 m6+IDdOEdX13cruWSZ321Ztl7B3YVhz1B286uWiZM3HR8Lp9pk6MhjYdLMR37ZQ2+d+I fmI77CzHUrMIlytA2o83kTQy2GIt6/hvwAOk5Hbahy5kQDvS9jVTTYF/vADKwySW+9zK uhXweCjL9rzBW4ARfxM47naA8BQyxtDrKYwNRmz+KLGZerIlzYfLAqQdn1/kGrjiHi3i jyoA== X-Gm-Message-State: AOAM532+z9qk2AOxY288WckZ/vORl1Wa9YbBRX2BGZO5RmAECZunqBhn 3tOXvvl8IFCSaViYFmQ7y7swrnmTxpgruqBbuH2+94BR+Xq9cLgN0RvykLewEPiiREtmkiWBw8Y p6yZsgMLIutNyfbVDtxVDS01uskm6PWTzX/VRB/lgHsp8YXWm2bEysjEmKrzydPPp8yBuwgb1gt I2/jPKz/wgYU7l2yW3NX1smW0X/xOO9KMbgwl365yJXXfRlUeQPHBe5geHYFKHzqKhe4YR3LPBC qFFoCwmZ0P25wEJ9ir9GUAgVSr/H1s48HLDdQ== X-Google-Smtp-Source: ABdhPJxdTp7RPW8UO/EgN0JyKzQCSCi15xVb5ix3S+HM/8gjFrp4wcHuPf1k6R1Nsu+6wlrXn8M84A== X-Received: by 2002:a17:906:ad98:: with SMTP id la24mr123363ejb.315.1613086928044; Thu, 11 Feb 2021 15:42:08 -0800 (PST) Received: from [10.137.0.20] (ip-86-49-253-127.net.upcbroadband.cz. [86.49.253.127]) by smtp.gmail.com with ESMTPSA id y20sm4743374edc.84.2021.02.11.15.42.06 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Thu, 11 Feb 2021 15:42:07 -0800 (PST) Subject: Re: WIP: WAL prefetch (another approach) To: Stephen Frost , Thomas Munro Cc: Jakub Wartak , Alvaro Herrera , Tomas Vondra , Dmitry Dolgov <9erthalion6@gmail.com>, David Steele , Andres Freund , pgsql-hackers References: <20200908231235.lsgat5ni35h6odqt@development> <20201010112935.qrhm572v4djrjljo@development> <5437ce5b-d305-bd85-23ec-ddb15735d93f@enterprisedb.com> <20201113151344.GU16415@tamriel.snowman.net> <20210210215033.GA27507@tamriel.snowman.net> From: Tomas Vondra Message-ID: <103ec76d-8bbc-09e1-460c-8785751431b5@enterprisedb.com> Date: Fri, 12 Feb 2021 00:42:04 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.6.0 MIME-Version: 1.0 In-Reply-To: <20210210215033.GA27507@tamriel.snowman.net> Content-Type: text/plain; charset=windows-1252; format=flowed Content-Language: en-US Content-Transfer-Encoding: 7bit X-CLOUD-SEC-AV-Info: enterprisedb,google_mail,monitor X-CLOUD-SEC-AV-Sent: true X-Gm-Spam: 0 X-Gm-Phishy: 0 List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk On 2/10/21 10:50 PM, Stephen Frost wrote: > > ... > >> +/* >> + * Scan the current record for block references, and consider prefetching. >> + * >> + * Return true if we processed the current record to completion and still have >> + * queue space to process a new record, and false if we saturated the I/O >> + * queue and need to wait for recovery to advance before we continue. >> + */ >> +static bool >> +XLogPrefetcherScanBlocks(XLogPrefetcher *prefetcher) >> +{ >> + DecodedXLogRecord *record = prefetcher->record; >> + >> + Assert(!XLogPrefetcherSaturated(prefetcher)); >> + >> + /* >> + * We might already have been partway through processing this record when >> + * our queue became saturated, so we need to start where we left off. >> + */ >> + for (int block_id = prefetcher->next_block_id; >> + block_id <= record->max_block_id; >> + ++block_id) >> + { >> + DecodedBkpBlock *block = &record->blocks[block_id]; >> + PrefetchBufferResult prefetch; >> + SMgrRelation reln; >> + >> + /* Ignore everything but the main fork for now. */ >> + if (block->forknum != MAIN_FORKNUM) >> + continue; >> + >> + /* >> + * If there is a full page image attached, we won't be reading the >> + * page, so you might think we should skip it. However, if the >> + * underlying filesystem uses larger logical blocks than us, it >> + * might still need to perform a read-before-write some time later. >> + * Therefore, only prefetch if configured to do so. >> + */ >> + if (block->has_image && !recovery_prefetch_fpw) >> + { >> + pg_atomic_unlocked_add_fetch_u64(&Stats->skip_fpw, 1); >> + continue; >> + } > > FPIs in the stream aren't going to just avoid reads when the > filesystem's block size matches PG's- they're also going to avoid > subsequent modifications to the block, provided we don't end up pushing > that block out of shared buffers, rights? > > That is, if you have an empty shared buffers and see: > > Block 5 FPI > Block 6 FPI > Block 5 Update > Block 6 Update > > it seems like, with this patch, we're going to Prefetch Block 5 & 6, > even though we almost certainly won't actually need them. > Yeah, that's a good point. I think it'd make sense to keep track of recent FPIs and skip prefetching such blocks. But how exactly should we implement that, how many blocks do we need to track? If you get an FPI, how long should we skip prefetching of that block? I don't think the history needs to be very long, for two reasons. Firstly, the usual pattern is that we have FPI + several changes for that block shortly after it. Secondly, maintenance_io_concurrency limits this naturally - after crossing that, redo should place the FPI into shared buffers, allowing us to skip the prefetch. So I think using maintenance_io_concurrency is sufficient. We might track more buffers to allow skipping prefetches of blocks that were evicted from shared buffers, but that seems like an overkill. However, maintenance_io_concurrency can be quite high, so just a simple queue is not very suitable - searching it linearly for each block would be too expensive. But I think we can use a simple hash table, tracking (relfilenode, block, LSN), over-sized to minimize collisions. Imagine it's a simple array with (2 * maintenance_io_concurrency) elements, and whenever we prefetch a block or find an FPI, we simply add the block to the array as determined by hash(relfilenode, block) hashtable[hash(...)] = {relfilenode, block, LSN} and then when deciding whether to prefetch a block, we look at that one position. If the (relfilenode, block) match, we check the LSN and skip the prefetch if it's sufficiently recent. Otherwise we prefetch. We may issue some extra prefetches due to collisions, but that's fine I think. There should not be very many of them, thanks to having the hash table oversized. The good thing is this is quite simple, fixed-sized data structure, there's no need for allocations etc. >> + /* Fast path for repeated references to the same relation. */ >> + if (RelFileNodeEquals(block->rnode, prefetcher->last_rnode)) >> + { >> + /* >> + * If this is a repeat access to the same block, then skip it. >> + * >> + * XXX We could also check for last_blkno + 1 too, and also update >> + * last_blkno; it's not clear if the kernel would do a better job >> + * of sequential prefetching. >> + */ >> + if (block->blkno == prefetcher->last_blkno) >> + { >> + pg_atomic_unlocked_add_fetch_u64(&Stats->skip_seq, 1); >> + continue; >> + } > > I'm sure this will help with some cases, but it wouldn't help with the > case that I mention above, as I understand it. > It won't but it's a pretty effective check. I've done some experiments recently, and with random pgbench this eliminates ~15% of prefetches. regards -- Tomas Vondra EnterpriseDB: http://www.enterprisedb.com The Enterprise PostgreSQL Company