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

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.33    ! paf         8: static const char* IDENT="$Date: 2003/11/06 12:58:27 $";
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: 
                     19: const int 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.33    ! paf        27:        throw Exception("file.access",
1.22      paf        28:                0,
1.33    ! paf        29:                "%s error: %s (%d)", 
        !            30:                        step, strerror(status), status);
1.22      paf        31: }
                     32: 
                     33: void VHashfile::open(const String& afile_name) {
1.27      paf        34:        check("apr_sdbm_open(shared)", apr_sdbm_open(&db, file_name=afile_name.cstr(String::L_FILE_SPEC), 
                     35:                                         APR_CREATE|APR_READ|APR_SHARELOCK, 
1.22      paf        36:                                         0664, 0));
                     37: }
                     38: 
1.27      paf        39: void VHashfile::make_writable() {
                     40:        if(db && apr_sdbm_rdonly(db)) {
                     41:                check("apr_sdbm_close", apr_sdbm_close(db));
                     42:                check("apr_sdbm_open(exclusive)", apr_sdbm_open(&db, file_name, 
                     43:                                                                                        APR_WRITE, 
                     44:                                                                                        0664, 0));
                     45:        }
                     46: }
                     47: 
1.22      paf        48: VHashfile::~VHashfile() {
                     49:        if(db)
                     50:                check("apr_sdbm_close", apr_sdbm_close(db));
                     51: }
                     52: 
1.32      paf        53: struct Hashfile_value_serialized_prolog {
                     54:        int version;
                     55:        time_t time_to_die;
                     56: };
                     57: 
                     58: static apr_sdbm_datum_t serialize_value(const String& string, time_t time_to_die) {
                     59:        apr_sdbm_datum_t result;
                     60: 
                     61:        size_t length=string.length();
                     62:        result.dsize=sizeof(Hashfile_value_serialized_prolog)+length;
                     63:        result.dptr=new(PointerFreeGC) char[result.dsize];
                     64: 
                     65:        Hashfile_value_serialized_prolog& prolog=*reinterpret_cast<Hashfile_value_serialized_prolog*>(result.dptr);
                     66:        char *output_cstr=result.dptr+sizeof(Hashfile_value_serialized_prolog);
                     67: 
                     68:        prolog.version=HASHFILE_VALUE_SERIALIZED_VERSION;
                     69:        prolog.time_to_die=time_to_die;
                     70:        memcpy(output_cstr, string.cstr(), length);
                     71: 
                     72:        return result;
                     73: }
                     74: 
                     75: static const String* deserialize_value(const apr_sdbm_datum_t datum) {
                     76:        if(!datum.dptr || datum.dsize<sizeof(Hashfile_value_serialized_prolog))
                     77:                return 0;
                     78: 
                     79:        Hashfile_value_serialized_prolog& prolog=*reinterpret_cast<Hashfile_value_serialized_prolog*>(datum.dptr);
                     80:        if(prolog.version!=HASHFILE_VALUE_SERIALIZED_VERSION)
                     81:                return 0;
                     82:        
                     83:        if(prolog.time_to_die/*specified*/ 
                     84:                && (prolog.time_to_die <= time(0)/*expired*/))
                     85:                return 0;
                     86:        
                     87:        char *input_cstr=datum.dptr+sizeof(Hashfile_value_serialized_prolog);
                     88:        size_t input_length=datum.dsize-sizeof(Hashfile_value_serialized_prolog);
                     89: 
                     90:        return new String(pa_strdup(input_length?input_cstr:0, input_length), true);
                     91: }
                     92: 
1.27      paf        93: void VHashfile::put_field(const String& aname, Value *avalue) {
                     94:        make_writable();
1.22      paf        95: 
1.8       parser     96:        time_t time_to_die=0;
                     97:        const String *value_string;
                     98: 
1.23      paf        99:        if(HashStringValue *hash=avalue->get_hash()) {
                    100:                if(Value *value_value=hash->get(value_name)) {
1.9       parser    101:                        if(value_value->get_junction())
1.23      paf       102:                                throw Exception(0,
                    103:                                        0,
                    104:                                        VALUE_NAME" must not be code");
1.8       parser    105: 
                    106:                        value_string=&value_value->as_string();
                    107: 
1.32      paf       108:                        if(Value *expires=hash->get(expires_name)) {
                    109:                                if(Value* vdate=expires->as(VDATE_TYPE, false))
                    110:                                        time_to_die=static_cast<VDate*>(vdate)->get_time(); // $expires[DATE]
                    111:                                else if(double days_till_expire=expires->as_double())
                    112:                                        time_to_die=time(NULL)+(time_t)(60*60*24*days_till_expire); // $expires(days)
                    113:                        }
1.8       parser    114:                } else
1.23      paf       115:                        throw Exception(0,
1.8       parser    116:                                &aname,
1.23      paf       117:                                "put hash value must contain ."VALUE_NAME);
1.8       parser    118:        } else
                    119:                value_string=&avalue->as_string();
1.5       parser    120: 
1.23      paf       121:        apr_sdbm_datum_t key;
                    122:        key.dptr=const_cast<char*>(aname.cstr());
1.24      paf       123:        key.dsize=aname.length();
1.23      paf       124: 
1.32      paf       125:        apr_sdbm_datum_t value=serialize_value(*value_string, time_to_die);
1.23      paf       126: 
                    127:        check("apr_sdbm_store", apr_sdbm_store(db, key, value, APR_SDBM_REPLACE));
1.1       parser    128: }
                    129: 
1.11      paf       130: Value *VHashfile::get_field(const String& aname) {
1.23      paf       131:        apr_sdbm_datum_t key;
                    132:        key.dptr=const_cast<char*>(aname.cstr());
1.24      paf       133:        key.dsize=aname.length();
1.23      paf       134: 
                    135:        apr_sdbm_datum_t value;
                    136: 
                    137:        check("apr_sdbm_fetch", apr_sdbm_fetch(db, &value, key));
                    138: 
1.32      paf       139:        const String *sresult=deserialize_value(value);
                    140:        return sresult? new VString(*sresult): 0;
1.24      paf       141: }
                    142: 
                    143: void VHashfile::remove(const String& aname) {
1.27      paf       144:        make_writable();
                    145: 
1.24      paf       146:        apr_sdbm_datum_t key;
                    147:        key.dptr=const_cast<char*>(aname.cstr());
                    148:        key.dsize=aname.length();
                    149: 
                    150:        check("apr_sdbm_delete", apr_sdbm_delete(db, key));
1.1       parser    151: }
                    152: 
1.27      paf       153: void VHashfile::for_each(void callback(apr_sdbm_datum_t, void*), void* info) const {
1.30      paf       154:        Array<apr_sdbm_datum_t> keys;
                    155: 
                    156:        // collect keys
1.25      paf       157:        check("apr_sdbm_lock", apr_sdbm_lock(db, APR_FLOCK_SHARED));
                    158:        try {
1.30      paf       159:                apr_sdbm_datum_t key;
                    160:                if(apr_sdbm_firstkey(db, &key)==APR_SUCCESS)
1.25      paf       161:                        do {
1.30      paf       162:                                keys+=key;
                    163:                        } while(apr_sdbm_nextkey(db, &key)==APR_SUCCESS);
1.25      paf       164:        } catch(...) {
                    165:                        check("apr_sdbm_unlock", apr_sdbm_unlock(db));
                    166:                        rethrow;
1.4       parser    167:        }
1.30      paf       168:        check("apr_sdbm_unlock", apr_sdbm_unlock(db));
1.4       parser    169: 
1.30      paf       170:        // iterate them
                    171:        keys.for_each(callback, info);
1.26      paf       172: }
1.27      paf       173: 
                    174: #ifndef DOXYGEN
                    175: struct For_each_string_callback_info {
                    176:        apr_sdbm_t *db;
                    177:        void* nested_info;
                    178:        void (*nested_callback)(const String::Body, const String&, void*);
                    179: };
                    180: #endif
                    181: static void for_each_string_callback(apr_sdbm_datum_t apkey, void* ainfo) {
                    182:        For_each_string_callback_info& info=*static_cast<For_each_string_callback_info *>(ainfo);
                    183: 
                    184:        apr_sdbm_datum_t apvalue;
                    185:        check("apr_sdbm_fetch", apr_sdbm_fetch(info.db, &apvalue, apkey));
                    186: 
                    187:        const char *clkey=pa_strdup(apkey.dptr, apkey.dsize);
1.32      paf       188:        if(const String* svalue=deserialize_value(apvalue))
                    189:                info.nested_callback(clkey, *svalue, info.nested_info);
1.27      paf       190: }
                    191: void VHashfile::for_each(void callback(const String::Body, const String&, void*), void* ainfo) const {
                    192:        For_each_string_callback_info info;
                    193:        
                    194:        info.db=db;
                    195:        info.nested_info=ainfo;
                    196:        info.nested_callback=callback;
                    197: 
                    198:        for_each(for_each_string_callback, &info);
                    199: }
                    200: 
1.30      paf       201: static void clear_delete_key(apr_sdbm_datum_t key, void* adb) {
                    202:        check("apr_sdbm_delete", apr_sdbm_delete(static_cast<apr_sdbm_t*>(adb), key));
1.27      paf       203: }
                    204: void VHashfile::clear() {
                    205:        make_writable();
                    206: 
1.30      paf       207:        for_each(clear_delete_key, db);
1.27      paf       208: }
                    209: 
1.26      paf       210: 
                    211: static void get_hash__put(const String::Body key, const String& value, void* aresult) {
                    212:        static_cast<HashStringValue*>(aresult)->put(key, new VString(value));
                    213: }
                    214: HashStringValue *VHashfile::get_hash() {
                    215:        HashStringValue& result=*new HashStringValue();
                    216: 
                    217:        for_each(get_hash__put, &result);
                    218:        return &result;
1.1       parser    219: }

E-mail: