{"id":396,"date":"2015-01-05T00:53:17","date_gmt":"2015-01-04T23:53:17","guid":{"rendered":"http:\/\/paguilar.org\/?p=396"},"modified":"2015-01-05T00:58:50","modified_gmt":"2015-01-04T23:58:50","slug":"running-mysql-in-arm-with","status":"publish","type":"post","link":"https:\/\/paguilar.org\/?p=396","title":{"rendered":"Running MySQL with <16MB memory in an ARM processor"},"content":{"rendered":"<p>In many small embedded systems it doesn&#8217;t make much sense to have a powerful Relational Data Base Management System (RDBMS) such as MySQL because there is only one application that access the database or one that writes and one\/many that reads. In these cases, the best option is <a href=\"http:\/\/www.sqlite.org\/\" title=\"SQLite\">SQLite<\/a> that is may be the widest used embedded database.<\/p>\n<p>However, small systems are getting more complex and even when there are only few MB of memory  and few MHz (in my case 64MB and 210MHz respectively), there could be several applications accessing the database simultaneously. For example, several C programs writting and several PHP script reading and writting (through a built-in web server such as Busybox&#8217;s httpd or lighttpd).<br \/>\nIn these cases SQLite starts to have issues handling the concurrence even if you configure it for using <a href=\"https:\/\/www.sqlite.org\/wal.html\" title=\"SQLite3 Write-Ahead-Log\">Write-Ahead-Log (WAL)<\/a> instead of the default rollback journal.<\/p>\n<p>I was curious about the minimum requirements I would need to run MySQL in an small embedded system just to see if it was technically feasible.  I gave it a try and I managed to run it in an ARM Atmel AT91SAM9260 with only 64MB.<br \/>\nIn fact, MySQL was running exactly in 13.58MB:<\/p>\n<p><a href=\"https:\/\/paguilar.org\/wp-content\/uploads\/2014\/11\/htop_mysql.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/paguilar.org\/wp-content\/uploads\/2014\/11\/htop_mysql-281x300.png\" alt=\"htop_mysql\" width=\"281\" height=\"300\" class=\"alignnone size-medium wp-image-399\" srcset=\"https:\/\/paguilar.org\/wp-content\/uploads\/2014\/11\/htop_mysql-281x300.png 281w, https:\/\/paguilar.org\/wp-content\/uploads\/2014\/11\/htop_mysql-660x702.png 660w, https:\/\/paguilar.org\/wp-content\/uploads\/2014\/11\/htop_mysql.png 700w\" sizes=\"auto, (max-width: 281px) 100vw, 281px\" \/><\/a><\/p>\n<p>The first thing was obviously building MySQL for my ARM processor. I didn&#8217;t find any <em>easy<\/em> method, but this procedure worked for me. It&#8217;s based on <a href=\"http:\/\/dp.nonoo.hu\/cross-compiling-mysql\/\" title=\"Building MySQL\">this guide<\/a> written by <a href=\"http:\/\/dp.nonoo.hu\" title=\"nonoo\">nonoo<\/a>.<\/p>\n<p>The most imporant thing when cross-building MySQL is that you have to build first a native MySQL and then cross-build MySQL for your target. This is necessary because MySQL, for building some pieces of itself, it uses binaries generated on-the-fly.<\/p>\n<p>First, let&#8217;s export common environment variables that make our life easier:<\/p>\n<pre lang=\"bash\">export HOST=arm-linux\r\nexport BUILD=i386-linux\r\nexport ROOTFS=\/home\/projects\/rootfs<\/pre>\n<p><strong>Requirements<\/strong><\/p>\n<p><span style=\"color: #5077d7;\">libncurses<\/span><br \/>\nPackage: <a href=\"http:\/\/ftp.gnu.org\/pub\/gnu\/ncurses\/ncurses-5.7.tar.gz\">libncurses 5.7<\/a><\/p>\n<p>Configure, build and install the only requirement:<\/p>\n<pre lang=\"bash\">\r\ncd \/home\/nonoo\/mysql\r\ntar xvf ncurses-5.7.tar.gz\r\ncd ncurses-5.7\r\nCC=arm-linux-gcc CXX=arm-linux-g++ .\/configure --host=arm-linux-gnu --prefix=\/usr\r\nmake\r\nmake install DESTDIR=\/home\/projects\/libncurses-compiled\r\n<\/pre>\n<p><span style=\"color: #5077d7;\">MySQL<\/span><br \/>\nPackage: <a href=\"http:\/\/dev.mysql.com\/downloads\/mysql\/5.5.html\">MySQL 5.5.37<\/a><\/p>\n<p><strong>MySQL<\/strong><\/p>\n<p>Download MySQL and copy it these two directories:<\/p>\n<pre lang=\"bash\">\r\nmkdir mysql-src-x86   mysql-src-arm\r\ntar xvf mysql-5.5.37.tar.gz\r\nmv mysql-5.5.37 mysql-src-x86\r\ntar xvf mysql-5.5.37.tar.gz\r\nmv mysql-5.5.37 mysql-src-arm\r\n<\/pre>\n<p>Compile the host version. In my case I have an AMD 64 bits processor. Choose the one that fits your host:<\/p>\n<pre lang=\"bash\">\r\ncd mysql-src-x86\/BUILD\r\n.\/compile-amd64-max\r\n<\/pre>\n<p>Now we can start to cross-build MySQL:<\/p>\n<p><strong>Configuring<\/strong><\/p>\n<p>Create the CMake toolchain file <em>mysql-src-arm\/build\/mysql_at91sam9260.cmake<\/em>:<\/p>\n<pre lang=\"bash\">\r\n# this one is important\r\nSET(CMAKE_SYSTEM_NAME Linux)\r\n#this one not so much\r\nSET(CMAKE_SYSTEM_VERSION 1)\r\n\r\n# specify the cross compiler\r\nSET(CMAKE_C_COMPILER   \/opt\/buildroot-we500\/usr\/bin\/arm-linux-gcc)\r\nSET(CMAKE_CXX_COMPILER \/opt\/buildroot-we500\/usr\/bin\/arm-linux-g++)\r\n\r\n# where is the target environment \r\nSET(CMAKE_FIND_ROOT_PATH  \/opt\/buildroot\/usr\/arm-linux\/sysroot \/home\/projects\/rootfs)\r\n\r\n# search for programs in the build host directories\r\nSET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)\r\n# for libraries and headers in the target directories\r\nSET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)\r\nSET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)\r\n\r\nSET(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} \/home\/projects\/libncurses-compiled\/usr)\r\n\r\nSET(CMAKE_INSTALL_PREFIX \/home\/projects\/rootfs)\r\n\r\n# MySQL specific\r\nSET(STACK_DIRECTION 1)\r\nSET(WITH_UNIT_TESTS OFF)\r\n<\/pre>\n<p>Create and run the script <em>mysql-src-arm\/BUILD\/doconfig<\/em>:<\/p>\n<pre lang=\"bash\">\r\n#!\/bin\/bash\r\nrm CMakeCache.txt\r\n#path=`dirname $0`\r\ncmake -DCMAKE_TOOLCHAIN_FILE=mysql_at91sam9260.cmake ..  \r\n<\/pre>\n<p><strong>Prepare to build<\/strong><\/p>\n<p>Create the script <em>mysql-src-arm\/BUILD\/domake<\/em>:<\/p>\n<pre lang=\"bash\">\r\n#!\/bin\/bash\r\nexport PATH=$PATH:`pwd`\/extra\r\nexport PATH=$PATH:`pwd`\/..\/scripts\r\n\r\n# These scripts are needed to be copied from the x86 dir every time before make\r\n# runs because they will be overwritten with ARM versions after a while.\r\ncp ..\/..\/mysql-5.5.37-x86\/sql\/gen_lex_hash   sql\/gen_lex_hash\r\nexport PATH=$PATH:`pwd`\/sql\r\ncp ..\/..\/mysql-5.5.37-x86\/storage\/perfschema\/gen_pfs_lex_token   storage\/perfschema\/gen_pfs_lex_token\r\nexport PATH=$PATH:`pwd`\/storage\/perfschema\/\r\n\r\nmake\r\n<\/pre>\n<p>The above script copies a couple of files before building. THis is needed everytime because MySQL will try to run the auto-generated binaries for ARM, but we need to execute them in our host (x86). Not doing this gives these errors:<\/p>\n<pre lang=\"bash\">\r\nGenerating pfs_lex_token.h\r\n\/bin\/sh: 1: gen_pfs_lex_token: not found\r\n<\/pre>\n<pre lang=\"bash\">\r\nBuilding CXX object client\/CMakeFiles\/mysqladmin.dir\/mysqladmin.cc.o\r\n\/home\/nonoo\/mysql\/mysql-src-arm\/sql\/sql_lex.cc: In function 'void lex_init()':\r\n\/home\/nonoo\/mysql\/mysql-src-arm\/sql\/sql_lex.cc:153:18: error: 'symbols' was not declared in this scope\r\n<\/pre>\n<p><strong>Cross-building<\/strong><\/p>\n<p>Copy the following ncurses include files generated when building ncurses inside the <em>client\/<\/em> directory, otherwise the building process won&#8217;t find them:<\/p>\n<pre lang=\"bash\">\r\ncurses.h\r\nncurses_dll.h\r\nunctrl.h\r\n<\/pre>\n<p>and edit the file <em>mysql.cc<\/em> by modifying how the above files are included:<\/p>\n<pre lang=\"bash\">\r\n\"curses.h\"\r\n\"unctrl.h\"\r\n<\/pre>\n<p>Run <em>domake<\/em>. If you&#8217;re lucky it will finish successfully at the first try. <\/p>\n<p>If you have the following error<\/p>\n<pre lang=\"bash\">  \r\nGenerating ..\/include\/mysqld_error.h, ..\/sql\/share\/english\/errmsg.sys\r\n\/bin\/sh: 1: comp_err: not found\r\n<\/pre>\n<p>copy all executables from <em>mysql-src-x86\/BUILD\/extra<\/em> to <em>mysql-src-arm\/BUILD\/extra<\/em> and <em>mysql-src-arm\/extra<\/em>.<br \/>\nRun <em>domake<\/em> again.<\/p>\n<p>If you still have problems and get this error:<\/p>\n<pre lang=\"bash\">\r\nmake[2]: *** No rule to make target `..\/scripts\/comp_sql', needed by `scripts\/mysql_fix_privilege_tables_sql.c'.  Stop.\r\n<\/pre>\n<p>Copy <em>mysql-src-x86\/BUILD\/scripts\/comp_sql<\/em> to <em>mysql-src-arm\/scripts\/comp_sql<\/em>.<br \/>\nRun domake again.<\/p>\n<p>At this point you should have built it successfully.<\/p>\n<p><strong>Installing<\/strong><\/p>\n<pre lang=\"bash\">\r\nmake install DESTDIR=$ROOTFS\r\n<\/pre>\n<p>It will install in the <em>usr\/local\/<\/em> directory inside the $ROOTFS.<\/p>\n<p>Add the mysql user and group in your target board. If you have more users than root, you have to adapt it by changing the user and group id:<\/p>\n<p>Edit <em>\/etc\/passwd<\/em><\/p>\n<pre lang=\"bash\">\r\nmysql:x:1:1:mysql:\/nonexistent:\/bin\/false\r\n<\/pre>\n<p>Edit <em>\/etc\/group<\/em><\/p>\n<pre lang=\"bash\">\r\nmysql:x:1:\r\n<\/pre>\n<p>and create the required directory<\/p>\n<pre lang=\"bash\">\r\nmkdir -p \/var\/lib\r\n<\/pre>\n<p>Now you can run MySQL&#8217;s install script:<\/p>\n<pre lang=\"bash\">\r\ncd \/usr\/local\/\r\n.\/scripts\/mysql_install_db\r\nchown -R mysql:mysql data \/var\/lib\/mysql\r\n<\/pre>\n<p>Now that you have the MySQL server binary in your rootfs you can execute it, but if you have less than 128MB, it will refuse to start.<\/p>\n<p>You need to configure it properly (<em>my.conf<\/em>) to use as less memory as possible. I made several tests and the best configuration in which I managed to make it work is the following:<\/p>\n<pre lang=\"bash\">\r\n# MySQL clients\r\n[client]\r\nport = 3306\r\nsocket = \/var\/run\/mysqld\/mysqld.sock\r\n\r\n# MySQL server\r\n[mysqld]\r\nport = 3306\r\nsocket = \/var\/run\/mysqld\/mysqld.sock\r\n\r\n# The maximum permitted number of simultaneous client connections\r\nmax_connections = 10\r\n\r\n# How many threads the server should cache for reuse\r\nthread_cache_size = 0 \r\n\r\n# The maximum size of one packet or any generated\/intermediate string\r\nmax_allowed_packet = 256K\r\n\r\n# Each session that needs to do a sort allocates a buffer of this size\r\nsort_buffer_size = 64K\r\n\r\n# Improve ORDER BY performance\r\nread_rnd_buffer_size = 64K\r\n\r\n# Each client thread is associated with a connection buffer and result buffer \r\n# that begin with a size given by net_buffer_length but are dynamically \r\n# enlarged up to max_allowed_packet bytes as needed. \r\nnet_buffer_length = 1K\r\n\r\n# The stack size for each thread\r\nthread_stack = 128K\r\n\r\n# Do not cache results that are larger than this number of bytes\r\nquery_cache_limit = 16K\r\n\r\n# Don\u2019t listen on a TCP\/IP port at all\r\nskip-networking\r\n\r\n# The common part of the directory path for all InnoDB data files\r\ninnodb_data_home_dir = \/var\/lib\/mysql\/\r\n\r\n# The paths to individual InnoDB data files and their sizes\r\ninnodb_data_file_path = ibdata1:10M:autoextend\r\n\r\n# Stores data and indexes for each newly created table in a separate .ibd file,\r\n# rather than in the system tablespace\r\n#innodb_file_per_table = on\r\n\r\n# The directory path to the InnoDB redo log files\r\ninnodb_log_group_home_dir = \/var\/lib\/mysql\/\r\n\r\n# The size in bytes of the buffer pool, the memory area where InnoDB \r\n# caches table and index data\r\ninnodb_buffer_pool_size = 5M\r\n\r\n# The size in bytes of a memory pool InnoDB uses to store data dictionary \r\n# information and other internal data structures\r\ninnodb_additional_mem_pool_size = 2M\r\n\r\n# The size in bytes of each log file in a log group\r\ninnodb_log_file_size = 1M\r\n\r\n# The size in bytes of the buffer that InnoDB uses to write to the log files \r\n# on disk\r\ninnodb_log_buffer_size = 256K\r\n\r\n# The length of time in seconds an InnoDB transaction waits for a row lock \r\n# before giving up\r\ninnodb_lock_wait_timeout = 50\r\n\r\n# Use InnoDB memory allocator instead of system's malloc\/free\r\ninnodb_use_sys_malloc = 0\r\n\r\ntable_cache = 4\r\n\r\n### MyISAM only???\r\n\r\n# Index blocks for MyISAM tables are buffered and are shared by all threads\r\nkey_buffer_size = 16K\r\nread_buffer_size = 256K\r\n\r\n[mysqldump]\r\nquick\r\nmax_allowed_packet = 4M\r\n\r\n[mysql]\r\nno-auto-rehash\r\n# Remove the next comment character if you are not familiar with SQL\r\n#safe-updates\r\n\r\n[isamchk]\r\nkey_buffer = 1M\r\nsort_buffer_size = 1M\r\n\r\n[myisamchk]\r\nkey_buffer = 1M\r\nsort_buffer_size = 1M\r\n\r\n[mysqlhotcopy]\r\ninteractive-timeout\r\n<\/pre>\n<p>Some of the parameters have hard-coded minimums and MySQL will refuse to start if you set a smaller number or simply ignore it and start with it&#8217;s default.<\/p>\n<p>Notice that some of these options reduced significantly its functionality. For example, I was not interested in a TCP\/IP server, everything runs inside the embedded device, so I set the <em>skip-networking<\/em> option.<\/p>\n<p>Play around with the different options to fit your needs.<\/p>\n<p>With this configuration I was able to run MySQL and to have several clients connected writing and reading simultaneously without any memory issues. Even the processor behave nicely when there were only few simultaneous writes and reads.<\/p>\n<p>Have fun!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In many small embedded systems it doesn&#8217;t make much sense to have a powerful Relational Data Base Management System (RDBMS) such as MySQL because there is only one application that access the database or one that writes and one\/many that reads. In these cases, the best option is SQLite that is may be the widest\u2026 <span class=\"read-more\"><a href=\"https:\/\/paguilar.org\/?p=396\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,44],"tags":[],"class_list":["post-396","post","type-post","status-publish","format-standard","hentry","category-compiling","category-databases"],"_links":{"self":[{"href":"https:\/\/paguilar.org\/index.php?rest_route=\/wp\/v2\/posts\/396","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/paguilar.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/paguilar.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/paguilar.org\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/paguilar.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=396"}],"version-history":[{"count":17,"href":"https:\/\/paguilar.org\/index.php?rest_route=\/wp\/v2\/posts\/396\/revisions"}],"predecessor-version":[{"id":416,"href":"https:\/\/paguilar.org\/index.php?rest_route=\/wp\/v2\/posts\/396\/revisions\/416"}],"wp:attachment":[{"href":"https:\/\/paguilar.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=396"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/paguilar.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=396"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/paguilar.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=396"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}