Re: Support for N synchronous standby servers - take 2
| От | Kyotaro HORIGUCHI |
|---|---|
| Тема | Re: Support for N synchronous standby servers - take 2 |
| Дата | |
| Msg-id | 20160225.184628.47734634.horiguchi.kyotaro@lab.ntt.co.jp обсуждение исходный текст |
| Ответ на | Re: Support for N synchronous standby servers - take 2 (Masahiko Sawada <sawada.mshk@gmail.com>) |
| Ответы |
Re: Support for N synchronous standby servers - take 2
|
| Список | pgsql-hackers |
Hello,
At Wed, 24 Feb 2016 18:01:59 +0900, Masahiko Sawada <sawada.mshk@gmail.com> wrote in
<CAD21AoCetS5BMcTpXXtMwG0hyszZgNn=zK1U73GcWTgJ-Wn3pQ@mail.gmail.com>
> On Wed, Feb 24, 2016 at 5:37 PM, Kyotaro HORIGUCHI
> <horiguchi.kyotaro@lab.ntt.co.jp> wrote:
> > Hello,
> >
> > Ok, I think we should concentrate the parser part for now.
> >
> > At Tue, 23 Feb 2016 17:44:44 +0900 (Tokyo Standard Time), Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> wrote
in<20160223.174444.178687579.horiguchi.kyotaro@lab.ntt.co.jp>
> >> Hello,
...
> >> So, to preserve or following the current behavior expct the last
> >> one, the following pattern definitions would do. The
> >> lexer/grammer for the new format of s_s_names could be simpler
> >> than what it is.
> >>
> >> space [ \n\r\f\t\v] /* See the definition of isspace(3) */
> >> whitespace {space}+
> >> dquote \"
> >> app_name_chars [\x21-\x2b\x2d-\x7e] /* excluding ' ', ',' */
> >> app_name_indq_chars [\x20\x21\x23-\x7e] /* excluding '"' */
> >> app_name_dq_chars ({app_name_indq_chars}|{dquote}{dquote})
> >> delimiter {whitespace}*,{whitespace}*
> >> app_name ({app_name_chars}+|{dquote}{app_name_dq_chars}+{dquote})
> >> s_s_names {app_name}({delimiter}{app_name})*
> >
> >
> > So I made a hasty independent parser for the syntax including the
> > group names for the convenience for separate testing. The parser
> > takes input from stdin and prints the result structure.
> >
> > It can take old s_s_name format and new list format. We haven't
> > discussed how to add gruop names but I added it as "<grpname>"
> > just before the # of syncronous standbys of [] and {} lists.
> >
> > Is this usable for further discussions?
>
> Thank you for your suggestion.
>
> Another option is to add group name with ":" to immediately after set
> of standbys as I said earlier.
> <http://www.postgresql.org/message-id/CAD21AoA9UqcbTnDKi0osd0yhN4FPgTrg6wuZeTtvpSYy2LqL5Q@mail.gmail.com>
>
> s_s_names with group name would be as follows.
> s_s_names = '2[local, 2[london1, london2, london3]:london, (tokyo1,
> tokyo2):tokyo]'
>
> Though?
I have no problem with it. The attached new sample parser does
so.
By the way, your parser also complains for an example I've seen
somewhere upthread "1[2,3,4]". This is because '2', '3' and '4'
are regarded as INT, not NAME. Whether a sequence of digits is a
prefix number of a list or a host name cannot be identified until
reading some following characters. So my previous test.l defined
NAME_OR_INTEGER and it is distinguished in the grammar side to
resolve this problem.
If you want them identified in the lexer side, it should do
looking-forward as <NAME_OR_PREFIX>{prefix} in the attached
test.l does. This makes the lexer a bit complex but in contrast
test.y simpler. The test.l, test.y attached got refactored but .l
gets a bit tricky..
regards,
--
Kyotaro Horiguchi
NTT Open Source Software Center
%{
#include <stdio.h>
#include <stdlib.h>
%}
%option noyywrap
%x DQNAME
%x NAME_OR_PREFIX
%x APPNAME
%x GRPCLOSED
space [ \t\n\r\f]
whitespace {space}+
dquote \"
app_name_chars [\x21-\x27\x2a\x2b\x2d-\x5a\x5c\x5e-\x7a\x7c\x7e]
app_name_indq_chars [\x20\x21\x23-\x7e]
app_name {app_name_chars}+
app_name_dq ({app_name_indq_chars}|{dquote}{dquote})+
delimiter {whitespace}*,{whitespace}*
app_name_start {app_name_chars}
any_app \*|({dquote}\*{dquote})
xdstart {dquote}
xdstop {dquote}
openlist [\[\(]
prefix [0-9]+{whitespace}*{openlist}
closelist [\]\)]
%%
{xdstart} { BEGIN(DQNAME); }
<DQNAME>{xdstop} { BEGIN(INITIAL); }
<DQNAME>{app_name_dq} { appname *name = (appname *)malloc(sizeof(appname)); int i, j;
for (i = j = 0 ; j < 63 && yytext[i] ; i++, j++) { if (yytext[i] == '"') { if (yytext[i+1] == '"')
name->str[j]= '"'; else fprintf(stderr, "illegal quote escape\n"); i++;} else name->str[j] =
yytext[i];
} name->str[j] = 0; name->quoted = 1;
yylval.name = name; return NAME;
}
{app_name_start} { BEGIN(NAME_OR_PREFIX); yyless(0);}
<NAME_OR_PREFIX>{app_name} { appname *name = (appname *)malloc(sizeof(appname));char *p;
name->quoted = 0;strncpy(name->str, yytext, 63);name->str[63] = 0;for (p = name->str ; *p ; p++){ if (*p >= 'A'
&&*p <= 'Z') *p = *p + ('a' - 'A');}yylval.name = name;BEGIN(INITIAL);return NAME;
}
<NAME_OR_PREFIX>{prefix} {static char prefix[16];int i, l;
/* find the last digit */for (l = 0 ; l < 16 && isdigit(yytext[l]) ; l++);if (l > 15) fprintf(stderr, "too long
prefixnumber for lists\n");for (i = 0 ; i < l ; i++) prefix[i] = yytext[i];prefix[i] = 0;yylval.str =
strdup(prefix);
/* prefix ends with a left brace or paren, so go backward by 1 char for further readin */
yyless(yyleng - 1); BEGIN(INITIAL);return PREFIX;
}
<GRPCLOSED>{whitespace}*. {BEGIN(INITIAL);if (yytext[yyleng - 1] == ':') return yytext[yyleng - 1];yyless(0);
}
{delimiter} { return DELIMITER;}
{openlist} {yylval.character = yytext[0];return OPENLIST;
}
{closelist} { BEGIN(GRPCLOSED);yylval.character = yytext[0];return CLOSELIST;
}
%%
//int main(void)
//{
// int r;
//
// while(r = yylex()) {
// fprintf(stderr, "#%d:(%s)#", r, yylval.str);
// yylval.str = "";
// }
//}
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#define YYDEBUG 1
typedef enum treeelemtype
{ TE_HOSTNAME, TE_PRIORITY_LIST, TE_QUORUM_LIST
} treeelemtype;
struct syncdef;
typedef struct syncdef
{ treeelemtype type; char *name; int quoted; int nsync; int nest;
struct syncdef *elems; struct syncdef *next;
} syncdef;
typedef struct
{int quoted;char str[64];
} appname;
void yyerror(const char *s);
int yylex(void);
int depth = 0;
syncdef *defroot = NULL;
syncdef *curr = NULL;
%}
%union
{ char character; char *str; appname *name; int ival; syncdef *syncdef;
}
%token <str> PREFIX
%token <name> NAME
%token <character> OPENLIST CLOSELIST
%token DELIMITER
%type <syncdef> group_list name_list name_elem name_elem_nonlist
%type <syncdef> old_list s_s_names
%type <name> opt_groupname
%type <str> opt_prefix
%%
s_s_names:old_list{ syncdef *t = (syncdef*)malloc(sizeof(syncdef));
t->type = TE_PRIORITY_LIST; t->name = NULL; t->quoted = 0; t->nsync = 1; t->elems = $1; t->next = NULL; defroot
=$$ = t;}| group_list{ defroot = $$ = $1;};
old_list:name_elem_nonlist{ $$ = $1;}| old_list DELIMITER name_elem_nonlist{ syncdef *p = $1;
while (p->next) p = p->next; p->next = $3;};
group_list: opt_prefix OPENLIST name_list CLOSELIST opt_groupname{ syncdef *t; char *p = $1; int n = atoi($1); if
(n== 0) { yyerror("prefix number is 0 or non-integer"); return 1; } if ($3->nest > 1) { yyerror("Up to 2
levelsof nesting is supported"); return 1; } for (t = $3 ; t ; t = t->next) { if (t->type == TE_HOSTNAME &&
t->next&& strcmp(t->name, "*") == 0) { yyerror("\"*\" is allowed only at the end of priority list");
return 1; } } if ($2 == '[' && $4 != ']' || $2 == '(' && $4 != ')') { yyerror("Unmatched group
parentheses"); return 1; } t = (syncdef*)malloc(sizeof(syncdef)); t->type = ($2 == '[' ? TE_PRIORITY_LIST
:TE_QUORUM_LIST); t->nsync = n; t->name = $5->str; t->quoted = $5->quoted; t->nest = $3->nest + 1; t->elems = $3;
t->next= NULL; $$ = t;} ;
opt_prefix:PREFIX{ $$ = $1; }| { $$ = "1"; };
opt_groupname:':' NAME{ $$ = $2; }| /* EMPTY */{ appname *name = (appname *)malloc(sizeof(name)); name->str[0]
=0; name->quoted = 0; $$ = name; };
name_list:name_elem{ $$ = $1;}| name_list DELIMITER name_elem{ syncdef *p = $1;
if (p->nest < $3->nest) p->nest = $3->nest; while (p->next) p = p->next; p->next = $3; $$ = $1;};
name_elem:name_elem_nonlist{ $$ = $1; }| group_list{ $$ = $1;};
name_elem_nonlist:NAME{ syncdef *t = (syncdef*)malloc(sizeof(syncdef)); t->type = TE_HOSTNAME; t->nsync = 0;
t->name= strdup($1->str); t->quoted = $1->quoted; t->nest = 0; t->elems = NULL; t->next = NULL; $$ = t; };
%%
void
indent(int level)
{ int i;
for (i = 0 ; i < level * 2 ; i++) putc(' ', stdout);
}
void
dump_def(syncdef *def, int level)
{ char *typelabel[] = {"HOSTNAME", "PRIO_LIST", "QUORUM_LIST"}; syncdef *p;
if (def == NULL) return; switch (def->type) { case TE_HOSTNAME: indent(level); puts("{");
indent(level+1); printf("TYPE: %s\n", typelabel[def->type]); indent(level+1); printf("HOSTNAME: %s\n",
def->name); indent(level+1); printf("QUOTED: %s\n", def->quoted ? "Yes" : "No"); indent(level+1);
printf("NEST:%d\n", def->nest); indent(level); puts("}"); if (def->next) dump_def(def->next,
level); break; case TE_PRIORITY_LIST: case TE_QUORUM_LIST: indent(level); printf("TYPE: %s\n",
typelabel[def->type]); indent(level); printf("GROUPNAME: %s\n", def->name ? def->name : "<none>");
indent(level); printf("NSYNC: %d\n", def->nsync); indent(level); printf("NEST: %d\n", def->nest);
indent(level); puts("CHILDREN {"); level++; dump_def(def->elems, level); level--;
indent(level); puts("}"); if (def->next) dump_def(def->next, level); break; default:
fprintf(stderr,"Unknown type?\n"); exit(1); } level--;
}
int main(void)
{
// yydebug = 1;if (!yyparse()) dump_def(defroot, 0);
}
void yyerror(const char* s)
{ fprintf(stderr, "Error: %s\n", s);
}
#include "lex.yy.c"
В списке pgsql-hackers по дате отправления: