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 1q5Ztu-0004Se-9k for pgsql-hackers@arkaria.postgresql.org; Sat, 03 Jun 2023 22:39:10 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1q5Ztr-0001G4-73 for pgsql-hackers@arkaria.postgresql.org; Sat, 03 Jun 2023 22:39:07 +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 1q5Ztq-0001Fv-3Q for pgsql-hackers@lists.postgresql.org; Sat, 03 Jun 2023 22:39:06 +0000 Received: from out3-smtp.messagingengine.com ([66.111.4.27]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1q5Ztj-0002nM-8G for pgsql-hackers@postgresql.org; Sat, 03 Jun 2023 22:39:04 +0000 Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailout.nyi.internal (Postfix) with ESMTP id 877CD5C0120; Sat, 3 Jun 2023 18:38:58 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute4.internal (MEProxy); Sat, 03 Jun 2023 18:38:58 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=anarazel.de; h= cc:cc:content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:reply-to:sender:subject :subject:to:to; s=fm1; t=1685831938; x=1685918338; bh=a/HYRl+Yny wx2B9e30jzys3iqvGEu34SFV/Chq/JMK0=; b=fPet5pkjOfUEuvwV/UU/Qn0WjI So5UQePz23ZythM05k01brWRXHg/DXIerrHcJB+iol4HaVyFkdiOqM9VMkRXyizn AG0bwno5mBnWZrPfHh+ZEkbRnOzYhswwZnSnVnY9BwEMAq240B8CMC8iLnSqAtzC tcUL2zkZMA/lYkcslputEXKiVhdEasDsGrLggxchX9PyvSQUyhPjbANVttVzkpiQ aeX5ez1xntX79JJH8E8Ywu+dYBzyr+o1LalkmDi211/GLhAVrvPGau9RO3GVIAcw EiqNHzcgsOpTvRnsyNOBQYVb/GuOWcQPoW1aXZQo/DZK/FR2xcCbMBVwj0Vw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:reply-to:sender:subject:subject:to:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; t=1685831938; x=1685918338; bh=a/HYRl+Ynywx2B9e30jzys3iqvGE u34SFV/Chq/JMK0=; b=OjSCk3Kx5oOaylF1ZS0UPwVEbYer0b2sBb178CspFP1H BrIuhxGgS/ki1gw16rsKDLp4xTB0r7K43Z7dPEMakxO7UH+6G3PH7jqKtinymwB4 G3vZZQuoo2569PUmhKxw0vLAr+pB5AV7filIxMcswTDZCewXBxdGWBzY+WCnlmi4 OrIBNPbCRTqsX24IbmcI+7Yy1AFVwo1oY4m2MJTwC+OgGu9LlROTJk/TyX7r/+UN yl3+HitV4FCasQXMqwsrT4z92rokZ4cf9cKpvqhrSFH67pU0mfv+gnqhWwTPDNme al0JZfWFlDk3Ksfh60qupNpw58kSSm/N8BzfkLVUdQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfeeliedgudegucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkgggtuggjsehttdertddttddvnecuhfhrohhmpeetnhgurhgv shcuhfhrvghunhguuceorghnughrvghssegrnhgrrhgriigvlhdruggvqeenucggtffrrg htthgvrhhnpeetfffgudefgefgfeeltddvfedvvefghfdtledtgffhhefgvedthfefgffh keegleenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpe grnhgurhgvshesrghnrghrrgiivghlrdguvg X-ME-Proxy: Feedback-ID: id4a34324:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sat, 3 Jun 2023 18:38:57 -0400 (EDT) Date: Sat, 3 Jun 2023 15:38:24 -0700 From: Andres Freund To: Bharath Rupireddy Cc: Dilip Kumar , Luc Vlaming , Justin Pryzby , PostgreSQL-development , Paul Guo , Jeff Davis , Michael Paquier , Matthias van de Meent Subject: Re: New Table Access Methods for Multi and Single Inserts Message-ID: <20230603223824.o7iyochli2dwwi7k@alap3.anarazel.de> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk Hi, This patch was referenced in a discussion at pgcon, so I thought I'd give it a look, even though Bharat said that he won't have time to drive it forward... On 2021-04-19 10:21:36 +0530, Bharath Rupireddy wrote: > diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c > index bd5faf0c1f..655de8e6b7 100644 > --- a/src/backend/access/heap/heapam_handler.c > +++ b/src/backend/access/heap/heapam_handler.c > @@ -2558,6 +2558,11 @@ static const TableAmRoutine heapam_methods = { > .tuple_insert_speculative = heapam_tuple_insert_speculative, > .tuple_complete_speculative = heapam_tuple_complete_speculative, > .multi_insert = heap_multi_insert, > + .tuple_insert_begin = heap_insert_begin, > + .tuple_insert_v2 = heap_insert_v2, > + .multi_insert_v2 = heap_multi_insert_v2, > + .multi_insert_flush = heap_multi_insert_flush, > + .tuple_insert_end = heap_insert_end, > .tuple_delete = heapam_tuple_delete, > .tuple_update = heapam_tuple_update, > .tuple_lock = heapam_tuple_lock, I don't think we should have multiple callback for the insertion APIs in tableam.h. I think it'd be good to continue supporting the old table_*() functions, but supporting multiple insert APIs in each AM doesn't make much sense to me. > +/* > + * GetTupleSize - Compute the tuple size given a table slot. > + * > + * For heap tuple, buffer tuple and minimal tuple slot types return the actual > + * tuple size that exists. For virtual tuple, the size is calculated as the > + * slot does not have the tuple size. If the computed size exceeds the given > + * maxsize for the virtual tuple, this function exits, not investing time in > + * further unnecessary calculation. > + * > + * Important Notes: > + * 1) Size calculation code for virtual slots is being used from > + * tts_virtual_materialize(), hence ensure to have the same changes or fixes > + * here and also there. > + * 2) Currently, GetTupleSize() handles the existing heap, buffer, minimal and > + * virtual slots. Ensure to add related code in case any new slot type is > + * introduced. > + */ > +inline Size > +GetTupleSize(TupleTableSlot *slot, Size maxsize) > +{ > + Size sz = 0; > + HeapTuple tuple = NULL; > + > + if (TTS_IS_HEAPTUPLE(slot)) > + tuple = ((HeapTupleTableSlot *) slot)->tuple; > + else if(TTS_IS_BUFFERTUPLE(slot)) > + tuple = ((BufferHeapTupleTableSlot *) slot)->base.tuple; > + else if(TTS_IS_MINIMALTUPLE(slot)) > + tuple = ((MinimalTupleTableSlot *) slot)->tuple; > + else if(TTS_IS_VIRTUAL(slot)) I think this embeds too much knowledge of the set of slot types in core code. I don't see why it's needed either? > diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h > index 414b6b4d57..2a1470a7b6 100644 > --- a/src/include/access/tableam.h > +++ b/src/include/access/tableam.h > @@ -229,6 +229,32 @@ typedef struct TM_IndexDeleteOp > TM_IndexStatus *status; > } TM_IndexDeleteOp; > > +/* Holds table insert state. */ > +typedef struct TableInsertState I suspect we should design it to be usable for updates and deletes in the future, and thus name it TableModifyState. > +{ > + Relation rel; > + /* Bulk insert state if requested, otherwise NULL. */ > + struct BulkInsertStateData *bistate; > + CommandId cid; Hm - I'm not sure it's a good idea to force the cid to be the same for all inserts done via one TableInsertState. > + int options; > + /* Below members are only used for multi inserts. */ > + /* Array of buffered slots. */ > + TupleTableSlot **mi_slots; > + /* Number of slots that are currently buffered. */ > + int32 mi_cur_slots; > + /* > + * Access method specific information such as parameters that are needed > + * for buffering and flushing decisions can go here. > + */ > + void *mistate; I think we should instead have a generic TableModifyState, which each AM then embeds into an AM specific AM state. Forcing two very related structs to be allocated separately doesn't seem wise in this case. > @@ -1430,6 +1473,50 @@ table_multi_insert(Relation rel, TupleTableSlot **slots, int nslots, > cid, options, bistate); > } > > +static inline TableInsertState* > +table_insert_begin(Relation rel, CommandId cid, int options, > + bool alloc_bistate, bool is_multi) Why have alloc_bistate and options? > +static inline void > +table_insert_end(TableInsertState *state) > +{ > + /* Deallocate bulk insert state here, since it's AM independent. */ > + if (state->bistate) > + FreeBulkInsertState(state->bistate); > + > + state->rel->rd_tableam->tuple_insert_end(state); > +} Seems like the order in here should be swapped? Greetings, Andres Freund