config_db.c

Go to the documentation of this file.
00001 #include "config_db_private.h"
00002 
00003 #include "ac_app_context.h"
00004 #include "application_config.h"
00005 #include "db_creation.h"
00006 #include "er_errors.h"
00007 #include "lua_cl2.h"
00008 #include "sqlite_cl2.h"
00009 
00010 #include "common/threading_mutex.h"
00011 
00012 #include <string.h>
00013 
00014 /** Config database file.
00015  */
00016 #define CONFIGDB_BASENAME "config.db"
00017 #define CONFIGDB_DIR CONFIG_DIR
00018 #define CONFIGDB_FILE (CONFIGDB_DIR DIR_SEP CONFIGDB_BASENAME)
00019 
00020 static const char create_tables_sql[] =
00021   "create table configuration (name TEXT UNIQUE, value TEXT);";
00022 
00023 static gboolean create_config_db(GError** error)
00024 {
00025   return create_database(CONFIGDB_DIR,
00026        CONFIGDB_FILE,
00027        create_tables_sql,
00028        error);
00029 }
00030 
00031 static gboolean ensure_config_db_created(GError** error)
00032 {
00033   assert_error_unset(error);
00034 
00035   if (!g_file_test(CONFIGDB_FILE, G_FILE_TEST_EXISTS)) {
00036     logg("file '%s' does not exist", CONFIGDB_FILE);
00037     return create_config_db(error);
00038   }
00039 
00040   return TRUE;
00041 }
00042 
00043 struct _ConfigDb
00044 {
00045   sqlite3* db;
00046 
00047   sqlite3_stmt* getStmt;
00048   sqlite3_stmt* setStmt;
00049 
00050 #if THREAD_SAFETY
00051   pthread_mutex_t mutex;
00052 #endif
00053 };
00054 
00055 static gboolean prepare_sql_statements(ConfigDb *self, GError **error)
00056 {
00057   if (sqlite_prepare(self->db, "select * from configuration where name = ? limit 1;", -1, &(self->getStmt), 0)) { goto fail; }
00058   // The OR REPLACE clause here states how to do conflict resolution
00059   // if the uniqueness constraints (in our case for "name") would be
00060   // violated.
00061   if (sqlite_prepare(self->db, "insert or replace into configuration (name, value) values (?, ?);", -1, &(self->setStmt), 0)) { goto fail; }
00062   return TRUE;
00063 
00064  fail:
00065   if (error) 
00066     *error = gx_error_new(domain_cl2app, code_database_state_init, "error preparing statements for database '%s': %s (%d)", CONFIGDB_FILE, sqlite3_errmsg(self->db), sqlite3_errcode(self->db));
00067   return FALSE;
00068 }
00069 
00070 #define FINALIZE_SQL_STATEMENT(lvalue) \
00071   if (lvalue) { sqlite3_finalize(lvalue); lvalue = NULL; }
00072 
00073 static void destroy_sql_statements(ConfigDb *self)
00074 {
00075   FINALIZE_SQL_STATEMENT(self->getStmt);
00076   FINALIZE_SQL_STATEMENT(self->setStmt);
00077 }
00078 
00079 static void close_config_db_session(ConfigDb* self)
00080 {
00081   if (self->db) {
00082     destroy_sql_statements(self);
00083 
00084     // Note that prepared statements and BLOB handles must be
00085     // freed separately.
00086     int errCode = sqlite3_close(self->db);
00087 #if __DO_LOGGING__
00088     if (errCode) {
00089       // A close failure is probably a programming error, so we
00090       // shall log it.
00091       logg("sqlite3_close failure %d", errCode);
00092     }
00093 #endif
00094     self->db = NULL;
00095   }
00096 }
00097 
00098 static gboolean open_config_db_session(ConfigDb* self, GError** error)
00099 {
00100   // This still allocates a handle, except for those cases in which
00101   // the memory for the handle cannot be allocated. We can hence get
00102   // an error message if "db" is non-NULL.
00103   int errCode = sqlite3_open(CONFIGDB_FILE, &self->db);
00104   if (errCode) {
00105     if (error)
00106       *error = gx_error_new(domain_cl2app, code_database_open, "error opening database '%s': %s (%d)", CONFIGDB_FILE, sqlite_get_error_string(self->db), errCode);
00107     close_config_db_session(self);
00108     return FALSE;
00109   }
00110 
00111   if (!prepare_sql_statements(self, error)) {
00112     close_config_db_session(self);
00113     return FALSE;
00114   }
00115 
00116   return TRUE;
00117 }
00118 
00119 ConfigDb* ConfigDb_new(GError** error)
00120 {
00121   if (!ensure_config_db_created(error)) {
00122     // If getting this error, do make sure that you have any database
00123     // binary right, statically linked or otherwise.
00124     return NULL;
00125   }
00126 
00127   ConfigDb* self = g_try_new0(ConfigDb, 1);
00128   if (G_UNLIKELY(!self)) {
00129     if (error) *error = gx_error_no_memory;
00130     return NULL;
00131   }
00132 
00133   mutex_init(&self->mutex);
00134 
00135   if (!open_config_db_session(self, error)) {
00136     // If getting this error, do make sure that you have any database
00137     // binary right, statically linked or otherwise.
00138     ConfigDb_destroy(self);
00139     return NULL;
00140   }
00141 
00142   return self;
00143 }
00144   
00145 void ConfigDb_destroy(ConfigDb* self)
00146 {
00147   if (self) {
00148     close_config_db_session(self);
00149     mutex_destroy(&self->mutex);
00150     g_free(self);
00151   }
00152 }
00153 
00154 #define do_nothing ((void)0)
00155 
00156 #define set_sql_error             \
00157   if (error)                \
00158     *error = gx_error_new(domain_cl2app, code_database_command,   \
00159         "ConfigDb database access error: %s (%d)",  \
00160         sqlite3_errmsg(self->db),     \
00161         sqlite3_errcode(self->db));     
00162 
00163 #define handle_sql_error_done { set_sql_error; goto done; }
00164 
00165 #define handle_sql_error_false { set_sql_error; return FALSE; }
00166 
00167 static gchar* db_get(ConfigDb* self, 
00168          const gchar* name,
00169          GError** error)
00170 {
00171   gchar* value = NULL;
00172 
00173   {
00174     if (sqlite3_bind_text(self->getStmt, 1, name, strlen(name), 
00175         SQLITE_STATIC)) {
00176       handle_sql_error_done;
00177     }
00178 
00179     // Upon success we should get either SQLITE_ROW and SQLITE_DONE.
00180     // Anything else we consider an error, since there should be no
00181     // locking issues or anything. Any of a number of error codes
00182     // could be returned, since we are (possibly) using the "v2"
00183     // interface. SQLITE_ROW should mean that we got our (one) row
00184     // of data, and an (immediate) SQLITE_DONE should mean that
00185     // there is no data that matched the request.
00186     int res = sqlite3_step(self->getStmt);
00187     switch (res)
00188       {
00189       case SQLITE_DONE:
00190   {
00191     if (error) *error = new_not_found_error;
00192     sqlite3_reset(self->getStmt);
00193     goto done;
00194   }
00195       case SQLITE_ROW:
00196   {
00197     // "value" will be NULL if there is an OOM error.
00198     value = (gchar *)sqlite3_column_text(self->getStmt, 1);
00199     if (value) { 
00200       value = strdup(value);
00201     }
00202     if (!value) {
00203       if (error) *error = gx_error_no_memory;
00204       sqlite3_reset(self->getStmt);
00205       goto done;
00206     }
00207     break;
00208   }
00209       default: // some error
00210   {
00211     sqlite3_reset(self->getStmt);
00212     handle_sql_error_done;
00213   }
00214       }
00215       
00216     // Note that this does not clear bindings, but we should not
00217     // need to, unless we must later use unbound parameters (which
00218     // are interpreted as NULL); see sqlite3_clear_bindings().
00219     if (sqlite3_reset(self->getStmt)) {
00220       handle_sql_error_done;
00221     }
00222 
00223   done:
00224     do_nothing;
00225   }
00226 
00227   return value;
00228 }
00229 
00230 gchar* ConfigDb_get_generic(ConfigDb* self, 
00231           const gchar* name,
00232           GError** error)
00233 {
00234   gchar* value = NULL;
00235   mutex_synchronized(&self->mutex, value = db_get(self, name, error));
00236   return value;
00237 }
00238 
00239 static gboolean db_set(ConfigDb* self, 
00240            const gchar* name, 
00241            const gchar* value, 
00242            GError** error)
00243 {
00244   assert(value);
00245 
00246   if (!validate_lua_syntax(value, error)) {
00247     return FALSE;
00248   }
00249 
00250   GError* getError = NULL;
00251   gchar* oldValue = db_get(self, name, &getError);
00252   if (!oldValue) {
00253     if (is_not_found_error(getError)) {
00254       g_error_free(getError);
00255     } else {
00256       if (error) *error = getError;
00257       else g_error_free(getError);
00258       return FALSE;
00259     }
00260   }
00261       
00262   if (oldValue) {
00263     if (strcmp(oldValue, value) == 0) {
00264       g_free(oldValue);
00265       return TRUE;
00266     }
00267     g_free(oldValue);
00268   }
00269     
00270   // Update database.
00271   {
00272     if (sqlite3_bind_text(self->setStmt, 1, name, strlen(name), 
00273         SQLITE_STATIC)) {
00274       handle_sql_error_false;
00275     }
00276 
00277     if (sqlite3_bind_text(self->setStmt, 2, value, strlen(value), 
00278         SQLITE_STATIC)) {
00279       sqlite3_reset(self->setStmt);
00280       handle_sql_error_false;
00281     }
00282     
00283     int res = sqlite3_step(self->setStmt);
00284     if (res != SQLITE_DONE) {
00285       sqlite3_reset(self->setStmt);
00286       handle_sql_error_false;
00287     }
00288 
00289     if (sqlite3_reset(self->setStmt)) {
00290       handle_sql_error_false;
00291     }
00292   }
00293     
00294   return TRUE;
00295 }
00296 
00297 gboolean ConfigDb_set_generic(ConfigDb* self, 
00298             const gchar* name, 
00299             const gchar* value, 
00300             GError** error)
00301 {
00302   gboolean success = FALSE;
00303   mutex_synchronized(&self->mutex, success = db_set(self, name, value, error));
00304 
00305   if (success) {
00306     // A question here is; what should we do if the notification should
00307     // fail. Should we perhaps roll back the ConfigDb change? We are not
00308     // doing that, and we consider it a separate issue whether the
00309     // concerned components are actually able to honor the new
00310     // configuration or not.
00311     kr_Controller* kr = ac_global_Controller;
00312     if (!kr_Controller_reconfigure(kr, name, value, error))
00313       return FALSE;
00314   }
00315 
00316   return success;
00317 }
00318 
00319 /**
00320 
00321 config_db.c
00322 
00323 Copyright 2009 Helsinki Institute for Information Technology (HIIT)
00324 and the authors. All rights reserved.
00325 
00326 Authors: Tero Hasu <tero.hasu@hut.fi>
00327 
00328 Permission is hereby granted, free of charge, to any person
00329 obtaining a copy of this software and associated documentation files
00330 (the "Software"), to deal in the Software without restriction,
00331 including without limitation the rights to use, copy, modify, merge,
00332 publish, distribute, sublicense, and/or sell copies of the Software,
00333 and to permit persons to whom the Software is furnished to do so,
00334 subject to the following conditions:
00335 
00336 The above copyright notice and this permission notice shall be
00337 included in all copies or substantial portions of the Software.
00338 
00339 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00340 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00341 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00342 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
00343 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
00344 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00345 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
00346 SOFTWARE.
00347 
00348  **/

ContextLogger2—ContextLogger2 Logger Daemon Internals—Generated on Mon May 2 13:49:52 2011 by Doxygen 1.6.1