<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>MCslp Coalface &#187; Programming</title>
	<atom:link href="http://coalface.mcslp.com/category/network-programming/feed/" rel="self" type="application/rss+xml" />
	<link>http://coalface.mcslp.com</link>
	<description>Thoughts from the bleeding edge of the MCslp keyboards</description>
	<lastBuildDate>Wed, 03 Mar 2010 10:37:15 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Dojo examples from UC2009</title>
		<link>http://coalface.mcslp.com/2009/07/15/dojo-examples-from-uc2009/</link>
		<comments>http://coalface.mcslp.com/2009/07/15/dojo-examples-from-uc2009/#comments</comments>
		<pubDate>Wed, 15 Jul 2009 15:05:03 +0000</pubDate>
		<dc:creator>Martin MC Brown</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Scripting]]></category>

		<guid isPermaLink="false">http://coalface.mcslp.com/?p=259</guid>
		<description><![CDATA[I know, I know, loads of people have been waiting for these&#8230;
So here we go, I&#8217;ve finally sorted a downloaded version of the Dojo examples from the presentation I provided at the MySQL Users Conference 2009. 
There are three examples: 

The auto-paging table example, which uses the functionality of the Dojo Toolkit and the QueryReadStore [...]]]></description>
			<content:encoded><![CDATA[<p>I know, I know, loads of people have been waiting for these&#8230;</p>
<p>So here we go, I&#8217;ve finally sorted a downloaded version of the Dojo examples from the presentation I provided at the MySQL Users Conference 2009. </p>
<p>There are three examples: </p>
<ul>
<li>The auto-paging table example, which uses the functionality of the Dojo Toolkit and the QueryReadStore to automatically load content from a table.<br />
<img src="http://coalface.mcslp.com/wp-content/uploads/2009/07/picture-3-300x239.png" alt="tableautopagesample" title="tableautopagesample" width="300" height="239" /></li>
<li>The basic graphing example, which loads data dynamically and plots a graph.<br />
<img src="http://coalface.mcslp.com/wp-content/uploads/2009/07/picture-4-300x236.png" alt="graphexample" title="graphexample" width="300" height="236" /></li>
<li>And the zooming version of the same basic graph interface</li>
<p>There&#8217;s a README in the download that contains instructions on getting everything up to speed, although it should be fairly obvious. It&#8217;s attached to the bottom of this post too.</p>
<p>Any questions for getting this to work, please go ahead and ask!</p>
<p>Download the package <a href="http://coalface.mcslp.com/downloads/dojoexuc2009v1.tar.bz2">here</a></p>
<p><code><br />
UC2009 Working with MySQL and Dojo<br />
==================================</p>
<p>MC Brown, 2009, http://mcslp.com and http://coalface.mcslp.com</p>
<p>Components:</p>
<p>There are three examples here:</p>
<p>- Dojo table with auto-paging<br />
  (table_autopage.html and table_autopage.cgi)</p>
<p>- Dojo Basic Graph<br />
  (graph_basic.html and graph_ajax.cgi)</p>
<p>- Dojo Zooming Graph<br />
  (graph.html and graph_ajaz_zoom.cgi)</p>
<p>You will also need the Dojo/Dijit and DojoX toolkit package from here:</p>
<p>http://www.dojotoolkit.org/downloads</p>
<p>Download the combined package, and then extract the contents and place in the same directory as the CGI scripts</p>
<p>Intructions for use:</p>
<p>For the Table example, you can create a table (or use an existing DB) from Wordpress using the wp_posts tabls.</p>
<p>In practice you need only create and populate a table with the following columns:</p>
<p>id (int)<br />
user_nicename (char)<br />
post_date (datetime)<br />
post_title (char)</p>
<p>To be compatible with the example without any more modifications.</p>
<p>For the Graphing examples, you need a table as follows:</p>
<p>CREATE TABLE `currencies` (<br />
  `currencyid` bigint(20) unsigned NOT NULL auto_increment,<br />
  `currency` char(20) default NULL,<br />
  `value` float default NULL,<br />
  `datetime` int(11) default NULL,<br />
  `new` int(11) default NULL,<br />
  PRIMARY KEY  (`currencyid`),<br />
  UNIQUE KEY `currencyid` (`currencyid`),<br />
  KEY `currencies_currency` (`currency`,`datetime`),<br />
  KEY `currencies_datetime` (`datetime`)<br />
) ENGINE=MyISAM AUTO_INCREMENT=170048 DEFAULT CHARSET=latin1</p>
<p>And then populate with date/value data according to the information you want to store.</p>
<p>Once done, make sure you change the database information in the CGI scripts to populate the information correctly during operation.<br />
</code></p>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://coalface.mcslp.com/2009/07/15/dojo-examples-from-uc2009/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>My Sessions at UC2009</title>
		<link>http://coalface.mcslp.com/2009/02/10/my-sessions-at-uc2009/</link>
		<comments>http://coalface.mcslp.com/2009/02/10/my-sessions-at-uc2009/#comments</comments>
		<pubDate>Tue, 10 Feb 2009 09:56:35 +0000</pubDate>
		<dc:creator>Martin MC Brown</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Solaris]]></category>
		<category><![CDATA[Virtualization]]></category>

		<guid isPermaLink="false">http://coalface.mcslp.com/?p=201</guid>
		<description><![CDATA[I&#8217;m speaking at the User Conference this year, with a half-day tutorial and three further sessions. The running theme is performance, both in terms of the performance of your queries, and in terms of scaling up. 
Scale Up, Scale Out, and High Availability: Solutions and Combinations
This is the big tutorial. It&#8217;s difficult to resolve what [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m speaking at the User Conference this year, with a half-day tutorial and three further sessions. The running theme is performance, both in terms of the performance of your queries, and in terms of scaling up. </p>
<p><b><a href="http://en.oreilly.com/mysql2009/public/schedule/detail/6805">Scale Up, Scale Out, and High Availability: Solutions and Combinations</a></b></p>
<p>This is the big tutorial. It&#8217;s difficult to resolve what I&#8217;ll be talking about into a few sentences, but think about all of the different technologies available here &#8211; replication, partitions, sharding, DRBD, memcached &#8211; I&#8217;ll be talking about all of them, and more importantly combinations of the different solutions and where the potential performance gains and pitfalls are. I&#8217;ll also be using the opportunity to demonstrate some of the more obscure combinations that you can use to provide the environment you need. </p>
<p><b><a href="http://en.oreilly.com/mysql2009/public/schedule/detail/6849">How I used Query Analysis to Speed Up my Applications</a></b></p>
<p>For query analysis, I&#8217;ll start with some of the basic methods available to us for performance monitoring, including EXPLAIN and DTrace, before I look at the query analysis provided by MySQL Enterprise Monitor. As an advisor to the group I&#8217;ve been looking at it for a while and used it on my own sites to identify a range of different query problems. </p>
<p><b><a href="http://en.oreilly.com/mysql2009/public/schedule/detail/6806">Improving performance by running MySQL multiple times</a></b></p>
<p>It isn&#8217;t talked about much, but there are times when running a single instance of MySQL doesn&#8217;t get you either the performance or environment that you need to support your applications. In this presentation I&#8217;m going to look at some of the benefits, from simply running multiple instances, to using solutions like VMware, Xen, LDOMs, BSD Jails, and Solaris Containers.  </p>
<p><b><a href="http://en.oreilly.com/mysql2009/public/schedule/detail/6850">Using MySQL with the Dojo Toolkit</a></b></p>
<p>The final presentation is something a little more fun. The Dojo Toolkit is a JavaScript kit for developing AJAX applications. There are some really fun things you can do with Dojo, but getting the best combination and cool and efficient with MySQL is an art. We&#8217;ll look at two quick examples; the first is a browsable interface to large quantities of data. The other is dynamic graphing using MySQL as the backend. </p>
<p>If, within the bounds of any of these presentations there is something you would like covered, please let me know. </p>
]]></content:encoded>
			<wfw:commentRss>http://coalface.mcslp.com/2009/02/10/my-sessions-at-uc2009/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>DTrace in MySQL: Documentation and a MySQL University Session</title>
		<link>http://coalface.mcslp.com/2009/02/09/dtrace-in-mysql-documentation-and-a-mysql-university-session/</link>
		<comments>http://coalface.mcslp.com/2009/02/09/dtrace-in-mysql-documentation-and-a-mysql-university-session/#comments</comments>
		<pubDate>Mon, 09 Feb 2009 12:16:26 +0000</pubDate>
		<dc:creator>Martin MC Brown</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Solaris]]></category>

		<guid isPermaLink="false">http://coalface.mcslp.com/?p=196</guid>
		<description><![CDATA[DTrace has been something that I&#8217;ve been trying to get into the MySQL server for more than a year now.
After a combination of my own patches and working with Mikael Ronstrom and Alexey Kopytov we finally have a suite of probes in MySQL 6.0.8. Better still, after a short hiatus while I was busy working [...]]]></description>
			<content:encoded><![CDATA[<p>DTrace has been something that I&#8217;ve been trying to get into the MySQL server for more than a year now.</p>
<p>After a combination of my own patches and working with Mikael Ronstrom and Alexey Kopytov we finally have a suite of probes in MySQL 6.0.8. Better still, after a short hiatus while I was busy working on a million-and-one other things, the documentation for those probes is now available: <a href="http://dev.mysql.com/doc/refman/6.0/en/dba-dtrace-server.html">Tracing mysqld with DTrace</a>. </p>
<p>The documentation is comparatively light and deep all at the same time. It&#8217;s lightweight from the perspective that I&#8217;ve added very little detail on the mechanics of DTrace itself, since there is no need to replicate the excellent guides that Sun already provide on the topic. At the same time, I&#8217;ve tried to provide at least one (and sometimes two) D script examples for each of the groups of probes in the 6.0.8 release. </p>
<p>So what next for MySQL DTrace probes? </p>
<p>Well, the next version of the probes has already been worked on. I&#8217;ve been testing them for a month or so, and due to a problem with the probes on SPARC I couldn&#8217;t approve the patch, but I managed to resolve that last week. The new patch extends the probes to enable a more detailed look at certain operations, and it enables us to expand the probes to be placed anywhere within the server, including individual engine-level row operations. </p>
<p>If you want a demonstration of DTrace in MySQL, some of the things you can monitor without using the user probes we&#8217;ve added, and those new probes I just mentioned, then you will want to attend the <a href="http://forge.mysql.com/wiki/Using_DTrace_with_MySQL">MySQL University session this Thursday (12th Feb), at 14:00UTC</a> where I&#8217;ll be doing all of the above. </p>
<p>As a side note, because I know there are people interested, last week I also finished the patch for these probes to go into the MySQL 5.1.30 version that we will be putting into OpenSolaris. Sunanda is working on getting that release out there as I type this.</p>
]]></content:encoded>
			<wfw:commentRss>http://coalface.mcslp.com/2009/02/09/dtrace-in-mysql-documentation-and-a-mysql-university-session/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Multiple VCS Updates and Cleanups</title>
		<link>http://coalface.mcslp.com/2008/11/22/multiple-vcs-updates-and-cleanups/</link>
		<comments>http://coalface.mcslp.com/2008/11/22/multiple-vcs-updates-and-cleanups/#comments</comments>
		<pubDate>Sat, 22 Nov 2008 11:27:05 +0000</pubDate>
		<dc:creator>Martin MC Brown</dc:creator>
				<category><![CDATA[Development Environments]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://coalface.mcslp.com/?p=182</guid>
		<description><![CDATA[I spend a lot of time updating a variety of different repositories of different varieties and denominations, and I hate having to do that all by hand &#8211; I&#8217;d rather just go up into a top-level directory and say update-all and let a script work out what to do, no matter what different repos are [...]]]></description>
			<content:encoded><![CDATA[<p>I spend a lot of time updating a variety of different repositories of different varieties and denominations, and I hate having to do that all by hand &#8211; I&#8217;d rather just go up into a top-level directory and say <code>update-all</code> and let a script work out what to do, no matter what different repos are there. </p>
<p>I do it with a function defined within my bash profile/rc scripts, and it covers git, bzr, svn, bk, and cvs. The trick is to identify what type of directory we are updating. I do this, lazily, for each type individually, rather than for each directory, but I&#8217;ve found this method to be more reliable.</p>
<blockquote><p><code>update-all ()<br />
{<br />
    for file in `ls -d */.svn 2>/dev/null`;<br />
    do<br />
        realdir=`echo $file|cut -d/ -f1`;<br />
        echo Updating in $realdir;<br />
        ( cd $realdir;<br />
        svn update );<br />
    done;<br />
    for file in `ls -d */.bzr 2>/dev/null`;<br />
    do<br />
        realdir=`echo $file|cut -d/ -f1`;<br />
        echo Updating in $realdir;<br />
        ( cd $realdir;<br />
        bzr pull );<br />
    done;<br />
    for file in `ls -d */.git 2>/dev/null`;<br />
    do<br />
        realdir=`echo $file|cut -d/ -f1`;<br />
        echo Updating in $realdir;<br />
        ( cd $realdir;<br />
        git pull );<br />
    done;<br />
    for file in `ls -d */CVS 2>/dev/null`;<br />
    do<br />
        realdir=`echo $file|cut -d/ -f1`;<br />
        echo Updating in $realdir;<br />
        ( cd $realdir;<br />
        cvs up );<br />
    done;<br />
    for file in `ls -d */BitKeeper 2>/dev/null`;<br />
    do<br />
        realdir=`echo $file|cut -d/ -f1`;<br />
        echo Updating in $realdir;<br />
        ( cd $realdir;<br />
        bk pull );<br />
    done;<br />
    unset realdir<br />
}<br />
</code></p></blockquote>
<p>That&#8217;s it &#8211; a quick way to update any directory of repos. </p>
]]></content:encoded>
			<wfw:commentRss>http://coalface.mcslp.com/2008/11/22/multiple-vcs-updates-and-cleanups/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Feeding Query Analyzer from DTrace</title>
		<link>http://coalface.mcslp.com/2008/11/15/feeding-query-analyzer-from-dtrace/</link>
		<comments>http://coalface.mcslp.com/2008/11/15/feeding-query-analyzer-from-dtrace/#comments</comments>
		<pubDate>Sat, 15 Nov 2008 09:02:54 +0000</pubDate>
		<dc:creator>Martin MC Brown</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Solaris]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://coalface.mcslp.com/?p=178</guid>
		<description><![CDATA[One of the new features in the new release of MySQL Enterprise Monitor is Query Analyzer. As the name suggests, the Query Analyzer provides information about the queries that are running on your server, the response times and row and byte statistics. The information provided is great, and it doesn&#8217;t take very long to see [...]]]></description>
			<content:encoded><![CDATA[<p>One of the new features in the new release of MySQL Enterprise Monitor is Query Analyzer. As the name suggests, the Query Analyzer provides information about the queries that are running on your server, the response times and row and byte statistics. The information provided is great, and it doesn&#8217;t take very long to see from the query data supplied that there are places where you could improve the the query, or even reduce the number of queries that you submit. </p>
<p>The system works by using the functionality of the MySQL Proxy to monitor the queries being executed and then provide that information up to the MySQL Enterprise Service Manager so that the information can be displayed within the Query Analyzer page. To get the queries monitored, you have to send the queries through the agent which both monitors their execution and sends the information on up to the Manager, along with all the other data being monitored. </p>
<p>The team, though, have been a bit clever and opened up the system to allow information to be sent to the Manager using a REST interface. This means that any system capable of providing information that you want to monitor can be sent up to the Manager. Of course, you can’t just send anything, the Manager needs to know how to handle it, but it shows the flexibility of the design and the potential for the future. </p>
<p>So how does this help us? </p>
<p>Well, one of the new features in MySQL 6.0 that I’ve been working on (with Mikael Ronstrom and Alexey Kopytov) is DTrace probes. We’ve added a bunch of static DTrace probes into MySQL 6.0 (the full set will appear in MySQL 6.0.8, I think) designed to let you  monitor the execution of queries within the server. The probes will allow you to see both the top-level information, such as overall execution time, but also deeper so that you can get information about individual row operations, whether the query used the query cache, and whether it used a filesort operation. </p>
<p>I haven’t finished the DTrace probes documentation yet, but I have been demonstrating the probes at conferences and talks (including my MySQL on OpenSolaris university session this week). Trust me, you’ll be pleased. I’ve got a separate blog post detailing some of the specifics in the works at the moment. </p>
<p>For obvious reasons, there’s a synergy here that should be obvious. Why don’t we feed up data extracted using DTrace and provide that up to the Enterprise Manager?</p>
<p>To do this, there are two parts to the process, the DTrace probes and the script hat passes that information up in a suitable format to the manager. </p>
<p>The D script is quite straightforward, we initialize the structures, populate the core information that we need (query string, bytes, rows and the time), and the use the remainder of the probes to finalize that information. Let&#8217;s have look at the script and then go through the detail: </p>
<blockquote><pre>#!/usr/sbin/dtrace -s

#pragma D option quiet

mysql*:::query-start
{
   self->query = copyinstr(arg0);
   self->db    = copyinstr(arg2);
   self->rows  = 0;
   self->querystart = timestamp;
   self->bytes = 0;
}

mysql*:::select-done
{
        self->rows = arg1;
}

mysql*:::insert-done
{
        self->rows = arg1;
}

mysql*:::update-done
{
        self->rows = arg2;
}

mysql*:::multi-delete-done
{
        self->rows = arg1;
}

mysql*:::delete-done
{
        self->rows = arg1;
}

mysql*:::multi-update-done
{
        self->rows = arg2;
}

mysql*:::net-write-start
{
        self->bytes = self->bytes + arg0;
}

mysql*:::query-done
/self->query != NULL/
{
        printf("%s:%s:%d:%d:%d\n",
        self->query,
        self->db,
        ((timestamp - self->querystart)/1000),
        self->rows,self->bytes);
}</pre>
</blockquote>
<p>First, we set a pragma to quieten down the output so that the DTrace script only reports what we explicitly write out: </p>
<blockquote><pre>#pragma D option quiet</pre>
</blockquote>
<p>In DTrace, the individual execution points are called probes, and probes are triggered each time that point in the code is reached. To specify the probes we want to watch for, you use a special format, <code>provider:module:function:name</code> that identifies the probe by the name of the provider (the application), the module, the function, and the probe, each separated by a colon. We can just specify the provider and probe name, like <code>mysql*:::query-start</code>.</p>
<p>It should also be noted that probes are often provided in pairs at the start and end of an operation, so you can identify the start and end of a query by looking for the <code>query-start</code> and <code>query-done</code> probes.</p>
<p>The DTrace probes in the server are set-up in a sort of nested structure, going deeper into the query process as needed. Although not at the very top of the execution cycle, the start of the main query processing is identified by the <code>query-start</code> probe. Each time a query is submitted to MySQL, this probe will get triggered, so for us, it is the start of the process. The probe has a number of arguments, but for our purposes we only need the first (<code>arg0</code>), which contains the full query string, and the third (<code>arg2</code>) which contains the name of the database that the query was executed against.</p>
<p>We also initialize the row and byte counts, and the time when the query was executed using the built-in <code>timestamp</code> value. All of this information is placed into the special <code>self</code> structure, which is a persistent structure used to share information between the individual probes that get fired during execution. </p>
<blockquote><pre>mysql*:::query-start
{
   self->query = copyinstr(arg0);
   self->db    = copyinstr(arg2);
   self->rows  = 0;
   self->querystart = timestamp;
   self->bytes = 0;
}</pre>
</blockquote>
<p>To get the counts of the number of rows, we can&#8217;t get the information from the <code>query-done</code> probe. This is because different operations actually provide different levels of information. For example, the <code>select-done</code> and <code>insert-done</code> just provide a count of the rows. But the <code>update-done</code> probe provides information both about the number of rows that matched the original <code>WHERE</code> clause, and the count of the number rows actually modified. </p>
<p>To record the number of the rows modified by the query, we therefore need to pull out each piece of information individually: </p>
<blockquote><pre>mysql*:::select-done
{
        self->rows = arg1;
}
mysql*:::insert-done
{
        self->rows = arg1;
}

mysql*:::update-done
{
        self->rows = arg2;
}

mysql*:::multi-delete-done
{
        self->rows = arg1;
}

mysql*:::delete-done
{
        self->rows = arg1;
}

mysql*:::multi-update-done
{
        self->rows = arg2;
}</pre>
</blockquote>
<p>For the bytes retrieved by each query, the information is a bit more difficult to identify. I&#8217;m going to cheat a bit and use the bytes sent by <code>mysqld</code> during a net write to the client. There is a limitation here I&#8217;ve skipped, which is that we could report data sent to any client, since I haven&#8217;t bothered to track connection IDs. I could do this, but it would make the script a little more complicated. Since the <code>net-write-start</code> might be called multiple times for a long query, we calculate a cumulative byte count.</p>
<blockquote><pre>mysql*:::net-write-start
{
        self->bytes = self->bytes + arg0;
}</pre>
</blockquote>
<p>That&#8217;s all of the information collection; now we just need to print out the information when the query completes. We do this by writing out a colon separated list of the information that we&#8217;ve collected. One additional point here though is that to calculate the duration of the query, you take the timestamp recorded when <code>query-start</code> was called away from the current <code>timestamp</code>. </p>
<p>Timestamp information is recorded in nanoseconds (yes, you read that right, nanoseconds), so we divide it by a thousand to get it in microseconds, which is what the Enterprise Manager will expected. </p>
<pre>
<blockquote>mysql*:::query-done
/self->query != NULL/
{
        printf("%s:%s:%d:%d:%d\n",
        self->query,
        self->db,
        ((timestamp - self->querystart)/1000),
        self->rows,self->bytes);
}</blockquote>
</pre>
<p>If you run this script on it&#8217;s own (against a MySQL running on Solaris/OpenSolaris, with probes, of course), then you&#8217;ll get output like this: </p>
<blockquote><pre>SELECT DATABASE()::391:1:44
show databases:test:947:2:84
show tables:test:2018:3:74
select * from t limit 5:test:595:5:51</pre>
</blockquote>
<p>To provide the information up to the Enterprise Manager we cannot use D scripts. Instead, a wrapper around the D script will read the raw information produced and then pass that up to the Enterprise Manager. </p>
<p>Before we look at that process, it is worth looking at the REST API that has been built in to v2 of the Enterprise Monitor. The interface is available through the standard URL for the Enterprise service, typically your hostname and the port 18080 if you&#8217;ve used the default settings. Therefore we can access the interface using the url <code>http://nautilus:18080/v2/rest/</code>, assuming our host is <code>nautilus</code>. </p>
<p>From the base URL, you can start to get information, or put information, about the different entries in the repository using the path in the URL to signifiy what it is we are looking for. Information about instances is within the <code>instance</code>, with the provider as <code>mysql</code>, and the MySQL server as <code>server</code>. Or better put, the base URL would be <code>http://nautilus:18080/v2/rest/instance/mysql/server/</code>.</p>
<p>The last fragment of information we need is the UUID. All objects within the repository have a unique ID, and these are split at different levels. For example, an agent has a UUID, and so does the server it is monitoring. In our example, we want the UUID of the MySQL server, which is conveniently stored within the server itself in the <code>mysql.inventory</code> table. </p>
<p>Finally, we need the username and password of the agent user. Through the REST API we use basic HTTP authentication, to make the process easy. </p>
<p>Putting all of this together, we can get the core information about an instance using wget:</p>
<blockquote><pre>$ wget -qO mysql.server --http-user=agent --http-password=password \
    'http://nautilus:18080/v2/rest/instance/mysql/server/2b86b277-fb2b-492d-b946-3a2acaec0869'
</pre>
</blockquote>
<p>If we now look at the output file, <code>mysql.server</code>:</p>
<blockquote><pre>{
    "name": "2b86b277-fb2b-492d-b946-3a2acaec0869",
    "parent": "/instance/os/Host/ssh:{88:e1:fc:6d:99:69:e4:5f:b4:0a:ec:5a:09:c0:6a:24}",
    "values":     {
        "blackout": "false",
        "displayname": null,
        "registration-complete": "true",
        "repl.groupName": null,
        "server.connected": 1,
        "server.last_error": null,
        "server.reachable": 1,
        "transport": "a3113263-4993-4890-8235-cadef9617c4b",
        "visible.displayname": "bear:3306"
    }
}
</pre>
</blockquote>
<p>I wont go into detail about what is here, most of it should be self explanatory. However, there are a few things of note. First, the information is in JSON format. This makes it easy to read and more importantly create. </p>
<p>Second, note the notation. The item is identified by its name, and also by it&#8217;s parent. This is an important construct because it helps identify the different elements with each other. In this case, the MySQL server is associated with a physical host (<code>/instance/os/Host</code>) and the individual host is identified by a SSH key, which is one of the alternative UUID formats support by the Enterprise Server to identify individual entities.</p>
<p>When submitting information, we need to flip the process around. We don&#8217;t use a GET request to obtain the information, we use a PUT to send up a JSON packet containing the information we want. The URL for sending the information depends on what we are uploading. The main element for the statements used for Query Analyzer is the <code>statementsummary</code>. </p>
<p>The URL for this is <code>http://nautilus:18080/v2/rest/instance/mysql/statementsummary/</code>. For the identifier at the end of the URL, you use a period-separated list that includes the UUID of the MySQL server, the name of the MySQL database the SQL statement relates to, and an MD5 hash of the SQL statement text. </p>
<p>For the actual packet, we use the following format, taken here from the Perl script: </p>
<blockquote><pre>{
    "name": "$server_uuid.$quanbase->{dbname}.$md5",
    "parent": "/instance/mysql/server/$server_uuid",
    "values" : {
	"count": "$quanbase->{count}",
	"text": "$quanbase->{query}",
	"query_type": "$quanbase->{qtype}",
	"text_hash": "$md5",
	"max_exec_time": "$quanbase->{max_exec_time}",
	"min_exec_time": "$quanbase->{min_exec_time}",
	"exec_time": "$quanbase->{exec_time}",
	"rows": "$quanbase->{rows}",
	"max_rows": "$quanbase->{max_rows}",
	"min_rows": "$quanbase->{min_rows}",
	"database": "$quanbase->{dbname}",
	"bytes": "$quanbase->{bytes}",
	"max_bytes": "$quanbase->{max_bytes}",
	"min_bytes": "$quanbase->{min_bytes}",
    }
}</pre>
</blockquote>
<p>Most of this should be self-explanatory. Remember that this is a statement <strong>summary</strong>, which means that we can send up information about multiple invocations of the same statement in one packet. Thus, within the statementsummary packet we have information about the count of invocations of the statement, execution, row and byte counts and maximum/minimum of each of them, and then the core information like the actual query text, database name, and query type (SELECT, INSERT, etc). </p>
<p>Once again, note the <code>name</code> and <code>parent</code>. Here the name is the same tuple as used in the URL, the UUID of the MySQL server, the database, and the hash of the query. This is used as the identifier for this query within the repository and allows us to uniquely identify the query, and the query execution on this server. The parent is the location of, and UUID of, the MySQL server. </p>
<p>Now, the Perl script that collates the information from our D script has to do two things, first read the raw output that we create with the D script, and second, supply this up as a PUT request to the Enterprise Server. </p>
<p>Dealing with the latter part first, I&#8217;ve used Perl and LWP (libwww-perl) module to construct a suitable request object with the HTTP authorization attached: </p>
<blockquote><pre>my $header = HTTP::Headers->new;
$header->content_type('text/text');
$header->authorization_basic('agent','password');
my $res = LWP::UserAgent->new();
</pre>
<p>Once we&#8217;ve constructed a packet, sending it is a case of specifying the URL, the header, and the content: </p>
<blockquote><pre>$header->content_length(length $bio);
my $req = HTTP::Request->new(PUT => $url, $header, $bio);

$res->request($req);
</pre>
</blockquote>
<p>The bulk of the rest of the script is devoted to reading the information from the D script output, and assembling the packet and min/max values per query. </p>
<p>Within the Query Analyzer, the SQL statements are normalized, or canonicalized so that variables are replaced with a question mark. This ensures that we are tracking the <strong>query</strong> and not the individual values. The significance here is that we want to compare the raw SQL statement, of which there may only be a few hundred in a typical application, not each individual query with it&#8217;s <code>WHERE</code> and other clauses. </p>
<p>Hence, the statement: </p>
<blockquote><pre>SELECT photoid,title from media_photos where photoid > 23785 limit 15</pre>
</blockquote>
<p>Would be normalized to:</p>
<blockquote><pre>SELECT photoid,title from media_photos where photoid > ? limit ?</pre>
</blockquote>
<p>For the Perl script, I do just one type of normalization, removing the value from a
<literal>LIMIT</literal> clause.</p>
<blockquote><pre>#!/usr/bin/perl
use Data::Dumper;
use LWP;
use HTTP::Request;
use Digest::MD5 qw/md5_hex/;

my $server_uuid = '2b86b277-fb2b-492d-b946-3a2acaec0869';

my $header = HTTP::Headers->new;
$header->content_type('text/text');
$header->authorization_basic('agent','password');
my $res = LWP::UserAgent->new();

my $interval = shift || 20;

print "Sending queries every $interval statement(s)\n";

open(DTRACE,"./merlin.d|") or die "Couldn't open DTRACE\n";

my $counter = 1;
my $querybase = {};

while(
<dtrace>)
{
    chomp;
    my ($origquery,$dbname,$time,$rows,$bytes) = split m{:};

    my $query = $origquery;
    $query =~ s/limit \d+/limit ?/g;

    $querybase->{$query}->{dbname} = $dbname;
    $querybase->{$query}->{query} = $query;
    $querybase->{$query}->{count}++;
    $querybase->{$query}->{rows} += $rows;
    $querybase->{$query}->{bytes} += $bytes;
    $querybase->{$query}->{exec_time} += $time;

    if (exists($querybase->{$query}))
    {
	$querybase->{$query}->{max_rows} = $rows if ($rows > $querybase->{$query}->{max_rows});
	$querybase->{$query}->{min_rows} = $rows if ($rows < $querybase->{$query}->{min_rows});
	$querybase->{$query}->{max_bytes} = $bytes if ($bytes > $querybase->{$query}->{max_bytes});
	$querybase->{$query}->{min_bytes} = $bytes if ($bytes < $querybase->{$query}->{min_bytes});
	$querybase->{$query}->{max_exec_time} = $time if ($time > $querybase->{$query}->{max_exec_time});
	$querybase->{$query}->{min_exec_time} = $time if ($time < $querybase->{$query}->{min_exec_time});
    }
    else
    {
	$querybase->{$query}->{max_rows} = $rows;
	$querybase->{$query}->{min_rows} = $rows;
	$querybase->{$query}->{max_bytes} = $bytes;
	$querybase->{$query}->{min_bytes} = $bytes;
	$querybase->{$query}->{max_exec_time} = $time;
	$querybase->{$query}->{min_exec_time} = $time;
    }	

    if (($counter % $interval) == 0)
    {
	print STDERR "Writing quan packets ($counter queries sent)\n";
        foreach my $query (keys %{$querybase})
        {
            send_quandata($querybase->{$query});
	    delete($querybase->{$query});
        }
    }
    $counter++;
}

sub send_quandata
{
    my ($quanbase) = @_;

    my $urlbase = 'http://nautilus:18080/v2/rest/instance/mysql/statementsummary/%s.%s.%s';

    my $md5 = md5_hex($quanbase->{query});
    my $url = sprintf($urlbase,$server_uuid,$quanbase->{dbname},$md5);

my $bio = < <EOF;
{
    "name": "$server_uuid.$quanbase->{dbname}.$md5",
    "parent": "/instance/mysql/server/$server_uuid",
    "values" : {
        "count": "$quanbase->{count}",
        "text": "$quanbase->{query}",
        "query_type": "$quanbase->{qtype}",
        "text_hash": "$md5",
        "max_exec_time": "$quanbase->{max_exec_time}",
        "min_exec_time": "$quanbase->{min_exec_time}",
        "exec_time": "$quanbase->{exec_time}",
        "rows": "$quanbase->{rows}",
        "max_rows": "$quanbase->{max_rows}",
        "min_rows": "$quanbase->{min_rows}",
        "database": "$quanbase->{dbname}",
        "bytes": "$quanbase->{bytes}",
        "max_bytes": "$quanbase->{max_bytes}",
        "min_bytes": "$quanbase->{min_bytes}",
    }
}
EOF

$header->content_length(length $bio);
my $req = HTTP::Request->new(PUT => $url, $header, $bio);

$res->request($req);
}</dtrace></pre>
</blockquote>
<p>The basic structure is: </p>
<ol>
<li>Open the DTrace script</li>
<li>Read a line</li>
<li>Add that to the temporary list of queries I know about, adding stats</li>
<li>When I&#8217;ve read N queries, send up the stats about each query as a JSON packet to the Enterprise Manager</li>
<li>Repeat</li>
</ol>
<p>Depending on how busy your server is, you may want to adjust the interval when the stats data is uploaded. The default is every 20 queries, but when running on a really busy server, or when running benchmarks, you might want to up that to prevent the script spending too much time sending fairly small packets of stats up. </p>
<p>If you run the script, it should just work in the background: </p>
<blockquote><pre>$ ./dtrace_merlin.pl
Sending queries every 20 statement(s)
Writing quan packets (20 queries sent)
Writing quan packets (40 queries sent)
Writing quan packets (60 queries sent)
</pre>
</blockquote>
<p>That&#8217;s it!</p>
<p>I set this up and then sent some random queries to the server. The following graphic shows the query data only from the DTrace sourced information. </p>
<p><a href="http://coalface.mcslp.com/wp-content/uploads/2008/11/picture-5.png"><img src="http://coalface.mcslp.com/wp-content/uploads/2008/11/picture-5-300x74.png" alt="" title="Quan data from DTrace" width="300" height="74" class="alignnone size-medium wp-image-179" /></a></p>
<p>There are some limitations to the current script. I don&#8217;t do full normalization, for example, and I dont send the detailed information about individual statements up at the moment. There is also an <code>EXPLAIN</code> packet that you can send that contains the output from an <code>EXPLAIN</code> on a long running query. I could do that by opening a connection to the server and picking out the information. </p>
<p>But what I&#8217;d really like to do is use the DTrace-based output to show the detail of each part of the query process <em>and</em> the <code>EXPLAIN</code> output. I&#8217;m sure I can work on that with the Enterprise team. </p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://coalface.mcslp.com/2008/11/15/feeding-query-analyzer-from-dtrace/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Compiling MySQL Workbench on Gentoo</title>
		<link>http://coalface.mcslp.com/2008/11/10/compiling-mysql-workbench-on-gentoo/</link>
		<comments>http://coalface.mcslp.com/2008/11/10/compiling-mysql-workbench-on-gentoo/#comments</comments>
		<pubDate>Mon, 10 Nov 2008 11:01:16 +0000</pubDate>
		<dc:creator>Martin MC Brown</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://coalface.mcslp.com/?p=166</guid>
		<description><![CDATA[The Workbench team have just announced the release of Workbench for Linux, including binary packages and source packages with instructions on how to build. 
I&#8217;m a Gentoo Linux user, so I prefer building from source, and you&#8217;ll need to emerge the following packages (and note the USE) requirement as part of the source build process:
# [...]]]></description>
			<content:encoded><![CDATA[<p>The Workbench team have just announced the release of <a href="http://dev.mysql.com/workbench/?page_id=152">Workbench for Linux</a>, including binary packages and source packages with instructions on how to build. </p>
<p>I&#8217;m a Gentoo Linux user, so I prefer building from source, and you&#8217;ll need to <code>emerge</code> the following packages (and note the <code>USE</code>) requirement as part of the source build process:</p>
<blockquote><pre># USE="svg" emerge libzip libxml2 libsigc++ \
    libglade libgtksourceviewmm media-libs/glut mysql lua \
    ossp-uuid libpcre libgnome gtk+ pango cairo
</pre>
</blockquote>
<p>Depending on your config and platform, you may need to bypass some package masking by adding the packages to your <code>/etc/portage/package.keywords</code> file. </p>
<p>Then download and install the <code>ctemplate</code> library from <a href="http://code.google.com/p/google-ctemplate/">google code page</a>. The current Gentoo version is 0.90, and you really should install the 0.91 version. </p>
<p>With the required packages and libraries in place, download the Workbench sources and then build:</p>
<blockquote><pre># cd mysql-workbench-5.1.4alpha
# ./autogen.sh
# make
# make install</pre>
</blockquote>
<p>That should build and install MySQL Workbench for you. </p>
<p>Just to confirm, here&#8217;s a screenshot of the built Workbench running on Gentoo Linux and displaying to my Mac OS X-based desktop.<br />
<a href="http://coalface.mcslp.com/wp-content/uploads/2008/11/picture-2.png"><img src="http://coalface.mcslp.com/wp-content/uploads/2008/11/picture-2-300x213.png" alt="" title="MySQL Workbench on Gentoo" width="300" height="213" class="alignnone size-medium wp-image-168" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://coalface.mcslp.com/2008/11/10/compiling-mysql-workbench-on-gentoo/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>How to analyze memory leaks on Windows</title>
		<link>http://coalface.mcslp.com/2008/10/13/how-to-analyze-memory-leaks-on-windows/</link>
		<comments>http://coalface.mcslp.com/2008/10/13/how-to-analyze-memory-leaks-on-windows/#comments</comments>
		<pubDate>Mon, 13 Oct 2008 10:13:35 +0000</pubDate>
		<dc:creator>Martin MC Brown</dc:creator>
				<category><![CDATA[Commentary]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[debugging]]></category>

		<guid isPermaLink="false">http://coalface.mcslp.com/?p=113</guid>
		<description><![CDATA[We use valgrind to find memory leaks in MySQL on Linux. The tool is a convenient, and often enlightening way of finding out where the real and potential problems are location. 
On Windows, you dont have valgrind, but Microsoft do provide a free native debugging tool, called the user-mode dump heap (UMDH) tool. This performs [...]]]></description>
			<content:encoded><![CDATA[<p>We use <a href="http://valgrind.org">valgrind</a> to find memory leaks in MySQL on Linux. The tool is a convenient, and often enlightening way of finding out where the real and potential problems are location. </p>
<p>On Windows, you dont have valgrind, but Microsoft do provide a free native debugging tool, called the user-mode dump heap (UMDH) tool. This performs a similar function to valgrind to determine memory leaks.  </p>
<p>Vladislav Vaintroub, who works on the Falcon team and is one of our resident Windows experts provides the following how-to for using UMDH:</p>
<ol>
<li>
<p>Download and install debugging tools for Windows from here<br />
<a href="http://www.microsoft.com/whdc/DevTools/Debugging/default.mspx">MS Debugging Tools</a><br />
Install 64 bit version if you&#8217;re on 64 bit Windows and 32 bit version<br />
otherwise.</p>
</li>
<li>
<p>Change the <code>PATH</code> environment variable to include bin directory of Debugging tools.<br />
On my system, I added<br />
<code>C:\Program Files\Debugging Tools for Windows 64-bit</code> to the <code>PATH</code>.</p>
</li>
<li>
<p>Instruct OS to collect  allocation stack for mysqld with <code>gflags -i<br />
mysqld.exe +ust</code>.<br />
On Vista and later, this should be done in &#8220;elevated&#8221; command prompt,<br />
it requires admin privileges.
</p>
<p>
Now collect the leak information. The mode of operation is that: take the<br />
heap snapshot once, and after some load take it once again. Compare<br />
snapshots and output leak info.</p>
</li>
<li>
<p>Preparation : setup debug symbol path.<br />
In the command prompt window, do</p>
<p><code>set _NT_SYMBOL_PATH= srv*C:\websymbols*http://msdl.microsoft.com/download/symbols;G:\bzr\mysql-6.0\sql\Debug</code></p>
<p>Adjust second path component for your needs, it should include directory<br />
where mysqld.exe is.</p>
</li>
<li>Start mysqld and run it for some minutes</li>
<li>
<p>Take first heap snapshot</p>
<p><code>umdh -p:6768 -f:dump1</code></p>
<p>Where -p:
<pid_of_process> actually, PID of my mysqld was 6768.
</pid_of_process></li>
<li>Let mysqld run for another some minutes</li>
<li>
<p>Take second heap snapshot</p>
<p><code>umdh -p:6768 -f:dump2</code></p>
</li>
<li>
<p>Compare snapshots</p>
<p><code>umdh -v dump1 dump2 > dump.compare.txt</code></p>
</li>
<li>Examine the result output file. It is human readable, but all numbers are<br />
in hex, to scare everyone except  geeks.</li>
<li>
<p><code>gflags -i mysqld.exe -ust</code></p>
<p>Instruct OS  not to collect mysqld user mode stacks for allocations<br />
anymore.</p>
</li>
</ol>
<p>These are 10 steps and it sounds like much work, but in reality it takes 15<br />
minutes first time you do it and 5 minutes next time.</p>
<p>Additional information is given in Microsoft KB article about UMDH<br />
<a href="http://support.microsoft.com/kb/268343">KB 268343</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://coalface.mcslp.com/2008/10/13/how-to-analyze-memory-leaks-on-windows/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>New VoiceXML/XQuery Demo</title>
		<link>http://coalface.mcslp.com/2008/03/19/new-voicexmlxquery-demo/</link>
		<comments>http://coalface.mcslp.com/2008/03/19/new-voicexmlxquery-demo/#comments</comments>
		<pubDate>Wed, 19 Mar 2008 16:39:05 +0000</pubDate>
		<dc:creator>Martin MC Brown</dc:creator>
				<category><![CDATA[Commentary]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://coalface.mcslp.com/2008/03/19/new-voicexmlxquery-demo/</guid>
		<description><![CDATA[I&#8217;ve got a new VoiceXML/XQuery article coming out, and IBM have asked that a demo of the service is live. 
The service is an interface RSS reader &#8211; you get to choose the topic and the feed (currently only four static feeds are provided), then it will read out the feed content. 
You can try [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve got a new VoiceXML/XQuery article coming out, and IBM have asked that a demo of the service is live. </p>
<p>The service is an interface RSS reader &#8211; you get to choose the topic and the feed (currently only four static feeds are provided), then it will read out the feed content. </p>
<p>You can try out the demo by calling: </p>
<ul>
<li>Skype: +99000936 9991260725</li>
<li></li>
<li>US (freephone): (800) 289-5570, then using PIN 9991260725</li>
</ul>
<p>Occasionally the hosting times out, in which case, please contact me and I&#8217;ll check it out and restart or reboot the service. </p>
]]></content:encoded>
			<wfw:commentRss>http://coalface.mcslp.com/2008/03/19/new-voicexmlxquery-demo/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>An introduction to Eclipse for Visual Studio users</title>
		<link>http://coalface.mcslp.com/2008/02/11/an-introduction-to-eclipse-for-visual-studio-users/</link>
		<comments>http://coalface.mcslp.com/2008/02/11/an-introduction-to-eclipse-for-visual-studio-users/#comments</comments>
		<pubDate>Mon, 11 Feb 2008 05:14:44 +0000</pubDate>
		<dc:creator>Martin MC Brown</dc:creator>
				<category><![CDATA[Commentary]]></category>
		<category><![CDATA[Development Environments]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://coalface.mcslp.com/2008/02/11/an-introduction-to-eclipse-for-visual-studio-users/</guid>
		<description><![CDATA[I&#8217;m seeing more and more people moving to Eclipse as a development platform, even those Windows users who have traditionally used Visual Studio. As an Eclipse user for quite a while now I&#8217;m often asked how good it is, or how to use it. 
Of course, telling people to simply try it out isn&#8217;t enough. [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m seeing more and more people moving to Eclipse as a development platform, even those Windows users who have traditionally used Visual Studio. As an Eclipse user for quite a while now I&#8217;m often asked how good it is, or how to use it. </p>
<p>Of course, telling people to simply try it out isn&#8217;t enough. Many people just don&#8217;t get Eclipse and cannot understand or translate the skills and experience they already have to the Eclipse environment. That&#8217;s where <a href="http://www.ibm.com/developerworks/opensource/library/os-eclipse-visualstudio/?ca=dgr-btw01Eclipse-VS">An introduction to Eclipse for Visual Studio users</a> can help. </p>
<p>It&#8217;s a quick overview of the fundamentals of Eclipse from the perspective of a Visual Studio user. For a more in depth examination, there&#8217;s a tutorial <a href="http://www.ibm.com/developerworks/edu/os-dw-os-eclipsevs-i.html">Eclipse for Visual Studio developers</a>, and another on migrating your applications from VS to Eclipse: <a href="http://www.ibm.com/developerworks/library/os-ecl-vscdt/">Migrate Visual Studio C and C++ projects to Eclipse CDT</a>.</p>
<p>I can recommend any (or indeed all) of these. </p>
]]></content:encoded>
			<wfw:commentRss>http://coalface.mcslp.com/2008/02/11/an-introduction-to-eclipse-for-visual-studio-users/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mysterious crashes? &#8211; check your temporary directory settings</title>
		<link>http://coalface.mcslp.com/2007/11/07/mysterious-crashes-check-your-temporary-directory-settings/</link>
		<comments>http://coalface.mcslp.com/2007/11/07/mysterious-crashes-check-your-temporary-directory-settings/#comments</comments>
		<pubDate>Wed, 07 Nov 2007 20:29:18 +0000</pubDate>
		<dc:creator>Martin MC Brown</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[OS]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Solaris]]></category>
		<category><![CDATA[Unix]]></category>

		<guid isPermaLink="false">http://coalface.mcslp.com/2007/11/07/mysterious-crashes-check-your-temporary-directory-settings/</guid>
		<description><![CDATA[Just recently I seem to have noticed an increased number of mysterious crashes and terminations of applications. This is generally on brand new systems that I&#8217;m setting up, or on existing systems where I&#8217;m setting up a new or duplicate account. 
Initially everything is fine, but then all of a sudden as I start syncing [...]]]></description>
			<content:encoded><![CDATA[<p>Just recently I seem to have noticed an increased number of mysterious crashes and terminations of applications. This is generally on brand new systems that I&#8217;m setting up, or on existing systems where I&#8217;m setting up a new or duplicate account. </p>
<p>Initially everything is fine, but then all of a sudden as I start syncing over my files, shell profile and so on applications will stop working. I&#8217;ve experienced it in MySQL, and more recently when starting up Gnome on Solaris 10 9/07. </p>
<p>Sometimes the problem is obvious, other times it takes me a while to realize what is happening and causing the problem. But in all cases it&#8217;s the same problem &#8211; my <code>TMPDIR environment variable points to a directory that doesn't exist. That's because for historical reasons (mostly related to HP-UX, bad permissions and global tmp directories) I've always set TMPDIR to a directory within my home directory. It's just a one of those things I've had in my bash profile for as long as I can remember. Probably 12 years or more at least. </p>
<p>This can be counterproductive on some systems - on Solaris for example the main </code><code>/tmp</code> directory is actually mounted on the swap space, which means that RAM will be used if it&#8217;s available, which can make a big difference during compilation. </p>
<p>But any setting is counterproductive if you point to a directory that doesn&#8217;t exist and then have an application that tries to create a temporary file, fails, and then never prints out a useful trace of why it had a problem (yes, I mean you Gnome!). </p>
<p>I&#8217;ve just reset my <code>TMPDIR</code> in <code>.bash_vars</code> to read: </p>
<blockquote><p>
<code>case $OSTYPE in<br />
    (solaris*) export set TMPDIR=/tmp/mc;mkdir -m 0700 -p $TMPDIR<br />
    ;;<br />
    (*) export set TMPDIR=~/tmp;mkdir -m 0700 -p $TMPDIR<br />
    ;;<br />
esac</code></p></blockquote>
<p>Now I explicitly create a directory in a suitable location during startup, so I shouldn&#8217;t experience those crashes anymore. </p>
]]></content:encoded>
			<wfw:commentRss>http://coalface.mcslp.com/2007/11/07/mysterious-crashes-check-your-temporary-directory-settings/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Brian is having the same issues</title>
		<link>http://coalface.mcslp.com/2007/08/10/brian-is-having-the-same-issues/</link>
		<comments>http://coalface.mcslp.com/2007/08/10/brian-is-having-the-same-issues/#comments</comments>
		<pubDate>Fri, 10 Aug 2007 11:07:24 +0000</pubDate>
		<dc:creator>Martin MC Brown</dc:creator>
				<category><![CDATA[Commentary]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Solaris]]></category>

		<guid isPermaLink="false">http://coalface.mcslp.com/?p=54</guid>
		<description><![CDATA[I mentioned the problem with setting up the stack on a new Solaris box yesterday and then realized this morning that I&#8217;d already added Brian Aker&#8217;s blog posting on the same issues to my queue (Solaris, HOW-TO, It works&#8230; Really&#8230;). 
Brian mentions pkg-get, the download solution from Blastwave which I neglected to mention yesterday. It [...]]]></description>
			<content:encoded><![CDATA[<p>I mentioned the problem with setting up the stack on a new Solaris box <a href="http://coalface.mcslp.com/?p=53">yesterday</a> and then realized this morning that I&#8217;d already added Brian Aker&#8217;s blog posting on the same issues to my queue (<a href="http://krow.livejournal.com/541082.html">Solaris, HOW-TO, It works&#8230; Really&#8230;</a>). </p>
<p>Brian mentions <code>pkg-get</code>, the download solution from <a href="http://blastware.org">Blastwave</a> which I neglected to mention yesterday. It certainly makes the downloading and installation easier, but its&#8217;s far from comprehensive and some of the stuff is out of date. </p>
<p>To be honest I find that I install the stuff from Sun Freeware to get me going, then spend time recompiling everything myself by hand, for the plain and simple reason that I then know it is up to date and/or working or both. This is particularly the case for Perl, which often needs an update of the entire perl binary to get the updated versions of some CPAN modules. </p>
<p>Ultimately, though, it sucks. </p>
]]></content:encoded>
			<wfw:commentRss>http://coalface.mcslp.com/2007/08/10/brian-is-having-the-same-issues/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Setting up the developer stack issues</title>
		<link>http://coalface.mcslp.com/2007/08/09/setting-up-the-developer-stack-issues/</link>
		<comments>http://coalface.mcslp.com/2007/08/09/setting-up-the-developer-stack-issues/#comments</comments>
		<pubDate>Thu, 09 Aug 2007 12:41:20 +0000</pubDate>
		<dc:creator>Martin MC Brown</dc:creator>
				<category><![CDATA[Commentary]]></category>
		<category><![CDATA[FOSS]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Solaris]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://coalface.mcslp.com/?p=53</guid>
		<description><![CDATA[There&#8217;s a great post on Coding Horror about Configuring the Stack.
Basically the gripe is with the complexity of installing the typical developer stack, in this case on Windows, using Visual Studio. My VS setup isn&#8217;t vastly different to the one Jeff mentions, and I have similar issues with the other stacks I use. 
I&#8217;ve just [...]]]></description>
			<content:encoded><![CDATA[<p>There&#8217;s a great post on <a href="http://www.codinghorror.com">Coding Horror</a> about <a href="http://www.codinghorror.com/blog/archives/000925.html">Configuring the Stack</a>.</p>
<p>Basically the gripe is with the complexity of installing the typical developer stack, in this case on Windows, using Visual Studio. My VS setup isn&#8217;t vastly different to the one Jeff mentions, and I have similar issues with the other stacks I use. </p>
<p>I&#8217;ve just set up the Ultra3 mobile workstation again for building MySQL and other stuff on, and it took about 30 packages (from <a href="http://sunfreeware.com">Sun Freeware</a>) just to get the basics like gcc, binutils, gdb, flex, bison and the rest set up. It took the best part of a day to get everything downloaded, installed, and configured. I haven&#8217;t even started on modules for Perl yet. </p>
<p>The Eclipse stack is no better. On Windows you&#8217;ll need the JDK of your choice, plus Eclipse. Then you&#8217;ll have to update Eclipse. Then add in the plugins and modules you want. Even though some of that is automated (and, annoyingly some of it is not although it could be), it generally takes me a few hours to get stuff installed. </p>
<p>Admittedly on my Linux boxes it&#8217;s easier &#8211; I use Gentoo and copy around a suitable make.conf with everything I need in it, so I need only run <b>emerge</b>, but that can still take a day or so to get everything compiled.</p>
<p>Although I&#8217;m sure we can all think of easier ways to create the base systems &#8211; I use Parallels for example and copy VM folders to create new environments for development &#8211; even the updating can take a considerable amount of time. </p>
<p>I suggest the new killer app is one that makes the whole process easier. </p>
]]></content:encoded>
			<wfw:commentRss>http://coalface.mcslp.com/2007/08/09/setting-up-the-developer-stack-issues/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Setting a remote key through ssh</title>
		<link>http://coalface.mcslp.com/2007/04/20/setting-a-remote-key-through-ssh/</link>
		<comments>http://coalface.mcslp.com/2007/04/20/setting-a-remote-key-through-ssh/#comments</comments>
		<pubDate>Fri, 20 Apr 2007 08:39:52 +0000</pubDate>
		<dc:creator>Martin MC Brown</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Solaris]]></category>
		<category><![CDATA[Unix]]></category>

		<guid isPermaLink="false">http://coalface.mcslp.com/?p=46</guid>
		<description><![CDATA[One of the steps I find myself doing a lot is distributing round an ssh key so that I can login and use different machines automatically. To help in that process I created a small function in my bash profile script (acutally for me it&#8217;s in .bash_aliases):
function setremotekey
{
    OLDDIR=`pwd`
    [...]]]></description>
			<content:encoded><![CDATA[<p>One of the steps I find myself doing a lot is distributing round an ssh key so that I can login and use different machines automatically. To help in that process I created a small function in my bash profile script (acutally for me it&#8217;s in <code>.bash_aliases</code>):</p>
<blockquote><p><code>function setremotekey<br />
{<br />
    OLDDIR=`pwd`<br />
    if [ -z "$1" ]<br />
    then<br />
        echo Need user@host info<br />
    fi<br />
    cd $HOME<br />
    if [ -e "./.ssh/id_rsa.pub" ]<br />
    then<br />
        cat ./.ssh/id_rsa.pub |ssh $1 'mkdir -p -m 0700 .ssh &#038;&#038; cat >> .ssh/authorized_keys'<br />
    else<br />
        ssh-keygen -t rsa<br />
        cat ./.ssh/id_rsa.pub |ssh $1 'mkdir -p -m 0700 .ssh &#038;&#038; cat >> .ssh/authorized_keys'<br />
    fi<br />
    cd $OLDDIR<br />
}</code></p></blockquote>
<p>To use, whenever I want to copy my public key to a remote machine I just have to specify the login and machine: </p>
<blockquote><p><code>$ setremotekey mc@narcissus</code></p></blockquote>
<p>Then type in my password once, and the the function does the rest. </p>
<p>How? Well it checks to make sure I&#8217;ve entered a user/host (or actually just a string of some kind). Then, if I haven&#8217;t created a public key before (which I might not have on a new machine), I run the ssh-keygen to create it. Once the key is in place, I output the key text and then use ssh to pipe append that to the remote <code>authorized_keys</code> file, creating the directory along the way if it doesn&#8217;t exist. </p>
<p>Short and sweet, but saves me a lot of time. </p>
]]></content:encoded>
			<wfw:commentRss>http://coalface.mcslp.com/2007/04/20/setting-a-remote-key-through-ssh/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Extra bash improvements</title>
		<link>http://coalface.mcslp.com/2007/02/03/extra-bash-improvements/</link>
		<comments>http://coalface.mcslp.com/2007/02/03/extra-bash-improvements/#comments</comments>
		<pubDate>Sat, 03 Feb 2007 08:54:25 +0000</pubDate>
		<dc:creator>Martin MC Brown</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Unix]]></category>

		<guid isPermaLink="false">http://coalface.mcslp.com/?p=43</guid>
		<description><![CDATA[If you&#8217;ve read my Getting the most out of bash article at IBM developerWorks then you be interested in some further bash goodness and improvements. 
Juliet Kemp covers some additional tricks on Improving bash to make working with bash easier. Some of the stuff there I have already covered, but the completion extensions might be [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;ve read my <a href="http://mcslp.com/?p=241">Getting the most out of bash</a> article at IBM developerWorks then you be interested in some further bash goodness and improvements. </p>
<p>Juliet Kemp covers some additional tricks on <a href="http://www.oreillynet.com/linux/blog/2007/02/improving_bash.html?CMP=OTC-0O724Z062301&#038;ATT=Improving+bash">Improving bash</a> to make working with bash easier. Some of the stuff there I have already covered, but the completion extensions might be useful if you like to optimize your typing. </p>
<p>Even better, one of the comments provides the hooks to change your prompt to include your current CVS branch, another to include your current platform, and a really cool way of simplifying your history searching. </p>
]]></content:encoded>
			<wfw:commentRss>http://coalface.mcslp.com/2007/02/03/extra-bash-improvements/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Controlling OS X volume through Cron</title>
		<link>http://coalface.mcslp.com/2007/01/05/controlling-os-x-volume-through-cron/</link>
		<comments>http://coalface.mcslp.com/2007/01/05/controlling-os-x-volume-through-cron/#comments</comments>
		<pubDate>Fri, 05 Jan 2007 06:30:33 +0000</pubDate>
		<dc:creator>Martin MC Brown</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://coalface.mcslp.com/?p=40</guid>
		<description><![CDATA[One of the biggest annoyances of working from home is that with the computers in the room next door, the volume of your computers can cause a problem if someone suddenly calls you on Skype, or your backup software suddenly kicks in and starts beeping. 
I never remember to mute the volume, so I started [...]]]></description>
			<content:encoded><![CDATA[<p>One of the biggest annoyances of working from home is that with the computers in the room next door, the volume of your computers can cause a problem if someone suddenly calls you on Skype, or your backup software suddenly kicks in and starts beeping. </p>
<p>I <i>never</i> remember to mute the volume, so I started looking for a way to this automatically through cron at specific times. I also wanted to be sure that rather than setting a specific volume (and having to remember it), that I could just use the OS X mute function. </p>
<p>The solution is to combine Applescript, which you can run from the command line using the osascript command, with the command line limitations of cron. </p>
<p>There are three components, the two Applescripts that mute and unmute the volume, and the lines in a crontab to run the scripts. </p>
<p>To mute the volume with Applescript: </p>
<blockquote><pre>set volume with output muted</pre>
</blockquote>
<p>To unmute: </p>
<blockquote><pre>set volume without output muted</pre>
</blockquote>
<p>Save both these into Applescripts (use the Applescript editor so they are compiled). </p>
<p>Then we can just set the scripts to execute when required: </p>
<blockquote><pre>0 9 * * * osascript /usr/local/mcslp/volume-unmute.scpt
0 19 * * * osascript /usr/local/mcslp/volume-mute.scpt</pre>
</blockquote>
<p>I&#8217;ve set this on the three machines and now we get a silent night!</p>
]]></content:encoded>
			<wfw:commentRss>http://coalface.mcslp.com/2007/01/05/controlling-os-x-volume-through-cron/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Making a single extractor</title>
		<link>http://coalface.mcslp.com/2006/09/04/making-a-single-extractor/</link>
		<comments>http://coalface.mcslp.com/2006/09/04/making-a-single-extractor/#comments</comments>
		<pubDate>Mon, 04 Sep 2006 10:52:48 +0000</pubDate>
		<dc:creator>Martin MC Brown</dc:creator>
				<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Unix]]></category>

		<guid isPermaLink="false">http://coalface.mcslp.com/?p=31</guid>
		<description><![CDATA[One of my new articles is on smplifying your command line, making your life easier as you move between different environments. The same principles can be applied just to make your life easier. ]]></description>
			<content:encoded><![CDATA[<p>One of my new articles is on smplifying your command line (read more about <a href="http://mcslp.com/?p=229">System Administrators Toolkit: Standardizing your UNIX command-line tools</a>, making your life easier as you move between different environments. The same principles can be applied just to make your life easier.  Here&#8217;s a function I&#8217;ve had in my bash init script for years that gets round the issue of extracting a compressed archive file of various types, even if your tar isn&#8217;t aware of the compression type: </p>
<blockquote><pre>function uz ()
{
    file=$1
    case $file in
        (*gz)  gunzip -c $file|tar xf -;;
        (*bz2) bunzip2 -c $file|tar xf -;;
        (*Z) tar zxf $file;;
        (*zip) unzip $file;;
    esac
}
</pre>
</blockquote>
<p>Now I can extract any file with: </p>
<blockquote><pre>$ uz file{gz|bz2|zip|Z)</pre>
</blockquote>
<p>And not worry that my Solaris tar isn&#8217;t bzip2 aware even though it is Gzip aware. </p>
]]></content:encoded>
			<wfw:commentRss>http://coalface.mcslp.com/2006/09/04/making-a-single-extractor/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Copying multiple files with scp</title>
		<link>http://coalface.mcslp.com/2006/07/21/copying-multiple-files-with-scp/</link>
		<comments>http://coalface.mcslp.com/2006/07/21/copying-multiple-files-with-scp/#comments</comments>
		<pubDate>Fri, 21 Jul 2006 09:16:24 +0000</pubDate>
		<dc:creator>Martin MC Brown</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Unix]]></category>

		<guid isPermaLink="false">http://coalface.mcslp.com/?p=25</guid>
		<description><![CDATA[A quick tip on how best to copy multiple files from the same location.]]></description>
			<content:encoded><![CDATA[<p>I keep my .bash init scripts on one machine and copy them over to each machine on which I have a login. There&#8217;s various bits of logic in there to ensure that the right PATH and other values are set according to the host and/or platform. </p>
<p>I then have a simple line that updates the .ocal .bash scripts from the main box that holds the main copies, so that I can just run:</p>
<blockquote><pre>update-bash</pre>
</blockquote>
<p>To update everything. I use scp and, depending on the system, use a preset key or require a password.</p>
<p>For copying multiple files there are many solutions; I could just use <i>.bash*</i>, but I&#8217;d also get the history and backup files. The typical advice is separate entries: </p>
<blockquote><pre>scp mc@narcissus:.bashrc mc@narcissus:.bash_aliases</pre>
</blockquote>
<p>This is less than optimal for a number of reasons &#8211; the first is that each location is treated individually, and that requires multiple connections and multiple password requirements. You can, though, use normal shell like expansion, just make sure you use quotes to ensure that it isn&#8217;t parsed and expanded by the local shell instead of the remote one: </p>
<blockquote><pre>scp mc@narcissus:".bash{rc,_path,_aliases,_vars}" ~</pre>
</blockquote>
]]></content:encoded>
			<wfw:commentRss>http://coalface.mcslp.com/2006/07/21/copying-multiple-files-with-scp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Stepped execution with cron and at</title>
		<link>http://coalface.mcslp.com/2006/07/10/stepped-execution-with-cron-and-at/</link>
		<comments>http://coalface.mcslp.com/2006/07/10/stepped-execution-with-cron-and-at/#comments</comments>
		<pubDate>Mon, 10 Jul 2006 15:53:03 +0000</pubDate>
		<dc:creator>Martin MC Brown</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Solaris]]></category>
		<category><![CDATA[Unix]]></category>

		<guid isPermaLink="false">http://coalface.mcslp.com/?p=22</guid>
		<description><![CDATA[I had a query from a reader today as a follow up to my System Administrators Toolkit: Time and event management article at developerWorks:
How do I execute a script at a specific interval, for example 28 days, rather than on a specific day or date?
It is the one limitation of cron that it doesn&#8217;t support [...]]]></description>
			<content:encoded><![CDATA[<p>I had a query from a reader today as a follow up to my <a href="http://mcslp.com/?p=213">System Administrators Toolkit: Time and event management</a> article at developerWorks:</p>
<blockquote><p>How do I execute a script at a specific interval, for example 28 days, rather than on a specific day or date?</p></blockquote>
<p>It is the one limitation of cron that it doesn&#8217;t support such an interval, although there are some systems (including many Linux installations) that provide an alternative method. There are some solutions to the problem that will work on any platform that uses the cron/at system.</p>
<p>One way is to run the script every 7 days, and have it record how many times it&#8217;s been called in a file. </p>
<p>All you have to do is, in the script, load the current count, work out if this is the fourth time, and run the script accordingly. </p>
<p>For example: </p>
<p><code>count=`cat counter`<br />
count=`expr $count + 1`</p>
<p>if [ $count -eq 4 ]<br />
then<br />
    echo 0 &gt;counter<br />
    echo 4th time called, going for it<br />
    # Do everything else<br />
else<br />
    echo $count &gt;counter<br />
fi</code></p>
<p>I suggest you put the counter file into a usable location, but you get the idea.</p>
<p>The other alternative is to use at, rather than cron, and then add a line in the script to execute the script again in 28 days time. For example, using this line at the end of your script: </p>
<p><code>at 9pm + 28 days &lt;myscript .sh</code></p>
<p>Because you are specifying the same time, but a different day, this will execute at the same time every 28 days. </p>
<p>If your script takes a long time to process and you run it, for example, at 23:59, put the &#8216;at&#8217; line at the start of the script, rather than the end, so that the request gets registered on the same day. </p>
]]></content:encoded>
			<wfw:commentRss>http://coalface.mcslp.com/2006/07/10/stepped-execution-with-cron-and-at/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Building an RPN to Equation Parser</title>
		<link>http://coalface.mcslp.com/2006/04/17/building-an-rpn-to-equation-parser/</link>
		<comments>http://coalface.mcslp.com/2006/04/17/building-an-rpn-to-equation-parser/#comments</comments>
		<pubDate>Mon, 17 Apr 2006 21:54:44 +0000</pubDate>
		<dc:creator>Martin MC Brown</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://coalface.mcslp.com/?p=9</guid>
		<description><![CDATA[In the final part of the examination of lex and yacc, here are the rules for building a parser that translates RPN input into standard equations.]]></description>
			<content:encoded><![CDATA[<p>In the final part of the examination of <a href="http://coalface.mcslp.com/?p=6">lex and yacc</a>, here are the rules for building a parser that translates RPN into equation input (the reverse of the <a href="http://coalface.mcslp.com/?p=8">Equation to RPN parser</a>.</p>
<p>Translating RPN into standard equation format is a lot more difficult. Although the fundamentals are similar to the <a href="http://coalface.mcslp.com/?p=6">RPN</a> parser (we still use a stack for values that are popped off when we see an operand), it is the recording of that process is much more difficult. </p>
<p>In the RPN calculator, we can place the result of the calculation back onto the stack so that the value can be used. To resolve something into the equation format we need to record the equivalent expression, not the value. For that, we use a temporary string, and then check if the temporary string has a value and append further expressions to that string. </p>
<p>Also, to help precedence in the final calculation (a process handled automatically by the sequence of numbers an operands in RPN) we also enclose each stage of the calculation in parentheses. </p>
<p>The resulting rules are shown below. Note that for the example, only the basic operands (+ &#8211; * /) are supported, but the principles are valid for any combination. </p>
<pre>%%
list:   /* nothing */
        | list EOLN
        | list expr EOLN        { printf( "%s\n",exprstring); }
        ;
expr:   primary
        | expr primary MUL
          {
            if (strlen(exprstring) > 0)
              {
                sprintf(tmpstring,"(%s * %g)",exprstring, pop());
              }
            else
              {
                sprintf(tmpstring,"( %g * %g )",pop(),pop());
              }
            strcpy(exprstring,tmpstring);
          }
        | expr primary DIV
          {
            temp=pop();
            if (strlen(exprstring) > 0)
              {
                sprintf(tmpstring,"(%s / %g)",exprstring, temp);
              }
            else
              {
                sprintf(tmpstring,"( %g / %g )",pop(),temp);
              }
            strcpy(exprstring,tmpstring);
          }
        | expr primary PLUS
          {
            if (strlen(exprstring) > 0)
              {
                sprintf(tmpstring,"(%s + %g)",exprstring, pop());
              }
            else
              {
                sprintf(tmpstring,"( %g + %g )",pop(),pop());
              }
            strcpy(exprstring,tmpstring);
          }
        | expr primary MINUS
          {
            temp=pop();
            if (strlen(exprstring) > 0)
              {
                sprintf(tmpstring,"(%s - %g)",exprstring, temp);
              }
            else
              {
                sprintf(tmpstring,"( %g - %g )",pop(),temp);
              }
            strcpy(exprstring,tmpstring);
          }
        ;
primary: NUMBER { push($1); }
        ;
%%</pre>
<p>You can see the resulting output below: </p>
<pre>4 5 + 6 *
(( 4 + 5 ) * 6)</pre>
<p>As mentioned in the original IBM article, we can pipe sequences together to show the parsing and calculation of an expression from different formats. For example: </p>
<pre>$ rpntoequ|calc
4 5 + 6 *
54</pre>
<p>And even rpntoequ and equtorpn:</p>
<pre>$ rpntoequ|equtorpn
4 5 + 6 *
4 5 + 6 *</pre>
<p>The current RPN translator as shown here is not as advanced as the main RPN system, and so it doesn&#8217;t support all the options, or expression formats, but you can get the general idea. </p>
<p>You can download the code for this example: <a href="http://coalface.mcslp.com/downloads/rpntoequ.tar.gz">rpntoequ.tar.gz (Unix)</a>. </p>
]]></content:encoded>
			<wfw:commentRss>http://coalface.mcslp.com/2006/04/17/building-an-rpn-to-equation-parser/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Building an Equation to RPN Parser</title>
		<link>http://coalface.mcslp.com/2006/04/17/building-an-equation-to-rpn-parser/</link>
		<comments>http://coalface.mcslp.com/2006/04/17/building-an-equation-to-rpn-parser/#comments</comments>
		<pubDate>Mon, 17 Apr 2006 21:21:59 +0000</pubDate>
		<dc:creator>Martin MC Brown</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://coalface.mcslp.com/?p=8</guid>
		<description><![CDATA[As part of the continuing examination of lex and yacc, here are the rules for building a parser that translates equations into RPN format.]]></description>
			<content:encoded><![CDATA[<p>As part of the continuing examination of <a href="http://coalface.mcslp.com/?p=6">lex and yacc</a>, here are the rules for building a parser that translates equations into RPN format.</p>
<p>The process is actually very simple. Because of the way the parser works, all you have to do is print out whatever component we see at each stage. For example, when you see a number, print it out, and when you see a operand, also print it out. The basic ruleset is shown below: </p>
<pre>%%
list:   /* nothing */
        | list EOLN
        | list expr EOLN        { printf( "\n" ); }
        ;
expr:   shift_expr
        ;
shift_expr: pow_expr
        | shift_expr LEFTSHIFT pow_expr { printf("< < "); }
        | shift_expr RIGHTSHIFT pow_expr { printf(">> "); }
        ;
pow_expr: add_expr
        | pow_expr POW add_expr { printf("^ "); }
        ;
add_expr: mul_expr
        | add_expr PLUS mul_expr  { printf("+ "); }
        | add_expr MINUS mul_expr { printf("- "); }
        ;
mul_expr: unary_expr
        | mul_expr MUL unary_expr { printf("* "); }
        | mul_expr DIV unary_expr { printf("/ "); }
        | mul_expr MOD unary_expr { printf("% "); }
        ;
unary_expr: postfix_expr
        | MINUS primary %prec UNARYMINUS { printf("-"); }
        | INC unary_expr { printf("++ "); }
        | DEC unary_expr { printf("-- "); }
        ;
postfix_expr: primary
        | postfix_expr INC { printf("++ "); }
        | postfix_expr DEC { printf("-- "); }
        | postfix_expr FACT { printf("! "); }
        ;
 primary: NUMBER { printf("%g ",$1); }
        | PI { printf("%g ", M_PI); }
        | OPENBRACKET expr CLOSEBRACKET { }
        | function_call
        ;
function_call: SIN OPENBRACKET expr CLOSEBRACKET { printf("sin "); }
        | COS OPENBRACKET expr CLOSEBRACKET { printf("cos "); }
        | TAN OPENBRACKET expr CLOSEBRACKET { printf("tan "); }
        | ASIN OPENBRACKET expr CLOSEBRACKET { printf("asin "); }
        | ACOS OPENBRACKET expr CLOSEBRACKET { printf("acos "); }
        | ATAN OPENBRACKET expr CLOSEBRACKET { printf("atan "); }
        ;
%%</pre>
<p>Why does it work? </p>
<p>It has to do with the parser evaluates the different components. When, for example, the parser identifies an addition with this rule: </p>
<pre>add_expr: mul_expr
        | add_expr PLUS mul_expr  { printf("+ "); }</pre>
<p>The code that the parser generates evaluates the sub-rules first, and in both cases the rules will ultimately lead to the numerical value. Each time the number is seen, the value is printed. Once both rules have been resolved, it then matches the full expression and outputs the plus sign. </p>
<p>In use, the parser generates all of the necessary RPN: </p>
<pre>4+5*6
4 5 6 * +
(4+5)*6
4 5 + 6 * </pre>
<p>You can download the source for the equation to RPN parser: <a href="http://coalface.mcslp.com/downloads/equtorpn.tar.gz">equtorpn.tar.gz (Unix)</a></p>
]]></content:encoded>
			<wfw:commentRss>http://coalface.mcslp.com/2006/04/17/building-an-equation-to-rpn-parser/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
