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

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.3     ! paf         7:        $Id: pa_db_table.C,v 1.2 2001/10/26 07:06:17 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"
1.3     ! paf        15: #include "pa_db_connection.h"
1.1       paf        16: 
                     17: // defines
                     18: 
1.3     ! paf        19: #define DEADLOCK_POSSIBILITY_REDUCTION_FLAGS DB_RMW
1.1       paf        20: 
                     21: // consts
                     22: 
                     23: const int DATA_STRING_SERIALIZED_VERSION=0x0100;
                     24: 
                     25: // helper types
                     26: 
                     27: #ifndef DOXYGEN
                     28: struct Data_string_serialized_prolog {
                     29:        int version;
                     30:        time_t time_to_die;
                     31: };
1.3     ! paf        32: 
        !            33: struct DBT_auto : public DBT {
        !            34:        DBT_auto() {
        !            35:                data=0; 
        !            36:                size=ulen=dlen=doff=0;
        !            37:                flags=DB_DBT_MALLOC;
        !            38:        }
        !            39: 
        !            40:        ~DBT_auto() {
        !            41:                if(flags & DB_DBT_MALLOC)
        !            42:                        free(data);
        !            43:        }
        !            44: };
        !            45: 
1.1       paf        46: #endif
                     47: 
                     48: // DB_Table
                     49: 
1.3     ! paf        50: DB_Table::DB_Table(Pool& pool, const String& afile_name, DB_Connection& aconnection) : Pooled(pool),
1.1       paf        51:        time_used(0), fservices_pool(0), 
                     52:        fconnection(aconnection),
                     53:        dbenv(aconnection.dbenv),
1.3     ! paf        54:        ffile_name(afile_name), file_name_cstr(afile_name.cstr(String::UL_FILE_SPEC)),
        !            55:        db(0) {
        !            56: 
        !            57:        // open
        !            58:        DB_INFO dbinfo;
        !            59:        memset(&dbinfo, 0, sizeof(dbinfo));
        !            60:        check("open/create", &ffile_name, db_open(
        !            61:                file_name_cstr, 
        !            62:                PA_DB_ACCESS_METHOD, 
        !            63:                DB_THREAD 
        !            64:                | DB_CREATE /* used in single thread, no need for |DB_THREAD*/,
        !            65:                0666, 
        !            66:                &dbenv, &dbinfo, &db));
        !            67: }
        !            68: /// @todo this one of reasons of not having ^try for now
        !            69: DB_Table::~DB_Table() { 
        !            70:        // close
        !            71:        check("close", &ffile_name, db->close(db, 0/*flags*/));  db=0; 
        !            72: }
        !            73: 
        !            74: void DB_Table::use() {
        !            75:        fconnection.use();
        !            76: 
        !            77:        time_used=time(0); // they started to use at this time
        !            78:        used++;
        !            79: }
        !            80: void DB_Table::unuse() {
        !            81:        used--;
        !            82: 
        !            83:        fconnection.unuse();
1.1       paf        84: }
                     85: 
1.3     ! paf        86: 
        !            87: 
1.1       paf        88: void DB_Table::check(const char *operation, const String *source, int error) {
                     89:        switch(error) {
                     90:        case 0: 
                     91:                // no error
                     92:                break; 
                     93:        
                     94:        case DB_KEYEXIST:
                     95:                // DB_KEYEXIST is a "normal" return, so should not be
                     96:                // thrown as an error
                     97:                break; 
                     98: 
                     99:        case DB_RUNRECOVERY:
                    100:                throw Exception(0, 0, 
                    101:                        source,
                    102:                        "action failed, RUN RECOVERY UTILITY. db %s error, real filename '%s'", 
1.3     ! paf       103:                        operation, file_name_cstr);
1.1       paf       104:                
                    105:        default:
                    106:                throw Exception(0, 0, 
                    107:                        source, 
                    108:                        "action failed. db %s error: %s (%d), real filename '%s'", 
1.3     ! paf       109:                        operation, strerror(error), error, file_name_cstr);
1.1       paf       110:        }
                    111: }
                    112: 
                    113: void DB_Table::key_string_to_dbt(const String& key_string, DBT& key_result) {
                    114:        memset(&key_result, 0, sizeof(key_result));
                    115:        key_result.data=key_string.cstr(String::UL_AS_IS);
                    116:        key_result.size=key_string.size();
                    117: }
                    118: 
1.3     ! paf       119: String& DB_Table::key_dbt_to_string(Pool& pool, const DBT& key_dbt) {
1.1       paf       120:        String& result=*new(*fservices_pool) String(*fservices_pool);
                    121:        if(key_dbt.size) {
1.3     ! paf       122:                char *request_data=(char *)pool.malloc(key_dbt.size);
1.1       paf       123:                memcpy(request_data, key_dbt.data, key_dbt.size);
1.3     ! paf       124:                result.APPEND_TAINTED(request_data, key_dbt.size, file_name_cstr, 0/*line*/);
1.1       paf       125:        }
                    126:        return result;
                    127: }
                    128: 
                    129: void DB_Table::data_string_to_dbt(const String& data_string, time_t time_to_die, 
                    130:                                                                           DBT& data_result) {
                    131:        memset(&data_result, 0, sizeof(data_result));
                    132: 
                    133:        data_string.serialize(
                    134:                sizeof(Data_string_serialized_prolog), 
                    135:                data_result.data, data_result.size);
                    136: 
                    137:        Data_string_serialized_prolog& prolog=
                    138:                *static_cast<Data_string_serialized_prolog *>(data_result.data);
                    139: 
                    140:        prolog.version=DATA_STRING_SERIALIZED_VERSION;
                    141:        prolog.time_to_die=time_to_die;
                    142: }
                    143: 
1.3     ! paf       144: String *DB_Table::data_dbt_to_string(Pool& pool, const DBT& data_dbt) {
1.1       paf       145:        Data_string_serialized_prolog& prolog=
                    146:                *static_cast<Data_string_serialized_prolog *>(data_dbt.data);
                    147: 
                    148:        if(prolog.version!=DATA_STRING_SERIALIZED_VERSION)
                    149:                throw Exception(0, 0,
1.3     ! paf       150:                        &ffile_name,
1.1       paf       151:                        "data string version 0x%04X not equal to 0x%04X, recreate file",
                    152:                                prolog.version, DATA_STRING_SERIALIZED_VERSION);
                    153: 
                    154:        if(prolog.time_to_die/*specified*/ && prolog.time_to_die <= time(0)/*expired*/)
                    155:                return 0;
                    156: 
1.3     ! paf       157:        String& result=*new(pool) String(pool);
        !           158:        if(data_dbt.size) {
        !           159:                char *data=(char *)pool.malloc(data_dbt.size);
        !           160:                memcpy(data, data_dbt.data, data_dbt.size);
        !           161:                result.deserialize(
        !           162:                        sizeof(Data_string_serialized_prolog), 
        !           163:                        data, data_dbt.size, file_name_cstr);
        !           164:        }
1.1       paf       165:        return &result;
                    166: }
                    167: 
1.3     ! paf       168: void DB_Table::put(DB_Transaction *t, const String& key, const String& data, time_t time_to_die) {
1.1       paf       169:        DBT dbt_key;  key_string_to_dbt(key, dbt_key);
                    170:        DBT dbt_data;  data_string_to_dbt(data, time_to_die, dbt_data);
1.3     ! paf       171:        check("put", &key, db->put(db, t?t->id():0, &dbt_key, &dbt_data, 0/*flags*/));
1.1       paf       172: }
                    173: 
1.3     ! paf       174: String *DB_Table::get(DB_Transaction *t, Pool& pool, const String& key) {
1.1       paf       175:        DBT dbt_key;  key_string_to_dbt(key, dbt_key);
1.3     ! paf       176:        DBT_auto dbt_data;
        !           177:        int error=db->get(db, t?t->id():0, &dbt_key, &dbt_data, 
        !           178:                DEADLOCK_POSSIBILITY_REDUCTION_FLAGS);
1.1       paf       179:        if(error==DB_NOTFOUND)
                    180:                return 0;
                    181:        else {
                    182:                check("get", &key, error);
1.3     ! paf       183:                String *result=data_dbt_to_string(pool, dbt_data);
1.1       paf       184:                if(!result) // save efforts by deleting expired keys
1.3     ! paf       185:                        check("del expired", &key, db->del(db, t?t->id():0, &dbt_key, 0/*flags*/));
1.1       paf       186:                return result;
                    187:        }               
                    188: }
                    189: 
1.3     ! paf       190: void DB_Table::remove(DB_Transaction *t, const String& key) {
1.1       paf       191:        DBT dbt_key;  key_string_to_dbt(key, dbt_key);
                    192: 
1.3     ! paf       193:        int error=db->del(db, t?t->id():0, &dbt_key, 0/*flags*/);
1.1       paf       194:        if(error!=DB_NOTFOUND)
                    195:                check("del", &key, error);
                    196: }
                    197: 
1.3     ! paf       198: // DB_Transaction
        !           199: 
        !           200: DB_Transaction::DB_Transaction(Pool& apool, DB_Table& atable, DB_Transaction *& aparent_ref) : 
        !           201:        fpool(apool), ftable(atable), fparent_ref(aparent_ref), 
        !           202:                parent(aparent_ref),
        !           203:                fid(0), marked_to_rollback(false) {
        !           204: 
        !           205:        check("txn_begin", 
        !           206:                &ftable.file_name(), txn_begin(ftable.dbenv.tx_info, parent?parent->fid:0, &fid));
        !           207: 
        !           208:        aparent_ref=this;
        !           209: }
        !           210: DB_Transaction::~DB_Transaction() { 
        !           211:        fparent_ref=parent;
        !           212: 
        !           213:        if(parent) // all in hands of our parent
        !           214:                return;
        !           215: 
        !           216:        if(marked_to_rollback)
        !           217:                check("txn_abort", &ftable.file_name(), txn_abort(fid));
        !           218:        else
        !           219:                check("txn_commit", &ftable.file_name(), txn_commit(fid));
        !           220: }
        !           221: void DB_Transaction::mark_to_rollback() {
        !           222:        if(parent)
        !           223:                parent->mark_to_rollback();
        !           224:        else
        !           225:                marked_to_rollback=true;
        !           226: }
        !           227: 
1.1       paf       228: // DB_Cursor
                    229: 
                    230: DB_Cursor::DB_Cursor(
1.3     ! paf       231:                                         DB_Table& atable, DB_Transaction *transaction, 
        !           232:                                         const String *asource) : 
        !           233:        ftable(atable), fsource(asource), 
        !           234:        cursor(0) {
        !           235: 
1.1       paf       236:        check("cursor", fsource, ftable.db->cursor(ftable.db,
1.3     ! paf       237:                transaction?transaction->id():0, &cursor, 0/*flags*/));
1.1       paf       238: }
                    239: 
                    240: DB_Cursor::~DB_Cursor() {
1.3     ! paf       241:        if(cursor)
        !           242:                check("c_close", fsource, cursor->c_close(cursor));
1.1       paf       243: }
                    244: 
1.3     ! paf       245: bool DB_Cursor::get(Pool& pool, String *& key, String *& data, u_int32_t flags) {
1.1       paf       246:        DBT dbt_key={0}; // must be zeroed
1.3     ! paf       247:        DBT_auto dbt_data;
1.1       paf       248:        
1.3     ! paf       249:        int error=cursor->c_get(cursor, &dbt_key, &dbt_data, 
        !           250:                DEADLOCK_POSSIBILITY_REDUCTION_FLAGS
        !           251:                | flags 
        !           252:        );
1.1       paf       253:        if(error==DB_NOTFOUND)
                    254:                return false;
                    255: 
                    256:        check("c_get", fsource, error);
                    257: 
1.3     ! paf       258:        if(data=data_dbt_to_string(pool, dbt_data)) // not expired
        !           259:                key=&key_dbt_to_string(pool, dbt_key);
1.1       paf       260:        else {
                    261:                // save efforts by deleting expired keys
                    262:                remove(0/*flags*/);
                    263:                key=0;
                    264:        }
                    265:        return true;
                    266: }
                    267: 
                    268: void DB_Cursor::remove(u_int32_t flags) {
                    269:        check("c_del", fsource,  cursor->c_del(cursor, flags));
                    270: }
                    271: 
                    272: #endif

E-mail: