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