Received: from malur.postgresql.org ([2a02:16a8:dc51::56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA384:256) (Exim 4.89) (envelope-from ) id 1fEgyX-0002n0-CQ for pgsql-hackers@arkaria.postgresql.org; Fri, 04 May 2018 20:06:41 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1fEgyW-0000Xm-39 for pgsql-hackers@arkaria.postgresql.org; Fri, 04 May 2018 20:06:40 +0000 Received: from makus.postgresql.org ([2001:4800:1501:1::229]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA384:256) (Exim 4.89) (envelope-from ) id 1fEgyV-0000Xc-Ld for pgsql-hackers@lists.postgresql.org; Fri, 04 May 2018 20:06:39 +0000 Received: from mail-qk0-x242.google.com ([2607:f8b0:400d:c09::242]) by makus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1fEgyS-0001e6-2d for pgsql-hackers@postgresql.org; Fri, 04 May 2018 20:06:38 +0000 Received: by mail-qk0-x242.google.com with SMTP id b39so17579605qkb.5 for ; Fri, 04 May 2018 13:06:35 -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=/ifu+Ssuu1TOjZ9h/ZgMKIdFenmL7A8/W8LPAvDfhds=; b=fnWQN48GoeEEY2hWiQvoej2Q07KVDIxumCNHDvg5nq7eeze487I/8oqDYXX0u7rNJK jWMiAkVsHSjWeFB/Z7hofoKM+gx6nNZZGUEVhgl/CuarXraoFLazC+k5TIPDjchrxR0v P7DArcyc+xPHWdLKqss7Wa9mPHfzvMplloeSQp/WAtRamiECRN+pDC7aT1Y1xhub5Hfp j9HCJdcO9Rwk011rB4E6JL1jthpll989bN57owYti0dpy279seTlCNaRwSf5hDYgcq0i 80vBRMS6uGWtkeT8tIXlfHNx93QoGd9Xn8UM5vd3C4BQbp/QPqIfR0ZI0FHhdC4K1pw5 pL4A== 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=/ifu+Ssuu1TOjZ9h/ZgMKIdFenmL7A8/W8LPAvDfhds=; b=QIlEcTav3yN+3XhVxC1H/20dKExlePT7VFSmB1UAGozzFa+wD6Rj2PkVbIMh4AwDdy B8vHv91SpsSVqfdc1Xr41+EeHLPJxzqKARYb7pUuEFZV7TQaugoKuysTsEmodOn1dJ2U tbYVmVw/qTpN4Hhqb+YkXxbM6kRatB+qSwxOQhKtdwFwmC2Ah7KKUln78XP0C0EzVnS3 JkXtXi9gWoRljAQeZesUgVF9faf5Ao0dTkhwP8/nCRmAwLphmgab1GeV/RHGL9HIUp+h C1m4owEYHj2/ORyKQr12BUFPDmpl5owngUMCRGzGEYaQ3xzvl4nFEqJ+t0Ehah/M2wri qJSw== X-Gm-Message-State: ALQs6tAjTAiXGTp+0+VRa/LyS/X7eAhU3NvaTywQhyCf4ce2X1EedoOc KPYrCFGYg/Vmfd4InRE13mQqrA== X-Google-Smtp-Source: AB8JxZpCKRIEgk4KJb0akPAEfC2urBY3z7dfP4xWsLrsWOA8hrJVwePNE3m0iFvxdvJyW7duenQ4ww== X-Received: by 10.55.207.80 with SMTP id e77mr22432743qkj.290.1525464394976; Fri, 04 May 2018 13:06:34 -0700 (PDT) Received: from alvin.alvh.no-ip.org ([179.56.29.253]) by smtp.gmail.com with ESMTPSA id o17sm14269260qki.60.2018.05.04.13.06.34 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 04 May 2018 13:06:34 -0700 (PDT) Received: by alvin.alvh.no-ip.org (Postfix, from userid 1000) id 5EBF7925; Fri, 4 May 2018 17:06:32 -0300 (-03) Date: Fri, 4 May 2018 17:06:32 -0300 From: Alvaro Herrera To: Pavan Deolasee Cc: "Wood, Dan" , "pgsql-hackers@postgresql.org" Subject: Re: VM map freeze corruption Message-ID: <20180504200632.i6lh4asitix5pil6@alvherre.pgsql> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="jakb5nxwemu4iuxo" Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: User-Agent: NeoMutt/20170306-137-4415bd-dirty (1.8.0) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk --jakb5nxwemu4iuxo Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline Content-Transfer-Encoding: 8bit Pavan Deolasee wrote: > I wonder if we should just avoid initialising those variables at the top > and take compiler's help to detect any missed branches. That way, we shall > know exactly why and where we are making them true/false. I also think that > we should differentiate between scenarios where xmin/xmax is already frozen > and scenarios where we are freezing them now. After staring at this code for a while, it strikes me that the xmin case is different enough from the xmax case that it works better to let the logic be different; namely for xmin a single bool suffices. I kept your logic for xmax, except that xmax_already_frozen requires initialization (to 'false') or we risk having it end up as 'true' due to random garbage in the stack and set totally_frozen_p to true spuriously because of this (or spuriously fail the assertion in line 6942). I noticed this when running Dan's test case with your patch -- the assertion failed for the xmin case: TRAP: FailedAssertion(«!(!xmin_already_frozen)», Archivo: «/pgsql/source/master/src/backend/access/heap/heapam.c», Línea: 6845) That led me to the rewrite of the xmin logic, and it also led me to looking deeper at the xmax case (with which I didn't run into any assertion failure, but it's clear that it could definitely happen if the stack happens to have that bit set.) I also chose to accept the suggestion in XXX to throw an error: if (tuple->t_infomask & HEAP_XMAX_IS_MULTI) ... else if (TransactionIdIsNormal(xid)) ... else if ((tuple->t_infomask & HEAP_XMAX_INVALID) || !TransactionIdIsValid(HeapTupleHeaderGetRawXmax(tuple))) else ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED), errmsg_internal("found xmax %u (infomask 0x%04x) not frozen, not multi, not normal", xid, tuple->t_infomask))); There's no place else in the backend where we report an infomask, but in this case it seems warranted (for forensics) if this elog ever fires. The tests involved are: which means that this ereport could fire is if the transaction is BootstrapTransactionId or FrozenTransactionId. In either case VACUUM should have removed the tuple as dead, so these cases shouldn't ever occur. (Looking at the other caller for this code, which is cluster.c for table rewrites, it appears that dead tuples are not passed to heap_freeze_tuple, so xmax=BootstrapXid/FrozenXid should not be a problem there either.) Patch attached. I intend to push this soon, to have it in next week's set. -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services --jakb5nxwemu4iuxo Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="frozen_v3.patch" diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 1a672150be..72395a50b8 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -6803,9 +6803,10 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, xl_heap_freeze_tuple *frz, bool *totally_frozen_p) { bool changed = false; - bool freeze_xmax = false; + bool xmax_already_frozen = false; + bool xmin_frozen; + bool freeze_xmax; TransactionId xid; - bool totally_frozen = true; frz->frzflags = 0; frz->t_infomask2 = tuple->t_infomask2; @@ -6814,6 +6815,8 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, /* Process xmin */ xid = HeapTupleHeaderGetXmin(tuple); + xmin_frozen = ((xid == FrozenTransactionId) || + HeapTupleHeaderXminFrozen(tuple)); if (TransactionIdIsNormal(xid)) { if (TransactionIdPrecedes(xid, relfrozenxid)) @@ -6832,9 +6835,8 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, frz->t_infomask |= HEAP_XMIN_FROZEN; changed = true; + xmin_frozen = true; } - else - totally_frozen = false; } /* @@ -6857,9 +6859,9 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, relfrozenxid, relminmxid, cutoff_xid, cutoff_multi, &flags); - if (flags & FRM_INVALIDATE_XMAX) - freeze_xmax = true; - else if (flags & FRM_RETURN_IS_XID) + freeze_xmax = (flags & FRM_INVALIDATE_XMAX); + + if (flags & FRM_RETURN_IS_XID) { /* * NB -- some of these transformations are only valid because we @@ -6873,7 +6875,6 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, if (flags & FRM_MARK_COMMITTED) frz->t_infomask |= HEAP_XMAX_COMMITTED; changed = true; - totally_frozen = false; } else if (flags & FRM_RETURN_IS_MULTI) { @@ -6895,11 +6896,6 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, frz->xmax = newxmax; changed = true; - totally_frozen = false; - } - else - { - Assert(flags & FRM_NOOP); } } else if (TransactionIdIsNormal(xid)) @@ -6927,11 +6923,24 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, freeze_xmax = true; } else - totally_frozen = false; + freeze_xmax = false; } + else if ((tuple->t_infomask & HEAP_XMAX_INVALID) || + !TransactionIdIsValid(HeapTupleHeaderGetRawXmax(tuple))) + { + freeze_xmax = false; + xmax_already_frozen = true; + } + else + ereport(ERROR, + (errcode(ERRCODE_DATA_CORRUPTED), + errmsg_internal("found xmax %u (infomask 0x%04x) not frozen, not multi, not normal", + xid, tuple->t_infomask))); if (freeze_xmax) { + Assert(!xmax_already_frozen); + frz->xmax = InvalidTransactionId; /* @@ -6984,7 +6993,8 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, } } - *totally_frozen_p = totally_frozen; + *totally_frozen_p = (xmin_frozen && + (freeze_xmax || xmax_already_frozen)); return changed; } --jakb5nxwemu4iuxo--