Annotation of parser3/src/main/pa_db_connection.C, revision 1.26
1.1 parser 1: /** @file
1.11 paf 2: Parser: sql driver connection implementation.
1.1 parser 3:
4: Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)
5: Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf)
6:
1.26 ! paf 7: $Id: pa_db_connection.C,v 1.25 2001/10/31 11:23:38 paf Exp $
1.20 paf 8:
9: developed with LIBDB 2.7.4
1.1 parser 10: */
11:
12: #include "pa_config_includes.h"
1.19 paf 13: #ifdef DB2
1.1 parser 14:
15: #include "pa_db_connection.h"
1.11 paf 16: #include "pa_db_table.h"
1.1 parser 17: #include "pa_exception.h"
1.11 paf 18: #include "pa_threads.h"
19: #include "pa_stack.h"
20: #include "pa_common.h"
1.1 parser 21:
1.14 paf 22: // defines
23:
1.11 paf 24: // consts
25:
1.15 paf 26: /// @test increase
27: const int DB_CHECKPOINT_MINUTES=1;
28:
1.11 paf 29: const int EXPIRE_UNUSED_TABLE_SECONDS=60;
30: const int CHECK_EXPIRED_TABLES_SECONDS=EXPIRE_UNUSED_TABLE_SECONDS*2;
31:
32: // callbacks
1.10 parser 33:
1.11 paf 34: static void db_paniccall(DB_ENV *dbenv, int error) {
35: throw Exception(0, 0,
36: 0,
37: "db_panic: %s (%d)",
38: strerror(error), error);
39: }
40:
41: static void db_errcall(const char *, char *buffer) {
42: throw Exception(0, 0,
43: 0,
1.23 paf 44: "db_err: %s",
1.11 paf 45: buffer);
46: }
1.5 parser 47:
1.13 paf 48: static void expire_table(const Hash::Key& key, Hash::Val *& value, void *info) {
1.22 paf 49: DB_Table& table=*static_cast<DB_Table *>(value);
1.11 paf 50: time_t older_dies=reinterpret_cast<time_t>(info);
1.5 parser 51:
1.13 paf 52: if(table.expired(older_dies)) {
1.22 paf 53: table.~DB_Table(); value=0;
1.13 paf 54: }
1.11 paf 55: }
1.5 parser 56:
1.3 parser 57: // DB_Connection
58:
1.13 paf 59: DB_Connection::DB_Connection(Pool& apool, const String& adb_home) : Pooled(apool),
60: time_used(0),
61: fdb_home(adb_home),
62: table_cache(apool),
1.11 paf 63: prev_expiration_pass_time(0) {
64: //_asm int 3;
65: char DB_DATA_DIR__VALUE[MAX_STRING];
66: char DB_LOG_DIR__VALUE[MAX_STRING];
67: char DB_TMP_DIR__VALUE[MAX_STRING];
68:
69: const char *db_home_cstr=fdb_home.cstr(String::UL_FILE_SPEC);
70:
71: snprintf(DB_DATA_DIR__VALUE, MAX_STRING, "DB_DATA_DIR %s", db_home_cstr);
72: snprintf(DB_LOG_DIR__VALUE, MAX_STRING, "DB_LOG_DIR %s", db_home_cstr);
73: snprintf(DB_TMP_DIR__VALUE, MAX_STRING, "DB_TMP_DIR %s", db_home_cstr);
74:
75: char *db_config[] = {
76: DB_DATA_DIR__VALUE,
77: DB_LOG_DIR__VALUE,
78: DB_TMP_DIR__VALUE,
79: 0
80: };
81:
82: u_int32_t flags=
1.25 paf 83: parser_multithreaded?DB_THREAD:0
1.13 paf 84: | DB_CREATE
1.11 paf 85: | DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN;
86:
1.16 paf 87: // trying to open with SOFT RECOVER option set
88: memset(&dbenv, 0, sizeof(dbenv));
89:
1.14 paf 90: // error handlers
1.20 paf 91: #if DB_VERSION_MINOR >= 7
1.14 paf 92: dbenv.db_paniccall=db_paniccall;
1.20 paf 93: #endif
1.14 paf 94: dbenv.db_errcall=db_errcall;
1.26 ! paf 95:
! 96: // lockdetector flags
! 97: dbenv.lk_detect=DB_LOCK_RANDOM;
1.16 paf 98:
99: // init
100: check("db_appinit", &fdb_home, db_appinit(
101: db_home_cstr,
102: db_config,
103: &dbenv,
104: flags
105: ));
1.11 paf 106: }
107:
1.13 paf 108: DB_Connection::~DB_Connection() {
1.11 paf 109: // close tables
1.13 paf 110: table_cache.for_each(expire_table,
1.11 paf 111: reinterpret_cast<void *>(0/* =in the past = expire[close] all*/));
112:
113: // destroy connection data
1.13 paf 114: check("db_appexit", &fdb_home, db_appexit(&dbenv));
1.11 paf 115: }
116:
117:
1.1 parser 118: void DB_Connection::check(const char *operation, const String *source, int error) {
119: switch(error) {
120: case 0:
121: // no error
122: break;
123:
124: default:
1.21 paf 125: if(error<0)
126: throw Exception(0, 0,
127: source,
128: "db %s error: %d",
129: operation, error);
130: else
131: throw Exception(0, 0,
132: source,
133: "db %s error: %s (%d)",
134: operation, strerror(error), error);
1.1 parser 135: }
136: }
137:
1.15 paf 138: DB_Table_ptr DB_Connection::get_table_ptr(const String& request_file_name, const String *source) {
139: // checkpoint
1.21 paf 140: {
141: int error=txn_checkpoint(dbenv.tx_info, 0/*kbyte*/, DB_CHECKPOINT_MINUTES/*min*/);
142: /*
143: DB_INCOMPLETE if there were pages that needed to be written
144: but that memp_sync was unable to write immediately.
145: In this case, the txn_checkpoint call should be retried.
146:
147: we'll just ignore that
148: */
149: if(error!=DB_INCOMPLETE)
150: check("checkpoint", source, error);
151: }
1.11 paf 152:
153: // first trying to get cached table
154: DB_Table *result=get_table_from_cache(request_file_name);
1.13 paf 155: if(!result) { // no cached table
1.11 paf 156: // make global_file_name C-string on global pool
1.24 paf 157: const char *request_file_name_cstr=request_file_name.cstr();
1.11 paf 158: char *global_file_name_cstr=(char *)malloc(strlen(request_file_name_cstr)+1);
159: strcpy(global_file_name_cstr, request_file_name_cstr);
160: // make global_file_name string on global pool
161: String& global_file_name=*new(this->pool()) String(this->pool(), global_file_name_cstr);
162:
163: // allocate in global pool
164: // associate with services[request]
165: // NOTE: never freed up!
166: result=new(this->pool()) DB_Table(this->pool(), global_file_name, *this);
1.13 paf 167: // cache it
168: put_table_to_cache(global_file_name, *result);
1.4 parser 169: }
1.1 parser 170:
1.13 paf 171: // return auto-it
172: return DB_Table_ptr(result);
1.1 parser 173: }
1.11 paf 174:
175: // table cache
176: /// @todo get rid of memory spending Stack [zeros deep inside got accumulated]
177: DB_Table *DB_Connection::get_table_from_cache(const String& file_name) {
178: SYNCHRONIZED;
1.17 paf 179:
180: maybe_expire_table_cache();
1.11 paf 181:
1.13 paf 182: return static_cast<DB_Table *>(table_cache.get(file_name));
1.3 parser 183: }
184:
1.13 paf 185: void DB_Connection::put_table_to_cache(const String& file_name, DB_Table& table) {
1.11 paf 186: SYNCHRONIZED;
1.3 parser 187:
1.13 paf 188: table_cache.put(file_name, &table);
1.3 parser 189: }
190:
1.11 paf 191: void DB_Connection::maybe_expire_table_cache() {
192: time_t now=time(0);
193:
194: if(prev_expiration_pass_time<now-CHECK_EXPIRED_TABLES_SECONDS) {
1.13 paf 195: table_cache.for_each(expire_table,
1.11 paf 196: reinterpret_cast<void *>(now-EXPIRE_UNUSED_TABLE_SECONDS));
1.3 parser 197:
1.11 paf 198: prev_expiration_pass_time=now;
1.9 parser 199: }
1.1 parser 200: }
201:
202: #endif
E-mail: