Annotation of parser3/src/main/pa_db_table.C, revision 1.2
1.1 paf 1: /** @file
2: Parser: Charset table implementation.
3:
4: Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)
5: Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf)
6:
1.2 ! paf 7: $Id: pa_db_table.C,v 1.1 2001/10/25 13:18:19 paf Exp $
1.1 paf 8: */
9:
10: #include "pa_config_includes.h"
11: #ifdef HAVE_LIBDB
12:
13: #include "pa_db_table.h"
14: #include "pa_exception.h"
15:
16: // defines
17:
18: #define READ_ADDITIONAL_FLAGS DB_RMW
19:
20: // consts
21:
22: const int DATA_STRING_SERIALIZED_VERSION=0x0100;
23:
24: // helper types
25:
26: #ifndef DOXYGEN
27: struct Data_string_serialized_prolog {
28: int version;
29: time_t time_to_die;
30: };
31: #endif
32:
33: // DB_Table
34:
35: DB_Table::DB_Table(Pool& pool, const String& afile_spec, DB_Connection& aconnection) : Pooled(pool),
36: time_used(0), fservices_pool(0),
37: fconnection(aconnection),
38: dbenv(aconnection.dbenv),
39: ffile_spec(afile_spec), file_spec_cstr(afile_spec.cstr(String::UL_FILE_SPEC)),
1.2 ! paf 40: db(0), ftid(0), ftid_has_parent(false), errors(0) {
1.1 paf 41: }
42:
43: void DB_Table::check(const char *operation, const String *source, int error) {
44: switch(error) {
45: case 0:
46: // no error
47: break;
48:
49: case DB_KEYEXIST:
50: // DB_KEYEXIST is a "normal" return, so should not be
51: // thrown as an error
52: break;
53:
54: case DB_RUNRECOVERY:
55: errors++;
56: throw Exception(0, 0,
57: source,
58: "action failed, RUN RECOVERY UTILITY. db %s error, real filename '%s'",
59: operation, file_spec_cstr);
60:
61: default:
62: errors++;
63: throw Exception(0, 0,
64: source,
65: "action failed. db %s error: %s (%d), real filename '%s'",
66: operation, strerror(error), error, file_spec_cstr);
67: }
68: }
69:
70: void DB_Table::key_string_to_dbt(const String& key_string, DBT& key_result) {
71: memset(&key_result, 0, sizeof(key_result));
72: key_result.data=key_string.cstr(String::UL_AS_IS);
73: key_result.size=key_string.size();
74: }
75:
76: String& DB_Table::key_dbt_to_string(const DBT& key_dbt) {
77: String& result=*new(*fservices_pool) String(*fservices_pool);
78: if(key_dbt.size) {
79: char *request_data=(char *)malloc(key_dbt.size);
80: memcpy(request_data, key_dbt.data, key_dbt.size);
81: result.APPEND_TAINTED(request_data, key_dbt.size, file_spec_cstr, 0/*line*/);
82: }
83: return result;
84: }
85:
86: void DB_Table::data_string_to_dbt(const String& data_string, time_t time_to_die,
87: DBT& data_result) {
88: memset(&data_result, 0, sizeof(data_result));
89:
90: data_string.serialize(
91: sizeof(Data_string_serialized_prolog),
92: data_result.data, data_result.size);
93:
94: Data_string_serialized_prolog& prolog=
95: *static_cast<Data_string_serialized_prolog *>(data_result.data);
96:
97: prolog.version=DATA_STRING_SERIALIZED_VERSION;
98: prolog.time_to_die=time_to_die;
99: }
100:
101: String *DB_Table::data_dbt_to_string(const DBT& data_dbt) {
102: Data_string_serialized_prolog& prolog=
103: *static_cast<Data_string_serialized_prolog *>(data_dbt.data);
104:
105: if(prolog.version!=DATA_STRING_SERIALIZED_VERSION)
106: throw Exception(0, 0,
107: &ffile_spec,
108: "data string version 0x%04X not equal to 0x%04X, recreate file",
109: prolog.version, DATA_STRING_SERIALIZED_VERSION);
110:
111: if(prolog.time_to_die/*specified*/ && prolog.time_to_die <= time(0)/*expired*/)
112: return 0;
113:
114: String& result=*new(*fservices_pool) String(*fservices_pool);
115: result.deserialize(
116: sizeof(Data_string_serialized_prolog),
117: data_dbt.data, data_dbt.size, file_spec_cstr);
118: return &result;
119: }
120:
121: void DB_Table::connect() {
122: // open
123: DB_INFO dbinfo;
124: memset(&dbinfo, 0, sizeof(dbinfo));
125: check("open/create", &ffile_spec, db_open(
126: file_spec_cstr,
127: PA_DB_ACCESS_METHOD,
128: DB_CREATE /* used in single thread, no need for |DB_THREAD*/,
129: 0666,
130: &dbenv, &dbinfo, &db));
131: }
132: /// @todo this one of reasons of not having ^try for now
133: void DB_Table::disconnect() {
134: check("close", &ffile_spec, db->close(db, 0/*flags*/)); db=0;
135: }
136:
137: void DB_Table::put(const String& key, const String& data, time_t time_to_die) {
138: DBT dbt_key; key_string_to_dbt(key, dbt_key);
139: DBT dbt_data; data_string_to_dbt(data, time_to_die, dbt_data);
140: check("put", &key, db->put(db, ftid, &dbt_key, &dbt_data, 0/*flags*/));
141: }
142:
143: String *DB_Table::get(const String& key) {
144: DBT dbt_key; key_string_to_dbt(key, dbt_key);
145: DBT dbt_data={0}; // must be zeroed
146: int error=db->get(db, ftid, &dbt_key, &dbt_data, READ_ADDITIONAL_FLAGS/*flags*/);
147: if(error==DB_NOTFOUND)
148: return 0;
149: else {
150: check("get", &key, error);
151: String *result=data_dbt_to_string(dbt_data);
152: if(!result) // save efforts by deleting expired keys
153: check("del expired", &key, db->del(db, ftid, &dbt_key, 0/*flags*/));
154: return result;
155: }
156: }
157:
158: void DB_Table::remove(const String& key) {
159: DBT dbt_key; key_string_to_dbt(key, dbt_key);
160:
161: int error=db->del(db, ftid, &dbt_key, 0/*flags*/);
162: if(error!=DB_NOTFOUND)
163: check("del", &key, error);
164: }
165:
166: // DB_Cursor
167:
168: DB_Cursor::DB_Cursor(
169: DB_Table& atable,
170: const String *asource) : fsource(asource), ftable(atable), cursor(0) {
171: check("cursor", fsource, ftable.db->cursor(ftable.db,
172: ftable.ftid, &cursor, 0/*flags*/));
173: }
174:
175: DB_Cursor::~DB_Cursor() {
176: if(cursor) {
177: check("c_close", fsource, cursor->c_close(cursor)); cursor=0;
178: }
179: }
180:
181: bool DB_Cursor::get(String *& key, String *& data, u_int32_t flags) {
182: DBT dbt_key={0}; // must be zeroed
183: DBT dbt_data={0}; // must be zeroed
184:
185: int error=cursor->c_get(cursor, &dbt_key, &dbt_data, flags | READ_ADDITIONAL_FLAGS);
186: if(error==DB_NOTFOUND)
187: return false;
188:
189: check("c_get", fsource, error);
190:
191: if(data=data_dbt_to_string(dbt_data)) // not expired
192: key=&key_dbt_to_string(dbt_key);
193: else {
194: // save efforts by deleting expired keys
195: remove(0/*flags*/);
196: key=0;
197: }
198: return true;
199: }
200:
201: void DB_Cursor::remove(u_int32_t flags) {
202: check("c_del", fsource, cursor->c_del(cursor, flags));
203: }
204:
205: #endif
E-mail: