From 0741fa56d0fc97d422b35d2380dea1bac0f70b7c Mon Sep 17 00:00:00 2001
From: Yoni Fogel <yoni@tokutek.com>
Date: Mon, 19 Nov 2007 15:52:02 +0000
Subject: [PATCH] Support for reading DB_CONFIG

git-svn-id: file:///svn/tokudb@641 c7de825b-a66e-492c-adef-691d508d4ae1
---
 src/ydb.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 134 insertions(+), 1 deletion(-)

diff --git a/src/ydb.c b/src/ydb.c
index 8c09527c3cd..14c05239d24 100644
--- a/src/ydb.c
+++ b/src/ydb.c
@@ -12,6 +12,7 @@
 #include <sys/fcntl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <ctype.h>
 #include <unistd.h>
 
 #include "cachetable.h"
@@ -87,6 +88,132 @@ static inline int db_env_opened(DB_ENV *env) {
     return env->i->cachetable != 0;
 }
 
+
+static int db_env_parse_config_line(DB_ENV* dbenv, char *command, char *value) {
+    int r;
+    
+    if (!strcmp(command, "set_data_dir")) {
+        r = dbenv->set_data_dir(dbenv, value);
+    }
+    else if (!strcmp(command, "set_tmp_dir")) {
+        r = dbenv->set_tmp_dir(dbenv, value);
+    }
+    else if (!strcmp(command, "set_lg_dir")) {
+        r = dbenv->set_lg_dir(dbenv, value);
+    }
+    else r = -1;
+        
+    return r;
+}
+
+static int db_env_read_config(DB_ENV *env, u_int32_t flags) {
+    const char* config_name = "DB_CONFIG";
+    char* full_name = NULL;
+    char* linebuffer = NULL;
+    int buffersize;
+    FILE* fp = NULL;
+    int r = 0;
+    int r2 = 0;
+    char* command;
+    char* value;
+    
+    full_name = construct_full_name(env->i->dir, config_name);
+    if (full_name == 0) {
+        r = ENOMEM;
+        goto cleanup;
+    }
+    if ((fp = fopen(full_name, "r")) == NULL) {
+        //Config file is optional.
+        if (errno == ENOENT) {
+            r = EXIT_SUCCESS;
+            goto cleanup;
+        }
+        r = errno;
+        goto cleanup;
+    }
+    //Read each line, applying configuration parameters.
+    //After ignoring leading white space, skip any blank lines
+    //or comments (starts with #)
+    //Command contains no white space.  Value may contain whitespace.
+    int linenumber;
+    int ch = '\0';
+    BOOL eof = FALSE;
+    char* temp;
+    char* end;
+    int index = 0;
+    
+    buffersize = 1<<10; //1KB
+    linebuffer = toku_malloc(buffersize);
+    if (!linebuffer) {
+        r = ENOMEM;
+        goto cleanup;
+    }
+    for (linenumber = 0; !eof; linenumber++) {
+        /* Read a single line. */
+        while (TRUE) {
+            if ((ch = getc(fp)) == EOF) {
+                eof = TRUE;
+                if (ferror(fp)) {
+                    /* Throw away current line and print warning. */
+                    r = errno;
+                    goto readerror;
+                }
+                break;
+            }
+            if (ch == '\n') break;
+            if (index + 1 >= buffersize) {
+                //Double the buffer.
+                buffersize *= 2;
+                linebuffer = toku_realloc(linebuffer, buffersize);
+                if (!linebuffer) {
+                    r = ENOMEM;
+                    goto cleanup;
+                }
+            }
+            linebuffer[index++] = ch;
+        }
+        linebuffer[index] = '\0';
+        end = &linebuffer[index];
+
+        /* Separate the line into command/value */
+        command = linebuffer;
+        //Strip leading spaces.
+        while (isspace(*command) && command < end) command++;
+        //Find end of command.
+        temp = command;
+        while (!isspace(*temp) && temp < end) temp++;
+        *temp++ = '\0'; //Null terminate command.
+        value = temp;
+        //Strip leading spaces.
+        while (!isspace(*value) && value < end) value++;
+        if (value < end) {
+            //Strip trailing spaces.
+            temp = end;
+            while (isspace(*(temp-1))) temp--;
+            //Null terminate value.
+            *temp = '\0';
+        }
+        //Parse the line.
+        
+        if (strlen(command) == 0 || command[0] == '#') continue; //Ignore Comments.
+        r = db_env_parse_config_line(env, command, value < end ? value : "");
+        if (r != 0) goto parseerror;
+    }
+    if (0) {
+readerror:
+        env->err(env, r, "Error reading from DB_CONFIG:%d.\n", linenumber);
+    }
+    if (0) {
+parseerror:
+        env->err(env, r, "Error parsing DB_CONFIG:%d.\n", linenumber);
+    }
+cleanup:
+    if (full_name) toku_free(full_name);
+    if (linebuffer) toku_free(linebuffer);
+    if (fp) r2 = fclose(fp);
+    return r ? r : r2;
+}
+
 int __toku_db_env_open(DB_ENV * env, const char *home, u_int32_t flags, int mode) {
     int r;
 
@@ -112,6 +239,11 @@ int __toku_db_env_open(DB_ENV * env, const char *home, u_int32_t flags, int mode
         env->i->dir = NULL;
         return r;
     }
+    if ((r = db_env_read_config(env, flags)) != 0) {
+        fprintf(stderr, "FOO FOO FOO \n");
+        goto died1;
+    }
+
     env->i->open_flags = flags;
     env->i->open_mode = mode;
 
@@ -487,7 +619,7 @@ int __toku_db_open(DB * db, DB_TXN * txn, const char *fname, const char *dbname,
 
     r = brt_open(db->i->brt, db->i->full_fname, dbname, flags & DB_CREATE, 
                  db->dbenv->i->cachetable,
-		 txn ? txn->i->tokutxn : NULL_TXN);
+		         txn ? txn->i->tokutxn : NULL_TXN);
     if (r != 0)
         goto error_cleanup;
 
@@ -516,6 +648,7 @@ int __toku_db_remove(DB * db, const char *fname, const char *dbname, u_int32_t f
     int r2;
     char ffull[PATH_MAX];
 
+    //TODO: DB_ENV->set_data_dir should affect db_remove's directories.
     //TODO: Verify DB* db not yet opened
 
     if (dbname) {
-- 
2.30.9