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

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

E-mail: