Annotation of parser3/src/main/pa_db_table.C, revision 1.17
1.1 paf 1: /** @file
2: Parser: Charset table implementation.
3:
4: Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)
1.11 paf 5: Author: Alexander Petrosyan <paf@design.ru> (http://paf.design.ru)
1.1 paf 6:
1.17 ! paf 7: $Id: pa_db_table.C,v 1.16 2001/12/17 19:16:09 paf Exp $
1.1 paf 8: */
9:
10: #include "pa_config_includes.h"
1.5 paf 11: #ifdef DB2
1.1 paf 12:
13: #include "pa_db_table.h"
14: #include "pa_exception.h"
1.3 paf 15: #include "pa_db_connection.h"
1.10 paf 16: #include "pa_threads.h"
1.1 paf 17:
18: // defines
19:
1.7 paf 20: #ifdef DB_RMW
1.6 paf 21: # define DEADLOCK_POSSIBILITY_REDUCTION_FLAGS DB_RMW
22: #else
23: # define DEADLOCK_POSSIBILITY_REDUCTION_FLAGS 0
24: #endif
1.1 paf 25:
26: // consts
27:
1.14 paf 28: const int DATA_STRING_SERIALIZED_VERSION=0x0002;
1.1 paf 29:
30: // helper types
31:
32: #ifndef DOXYGEN
33: struct Data_string_serialized_prolog {
34: int version;
1.14 paf 35: time_t time_of_creating;
36: time_t lifespan;
1.1 paf 37: };
1.3 paf 38:
39: struct DBT_auto : public DBT {
40: DBT_auto() {
41: data=0;
42: size=ulen=dlen=doff=0;
43: flags=DB_DBT_MALLOC;
44: }
45:
46: ~DBT_auto() {
47: if(flags & DB_DBT_MALLOC)
48: free(data);
49: }
50: };
51:
1.1 paf 52: #endif
53:
54: // DB_Table
55:
1.3 paf 56: DB_Table::DB_Table(Pool& pool, const String& afile_name, DB_Connection& aconnection) : Pooled(pool),
1.16 paf 57: time_used(0),
1.1 paf 58: fconnection(aconnection),
59: dbenv(aconnection.dbenv),
1.3 paf 60: ffile_name(afile_name), file_name_cstr(afile_name.cstr(String::UL_FILE_SPEC)),
1.11 paf 61: db(0), used(0) {
1.3 paf 62:
63: // open
64: DB_INFO dbinfo;
65: memset(&dbinfo, 0, sizeof(dbinfo));
66: check("open/create", &ffile_name, db_open(
67: file_name_cstr,
68: PA_DB_ACCESS_METHOD,
1.12 paf 69: (parser_multithreaded?DB_THREAD:0)
1.10 paf 70: | DB_CREATE,
1.14 paf 71: 0664,
1.3 paf 72: &dbenv, &dbinfo, &db));
73: }
74: /// @todo this one of reasons of not having ^try for now
75: DB_Table::~DB_Table() {
76: // close
77: check("close", &ffile_name, db->close(db, 0/*flags*/)); db=0;
78: }
79:
80: void DB_Table::use() {
81: fconnection.use();
82:
83: time_used=time(0); // they started to use at this time
84: used++;
85: }
86: void DB_Table::unuse() {
87: used--;
88:
89: fconnection.unuse();
1.1 paf 90: }
91:
1.3 paf 92:
93:
1.1 paf 94: void DB_Table::check(const char *operation, const String *source, int error) {
95: switch(error) {
96: case 0:
97: // no error
98: break;
99:
100: case DB_KEYEXIST:
101: // DB_KEYEXIST is a "normal" return, so should not be
102: // thrown as an error
103: break;
104:
1.6 paf 105: #ifdef DB_RUNRECOVERY
1.1 paf 106: case DB_RUNRECOVERY:
107: throw Exception(0, 0,
108: source,
109: "action failed, RUN RECOVERY UTILITY. db %s error, real filename '%s'",
1.3 paf 110: operation, file_name_cstr);
1.6 paf 111: #endif
112:
1.1 paf 113: default:
1.8 paf 114: if(error<0)
115: throw Exception(0, 0,
116: source,
117: "action failed. db %s error: %d, real filename '%s'",
118: operation, error, file_name_cstr);
119: else
120: throw Exception(0, 0,
121: source,
122: "action failed. db %s error: %s (%d), real filename '%s'",
123: operation, strerror(error), error, file_name_cstr);
1.1 paf 124: }
125: }
126:
127: void DB_Table::key_string_to_dbt(const String& key_string, DBT& key_result) {
128: memset(&key_result, 0, sizeof(key_result));
1.9 paf 129: key_result.data=key_string.cstr();
1.1 paf 130: key_result.size=key_string.size();
131: }
132:
1.3 paf 133: String& DB_Table::key_dbt_to_string(Pool& pool, const DBT& key_dbt) {
1.16 paf 134: String& result=*new(pool) String(pool);
1.1 paf 135: if(key_dbt.size) {
1.3 paf 136: char *request_data=(char *)pool.malloc(key_dbt.size);
1.1 paf 137: memcpy(request_data, key_dbt.data, key_dbt.size);
1.3 paf 138: result.APPEND_TAINTED(request_data, key_dbt.size, file_name_cstr, 0/*line*/);
1.1 paf 139: }
140: return result;
141: }
142:
1.14 paf 143: void DB_Table::data_string_to_dbt(const String& data_string, time_t lifespan,
1.1 paf 144: DBT& data_result) {
145: memset(&data_result, 0, sizeof(data_result));
146:
147: data_string.serialize(
148: sizeof(Data_string_serialized_prolog),
149: data_result.data, data_result.size);
150:
151: Data_string_serialized_prolog& prolog=
152: *static_cast<Data_string_serialized_prolog *>(data_result.data);
153:
154: prolog.version=DATA_STRING_SERIALIZED_VERSION;
1.14 paf 155: prolog.time_of_creating=time(0)/*now*/;
156: prolog.lifespan=lifespan;
1.1 paf 157: }
158:
1.14 paf 159: String *DB_Table::data_dbt_to_string(Pool& pool, const DBT& data_dbt, time_t lifespan) {
1.1 paf 160: Data_string_serialized_prolog& prolog=
161: *static_cast<Data_string_serialized_prolog *>(data_dbt.data);
162:
163: if(prolog.version!=DATA_STRING_SERIALIZED_VERSION)
164: throw Exception(0, 0,
1.3 paf 165: &ffile_name,
1.1 paf 166: "data string version 0x%04X not equal to 0x%04X, recreate file",
167: prolog.version, DATA_STRING_SERIALIZED_VERSION);
168:
1.14 paf 169: if(lifespan/*specified*/
170: && prolog.lifespan!=lifespan) // lifespan changed from storing to getting
171: return 0; // considering this 'expired'
172:
173: if(prolog.lifespan/*specified*/
174: && ((prolog.time_of_creating+prolog.lifespan) <= time(0)/*expired*/))
1.1 paf 175: return 0;
176:
1.3 paf 177: String& result=*new(pool) String(pool);
1.17 ! paf 178: if(data_dbt.size>sizeof(Data_string_serialized_prolog)) {
1.3 paf 179: char *data=(char *)pool.malloc(data_dbt.size);
180: memcpy(data, data_dbt.data, data_dbt.size);
181: result.deserialize(
182: sizeof(Data_string_serialized_prolog),
183: data, data_dbt.size, file_name_cstr);
184: }
1.1 paf 185: return &result;
186: }
187:
1.3 paf 188: void DB_Table::put(DB_Transaction *t, const String& key, const String& data, time_t time_to_die) {
1.1 paf 189: DBT dbt_key; key_string_to_dbt(key, dbt_key);
190: DBT dbt_data; data_string_to_dbt(data, time_to_die, dbt_data);
1.3 paf 191: check("put", &key, db->put(db, t?t->id():0, &dbt_key, &dbt_data, 0/*flags*/));
1.1 paf 192: }
193:
1.14 paf 194: String *DB_Table::get(DB_Transaction *t, Pool& pool, const String& key, time_t lifespan) {
1.1 paf 195: DBT dbt_key; key_string_to_dbt(key, dbt_key);
1.3 paf 196: DBT_auto dbt_data;
197: int error=db->get(db, t?t->id():0, &dbt_key, &dbt_data,
198: DEADLOCK_POSSIBILITY_REDUCTION_FLAGS);
1.1 paf 199: if(error==DB_NOTFOUND)
200: return 0;
201: else {
202: check("get", &key, error);
1.14 paf 203: String *result=data_dbt_to_string(pool, dbt_data, lifespan);
1.1 paf 204: if(!result) // save efforts by deleting expired keys
1.3 paf 205: check("del expired", &key, db->del(db, t?t->id():0, &dbt_key, 0/*flags*/));
1.1 paf 206: return result;
207: }
208: }
209:
1.3 paf 210: void DB_Table::remove(DB_Transaction *t, const String& key) {
1.1 paf 211: DBT dbt_key; key_string_to_dbt(key, dbt_key);
212:
1.3 paf 213: int error=db->del(db, t?t->id():0, &dbt_key, 0/*flags*/);
1.1 paf 214: if(error!=DB_NOTFOUND)
215: check("del", &key, error);
216: }
217:
1.3 paf 218: // DB_Transaction
219:
220: DB_Transaction::DB_Transaction(Pool& apool, DB_Table& atable, DB_Transaction *& aparent_ref) :
221: fpool(apool), ftable(atable), fparent_ref(aparent_ref),
222: parent(aparent_ref),
223: fid(0), marked_to_rollback(false) {
224:
225: check("txn_begin",
226: &ftable.file_name(), txn_begin(ftable.dbenv.tx_info, parent?parent->fid:0, &fid));
227:
228: aparent_ref=this;
229: }
230: DB_Transaction::~DB_Transaction() {
231: fparent_ref=parent;
232:
233: if(parent) // all in hands of our parent
234: return;
235:
236: if(marked_to_rollback)
237: check("txn_abort", &ftable.file_name(), txn_abort(fid));
238: else
239: check("txn_commit", &ftable.file_name(), txn_commit(fid));
240: }
241: void DB_Transaction::mark_to_rollback() {
242: if(parent)
243: parent->mark_to_rollback();
244: else
245: marked_to_rollback=true;
246: }
247:
1.1 paf 248: // DB_Cursor
249:
250: DB_Cursor::DB_Cursor(
1.3 paf 251: DB_Table& atable, DB_Transaction *transaction,
252: const String *asource) :
253: ftable(atable), fsource(asource),
254: cursor(0) {
255:
1.1 paf 256: check("cursor", fsource, ftable.db->cursor(ftable.db,
1.6 paf 257: transaction?transaction->id():0, &cursor
258: #if DB_VERSION_MINOR >= 7
259: , 0/*flags*/
260: #endif
261: ));
1.1 paf 262: }
263:
264: DB_Cursor::~DB_Cursor() {
1.3 paf 265: if(cursor)
266: check("c_close", fsource, cursor->c_close(cursor));
1.1 paf 267: }
268:
1.3 paf 269: bool DB_Cursor::get(Pool& pool, String *& key, String *& data, u_int32_t flags) {
1.1 paf 270: DBT dbt_key={0}; // must be zeroed
1.3 paf 271: DBT_auto dbt_data;
1.1 paf 272:
1.3 paf 273: int error=cursor->c_get(cursor, &dbt_key, &dbt_data,
274: DEADLOCK_POSSIBILITY_REDUCTION_FLAGS
275: | flags
276: );
1.1 paf 277: if(error==DB_NOTFOUND)
278: return false;
279:
280: check("c_get", fsource, error);
281:
1.14 paf 282: if(data=data_dbt_to_string(pool, dbt_data, 0)) // not expired
1.3 paf 283: key=&key_dbt_to_string(pool, dbt_key);
1.1 paf 284: else {
285: // save efforts by deleting expired keys
286: remove(0/*flags*/);
287: key=0;
288: }
1.4 paf 289: return true;
290: }
291:
292: bool DB_Cursor::move(u_int32_t flags) {
293: DBT dbt_key={0}; // must be zeroed
294: DBT dbt_data={0}; // must be zeroed
295: dbt_key.flags=dbt_data.flags=DB_DBT_PARTIAL; // just peep, not actually read [size=0]
296:
297: int error=cursor->c_get(cursor, &dbt_key, &dbt_data,
298: DEADLOCK_POSSIBILITY_REDUCTION_FLAGS
299: | flags
300: );
301: if(error==DB_NOTFOUND)
302: return false;
303:
304: check("c_get", fsource, error);
1.1 paf 305: return true;
306: }
307:
308: void DB_Cursor::remove(u_int32_t flags) {
309: check("c_del", fsource, cursor->c_del(cursor, flags));
310: }
311:
312: #endif
E-mail: