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 1qHnHX-0005xi-Gu for pgsql-hackers@arkaria.postgresql.org; Fri, 07 Jul 2023 15:22:04 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1qHnHW-0006DW-FM for pgsql-hackers@arkaria.postgresql.org; Fri, 07 Jul 2023 15:22:02 +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 1qHnHW-0006DE-1g for pgsql-hackers@lists.postgresql.org; Fri, 07 Jul 2023 15:22:02 +0000 Received: from meesny.iki.fi ([2001:67c:2b0:1c1::201]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1qHnHO-002YXJ-8X for pgsql-hackers@postgresql.org; Fri, 07 Jul 2023 15:22:00 +0000 Received: from [192.168.1.115] (dsl-hkibng22-54f8db-125.dhcp.inet.fi [84.248.219.125]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: hlinnaka) by meesny.iki.fi (Postfix) with ESMTPSA id 4QyHDm45bpzydW; Fri, 7 Jul 2023 18:21:44 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1688743306; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=9LcmfX9SJA/OHXzdJDskw4arWd9v0oenaUaWd0AhRf4=; b=M+XyF1j/wVgs5fjuWSLZ08PBMajmqm4soC0XLv9bMKzMQFLSAFeiLzgPbEV+me6pn2o2Qj dhWNWjK+uauU3Ey9+2QtR8Nvg2eDozEasjJjB9Ek0S0EhmCWNK1qDvdOHsDWOqzuorORYT 8Ef1wZ86xp3IGmDJEOZecF5T9T3P8+c= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1688743306; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=9LcmfX9SJA/OHXzdJDskw4arWd9v0oenaUaWd0AhRf4=; b=bHYR0GPovRPyIzs05Ua4g62KPp7EyTDBEs3j0QvmeXQCVnKnFldLF11d1aunwkXPv4TedW rvsoJrlboY74CcSNRBlPaAwRZLclBkanI3WjtpPkVgPvRMdWLB3VnQ4PEk5KHB4FnYEuQ7 M5TkJ204vNn2J1eoLwjD+ukFt216TsQ= ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=hlinnaka smtp.mailfrom=hlinnaka@iki.fi ARC-Seal: i=1; s=meesny; d=iki.fi; t=1688743306; a=rsa-sha256; cv=none; b=Q41IkG+E7tbL0v82RTfZ59LfyDvZx6eUaw2JBTX4jvc3QUtBgITwbKIVsysj3mCu5+Jsj2 TSLhlVrqj8J2hA31JFbtM7NqklVY6eZFMKwCL22H/rzw1e71kSGjerNNQYuwNROQ+1dpq8 CpCbG6vznB1RN1UoYLHtjDdnI4XXI4Q= Message-ID: <868b64cf-0d0f-7d49-d985-a0574a8678e1@iki.fi> Date: Fri, 7 Jul 2023 18:21:44 +0300 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.12.0 Subject: Re: Unlogged relations and WAL-logging Content-Language: en-US To: Robert Haas Cc: pgsql-hackers References: <6e5bbc08-cdfc-b2b3-9e23-1a914b9850a9@iki.fi> From: Heikki Linnakangas In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On 28/01/2022 15:57, Robert Haas wrote: > On Thu, Jan 27, 2022 at 2:32 PM Heikki Linnakangas wrote: >> Unlogged relations are not WAL-logged, but creating the init-fork is. >> There are a few things around that seem sloppy: >> >> 1. In index_build(), we do this: >> >>> */ >>> if (indexRelation->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED && >>> !smgrexists(RelationGetSmgr(indexRelation), INIT_FORKNUM)) >>> { >>> smgrcreate(RelationGetSmgr(indexRelation), INIT_FORKNUM, false); >>> indexRelation->rd_indam->ambuildempty(indexRelation); >>> } >> >> Shouldn't we call log_smgrcreate() here? Creating the init fork is >> otherwise not WAL-logged at all. > > Yes, that's a bug. Pushed and backpatched this patch (commit 3142a8845b). >> 2. Some implementations of ambuildempty() use the buffer cache (hash, >> gist, gin, brin), while others bypass it and call smgrimmedsync() >> instead (btree, spgist, bloom). I don't see any particular reason for >> those decisions, it seems to be based purely on which example the author >> happened to copy-paste. > > I thought that this inconsistency was odd when I was developing the > unlogged feature, but I tried to keep each routine's ambuildempty() > consistent with whatever ambuild() was doing. I don't mind if you want > to change it, though. > >> 3. Those ambuildempty implementations that bypass the buffer cache use >> smgrwrite() to write the pages. That doesn't make any difference in >> practice, but in principle it's wrong: You are supposed to use >> smgrextend() when extending a relation. > > That's a mistake on my part. > >> 4. Also, the smgrwrite() calls are performed before WAL-logging the >> pages, so the page that's written to disk has 0/0 as the LSN, not the >> LSN of the WAL record. That's harmless too, but seems a bit sloppy. > > That is also a mistake on my part. I'm still sitting on these fixes. I think the patch I posted still makes sense, but I got carried away with a more invasive approach that introduces a whole new set of functions for bulk-creating a relation, which would handle WAL-logging, smgrimmedsync() and all that (see below). We have some repetitive, error-prone code in all the index build functions for that. But that's not backpatchable, so I'll rebase the original approach next week. >> 5. In heapam_relation_set_new_filenode(), we do this: >> >>> >>> /* >>> * If required, set up an init fork for an unlogged table so that it can >>> * be correctly reinitialized on restart. An immediate sync is required >>> * even if the page has been logged, because the write did not go through >>> * shared_buffers and therefore a concurrent checkpoint may have moved the >>> * redo pointer past our xlog record. Recovery may as well remove it >>> * while replaying, for example, XLOG_DBASE_CREATE or XLOG_TBLSPC_CREATE >>> * record. Therefore, logging is necessary even if wal_level=minimal. >>> */ >>> if (persistence == RELPERSISTENCE_UNLOGGED) >>> { >>> Assert(rel->rd_rel->relkind == RELKIND_RELATION || >>> rel->rd_rel->relkind == RELKIND_MATVIEW || >>> rel->rd_rel->relkind == RELKIND_TOASTVALUE); >>> smgrcreate(srel, INIT_FORKNUM, false); >>> log_smgrcreate(newrnode, INIT_FORKNUM); >>> smgrimmedsync(srel, INIT_FORKNUM); >>> } >> >> The comment doesn't make much sense, we haven't written nor WAL-logged >> any page here, with nor without the buffer cache. It made more sense >> before commit fa0f466d53. > > Well, it seems to me (and perhaps I am just confused) that complaining > that there's no page written here might be a technicality. The point > is that there's no synchronization between the work we're doing here > -- which is creating a fork, not writing a page -- and any concurrent > checkpoint. So we both need to log it, and also sync it immediately. I see. I pushed the fix from the other thread that makes smgrcreate() call register_dirty_segment (commit 4b4798e13). I believe that makes this smgrimmedsync() unnecessary. If a concurrent checkpoint happens with a redo pointer greater than this WAL record, it must've received the fsync request created by smgrcreate(). That depends on the fact that we write the WAL record *after* smgrcreate(). Subtle.. Hmm, we have a similar smgrimmedsync() call after index build, because we have written pages directly with smgrextend(skipFsync=true). If no checkpoints have occurred during the index build, we could call register_dirty_segment() instead of smgrimmedsync(). That would avoid the fsync() latency when creating an index on an empty or small index. This is all very subtle to get right though. That's why I'd like to invent a new bulk-creation facility that would handle this stuff, and make the callers less error-prone. -- Heikki Linnakangas Neon (https://neon.tech)