2011-12-04 3 views
0

MySQLe를 임베디드 백엔드로 사용하는 프로그램을 작성 중입니다. 데이터베이스 라이브러리는 "도메인"이라는 오브젝트가 소유합니다. 이 도메인 개체는 주 스레드 내에서 실행됩니다.다중 스레드 환경에서 MySQL Embedded을 사용하는 방법은 무엇입니까?

프로그램은 XML-RPC 서버 (boost :: thread 및 xmlrpc_c :: serverAbyss)를 실행하는 다른 스레드를 시작합니다. Domain 객체에 링크됩니다.

는 XML-RPC 서버가 도메인 객체가 SQL 쿼리에게 프로그램이 충돌을 실행합니다

:
Program received signal: “EXC_BAD_ACCESS”. 
[Switching to process 73191] 
[Switching to process 73191] 
Xcode could not locate source file: regex.cpp (line: 74) 

마스터 스레드가 SQL 프로그램이 계속 실행 쿼리를 실행하는 도메인 객체의 메소드를 호출

.

/* 
* Ports listening 
* 
* - create a Rpc_Server object 
* - create a dedicated thread 
*/ 
Rpc_Server  server(&domain, &conf_params, &router); 
boost::thread server_thread(boost::bind(&Rpc_Server::run, &server)); // This thread makes the server crash 

/* 
* Domain routine 
* 
* - Check for ready jobs every minute 
*/ 
while (1) { 
    v_jobs jobs = domain.get_ready_jobs(conf_params.get_param("node_name")); // This method does NOT make the server crash 
    sleep(60); 
} 

도메인 개체의 메서드와 데이터베이스 개체의 메서드는 모두 다중 액세스를 방지하기 위해 뮤텍스를 잠급니다.

bool Mysql::execute(const std::string* query) { 
    MYSQL_RES* res; 
    MYSQL_ROW row; 

    if (query == NULL) 
     return false; 

    this->updates_mutex.lock(); 

    std::cout << query->c_str() << std::endl; 

    if (mysql_query(this->mysql, query->c_str()) != 0) { 
     std::cerr << query << std::endl << mysql_error(this->mysql); 
     UNLOCK_MUTEX; 
     return false; 
    } 

    res = mysql_store_result(this->mysql); 
    if (res) 
     while ((row = mysql_fetch_row(res))) 
      for (uint i=0 ; i < mysql_num_fields(res) ; i++) 
       std::cout << row[i] << std::endl; 
    else 
     if (mysql_field_count(this->mysql) != 0) { 
      std::cerr << "Erreur : " << mysql_error(this->mysql) << std::endl; 
      mysql_free_result(res); 
      this->updates_mutex.unlock(); 
      return false; 
     } 

    mysql_free_result(res); 
    this->updates_mutex.unlock(); 

    return true; 
} 


bool Domain::add_node(const std::string* running_node, const std::string* n, const int* w) { 
    std::string query; 

    this->updates_mutex.lock(); 
    query = "START TRANSACTION;"; 
    if (this->database.execute(&query) == false) { 
     this->updates_mutex.unlock(); 
     return false; 
    } 

    query = "REPLACE INTO node (node_name,node_weight) VALUES ('"; 
    query += n->c_str(); 
    query += "','"; 
    query += boost::lexical_cast<std::string>(*w); 
    query += "');"; 

    if (this->database.execute(&query) == false) { 
     query = "ROLLBACK;"; 
     this->database.execute(&query); 
     this->updates_mutex.unlock(); 
     return false; 
    } 

    query = "COMMIT;" 
    if (this->database.execute(&query) == false) { 
     this->updates_mutex.unlock(); 
     return false; 
    } else 
     this->updates_mutex.unlock(); 

    return true; 
} 

MySQLe가 생성됩니다

bool Mysql::prepare(const std::string* node_name, const std::string* db_skeleton) { 
    static char* server_args[] = {"this_program","--datadir=."}; 
    static char* server_groups[] = {"embedded","server","this_program_SERVER",(char *)NULL}; 
    std::string query("CREATE DATABASE IF NOT EXISTS "); 

    // DB init 
    if (mysql_library_init(sizeof(server_args)/sizeof(char *), server_args, server_groups)) 
     std::cerr << "could not initialize MySQL library" << std::endl; 

    std::cout << "mysql init..." << std::endl; 
    if ((this->mysql = mysql_init(NULL)) == NULL) 
     std::cerr << mysql_error(this->mysql) << std::endl; 

    if (! mysql_thread_safe()) { 
     std::cerr << "MySQL is NOT theadsafe !" << std::endl; 
     return false; 
    } 

    mysql_options(this->mysql, MYSQL_READ_DEFAULT_GROUP, "embedded"); 
    mysql_options(this->mysql, MYSQL_OPT_USE_EMBEDDED_CONNECTION, NULL); 

    mysql_real_connect(this->mysql, NULL, NULL, NULL, NULL, 0, NULL, 0); 

    // Creates the schema 
    query += this->translate_into_db(node_name); 
    query += ";"; 

    if (this->execute(&query) == false) 
     return false; 

    // Creates the schema 
    query = "CREATE SCHEMA IF NOT EXISTS "; 
    query += this->translate_into_db(node_name); 
    query += " DEFAULT CHARACTER SET latin1;"; 

    this->execute(&query); 

    // Uses it 
    query = "USE " + this->translate_into_db(node_name) + ";"; 

    this->execute(&query); 

    // Loads the skeleton from file 
    return this->load_file(db_skeleton->c_str()); 
} 

잘못 어딘가에을 있습니까? 나에게 보여줄 수있는 예가 있습니까?

답변

0

문제점에 대한 해결책을 찾았습니다. 각 스레드는 MySQL 환경을 초기화해야합니다. 즉, 몇 가지 mysql_ * 함수를 실행하는 것이다.

여기서 수정/신규 방법 :

bool Mysql::atomic_execute(const std::string* query) { 
    MYSQL_RES* res; 
    MYSQL_ROW row; 
    boost::regex empty_string("^\\s+$", boost::regex::perl); 

    if (query == NULL) 
     return false; 

    if (query->empty() == true or boost::regex_match(*query, empty_string) == true) { 
     std::cerr << "Error : query is empty !" << std::endl; 
     return false; 
    } 

    this->updates_mutex.lock(); 

    if (mysql_query(this->mysql, query->c_str()) != 0) { 
     std::cerr << query << std::endl << mysql_error(this->mysql); 
     this->updates_mutex.unlock();; 
     return false; 
    } 

    res = mysql_store_result(this->mysql); 
    if (res) 
     while ((row = mysql_fetch_row(res))) 
      for (uint i=0 ; i < mysql_num_fields(res) ; i++) 
       std::cout << row[i] << std::endl; 
    else 
     if (mysql_field_count(this->mysql) != 0) { 
      std::cerr << "Erreur : " << mysql_error(this->mysql) << std::endl; 
      mysql_free_result(res); 
      this->updates_mutex.unlock(); 
      return false; 
     } 

    mysql_free_result(res); 
    this->updates_mutex.unlock(); 

    return true; 
} 

bool Mysql::standalone_execute(const v_queries* queries) { 
    MYSQL*  local_mysql = this->init(); 
    std::string query  = "START TRANSACTION;"; 

    if (this->atomic_execute(&query) == false) { 
     mysql_close(local_mysql); 
     return false; 
    } 

    BOOST_FOREACH(std::string q, *queries) { 
     std::cout << q.c_str() << std::endl; 
     if (this->atomic_execute(&q) == false) { 
      query = "ROLLBACK"; 
      this->atomic_execute(&query); 
      mysql_close(local_mysql); 
      return false; 
     } 
    } 

    query = "COMMIT"; 

    if (this->atomic_execute(&query) == false) { 
     mysql_close(local_mysql); 
     return false; 
    } 

    mysql_close(local_mysql); 
    return true; 
} 

MYSQL*  Mysql::init() { 
    MYSQL* local_mysql; 

    local_mysql = mysql_init(this->mysql); 
    mysql_options(this->mysql, MYSQL_READ_DEFAULT_GROUP, "embedded"); 
    mysql_options(this->mysql, MYSQL_OPT_USE_EMBEDDED_CONNECTION, NULL); 
    mysql_real_connect(local_mysql, NULL, NULL, NULL, NULL, 0, NULL, 0); 

    return local_mysql; 
} 

atomic_execute 방법은 하나의 서버로 질의를 전송하는 데 사용된다.

standalone_execute 메소드는 연결과 트랜잭션을 초기화 한 다음 atomic_execute를 사용하여 전체 쿼리를 서버로 보냅니다.

롤백의 실패를 COMMIT의 경우에 유용 경우 몰라요 ...

이 코드는 몇 가지 개선해야 할 수도 있지만 작동합니다.