<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8118313070057098741</id><updated>2011-11-28T01:18:38.628Z</updated><category term='apache'/><category term='linux'/><category term='lvs'/><category term='clustering'/><category term='mysql'/><category term='sql'/><category term='php'/><category term='Javascript'/><category term='sockets'/><category term='uml'/><category term='lamp'/><category term='replication'/><category term='mongodb php'/><category term='ExtJS'/><title type='text'>Andrew Rose</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://blog.andrewrose.co.uk/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://blog.andrewrose.co.uk/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Andrew Rose</name><uri>http://www.blogger.com/profile/05883626584607606086</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>18</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8118313070057098741.post-1609126246212734660</id><published>2011-09-20T15:29:00.004+01:00</published><updated>2011-09-20T15:41:31.729+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mongodb php'/><title type='text'>MongoDb numeric field selection in PHP</title><content type='html'>If you are attempting to use numeric field selection with&amp;nbsp;MongoCollection::find() and run into the error:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;PHP Fatal error: &amp;nbsp;Uncaught exception 'MongoException' with message 'field names must be strings'&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;It is caused by PHP converting an array key that is defined as a string into an integer, so:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;array('123' =&amp;gt; 0);&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;becomes:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;array(123 =&amp;gt; 0);&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Unfortunately&amp;nbsp;mongo requires strings for all field names. &amp;nbsp;A quick workaround (found after browsing code, not yet documented) to the problem is to use an object instead of an array:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;$fields = new stdClass;&lt;/i&gt;&lt;br /&gt;&lt;i&gt;$fields-&amp;gt;{123} = 0;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Problem solved.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;
--&lt;br /&gt;
Copyright 2006-2008 Andrew Rose [rose.andrew@gmail.com] [&lt;a href="http://andrewrose.co.uk"&gt;andrewrose.co.uk&lt;/a&gt;]&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8118313070057098741-1609126246212734660?l=blog.andrewrose.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.andrewrose.co.uk/feeds/1609126246212734660/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8118313070057098741&amp;postID=1609126246212734660&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/1609126246212734660'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/1609126246212734660'/><link rel='alternate' type='text/html' href='http://blog.andrewrose.co.uk/2011/09/mongodb-numeric-field-selection-in-php.html' title='MongoDb numeric field selection in PHP'/><author><name>Andrew Rose</name><uri>http://www.blogger.com/profile/05883626584607606086</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8118313070057098741.post-7739009708777349308</id><published>2010-05-26T13:54:00.009+01:00</published><updated>2010-05-27T09:18:01.439+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='ExtJS'/><title type='text'>ExtJS - loading grid record into form with loadRecord() but getting the displayField instead of valueField submitted.</title><content type='html'>&lt;div&gt;&lt;br /&gt;&lt;/div&gt;A long title I know, but today was one of those days that every programmer dreads.. a day with a small problem that takes more than 5minutes to figure out.  This one took me a whole day! Reasons; partly because of a lack of documentation, partly me giving ExtJS to much magic credit and mostly me over-thinking the problem.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The only thing I could find online that really covered it, but not in a way that was at all obvious to me is here: &lt;a href="http://www.extjs.com/forum/showthread.php?88614-Combo-Box-question&amp;amp;highlight=loadrecord+combo"&gt;http://www.extjs.com/forum/showthread.php?88614-Combo-Box-question&amp;amp;highlight=loadrecord+combo&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.extjs.com/forum/showthread.php?88614-Combo-Box-question&amp;amp;highlight=loadrecord+combo"&gt;&lt;/a&gt;&lt;br /&gt;If you have a grid and you load that grid with combo displayField values (from the store) and use loadRecord() to populate the form you will notice that it seems to work on the outside.  However when you hit submit the displayField and not the valueField are submitted!  I would have assumed ExtJS would have some magic that compares the displayField value with the valueField and updates it accordingly. Wrong, the valueField is set to whatever you set it to and ExtJS will do nothing to change that.&lt;br /&gt;&lt;br /&gt;What you need to do is, add the valueField values to the grid as well as the displayField values but not including them in the column model.  This way the grid is not cluttered with combo valueField values.  But how do you then get that valueField to the form combos?  You need to set the hiddenName value in the combos to point to the valueField in the grid and the name to the relevant displayField.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm going to stop myself as I think a simple clean code example will speak louder than my confusing ramblings, so here you go:&lt;br /&gt;&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 13px; white-space: pre;"&gt;&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 16px; white-space: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;pre&gt;var form = new Ext.form.FormPanel({&lt;br /&gt; title : 'Test form',&lt;br /&gt; width : 300,&lt;br /&gt; items : [{&lt;br /&gt;  xtype : 'combo',&lt;br /&gt;  fieldLabel : 'Gender',&lt;br /&gt;  name : 'gender_',&lt;br /&gt;  hiddenName : 'gender',&lt;br /&gt;  store : new Ext.data.ArrayStore({&lt;br /&gt;   fields : ['valueField', 'displayField'],&lt;br /&gt;   data : [[1, 'Male'] , [2, 'Female']]&lt;br /&gt;  }),&lt;br /&gt;  mode : 'local',&lt;br /&gt;  valueField : 'valueField',&lt;br /&gt;  displayField : 'displayField'&lt;br /&gt; }]&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;var toolbar = new Ext.Toolbar({&lt;br /&gt; items : ['-&gt;']&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;toolbar.addButton({&lt;br /&gt; text : 'Clear',&lt;br /&gt; handler: function(b, e)&lt;br /&gt; {&lt;br /&gt;  form.getForm().reset();&lt;br /&gt; }&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;toolbar.addButton({&lt;br /&gt; text : 'Save',&lt;br /&gt; handler: function(b, e)&lt;br /&gt; {&lt;br /&gt;  var values = form.getForm().getFieldValues();&lt;br /&gt;  for(var field in form.getForm().getValues())&lt;br /&gt;  {&lt;br /&gt;   alert(field+':'+values[field]);&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;form.add(toolbar);&lt;br /&gt;&lt;br /&gt;var grid = new Ext.grid.GridPanel({&lt;br /&gt; title : 'test grid',&lt;br /&gt; width: 600,&lt;br /&gt; height: 300,&lt;br /&gt; columns : [&lt;br /&gt;  {id: 'id', header : 'id', dataIndex : 'id'},&lt;br /&gt;  {header : 'Gender', dataIndex : 'gender_'}&lt;br /&gt; ],&lt;br /&gt; store : new Ext.data.ArrayStore({&lt;br /&gt;  fields : [ 'id', 'gender_', 'gender' ],&lt;br /&gt;  data : [&lt;br /&gt;   [ 34, 'Male', 1],&lt;br /&gt;   [ 35, 'Female', 2]&lt;br /&gt;  ]&lt;br /&gt; }),&lt;br /&gt; sm: new Ext.grid.RowSelectionModel({&lt;br /&gt;  singleSelect: true,&lt;br /&gt;  listeners: {&lt;br /&gt;   rowselect: function(sm, row, rec) {&lt;br /&gt;    form.getForm().loadRecord(rec);&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt; })&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;var win = new Ext.Window({&lt;br /&gt; title : 'test',&lt;br /&gt; items : [{&lt;br /&gt;  xtype : 'panel',&lt;br /&gt;  layout : 'column',&lt;br /&gt;  items : [form, grid]&lt;br /&gt; }]&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;win.show();&lt;br /&gt;&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 16px; white-space: normal;"&gt;&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 13px; white-space: pre;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;Notice the '_' added to the name value of the combo.&lt;div&gt;&lt;br /&gt;&lt;div&gt;I hope that by documenting/explaining my problem it will help others avoid a wasted day as I have.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You may have noticed it has been over 2years since my last post.. well, starting your own business will do that to a blogger :D&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;
--&lt;br /&gt;
Copyright 2006-2008 Andrew Rose [rose.andrew@gmail.com] [&lt;a href="http://andrewrose.co.uk"&gt;andrewrose.co.uk&lt;/a&gt;]&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8118313070057098741-7739009708777349308?l=blog.andrewrose.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.andrewrose.co.uk/feeds/7739009708777349308/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8118313070057098741&amp;postID=7739009708777349308&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/7739009708777349308'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/7739009708777349308'/><link rel='alternate' type='text/html' href='http://blog.andrewrose.co.uk/2010/05/extjs-loading-grid-record-into-form.html' title='ExtJS - loading grid record into form with loadRecord() but getting the displayField instead of valueField submitted.'/><author><name>Andrew Rose</name><uri>http://www.blogger.com/profile/05883626584607606086</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8118313070057098741.post-4446736970905215014</id><published>2008-04-11T12:17:00.001+01:00</published><updated>2008-04-11T12:19:47.363+01:00</updated><title type='text'>Sponsor me! - Manchester 10k</title><content type='html'>I wouldn't normally post OT on my blog but this is for a good cause.&lt;br /&gt;&lt;br /&gt;I'm running the &lt;a href="http://gmr.realbuzz.com/"&gt;Manchester 10k&lt;/a&gt; on the 18th of May and am trying to raise £200 for the Rainbow Family Trust (Francis House) who support and improve the quality of life for terminally ill children diagnosed with 'no cure'.&lt;br /&gt;&lt;br /&gt;So dig deep and help me reach my target by going to this site and making a donation: &lt;a href="http://www.justgiving.com/roseandrew" target="_blank" rel="nofollow"&gt;&lt;span&gt;http://www.justgiving.com/&lt;/span&gt;&lt;wbr&gt;&lt;span class="word_break"&gt;&lt;/span&gt;roseandrew&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Many thanks!&lt;br /&gt;Andrew&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;
--&lt;br /&gt;
Copyright 2006-2008 Andrew Rose [rose.andrew@gmail.com] [&lt;a href="http://andrewrose.co.uk"&gt;andrewrose.co.uk&lt;/a&gt;]&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8118313070057098741-4446736970905215014?l=blog.andrewrose.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.andrewrose.co.uk/feeds/4446736970905215014/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8118313070057098741&amp;postID=4446736970905215014&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/4446736970905215014'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/4446736970905215014'/><link rel='alternate' type='text/html' href='http://blog.andrewrose.co.uk/2008/04/sponsor-me-manchester-10k.html' title='Sponsor me! - Manchester 10k'/><author><name>Andrew Rose</name><uri>http://www.blogger.com/profile/05883626584607606086</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8118313070057098741.post-3716576100883006522</id><published>2008-02-05T09:02:00.001Z</published><updated>2009-05-11T13:53:14.521+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='uml'/><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='replication'/><category scheme='http://www.blogger.com/atom/ns#' term='clustering'/><category scheme='http://www.blogger.com/atom/ns#' term='apache'/><category scheme='http://www.blogger.com/atom/ns#' term='lvs'/><title type='text'>Roll your own N-server sandbox</title><content type='html'>Have you ever wanted to play around with(test ;) MySQL replication/clustering techniques, LVS/Apache load balancing etc but didn't have the hardware available and where smart enough not to use a production environment?&lt;br /&gt;&lt;br /&gt;Well an easy way to be able to do this is by creating a sandbox environment using something like  &lt;a href="http://fabrice.bellard.free.fr/qemu/"&gt;qemu&lt;/a&gt;, &lt;a href="http://www.xen.org/"&gt;xen&lt;/a&gt;, &lt;a href="http://www.vmware.com/"&gt;vmware&lt;/a&gt; or &lt;a href="http://user-mode-linux.sourceforge.net/"&gt;UML&lt;/a&gt; which allow you to create virtual machines running inside a protected environment on your own desktop machine or whatever hardware you have spare, just be sure you have enough memory.   This article will cover setting up a sandbox using UML.&lt;br /&gt;&lt;br /&gt;My GNU distro of choice is Archlinux and this article will be based around it, but you should be able to take the information provided here and apply it relatively easily to which ever distro you use.   Please also note that I am not going to go into depth about UML as there are plenty of resources just a search away.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Preparing the host.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So first things first we need to have a system capable of running UML, and luckily Archlinux is ready, all we need to do is install a few packages:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[root@ishell ~]# pacman -S user-mode-linux uml_utilities&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Then setup our play area.  In this example I am setting up a 4 server playground in roots home directory.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[root@ishell ~]# mkdir servers&lt;br /&gt;[root@ishell ~]# cd servers&lt;br /&gt;[root@ishell servers]# mkdir 1 2 3 4&lt;br /&gt;[root@ishell servers]# ls&lt;br /&gt;1  2  3  4&lt;br /&gt;[root@ishell servers]#&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Setup the host (the host is the machine "hosting" the UML instances) for networking the UMLs.  There are all kinds of ways to do this but I use the uml_switch which is a virtual network switch that is a breeze to use.  To allow the UMLs to communicate to and from the host and the outside world we need to create a tunnel and setup IP forwarding (We will start the actual uml_switch at the end in a startup script):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[root@ishell ~]# modprobe tun&lt;br /&gt;[root@ishell ~]# tunctl -u root -t tap0&lt;br /&gt;[root@ishell ~]# ifconfig tap0 192.168.0.100 up&lt;br /&gt;[root@ishell ~]# iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE&lt;br /&gt;[root@ishell ~]# echo 1 &gt; /proc/sys/net/ipv4/ip_forward&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Setup of the UML filesystem&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The UML instances require a file to hold their filesystem and a base GNU install.  So we create one with dd.  As ever salt to your tastes:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[root@ishell servers]# dd if=/dev/zero of=root.fs bs=1MB count=1000&lt;br /&gt;[root@ishell servers]# mkfs.ext3 root.fs&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now we have formatted image we can loopback mount it ready for setting up the base install.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[root@ishell servers]# mount -o loop root.fs /mnt/cd/&lt;br /&gt;[root@ishell servers]# mkdir -p /mnt/cd/var/lib/pacman&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To install the base packages with Archlinux I wget the packages.txt from the main package download area which has a list of all base packages prefixed with base/. To install the base packages to the disk image which we have mounted to /mnt/cd we need to first initialize pacman with the -Sy --dbpath options then instruct pacman to install packages to our /mnt/cd root with the --dbpath and --root options.  In this case I am also including apache, php, mysql and openssh.&lt;br /&gt;&lt;div style="overflow: auto; overflow-y: auto;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[root@ishell servers]# wget ftp://ftp.archlinux.org/current/os/x86_64/packages.txt&lt;br /&gt;[root@ishell servers]# pacman -Sy --dbpath /mnt/cd/var/lib/pacman&lt;br /&gt;[root@ishell servers]# pacman -S --dbpath /mnt/cd/var/lib/pacman --root /mnt/cd/ \&lt;br /&gt;`cat packages.txt | egrep '^base/' | sed 's|^.*/||;s/-[0-9]\+.*//' | grep -v kernel` \&lt;br /&gt;apache mysql php openssh&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Once we have the base install we need to modify some files. These changes apply to all servers we use this image for so it will save us some time if we make the changes now before making copies of the image.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;add "/dev/ubd0 / ext3 defaults 0 0" to etc/fstab&lt;/li&gt;&lt;li&gt;edit /etc/hosts.deny and comment out ALL:ALL so we can gain ssh access&lt;/li&gt;&lt;li&gt;edit /etc/innittab and comment out all but the first virtual console&lt;/li&gt;&lt;li&gt;add sshd to daemons in rc.conf&lt;/li&gt;&lt;li&gt;change default gateway to 192.168.0.100 (or what you set the tunnel IP to)&lt;/li&gt;&lt;li&gt;chroot to /mnt/cd and change the root password other wise you will not be able to gain ssh access.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Now umount the image and copy to all servers:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[root@ishell servers]# umount /mnt/cd&lt;br /&gt;[root@ishell servers]# cp root.fs 1/ &amp;amp;&lt;br /&gt;[root@ishell servers]# cp root.fs 2/ &amp;amp;&lt;br /&gt;[root@ishell servers]# cp root.fs 3/ &amp;amp;&lt;br /&gt;[root@ishell servers]# cp root.fs 4/ &amp;amp;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Mount each root image in turn and make configuration changes to the eth0 ip address and hostname in rc.conf, these have to be unique for each server and are the IPs you will use to access the servers via ssh:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[root@ishell servers]# mount -o loop 1/root.fs /mnt/cd/&lt;br /&gt;[root@ishell servers]# nano /mnt/cd/etc/rc.conf&lt;br /&gt;[root@ishell servers]# umount /mnt/cd&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;And the finishing touch&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Create a startup script (i.e. run.sh) and modify the mem parameter to suit your needs.  ubd0 specifies the file that contains the filesystem the UML will use and con=null tell the UML not to spawn any consoles or direct any output from the kernel to the console as we will be using ssh as the main form of access, however you can change this if you wish.&lt;br /&gt;&lt;br /&gt;The uml_switch is also started here and is passed the name of the tunnel device we setup earlier and told to fork off into a daemon.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/bin/bash&lt;br /&gt;exec uml_switch -tap tap0 -daemon &amp;amp;&lt;br /&gt;exec linux ubd0=1/root.fs con=null eth0=daemon mem=128M &amp;amp;&lt;br /&gt;exec linux ubd0=2/root.fs con=null eth0=daemon mem=128M &amp;amp;&lt;br /&gt;exec linux ubd0=3/root.fs con=null eth0=daemon mem=128M &amp;amp;&lt;br /&gt;exec linux ubd0=4/root.fs con=null eth0=daemon mem=128M &amp;amp;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Final thoughts&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;After running the above script you should have 4 servers ready to go within a few minutes.  Simply ssh to them as you would any other server and have fun!&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;
--&lt;br /&gt;
Copyright 2006-2008 Andrew Rose [rose.andrew@gmail.com] [&lt;a href="http://andrewrose.co.uk"&gt;andrewrose.co.uk&lt;/a&gt;]&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8118313070057098741-3716576100883006522?l=blog.andrewrose.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.andrewrose.co.uk/feeds/3716576100883006522/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8118313070057098741&amp;postID=3716576100883006522&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/3716576100883006522'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/3716576100883006522'/><link rel='alternate' type='text/html' href='http://blog.andrewrose.co.uk/2008/02/roll-your-own-n-server-sandbox.html' title='Roll your own N-server sandbox'/><author><name>Andrew Rose</name><uri>http://www.blogger.com/profile/05883626584607606086</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8118313070057098741.post-6322520395706090288</id><published>2008-02-01T08:39:00.001Z</published><updated>2009-04-28T13:32:09.809+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sockets'/><category scheme='http://www.blogger.com/atom/ns#' term='php'/><title type='text'>PHP: Getting signals through to blocking socket_accept</title><content type='html'>Have you ever written a sockets server in PHP and wanted to use the blocking option but found you where unable to kill the process off cleanly and instead had to resort to &lt;span style="font-style: italic;"&gt;kill -9&lt;/span&gt; or even worse set blocking to false and set a delay in the main event loop?&lt;br /&gt;&lt;br /&gt;Well there is a way to use blocking and be able to shutdown the process cleanly.  &lt;span style="font-style: italic;"&gt;socket_accept()&lt;/span&gt; blocking may ignore general signals, but it does not ignore pcntl alarms.  An alarm fired every second or so will break you out of a blocking call to &lt;span style="font-style: italic;"&gt;socket_accept()&lt;/span&gt; (with a warning) and allow your normal flow of logic to detect a shutdown signal i.e. sigterm.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Example code&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="overflow: auto; overflow-y: auto;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;?php&lt;br /&gt;declare(ticks = 1);&lt;br /&gt;&lt;br /&gt;class test&lt;br /&gt;{&lt;br /&gt;  private $shutdown = FALSE;&lt;br /&gt;&lt;br /&gt;  function sigTerm()&lt;br /&gt;  {&lt;br /&gt;          $this-&gt;shutdown = TRUE;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  function sigAlarm()&lt;br /&gt;  {&lt;br /&gt;          pcntl_alarm(1);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public function doit()&lt;br /&gt;  {&lt;br /&gt;          $socket = socket_create(AF_INET, SOCK_STREAM, 0);&lt;br /&gt;          socket_bind($socket,'127.0.0.1', 5555);&lt;br /&gt;          socket_listen($socket);&lt;br /&gt;&lt;br /&gt;          socket_set_block($socket);&lt;br /&gt;&lt;br /&gt;          pcntl_signal(SIGTERM, array(&amp;amp;$this, "sigTerm"));&lt;br /&gt;          pcntl_signal(SIGALRM, array(&amp;amp;$this, "sigAlarm"));&lt;br /&gt;          pcntl_alarm(1);&lt;br /&gt;&lt;br /&gt;          while(1)&lt;br /&gt;          {&lt;br /&gt;                  if($c = @socket_accept($socket))&lt;br /&gt;                  {&lt;br /&gt;                          echo "Got a connection\n";&lt;br /&gt;                          socket_close($c);&lt;br /&gt;                  }&lt;br /&gt;                  else&lt;br /&gt;                  {&lt;br /&gt;                          echo "Alarm has broken us out of socket_accept blocking, ";&lt;br /&gt;&lt;br /&gt;                          if($this-&gt;shutdown)&lt;br /&gt;                          {&lt;br /&gt;                                  echo "and it is time to shutdown now Dave.\n";&lt;br /&gt;                                  return;&lt;br /&gt;                          }&lt;br /&gt;&lt;br /&gt;                          echo "but it is not time to shutdown yet Dave.\n";&lt;br /&gt;                  }&lt;br /&gt;          }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;$test = new test;&lt;br /&gt;$test-&gt;doit();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;And Finally&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To test the code simply &lt;span style="font-style: italic;"&gt;telnet 127.0.0.1 5555&lt;/span&gt; to see it handling connections.  Then when you're done a simple &lt;span style="font-style: italic;"&gt;killall php&lt;/span&gt; should do the trick (just be sure you don't kill any other php process).&lt;br /&gt;&lt;br /&gt;I should point out that &lt;span style="font-style: italic;"&gt;socket_stream_accept()&lt;/span&gt; will respond to signals without the need for an alarm.  So if you can, it may be worth going with the stream functions over the cardinal socket functions.  (Edit: 04/02/2008) However the stream function response to signals seems a little erratic so I would use an alarm anyway.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;UPDATE - 5th March 2008&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I was stung by a nasty little oversight that you should know.  When reading from a socket, any interrupt (read: alarm) will cause the read to abort.  To solve this, after successfully establishing a connection with socket_accept() be sure to run pcntl_alarm(0) then socket_read() and then pcntl_alarm(1) again.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;
--&lt;br /&gt;
Copyright 2006-2008 Andrew Rose [rose.andrew@gmail.com] [&lt;a href="http://andrewrose.co.uk"&gt;andrewrose.co.uk&lt;/a&gt;]&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8118313070057098741-6322520395706090288?l=blog.andrewrose.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.andrewrose.co.uk/feeds/6322520395706090288/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8118313070057098741&amp;postID=6322520395706090288&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/6322520395706090288'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/6322520395706090288'/><link rel='alternate' type='text/html' href='http://blog.andrewrose.co.uk/2008/02/php-getting-signals-through-to-blocking.html' title='PHP: Getting signals through to blocking socket_accept'/><author><name>Andrew Rose</name><uri>http://www.blogger.com/profile/05883626584607606086</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8118313070057098741.post-8705679051604692972</id><published>2008-01-30T07:52:00.001Z</published><updated>2010-08-06T10:29:08.759+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lamp'/><title type='text'>LAMP: The mailing lists you *SHOULD* be subscribed to.</title><content type='html'>The LAMP stack consists of some complicated software, and this software from time to time will develop faults and security flaws.  How do you keep yourself informed?  Hope that the issues crop up on Digg, Slashdot?  Well the best way is to join the Announce lists for each of the LAMP stack components.&lt;br /&gt;&lt;br /&gt;The Announce lists are used by the developers of the different components of the LAMP stack to keep users informed of important events, like when a security flaw emerges or a new version of there software is released, etc.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;The lists&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The first one is dependent on the GNU/Linux distribution your running, in my case it is Archlinux, so I've subscribed to:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://archlinux.org/mailman/listinfo/arch-announce"&gt;http://archlinux.org/mailman/listinfo/arch-announce&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Next in the LAMP stack is Apache, and you can find its Announce list here:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://httpd.apache.org/lists.html"&gt;http://httpd.apache.org/lists.html&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;For MySQL:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://lists.mysql.com/"&gt;http://lists.mysql.com/&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;And PHP:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.php.net/mailing-lists.php"&gt;http://www.php.net/mailing-lists.php&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;And lastly, considering that SSH is the primary form of entry to my systems (and most likely yours) I am subscribed to the OpenSSL and OpenSSH mailing lists:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.openssl.org/support/"&gt;http://www.openssl.org/support/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://lists.mindrot.org/mailman/listinfo/openssh-unix-announce"&gt;https://lists.mindrot.org/mailman/listinfo/openssh-unix-announce&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Final points&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now, subscribing to these lists in no way secures you from attack, but it should give you a fighting chance.  When bugs / security issues do crop up you will need to take the necessary action, which should be as simple as upgrading the relevant software.  But be prepared to build replacement packages from source if your GNU/Linux distribution is slow to release an updated package.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;
--&lt;br /&gt;
Copyright 2006-2008 Andrew Rose [rose.andrew@gmail.com] [&lt;a href="http://andrewrose.co.uk"&gt;andrewrose.co.uk&lt;/a&gt;]&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8118313070057098741-8705679051604692972?l=blog.andrewrose.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.andrewrose.co.uk/feeds/8705679051604692972/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8118313070057098741&amp;postID=8705679051604692972&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/8705679051604692972'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/8705679051604692972'/><link rel='alternate' type='text/html' href='http://blog.andrewrose.co.uk/2008/01/lamp-mailing-lists-you-should-be.html' title='LAMP: The mailing lists you *SHOULD* be subscribed to.'/><author><name>Andrew Rose</name><uri>http://www.blogger.com/profile/05883626584607606086</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8118313070057098741.post-3866293579633352880</id><published>2008-01-08T12:36:00.003Z</published><updated>2010-08-06T10:29:21.790+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='replication'/><title type='text'>MySQL (5.0): Recovering failed circular replication</title><content type='html'>There is a lot of information out there about how to setup circular replication but nothing about how to recover it when all else fails. This article will cover a quick and easy method I use. Depending on the size of your database and the interconnects between servers this method may not be suitable due to the need to copy all replicated databases from one good server to all other servers in the replication circle which requires a certain amount of down time respectively.&lt;br /&gt;&lt;br /&gt;OK, so one server or more is showing &lt;code&gt;Slave_IO_Running&lt;/code&gt; and/or &lt;code&gt;Slave_SQL_Running&lt;/code&gt; as &lt;code&gt;No&lt;/code&gt; and there is some error about a failed query when you run "&lt;code&gt;show slave status;&lt;/code&gt;" and no amount of effort to fix it is working. First DO NOT PANIC. It is broken, OK, tell yourself that and realise that trying to fix something when you are in a panicked state is only liable to make the situation worse, hell I'd guarantee it, so relax.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;strong&gt;The checklist&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Below is our checklist of things to do, with more detailed information about each step afterward.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Make sure ALL connections to MySQL are closed&lt;/li&gt;&lt;li&gt;Back everything up (/var/lib/mysql)&lt;/li&gt;&lt;li&gt;Pick the most up-to-date database&lt;/li&gt;&lt;li&gt;Run &lt;code&gt;stop slave;&lt;/code&gt; on all servers&lt;/li&gt;&lt;li&gt;Run &lt;code&gt;reset master;&lt;/code&gt; and &lt;code&gt;reset slave;&lt;/code&gt; on all servers&lt;/li&gt;&lt;li&gt;Shutdown all servers (&lt;code&gt;e.g. /etc/rc.d/mysqld stop&lt;/code&gt;)&lt;/li&gt;&lt;li&gt;Copy database decided on from step 3; files/ibdata etc to other servers&lt;/li&gt;&lt;li&gt;Start servers (e.g. &lt;code&gt;/etc/rc.d/mysqld start&lt;/code&gt;)&lt;/li&gt;&lt;li&gt;Run &lt;code&gt;start slave;&lt;/code&gt; on all servers&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;Step 1&lt;/span&gt; - Make sure ALL connections to MySQL are closed&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;If you have anything still connected to MySQL when your fixing replication your going to find your worse off than where you started. In an ideal world you would know EXACTLY what is connected to your MySQL server. But if in doubt, or even better if you like to second check then fire up the MySQL client on all servers and run &lt;code&gt;show full processlist;&lt;/code&gt; all you want to see there is rows with &lt;code&gt;system user&lt;/code&gt; and one for your connected client which should show &lt;code&gt;show full processlist&lt;/code&gt; in the Info column. If there is anything else, get rid before proceeding to Step 2.&lt;br /&gt;&lt;br /&gt;Don't forget things like Apache running PHP scripts and PHP scripts under cron control for example which may be waiting to start a new connection without your knowledge.&lt;br /&gt;&lt;br /&gt;An easy way to be sure nothing has modified your database is to run &lt;code&gt;show master status;&lt;/code&gt; and note down the values of the &lt;code&gt;File&lt;/code&gt; and &lt;code&gt;Position&lt;/code&gt; columns.  As you progress though the recovery check these values now and then to be sure they have not changed.  The only time they should change is after step 8.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;Step 2&lt;/span&gt; - Back everything up (/var/lib/mysql)&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;This should be obvious, but as a reminder I've put it in. Before I fix anything in the way that is laid out in this article I make a copy of the MySQL data directory by simply doing (You may want to stop the MySQL server before doing this.):&lt;br /&gt;&lt;br /&gt;&lt;code&gt;cp -a /var/lib/mysql /var/lib/mysql-[yyyymmdd]&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;This will allow me to move the old directory back into play (after the whole procedure obviously) by:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Stopping the MySQL server&lt;/li&gt;&lt;li&gt;&lt;code&gt;mv /var/lib/mysql /var/lib/mysql-tmp&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;mv /var/lib/mysql-[yyyymmdd] /var/lib/mysql&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Starting MySQL server&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;You may need to do this to check data in the old version of the database.  I would NOT &lt;code&gt;start slave;&lt;/code&gt; if you do this it will most likely break replication in the other servers and you won't be able to switch back to the new database and your have to start all over again :(&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;Step 3&lt;/span&gt; - Pick the most up-to-date database&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;When replication fails beyond repair you need to select a server who's database to use. This is completely your call. However if it is one server that has hiccuped use its masters database as every node after the failed server would have it's events replicated all the way around to its master.&lt;br /&gt;&lt;br /&gt;At this point it may be a good idea to get a list of the databases that you are replicating. I use a quick call to &lt;code&gt;show master status;&lt;/code&gt; to get a list of databases in usable format. I.e. &lt;code&gt;db0,db1,db2&lt;/code&gt; in the &lt;code&gt;Binlog_Do_Db&lt;/code&gt; column. We will use this in step 7.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;Step 4&lt;/span&gt; - Run stop slave; on all servers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;This step is pretty self explanatory. We stop the slave process from running in preparation for the next step. We "should" get away without stopping the slave process I'll admit, but it's better to be safe than sorry.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;Step 5&lt;/span&gt; - Run reset master; and reset slave; on all servers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;This step purges bin logs and resets bin log position counters (relay-log.info and master.info) for the master and slave. This way when we copy our best database to all other servers they will all be at a common starting point.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;Step 6&lt;/span&gt; - Shutdown all servers (e.g. /etc/rc.d/mysqld stop)&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Pretty simply stop all servers. We do this because the next step involves copying from one server to all other servers, so we don't want MySQL modifying anything mid copy.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;Step 7&lt;/span&gt; - Copy database decided on from step 3; files/ibdata etc to other servers &lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Now we need to copy the database you chose in step 3 to all other servers.&lt;br /&gt;&lt;br /&gt;I use scp for this like so (salt to your taste):&lt;br /&gt;&lt;br /&gt;&lt;code&gt;scp -r /var/lib/mysql/{db0,db1,db2} /var/lib/mysql/ib* server1:/var/lib/mysql &amp;amp;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Note, if you do not replicate any InnoDB tables remove the &lt;code&gt;/var/lib/mysql/ib*&lt;/code&gt; bit. I also background the process just in case I lose my ssh connection (i.e. to the dreaded felis silvestris catus bug), it also means you can run &lt;code&gt;scp&lt;/code&gt; for each server from the same console. To check up on the scp processes I simply use &lt;code&gt;watch "ps aux | grep scp"&lt;/code&gt;. When all processes are gone from the list your good to go to step 8.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;Step 8&lt;/span&gt; - Start servers (e.g. /etc/rc.d/mysqld start)&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Start the servers. This can be done in any order you feel like doing it in.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;Step 9&lt;/span&gt; - Run &lt;code&gt;start slave;&lt;/code&gt; on all servers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;You may have MySQL setup to start the slave automatically, if not however now is the time to start the slave processes on all servers. Give the servers time to get going as they have by default 60 second timeouts so may not connect to there master straight away, especially if you haven't actually started it before hand. If your impatient however simple run &lt;code&gt;stop slave;&lt;/code&gt; and &lt;code&gt;start slave;&lt;/code&gt; on each server going from master to slave around the circle.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;Final thoughts&lt;/span&gt; &lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;OK so that may have seemed a bit long winded, but I'll guarantee that after doing it once successfully your see it for the relatively simple process it is. Off course it doesn't help when your expected to keep 100% up time.&lt;br /&gt;&lt;br /&gt;I never explained how to restore around a failed node which is a common problem. I thought it would simply confuse things to much even though it is a pretty simple thing to slot in around step 6. I will follow up with another blog entry to cover it another day. If you want it sooner feel free to poke me via email.&lt;br /&gt;&lt;br /&gt;Well I hope all that helps someone, especially the lads in my team which should now have no excuse for dodging the night watch ;)&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;
--&lt;br /&gt;
Copyright 2006-2008 Andrew Rose [rose.andrew@gmail.com] [&lt;a href="http://andrewrose.co.uk"&gt;andrewrose.co.uk&lt;/a&gt;]&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8118313070057098741-3866293579633352880?l=blog.andrewrose.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.andrewrose.co.uk/feeds/3866293579633352880/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8118313070057098741&amp;postID=3866293579633352880&amp;isPopup=true' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/3866293579633352880'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/3866293579633352880'/><link rel='alternate' type='text/html' href='http://blog.andrewrose.co.uk/2008/01/mysql-recovering-failed-circular.html' title='MySQL (5.0): Recovering failed circular replication'/><author><name>Andrew Rose</name><uri>http://www.blogger.com/profile/05883626584607606086</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8118313070057098741.post-6197127848200236606</id><published>2007-12-06T10:16:00.000Z</published><updated>2008-02-01T10:38:46.107Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><title type='text'>MySQL: Unlimited updates in one query - ish.</title><content type='html'>One of the major parts of my job is/was developing the interface to our MIS that handles hundreds of connections on a nightly basis from other MIS systems which push data in a CSV format.  These CSV files contain information that then needs to be pushed into our MIS (thousands of inserts and updates, plus some deletes).&lt;br /&gt;&lt;br /&gt;Now, creating the insert statements are a breeze with the "insert into tbl0(...) values(...),(...),..." MySQL syntax.  I can push thousands of inserts in a single query, the only limit being the MySQL packet size, hence the 'ish' in the title.  But what about updates? before now I've resorted to just running the updates as single queries, which lets face it, is slow.  So lets look at how we can speed this up.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;The Meat&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;First create a test table:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;create table test0(sid int, staffid varchar(255), name varchar(255), unique(sid, staffid));&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Insert some data:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;insert into test0(sid, staffid, name) values(1, 'ar', 'Andrew'), (1, 'jm', 'John'), (1, 'sl', 'Seb');&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Now we want to turn:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;update test1 set name = 'Andrew 2' where sid = 1 and staffid = 'ar';&lt;br /&gt;update test1 set name = 'John 2' where sid = 1 and staffid = 'jm';&lt;br /&gt;update test1 set name = 'Seb 2' where sid = 1 and staffid = 'sl';&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Into a single query, and we do this like so:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;insert into test0(sid, staffid, name) values(1, 'ar', 'Andrew 2'),&lt;/code&gt;&lt;code&gt;(1, 'jm', 'John 2'),&lt;/code&gt;&lt;code&gt;(1, 'sl', 'Seb 2') on &lt;/code&gt;&lt;code&gt;duplicate key update test0.name = values(name);&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;`test0` should now have been updated with the new values.  The key to all this is using "on duplicate key update".&lt;br /&gt;&lt;br /&gt;I should point out, for the uninitiated that you need a unique key for this to work. In this case it is (sid, staffid) plus there is no need to update the unique keys.&lt;br /&gt;&lt;br /&gt;Initial tests show a two thirds increase in speed when we are:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Hitting MySQL from a PHP script.&lt;/li&gt;&lt;li&gt;Breaking the updates into 1024k chunks.&lt;/li&gt;&lt;li&gt;Connecting to MySQL on the localhost&lt;/li&gt;&lt;/ol&gt;If you are connecting to MySQL over a network you should see even better speed improvements because of the effects of network latency.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Drawbacks and Unknowns&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;I've not tested this against multiple update queries sent in one go. i.e. "update tbl0 set col1 = 1 where col0 = 0; update tbl0 set col1 = 2 where col0 =1; ...".&lt;/li&gt;&lt;li&gt;Increased memory use from the size of the insert statement. However I took the chunks down to 500k and even 250k and lost no more than 5-10% performance.&lt;/li&gt;&lt;li&gt;If your using PHP watch the memory limit. Also keep your chunks below the max allowed packet size.&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;
--&lt;br /&gt;
Copyright 2006-2008 Andrew Rose [rose.andrew@gmail.com] [&lt;a href="http://andrewrose.co.uk"&gt;andrewrose.co.uk&lt;/a&gt;]&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8118313070057098741-6197127848200236606?l=blog.andrewrose.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.andrewrose.co.uk/feeds/6197127848200236606/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8118313070057098741&amp;postID=6197127848200236606&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/6197127848200236606'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/6197127848200236606'/><link rel='alternate' type='text/html' href='http://blog.andrewrose.co.uk/2007/12/mysql-unlimited-updates-in-only-two.html' title='MySQL: Unlimited updates in one query - ish.'/><author><name>Andrew Rose</name><uri>http://www.blogger.com/profile/05883626584607606086</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8118313070057098741.post-7451816115817427213</id><published>2007-03-30T09:50:00.001+01:00</published><updated>2010-08-06T10:28:11.660+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='replication'/><category scheme='http://www.blogger.com/atom/ns#' term='php'/><title type='text'>PHP: Handling MySQL replication failure gracefully - Part 2</title><content type='html'>The first version of this code failed to work on 5.1 so here is a version that does:&lt;br /&gt;&lt;pre&gt;if(DATABASE_REPLICATION_CHECK)&lt;br /&gt;{&lt;br /&gt;$result = mysql_query("show slave status;");&lt;br /&gt;$row = mysql_fetch_assoc($result);&lt;br /&gt;if( ($row['Slave_IO_Running']!='Yes') || ($row['Slave_SQL_Running']!='Yes') )&lt;br /&gt;{&lt;br /&gt;$fp = fopen('tmp/halt', 'w+');&lt;br /&gt;fclose($fp);&lt;br /&gt;header('Location: index.php');&lt;br /&gt;}&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Remember to add something like:&lt;br /&gt;&lt;pre&gt;if(file_exists('tmp/halt')) exit('Unable to complete request at this time');&lt;/pre&gt;&lt;br /&gt;at the start of your app execution so as to stop users entering data that can cause all kinds of living nightmares when it comes to patching the data together.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;
--&lt;br /&gt;
Copyright 2006-2008 Andrew Rose [rose.andrew@gmail.com] [&lt;a href="http://andrewrose.co.uk"&gt;andrewrose.co.uk&lt;/a&gt;]&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8118313070057098741-7451816115817427213?l=blog.andrewrose.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.andrewrose.co.uk/feeds/7451816115817427213/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8118313070057098741&amp;postID=7451816115817427213&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/7451816115817427213'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/7451816115817427213'/><link rel='alternate' type='text/html' href='http://blog.andrewrose.co.uk/2007/03/handling-mysql-replication-failure.html' title='PHP: Handling MySQL replication failure gracefully - Part 2'/><author><name>Andrew Rose</name><uri>http://www.blogger.com/profile/05883626584607606086</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8118313070057098741.post-7790451519171797119</id><published>2007-03-28T14:08:00.000+01:00</published><updated>2008-02-13T12:15:03.477Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><title type='text'>Pivoting Data in MySQL</title><content type='html'>&lt;a href="http://en.wikibooks.org/wiki/MySQL/Pivot_table"&gt;This is a good read&lt;/a&gt; for anyone who has ever tried to pivot data from a table in MySQL using client side code like PHP when you can with some careful query construction do it in MySQL.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;
--&lt;br /&gt;
Copyright 2006-2008 Andrew Rose [rose.andrew@gmail.com] [&lt;a href="http://andrewrose.co.uk"&gt;andrewrose.co.uk&lt;/a&gt;]&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8118313070057098741-7790451519171797119?l=blog.andrewrose.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.andrewrose.co.uk/feeds/7790451519171797119/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8118313070057098741&amp;postID=7790451519171797119&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/7790451519171797119'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/7790451519171797119'/><link rel='alternate' type='text/html' href='http://blog.andrewrose.co.uk/2007/03/pivoting-data-in-mysql.html' title='Pivoting Data in MySQL'/><author><name>Andrew Rose</name><uri>http://www.blogger.com/profile/05883626584607606086</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8118313070057098741.post-259173561147807662</id><published>2007-03-09T18:28:00.000Z</published><updated>2007-03-09T18:30:27.882Z</updated><title type='text'>All in the "swizzle"</title><content type='html'>Just incase I lose it.. and as some proof I was on the track with it.. this is the foundation of a new tree theory I am working on.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;char *rotKeys(char *key)&lt;br /&gt;{&lt;br /&gt; int x,y;&lt;br /&gt; char *ret = (char *)calloc(8, 1);&lt;br /&gt;&lt;br /&gt; for(x=0;x&lt;=7;x++,key++)&lt;br /&gt; {&lt;br /&gt;  for(y=0;y&lt;=7;y++)&lt;br /&gt;  {&lt;br /&gt;   ret[y]|=(!!(*key&amp;(1&amp;lt;&amp;lt;y)))&amp;lt;&amp;lt;x;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt; return ret;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;
--&lt;br /&gt;
Copyright 2006-2008 Andrew Rose [rose.andrew@gmail.com] [&lt;a href="http://andrewrose.co.uk"&gt;andrewrose.co.uk&lt;/a&gt;]&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8118313070057098741-259173561147807662?l=blog.andrewrose.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.andrewrose.co.uk/feeds/259173561147807662/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8118313070057098741&amp;postID=259173561147807662&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/259173561147807662'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/259173561147807662'/><link rel='alternate' type='text/html' href='http://blog.andrewrose.co.uk/2007/03/all-in-swizzle.html' title='All in the &quot;swizzle&quot;'/><author><name>Andrew Rose</name><uri>http://www.blogger.com/profile/05883626584607606086</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8118313070057098741.post-812740988969997911</id><published>2007-01-24T14:07:00.002Z</published><updated>2007-01-24T14:10:45.485Z</updated><title type='text'>MyStatsQL - Screen shot of data in graphical format</title><content type='html'>For anyone interested in what can be done with the stats gathered with MyStatsQL, here is a screen shot.  Eventually I will put a package together for download.  The different color lines represent different servers, in this case two.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_QXhmkIQBJZs/RbdorJa_tDI/AAAAAAAAAAM/5qmBXek7zto/s1600-h/mystatsql.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp0.blogger.com/_QXhmkIQBJZs/RbdorJa_tDI/AAAAAAAAAAM/5qmBXek7zto/s320/mystatsql.jpg" alt="" id="BLOGGER_PHOTO_ID_5023598999827887154" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;
--&lt;br /&gt;
Copyright 2006-2008 Andrew Rose [rose.andrew@gmail.com] [&lt;a href="http://andrewrose.co.uk"&gt;andrewrose.co.uk&lt;/a&gt;]&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8118313070057098741-812740988969997911?l=blog.andrewrose.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.andrewrose.co.uk/feeds/812740988969997911/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8118313070057098741&amp;postID=812740988969997911&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/812740988969997911'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/812740988969997911'/><link rel='alternate' type='text/html' href='http://blog.andrewrose.co.uk/2007/01/mystatsql-screen-shot-of-data-in.html' title='MyStatsQL - Screen shot of data in graphical format'/><author><name>Andrew Rose</name><uri>http://www.blogger.com/profile/05883626584607606086</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp0.blogger.com/_QXhmkIQBJZs/RbdorJa_tDI/AAAAAAAAAAM/5qmBXek7zto/s72-c/mystatsql.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8118313070057098741.post-8625333189620873051</id><published>2007-01-23T12:45:00.000Z</published><updated>2007-01-23T13:24:56.158Z</updated><title type='text'>MyStatsQL - Easy temporal stats gathering of MySQL server(s)</title><content type='html'>To make life a little easier at home and work I've put together a simple enough script that is run by &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;&lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;cron&lt;/span&gt;&lt;/span&gt; to tally up statistics like: &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;&lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;Innodb&lt;/span&gt;&lt;/span&gt;_data_reads, &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;&lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;Innodb&lt;/span&gt;&lt;/span&gt;_data_writes, &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;&lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;Qcache&lt;/span&gt;&lt;/span&gt;_hits, &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;&lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;Qcache&lt;/span&gt;&lt;/span&gt;_inserts, Questions, Open_files and Open_tables over time (I sample every hour) with the ability to easily expand and add your own `show status` variables.&lt;br /&gt;&lt;br /&gt;Next I'll create some nice graphical interface so it's more obvious how the server or cluster is running.  You can &lt;a href="http://andrewrose.co.uk/mystatsql.phps"&gt;grab the script over at my CV hosting&lt;/a&gt;.  Note that actual client writes in a master &lt;-&gt; master environment would be (writes / number of servers) roughly, very roughly.  If you have any ideas for countering this please let me know.&lt;br /&gt;&lt;br /&gt;Enjoy.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;
--&lt;br /&gt;
Copyright 2006-2008 Andrew Rose [rose.andrew@gmail.com] [&lt;a href="http://andrewrose.co.uk"&gt;andrewrose.co.uk&lt;/a&gt;]&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8118313070057098741-8625333189620873051?l=blog.andrewrose.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.andrewrose.co.uk/feeds/8625333189620873051/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8118313070057098741&amp;postID=8625333189620873051&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/8625333189620873051'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/8625333189620873051'/><link rel='alternate' type='text/html' href='http://blog.andrewrose.co.uk/2007/01/mystatsql-easy-temporal-stats-gathering.html' title='MyStatsQL - Easy temporal stats gathering of MySQL server(s)'/><author><name>Andrew Rose</name><uri>http://www.blogger.com/profile/05883626584607606086</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8118313070057098741.post-7328844094503681116</id><published>2007-01-22T18:39:00.000Z</published><updated>2007-01-22T18:58:26.550Z</updated><title type='text'>Handling MySQL replication failure gracefully</title><content type='html'>As any serious MySQL DBA knows, MySQL can and will now and again go out of sync, most of the time it cures itself, but sometimes the worst happens and a slave stops replicating.  Yet I bet most apps keep on going with random outcomes, especially if your storing the users sessions in MySQL and have a master&lt;-&gt;master setup.&lt;br /&gt;&lt;br /&gt;To counter this problem I implemented a quick an easy check.  If the check catches a replication failure `touch` a file to the nfs mounted tmp directory that is shared by all nodes.&lt;br /&gt;&lt;br /&gt;Each node before executing anything (in index.php) checks for a file called 'halt' in tmp.  If found exits and bingo no weirdness, corruption, or wondering why something is there one click, gone the next.  It even emails you, and with a simple addition can sms.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;mysql_query("show slave status;", CONNECTION);&lt;br /&gt;if(mysql_errno(CONNECTION)!=0)&lt;br /&gt;{&lt;br /&gt;   mail('team@&amp;lt;some url&amp;gt;',&lt;br /&gt; '&amp;lt;project&amp;gt; REPLICATION ERROR!',&lt;br /&gt; "Error show Slave Status: ".&lt;br /&gt; mysql_errno(CONNECTION).'-'.mysql_error(CONNECTION));&lt;br /&gt;   $fp = fopen('tmp/halt', 'w+');&lt;br /&gt;   fclose($fp);&lt;br /&gt;   header('Location: index.php');&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Don't forget to remove the 'halt' file after you have the replication under control.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;
--&lt;br /&gt;
Copyright 2006-2008 Andrew Rose [rose.andrew@gmail.com] [&lt;a href="http://andrewrose.co.uk"&gt;andrewrose.co.uk&lt;/a&gt;]&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8118313070057098741-7328844094503681116?l=blog.andrewrose.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.andrewrose.co.uk/feeds/7328844094503681116/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8118313070057098741&amp;postID=7328844094503681116&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/7328844094503681116'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/7328844094503681116'/><link rel='alternate' type='text/html' href='http://blog.andrewrose.co.uk/2007/01/handling-mysql-replication-failure.html' title='Handling MySQL replication failure gracefully'/><author><name>Andrew Rose</name><uri>http://www.blogger.com/profile/05883626584607606086</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8118313070057098741.post-6928975608194981566</id><published>2007-01-16T21:20:00.001Z</published><updated>2007-01-22T18:22:49.798Z</updated><title type='text'>Bitmaps | Bit Arrays - Part2</title><content type='html'>I was going to write an article on wikipedia about bitmaps. But came across this &lt;a href="http://en.wikipedia.org/wiki/Bit_array"&gt;article on Bit Arrays&lt;/a&gt;.. ala Bitmaps after a little searching beyond raster graphics. Gotta love that wikipedia.&lt;br /&gt;&lt;br /&gt;It's well worth the time learning how it all works and I've created the toggle macro for you:&lt;br /&gt;&lt;br /&gt;#define bitmap_toggle(bitmap, i) bitmap[i/8]~=(1&lt;&lt;(i%8))&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;
--&lt;br /&gt;
Copyright 2006-2008 Andrew Rose [rose.andrew@gmail.com] [&lt;a href="http://andrewrose.co.uk"&gt;andrewrose.co.uk&lt;/a&gt;]&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8118313070057098741-6928975608194981566?l=blog.andrewrose.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.andrewrose.co.uk/feeds/6928975608194981566/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8118313070057098741&amp;postID=6928975608194981566&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/6928975608194981566'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/6928975608194981566'/><link rel='alternate' type='text/html' href='http://blog.andrewrose.co.uk/2007/01/bitmaps-bit-arrays-part2_16.html' title='Bitmaps | Bit Arrays - Part2'/><author><name>Andrew Rose</name><uri>http://www.blogger.com/profile/05883626584607606086</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8118313070057098741.post-6034094784680709891</id><published>2007-01-08T14:42:00.000Z</published><updated>2007-01-15T11:27:46.729Z</updated><title type='text'>Semaphores</title><content type='html'>I've &lt;a href="http://greenteapress.com/semaphores/"&gt;found&lt;/a&gt; a great free &lt;a href="http://greenteapress.com/semaphores/downey05semaphores.pdf"&gt;pdf&lt;/a&gt; book all about semephores, it's 261 pages long and called "&lt;span style="font-size:100%;"&gt;The Little Book of Semaphores" :D&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;
--&lt;br /&gt;
Copyright 2006-2008 Andrew Rose [rose.andrew@gmail.com] [&lt;a href="http://andrewrose.co.uk"&gt;andrewrose.co.uk&lt;/a&gt;]&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8118313070057098741-6034094784680709891?l=blog.andrewrose.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.andrewrose.co.uk/feeds/6034094784680709891/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8118313070057098741&amp;postID=6034094784680709891&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/6034094784680709891'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/6034094784680709891'/><link rel='alternate' type='text/html' href='http://blog.andrewrose.co.uk/2007/01/semaphores.html' title='Semaphores'/><author><name>Andrew Rose</name><uri>http://www.blogger.com/profile/05883626584607606086</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8118313070057098741.post-4488519998577811554</id><published>2007-01-08T12:08:00.001Z</published><updated>2007-01-22T18:26:28.471Z</updated><title type='text'>Bitmaps - Part 1</title><content type='html'>I've heard of bitmaps but never seen an implementation.  I guess I've not browsed enough code.  Anyway I was thinking about it whilst watching "You, Me and Dupree", and thinking about it again as I ran to catch quiz night at the woody, and some more as we tried to work out what a Raider bar(twix) was called in Europe.&lt;br /&gt;&lt;br /&gt;Anyway I just got home and implemented some nice and simple bitmap code.  It should come in handy with keeping track of paging in the DB project.  Enjoy.  Oh and excuse the sloppy code, it's a first attempt and all.&lt;br /&gt;&lt;br /&gt;#define bitmap_init(size) calloc(1, sizeof(char)*((size/8)+1))&lt;br /&gt;#define bitmap_set(bitmap, i) bitmap[i/8]|=(1&lt;&lt;(i%8))&lt;br /&gt;#define bitmap_unset(bitmap, i) bitmap[i/8]&amp;=~(1&lt;&lt;(i%8))&lt;br /&gt;#define bitmap_isset(bitmap, i)!!(bitmap[i/8]&amp;amp;(1&lt;&lt;(i%8)))&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;
--&lt;br /&gt;
Copyright 2006-2008 Andrew Rose [rose.andrew@gmail.com] [&lt;a href="http://andrewrose.co.uk"&gt;andrewrose.co.uk&lt;/a&gt;]&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8118313070057098741-4488519998577811554?l=blog.andrewrose.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.andrewrose.co.uk/feeds/4488519998577811554/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8118313070057098741&amp;postID=4488519998577811554&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/4488519998577811554'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/4488519998577811554'/><link rel='alternate' type='text/html' href='http://blog.andrewrose.co.uk/2007/01/bitmaps-part-1.html' title='Bitmaps - Part 1'/><author><name>Andrew Rose</name><uri>http://www.blogger.com/profile/05883626584607606086</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8118313070057098741.post-9169088805901184983</id><published>2007-01-04T17:53:00.001Z</published><updated>2010-08-06T10:27:53.050+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><title type='text'>Manifestation type</title><content type='html'>You may or may not have heard of it, SQLite has them, but what is a manifestation type (I'll call them mtypes from now on)?&lt;br /&gt;&lt;br /&gt;You can think of an mtype as a untyped variable with a twist. That is you can assign anything you want to it without having to first declare its type OR size.  But first lets look at a typed variable example using the C programming language.  In C if you want to store a string you will need to declare a fixed char array or create a char pointer to some malloc'd memory cast as char:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;// fixed length array&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt;char str[28];&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;or&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;// malloc'd fixed length array&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt;char *str;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt;str = (char)malloc(sizeof(char)*28);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You need to know ahead of time how much space you will need to store a string.  If your string was longer than 28 characters you would lose everything after character 28, safely off course by being sure not to write more than 28 bytes ;)  This is very much the same principle in the database world, you must know the type and size before hand of a column.&lt;br /&gt;&lt;br /&gt;Now lets use PHPs untyped variables to show an example of a more mtype way of doing things:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;$str = "Hello World!\n"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;and&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;$str .= "from Andrew Roses blog!\n";&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The first line of code created the variable without being told what type it is or how big it is or is going to be and stored the string, the second line adds more to it (showing how there's no need to specify size).  Now, watch this!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;$str = 42;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Try doing something like that in C ;) What we have done it assigned what was once a string an integer.&lt;br /&gt;&lt;br /&gt;Lets move to the database world now with the examples before in mind.  First lets create a table:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;create table test (&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt; id int,&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt; name varchar(32)&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now if we insert some data which sticks to the types(I'm using set in insert so things are clearer):&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;insert into test set id = 42, name = "Andrew Rose";*&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This works, because we stuck to the types, but if we try this instead:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;insert into test set id = "Andrew Rose", name = 42;*&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If your DBMS does not support mtypes id will become 0 and name will be "42", but not the number 42, but the string.  Most DBMSs will convert numeric to string and vica-versa.  id became 0 because it has no logical numeric value.&lt;br /&gt;&lt;br /&gt;A DBMS that supports mtypes would have ended up putting "Andrew Rose" in id and 42 most likely as a string in id, but possibly as an integer.&lt;br /&gt;&lt;br /&gt;In fact in SQLite the table we created can be created without declaring the types at all:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;create table test(&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt; id,&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt; name&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So are mtypes good or evil?  That all depends on the user I believe.&lt;br /&gt;&lt;br /&gt;*SQLite does not support the set in insert syntax.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;
--&lt;br /&gt;
Copyright 2006-2008 Andrew Rose [rose.andrew@gmail.com] [&lt;a href="http://andrewrose.co.uk"&gt;andrewrose.co.uk&lt;/a&gt;]&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8118313070057098741-9169088805901184983?l=blog.andrewrose.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.andrewrose.co.uk/feeds/9169088805901184983/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8118313070057098741&amp;postID=9169088805901184983&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/9169088805901184983'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8118313070057098741/posts/default/9169088805901184983'/><link rel='alternate' type='text/html' href='http://blog.andrewrose.co.uk/2007/01/manifestation-type.html' title='Manifestation type'/><author><name>Andrew Rose</name><uri>http://www.blogger.com/profile/05883626584607606086</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
