diff options
| author | Anand Avati <avati@gluster.com> | 2010-06-07 12:37:34 +0000 | 
|---|---|---|
| committer | Anand V. Avati <avati@dev.gluster.com> | 2010-06-07 11:58:50 -0700 | 
| commit | 79241696fbdebe2583298f12cbaee068ce60c655 (patch) | |
| tree | 42e60d351e328fa34f17242c6c3359a8c01e8fa3 /libglusterfs/src/graph.y | |
| parent | c4ebd25a176d6d51d702b1009e261c3c27237a48 (diff) | |
dynamic volume changes for graph replacement
Signed-off-by: Anand V. Avati <avati@blackhole.gluster.com>
Signed-off-by: Anand V. Avati <avati@dev.gluster.com>
BUG: 971 (dynamic volume management)
URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=971
Diffstat (limited to 'libglusterfs/src/graph.y')
| -rw-r--r-- | libglusterfs/src/graph.y | 651 | 
1 files changed, 651 insertions, 0 deletions
diff --git a/libglusterfs/src/graph.y b/libglusterfs/src/graph.y new file mode 100644 index 00000000000..4ac07660f95 --- /dev/null +++ b/libglusterfs/src/graph.y @@ -0,0 +1,651 @@ +/* +   Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> +   This file is part of GlusterFS. + +   GlusterFS is free software; you can redistribute it and/or modify +   it under the terms of the GNU General Public License as published +   by the Free Software Foundation; either version 3 of the License, +   or (at your option) any later version. + +   GlusterFS is distributed in the hope that it will be useful, but +   WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with this program.  If not, see +   <http://www.gnu.org/licenses/>. +*/ + + +%token VOLUME_BEGIN VOLUME_END OPTION NEWLINE SUBVOLUME ID WHITESPACE COMMENT TYPE STRING_TOK + +%{ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include "xlator.h" +#include "logging.h" + +static int new_volume (char *name); +static int volume_type (char *type); +static int volume_option (char *key, char *value); +static int volume_sub (char *sub); +static int volume_end (void); +static void sub_error (void); +static void type_error (void); +static void option_error (void); + +#define YYSTYPE char * +#define GF_CMD_BUFFER_LEN (8 * GF_UNIT_KB) + +int yyerror (const char *); +int yylex (); +%} + + +%% +VOLUMES: VOLUME | VOLUMES VOLUME; + +VOLUME: VOLUME_HEADER VOLUME_DATA VOLUME_FOOTER; +VOLUME_HEADER: VOLUME_BEGIN WORD {if (new_volume ($2) == -1) { YYABORT; }}; +VOLUME_FOOTER: VOLUME_END {if (volume_end () == -1) { YYABORT; }}; + +VOLUME_DATA: TYPE_LINE OPTIONS_LINE SUBVOLUME_LINE OPTIONS_LINE | +              TYPE_LINE SUBVOLUME_LINE OPTIONS_LINE | +              TYPE_LINE OPTIONS_LINE SUBVOLUME_LINE | +              TYPE_LINE SUBVOLUME_LINE | +              TYPE_LINE OPTIONS_LINE | +              OPTIONS_LINE SUBVOLUME_LINE OPTIONS_LINE | /* error case */ +              OPTIONS_LINE;  /* error case */ + +TYPE_LINE: TYPE WORD {if (volume_type ($2) == -1) { YYABORT; }} | TYPE { type_error(); YYABORT; }; + +SUBVOLUME_LINE: SUBVOLUME WORDS | SUBVOLUME { sub_error (); YYABORT; }; + +OPTIONS_LINE: OPTION_LINE | OPTIONS_LINE OPTION_LINE; + +OPTION_LINE: OPTION WORD WORD {if (volume_option ($2, $3) == -1) { YYABORT; }} | +	     OPTION WORD { option_error (); YYABORT; } | +	     OPTION { option_error (); YYABORT; }; + +WORDS: WORD {if (volume_sub ($1) == -1) {YYABORT; }} | WORDS WORD { if (volume_sub ($2) == -1) { YYABORT; }}; +WORD: ID | STRING_TOK ; +%% + +xlator_t *curr; +glusterfs_graph_t *construct; + + +static void +type_error (void) +{ +        extern int yylineno; + +        gf_log ("parser", GF_LOG_ERROR, +                "Volume %s, before line %d: Please specify volume type", +                curr->name, yylineno); +        return; +} + + +static void +sub_error (void) +{ +        extern int yylineno; + +        gf_log ("parser", GF_LOG_ERROR, +                "Volume %s, before line %d: Please specify subvolumes", +                curr->name, yylineno); +        return; +} + + +static void +option_error (void) +{ +        extern int yylineno; + +        gf_log ("parser", GF_LOG_ERROR, +                "Volume %s, before line %d: Please specify " +                "option <key> <value>", +                curr->name, yylineno); +        return; +} + + +static int +new_volume (char *name) +{ +        extern int   yylineno; +        xlator_t    *trav = NULL; +        int          ret = 0; + +        if (!name) { +                gf_log ("parser", GF_LOG_DEBUG, +			"Invalid argument name: '%s'", name); +                ret = -1; +                goto out; +        } + +        if (curr) { +                gf_log ("parser", GF_LOG_ERROR, +                        "new volume (%s) defintion in line %d unexpected", +                        name, yylineno); +                ret = -1; +                goto out; +        } + +        curr = (void *) GF_CALLOC (1, sizeof (*curr), +                                   gf_common_mt_xlator_t); + +        if (!curr) { +                gf_log ("parser", GF_LOG_ERROR, "Out of memory"); +                ret = -1; +                goto out; +        } + +        trav = construct->first; + +        while (trav) { +                if (!strcmp (name, trav->name)) { +                        gf_log ("parser", GF_LOG_ERROR, +				"Line %d: volume '%s' defined again", +                                yylineno, name); +                        ret = -1; +                        goto out; +                } +                trav = trav->next; +        } + +        curr->name = gf_strdup (name); +        if (!curr->name) { +                GF_FREE (curr); +                ret = -1; +                goto out; +        } + +        curr->options = get_new_dict (); + +        if (!curr->options) { +                GF_FREE (curr->name); +                GF_FREE (curr); +                ret = -1; +                goto out; +        } + +        curr->next = construct->first; +        if (curr->next) +                curr->next->prev = curr; + +        curr->graph = construct; + +        construct->first = curr; + +        construct->xl_count++; + +        gf_log ("parser", GF_LOG_TRACE, "New node for '%s'", name); + +out: +        GF_FREE (name); + +        return ret; +} + + +static int +volume_type (char *type) +{ +        extern int   yylineno; +        int32_t      ret = 0; + +        if (!type) { +                gf_log ("parser", GF_LOG_DEBUG, "Invalid argument type"); +                ret = -1; +                goto out; +        } + +        ret = xlator_set_type (curr, type); +        if (ret) { +                gf_log ("parser", GF_LOG_ERROR, +                        "Volume '%s', line %d: type '%s' is not valid or " +			"not found on this machine", +                        curr->name, yylineno, type); +                ret = -1; +                goto out; +        } + +        gf_log ("parser", GF_LOG_TRACE, "Type:%s:%s", curr->name, type); + +out: +        GF_FREE (type); + +        return 0; +} + + +static int +volume_option (char *key, char *value) +{ +        extern int  yylineno; +        int         ret = 0; +        char       *set_value = NULL; + +        if (!key || !value){ +                gf_log ("parser", GF_LOG_ERROR, "Invalid argument"); +                ret = -1; +                goto out; +        } + +        set_value = gf_strdup (value); +	ret = dict_set_dynstr (curr->options, key, set_value); + +        if (ret == 1) { +                gf_log ("parser", GF_LOG_ERROR, +                        "Volume '%s', line %d: duplicate entry " +			"('option %s') present", +                        curr->name, yylineno, key); +                ret = -1; +                goto out; +        } + +        gf_log ("parser", GF_LOG_TRACE, "Option:%s:%s:%s", +                curr->name, key, value); + +out: +        GF_FREE (key); +        GF_FREE (value); + +        return 0; +} + + +static int +volume_sub (char *sub) +{ +        extern int       yylineno; +        xlator_t        *trav = NULL; +        xlator_list_t   *xlchild = NULL; +        xlator_list_t   *tmp = NULL; +        xlator_list_t   *xlparent = NULL; +        int              ret = 0; + +        if (!sub) { +                gf_log ("parser", GF_LOG_ERROR, "Invalid subvolumes argument"); +                ret = -1; +                goto out; +        } + +        trav = construct->first; + +        while (trav) { +                if (!strcmp (sub,  trav->name)) +                        break; +                trav = trav->next; +        } + +        if (!trav) { +                gf_log ("parser", GF_LOG_ERROR, +                        "Volume '%s', line %d: subvolume '%s' is not defined " +			"prior to usage", +                        curr->name, yylineno, sub); +                ret = -1; +                goto out; +        } + +        if (trav == curr) { +                gf_log ("parser", GF_LOG_ERROR, +                        "Volume '%s', line %d: has '%s' itself as subvolume", +                        curr->name, yylineno, sub); +                ret = -1; +                goto out; +        } + +        xlparent = (void *) GF_CALLOC (1, sizeof (*xlparent), +                                       gf_common_mt_xlator_list_t); + +        if (!xlparent) { +                gf_log ("parser", GF_LOG_ERROR, "Out of memory"); +                ret = -1; +                goto out; +        } + +        xlparent->xlator = curr; + +        tmp = trav->parents; +        if (tmp == NULL) { +                trav->parents = xlparent; +        } else { +                while (tmp->next) +                        tmp = tmp->next; +                tmp->next = xlparent; +        } + +        xlchild = (void *) GF_CALLOC (1, sizeof(*xlchild), +                                      gf_common_mt_xlator_list_t); +        if (!xlchild) { +                gf_log ("parser", GF_LOG_ERROR, "Out of memory"); +                ret = -1; +                goto out; +        } + +        xlchild->xlator = trav; + +        tmp = curr->children; +        if (tmp == NULL) { +                curr->children = xlchild; +        } else { +                while (tmp->next) +                        tmp = tmp->next; +                tmp->next = xlchild; +        } + +        gf_log ("parser", GF_LOG_TRACE, "child:%s->%s", curr->name, sub); + +out: +        GF_FREE (sub); + +        return 0; +} + + +static int +volume_end (void) +{ +        if (!curr->fops) { +                gf_log ("parser", GF_LOG_ERROR, +                        "\"type\" not specified for volume %s", curr->name); +                return -1; +        } +        gf_log ("parser", GF_LOG_TRACE, "end:%s", curr->name); + +        curr = NULL; +        return 0; +} + + +int +yywrap () +{ +        return 1; +} + + +int +yyerror (const char *str) +{ +        extern char  *yytext; +        extern int    yylineno; + +        if (curr && curr->name) { +                if (!strcmp (yytext, "volume")) { +                        gf_log ("parser", GF_LOG_ERROR, +                                "'end-volume' not defined for volume '%s'", +				curr->name); +                } else if (!strcmp (yytext, "type")) { +                        gf_log ("parser", GF_LOG_ERROR, +                                "line %d: duplicate 'type' defined for " +				"volume '%s'", +                                yylineno, curr->name); +                } else if (!strcmp (yytext, "subvolumes")) { +                        gf_log ("parser", GF_LOG_ERROR, +                                "line %d: duplicate 'subvolumes' defined for " +				"volume '%s'", +                                yylineno, curr->name); +                } else if (curr) { +                        gf_log ("parser", GF_LOG_ERROR, +                                "syntax error: line %d (volume '%s'): \"%s\"" +				"\nallowed tokens are 'volume', 'type', " +				"'subvolumes', 'option', 'end-volume'()", +                                yylineno, curr->name, +				yytext); +                } else { +                        gf_log ("parser", GF_LOG_ERROR, +                                "syntax error: line %d (just after volume " +				"'%s'): \"%s\"\n(%s)", +                                yylineno, curr->name, +				yytext, +                                "allowed tokens are 'volume', 'type', " +				"'subvolumes', 'option', 'end-volume'"); +                } +        } else { +                gf_log ("parser", GF_LOG_ERROR, +                        "syntax error in line %d: \"%s\" \n" +                        "(allowed tokens are 'volume', 'type', " +			"'subvolumes', 'option', 'end-volume')\n", +                        yylineno, yytext); +        } + +        return -1; +} + + +static int +execute_cmd (char *cmd, char **result, size_t size) +{ +	FILE       *fpp = NULL; +	int         i = 0; +        int         status = 0; +	int         character = 0; +	char       *buf = *result; + +	fpp = popen (cmd, "r"); +	if (!fpp) { +		gf_log ("parser", GF_LOG_ERROR, "%s: failed to popen", cmd); +		return -1; +	} + +	while ((character = fgetc (fpp)) != EOF) { +		if (i == size) { +			size *= 2; +			buf = *result = GF_REALLOC (*result, size); +                } + +		buf[i++] = character; +	} + +	if (i > 0) { +		i--; +		buf[i] = '\0'; +	} + +	status = pclose (fpp); +	if (status == -1 || !WIFEXITED (status) || +	    ((WEXITSTATUS (status)) != 0)) { +		i = -1; +		buf[0] = '\0'; +	} + +	return i; +} + + +static int +preprocess (FILE *srcfp, FILE *dstfp) +{ +	int     ret = 0; +        int     i = 0; +	char   *cmd = NULL; +        char   *result = NULL; +	size_t  cmd_buf_size = GF_CMD_BUFFER_LEN; +	char    escaped = 0; +        char    in_backtick = 0; +	int     line = 1; +        int     column = 0; +        int     backtick_line = 0; +        int     backtick_column = 0; +        int     character = 0; + + +	fseek (srcfp, 0L, SEEK_SET); +	fseek (dstfp, 0L, SEEK_SET); + +	cmd = GF_CALLOC (cmd_buf_size, 1, +                         gf_common_mt_char); +        if (cmd == NULL) { +                gf_log ("parser", GF_LOG_ERROR, "Out of memory"); +                return -1; +        } + +	result = GF_CALLOC (cmd_buf_size * 2, 1, +                            gf_common_mt_char); +        if (result == NULL) { +                GF_FREE (cmd); +                gf_log ("parser", GF_LOG_ERROR, "Out of memory"); +                return -1; +        } + +	while ((character = fgetc (srcfp)) != EOF) { +		if ((character == '`') && !escaped) { +			if (in_backtick) { +				cmd[i] = '\0'; +				result[0] = '\0'; + +				ret = execute_cmd (cmd, &result, +                                                   2 * cmd_buf_size); +				if (ret < 0) { +					ret = -1; +					goto out; +				} +				fwrite (result, ret, 1, dstfp); +			} else { +				i = 0; +				cmd[i] = '\0'; + +				backtick_column = column; +				backtick_line = line; +			} + +			in_backtick = !in_backtick; +		} else { +			if (in_backtick) { +				if (i == cmd_buf_size) { +					cmd_buf_size *= 2; +					cmd = GF_REALLOC (cmd, cmd_buf_size); +                                        if (cmd == NULL) { +                                                return -1; +                                        } + +					result = GF_REALLOC (result, +                                                             2 * cmd_buf_size); +                                        if (result == NULL) { +                                                GF_FREE (cmd); +                                                return -1; +                                        } +                                } + +				cmd[i++] = character; +                        } else { +				fputc (character, dstfp); +                        } +                } + +		if (character == '\\') { +			escaped = !escaped; +		} else { +			escaped = 0; +                } + +		if (character == '\n') { +			line++; +			column = 0; +		} else { +			column++; +		} +        } + +	if (in_backtick) { +		gf_log ("parser", GF_LOG_ERROR, +			"Unterminated backtick in volume specfication file at line (%d), column (%d).", +			line, column); +                ret = -1; +	} + +out: +	fseek (srcfp, 0L, SEEK_SET); +	fseek (dstfp, 0L, SEEK_SET); +	GF_FREE (cmd); +	GF_FREE (result); + +	return ret; +} + + +extern FILE *yyin; + +glusterfs_graph_t * +glusterfs_graph_new () +{ +        glusterfs_graph_t *graph = NULL; + +        graph = GF_CALLOC (1, sizeof (*graph), +                           gf_common_mt_glusterfs_graph_t); +        if (!graph) +                return NULL; + +        INIT_LIST_HEAD (&graph->list); + +        gettimeofday (&graph->dob, NULL); + +        return graph; +} + + +glusterfs_graph_t * +glusterfs_graph_construct (FILE *fp) +{ +        int                ret = 0; +        glusterfs_graph_t *graph = NULL; +	FILE              *tmp_file = NULL; + +        graph = glusterfs_graph_new (); +        if (!graph) +                return NULL; + +	tmp_file = tmpfile (); + +	if (tmp_file == NULL) { +		gf_log ("parser", GF_LOG_ERROR, +			"cannot create temparory file"); + +                glusterfs_graph_destroy (graph); +		return NULL; +	} + +	ret = preprocess (fp, tmp_file); +	if (ret < 0) { +		gf_log ("parser", GF_LOG_ERROR, +			"parsing of backticks failed"); + +                glusterfs_graph_destroy (graph); +		fclose (tmp_file); +		return NULL; +	} + +        yyin = tmp_file; + +        construct = graph; + +        ret = yyparse (); + +        construct = NULL; + +	fclose (tmp_file); + +        if (ret == 1) { +                gf_log ("parser", GF_LOG_DEBUG, +			"parsing of volfile failed, please review it " +			"once more"); + +                glusterfs_graph_destroy (graph); +                return NULL; +        } + +        return graph; +} +  | 
