Annotation of parser3/src/types/pa_vhashfile.C, revision 1.45

1.1       parser      1: /** @file
                      2:        Parser: @b table class.
                      3: 
1.20      paf         4:        Copyright(c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com)
1.19      paf         5:        Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
1.1       parser      6: */
                      7: 
1.45    ! paf         8: static const char * const IDENT="$Date: 2004/09/13 08:57:43 $";
1.1       parser      9: 
1.32      paf        10: #include "pa_globals.h"
                     11: #include "pa_threads.h"
1.1       parser     12: #include "pa_vtable.h"
                     13: #include "pa_vstring.h"
                     14: #include "pa_vhashfile.h"
1.32      paf        15: #include "pa_vdate.h"
                     16: 
                     17: // consts
                     18: 
1.41      paf        19: const uint HASHFILE_VALUE_SERIALIZED_VERSION=0x0001;
1.1       parser     20: 
                     21: // methods
                     22: 
1.22      paf        23: void check(const char *step, apr_status_t status) {
                     24:        if(status==APR_SUCCESS)
                     25:                return;
                     26: 
1.40      paf        27:        const char* str=strerror(status);
1.33      paf        28:        throw Exception("file.access",
1.22      paf        29:                0,
1.33      paf        30:                "%s error: %s (%d)", 
1.40      paf        31:                        step, str?str:"<unknown>", status);
1.22      paf        32: }
                     33: 
                     34: void VHashfile::open(const String& afile_name) {
1.34      paf        35:        check("apr_sdbm_open(shared)", apr_sdbm_open(&m_db, file_name=afile_name.cstr(String::L_FILE_SPEC), 
1.27      paf        36:                                         APR_CREATE|APR_READ|APR_SHARELOCK, 
1.22      paf        37:                                         0664, 0));
                     38: }
                     39: 
1.34      paf        40: void VHashfile::close() {
                     41:        check_db();
                     42: 
                     43:        check("apr_sdbm_close", apr_sdbm_close(m_db));  m_db=0;
                     44: }
                     45: 
                     46: void VHashfile::check_db() const {
                     47:        if(!m_db)
                     48:                throw Exception(0,
                     49:                        0,
                     50:                        "%s is closed", type());
                     51: }
                     52: 
                     53: apr_sdbm_t *VHashfile::get_db_for_reading() const {
                     54:        check_db();
                     55: 
                     56:        return m_db;
                     57: }
                     58: 
                     59: apr_sdbm_t *VHashfile::get_db_for_writing() {
                     60:        check_db();
                     61: 
                     62:        if(apr_sdbm_rdonly(m_db)) {
                     63:                // reopen in write mode & exclusive lock
                     64:                close();
                     65:                check("apr_sdbm_open(exclusive)", apr_sdbm_open(&m_db, file_name, 
1.27      paf        66:                                                                                        APR_WRITE, 
                     67:                                                                                        0664, 0));
                     68:        }
1.34      paf        69: 
                     70:        return m_db;
1.27      paf        71: }
                     72: 
1.22      paf        73: VHashfile::~VHashfile() {
1.34      paf        74:        if(m_db)
                     75:                close();
1.22      paf        76: }
                     77: 
1.32      paf        78: struct Hashfile_value_serialized_prolog {
1.41      paf        79:        uint version;
1.32      paf        80:        time_t time_to_die;
                     81: };
                     82: 
1.35      paf        83: apr_sdbm_datum_t VHashfile::serialize_value(const String& string, time_t time_to_die) const {
1.32      paf        84:        apr_sdbm_datum_t result;
                     85: 
                     86:        size_t length=string.length();
                     87:        result.dsize=sizeof(Hashfile_value_serialized_prolog)+length;
                     88:        result.dptr=new(PointerFreeGC) char[result.dsize];
                     89: 
                     90:        Hashfile_value_serialized_prolog& prolog=*reinterpret_cast<Hashfile_value_serialized_prolog*>(result.dptr);
                     91:        char *output_cstr=result.dptr+sizeof(Hashfile_value_serialized_prolog);
                     92: 
                     93:        prolog.version=HASHFILE_VALUE_SERIALIZED_VERSION;
                     94:        prolog.time_to_die=time_to_die;
1.45    ! paf        95:        if(length) // reported errors on storing empty values to hashfiles, but without details. maybe here [win32, intel:solaris, freebsd were OK...]
        !            96:                memcpy(output_cstr, string.cstr(), length);
1.32      paf        97: 
                     98:        return result;
                     99: }
                    100: 
1.35      paf       101: const String* VHashfile::deserialize_value(apr_sdbm_datum_t key, const apr_sdbm_datum_t value) {
                    102:        // key not found || it's surely not in our format
1.38      paf       103:        if(!value.dptr || (size_t)value.dsize<sizeof(Hashfile_value_serialized_prolog))
1.35      paf       104:                return 0; 
                    105: 
1.41      paf       106:        // [WARNING: not cast, addresses must be %4=0 on sparc]
1.42      paf       107:        Hashfile_value_serialized_prolog prolog;
                    108:        memcpy(&prolog, value.dptr, sizeof(prolog));
1.41      paf       109:        
1.42      paf       110:        if(prolog.version!=HASHFILE_VALUE_SERIALIZED_VERSION
                    111:                || (prolog.time_to_die/*specified*/ 
                    112:                        && (prolog.time_to_die <= time(0)/*expired*/))) {
1.35      paf       113:                // old format || exipred value
                    114:                remove(key);
1.32      paf       115:                return 0;
1.35      paf       116:        }
1.32      paf       117:        
1.35      paf       118:        char *input_cstr=value.dptr+sizeof(Hashfile_value_serialized_prolog);
                    119:        size_t input_length=value.dsize-sizeof(Hashfile_value_serialized_prolog);
1.32      paf       120: 
1.39      paf       121:        return new String(pa_strdup(input_length?input_cstr:"", input_length), true);
1.32      paf       122: }
                    123: 
1.27      paf       124: void VHashfile::put_field(const String& aname, Value *avalue) {
1.34      paf       125:        apr_sdbm_t *db=get_db_for_writing();
1.22      paf       126: 
1.8       parser    127:        time_t time_to_die=0;
                    128:        const String *value_string;
                    129: 
1.23      paf       130:        if(HashStringValue *hash=avalue->get_hash()) {
                    131:                if(Value *value_value=hash->get(value_name)) {
1.9       parser    132:                        if(value_value->get_junction())
1.23      paf       133:                                throw Exception(0,
                    134:                                        0,
                    135:                                        VALUE_NAME" must not be code");
1.8       parser    136: 
                    137:                        value_string=&value_value->as_string();
                    138: 
1.32      paf       139:                        if(Value *expires=hash->get(expires_name)) {
                    140:                                if(Value* vdate=expires->as(VDATE_TYPE, false))
                    141:                                        time_to_die=static_cast<VDate*>(vdate)->get_time(); // $expires[DATE]
                    142:                                else if(double days_till_expire=expires->as_double())
                    143:                                        time_to_die=time(NULL)+(time_t)(60*60*24*days_till_expire); // $expires(days)
                    144:                        }
1.8       parser    145:                } else
1.23      paf       146:                        throw Exception(0,
1.8       parser    147:                                &aname,
1.23      paf       148:                                "put hash value must contain ."VALUE_NAME);
1.8       parser    149:        } else
                    150:                value_string=&avalue->as_string();
1.43      paf       151: 
                    152:        if(aname.is_empty())
                    153:                throw Exception("parser.runtime",
                    154:                        0,
                    155:                        "hashfile key must not be empty");
1.5       parser    156: 
1.23      paf       157:        apr_sdbm_datum_t key;
                    158:        key.dptr=const_cast<char*>(aname.cstr());
1.24      paf       159:        key.dsize=aname.length();
1.23      paf       160: 
1.32      paf       161:        apr_sdbm_datum_t value=serialize_value(*value_string, time_to_die);
1.23      paf       162: 
                    163:        check("apr_sdbm_store", apr_sdbm_store(db, key, value, APR_SDBM_REPLACE));
1.1       parser    164: }
                    165: 
1.11      paf       166: Value *VHashfile::get_field(const String& aname) {
1.34      paf       167:        apr_sdbm_t *db=get_db_for_reading();
                    168: 
1.23      paf       169:        apr_sdbm_datum_t key;
                    170:        key.dptr=const_cast<char*>(aname.cstr());
1.24      paf       171:        key.dsize=aname.length();
1.23      paf       172: 
                    173:        apr_sdbm_datum_t value;
                    174: 
                    175:        check("apr_sdbm_fetch", apr_sdbm_fetch(db, &value, key));
                    176: 
1.35      paf       177:        const String *sresult=deserialize_value(key, value);
1.32      paf       178:        return sresult? new VString(*sresult): 0;
1.24      paf       179: }
                    180: 
1.35      paf       181: void VHashfile::remove(const apr_sdbm_datum_t key) {
1.34      paf       182:        apr_sdbm_t *db=get_db_for_writing();
1.27      paf       183: 
1.35      paf       184:        check("apr_sdbm_delete", apr_sdbm_delete(db, key));
                    185: }
                    186: 
                    187: void VHashfile::remove(const String& aname) {
1.24      paf       188:        apr_sdbm_datum_t key;
                    189:        key.dptr=const_cast<char*>(aname.cstr());
                    190:        key.dsize=aname.length();
                    191: 
1.35      paf       192:        remove(key);
1.1       parser    193: }
                    194: 
1.27      paf       195: void VHashfile::for_each(void callback(apr_sdbm_datum_t, void*), void* info) const {
1.34      paf       196:        apr_sdbm_t *db=get_db_for_reading();
                    197: 
1.30      paf       198:        Array<apr_sdbm_datum_t> keys;
                    199: 
                    200:        // collect keys
1.25      paf       201:        check("apr_sdbm_lock", apr_sdbm_lock(db, APR_FLOCK_SHARED));
                    202:        try {
1.30      paf       203:                apr_sdbm_datum_t key;
                    204:                if(apr_sdbm_firstkey(db, &key)==APR_SUCCESS)
1.25      paf       205:                        do {
1.30      paf       206:                                keys+=key;
                    207:                        } while(apr_sdbm_nextkey(db, &key)==APR_SUCCESS);
1.25      paf       208:        } catch(...) {
                    209:                        check("apr_sdbm_unlock", apr_sdbm_unlock(db));
                    210:                        rethrow;
1.4       parser    211:        }
1.30      paf       212:        check("apr_sdbm_unlock", apr_sdbm_unlock(db));
1.4       parser    213: 
1.30      paf       214:        // iterate them
                    215:        keys.for_each(callback, info);
1.26      paf       216: }
1.27      paf       217: 
                    218: #ifndef DOXYGEN
                    219: struct For_each_string_callback_info {
1.35      paf       220:        VHashfile* self;
1.27      paf       221:        void* nested_info;
                    222:        void (*nested_callback)(const String::Body, const String&, void*);
                    223: };
                    224: #endif
                    225: static void for_each_string_callback(apr_sdbm_datum_t apkey, void* ainfo) {
                    226:        For_each_string_callback_info& info=*static_cast<For_each_string_callback_info *>(ainfo);
1.35      paf       227:        apr_sdbm_t *db=info.self->get_db_for_reading();
1.27      paf       228: 
                    229:        apr_sdbm_datum_t apvalue;
1.35      paf       230:        check("apr_sdbm_fetch", apr_sdbm_fetch(db, &apvalue, apkey));
                    231: 
                    232:        if(const String* svalue=info.self->deserialize_value(apkey, apvalue)) {
                    233:                const char *clkey=pa_strdup(apkey.dptr, apkey.dsize);
1.27      paf       234: 
1.32      paf       235:                info.nested_callback(clkey, *svalue, info.nested_info);
1.35      paf       236:        }
1.27      paf       237: }
1.35      paf       238: void VHashfile::for_each(void callback(const String::Body, const String&, void*), void* ainfo) {
1.27      paf       239:        For_each_string_callback_info info;
                    240:        
1.35      paf       241:        info.self=this;
1.27      paf       242:        info.nested_info=ainfo;
                    243:        info.nested_callback=callback;
                    244: 
                    245:        for_each(for_each_string_callback, &info);
                    246: }
                    247: 
1.30      paf       248: static void clear_delete_key(apr_sdbm_datum_t key, void* adb) {
                    249:        check("apr_sdbm_delete", apr_sdbm_delete(static_cast<apr_sdbm_t*>(adb), key));
1.27      paf       250: }
                    251: void VHashfile::clear() {
1.34      paf       252:        apr_sdbm_t *db=get_db_for_writing();
1.27      paf       253: 
1.30      paf       254:        for_each(clear_delete_key, db);
1.27      paf       255: }
                    256: 
1.26      paf       257: 
                    258: static void get_hash__put(const String::Body key, const String& value, void* aresult) {
                    259:        static_cast<HashStringValue*>(aresult)->put(key, new VString(value));
                    260: }
                    261: HashStringValue *VHashfile::get_hash() {
                    262:        HashStringValue& result=*new HashStringValue();
                    263: 
                    264:        for_each(get_hash__put, &result);
                    265:        return &result;
1.34      paf       266: }
                    267: 
                    268: static void delete_file(const char* base_name, const char* ext) {
                    269:        String sfile_name(base_name, false/*already removed tainting at ::open*/);
                    270:        sfile_name<<ext;
                    271:        file_delete(sfile_name);
                    272: }
                    273: 
                    274: void VHashfile::delete_files() {
                    275:        close();
                    276:        delete_file(file_name, APR_SDBM_DIRFEXT);
                    277:        delete_file(file_name, APR_SDBM_PAGFEXT);
1.1       parser    278: }

E-mail: