最近待业,闲的蛋疼,发现C++下连mysql连接池这么基础的东西都没用过,身为一名计算机毕业生,深感愧疚,遂生一想法,写个或者找个连接池,以增强本人垃圾一样的专业修养。
没想到写出来第一版就存在内存管理问题导致的coredump,查了半天,发现是调用了空指针的成员函数,彻底晕倒,其间为了调试gdb core中bt出来的libmysqlclient.so的mysql_real_connect调用,我下了mysql的5.5.31源代码来编了若干遍,想编个debug版调试最后也是没有成功。发现问题还是看网上帖子讲segfault11这种问题多半都是空指针搞的,反过头加了些指针的打印语句才意识到低级的错误,后来debug过程中还发现了更低级的逻辑错误,略去不表,还是自己太菜,连个空指针这个白痴的内存问题都不预先防范,搞得一个300+行的东西,弄了三天才算稳定了,大大的罪过,浪费自己和社会的生产力。
过程中想到自己既然写不好,干脆找个好用的,结果发现了个libzdb,支持好些个开源db的连接池,随便下了个破代码测了一下,也没仔细搞,debug中参考了一下它的源码,还算是有点启发。
目前这个源码用valgrind自己测,有74KB左右的内存泄露,明白人能改改的话最好,作为一个菜鸟我只能帮自己到这了,当然这个泄露不会随时间线性的增长,这个我还是测过了的,有人能用到生产环境的话,麻烦给我提点改进意见,72小时的作品,太经不起考验了,目前本机上只能支持最多 152条连接,设成153就会报连接失败,牛逼的前辈们狠狠的批这份代码好了,自己也感觉自己水平太残废了,不知道是mysql设置还是系统设置的问题,总之无论是建议还是问题尽管扔过来吧,作为一个傻逼二货我照单全收。
上代码
去Github搞代码看这里 https://github.com/githcx/xPool
pool.h (1 in 3)
#include <mysql.h> #include <stdio.h> #include <string.h> #include <map> #include <vector> #include <string> #include <iostream> #include <pthread.h> using std::string; using std::vector; class Connection; class some{ public: some(){} Connection * first; bool second; }; class Pool{ public: static int initPool(string host,string user,string pass,string dbname,int poolSize); static void destroyPool(); static Connection* getConnection(); static int releaseConnection(Connection*); static void lock(); static void unlock(); static void locke(); static void unlocke(); static void locki(); static void unlocki(); static void lockl(); static void unlockl(); private: static pthread_mutex_t mutex; static pthread_mutex_t execmutex; static pthread_mutex_t initmutex; static pthread_mutex_t logmutex; static Pool* pool_; private: some* vec; // need an instance to init public: static string host_ ; static string user_ ; static string pass_ ; static string dbname_; static int poolSize_ ; public: Pool(string host,string user,string pass,string dbname,int poolSize); virtual ~Pool(); }; class QueryResult; class Connection{ public: Connection(string host,string user,string pass,string dbname); virtual ~Connection(); QueryResult executeQuery(string statement); private: // MYSQL代表了一条TCP连接 MYSQL* conn; }; class QueryResult{ public: int getRowCount(){return string_table.size();} int getColumnCount(){return string_table[0].size();}; string getElement(int row,int column){return string_table[row][column];} void addRow(const vector<string>& row){string_table.push_back(row);} private: vector<vector<string> > string_table; };
pool.h (2 in 3)
#include "pool.h" #include <stdlib.h> // for DEBUG using std::cout; using std::endl; // static field init string Pool::host_ = ""; string Pool::user_ = ""; string Pool::pass_ = ""; string Pool::dbname_ = ""; int Pool::poolSize_ = 0; Pool* Pool::pool_ = NULL; pthread_mutex_t Pool::mutex; pthread_mutex_t Pool::execmutex; pthread_mutex_t Pool::initmutex; pthread_mutex_t Pool::logmutex; void Pool::lock(){ pthread_mutex_lock(&mutex); } void Pool::unlock(){ pthread_mutex_unlock(&mutex); } void Pool::locke(){ pthread_mutex_lock(&execmutex); } void Pool::unlocke(){ pthread_mutex_unlock(&execmutex); } void Pool::locki(){ pthread_mutex_lock(&initmutex); } void Pool::unlocki(){ pthread_mutex_unlock(&initmutex); } void Pool::lockl(){ pthread_mutex_lock(&logmutex); } void Pool::unlockl(){ pthread_mutex_unlock(&logmutex); } Pool::Pool(string host,string user,string pass,string dbname,int poolSize){ vec = new some[Pool::poolSize_]; for(int i=0; i<poolSize_; i++){ Connection* conn = new Connection(Pool::host_,Pool::user_,Pool::pass_,Pool::dbname_); //std::cout << conn << std::endl; //std::cout << host << " " << user << " " << pass << " " << dbname << " " << poolSize << std::endl; if(!conn){ cout << "xPool: new Connection Operation failed" << endl; exit(-1); } vec[i].first = conn; vec[i].second = false; } } Pool::~Pool(){ for(int i=0;i<poolSize_;i++){ delete vec[i].first; } delete[] vec; //mysql_library_end(); } int Pool::initPool(string host,string user,string pass,string dbname,int poolSize){ host_ = host; user_ = user; pass_ = pass; dbname_ = dbname; poolSize_ = poolSize; return 0; } void Pool::destroyPool(){ if(pool_){ delete pool_; pool_ = NULL; } } Connection* Pool::getConnection(){ // init pool, open connections Pool::locki(); if(pool_ == NULL){ pthread_mutex_init(&mutex,0); pthread_mutex_init(&execmutex,0); //mysql_library_init(0,NULL,NULL); pool_ = new Pool(host_,user_,pass_,dbname_,poolSize_); } Pool::unlocki(); //get connection operation Connection* ret = NULL; while(true){ Pool::lock(); bool flag = false; for(int i=0;i<poolSize_;i++){ if(pool_->vec[i].second == false){ pool_->vec[i].second = true; ret = pool_->vec[i].first; flag = true; break; } } if(flag == true){ Pool::unlock(); break; } else{ //cout << "wait" << endl; Pool::unlock(); usleep(1000); continue; } } return ret; } int Pool::releaseConnection(Connection* conn){ lock(); for(int i=0;i<poolSize_;i++){ if(pool_->vec[i].first == conn ){ pool_->vec[i].second = false; break; } } unlock(); return 1; } Connection::Connection(string host,string user,string pass,string dbname){ static int connectionCount = 0; //cout << "C#:" << connectionCount++ << endl; // 初始化连接 conn = mysql_init(NULL); //cout << "conn:" << conn << endl; // 执行物理的tcp连接动作,完成三次握手 if (!mysql_real_connect(conn,"localhost", "root", "jiqim1ma", "hcx",0,NULL,0)){ printf( "xPool: Error connecting to database: %s\n",mysql_error(conn)); exit(-1); } else{ } } Connection::~Connection(){ //mysql_thread_end(); // 关闭TCP连接,四次挥手 mysql_close(conn); } QueryResult Connection::executeQuery(string statement){ //Pool::locke(); //cout << "0.start query" << endl; const char* query = statement.c_str(); //cout << "1.before mysql_real_query" << endl; //cout << "strlen=[" << strlen(query) << "]" << endl; unsigned int len = (unsigned int) strlen(query); char q[100]; strncpy(q,query,len); q[len]=0; int status = mysql_real_query(conn,q,len); //cout << "1.after mysql_real_query" << endl; if(status){ printf("Error making query: %s\n", mysql_error(conn)); } else{ //printf("[%s] made...\n", query); } MYSQL_RES* resultSet; //cout << "2.before mysql_store_result" << endl; resultSet = mysql_store_result(conn); //cout << "2.after mysql_store_result" << endl; //cout << "3.before mysql_fetch_row" << endl; QueryResult queryResult; while(true){ MYSQL_ROW row; if(!(row = mysql_fetch_row(resultSet))){ break; } vector<string> string_row; for(int i=0; i < mysql_num_fields(resultSet); i++){ string_row.push_back(row[i]); } queryResult.addRow(string_row); } //cout << "3.after mysql_fetch_row" << endl; //cout << "4.before mysql_free_result" << endl; mysql_free_result(resultSet); //free result after you get the result //cout << "4.after mysql_free_result" << endl; //cout << "0.finish query" << endl; //Pool::unlocke(); return queryResult; }
mine.cpp ( 3 in 3 )
#include "pool.h" #include <unistd.h> #include <stdlib.h> using std::cout; using std::endl; void* handler(void* arg){ long tid = (long)arg; //cout << "tid =[" << tid << "]" << endl; Connection* conn = Pool::getConnection(); if(!conn){ cout << "getConnection NULL pointer" << endl; exit(-1); } //cout << "Connection.this:" << conn << endl; const char* query; query = "select * from student;"; QueryResult queryResult = conn->executeQuery(query); Pool::releaseConnection(conn); //for(int i=0;i<queryResult.getRowCount();i++){ // for(int j=0;j<queryResult.getColumnCount();j++){ // cout << queryResult.getElement(i,j) << " "; // } // cout << endl; //} } int main(int argc, char* argv[]){ string host = "localhost"; string user = "root"; string pass = "jiqim1ma"; string dbname = "hcx"; int poolSize = 152; Pool::initPool(host,user,pass,dbname,poolSize); ///std::cin.get(); unsigned int count = -1; if(argc>1){ count = atoi(argv[1]); } for(int i=0;i < count;i++){ const int THREAD_COUNT = 250; pthread_t threads[THREAD_COUNT]; for(long i=0;i<THREAD_COUNT;i++){ pthread_create(&threads[i],NULL,handler,(void*)i); //sleep(1); } for(int i=0;i<THREAD_COUNT;i++){ pthread_join(threads[i],0); } cout << "==============================LOOPBACK=================================" << endl; } Pool::destroyPool(); return 0; }
Makefile
all: sbpool sbpool: mine.cpp pool.cpp g++ -g -o sbpool mine.cpp pool.cpp -lmysqlclient -lpthread clean: rm -f *.o accessdb sbpool core*