|
|
| version 1.4, 2001/10/24 09:03:42 | version 1.16, 2001/11/05 10:42:59 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: sql db decl. | Parser: sql driver connection decl. |
| global sql driver connection, must be thread-safe | |
| Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com) | Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com) |
| Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf) | Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf) |
| Line 12 | Line 13 |
| #include "pa_config_includes.h" | #include "pa_config_includes.h" |
| #include "pa_pool.h" | #include "pa_pool.h" |
| #include "pa_db_manager.h" | #include "pa_hash.h" |
| #include "pa_globals.h" | #include "pa_db_table.h" |
| #ifdef HAVE_DB_H | |
| # include <db.h> | |
| #endif | |
| // defines | // defines |
| #define PA_DB_ACCESS_METHOD DB_BTREE | |
| // forwards | // forwards |
| class Auto_transaction; | class DB_Table; |
| class DB_Cursor; | class DB_Connection_ptr; |
| // class | |
| /// DB connection. handy wrapper around low level <db.h> calls | /// sql driver connection |
| class DB_Connection : public Pooled { | class DB_Connection : public Pooled { |
| friend Auto_transaction; | friend class DB_Table; |
| friend DB_Cursor; | friend class DB_Connection_ptr; |
| public: | public: |
| DB_Connection(Pool& pool, const String& afile_spec, DB_ENV& adbenv); | DB_Connection(Pool& apool, const String& db_home); |
| ~DB_Connection(); | |
| //const String& url() { return ffile_spec; } | |
| void set_services(Pool *aservices_pool) { | |
| time_used=time(0); // they started to use at this time | |
| fservices_pool=aservices_pool; | |
| } | |
| bool expired(time_t older_dies) { | bool expired(time_t older_dies) { |
| return time_used<older_dies; | return !used && time_used<older_dies; |
| } | } |
| time_t get_time_used() { return time_used; } | |
| int get_users_count() { return used; } | |
| /** | |
| connect to specified file_name | |
| */ | |
| DB_Table_ptr get_table_ptr(const String& file_name, const String *source); | |
| void close() { | private: // connection usage methods |
| DB_manager->close_connection(ffile_spec, *this); | |
| void use() { | |
| time_used=time(0); // they started to use at this time | |
| used++; | |
| } | |
| void unuse() { | |
| used--; | |
| } | } |
| bool connected() { return db!=0; } | private: // connection usage data |
| void connect(); | |
| void disconnect(); | |
| bool ping() { return !needs_recovery; } | |
| void put(const String& key, const String& data); | int used; |
| String *get(const String& key); | |
| void _delete(const String& key); | |
| DB_Cursor cursor(const String *source); | private: // table cache |
| DB_Table *get_table_from_cache(const String& file_name); | |
| void put_table_to_cache(const String& file_name, DB_Table& table); | |
| void maybe_expire_table_cache(); | |
| private: | private: |
| time_t prev_expiration_pass_time; | |
| DB_ENV& fdbenv; | private: // for DB_Table |
| const String& ffile_spec; const char *file_spec_cstr; | |
| Pool *fservices_pool; | |
| DB *db; | |
| bool needs_recovery; | |
| DB_TXN *ftid; | |
| time_t time_used; | |
| private: // transaction | /// caches table |
| void close_table(const String& file_name, DB_Table& table); | |
| /// commits current transaction, restores previous transaction handle | private: |
| void commit_restore(DB_TXN *atid) { | |
| if(ftid) | |
| check("txn_commit", &ffile_spec, txn_commit(ftid)); | |
| ftid=atid; | time_t time_used; |
| } | |
| /// rolls current transaction back, restores previous transaction handle | |
| void rollback_restore(DB_TXN *atid) { | |
| if(ftid) | |
| check("txn_abort", &ffile_spec, txn_abort(ftid)); | |
| ftid=atid; | const String& fdb_home; |
| } | DB_ENV dbenv; |
| Hash table_cache; | |
| /// stars new current trunsaction @returns previous transaction handle | |
| DB_TXN *transaction_begin_save() { | |
| DB_TXN *result=ftid; | |
| check("txn_begin", &ffile_spec, ::txn_begin(fdbenv.tx_info, 0/*parent*/, &ftid)); | |
| return result; | |
| } | |
| private: | private: |
| void check(const char *operation, const String *source, int error); | void check(const char *operation, const String *source, int error); |
| void *malloc(size_t size) { return fservices_pool->malloc(size); } | |
| void *calloc(size_t size) { return fservices_pool->calloc(size); } | |
| /// pass empty dbt, would fill it from string | |
| void key_string_to_dbt(const String& key_string, DBT& key_result); | |
| /// pass empty dbt, would fill it from string | |
| void key_dbt_to_string(const DBT& key_dbt, String& key_result); | |
| /// pass empty dbt, would fill it from string | |
| void data_string_to_dbt(const String& data_string, DBT& data_result); | |
| /// pass empty string, would fill it from dbt | |
| void data_dbt_to_string(const DBT& data_dbt, String& data_result); | |
| }; | }; |
| /// Auto-object used for temporary changing DB_Connection::tid. | /// Auto-object used to track DB_Connection usage |
| class Auto_transaction { | class DB_Connection_ptr { |
| DB_Connection& fconnection; | DB_Connection *fconnection; |
| bool marked_to_rollback; | |
| DB_TXN *saved_tid; | |
| public: | public: |
| Auto_transaction(DB_Connection& aconnection) : | DB_Connection_ptr(DB_Connection *aconnection) : fconnection(aconnection) { |
| fconnection(aconnection), marked_to_rollback(false), | fconnection->use(); |
| saved_tid(aconnection.transaction_begin_save()) { | |
| } | |
| ~Auto_transaction() { | |
| if(marked_to_rollback) | |
| fconnection.rollback_restore(saved_tid); | |
| else | |
| fconnection.commit_restore(saved_tid); | |
| } | } |
| void mark_to_rollback() { | ~DB_Connection_ptr() { |
| marked_to_rollback=true; | fconnection->unuse(); |
| } | |
| DB_Connection* operator->() { | |
| return fconnection; | |
| } | } |
| }; | |
| /// DB cursor. handy wrapper around low level <db.h> calls | // copying |
| class DB_Cursor { | DB_Connection_ptr(const DB_Connection_ptr& src) : fconnection(src.fconnection) { |
| friend DB_Connection; | fconnection->use(); |
| private: | |
| DB_Cursor(DB_Connection& aconnection, const String *asource); | |
| public: | |
| ~DB_Cursor(); | |
| /// pass empty strings to key&data, would fill them | |
| bool get(String& key, String& data, u_int32_t flags); | |
| private: | |
| const String *fsource; | |
| DB_Connection& fconnection; | |
| DBC *cursor; | |
| private: | |
| void check(const char *operation, const String *source, int error) { | |
| fconnection.check(operation, source, error); | |
| } | } |
| /// pass empty string, would fill it from dbt | DB_Connection_ptr& operator =(const DB_Connection_ptr& src) { |
| void key_dbt_to_string(DBT& dbt, String& result) { | // may do without this=src check |
| fconnection.key_dbt_to_string(dbt, result); | fconnection->unuse(); |
| } | fconnection=src.fconnection; |
| /// pass empty string, would fill it from dbt | fconnection->use(); |
| void data_dbt_to_string(DBT& dbt, String& result) { | |
| fconnection.data_dbt_to_string(dbt, result); | return *this; |
| } | } |
| }; | }; |