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 1h6mPy-0006fi-87 for pgsql-hackers@arkaria.postgresql.org; Thu, 21 Mar 2019 01:22:50 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1h6mPw-0006QG-1U for pgsql-hackers@arkaria.postgresql.org; Thu, 21 Mar 2019 01:22:48 +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 1h6mPv-0006Q9-KS for pgsql-hackers@lists.postgresql.org; Thu, 21 Mar 2019 01:22:47 +0000 Received: from mail-wm1-x342.google.com ([2a00:1450:4864:20::342]) by magus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1h6mPs-0007yv-K5 for pgsql-hackers@lists.postgresql.org; Thu, 21 Mar 2019 01:22:47 +0000 Received: by mail-wm1-x342.google.com with SMTP id h18so1060275wml.1 for ; Wed, 20 Mar 2019 18:22:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=2ndquadrant-com.20150623.gappssmtp.com; s=20150623; h=subject:from:to:cc:references:message-id:date:user-agent :mime-version:in-reply-to:content-language; bh=O9Cu4HbcozKFH1vtWW4OIuPTwrBiGynH4sLz/8DCcSw=; b=khzmUT3iJgTerDLOFMSqx00696aaFY6jPYPnt+5tpIKs0u4FB9L1ijEJ3H1gnYUkOn gKSjxBLxwS0CMpT9aRvEIa0v3h0bhc26ukVj9h5OzKMnaQX4nSjTduivVA5jGaQbnQZ8 a5Ldlf+N552gUyET6kEsh1aIXXgGGdwpp3/JO9oneKIqYRzPKeONB2sjHlrw0MLL9/xn SCpsW/ZG6yK+uRSkZT7u4giopxGPGHjJRUhN4XzyY4MMFTSptlQbqJfHndVaaIsOSyJn MSR67blKZp1/Cf6LN+MIO8/jepYmH5Caf7KdDSaDe+gMmHC3qZFa9tmtMf8h3pCJ+DgT Yp1Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:from:to:cc:references:message-id:date :user-agent:mime-version:in-reply-to:content-language; bh=O9Cu4HbcozKFH1vtWW4OIuPTwrBiGynH4sLz/8DCcSw=; b=PFxKv9ExymQb5TTYe5EywriMnuA2jpxTK+RH8g1vmIZMarGzS3zZqUV+fbbdYXRH4Q bVp4j3PQNFscSJqZ+H7VeLZdI9BDhToQyoV9/O8XOp3UJHBPYifJo+Qm9c7PG6mFAKI7 ZGJr9KXcd7DTYmN9J6gEfrlbRoUKFxVxV5IHc5tRHoP6fO7j1/9gNFXY3/p3OYLY44XG zsb7kQ7H6AC2k66Z5MjRzYyKF+v34enIoDsIiyIssBr++9IivPzYG5eF84jWXqU1zaKZ eAyien85E9hnKZmUUCJ4qJPnvNHnxBSQWFKcH3meqPoOFpNuVW3J5LP+Pdg/zjFWgj33 03aA== X-Gm-Message-State: APjAAAVNJoh3YO6w6LpaVBCYZWpt0Z3WgtWZf/nfXx5OTjGSBdGgzqFe +hwvplrLRac4I88Ny/+VLSmiCoyNdtsZ7yPV3yAwmMiPGQauylQPNoJrE7VSJIFeBEbSZOXPcWd UttuqrJDs1sh5+/Tst5O4UsdEC75BKhpv8coK88dz6OciHoPM76MpiMUWdpRSRiSvHJ8XcEMNFX Krc4Wf9bUEnFdwCYbWW4wxDw== X-Google-Smtp-Source: APXvYqxNy8gOaNxgtNKy5Tob2tADM8YZ/3R6+vmT/q1ESXXc0AOp30fPL4yBeRalz45pCVjxQAgSQQ== X-Received: by 2002:a1c:63c3:: with SMTP id x186mr615324wmb.47.1553131362397; Wed, 20 Mar 2019 18:22:42 -0700 (PDT) Received: from [10.137.0.17] (ip-86-49-243-43.net.upcbroadband.cz. [86.49.243.43]) by smtp.gmail.com with ESMTPSA id d7sm4678548wmf.31.2019.03.20.18.22.40 (version=TLS1_3 cipher=AEAD-AES128-GCM-SHA256 bits=128/128); Wed, 20 Mar 2019 18:22:40 -0700 (PDT) Subject: Re: performance issue in remove_from_unowned_list() From: Tomas Vondra To: Alvaro Herrera Cc: Postgres hackers References: <20190310200923.GA4108@alvherre.pgsql> <7c599eff-8125-091c-61ef-90e02aa57486@2ndquadrant.com> Message-ID: Date: Thu, 21 Mar 2019 02:22:40 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.5.1 MIME-Version: 1.0 In-Reply-To: <7c599eff-8125-091c-61ef-90e02aa57486@2ndquadrant.com> Content-Type: multipart/mixed; boundary="------------780AE791F4DB6C4AE9A952FE" Content-Language: en-US List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk This is a multi-part message in MIME format. --------------780AE791F4DB6C4AE9A952FE Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit On 3/12/19 11:54 PM, Tomas Vondra wrote: > > > On 3/10/19 9:09 PM, Alvaro Herrera wrote: >> On 2019-Feb-07, Tomas Vondra wrote: >> >>> Attached is a WIP patch removing the optimization from DropRelationFiles >>> and adding it to smgrDoPendingDeletes. This resolves the issue, at least >>> in the cases I've been able to reproduce. But maybe we should deal with >>> this issue earlier by ensuring the two lists are ordered the same way >>> from the very beginning, somehow. >> >> I noticed that this patch isn't in the commitfest. Are you planning to >> push it soon? >> > > I wasn't planning to push anything particularly soon, for two reasons: > Firstly, the issue is not particularly pressing except with non-trivial > number of relations (and I only noticed that during benchmarking). > Secondly, I still have a feeling I'm missing something about b4166911 > because for me that commit does not actually fix the issue - i.e. I can > create a lot of relations in a transaction, abort it, and observe that > the replica actually accesses the relations in exactly the wrong order. > So that commit does not seem to actually fix anything. > > Attached is a patch adopting the dlist approach - it seems to be working > quite fine, and is a bit cleaner than just slapping another pointer into > the SMgrRelationData struct. So I'd say this is the way to go. > > I see b4166911 was actually backpatched to all supported versions, on > the basis that it fixes oversight in 279628a0a7. So I suppose this fix > should also be backpatched. > OK, so here is a bit more polished version of the dlist-based patch. It's almost identical to what I posted before, except that it: 1) undoes the non-working optimization in DropRelationFiles() 2) removes add_to_unowned_list/remove_from_unowned_list entirely and just replaces that with dlist_push_tail/dlist_delete I've originally planned to keep those functions, mostly because the remove_from_unowned_list comment says this: - * If the reln is not present in the list, nothing happens. - * Typically this would be caller error, but there seems no - * reason to throw an error. I don't think dlist_delete allows that. But after further inspection of all places calling those functions, don't think that can happen. I plan to commit this soon-ish and backpatch it as mentioned before, because I consider it pretty much a fix for b4166911. I'm however still mildly puzzled that b4166911 apparently improved the behavior in some cases, at least judging by [1]. OTOH there's not much detail about how it was tested, so I can't quite run it again. [1] https://www.postgresql.org/message-id/flat/CAHGQGwHVQkdfDqtvGVkty%2B19cQakAydXn1etGND3X0PHbZ3%2B6w%40mail.gmail.com regards -- Tomas Vondra http://www.2ndQuadrant.com PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services --------------780AE791F4DB6C4AE9A952FE Content-Type: text/x-patch; name="smgr-fix-20190321.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="smgr-fix-20190321.patch" diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c index 2aba2dfe91..6ed68185ed 100644 --- a/src/backend/storage/smgr/md.c +++ b/src/backend/storage/smgr/md.c @@ -1699,13 +1699,7 @@ DropRelationFiles(RelFileNode *delrels, int ndelrels, bool isRedo) smgrdounlinkall(srels, ndelrels, isRedo); - /* - * Call smgrclose() in reverse order as when smgropen() is called. - * This trick enables remove_from_unowned_list() in smgrclose() - * to search the SMgrRelation from the unowned list, - * with O(1) performance. - */ - for (i = ndelrels - 1; i >= 0; i--) + for (i = 0; i < ndelrels; i++) smgrclose(srels[i]); pfree(srels); } diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c index 0c0bba4ab3..f6de9df9e6 100644 --- a/src/backend/storage/smgr/smgr.c +++ b/src/backend/storage/smgr/smgr.c @@ -18,6 +18,7 @@ #include "postgres.h" #include "commands/tablespace.h" +#include "lib/ilist.h" #include "storage/bufmgr.h" #include "storage/ipc.h" #include "storage/smgr.h" @@ -97,12 +98,10 @@ static const int NSmgr = lengthof(smgrsw); */ static HTAB *SMgrRelationHash = NULL; -static SMgrRelation first_unowned_reln = NULL; +static dlist_head unowned_relns; /* local function prototypes */ static void smgrshutdown(int code, Datum arg); -static void add_to_unowned_list(SMgrRelation reln); -static void remove_from_unowned_list(SMgrRelation reln); /* @@ -165,7 +164,7 @@ smgropen(RelFileNode rnode, BackendId backend) ctl.entrysize = sizeof(SMgrRelationData); SMgrRelationHash = hash_create("smgr relation table", 400, &ctl, HASH_ELEM | HASH_BLOBS); - first_unowned_reln = NULL; + dlist_init(&unowned_relns); } /* Look up or create an entry */ @@ -192,7 +191,7 @@ smgropen(RelFileNode rnode, BackendId backend) reln->md_num_open_segs[forknum] = 0; /* it has no owner yet */ - add_to_unowned_list(reln); + dlist_push_tail(&unowned_relns, &reln->node); } return reln; @@ -222,7 +221,7 @@ smgrsetowner(SMgrRelation *owner, SMgrRelation reln) if (reln->smgr_owner) *(reln->smgr_owner) = NULL; else - remove_from_unowned_list(reln); + dlist_delete(&reln->node); /* Now establish the ownership relationship. */ reln->smgr_owner = owner; @@ -246,53 +245,8 @@ smgrclearowner(SMgrRelation *owner, SMgrRelation reln) /* unset our reference to the owner */ reln->smgr_owner = NULL; - add_to_unowned_list(reln); -} - -/* - * add_to_unowned_list -- link an SMgrRelation onto the unowned list - * - * Check remove_from_unowned_list()'s comments for performance - * considerations. - */ -static void -add_to_unowned_list(SMgrRelation reln) -{ - /* place it at head of the list (to make smgrsetowner cheap) */ - reln->next_unowned_reln = first_unowned_reln; - first_unowned_reln = reln; -} - -/* - * remove_from_unowned_list -- unlink an SMgrRelation from the unowned list - * - * If the reln is not present in the list, nothing happens. Typically this - * would be caller error, but there seems no reason to throw an error. - * - * In the worst case this could be rather slow; but in all the cases that seem - * likely to be performance-critical, the reln being sought will actually be - * first in the list. Furthermore, the number of unowned relns touched in any - * one transaction shouldn't be all that high typically. So it doesn't seem - * worth expending the additional space and management logic needed for a - * doubly-linked list. - */ -static void -remove_from_unowned_list(SMgrRelation reln) -{ - SMgrRelation *link; - SMgrRelation cur; - - for (link = &first_unowned_reln, cur = *link; - cur != NULL; - link = &cur->next_unowned_reln, cur = *link) - { - if (cur == reln) - { - *link = cur->next_unowned_reln; - cur->next_unowned_reln = NULL; - break; - } - } + /* add to list of unowned relations */ + dlist_push_tail(&unowned_relns, &reln->node); } /* @@ -319,7 +273,7 @@ smgrclose(SMgrRelation reln) owner = reln->smgr_owner; if (!owner) - remove_from_unowned_list(reln); + dlist_delete(&reln->node); if (hash_search(SMgrRelationHash, (void *) &(reln->smgr_rnode), @@ -812,13 +766,19 @@ smgrpostckpt(void) void AtEOXact_SMgr(void) { + dlist_mutable_iter iter; + /* * Zap all unowned SMgrRelations. We rely on smgrclose() to remove each * one from the list. */ - while (first_unowned_reln != NULL) + dlist_foreach_modify(iter, &unowned_relns) { - Assert(first_unowned_reln->smgr_owner == NULL); - smgrclose(first_unowned_reln); + SMgrRelation rel = dlist_container(SMgrRelationData, node, + iter.cur); + + Assert(rel->smgr_owner == NULL); + + smgrclose(rel); } } diff --git a/src/include/storage/smgr.h b/src/include/storage/smgr.h index 4d60b28dac..8e98273878 100644 --- a/src/include/storage/smgr.h +++ b/src/include/storage/smgr.h @@ -14,6 +14,7 @@ #ifndef SMGR_H #define SMGR_H +#include "lib/ilist.h" #include "storage/block.h" #include "storage/relfilenode.h" @@ -71,7 +72,7 @@ typedef struct SMgrRelationData struct _MdfdVec *md_seg_fds[MAX_FORKNUM + 1]; /* if unowned, list link in list of all unowned SMgrRelations */ - struct SMgrRelationData *next_unowned_reln; + dlist_node node; } SMgrRelationData; typedef SMgrRelationData *SMgrRelation; --------------780AE791F4DB6C4AE9A952FE--