Skip to content

Commit 08e7854

Browse files
committed
Get rid of GenericXLogUnregister().
This routine is unsafe as implemented, because it invalidates the page image pointers returned by previous GenericXLogRegister() calls. Rather than complicate the API or the implementation to avoid that, let's just get rid of it; the use-case for having it seems much too thin to justify a lot of work here. While at it, do some wordsmithing on the SGML docs for generic WAL.
1 parent 80cf189 commit 08e7854

File tree

3 files changed

+69
-84
lines changed

3 files changed

+69
-84
lines changed

doc/src/sgml/generic-wal.sgml

Lines changed: 68 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,139 +1,154 @@
11
<!-- doc/src/sgml/generic-wal.sgml -->
22

33
<chapter id="generic-wal">
4-
<title>Generic WAL records</title>
4+
<title>Generic WAL Records</title>
55

66
<para>
7-
Despite all built-in access methods and WAL-logged modules having their own
8-
types of WAL records, there is also a generic WAL record type, which describes
9-
changes to pages in a generic way. This is useful for extensions that
10-
provide custom access methods, because they cannot register their own
11-
WAL redo routines.
7+
Although all built-in WAL-logged modules have their own types of WAL
8+
records, there is also a generic WAL record type, which describes changes
9+
to pages in a generic way. This is useful for extensions that provide
10+
custom access methods, because they cannot register their own WAL redo
11+
routines.
1212
</para>
1313

1414
<para>
1515
The API for constructing generic WAL records is defined in
16-
<filename>generic_xlog.h</> and implemented in <filename>generic_xlog.c</>.
17-
Each generic WAL record must be constructed by following these steps:
16+
<filename>access/generic_xlog.h</> and implemented
17+
in <filename>access/transam/generic_xlog.c</>.
18+
</para>
19+
20+
<para>
21+
To perform a WAL-logged data update using the generic WAL record
22+
facility, follow these steps:
1823

1924
<orderedlist>
2025
<listitem>
2126
<para>
2227
<function>state = GenericXLogStart(relation)</> &mdash; start
23-
construction of a generic xlog record for the given relation.
28+
construction of a generic WAL record for the given relation.
2429
</para>
2530
</listitem>
2631

2732
<listitem>
2833
<para>
2934
<function>page = GenericXLogRegister(state, buffer, isNew)</> &mdash;
30-
register one or more buffers (one at a time) for the current generic
31-
xlog record. This function returns a copy of the page image, where
32-
modifications can be made. The second argument indicates if the page
33-
is new (eventually, this will result in a full page image being put into
34-
the xlog record).
35+
register a buffer to be modified within the current generic WAL
36+
record. This function returns a pointer to a temporary copy of the
37+
buffer's page, where modifications should be made. (Do not modify the
38+
buffer's contents directly.) The third argument indicates if the page
39+
is new; if true, this will result in a full-page image rather than a
40+
delta update being included in the WAL record.
41+
<function>GenericXLogRegister</> can be repeated if the WAL-logged
42+
action needs to modify multiple pages.
3543
</para>
3644
</listitem>
3745

3846
<listitem>
3947
<para>
40-
Apply modifications to page images obtained in the previous step.
48+
Apply modifications to the page images obtained in the previous step.
4149
</para>
4250
</listitem>
4351

4452
<listitem>
4553
<para>
46-
<function>GenericXLogFinish(state)</> &mdash; finish construction of
47-
a generic xlog record.
54+
<function>GenericXLogFinish(state)</> &mdash; apply the changes to
55+
the buffers and emit the generic WAL record.
4856
</para>
4957
</listitem>
5058
</orderedlist>
5159
</para>
5260

5361
<para>
54-
The xlog record construction can be canceled between any of the above
55-
steps by calling <function>GenericXLogAbort(state)</>. This will discard all
62+
WAL record construction can be canceled between any of the above steps by
63+
calling <function>GenericXLogAbort(state)</>. This will discard all
5664
changes to the page image copies.
5765
</para>
5866

5967
<para>
60-
Please note the following points when constructing generic xlog records:
68+
Please note the following points when using the generic WAL record
69+
facility:
70+
6171
<itemizedlist>
6272
<listitem>
6373
<para>
64-
No direct modifications of page images are allowed! All modifications
74+
No direct modifications of buffers are allowed! All modifications
6575
must be done in copies acquired from <function>GenericXLogRegister()</>.
66-
In other words, code which makes generic xlog records must never call
67-
<function>BufferGetPage()</>.
76+
In other words, code that makes generic WAL records should never call
77+
<function>BufferGetPage()</> for itself. However, it remains the
78+
caller's responsibility to pin/unpin and lock/unlock the buffers at
79+
appropriate times. Exclusive lock must be held on each target buffer
80+
from before <function>GenericXLogRegister()</> until after
81+
<function>GenericXLogFinish()</>.
6882
</para>
6983
</listitem>
7084

7185
<listitem>
7286
<para>
7387
Registrations of buffers (step 2) and modifications of page images
7488
(step 3) can be mixed freely, i.e., both steps may be repeated in any
75-
sequence. The only restriction is that you can modify a page image
76-
only after the registration of the corresponding buffer.
89+
sequence. Keep in mind that buffers should be registered in the same
90+
order in which locks are to be obtained on them during replay.
7791
</para>
7892
</listitem>
7993

8094
<listitem>
8195
<para>
82-
After registration, the buffer can also be unregistered by calling
83-
<function>GenericXLogUnregister(buffer)</>. In this case, the changes
84-
made to that particular page image copy will be discarded.
96+
The maximum number of buffers that can be registered for a generic WAL
97+
record is <literal>MAX_GENERIC_XLOG_PAGES</>. An error will be thrown
98+
if this limit is exceeded.
8599
</para>
86100
</listitem>
87101

88102
<listitem>
89103
<para>
90-
Generic xlog assumes that pages are using standard layout. I.e., all
91-
information between pd_lower and pd_upper will be discarded.
104+
Generic WAL assumes that the pages to be modified have standard
105+
layout, and in particular that there is no useful data between
106+
<structfield>pd_lower</> and <structfield>pd_upper</>.
92107
</para>
93108
</listitem>
94109

95110
<listitem>
96111
<para>
97-
The maximum number of buffers that can be simultaneously registered
98-
for a generic xlog is <literal>MAX_GENERIC_XLOG_PAGES</>. An error will
99-
be thrown if this limit is exceeded.
100-
</para>
101-
</listitem>
102-
<listitem>
103-
<para>
104-
Since you modify copies of page images, <function>GenericXLogStart()</>
105-
does not start a critical section. Thus, you can do memory allocation,
106-
error throwing, etc. between <function>GenericXLogStart()</> and
107-
<function>GenericXLogFinish()</>. The actual critical section is present
108-
inside <function>GenericXLogFinish()</>.
112+
Since you are modifying copies of buffer
113+
pages, <function>GenericXLogStart()</> does not start a critical
114+
section. Thus, you can safely do memory allocation, error throwing,
115+
etc. between <function>GenericXLogStart()</> and
116+
<function>GenericXLogFinish()</>. The only actual critical section is
117+
present inside <function>GenericXLogFinish()</>. There is no need to
118+
worry about calling <function>GenericXLogAbort()</> during an error
119+
exit, either.
109120
</para>
110121
</listitem>
122+
111123
<listitem>
112124
<para>
113-
<function>GenericXLogFinish()</> takes care of marking buffers as dirty
125+
<function>GenericXLogFinish()</> takes care of marking buffers dirty
114126
and setting their LSNs. You do not need to do this explicitly.
115127
</para>
116128
</listitem>
129+
117130
<listitem>
118131
<para>
119-
For unlogged relations, everything works the same except there is no
120-
WAL record produced. Thus, you typically do not need to do any explicit
121-
checks for unlogged relations.
132+
For unlogged relations, everything works the same except that no
133+
actual WAL record is emitted. Thus, you typically do not need to do
134+
any explicit checks for unlogged relations.
122135
</para>
123136
</listitem>
137+
124138
<listitem>
125139
<para>
126-
If a registered buffer is not new, the generic xlog record contains
127-
a delta between the old and the new page images. This delta is produced
128-
using per byte comparison. The current delta mechanism is not effective
129-
for moving data within a page and may be improved in the future.
140+
The generic WAL redo function will acquire exclusive locks to buffers
141+
in the same order as they were registered. After redoing all changes,
142+
the locks will be released in the same order.
130143
</para>
131144
</listitem>
145+
132146
<listitem>
133147
<para>
134-
The generic xlog redo function will acquire exclusive locks to buffers
135-
in the same order as they were registered. After redoing all changes,
136-
the locks will be released in the same order.
148+
If a registered buffer is not new, the generic WAL record contains
149+
a delta between the old and the new page images. This delta is based
150+
on byte-by-byte comparison. This is not very compact for the case of
151+
moving data within a page, and might be improved in the future.
137152
</para>
138153
</listitem>
139154
</itemizedlist>

src/backend/access/transam/generic_xlog.c

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -257,35 +257,6 @@ GenericXLogRegister(GenericXLogState *state, Buffer buffer, bool isNew)
257257
return NULL;
258258
}
259259

260-
/*
261-
* Unregister particular buffer for generic xlog record.
262-
*
263-
* XXX this is dangerous and should go away.
264-
*/
265-
void
266-
GenericXLogUnregister(GenericXLogState *state, Buffer buffer)
267-
{
268-
int block_id;
269-
270-
/* Find block in array to unregister */
271-
for (block_id = 0; block_id < MAX_GENERIC_XLOG_PAGES; block_id++)
272-
{
273-
if (state->pages[block_id].buffer == buffer)
274-
{
275-
/*
276-
* Preserve order of pages in array because it could matter for
277-
* concurrency.
278-
*/
279-
memmove(&state->pages[block_id], &state->pages[block_id + 1],
280-
(MAX_GENERIC_XLOG_PAGES - block_id - 1) * sizeof(PageData));
281-
state->pages[MAX_GENERIC_XLOG_PAGES - 1].buffer = InvalidBuffer;
282-
return;
283-
}
284-
}
285-
286-
elog(ERROR, "registered generic xlog buffer not found");
287-
}
288-
289260
/*
290261
* Apply changes represented by GenericXLogState to the actual buffers,
291262
* and emit a generic xlog record.

src/include/access/generic_xlog.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ typedef struct GenericXLogState GenericXLogState;
2929
/* API for construction of generic xlog records */
3030
extern GenericXLogState *GenericXLogStart(Relation relation);
3131
extern Page GenericXLogRegister(GenericXLogState *state, Buffer buffer,
32-
bool isNew);
33-
extern void GenericXLogUnregister(GenericXLogState *state, Buffer buffer);
32+
bool isNew);
3433
extern XLogRecPtr GenericXLogFinish(GenericXLogState *state);
3534
extern void GenericXLogAbort(GenericXLogState *state);
3635

0 commit comments

Comments
 (0)