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