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