Skip to content

Commit 3ec3013

Browse files
gongxun0928my-ship-it
authored andcommitted
support implementing custom storage manager in extension
We add a new smgr and need to make the following changes: Firstly we should to define our own f_smgr structure in extension. struct f_smgr custom_smgr = { .smgr_name = "custom smgr", .smgr_name = = md_init, ... } Then register our own structure in shared_preload_libraries phase. smgr_register(&custom_smgr, CUSTOM_SMGR_ID); CUSTOM_SMGR_ID should be unique and cannot be changed, and should not conflict with other extensions. Finally we need to correctly return the relation's smgr id in smgr_get_impl the extension need to implement smgr_get_impl_hook correctly
1 parent 9319f8e commit 3ec3013

File tree

6 files changed

+145
-12
lines changed

6 files changed

+145
-12
lines changed

src/backend/access/rmgrdesc/smgrdesc.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ smgr_desc(StringInfo buf, XLogReaderState *record)
2727
{
2828
xl_smgr_create *xlrec = (xl_smgr_create *) rec;
2929
char *path = relpathperm(xlrec->rnode, xlrec->forkNum);
30-
appendStringInfo(buf, "%s; smgr: %s", path, xlrec->impl == SMGR_MD ? "heap" : "ao");
30+
#ifndef FRONTEND
31+
appendStringInfo(buf, "%s; smgr: %s", path, smgr_get_name(xlrec->impl));
32+
#else
33+
appendStringInfo(buf, "%s; smgr: %s", path, xlrec->impl == SMGR_MD ? "heap" : (xlrec->impl == SMGR_AO ? "ao" : "unknown"));
34+
#endif
3135
pfree(path);
3236
}
3337
else if (info == XLOG_SMGR_TRUNCATE)

src/backend/catalog/storage.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,7 @@ RelationDropStorage(Relation rel)
213213
pending->relnode.isTempRelation = rel->rd_backend == TempRelBackendId;
214214
pending->atCommit = true; /* delete if commit */
215215
pending->nestLevel = GetCurrentTransactionNestLevel();
216-
pending->relnode.smgr_which =
217-
RelationIsAppendOptimized(rel) ? SMGR_AO : SMGR_MD;
216+
pending->relnode.smgr_which = smgr_get_impl(rel);
218217
pending->action = &storage_pending_rel_deletes_action;
219218
RegisterPendingDelete(pending);
220219

src/backend/commands/tablecmds.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16559,7 +16559,7 @@ index_copy_data(Relation rel, RelFileNode newrnode)
1655916559
{
1656016560
SMgrRelation dstrel;
1656116561

16562-
SMgrImpl smgr_which = RelationIsAppendOptimized(rel) ? SMGR_AO : SMGR_MD;
16562+
SMgrImpl smgr_which = smgr_get_impl(rel);
1656316563

1656416564
dstrel = smgropen(newrnode, rel->rd_backend, smgr_which, rel);
1656516565

src/backend/storage/smgr/smgr.c

Lines changed: 88 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,17 @@ file_extend_hook_type file_extend_hook = NULL;
5050
file_truncate_hook_type file_truncate_hook = NULL;
5151
file_unlink_hook_type file_unlink_hook = NULL;
5252

53+
smgr_get_impl_hook_type smgr_get_impl_hook = NULL;
54+
5355
/* Hook for plugins to get control in smgr */
5456
smgr_init_hook_type smgr_init_hook = NULL;
5557
smgr_hook_type smgr_hook = NULL;
5658
smgr_shutdown_hook_type smgr_shutdown_hook = NULL;
57-
58-
static const f_smgr smgrsw[] = {
59+
#define SMGR_MAX_ID UINT8_MAX
60+
static f_smgr smgrsw[SMGR_MAX_ID + 1] = {
5961
/* magnetic disk */
6062
{
63+
.smgr_name = "heap",
6164
.smgr_init = mdinit,
6265
.smgr_shutdown = NULL,
6366
.smgr_open = mdopen,
@@ -82,6 +85,7 @@ static const f_smgr smgrsw[] = {
8285
* Append-optimized relation files currently fall in this category.
8386
*/
8487
{
88+
.smgr_name = "ao",
8589
.smgr_init = mdinit,
8690
.smgr_shutdown = NULL,
8791
.smgr_open = mdopen,
@@ -115,8 +119,6 @@ static const f_smgr_ao smgrswao[] = {
115119
};
116120

117121

118-
static const int NSmgr = lengthof(smgrsw);
119-
120122
/*
121123
* Each backend has a hashtable that stores all extant SMgrRelation objects.
122124
* In addition, "unowned" SMgrRelation objects are chained together in a list.
@@ -128,6 +130,79 @@ static dlist_head unowned_relns;
128130
/* local function prototypes */
129131
static void smgrshutdown(int code, Datum arg);
130132

133+
void smgr_register(const f_smgr *smgr, SMgrImpl smgr_impl)
134+
{
135+
if (!process_shared_preload_libraries_in_progress)
136+
{
137+
ereport(ERROR, (errmsg("smgr_register not in shared_preload_libraries")));
138+
}
139+
140+
if (smgr_impl > SMGR_MAX_ID)
141+
{
142+
elog(ERROR, "smgr_impl is out of range");
143+
}
144+
145+
if (smgr->smgr_name == NULL)
146+
{
147+
elog(ERROR, "smgr_name is not set");
148+
}
149+
150+
// check if the smgr_impl is already registered, avoid conflict with existing smgr_impl
151+
if (smgrsw[smgr_impl].smgr_name != NULL)
152+
{
153+
elog(ERROR, "smgr_impl is already registered");
154+
}
155+
156+
smgrsw[smgr_impl] = *smgr;
157+
}
158+
159+
const f_smgr *smgr_get(SMgrImpl smgr_impl)
160+
{
161+
if (smgr_impl > SMGR_MAX_ID)
162+
{
163+
elog(ERROR, "smgr_impl is out of range");
164+
}
165+
166+
if (smgrsw[smgr_impl].smgr_name == NULL)
167+
{
168+
elog(ERROR, "smgr_impl is not registered");
169+
}
170+
171+
return &smgrsw[smgr_impl];
172+
}
173+
174+
/*
175+
* smgr_get_impl() is used to get the smgr id of the relation.
176+
*
177+
* FIXME: For PAX_AM_OID, Cloudberrydb reserves this value for ORCA, a
178+
* predefined value is used here to reserve the smgr id for PAX_AM_OID.
179+
* should we add a hook to get the smgr id of the relation?
180+
*/
181+
SMgrImpl smgr_get_impl(const Relation rel)
182+
{
183+
SMgrImpl smgr_impl = SMGR_MD;
184+
185+
if (RelationIsAppendOptimized(rel))
186+
{
187+
smgr_impl = SMGR_AO;
188+
}
189+
else if (RelationIsPax(rel))
190+
{
191+
smgr_impl = SMGR_PAX;
192+
}
193+
else
194+
{
195+
if (smgr_get_impl_hook)
196+
{
197+
(*smgr_get_impl_hook)(rel, &smgr_impl);
198+
Assert(smgr_impl >= SMGR_MD && smgr_impl <= SMGR_MAX_ID);
199+
Assert(smgrsw[smgr_impl].smgr_name != NULL);
200+
}
201+
}
202+
203+
204+
return smgr_impl;
205+
}
131206

132207
/*
133208
* smgrinit(), smgrshutdown() -- Initialize or shut down storage
@@ -142,7 +217,7 @@ smgrinit(void)
142217
{
143218
int i;
144219

145-
for (i = 0; i < NSmgr; i++)
220+
for (i = 0; i <= SMGR_MAX_ID; i++)
146221
{
147222
if (smgrsw[i].smgr_init)
148223
smgrsw[i].smgr_init();
@@ -163,7 +238,7 @@ smgrshutdown(int code, Datum arg)
163238
{
164239
int i;
165240

166-
for (i = 0; i < NSmgr; i++)
241+
for (i = 0; i <= SMGR_MAX_ID; i++)
167242
{
168243
if (smgrsw[i].smgr_shutdown)
169244
smgrsw[i].smgr_shutdown();
@@ -777,3 +852,10 @@ AtEOXact_SMgr(void)
777852
smgrclose(rel);
778853
}
779854
}
855+
856+
const char *smgr_get_name(SMgrImpl impl)
857+
{
858+
if (impl > SMGR_MAX_ID)
859+
return "invalid";
860+
return smgrsw[impl].smgr_name ? smgrsw[impl].smgr_name : "unknown";
861+
}

src/include/storage/smgr.h

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,35 @@
2424
#include "storage/fd.h"
2525
#include "utils/relcache.h"
2626

27+
/*
28+
* Extension can register a new storage manager(smgr) by implementing
29+
* its own struct f_smgr.
30+
* Each storage manager has a unique implementation id, which is used
31+
* to identify the smgr.
32+
*
33+
* The smgr_register function is used to register the smgr. it will
34+
* check if the smgr is already registered, if so, return SMGR_INVALID.
35+
* otherwise, register the smgr and return the implementation id.
36+
*
37+
* The smgr id of each relation is fixed and cannot be changed. because the
38+
* type of smgr is logged in the commit log and wal log. If the value of
39+
* smgr is changed, data corruption may occur.
40+
*
41+
* How to ensure that the smgr of each extension does not conflict? One way
42+
* is to predefine the smgr id used by the extension in Cloudberry; the other
43+
* way is to refer to the practice of custom rmgr and provide a wiki page
44+
* [https://wiki.postgresql.org/wiki/CustomWALResourceManagers] to record
45+
* the use of smgr to avoid conflicts.
46+
*
47+
* FIXME: For PAX_AM_OID, Cloudberrydb reserves this value for ORCA, a
48+
* predefined value is used here to reserve the smgr id for PAX_AM_OID.
49+
*/
2750
typedef enum SMgrImplementation
2851
{
2952
SMGR_INVALID = -1,
3053
SMGR_MD = 0,
3154
SMGR_AO = 1,
55+
SMGR_PAX = 2,
3256
} SMgrImpl;
3357

3458
struct f_smgr;
@@ -105,6 +129,7 @@ typedef SMgrRelationData *SMgrRelation;
105129
*/
106130
typedef struct f_smgr
107131
{
132+
const char *smgr_name;
108133
void (*smgr_init) (void); /* may be NULL */
109134
void (*smgr_shutdown) (void); /* may be NULL */
110135
void (*smgr_open) (SMgrRelation reln);
@@ -148,9 +173,16 @@ typedef void (*smgr_shutdown_hook_type) (void);
148173
extern PGDLLIMPORT smgr_init_hook_type smgr_init_hook;
149174
extern PGDLLIMPORT smgr_hook_type smgr_hook;
150175
extern PGDLLIMPORT smgr_shutdown_hook_type smgr_shutdown_hook;
151-
152176
extern bool smgr_is_heap_relation(SMgrRelation reln);
153177

178+
// must be registered in the shared_preload_libraries phase in extension
179+
// we should check whether smgr and smgr_impl is valid.
180+
extern void smgr_register(const f_smgr *smgr, SMgrImpl smgr_impl);
181+
182+
extern const f_smgr *smgr_get(SMgrImpl smgr_impl);
183+
184+
extern SMgrImpl smgr_get_impl(const Relation rel);
185+
154186
extern void smgrinit(void);
155187
extern SMgrRelation smgropen(RelFileNode rnode, BackendId backend,
156188
SMgrImpl smgr_which, Relation rel);
@@ -183,6 +215,8 @@ extern void AtEOXact_SMgr(void);
183215

184216
extern const struct f_smgr_ao * smgrAOGetDefault(void);
185217

218+
extern const char* smgr_get_name(SMgrImpl impl);
219+
186220

187221
/*
188222
* Hook for plugins to collect statistics from storage functions
@@ -201,4 +235,14 @@ extern PGDLLIMPORT file_truncate_hook_type file_truncate_hook;
201235
typedef void (*file_unlink_hook_type)(RelFileNodeBackend rnode);
202236
extern PGDLLIMPORT file_unlink_hook_type file_unlink_hook;
203237

238+
/*
239+
* This hook is used to get the smgr implementation id of the relation for extension.
240+
* If the hook is not set, the default smgr implementation id is SMGR_MD.
241+
* If the extension register a custom smgr to manage its own relation, it needs
242+
* to implement this hook and then set the smgr_impl to the correct value for
243+
* the relation which is managed by the extension, otherwise should ignore it.
244+
*/
245+
typedef void (*smgr_get_impl_hook_type)(const Relation rel, SMgrImpl* smgr_impl);
246+
extern PGDLLIMPORT smgr_get_impl_hook_type smgr_get_impl_hook;
247+
204248
#endif /* SMGR_H */

src/include/utils/rel.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,10 @@ typedef struct ViewOptions
532532
* can't distinguish the PAX and renamed heap(heap_psql) in test `psql`.
533533
*/
534534
#define PAX_AM_OID 7047
535+
536+
#define RelationIsPax(relation) \
537+
((relation)->rd_rel->relam == PAX_AM_OID)
538+
535539
/*
536540
* CAUTION: this macro is a violation of the absraction that table AM and
537541
* index AM interfaces provide. Use of this macro is discouraged. If
@@ -548,7 +552,7 @@ typedef struct ViewOptions
548552
*/
549553
#define RelationIsNonblockRelation(relation) \
550554
(RelationIsAppendOptimized(relation) || \
551-
(relation)->rd_rel->relam == PAX_AM_OID)
555+
RelationIsPax(relation))
552556

553557
/*
554558
* RelationIsBitmapIndex

0 commit comments

Comments
 (0)