On Wed, Dec 15, 2021 at 6:33 AM Peter Geoghegan <p...@bowt.ie> wrote:
>

> How did you test this? I ask because it would be nice if there was a
> convenient way to try this out, as somebody with a general interest.
> Even just a minimal test module, that you used for development work.
>

I have tested this using a simple extension over the conveyor belt
APIs, this extension provides wrapper apis over the conveyor belt
APIs.  These are basic APIs which can be extended even further for
more detailed testing, e.g. as of now I have provided an api to read
complete page from the conveyor belt but that can be easily extended
to read from a particular offset and also the amount of data to read.

Parallelly I am also testing this by integrating it with the vacuum,
which is still a completely WIP patch and needs a lot of design level
improvement so not sharing it, so once it is in better shape I will
post that in the separate thread.

Basically, we have decoupled different vacuum phases (only for manual
vacuum ) something like below,
VACUUM (first_pass) t;
VACUUM idx;
VACUUM (second_pass) t;

So in the first pass we are just doing the first pass of vacuum and
wherever we are calling lazy_vacuum() we are storing those dead tids
in the conveyor belt.  In the index pass, user can vacuum independent
index and therein it will just fetch the last conveyor belt point upto
which it has already vacuum, then from there load dead tids which can
fit in maintenance_work_mem and then call the index bulk delete (this
will be done in loop until we complete the index vacuum).  In the
second pass, we check all the indexes and find the minimum conveyor
belt point upto which all indexes have vacuumed.  We also fetch the
last point where we left the second pass of the heap.  Now we fetch
the dead tids from the conveyor belt (which fits in
maintenance_work_mem) from the last vacuum point of heap upto the min
index vacuum point.  And perform the second heap pass.

I have given the highlights of the decoupling work just to show what
sort of testing we are doing for the conveyor belt.  But we can
discuss this on a separate thread when I am ready to post that patch.

-- 
Regards,
Dilip Kumar
EnterpriseDB: http://www.enterprisedb.com
From b6affd2a778b7b4cff5738ad99f34ea21a816562 Mon Sep 17 00:00:00 2001
From: Dilip Kumar <dilipkumar@localhost.localdomain>
Date: Wed, 15 Dec 2021 10:28:49 +0530
Subject: [PATCH v1] Conveyor belt testing extention

This extention provide wrapper over the conveyor belt infrastructure
for testing the conveyor belt.
---
 contrib/pg_conveyor/Makefile                 |  23 +++
 contrib/pg_conveyor/expected/pg_conveyor.out | 185 ++++++++++++++++++++++++
 contrib/pg_conveyor/pg_conveyor--1.0.sql     |  32 +++++
 contrib/pg_conveyor/pg_conveyor.c            | 207 +++++++++++++++++++++++++++
 contrib/pg_conveyor/pg_conveyor.control      |   5 +
 contrib/pg_conveyor/sql/pg_conveyor.sql      | 125 ++++++++++++++++
 src/common/relpath.c                         |   3 +-
 src/include/common/relpath.h                 |   5 +-
 8 files changed, 582 insertions(+), 3 deletions(-)
 create mode 100644 contrib/pg_conveyor/Makefile
 create mode 100644 contrib/pg_conveyor/expected/pg_conveyor.out
 create mode 100644 contrib/pg_conveyor/pg_conveyor--1.0.sql
 create mode 100644 contrib/pg_conveyor/pg_conveyor.c
 create mode 100644 contrib/pg_conveyor/pg_conveyor.control
 create mode 100644 contrib/pg_conveyor/sql/pg_conveyor.sql

diff --git a/contrib/pg_conveyor/Makefile b/contrib/pg_conveyor/Makefile
new file mode 100644
index 0000000..8c29ffd
--- /dev/null
+++ b/contrib/pg_conveyor/Makefile
@@ -0,0 +1,23 @@
+# contrib/pg_conveyor/Makefile
+
+MODULE_big = pg_conveyor
+OBJS = \
+	$(WIN32RES) \
+	pg_conveyor.o
+
+EXTENSION = pg_conveyor
+DATA = pg_conveyor--1.0.sql
+PGFILEDESC = "pg_conveyor - conveyor belt test"
+
+REGRESS = pg_conveyor
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = contrib/pg_conveyor
+top_builddir = ../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/contrib/pg_conveyor/expected/pg_conveyor.out b/contrib/pg_conveyor/expected/pg_conveyor.out
new file mode 100644
index 0000000..6ae5cd3
--- /dev/null
+++ b/contrib/pg_conveyor/expected/pg_conveyor.out
@@ -0,0 +1,185 @@
+CREATE EXTENSION pg_conveyor;
+CREATE TABLE test(a int);
+SELECT pg_conveyor_init('test'::regclass::oid, 4);
+ pg_conveyor_init 
+------------------
+ 
+(1 row)
+
+SELECT pg_conveyor_insert('test'::regclass::oid, 'test_data');
+ pg_conveyor_insert 
+--------------------
+ 
+(1 row)
+
+SELECT pg_conveyor_read('test'::regclass::oid, 0);
+ pg_conveyor_read 
+------------------
+ test_data
+(1 row)
+
+--CASE1
+do $$
+<<first_block>>
+declare
+  i int := 0;
+  data varchar;
+begin
+  for i in 1..1000 loop
+	data := 'test_dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' || i;
+	PERFORM pg_conveyor_insert('test'::regclass::oid, data);
+  end loop;
+end first_block $$;
+-- read from some random blocks
+SELECT pg_conveyor_read('test'::regclass::oid, 100);
+               pg_conveyor_read                
+-----------------------------------------------
+ test_dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa100
+(1 row)
+
+SELECT pg_conveyor_read('test'::regclass::oid, 800);
+               pg_conveyor_read                
+-----------------------------------------------
+ test_dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa800
+(1 row)
+
+--CASE2
+do $$
+<<first_block>>
+declare
+  i int := 0;
+  data varchar;
+begin
+  for i in 1..5000 loop
+	data := 'test_dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' || i+1000;
+	PERFORM pg_conveyor_insert('test'::regclass::oid, data);
+  end loop;
+end first_block $$;
+SELECT pg_conveyor_read('test'::regclass::oid, 4000);
+                pg_conveyor_read                
+------------------------------------------------
+ test_dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4000
+(1 row)
+
+SELECT pg_conveyor_read('test'::regclass::oid, 3000);
+                pg_conveyor_read                
+------------------------------------------------
+ test_dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3000
+(1 row)
+
+--CASE3
+DROP TABLE test;
+CREATE TABLE test(a int);
+SELECT pg_conveyor_init('test'::regclass::oid, 4);
+ pg_conveyor_init 
+------------------
+ 
+(1 row)
+
+do $$
+<<first_block>>
+declare
+  i int := 0;
+  data varchar;
+begin
+  for i in 1..50000 loop
+	data := 'test_dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' || i;
+	PERFORM pg_conveyor_insert('test'::regclass::oid, data);
+  end loop;
+end first_block $$;
+--CASE4--(vacuum is failing)
+DROP TABLE test;
+CREATE TABLE test(a int);
+SELECT pg_conveyor_init('test'::regclass::oid, 4);
+ pg_conveyor_init 
+------------------
+ 
+(1 row)
+
+do $$
+<<first_block>>
+declare
+  i int := 0;
+  data varchar;
+begin
+  for i in 1..5000 loop
+	data := 'test_dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' || i;
+	PERFORM pg_conveyor_insert('test'::regclass::oid, data);
+  end loop;
+end first_block $$;
+SELECT pg_conveyor_truncate('test'::regclass::oid, 3000);
+ pg_conveyor_truncate 
+----------------------
+ 
+(1 row)
+
+--SELECT pg_conveyor_vacuum('test'::regclass::oid); //not implemented
+--CASE5
+DROP TABLE test;
+CREATE TABLE test(a int);
+SELECT pg_conveyor_init('test'::regclass::oid, 4);
+ pg_conveyor_init 
+------------------
+ 
+(1 row)
+
+do $$
+<<first_block>>
+declare
+  i int := 0;
+  data varchar;
+begin
+  for i in 1..50000 loop
+	data := 'test_dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' || i;
+	PERFORM pg_conveyor_insert('test'::regclass::oid, data);
+  end loop;
+end first_block $$;
+--CASE6 (multi truncate single vacuum)
+DROP TABLE test;
+CREATE TABLE test(a int);
+SELECT pg_conveyor_init('test'::regclass::oid, 4);
+ pg_conveyor_init 
+------------------
+ 
+(1 row)
+
+do $$
+<<first_block>>
+declare
+  i int := 0;
+  data varchar;
+begin
+  for i in 1..1000 loop
+	data := 'test_dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' || i;
+	PERFORM pg_conveyor_insert('test'::regclass::oid, data);
+  end loop;
+end first_block $$;
+SELECT pg_conveyor_truncate('test'::regclass::oid, 500);
+ pg_conveyor_truncate 
+----------------------
+ 
+(1 row)
+
+do $$
+<<first_block>>
+declare
+  i int := 0;
+  data varchar;
+begin
+  for i in 1..1000 loop
+	data := 'test_dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' || i;
+	PERFORM pg_conveyor_insert('test'::regclass::oid, data);
+  end loop;
+end first_block $$;
+SELECT pg_conveyor_truncate('test'::regclass::oid, 1800);
+ pg_conveyor_truncate 
+----------------------
+ 
+(1 row)
+
+SELECT pg_conveyor_vacuum('test'::regclass::oid);
+ pg_conveyor_vacuum 
+--------------------
+ 
+(1 row)
+
diff --git a/contrib/pg_conveyor/pg_conveyor--1.0.sql b/contrib/pg_conveyor/pg_conveyor--1.0.sql
new file mode 100644
index 0000000..301bb88
--- /dev/null
+++ b/contrib/pg_conveyor/pg_conveyor--1.0.sql
@@ -0,0 +1,32 @@
+/* contrib/pg_conveyor/pg_conveyor--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION pg_conveyor" to load this file. \quit
+
+-- Initialize the conveyor belt for the relation.
+CREATE FUNCTION pg_conveyor_init(relid OID, blocks_per_seg int)
+RETURNS void
+AS 'MODULE_PATHNAME', 'pg_conveyor_init'
+LANGUAGE C STRICT;
+
+/* Insert given data in the relation's conveyor belt. */
+CREATE FUNCTION pg_conveyor_insert(relid OID, data TEXT)
+RETURNS void
+AS 'MODULE_PATHNAME', 'pg_conveyor_insert'
+LANGUAGE C STRICT;
+
+/* Read relation's conveyor belt data. */
+CREATE FUNCTION pg_conveyor_read(relid OID, blockno bigint)
+RETURNS TEXT
+AS 'MODULE_PATHNAME', 'pg_conveyor_read'
+LANGUAGE C STRICT;
+
+CREATE FUNCTION pg_conveyor_truncate(relid OID, blockno bigint)
+RETURNS void
+AS 'MODULE_PATHNAME', 'pg_conveyor_truncate'
+LANGUAGE C STRICT;
+
+CREATE FUNCTION pg_conveyor_vacuum(relid OID)
+RETURNS void
+AS 'MODULE_PATHNAME', 'pg_conveyor_vacuum'
+LANGUAGE C STRICT;
diff --git a/contrib/pg_conveyor/pg_conveyor.c b/contrib/pg_conveyor/pg_conveyor.c
new file mode 100644
index 0000000..c9e56c4
--- /dev/null
+++ b/contrib/pg_conveyor/pg_conveyor.c
@@ -0,0 +1,207 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_conveyor.c
+ *
+ * provide APIs over the conveyor belt infrastructure to create, insert and
+ * fetch the data from the conveyor belt.
+ *
+ * Copyright (c) 2016-2021, PostgreSQL Global Development Group
+ *
+ * contrib/pg_conveyor/pg_conveyor.c
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/conveyor.h"
+#include "access/relation.h"
+#include "fmgr.h"
+#include "miscadmin.h"
+#include "storage/bufpage.h"
+#include "storage/smgr.h"
+#include "utils/builtins.h"
+#include "utils/rel.h"
+
+PG_MODULE_MAGIC;
+
+PG_FUNCTION_INFO_V1(pg_conveyor_init);
+PG_FUNCTION_INFO_V1(pg_conveyor_insert);
+PG_FUNCTION_INFO_V1(pg_conveyor_read);
+PG_FUNCTION_INFO_V1(pg_conveyor_truncate);
+PG_FUNCTION_INFO_V1(pg_conveyor_vacuum);
+
+static ConveyorBelt*
+OpenConveyorBeltForRel(Relation rel)
+{
+	SMgrRelation	reln;
+
+	/* Open the relation at smgr level. */
+	reln = RelationGetSmgr(rel);
+
+	if (!smgrexists(reln, DEADTID_FORKNUM))
+		elog(ERROR, "conveyor belt not initialized for relid %u", RelationGetRelid(rel));
+
+	/* Open the conveyor belt. */
+	return ConveyorBeltOpen(rel, DEADTID_FORKNUM, CurrentMemoryContext);
+}
+
+/*
+ * Initialize a new conveyor belt for input relid.
+ */
+Datum
+pg_conveyor_init(PG_FUNCTION_ARGS)
+{
+	Oid	relid = PG_GETARG_OID(0);
+	int	block_per_seg = PG_GETARG_INT32(1);
+	SMgrRelation	reln;
+	Relation		rel;
+
+	rel = relation_open(relid, AccessShareLock);
+
+	/* Open the relation at smgr level. */
+	reln = RelationGetSmgr(rel);
+
+	/*
+	 * If the dead_tid fork doesn't exist then create it and initialize the
+	 * conveyor belt, otherwise just open the conveyor belt.
+	 */
+	if (!smgrexists(reln, DEADTID_FORKNUM))
+	{
+		smgrcreate(reln, DEADTID_FORKNUM, false);
+		ConveyorBeltInitialize(rel, DEADTID_FORKNUM, block_per_seg,
+							   CurrentMemoryContext);
+	}
+
+	relation_close(rel, AccessShareLock);
+
+	/* Nothing to return. */
+	PG_RETURN_VOID();
+}
+
+/*
+ * Insert input buffer data into the conveyor belt.
+ */
+Datum
+pg_conveyor_insert(PG_FUNCTION_ARGS)
+{
+	Oid	relid = PG_GETARG_OID(0);
+	char   *data = text_to_cstring(PG_GETARG_TEXT_PP(1));
+	Relation	rel;
+	ConveyorBelt   *cb;
+	CBPageNo		pageno;
+	Buffer			buffer;
+	PageHeader		phdr;
+	Page			page;
+	char		   *pagedata;
+	int				len = strlen(data);
+
+	rel = relation_open(relid, AccessExclusiveLock);
+
+	cb = OpenConveyorBeltForRel(rel);
+
+	buffer = ConveyorBeltGetNewPage(cb, &pageno);
+	page = BufferGetPage(buffer);
+	pagedata = PageGetContents(page);
+	PageInit(page, BLCKSZ, 0);
+
+	if (len > (BLCKSZ) - MAXALIGN(SizeOfPageHeaderData))
+		elog(ERROR, "data too large");
+
+	phdr = (PageHeader) page;
+
+	START_CRIT_SECTION();
+	memcpy(pagedata, data, strlen(data));
+	phdr->pd_lower += strlen(data);
+	ConveyorBeltPerformInsert(cb, buffer);
+	END_CRIT_SECTION();
+
+	ConveyorBeltCleanupInsert(cb, buffer);
+
+	relation_close(rel, AccessExclusiveLock);
+
+	/* Nothing to return. */
+	PG_RETURN_VOID();
+}
+
+/*
+ * Read data from the conveyor belt's logical page .
+ */
+Datum
+pg_conveyor_read(PG_FUNCTION_ARGS)
+{
+	Oid		relid = PG_GETARG_OID(0);
+	CBPageNo		pageno = PG_GETARG_INT64(1);
+	CBPageNo		oldest_page;
+	CBPageNo		next_page;
+	Relation		rel;
+	ConveyorBelt   *cb;
+	Buffer			buffer;
+	char			pagedata[BLCKSZ];
+
+	rel = relation_open(relid, AccessShareLock);
+
+	cb = OpenConveyorBeltForRel(rel);
+
+	ConveyorBeltGetBounds(cb, &oldest_page, &next_page);
+	if (pageno < oldest_page || pageno >= next_page)
+		elog(ERROR, "conveyor belt pageno is out of bound");
+
+	buffer = ConveyorBeltReadBuffer(cb, pageno, BUFFER_LOCK_SHARE, NULL);
+	if (BufferIsInvalid(buffer))
+		elog(ERROR, "could not read data");
+
+	memcpy(pagedata, BufferGetPage(buffer), BLCKSZ);
+	UnlockReleaseBuffer(buffer);
+
+	relation_close(rel, AccessShareLock);
+
+	PG_RETURN_DATUM(CStringGetTextDatum((char *) PageGetContents((char *) pagedata)));
+}
+
+/*
+ * Truncate the conveyor belt wrapper.
+ */
+Datum
+pg_conveyor_truncate(PG_FUNCTION_ARGS)
+{
+	Oid		relid = PG_GETARG_OID(0);
+	CBPageNo		pageno = PG_GETARG_INT64(1);
+	CBPageNo		oldest_page;
+	CBPageNo		next_page;
+	Relation		rel;
+	ConveyorBelt   *cb;
+
+	rel = relation_open(relid, AccessExclusiveLock);
+
+	cb = OpenConveyorBeltForRel(rel);
+
+	ConveyorBeltGetBounds(cb, &oldest_page, &next_page);
+	if (pageno < oldest_page || pageno >= next_page)
+		elog(ERROR, "conveyor belt pageno is out of bound");
+
+	ConveyorBeltLogicalTruncate(cb, pageno);
+	relation_close(rel, AccessExclusiveLock);
+
+	/* Nothing to return. */
+	PG_RETURN_VOID();
+}
+
+/*
+ * Vacuum conveyor belt wrapper.
+ */
+Datum
+pg_conveyor_vacuum(PG_FUNCTION_ARGS)
+{
+	Oid		relid = PG_GETARG_OID(0);
+	Relation		rel;
+	ConveyorBelt   *cb;
+
+	rel = relation_open(relid, AccessExclusiveLock);
+
+	cb = OpenConveyorBeltForRel(rel);
+
+	ConveyorBeltVacuum(cb);
+	relation_close(rel, AccessExclusiveLock);
+
+	/* Nothing to return. */
+	PG_RETURN_VOID();
+}
diff --git a/contrib/pg_conveyor/pg_conveyor.control b/contrib/pg_conveyor/pg_conveyor.control
new file mode 100644
index 0000000..7e95dab
--- /dev/null
+++ b/contrib/pg_conveyor/pg_conveyor.control
@@ -0,0 +1,5 @@
+# pg_conveyor test extension
+comment = 'test conveyor'
+default_version = '1.0'
+module_pathname = '$libdir/pg_conveyor'
+relocatable = true
diff --git a/contrib/pg_conveyor/sql/pg_conveyor.sql b/contrib/pg_conveyor/sql/pg_conveyor.sql
new file mode 100644
index 0000000..a4bd146
--- /dev/null
+++ b/contrib/pg_conveyor/sql/pg_conveyor.sql
@@ -0,0 +1,125 @@
+CREATE EXTENSION pg_conveyor;
+
+CREATE TABLE test(a int);
+
+SELECT pg_conveyor_init('test'::regclass::oid, 4);
+SELECT pg_conveyor_insert('test'::regclass::oid, 'test_data');
+SELECT pg_conveyor_read('test'::regclass::oid, 0);
+
+--CASE1
+do $$
+<<first_block>>
+declare
+  i int := 0;
+  data varchar;
+begin
+  for i in 1..1000 loop
+	data := 'test_dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' || i;
+	PERFORM pg_conveyor_insert('test'::regclass::oid, data);
+  end loop;
+end first_block $$;
+
+-- read from some random blocks
+SELECT pg_conveyor_read('test'::regclass::oid, 100);
+SELECT pg_conveyor_read('test'::regclass::oid, 800);
+
+--CASE2
+do $$
+<<first_block>>
+declare
+  i int := 0;
+  data varchar;
+begin
+  for i in 1..5000 loop
+	data := 'test_dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' || i+1000;
+	PERFORM pg_conveyor_insert('test'::regclass::oid, data);
+  end loop;
+end first_block $$;
+SELECT pg_conveyor_read('test'::regclass::oid, 4000);
+SELECT pg_conveyor_read('test'::regclass::oid, 3000);
+
+--CASE3
+DROP TABLE test;
+CREATE TABLE test(a int);
+SELECT pg_conveyor_init('test'::regclass::oid, 4);
+
+do $$
+<<first_block>>
+declare
+  i int := 0;
+  data varchar;
+begin
+  for i in 1..50000 loop
+	data := 'test_dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' || i;
+	PERFORM pg_conveyor_insert('test'::regclass::oid, data);
+  end loop;
+end first_block $$;
+
+
+--CASE4--(vacuum is failing)
+DROP TABLE test;
+CREATE TABLE test(a int);
+SELECT pg_conveyor_init('test'::regclass::oid, 4);
+do $$
+<<first_block>>
+declare
+  i int := 0;
+  data varchar;
+begin
+  for i in 1..5000 loop
+	data := 'test_dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' || i;
+	PERFORM pg_conveyor_insert('test'::regclass::oid, data);
+  end loop;
+end first_block $$;
+
+SELECT pg_conveyor_truncate('test'::regclass::oid, 3000);
+--SELECT pg_conveyor_vacuum('test'::regclass::oid); //not implemented
+
+--CASE5
+DROP TABLE test;
+CREATE TABLE test(a int);
+SELECT pg_conveyor_init('test'::regclass::oid, 4);
+
+do $$
+<<first_block>>
+declare
+  i int := 0;
+  data varchar;
+begin
+  for i in 1..50000 loop
+	data := 'test_dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' || i;
+	PERFORM pg_conveyor_insert('test'::regclass::oid, data);
+  end loop;
+end first_block $$;
+
+--CASE6 (multi truncate single vacuum)
+DROP TABLE test;
+CREATE TABLE test(a int);
+SELECT pg_conveyor_init('test'::regclass::oid, 4);
+do $$
+<<first_block>>
+declare
+  i int := 0;
+  data varchar;
+begin
+  for i in 1..1000 loop
+	data := 'test_dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' || i;
+	PERFORM pg_conveyor_insert('test'::regclass::oid, data);
+  end loop;
+end first_block $$;
+
+SELECT pg_conveyor_truncate('test'::regclass::oid, 500);
+do $$
+<<first_block>>
+declare
+  i int := 0;
+  data varchar;
+begin
+  for i in 1..1000 loop
+	data := 'test_dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' || i;
+	PERFORM pg_conveyor_insert('test'::regclass::oid, data);
+  end loop;
+end first_block $$;
+
+SELECT pg_conveyor_truncate('test'::regclass::oid, 1800);
+SELECT pg_conveyor_vacuum('test'::regclass::oid);
diff --git a/src/common/relpath.c b/src/common/relpath.c
index 1f5c426..20624e2 100644
--- a/src/common/relpath.c
+++ b/src/common/relpath.c
@@ -34,7 +34,8 @@ const char *const forkNames[] = {
 	"main",						/* MAIN_FORKNUM */
 	"fsm",						/* FSM_FORKNUM */
 	"vm",						/* VISIBILITYMAP_FORKNUM */
-	"init"						/* INIT_FORKNUM */
+	"init",						/* INIT_FORKNUM */
+	"tid"						/* DEADTID_FORKNUM */
 };
 
 StaticAssertDecl(lengthof(forkNames) == (MAX_FORKNUM + 1),
diff --git a/src/include/common/relpath.h b/src/include/common/relpath.h
index a44be11..0d38e07 100644
--- a/src/include/common/relpath.h
+++ b/src/include/common/relpath.h
@@ -43,7 +43,8 @@ typedef enum ForkNumber
 	MAIN_FORKNUM = 0,
 	FSM_FORKNUM,
 	VISIBILITYMAP_FORKNUM,
-	INIT_FORKNUM
+	INIT_FORKNUM,
+	DEADTID_FORKNUM
 
 	/*
 	 * NOTE: if you add a new fork, change MAX_FORKNUM and possibly
@@ -52,7 +53,7 @@ typedef enum ForkNumber
 	 */
 } ForkNumber;
 
-#define MAX_FORKNUM		INIT_FORKNUM
+#define MAX_FORKNUM		DEADTID_FORKNUM
 
 #define FORKNAMECHARS	4		/* max chars for a fork name */
 
-- 
1.8.3.1

Reply via email to