--- parser3/src/main/Attic/pa_db_manager.C 2001/10/24 14:11:25 1.4 +++ parser3/src/main/Attic/pa_db_manager.C 2001/10/26 13:48:19 1.7 @@ -4,14 +4,13 @@ Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com) Author: Alexander Petrosyan (http://design.ru/paf) - $Id: pa_db_manager.C,v 1.4 2001/10/24 14:11:25 parser Exp $ + $Id: pa_db_manager.C,v 1.7 2001/10/26 13:48:19 paf Exp $ */ #include "pa_config_includes.h" #ifdef HAVE_LIBDB #include "pa_db_manager.h" -#include "ltdl.h" #include "pa_db_connection.h" #include "pa_exception.h" #include "pa_threads.h" @@ -28,163 +27,78 @@ const int CHECK_EXPIRED_CONNECTIONS_SECO // callbacks -static void db_paniccall(DB_ENV *dbenv, int error) { - throw Exception(0, 0, - 0, - "db_paniccall: %s (%d)", - strerror(error), error); -} +static void expire_connection(const Hash::Key& key, Hash::Val *& value, void *info) { + DB_Connection& connection=*static_cast(value); + time_t older_dies=reinterpret_cast(info); -static void db_errcall(const char *, char *buffer) { - throw Exception(0, 0, - 0, - "db_errcall: %s", - buffer); + if(connection.expired(older_dies)) { + connection.~DB_Connection(); value=0; + } } // DB_Manager -/// @test db_paniccall & co DB_Manager::DB_Manager(Pool& pool) : Pooled(pool), connection_cache(pool), prev_expiration_pass_time(0) { - //_asm int 3; - memset(&dbenv, 0, sizeof(dbenv)); - dbenv.db_paniccall=db_paniccall; - dbenv.db_errcall=db_errcall; - - check("db_appinit", 0/*global*/, db_appinit( - 0/*db_home*/, - 0/*db_config*/, - &dbenv, - DB_CREATE | DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN)); } DB_Manager::~DB_Manager() { - check("db_appexit", 0/*global*/, db_appexit(&dbenv)); + // close connections + connection_cache.for_each(expire_connection, + reinterpret_cast(0/* =in the past = expire[close] all*/)); } - -void DB_Manager::check(const char *operation, const String *source, int error) { - switch(error) { - case 0: - // no error - break; - - default: - throw Exception(0, 0, - source, - "db %s error: %s (%d)", - operation, strerror(error), error); - } -} - -DB_Connection& DB_Manager::get_connection(const String& request_file_spec, - const String& request_origin) { - Pool& pool=request_origin.pool(); // request pool +/// @test subpools mechanizm. one connection, one subpool. ~connection destructs it +DB_Connection_ptr DB_Manager::get_connection_ptr(const String& request_db_home, + const String *source) { + if(request_db_home.size()==0) + throw Exception(0, 0, + source, + "empty DB_HOME specified"); // first trying to get cached connection - DB_Connection *result=get_connection_from_cache(request_file_spec); - if(result && !result->ping()) { // we have some cached connection, is it pingable? - result->disconnect(); // kill unpingabe=dead connection - result=0; - } - - char *request_file_spec_cstr; - if(result) - request_file_spec_cstr=0; // calm, compiler - else { // no cached connection - // make global_file_spec C-string on global pool - request_file_spec_cstr=request_file_spec.cstr(String::UL_AS_IS); - char *global_file_spec_cstr=(char *)malloc(strlen(request_file_spec_cstr)+1); - strcpy(global_file_spec_cstr, request_file_spec_cstr); - // make global_file_spec string on global pool - String& global_file_spec=*new(this->pool()) String(this->pool(), global_file_spec_cstr); + DB_Connection *result=get_connection_from_cache(request_db_home); + if(!result) { // no cached connection + // make global_db_home C-string on global pool + const char *request_db_home_cstr=request_db_home.cstr(String::UL_AS_IS); + char *global_db_home_cstr=(char *)malloc(strlen(request_db_home_cstr)+1); + strcpy(global_db_home_cstr, request_db_home_cstr); + // make global_db_home string on global pool + String& global_db_home=*new(this->pool()) String(this->pool(), global_db_home_cstr); // allocate in global pool - // associate with services[request] // NOTE: never freed up! - result=new(this->pool()) DB_Connection(this->pool(), global_file_spec, dbenv); + result=new(this->pool()) DB_Connection(this->pool(), global_db_home); + // cache it + put_connection_to_cache(global_db_home, *result); } - // associate with services[request] (deassociates at close) - result->set_services(&pool); - // if not connected yet, do that now, when result has services - if(!result->connected()) - result->connect(); - // return it - return *result; -} -void DB_Manager::clear_dbfile(const String& file_spec) { - // open&clear - DB *db; - DB_INFO dbinfo; - memset(&dbinfo, 0, sizeof(dbinfo)); - check("open(clear)", &file_spec, db_open( - file_spec.cstr(String::UL_FILE_SPEC), - PA_DB_ACCESS_METHOD, - DB_CREATE | DB_TRUNCATE/* used in single thread, no need for |DB_THREAD*/, - 0666, - &dbenv, &dbinfo, &db)); - - check("close", &file_spec, db->close(db, 0/*flags*/)); db=0; -} - -void DB_Manager::close_connection(const String& file_spec, - DB_Connection& connection) { - // deassociate from services[request] - connection.set_services(0); - put_connection_to_cache(file_spec, connection); + // return auto-it + return DB_Connection_ptr(result); } - // connection cache /// @todo get rid of memory spending Stack [zeros deep inside got accumulated] -DB_Connection *DB_Manager::get_connection_from_cache(const String& file_spec) { +DB_Connection *DB_Manager::get_connection_from_cache(const String& db_home) { SYNCHRONIZED; - maybe_expire_connection_cache(); - - if(Stack *connections=static_cast(connection_cache.get(file_spec))) - while(connections->top_index()>=0) { // there are cached connections to that 'file_spec' - DB_Connection *result=static_cast(connections->pop()); - if(result->connected()) // not expired? - return result; - } - - return 0; + return static_cast(connection_cache.get(db_home)); } -void DB_Manager::put_connection_to_cache(const String& file_spec, +void DB_Manager::put_connection_to_cache(const String& db_home, DB_Connection& connection) { SYNCHRONIZED; - Stack *connections=static_cast(connection_cache.get(file_spec)); - if(!connections) { // there are no cached connections to that 'file_spec' yet? - connections=NEW Stack(pool()); // NOTE: never freed up! - connection_cache.put(file_spec, connections); - } - connections->push(&connection); + connection_cache.put(db_home, &connection); } -static void expire_connection(Array::Item *value, void *info) { - DB_Connection& connection=*static_cast(value); - time_t older_dies=reinterpret_cast(info); - - if(connection.connected() && connection.expired(older_dies)) - connection.disconnect(); -} -static void expire_connections(const Hash::Key& key, Hash::Val *value, void *info) { - Stack& stack=*static_cast(value); - for(int i=0; i<=stack.top_index(); i++) - expire_connection(stack.get(i), info); -} void DB_Manager::maybe_expire_connection_cache() { time_t now=time(0); if(prev_expiration_pass_time(now-EXPIRE_UNUSED_CONNECTION_SECONDS)); prev_expiration_pass_time=now;