zoukankan      html  css  js  c++  java
  • mysqld with valgrind

    使用编译脚本编译MariaDB
    
    现在进入源代码目录并执行符合你的配置的编译脚本,比如:
    
    cd $maria-source-dir # ex: ~/repos/maria/trunk
    
    BUILD/compile-pentium64-max           # 为64位intel/amd编译(带所有选项)
    BUILD/compile-pentium-max             # 为32位pentum编译(带所有选项)
    
    BUILD/compile-pentium64-debug-max     # 为64位intel/amd编译(带调试选项)  
    BUILD/compile-pentium64-valgrind-max  # 为64位intel/amd编译测试(带valgrind)
    注:Valgrind是一款用于内存调试、内存泄漏检测以及性能分析的软件开发工具。
    
    这里有许多涵盖不同配置和处理器架构的编译脚本。
    
    你可以在运行时加上 --print 选项,来查看编译脚本都做了什么。
    
    在使用一个编译脚本编译MariaDB后,用以下的命令安装MariaDB:
    
    sudo make install
    手动编译MariaDB
    
    如果没有相应的脚本,你也可以直接执行编译命令:
    
    cd $maria-source-dir # ex: ~/repos/maria/trunk
    BUILD/autorun.sh
    ./configure
    make
    sudo make install
    如果使用上面的命令编译出现问题,你也可以通过下面的方法显示编译参数细节方便查询:
    
    make VERBOSE=1
    MariaDB starting with 5.5
    
    关于cmake
    
    MariaDB 5.5及更高版本使用cmake编译。autorun.sh脚本、配置脚本和Makefile都重新修改了,所以你仍然可以使用上面的命令作为书写(仍然建议您使用适当的编译脚本),只是已经和以前版本的方式不同了。
    
    我们建议你需要上面的编译脚本,或者,一个较为理想的编译MariaDB的编译脚本,但你可以,如果你选择使用cmake命令手动编译MariaDB。以下是一个使用默认编译选项的简单例子:
    
    cmake .
    make
    sudo make install
    cmake的配置选项可以通过下面的命令显示:
    
    cmake . -LH
    下面是一个使用cmake置配选项的例子:
    
    cmake . -DCMAKE_INSTALL_PREFIX:PATH=/usr/local/mariadb
    首次启动MariaDB
    
    在安装MariaDB后(使用 sudo make install),但在第一次启动MariaDB之前应该先:
    
    确保你安装MariaDB的目录为mysql用户所有。(如果用户不存在,你需要创建)
    运行 mysql_install_db 脚本来生成所需的系统表。
    范例:
    
    # 下面假设“mysql”用户已经存在,并且MariaDB安装在 /usr/local/mysql
    chown -R mysql /usr/local/mysql/
    scripts/mysql_install_db --user=mysql
    /usr/local/mysql/bin/mysqld_safe --user=mysql &
    MariaDB until 5.3
    
    最大化编译命令行
    
    下面的配置命令行是我们在最大化编译时使用的(包含所有我们认为相关的选项),也是我们大多数二进制编译时所使用的:
    
    ./configure --prefix=/usr/local/mysql --enable-assembler 
    --with-extra-charsets=complex  --enable-thread-safe-client  --with-big-tables 
    --with-plugin-maria --with-aria-tmp-tables --without-plugin-innodb_plugin 
    --with-mysqld-ldflags=-static --with-client-ldflags=-static --with-readline 
    --with-ssl --with-plugins=max-no-ndb --with-embedded-server --with-libevent 
    --with-mysqld-ldflags=-all-static  --with-client-ldflags=-all-static 
    --with-zlib-dir=bundled --enable-local-infile
    显示完整的选项列表:
    
    ./configure --help
    测试MariaDB
    
    你可以使用下面的任何一种方式来测试你编译的MariaDB
    
    make test
    或者
    
    cd mysql-test ; ./mysql-test-run --force
    上面的方法都是从源目录运行的,在运行之前没有必要 'sudo make install'

    http://blog.chinaunix.net/uid-28364803-id-3508914.html

    mysql bug#64624: 备库开启query cache后导致crash的分析 2012-11-10 23:50:11
    分类: Mysql/postgreSQL
    主库:mysql-5.1.48
    备库:percona server 5.5.18(query cache on)
    
    重现:
    备库在valgrind下启动:
    点击(此处)折叠或打开
    valgrind --leak-check=full --trace-children=yes --log-file=$HOME/valgrind.1 ./bin/mysqld --defaults-file=my.s.s.cnf
    
    主库上执行:
    点击(此处)折叠或打开
    /*!40000 ALTER TABLE `t1` DISABLE KEYS */;
    
    出错结果:
    点击(此处)折叠或打开
    Thread 21:
    Conditional jump or move depends on uninitialised value(s)
        at 0x5A6743: Query_cache::send_result_to_client(THD*, char*, unsigned int) (sql_cache.cc:2051)
        by 0x5EDE27: mysql_parse(THD*, char*, unsigned int, Parser_state*) (sql_parse.cc:5756)
        by 0x800B79: Query_log_event::do_apply_event(Relay_log_info const*, char const*, unsigned int) (log_event.cc:3398)
        by 0x800157: Query_log_event::do_apply_event(Relay_log_info const*) (log_event.cc:3166)
        by 0x572005: Log_event::apply_event(Relay_log_info const*) (log_event.h:1135)
        by 0x56B1A9: apply_event_and_update_pos(Log_event*, THD*, Relay_log_info*) (slave.cc:2351)
        by 0x56B6E9: exec_relay_log_event(THD*, Relay_log_info*) (slave.cc:2511)
        by 0x56D8F6: handle_slave_sql (slave.cc:3329)
        by 0x3A01806D63: start_thread (pthread_create.c:308)
    
    原因分析:
    理论上讲,只有SQL导致数据变更了才会写binlog,而select语句是不会被备库复制执行的,那为何备库在do_apply_event时会访问query cache?
    
    因为mysql执行sql的入口是mysql_parse,对于从主库上复制过来的binlog,如果是SQL形式(DDL或者binlog format为statement),会进入mysql_parse,
    而mysql_parse的逻辑是首先查看query cache,如果不能返回结果就执行mysql_execute_command,并且对于select query,之后还会将结果写到query cache.
    
    在Query_cache::send_result_to_client函数中会对sql语句进行检查,如果不是SELECT语句会直接返回,检查逻辑如下:
    
    点击(此处)折叠或打开
    if (!((i + 2 < query_length) &&
        ((my_toupper(system_charset_info, sql[i]) == 'S' &&
          my_toupper(system_charset_info, sql[i + 1]) == 'E' &&
          my_toupper(system_charset_info, sql[i + 2]) == 'L') ||
         sql[i] == '/')))
    {
      DBUG_PRINT("qcache", ("The statement is not a SELECT; Not cached"));
      goto err;
    }
    
    因此,备库复制执行binlog时虽然会进入到query cache,但是由于它们不是SELECT QUERY会直接返回,其实并没有真正访问query cache,然而上述判断逻辑也有出现问题的时候,那就是类似这样的SQL:
    /*!40000 ALTER TABLE `t1` DISABLE KEYS */;
    会和SELECT一样继续往下执行...,直到:
    
    点击(此处)折叠或打开
    size_t db_len;
    memcpy((char *) &db_len, (sql + query_length + 1), sizeof(size_t));
    if (thd->db_length != db_len) <-- 出错!
    {
      ...
      DBUG_PRINT("qcache", ("Current database has changed since start of query"));
      goto err;
    }
    
    这是因为memcpy读到的未初始化的数据!
    
    在alloc_query中,query buffer的内存布局如下:
    +-------+-------+----------------------------------------+-------+
    | Query |db len |        db_name                         | FLAGS |
    +-------+-------+----------------------------------------+-------+
    其中db len类型为size_t,保存db_name的长度
    
    send_result_to_client中的计算tot_length的方式可以说明
    
    点击(此处)折叠或打开
    tot_length= query_length + 1 + sizeof(size_t) + thd->db_length + QUERY_CACHE_FLAGS_SIZE;
    
    而在Query_log_event::Query_log_event函数中,data buffer如下:(下面的接在上面之后)
    +--------+-----------+------+------+---------+----+
    | catlog | time_zone | user | host | db name | 0 |
    +--------+-----------+------+------+---------+----+
    +-------+----------------------------------------+-------+
    | Query | uninitiatlized space of size of db len | FLAGS |
    +-------+----------------------------------------+-------+
    其中为query buffer分配的空间从Query开始,比较可知,相对于alloc_query中的缺少了db len部分(sizeof(size_t))
    
    在将其传入到send_result_to_client函数中时,就导致了memecpy读取未初始化的数据,从而使得条件不满足而退出query cache,但是这并不会导致任何问题,因为备库执行binlog本该不访问query cache,由于memcpy只是copy了未初始化的数据(后面还有空间)而并没有访问NULL pointer,因此不会出现问题,而这也是重现crash比较困难的原因!
    
    但是,这里存在一个隐患,如果读取的未初始化数据db_len正好和thd->db_length相同,那么Query_cache::send_result_to_client还将继续执行下去,直到...
    
    点击(此处)折叠或打开
    memcpy((uchar *)(sql + (tot_length - QUERY_CACHE_FLAGS_SIZE)),
         (uchar*) &flags, QUERY_CACHE_FLAGS_SIZE);
    
    悲剧发生了...tot_length是按照alloc_query中的内存布局计算出来的,但是实际传给send_result_to_client的query是缺少一个字段的,于是memcpy访问越界,导致slave crash
    
    mysql官方和percona都为此bug提供了patch,percona通过thd->alloc重新分配了一个query buffer,而mysql官方直接修改了bug的源头,都放进来。
    
    patch:
    http://bazaar.launchpad.net/~mysql/mysql-server/5.5/revision/3837
    https://bugs.launchpad.net/percona-server/+bug/915814
  • 相关阅读:
    linux 日常命令
    apache2 修改默认php版本
    centos 6.5 创建守护进程
    ubuntu18.04 Yii2.0 安装yii2-queue并在Linux启动守护进程监听消息设置
    Ubuntu18.04 使用 deepinwine 安装企业微信后无法查看图片/头像/登陆二维码的解决方法
    CentOS 8安装Redis的两种方式
    如何在ubuntu 18.04中升级python 3.6到3.7
    Navicat 15 premium AppImage格式激活
    爬取彼岸图网实例
    requests库的介绍及get请求 + 小案例
  • 原文地址:https://www.cnblogs.com/zengkefu/p/5643916.html
Copyright © 2011-2022 走看看