Annotation of parser3/src/main/pa_db_connection.C, revision 1.22

1.1       parser      1: /** @file
1.11      paf         2:        Parser: sql driver connection implementation.
1.1       parser      3: 
                      4:        Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)
                      5:        Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf)
                      6: 
1.22    ! paf         7:        $Id: pa_db_connection.C,v 1.21 2001/10/28 14:19:27 paf Exp $
1.20      paf         8: 
                      9:        developed with LIBDB 2.7.4
1.1       parser     10: */
                     11: 
                     12: #include "pa_config_includes.h"
1.19      paf        13: #ifdef DB2
1.1       parser     14: 
                     15: #include "pa_db_connection.h"
1.11      paf        16: #include "pa_db_table.h"
1.1       parser     17: #include "pa_exception.h"
1.11      paf        18: #include "pa_threads.h"
                     19: #include "pa_stack.h"
                     20: #include "pa_common.h"
1.1       parser     21: 
1.14      paf        22: // defines
                     23: 
                     24: #define DB_ERROR_PREFIX "db_err: "
                     25: #define DB_EXCEPTION_NO_LOG_MESSAGE1 DB_ERROR_PREFIX"Ignoring log file"
                     26: #define DB_EXCEPTION_NO_LOG_MESSAGE2 DB_ERROR_PREFIX"log_get: unable to find checkpoint record"
                     27: 
1.11      paf        28: // consts
                     29: 
1.15      paf        30: /// @test increase
                     31: const int DB_CHECKPOINT_MINUTES=1; 
                     32: 
1.11      paf        33: const int EXPIRE_UNUSED_TABLE_SECONDS=60;
                     34: const int CHECK_EXPIRED_TABLES_SECONDS=EXPIRE_UNUSED_TABLE_SECONDS*2;
                     35: 
                     36: // callbacks
1.10      parser     37: 
1.11      paf        38: static void db_paniccall(DB_ENV *dbenv, int error) {
                     39:        throw Exception(0, 0, 
                     40:                0, 
                     41:                "db_panic: %s (%d)", 
                     42:                strerror(error), error);
                     43: }
                     44: 
                     45: static void db_errcall(const char *, char *buffer) {
                     46:        throw Exception(0, 0, 
                     47:                0, 
1.14      paf        48:                DB_ERROR_PREFIX "%s", 
1.11      paf        49:                buffer);
                     50: }
1.5       parser     51: 
1.13      paf        52: static void expire_table(const Hash::Key& key, Hash::Val *& value, void *info) {
1.22    ! paf        53:        DB_Table& table=*static_cast<DB_Table *>(value);
1.11      paf        54:        time_t older_dies=reinterpret_cast<time_t>(info);
1.5       parser     55: 
1.13      paf        56:        if(table.expired(older_dies)) {
1.22    ! paf        57:                table.~DB_Table();  value=0;
1.13      paf        58:        }
1.11      paf        59: }
1.5       parser     60: 
1.3       parser     61: // DB_Connection
                     62: 
1.13      paf        63: DB_Connection::DB_Connection(Pool& apool, const String& adb_home) : Pooled(apool),
                     64:        time_used(0),
                     65:        fdb_home(adb_home), 
                     66:        table_cache(apool),
1.11      paf        67:        prev_expiration_pass_time(0) {
                     68:        //_asm  int 3;
                     69:        char DB_DATA_DIR__VALUE[MAX_STRING];
                     70:        char DB_LOG_DIR__VALUE[MAX_STRING];
                     71:        char DB_TMP_DIR__VALUE[MAX_STRING];
                     72: 
                     73:        const char *db_home_cstr=fdb_home.cstr(String::UL_FILE_SPEC);
                     74: 
                     75:        snprintf(DB_DATA_DIR__VALUE, MAX_STRING, "DB_DATA_DIR %s", db_home_cstr);
                     76:        snprintf(DB_LOG_DIR__VALUE, MAX_STRING, "DB_LOG_DIR %s", db_home_cstr);
                     77:        snprintf(DB_TMP_DIR__VALUE, MAX_STRING, "DB_TMP_DIR %s", db_home_cstr);
                     78: 
                     79:        char *db_config[] = {
                     80:                DB_DATA_DIR__VALUE,
                     81:                DB_LOG_DIR__VALUE,
                     82:                DB_TMP_DIR__VALUE, 
                     83:                0
                     84:        };
                     85: 
                     86:        u_int32_t flags=
1.13      paf        87:                DB_THREAD
                     88:                | DB_CREATE 
1.11      paf        89:                | DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN;
                     90: 
1.16      paf        91:        // trying to open with SOFT RECOVER option set
                     92:        memset(&dbenv, 0, sizeof(dbenv));
                     93:        
1.14      paf        94:        // error handlers
1.20      paf        95: #if DB_VERSION_MINOR >= 7
1.14      paf        96:        dbenv.db_paniccall=db_paniccall;
1.20      paf        97: #endif
1.14      paf        98:        dbenv.db_errcall=db_errcall;
1.16      paf        99: 
                    100:        // init
                    101:        check("db_appinit", &fdb_home, db_appinit(
                    102:                db_home_cstr,
                    103:                db_config, 
                    104:                &dbenv, 
                    105:                flags
                    106:                ));
1.11      paf       107: }
                    108: 
1.13      paf       109: DB_Connection::~DB_Connection() {
1.11      paf       110:        // close tables
1.13      paf       111:        table_cache.for_each(expire_table, 
1.11      paf       112:                reinterpret_cast<void *>(0/* =in the past = expire[close] all*/));
                    113:        
                    114:        // destroy connection data
1.13      paf       115:        check("db_appexit", &fdb_home, db_appexit(&dbenv));
1.11      paf       116: }
                    117: 
                    118: 
1.1       parser    119: void DB_Connection::check(const char *operation, const String *source, int error) {
                    120:        switch(error) {
                    121:        case 0: 
                    122:                // no error
                    123:                break; 
                    124:        
                    125:        default:
1.21      paf       126:                if(error<0)
                    127:                        throw Exception(0, 0, 
                    128:                                source, 
                    129:                                "db %s error: %d", 
                    130:                                operation, error);
                    131:                else
                    132:                        throw Exception(0, 0, 
                    133:                                source, 
                    134:                                "db %s error: %s (%d)", 
                    135:                                operation, strerror(error), error);
1.1       parser    136:        }
                    137: }
                    138: 
1.15      paf       139: DB_Table_ptr DB_Connection::get_table_ptr(const String& request_file_name, const String *source) {
                    140:        // checkpoint
1.21      paf       141:        {
                    142:                int error=txn_checkpoint(dbenv.tx_info, 0/*kbyte*/, DB_CHECKPOINT_MINUTES/*min*/);
                    143:                /*
                    144:                DB_INCOMPLETE if there were pages that needed to be written 
                    145:                but that memp_sync was unable to write immediately. 
                    146:                In this case, the txn_checkpoint call should be retried. 
                    147: 
                    148:                we'll just ignore that
                    149:                */
                    150:                if(error!=DB_INCOMPLETE)
                    151:                        check("checkpoint", source, error);
                    152:        }
1.11      paf       153: 
                    154:        // first trying to get cached table
                    155:        DB_Table *result=get_table_from_cache(request_file_name);
1.13      paf       156:        if(!result) { // no cached table
1.11      paf       157:                // make global_file_name C-string on global pool
1.13      paf       158:                const char *request_file_name_cstr=request_file_name.cstr(String::UL_AS_IS);
1.11      paf       159:                char *global_file_name_cstr=(char *)malloc(strlen(request_file_name_cstr)+1);
                    160:                strcpy(global_file_name_cstr, request_file_name_cstr);
                    161:                // make global_file_name string on global pool
                    162:                String& global_file_name=*new(this->pool()) String(this->pool(), global_file_name_cstr);
                    163:                
                    164:                // allocate in global pool 
                    165:                // associate with services[request]
                    166:                // NOTE: never freed up!
                    167:                result=new(this->pool()) DB_Table(this->pool(), global_file_name, *this);
1.13      paf       168:                // cache it
                    169:                put_table_to_cache(global_file_name, *result);
1.4       parser    170:        }
1.1       parser    171: 
1.13      paf       172:        // return auto-it
                    173:        return DB_Table_ptr(result);
1.1       parser    174: }
1.11      paf       175: 
                    176: // table cache
                    177: /// @todo get rid of memory spending Stack [zeros deep inside got accumulated]
                    178: DB_Table *DB_Connection::get_table_from_cache(const String& file_name) { 
                    179:        SYNCHRONIZED;
1.17      paf       180: 
                    181:        maybe_expire_table_cache();
1.11      paf       182: 
1.13      paf       183:        return static_cast<DB_Table *>(table_cache.get(file_name));
1.3       parser    184: }
                    185: 
1.13      paf       186: void DB_Connection::put_table_to_cache(const String& file_name, DB_Table& table) { 
1.11      paf       187:        SYNCHRONIZED;
1.3       parser    188: 
1.13      paf       189:        table_cache.put(file_name, &table);
1.3       parser    190: }
                    191: 
1.11      paf       192: void DB_Connection::maybe_expire_table_cache() {
                    193:        time_t now=time(0);
                    194: 
                    195:        if(prev_expiration_pass_time<now-CHECK_EXPIRED_TABLES_SECONDS) {
1.13      paf       196:                table_cache.for_each(expire_table, 
1.11      paf       197:                        reinterpret_cast<void *>(now-EXPIRE_UNUSED_TABLE_SECONDS));
1.3       parser    198: 
1.11      paf       199:                prev_expiration_pass_time=now;
1.9       parser    200:        }
1.1       parser    201: }
                    202: 
                    203: #endif

E-mail: