nfs-ganesha 1.4

posixdb_connect.c

Go to the documentation of this file.
00001 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; -*-
00002  * vim:expandtab:shiftwidth=4:tabstop=4:
00003  */
00004 #ifdef HAVE_CONFIG_H
00005 #include "config.h"
00006 #endif
00007 #include "posixdb_internal.h"
00008 
00009 #include <ctype.h>
00010 #include <string.h>
00011 #include "abstract_mem.h"
00012 
00013 /* forward declaration of function */
00014 fsal_posixdb_status_t fsal_posixdb_initPreparedQueries(fsal_posixdb_conn * p_conn);
00015 
00016 /* read a password in a file */
00017 static int ReadPasswordFromFile(char *filename, char *password)
00018 {
00019   FILE *passfile;
00020   char errstr[1024];
00021   int rc;
00022 
00023   passfile = fopen(filename, "r");
00024   if(!passfile)
00025     {
00026       rc = errno;
00027       strerror_r(rc, errstr, 1024);
00028       LogCrit(COMPONENT_FSAL, "Error openning password file '%s' : %s", filename, errstr);
00029       return rc;
00030     }
00031   fscanf(passfile, "%1023s", password);
00032   if(ferror(passfile))
00033     {
00034       rc = errno;
00035       strerror_r(rc, errstr, 1024);
00036       LogCrit(COMPONENT_FSAL, "Error reading password file '%s' : %s", filename, errstr);
00037       fclose(passfile);
00038       return rc;
00039     }
00040   fclose(passfile);
00041   return 0;
00042 }
00043 
00045 fsal_posixdb_status_t fsal_posixdb_connect(fsal_posixdb_conn_params_t * dbparams,
00046                                            fsal_posixdb_conn ** p_conn)
00047 {
00048   my_bool reconnect = 1;
00049   char password[1024] = "";
00050   int rc;
00051   unsigned int port;
00052 
00053   /* read password from password file */
00054   rc = ReadPasswordFromFile(dbparams->passwdfile, password);
00055   if(rc)
00056     ReturnCodeDB(ERR_FSAL_POSIXDB_CMDFAILED, rc);
00057 
00058   /* resolve the port number */
00059   if(dbparams->port[0] != '\0')
00060     {
00061       if(!isdigit(dbparams->port[0]))
00062         {
00063           LogCrit(COMPONENT_FSAL,
00064                "Numerical value expected for database port number (invalid value: %s)",
00065                dbparams->port);
00066           ReturnCodeDB(ERR_FSAL_POSIXDB_CMDFAILED, 0);
00067         }
00068 
00069       port = atoi(dbparams->port);
00070     }
00071   else
00072     port = 0;
00073 
00074   *p_conn = gsh_malloc(sizeof(fsal_posixdb_conn));
00075   if(*p_conn == NULL)
00076     {
00077       LogCrit(COMPONENT_FSAL, "ERROR: failed to allocate memory");
00078       ReturnCodeDB(ERR_FSAL_POSIXDB_NO_MEM, errno);
00079     }
00080 
00081   /* Init client structure */
00082   if(mysql_init(&(*p_conn)->db_conn) == NULL)
00083     {
00084       gsh_free(*p_conn);
00085       LogCrit(COMPONENT_FSAL, "ERROR: failed to create MySQL client struct");
00086       ReturnCodeDB(ERR_FSAL_POSIXDB_BADCONN, errno);
00087     }
00088 #if ( MYSQL_VERSION_ID >= 50013 )
00089   /* set auto-reconnect option */
00090   mysql_options(&(*p_conn)->db_conn, MYSQL_OPT_RECONNECT, &reconnect);
00091 #else
00092   /* older version */
00093   (*p_conn)->db_conn->reconnect = 1;
00094 #endif
00095 
00096   /* connect to server */
00097   if(!mysql_real_connect(&(*p_conn)->db_conn, dbparams->host, dbparams->login,
00098                          password, dbparams->dbname, port, NULL, 0))
00099     {
00100       int rc;
00101       LogCrit(COMPONENT_FSAL, "Failed to connect to MySQL server: Error: %s",
00102                  mysql_error(&(*p_conn)->db_conn));
00103       rc = mysql_errno(&(*p_conn)->db_conn);
00104       gsh_free(*p_conn);
00105       ReturnCodeDB(ERR_FSAL_POSIXDB_BADCONN, rc);
00106     }
00107 
00108   /* Note [MySQL reference guide]: mysql_real_connect()  incorrectly reset
00109    * the MYSQL_OPT_RECONNECT  option to its default value before MySQL 5.1.6.
00110    * Therefore, prior to that version, if you want reconnect to be enabled for
00111    * each connection, you must call mysql_options() with the MYSQL_OPT_RECONNECT
00112    * option after each call to mysql_real_connect().
00113    */
00114 #if (MYSQL_VERSION_ID >= 50013) && (MYSQL_VERSION_ID < 50106)
00115   /* reset auto-reconnect option */
00116   mysql_options(&(*p_conn)->db_conn, MYSQL_OPT_RECONNECT, &reconnect);
00117 #endif
00118 
00119   LogEvent(COMPONENT_FSAL, "Logged on to database sucessfully");
00120 
00121   /* Create prepared statements */
00122   return fsal_posixdb_initPreparedQueries(*p_conn);
00123 
00124 }
00125 
00126 fsal_posixdb_status_t fsal_posixdb_disconnect(fsal_posixdb_conn * p_conn)
00127 {
00128   mysql_close(&p_conn->db_conn);
00129   gsh_free(p_conn);
00130   ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0);
00131 }
00132 
00133 fsal_posixdb_status_t fsal_posixdb_initPreparedQueries(fsal_posixdb_conn * p_conn)
00134 {
00135   int rc;
00136   unsigned int retry = 1;
00137 
00138   static const char *buildonepath_query =
00139       "SELECT CONCAT('/',name), handleidparent, handletsparent FROM Parent WHERE handleid=? AND handlets=?";
00140 
00141   /* @TODO  retry = lmgr_config.connect_retry_min; */
00142 
00143   /* create prepared statements */
00144 
00145   do
00146     {
00147       /* First create the prepared statement */
00148       p_conn->stmt_tab[BUILDONEPATH] = mysql_stmt_init(&p_conn->db_conn);
00149 
00150       /* retry if connection to server failed */
00151       if((p_conn->stmt_tab[BUILDONEPATH] == NULL)
00152          && db_is_retryable(mysql_errno(&p_conn->db_conn)))
00153         {
00154           LogCrit(COMPONENT_FSAL, "Connection to database lost in %s()... Retrying in %u sec.",
00155                      __FUNCTION__, retry);
00156           sleep(retry);
00157           retry *= 2;
00158           /*if ( retry > lmgr_config.connect_retry_max )
00159              retry = lmgr_config.connect_retry_max; */
00160         }
00161       else
00162         break;
00163 
00164     }
00165   while(1);
00166 
00167   if(!p_conn->stmt_tab[BUILDONEPATH])
00168     ReturnCodeDB(ERR_FSAL_POSIXDB_CMDFAILED, mysql_errno(&p_conn->db_conn));
00169 
00170   /* another retry loop */
00171   /* @TODO retry = lmgr_config.connect_retry_min; */
00172   retry = 1;
00173 
00174   do
00175     {
00176       /* prepare the request */
00177       rc = mysql_stmt_prepare(p_conn->stmt_tab[BUILDONEPATH], buildonepath_query,
00178                               strlen(buildonepath_query));
00179 
00180       if(rc && db_is_retryable(mysql_stmt_errno(p_conn->stmt_tab[BUILDONEPATH])))
00181         {
00182           LogCrit(COMPONENT_FSAL, "Connection to database lost in %s()... Retrying in %u sec.",
00183                      __FUNCTION__, retry);
00184           sleep(retry);
00185           retry *= 2;
00186           /*if ( retry > lmgr_config.connect_retry_max )
00187              retry = lmgr_config.connect_retry_max; */
00188 
00189         }
00190       else
00191         break;
00192 
00193     }
00194   while(1);
00195 
00196   if(rc)
00197     {
00198       LogCrit(COMPONENT_FSAL, "Failed to create prepared statement: Error: %s (query='%s')",
00199                  mysql_stmt_error(p_conn->stmt_tab[BUILDONEPATH]), buildonepath_query);
00200       mysql_stmt_close(p_conn->stmt_tab[BUILDONEPATH]);
00201       ReturnCodeDB(ERR_FSAL_POSIXDB_CMDFAILED, rc);
00202     }
00203 
00204   ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0);
00205 }