Annotation of parser3/src/main/pa_db_manager.C, revision 1.2
1.1 parser 1: /** @file
2: Parser: sql driver manager 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.2 ! parser 7: $Id: pa_db_manager.C,v 1.1 2001/10/22 16:44:42 parser Exp $
1.1 parser 8: */
9:
10: #include "pa_db_manager.h"
11: #include "ltdl.h"
1.2 ! parser 12: #include "pa_db_connection.h"
1.1 parser 13: #include "pa_exception.h"
14: #include "pa_threads.h"
15: #include "pa_stack.h"
16:
17: // globals
18:
19: DB_Manager *DB_manager;
20:
21: // consts
22:
23: const int EXPIRE_UNUSED_CONNECTION_SECONDS=60;
24: const int CHECK_EXPIRED_CONNECTIONS_SECONDS=EXPIRE_UNUSED_CONNECTION_SECONDS*2;
25:
26:
27: // DB_Manager
28:
29: /// @test db_paniccall & co
30: DB_Manager::DB_Manager(Pool& pool) : Pooled(pool),
31: connection_cache(pool),
32: prev_expiration_pass_time(0) {
33:
34: memset(&dbenv, 0, sizeof(dbenv));
1.2 ! parser 35: check("db_appinit", 0/*global*/, db_appinit(
1.1 parser 36: 0/*db_home*/,
37: 0/*db_config*/,
38: &dbenv,
39: DB_CREATE | DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN));
40: }
41:
42: DB_Manager::~DB_Manager() {
1.2 ! parser 43: check("db_appexit", 0/*global*/, db_appexit(&dbenv));
1.1 parser 44: }
45:
46:
1.2 ! parser 47: void DB_Manager::check(const char *operation, const String *source, int error) {
1.1 parser 48: switch(error) {
49: case 0:
50: // no error
51: break;
52:
53: default:
54: throw Exception(0, 0,
1.2 ! parser 55: source,
1.1 parser 56: "db %s error: %s (%d)",
57: operation, strerror(errno), errno);
58: }
59: }
60:
61: DB_Connection& DB_Manager::get_connection(const String& request_file_spec,
62: const String& request_origin) {
63: Pool& pool=request_origin.pool(); // request pool
64:
65: // first trying to get cached connection
66: DB_Connection *result=get_connection_from_cache(request_file_spec);
67: if(result && !result->ping()) { // we have some cached connection, is it pingable?
68: result->disconnect(); // kill unpingabe=dead connection
69: result=0;
70: }
71:
72: char *request_file_spec_cstr;
73: if(result)
74: request_file_spec_cstr=0; // calm, compiler
75: else { // no cached connection
76: // make global_file_spec C-string on global pool
77: request_file_spec_cstr=request_file_spec.cstr(String::UL_AS_IS);
78: char *global_file_spec_cstr=(char *)malloc(strlen(request_file_spec_cstr)+1);
79: strcpy(global_file_spec_cstr, request_file_spec_cstr);
80: // make global_file_spec string on global pool
81: String& global_file_spec=*new(this->pool()) String(this->pool(), global_file_spec_cstr);
82:
83: // allocate in global pool
84: // associate with services[request]
85: // NOTE: never freed up!
86: result=new(this->pool()) DB_Connection(this->pool(), global_file_spec, dbenv);
87: }
88:
89: // associate with services[request] (deassociates at close)
90: result->set_services(&pool);
91: // if not connected yet, do that now, when result has services
92: if(!result->connected())
93: result->connect();
94: // return it
95: return *result;
1.2 ! parser 96: }
! 97: void DB_Manager::clear_dbfile(const String& file_spec) {
! 98: // open&clear
! 99: DB *db;
! 100: DB_INFO dbinfo;
! 101: memset(&dbinfo, 0, sizeof(dbinfo));
! 102: check("open(clear)", &file_spec, db_open(
! 103: file_spec.cstr(String::UL_FILE_SPEC),
! 104: PA_DB_ACCESS_METHOD,
! 105: DB_CREATE | DB_TRUNCATE/* used in single thread, no need for |DB_THREAD*/,
! 106: 0666,
! 107: &dbenv, &dbinfo, &db));
! 108:
! 109: check("close", &file_spec, db->close(db, 0/*flags*/)); db=0;
1.1 parser 110: }
111:
112: void DB_Manager::close_connection(const String& file_spec,
113: DB_Connection& connection) {
114: // deassociate from services[request]
115: connection.set_services(0);
116: put_connection_to_cache(file_spec, connection);
117: }
118:
119:
120: // connection cache
121: /// @todo get rid of memory spending Stack [zeros deep inside got accumulated]
122: DB_Connection *DB_Manager::get_connection_from_cache(const String& file_spec) {
123: SYNCHRONIZED;
124:
125: maybe_expire_connection_cache();
126:
127: if(Stack *connections=static_cast<Stack *>(connection_cache.get(file_spec)))
128: while(connections->top_index()>=0) { // there are cached connections to that 'file_spec'
129: DB_Connection *result=static_cast<DB_Connection *>(connections->pop());
130: if(result->connected()) // not expired?
131: return result;
132: }
133:
134: return 0;
135: }
136:
137: void DB_Manager::put_connection_to_cache(const String& file_spec,
138: DB_Connection& connection) {
139: SYNCHRONIZED;
140:
141: Stack *connections=static_cast<Stack *>(connection_cache.get(file_spec));
142: if(!connections) { // there are no cached connections to that 'file_spec' yet?
143: connections=NEW Stack(pool()); // NOTE: never freed up!
144: connection_cache.put(file_spec, connections);
145: }
146: connections->push(&connection);
147: }
148:
149: static void expire_connection(Array::Item *value, void *info) {
150: DB_Connection& connection=*static_cast<DB_Connection *>(value);
151: time_t older_dies=reinterpret_cast<time_t>(info);
152:
153: if(connection.connected() && connection.expired(older_dies))
154: connection.disconnect();
155: }
156: static void expire_connections(const Hash::Key& key, Hash::Val *value, void *info) {
157: Stack& stack=*static_cast<Stack *>(value);
158: for(int i=0; i<=stack.top_index(); i++)
159: expire_connection(stack.get(i), info);
160: }
161: void DB_Manager::maybe_expire_connection_cache() {
162: time_t now=time(0);
163:
164: if(prev_expiration_pass_time<now-CHECK_EXPIRED_CONNECTIONS_SECONDS) {
165: connection_cache.for_each(expire_connections,
166: reinterpret_cast<void *>(now-EXPIRE_UNUSED_CONNECTION_SECONDS));
167:
168: prev_expiration_pass_time=now;
169: }
170: }
E-mail: