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

<channel>
	<title>From the CEO</title>
	<atom:link href="http://www.amainhobbies.com/FromTheCEO/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.amainhobbies.com/FromTheCEO</link>
	<description>Comments from the CEO of A Main Hobbies</description>
	<lastBuildDate>Mon, 10 Sep 2012 18:30:12 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Using Couchbase as an ASP.NET Session State Provider</title>
		<link>http://www.amainhobbies.com/FromTheCEO/2012/09/09/using-couchbase-as-an-asp-net-session-state-provider/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=using-couchbase-as-an-asp-net-session-state-provider</link>
		<comments>http://www.amainhobbies.com/FromTheCEO/2012/09/09/using-couchbase-as-an-asp-net-session-state-provider/#comments</comments>
		<pubDate>Mon, 10 Sep 2012 00:00:53 +0000</pubDate>
		<dc:creator>Kendall Bennett</dc:creator>
				<category><![CDATA[None]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[ASP.NET MVC]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Couchbase]]></category>
		<category><![CDATA[NoSQL]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.amainhobbies.com/FromTheCEO/?p=231</guid>
		<description><![CDATA[As you probably know by now, we are using Couchbase for caching data on our web site. However Couchbase contains support for not just cache data, but also for persistent data that is stored on disk using a NoSQL architecture. Once we were actively using Couchbase for our caching tier, the next step was to [...]]]></description>
				<content:encoded><![CDATA[<p>As you probably know by now, we are using <a href="http://www.couchbase.com/">Couchbase </a>for caching data on our web site. However Couchbase contains support for not just cache data, but also for persistent data that is stored on disk using a NoSQL architecture. Once we were actively using Couchbase for our caching tier, the next step was to use it for storing data. The first thing we decided to move to Couchbase, was our session data, which up until that point had been stored in MySQL.<br />
<span id="more-231"></span><br />
Storing session data in Couchbase was pretty easy to get started with using the Couchbase ASP.NET library which contains a port of the Enyim project Memcached provider to Couchbase. I started with this library and created my own fork on GitHub, so I could add the features we needed for our version (and also to fix any bugs we ran across). You can find my fork of the ASP.NET provider library using the URL below:</p>
<p><a href="https://github.com/kendallb/couchbase-aspnet" target="_blank">https://github.com/kendallb/couchbase-aspnet</a></p>
<p>The first thing we noticed when we starting using the new session state provider is that the web site would lock up for about 30 seconds when rendering certain web pages. It turns out that there were some nasty bugs in the Enyim code that would crop up if you had a lot of parallel requests to the same session state store item. This is not something most web sites would have to deal with, but in our case we have some pages that generate a flurry of AJAX requests to the server when they load that would cause the session state provider to leave a session stuck in the locked state. When this happens IIS will spin attempting to get a write lock on the session state item, until a timeout occurs (usually 30 seconds) at which time it will forcibly clear the lock and continue on.</p>
<p>Examining the session state code in detail and comparing it line by line to our existing MySQL session state provider (which did not have this problem), we discovered the primary cause of the issue was that the code to release the locks on a session state item was not using the Couchbase CAS operation. Hence you could end up with a situation where one thread had a lock on the session and would clear it, but it&#8217;s cleared value would get overwritten by another thread attempting to lock it and it would never get cleared. The fix for this is included in the session state provider library in the above link.</p>
<h3>Disabling Session Exclusive Access for Performance</h3>
<p>One annoying feature that IIS has is that it considers session state to be exclusive and will block concurrent access to the session state unless you mark the session state as read only. You can read more about it on the <a href="http://msdn.microsoft.com/en-us/library/ms178581.aspx" target="_blank">MSDN documentation pages for the ASP.NET session state</a>, but the important part is as follows:</p>
<blockquote>
<h3>Concurrent Requests and Session State</h3>
<p>Access to ASP.NET session state is exclusive per session, which means that if two different users make concurrent requests, access to each separate session is granted concurrently. However, if two concurrent requests are made for the same session (by using the same <a href="http://msdn.microsoft.com/en-us/library/system.web.sessionstate.httpsessionstate.sessionid.aspx">SessionID</a> value), the first request gets exclusive access to the session information. The second request executes only after the first request is finished. (The second session can also get access if the exclusive lock on the information is freed because the first request exceeds the lock time-out.) If the <a href="http://msdn.microsoft.com/en-us/library/system.web.configuration.pagessection.enablesessionstate.aspx">EnableSessionState</a> value in the @ Page directive is set to ReadOnly, a request for the read-only session information does not result in an exclusive lock on the session data. However, read-only requests for session data might still have to wait for a lock set by a read-write request for session data to clear.</p></blockquote>
<p>Although this seems like a reasonable requirement, and in fact ensures that two threads may not stomp on the same session data, it can in fact lead to performance issues when you have pages that make a lot of concurrent AJAX requests to the server. The <em>correct</em> solution is to decorate your AJAX methods in ASP.NET MVC with the <a href="http://msdn.microsoft.com/en-us/library/system.web.sessionstate.sessionstatebehavior.aspx" target="_blank">Read Only session state behavior </a>using the <a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.sessionstateattribute.aspx" target="_blank">ASP.NET MVC SessionState</a> attribute. That way no session data is going to be written out when those AJAX methods execute so IIS will allow them to run in parallel.</p>
<p>However in our case we are compiling and running a ton of legacy PHP code using <a href="http://www.php-compiler.net/" target="_blank">Phalanger</a>, which compiles the PHP code into .NET code that executes alongside our ASP.NET MVC code. Since this kind of session locking is not implemented in PHP at all, and it is difficult (if not impossible) to change the legacy code to enable read only sessions when needed, we started looking for a way to disable this feature in our custom session handler so we could get the Phalanger compiled PHP code to perform the same as it did under real PHP.</p>
<p>It turns out that supporting this is quite easy by adding a new flag to the Web.config provider entry and simply avoiding any locking in the session handler if is not desired. If you are interested in the implementation, look at the code and how it uses the exclusiveAccess flag internally in the handler. If you just want to use it, you can set the value using the &#8220;exclusiveAccess&#8221; attribute of the provider entry:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;sessionState customProvider=&quot;Couchbase&quot; mode=&quot;Custom&quot;&gt;
  &lt;providers&gt;
    &lt;add name=&quot;Couchbase&quot; type=&quot;Couchbase.AspNet.SessionState.CouchbaseSessionStateProvider, Couchbase.AspNet&quot; exclusiveAccess=&quot;false&quot; /&gt;
  &lt;/providers&gt;
&lt;/sessionState&gt;
</pre>
<p>Although I would highly recommend you use the correct solution of marking code you need to run in parallel with the ReadOnly session state attributes, sometimes it is easier when working with legacy code to simply turn off this feature <img src='http://www.amainhobbies.com/FromTheCEO/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.amainhobbies.com/FromTheCEO/2012/09/09/using-couchbase-as-an-asp-net-session-state-provider/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Invalidating Couchbase Cache Entries with Sentinels</title>
		<link>http://www.amainhobbies.com/FromTheCEO/2012/09/09/invalidating-couchbase-cache-entries-with-sentinels/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=invalidating-couchbase-cache-entries-with-sentinels</link>
		<comments>http://www.amainhobbies.com/FromTheCEO/2012/09/09/invalidating-couchbase-cache-entries-with-sentinels/#comments</comments>
		<pubDate>Sun, 09 Sep 2012 23:23:16 +0000</pubDate>
		<dc:creator>Kendall Bennett</dc:creator>
				<category><![CDATA[None]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Caching]]></category>
		<category><![CDATA[Couchbase]]></category>
		<category><![CDATA[NoSQL]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.amainhobbies.com/FromTheCEO/?p=229</guid>
		<description><![CDATA[In my previous blog post I discussed how we converted from a file based caching solution to one based on Couchbase. In this blog post I am going discuss the system we built to group cache entries together into logical groups, and the mechanism used to quickly invalidate all cache entries for a particular group [...]]]></description>
				<content:encoded><![CDATA[<p>In my <a title="Couchbase – High performance caching for ASP.NET" href="http://www.amainhobbies.com/FromTheCEO/2012/07/27/couchbase-caching-on-windows-for-asp-net/">previous blog post</a> I discussed how we converted from a file based caching solution to one based on <a href="http://www.couchbase.com/">Couchbase</a>. In this blog post I am going discuss the system we built to group cache entries together into logical groups, and the mechanism used to quickly invalidate all cache entries for a particular group using sentinels rather than lists.<span id="more-229"></span></p>
<h3>First Version: Lists of Cached Items</h3>
<p>The original file based solution simply managed groups of cache values as part of a cache block, and because the groups were structured as directories on disk, it was easy enough to invalidate all cache entries for a group simply by recursing over the directory and deleting all the cache files. Hence the first version of our Couchbase cache store class was implemented very similarly. When an item was added to the cache, it was also added to a list of all cached items store in a meta data object for the cache group. Then when a group of cached items needed to be invalidated, we would read the list of items from the cache and then iterate over it deleting them from the Couchbase cache.</p>
<p>The initial implementation of the Read and Write functions looked like this:</p>
<pre class="brush: csharp; title: ; notranslate">
/// &lt;summary&gt;
/// Adds a value to a dictionary of type &lt;TKey, TValue&gt; with the given key and value using a
/// Check-And-Set operation and retries. Note that if the item exists in the list, the value
/// is updated otherwise a new entry is added.
/// &lt;/summary&gt;
/// &lt;typeparam name=&quot;TKey&quot;&gt;Type of the key for the items in the list&lt;/typeparam&gt;
/// &lt;typeparam name=&quot;TValue&quot;&gt;Type of the value for the items in the list&lt;/typeparam&gt;
/// &lt;param name=&quot;client&quot;&gt;Couchbase client&lt;/param&gt;
/// &lt;param name=&quot;key&quot;&gt;Key used to identify the hash table&lt;/param&gt;
/// &lt;param name=&quot;entryKey&quot;&gt;Key for the entry to be stored in the hash table&lt;/param&gt;
/// &lt;param name=&quot;entryValue&quot;&gt;Value for the entry to be stored in the hash table&lt;/param&gt;
private void AddToHashWithCas&lt;TKey, TValue&gt;(
    ICouchbaseClient client,
    string key,
    TKey entryKey,
    TValue entryValue)
{
    // Now keep track of all the items in this cache group
    CasResult&lt;bool&gt; casResult;
    do {
        // Try to read the existing list (or create one if it does not exist)
        var result = client.GetWithCas&lt;Dictionary&lt;TKey, TValue&gt;&gt;(key);
        var items = result.Result ?? new Dictionary&lt;TKey, TValue&gt;();

        // See if there is an existing entry
        if (items.ContainsKey(entryKey)) {
            // Update the value if it exists already
            items[entryKey] = entryValue;
        } else {
            // Add a new entry if it does not exist
            items.Add(entryKey, entryValue);
        }

        // Attempt to save the items using a Check-And-Set operation
        casResult = client.Cas(StoreMode.Set, key, items, result.Cas);
    } while (casResult.Result == false);
}

/// &lt;summary&gt;
/// Writes out a serialized object to the cache
/// &lt;/summary&gt;
/// &lt;param name=&quot;o&quot;&gt;Object to write to the cache&lt;/param&gt;
/// &lt;param name=&quot;group&quot;&gt;Cache group that this item belongs to&lt;/param&gt;
/// &lt;param name=&quot;key&quot;&gt;Key name for this cache item&lt;/param&gt;
/// &lt;param name=&quot;expiresAt&quot;&gt;Optional date/time stamp that the cached item will expire at&lt;/param&gt;
public void Write(
    object o,
    string group,
    string key,
    DateTime? expiresAt)
{
    // Get access to the cache
    var client = GT.CBCache;

    // Determine the full key name for this cache item
    var fullKey = group + '/' + key;
    var lockKey = fullKey + &quot;.lock&quot;;

    // Store the item in the cache
    if (expiresAt == null) {
        client.Store(StoreMode.Set, fullKey, o);
    } else {
        client.Store(StoreMode.Set, fullKey, o, (DateTime)expiresAt);
    }

    // Now keep track of all the items in this cache group
    AddToHashWithCas&lt;string, DateTime?&gt;(client, group, fullKey, expiresAt);

    // Clear the lock
    client.Store(StoreMode.Set, lockKey, false);
}

/// &lt;summary&gt;
/// Reads a serialized object from the cache
/// &lt;/summary&gt;
/// &lt;param name=&quot;o&quot;&gt;Place to return the object read from the cache&lt;/param&gt;
/// &lt;param name=&quot;group&quot;&gt;Cache group that this item belongs to&lt;/param&gt;
/// &lt;param name=&quot;key&quot;&gt;Key name for this cache item&lt;/param&gt;
/// &lt;returns&gt;True if the item was read from the cache, false if not&lt;/returns&gt;
public bool Read(
    out object o,
    string group,
    string key)
{
    // Get access to the cache
    var client = GT.CBCache;

    // Determine the keys we need. The key of the item we key off the primary group
    var fullKey = group + '/' + key;
    var lockKey = fullKey + &quot;.lock&quot;;

    // Loop around trying to read the cache until either it is valid, or we get the write lock for the cache. This way
    // we guarantee that we will only ever have one writer actually generating the cache data at a time.
    CasResult&lt;bool&gt; casResult;
    CasResult&lt;bool&gt; locked = new CasResult&lt;bool&gt;();
    do {
        // Loop until the lock is clear in case another instance is writing the cache. We time out after 10 seconds
        for (int i = 0; i &lt; TimeoutLoops; i++) {
            // Check if someone has the lock
            locked = client.GetWithCas&lt;bool&gt;(lockKey);
            if (!locked.Result) {
                // Not locked for writing, so we are good to go
                break;
            }

            // Sleep for 100 milliseconds to allow the lock to get cleared
            System.Threading.Thread.Sleep(TimeoutSleep);
        }

        // Read the item from the cache and return it if found
        if ((o = client.Get(fullKey)) != null) {
            return true;
        }

        // Check if we got the lock. If not then someone has the lock and we timed out, so just clear the lock
        // and move on. This should not happen, but if it does it is OK.
        if (locked.Result) {
            client.Store(StoreMode.Set, lockKey, false);
            return false;
        }

        // Attempt to set the lock using a Check-And-Set operation
        casResult = client.Cas(StoreMode.Set, lockKey, true, locked.Cas);
    } while (casResult.Result == false);

    // Return false indicating that the cache is invalid and we have the write lock
    return false;
}

/// &lt;summary&gt;
/// Resets all the cache entries for this specific cache group
/// &lt;/summary&gt;
/// &lt;param name=&quot;groupKey&quot;&gt;Cache group to clear&lt;/param&gt;
public void ClearGroup(
    ICouchbaseClient client,
    string groupKey)
{
    Dictionary&lt;string, DateTime?&gt; items;
    CasResult&lt;bool&gt; casResult;
    do {
        // Try to read the existing list (or create one if it does not exist)
        var result = client.GetWithCas&lt;Dictionary&lt;string, DateTime?&gt;&gt;(groupKey);
        items = result.Result ?? new Dictionary&lt;string, DateTime?&gt;();

        // Clear the list using a Check-And-Set operation
        casResult = client.Cas(StoreMode.Set, groupKey, new Dictionary&lt;string, DateTime?&gt;(), result.Cas);
    } while (casResult.Result == false);

    // Now loop through and kill off all the cache entries referenced in the list. Although
    // it is possible someone might have added a new cache entry to the list while this is
    // being processed, as long as we clear each one each cache entry will end up being
    // correctly refreshed
    foreach (var item in items) {
        client.Remove(item.Key);
    }
}
</pre>
<p>Using these functions is pretty simple. Code that wants to cache something will first call the Read() function and attempt to read an existing cache block from the cache and if that fails, it will then generate the cached block data, and call the write function:</p>
<pre class="brush: csharp; title: ; notranslate">
string group = &quot;myGroup&quot;;
string key = &quot;myItem&quot;;
object o;
if (!Read(out o, group, key)) {
    o = &quot;Something to cache&quot;;
    Write(o, group, key, DateTime.Now.AddMinutes(5));
}

// Do something with object o
</pre>
<p>If the Read() function finds a valid cache entry, it simply returns the result. If the Read() function fails, it will grab the lock for the cached item using a <a href="http://www.couchbase.com/docs/couchbase-sdk-net-1.1/couchbase-sdk-net-retrieve-get.html#table-couchbase-sdk_net_getwithcas">Check And Set operation</a> in Couchbase, and then return false. The caller then generates the content to be cached, and calls the Write() function. This function then writes the cached data to the cache, adds a reference to the cached item to the list of all cache items for this group and then clears the lock. This ensures that no other code will be generating the same cached item at the same time, so if an item expires any other threads needing that same cached item will end up blocking until the locks is cleared, at which time they will pick up the newly generated cache item.</p>
<p>Although it may seem inefficient to make all the other threads block and wait for the first thread to generate the cached item, in practice this turns out to be more efficient than letting all the threads attempt to generate the cached item at the same time. If for instance the cached item is generated using expensive calls to a SQL database, and suddenly 100 threads all need the same cached item, the SQL server is going to be able to generate the content for 1 thread making a set of expensive SQL calls much faster than having 100 threads all make the same SQL calls in parallel.</p>
<p>Also it is worth pointing out that in this implementation we use a hash table to store the list of items in a cache block rather than a list, primarily because our caches end up with thousands of items per group and using a hash table makes maintaining the list much more efficient than using a link list (which would have to do a linear search to see if the item was already in the list).</p>
<p>Although the code above works fine, the process of invalidating cache entries is still time consuming because the ClearGroup() function has to iterate through all the items in the group and remove them from the cache store, which can take some time with thousands of items in the group. Also the cache items in the group may be already getting generated while the clear operation is in progress, since we don&#8217;t block them from being generate during clears.</p>
<p>On top of that we can only group cache entries together by placing them in a single group. It would be nice if there was a way to be able to make a cache entry belong to multiple groups, giving you more control over when an item is invalidated in the cache. And it would also be nice to be able to improve the performance of the clear operation. Thankfully all of this can be done using the concept of Sentinels!</p>
<h3>Second Version: Using Sentinels to Avoid Lists</h3>
<p>So how does a sentinel work? The basic concept is that rather than storing references to all the cache items in a list that represent a group of cache items, we instead store a list of prior <strong>sentinel</strong> values as meta data long with the cached item. In essence we are flipping things upside down, and don&#8217;t store what items are in a group, but rather what groups an item belongs to. When we need to read a cached item, we read a list of prior sentinel values stored with the item, and compare it to all the current sentinel values. If any of the values do not match, we consider the item invalidated and we ignore it even if it still exists in the cache.</p>
<p>What is great about using this is that the overhead of managing lists of items in a group is gone, because we no longer track what items belong to a group. Instead we have a much smaller overhead to keep track of the groups that an item might belong to. But more importantly, we can very quickly invalidate all items in a group simply by doing a fast, atomic <a href="http://www.couchbase.com/docs/couchbase-sdk-net-1.1/couchbase-sdk-net-update-increment.html#table-couchbase-sdk_net_increment">Couchbase Increment operation</a> on a sentinel. This will instantly invalidate any items that belong to that group the next time a read attempt is made for any items in that group.</p>
<p>So our final implementation of the Read and Write functions looks like this:</p>
<pre class="brush: csharp; title: ; notranslate">
/// &lt;summary&gt;
/// Writes out a serialized object to the cache
/// &lt;/summary&gt;
/// &lt;param name=&quot;o&quot;&gt;Object to write to the cache&lt;/param&gt;
/// &lt;param name=&quot;group&quot;&gt;Cache group that this item belongs to&lt;/param&gt;
/// &lt;param name=&quot;key&quot;&gt;Key name for this cache item&lt;/param&gt;
/// &lt;param name=&quot;expiresAt&quot;&gt;Optional date/time stamp that the cached item will expire at&lt;/param&gt;
public void Write(
    object o,
    string group,
    string key,
    DateTime? expiresAt)
{
    // Get access to the cache
    var client = GT.CBCache;

    // Determine the keys we need
    var fullKey = group + '/' + key;
    var lockKey = fullKey + &quot;.lock&quot;;

    // Store the item in the cache
    if (expiresAt == null) {
        client.Store(StoreMode.Set, fullKey, o);
    } else {
        client.Store(StoreMode.Set, fullKey, o, (DateTime)expiresAt);
    }

    // Clear the lock to let other processes into the cached item
    client.Store(StoreMode.Set, lockKey, false);
}

/// &lt;summary&gt;
/// Reads a serialized object from the cache
/// &lt;/summary&gt;
/// &lt;param name=&quot;o&quot;&gt;Place to return the object read from the cache&lt;/param&gt;
/// &lt;param name=&quot;group&quot;&gt;Cache group that this item belongs to&lt;/param&gt;
/// &lt;param name=&quot;key&quot;&gt;Key name for this cache item&lt;/param&gt;
/// &lt;param name=&quot;dependencies&quot;&gt;List of dependent sentinels this item is dependent on&lt;/param&gt;
/// &lt;returns&gt;True if the item was read from the cache, false if not&lt;/returns&gt;
public bool Read(
    out object o,
    string group,
    string key,
    List&lt;string&gt; dependencies = null)
{
    // Get access to the cache
    var client = GT.CBCache;

    // Determine the keys we need. The key of the item we key off the primary group
    var fullKey = group + '/' + key;
    var metaKey = fullKey + &quot;.meta&quot;;
    var lockKey = fullKey + &quot;.lock&quot;;

    // Set the default return values
    o = null;

    // Loop around trying to read the cache until either it is valid, or we get the write lock for the cache. This way
    // we guarantee that we will only ever have one writer actually generating the cache data at a time.
    CasResult&lt;bool&gt; casResult;
    CasResult&lt;bool&gt; locked = new CasResult&lt;bool&gt;();
    List&lt;string&gt; priorSentinels, sentinels;
    do {
        // Loop until the lock is clear in case another instance is writing the cache. We time out after 10 seconds
        for (int i = 0; i &lt; TimeoutLoops; i++) {
            // Check if someone has the lock
            locked = client.GetWithCas&lt;bool&gt;(lockKey);
            if (!locked.Result) {
                // Not locked for writing, so we are good to go
                break;
            }

            // First try to get the cached item. If it is still present then we can simply serve up stale
            // data while one thread is writing the new cache data is being generated
            if ((o = client.Get(fullKey)) != null) {
                return true;
            }

            // Sleep for 100 milliseconds to allow the lock to get cleared
            System.Threading.Thread.Sleep(TimeoutSleep);
        }

        // Read the items we need from the cache with a multi-get
        var keys = new List&lt;string&gt; { group, metaKey, fullKey };
        if (dependencies != null) {
            // Add in any dependencies that this item depends on if required
            keys.AddRange(dependencies);
        }
        var results = client.Get(keys);
        priorSentinels = results.ContainsKey(metaKey) ? (List&lt;string&gt;)results[metaKey] : new List&lt;string&gt; { &quot;0&quot; };
        sentinels = new List&lt;string&gt; { results.ContainsKey(group) ? (string)results[group] : &quot;0&quot; };
        if (dependencies != null) {
            // If we have dependencies, make sure we get the sentinel value or set it to the default if not present
            foreach (var dependency in dependencies) {
                sentinels.Add(results.ContainsKey(dependency) ? (string)results[dependency] : &quot;0&quot;);
            }
        }

        // Check if any of the sentinels indicate this item is invalidated. If any sentinels don't match the values
        // last time the cache was written then this item is invalid
        if (priorSentinels.SequenceEqual(sentinels)) {
            // Check if we got the cached item
            if (results.ContainsKey(fullKey) &amp;&amp; ((o = results[fullKey]) != null)) {
                return true;
            }
        }

        // Check if we got the lock. If not then someone has the lock and we timed out just continue on. The write
        // code will eventually clear the lock and let other threads in. But we log this so we know it happened.
        if (locked.Result) {
            // NOTE: Add code to log this error to an error log in here...
            break;
        }

        // Attempt to set the lock using a Check-And-Set operation
        casResult = client.Cas(StoreMode.Set, lockKey, true, locked.Cas);
    } while (casResult.Result == false);

    // Store the sentinels for this item before it gets written since we know the cached item will now
    // be valid after the write completes. But we cannot write the value in the write code, because we
    // have to make sure we write the sentinel values we read above in case any of them have now been changed
    // (in which case the next read for the cache would be invalid also). So it is better to write them here
    // than to expect the caller to pass them to the write function.
    client.Store(StoreMode.Set, metaKey, sentinels);

    // Return false indicating that the cache is invalid and we have the write lock
    return false;
}

/// &lt;summary&gt;
/// Resets all the cache entries for this specific cache group
/// &lt;/summary&gt;
/// &lt;param name=&quot;sentinel&quot;&gt;Cache group to clear&lt;/param&gt;
public void InvalidateCache(
    string sentinel)
{
    // Increment the sentinel for this group to invalidate old entries. We start with a default value of 1
    // the first time a value is written since by default when the value is not present we assume it is 0
    GT.CBCache.Increment(sentinel, 1, 1);
}
</pre>
<p>As you can see from the code above, the Write() function is now much simpler as it no longer has to update a list of items in the group when it writes an item to the cache. The read function on the other hand is more complex, as it is passed in an optional list of extra sentinel values that a cache item may depend upon. Once the read function has obtained the cache lock for the item, it then uses a fast Mult-Get operation in Couchbase to read all the values it needs, including the cached item and the value of all sentinel keys it depends upon. If the sentinels don&#8217;t exist, we give it a default value of &#8220;0&#8243; which will happen the first time that a sentinel is used and it has never been invalidated. Once the read operation has a list of current sentinel values and prior sentinel values we can compare if the two lists are identical and if they are, return the actual cache item if it was present.</p>
<p>Also note that the Write() function never writes the current sentinel values to the meta data item, but rather the Read() function does that right before it exits and returns false. We know that whoever is calling the Read() function will immediately call the Write() function if Read() returns false, and we also know that the Read() function has the write lock for the cache item when it exits also.</p>
<p>Using the new code is pretty much the same as before, but we can also pass in an optional list of other sentinels we might want to use to invalidate that particular cache entry:</p>
<pre class="brush: csharp; title: ; notranslate">
string group = &quot;myGroup&quot;;
string key = &quot;myItem&quot;;
object o;
if (!Read(out o, group, key, new List&lt;string&gt; { &quot;secondGroup&quot; })) {
    o = &quot;Something to cache&quot;;
    Write(o, group, key, DateTime.Now.AddMinutes(5));
}

// Do something with object o
</pre>
<p>Finally when we decide we wish to invalidate a group of cache items using a particular sentinel, we use the InvalidateCache() function above which just increments the sentinel value by 1. Note that we always start incrementing with a value of 1 in this function since we assume the absence of a sentinel value is equivalent to a value of 0 in the read code. So the first time we write a sentinel value, it must be 1 to ensure it actually caused any items covered by the sentinel to be invalidated.</p>
<p>That&#8217;s it! Have fun using Couchbase and I hope this blog will help you build a better caching solution for your own software.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.amainhobbies.com/FromTheCEO/2012/09/09/invalidating-couchbase-cache-entries-with-sentinels/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL MyISAM: Not a good choice for high performance web sites!</title>
		<link>http://www.amainhobbies.com/FromTheCEO/2012/07/31/mysql-myisam-not-a-good-choice-for-high-performance-web-sites/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=mysql-myisam-not-a-good-choice-for-high-performance-web-sites</link>
		<comments>http://www.amainhobbies.com/FromTheCEO/2012/07/31/mysql-myisam-not-a-good-choice-for-high-performance-web-sites/#comments</comments>
		<pubDate>Tue, 31 Jul 2012 22:12:09 +0000</pubDate>
		<dc:creator>Kendall Bennett</dc:creator>
				<category><![CDATA[None]]></category>
		<category><![CDATA[Databases]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.amainhobbies.com/FromTheCEO/?p=190</guid>
		<description><![CDATA[As mentioned in my previous blog post, we had been having site performance problems for a while now. The previous blog post detailed how we solved the performance problems we had at night when our nighty scripts would run, but that was not the final solution. We still had more performance problems that would crop [...]]]></description>
				<content:encoded><![CDATA[<p>As mentioned in <a title="Solving MySQL nightly performance problems with low_priority_updates" href="http://www.amainhobbies.com/FromTheCEO/2012/07/30/solving-mysql-nightly-performance-problems-with-low_priority_updates/" target="_blank">my previous blog post</a>, we had been having site performance problems for a while now. The previous blog post detailed how we solved the performance problems we had at night when our nighty scripts would run, but that was not the final solution. We still had more performance problems that would crop up during the day, and this blog post details the steps we took to finally resolve the problem for good.<span id="more-190"></span></p>
<h3>Faster web site == slower MySQL!</h3>
<p>One of the things we did in our quest for performance was to <a title="PHP on Windows; what a silly idea!" href="http://www.amainhobbies.com/FromTheCEO/2012/03/10/php-on-windows-what-a-silly-idea/" target="_blank">re-compile all our PHP code into .NET using Phalanger</a>. This definitely made the web site faster and lowered the CPU load on the Windows web server substantially, but we quickly discovered that having faster code on the web server had the side effect of causing more performance problems with MySQL, not less. Clearly the MySQL server was not able to keep up with the amount of traffic being sent it&#8217;s way during normal operation, which was odd because when these issues were happening there was really not a whole lot going of activity on the MySQL server.</p>
<h3>Caching won&#8217;t solve core DB issues</h3>
<p>The first thing we did in an attempt to solve these performance problems was to revisit our caching system, and <a title="Couchbase – High performance caching for ASP.NET" href="http://www.amainhobbies.com/FromTheCEO/2012/07/27/couchbase-caching-on-windows-for-asp-net/" target="_blank">re-implement it using Couchbase</a>. This produced significant performance improvements in the best case when items were in the cache, but the worst case performance problems remained.</p>
<p>Part of our caching architecture is to ensure that only one web server thread is actively generating the cached pages at a time to ensure that the load on the MySQL server is kept as low as possible. It is much faster to have only one thread generating the SQL select traffic to the MySQL server and to have the other threads wait, rather than to have them all send the same SQL select traffic at the same time. In the best case all the threads would run at the same speed anyway, however if you have 100 threads all asking the MySQL server to do the same thing in parallel, it is going to run about 100X slower than just one thread making those calls! So when another thread tries to get a cache item that is expired and another thread needs the same cache entry, the second thread will end up blocking with small sleeps in a loop until either the cache entry is valid again, or we hit a timeout after 10 seconds. Ten seconds is a LONG time for a web page, so it seemed like a reasonable timeout that should never happen in practice.</p>
<p>In theory if the MySQL server was acting up and behaving really slow, we might be be getting cache timeouts. So we went ahead and added some logging to the code to keep track of any timeouts that did occur. Once we enabled the logging on the live site we could clearly see the caching code was timing out hundreds of times a day! Which means that hundreds of times a day, pages were taking longer than 10 seconds to render, which is totally unacceptable. Clearly when the web site code had to reach out to MySQL to get the data to generate the web page content, it was slow. This has to be our performance bottleneck, so we kept looking.</p>
<h3>Slow performance when DB server seems idle?</h3>
<p>The real question was why? Looking at the first graph below taken while the web site was responding slowly, you can see that the MySQL server is not really doing a whole lot. The CPU usage was very low sitting around 5% with spikes up to 10%. The number of MySQL connections was also low hovering around 150 connections on average, and the database activity was not really all that high at an average of maybe 180 statements per second. By all counts the MySQL server should be blazing fast, but it was not! And we knew that the web server was quite slow during the peaks in the CPU activity from 13:00 to 14:00 and again from about 15:10 to 15:40.</p>
<div id="attachment_207" class="wp-caption alignnone" style="width: 567px"><a href="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/cpu_726.jpg"><img class="size-full wp-image-207" title="cpu_726" src="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/cpu_726.jpg" alt="" width="557" height="207" /></a><p class="wp-caption-text">CPU usage using MyISAM</p></div>
<div id="attachment_205" class="wp-caption alignnone" style="width: 564px"><a href="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/conn_726.jpg"><img class="size-full wp-image-205" title="conn_726" src="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/conn_726.jpg" alt="" width="554" height="206" /></a><p class="wp-caption-text">MySQL connections usings MyISAM</p></div>
<div id="attachment_209" class="wp-caption alignnone" style="width: 571px"><a href="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/db_726.jpg"><img class="size-full wp-image-209" title="db_726" src="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/db_726.jpg" alt="" width="561" height="205" /></a><p class="wp-caption-text">Database activity using MyISAM</p></div>
<h3>Excessive table locks will KILL performance!</h3>
<p>There had to be something else going on so we kept looking at the data with the MySQL Enterprise Monitor. One thing that caught my eye was the number of table locks going on, and here is where things start to get interesting. If you look at the graphs below you can see that there were a lot of table locks that were all grabbed immediately, but creeping in at the bottom of the graph are table locks that caused a wait condition. Then if you take a look at the table lock to wait ratio you can see big spikes in the graph that correspond to times when the web site performance was suffering! Aha! You will also notice that at the same time this happens we see spikes in CPU usage where it doubles from the low 5% to about 10% (visible in the graph above).</p>
<div id="attachment_213" class="wp-caption alignnone" style="width: 573px"><a href="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/table_locks_726.jpg"><img class="size-full wp-image-213" title="table_locks_726" src="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/table_locks_726.jpg" alt="" width="563" height="207" /></a><p class="wp-caption-text">Table locks using MyISAM</p></div>
<div id="attachment_211" class="wp-caption alignnone" style="width: 558px"><a href="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/lock_ratio_726.jpg"><img class="size-full wp-image-211" title="lock_ratio_726" src="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/lock_ratio_726.jpg" alt="" width="548" height="201" /></a><p class="wp-caption-text">Table lock wait ratio using MyISAM</p></div>
<p>So the core problem we had was the excessive amount of table locking going on, or more importantly, the fact that way too many threads were getting stuck waiting to get a table lock! This clearly explains why the DB server appeared slow, when in fact the CPU load indicated not much was going on. Clearly this was the cause of our MySQL server acting like it was overloaded, when nothing of significance was really going on.</p>
<h3>MyISAM tables don&#8217;t handle update load well</h3>
<p>So we spoke to Oracle support, and they pretty much told us the problem we had is that the MyISAM table type we are using just does not work well when you have large tables with a mix of selects and updates going on. One of the core issues with the MyISAM table type is that it does not support row level locking, but rather will lock the entire table when you need to do an update on any record in a table. Or worse, if you have deleted a record from a table which leaves a hole in the table file on disk where the deleted record was, it will also lock the table for inserts also as it will try to fill in that hole. You can work around the insert problem by <a href="http://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_concurrent_insert" target="_blank">setting the concurrent_insert feature to ALWAYS</a>, which will always insert new records at the end of the MyISAM table. We had already implemented that based on Oracle&#8217;s recommendation previously, however this simply does not solve the problem of table row updates. Some of our tables are really large so the updates can take a while due to indexing, so select traffic was getting blocked by updates on tables that also get lots of select traffic. Clearly we had reached the end of the road for the venerable MyISAM table type!</p>
<h3>InnoDB to the rescue!</h3>
<p>One of the biggest advantages of the InnoDB table type over the MyISAM table table (other than support for transactions) is that it can properly handle row level locking. This means that if you need to update a record in the database, the only time another thread that needs to read from the same table will block is if that thread needs to read the exact same record. Otherwise there is no lock contention and all of the requests can be handled nicely in parallel.</p>
<p>We had been planning for some time to convert our entire database over to the InnoDB table type format but this was a significant undertaking that would require our site to be down for an extended period of time, and it would require us to re-work all our existing database backup strategies. But it was sounding like we really needed to make the change, so we set about putting together a plan to make it happen. One of the first things we discovered was how to <a href="http://dev.mysql.com/doc/refman/5.5/en/innodb-multiple-tablespaces.html" target="_blank">enable a file per table for the InnoDB databases</a>, so each table would end up in a separate file just like our MyISAM tables. This makes it much, much easier to manage backups and deal with smaller parts of the database at a time for development purposes.</p>
<p>The next part was to schedule the downtime and run the upgrade. It ended up taking an entire hour of downtime on the web site to complete the upgrade on all the applications that needed it. Once the upgrade was done, it was really clear the next day during normal business hours that this was the right move and we should have done this a long, LONG time ago! As you can see from the graphs below, we started the upgrade process around 18:45, and it was all finished around 19:45 and performance normalized around 21:00 or so. The total CPU usage was much lower than it was prior to the upgrade, but more importantly it was fairly constant without the odd peaks we were seeing before. The total MySQL connections dropped off to about 100 connections after the upgrade, and the total database activity saw a small drop after the upgrade.</p>
<div id="attachment_206" class="wp-caption alignnone" style="width: 568px"><a href="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/cpu_726_innodb.jpg"><img class="size-full wp-image-206" title="cpu_726_innodb" src="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/cpu_726_innodb.jpg" alt="" width="558" height="200" /></a><p class="wp-caption-text">CPU usage using InnoDB</p></div>
<div id="attachment_204" class="wp-caption alignnone" style="width: 562px"><a href="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/conn_726_innodb.jpg"><img class="size-full wp-image-204" title="conn_726_innodb" src="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/conn_726_innodb.jpg" alt="" width="552" height="201" /></a><p class="wp-caption-text">MySQL connections usings InnoDB</p></div>
<div id="attachment_208" class="wp-caption alignnone" style="width: 564px"><a href="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/db_726_innodb.jpg"><img class="size-full wp-image-208" title="db_726_innodb" src="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/db_726_innodb.jpg" alt="" width="554" height="200" /></a><p class="wp-caption-text">Database activity using InnoDB</p></div>
<p>The big difference can be seen in the table lock to wait ratio. The total number of table locks did not really drop that much, but the table lock to wait ratio went to ZERO. More importantly, the web site performance was fantastic all day long! Now all the work we had done previously to improve the performance by compiling the web site with Phalanger and implementing better caching with Couchbase was finally paying off.</p>
<div id="attachment_212" class="wp-caption alignnone" style="width: 563px"><a href="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/table_locks_726_innodb.jpg"><img class="size-full wp-image-212" title="table_locks_726_innodb" src="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/table_locks_726_innodb.jpg" alt="" width="553" height="199" /></a><p class="wp-caption-text">Table locks using InnoDB</p></div>
<div id="attachment_210" class="wp-caption alignnone" style="width: 556px"><a href="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/lock_ratio_726_innodb.jpg"><img class="size-full wp-image-210" title="lock_ratio_726_innodb" src="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/lock_ratio_726_innodb.jpg" alt="" width="546" height="200" /></a><p class="wp-caption-text">Table lock wait ratio using InnoDB</p></div>
<h3>Conclusion</h3>
<p>So in conclusion, if you are still using the MyISAM table type and you still believe (as we did) that MyISAM is one of the fastest table types for most web sites where there is a mostly lots of select activity going on, think again! Clearly the InnoDB table type is significantly faster when you have large amounts of table data and even have a small amount of update traffic going on. And I would suspect that for small web sites, the performance difference between the two table tables would be negligible at best. One thing I know for sure is that I won&#8217;t build another database driven web site using MyISAM &#8211; our default table table will now always be InnoDB.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.amainhobbies.com/FromTheCEO/2012/07/31/mysql-myisam-not-a-good-choice-for-high-performance-web-sites/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Solving MySQL nightly performance problems with low_priority_updates</title>
		<link>http://www.amainhobbies.com/FromTheCEO/2012/07/30/solving-mysql-nightly-performance-problems-with-low_priority_updates/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=solving-mysql-nightly-performance-problems-with-low_priority_updates</link>
		<comments>http://www.amainhobbies.com/FromTheCEO/2012/07/30/solving-mysql-nightly-performance-problems-with-low_priority_updates/#comments</comments>
		<pubDate>Tue, 31 Jul 2012 04:26:43 +0000</pubDate>
		<dc:creator>Kendall Bennett</dc:creator>
				<category><![CDATA[None]]></category>
		<category><![CDATA[Databases]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.amainhobbies.com/FromTheCEO/?p=106</guid>
		<description><![CDATA[As anyone who developers software for a living knows, MySQL is a popular Open Source, high performance database system that is used by millions of active web sites every day. Our web site has been running on MySQL since the day it went live, and until recently the performance of MySQL has been excellent. However [...]]]></description>
				<content:encoded><![CDATA[<p>As anyone who developers software for a living knows, <a title="MySQL Open Source Database" href="http://en.wikipedia.org/wiki/MySQL" target="_blank">MySQL is a popular Open Source, high performance database system</a> that is used by millions of active web sites every day. Our web site has been running on MySQL since the day it went live, and until recently the performance of MySQL has been excellent. However a number of things happened over the last 12 months that caused our web site to have noticeable performance problems, most of which was caused by the growth in the size of the database. So for the last 12 months we have been on the hunt to solve the performance problems.<span id="more-106"></span></p>
<h3>New Hardware</h3>
<p>When we first started noticing performance issues we were running our entire web site all on one server, running under Windows Server 2008. The web site was running PHP for most of the front end, ASP.NET MVC for a lot of the back end and WCF web services for client/server warehousing applications. The initial thinking after examining the code was that the web server was just getting overloaded and we simply needed more horse power. So we ended up moving the database off the Windows machine that hosted the web site and the database, and onto a stand alone Linux machine just running MySQL. We also made sure the new machine had significantly improved hardware with more memory and more CPU. We also invested in an enterprise license for MySQL with Oracle, to get their reporting tools and technical support. After moving MySQL to the new hardware, things seemed a little better, but the problem was not solved. We still had terrible worst case performance issues where the site would stall.</p>
<h3>Recompile PHP code with Phalanger</h3>
<p>Around the same time we were still having performance problems with the web site we had also been experimenting with a fantastic tool called <a title="Phanalger - A PHP compiler for .NET" href="http://www.php-compiler.net/" target="_blank">Phalanger, a PHP compiler for .NET</a>. Since we had already been implementing all our new back end web site functionality in C# using ASP.NET MVC for the web site and WCF for our handheld warehousing computers, it made a lot of sense to work on recompiling all the PHP code into .NET so it could all run on the same platform. Not to mention I wanted to get off PHP and move towards .NET anyway for performance reasons, which I documented in <a title="Running PHP on Windows" href="http://www.amainhobbies.com/FromTheCEO/2012/03/10/php-on-windows-what-a-silly-idea/" target="_blank">one of my previous blog posts</a>. So around March this year we finished up the project to port to Phalanger and launched the new compiled web site. I was expecting to see big performance gains since on our development and testing machines we could see Phalanger was much faster than regular PHP.</p>
<p>But the problem was still not solved! Although the Windows server has much lower CPU usage than it did running on real PHP, we were still having worst case performance problems where the site would slow down for no apparent reason.</p>
<h3>Problems with Nightly Scripts</h3>
<p>Once we launched the web site live with Phalanger, we started running into another issue that had not cropped up before. Something was going on such that the web site would basically crash and need some CPR in the middle of the night when our nightly scripts fired up (big thanks to <a title="Rackspace - Awesome managed hosting!" href="http://www.rackspace.com/" target="_blank">Rackspace Rackers </a>for restarting the web site at 3am multiple times when it died over the last 6 months!). To help us figure these issues out we got the Oracle MySQL monitoring tools installed and could see that during the night when the nightly scripts started, we would see the number of connections from the web site to MySQL start to sky rocket, and the CPU load on the MySQL server would go nuts.</p>
<p>One of the biggest differences between running real PHP on Windows and running PHP compiled under Phalanger, is how IIS handles scaling the load. With real PHP it runs under FastCGI and there is a limit on the number of PHP processes that will be spawned to handle the load based on how you configure FastCGI. We found our site worked well with up to about 100 PHP processes running, but things would fall apart if we let it go much past that value. However with IIS running an ASP.NET web site, it will automatically keep adding application instances to the application pool based on how slow the site is responding to incoming page requests until it is maxing out the CPU and memory on the machine. There is no way for us to control the maximum number of &#8216;applications&#8217; that IIS will have running in the application pool.</p>
<p>The problem with that is all those new application instances then start requesting connections to MySQL and executing more and more SQL queries for the pages they are trying to serve! This then causes MySQL gets even more overloaded and starts responding even slower, which then causes IIS to spin up even more application instances. This feedback loop continues until eventually you get a site crash as the IIS applications can no longer get MySQL connections and MySQL is working so hard nothing can get done. We never had this problem with real PHP because we would only ever have a maximum of 100 PHP instances running so although the web site was really slow in the middle of the night, neither MySQL nor IIS would completely overload and cause the site to crash.</p>
<p>This was all pretty obvious once we had the MySQL Enterprise Monitor tools installed, but we just did not know what to do about it. With the graphs below you can see the problem clearly on April 25th, where the nightly process ran from 03:05 to 03:19. You can see the number of connections to the MySQL server start to head steadily towards the maximum, the CPU load on the server get higher and higher and the query cache start to constantly miss. It is clear from the graph that the MySQL machine is completely overloaded, as the load average goes up to around 30, when the machine only has 12 physical cores (24 with hyper threading). Pretty much any load past about 20 means the machine is running full tilt. The end result of this is aborted SQL connections and/or timeouts. We tried playing around the maximum number of connections, but all that did is cause more load on the MySQL server and eventually IIS would fall over.</p>
<div id="attachment_172" class="wp-caption alignnone" style="width: 510px"><a href="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/cpu_0425.png"><img class="size-full wp-image-172" title="cpu_0425_small" src="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/cpu_0425_small.png" alt="" width="500" height="97" /></a><p class="wp-caption-text">CPU load on April 25th</p></div>
<div id="attachment_175" class="wp-caption alignnone" style="width: 510px"><a href="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/loadavg_0425.png"><img class="size-full wp-image-175" title="loadavg_0425_small" src="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/loadavg_0425_small.png" alt="" width="500" height="106" /></a><p class="wp-caption-text">Load Average on April 25th</p></div>
<div id="attachment_178" class="wp-caption alignnone" style="width: 510px"><a href="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/querycache_0425.png"><img class="size-full wp-image-178" title="querycache_0425_small" src="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/querycache_0425_small.png" alt="" width="500" height="102" /></a><p class="wp-caption-text">Query cache misses on April 25th</p></div>
<div id="attachment_169" class="wp-caption alignnone" style="width: 510px"><a href="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/conns_0425.png"><img class="size-full wp-image-169" title="conns_0425_small" src="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/conns_0425_small.png" alt="" width="500" height="102" /></a><p class="wp-caption-text">MySQL connections on April 25th</p></div>
<p>So for the night of April 26th we optimized the code somewhat and nearly halved the number of iterations for the driving loop (~45K down to ~23K), and added a very small micro sleep to each iteration (about 1/40th of a second). This actually produced some completely odd results which was not what we were expecting. From the graphs you can see the nightly script in question ran from 03:07 to 03:39. Not only did it take twice as long, but the load average went all the way up to 55. Clearly adding a sleep in there simply slowed everything down, but did nothing to lower the server load and in fact made everything worse, not better.</p>
<div id="attachment_173" class="wp-caption alignnone" style="width: 510px"><a href="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/cpu_0426.png"><img class="size-full wp-image-173" title="cpu_0426_small" src="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/cpu_0426_small.png" alt="" width="500" height="104" /></a><p class="wp-caption-text">CPU load on April 26th</p></div>
<div id="attachment_176" class="wp-caption alignnone" style="width: 510px"><a href="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/loadavg_0427_small.png"><img class="size-full wp-image-176" title="loadavg_0426_small" src="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/loadavg_0426_small.png" alt="" width="500" height="103" /></a><p class="wp-caption-text">Load average on April 26th</p></div>
<div id="attachment_179" class="wp-caption alignnone" style="width: 510px"><a href="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/querycache_0426.png"><img class="size-full wp-image-179" title="querycache_0426_small" src="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/querycache_0426_small.png" alt="" width="500" height="101" /></a><p class="wp-caption-text">Query cache misses on April 26th</p></div>
<div id="attachment_170" class="wp-caption alignnone" style="width: 510px"><a href="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/conns_0426.png"><img class="size-full wp-image-170" title="conns_0426_small" src="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/conns_0426_small.png" alt="" width="500" height="100" /></a><p class="wp-caption-text">MySQL connections on April 26th</p></div>
<h3>Solution: MySQL Low Priority Updates</h3>
<p>After doing some more thinking after the failure of our changes on the night of April 26th it occurred to me that part of the problem was that the nightly scripts run full tilt and were very update heavy. We needed some way to be able to &#8216;slow down&#8217; the MySQL server, like a feature similar to the UNIX nice command but for our background MySQL process. The solution to this problem came in the form of the <a title="MySQL update keyword and LOW_PRIORITY" href="http://dev.mysql.com/doc/refman/5.5/en/update.html" target="_blank">LOW_PRIORITY keyword for the MySQL update operation</a>, or the use of the <a title="Low Priority Updates variable for MySQL" href="http://dev.mysql.com/doc/refman/5.5/en/server-options.html#option_mysqld_low-priority-updates" target="_blank">low_priority_updates variable</a> for all queries on a connection. The idea behind this feature is that if you issue an update operation that is considered a &#8216;low priority&#8217; and mark it as such MySQL will schedule the update operation to happen ONLY when all pending select operations have completed. This essentially gives the effect of making the updates happen in the background, so that all the foreground &#8216;web page&#8217; tasks get to complete and the server won&#8217;t get overload.</p>
<p>So for the night of April 27th, we removed the sleeps and added in the low_priority support for the critical queries. The nightly process in question ran from 03:04 to 03:16. You can see that this time the CPU utilization stayed really low the whole time, the load average barely got over 1, the cache hit ratio never dipped below 60% and the total number of connections never went above 75. The entire process actually finished faster than the original code now, with no adverse load on the MySQL server (although the iterations of the loop are effectively half what they used to be, so the low priority update versions of the nightly scripts took almost 2x as long as before).</p>
<div id="attachment_187" class="wp-caption alignnone" style="width: 510px"><a href="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/cpu_0427.png"><img class="size-full wp-image-187" title="cpu_0427_small" src="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/cpu_0427_small.png" alt="" width="500" height="102" /></a><p class="wp-caption-text">CPU load on April 27th</p></div>
<div id="attachment_177" class="wp-caption alignnone" style="width: 510px"><a href="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/loadavg_0427.png"><img class="size-full wp-image-177" title="loadavg_0427_small" src="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/loadavg_0427_small.png" alt="" width="500" height="103" /></a><p class="wp-caption-text">Load average on April 27th</p></div>
<div id="attachment_180" class="wp-caption alignnone" style="width: 510px"><a href="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/querycache_0427.png"><img class="size-full wp-image-180" title="querycache_0427_small" src="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/querycache_0427_small.png" alt="" width="500" height="102" /></a><p class="wp-caption-text">Query cache misses on April 27th</p></div>
<div id="attachment_171" class="wp-caption alignnone" style="width: 510px"><a href="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/conns_0427.png"><img class="size-full wp-image-171" title="conns_0427_small" src="http://www.amainhobbies.com/FromTheCEO/wp-content/uploads/2012/07/conns_0427_small.png" alt="" width="500" height="100" /></a><p class="wp-caption-text">MySQL connections on April 27th</p></div>
<h3>Conclusion</h3>
<p>So in conclusion it should be pretty clear that if you are using MySQL and you need to run nightly processes that hit the database pretty hard, it is a really good idea to make sure all that code runs with low priority updates to ensure any select operations for web pages will get priority and not get blocked out. Not to mention that enabling low priority updates keeps the load on the MySQL server down which then allows it to do the same amount of work much more efficiently. Just be aware that if your MySQL server is totally overloaded already and you enable low priority updates, the update operation may get blocked indefinitely and never complete. If you have that problem you may need to consider moving select traffic off the database server onto a dedicated slave server.</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.amainhobbies.com/FromTheCEO/2012/07/30/solving-mysql-nightly-performance-problems-with-low_priority_updates/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Couchbase &#8211; High performance caching for ASP.NET</title>
		<link>http://www.amainhobbies.com/FromTheCEO/2012/07/27/couchbase-caching-on-windows-for-asp-net/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=couchbase-caching-on-windows-for-asp-net</link>
		<comments>http://www.amainhobbies.com/FromTheCEO/2012/07/27/couchbase-caching-on-windows-for-asp-net/#comments</comments>
		<pubDate>Sat, 28 Jul 2012 00:02:46 +0000</pubDate>
		<dc:creator>Kendall Bennett</dc:creator>
				<category><![CDATA[None]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Caching]]></category>
		<category><![CDATA[Couchbase]]></category>
		<category><![CDATA[NoSQL]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.amainhobbies.com/FromTheCEO/?p=109</guid>
		<description><![CDATA[Recently as we spent a lot of time trying to sort out performance issues on our web site, we spent a lot of time going over our caching system and working to improve it. Our old caching system was originally written to use the file system, which actually worked really well when the site used [...]]]></description>
				<content:encoded><![CDATA[<p>Recently as we spent a lot of time trying to sort out performance issues on our web site, we spent a lot of time going over our caching system and working to improve it. Our old caching system was originally written to use the file system, which actually worked really well when the site used to run under Linux. But it was beginning to show it&#8217;s age and was really expensive to maintain, so we started looking for alternative. I looked at a number of different options, and had read a lot about <a title="memcached - a distributed memory object caching system" href="http://memcached.org/">memcached</a>, but alas I could not find any good memcached implementations for Windows which I needed for our development and testing. That is until I came across <a title="Couchbase |  Simple, Fast, Elastic NoSQL Database" href="http://www.couchbase.com/" target="_blank">Couchbase</a> while I was researching the option of using NoSQL for parts of our web site for the future. Not only is Couchbase a super fast NoSQL database, it is also entirely <a title="Couchbase caching support" href="http://www.couchbase.com/couchbase-server/features#cache" target="_blank">memcached compatible</a> so makes is a great commercial memcached implementation. And it runs on Windows!</p>
<h3><span id="more-109"></span>File Systems are SLOW!</h3>
<p>One of the biggest problems we had with the file system cache was simply that it was too expensive to actually get rid of items that had expired from the cache. So our simple cache system would use the file timestamp to determine if a file was old and had expired and hence needed to be refreshed. But nothing would ever come back to clean up old &#8216;expired&#8217; entries that had not been looked at for a while so the file system would end up with hundreds of thousands of tiny cache files on it over time. Thankfully that problem is neatly solved with Couchbase caching as it is entirely memory based. Nothing is stored on disk, and if you use more memory than you have allocated, old stuff starts to get tossed out automatically (and efficiently).</p>
<p>But another major problem we had was that the file system was really, REALLY slow when it comes to deleting files and dealing with directories full of LOTS of files. And this is an area where Windows is just plain bad compared to Linux and other UNIX file systems. Having a really slow file system leads to the problem of taking a long time to delete cache files from disk, if we ever needed to purge the cache. Purging the cache which was commonly needed after a major site upgrade, and it would literally take 30 minutes or more to delete the files. We ended up changing our cache purging code to rename the old cache directory so a new one would be created to take it&#8217;s place, and then deleting the old files in the background. We even went so far as to put the cache files into a Windows FAT32 ramdisk, but it still took forever to delete the files. And once again that problem is neatly solved by Couchbase because it is all memory based. A couple of mouse clicks is all that is needed to purge the cache, or a single call to the client library can also purge it instantly.</p>
<h3>Couchbase to the Rescue</h3>
<p>So we recently went live with our new site caching system using Couchbase, and the results are excellent. The overhead of getting a cache entry from Couchbase over the network from an entirely separate machine is actually less than the overhead we had in managing all the little files on disk. But more importantly we now have a lot of flexibility to automatically expire items and purge the entire cache quickly if we need to.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.amainhobbies.com/FromTheCEO/2012/07/27/couchbase-caching-on-windows-for-asp-net/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>All about ISO-8859-1, Windows-1252 and latin1 HTML and MySQL</title>
		<link>http://www.amainhobbies.com/FromTheCEO/2012/03/31/all-about-iso-8859-1-windows-1252-and-latin1-html-and-mysql/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=all-about-iso-8859-1-windows-1252-and-latin1-html-and-mysql</link>
		<comments>http://www.amainhobbies.com/FromTheCEO/2012/03/31/all-about-iso-8859-1-windows-1252-and-latin1-html-and-mysql/#comments</comments>
		<pubDate>Sun, 01 Apr 2012 00:08:23 +0000</pubDate>
		<dc:creator>Kendall Bennett</dc:creator>
				<category><![CDATA[None]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.amainhobbies.com/FromTheCEO/?p=97</guid>
		<description><![CDATA[Anyone who has written a web page has probably had to work out what character encoding to use for their web site, which is communicated from the web server to the browser using either the charset field in the HTML content meta tag, or the Content-Type header. Most new web sites are developed with the [...]]]></description>
				<content:encoded><![CDATA[<p>Anyone who has written a web page has probably had to work out what character encoding to use for their web site, which is communicated from the web server to the browser using either the charset field in the <a title="HTML content meta tag" href="http://en.wikipedia.org/wiki/Meta_element" target="_blank">HTML content meta tag</a>, or the <a title="Content-Type HTML header" href="http://en.wikipedia.org/wiki/List_of_HTTP_header_fields" target="_blank">Content-Type header</a>. Most new web sites are developed with the <a title="UTF-8 character set" href="http://en.wikipedia.org/wiki/Utf-8" target="_blank">UTF-8 character set</a> encoding as it can be used to represent any character possible (including Kanji, Chinese, Arabic etc), but many legacy web sites deal with an extended ASCII character set commonly called latin1. Our web site is one of those web sites that has always used the latin1 character set, and more importantly, all our database tables are encoded in that same character set. Up until this past week, I had always worked under the assumption that the <a title="ISO-8859-1 character set" href="http://en.wikipedia.org/wiki/ISO/IEC_8859-1" target="_blank">ISO-8859-1 character set</a> was in fact the same as latin1, but in the case of MySQL we found out this NOT to be the case, even though all browsers will happily display a page encoded in ISO-8859-1 with characters that are not technically legal for that encoding.<span id="more-97"></span></p>
<p>The first part of the problem we had is that most content that is encoded in latin1 that most people probably think is ISO-8859-1 is not actually using that encoding, but is rather using the <a title="Windows-1252 character set" href="http://en.wikipedia.org/wiki/Windows-1252" target="_blank">Windows-1252 character set</a> encoding, which is a superset of ISO-8859-1. For this reason, most browsers will happily go ahead and accept pages that present themselves as ISO-8859-1 but in reality they treat the page as the Windows-1252 encoding so that all the extended characters like smart quotes (“ and ”) and the Euro symbol (€) work correctly.</p>
<p>Now the second part of the problem we had is that all our MySQL databases are encoded in latin1, and in fact MySQL does not have any character set called ISO-8859-1 or Windows-1252 at all. So although ISO-8859-1 is commonly known as latin1 according to Wikipedia, in the case of <a title="MySQL character sets" href="http://dev.mysql.com/doc/refman/5.6/en/charset-we-sets.html" target="_blank">MySQL it is really Windows-1252</a>, or what they call the cp1252 encoding. Specifically they state:</p>
<blockquote><p><code>"latin1</code> is the default character set. MySQL&#8217;s <code>latin1</code> is the same as the Windows <code>cp1252</code> character set. This means it is the same as the official <code>ISO 8859-1</code> or IANA (Internet Assigned Numbers Authority) <code>latin1</code>, except that IANA <code>latin1</code> treats the code points between <code>0x80</code> and <code>0x9f</code> as “undefined,” whereas <code>cp1252</code>, and therefore MySQL&#8217;s <code>latin1</code>, assign characters for those positions. For example, <code>0x80</code> is the Euro sign.&#8221;</p></blockquote>
<p>So why exactly is this a problem, if the browsers will happily accept a page presenting itself as ISO-8859-1 and let characters from the Windows-1252 character set work properly? Normally it would not, because as long as we can take the string from the MySQL database and send them directly to the browser, or take string from the browser and stick them directly into the database, everything works as expected (even though the encoding is not technically legal). And in fact until recently, this never caused a problem because the pages on our web site were written in PHP and internally PHP stores the strings in the native Windows-1252 encoding. Hence reading a value from the database and sending it to the browser works just fine.</p>
<p>Enter <a title="Phalanger - The PHP compiler" href="http://www.php-compiler.net/" target="_blank">Phalanger</a> (again). Phalanger is a compiler for PHP that compiles the PHP code into native .NET code so it can run natively under ASP.NET on the web server or as native .NET executable if run from the command line. Apart from being a lot faster than running it under the normal PHP interpreter, it also allows for interoperability between PHP code and native .NET code such as C# etc. Now the problem is that when running under .NET, strings are represented in Unicode format (<a title="UTF-16 character set" href="http://en.wikipedia.org/wiki/Utf-16" target="_blank">UTF-16 to be exact</a>). So when we read a value from the database under Phalanger, it happily converts our strings from the database latin1/Windows-1252 encoding into a native .NET System.String type, which is encoded as a Unicode UTF-16 format string. Since the MySQL database is really using the Windows-1252 code page, the strings all get converted correctly to the appropriate characters in Unicode. Hence when it takes the Unicode strings and sends them to the browser, it has to convert them to the correct format to put into the HTML page, which we had previously set up as ISO-8859-1 since we always used that with our existing PHP pages. Now the problem is that .NET is very strict about character encoding and since we told the ASP.NET server to use the ISO-8859-1 encoding, when it came across invalid characters like smart quotes mentioned above it simply replaced them with a ? character to indicate that it could not convert them!</p>
<p>So after a lot of Googling, head scratching and testing, it finally became clear the ISO-8859-1 != Windows-1252. And also ISO-8859-1 != MySQL latin1! The end result is that once we changed the character encoding for our Phalanger pages to Windows-1252, everything magically worked <img src='http://www.amainhobbies.com/FromTheCEO/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://www.amainhobbies.com/FromTheCEO/2012/03/31/all-about-iso-8859-1-windows-1252-and-latin1-html-and-mysql/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Why you should NOT Shop Local!</title>
		<link>http://www.amainhobbies.com/FromTheCEO/2012/03/24/why-you-should-not-shop-local/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=why-you-should-not-shop-local</link>
		<comments>http://www.amainhobbies.com/FromTheCEO/2012/03/24/why-you-should-not-shop-local/#comments</comments>
		<pubDate>Sun, 25 Mar 2012 01:46:57 +0000</pubDate>
		<dc:creator>Kendall Bennett</dc:creator>
				<category><![CDATA[None]]></category>
		<category><![CDATA[Customer Service]]></category>

		<guid isPermaLink="false">http://www.amainhobbies.com/FromTheCEO/?p=91</guid>
		<description><![CDATA[There is a common rally cry right now amongst local businesses to convince customers to spend their money locally, rather than spending in a national chain store, or online. Movements such as the 3/50 project and “Think. Shop. Buy. Local” all point out that spending money in local businesses will improve your local economy. As [...]]]></description>
				<content:encoded><![CDATA[<p>There is a common rally cry right now amongst local businesses to convince customers to spend their money locally, rather than spending in a national chain store, or online. Movements such as <a title="The 3/50 Project" href="http://www.the350project.net/home.html" target="_blank">the 3/50 project</a> and <a title="Think. Shop. Buy. Local." href="http://thinkshopbuylocal.com/" target="_blank">“Think. Shop. Buy. Local”</a> all point out that spending money in local businesses will improve your local economy. As a business owner that has both a local bricks and mortar retail hobby shop, and a large online retail hobby shop, I know what it takes to run both a local business and an online business.<span id="more-91"></span></p>
<p>The problem I see with the ‘Buy Local’ campaigns is that they generally leave out some important issues. Simply spending your money on a local business JUST because they are local, does not make any sense. Not EVERY business deserves your dollars, especially when those local businesses don’t provide good customer service or after sales support. One of the common misconceptions out there amongst small bricks and mortar shops is that buying online is an impersonal experience, and online stores can never provide the same level of customer service as a local small business. Nothing can be further from the truth! Modern online businesses have highly trained customer service representatives to take care of their customers via phone, email or live chat. More importantly, online businesses know that after sales service and customer support are critical to remain competitive, because customers simply won’t come back and shop with you again if you don’t treat them right. There are plenty of other businesses out there for them to spend their money with.</p>
<p>So the core point I want to make is that if a local business wants customers to spend their money with them, they need to understand that they HAVE to start providing a high level of customer service and after sales support. This should not be something new, as local businesses have always had to do this, but before the internet the local businesses had a more captive market as customers did not have much else in the way of options, especially in smaller towns such as Chico where I currently live. With the advent of the internet, the local business now has to contend with a whole new range of online businesses that are competing in their own back yard. This is similar to small businesses lining the streets in a highly competitive shopping district (such as down Bridge Road in Melbourne, Australia). With so many businesses all selling the same products in close proximity, if they DON’T learn how to treat their customers right the store next door is going to steal their sales, and they will go out of business. This is effectively what is happening now with local businesses as the online business is the new business that just moved in next door.</p>
<p>There is a good article from Carol Tice on Entrepreneur.com discussing <a title="New Study Shows What Makes Shoppers Buy Local" href="http://www.entrepreneur.com/blog/218790" target="_blank">what makes shoppers buy local</a>. In this article she says:</p>
<blockquote><p><strong>Personal service.</strong> I have yet to talk to a small business owner who thinks they don&#8217;t have great customer service. But customers tell another story. On review sites and local forums, the fangs come out about rudeness, sloppy follow-up, or a just-don&#8217;t-care attitude.</p></blockquote>
<p>Personal service, or just plain good customer service is critical for a business to retain customers whether they are local or online. But my experience with many local businesses in recent years (and alas some online ones), is that sometimes customer service seems to be an afterthought and something the business owner would prefer not to do. Once the sale is done, it is done. If the customer has an issue, they explain why they cannot help you and send you on your way. The end result is that single sale was saved, but the business just lost that customer and they likely won’t ever come back. Worse, if they are really upset they may tell all their friends via Facebook or Twitter about their experience, and THEY then won’t spend their money with that business.</p>
<p>So it is pretty clear that if any local business wants customers to spend their money with their business, they need to EARN that business. They should not ever simply EXPECT that business because they happen to be local.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.amainhobbies.com/FromTheCEO/2012/03/24/why-you-should-not-shop-local/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Batterygate? Does the Apple iPad really &#8216;Fib&#8217; when charging?</title>
		<link>http://www.amainhobbies.com/FromTheCEO/2012/03/24/batterygate-does-the-apple-ipad-really-fib-when-charging/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=batterygate-does-the-apple-ipad-really-fib-when-charging</link>
		<comments>http://www.amainhobbies.com/FromTheCEO/2012/03/24/batterygate-does-the-apple-ipad-really-fib-when-charging/#comments</comments>
		<pubDate>Sun, 25 Mar 2012 00:40:23 +0000</pubDate>
		<dc:creator>Kendall Bennett</dc:creator>
				<category><![CDATA[None]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.amainhobbies.com/FromTheCEO/?p=84</guid>
		<description><![CDATA[Steven J. Vaughan-Nichols, a blogger on ZDNet wrote on March 23rd about an issue supposedly present on the new 2012 model Apple iPad (aka iPad 3) where the battery status indicator on the iPad indicates that the battery is fully charged when in fact it is not. He says: An expert finds that when your [...]]]></description>
				<content:encoded><![CDATA[<p><a href="http://www.zdnet.com/search?q=steven+j.+vaughan-nichols" target="_blank">Steven J. Vaughan-Nichols</a>, a blogger on ZDNet wrote on March 23<sup>rd</sup> about <a title="Batterygate? Apple&amp;#039;s iPad &quot;Fibbing&quot; battery charger" href="http://www.zdnet.com/blog/btl/batterygate-apples-ipad-fibbing-battery-charger/72302" target="_blank">an issue supposedly present on the new 2012 model Apple iPad</a> (aka iPad 3) where the battery status indicator on the iPad indicates that the battery is fully charged when in fact it is not. He says:</p>
<blockquote><p>An expert finds that when your new iPad tells you that it’s fully-charged, it’s not even close to being charged up. Are we looking at an Apple iPad “Batterygate?”</p></blockquote>
<p>The core issue they identified is that “the power actually drawn by the AC Adapter and first found that the new iPad continues to charge for up to 1 hour after it claims to reach 100%. This affects the battery run time if you stop charging when it says 100%.” The article goes on to discuss the issue and wonders why the new iPad lies about the charge status, when the battery is not yet fully charged.<span id="more-84"></span></p>
<p>Dr. Raymond Soneira, president of <a title="DisplayMate" href="http://www.displaymate.com/" target="_blank">DisplayMate</a>, the world’s leading display and display tuning company, theorizes that “There is something wrong with the battery charge mathematical model on the iPad. It should not say 100% until it stops recharging and goes from the full recharging rate of about 10 watts to a trickle charging rate of about 1 watt. Otherwise the user will not get the maximum running time that the iPad is capable of delivering.”</p>
<p>After reading these blog posts and being involved in the RC hobby industry where we use Lithium Polymer batteries day in and day out, I felt I had to comment on this issue to explain a few things about Lithium battery technology. Although the new iPad has a 4.1V 11,560mAh Lithium-Ion battery and not a Lithium Polymer battery, the charging characteristics of these batteries are virtually identical. The primary difference is Li-Ion batteries have a lower overall voltage (4.1V fully charged versus 4.2V for Li-Poly) and are generally more stable for low current draw applications like phones and tablets. Li-Poly is generally used where you need high discharge rates, such as in RC helicopters, airplanes and cars.</p>
<p>So coming from the RC hobby industry, it is very well known that the charging cycle for these types of batteries is done in two phases. The first phase is the constant current (CC) phase, and is what is considered the &#8216;fast&#8217; charging phase. During this time the battery is charged at the maximum current possible until it reaches the maximum voltage of the cells, which for Lithium-Ion batteries is 4.1V per cell. When this occurs the battery is considered at about 80% of the total charge capacity, but it has in fact already reached 100% of the maximum voltage. If you put a volt meter across the battery at this point in the charging cycle, with the charger still attached, it would read 4.1V.</p>
<p>After the first phase is complete, the charger changes to a constant voltage (CV) phase where the current tapers off until it effectively gets to zero, and the battery is now fully charged. During the entire time the battery is being charged in the CV phase, the battery voltage remains at 4.1V per cell but the current tapers off. In general this last 20% of battery capacity takes a LONG time to complete, and since the current tapers off it actually goes from 80% to 90% capacity in a relatively short period of time. Then it takes it takes longer and longer to get to 95%, then to 97.5% etc due to the fact that the charge current is tapering off.</p>
<p>Now the catch in all this is that in order to measure the effective capacity left in the battery when the battery is NOT on the charger, you need to look at the voltage of the battery and run some complex math based on the discharge curve of the battery to estimate how much capacity is really left. Now most Lithium batteries under a small load will not have much voltage drop so they will measure pretty close to the maximum voltage when they come right off the charger (and compared to RC models which can run a battery flat in 5 minutes, 10+ hour discharge times is a SMALL load!). Now when the iPad is attached to the charger, once the charger changes to the CV phase at the 80% charge point, the voltage of the batteries will ALWAYS show full 4.1V per cell because the charger is currently pegging the battery voltage at that value. So for that reason, once the battery reaches 80% of its maximum capacity, the battery meter on the iPad is going to always show 100%! However if you remove the iPad from the charger as soon as it first reads 100% on the battery meter, it would not actually have reached full capacity yet so the voltage would immediately drop.</p>
<p>For the most part the battery meter is really designed to let you know and approximate capacity left when the unit is NOT ON THE CHARGER! So it will always give some odd results when the battery is being charged and is not under load. So it seems to me this is all a lot of hoopla about nothing, since what is being described is pretty standard stuff for charging Lithium batteries, so I hardly think we have a ‘Batterygate’ or ‘Chargergate’ type situation on our hands. I have no doubt most (if not all) other tablets and phones that all use Li-Ion batteries do exactly the same thing.</p>
<p>Talk back below and let me know what you think!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.amainhobbies.com/FromTheCEO/2012/03/24/batterygate-does-the-apple-ipad-really-fib-when-charging/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>PHP on Windows; what a silly idea!</title>
		<link>http://www.amainhobbies.com/FromTheCEO/2012/03/10/php-on-windows-what-a-silly-idea/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=php-on-windows-what-a-silly-idea</link>
		<comments>http://www.amainhobbies.com/FromTheCEO/2012/03/10/php-on-windows-what-a-silly-idea/#comments</comments>
		<pubDate>Sun, 11 Mar 2012 03:19:30 +0000</pubDate>
		<dc:creator>Kendall Bennett</dc:creator>
				<category><![CDATA[None]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[ASP.NET MVC]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.amainhobbies.com/FromTheCEO/?p=61</guid>
		<description><![CDATA[The software that runs our site originally started out based on an Open Source project called osCommerce, which is written in PHP. The back end database has always been MySQL, so all our initial code was originally written in PHP. As the business grew, we quickly realized that we needed some back end software that [...]]]></description>
				<content:encoded><![CDATA[<p>The software that runs our site originally started out based on an <a title="Open Source Initiative" href="http://www.opensource.org/" target="_blank">Open Source</a> project called <a title="osCommerce project web site" href="http://www.oscommerce.com/" target="_blank">osCommerce</a>, which is written in <a title="PHP" href="http://us2.php.net/" target="_blank">PHP</a>. The back end database has always been <a title="MySQL database" href="http://www.mysql.com/" target="_blank">MySQL</a>, so all our initial code was originally written in PHP. As the business grew, we quickly realized that we needed some back end software that ran natively on the desktop, rather than in the browser as we needed to integrate with barcode scanners, label printers and other hardware devices, which simply cannot be done easily from a web site running in a browser. To build the software, given my background in device driver development I naturally decided to use C++ on the desktop and write the programs with a cross platform user interface called <a title="Qt web site" href="http://qt.nokia.com/" target="_blank">Qt</a>. So off I went and started writing a C++ desktop application that would communicate with our PHP based web server running on Linux.<br />
<span id="more-61"></span><br />
In order for the desktop application to communicate with our server, we had to use some kind of client server architecture and given that developing a <a title="SOAP protocol" href="http://www.w3.org/TR/soap/" target="_blank">SOAP</a> server in PHP is a little on the complex side, I settled on using <a title="XML-RPC protocol" href="http://www.xml-rpc.net/" target="_blank">XML-RPC</a> as our communication mechanism. Part of the reason was also that at the time I was sold on using the <a title="Zend Framework" href="http://framework.zend.com/" target="_blank">Zend Framework</a> for all our &#8216;future&#8217; web development, so we could change our site over to using a more maintainable <a title="Model View Controller architecture" href="http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller" target="_blank">MVC </a>architecture. And since Zend Framework had a built in XML-RPC server class, it seemed like a logical choice and it would be simple and lightweight. I spent quite a bit of time developing my own XML-RPC library for C++ using Qt for the background communications and fleshed out the basics of our desktop application. The first page I was building was one to download a list of packing slips to be printed for the warehouse, and when I had it going I noticed something odd. The desktop app was quite slow at downloading the list of packing slips!</p>
<p>Investigating the problem had me even more confused, because I was able to display the same list of packing slips in a desktop browser almost instantly from the live web site, yet it was take 4-5 seconds for the desktop app to download an XML document containing the same data feeding off a local web server on my development machine. It should not be taking that long! To get to the bottom of the problem I added some profiling information to my page to find out where it was spending all the time. What I found was rather startling! The page was able to get through the entire process of getting all the information needed from the database and put it into a PHP array in a fraction of a second, and then the other 95% of the time was spent inside the Zend Framework, turning the PHP array into an XML packet to send back to the client! Not good.</p>
<p>At that point I called in Steve, one of my programmers and said &#8216;What can we do to fix this?&#8217;. Steve of course, simply said; &#8220;Why are you using Zend Framework? Isn&#8217;t there XML-RPC server extension for PHP?&#8221;. Yes! There <a title="XML-RPC for PHP" href="http://us2.php.net/manual/en/book.xmlrpc.php" target="_blank">really is</a>. So with a flurry of key strokes we ripped out the Zend Framework XML-RPC server code and changed it to use the extension for PHP. Magically the code that used to take so long was now humming along nice and fast! It was at that point I realized that PHP was a really, REALLY bad choice of language for complicated algorithms or any heavy lifting and business logic (Facebook figured that out also; hence the <a title="HipHop for PHP" href="http://developers.facebook.com/blog/post/358/" target="_blank">HipHop </a>project was born). I knew PHP was a scripting language, but I thought the <a title="Zend Optimizer" href="http://www.zend.com/en/products/guard/runtime-decoders" target="_blank">Zend Optimizer</a> built into Zend Server would make it run fast enough for our use. How wrong I was! PHP is a reasonable solution for putting something together quickly and stitching together HTML for a web page, and it works OK as long as you can off-load the heavy lifting to a PHP extension written in C (like the XML-RPC extension). But for writing complex business logic and algorithms? Not a good choice.</p>
<p>Suddenly I was in a quandry because I needed to get moving on our new back end warehousing tools so we could start using bar code scanners, but coding the server side in PHP was not going to make any sense. I needed something better. Unlike Facebook, who probably has millions of lines of PHP code, I had the luxury of tossing out what I had started on and starting over with a new architecture. I spent some time investigating Java and as much as I like the language, the tools just did not appeal to me; after having used Zend Studio for some time which is based on <a title="Eclipse web site" href="http://www.eclipse.org/" target="_blank">Eclipse</a>, I did not particularly want to be developing using Eclipse for my IDE. So I took a look at C# and fell in love with the Language. And alas, much to my dismay, I found Visual Studio to be an amazing piece of software and the best IDE I had used for a long time. So I was off an running with C# to develop my server code.</p>
<p>Pretty quickly I realized that C# has amazing support for SOAP built right in, and it was super simple to build a SOAP server using <a title="Windows Communication Foundation" href="http://msdn.microsoft.com/en-us/netframework/aa663324" target="_blank">WCF</a> and just as easy to build a client for it in C#. It was at that point that I gave up on C++ and Qt, and ended up building our client software in C# and Windows Forms (and eventually Windows Mobile for our <a title="Intermec CK71 handheld computer" href="http://www.intermec.com/products/cmptrck71a/" target="_blank">Intermec CK71</a> handheld computers).</p>
<p>Anyway, to cut a long story short once we had decided upon C# and WCF for our SOAP server we had to host it somewhere. Rather than deal with setting up <a title="Mono Project" href="http://www.mono-project.com/Main_Page" target="_blank">Mono</a> on our Linux server and it&#8217;s limited WCF support, I decided to move our entire web server over to running on Windows. After all, PHP and MySQL seemed to run fine on Windows as we had been doing all our development on Windows machines for some time. So we made the switch, and started the process of writing all our new C# and SOAP code. When I had re-implemented the same program from C++/Qt with a PHP XML-RPC server into a Windows Forms application written in C# and using WCF to communicate to the server, it was significantly faster again than the C++ version using the XML-RPC extension in PHP so I knew I was on the right track to get off PHP for the server.</p>
<p>Now, after having run PHP on our Windows servers for probably 2 years, I can say that Windows is NOT the best platform to run PHP applications. I don&#8217;t know if the problem is IIS itself, or the Microsoft WinCache solution (forget about the commercial Zend Server on Windows; it crashed our server multiple times and Zend could not fix it). But it hangs up on a regular basis and in fact some applications (mostly forum software) were so bad we simply ended up moving them all to a cloud Linux based machine and then proxy the requests over there from our IIS server. It looks like they run on our main server, but in reality they don&#8217;t <img src='http://www.amainhobbies.com/FromTheCEO/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
<p>Our primary web site still runs mostly on PHP for the front end and we are in the process of re-writing a lot of the back end code in <a title="ASP.NET MVC" href="http://www.asp.net/mvc" target="_blank">ASP.NET MVC</a> and moving it off PHP. We are also in the process of getting ready to re-write parts of the front end in C# as well, since all our new code is written in C# so I then started looking around to find ways to integrate PHP and C# code on the same platform. I ended up building my own shared session architecture so that PHP pages and ASP.NET MVC pages can share session data and we can transparently move from one to the other, but there was still no way to actually call PHP code from C# or vice versa.</p>
<p>Enter  the Open Source project <a title="PHP Compiler for .Net" href="http://www.php-compiler.net/" target="_blank">Phalanger</a>! I forget exactly how I came across this particularly nifty piece of software (I think Steve sent me a link to it one day), but Phalanger is basically a compiler for PHP. Kind of like <a title="HipHop for PHP" href="http://developers.facebook.com/blog/post/358/" target="_blank">HipHop for PHP</a>, but rather than compiling the PHP code into native code, it compiles it into .NET code which can then be executed natively on the server, just like C# code. By compiling the PHP code into .NET assemblies, not only is the code <a title="Phalanger PHP compiler benchmarks" href="http://www.php-compiler.net/benchmarks" target="_blank">significantly faster</a> than native PHP but once it is compiled into .NET code you can share the code easily with C# code. It is possible to load PHP code and call PHP functions from C# code, as well as have PHP render the entire page but be able to call across to .NET assemblies written in C#.</p>
<p>We have now been in the process of getting our web site to compile in Phalanger since November and are just about to launch it live. During the process we have relied heavily on a support contract with <a title="Devsense Software Solutions" href="http://www.devsense.com/" target="_blank">Devsense</a>, who have been fantastic at adding missing features and helping to fix bugs in Phalanger so we can get all the features our sites needs implemented so it can run. With any luck our web site will be running entirely on .NET and compiled with Phalanger sometime next week.</p>
<p>So to wrap up this blog post and tie it into the title, running PHP on Windows really is silly! Native PHP runs best on Linux. But if you really want to run PHP apps on Windows (or on Linux using Mono for that matter), you really should check out Phalanger. And if you are a PHP developer and wish you could call .NET code or are a .NET developer and wish you could use some PHP libraries you found, give Phalanger a good look!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.amainhobbies.com/FromTheCEO/2012/03/10/php-on-windows-what-a-silly-idea/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Welcome to my blog!</title>
		<link>http://www.amainhobbies.com/FromTheCEO/2012/03/10/welcome-to-my-blog/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=welcome-to-my-blog</link>
		<comments>http://www.amainhobbies.com/FromTheCEO/2012/03/10/welcome-to-my-blog/#comments</comments>
		<pubDate>Sat, 10 Mar 2012 23:26:07 +0000</pubDate>
		<dc:creator>Kendall Bennett</dc:creator>
				<category><![CDATA[None]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.amainhobbies.com/FromTheCEO/?p=50</guid>
		<description><![CDATA[Welcome to my new blog! I have always wanted a blog of my own, so I could share my opinions and views with the world on topics that range from Customer Service to Computer Programming and even R/C Racing. Basically anything that relates to my business whether it is on the technical and computer programming [...]]]></description>
				<content:encoded><![CDATA[<p>Welcome to my new blog! I have always wanted a blog of my own, so I could share my opinions and views with the world on topics that range from Customer Service to Computer Programming and even R/C Racing. Basically anything that relates to my business whether it is on the technical and computer programming side or on the business side.<br />
<span id="more-50"></span><br />
My experience on the business side ranges from running a small boutique software company for many years, to starting an E-Commerce company from the ground up and growing it from nothing to a 70+ person company with more than 35 million dollars a year in sales. So from time to time I will be commenting on business issues that I feel might be interesting to talk about, especially if I get burned by another company. I will likely recount those experiences on these pages also.</p>
<p>My experience on the programming side ranges from C/C++ and assembly programming and low level device driver programming to E-Commerce and web site programming in PHP, C# and ASP.NET MVC. I expect I will be writing a lot about C# and ASP.NET MVC programming, as well as database programming on these pages. My current platform of choice is C#, ASP.NET MVC and the MySQL database using the PetaPoco micro-ORM layer. Although we have a lot of PHP code on our site, and we still maintain it and add to it, I personally can&#8217;t stand programming in PHP at all and one of our goals is to get rid of PHP completely from our systems over the coming years and replace it all with C# and ASP.NET MVC code.</p>
<p>I am also an avid techie and I love new gadgets so you will probably see me posting about new gadgets I might come across that you might find interesting as well. As anyone who knows me will tell you, I am an avid Apple product fan and have has Apple products since back in the Apple II days. I even use primarily Macintosh computers for all my work, although at this point I am still stuck running Windows on my Macs to get real work done. I wish someone would come out with a hardware graphics accelerator for Parallels on the Mac, so I can run windows apps under Mac OS at native speeds! If I could, I would only use Mac OS as my primary OS, but the emulators are just too slow for real work for me at the moment. Anyway, the point is, don&#8217;t be shocked if you see me writing stuff about Apple products on these pages also. I have a lot of them, and I love them, so I will probably write something about them from time to time <img src='http://www.amainhobbies.com/FromTheCEO/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Well, let&#8217;s get down to business and start blogging, and I hope you enjoy this site!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.amainhobbies.com/FromTheCEO/2012/03/10/welcome-to-my-blog/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>
