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

1.1       parser      1: /** @file
                      2:        Parser: Charset connection implementation.
                      3: 
                      4:        Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)
                      5:        Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf)
                      6: 
1.10    ! parser      7:        $Id: pa_db_connection.C,v 1.9 2001/10/24 10:26:16 parser Exp $
1.1       parser      8: */
                      9: 
                     10: #include "pa_config_includes.h"
                     11: #ifdef HAVE_LIBDB
                     12: 
                     13: #include "pa_db_connection.h"
                     14: #include "pa_exception.h"
                     15: 
1.10    ! parser     16: // defines
        !            17: 
        !            18: #define READ_ADDITIONAL_FLAGS DB_RMW
        !            19: 
1.5       parser     20: // consts
                     21: 
                     22: const int DATA_STRING_SERIALIZED_VERSION=0x0100;
                     23: 
                     24: // helper types
                     25: 
                     26: #ifndef DOXYGEN
                     27: struct Data_string_serialized_prolog {
                     28:        int version;
                     29:        time_t time_to_die;
                     30: };
                     31: #endif
                     32: 
1.3       parser     33: // DB_Connection
                     34: 
1.1       parser     35: void DB_Connection::check(const char *operation, const String *source, int error) {
                     36:        switch(error) {
                     37:        case 0: 
                     38:                // no error
                     39:                break; 
                     40:        
                     41:        case DB_KEYEXIST:
                     42:                // DB_KEYEXIST is a "normal" return, so should not be
                     43:                // thrown as an error
                     44:                break; 
                     45: 
                     46:        case DB_RUNRECOVERY:
                     47:                // mark as unsafe, so not to cache it
                     48:                needs_recovery=true;
                     49:                throw Exception(0, 0, 
1.3       parser     50:                        source,
                     51:                        "action failed, RUN RECOVERY UTILITY. db %s error, real filename '%s'", 
                     52:                        operation, file_spec_cstr);
1.1       parser     53:                
                     54:        default:
                     55:                throw Exception(0, 0, 
1.3       parser     56:                        source, 
                     57:                        "action failed. db %s error: %s (%d), real filename '%s'", 
                     58:                        operation, strerror(error), error, file_spec_cstr);
1.1       parser     59:        }
                     60: }
                     61: 
1.4       parser     62: void DB_Connection::key_string_to_dbt(const String& key_string, DBT& key_result) {
                     63:        memset(&key_result, 0, sizeof(key_result));
                     64:        key_result.data=key_string.cstr(String::UL_AS_IS);
                     65:        key_result.size=key_string.size();
                     66: }
                     67: 
1.5       parser     68: String& DB_Connection::key_dbt_to_string(const DBT& key_dbt) {
                     69:        String& result=*new(*fservices_pool) String(*fservices_pool);
1.4       parser     70:        if(key_dbt.size) {
                     71:                char *request_data=(char *)malloc(key_dbt.size);
                     72:                memcpy(request_data, key_dbt.data, key_dbt.size);
1.5       parser     73:                result.APPEND_TAINTED(request_data, key_dbt.size, file_spec_cstr, 0/*line*/);
1.4       parser     74:        }
1.5       parser     75:        return result;
1.4       parser     76: }
                     77: 
1.5       parser     78: void DB_Connection::data_string_to_dbt(const String& data_string, time_t time_to_die, 
                     79:                                                                           DBT& data_result) {
1.4       parser     80:        memset(&data_result, 0, sizeof(data_result));
1.5       parser     81: 
                     82:        data_string.serialize(
                     83:                sizeof(Data_string_serialized_prolog), 
                     84:                data_result.data, data_result.size);
                     85: 
                     86:        Data_string_serialized_prolog& prolog=
                     87:                *static_cast<Data_string_serialized_prolog *>(data_result.data);
                     88: 
                     89:        prolog.version=DATA_STRING_SERIALIZED_VERSION;
                     90:        prolog.time_to_die=time_to_die;
1.4       parser     91: }
                     92: 
1.5       parser     93: String *DB_Connection::data_dbt_to_string(const DBT& data_dbt) {
                     94:        Data_string_serialized_prolog& prolog=
                     95:                *static_cast<Data_string_serialized_prolog *>(data_dbt.data);
                     96: 
                     97:        if(prolog.version!=DATA_STRING_SERIALIZED_VERSION)
                     98:                throw Exception(0, 0,
                     99:                        &ffile_spec,
                    100:                        "data string version 0x%04X not equal to 0x%04X, recreate file",
                    101:                                prolog.version, DATA_STRING_SERIALIZED_VERSION);
                    102: 
1.8       parser    103:        if(prolog.time_to_die/*specified*/ && prolog.time_to_die <= time(0)/*expired*/)
1.5       parser    104:                return 0;
                    105: 
                    106:        String& result=*new(*fservices_pool) String(*fservices_pool);
                    107:        result.deserialize(
                    108:                sizeof(Data_string_serialized_prolog), 
                    109:                data_dbt.data, data_dbt.size, file_spec_cstr);
                    110:        return &result;
1.4       parser    111: }
                    112: 
1.1       parser    113: DB_Connection::DB_Connection(Pool& pool, const String& afile_spec, DB_ENV& adbenv) : Pooled(pool),
                    114:        fdbenv(adbenv),
1.3       parser    115:        ffile_spec(afile_spec), file_spec_cstr(afile_spec.cstr(String::UL_FILE_SPEC)),
1.2       parser    116:        fservices_pool(0), db(0), ftid(0), needs_recovery(false), 
1.1       parser    117:        time_used(0) {
                    118: }
                    119: 
                    120: void DB_Connection::connect() { 
                    121:        // open
                    122:        DB_INFO dbinfo;
                    123:        memset(&dbinfo, 0, sizeof(dbinfo));
                    124:        check("open/create", &ffile_spec, db_open(
1.3       parser    125:                file_spec_cstr, 
1.1       parser    126:                PA_DB_ACCESS_METHOD, 
1.2       parser    127:                DB_CREATE /* used in single thread, no need for |DB_THREAD*/,
1.1       parser    128:                0666, 
                    129:                &fdbenv, &dbinfo, &db));
                    130: }
1.2       parser    131: /// @todo this one of reasons of not having ^try for now
                    132: void DB_Connection::disconnect() { 
                    133:        check("close", &ffile_spec, db->close(db, 0/*flags*/));  db=0; 
                    134: }
1.1       parser    135: 
1.5       parser    136: void DB_Connection::put(const String& key, const String& data, time_t time_to_die) {
1.4       parser    137:        DBT dbt_key;  key_string_to_dbt(key, dbt_key);
1.5       parser    138:        DBT dbt_data;  data_string_to_dbt(data, time_to_die, dbt_data);
1.2       parser    139:        check("put", &key, db->put(db, ftid, &dbt_key, &dbt_data, 0/*flags*/));
1.1       parser    140: }
                    141: 
                    142: String *DB_Connection::get(const String& key) {
1.4       parser    143:        DBT dbt_key;  key_string_to_dbt(key, dbt_key);
1.1       parser    144:        DBT dbt_data={0}; // must be zeroed
1.10    ! parser    145:        int error=db->get(db, ftid, &dbt_key, &dbt_data, READ_ADDITIONAL_FLAGS/*flags*/);
1.2       parser    146:        if(error==DB_NOTFOUND)
                    147:                return 0;
                    148:        else {
                    149:                check("get", &key, error);
1.9       parser    150:                String *result=data_dbt_to_string(dbt_data);
                    151:                if(!result) // save efforts by deleting expired keys
                    152:                        check("del expired", &key, db->del(db, ftid, &dbt_key, 0/*flags*/));
                    153:                return result;
1.2       parser    154:        }               
                    155: }
                    156: 
1.9       parser    157: void DB_Connection::remove(const String& key) {
1.4       parser    158:        DBT dbt_key;  key_string_to_dbt(key, dbt_key);
1.1       parser    159: 
1.2       parser    160:        int error=db->del(db, ftid, &dbt_key, 0/*flags*/);
                    161:        if(error!=DB_NOTFOUND)
                    162:                check("del", &key, error);
1.3       parser    163: }
                    164: 
                    165: // DB_Cursor
                    166: 
                    167: DB_Cursor::DB_Cursor(
                    168:                                         DB_Connection& aconnection, 
                    169:                                         const String *asource) : fsource(asource), fconnection(aconnection), cursor(0) {
                    170:        check("cursor", fsource, fconnection.db->cursor(fconnection.db,
                    171:                fconnection.ftid, &cursor, 0/*flags*/));
                    172: }
                    173: 
                    174: DB_Cursor::~DB_Cursor() {
                    175:        if(cursor) {
                    176:                check("c_close", fsource, cursor->c_close(cursor));  cursor=0;
                    177:        }
                    178: }
                    179: 
1.5       parser    180: bool DB_Cursor::get(String *& key, String *& data, u_int32_t flags) {
1.3       parser    181:        DBT dbt_key={0}; // must be zeroed
                    182:        DBT dbt_data={0}; // must be zeroed
                    183:        
1.10    ! parser    184:        int error=cursor->c_get(cursor, &dbt_key, &dbt_data, flags | READ_ADDITIONAL_FLAGS);
1.3       parser    185:        if(error==DB_NOTFOUND)
                    186:                return false;
                    187: 
                    188:        check("c_get", fsource, error);
                    189: 
1.7       parser    190:        if(data=data_dbt_to_string(dbt_data)) // not expired
                    191:                key=&key_dbt_to_string(dbt_key);
1.9       parser    192:        else {
                    193:                // save efforts by deleting expired keys
                    194:                remove(0/*flags*/);
1.7       parser    195:                key=0;
1.9       parser    196:        }
1.3       parser    197:        return true;
1.9       parser    198: }
                    199: 
                    200: void DB_Cursor::remove(u_int32_t flags) {
                    201:        check("c_del", fsource,  cursor->c_del(cursor, flags));
1.1       parser    202: }
                    203: 
                    204: #endif

E-mail: