CVS User Account cvsuser
Fri Sep 24 19:51:52 PDT 2004
Log Message:
-----------
Ok it's finaly here, a slon config file.  There are no command line argument chages, so this should be a transparent dropin.  I'll be following this up with some documentation and the like RSN(tm).

Modified Files:
--------------
    slony1-engine/src/slon:
        Makefile (r1.21 -> r1.22)
        misc.c (r1.11 -> r1.12)
        remote_worker.c (r1.60 -> r1.61)
        slon.c (r1.28 -> r1.29)
        slon.h (r1.37 -> r1.38)
        sync_thread.c (r1.11 -> r1.12)

Added Files:
-----------
    slony1-engine/src/slon:
        conf-file.l (r1.1)
        confoptions.c (r1.1)
        confoptions.h (r1.1)
        misc.h (r1.1)

-------------- next part --------------
--- /dev/null
+++ src/slon/misc.h
@@ -0,0 +1,26 @@
+#ifndef _MISC_H_
+#define _MISC_H_
+/* ----------
+ * Functions in misc.c
+ * ----------
+ */
+#include "config.h"
+#include "c.h"
+
+typedef enum {
+        SLON_FATAL,
+        SLON_ERROR,
+        SLON_WARN,
+        SLON_CONFIG,
+        SLON_INFO,
+        SLON_DEBUG1,
+        SLON_DEBUG2,
+        SLON_DEBUG3,
+        SLON_DEBUG4
+} SlonLogLevel;
+
+extern void             slon_log(SlonLogLevel level, char * fmt, ...);
+
+extern int              slon_scanint64(char *str, int64 *result);
+
+#endif
--- /dev/null
+++ src/slon/confoptions.h
@@ -0,0 +1,208 @@
+#ifndef _CONFOPTIONS_H_
+#define _CONFOPTIONS_H_
+
+#include "c.h"
+
+
+void InitializeConfOptions(void);
+
+bool set_config_option(const char *name, const char *value);
+
+extern double real_placeholder;
+extern char *string_placeholder;
+
+
+extern int vac_frequency;
+extern int slon_log_level;
+extern int sync_interval;
+extern int sync_interval_timeout;
+
+extern int sync_group_maxsize;
+
+bool logpid;
+bool logtimestamp;
+
+
+enum config_type
+{
+        SLON_C_BOOL,
+        SLON_C_INT,
+        SLON_C_REAL,
+        SLON_C_STRING
+};
+
+struct config_generic
+{
+        /* constant fields, must be set correctly in initial value: */
+        const char *name;
+        const char *short_desc;
+        const char *long_desc;
+        enum config_type vartype;       /* type of variable (set only at startup) */
+};
+
+
+struct config_int
+{
+	struct config_generic gen;
+	/* these fields must be set correctly in initial value: */
+	/* (all but reset_val are constants) */
+	int	*variable;
+        int	default_val;
+        int     min;
+        int     max;
+};
+
+struct config_bool
+{
+        struct config_generic gen;
+        /* these fields must be set correctly in initial value: */
+        /* (all but reset_val are constants) */
+        bool	*variable;
+        bool    default_val;
+};
+
+struct config_real
+{
+        struct config_generic gen;
+        /* these fields must be set correctly in initial value: */
+        /* (all but reset_val are constants) */
+        double	*variable;
+        double  default_val;
+        double  min;
+        double  max;
+};
+
+struct config_string
+{
+        struct config_generic gen;
+        /* these fields must be set correctly in initial value: */
+        /* (all are constants) */
+        char		**variable;
+        const char	*default_val;
+};
+
+
+
+static struct config_int ConfigureNamesInt[] =
+{
+        {
+                {
+                        (const char *)"vac_frequency",                                                                /* conf name */
+                        gettext_noop("Sets how many cleanup cyclse to run before a vacum is done"),    /* short desc */
+                        gettext_noop("Sets how many cleanup cyclse to run before a vacum is done"),    /* long desc */
+                        SLON_C_INT                                                                      /* config type */
+                },
+                &vac_frequency,                                                                         /* var name */
+                3,                                                                                      /* default val */
+                0,                                                                                      /* min val */
+                100                                                                                     /* max val */
+        },
+	{
+		{
+			(const char *)"log_level",
+			gettext_noop("debug log level"),
+			gettext_noop("debug log level"),
+			SLON_C_INT
+		},
+		&slon_log_level,
+		4,
+		0,
+		4
+	},
+	{
+		{
+			(const char *)"sync_interval",
+			gettext_noop("sync even interval"),
+			gettext_noop("sync even interval in ms"),
+			SLON_C_INT			
+		},
+		&sync_interval,
+		100,
+		10,
+		60000
+	},
+	{
+		{
+			(const char *)"sync_interval_timeout",
+			gettext_noop("sync interval time out"),
+			gettext_noop("sync interval time out"),
+			SLON_C_INT
+		},
+		&sync_interval_timeout,
+		1000,
+		0,
+		120000
+	},
+	{
+		{
+			(const char *)"sync_group_maxsize",
+			gettext_noop("sync group"),
+			gettext_noop("sync group"),
+			SLON_C_INT
+		},
+		&sync_group_maxsize,
+		6,
+		0,
+		100
+	},
+
+        NULL
+};
+static struct config_int ConfigureNamesBool[] =
+{
+        {
+                {
+                        (const char *)"log_pid",                                                             /* conf name */
+                        gettext_noop("place holder"),                                                   /* short desc */
+                        gettext_noop("place holder"),                                                   /* long desc */
+                        SLON_C_BOOL                                                                     /* config type */
+                },
+                &logpid,                                                                      /* var_name */
+                false                                                                                    /* default_value */
+        },
+        {
+		{
+			(const char *)"log_timestamp",
+			gettext_noop("place holder"),
+			gettext_noop("place holder"),
+			SLON_C_BOOL
+		},
+		&logtimestamp,
+		true
+	},
+	NULL
+};
+
+static struct config_int ConfigureNamesReal[] =
+{
+        {
+                {
+                        (const char *)"real_placeholder",                                                             /* conf name */
+                        gettext_noop("place holder"),                                                   /* short desc */
+                        gettext_noop("place holder"),                                                   /* long desc */
+                        SLON_C_REAL                                                                     /* config type */
+                },
+                &real_placeholder,                                                                      /* var_name */
+                0.0,                                                                                    /* default val */
+                0.0,                                                                                    /* min_value */
+                1.0                                                                                     /* max value */
+        },
+        NULL
+};
+
+static struct config_int ConfigureNamesString[] =
+{
+        {
+                {
+                        (const char *)"string_placeholder",                                                           /* conf name */
+                        gettext_noop("place holder"),                                                   /* short desc */
+                        gettext_noop("place holder"),                                                   /* long desc */
+                        SLON_C_STRING                                                                   /* config type */
+                },
+                &string_placeholder,                                                                    /* var_name */
+                "default"                                                                               /* default value */
+        },
+	NULL
+};
+
+#endif
Index: remote_worker.c
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slon/remote_worker.c,v
retrieving revision 1.60
retrieving revision 1.61
diff -Lsrc/slon/remote_worker.c -Lsrc/slon/remote_worker.c -u -w -r1.60 -r1.61
--- src/slon/remote_worker.c
+++ src/slon/remote_worker.c
@@ -199,7 +199,7 @@
 static struct node_confirm_status  *node_confirm_tail = NULL;
 pthread_mutex_t						node_confirm_lock = PTHREAD_MUTEX_INITIALIZER;
 
-int		sync_group_maxsize = 6;
+int		sync_group_maxsize;
 
 
 /* ----------
Index: sync_thread.c
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slon/sync_thread.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -Lsrc/slon/sync_thread.c -Lsrc/slon/sync_thread.c -u -w -r1.11 -r1.12
--- src/slon/sync_thread.c
+++ src/slon/sync_thread.c
@@ -32,8 +32,8 @@
  * Global variables
  * ----------
  */
-int		sync_interval = 10000;
-int		sync_interval_timeout = 60000;
+int		sync_interval;
+int		sync_interval_timeout;
 
 
 /* ----------
Index: slon.h
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slon/slon.h,v
retrieving revision 1.37
retrieving revision 1.38
diff -Lsrc/slon/slon.h -Lsrc/slon/slon.h -u -w -r1.37 -r1.38
--- src/slon/slon.h
+++ src/slon/slon.h
@@ -13,7 +13,9 @@
 #ifndef SLON_H_INCLUDED
 #define SLON_H_INCLUDED
 
+
 #include "config.h"
+#include "misc.h"
 
 #define SLON_MEMDEBUG	1
 
@@ -52,6 +54,8 @@
 } SlonThreadStatus;
 
 
+extern bool logpid;
+
 /* ----------
  * In memory structures for cluster configuration
  * ----------
@@ -492,27 +496,5 @@
  */
 extern int		slon_log_level;
 
-/* ----------
- * Functions in misc.c
- * ----------
- */
-typedef enum {
-	SLON_FATAL,
-	SLON_ERROR,
-	SLON_WARN,
-	SLON_CONFIG,
-	SLON_INFO,
-	SLON_DEBUG1,
-	SLON_DEBUG2,
-	SLON_DEBUG3,
-	SLON_DEBUG4
-} SlonLogLevel;
-
-extern void		slon_log(SlonLogLevel level, char * fmt, ...);
-
-extern int		slon_scanint64(char *str, int64 *result);
-
-
-
 #endif /*  SLON_H_INCLUDED */
 
Index: misc.c
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slon/misc.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -Lsrc/slon/misc.c -Lsrc/slon/misc.c -u -w -r1.11 -r1.12
--- src/slon/misc.c
+++ src/slon/misc.c
@@ -27,11 +27,14 @@
 #include "libpq-fe.h"
 #include "c.h"
 
+#include "confoptions.h"
 #include "slon.h"
 
 
-int		slon_log_level = SLON_INFO;
+extern int		slon_log_level;
 
+extern bool		logpid;
+extern bool		logtimestamp;
 
 static pthread_mutex_t	log_mutex = PTHREAD_MUTEX_INITIALIZER;
 
@@ -88,9 +91,20 @@
 		}
 	}
 
+	sprintf(outbuf, "");
+	
+	if (logtimestamp == true)
+	{
 	strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S %Z", localtime(&stamp_time));
+		sprintf(outbuf, "%s ", time_buf);
+	}
+
+	if (logpid == true)
+	{
+		sprintf(outbuf, "%s[%d] ", outbuf, slon_pid);
+	}
+	sprintf(outbuf, "%s%-6.6s ",outbuf, level_c);
 
-	sprintf(outbuf, "%-6.6s [%s] ", level_c, time_buf);
 	off = strlen(outbuf);
 
 	while(vsnprintf(&outbuf[off], outsize - off, fmt, ap) >= outsize - off)
--- /dev/null
+++ src/slon/conf-file.l
@@ -0,0 +1,338 @@
+/* Scanner for slon config file */
+
+%{
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+#include <pthread.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "misc.h"
+#include "confoptions.h"
+
+
+#define CONFIG_FILENAME "./slon.conf"
+
+static unsigned ConfigFileLineno;
+
+enum {
+        SLON_ID = 1,
+        SLON_STRING = 2,
+        SLON_INTEGER = 3,
+        SLON_REAL = 4,
+        SLON_EQUALS = 5,
+        SLON_UNQUOTED_STRING = 6,
+        SLON_QUALIFIED_ID = 7,
+        SLON_EOL = 99,
+        SLON_FERROR = 100
+};
+
+#define YY_USER_INIT (ConfigFileLineno = 1)
+
+/* prototype, so compiler is happy with our high warnings setting */
+int SLON_yylex(void);
+char *SLON_scanstr(char *);
+%}
+
+%option 8bit
+%option never-interactive
+%option nodefault
+%option nounput
+%option noyywrap
+
+SIGN            ("-"|"+")
+DIGIT           [0-9]
+HEXDIGIT        [0-9a-fA-F]
+
+INTEGER         {SIGN}?({DIGIT}+|0x{HEXDIGIT}+)
+
+EXPONENT        [Ee]{SIGN}?{DIGIT}+
+REAL            {SIGN}?{DIGIT}*"."{DIGIT}*{EXPONENT}?
+
+LETTER          [A-Za-z_\200-\377]
+LETTER_OR_DIGIT [A-Za-z_0-9\200-\377]
+
+ID              {LETTER}{LETTER_OR_DIGIT}*
+QUALIFIED_ID    {ID}"."{ID}
+
+UNQUOTED_STRING {LETTER}({LETTER_OR_DIGIT}|[-._:/])*
+STRING          \'([^'\n]|\\.)*\'
+
+%%
+
+\n              ConfigFileLineno++; return SLON_EOL;
+[ \t\r]+        /* eat whitespace */
+#.*$            /* eat comment */
+
+{ID}            return SLON_ID;
+{QUALIFIED_ID}  return SLON_QUALIFIED_ID;
+{STRING}        return SLON_STRING;
+{UNQUOTED_STRING} return SLON_UNQUOTED_STRING;
+{INTEGER}       return SLON_INTEGER;
+{REAL}          return SLON_REAL;
+=               return SLON_EQUALS;
+
+.               return SLON_FERROR;
+
+%%
+
+struct name_value_pair
+{
+        char       *name;
+        char       *value;
+        struct name_value_pair *next;
+};
+
+/*
+ * Free a list of name/value pairs, including the names and the values
+ */
+static void
+free_name_value_list(struct name_value_pair * list)
+{
+        struct name_value_pair *item;
+
+        item = list;
+        while (item)
+        {
+                struct name_value_pair *save;
+
+                save = item->next;
+                free(item->name);
+                free(item->value);
+                free(item);
+                item = save;
+        }
+}
+
+void ProcessConfigFile(const char *filename)
+{
+	int token, parse_state;
+	char *opt_name, *opt_value;
+	int elevel;
+	struct name_value_pair *item, *head, *tail;
+	FILE * fp;
+
+	elevel = SLON_ERROR;
+
+	/*
+	 * Open the conf file
+	 */
+	if (filename == NULL)
+	{
+		fp = fopen(CONFIG_FILENAME, "r");
+	}
+	else
+	{
+		fp = fopen(filename, "r");
+	}
+	if (!fp)
+	{
+		/* File not found is fine */
+		if (errno != ENOENT)
+		{
+			slon_log(elevel,"could not open configuration file \"%s\"\n", filename);
+			
+		}
+		return;
+	} 
+
+	/* Ok we have the file, lets parse it */
+
+	yyin = fp;
+	parse_state = 0;
+	head = NULL;
+	tail = head;
+	opt_name = NULL;
+	opt_value = opt_name;
+
+	while (token = yylex())
+	{
+		switch(parse_state)
+		{
+			case 0:
+				if (token == SLON_EOL) /* empty line */
+				{
+					continue;
+				}
+				if (token != SLON_ID && token != SLON_QUALIFIED_ID)
+				{
+					goto parse_error;
+				}
+				opt_name = strdup(yytext);
+				parse_state = 1;
+				break;
+			case 1:
+				/* ignore equals sign */
+				if (token == SLON_EQUALS)
+				{
+					token =  yylex();
+				}
+				if (token != SLON_ID && token != SLON_STRING && token != SLON_INTEGER && token != SLON_REAL && token != SLON_UNQUOTED_STRING)
+				{
+					goto parse_error;
+				}
+				opt_value = strdup(yytext);
+				if (token == SLON_STRING)
+				{
+					memmove(opt_value,opt_value+1,strlen(opt_value)-1);
+					opt_value[strlen(opt_value)-2]='\0';
+					opt_value=SLON_scanstr(opt_value);
+				}
+				parse_state = 2;
+				break;
+			case 2:	/* OEL ? */
+				if (token != SLON_EOL)
+				{
+					 goto parse_error;
+				}
+				item = malloc(sizeof *item);
+				item->name = opt_name;
+				item->value = opt_value;
+
+				if (strcmp(opt_name, "custom_variable_classes") == 0)
+				{
+					item->next = head;
+					head = item;
+					if (!tail)
+					{
+						tail = item;
+					}
+				}
+				else
+				{
+					/* append to list */
+					item->next = NULL;
+					if (!head)
+					{
+						head = item;
+					}
+					else
+					{
+						tail->next = item;
+					}
+					tail = item;
+				}
+			parse_state = 0;
+			break;
+		}
+	}
+
+	fclose(fp);
+
+	for (item = head; item; item=item->next)
+	{
+		if (!set_config_option(item->name, item->value))
+		{
+			goto cleanup_exit;
+		}
+	}
+	for(item = head; item; item=item->next)
+	{
+		set_config_option(item->name, item->value);
+	}
+
+	cleanup_exit:
+		free_name_value_list(head);
+		return;
+
+	parse_error:
+		fclose(fp);
+		free_name_value_list(head);
+		if (token == SLON_EOL)
+		{
+			slon_log(elevel, "syntax error in file \"%s\" line %u, near end of line", filename, ConfigFileLineno - 1);
+		}
+		else
+		{
+			slon_log(elevel, "syntax error in file \"%s\" line %u, near end of line", filename, ConfigFileLineno - 1);
+		}
+}
+
+
+
+
+
+
+
+char *SLON_scanstr(char *s)
+{
+        char       *newStr;
+        int                     len,
+                                i,
+                                j;
+
+        if (s == NULL || s[0] == '\0')
+        {
+                if (s != NULL)
+                        free(s);
+                return strdup("");
+        }
+        len = strlen(s);
+
+        newStr = malloc(len + 1);       /* string cannot get longer */
+        if (newStr == NULL)
+		slon_log(SLON_FATAL, "out of memory");
+
+        for (i = 0, j = 0; i < len; i++)
+        {
+                if (s[i] == '\\')
+                {
+                        i++;
+                        switch (s[i])
+                        {
+                                case 'b':
+                                        newStr[j] = '\b';
+                                        break;
+                                case 'f':
+                                        newStr[j] = '\f';
+                                        break;
+                                case 'n':
+                                        newStr[j] = '\n';
+                                        break;
+                                case 'r':
+                                        newStr[j] = '\r';
+                                        break;
+                                case 't':
+                                        newStr[j] = '\t';
+                                        break;
+                                case '0':
+                                case '1':
+                                case '2':
+                                case '3':
+                                case '4':
+                                case '5':
+                                case '6':
+                                case '7':
+                                        {
+                                                int                     k;
+                                                long            octVal = 0;
+
+                                                for (k = 0;
+                                                         s[i + k] >= '0' && s[i 
++ k] <= '7' && k < 3;
+                                                         k++)
+                                                        octVal = (octVal << 3) +
+ (s[i + k] - '0');
+                                                i += k - 1;
+                                                newStr[j] = ((char) octVal);
+                                        }
+                                        break;
+                                default:
+                                        newStr[j] = s[i];
+                                        break;
+                                }
+                        }                                       /* switch */
+                else
+                        newStr[j] = s[i];
+                j++;
+        }
+        newStr[j] = '\0';
+        free(s);
+        return newStr;
+}
+
--- /dev/null
+++ src/slon/confoptions.c
@@ -0,0 +1,472 @@
+#include <pthread.h>
+#include "libpq-fe.h"
+#include "confoptions.h"
+#include "postgres.h"
+#include "misc.h"
+
+
+static struct config_generic **conf_variables;
+static int      size_conf_variables;
+static int	num_conf_variables;
+
+static int      conf_var_compare(const void *a, const void *b);
+static int      conf_name_compare(const char *namea, const char *nameb);
+
+bool set_config_option(const char *name, const char *value);
+
+
+bool bool_placeholder;
+double real_placeholder;
+char *string_placeholder;
+
+
+
+void build_conf_variables(void)
+{
+	int	size_vars;
+	int	num_vars=0;
+	struct config_generic **conf_vars;
+	int	i;
+
+	for (i = 0; ConfigureNamesBool[i].gen.name; i++)
+	{
+		struct config_bool *conf = &ConfigureNamesBool[i];
+
+		/* Rather than requiring vartype to be filled in by hand, do this: */
+		conf->gen.vartype = SLON_C_BOOL;
+		num_vars++;
+	}
+
+	for (i = 0; ConfigureNamesInt[i].gen.name; i++)
+	{
+		struct config_int *conf = &ConfigureNamesInt[i];
+		conf->gen.vartype = SLON_C_INT;
+		 num_vars++;
+	}
+
+	for (i = 0; ConfigureNamesReal[i].gen.name; i++)
+	{
+		struct config_real *conf = &ConfigureNamesReal[i];
+		conf->gen.vartype = SLON_C_REAL;
+		num_vars++;
+	}
+
+	for (i = 0; ConfigureNamesString[i].gen.name; i++)
+	{
+		struct config_string *conf = &ConfigureNamesString[i];
+		conf->gen.vartype = SLON_C_STRING;
+		num_vars++;
+	}
+
+	size_vars = num_vars + num_vars / 4;
+
+	conf_vars = (struct config_generic **) malloc(size_vars * sizeof(struct config_generic *));
+	if (conf_vars == NULL)
+	{
+		slon_log(FATAL, "malloc failed");
+		return;
+	}
+
+	num_vars = 0;
+
+	for (i = 0; ConfigureNamesBool[i].gen.name; i++)
+	{
+		conf_vars[num_vars++] = &ConfigureNamesBool[i].gen;
+	}
+        for (i = 0; ConfigureNamesInt[i].gen.name; i++)
+        {
+                conf_vars[num_vars++] = &ConfigureNamesInt[i].gen;
+        }
+        for (i = 0; ConfigureNamesReal[i].gen.name; i++)
+        {
+                conf_vars[num_vars++] = &ConfigureNamesReal[i].gen;
+        }
+        for (i = 0; ConfigureNamesString[i].gen.name; i++)
+        {
+                conf_vars[num_vars++] = &ConfigureNamesString[i].gen;
+        }
+
+	if (conf_variables)
+	{
+		free(conf_variables);
+	}
+	conf_variables = conf_vars;
+	num_conf_variables = num_vars;
+	size_conf_variables = size_vars;
+	qsort((void *) conf_variables, num_conf_variables, sizeof(struct config_generic *), conf_var_compare);
+}
+
+
+static bool
+add_conf_variable(struct config_generic * var, int elevel)
+{
+        if (num_conf_variables + 1 >= size_conf_variables)
+        {
+                /*
+                 * Increase the vector by 25%
+                 */
+                int                     size_vars = size_conf_variables + size_conf_variables / 4;
+                struct config_generic **conf_vars;
+
+                if (size_vars == 0)
+                {
+                        size_vars = 100;
+                        conf_vars = (struct config_generic **)
+                                malloc(size_vars * sizeof(struct config_generic *));
+                }
+                else
+                {
+                        conf_vars = (struct config_generic **)
+                                realloc(conf_variables, size_vars * sizeof(struct config_generic *));
+                }
+
+                if (conf_vars == NULL)
+		{
+			slon_log(elevel,"malloc failed");
+                        return false;           /* out of memory */
+		}
+
+                conf_variables = conf_vars;
+                size_conf_variables = size_vars;
+        }
+        conf_variables[num_conf_variables++] = var;
+        qsort((void *) conf_variables, num_conf_variables,
+                  sizeof(struct config_generic *), conf_var_compare);
+        return true;
+}
+
+void InitializeConfOptions(void)
+{
+	int	i;
+	char *env;
+
+	build_conf_variables();
+
+	for (i = 0; i < num_conf_variables; i++)
+	{
+		struct config_generic *gconf = conf_variables[i];
+		
+		switch (gconf->vartype)
+		{
+			case SLON_C_BOOL:
+				{
+					struct config_bool *conf = (struct config_bool *) gconf;
+					*conf->variable = conf->default_val;
+					break;
+				}
+			case SLON_C_INT:
+				{
+					struct config_int *conf = (struct config_int *) gconf;
+					*conf->variable = conf->default_val;
+					break;
+				}
+			case SLON_C_REAL:
+				{
+					struct config_int *conf = (struct config_int *) gconf;
+					*conf->variable = conf->default_val;
+					break;
+				}
+			case SLON_C_STRING:
+				{
+					char	*str;
+					struct config_int *conf = (struct config_int *) gconf;
+					*conf->variable = NULL;
+					str = strdup(conf->default_val);
+					*conf->variable = str;
+					break;
+				}
+		}
+	}
+
+	env = getenv("CLUSTER");
+	if (env != NULL)
+	{
+		set_config_option("cluster_name", env);
+	}
+}	
+
+static bool
+parse_bool(const char *value, bool *result)
+{
+	size_t	len = strlen(value);
+
+	if (strncasecmp(value, "true", len) == 0)
+	{
+		if (result)
+		{
+			*result = true;
+		}
+	}
+	else if (strncasecmp(value, "false", len) == 0)
+	{
+		if (result)
+		{
+			*result = false;
+		}
+	}
+        else if (strncasecmp(value, "yes", len) == 0)
+        {
+                if (result)
+                {
+                        *result = true;
+                }
+        }
+        else if (strncasecmp(value, "no", len) == 0)
+        {
+                if (result)
+                {
+                        *result = false;
+                }
+        }
+        else if (strncasecmp(value, "on", len) == 0)
+        {
+                if (result)
+                {
+                        *result = true;
+                }
+        }
+        else if (strncasecmp(value, "off", len) == 0)
+        {
+                if (result)
+                {
+                        *result = false;
+                }
+        }
+        else if (strncasecmp(value, "1", len) == 0)
+        {
+                if (result)
+                {
+                        *result = true;
+                }
+        }
+        else if (strncasecmp(value, "o", len) == 0)
+        {
+                if (result)
+                {
+                        *result = false;
+                }
+        }
+	else
+	{
+		return false;
+	}
+	return true;
+}
+
+/*
+ * Try to parse value as an integer.  The accepted formats are the
+ * usual decimal, octal, or hexadecimal formats.  If the string parses
+ * okay, return true, else false.  If result is not NULL, return the
+ * value there.
+ */
+static bool
+parse_int(const char *value, int *result)
+{
+        long            val;
+        char       *endptr;
+
+        errno = 0;
+        val = strtol(value, &endptr, 0);
+
+        if (endptr == value || *endptr != '\0' || errno == ERANGE
+#ifdef HAVE_LONG_INT_64
+        /* if long > 32 bits, check for overflow of int4 */
+                || val != (long) ((int32) val)
+#endif
+                )
+                return false;
+        if (result)
+                *result = (int) val;
+        return true;
+}
+
+/*
+ * Try to parse value as a floating point constant in the usual
+ * format.      If the value parsed okay return true, else false.  If
+ * result is not NULL, return the semantic value there.
+ */
+static bool
+parse_real(const char *value, double *result)
+{
+        double          val;
+        char       *endptr;
+
+        errno = 0;
+        val = strtod(value, &endptr);
+        if (endptr == value || *endptr != '\0' || errno == ERANGE)
+                return false;
+        if (result)
+                *result = val;
+        return true;
+}
+
+
+static struct config_generic *find_option(const char *name, int elevel)
+{
+	const char *dot;
+	const char **key = &name;
+	struct config_generic **res;
+	int	i;
+
+	res = (struct config_generic **) 
+		bsearch((void *) &key,
+		(void *) conf_variables,
+		num_conf_variables,
+		sizeof(struct config_generic *),
+		conf_var_compare);
+	if (res)
+		return *res;
+}
+
+static int
+conf_var_compare(const void *a, const void *b)
+{
+        struct config_generic *confa = *(struct config_generic **) a;
+        struct config_generic *confb = *(struct config_generic **) b;
+
+        return conf_name_compare(confa->name, confb->name);
+}
+
+static int
+conf_name_compare(const char *namea, const char *nameb)
+{
+        /*
+         * The temptation to use strcasecmp() here must be resisted, because
+         * the array ordering has to remain stable across setlocale() calls.
+         * So, build our own with a simple ASCII-only downcasing.
+         */
+        while (*namea && *nameb)
+        {
+                char            cha = *namea++;
+                char            chb = *nameb++;
+
+                if (cha >= 'A' && cha <= 'Z')
+                        cha += 'a' - 'A';
+                if (chb >= 'A' && chb <= 'Z')
+                        chb += 'a' - 'A';
+                if (cha != chb)
+                        return cha - chb;
+        }
+        if (*namea)
+                return 1;                               /* a is longer */
+        if (*nameb)
+                return -1;                              /* b is longer */
+        return 0;
+}
+
+
+bool set_config_option(const char *name, const char *value)
+{
+  struct config_generic *record;
+  int elevel;
+
+  elevel = SLON_WARN;
+
+  record = find_option(name, elevel);
+
+  if (record == NULL)
+  {
+    slon_log(elevel, "unrecognized configuration parameter \"%s\"\n", name);
+    return false;
+  }
+
+  switch (record->vartype)
+  {
+    case SLON_C_BOOL:
+	{
+		struct config_bool *conf = (struct config_bool *) record;
+		bool	newval;
+		if (value)
+		{
+			if (!parse_bool(value, &newval))
+			{
+				slon_log(elevel, "parameter \"%s\" requires a Boolean value\n", name);
+				return false;
+			}
+		}
+		else
+		{
+			slon_log(elevel, "parameter \"%s\"\n", name );
+		}
+
+		*conf->variable = newval;
+
+		break;
+	}
+  case SLON_C_INT:
+	{
+		struct config_int *conf = (struct config_int *) record;
+		int newval;
+		if (value)
+		{
+			if (!parse_int(value, &newval))
+			{
+				slon_log(elevel, "parameter \"%s\" requires a integer value\n", name);
+				return false;
+			}
+			if (newval < conf->min || newval > conf->max)
+			{
+				slon_log(elevel, "%d is outside the valid range for parameter \"%s\" (%d .. %d)\n",
+					 newval, name, conf->min, conf->max);
+				return false;
+			}
+		}
+		else
+		{
+			slon_log(elevel, "parameter \"%s\"\n", name );
+		}
+		*conf->variable = newval;
+		break;
+	}
+  case SLON_C_REAL:
+	{
+		struct config_real *conf = (struct config_real *) record;
+		double newval;
+
+		if (value)
+		{
+			if (!parse_real(value, &newval))
+			{
+				slon_log(elevel, "parameter \"%s\" requires a numeric value\n", name);
+				return false;
+			}
+			if (newval < conf->min || newval > conf->max)
+			{
+				slon_log(elevel, "%g is outside the valid range for parameter \"%s\" (%g .. %g)\n",
+					newval, name, conf->min, conf->max);
+				return false;
+			}
+		}
+		else
+		{
+			slon_log(elevel, "parameter \"%s\"\n", name );
+		}
+		*conf->variable = newval;
+		break;
+	}
+  case SLON_C_STRING:
+	{
+		struct config_string *conf = (struct config_string *) record;
+		char *newval;
+
+		if (value)
+		{
+			newval = strdup(value);
+			if (newval == NULL)
+			{
+				return false;
+			}
+
+		}
+		else
+		{
+			slon_log(elevel, "parameter \"%s\"\n", name );
+			free(newval);
+		}
+		*conf->variable = newval;
+		break;
+	}
+  }
+  return true;
+}
+
Index: slon.c
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slon/slon.c,v
retrieving revision 1.28
retrieving revision 1.29
diff -Lsrc/slon/slon.c -Lsrc/slon/slon.c -u -w -r1.28 -r1.29
--- src/slon/slon.c
+++ src/slon/slon.c
@@ -27,7 +27,7 @@
 #include "c.h"
 
 #include "slon.h"
-
+#include "confoptions.h"
 
 /* ----------
  * Global data
@@ -52,6 +52,8 @@
 static char *const	   *main_argv;
 static void				sigalrmhandler(int signo);
 
+int slon_log_level;
+
 
 /* ----------
  * main
@@ -73,62 +75,39 @@
 	int			group_size_set = 0;
 
 
-	while ((c = getopt(argc, argv, "d:s:t:g:c:h")) != EOF)
+        InitializeConfOptions();
+
+
+	while ((c = getopt(argc, argv, "f:d:s:t:g:c:f:h")) != EOF)
 	{
 		switch(c)
 		{
-			case 'd':	slon_log_level = strtol(optarg, NULL, 10);
-						if (slon_log_level < 0 || slon_log_level > 4)
-						{
-							fprintf(stderr, "illegal debug level %d\n",
-									slon_log_level);
-							errors++;
-						}
-						slon_log_level += SLON_INFO;
+			case 'f':
+				ProcessConfigFile(optarg);
 						break;
 
-			case 's':	sync_interval = strtol(optarg, NULL, 10);
-						if (sync_interval < 100 || sync_interval > 60000)
-						{
-							fprintf(stderr, "sync interval must be between 100 and 60000 ms\n");
-							errors++;
-						}
-						else if (!group_size_set)
-						{
-							sync_group_maxsize = 60000 / sync_interval;
-							if (sync_group_maxsize > 100)
-								sync_group_maxsize = 100;
-						}
-
+			case 'd':	
+				set_config_option("log_level", optarg);
 						break;
 
-			case 't':	sync_interval_timeout = strtol(optarg, NULL, 10);
-						if (sync_interval < 0)
-						{
-							fprintf(stderr, "sync interval must be >= 0\n");
-							errors++;
-						}
+			case 's':	
+				set_config_option("sync_group_maxsize", optarg);
+				break;
 
+			case 't':	
+				set_config_option("sync_interval_timeout", optarg);
 						break;
 
-			case 'g':	sync_group_maxsize = strtol(optarg, NULL, 10);
-						if (sync_group_maxsize < 1 || sync_group_maxsize > 100)
-						{
-							fprintf(stderr, "sync group size must be between 1 and 100 ms\n");
-							errors++;
-						}
-						group_size_set = 1;
+			case 'g':
+				set_config_option("sync_group_maxsize", optarg);
 						break;
 
-			case 'c':	vac_frequency = strtol(optarg, NULL, 10);
-						if (vac_frequency < 0 || vac_frequency > 10)
-						{
-							fprintf(stderr, "Vaccum frequency must be between 0 (disable) and 10\n");
-							errors++;
-						}
+			case 'c':
+				set_config_option("vac_frequency", optarg);
 						break;
 
-                        case 'h':       errors++;
+                        case 'h':
+				errors++;
                                                 break;
 
 			default:	fprintf(stderr, "unknown option '%c'\n", c);
@@ -136,7 +115,18 @@
 						break;
 		}
 	}
-
+#if 0
+fprintf( stderr, "config:   vac_frequency %d\n"
+                 "          sync_group_maxsize %d\n"
+                 "          sync_interval_timeout %d\n"
+                 "          sync_interval %d\n"
+                 "          slon_log_level %d\n"
+		 "          log_pid %d\n"
+                 "	    log_timestamp %d\n",
+		 vac_frequency, sync_group_maxsize, sync_interval_timeout,
+		 sync_interval, slon_log_level, logpid, logtimestamp);
+fflush(NULL);
+#endif
 	if (argc - optind != 2)
 		errors++;
 
@@ -150,6 +140,7 @@
 		fprintf(stderr, "    -t <milliseconds>     SYNC interval timeout (default 60000)\n");
 		fprintf(stderr, "    -g <num>              maximum SYNC group size (default 6)\n");
 		fprintf(stderr, "    -c <num>		   how often to vaccum in cleanup cycles\n");
+		fprintf(stderr, "    -f <filename>	   slon configuration file\n");
 		return 1;
 	}
 
Index: Makefile
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slon/Makefile,v
retrieving revision 1.21
retrieving revision 1.22
diff -Lsrc/slon/Makefile -Lsrc/slon/Makefile -u -w -r1.21 -r1.22
--- src/slon/Makefile
+++ src/slon/Makefile
@@ -36,6 +36,8 @@
 	cleanup_thread.o	\
 	scheduler.o			\
 	dbutils.o			\
+	conf-file.o	\
+	confoptions.o	\
 	misc.o
 
 DISTFILES = Makefile README $(wildcard *.c) $(wildcard *.h)
@@ -59,6 +61,11 @@
 scheduler.o:		scheduler.c slon.h
 slon.o:				slon.c slon.h
 sync_thread.o:		sync_thread.c slon.h
+conf-file.o:		conf-file.c slon.h confoptions.h
+confoptions.o:		confoptions.c slon.h confoptions.h
+
+conf-file.c:		conf-file.l
+	$(FLEX) -o$(@) $<
 
 clean distclean maintainer-clean:
 	rm -f $(ALL) $(OBJS)


More information about the Slony1-commit mailing list