Re: Support for N synchronous standby servers - take 2

Поиск
Список
Период
Сортировка
От Kyotaro HORIGUCHI
Тема Re: Support for N synchronous standby servers - take 2
Дата
Msg-id 20160224.173757.38720623.horiguchi.kyotaro@lab.ntt.co.jp
обсуждение исходный текст
Ответ на Re: Support for N synchronous standby servers - take 2  (Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>)
Ответы Re: Support for N synchronous standby servers - take 2  (Masahiko Sawada <sawada.mshk@gmail.com>)
Список pgsql-hackers
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,
> 
> At Mon, 22 Feb 2016 22:52:29 +0900, Fujii Masao <masao.fujii@gmail.com> wrote in
<CAHGQGwENujogaQvcc=u0tffNfFGtwXNb1yFcphdTYCJdG1_j1A@mail.gmail.com>
> > Thanks for updating the patch!
> > 
> > When I changed s_s_names to 'hoge*' and reloaded the configuration file,
> > the server crashed unexpectedly with the following error message.
> > This is obviously a bug.
> > 
> >     FATAL:  syntax error
> 
> I had a glance on the lexer part in the new patch.  It'd be
> better to design the lexer from the beginning according to the
> required behavior.
> 
> The documentation for the syntax is saying as the following,
> 
> http://www.postgresql.org/docs/current/static/runtime-config-logging.html
> 
> > application_name (string)
> > 
> > The application_name can be any string of less than NAMEDATALEN
> > characters (64 characters in a standard build). <snip> Only
> > printable ASCII characters may be used in the application_name
> > value. Other characters will be replaced with question marks (?).
> 
> And according to what some functions mentioned so far do, totally
> an application_name is treated as follwoing, I suppose.
> 
> - check_application_name() currently allows [\x20-\x7e], which
>   differs from the definition of the SQL identifiers.
> 
> - SplitIdentifierString() and syncrep code
> 
>   - allows any byte except a double quote in double-quoted
>    representation. A double-quote just after a delimiter can open
>    quoted representation.
> 
>   - Non-quoted name can contain any character including double
>     quotes except ',' and white spaces.
> 
>   - The syncrep code does case-insensitive matching with the
>    application_name.
> 
> 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?

The sources can be compiles by the following commandline.

$ bison -v test.y; flex -l test.l; gcc -g -DYYDEBUG=1 -DYYERROR_VERBOSE -o ltest test.tab.c

and it makes the output like following.

[horiguti@drain tmp]$ echo '123[1,3,<x>3{a,b,e},4,*]' | ./ltest

TYPE: PRIO_LIST
GROUPNAME: <none>
NSYNC: 123
NEST: 2
CHILDREN { {   TYPE: HOSTNAME   HOSTNAME: 1   QUOTED: No   NEST: 1 } {   TYPE: HOSTNAME   HOSTNAME: 3   QUOTED: No
NEST:0 } TYPE: QUORUM_LIST GROUPNAME: x NSYNC: 3 NEST: 1 CHILDREN {   {     TYPE: HOSTNAME     HOSTNAME: a     QUOTED:
No    NEST: 0   }   {     TYPE: HOSTNAME     HOSTNAME: b     QUOTED: No     NEST: 0   }   {     TYPE: HOSTNAME
HOSTNAME:e     QUOTED: No     NEST: 0   } } {   TYPE: HOSTNAME   HOSTNAME: 4   QUOTED: No   NEST: 0 } {   TYPE:
HOSTNAME  HOSTNAME: *   QUOTED: No   NEST: 0 }
 
}


regards,

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
%{
#include <stdio.h>
#include <stdlib.h>

%}

%option noyywrap

%x DQNAME
%x APPNAME

space            [ \t\n\r\f]
whitespace        {space}+

dquote            \"
app_name_chars    [\x21-\x2b\x2d-\x3b\x3d\x3f-\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}
self    [\[\]\{\}<>]
%%
{xdstart} { BEGIN(DQNAME); }
<DQNAME>{xdstop} { BEGIN(INITIAL); }
<DQNAME>{app_name_dq} { static char name[64]; int i, j;
 for (i = j = 0 ; j < 63 && yytext[i] ; i++, j++) {   if (yytext[i] == '"')   {    if (yytext[i+1] == '"')
name[j]= '"';    else        fprintf(stderr, "illegal quote escape");    i++;}   else    name[j] = yytext[i];
 
 } name[j] = 0;
 yylval.str = strdup(name); return QUOTED_NAME;
}
{app_name_start} { BEGIN(APPNAME); yyless(0);}
<APPNAME>{app_name} {char *p;
yylval.str = strdup(yytext);for (p = yylval.str ; *p ; p++){    if (*p >= 'A' && *p <= 'Z')        *p = *p + ('a' -
'A');}BEGIN(INITIAL);returnNAME_OR_NUMBER;
 
}
{delimiter} { return DELIMITER;}
{self} { return yytext[0];}

%%

//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;
void yyerror(const char *s);
int yylex(void);
int depth = 0;
syncdef *defroot = NULL;
syncdef *curr = NULL;
%}


%union
{ char *str; int    ival; syncdef *syncdef;
}
%token <str> NAME_OR_NUMBER
%token <str> QUOTED_NAME
%token DELIMITER

%type <syncdef> qlist plist name_list name_elem name_elem_nonlist
%type <syncdef> old_list s_s_names list_maybe_with_name
%type <str> group_name

%%
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;}| list_maybe_with_name{ 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;};
list_maybe_with_name:plist{$$ = $1;}| qlist{$$ = $1;}| '<' group_name '>' plist{    $4->name = $2;    $$ = $4;}| '<'
group_name'>' qlist{    $4->name = $2;    $$ = $4;};
 

group_name:NAME_OR_NUMBER{ $$ = strdup($1); }| QUOTED_NAME{ $$ = strdup($1); };

plist: NAME_OR_NUMBER '[' name_list ']'{  syncdef *t;  int n = atoi($1);  if (n == 0)  {    yyerror("prefix number is 0
ornon-integer");    return 1;  }  if ($3->nest > 1)  {    yyerror("Up to 2 levels of 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;      }  }  t =
(syncdef*)malloc(sizeof(syncdef)); t->type = TE_PRIORITY_LIST;  t->nsync = n;  t->name = NULL;  t->quoted = 0;  t->nest
=$3->nest + 1;  t->elems = $3;  t->next = NULL;  $$ = t;}  ;
 

qlist: NAME_OR_NUMBER '{' name_list '}'{  syncdef *t;  int n = atoi($1);  if (n == 0)  {    yyerror("prefix number is 0
ornon-integer");    return 1;  }  if ($3->nest > 1)  {    yyerror("Up to 2 levels of nesting is supported");    return
1; }
 
  for (t = $3 ; t ; t = t->next)  {      if (t->type == TE_HOSTNAME && strcmp(t->name, "*") == 0)      {
yyerror("\"*\"is not allowed in quorum list");          return 1;      }  }              t =
(syncdef*)malloc(sizeof(syncdef)); t->type = TE_QUORUM_LIST;  t->nsync = n;  t->name = NULL;  t->quoted = 0;  t->nest =
$3->nest+ 1;  t->elems = $3;  t->next = NULL;  $$ = t;}
 
;

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;   }| list_maybe_with_name{  $$ = $1;};

name_elem_nonlist:NAME_OR_NUMBER{  syncdef *t = (syncdef*)malloc(sizeof(syncdef));  t->type = TE_HOSTNAME;  t->nsync =
0; t->name = strdup($1);  t->quoted = 0;  t->nest = 0;  t->elems = NULL;  t->next = NULL;  $$ = t;   }| QUOTED_NAME{
syncdef*t = (syncdef*)malloc(sizeof(syncdef));  t->type = TE_HOSTNAME;  t->nsync = 0;  t->name = strdup($1);  t->quoted
=1;  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 по дате отправления:

Предыдущее
От: Amit Langote
Дата:
Сообщение: Re: Declarative partitioning
Следующее
От: Masahiko Sawada
Дата:
Сообщение: Re: Support for N synchronous standby servers - take 2