Annotation of parser3/src/types/pa_vhashfile.C, revision 1.35
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.35 ! paf 8: static const char* IDENT="$Date: 2003/11/10 06:51:06 $";
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.34 paf 34: check("apr_sdbm_open(shared)", apr_sdbm_open(&m_db, file_name=afile_name.cstr(String::L_FILE_SPEC),
1.27 paf 35: APR_CREATE|APR_READ|APR_SHARELOCK,
1.22 paf 36: 0664, 0));
37: }
38:
1.34 paf 39: void VHashfile::close() {
40: check_db();
41:
42: check("apr_sdbm_close", apr_sdbm_close(m_db)); m_db=0;
43: }
44:
45: void VHashfile::check_db() const {
46: if(!m_db)
47: throw Exception(0,
48: 0,
49: "%s is closed", type());
50: }
51:
52: apr_sdbm_t *VHashfile::get_db_for_reading() const {
53: check_db();
54:
55: return m_db;
56: }
57:
58: apr_sdbm_t *VHashfile::get_db_for_writing() {
59: check_db();
60:
61: if(apr_sdbm_rdonly(m_db)) {
62: // reopen in write mode & exclusive lock
63: close();
64: check("apr_sdbm_open(exclusive)", apr_sdbm_open(&m_db, file_name,
1.27 paf 65: APR_WRITE,
66: 0664, 0));
67: }
1.34 paf 68:
69: return m_db;
1.27 paf 70: }
71:
1.22 paf 72: VHashfile::~VHashfile() {
1.34 paf 73: if(m_db)
74: close();
1.22 paf 75: }
76:
1.32 paf 77: struct Hashfile_value_serialized_prolog {
78: int version;
79: time_t time_to_die;
80: };
81:
1.35 ! paf 82: apr_sdbm_datum_t VHashfile::serialize_value(const String& string, time_t time_to_die) const {
1.32 paf 83: apr_sdbm_datum_t result;
84:
85: size_t length=string.length();
86: result.dsize=sizeof(Hashfile_value_serialized_prolog)+length;
87: result.dptr=new(PointerFreeGC) char[result.dsize];
88:
89: Hashfile_value_serialized_prolog& prolog=*reinterpret_cast<Hashfile_value_serialized_prolog*>(result.dptr);
90: char *output_cstr=result.dptr+sizeof(Hashfile_value_serialized_prolog);
91:
92: prolog.version=HASHFILE_VALUE_SERIALIZED_VERSION;
93: prolog.time_to_die=time_to_die;
94: memcpy(output_cstr, string.cstr(), length);
95:
96: return result;
97: }
98:
1.35 ! paf 99: const String* VHashfile::deserialize_value(apr_sdbm_datum_t key, const apr_sdbm_datum_t value) {
! 100: // key not found || it's surely not in our format
! 101: if(!value.dptr || value.dsize<sizeof(Hashfile_value_serialized_prolog))
! 102: return 0;
! 103:
! 104: Hashfile_value_serialized_prolog& prolog=*reinterpret_cast<Hashfile_value_serialized_prolog*>(value.dptr);
! 105: if(prolog.version!=HASHFILE_VALUE_SERIALIZED_VERSION
! 106: || (prolog.time_to_die/*specified*/
! 107: && (prolog.time_to_die <= time(0)/*expired*/))) {
! 108: // old format || exipred value
! 109: remove(key);
1.32 paf 110: return 0;
1.35 ! paf 111: }
1.32 paf 112:
1.35 ! paf 113: char *input_cstr=value.dptr+sizeof(Hashfile_value_serialized_prolog);
! 114: size_t input_length=value.dsize-sizeof(Hashfile_value_serialized_prolog);
1.32 paf 115:
116: return new String(pa_strdup(input_length?input_cstr:0, input_length), true);
117: }
118:
1.27 paf 119: void VHashfile::put_field(const String& aname, Value *avalue) {
1.34 paf 120: apr_sdbm_t *db=get_db_for_writing();
1.22 paf 121:
1.8 parser 122: time_t time_to_die=0;
123: const String *value_string;
124:
1.23 paf 125: if(HashStringValue *hash=avalue->get_hash()) {
126: if(Value *value_value=hash->get(value_name)) {
1.9 parser 127: if(value_value->get_junction())
1.23 paf 128: throw Exception(0,
129: 0,
130: VALUE_NAME" must not be code");
1.8 parser 131:
132: value_string=&value_value->as_string();
133:
1.32 paf 134: if(Value *expires=hash->get(expires_name)) {
135: if(Value* vdate=expires->as(VDATE_TYPE, false))
136: time_to_die=static_cast<VDate*>(vdate)->get_time(); // $expires[DATE]
137: else if(double days_till_expire=expires->as_double())
138: time_to_die=time(NULL)+(time_t)(60*60*24*days_till_expire); // $expires(days)
139: }
1.8 parser 140: } else
1.23 paf 141: throw Exception(0,
1.8 parser 142: &aname,
1.23 paf 143: "put hash value must contain ."VALUE_NAME);
1.8 parser 144: } else
145: value_string=&avalue->as_string();
1.5 parser 146:
1.23 paf 147: apr_sdbm_datum_t key;
148: key.dptr=const_cast<char*>(aname.cstr());
1.24 paf 149: key.dsize=aname.length();
1.23 paf 150:
1.32 paf 151: apr_sdbm_datum_t value=serialize_value(*value_string, time_to_die);
1.23 paf 152:
153: check("apr_sdbm_store", apr_sdbm_store(db, key, value, APR_SDBM_REPLACE));
1.1 parser 154: }
155:
1.11 paf 156: Value *VHashfile::get_field(const String& aname) {
1.34 paf 157: apr_sdbm_t *db=get_db_for_reading();
158:
1.23 paf 159: apr_sdbm_datum_t key;
160: key.dptr=const_cast<char*>(aname.cstr());
1.24 paf 161: key.dsize=aname.length();
1.23 paf 162:
163: apr_sdbm_datum_t value;
164:
165: check("apr_sdbm_fetch", apr_sdbm_fetch(db, &value, key));
166:
1.35 ! paf 167: const String *sresult=deserialize_value(key, value);
1.32 paf 168: return sresult? new VString(*sresult): 0;
1.24 paf 169: }
170:
1.35 ! paf 171: void VHashfile::remove(const apr_sdbm_datum_t key) {
1.34 paf 172: apr_sdbm_t *db=get_db_for_writing();
1.27 paf 173:
1.35 ! paf 174: check("apr_sdbm_delete", apr_sdbm_delete(db, key));
! 175: }
! 176:
! 177: void VHashfile::remove(const String& aname) {
1.24 paf 178: apr_sdbm_datum_t key;
179: key.dptr=const_cast<char*>(aname.cstr());
180: key.dsize=aname.length();
181:
1.35 ! paf 182: remove(key);
1.1 parser 183: }
184:
1.27 paf 185: void VHashfile::for_each(void callback(apr_sdbm_datum_t, void*), void* info) const {
1.34 paf 186: apr_sdbm_t *db=get_db_for_reading();
187:
1.30 paf 188: Array<apr_sdbm_datum_t> keys;
189:
190: // collect keys
1.25 paf 191: check("apr_sdbm_lock", apr_sdbm_lock(db, APR_FLOCK_SHARED));
192: try {
1.30 paf 193: apr_sdbm_datum_t key;
194: if(apr_sdbm_firstkey(db, &key)==APR_SUCCESS)
1.25 paf 195: do {
1.30 paf 196: keys+=key;
197: } while(apr_sdbm_nextkey(db, &key)==APR_SUCCESS);
1.25 paf 198: } catch(...) {
199: check("apr_sdbm_unlock", apr_sdbm_unlock(db));
200: rethrow;
1.4 parser 201: }
1.30 paf 202: check("apr_sdbm_unlock", apr_sdbm_unlock(db));
1.4 parser 203:
1.30 paf 204: // iterate them
205: keys.for_each(callback, info);
1.26 paf 206: }
1.27 paf 207:
208: #ifndef DOXYGEN
209: struct For_each_string_callback_info {
1.35 ! paf 210: VHashfile* self;
1.27 paf 211: void* nested_info;
212: void (*nested_callback)(const String::Body, const String&, void*);
213: };
214: #endif
215: static void for_each_string_callback(apr_sdbm_datum_t apkey, void* ainfo) {
216: For_each_string_callback_info& info=*static_cast<For_each_string_callback_info *>(ainfo);
1.35 ! paf 217: apr_sdbm_t *db=info.self->get_db_for_reading();
1.27 paf 218:
219: apr_sdbm_datum_t apvalue;
1.35 ! paf 220: check("apr_sdbm_fetch", apr_sdbm_fetch(db, &apvalue, apkey));
! 221:
! 222: if(const String* svalue=info.self->deserialize_value(apkey, apvalue)) {
! 223: const char *clkey=pa_strdup(apkey.dptr, apkey.dsize);
1.27 paf 224:
1.32 paf 225: info.nested_callback(clkey, *svalue, info.nested_info);
1.35 ! paf 226: }
1.27 paf 227: }
1.35 ! paf 228: void VHashfile::for_each(void callback(const String::Body, const String&, void*), void* ainfo) {
1.34 paf 229: apr_sdbm_t *db=get_db_for_reading();
230:
1.27 paf 231: For_each_string_callback_info info;
232:
1.35 ! paf 233: info.self=this;
1.27 paf 234: info.nested_info=ainfo;
235: info.nested_callback=callback;
236:
237: for_each(for_each_string_callback, &info);
238: }
239:
1.30 paf 240: static void clear_delete_key(apr_sdbm_datum_t key, void* adb) {
241: check("apr_sdbm_delete", apr_sdbm_delete(static_cast<apr_sdbm_t*>(adb), key));
1.27 paf 242: }
243: void VHashfile::clear() {
1.34 paf 244: apr_sdbm_t *db=get_db_for_writing();
1.27 paf 245:
1.30 paf 246: for_each(clear_delete_key, db);
1.27 paf 247: }
248:
1.26 paf 249:
250: static void get_hash__put(const String::Body key, const String& value, void* aresult) {
251: static_cast<HashStringValue*>(aresult)->put(key, new VString(value));
252: }
253: HashStringValue *VHashfile::get_hash() {
254: HashStringValue& result=*new HashStringValue();
255:
256: for_each(get_hash__put, &result);
257: return &result;
1.34 paf 258: }
259:
260: static void delete_file(const char* base_name, const char* ext) {
261: String sfile_name(base_name, false/*already removed tainting at ::open*/);
262: sfile_name<<ext;
263: file_delete(sfile_name);
264: }
265:
266: void VHashfile::delete_files() {
267: close();
268: delete_file(file_name, APR_SDBM_DIRFEXT);
269: delete_file(file_name, APR_SDBM_PAGFEXT);
1.1 parser 270: }
E-mail: