Annotation of parser3/src/main/pa_db_connection.C, revision 1.15
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.15 ! paf 7: $Id: pa_db_connection.C,v 1.14 2001/10/26 15:26:37 paf Exp $
1.1 parser 8: */
9:
10: #include "pa_config_includes.h"
11: #ifdef HAVE_LIBDB
12:
13: #include "pa_db_connection.h"
1.11 paf 14: #include "pa_db_table.h"
1.1 parser 15: #include "pa_exception.h"
1.11 paf 16: #include "pa_threads.h"
17: #include "pa_stack.h"
18: #include "pa_common.h"
1.1 parser 19:
1.14 paf 20: // defines
21:
22: #define DB_ERROR_PREFIX "db_err: "
23: #define DB_EXCEPTION_NO_LOG_MESSAGE1 DB_ERROR_PREFIX"Ignoring log file"
24: #define DB_EXCEPTION_NO_LOG_MESSAGE2 DB_ERROR_PREFIX"log_get: unable to find checkpoint record"
25:
1.11 paf 26: // consts
27:
1.15 ! paf 28: /// @test increase
! 29: const int DB_CHECKPOINT_MINUTES=1;
! 30:
1.11 paf 31: const int EXPIRE_UNUSED_TABLE_SECONDS=60;
32: const int CHECK_EXPIRED_TABLES_SECONDS=EXPIRE_UNUSED_TABLE_SECONDS*2;
33:
34: // callbacks
1.10 parser 35:
1.11 paf 36: static void db_paniccall(DB_ENV *dbenv, int error) {
37: throw Exception(0, 0,
38: 0,
39: "db_panic: %s (%d)",
40: strerror(error), error);
41: }
42:
43: static void db_errcall(const char *, char *buffer) {
44: throw Exception(0, 0,
45: 0,
1.14 paf 46: DB_ERROR_PREFIX "%s",
1.11 paf 47: buffer);
48: }
1.5 parser 49:
1.13 paf 50: static void expire_table(const Hash::Key& key, Hash::Val *& value, void *info) {
51: DB_Connection& table=*static_cast<DB_Connection *>(value);
1.11 paf 52: time_t older_dies=reinterpret_cast<time_t>(info);
1.5 parser 53:
1.13 paf 54: if(table.expired(older_dies)) {
55: table.~DB_Connection(); value=0;
56: }
1.11 paf 57: }
1.5 parser 58:
1.3 parser 59: // DB_Connection
60:
1.13 paf 61: DB_Connection::DB_Connection(Pool& apool, const String& adb_home) : Pooled(apool),
62: time_used(0),
63: fdb_home(adb_home),
64: table_cache(apool),
1.11 paf 65: prev_expiration_pass_time(0) {
66: //_asm int 3;
67: char DB_DATA_DIR__VALUE[MAX_STRING];
68: char DB_LOG_DIR__VALUE[MAX_STRING];
69: char DB_TMP_DIR__VALUE[MAX_STRING];
70:
71: const char *db_home_cstr=fdb_home.cstr(String::UL_FILE_SPEC);
72:
73: snprintf(DB_DATA_DIR__VALUE, MAX_STRING, "DB_DATA_DIR %s", db_home_cstr);
74: snprintf(DB_LOG_DIR__VALUE, MAX_STRING, "DB_LOG_DIR %s", db_home_cstr);
75: snprintf(DB_TMP_DIR__VALUE, MAX_STRING, "DB_TMP_DIR %s", db_home_cstr);
76:
77: char *db_config[] = {
78: DB_DATA_DIR__VALUE,
79: DB_LOG_DIR__VALUE,
80: DB_TMP_DIR__VALUE,
81: 0
82: };
83:
84: u_int32_t flags=
1.13 paf 85: DB_THREAD
86: | DB_CREATE
1.11 paf 87: | DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN;
88:
1.14 paf 89: try {
1.11 paf 90: // 1: trying to open with SOFT RECOVER option set
1.14 paf 91: memset(&dbenv, 0, sizeof(dbenv));
1.11 paf 92: check("db_appinit soft recover", &fdb_home, db_appinit(
93: db_home_cstr,
94: db_config,
95: &dbenv,
96: flags | DB_RECOVER
97: ));
1.14 paf 98: } catch(const Exception& e) {
99: if(
100: strncmp(
101: e.comment(),
102: DB_EXCEPTION_NO_LOG_MESSAGE1,
103: strlen(DB_EXCEPTION_NO_LOG_MESSAGE1))==0 ||
104: strncmp(
105: e.comment(),
106: DB_EXCEPTION_NO_LOG_MESSAGE2,
107: strlen(DB_EXCEPTION_NO_LOG_MESSAGE2))==0) {
108: // no log = no SOFT RECOVER
109: // 2.1: trying to open with NO RECOVER option set
110: memset(&dbenv, 0, sizeof(dbenv));
1.11 paf 111: check("db_appinit no recover", &fdb_home, db_appinit(
112: db_home_cstr,
113: db_config,
114: &dbenv,
115: flags
116: ));
1.14 paf 117: } else {
118: // some serious error
119: // 2.2: trying to open with FATAL RECOVER option set
120: memset(&dbenv, 0, sizeof(dbenv));
1.11 paf 121: check("db_appinit fatal recover", &fdb_home, db_appinit(
122: db_home_cstr,
123: db_config,
124: &dbenv,
125: flags | DB_RECOVER_FATAL
126: ));
127: }
1.14 paf 128: }
129:
130: // error handlers
131: dbenv.db_paniccall=db_paniccall;
132: dbenv.db_errcall=db_errcall;
1.11 paf 133: }
134:
1.13 paf 135: DB_Connection::~DB_Connection() {
1.11 paf 136: // close tables
1.13 paf 137: table_cache.for_each(expire_table,
1.11 paf 138: reinterpret_cast<void *>(0/* =in the past = expire[close] all*/));
139:
140: // destroy connection data
1.13 paf 141: check("db_appexit", &fdb_home, db_appexit(&dbenv));
1.11 paf 142: }
143:
144:
1.1 parser 145: void DB_Connection::check(const char *operation, const String *source, int error) {
146: switch(error) {
147: case 0:
148: // no error
149: break;
150:
151: default:
152: throw Exception(0, 0,
1.3 parser 153: source,
1.11 paf 154: "db %s error: %s (%d)",
155: operation, strerror(error), error);
1.1 parser 156: }
157: }
158:
1.15 ! paf 159: DB_Table_ptr DB_Connection::get_table_ptr(const String& request_file_name, const String *source) {
! 160: // checkpoint
! 161: check("checkpoint", source,
! 162: txn_checkpoint(dbenv.tx_info, 0/*kbyte*/, DB_CHECKPOINT_MINUTES/*min*/));
1.11 paf 163:
164: // first trying to get cached table
165: DB_Table *result=get_table_from_cache(request_file_name);
1.13 paf 166: if(!result) { // no cached table
1.11 paf 167: // make global_file_name C-string on global pool
1.13 paf 168: const char *request_file_name_cstr=request_file_name.cstr(String::UL_AS_IS);
1.11 paf 169: char *global_file_name_cstr=(char *)malloc(strlen(request_file_name_cstr)+1);
170: strcpy(global_file_name_cstr, request_file_name_cstr);
171: // make global_file_name string on global pool
172: String& global_file_name=*new(this->pool()) String(this->pool(), global_file_name_cstr);
173:
174: // allocate in global pool
175: // associate with services[request]
176: // NOTE: never freed up!
177: result=new(this->pool()) DB_Table(this->pool(), global_file_name, *this);
1.13 paf 178: // cache it
179: put_table_to_cache(global_file_name, *result);
1.4 parser 180: }
1.1 parser 181:
1.13 paf 182: // return auto-it
183: return DB_Table_ptr(result);
1.11 paf 184: }
185: void DB_Connection::clear_dbfile(const String& file_name) {
186: // open&clear
187: DB *db;
1.1 parser 188: DB_INFO dbinfo;
189: memset(&dbinfo, 0, sizeof(dbinfo));
1.11 paf 190: check("open(clear)", &file_name, db_open(
191: file_name.cstr(String::UL_FILE_SPEC),
1.1 parser 192: PA_DB_ACCESS_METHOD,
1.11 paf 193: DB_CREATE | DB_TRUNCATE/* used in single thread, no need for |DB_THREAD*/,
1.1 parser 194: 0666,
1.11 paf 195: &dbenv, &dbinfo, &db));
196:
197: check("close", &file_name, db->close(db, 0/*flags*/)); db=0;
1.1 parser 198: }
1.11 paf 199:
200: // table cache
201: /// @todo get rid of memory spending Stack [zeros deep inside got accumulated]
202: DB_Table *DB_Connection::get_table_from_cache(const String& file_name) {
203: SYNCHRONIZED;
204:
1.13 paf 205: return static_cast<DB_Table *>(table_cache.get(file_name));
1.3 parser 206: }
207:
1.13 paf 208: void DB_Connection::put_table_to_cache(const String& file_name, DB_Table& table) {
1.11 paf 209: SYNCHRONIZED;
1.3 parser 210:
1.13 paf 211: table_cache.put(file_name, &table);
1.3 parser 212: }
213:
1.11 paf 214: void DB_Connection::maybe_expire_table_cache() {
215: time_t now=time(0);
216:
217: if(prev_expiration_pass_time<now-CHECK_EXPIRED_TABLES_SECONDS) {
1.13 paf 218: table_cache.for_each(expire_table,
1.11 paf 219: reinterpret_cast<void *>(now-EXPIRE_UNUSED_TABLE_SECONDS));
1.3 parser 220:
1.11 paf 221: prev_expiration_pass_time=now;
1.9 parser 222: }
1.1 parser 223: }
224:
225: #endif
E-mail: