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 1gm6Ve-0003NS-VV for pgsql-hackers@arkaria.postgresql.org; Wed, 23 Jan 2019 00:35:15 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1gm6Vd-0003ds-Cb for pgsql-hackers@arkaria.postgresql.org; Wed, 23 Jan 2019 00:35:13 +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 1gm6Vd-0003da-01 for pgsql-hackers@lists.postgresql.org; Wed, 23 Jan 2019 00:35:13 +0000 Received: from mail-wr1-x42e.google.com ([2a00:1450:4864:20::42e]) by magus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1gm6VV-0007Yv-B0 for pgsql-hackers@lists.postgresql.org; Wed, 23 Jan 2019 00:35:12 +0000 Received: by mail-wr1-x42e.google.com with SMTP id x10so411728wrs.8 for ; Tue, 22 Jan 2019 16:35:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=2ndquadrant-com.20150623.gappssmtp.com; s=20150623; h=subject:to:cc:references:from:message-id:date:user-agent :mime-version:in-reply-to:content-language; bh=SydTTt59wK50T0yI7/v3qRJUcjvl14vLFIAyn9aqgsg=; b=QoEdsWVLKGS2Y2aJ0h8H8m56vogeU6HnF4pc5Rv3xuUvx6oOq9hKMH+KKSE482uKCU ofVHdbS6t2LkLO371On3qucSckFYf5wDQkdr5RFTqz4qaCThofQUziMGFO+2UJ20gCeK dtjocfElsLo/ihaSzq85BG0gpaRGjsyzSHZodJqkxKQkZzzx5XiOLK0B3uZ9eePg4sSX CU2lWfZC4g0cc87C8EHAkwe/N3Rrc0HJ8rDIxL2hrIKkOep6XxrsmR9hMRNPN1JYP3U4 DGwUH3X1LS2ISXV858pvnSGg5FqCxPmjbAXzkuJOG0gktsC+jlKhkRdVi0KAC3WJYip/ PWAQ== 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; bh=SydTTt59wK50T0yI7/v3qRJUcjvl14vLFIAyn9aqgsg=; b=ZZWl9ZHMIV0aeROK91q5m+suc0vqYolKTdJDAUVyqXqPa9HKsyqsMk9ozD/kcfRY4g t8BMA9dSl9aSP/2+XWddtiYA0fnhXiNosQJwcCc/ePcb29mcq03euJWdELyXLLCV0Fkk 4Ewhk36pKp9CHZ1PT14+a41PooVIr+ZhQXF59RO+9DY5TPA+Vf9owyiRnM+7s147tWQ9 wTTR2v1SG7Z9cjxTwoOhOs3Qbs1KbgLDZGcNRx5Vt/E6o7EddpHBUf9xwGpiNDYCHxWA fXiGfEqOHJcVhxrcafEYwlV3yvSsGwOnFl5RdvJdlvwjHnQhR5OupAe19squgsoMp0Q3 M0GA== X-Gm-Message-State: AJcUukc5Q6Vn85YzCuvQJlZR5UOTNYI+/Vi8kJq7m+0KZ9y5uQWaAGhg ddvNxyNTNcwDZsyW4iuFXRpnMAZQ8vScKvc43CgVdNoMb7qkGeIzjIp0C5kh8M0wysZxhTTgd4M 6USQ0CddW/kNj/Vaf01z8sZLc1k7HGeLSVFS4GHWMmGBb8uPAfAFuB9kfkMmt68KLeLaURuLJ/2 khR2U5oTlnxpOq/EhNBnI= X-Google-Smtp-Source: ALg8bN4X8w7NEouIspH+Ktufseq/CeNGzg0tL1QVxiVB88uFkSZJnbwsjY929GHh+SFsWI96ugEuFQ== X-Received: by 2002:adf:81c6:: with SMTP id 64mr108115wra.186.1548203703052; Tue, 22 Jan 2019 16:35:03 -0800 (PST) Received: from [10.137.2.19] (ip-86-49-251-50.net.upcbroadband.cz. [86.49.251.50]) by smtp.gmail.com with ESMTPSA id x15sm126567236wrs.27.2019.01.22.16.35.01 (version=TLS1_3 cipher=AEAD-AES128-GCM-SHA256 bits=128/128); Tue, 22 Jan 2019 16:35:02 -0800 (PST) Subject: Re: COPY FROM WHEN condition To: Surafel Temesgen Cc: Andres Freund , Alvaro Herrera , Adam Berlin , pgsql-hackers@lists.postgresql.org References: <194e2225-b186-9325-0cd1-9a5b09d28251@2ndquadrant.com> <20181204094418.wpr6mxrtsuxb5mlq@alvherre.pgsql> <3b2b1aac-5861-acd8-fda3-054c4e4da888@2ndquadrant.com> <20190121012405.633row4iw7nfxz7h@alap3.anarazel.de> <6e80b7c1-58cd-4212-41d3-7c519aed0500@2ndquadrant.com> <20190121020805.3kdscvwzwvijlees@alap3.anarazel.de> <20190121021220.7tbu3oizvydov5by@alap3.anarazel.de> <52b10375-aca3-ea9b-10a1-2e4e9a011665@2ndquadrant.com> From: Tomas Vondra Message-ID: <68edcb85-37cd-132c-b97c-2c7924affb53@2ndquadrant.com> Date: Wed, 23 Jan 2019 01:34:58 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.4.0 MIME-Version: 1.0 In-Reply-To: Content-Type: multipart/mixed; boundary="------------FCBAE275A70A53C0DCF2F0DA" 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. --------------FCBAE275A70A53C0DCF2F0DA Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit On 1/22/19 10:00 AM, Surafel Temesgen wrote: > > > On Mon, Jan 21, 2019 at 6:22 PM Tomas Vondra > > wrote: > > > I think the condition can be just > >     if (contain_volatile_functions(cstate->whereClause)) { ... } > > I've pushed a fix for the volatility check. Attached is a patch for the other issue, creating a separate batch context long the lines outlined in the previous email. It's a bit too late for me to push it now, especially right before a couple of days off. So I'll push that in a couple of days. regards -- Tomas Vondra http://www.2ndQuadrant.com PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services --------------FCBAE275A70A53C0DCF2F0DA Content-Type: text/x-patch; name="copy-context-fix.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="copy-context-fix.patch" diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 03745cca75..41dbcd5b42 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -2323,9 +2323,9 @@ CopyFrom(CopyState cstate) ExprContext *econtext; TupleTableSlot *myslot; MemoryContext oldcontext = CurrentMemoryContext; + MemoryContext batchcontext; PartitionTupleRouting *proute = NULL; - ExprContext *secondaryExprContext = NULL; ErrorContextCallback errcallback; CommandId mycid = GetCurrentCommandId(true); int hi_options = 0; /* start with default heap_insert options */ @@ -2639,20 +2639,10 @@ CopyFrom(CopyState cstate) * Normally, when performing bulk inserts we just flush the insert * buffer whenever it becomes full, but for the partitioned table * case, we flush it whenever the current tuple does not belong to the - * same partition as the previous tuple, and since we flush the - * previous partition's buffer once the new tuple has already been - * built, we're unable to reset the estate since we'd free the memory - * in which the new tuple is stored. To work around this we maintain - * a secondary expression context and alternate between these when the - * partition changes. This does mean we do store the first new tuple - * in a different context than subsequent tuples, but that does not - * matter, providing we don't free anything while it's still needed. + * same partition as the previous tuple. */ if (proute) - { insertMethod = CIM_MULTI_CONDITIONAL; - secondaryExprContext = CreateExprContext(estate); - } else insertMethod = CIM_MULTI; @@ -2685,6 +2675,14 @@ CopyFrom(CopyState cstate) errcallback.previous = error_context_stack; error_context_stack = &errcallback; + /* + * Set up memory context for batches. For cases without batching we could + * use the per-tuple context, but it does not seem worth the complexity. + */ + batchcontext = AllocSetContextCreate(CurrentMemoryContext, + "batch context", + ALLOCSET_DEFAULT_SIZES); + for (;;) { TupleTableSlot *slot; @@ -2692,18 +2690,14 @@ CopyFrom(CopyState cstate) CHECK_FOR_INTERRUPTS(); - if (nBufferedTuples == 0) - { - /* - * Reset the per-tuple exprcontext. We can only do this if the - * tuple buffer is empty. (Calling the context the per-tuple - * memory context is a bit of a misnomer now.) - */ - ResetPerTupleExprContext(estate); - } + /* + * Reset the per-tuple exprcontext. We do this after every tuple, to + * clean-up after expression evaluations etc. + */ + ResetPerTupleExprContext(estate); - /* Switch into its memory context */ - MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); + /* Switch into per-batch memory context. */ + MemoryContextSwitchTo(batchcontext); if (!NextCopyFrom(cstate, econtext, values, nulls)) break; @@ -2756,7 +2750,7 @@ CopyFrom(CopyState cstate) */ if (nBufferedTuples > 0) { - ExprContext *swapcontext; + MemoryContext oldcontext; CopyFromInsertBatch(cstate, estate, mycid, hi_options, prevResultRelInfo, myslot, bistate, @@ -2765,29 +2759,26 @@ CopyFrom(CopyState cstate) nBufferedTuples = 0; bufferedTuplesSize = 0; - Assert(secondaryExprContext); - /* - * Normally we reset the per-tuple context whenever - * the bufferedTuples array is empty at the beginning - * of the loop, however, it is possible since we flush - * the buffer here that the buffer is never empty at - * the start of the loop. To prevent the per-tuple - * context from never being reset we maintain a second - * context and alternate between them when the - * partition changes. We can now reset - * secondaryExprContext as this is no longer needed, - * since we just flushed any tuples stored in it. We - * also now switch over to the other context. This - * does mean that the first tuple in the buffer won't - * be in the same context as the others, but that does - * not matter since we only reset it after the flush. + * The tuple is allocated in the batch context, which we + * want to reset. So to keep the tuple we copy the tuple + * into the short-lived (per-tuple) context, reset the + * batch context and then copy it back into it. */ - ReScanExprContext(secondaryExprContext); + oldcontext = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); + tuple = heap_copytuple(tuple); + MemoryContextSwitchTo(oldcontext); - swapcontext = secondaryExprContext; - secondaryExprContext = estate->es_per_tuple_exprcontext; - estate->es_per_tuple_exprcontext = swapcontext; + /* cleanup the old batch */ + MemoryContextReset(batchcontext); + + /* copy the tuple back to the per-tuple context */ + oldcontext = MemoryContextSwitchTo(batchcontext); + tuple = heap_copytuple(tuple); + MemoryContextSwitchTo(oldcontext); + + /* push the tuple copy to the slot */ + ExecStoreHeapTuple(tuple, slot, false); } nPartitionChanges++; @@ -2893,10 +2884,10 @@ CopyFrom(CopyState cstate) slot = execute_attr_map_slot(map->attrMap, slot, new_slot); /* - * Get the tuple in the per-tuple context, so that it will be + * Get the tuple in the per-batch context, so that it will be * freed after each batch insert. */ - oldcontext = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); + oldcontext = MemoryContextSwitchTo(batchcontext); tuple = ExecCopySlotHeapTuple(slot); MemoryContextSwitchTo(oldcontext); } @@ -2972,6 +2963,9 @@ CopyFrom(CopyState cstate) firstBufferedLineNo); nBufferedTuples = 0; bufferedTuplesSize = 0; + + /* free memory occupied by tuples from the batch */ + MemoryContextReset(batchcontext); } } else @@ -3053,6 +3047,8 @@ CopyFrom(CopyState cstate) MemoryContextSwitchTo(oldcontext); + MemoryContextDelete(batchcontext); + /* * In the old protocol, tell pqcomm that we can process normal protocol * messages again. --------------FCBAE275A70A53C0DCF2F0DA--