<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
    <channel>
        <title>Ramblings of a web guy (Tag: mysql)</title>
        <description>Brian Moon, of dealnews.com, shares what he knows (and learns) about PHP, MySQL and other stuff</description>
        <link>http://brian.moonspot.net/feed.php?type=rss&amp;amp;tag=mysql</link>
        <lastBuildDate>Tue, 07 Sep 2010 21:08:20 -0500</lastBuildDate>
        <generator>Wordcraft 0.10</generator>
        <item>
            <guid>http://brian.moonspot.net/php-5-3-mysqlnd</guid>
            <title>PHP 5.3 and mysqlnd - Unexpected results</title>
            <link>http://brian.moonspot.net/php-5-3-mysqlnd</link>
            <description><![CDATA[I have started seriously using PHP 5.3 recently due to it finally making it into <a>Portage</a>. (Gentoo really isn't full of bleeding edge packages people.) I have used mysqlnd a little here and there in the past, but until it was really coming to my servers I did not put too much time into it.<br><br><strong>What is mysqlnd?</strong><br><br>mysqlnd is short for MySQL Native Driver. In short, it is a driver for MySQL for PHP that uses internal functions of the PHP engine rather than using the externally linked libmysqlclient that has been used in the past. There are two reasons for this. The first reason is licensing. MySQL is a GPL project. The GPL and the PHP License don't play well together. The second is better memory management and hopefully more performance. Being a performance junky, this is what peaked my interests. Enabling mysqlnd means it is used by the older MySQL extension, the newer MySQLi extension and the MySQL PDO driver.<br><br><strong>New Key Feature - fetch_all</strong><br><br>One new feature of mysqlnd was the fetch_all method on MySQLi Result objects. At both <a href="http://dealnews.com/">dealnews.com</a> and in <a href="http://www.phorum.org/">Phorum</a> I have written a function to simply run a query and fetch all the results into an array and return it. It is a common operation when writing API or ORM layers. mysqlnd introduces a native fetch_all method that does this all in the extension. No PHP code needed. PDO already offers a fetchAll method, but PDO comes with a little more overhead than the native extensions and I have been using mysql functions for 14 years. I am very happy using them.<br><br><strong>Store Result vs. Use Result</strong><br><br>I have spoken in the past (see my slides and interview: <a>MySQL Tips and Tricks</a>) about using mysql_unbuffered_query or using mysqli_query with the MYSQLI_USE_RESULT flag. Without going into a whole post about that topic, it basically allows you to stream the results from MySQL back into your PHP code rather than having them buffered in memory. In the case of libmysqlclient, they could be buffered twice. So, my natural thought was that using MYSQLI_USE_RESULT with fetch_all would yield the most awesome performance ever. The data would not be buffered and it would get put into a PHP array in C instead of native code. The code I had hoped to use would look like:<pre>$res = $db-&gt;query($sql, MYSQLI_USE_RESULT);<br>$rows = $res-&gt;fetch_all(MYSQLI_ASSOC);<br></pre>
But, I quickly found out that this does not work. For some reason, this is not supported. fetch_all only works with the default which is MYSQLI_STORE_RESULT. I filed a bug which was marked bogus. Which I put back to new because I really don't see a reason this should not work other than a complete oversight by the mysqlnd developers. So, I started doing some tests in hopes I could show the developers how much faster using MYSQLI_USE_RESULT could be. What happened next was not expected. I ended up benchmarking several different options for fetching all the rows of a result into an array.<br><br><strong>Test Data</strong><br><br>I tested using PHP 5.3.3 and MySQL 5.1.44 using InnoDB tables. For test data I made a table that has one varchar(255) column. I filled that table with 30k rows of random lengths between 10 and 255 characters. I then selected all rows and fetched them using 4 different methods.<span class="methodname"></span><span style="font-weight: bold;"></span><br><ol><li><a href="http://us.php.net/manual/en/mysqli-result.fetch-all.php">mysqli_result::fetch_all*</a></li><li><a href="http://us.php.net/manual/en/pdostatement.fetchall.php">PDOStatement::fetchAll</a></li><li><a href="http://us.php.net/manual/en/mysqli.query.php">mysqli_query with MYSQLI_STORE_RESULT followed by a loop</a></li><li><a href="http://us.php.net/manual/en/mysqli.query.php">mysqli_query with MYSQLI_USE_RESULT followed by a loop</a></li></ol></li>In addition, I ran this test with mysqlnd enabled and disabled. For mysqli_result::fetch_all, only mysqlnd was tested as it is only available with mysqlnd. I ran each test 6 times and threw out the worst and best result for each test. FWIW, the best and worst did not show any major deviation for any of the tests. For measuring memory usage, I read the VmRSS value from Linux's /proc data. memory_get_usage() does not show the hidden memory used by libmysqlclient and does not seem to show all the memory used by mysqlnd either.<br><br><img  alt="" style="width: 574px;" src="http://content.screencast.com/users/brianlmoon/folders/Jing/media/18ecdea6-1a2c-4b9b-b267-b7676effdcb1/00000117.png"><br><br>So, that is what I found. The memory usage graphs are all what I thought they would be. PDO has more overhead by its nature. Storing the result always uses more memory than using it. mysqli_result::fetch_all uses less memory than the loop, but more than directly using the results. <br><br>There are some very surprising things in the timing graphs however. First, the tried and true method of using the result followed by a loop is clearly still the right choice in libmysqlclient. However, it is a horrible choice for mysqlnd. I don't really see why this is so. It is nearly twice as slow. There is something really, really wrong with MYSQLI_USE_RESULT in mysqlnd. There is no reason it should ever be slower than storing the result and then reading it again. This is also evidenced in the poor performance of PDO (since even PDO uses mysqlnd when enabled). PDO uses an unbuffered query for its fetchAll method and it too got slower. It is noticably slower than libmysqlclient. The good news I guess is that if you are using mysqlnd, the fetch_all method is the best option for getting all the data back. <br><br><strong>Next Steps</strong><br><br>My next steps from here will be to find some real workloads that I can test this on. Phorum has several places where I can apply real world pages loads to these different methods and see how they perform. Perhaps the test data is too small. Perhaps the number of columns would have a different effect. I am not sure.<br><br>If you are reading this and have worked on or looked at the mysqlnd code and can explain any of it, please feel free to comment.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Tue, 03 Aug 2010 08:00:00 -0500</pubDate>
            <category>mysql</category>
            <category>php</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/understanding-mysql-indexes</guid>
            <title>Want to understand MySQL indexes?</title>
            <link>http://brian.moonspot.net/understanding-mysql-indexes</link>
            <description><![CDATA[I have introduced some new people to MySQL recently and had to back track the years to figure out how I learned what I learned about MySQL indexes.&nbsp; A quick way to get up to speed about MySQL indexes is these three podcasts by <a href="http://www.sheeri.com/">Sheeri Cabral</a>.<br><ol><li><a href="http://www.technocation.org/content/oursql-episode-13%3A-nitty-gritty-indexes">OurSQL Episode 13: The Nitty Gritty of Indexes</a></li><li><a href="http://www.technocation.org/content/oursql-episode-17%3A-hashing-it-out-0">OurSQL Episode 17: Hashing it out</a></li><li><a href="http://www.technocation.org/content/oursql-episode-18%3A-de-myth-tifying-indexes-0">OurSQL Episode 18: De-myth-tifying Indexes</a></li></ol></li>Those three episodes do a good job of explaining how indexes work so that you have a better understanding of how MySQL indexes find your data.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Tue, 15 Jun 2010 17:14:40 -0500</pubDate>
            <category>mysql</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/mysql-conference-review</guid>
            <title>MySQL Conference Review</title>
            <link>http://brian.moonspot.net/mysql-conference-review</link>
            <description><![CDATA[I am back home from a good week at the 2010 O'Reilly MySQL Conference &amp; Expo. I had a great time and got to see some old friends I had not seen in a while.<br><br>Oracle gave the opening keynote and it went pretty much like I thought it would. Oracle said they will keep MySQL alive. They talked about the new 5.5 release. It was pretty much the same keynote Sun gave last year. Time will tell what Oracle does with MySQL.<br><br>The expo hall was sparse. Really sparse. There were a fraction of the booths compared to the past. I don't know why the vendors did not come. Maybe because they don't want to compete with Oracle/Sun? In the past you would see HP or Intel have a booth at the conference. But, with Oracle/Sun owning MySQL, why even try. Or maybe they are not allowed? I don't know. It was just sad.<br><br>I did stop by the <a href="http://www.maatkit.org/">Maatkit</a> booth and was embarrassed to tell <a href="http://www.xaprb.com/">Baron</a> (its creator) I was not already using it. I had heard people talk about it in the past, but never stopped to see what it does. It would have only saved me hours and hours of work over the last few years. Needless to say it is now being installed on our servers. If you use MySQL, just go install Maatkit now and start using it. Don't be like me. Don't wait for years, writing the same code over and over to do simple maintenance tasks.<br><br><a href="http://gearman.org/">Gearman</a> had a good deal of coverage at the conference. There were three talks and a <a href="http://en.wikipedia.org/wiki/Birds_of_a_Feather_%28computing%29">BoF</a>. All were well attended. Some people seemed to have an AHA! moment where they saw how Gearman could help their architecture. I also got to sit down with the PECL/gearman maintainers and discuss the recent bug I found that is keeping me from using it.<br><br>I spoke about <a href="http://memcached.org/">Memcached</a> as did others. Again, there was a BoF. It was well attended and people had good questions about it. There seemed to be some FUD going around that memcached is somehow inefficient or not keeping up with technology. However, I have yet to see numbers or anything that proves any of this. They are just wild claims by people that have something to sell. Everyone wants to be the caching company since there is no "Memcached, Inc.". There is no company in charge. That is a good thing, IMO.<br><br>That brings me to my favorite topic for the conference, Drizzle. I <a href="http://brian.moonspot.net/2008/07/24/156/">wrote about Drizzle</a> here on this blog when it was first announced. At the time MySQL looked like it was moving forward at a good pace. So, I had said that it would only replace MySQL in one part of our stack. However, after what, in my opinion, has been a lack of real change in MySQL, I think I may have changed my mind. Brian Aker echoed this sentiment in <a href="http://www.slideshare.net/brianaker/drizzle-keynote-at-the-mysql-users-conference">his keynote address about Drizzle</a>. He talked about how MySQL AB and later Sun had stopped focusing on the things that made MySQL popular and started trying to be a cheap version of Oracle. That is my interpretation of what he said, not his words. <br><br>Why is Drizzle different? Like Memcached and Gearman, there is no "Drizzle, Inc.". It is an Open Source project that is supported by the community. It is being supported by companies like <a href="http://www.rackspacecloud.com/blog/2010/03/13/rackspace-and-drizzle-its-time-to-rethink-everything/">Rackspace who hired five developers</a> to work on it. The code is kept on <a href="https://launchpad.net/drizzle">Launchpad</a> and is completely open. Anyone can create a branch and work on the code. If your patches are good, they will be merged into the main branch. But, you can keep your own branch going if you want to. Unlike the other forks, Drizzle has started over in both the code and the community. I personally see it as the only way forward. It is not ready today, but my money is on Drizzle five or ten years from now.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Sat, 17 Apr 2010 10:54:52 -0500</pubDate>
            <category>drizzle</category>
            <category>gearman</category>
            <category>memcached</category>
            <category>mysql</category>
            <category>php</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/logging-with-mysql</guid>
            <title>Logging with MySQL</title>
            <link>http://brian.moonspot.net/logging-with-mysql</link>
            <description><![CDATA[I was reading a post by <span class="post-author vcard"><span class="fn">Dathan Vance Pattishall titled "</span></span><a href="http://mysqldba.blogspot.com/2010/03/cassandra-is-my-nosql-solution-but.html">Cassandra is my NoSQL solution but..</a>". In the post, Dathan explains that he uses Cassandra to store clicks because it can write a lot faster than MySQL. However, he runs into problems with the read speed when he needs to get a range of data back from Cassandra. This is the number one problem I have with NoSQL solutions.<br><br>SQL is really good at retrieving a set of data based on a key or range of keys. Whereas NoSQL products are really good at writing things and retrieving one item from storage. When looking at redoing our architecture a few years ago to be more scalable, I had to consider these two issues. For what it is worth, the NoSQL market was not nearly as mature as it is now. So, my choices were much more limited. In the end, we decided to stick with MySQL. It turns out that a primary or unique key lookup on a MySQL/InnoDB table is really fast. It is sort of like having a key/value storage system. And, I can still do range based queries against it.<br><br>But, back to Dathan's problem: clicks. We store clicks at dealnews. Lots of clicks. We also store views. We store more views than we do clicks. So, lots of views and lots of clicks. (Sorry for the vague numbers, company secrets and all. We are a top <a href="http://siteanalytics.compete.com/dealnews.com/?metric=rank&months=12">1,000 Compete.com</a> site during peak shopping season.) And we do it all in MySQL. And we do it all with one server. I should disclose we are deploying a 
second server, but it is more for high availability than processing 
power. Like Dathan, we only use about the last 24 hours of data at any given time. There are three keys for us doing logging like this in MySQL.<br><br><strong>Use MyISAM<br><br></strong>MyISAM supports concurrent inserts. Concurrent inserts means that inserts can add rows to the end of a table while selects are being performed on other parts of the data set. This is exactly the use case for our logging. There are caveats with range queries as pointed out by the <a href="http://www.mysqlperformanceblog.com/2006/06/13/myisam-concurrent-insert/">MySQL Performance Blog</a>.<strong> <br><br>Rotating tables<br><br></strong>MySQL (and InnoDB in particular) really sucks at deleting rows. Like, really sucks. Deleting causes locks. Bleh. So, we never delete rows from our logging tables. Instead, nightly we rotate the tables. RENAME TABLE is an (near) atomic process in MySQL. So, we just create a new table.<br><pre>create table clicks_new like clicks;<br>rename table clicks to clicks_2010032500001, clicks_new to clicks;</pre>
<br>Tada! We now have an empty table for today's clicks. We now drop any table with a date stamp that is longer than x days old. Drops are fast, we like drops.<br><br>For querying these tables, we use UNION. It works really well. We just issue a SHOW TABLES LIKE 'clicks%' and union the query across all the tables. Works like a charm.<br><br><strong>Gearman</strong><br><br>So, I get a lot of flack at work for my outright lust for <a href="http://gearman.org/">Gearman</a>. It is my new <a href="http://en.wikipedia.org/wiki/Duct_tape#In_popular_culture">duct tape</a>. When you have a scalability problem, there is a good chance you can solve it with Gearman. So, how does this help with logging to MySQL? Well, sometimes, MySQL can become backed up with inserts. It happens to the best of us. So, instead of letting that pile up in our web requests, we let it pile up in Gearman. Instead of having our web scripts write to MySQL directly, we have them fire Gearman background jobs with the logging data in them. The Gearman workers can then write to the MySQL server when it is available. Under normal operating procedure, that is in near real time. But, if the MySQL server does get backed up, the jobs just queue up in Gearman and are processed when the MySQL server is available.<br><br><strong>BONUS! Insert Delayed</strong><br><br>This is our old trick before we used Gearman. MySQL (MyISAM) has a neat feature where you can have <a href="http://dev.mysql.com/doc/refman/5.1/en/insert-delayed.html">inserts delayed</a> until the table is available. The query is sent to the MySQL server and it answers with success immediately to the client. This means your web script can continue on and not get blocked waiting for the insert. But, MySQL will only queue up so many before it starts erroring out. So, it is not as fool proof as a job processing system like Gearman.<br><br><strong>Summary</strong><br><br>To log with MySQL:<br><ul><li>Use MyISAM with concurrent inserts</li><li>Rotate tables daily and use UNION to query</li><li>Use delayed inserts with MySQL or a job processing agent like Gearman</li></ul>Happy logging!<br><br>PS: You may be asking, "Brian, what about <a href="http://dev.mysql.com/doc/refman/5.1/en/partitioning.html">Partitioned Tables</a>?" I asked myself that before deploying this solution. More importantly, in IRC I asked <a href="http://krow.livejournal.com/">Brian Aker</a> about MySQL partitioned tables. I am paraphrasing, but he said that if I ever think I might alter that table, I would not trust it with the partitions in MySQL. So, that kind of turned me off of them.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Wed, 24 Mar 2010 00:20:12 -0500</pubDate>
            <category>gearman</category>
            <category>mysql</category>
            <category>php</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/using-ini-files-for-php-application-settings</guid>
            <title>Using ini files for PHP application settings</title>
            <link>http://brian.moonspot.net/using-ini-files-for-php-application-settings</link>
            <description><![CDATA[At dealnews we have three tiers of servers. First is our development servers, then staging and finally production. The complexity of the environment increases at each level. On a development server, everything runs on the localhost: mysql, memcached, etc. At the staging level, there is a dedicated MySQL server. In production, it gets quite wild with redundant services and two data centers.<br><br>One of the challenges of this is where and how to store the connection information for all these services. We have done several things in the past. The most common thing is to store this information in a PHP file. It may be per server or there could be one big file like:<br><br>

<code>

&lt;?php<br>

<br>

if(DEV){<br>

&nbsp;&nbsp;&nbsp;&nbsp;$server = "localhost";<br>

} else {<br>

&nbsp;&nbsp;&nbsp;&nbsp;$server = "10.1.1.25";<br>

}<br>

<br>

?&gt;

</code><br><br>This gets messy quickly. Option two is to deploy a single file that has the settings in a PHP array. And that is a good option. But, we have taken that one step further using some PHP ini trickeration. We use ini files that are loaded at PHP's startup and therefore the information is kept in PHP's memory at all times.<br><br>When compiling PHP, you can specify the --with-config-file-scan-dir to tell PHP to look in that directory for additional ini files. Any it finds will be parsed when PHP starts up. Some distros (Gentoo I know) use this for enabling/disabling PHP extensions via configuration. For our uses we put our custom configuration files in this directory. FWIW, you could just put the above settings into php.ini, but that is quite messy, IMO.<br><br>To get to this information, you can't use ini_get() as you might think.&nbsp; No, you have to use get_cfg_var() instead. get_cfg_var returns you the setting, in php.ini or any other .ini file when PHP was started. ini_get will only return values that are registered by an extension or the PHP core. Likewise, you can't use ini_set on these variables. Also, get_cfg_var will always reflect the initial value from the ini file and not anything changed with ini_set.<br><br>So, lets look at an example.<br><br>

<code>

;&nbsp;db.ini<br>

[myconfig]<br>

myconfig.db.mydb.db&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;mydb<br>

myconfig.db.mydb.user&nbsp;&nbsp;&nbsp;=&nbsp;user<br>

myconfig.db.mydb.pass&nbsp;&nbsp;&nbsp;=&nbsp;pass<br>

myconfig.db.mydb.server&nbsp;=&nbsp;host</code><br>



<br>This is our ini file. the group in the braces is just for looks. It has no impact on our usage. Because this is parsed along with the rest of our php.ini, it needs a unique namespace within the ini scope. That is what myconfig is for. We could have used a DSN style here, but it would have required more parsing in our PHP code.<br><br>



<code>



&lt;?php<br>

<br>

/**<br>

&nbsp;*&nbsp;Creates&nbsp;a&nbsp;MySQLi&nbsp;instance&nbsp;using&nbsp;the&nbsp;settings&nbsp;from&nbsp;ini&nbsp;files<br>

&nbsp;*<br>

&nbsp;*&nbsp;@author&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Brian&nbsp;Moon&nbsp;&lt;brianm@dealnews.com&gt;<br>

&nbsp;*&nbsp;@copyright&nbsp;&nbsp;1997-Present&nbsp;dealnews.com,&nbsp;Inc.<br>

&nbsp;*<br>

&nbsp;*/<br>

<br>

class&nbsp;MyDB&nbsp;{<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;/**<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Namespace&nbsp;for&nbsp;my&nbsp;settings&nbsp;in&nbsp;the&nbsp;ini&nbsp;file<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/<br>

&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;INI_NAMESPACE&nbsp;=&nbsp;"dealnews";<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;/**<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Creates&nbsp;a&nbsp;MySQLi&nbsp;instance&nbsp;using&nbsp;the&nbsp;settings&nbsp;from&nbsp;ini&nbsp;files<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;&nbsp;string&nbsp;&nbsp;$group&nbsp;&nbsp;The&nbsp;group&nbsp;of&nbsp;settings&nbsp;to&nbsp;load.<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;&nbsp;object<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/<br>

&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;init($group)&nbsp;{<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;$dbs&nbsp;=&nbsp;array();<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!is_string($group))&nbsp;{<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;Exception("Invalid&nbsp;group&nbsp;requested");<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(empty($dbs["group"])){<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$prefix&nbsp;=&nbsp;MyDB::INI_NAMESPACE.".db.$group";<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$db&nbsp;&nbsp;&nbsp;=&nbsp;get_cfg_var("$prefix.db");<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$host&nbsp;=&nbsp;get_cfg_var("$prefix.server");<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$user&nbsp;=&nbsp;get_cfg_var("$prefix.user");<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$pass&nbsp;=&nbsp;get_cfg_var("$prefix.pass");<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$port&nbsp;=&nbsp;get_cfg_var("$prefix.port");<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(empty($port)){<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$port&nbsp;=&nbsp;null;<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sock&nbsp;=&nbsp;get_cfg_var("$prefix.socket");<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(empty($sock)){<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sock&nbsp;=&nbsp;null;<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$dbs[$group]&nbsp;=&nbsp;new&nbsp;MySQLi($host,&nbsp;$user,&nbsp;$pass,&nbsp;$db,&nbsp;$port,&nbsp;$sock);<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!$dbs[$group]&nbsp;||&nbsp;$dbs[$group]-&gt;connect_errno){<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;Exception("Invalid&nbsp;MySQL&nbsp;parameters&nbsp;for&nbsp;$group");<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$dbs[$group];<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;}<br>

<br>

}<br>

<br>

?&gt;



</code>

<br><br>We can now call DB::init("myconfig") and get a mysqli object that is connected to the database we want. No file IO was needed to load these settings except when the PHP process started initially.&nbsp; They are truly constant and will not change while this process is running.<br><br>Once this was working, we created separate ini files for our different datacenters. That is now simply configuration information just like routing or networking configuration. No more worrying in code about where we are.<br><br>We extended this to all our services like memcached, gearman or whatever. We keep all our configuration in one file rather than having lots of them. It just makes administration easier. For us it is not an issue as each location has a unique setting, but every server in that location will have the same configuration.<br><br>Here is a more real example of how we set up our files.<br><br>



<code>

[myconfig.db]<br>

myconfig.db.db1.db&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;db1<br>

myconfig.db.db1.server&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;db1hostname<br>

myconfig.db.db1.user&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;db1username<br>

myconfig.db.db1.pass&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;db1password<br>

<br>

myconfig.db.db2.db&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;db2<br>

myconfig.db.db2.server&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;db2hostname<br>

myconfig.db.db2.user&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;db2username<br>

myconfig.db.db2.pass&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;db2password<br>

<br>

[myconfig.memcache]<br>

myconfig.memcache.app.servers&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;10.1.20.1,10.1.20.2,10.1.20.3<br>

myconfig.memcache.proxy.servers&nbsp;&nbsp;=&nbsp;10.1.20.4,10.1.20.5,10.1.20.6<br>

<br>

[myconfig.gearman]<br>

myconfig.gearman.workload1.servers&nbsp;=&nbsp;10.1.20.20<br>

myconfig.gearman.workload2.servers&nbsp;=&nbsp;10.1.20.21

</code>]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Tue, 19 Jan 2010 17:24:35 -0600</pubDate>
            <category>gearman</category>
            <category>memcached</category>
            <category>mysql</category>
            <category>php</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/forums-are-crap-help-us</guid>
            <title>Forums are crap. Can we get some help?</title>
            <link>http://brian.moonspot.net/forums-are-crap-help-us</link>
            <description><![CDATA[Amy Hoy has written a blog post about why <a href=
"http://sweatyd.posterous.com/forums-are-crap">forums are crap</a>.
And she is right. Forum software does not always do a good job of
helping people communicate. I have worked with Amy. She did a great
analysis of <a href="http://dealnews.com/">dealnews.com</a> that
led to our new design. So, she is not to be ignored.<br>
<br>
However, as a software developer (<a href=
"http://www.phorum.org/">Phorum</a>), I see a lot of problems and
no answers.&nbsp; And it is not all on the software.&nbsp; Web site
owners use forums to solve problems that they really, really suck
at.&nbsp; Ideally, every web site would be very unique for their
audience.&nbsp; They would use a custom solution that fits a number
of patterns that best solves their problem.&nbsp; However, most web
site owners don't want to take the time to do such things.&nbsp;
They want a one stop, drop in solution. See the monolith that is
vBulletin, scary.<br>
<br>
And what if a forum is the best solution? Well, software
developers, in general, are not good designers. They don't think
like normal people. And they don't see their applications as a
whole, but as pieces that do jobs. The forum software market has
been run by software developers for over 10 years. Most of them all
are still copies of what <a href=
"http://en.wikipedia.org/wiki/UBB.classic">UBB</a> was 13 years
ago. And software (like Phorum) that has tried to be different is
shunned by the online communities of the world because they don't
work/look/feel like every other forum software on the planet.<br>
<br>
So, as software developers, what are we to do? We want to make
great software. We want to help our users help their users. But,
what we have been doing for 10+ years has only been adequate. As
the leader of an open source forum software project, I am open to
any and all ideas.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Mon, 12 Oct 2009 10:01:44 -0500</pubDate>
            <category>mysql</category>
            <category>phorum</category>
            <category>php</category>
            <category>usability</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/wordcraft-0-10-available</guid>
            <title>Wordcraft 0.10 available</title>
            <link>http://brian.moonspot.net/wordcraft-0-10-available</link>
            <description><![CDATA[The latest package of <a href=
"http://brian.moonspot.net/what-is-wordcraft-">Wordcraft</a>, the
PHP/MySQL based blog software that runs this site, is available for
<a href=
"http://code.google.com/p/wordcraft/downloads/list?can=3">download
from Google Code</a>.&nbsp; Just some minor bug fixes and cosmetic
stuff.&nbsp; Its getting a little use in the wild.&nbsp; That is
always fun to see.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Mon, 10 Aug 2009 00:12:20 -0500</pubDate>
            <category>mysql</category>
            <category>php</category>
            <category>wordcraft</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/using-the-glammp-stack</guid>
            <title>The rise of the GLAMMP stack</title>
            <link>http://brian.moonspot.net/using-the-glammp-stack</link>
            <description><![CDATA[First there was <a href=
"http://en.wikipedia.org/wiki/LAMP_%28software_bundle%29">LAMP</a>.&nbsp;
But are you using GLAMMP?&nbsp; You have probably not heard of it
because we just coined the term while chatting at work.&nbsp; You
know LAMP (Linux, Apache, MySQL and PHP or Perl and sometimes
Python). So, what are the extra letters for?<br>
<br>
<strong>The G is for Gearman</strong> - <a href=
"http://www.gearman.org/">Gearman</a> is a system to farm out work
to other machines, dispatching function calls to machines that are
better suited to do work, to do work in parallel, to load balance
lots of function calls, or to call functions between languages.<br>
<br>
<strong>The extra M is for Memcached</strong> - <a href=
"http://www.danga.com/memcached/">memcached</a> is a
high-performance, distributed memory object caching system, generic
in nature, but intended for use in speeding up dynamic web
applications by alleviating database load.<br>
<br>
More and more these days, you can't run a web site on <em>just</em>
LAMP.&nbsp; You need these extra tools (or ones like them) to do
all the cool things you want to do.&nbsp; What other tools do we
need to work into the acronym?&nbsp; <a href=
"http://www.postgresql.org/">PostgreSQL</a> replaces MySQL in lots
of stacks to form LAPP.&nbsp; I guess <a href=
"http://drizzle.org/">Drizzle</a> may replace MySQL in some stacks
soon.&nbsp; For us, it will likely be <a href=
"http://brian.moonspot.net/2008/07/24/156/">added to the
stack</a>.&nbsp; Will that make it GLAMMPD?&nbsp; We need more
vowels!&nbsp; If you are starting the next must use tool for
running web sites on open source software, please use a vowel for
the first letter.<br>
<br>]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Fri, 22 May 2009 11:34:39 -0500</pubDate>
            <category>apache</category>
            <category>gearman</category>
            <category>linux</category>
            <category>memcache</category>
            <category>mysql</category>
            <category>php</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/speaking-velocity-2009</guid>
            <title>Scaling for the Expected and Unexpected - Speaking at Velocity</title>
            <link>http://brian.moonspot.net/speaking-velocity-2009</link>
            <description><![CDATA[Last year I was surprised to be <a href=
"http://brian.moonspot.net/2008/06/18/did-you-know-i-am-going-to-be-at-velocity/">
going to Velocity</a>.&nbsp; Read the post, it was an
adventure.&nbsp; But, I <a href=
"http://brian.moonspot.net/2008/07/01/velocity-conference-roundup/">
really like the conference</a>.&nbsp; It is the perfect conference
for me.&nbsp; While a good majority of my work is done coding
PHP/MySQL apps, I tend to focus on architecture, frameworks,
performance and that kind of stuff.&nbsp; So, a web performance and
operations conference is just perfect.<br>
<br>
Last year, I was on a panel with <a href=
"http://en.oreilly.com/velocity2008/public/schedule/detail/4762">some
great guys</a>.&nbsp; I was able to share just a bit about my
experience dealing with the instant success of a web site.&nbsp;
This year, my proposal was accepted to talk more about dealing with
success of a web site.&nbsp; The talk will be focused on my
experience at <a href="http://dealnews.com/">dealnews.com</a> and
from working with power users for <a href=
"http://www.phorum.org/">Phorum</a>.&nbsp; Here is the summary:<br>

<blockquote>
    <div>
        <p>
            Lots of people talk about scaling and performance. But,
            are they preparing for all the things that could
            happen? There are multiple problems and there is not
            one solution to solve them all.
        </p>

        <p>
            Everything is running fine and <span class=
            "caps">BAM</span>! – your site is linked from the front
            page of Yahoo! What do you do? How can you handle that
            sudden rush of traffic. Requests per second are running
            5x normal levels. Servers have <span class=
            "caps">CPU</span> spikes. Daemons are hitting the
            maximums. You are running out of bandwidth. How could
            you have been prepared for this? What are the tools and
            techniques for this type of sudden rush?
        </p>

        <p>
            Or, lets say you have just come out of a meeting where
            everyone discovered that your site is growing in
            traffic 70% – 80% year over year. That means that 1
            million page views this month will be nearly 3 million
            this time in 2 years. How can you plan for that? You
            don’t want to redesign the whole architecture every 2
            years. What methods could be used to deal with this
            constant long term growth?
        </p>

        <p>
            While there is no magic bullet for either of these
            scenarios, there are techniques used by many sites out
            there to help you get through these situations. This
            session will cover some of these techniques and talk
            about their pros and cons.
        </p>
    </div>
</blockquote>

<div>
    <p>
        I must admit, this if the first time since 2000 that I am a
        little intimidated to speak at a conference.&nbsp; The
        people that present and attend Velocity are so
        awesome.&nbsp; I just hope I don't disappoint.
    </p>
</div>]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Thu, 07 May 2009 11:57:27 -0500</pubDate>
            <category>mysql</category>
            <category>php</category>
            <category>velocity</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/wordcraft-0-9-1-available</guid>
            <title>Wordcraft 0.9.1 available</title>
            <link>http://brian.moonspot.net/wordcraft-0-9-1-available</link>
            <description><![CDATA[There are several key changes in Wordcraft 0.9.1. The two big
things are:<br>

<ul>
    <li>
        <span>Tokens on post forms in the admin to help ward off
        <a href=
        "http://shiflett.org/articles/cross-site-request-forgeries">
        CSRF attacks</a>.&nbsp;&nbsp;</span>
    </li>

    <li>
        <span>Database schema updates automated.</span>
    </li>
</ul>
<span>The first comes as a result of us doing the same work on
Phorum recently.&nbsp; I realized I needed the same protection in
Wordcraft.&nbsp; The second was done out of neccesity as I changed
the datetime fields in the database schema into int fields.&nbsp;
Not sure why I ever made them datetime fields.&nbsp; Unix
timestamps are much easier to work with.&nbsp; It saves many
strtotime() calls and will make eventual time zone settings much
easier to implement.<br>
<br>
In addition to those two big ones, there were some notable small
ones:<br></span>
<ul>
    <li>HTML 4.01 validation fixes
    </li>

    <li>Ensuring UTF-8 on all encoding function calls
    </li>

    <li>Protection against hitting the back button when writing a
    post (most annoying on Macs as the back button and the
    beginning of line keystroke is the same).
    </li>
</ul>
And there were other a few <a href=
"http://code.google.com/p/wordcraft/source/list">other bug
fixes</a>.<br>
<br>
I will or course need many more testers and users before I can ever
declare this software as stable.&nbsp; If you need a simple blog,
give it a try.<br>
<br>
<strong>About Wordcraft</strong><br>
Wordcraft aims to be a simple, lightweight blogging
application.&nbsp; Wordcraft is written exclusively for PHP 5+ and
MySQL 5.0+ using only the PHP mysqli extension, UTF-8, and HTML
4.01 to achieve that simpleness.<br>]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Wed, 08 Apr 2009 08:00:00 -0500</pubDate>
            <category>mysql</category>
            <category>php</category>
            <category>wordcraft</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/wordcraft-0-8-available</guid>
            <title>Wordcraft 0.8 available</title>
            <link>http://brian.moonspot.net/wordcraft-0-8-available</link>
            <description><![CDATA[I am pleased to announce the release of <span><a href=
"http://wordcraft.googlecode.com/files/wordcraft-0.8.tar.gz">Wordcraft
0.8</a>.&nbsp; I have managed to release about once a month since
November.&nbsp; I also have actually gotten some feedback and
tickets posted.&nbsp; Thanks to those that have tried it out.<br>
<br>
I have decided to go back to YUI's Editor.&nbsp; I tried TinyMCE in
the last release.&nbsp; But, using it full time I found it messed
with my HTML too much for my liking.&nbsp; When I would switch to
raw HTML mode and add something like a &lt;code&gt; tag, it would
be lost when saving the data back into the WYSIWYG editor.<br>
<br>
I also converted the admin HTML to HTML 4.01 Transitional.&nbsp; I
never use XHTML anymore these days.&nbsp; So, I was writing invalid
XHTML inadvertantly.<br>
<br>
I worked on the session handling some more in this release.&nbsp;
Users should stay logged in to the admin better now.<br>
<br>
I put comment blocks in all the files and documented every
function.&nbsp; This should help anyone wanting to dig in and help
out.<br>
<br>
I fixed several bugs reported by users (or maybe just testers, not
sure).&nbsp; Thanks for that and keep the feedback
coming.<br></span>]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Mon, 23 Feb 2009 08:00:00 -0600</pubDate>
            <category>Blogging</category>
            <category>MySQL</category>
            <category>PHP</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/mysql-alter-multiple-things</guid>
            <title>Altering several things in a MySQL table at one time</title>
            <link>http://brian.moonspot.net/mysql-alter-multiple-things</link>
            <description><![CDATA[To some kick ass DBA or someone that works on MySQL internals, this
is probably a no brainer.&nbsp; But, for just joe schmoe power user
types, we wonder about these things.&nbsp; We could not find the
answer on the internet, so I decided to blog about it.&nbsp; We
expected the result we found, but I think it's good
information.<br>
<br>
Have you ever had to make changes to several indexes or columns in
a table?&nbsp; With <a href="http://www.phorum.org/">Phorum</a>, we
keep a series of scripts that run queries to upgrade the database
as we make changes.&nbsp; Recently I had to delete about 12 keys
and add about 7 back in their place.&nbsp; I initially thought to
make two sql statements.&nbsp; One to delete indexes and one to
create new ones.&nbsp; But, Thomas, one of the other developers,
wondered if that was really any better.&nbsp; So, I decided to run
some tests.<br>
<br>
First I altered a table with 70k rows, dropping one key.&nbsp; That
took 16 seconds.&nbsp; I then added a key to that same table.&nbsp;
Again, about 16 seconds.&nbsp; So, I then dropped a key and added a
key in one query.&nbsp; Again 16 seconds.&nbsp; So, I decided to go
for the ultimate challenge.&nbsp; I dropped 12 keys and added back
12 keys all in one query.&nbsp; TADA!&nbsp; 16 or so seconds.&nbsp;
The table was an InnoDB table, so I repeated after converting the
table to MyISAM.&nbsp; Again, all the alters took about the same
time, regardless of the number of changes.<br>
<strong><br>
Update</strong><br>
<strong><br></strong>I was told in the comments that the data was
not big enough for a real test.&nbsp; I hold to the fact that
because, as Eric Bergen pointed out, the most time is taken in
copying the data, the data size is not that important here.&nbsp;
However, I tried it out on a table with 750k rows just to
see.&nbsp; Dropping 4 keys on a table with 12 keys took 1min
46sec.&nbsp; Adding 4 keys to the same table, (now with 8 keys)
took 1min 52sec.&nbsp; Adding 4 keys and dropping 4 keys in one
alter table took 1min 49sec.&nbsp; So, looks like I was
right.&nbsp; For fun, I decided to drop all the keys except the
primary.&nbsp; That only took 28sec.&nbsp; That is what I
guessed.&nbsp; The slow part is copying the table to a new
table.&nbsp; That includes filling in indexes.&nbsp; It is much
faster to write a table with indexes than it is a table with 12
indexes.&nbsp; However, that was not my use case and not the reason
for my testing.&nbsp; But, it is good information to attach to this
blog post.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Sun, 22 Feb 2009 18:00:00 -0600</pubDate>
            <category>mysql</category>
            <category>php</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/wordcraft-0-7-available</guid>
            <title>Wordcraft 0.7 available</title>
            <link>http://brian.moonspot.net/wordcraft-0-7-available</link>
            <description><![CDATA[<p>
    I am happy to announce <a href=
    "http://wordcraft.googlecode.com/files/wordcraft-0.7.tar.gz">Wordcraft
    0.7</a>.&nbsp; There are two big changes in this release.&nbsp;
    On the front end, I added a simple search.&nbsp; It just uses a
    LIKE clause.&nbsp; But, I figure a lot of blogs never reach
    1,000 posts.&nbsp; Even at 10,000 posts, a LIKE would not be
    too bad.&nbsp; On the backend, I have switched the post editor
    to <a href="http://tinymce.moxiecode.com/">TinyMCE</a>. YUI's
    editor is decent, but it needs polish.&nbsp; Perhaps my time
    with Wordpress just made me more familiar with it.&nbsp;
    TinyMCE does save XHTML.&nbsp; I put some code in the PHP side
    to use Tidy if it is available to convert it to HTML 4.01,
    which I prefer.
</p>

<p>
    Also in this release:
</p>

<ul>
    <li>Fixed an XSS issue in tag.php.
    </li>

    <li>Fixing a parsing issue with anchor tags when doing
    pingbacks.
    </li>

    <li>Fixed an error when the remote site can not be contacted.
    </li>

    <li>Fix for pingbacks with nice URLs enabled. Was blocking
    pingbacks.
    </li>
</ul>]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Mon, 12 Jan 2009 08:00:00 -0600</pubDate>
            <category>mysql</category>
            <category>php</category>
            <category>wordcraft</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/seven-things-about-brian-moon</guid>
            <title>Seven Things about me - tagged by Brian DeShong</title>
            <link>http://brian.moonspot.net/seven-things-about-brian-moon</link>
            <description><![CDATA[So, my Haystacks teammate <a href=
"http://www.deshong.net/?p=145">Brian DeShong</a> tagged me in his
list of seven.&nbsp; We won<br>
that trivia contest by the way.&nbsp; It was a real team
effort.<br>
<br>
So, here goes my seven things:<br>

<ol>
    <li>I have six kids.&nbsp; Okay, let that sink in.&nbsp; Yes,
    six.&nbsp; Logan(12), Macy(11), Molly(9), Parker(7), Collin(3),
    and Hudson(6 months).&nbsp; I know what causes it.&nbsp; Yes,
    it is hard at times.&nbsp; But, there are those moments when
    you are sitting in the yard or in the den and all is right in
    the world.&nbsp; The best program I will ever write will not
    compare to what have done with my children.&nbsp; They are
    truly my greatest project.&nbsp; My wonderful wife blogs about
    them at <a href="http://moonmania.blogspot.com/">Moonmania</a>.
    </li>

    <li>I started my career as a Visual Basic programmer.&nbsp; PHP
    and VB are very much alike.&nbsp; Neither is OOP, yet people
    keep trying to make them so.&nbsp; You can write truly powerful
    applications if you know what you are doing.&nbsp; Much of the
    outside community thinks poorly of the language.&nbsp; In both
    cases I was way too busy making cool things and getting stuff
    done to care or pay attention.
    </li>

    <li>I play <a href="http://www.pdga.com/">disc golf</a>.&nbsp;
    It is a great sport.&nbsp; It reminds me of the Open Source
    community in that it is a very community driven sport.&nbsp;
    The courses are installed and maintained by the players,
    usually on public land such as parks.&nbsp; The tournaments are
    run by local players.&nbsp; The sport is largely managed by
    players.&nbsp; I maintain the web site of one of the larger
    regional (maybe the largest) <a href="http://www.sndg.org/">
        tournament series</a> in the world.&nbsp; I have played in
        most cities that I have visited including those I go to for
        conferences.&nbsp; We have a group of 9 or so people at
        dealnews that play on a semi-regular basis when the weather
        is right.
    </li>

    <li>I never graduated college.&nbsp; The VB work and then the
    PHP work got in the way.&nbsp; It is a regret in some
    ways.&nbsp; But, I can't tell you what I would have changed
    about how my life has gone.&nbsp; Perhaps I will go back and
    finish my degree at some point.&nbsp; Sadly, in this world,
    there are doors that are closed to you no matter how brilliant
    you are if you don't have a simple piece of paper.&nbsp; I know
    people with that piece of paper that ended up working fast
    food.&nbsp; But, they could get an interview where I could
    not.&nbsp; They would not get the job, but I can't even get in
    the door.
    </li>

    <li>I have contributed two PHP internals functions.&nbsp;
    mysql_fetch_assoc and the now deprecated <span class="refname">
        set_file_buffer</span>.&nbsp; In the case of
        mysql_fetch_assoc, I was fixing what was IMO a bug.&nbsp;
        mysql_fetch_array originally returned only an associative
        array.&nbsp; Someone decided it should return the data in
        both associative and numeric forms.&nbsp; mysql_fetch_row
        already existed to return numeric keys.&nbsp; So, I simply
        copied it and added mysql_fetch_assoc.&nbsp; That was the
        real wild wild west days of PHP CVS.&nbsp; You either had
        full access or you didn't have any access.&nbsp; I did not
        keep my development up on PHP so I lost karma on the core
        later.&nbsp; My C is not super polished.&nbsp; Still I will
        admit I liked being part of the club.
    </li>

    <li>I watch pro wrestling.&nbsp; There I said it.&nbsp; Guilty
    pleasure.&nbsp; The Tivo makes it easy.&nbsp; 2 hour show only
    takes about 40 minutes.&nbsp; Heh, I skip most of the
    wrestling.&nbsp; Not everyone is entertaining.&nbsp; My great
    grandmother would sit and watch it every Saturday night.&nbsp;
    I was hooked from that point.&nbsp; I won't get going on
    it.&nbsp; I would lose you guys.&nbsp; FWIW, I am a big fan of
    mixed martial arts too.&nbsp; That stuff IS real and very
    exciting.
    </li>

    <li>I am a compulsive code rewriter and/or write it myself kind
    of guy.&nbsp; It is something I struggle with every day.&nbsp;
    It is why I started <a href="http://www.phorum.org/">Phorum</a>
    and <a href=
    "http://brian.moonspot.net/what-is-wordcraft-">Wordcraft</a>.&nbsp;
    Luckily, the guys I work with at both dealnews and on Phorum
    are good programmers.&nbsp; My biggest problem is opening a
    file I last worked on 5 years ago.&nbsp; The way we write web
    applicaitons has evolved so much in the 11 years I have been
    doing this.&nbsp; I am using the same language, but have such
    different ideas.&nbsp; I can only imagine what the next 11
    years will bring.
    </li>
</ol>
<br>
I will be tagging these seven.&nbsp; Forgive me if I get a title
wrong.<br>

<ol>
    <li>
        <a href="http://krow.livejournal.com/">Brian
        Aker</a>.&nbsp; The creators of sites like Facebook and
        Digg may have had some great ideas.&nbsp; But, without guys
        like Brian Aker, they would be nowhere.&nbsp; He makes the
        things that make dealnews, Facebook and Digg
        possible.&nbsp; And he continues to contribute with Drizzle
        and the new C based gearmand.
    </li>

    <li>
        <a href="http://www.kitchensoap.com/">John
        Allspaw</a>.&nbsp; John manages the operations team for
        Flickr.&nbsp; He is a smart guy.&nbsp; He and I see eye to
        eye on a lot of web performance topics.
    </li>

    <li>
        <a href="http://www.joestump.net/">Joe Stump</a>. Joe is
        the lead architect for Digg.&nbsp; I have not met Joe in
        person.&nbsp; But, I have heard him interviewed and we are
        on the same page about a lot of things.&nbsp; I have
        started using some of his <a href=
        "http://code.google.com/p/digg">contributed PHP</a> code
        lately as well.
    </li>

    <li>
        <a href="http://consoleninja.net/">Alan Kasindorf aka
        Dormando</a>.&nbsp; Alan works for operations at Six
        Apart.&nbsp; They bought Danga.&nbsp; They formerly owned
        Live Journal.&nbsp; He has kind of become the care taker of
        memcached, gearmand and all those other cool things that
        Danga created.&nbsp; The community is helping him more each
        day, but he still does a lot of work for those
        projects.&nbsp; Including, but not limited to coding.
    </li>

    <li>
        <a href="http://jpipes.com/index.php">Jay Pipes</a>.&nbsp;
        I think I saw him on someone else's list.&nbsp; But, I am
        putting him down anyway.&nbsp; Jay has been good to me over
        the years.&nbsp; It is cool that someone can chair the
        MySQL Conference, go around talking to user groups and
        commit code to fix MySQL bugs.&nbsp; Jay is great because
        he and I can disagree on just about everything when it
        comes to programming then toast our beers.&nbsp; You need
        people like that in the world.
    </li>

    <li>
        <a href="http://www.marketing-ontheweb.com/blog/">John
        Allen</a>.&nbsp; I work with John at dealnews.&nbsp; He has
        learned the search engine optimization and marketing world
        the way I learned programming.&nbsp; John posses skills
        that I don't.&nbsp; We butt heads on a regular basis about
        things.&nbsp; But, the end result is always better than
        what existed before we started.&nbsp; I have learned many
        things from him.
    </li>

    <li>
        <a href="http://glazed.org/">Daniel Beckham</a>.&nbsp;
        Daniel is my partner in crime at dealnews.&nbsp; We have
        been a two headed monster (yeah, a monster.&nbsp; Just ask
        the CEO.) for 8 or so years now.&nbsp; Unfortunately,
        Daniel does not blog or twitter or much of anything like
        that.&nbsp; So, we likely won't see his seven things.&nbsp;
        Many of the things I have blogged about when it comes to
        building dealnews' architecture were thought of and done by
        both of us.&nbsp; I am just a show off extrovert that needs
        a lot of attention.&nbsp; So, I do all the blogging and
        talking at conferences. &nbsp;
    </li>
</ol>
And, I am told I need to post this for my taggies to follow:<br>

<ul>
    <li>Link your original tagger(s), and list these rules on your
    blog.
    </li>

    <li>Share seven facts about yourself in the post - some random,
    some weird.
    </li>

    <li>Tag seven people at the end of your post by leaving their
    names and the links to their blogs.
    </li>

    <li>Let them know they’ve been tagged by leaving a comment on
    their blogs and/or Twitter.
    </li>
</ul>]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Mon, 05 Jan 2009 00:08:27 -0600</pubDate>
            <category>mysql</category>
            <category>php</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/wordcraft-0-6-available</guid>
            <title>Wordcraft 0.6 available</title>
            <link>http://brian.moonspot.net/wordcraft-0-6-available</link>
            <description><![CDATA[I am pleased to announce the release of <a href=
"http://wordcraft.googlecode.com/files/wordcraft-0.6.tar.gz">Wordcraft
0.6</a>.&nbsp; I have been using it for a month or so now and I am
learning some things.<br>
<br>
I had been having trouble logging in lately from multiple
places.&nbsp; So, instead of trying to work on the built in session
handling I had written, I took my own advice (use stuff that
exists) and just switched to PHP sessions.&nbsp; All the cookie
stuff is worked out and I can get a lot done with just a little
work.&nbsp; PHP sessions make me a little nervous.&nbsp; If you
have lots of applications installed on the same site that use them,
you can get some odd behavior.&nbsp; But, why reinvent the wheel
right?<br>
<br>
I have found myself wanting to save a post while working on
it.&nbsp; To do that before, I would have to uncheck the Published
box.&nbsp; To solve this, I changed the behavior of the Save
button.&nbsp; When pressed it now saves the post, but with the
published flag set to 0.&nbsp; This lets you save a post while
working on it quickly.&nbsp; I then added a Publish button to the
post form.&nbsp; The Publish button will save the post with the
published flag set to 1.&nbsp; If a post is already published, you
just get an Update button that will save whatever is set in the
form.<br>
<br>
From a code perspective, I have made all the code use the same
array for user data.&nbsp; I had a separate one for the core, one
for the template and one for the admin before.&nbsp; That was
getting complicated.&nbsp; So, they all just use the same one
now.<br>
<br>
The last thing I did was add meta refresh tags to the admin success
pages.&nbsp; I like having a success page to tell me something
worked.&nbsp; But, I really want it to move along after it is
done.&nbsp; It does that now.&nbsp; It is set to 3 seconds.&nbsp; I
may knock that down a bit.&nbsp; That 3 seconds starts after the
page is fully loaded.&nbsp; So, it can be more like 5 or 6 if stuff
has to load.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Wed, 17 Dec 2008 01:26:32 -0600</pubDate>
            <category>blogging</category>
            <category>mysql</category>
            <category>php</category>
            <category>wordcraft</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/oscon-moving-to-san-jose</guid>
            <title>OSCON moves to San Jose - or - I will miss Portland</title>
            <link>http://brian.moonspot.net/oscon-moving-to-san-jose</link>
            <description><![CDATA[I have had the privilege to go to the <a href="http://conferences.oreillynet.com/">O'Reilly Open Source Convention</a> 4 of the past 5 years.&nbsp; During that time, it has been held in beautiful <a href="http://en.wikipedia.org/wiki/Portland,_Oregon">Portland, Oregon</a>.&nbsp; Well, the <a href="http://en.oreilly.com/oscon2009/public/content/home">OSCON 2009</a> web site is up and they are moving it to <a href="http://en.wikipedia.org/wiki/San_Jose,_California">San Jose, CA</a>.&nbsp; I have never been to the <a href="http://www.sanjose.org/meetings/facilities/convention.php">San Jose Convention Center</a>.&nbsp; The pictures look nice.&nbsp; I have only been to San Jose at all to get off a plane and go to the <a href="http://www.santaclara.org/conventioncenter/">Santa Clara Convention Center</a>.&nbsp; I hope San Jose has more to offer than Santa Clara.&nbsp; The Santa Clara Convention Center is nice.&nbsp; And the hotel it is attached to is also quite nice.&nbsp; I have attended an <a href="http://www.apachecon.com/2001/US/">Apachecon in 2001</a> and two <a href="http://mysqlconf.com/">MySQL Conferences</a> (2007 and 2008) there.&nbsp; But, outside of the convention center, there is not a lot of fun stuff to do.&nbsp; You have to travel a good distance to find good medium to high end restaurants.&nbsp; It is in the middle of a lot of large office buildings with names like Yahoo!, Intel, AMD, nVidia, etc. on them.&nbsp; The other space is taken up by apartments.&nbsp; But, I did not start this post to dig on Santa Clara.<br><br>I will miss Portland.&nbsp; It is a neat town.&nbsp; Lots of good food.&nbsp; Lots of good beer.&nbsp; Easy to navigate once you get used to the bridges.&nbsp; If you like public transport it is quite accesible.&nbsp; There is good <a href="http://en.wikipedia.org/wiki/Disc_golf">disc golf</a> in the area too.&nbsp; That was always a plus. <br><br>But, here is to new beginnings in San Jose.&nbsp; May it be as fun and educational as Portland has been these past few years.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Sat, 13 Dec 2008 00:37:22 -0600</pubDate>
            <category>mysql</category>
            <category>oscon</category>
            <category>php</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/build-dealnews-for-250</guid>
            <title>Know PHP/MySQL and wanna earn a buck?</title>
            <link>http://brian.moonspot.net/build-dealnews-for-250</link>
            <description><![CDATA[Apparently, all the work we have put into <a href="http://dealnews.com/">dealnews.com</a> over the last 11 1/2 years can be had for $250 and can be delivered in 10 hours.<br><br><a href="http://www.getafreelancer.com/projects/PHP-Joomla/Clone-dealnews-com-CMS.html">http://www.getafreelancer.com/projects/PHP-Joomla/Clone-dealnews-com-CMS.html</a><br><br>I see it was canceled.&nbsp; That is smart.&nbsp; What we do can not be done for that kind of money.&nbsp; $350?&nbsp; Maybe. =)<br><br>Speaking of dealnews, we have been rated the <a href="http://www.pcmag.com/slideshow/0,1206,l=234259&amp;a=234260,00.asp">#1 Black Friday site by PC Magazine</a>.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Mon, 24 Nov 2008 16:53:02 -0600</pubDate>
            <category>dealnews</category>
            <category>mysql</category>
            <category>php</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/open-source-design</guid>
            <title>Open Source Web Design</title>
            <link>http://brian.moonspot.net/open-source-design</link>
            <description><![CDATA[So, my wife told me that my site design was boring.&nbsp; Yeah, she was right.&nbsp; I am no designer.&nbsp; I just don't have that gene.&nbsp; But, during my work on Wordcraft, I came across some cool places to find designs that are relased under Open Source licenses.<br><ul>




<li><a href="http://www.opendesigns.org/">Open Designs</a> - This is arguably the the prettiest of the three. The search, however, is painfully slow because all results return on one page.&nbsp; I guess if you can wait, this is a plus as browsing is easier.&nbsp; Also, you can pick multiple colors and choose by license.&nbsp; They only list XHTML templates (at least as search options).&nbsp; That could be a turn off if you like HTML 4 like me.</li>
<li><a href="http://www.openwebdesign.org/">Open Web Design</a> - The site itself could use a design overhaul.&nbsp; But, the content is good.&nbsp; The search lets you choose primary and secondary color, a unique feature among these sites.&nbsp; Thumbnails are a bit small though.</li>
<li><a href="http://www.oswd.org/">Open Source Web Design</a> - Their search is not as powerful as the others, but it does return very fast.&nbsp; The thumbnails are a nice size.</li>
</ul>
You will find the same content on all three sometimes.&nbsp; But, it comes down to browsing and searching.<br><br>I found my new design at one of those.&nbsp; Not sure which, I looked at a lot of them.&nbsp; I did not use the template's HTML exactly as I like HTML 4.0 and wanted a different sidebar than the original author.&nbsp; But, the design is the hard part.&nbsp; So, thanks for <a href="http://templates.arcsin.se/deep-red-website-template/">Deep Red</a>.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Mon, 17 Nov 2008 12:00:00 -0600</pubDate>
            <category>design</category>
            <category>html</category>
            <category>mysql</category>
            <category>php</category>
            <category>template</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/wordcraft-0-5-available</guid>
            <title>Wordcraft 0.5 available</title>
            <link>http://brian.moonspot.net/wordcraft-0-5-available</link>
            <description><![CDATA[Well, I <a href=
"http://brian.moonspot.net/wordcraft-simple-php-blog">blogged about
Wordcraft</a> the other day.&nbsp; I have just been running live on
the software for 4 days now.&nbsp; Well, that post had no URI
associated with it.&nbsp; It took me two days to figure this
out.&nbsp; Oops.&nbsp; Welcome to <a href=
"http://en.wikipedia.org/wiki/Dogfooding">eating my own dog
food</a>.&nbsp; So, running this live with actual users (and a host
of bot spam attempts) I am learning a lot and making a lot of
commits.&nbsp; So, I may very well roll once or twice a week for
the first few weeks.<br>
<br>
So, with that, I have packaged 0.5.&nbsp; There are 15 changes in
this package.&nbsp; Some features, but mostly bug fixes.&nbsp; So,
if you could use a simple blog, give it a try and help me debug
it.&nbsp; If you do, please use the Google Code <a href=
"http://code.google.com/p/wordcraft/issues/list">issue
tracker</a>.&nbsp; Maybe I can figure out how to have those things
emailed to me.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Mon, 10 Nov 2008 08:00:00 -0600</pubDate>
            <category>blogging</category>
            <category>mysql</category>
            <category>php</category>
            <category>wordcraft</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/wordcraft-simple-php-blog</guid>
            <title>Wordcraft, a simple PHP blogging application</title>
            <link>http://brian.moonspot.net/wordcraft-simple-php-blog</link>
            <description><![CDATA[<p>So, a while back, not sure when, I was listening to the P3 Podcast
and Paul mentioned his dislike for Wordpress.&nbsp; He said he wished there
was a simple blogging application.&nbsp; I am probably misquoting him
horribly.&nbsp; It was an idea that I had been tinkering with.&nbsp; So, I
started on <a href="http://code.google.com/p/wordcraft">Wordcraft</a> in my spare time.&nbsp; Like super spare time.&nbsp; That
time between the kids going to bed and me falling&nbsp; asleep.&nbsp; So, it took
a while to get it to a usable state.</p>
<p>Up until now, I have used Wordpress.com for my blogging.&nbsp; It works
quite well.&nbsp; You can get started quite quickly and it does what most
people need.&nbsp; My wife uses Blogger for our family blog.&nbsp; It is, IMO,
not as nice as Wordpress.com in some ways.&nbsp; But, it does allow you to
edit your styles (for free) and such which is nice.</p>
<p>So, why would I want to reinvent the wheel?&nbsp; I am a control freak
and rarely run other people's code.&nbsp; I know, it is a character flaw.&nbsp; I
am working on it.&nbsp; So, what did I come up with?</p>
<p>I had some goals when I started on this.</p>
<ol>


<li>Keep it simple.</li>
<li>Focus on what I am good at doing.</li>
</ol>



<p><strong>Keeping it simple</strong></p>
<p>I use MySQL.&nbsp; I didn't try to make it work with every possible
database.&nbsp; In fact, it only uses the mysqli PHP extenstion.&nbsp; The few
objects (CAPTCHA) are all PHP 5 objects.&nbsp; I don't plan to worry about
PHP 4.&nbsp; The templates don't use a template language.&nbsp; They use plain
old PHP.&nbsp; The are scoped to protect template authors from global
scope.&nbsp; There are only 6 files required to make a new template.&nbsp; There
are just 589 lines of code in the forward facing scripts.&nbsp; The admin
has 2,446.</p>
<p><strong>What am I good at doing?</strong></p>
<p>I write PHP/MySQL code that has to work fast for a living.&nbsp; It is
what I get paid to do.&nbsp; I am not a designer.&nbsp; I am not a spam catching
wizard.&nbsp; I don't write cool javascript widgets.&nbsp; So, I focused on the
PHP/MySQL parts of the code.&nbsp; For templates, I used designs that are
released under the Creative Commons license.&nbsp; I use Akismet and the
CAPTCHA libraries from Phorum for spam catching.&nbsp; I used the YUI Rich
Editor for the admin where I needed a WYSIWYG widget.&nbsp; I even link to
the YUI sources that are hosted by Yahoo.&nbsp; No sense taking on that
bandwidth or storage.</p>
<p>So, what does it do you ask?&nbsp; Well, here are some of the features:</p>
<ul>


<li>WYSIWYG editing via YUI.</li>
<li>Comments with optional CAPTCHA and/or Akismet.</li>
<li>Custom pages can be created.</li>
<li>Tagging of posts</li>
<li>Custom publish dates</li>
<li>Automatic Pingback support</li>
<li>Friendly URL support with mod_rewrite</li>
<li>5 Templates in first release.&nbsp; Easy to build more.</li>
<li>Email notifications to authors</li>
</ul>
<p>There are some things missing of course.&nbsp; Internationalization of
both the admin and templates is a big one.&nbsp; There is no current search
engine for blog posts.&nbsp; There is no "blog roll" type of feature.&nbsp; There
is no date based archive.&nbsp; And I am sure there is more missing.&nbsp; And I
am sure there are bugs.</p>
<p>But, if you would like to try out yet another PHP application, I welcome you to give it a try.&nbsp; The code is hosted at <a href="http://code.google.com/p/wordcraft/" mce_href="http://code.google.com/p/wordcraft/">Google Code</a>.&nbsp; It is a BSD licensed application.</p>]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Thu, 06 Nov 2008 08:00:00 -0600</pubDate>
            <category>blogging</category>
            <category>mysql</category>
            <category>php</category>
            <category>wordcraft</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/2008/10/15/php-appalachia-corrections/</guid>
            <title>PHP Appalachia Corrections</title>
            <link>http://brian.moonspot.net/2008/10/15/php-appalachia-corrections/</link>
            <description><![CDATA[Just got home finally from PHP Appalachia.&nbsp; I enjoyed meeting
all the great people.<br>
<br>
I presented about what I learned and how we deal with importing
large amounts of CSV data into MySQL.&nbsp; I threw my idea onto
the wiki at the last minute, made the slides while everyone ate
breakfast and I had planned on researching it all (been a few years
since I wrote it), but we had no reliable internet.&nbsp; Some
claims I made and their corrections.<br>

<ol>
    <li style="list-style: none">
        <br>
    </li>

    <li>I said our largest file is about 1.8 million lines.&nbsp;
    WRONG.&nbsp; Actually it is about 4.6 million.&nbsp; I was
    correct however that it does finish importing and indexing in
    about 5 minutes.
    </li>

    <li style="list-style: none">
        <br>
    </li>

    <li>I claimed I LOAD DATA INFILE to MyISAM first and then
    "insert into ... select from" into an InnoDB table for speed
    reasons.&nbsp; WRONG.&nbsp; In fact, I do that because I need
    to merge fields from the file sometimes into one field in the
    databaes.&nbsp; I could not find a way to do that with LOAD
    DATA INFILE.&nbsp; As to speed.&nbsp; I can't say either way as
    I have no solid data.&nbsp; Sounds like a good test.&nbsp;
    MyISAM probably still wins on a LOAD DATA INFILE into a blank,
    fresh table based on my experience.
    </li>

    <li style="list-style: none">
        <br>
    </li>

    <li>Total rows currently indexed is 7.2 million.&nbsp; I did
    not make a claim, but I thought I would just mention
    that.&nbsp; I wanted to include that, but did not have
    Internet.&nbsp; (Damn you Hughes)
    </li>

    <li style="list-style: none">
        <br>
    </li>
</ol>]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Tue, 14 Oct 2008 23:03:05 -0500</pubDate>
            <category>MySQL</category>
            <category>PHP</category>
            <category>Programming</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/2008/10/03/deploying-scalable-websites-with-memcached/</guid>
            <title>Deploying Scalable Websites with Memcached </title>
            <link>http://brian.moonspot.net/2008/10/03/deploying-scalable-websites-with-memcached/</link>
            <description><![CDATA[I spoke at the MySQL Conference and Expo this year about the architecture we have here at <a href="http://dealnews.com/">dealnews.com</a>.  After my talk, Jimmy Guerrero of Sun/MySQL invited me to give a webinar on how dealnews uses memcached.  That is taking place next week, Thursday, October 09, 2008.  It is a free webinar.  We have used memcached in a variety of ways as we have grown. So, I will be talking about how dealnews used memcached in the past and present.<br />
<br />
For more information, visit the <a href="http://www.mysql.com/news-and-events/web-seminars/display-220.html">MySQL web site</a>.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Fri, 03 Oct 2008 09:55:45 -0500</pubDate>
            <category>memcached</category>
            <category>MySQL</category>
            <category>PHP</category>
            <category>Programming</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/2008/09/20/strtotime-the-php-date-swiss-army-knife/</guid>
            <title>strtotime() - The PHP, date swiss army knife</title>
            <link>http://brian.moonspot.net/2008/09/20/strtotime-the-php-date-swiss-army-knife/</link>
            <description><![CDATA[Man, what did I do before <a href=
"http://php.net/strtotime">strtotime()</a>.&nbsp; Oh, I know, I had
a 482 line function to parse date formats and return
timestamps.&nbsp; And I still could not do really cool stuff.&nbsp;
Like tonight I needed to figure out when Thanksgiving was in the
US.&nbsp; I knew it was the 4th Thursday in November.&nbsp; So, I
started with some math stuff and checking what day of the week Nov.
1 would fall on.&nbsp; All that was making my head hurt.&nbsp; So,
I just tried this for fun.<br>

<pre>
strtotime("thursday, november ".date("Y")." + 3 weeks")
</pre><br>
That gives me Thanksgiving.&nbsp; Awesome.&nbsp; It is cool for
other stuff too.&nbsp; At its very basic, it can take a MySQL
datetime field and turn it into a timestamp.&nbsp; Very handy for
date calculations.&nbsp; It also understands <a class=
"link external" href="http://www.faqs.org/rfcs/rfc2822">RFC
2822</a> and ISO 8601 date formats.&nbsp; These are common in HTTP
headers and some XML documents like RSS and Atom feeds.&nbsp; Also,
PHP can output those two standard formats with the <a href=
"http://php.net/date">date()</a> function.&nbsp; So, this makes
them a good standards compliant way to pass full, timezone specific
dates around.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Fri, 19 Sep 2008 22:02:47 -0500</pubDate>
            <category>MySQL</category>
            <category>PHP</category>
            <category>Programming</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/2008/08/22/shrinking-ibdata-files-after-innodb_file_per_table/</guid>
            <title>Shrinking ibdata files after innodb_file_per_table</title>
            <link>http://brian.moonspot.net/2008/08/22/shrinking-ibdata-files-after-innodb_file_per_table/</link>
            <description><![CDATA[Patrick Galbraith wrote in his blog about <a href="http://capttofu.livejournal.com/11479.html">switching to innodb_file_per_table</a>.  For those that don't know about this setting, it places the data for the tables into .ibd files within the database dir instead of storing it in the ibdata files in the main datadir.  This is useful if you don't want to babysit your innodb tablespace.  At least, that was my main reason for wanting to use it.  There is still dictionary data stored in the ibdata file(s) so you can't just remove them.<br />
<br />
Anyhow, the delima Patrick wrote about is recovering the space used by the ibdata files in the datadir after you have converted the tables to one file per table.  I commented on his blog, but thought it worth a full post to be sure others could find my solution.<br />
<ol><br />
	<li>Backup your data (cuz, you never know)</li><br />
	<li>Convert all tables to MyISAM</li><br />
	<li>Stop MySQL.</li><br />
	<li>Delete ib* in the datadir</li><br />
	<li>Restart MySQL.  MySQL will recreate the files.</li><br />
	<li>Convert all tables to InnoDB</li><br />
</ol><br />
It worked for me.  Your mileage may vary.  No warranty that you won't lose all your data.  Try it on a dev server first.<br />
<br />
The benefits of this were that the data was online while we converted the tables.  The only downtime was while we shut down MySQL, removed the files and waited on MySQL to recreate a small 10MB ibdata file and the ib_logfiles.  I am not 100% sure you have to remove the ib_logfiles, but I did for good measure.  I just run with a single 10MB autoextend ibdata file.  I think it is at 34MB or so on our main database server now.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Thu, 21 Aug 2008 23:54:21 -0500</pubDate>
            <category>MySQL</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/2008/08/20/dealnews-is-hiring-a-systems-administrator/</guid>
            <title>dealnews is hiring a Systems Administrator</title>
            <link>http://brian.moonspot.net/2008/08/20/dealnews-is-hiring-a-systems-administrator/</link>
            <description><![CDATA[We are hiring!&nbsp; dealnews is looking for a full time systems administrator.&nbsp; The developers have been sharing the sys admin load for over 10 years now.&nbsp; But, we really need a dedicated person now.&nbsp; If you are interested, see our <a href="http://dealnews.com/pages/jobs.html#sysadmin">jobs page</a>.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Wed, 20 Aug 2008 18:02:15 -0500</pubDate>
            <category>dealnews</category>
            <category>Linux</category>
            <category>MySQL</category>
            <category>PHP</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/2008/08/17/replication-to-the-rescue/</guid>
            <title>Replication is much better than cold backups</title>
            <link>http://brian.moonspot.net/2008/08/17/replication-to-the-rescue/</link>
            <description><![CDATA[So, I wrote about the begining of our <a href="http://brian.moonspot.net/2008/08/05/database-nightmare/">wild database issues</a>. Since then, I have been fighting a cold, coaching little league football and trying to help out in getting our backup solutions working in top shape.  That does not leave much time for blogging.<br />
<br />
Never again will we have ONLY a cold backup of anything.  We were moving nightly full database dumps and hourly backups of critical tables over to that box all day long.  Well, when the filesystem fails on both the primary database server and your cold backup server, you question everything.  A day after my marathon drive to fix the backup server and get it up and running, the backup mysql server died again with RAID errors.  I guess that was the problem all along.  In the end, we had to have a whole new RAID subsystem in our backup database server.  So, my coworker headed over to the data center to pull the all nighter to get the original, main database server up and running.  The filesystem was completely shot.  ReiserFS failed us miserably.  It is no longer to be used at dealnews.<br />
<br />
Well, today at 6:12PM, the main database server stops responding again.  ARGH!!  Input/Ouput errors.  That means RAID based on last weeks experience.  We reboot it.  It reports memory or battery errors on the RAID card.  So, I call Dell.  Our warranty on these servers includes 4 hour, onsite service.  They are important.  While on the phone with Dell, I run the Dell diagnostic tool on the box.  During the diagnostic test, the box shuts down.  Luckily, the Dell service tech had heard enough.  He orders a whole new RAID subsystem for this one as well.<br />
<br />
There is one cool thing about the PERC4 (aka, LSI Megaraid) RAID cards in these boxes.  They write the RAID configuration to the drives as well as on the card.  So, when a new blank RAID card is installed, it finds the RAID config on the drives and boots the box up.  Neato.  I am sure all the latest cards do it.  It was just nice to see it work.<br />
<br />
So, box came up, but this time we had Innodb corruption.  XFS did a fine job in keeping the filesystem in tact.  So, we had to go from backups.  But, this time we had a live replicated database that we could just dump and restore.  We should have had it all along, but in the past (i.e. before widespread Innodb) we were gun shy about replication.  We had large MyISAM tables that would constantly get corrupted on the master or slave and would halt replication on a weekly basis.  It was just not worth the hassle.  But, we have used it for over a year now in our front end database servers with an all Innodb data set.  As of now, only two tables in our main database are not Innodb.  And I am trying to drop the need for a Full-Text index on those right now.<br />
<br />
So, here is to hoping our database problems are behind us.  We have replaced almost everything in one except the chassis.  The other has had all internal parts but a motherboard.  Kudos to Dell's service.  The tech was done with the repair in under 4 hours.  Glad to have that service.  I recommend it to anyone that needs it.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Sun, 17 Aug 2008 01:58:47 -0500</pubDate>
            <category>Linux</category>
            <category>MySQL</category>
            <category>Scalability</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/2008/08/05/database-nightmare/</guid>
            <title>Database nightmare</title>
            <link>http://brian.moonspot.net/2008/08/05/database-nightmare/</link>
            <description><![CDATA[Its 12:30AM (00:30 for you Euros).  I am watching The Daily Show on Tivo.  All is well.  Then the phone beeps.<br />
<br />
<strong>MySQL Main is critical</strong><br />
<br />
SSH?  no.<br />
<br />
Digi console?  no.<br />
<br />
About a week ago, we had a mysqldump file that was corrupt.  We cleaned it up.  My worst fears came to my mind.  We tried power cycling it.  It did not come back.<br />
<br />
While my coworker was dealing with the facilily people, I worked on the backup server.  Had to ensure the last full backup was in place and apply the incremental data.  Suddenly, my SSH connection dies.  OMG.  THAT DUMB A** GUY POWER CYCLED THE WRONG BOX!!! --- FS corrupted.  Damn you ReiserFS!<br />
<br />
By now, it's 4AM.  Tech took an hour to get to the rack.  It is 20 feet from his cubicle.  I get in the car.  I am two hours away from the facility.  No sleep.  It is still dark.  I play loud music.  I talk to myself.  I curse the guy that power cycled the wrong box. The sun comes up and it is easier to drive.<br />
<br />
I sit here, waiting on the OS to finish installing so I can restore the backup and incremental data again.  Hours of content lost.  The content team is hand writing HTML that other developers are rsyncing around to the servers.<br />
<br />
The good news?  All the work done in 2007 to separate our front end and backend worked.  The front end works fine (99%).  Just no new content.  Well, except for the hand done HTML.<br />
<br />
Note to self: Get that main database replication working again.  ASAP.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Tue, 05 Aug 2008 09:39:20 -0500</pubDate>
            <category>MySQL</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/2008/07/24/156/</guid>
            <title>Where Drizzle fits in for me</title>
            <link>http://brian.moonspot.net/2008/07/24/156/</link>
            <description><![CDATA[So, most of you have heard about Drizzle by now.  For those that have not, you can check out <a href="http://www.google.com/search?q=drizzle+site%3Aplanetmysql.org&amp;ie=utf-8&amp;oe=utf-8&amp;aq=t&amp;rls=org.mozilla:en-US:official&amp;client=firefox-a">many, many blog posts</a> or the <a href="https://launchpad.net/drizzle">Launchpad page</a>.<br />
<br />
The <a href="http://developers.slashdot.org/article.pl?sid=08/07/23/1234203">thread on Slashdot</a> about Drizzle was quite negative.  Most misunderstand what Drizzle is about.  SQLite is not a good solution when you have 100 web servers.  Let me describe how it I would use it and maybe that will help some understand it.<br />
<br />
When it comes to MySQL use, <a href="http://dealnews.com/">dealnews</a> has two very different use cases.  The first is an enterprise storage system that involves content creation, reporting and data warehousing.  For that layer of our business, we are using more and more advanced features as they become available.  We use triggers and stored procedures.  We use complex data types for specific use cases.  All those features are a big gain.<br />
<br />
The other way that we use MySQL is for serving content to our readers.  I have <a href="http://brian.moonspot.net/2007/06/23/caching-and-patience/">written</a> <a href="http://brian.moonspot.net/2007/08/29/out-with-cluster-hello-replication/">about</a> this before.  For this purpose, we avoid joins, don't use any advanced features.  We do use replication, indexes and intelligent queries.  We don't (as one slashdot reader claimed) do all of our processing in the code.  That would be stupid.  If you do that you are ignorant.  I will stop talking about that before this becomes a rant.  I do believe in letting MySQL do my work for me.<br />
<br />
This is where Drizzle fits in.  To serve content, I don't need stored procedures, triggers, views or any of that other stuff.  The whole database that the front end web servers use is basically a view.  It is a denormalized, prepared version of the real data.  I store objects. But, I have to be able to sort and filter the data in a way that SQL allows me to do.  CouchDB sounds interesting.  Maybe one day it will be there.  It is sill in the optimization phase.<br />
<br />
Now, some say that this is just MySQL 3.x all over again.  Well, you clearly have not been listening to the really smart people that are working on Drizzle.  They are doing more than just removing the 4.1 and 5.x features from MySQL.  They are removing things that don't make sense for this use case.  They are adding things that do make sense.  They are replacing parts of the code base where there is a better library or way of doing it.  At this point, they have no feature requirements to meet.  They have no deadlines.  They are making what they think the high volume web world and/or cloud computing needs.  They are making it plugable:  think Apache modules or PHP extensions.  So, if you need feature XYZ that was yanked out, you can add it back in (hopefully) via the internal API.  There is a lot more going on here than just removing "features".<br />
<br />
So, I am cheering on the folks working on Drizzle.  I have joined their community and will provide what feedback I can from userland.  I am no C++ coder.  I can read it.  I can debug it.  But, writing it or doing heavy lifting is not in my skill set.  Hopefully I can contribute]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Thu, 24 Jul 2008 13:17:26 -0500</pubDate>
            <category>memcached</category>
            <category>MySQL</category>
            <category>PHP</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/2008/07/22/usability-fail/</guid>
            <title>Usability FAIL</title>
            <link>http://brian.moonspot.net/2008/07/22/usability-fail/</link>
            <description><![CDATA[I can't be at OSCON this year.  But my colleague Rob is and he just posted a <a href="http://codelemur.wordpress.com/2008/07/21/usability-in-everyday-life/">usability post</a> about, of all things, the Double Tree hotel where I am sure a lot of you are staying.  Great stuff.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Tue, 22 Jul 2008 09:52:03 -0500</pubDate>
            <category>MySQL</category>
            <category>PHP</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/2008/07/03/caching-and-ttl-behavior/</guid>
            <title>Caching and TTL behavior</title>
            <link>http://brian.moonspot.net/2008/07/03/caching-and-ttl-behavior/</link>
            <description><![CDATA[So, I am working on <a href="http://code.google.com/p/memproxy/">MemProxy</a> some.  Mainly, I am trying to implement more of the Cache-Control header's many options.  The one that has me a bit perplexed s-maxage.  Particularly when combined with max-age.<br />
<br />
s-maxage is the maximum time in seconds an item should remain in a shared cache.  So, if s-maxage is set by the application server, my proxy should keep it for that amount of time at the most.  Up until now, I have just been looking at max-age.  But, s-maxage is the proper one for a proxy to use if it is present.  I do not send the s-maxage through because this is a reverse proxy and, IMO, that is proper behavior for an application accelerating proxy.  However, I do send forward the max-age value that is set by the application servers.  If no max-age is set, I send a default as defined in the script.  Also, if no-cache or no-store is set, I send those and a max-age of 0.<br />
<br />
My problem arises when max-age is less than s-maxage.  Up until now, I have sent a max-age back to the client that represents the time left for the cached item in my proxy's cache.  So, if the app server sent back max-age=300 and a request comes in and the cache is found and the cache was created 100 seconds ago, I send max-age-200 back to the client.  But, I was only using max-age before.  Now, in cases where s-maxage is longer than max-age, I would come up with negative numbers.  That is not cool.  The easiest solution would be to always send the original max-age back to the client.  But, that seems kind of lame.<br />
<br />
So, my question is, if you are using an application (HTTP or otherwise) accelerator, what would you expect?  If you application set a max-age of 300 would you always expect the end client to receive a max-age of 300?  Or should it count down over time?  The only experience I have is a CDN.  If you watch CDN traffic, the max-age gets smaller and smaller over time until it hits 0.  I have not tried sending an s-maxage to my CDN.  I don't know what they would do with that.  Maybe that is a good test.<br />
<br />
UPDATE: Writing this gave me an idea.  If the item will be in the proxy cache longer than the max-age ttl, send the full max-age ttl.  Otherwise, send the time left in the proxy cache.  Thoughts on that?<br />
<br />
(thanks for being my <a href="http://compaspascal.blogspot.com/2007/12/teddy-bear-principle-in-programming.html">teddy bear</a> blogosphere)]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Wed, 02 Jul 2008 23:56:25 -0500</pubDate>
            <category>Caching</category>
            <category>memcached</category>
            <category>MySQL</category>
            <category>PHP</category>
            <category>Programming</category>
        </item>
    </channel>
</rss>
