Friday, August 1, 2014

Basic Windows MySQL Installation Without Installer

It dawned on me that most folks are using the Installer these days.

As I need quick access to every MySQL version,  using an Installer is never an option.
And for folks wanting 100% control over their setups, they may not want an installer doing things.

So this shows how to setup an instance manually.

  1. download non-installer .zip version from dev.mysql.com
  2. create a directory c:\mysql and c:\mysql\tmp
  3. unzip the .zip into c:\mysql
  4. move the data directory into c:\mysql for easier future upgrades
  5. create a basic my.ini
  6. install the service
  7. start the service


Here I'll show each step with more detail.   I purposely leave out things like post-installation security, to keep it simple.

1.  Create a directory.

Decide where you will put the installation and datadir.  I use c:\mysql and c:\mysql\data
since I truly despise the "windows way" with long paths such as "c:\Program Files\MySQL Server 5.6" ...

C:\>mkdir mysql
C:\>cd mysql
C:\mysql>mkdir tmp
C:\mysql>dir
 Volume in drive C has no label.
 Volume Serial Number is 802E-2730
 Directory of C:\mysql
2014/08/01  09:31    <DIR>          .
2014/08/01  09:31    <DIR>          ..
2014/08/01  09:31    <DIR>          tmp
               0 File(s)              0 bytes
               3 Dir(s)  74 040 700 928 bytes free

2.   Download the non-installer .zip version.

       Use a browser to download the latest version, for example:  


3.   Extract the zip file.


I use 7zip or winrar, but windows explorer can also be used to extract the .zip file right here.


4.  Move the data directory

The non-installer .zip comes with a data directory which I will use in this installation.
As you might want to upgrade the instance later,  I prefer to put the datadir a separate location to the version just downloaded.


C:\mysql>dir
 Volume in drive C has no label.
 Volume Serial Number is 802E-2730
 Directory of C:\mysql
2014/08/01  08:11    <DIR>          .
2014/08/01  08:11    <DIR>          ..
2014/08/01  08:11    <DIR>          tmp
2014/08/01  08:11    <DIR>          mysql-5.6.20-win32
2014/08/01  07:52       353 970 000 mysql-5.6.20-win32.zip
               1 File(s)    353 970 000 bytes
               4 Dir(s)  73 969 897 472 bytes free
C:\mysql>move mysql-5.6.20-win32\data data
        1 dir(s) moved.



5.  Write the my.ini.

I'll keep the my.ini in the datadir, to lesson complexity.

C:\mysql>notepad data\my.ini
C:\mysql>type data\my.ini
[mysqld]
datadir=c:/mysql/data
tmpdir=c:/mysql/tmp
log-error=c:/mysql/data/mysql.err
port=3306
slow-start-timeout=0
log-warnings=2


6.  Install mysqld as a service.

This part seems confusing due to the options used.  To keep things clear, I use a specific service name for each version, so that I know what it is later.
You must be running cmd.exe as an administrative user to do this.


C:\mysql>cd mysql-5.6.20-win32
C:\mysql\mysql-5.6.20-win32>cd bin
C:\mysql\mysql-5.6.20-win32\bin>mysqld.exe --install MySQL_5620 --defaults-file=c:/mysql/data/my.ini --local-service
Service successfully installed.
C:\mysql\mysql-5.6.20-win32\bin>cd..\..\


7.   Start the service.



C:\mysql>sc start MySQL_5620
SERVICE_NAME: MySQL_5620
        TYPE               : 10  WIN32_OWN_PROCESS
        STATE              : 2  START_PENDING
                                (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x1
        WAIT_HINT          : 0x1f40
        PID                : 4352
        FLAGS              :

If you have larger innodb settings, give it a few seconds/minutes to start, then check it.


C:\mysql>mysql-5.6.20-win32\bin\mysql.exe --no-defaults -h127.0.0.1 -uroot -P3306
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.6.20 MySQL Community Server (GPL)
Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> \s
--------------
mysql-5.6.20-win32\bin\mysql.exe  Ver 14.14 Distrib 5.6.20, for Win32 (x86)
Connection id:          1
Current database:
Current user:           root@localhost
SSL:                    Not in use
Using delimiter:        ;
Server version:         5.6.20 MySQL Community Server (GPL)
Protocol version:       10
Connection:             127.0.0.1 via TCP/IP
Server characterset:    latin1
Db     characterset:    latin1
Client characterset:    cp850
Conn.  characterset:    cp850
TCP port:               3306
Uptime:                 2 min 37 sec
Threads: 1  Questions: 5  Slow queries: 0  Opens: 67  Flush tables: 1  Open tables: 60  Queries per second avg: 0.031
--------------

The way I personally stay sane with >50 versions on my machine is to follow simple rules:

  • not any MySQL products 'installed' on my work machine.
  • not any global my.cnf and my.ini lurking around.
  • always use --no-defaults when running mysql programs, in case I broke the last rule.
  • not any mysql program in the path.

Note, the manual pages cover everything here, and even more verbosely.

The reason I prefer this method is that upgrades are generally easier. You simply download the next 5.6.21, extract it, delete the existing MySQL_5620 service, create a new MySQL_5621 service using same command, and run mysql_upgrade once it's started.


Friday, January 4, 2013

protocol speed comparison on windows

Comparison of Protocols


A while ago I wrote a small random function tester to fuzz test native functions such as linestring, polygon, astext, etc.  The queries it sends are generally small (100 bytes or less) and a totally CPU bound workload, since no data/tables are accessed.

As this was pretty much an open-ended test,  simply pumping random data into the functions, I had planned to let it run for a few days and see if any problems arose.

I benchmarked all the ways to connect on windows;  TCP/IP, named pipe, shared memory, and embedded server.

5.5.29 client and server are used here in all tests.  Roughly 345 million queries are sent via 8 threads.  Below is a graph to show the QPS of each protocol for the run:

Averages:



The QPS taken every minute is here.
As we see, libmysqld can do nearly 8x the throughput of tcp/ip in this test.  This matters, when you're running hundreds of billions of small fast queries.

Conclusion 

Embedded speed is clearly superior.  For this reason, I always try writing QA/testing code in C/C++ if I think it might need to be run billions of times.    But you lose ability to monitor the embedded server status from a mysql client, which is annoying.   However, distributing an embedded server application is far easier as it's self-contained. :)

Shared memory doesn't care to enforce wait_timeout, so you may want an idle-connection-killer script
looping in the background.  Also, shared memory connection isn't very stable at high concurrency.  This stability issue is already being dealt with so that's a plus.

Happy testing!

Monday, September 10, 2012

How to obtain all executing queries from a core file

When investigating core files from crashes, one can quite easily figure out which query crashed, as we've seen.

Sometimes you want to just list all the currently executing statements, this is useful for diagnosing hangs or corruptions.

At least GDB 7 supports python macros, which can help us a lot here.   I use a core file from 5.5.27, also a non-debug build but not "stripped".   So it's a standard build made with -g allowing us to reference symbols.

I wrote a simplistic macro to iterate through mysqld's global "threads" variable.
This is what my ~./.gdbinit looks like:


set history filename gdb_history.txt
set history size 32000
set history save on
set pagination off
set logging overwrite on
set logging on
set print elements 1024
set print pretty on
set print object on
define print_thds
        set $thd = ($arg0)->first
        while ( $thd != 0 && $thd->next != 0)
             
                set $thread_id=$thd->thread_id
                set $cmd=$thd->command
                set $proc_info=$thd->proc_info ? $thd->proc_info : ""
                 set $query = $thd->query_string->string
printf "thread id: %lu\n",$thread_id print $cmd
print $proc_info
print $query.str
printf "\n\n"      
                set $thd=$thd->next
        end
end
document print_thds
  print_thds : Dumps the query_strings in a list of THD objects
end

Loading a corefile and executing the macro, see now how it works :

[sbester@fc14 mysql-advanced-5.5.27-linux2.6-x86_64]$ gdb ./bin/mysqld ./core.5376
GNU gdb (GDB) Fedora (7.2-52.fc14)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
...
SIGINT is used by the debugger.
Are you sure you want to change it? (y or n) [answered Y; input not from terminal]
Reading symbols from /home/sbester/mysql/5.5/mysql-advanced-5.5.27-linux2.6-x86_64/bin/mysqld...done.
[New Thread 5417]
[New Thread 5376]
Reading symbols from /lib/modules/2.6.35.14-106.fc14.x86_64/vdso/vdso.so...Reading symbols from /usr/lib/debug/lib/modules/2.6.35.14-106.fc14.x86_64/vdso/vdso.so.debug...done.
done.
(gdb) print_thds threads
thread id: 22
$1 = COM_QUERY
$2 = 0x9ae27c "init"
$3 = 0x7fffc801dc80 "/* 50605 */  delete  ignore from `t1` order by  ( `b`<>  null )"


thread id: 21
$4 = COM_QUERY
$5 = 0xa0aeda "update"
$6 = 0x1880850 "/* 50605   explain extended   */  insert  ignore into `t1` set `a`=`a`"


thread id: 20
$7 = COM_SLEEP
$8 = ""
$9 = 0x0


thread id: 19
$10 = COM_SLEEP
$11 = ""
$12 = 0x0


thread id: 18
$13 = COM_QUERY
$14 = 0xa10e30 "updating"
$15 = 0x7fffd800e540 "/* 50605 */  delete  ignore from `t1` where (  ( `b` )    ) >= (  ( `a` is  null  )  )"


thread id: 17
$16 = COM_SLEEP
$17 = ""
$18 = 0x0


thread id: 16
$19 = COM_QUERY
$20 = 0x9ae27c "init"
$21 = 0x7fffd0017930 "/* 50605   explain extended   */ update  ignore`t3` set `a` = 4.7  order by  (  ( `a` is  null  )   sounds like  ( `a` )   ) desc limit 8"


thread id: 15
$22 = COM_QUERY
$23 = 0x9be1e5 "Updating"
$24 = 0x7fffc8005230 "/* 50605  explain partitions  */ update `t3` set `a` = `a`  where  ( `a` )    limit 1"


thread id: 14
$25 = COM_SLEEP
$26 = ""
$27 = 0x0


thread id: 13
$28 = COM_QUERY
$29 = 0x9ae27c "init"
$30 = 0x7fffc0045e10 "/* 50605   explain extended   */ update `t1` set `b` =  'e'   order by   ( `a`  not like  `b` )   desc limit 7"


thread id: 12
$31 = COM_QUERY
$32 = 0x9be1e5 "Updating"
$33 = 0x1850f80 "/* 50605 */ update  ignore`t3` set `b` = `b`  where (   ( `b`  and  `a` )  ) = (  (  ( `a` is  null  )<> ( `a` )   ) ) limit 7"


thread id: 11
$34 = COM_QUERY
$35 = 0x9ae27c "init"
$36 = 0x7ffff0005760 "/* 50605  explain /*!50605 format= json*/  */ update  ignore`t2` set `a` = -1.4  where (   ( `a`<=  `a` )  ) < (     CONCAT(  ( `b` )   ,   ( `a`  xor   null )   ,   ( `a` is  null  )   )     ) order by   (   null )   desc limit 5"


thread id: 9
$37 = COM_QUERY
$38 = 0x9ae27c "init"
$39 = 0x7fffd8005140 "/* 50605  explain   */  delete  from `t2` order by  (  ( `b` )  = ( `b`   sounds like -4.6 )    ) desc"


thread id: 8
$40 = COM_QUERY
$41 = 0x9be1e5 "Updating"
$42 = 0x7fffdc004d40 "/* 50605  explain /*!50605 format= json*/  */ update `t1` set `a` =  'deg'   where   ( `a`<`a` )"


thread id: 7
$43 = COM_QUERY
$44 = 0x9ae27c "init"
$45 = 0x7fffd00048e0 "/* 50605   explain extended   */ update `t2` set `a` = 8  order by   ( `b`>`b` )  asc  limit 4"


thread id: 5
$46 = COM_QUERY
$47 = 0xa10e30 "updating"
$48 = 0x7fffcc034000 "/* 50605  explain /*!50605 format=traditional */  */  delete  ignore from `t3`"


thread id: 4
$49 = COM_QUERY
$50 = 0x9ae27c "init"
$51 = 0x7fffc001b8d0 "/* 50605 */  delete  from `t1` where (  (  ( `a` )  < (  ( `b` is  null  )<=   ( `a`<>  null )    ) ) )  &   (     OCTET_LENGTH(  ( `b` )     )     ) order by  ( `b` )    desc limit 7"


thread id: 3
$52 = COM_SLEEP
$53 = ""
$54 = 0x0


thread id: 2
$55 = COM_QUERY
$56 = 0x9ae27c "init"
$57 = 0x7fffc0004a90 "/* 50605  explain /*!50605 format= json*/  */ update  ignore`t3` set `b` =   null  order by   ( 1.5 )   limit 8"


thread id: 1
$58 = COM_QUERY
$59 = 0xa0aeda "update"
$60 = 0x7fffcc004a90 "/* 50605   explain extended   */  insert  ignore into `t1` set `a`=6"

Wednesday, September 29, 2010

A Quick Review of Stack Traces

I'll try to pass on some basic knowledge about those confusing stack traces we sometimes see in the mysql error logs.  What can you tell from them, what are they useful for, and how to validate them?

Debugging Crashes

We tried to improve postmortem debugging of crashes + stack traces in the error log:
o) old versions of mysqld only printed numerical numbers instead of function names (if you're lucky!)
o) some platforms/architectures printed no stack trace what-so-ever!
o) faulty implementations of the crash error reporting and running query.

So, the result is that on modern supported platforms and recent versions of mysqld, you should get a useful stack trace.  A simple example from 5.5.5 on Windows:

mysqld.exe!mysql_admin_table()[sql_table.cc:5150]
mysqld.exe!mysql_optimize_table()[sql_table.cc:5226]
mysqld.exe!mysql_execute_command()[sql_parse.cc:3107]
mysqld.exe!mysql_parse()[sql_parse.cc:5911]
mysqld.exe!dispatch_command()[sql_parse.cc:1138]
mysqld.exe!do_command()[sql_parse.cc:807]
mysqld.exe!do_handle_one_connection()[sql_connect.cc:1196]
mysqld.exe!handle_one_connection()[sql_connect.cc:1136]
mysqld.exe!pthread_start()[my_winthread.c:62]
mysqld.exe!_callthreadstartex()[threadex.c:348]
mysqld.exe!_threadstartex()[threadex.c:331]
kernel32.dll!BaseThreadStart()

It should be obvious that OPTIMIZE TABLE crashed here, since the function name is clear.
The reason I always use windows stack traces in bug reports is because they are readable.  Most GDB and linux error log stack traces are not readable by the human brain at a glance, and therefore not memorable.  One reason is excessive wrapping, another reason is offsets and arguments to the functions are irrelevant and not useful for search engine indexes or the average Joe trying to find a bug report matching a stack trace.

In the old days, a crash only this printed (only 32-bit), and you had to resolve it yourself:

0x81a0705
0x8407eef
0x8408a8f
0x8408b75
0x8408dd2
0x8409af7
0x83e7fc9
0x83eefc3
0x826014c
0x826035c
0x825ec43
0x82106fd
0x81b86da
0x81bd78b
0x81bdd16
0x81bfae2

Which, on a side note is not always possible to do properly with optimized binaries so you get a partially bogus looking stack and you might be tempted to wrongly suspect faulty hardware, foul play, or bad binaries:

0x81a0705 handle_segfault + 805
0x8407eef my_write + 671
0x8408a8f init_key_cache + 1279
0x8408b75 init_key_cache + 1509
0x8408dd2 init_key_cache + 2114
0x8409af7 flush_key_blocks + 55
0x83e7fc9 flush_blocks + 41
0x83eefc3 mi_repair_by_sort + 451
0x826014c ha_myisam::repair(THD*, st_mi_check_param&, bool) + 1900
0x826035c ha_myisam::enable_indexes(unsigned int) + 364
0x825ec43 ha_myisam::end_bulk_insert() + 99
0x82106fd mysql_insert(THD*, TABLE_LIST*, List&, List >&, List&, List&, enum_duplicates, bool) + 5037
0x81b86da mysql_execute_command(THD*) + 9610
0x81bd78b mysql_parse(THD*, char const*, unsigned int, char const**) + 379
0x81bdd16 dispatch_command(enum_server_command, THD*, char*, unsigned int) + 1238
0x81bfae2 handle_one_connection + 2578

Using a technique that involves disassembling the mysqld binary into ASM and piecing together C/C++ source code/comments, it's quite possible to find those inlined functions, expanded macros, or functions that have no name in the symbols file.  A nice topic for another posting.  So, after manually inspecting the binary + numeric offsets, I could get a proper stack trace:

0x81a0705 handle_segfault
0x8407eef unlink_block
0x8408a8f free_block
0x8408b75 flush_cached_blocks
0x8408dd2 flush_key_blocks_int
0x8409af7 flush_key_blocks
0x83e7fc9 flush_blocks
0x83eefc3 mi_repair_by_sort
0x826014c ha_myisam::repair
0x826035c ha_myisam::enable_indexes
0x825ec43 ha_myisam::end_bulk_insert
0x82106fd mysql_insert
0x81b86da mysql_execute_command
0x81bd78b mysql_parse
0x81bdd16 dispatch_command
0x81bfae2 handle_one_connection

This is simply a bulk insert performing a 'repair by sort'.  It crashed in the keycache when flushing blocks, perhaps due to a memory corruption or overrun of something.  I remember fulltext indexes or large table having this problem..

Some Identifying Elements of a Stack Trace
If your 5.1. or 5.5. server ever crashes, please keep the stack trace as it can help identify exactly what the problem is, and you can search google for clues.  
  • prepared statements
Easily distinguishable by looking for the functions similar to this:
.....
mysqld-debug.exe!Prepared_statement::execute()[sql_prepare.cc:3050]
mysqld-debug.exe!mysql_sql_stmt_execute()[sql_prepare.cc:2393]
mysqld-debug.exe!mysql_execute_command()[sql_parse.cc:2935]
.....
  • stored routines and their call depth
Seeing sp_* is a sign of some stored routine activity  You can even see how many SP calls there are nested, whether they called triggers.  Takes some intuition to follow.

.......
06 mysqld_debug!sp_instr_stmt::exec_core
07 mysqld_debug!sp_lex_keeper::reset_lex_and_exec_core
08 mysqld_debug!sp_instr_stmt::execute
09 mysqld_debug!sp_head::execute
0a mysqld_debug!sp_head::execute_procedure
0b mysqld_debug!mysql_execute_command
.......
  • storage engine code (archive, innodb, myisam, merge)
InnoDB mostly asserts, and this is clearly identified in the error log before a stack trace.
"070223 21:47:40  InnoDB: Assertion failure in thread 1655241648 in file row0mysql.c line 3228"

Archive crashes can be easily seen by ha_archive functions:
.....
mysqld.exe!ha_archive::free_share()[ha_archive.cc:411]
mysqld.exe!ha_archive::open()[ha_archive.cc:498]
mysqld.exe!handler::ha_open()[handler.cc:2059]
.....
  • query cache
Any thing involving the Query_Cache class functions:
.....
#5  0x000000000065f390 in Query_cache::insert_table ()
#6  0x000000000065f63a in Query_cache::register_tables_from_list ()
#7  0x000000000065f6a5 in Query_cache::register_all_tables ()
#8  0x000000000065fc0a in Query_cache::store_query ()
#9  0x000000000058cd38 in mysql_execute_command ()
.....
  • mysql functions (string, math, datetime, comparative)
Look out for specific Item_func* methods...
.....
mysqld.exe!Arg_comparator::compare_binary_string()[item_cmpfunc.cc:1158]
mysqld.exe!Item_func_eq::val_int()[item_cmpfunc.cc:1692]
mysqld.exe!Item::val_bool()[item.cc:184]
mysqld.exe!Item_cond_and::val_int()[item_cmpfunc.cc:4222]
.....
  • first calling function in the application
You can nearly always expect a valid stack trace to have these functions at the bottom:
.....
mysqld-debug.exe!mysql_execute_command()[sql_parse.cc:2256]
mysqld-debug.exe!mysql_parse()[sql_parse.cc:5974]
mysqld-debug.exe!dispatch_command()[sql_parse.cc:1233]
mysqld-debug.exe!do_command()[sql_parse.cc:872]
mysqld-debug.exe!handle_one_connection()[sql_connect.cc:1127]
  • last calling functions before the crash
Crashing is usually handled by mysqld's segfault handler.  It depends on the OS and environment.  Most of the time you'll have:

mysqld-debug.exe!my_sigabrt_handler()[mysqld.cc:2048]
mysqld-debug.exe!raise()[winsig.c:597]
mysqld-debug.exe!abort()[abort.c:78]
......

or

0   mysqld   0x00579d3e my_print_stacktrace + 44
1   mysqld   0x00100f78 handle_segfault + 836
......


Debugging Hangs

When mysqld hangs or flatlines the CPU and logging in or killing queries doesn't help, you'd better either create a corefile,  break into the process with a debugger, or just use the PMP.

You'll probably need stack trace of all the threads to determine what is going on:

  1. A single thread is looping endlessly in some loop
  2. Multiple threads are hitting a hot mutex, or totally deadlocked, waiting for each other.


If the deadlock is in innodb you often get useful innodb outputs in the error log
for each waiting thread. But it can be extremely helpful to get full stack traces too.

--Thread 3003468656 has waited at fsp/fsp0fsp.c line 2204 for 556.00 seconds the
semaphore:
X-lock on RW-latch at 0xb759ceb0 created in file fil/fil0fil.c line 1061
That's all for now.!

Wednesday, June 16, 2010

quick update from down under...

I'm pleased to report that so far the Soccer World Cup has been pulled off rather successfully, with only minor incidents reported. I have however noticed local news showing some 'feel-good' stories that are obviously written to give a false impression to the international media of the real situation here. Let's hope the unions and Eskom workers don't mess things up by holding a gun to the Country's head with protesting/striking too much in the international media's light.. Hold thumbs..

BTW, I hate the vuvuzela :)


I thought I should share two important MySQL bugs with you today. In case you ever used YaSSL to establish SSL connections, you were at risk of hitting random crashes due to bug #34236 (Various possibly related SSL crashes) if more than one concurrent connection was ever made. The reason is the YaSSL code was built without mutexes as if for single threaded apps...


Next bug I think is widespread enough to mention is optimizer/query plan related. Examine the testcase on bug #48537 (difference of index selection between rpm binary and .tar.gz, windows vs linux..) And read the changeset notes:


On Intel x86 machines index selection by the MySQL query
optimizer could sometimes depend on the compiler version and
optimization flags used to build the server binary.

The problem was a result of a known issue with floating point
calculations on x86: since internal FPU precision (80 bit)
differs from precision used by programs (32-bit float or 64-bit
double), the result of calculating a complex expression may
depend on how FPU registers are allocated by the compiler and
whether intermediate values are spilled from FPU to memory. In
this particular case compiler versions and optimization flags
had an effect on cost calculation when choosing the best index
in best_access_path().

A possible solution to this problem which has already been
implemented in mysql-trunk is to limit FPU internal precision
to 64 bits. So the fix is a backport of the relevant code to
5.1 from mysql-trunk.


Now I'll get back to enjoying the public holiday and bugs reporting ;-)

Friday, May 14, 2010

vmstat/iostat replacement for windows ?

I dislike the old perfmon interface and it's unreadable graphs and logs. For a long time I've been searching for a basic vmstat and/or iostat windows port, and one that doesn't rely on that nonsensical cygwin. If anybody knows of one, please leave a comment.


Here's a proof on concept I cooked up in 20 minutes using the PDH (performance data helper) functions. In a nutshell, it queries the PDH counters directly and I'm be free to display
the data however I like.

Here's what I got so far:


proc_q_len pagefile interrupt/s cswitch/s %cpu_user %cpu_sys %cpu_idle %disk_busy %disk_read %disk_write
10 2308780032 2016 2555 64 26 9 100 0 100
3 2308911104 2863 3669 62 13 23 100 1 100
0 2309206016 1857 3057 79 10 9 2 0 2
0 2310217728 2579 3664 64 9 26 100 0 100
1 2309140480 2195 2985 71 3 25 100 0 100
2 2309140480 2241 3042 76 4 18 100 0 100


Not perfect, and I'm still trying to devise a proper layout for the stuff I want to display.
The columns shown correspond to the counters:
  • \System\Processor Queue Length
  • \Process(_Total)\Page File Bytes
  • \Processor(_Total)\Interrupts/sec
  • \System\Context Switches/sec
  • \Processor(_Total)\% User Time
  • \Processor(_Total)\% Privileged Time
  • \Processor(_Total)\% Idle Time
  • \PhysicalDisk(_Total)\% Disk Time
  • \PhysicalDisk(_Total)\% Disk Read Time
  • \PhysicalDisk(_Total)\% Disk Write Time

The general flow of code is like this (there are samples online):

2. PdhAddCounter for each counter
3. for each X seconds:
3.2 PdhGetFormattedCounterValue for each counter
3.3 print the result for each counter



Monday, May 3, 2010

Beware of RBR and tables without indexes

I always knew RBR and unindexed tables didn't play along very well, but never realized just how much you can distress a slave can in some cases.
Consider this statement (yeah yeah, i know :)


mysql> delete from t1 order by rand();
Query OK, 78130 rows affected (2.61 sec)

t1 has no indexes and is an int field with numbers from 1 to 78130. However, this will cause the slave to re-read entire table for each row deleted! Here it's still running, causing 100% cpu usage:

---TRANSACTION 0 1799, ACTIVE 2390 sec, OS thread id 3672 fetching rows mysql tables in use 1, locked 1 153 lock struct(s), heap size 30704, 78281 row lock(s), undo log entries 35423

Number of rows inserted 78130, updated 0, deleted 35423, read 1076560253 0.00 inserts/s, 0.00 updates/s, 17.58 deletes/s, 367099.91 reads/s

Over a billion row reads 40 minutes later and it's not even half done yet.For a large table this could take weeks or years to complete. It would be nice if there was a way to prevent this situation from happening.

Friday, February 12, 2010

debugging mysqld corefile on AIX

I recently had the pleasure of logging into an AIX 5.3 machine for the first time ever, to debug a corefile.

Firstly, having the mysqld binary and core is not enough, unless you have an identical machine on which to study the corefile. Library mismatches can be a problem.. IBM was kind enough to provide the snapcore utility to solve this easily.

Snapcore will gather all the libraries and create a single archive contain libs, binary, core.

So we now have a file called something like: snapcore_555060.pax
On our dev box, extract the pax archive:

gunzip snapcore_555060.pax.Z
pax -r -f snapcore_555060.pax

On your dev AIX box, make sure you have DBX installed!!

bash-3.00# lslpp -l | grep bos.adt.debug
bos.adt.debug 5.3.8.0 COMMITTED Base Application Development

Now, we are ready to debug a core. But we have to instruct DBX to read the libraries
that we got from the pax archive, instead of the default libraries on this system.

dbx -F -p /usr=/home/sbester/core/usr ./mysqld ./core


And since this isn't a DBX tutorial, I'll stop here, but you'll use normal DBX commands to print a stack trace, move up/down frames, print variables, list the source code.



Tuesday, December 1, 2009

a little challenge

How do you make mysqld write a DELETE to the binlog just by entering a SELECT statement ?
No triggers and no stored routines/functions are involved.

Saturday, June 27, 2009

5.1 doesn't solve all merge table hell from 5.0.

This week I've had to revisit merge tables once again due to customers experiencing problems. Although 5.1 merge table implementation is a huge improvement over 5.0, there still remains some critical bugs.

My list is still growing:

bug #45800: crash when replacing into a merge table and there is a duplicate
bug #45781: infinite hang/crash in "opening tables" after handler tries to open merge table
bug #45796: invalid memory reads and writes when altering merge and base tables
bug #45777: check table doesn't show all problems for merge table compliance in 5.1

Not to mention a few feature requests, and even documentation clarification for some manual sections.

Friday, June 19, 2009

some useful additions to query generator

I've been on vacation this week, and decided to fine-tune some old QA code. Opened the manual to see the syntax for a select statement, and afterwards added to my random select generator the following:

  • all index hints (force, use, ignore, for join, for order by, for group by)
  • lock in share mode, for update
  • key_block_size for individual indexes
  • hash, btree, rtree for individual indexes
  • unique, fulltext, spatial for indexes
Especially important is the 'lock in share mode' addition. The reason is InnoDB
has many serious bugs with this locking mode (insert ... select, and others) in read committed mode.

So, I don't need multitable delete or update to reproduce those bugs, since I can just do a simple select locking in share mode. For example, the following bugs previously went without proper testcase until I discovered this:

assert btr/btr0pcur.c line 217 -innodb_locks_unsafe_for_binlog or read committed
5.1.35 crashes with Failing assertion: index->type & DICT_CLUSTERED
Strange error messages about locks from InnoDB

Tuesday, June 2, 2009

some bug stats

So I did some checking at the number of bugs I've reported since start of 2005. Seems I'm at the top of my game here!

  • P1 Server bugs: 180 (next runner up PeterG with 127)
  • P1 + P2 Server bugs: 321 (next runner up PeterG with 311)
Interesting to note that most of my bug filing happened after 2006, but I started working at MySQL in 2005, so that's why I've used that start date.

The runner ups mostly report bugs in alpha versions, falcon, maria, and beta versions of mysql.
Nearly all of my bugs are in the current GA versions since that is what most of our customers use.

On occasion I go off on a tangent and try break the subquery optimizations in 6.0, but this
is only a small percentage of the total.

Monday, May 11, 2009

been a shocking week for 5.1.35

so last week i started tweaking some of my old 'rainbow' scripts, and found 1 bug for each day of the week. there are a few more in the pipeline still...

Bug #44774 (load_file function produces valgrind warnings)
Bug #44768 (SIGFPE crash when selecting rand from a view containing null)
Bug #44767 (invalid memory reads in password() and old_password() functions)
Bug #44766 (valgrind error when using convert() in a subquery)
Bug #44684 (valgrind reports invalid reads in Item_func_spatial_collection::val_str)
Bug #44672 (Assertion failed: thd->transaction.xid_state.xid.is_null())
Bug #44664 (valgrind warning for COMMIT_AND_CHAIN and ROLLBACK_AND_CHAIN)
Bug #44633 (Automatic search depth and nested join's results in server crash - v2)

so, it seems i am still useful for bug finding, even with old tools i created pre-5.1 GA

Saturday, January 10, 2009

MXit !

Today I started writing a PC client for MXit, because the existing ones suck. Since the company uses a proprietary variation of the jabber protocol to reduce bandwidth usage, I have to decode the protocol myself.. Will post details of it later...

Get MXit http://www.mxit.co.za/web/downloadmxit.htm

Monday, January 5, 2009

Kilimanjaro preparations

So I have started training to get fit enough to gracefully reach the top of Kilimanjaro in 2009.
Information on the various routes here.

Here I will keep a log of certain walks I do, and their timings.
Note that time_down usually includes time spent at the summit.


+------------+------------+------------+-----------+------------+------------------------------------------------------+
| date | start_time | time_there | time_back | time_total | venue |
+------------+------------+------------+-----------+------------+------------------------------------------------------+
| 2008-12-27 | 16:37:00 | 00:47:00 | 00:32:00 | 01:19:00 | Lions Head |
| 2008-12-28 | 05:47:00 | 00:48:00 | 00:35:00 | 01:23:00 | Lions Head |
| 2008-12-30 | 12:57:00 | 00:42:00 | 00:30:00 | 01:12:00 | Lions Head |
| 2008-12-31 | 12:24:00 | 00:39:00 | 00:30:00 | 01:09:00 | Lions Head |
| 2009-01-02 | 12:09:00 | 00:37:00 | 00:28:00 | 01:05:00 | Lions Head |
| 2009-01-05 | 12:45:00 | 00:39:00 | 00:22:00 | 01:01:00 | Lions Head |
| 2009-01-07 | 17:19:00 | 00:37:00 | 00:21:00 | 00:58:00 | Lions Head |
| 2009-01-14 | 12:10:00 | 01:01:00 | 01:29:00 | 02:30:00 | Home->La Med (via KloofNek)->Joburg (via Sea Point) |
| 2009-01-24 | 06:00:00 | 01:05:00 | 00:47:00 | 01:52:00 | Platteklip |
| 2009-01-29 | 13:30:00 | 00:38:00 | 00:27:00 | 01:05:00 | Lions Head |
| 2009-02-21 | 07:26:00 | 00:58:00 | 01:31:00 | 02:29:00 | Home->La Med (via KloofNek)->Joburg) (via Sea Point) |
+------------+------------+------------+-----------+------------+------------------------------------------------------+
11 rows in set (0.03 sec)






Saturday, September 20, 2008

innodb index page format

Today I had to decode an innodb index page, so I documented the entire process here:

E:\mysql-enterprise-gpl-5.0.66a-winx64\bin>mysqld-nt --console --skip-grant-tables --skip-name-resolve
InnoDB: The first specified data file .\ibdata1 did not exist:
InnoDB: a new database to be created!
080919 14:29:00 InnoDB: Setting file .\ibdata1 size to 10 MB
InnoDB: Database physically writes the file full: wait...
080919 14:29:00 InnoDB: Log file .\ib_logfile0 did not exist: new to be created
InnoDB: Setting log file .\ib_logfile0 size to 5 MB
InnoDB: Database physically writes the file full: wait...
080919 14:29:01 InnoDB: Log file .\ib_logfile1 did not exist: new to be created
InnoDB: Setting log file .\ib_logfile1 size to 5 MB
InnoDB: Database physically writes the file full: wait...
InnoDB: Doublewrite buffer not found: creating new
InnoDB: Doublewrite buffer created
InnoDB: Creating foreign key constraint system tables
InnoDB: Foreign key constraint system tables created
080919 14:29:01 InnoDB: Started; log sequence number 0 0
080919 14:29:01 [Note] mysqld-nt: ready for connections.
Version: '5.0.66a-enterprise-gpl-nt' socket: '' port: 3306 MySQL Enterprise Server (GPL)


create table t1(a varchar(20) primary key, b varchar(20), c varchar(20),key(b),key(c,b))engine=innodb;
insert into t1(a,b,c) values ('aaaa','bbbbb','cccccc');
insert into t1(a,b,c) values ('aaaaaaa',null,'ccc');
insert into t1(a,b,c) values ('a','b',null);
insert into t1(a,b,c) values ('aaaaaaaaaa','bbb','c');



080919 14:37:59 [Note] mysqld-nt: Normal shutdown

080919 14:37:59 InnoDB: Starting shutdown...
080919 14:38:14 InnoDB: Shutdown completed; log sequence number 0 48536
080919 14:38:14 [Note] mysqld-nt: Shutdown complete



we have secondary indexes on this table

this is key(c,b) (directly from ibdata1):


000d0000h: 35 56 71 04 00 00 00 34 FF FF FF FF FF FF FF FF ; 5Vq....4ÿÿÿÿÿÿÿÿ
000d0010h: 00 00 00 00 00 00 BD 92 45 BF 00 00 00 00 00 00 ; ......½’E¿......
000d0020h: 00 00 00 00 00 00 00 02 00 C3 80 06 00 00 00 00 ; .........À.....
000d0030h: 00 B5 00 05 00 00 00 04 00 00 00 00 00 00 03 05 ; .µ..............
000d0040h: 00 00 00 00 00 00 00 00 00 11 00 00 00 00 00 00 ; ................
000d0050h: 00 02 15 F2 00 00 00 00 00 00 00 02 15 32 01 00 ; ...ò.........2..
000d0060h: 02 00 47 69 6E 66 69 6D 75 6D 00 05 00 0B 00 00 ; ..Ginfimum......
000d0070h: 73 75 70 72 65 6D 75 6D 04 05 06 00 00 00 10 FF ; supremum.......ÿ
000d0080h: EF 63 63 63 63 63 63 62 62 62 62 62 61 61 61 61 ; ïccccccbbbbbaaaa
000d0090h: 07 03 02 00 00 18 FF E9 63 63 63 61 61 61 61 61 ; ......ÿécccaaaaa
000d00a0h: 61 61 01 01 01 00 00 20 00 0B 62 61 0A 03 01 00 ; aa..... ..ba....
000d00b0h: 00 00 28 FF E3 63 62 62 62 61 61 61 61 61 61 61 ; ..(ÿãcbbbaaaaaaa
000d00c0h: 61 61 61 00 00 00 00 00 00 00 00 00 00 00 00 00 ; aaa.............




Let's reformat this page into the correct fields as seen by InnoDB:

0000: 35567104 -> FIL_PAGE_SPACE_OR_CHKSUM
0004: 00000034 -> FIL_PAGE_OFFSET
0008: FFFFFFFF -> FIL_PAGE_PREV
0012: FFFFFFFF -> FIL_PAGE_NEXT
0016: 000000000000BD92 -> FIL_PAGE_LSN
0024: 45BF -> FIL_PAGE_TYPE (#define FIL_PAGE_INDEX 17855)
0026: 0000000000000000 -> FIL_PAGE_FILE_FLUSH_LSN
0034: 00000000 -> FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID

0038: 0002 -> PAGE_N_DIR_SLOTS
0040: 00C3 -> PAGE_HEAP_TOP (195 ...)
0042: 8006 -> PAGE_N_HEAP (6 records in heap (remove 15th bit)
0044: 0000 -> PAGE_FREE
0046: 0000 -> PAGE_GARBAGE
0048: 00B5 -> PAGE_LAST_INSERT
0050: 0005 -> PAGE_DIRECTION (PAGE_NO_DIRECTION)
0052: 0000 -> PAGE_N_DIRECTION
0054: 0004 -> PAGE_N_RECS
0056: 0000000000000305 -> PAGE_MAX_TRX_ID (773)
0064: 0000 -> PAGE_LEVEL
0066: 0000000000000011 -> PAGE_INDEX_ID ( Page may be an index page where index id is 0 277385)
0074: 000000000000000215F2 -> PAGE_BTR_SEG_LEAF
0084: 00000000000000021532 -> PAGE_BTR_SEG_TOP

infimum:
0094: 01 -> info_bits=0, n_owned=1 (always 1 for the infimum)
0095: 00 -> heap number
0096: 02 -> status bits
0097: 0047 -> next record (71 bytes)
0099: 696E66696D756D00 -> "infimum"

supremum:
0107: 05000b -> extra bytes
0110: 0000 -> next record, zero since supremum is always last
0112: 73757072656D756D -> "supremum"

index row1:
0120: 040506 -> field offsets, starting with the last field.
0123: 00000010 -> extra bytes
0127: FFEF -> offset to next record (17 bytes back (offset 112))
0129: 636363636363 -> 'cccccc' (keypart1)
0135: 6262626262 -> 'bbbbb' (keypart2)
0140: 61616161 -> 'aaaa' (primary key appended)

index row2:
0144: 0703 -> field lengths, starting with the last field (excluding null!).
0146: 02000018 -> extra bytes
0150: FFE9 -> offset to next record (23 bytes back (offset 129))
0152: 636363 -> 'ccc' (keypart1)
0155: 61616161616161 -> 'aaaaaaa' (primary key appended)

index row3:
0162: 0101 -> field lengths, starting with the last field (excluding null!).
0164: 01000020 -> extra bytes
0168: 000B -> offset to next record (11 bytes (offset 181))
0170: 62 -> 'b' (keypart2)
0171: 61 -> 'a' (primary key appended)

index row4:
0172: 0A0301 -> field lengths
0175: 00000028 -> extra bytes
0179: FFE3 -> offset to next record (29 bytes back (offset 152!))
0181: 63 -> 'c' (keypart1)
0182: 626262 -> 'bbb' (keypart2)
0185: 61616161616161616161 -> 'aaaaaaaaaa' (primary key appended)



explanation of "extra bytes" still to be done

Thursday, August 21, 2008

how to debug a mysqld core file from an rpm install

You have a typical rpm installation of mysql, and the process is crashing. Here are the basic steps needed to find out more info about a crash:

  • Configure the OS to be able to create corefiles. (Redhat details), (Solaris details)
  • Tell mysqld to create a corefile by adding the following options to my.cnf:

[mysqld_safe]
core-file-size=unlimited

[mysqld]
core-file
Usually the corefile will be created in the datadir with a name like core.2921 where 2921 was the pid of the running process. The location is configurable on most OS's.

You'll need the following to study the core file:

  • exact mysqld binary that created the core file
  • the core file
  • the glibc version of the original system (rpm -qa|grep -i glibc)
  • the debuginfo package corresponding to the original mysql rpms.
Let's go through a hypothetical example next.
On my server I have installed MySQL-server-community-5.0.67-0.rhel5.x86_64.rpm and it's been crashing. I have a corefile called core.12345 which I've moved to a test system because I don't want to impact production while playing around with it.

On the production server we have glibc 2.3.4-2.36 installed. So to setup the test box to study the core I do this:

From dev.mysql.com download the MySQL-community-debuginfo-5.0.67-0.rhel5.x86_64.rpm
Download the glibc-2.3.4-2.36.x86_64.rpm from somewhere (in case test system isn't running same version). Next we extract the RPMS and launch gdb and tell it the path to load libraries and symbol files:

rpm2cpio MySQL-community-debuginfo-5.0.67-0.rhel5.x86_64.rpm | cpio -idvu
rpm2cpio glibc-2.3.4-2.36.x86_64.rpm | cpio -idvu

gdb ./mysqld --core ./core.12345
set solib-absolute-prefix .
file ./usr/lib/debug/usr/sbin/mysqld.debug

From here you should get reasonable output from GDB, such as "thread apply all bt" and "bt full" and continue to examine the corefile...

Friday, July 4, 2008

gypsy is resumed

In search of better qa tools, i have resumed work on my gypsy. Within hours i verified a bug i thought was not possible any time soon...

crash on prepared statement + cursor + geometry + too many open files !

The code is also in launchpad (bzr branch lp:gypsy) if anybody cares.

Wednesday, April 16, 2008

innodb plugin and new features!

check it out:
the announcement

plugin documentation


o) Fast Index Creation in the InnoDB Storage Engine
o) InnoDB Data Compression
o) InnoDB File Format Management
o) InnoDB INFORMATION_SCHEMA tables


yay!! gonna test the compression immediately :)