Annotation of parser3/src/main/pa_db_table.C, revision 1.2

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

E-mail: