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 1k8Sdr-0005a2-8I for pgsql-hackers@arkaria.postgresql.org; Wed, 19 Aug 2020 18:16:55 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1k8Sdp-0000ji-FA for pgsql-hackers@arkaria.postgresql.org; Wed, 19 Aug 2020 18:16:53 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1k8Sdp-0000jQ-3b for pgsql-hackers@lists.postgresql.org; Wed, 19 Aug 2020 18:16:53 +0000 Received: from mail-qt1-x842.google.com ([2607:f8b0:4864:20::842]) by makus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1k8Sdm-0008Gv-BS for pgsql-hackers@lists.postgresql.org; Wed, 19 Aug 2020 18:16:51 +0000 Received: by mail-qt1-x842.google.com with SMTP id v22so18525785qtq.8 for ; Wed, 19 Aug 2020 11:16:50 -0700 (PDT) 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:mime-version:content-disposition :content-transfer-encoding:in-reply-to:user-agent; bh=J7Mcy2OPrYoj7Ps2L+1P+hNevJBZqD6rSnmjwZ9xvFY=; b=LR0Y6G7+c5yVLBiHoyRNZu5pH0o6Bs3zmXZglcNuqArbR9zr0jfT98j0fg7MhUzq6S mWVYhgSRJl8YBuQ12H2hWmavFN6CejW7kx0uAF20JLLYAny+l7RS7a05Gu7oiFHA65cY /+sZrnN1P0mcfOMI8LKKSZPWI0yo/Ja+YOmpbGc8w1GDmd9P1Oc4/gyDFmq5Q4av0OAX mydhB+Psi9c3B92Hql0nP8eN6Yad4xIY45sLYGvkn/gjuAvlGrdyR/f9ak15saWpwZIY wSHgyFMy6qVWcUxESzssKZb7yGuM1I/RLcqJsyjCN63B6THKhOo+VeheRqKTB8qouOtx qHqg== 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:mime-version :content-disposition:content-transfer-encoding:in-reply-to :user-agent; bh=J7Mcy2OPrYoj7Ps2L+1P+hNevJBZqD6rSnmjwZ9xvFY=; b=ThSYsRNC5xjgjETa0xkhrW0jG07Y0zCBsO4XfzlooJkUOI4CKtj0UJLhCJaGd2R5Yf koygQLJKPBX0Ey2AS78MJfJ98a7EkmtccFz2xAXIzpw4lFJr3Tn3QOw0AQHkQgwYhWg/ nGzKAImG89lYr8j3h4QkCSD7OZuQwx2l2EeK1sop2VQ2uCvqQCwoHSHWJXjfGXetU07t Qdg8mh5Bd65hXuw3Ql7GxILSD5AslsYOVOYYOBmathnfNOwMUm7pyu2+PJGKLGlNhkC9 VwzA5g6whlebMtDaFeuxQnVcQX9XFTGVHfH4HD5bNNTdxVgn4YaIAAmCslbJE0pImzyR wokQ== X-Gm-Message-State: AOAM533b8QRjH+uFdqGhEH1Us1ELWUxqtb8o7GpS3CG3PCQB5Ejw48Dg gqP2Gr1sbCcEoHLAHA3xKWOVWQ== X-Google-Smtp-Source: ABdhPJxPKf+Tgem1/8mdU8Q+1rY6nvTxESzfuCoeML1wlosKnksUR3xNTzE3cXNR+uLvX3WwYUni7w== X-Received: by 2002:ac8:1788:: with SMTP id o8mr22392336qtj.330.1597861009323; Wed, 19 Aug 2020 11:16:49 -0700 (PDT) Received: from perhan.alvh.no-ip.org ([190.95.19.47]) by smtp.gmail.com with ESMTPSA id l189sm25182077qke.67.2020.08.19.11.16.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 Aug 2020 11:16:48 -0700 (PDT) Received: by perhan.alvh.no-ip.org (Postfix, from userid 1000) id 55DB42A0EF6; Wed, 19 Aug 2020 14:16:46 -0400 (-04) Date: Wed, 19 Aug 2020 14:16:46 -0400 From: Alvaro Herrera To: James Coleman Cc: Tom Lane , Pg Hackers Subject: Re: remove spurious CREATE INDEX CONCURRENTLY wait Message-ID: <20200819181646.GA1559@alvherre.pgsql> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="nFreZHaLTZJo0R7j" Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk --nFreZHaLTZJo0R7j Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline Content-Transfer-Encoding: 8bit On 2020-Aug-11, James Coleman wrote: > In [3] I'd brought up that a function index can do arbitrary > operations (including, terribly, a query of another table), and Andres > (in [4]) noted that: > > > Well, even if we consider this an actual problem, we could still use > > PROC_IN_CIC for non-expression non-partial indexes (index operator > > themselves better ensure this isn't a problem, or they're ridiculously > > broken already - they can get called during vacuum). > > But went on to describe how this is a problem with all expression > indexes (even if those expressions don't do dangerous things) because > of syscache lookups, but that ideally for expression indexes we'd have > a way to use a different (or more frequently taken) snapshot for the > purpose of computing those expressions. That's a significantly more > involved patch though. So the easy first patch here is to add the flag as PROC_IN_SAFE_CIC, which is set only for CIC when it's used for indexes that are neither on expressions nor partial. Then ignore those in WaitForOlderSnapshots. The attached patch does it that way. (Also updated per recent conflicts). I did not set the flag in REINDEX CONCURRENTLY, but as I understand it can be done too, since in essence it's the same thing as a CIC from a snapshot management point of view. Also, per [1], ISTM this flag could be used to tell lazy VACUUM to ignore the Xmin of this process too, which the previous formulation (where all CICs were so marked) could not. This patch doesn't do that yet, but it seems the natural next step to take. [1] https://postgr.es/m/20191101203310.GA12239@alvherre.pgsql -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services --nFreZHaLTZJo0R7j Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v2-0001-Avoid-spurious-CREATE-INDEX-CONCURRENTLY-waits.patch" From 2a5088dfa35cbc800a87dc2154b6ebfa22837a66 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Tue, 4 Aug 2020 22:04:57 -0400 Subject: [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits --- src/backend/commands/indexcmds.c | 50 ++++++++++++++++++++++++++++++-- src/include/storage/proc.h | 6 +++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 254dbcdce5..459f6fa5db 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -372,7 +372,10 @@ CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts) * lazy VACUUMs, because they won't be fazed by missing index entries * either. (Manual ANALYZEs, however, can't be excluded because they * might be within transactions that are going to do arbitrary operations - * later.) + * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY + * on indexes that are neither expressional nor partial are also safe to + * ignore, since we know that those processes won't examine any data + * outside the table they're indexing. * * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * check for that. @@ -393,7 +396,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) VirtualTransactionId *old_snapshots; old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_old_snapshots); if (progress) pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, n_old_snapshots); @@ -413,7 +417,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) newer_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_newer_snapshots); for (j = i; j < n_old_snapshots; j++) { @@ -506,6 +511,7 @@ DefineIndex(Oid relationId, bool amcanorder; amoptions_function amoptions; bool partitioned; + bool safe_index; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; @@ -1033,6 +1039,17 @@ DefineIndex(Oid relationId, } } + /* + * When doing concurrent index builds, we can set a PGPROC flag to tell + * concurrent VACUUM, CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY + * to ignore us when waiting for concurrent snapshots. That can only be + * done for indexes that don't execute any expressions. Determine that. + * (The flag is reset automatically at transaction end, so it must be + * set for each transaction.) + */ + safe_index = indexInfo->ii_Expressions == NIL && + indexInfo->ii_Predicate == NIL; + /* * Report index creation if appropriate (delay this till after most of the * error checks) @@ -1419,6 +1436,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * The index is now visible, so we can report the OID. */ @@ -1478,6 +1504,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 3 of concurrent index build * @@ -1534,6 +1569,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* We should now definitely not be advertising any xmin. */ Assert(MyProc->xmin == InvalidTransactionId); diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 9c9a50ae45..d91e199a60 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -53,13 +53,17 @@ struct XidCache */ #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ +#define PROC_IN_SAFE_CIC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX + * CONCURRENTLY on non-expressional, + * non-partial index */ #define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ #define PROC_IN_LOGICAL_DECODING 0x10 /* currently doing logical * decoding outside xact */ /* flags reset at EOXact */ #define PROC_VACUUM_STATE_MASK \ - (PROC_IN_VACUUM | PROC_VACUUM_FOR_WRAPAROUND) + (PROC_IN_VACUUM | PROC_IN_SAFE_CIC | PROC_VACUUM_FOR_WRAPAROUND) /* * We allow a small number of "weak" relation locks (AccessShareLock, -- 2.20.1 --nFreZHaLTZJo0R7j--