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: