Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit db6856c

Browse files
committed
syncrep parser: pure parser and reentrant scanner
Use the flex %option reentrant and the bison option %pure-parser to make the generated scanner and parser pure, reentrant, and thread-safe. Make the generated scanner use palloc() etc. instead of malloc() etc. Previously, we only used palloc() for the buffer, but flex would still use malloc() for its internal structures. Now, all the memory is under palloc() control. Simplify flex scan buffer management: Instead of constructing the buffer from pieces and then using yy_scan_buffer(), we can just use yy_scan_string(), which does the same thing internally. The previous code was necessary because we allocated the buffer with palloc() and the rest of the state was handled by malloc(). But this is no longer the case; everything is under palloc() now. Use flex yyextra to handle context information, instead of global variables. This complements the other changes to make the scanner reentrant. Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi> Reviewed-by: Andreas Karlsson <andreas@proxel.se> Discussion: https://www.postgresql.org/message-id/flat/eb6faeac-2a8a-4b69-9189-c33c520e5b7b@eisentraut.org
1 parent e4a8fb8 commit db6856c

File tree

5 files changed

+90
-51
lines changed

5 files changed

+90
-51
lines changed

src/backend/nls.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ GETTEXT_TRIGGERS = $(BACKEND_COMMON_GETTEXT_TRIGGERS) \
1111
parser_yyerror \
1212
replication_yyerror:2 \
1313
scanner_yyerror \
14-
syncrep_yyerror \
14+
syncrep_yyerror:2 \
1515
report_invalid_record:2 \
1616
ereport_startup_progress \
1717
json_token_error:2 \

src/backend/replication/syncrep.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,7 @@ check_synchronous_standby_names(char **newval, void **extra, GucSource source)
992992
{
993993
if (*newval != NULL && (*newval)[0] != '\0')
994994
{
995+
yyscan_t scanner;
995996
int parse_rc;
996997
SyncRepConfigData *pconf;
997998

@@ -1000,9 +1001,9 @@ check_synchronous_standby_names(char **newval, void **extra, GucSource source)
10001001
syncrep_parse_error_msg = NULL;
10011002

10021003
/* Parse the synchronous_standby_names string */
1003-
syncrep_scanner_init(*newval);
1004-
parse_rc = syncrep_yyparse();
1005-
syncrep_scanner_finish();
1004+
syncrep_scanner_init(*newval, &scanner);
1005+
parse_rc = syncrep_yyparse(scanner);
1006+
syncrep_scanner_finish(scanner);
10061007

10071008
if (parse_rc != 0 || syncrep_parse_result == NULL)
10081009
{

src/backend/replication/syncrep_gram.y

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,6 @@ char *syncrep_parse_error_msg;
2626
static SyncRepConfigData *create_syncrep_config(const char *num_sync,
2727
List *members, uint8 syncrep_method);
2828

29-
/* silence -Wmissing-variable-declarations */
30-
extern int syncrep_yychar;
31-
extern int syncrep_yynerrs;
32-
3329
/*
3430
* Bison doesn't allocate anything that needs to live across parser calls,
3531
* so we can easily have it use palloc instead of malloc. This prevents
@@ -40,6 +36,9 @@ extern int syncrep_yynerrs;
4036

4137
%}
4238

39+
%parse-param {yyscan_t yyscanner}
40+
%lex-param {yyscan_t yyscanner}
41+
%pure-parser
4342
%expect 0
4443
%name-prefix="syncrep_yy"
4544

@@ -60,7 +59,10 @@ extern int syncrep_yynerrs;
6059

6160
%%
6261
result:
63-
standby_config { syncrep_parse_result = $1; }
62+
standby_config {
63+
syncrep_parse_result = $1;
64+
(void) yynerrs; /* suppress compiler warning */
65+
}
6466
;
6567

6668
standby_config:

src/backend/replication/syncrep_scanner.l

Lines changed: 68 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,27 @@ fprintf_to_ereport(const char *fmt, const char *msg)
3737
ereport(ERROR, (errmsg_internal("%s", msg)));
3838
}
3939

40-
/* Handles to the buffer that the lexer uses internally */
41-
static YY_BUFFER_STATE scanbufhandle;
42-
43-
static StringInfoData xdbuf;
40+
struct syncrep_yy_extra_type
41+
{
42+
StringInfoData xdbuf;
43+
};
44+
#define YY_EXTRA_TYPE struct syncrep_yy_extra_type *
4445

4546
/* LCOV_EXCL_START */
4647

4748
%}
4849

50+
%option reentrant
51+
%option bison-bridge
4952
%option 8bit
5053
%option never-interactive
5154
%option nodefault
5255
%option noinput
5356
%option nounput
5457
%option noyywrap
58+
%option noyyalloc
59+
%option noyyrealloc
60+
%option noyyfree
5561
%option warn
5662
%option prefix="syncrep_yy"
5763

@@ -82,38 +88,38 @@ xdinside [^"]+
8288
[Ff][Ii][Rr][Ss][Tt] { return FIRST; }
8389

8490
{xdstart} {
85-
initStringInfo(&xdbuf);
91+
initStringInfo(&yyextra->xdbuf);
8692
BEGIN(xd);
8793
}
8894
<xd>{xddouble} {
89-
appendStringInfoChar(&xdbuf, '"');
95+
appendStringInfoChar(&yyextra->xdbuf, '"');
9096
}
9197
<xd>{xdinside} {
92-
appendStringInfoString(&xdbuf, yytext);
98+
appendStringInfoString(&yyextra->xdbuf, yytext);
9399
}
94100
<xd>{xdstop} {
95-
syncrep_yylval.str = xdbuf.data;
96-
xdbuf.data = NULL;
101+
yylval->str = yyextra->xdbuf.data;
102+
yyextra->xdbuf.data = NULL;
97103
BEGIN(INITIAL);
98104
return NAME;
99105
}
100106
<xd><<EOF>> {
101-
syncrep_yyerror("unterminated quoted identifier");
107+
syncrep_yyerror(yyscanner, "unterminated quoted identifier");
102108
return JUNK;
103109
}
104110

105111
{identifier} {
106-
syncrep_yylval.str = pstrdup(yytext);
112+
yylval->str = pstrdup(yytext);
107113
return NAME;
108114
}
109115

110116
{digit}+ {
111-
syncrep_yylval.str = pstrdup(yytext);
117+
yylval->str = pstrdup(yytext);
112118
return NUM;
113119
}
114120

115121
"*" {
116-
syncrep_yylval.str = "*";
122+
yylval->str = "*";
117123
return NAME;
118124
}
119125

@@ -126,10 +132,16 @@ xdinside [^"]+
126132

127133
/* LCOV_EXCL_STOP */
128134

135+
/* see scan.l */
136+
#undef yyextra
137+
#define yyextra (((struct yyguts_t *) yyscanner)->yyextra_r)
138+
129139
/* Needs to be here for access to yytext */
130140
void
131-
syncrep_yyerror(const char *message)
141+
syncrep_yyerror(yyscan_t yyscanner, const char *message)
132142
{
143+
struct yyguts_t * yyg = (struct yyguts_t *) yyscanner; /* needed for yytext macro */
144+
133145
/* report only the first error in a parse operation */
134146
if (syncrep_parse_error_msg)
135147
return;
@@ -142,32 +154,51 @@ syncrep_yyerror(const char *message)
142154
}
143155

144156
void
145-
syncrep_scanner_init(const char *str)
157+
syncrep_scanner_init(const char *str, yyscan_t *yyscannerp)
158+
{
159+
yyscan_t yyscanner;
160+
struct syncrep_yy_extra_type *yyext = palloc0_object(struct syncrep_yy_extra_type);
161+
162+
if (yylex_init(yyscannerp) != 0)
163+
elog(ERROR, "yylex_init() failed: %m");
164+
165+
yyscanner = *yyscannerp;
166+
167+
yyset_extra(yyext, yyscanner);
168+
169+
yy_scan_string(str, yyscanner);
170+
}
171+
172+
void
173+
syncrep_scanner_finish(yyscan_t yyscanner)
146174
{
147-
Size slen = strlen(str);
148-
char *scanbuf;
149-
150-
/*
151-
* Might be left over after ereport()
152-
*/
153-
if (YY_CURRENT_BUFFER)
154-
yy_delete_buffer(YY_CURRENT_BUFFER);
155-
156-
/*
157-
* Make a scan buffer with special termination needed by flex.
158-
*/
159-
scanbuf = (char *) palloc(slen + 2);
160-
memcpy(scanbuf, str, slen);
161-
scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR;
162-
scanbufhandle = yy_scan_buffer(scanbuf, slen + 2);
163-
164-
/* Make sure we start in proper state */
165-
BEGIN(INITIAL);
175+
pfree(yyextra);
176+
yylex_destroy(yyscanner);
177+
}
178+
179+
/*
180+
* Interface functions to make flex use palloc() instead of malloc().
181+
* It'd be better to make these static, but flex insists otherwise.
182+
*/
183+
184+
void *
185+
yyalloc(yy_size_t size, yyscan_t yyscanner)
186+
{
187+
return palloc(size);
188+
}
189+
190+
void *
191+
yyrealloc(void *ptr, yy_size_t size, yyscan_t yyscanner)
192+
{
193+
if (ptr)
194+
return repalloc(ptr, size);
195+
else
196+
return palloc(size);
166197
}
167198

168199
void
169-
syncrep_scanner_finish(void)
200+
yyfree(void *ptr, yyscan_t yyscanner)
170201
{
171-
yy_delete_buffer(scanbufhandle);
172-
scanbufhandle = NULL;
202+
if (ptr)
203+
pfree(ptr);
173204
}

src/include/replication/syncrep.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,15 @@ extern void SyncRepUpdateSyncStandbysDefined(void);
100100
* Internal functions for parsing synchronous_standby_names grammar,
101101
* in syncrep_gram.y and syncrep_scanner.l
102102
*/
103-
extern int syncrep_yyparse(void);
104-
extern int syncrep_yylex(void);
105-
extern void syncrep_yyerror(const char *str);
106-
extern void syncrep_scanner_init(const char *str);
107-
extern void syncrep_scanner_finish(void);
103+
union YYSTYPE;
104+
#ifndef YY_TYPEDEF_YY_SCANNER_T
105+
#define YY_TYPEDEF_YY_SCANNER_T
106+
typedef void *yyscan_t;
107+
#endif
108+
extern int syncrep_yyparse(yyscan_t yyscanner);
109+
extern int syncrep_yylex(union YYSTYPE *yylval_param, yyscan_t yyscanner);
110+
extern void syncrep_yyerror(yyscan_t yyscanner, const char *str);
111+
extern void syncrep_scanner_init(const char *str, yyscan_t *yyscannerp);
112+
extern void syncrep_scanner_finish(yyscan_t yyscanner);
108113

109114
#endif /* _SYNCREP_H */

0 commit comments

Comments
 (0)