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

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

E-mail: