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