Diff for /parser3/src/main/Attic/pa_db_connection.C between versions 1.2 and 1.37

version 1.2, 2001/10/23 12:41:05 version 1.37, 2002/02/08 08:30:15
Line 1 Line 1
 /** @file  /** @file
         Parser: Charset connection implementation.          Parser: sql driver connection implementation.
   
         Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)          Copyright (c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com)
         Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf)          Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
   
         $Id$          $Id$
   
           developed with LIBDB 2.7.4
 */  */
   
 #include "pa_config_includes.h"  #include "pa_config_includes.h"
 #ifdef HAVE_LIBDB  #ifdef DB2
   
 #include "pa_db_connection.h"  #include "pa_db_connection.h"
   #include "pa_db_table.h"
 #include "pa_exception.h"  #include "pa_exception.h"
   #include "pa_threads.h"
   #include "pa_stack.h"
   #include "pa_common.h"
   #include "pa_vtable.h"
   
   // defines
   
   // consts
   
   /// @test increase
   const int DB_CHECKPOINT_MINUTES=1; 
   
   const int EXPIRE_UNUSED_TABLE_SECONDS=60;
   const int CHECK_EXPIRED_TABLES_SECONDS=EXPIRE_UNUSED_TABLE_SECONDS*2;
   
   // callbacks
   
   static void db_paniccall(DB_ENV *dbenv, int error) {
           throw Exception(0, 0, 
                   0, 
                   "db_panic: %s (%d)", 
                   strerror(error), error);
   }
   
   static void db_errcall(const char *, char *buffer) {
           throw Exception(0, 0, 
                   0, 
                   "db_err: %s", 
                   buffer);
   }
   
   static void expire_table(const Hash::Key& key, Hash::Val *& value, void *info) {
           DB_Table *table=static_cast<DB_Table *>(value);
           time_t older_dies=reinterpret_cast<time_t>(info);
   
           if(table->expired(older_dies)) {
                   table->~DB_Table();  value=0;
           }
   }
   
   // DB_Connection
   
   DB_Connection::DB_Connection(Pool& apool, const String& adb_home) : Pooled(apool),
           time_used(0),
           fdb_home(adb_home), used(0),
           table_cache(apool),
           prev_expiration_pass_time(0) {
           //_asm  int 3;
           char DB_DATA_DIR__VALUE[MAX_STRING];
           char DB_TMP_DIR__VALUE[MAX_STRING];
   
           const char *db_home_cstr=fdb_home.cstr(String::UL_FILE_SPEC);
   
           snprintf(DB_DATA_DIR__VALUE, MAX_STRING, "DB_DATA_DIR %s", db_home_cstr);
           snprintf(DB_TMP_DIR__VALUE, MAX_STRING, "DB_TMP_DIR %s", db_home_cstr);
   
           char *db_config[] = {
                   DB_DATA_DIR__VALUE,
                   DB_TMP_DIR__VALUE, 
                   0
           };
   
           u_int32_t flags=
                   (parser_multithreaded?DB_THREAD:0)
                   | DB_CREATE 
                   | DB_INIT_MPOOL;
   
           // prepare dbenv structure
           memset(&dbenv, 0, sizeof(dbenv));
           
           // error handlers
   #if DB_VERSION_MINOR >= 7
           dbenv.db_paniccall=db_paniccall;
   #endif
           dbenv.db_errcall=db_errcall;
   
           // lockdetector flags
           dbenv.lk_detect=DB_LOCK_RANDOM;
   
           // init
           check("db_appinit", &fdb_home, db_appinit(
                   db_home_cstr,
                   db_config, 
                   &dbenv, 
                   flags
                   ));
   }
   
   DB_Connection::~DB_Connection() {
           // close tables
           table_cache.for_each(expire_table, 
                   reinterpret_cast<void *>(time(0)+1/* =future= expire[close] all*/));
           
           // destroy connection data
           check("db_appexit", &fdb_home, db_appexit(&dbenv));
   }
   
   
 void DB_Connection::check(const char *operation, const String *source, int error) {  void DB_Connection::check(const char *operation, const String *source, int error) {
         switch(error) {          switch(error) {
Line 19  void DB_Connection::check(const char *op Line 119  void DB_Connection::check(const char *op
                 // no error                  // no error
                 break;                   break; 
                   
         case DB_KEYEXIST:          default:
                 // DB_KEYEXIST is a "normal" return, so should not be                  if(error<0)
                 // thrown as an error                          throw Exception(0, 0, 
                 break;                                   source, 
                                   "db %s error: %d", 
                                   operation, error);
                   else
                           throw Exception(0, 0, 
                                   source, 
                                   "db %s error: %s (%d)", 
                                   operation, strerror(error), error);
           }
   }
   
         case DB_RUNRECOVERY:  DB_Table_ptr DB_Connection::get_table_ptr(const String& request_file_name, const String *source) {
                 // mark as unsafe, so not to cache it          // first trying to get cached table
                 needs_recovery=true;          DB_Table *result=get_table_from_cache(request_file_name);
                 throw Exception(0, 0,           if(!result) { // no cached table
                         &ffile_spec,                   // make global_file_name C-string on global pool
                         "db %s error, run recovery utility",                   const char *request_file_name_cstr=request_file_name.cstr();
                         operation);                  char *global_file_name_cstr=(char *)malloc(strlen(request_file_name_cstr)+1);
                   strcpy(global_file_name_cstr, request_file_name_cstr);
                   // make global_file_name string on global pool
                   String& global_file_name=*new(this->pool()) String(this->pool(), global_file_name_cstr);
                                   
         default:                  // allocate in global pool 
                 throw Exception(0, 0,                   // associate with services[request]
                         &ffile_spec,                   // NOTE: never freed up!
                         "db %s error: %s (%d)",                   result=new(this->pool()) DB_Table(this->pool(), global_file_name, *this);
                         operation, strerror(error), error);                  // cache it
                   put_table_to_cache(global_file_name, *result);
         }          }
   
           // return auto-it
           return DB_Table_ptr(result);
 }  }
   
 DB_Connection::DB_Connection(Pool& pool, const String& afile_spec, DB_ENV& adbenv) : Pooled(pool),  // table cache
         fdbenv(adbenv),  /// @todo get rid of memory spending Stack [zeros deep inside got accumulated]
         ffile_spec(afile_spec),  DB_Table *DB_Connection::get_table_from_cache(const String& file_name) { 
         fservices_pool(0), db(0), ftid(0), needs_recovery(false),           SYNCHRONIZED;
         time_used(0) {  
 }  
   
 void DB_Connection::connect() {   
         // open  
         DB_INFO dbinfo;  
         memset(&dbinfo, 0, sizeof(dbinfo));  
         check("open/create", &ffile_spec, db_open(  
                 ffile_spec.cstr(String::UL_FILE_SPEC),   
                 PA_DB_ACCESS_METHOD,   
                 DB_CREATE /* used in single thread, no need for |DB_THREAD*/,  
                 0666,   
                 &fdbenv, &dbinfo, &db));  
 }  
 /// @todo this one of reasons of not having ^try for now  
 void DB_Connection::disconnect() {   
         check("close", &ffile_spec, db->close(db, 0/*flags*/));  db=0;   
 }  
   
 ///     @test string pieces [get/put preserve lang]  
 void DB_Connection::put(const String& key, const String& data) {  
         // key  
         const char *cstr_key=key.cstr(String::UL_AS_IS);  
         DBT dbt_key={  
                 (void *)cstr_key,  
                 key.size()  
         };  
   
         // data          maybe_expire_table_cache();
         const char *cstr_data=data.cstr(String::UL_AS_IS);  
         DBT dbt_data={          return static_cast<DB_Table *>(table_cache.get(file_name));
                 (void *)cstr_data,  
                 data.size()  
         };  
         check("put", &key, db->put(db, ftid, &dbt_key, &dbt_data, 0/*flags*/));  
 }  }
   
 String *DB_Connection::get(const String& key) {  void DB_Connection::put_table_to_cache(const String& file_name, DB_Table& table) { 
         // key          SYNCHRONIZED;
         const char *cstr_key=key.cstr(String::UL_AS_IS);  
         DBT dbt_key={  
                 (void *)cstr_key,  
                 key.size()  
         };  
   
         // data          table_cache.put(file_name, &table);
         DBT dbt_data={0}; // must be zeroed  }
         int error=db->get(db, ftid, &dbt_key, &dbt_data, 0/*flags*/);  
         if(error==DB_NOTFOUND)  void DB_Connection::maybe_expire_table_cache() {
                 return 0;          time_t now=time(0);
         else {  
                 check("get", &key, error);          if(prev_expiration_pass_time<now-CHECK_EXPIRED_TABLES_SECONDS) {
                   table_cache.for_each(expire_table, 
                 if(dbt_data.size) {                          reinterpret_cast<void *>(now-EXPIRE_UNUSED_TABLE_SECONDS));
                         char *request_data=(char *)malloc(dbt_data.size);  
                         memcpy(request_data, dbt_data.data, dbt_data.size);                  prev_expiration_pass_time=now;
                         return NEW String(pool(), request_data, dbt_data.size, true/*tainted*/);          }
                 } else  }
                         return NEW String(pool());  
         }                 static void add_table_to_status_table(const Hash::Key& key, Hash::Val *& value, void *info) {
 }          DB_Table *db_table=static_cast<DB_Table *>(value);
           Table& status_table=*static_cast<Table *>(info);
 void DB_Connection::_delete(const String& key) {          Pool& pool=status_table.pool();
         // key  
         const char *cstr_key=key.cstr(String::UL_AS_IS);          Array& row=*new(pool) Array(pool);
         DBT dbt_key={  
                 (void *)cstr_key,          // name
                 key.size()          row+=&db_table->file_name();
         };          // time
           time_t time_stamp=db_table->get_time_used();
           const char *unsafe_time_cstr=ctime(&time_stamp);
           int time_buf_size=strlen(unsafe_time_cstr);
           char *safe_time_buf=(char *)pool.malloc(time_buf_size);
           memcpy(safe_time_buf, unsafe_time_cstr, time_buf_size);
           row+=new(pool) String(pool, safe_time_buf, time_buf_size);
           // users
           char *users_buf=(char *)pool.malloc(MAX_NUMBER);
           row+=new(pool) String(pool, 
                   users_buf, snprintf(users_buf, MAX_NUMBER, "%d", db_table->get_users_count()));
   
           status_table+=&row;
   }
   Value& DB_Connection::get_status(Pool& pool, const String *source) {
           Array& columns=*new(pool) Array(pool);
           columns+=new(pool) String(pool, "name");
           columns+=new(pool) String(pool, "time");
           columns+=new(pool) String(pool, "users");
           Table& table=*new(pool) Table(pool, 0, &columns, table_cache.size());
   
           table_cache.for_each(add_table_to_status_table, &table);
   
         int error=db->del(db, ftid, &dbt_key, 0/*flags*/);          return *new(pool) VTable(pool, &table);
         if(error!=DB_NOTFOUND)  
                 check("del", &key, error);  
 }  }
   
 #endif  #endif

Removed from v.1.2  
changed lines
  Added in v.1.37


E-mail: