<?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>SLDN</title>
	<atom:link href="http://sldn.softlayer.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://sldn.softlayer.com</link>
	<description>SoftLayer API Developer Network</description>
	<lastBuildDate>Fri, 26 Feb 2010 05:51:13 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Something new for your API Toolbox</title>
		<link>http://sldn.softlayer.com/02/2010/something-new-for-your-api-toolbox/</link>
		<comments>http://sldn.softlayer.com/02/2010/something-new-for-your-api-toolbox/#comments</comments>
		<pubDate>Fri, 26 Feb 2010 05:51:13 +0000</pubDate>
		<dc:creator>Kevin Laude</dc:creator>
				<category><![CDATA[Implementations]]></category>
		<category><![CDATA[News]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://sldn.softlayer.com/?p=149</guid>
		<description><![CDATA[pre { display: block; background:#dddddd; border: 1px solid #999999; padding: 5px; }
An interesting facet of the development and systems administration business is the number of 80% projects that build up over time. An 80% project is that awesome library, script, rewrite, new system, or what have you that&#8217;s cooling on your back burner. It&#8217;s almost [...]]]></description>
			<content:encoded><![CDATA[<style type="text/css">pre { display: block; background:#dddddd; border: 1px solid #999999; padding: 5px; }</style>
<p>An interesting facet of the development and systems administration business is the number of 80% projects that build up over time. An 80% project is that awesome library, script, rewrite, new system, or what have you that&#8217;s cooling on your back burner. It&#8217;s almost done but it&#8217;s missing the finishing touches. Maybe it needs a few code tweaks. Maybe it needs a little more documentation. Maybe you&#8217;re still finalizing settings and playing with patches. Don&#8217;t lie; we know you&#8217;ve got these projects hanging around. I&#8217;ve got a list of 80% projects as long as my arm.</p>
<p>It&#8217;s time to check something off my 80% projects list. I&#8217;ve finally finished documenting and am happy to release the SoftLayer API Perl client library! This module will make Perl API hackers&#8217; lives a whole lot easier. Previously you had to build SOAP API calls manually using the <a href="http://www.soaplite.com/">SOAP::Lite</a> module and parse the response into something easier to handle.  Now you can accomplish the same thing with a series of easy to use helper methods. Functionality is very similar to our <a href="http://github.com/softlayer/softlayer-api-php-client">PHP client</a> but with a Perl twist. For instance, you can do clever one liners!</p>
<pre>
use SoftLayer::API::SOAP;

# Grab my account information.
my $account = SoftLayer::API::SOAP->new(
    'SoftLayer_Account',
    undef,
    'my API username',
    'my API key')->getObject();
</pre>
<p>Check out our <a href="http://github.com/softlayer/softlayer-api-perl-client/blob/master/README.pod">README</a> for many and more comprehensive examples. Download the library from our <a href="http://github.com/softlayer">github page</a> at:</p>
<p>&nbsp;<br />
<br />
<b><a href="http://github.com/softlayer/softlayer-api-perl-client">http://github.com/softlayer/softlayer-api-perl-client</a></b><br />
<br />&nbsp;<br />
</p>
<p>As with all of our projects we&#8217;re very open to feedback, so please comment or post on our <a href="http://forums.softlayer.com/">forums</a> and let us know what you think. I can&#8217;t wait knock a few more 80% projects off the ol&#8217; list. You&#8217;re going to love them. <img src='http://sldn.softlayer.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  See y&#8217;all next time!</p>
]]></content:encoded>
			<wfw:commentRss>http://sldn.softlayer.com/02/2010/something-new-for-your-api-toolbox/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Another Expo in the Bag</title>
		<link>http://sldn.softlayer.com/02/2010/another-expo-in-the-bag/</link>
		<comments>http://sldn.softlayer.com/02/2010/another-expo-in-the-bag/#comments</comments>
		<pubDate>Tue, 23 Feb 2010 21:13:54 +0000</pubDate>
		<dc:creator>Kevin Laude</dc:creator>
				<category><![CDATA[News]]></category>
		<category><![CDATA[expo]]></category>
		<category><![CDATA[SCaLE]]></category>

		<guid isPermaLink="false">http://sldn.softlayer.com/?p=146</guid>
		<description><![CDATA[After a three hour flight that took five hours from LA to Dallas I&#8217;m finally home from the Southern California Linux Expo. This was SCaLE&#8217;s 8th show, an evolution that started as a meeting of Linux User Groups from the Los Angeles area that grew into one of the largest Linux, open technology, and community [...]]]></description>
			<content:encoded><![CDATA[<p>After a three hour flight that took five hours from LA to Dallas I&#8217;m finally home from the <a href="http://www.socallinuxexpo.org/">Southern California Linux Expo</a>. This was SCaLE&#8217;s 8th show, an evolution that started as a meeting of Linux User Groups from the Los Angeles area that grew into one of the largest Linux, open technology, and community focused events in the region.</p>
<p>This is my second year attending SCaLE. I went last year as a part of an open source project I was working with and had a pretty good time. I jumped at the chance to go again when I found SoftLayer had a booth at and was sponsoring SCaLE 8x.</p>
<p>I&#8217;m really glad I went; I dig these community-focused events. What strikes me about these events, and SCaLE in particular, was the general optimism of the staff, attendees, speakers, and exhibitors. This show is on a weekend, and people came because they genuinely care about FOSS, cool new (and sometimes old) tech, and community advocacy. Most attendees fit the classic nerd stereotype. We got to meet our fair share of skinny pale guys, scruffy and ponytailed sysadmin types, and bearded folks with wallet chains and Star Trek t-shirts. </p>
<p>When not working our booth I was able to duck out and attend some of the talks at the expo. Aside from being informative (I picked up a lot about technical writing that I can&#8217;t wait to throw into our API documentation), every single talk I attended was completely packed to the point where there was standing room only. It&#8217;s refreshing to see speakers talk about things other than the company they work for. Instead, they focused on cool tech or how to be more productive in your community or with a specific technology. I took pages and pages of notes this weekend, it felt like being in school again.</p>
<p>I think SoftLayer did well at SCaLE 8x. We got our name out like we usually do at these events, and got to introduce a new group of people to SoftLayer and our ever-changing and sometimes hidden industry. I hope we&#8217;re sponsoring SCaLE 9x. Even if we don&#8217;t you&#8217;ll still find me there. See you next year!</p>
]]></content:encoded>
			<wfw:commentRss>http://sldn.softlayer.com/02/2010/another-expo-in-the-bag/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Object Masks and Filters in C Sharp</title>
		<link>http://sldn.softlayer.com/02/2010/object-masks-and-filters-in-c-sharp/</link>
		<comments>http://sldn.softlayer.com/02/2010/object-masks-and-filters-in-c-sharp/#comments</comments>
		<pubDate>Fri, 19 Feb 2010 21:43:31 +0000</pubDate>
		<dc:creator>William Francis</dc:creator>
				<category><![CDATA[Implementations]]></category>
		<category><![CDATA[Tips and Tricks]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[CSharp]]></category>
		<category><![CDATA[ObjectMask]]></category>

		<guid isPermaLink="false">http://sldn.softlayer.com/?p=124</guid>
		<description><![CDATA[pre { display: block; background:#dddddd; border: 1px solid #999999; padding: 5px; }
Object Masks, Filters, and Other V3 Black Magic
Everyone has heard the age old saying for any given job you need to have the right tool. Just as most of us have tried to use the flat rounded edge of a butter knife a time [...]]]></description>
			<content:encoded><![CDATA[<style type="text/css">pre { display: block; background:#dddddd; border: 1px solid #999999; padding: 5px; }</style>
<p><strong>Object Masks, Filters, and Other V3 Black Magic</strong></p>
<p>Everyone has heard the age old saying for any given job you need to have the right tool. Just as most of us have tried to use the flat rounded edge of a butter knife a time or two when what we desperately needed was a screw driver. Does that mean you weren&#8217;t able to open that little compartment on whatever gizmo and replace the batteries? Probably not. In most cases it is possible to use a butter knife when a screw driver is the tool of choice; it&#8217;s just more painful and a lot less effective.</p>
<p>The same can said of the <a href="http://sldn.softlayer.com/wiki/index.php/The_SoftLayer_API">SoftLayer API</a> (SLAPI). It&#8217;s a toolset. A very flexible set of tools allowing a developer to manage every aspect of dedicated hosting from accounting and billing to physical status of remote hardware. And yet there are so many tools in the V3 API toolbox, a number of them only subtlety different from their binary brethren ( at least on the surface), it&#8217;s tempting just to reach your hand into the bag, find the first thing that resembles a screw driver, and begin turning.</p>
<p>I know. I&#8217;m speaking from my own experiences. As a developer who largely works on SoftLayer&#8217;s back end systems, somewhere between the bottom of TCP/IP stack and the top edge of the kernel, recently getting to do production user portal code was a new experience for me. Sure I wrote some demos, dabbled a little here and there, but when I started doing my first &#8220;real&#8221; V3/SLAPI intensive project I realized my prior attempts had entirely missed the true power and elegance of SLAPI. The magic if you will. A little something called ORM.</p>
<p>Those of you who spend your days toiling in the world or relational databases are probably fairly familiar with the term ORM. But for someone like me who usually comes no closer to a database than reading an I/O address from the Windows registry, I was only vaguely aware of what the acronym even stood for. I turned to Webopedia. There I discovered the following. &#8220;Short for object role modeling, ORM is a conceptual database design methodology that allows the user to express information as an object and explore how it relates to other information objects&#8221;.</p>
<p>So there we have it. Database. Objects. Relations. I learn hands on—so none of that amounts to a hill of beans without some real code I can see and type and run for myself. So rather than regurgitate the SLDN documentation, I will just share a simple yet real life example. Then, in the second part of the article, we can expand that example to show some of the more powerful and less documented features of the V3 SLAPI.</p>
<p>The code that follows is written in Microsoft C Sharp using Visual Studio 2008 Professional Edition. I am not going to step through the basics of connecting a WSDL and generating a SOAP wrapper in this article. If you need help with that, there is an SLDN blog I did a while back which covers those steps entitled, &#8220;Dot Net? You Bet!&#8221;. It is still available under the implementations section of the SLDN website. True to my MO, I am not a big GUI guy so the code I am presenting runs as a Windows console application.</p>
<p>For the sake of making the example clear, I am going to simplify my task. In the example in both this article, and the next in the series, we will be playing the role of a developer who needs to count how many of his or her servers are running the Microsoft Windows operating system, as opposed to one of the many Linux variants SoftLayer also offers its customers. For our first code sample, we require two WSDLs: the <a href="http://sldn.softlayer.com/wiki/index.php/SoftLayer_Account">SoftLayer_Account</a> service as well as the <a href="http://sldn.softlayer.com/wiki/index.php/SoftLayer_Hardware_Server">SoftLayer_Hardware_Server</a> service. The console program below will get us connected to the SoftLayer application servers, as well as provide us some timing metrics.</p>
<pre>using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SLDN_Magic
{
   class Program
   {
       static void Main(string[] args)
       {
           //global timing vars
           DateTime stopwatch;
           TimeSpan elapsed;

           //replace with your username and api key
           string user_name = "Replace With Your User Name";
           string api_key = "Replace With Your API Key";

           Console.Write("Establishing connection to SLDN service...");

           //time it
           stopwatch = DateTime.Now;
           //declare the services
           SLDN_ACCT.SoftLayer_AccountService acct = new
               SLDN_ACCT.SoftLayer_AccountService();
           SLDN_SVR.SoftLayer_Hardware_ServerService svr = new
               SLDN_SVR.SoftLayer_Hardware_ServerService(); 

           //create an authentification object for each
           SLDN_ACCT.authenticate credentials_a = new
               SLDN_ACCT.authenticate();
           SLDN_SVR.authenticate credentials_b = new
               SLDN_SVR.authenticate();

           //assign credentials
           credentials_a.username = credentials_b.username = user_name;
           credentials_a.apiKey = credentials_b.apiKey = api_key;

           //authenticate
           acct.authenticateValue = credentials_a;
           svr.authenticateValue = credentials_b;

           elapsed = DateTime.Now.Subtract(stopwatch);
           Console.WriteLine("done (" +  elapsed.TotalSeconds.ToString() + " seconds)");

           Console.WriteLine("\nPress <enter> to exit.");
           Console.ReadLine();
       }
   }
}</pre>
<p>At this point, we can go ahead and run our code. It doesn&#8217;t really do anything all that useful. But never the less you should get an output similar to this.</p>
<p><img src="/wp-content/sldn/124/Blog_orm_console_1.png" /></p>
<p>While writing this article I connected to the SoftLayer API servers numerous times from my home. My connection times were pretty consistent. It took somewhere in the neighborhood of 20 seconds to get everything set up. That seems like a lot. But keep in mind that you only incur the overhead of connecting your services one time. Plus as we get a little further along in this article I will show you how we can use ORM to get rid of one of the references entirely. For now though, let&#8217;s move on.</p>
<p>For someone of my background and mindset, what seemed the most straight-forward and correct way to find out which servers were running MS Windows was to access the public method &#8220;<a href="http://sldn.softlayer.com/wiki/index.php/SoftLayer_Hardware_Server::isWindowsServer">isWindowsServer()</a>&#8220;. This is a method off the server class. That&#8217;s why we needed to import the SoftLayer_Hardware_Server service. But we don&#8217;t want to check the OS on a single server. We want to recurse through all the servers for an account. Which is why we brought in the SoftLayer_Account service and its attractive public offering &#8220;<a href="http://sldn.softlayer.com/wiki/index.php/SoftLayer_Account::getAllHardware">getAllHardware()</a>&#8220;.</p>
<p>Keeping this plan in mind, let&#8217;s go ahead and implement it in our console application.</p>
<pre>using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SLDN_Magic
{
   class Program
   {
       static void Main(string[] args)
       {
           //global timing vars
           DateTime stopwatch;
           TimeSpan elapsed;

           //global container
           SLDN_ACCT.SoftLayer_Hardware[] hw;

           //replace with your username and api key
           string user_name = "Replace With Your User Name";
           string api_key = "Replace With Your API Key";

           Console.Write("Establishing connection to SLDN service...");

           //time it
           stopwatch = DateTime.Now;

           //declare the services
           SLDN_ACCT.SoftLayer_AccountService acct = new
               SLDN_ACCT.SoftLayer_AccountService();
           SLDN_SVR.SoftLayer_Hardware_ServerService svr = new
               SLDN_SVR.SoftLayer_Hardware_ServerService(); 

           //create an authentification object for each
           SLDN_ACCT.authenticate credentials_a = new
               SLDN_ACCT.authenticate();
           SLDN_SVR.authenticate credentials_b = new
               SLDN_SVR.authenticate();

           //assign credentials
           credentials_a.username = credentials_b.username = user_name;
           credentials_a.apiKey = credentials_b.apiKey = api_key;

           //authenticate
           acct.authenticateValue = credentials_a;
           svr.authenticateValue = credentials_b;

           elapsed = DateTime.Now.Subtract(stopwatch);
           Console.WriteLine("done (" + elapsed.TotalSeconds.ToString() + " seconds)");

           //butter knife method

           Console.Write("Retrieving hardware using method 1...");

           //get time stamp
           stopwatch = DateTime.Now;

           hw = null;
           try
           {
               hw = acct.getHardware();
           }
           catch (Exception e)
           {
               Console.WriteLine("Exception encountered [" + e.Message + "]");
               hw = null;
           }

           int cnt = 0;

           foreach (SLDN_ACCT.SoftLayer_Hardware server in hw)
           {
               try
               {
                   SLDN_SVR.SoftLayer_Hardware_ServerInitParameters box = new
                       SLDN_SVR.SoftLayer_Hardware_ServerInitParameters();
                   box.id = (int)server.id;
                   svr.SoftLayer_Hardware_ServerInitParametersValue = box;
                   if (svr.isWindowsServer())
                   {
                       cnt++;
                   }
               }
               catch (NullReferenceException)
               {
                   //ignore...this server has not had the
                   //OS loaded on it yet!
               }
           }

           elapsed = DateTime.Now.Subtract(stopwatch);

           Console.WriteLine("done (" + elapsed.TotalSeconds.ToString() + " seconds)");
           Console.WriteLine("counted " + cnt.ToString() + " MS Windows licenses");
           Console.WriteLine("\nPress <enter> to exit.");
           Console.ReadLine();
       }
   }
}</pre>
<p>That&#8217;s it. Pretty straight forward stuff possibly with the exception of the way SLAPI allows you to reinitialize the server (or any object) on the fly by use of:&#8221;SoftLayer_Hardware_ServerInitParameters&#8221;. If this confuses you, again I&#8217;ll refer you to the blog &#8220;Dot Net? You Bet!&#8221;. At this point, I think we are ready for another test run.</p>
<p><img src="/wp-content/sldn/124/BlogOrmConsole2.png" /></p>
<p>Once again we find ourselves in the twenty second range both for connecting the services and counting the hardware. What you can&#8217;t tell from looking at this output is that the account I was using for testing had about 100 servers on it. So basically we are talking 1/5 of a second per server. It&#8217;s certainly doable with a handful of servers, but this would obviously never work if you were trying to present this information real time to users if you managed 500 or 5,000 or 50,000 servers. So you are probably asking yourself the same thing I did. What gives? If SoftLayer wishes its customers success on an enterprise level, why create an API that comes to its knees when you start trying to manage more than a few hundred servers?</p>
<p>Luckily, the architects of SLAPI were a lot more web / database savvy than me. The above implementation, while correct syntactically, is a gross misuse of the SLAPI. It&#8217;s the butter knife, when what we really need is the screwdriver. What we need are object masks. But exactly what are object masks and how do they relate to ORM?</p>
<p>The best way I have found to understand ORM and object masks, is to think of the SLAPI data objects, as a self supporting entities. Each object provides its own methods and exposes some properties specific to that object. Yet thanks to ORM, most objects can actually get to properties in related objects, through a process called tapping. You simply tap each object down the chain until you find the property or properties you are interested in, prior to retrieving an instance or instances of the object. Then the set of objects returned will expose any relevant properties in the same manner you tapped them.</p>
<p>For example in our case the SLDN architecture relates a server to an operating system in the following manner.</p>
<p><img src="/wp-content/sldn/124/BlogOrm3.png" /></p>
<p>The diagram shows us that essentially, as long as we can get a hardware object, we can tap all the way down to the software description — which as the SLDN documentation states has a &#8220;name&#8221; property. There by we eliminate two of our most time consuming tasks from our original application. First off we no longer need to instantiate the SoftLayer_Hardware_Server service, since we can get to server from hardware and hardware can be retrieved via the account class. Secondly, if when we return the hardware it already contains the name of the operating system, we no longer have a need to call the &#8220;isWindows()&#8221; method. Take a look.</p>
<pre>using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SLDN_Magic
{
   class Program
   {
       static void Main(string[] args)
       {
           //global timing vars
           DateTime stopwatch;
           TimeSpan elapsed;

           //global container
           SLDN_ACCT.SoftLayer_Hardware[] hw;

           //replace with your username and api key
           string user_name = "Your User Name Here";
           string api_key = "Your Api Key Here";

           Console.Write("Establishing connection to SLDN service...");

           //time it
           stopwatch = DateTime.Now;

           //declare the services
           SLDN_ACCT.SoftLayer_AccountService acct = new
               SLDN_ACCT.SoftLayer_AccountService();

           //create an authentification object
           SLDN_ACCT.authenticate credentials_a = new
               SLDN_ACCT.authenticate();

           //assign credentials
           credentials_a.username = user_name;
           credentials_a.apiKey = api_key;

           //authenticate
           acct.authenticateValue = credentials_a;

           elapsed = DateTime.Now.Subtract(stopwatch);
           Console.WriteLine("done (" + elapsed.TotalSeconds.ToString() + " seconds)");

           //method 2
           Console.Write("Retrieving hardware using method 2...");

           //get time stamp
           stopwatch = DateTime.Now;

           hw = null;
           //attempt to pull a hardware list for this user
           try
           {
               acct.SoftLayer_AccountObjectMaskValue = new
                   SLDN_ACCT.SoftLayer_AccountObjectMask();
               acct.SoftLayer_AccountObjectMaskValue.mask = new
                   SLDN_ACCT.SoftLayer_Account();
               acct.SoftLayer_AccountObjectMaskValue.mask.hardware = new
                   SLDN_ACCT.SoftLayer_Hardware_Server[1];
               acct.SoftLayer_AccountObjectMaskValue.mask.hardware[0] = new
                   SLDN_ACCT.SoftLayer_Hardware_Server();
               acct.SoftLayer_AccountObjectMaskValue.mask.hardware[0].operatingSystem = new
                   SLDN_ACCT.SoftLayer_Software_Component();
               acct.SoftLayer_AccountObjectMaskValue.mask.hardware[0].operatingSystem.softwareLicense = new
                   SLDN_ACCT.SoftLayer_Software_License();
               acct.SoftLayer_AccountObjectMaskValue.mask.hardware[0].operatingSystem.softwareLicense.softwareDescription = new
                   SLDN_ACCT.SoftLayer_Software_Description();
               hw = acct.getHardware();
           }
           catch (Exception e)
           {
               Console.WriteLine("Exception encountered [" + e.Message + "]");
               hw = null;
           }

           cnt = 0;

           foreach (SLDN_ACCT.SoftLayer_Hardware server in hw)
           {
               try
               {
                   if (server.operatingSystem.softwareLicense.
                                   softwareDescription.name.ToLower().
                                   Contains("windows"))
                   {
                       cnt++;
                   }
               }
               catch (NullReferenceException)
               {
                   //ignore...this server has not
                   //had the OS loaded on it yet!!!
               }
           }

           elapsed = DateTime.Now.Subtract(stopwatch);

           Console.WriteLine("done ("+ elapsed.TotalSeconds.ToString()+" seconds)");
           Console.WriteLine("counted " + cnt.ToString() + " MS Windows licenses");

           Console.WriteLine("\nPress <enter> to exit.");
           Console.ReadLine();
       }
   }
}</pre>
<p>You should notice right away all the references to SoftLayer_AccountObjectMaskValue prior to calling the &#8220;getHardware()&#8221; method. This is the object mask. Essentially we must create a new instance of each entity we want to include down the chain. Then when the target object is retrieved, in our case the hardware, all related objects which we have made room for will get created for that specific instance of hardware, assuming of course a record exists. You must instantiate each object down the chain. If you skip any link your result set will not conatain the property or method you were trying to get to. Some less structured langagues, like PHP, do not have this requirement. But with V3 and dot NET there is no getting around it. You&#8217;re probably thinking this version of the code looks far more cluttered and is not as straight-forward to read. You&#8217;re right. But I contend this is the electric screwdriver in the SLDN toolbox. See for yourself.</p>
<p><img src="/wp-content/sldn/124/Image004.png" /></p>
<p>As you can see the connection overhead dropped in half, which is to be expected since we are only authenticating to half the number of services. But take a look at the second number, the number of seconds it takes to count the servers with Windows installed. It dropped from 20 seconds, to under 2 seconds. That&#8217;s a 10 times speed gain. And wait there&#8217;s more&#8211; because we are only making one call to the SLDN application servers to retrieve those records what you see is what you get. Meaning you should not expect that time to increase noticeably whether you have a hundred servers or a hundred thousand servers! That my friend is the magic of V3. The power of ORM.</p>
<p>Following this article I will include the entire code base, in a combined application that lets you run the tests sequentially so you can see the amazing difference object masks make for yourself. In the second part to this article, we&#8217;ll continue with the sample so if you download it keep it handy. In part two I&#8217;ll discuss the next best thing to object masks—object filters. With object filters we&#8217;ll be able to streamline this code even more. Until then…happy SLDNing!</p>
<pre>using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SLDN_Magic
{
   class Program
   {
       static void Main(string[] args)
       {
           //global timing vars
           DateTime stopwatch;
           TimeSpan elapsed;

           //global container
           SLDN_ACCT.SoftLayer_Hardware[] hw;

           //replace with your username and api key
           string user_name = "";
           string api_key = "";

           Console.Write("Establishing connection to SLDN service...");

           //time it
           stopwatch = DateTime.Now;

           //declare the services
           SLDN_ACCT.SoftLayer_AccountService acct = new SLDN_ACCT.SoftLayer_AccountService();
           SLDN_SVR.SoftLayer_Hardware_ServerService svr = new SLDN_SVR.SoftLayer_Hardware_ServerService(); 

           //create an authentification object for each
           SLDN_ACCT.authenticate credentials_a = new SLDN_ACCT.authenticate();
           SLDN_SVR.authenticate credentials_b = new SLDN_SVR.authenticate();

           //assign credentials
           credentials_a.username = credentials_b.username = user_name;
           credentials_a.apiKey = credentials_b.apiKey = api_key;

           //authenticate
           acct.authenticateValue = credentials_a;
           svr.authenticateValue = credentials_b;

           elapsed = DateTime.Now.Subtract(stopwatch);
           Console.WriteLine("done (" + elapsed.TotalSeconds.ToString() + " seconds)");

           //method 1

           Console.Write("Retrieving hardware using method 1...");

           //get time stamp
           stopwatch = DateTime.Now;

           hw = null;
           try
           {
               hw = acct.getHardware();
           }
           catch (Exception e)
           {
               Console.WriteLine("Exception encountered [" + e.Message + "]");
               hw = null;
           }

           int cnt = 0;

           foreach (SLDN_ACCT.SoftLayer_Hardware server in hw)
           {
               try
               {
                   SLDN_SVR.SoftLayer_Hardware_ServerInitParameters box = new SLDN_SVR.SoftLayer_Hardware_ServerInitParameters();
                   box.id = (int)server.id;
                   svr.SoftLayer_Hardware_ServerInitParametersValue = box;
                   if (svr.isWindowsServer())
                   {
                       cnt++;
                   }
               }
               catch (NullReferenceException)
               {
                   //ignore...this server has not had the OS loaded on it yet
               }
           }

           elapsed = DateTime.Now.Subtract(stopwatch);

           Console.WriteLine("done (" + elapsed.TotalSeconds.ToString() + " seconds)");
           Console.WriteLine("counted " + cnt.ToString() + " MS Windows licenses");

           //method 2
           Console.Write("Retrieving hardware using method 2...");

           //get time stamp
           stopwatch = DateTime.Now;

           hw = null;
           //attempt to pull a hardware list for this user
           try
           {
               acct.SoftLayer_AccountObjectMaskValue = new SLDN_ACCT.SoftLayer_AccountObjectMask();
               acct.SoftLayer_AccountObjectMaskValue.mask = new SLDN_ACCT.SoftLayer_Account();
               acct.SoftLayer_AccountObjectMaskValue.mask.hardware = new SLDN_ACCT.SoftLayer_Hardware_Server[1];
               acct.SoftLayer_AccountObjectMaskValue.mask.hardware[0] = new SLDN_ACCT.SoftLayer_Hardware_Server();
               acct.SoftLayer_AccountObjectMaskValue.mask.hardware[0].operatingSystem = new SLDN_ACCT.SoftLayer_Software_Component();
               acct.SoftLayer_AccountObjectMaskValue.mask.hardware[0].operatingSystem.softwareLicense = new SLDN_ACCT.SoftLayer_Software_License();
               acct.SoftLayer_AccountObjectMaskValue.mask.hardware[0].operatingSystem.softwareLicense.softwareDescription = new SLDN_ACCT.SoftLayer_Software_Description();
               hw = acct.getHardware();
           }
           catch (Exception e)
           {
               Console.WriteLine("Exception encountered [" + e.Message + "]");
               hw = null;
           }

           cnt = 0;

           foreach (SLDN_ACCT.SoftLayer_Hardware server in hw)
           {
               try
               {
                   if (server.operatingSystem.softwareLicense.softwareDescription.name.ToLower().Contains("windows"))
                   {
                       cnt++;
                   }
               }
               catch (NullReferenceException)
               {
                   //ignore...this server has not had the OS loaded on it yet
               }
           }

           elapsed = DateTime.Now.Subtract(stopwatch);

           Console.WriteLine("done ("+elapsed.TotalSeconds.ToString()+" seconds)");
           Console.WriteLine("counted " + cnt.ToString() + " MS Windows licenses");

           Console.WriteLine("\nPress <enter> to exit.");
           Console.ReadLine();
       }
   }
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://sldn.softlayer.com/02/2010/object-masks-and-filters-in-c-sharp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Building the Data Warehouse</title>
		<link>http://sldn.softlayer.com/09/2009/building-the-data-warehouse/</link>
		<comments>http://sldn.softlayer.com/09/2009/building-the-data-warehouse/#comments</comments>
		<pubDate>Tue, 29 Sep 2009 19:33:21 +0000</pubDate>
		<dc:creator>Daniel McAloon</dc:creator>
				<category><![CDATA[Features]]></category>
		<category><![CDATA[Tips and Tricks]]></category>
		<category><![CDATA[data warehouse]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://sldn.softlayer.com/?p=113</guid>
		<description><![CDATA[Here at SoftLayer, we have a lot of things that we need to keep track of. It&#8217;s not just payments, servers, rack slots, network ports, processors, hard drives, RAM sticks, and operating systems, it&#8217;s also bandwidth, monitoring, network intrusions, firewall logs, VPN access logs, API access, user history, and a whole host more. Last year, [...]]]></description>
			<content:encoded><![CDATA[<p>Here at SoftLayer, we have a lot of things that we need to keep track of. It&#8217;s not just payments, servers, rack slots, network ports, processors, hard drives, RAM sticks, and operating systems, it&#8217;s also bandwidth, monitoring, network intrusions, firewall logs, VPN access logs, API access, user history, and a whole host more. Last year, I was tapped to completely overhaul the existing bandwidth system. The old system was starting to show its age, and with our phenomenal growth it just hasn&#8217;t been able to keep up. </p>
<p>SoftLayer has 20,000+ servers. Each of those servers is on 2 networks, the public network open to the Internet, and the private network that only our customers can use. Each of those networks exists on a 3 to 4-level network hierarchy. This gives us more than 50,000 switch ports, but we&#8217;ll use 50,000 to make the math easier. Each switch port has bandwidth in and bandwidth out, as well as packets in and packets out. That gives us 200,000 data points to poll. Bandwidth is polled every 5 minutes, giving us 57,600,000 data points per day, or 1,728,000,000 per month. Given that bandwidth data points are all 64 bit numbers, and we also have to track the server ID (32 bit), the network (32 bit), and the datetime (32 bit), that makes a month&#8217;s worth of raw data (excluding any overhead from storage engines) 34.56GB. Now, the data is to be stored redundantly, so double that. Also, we have to track bandwidth for racks, virtual racks, and private racks, so add another 50% onto the data. That gives us around 90GB per month of data.</p>
<p>This doesn&#8217;t seem like a lot of data at first, but we need to generate custom bandwidth graphs for use on the web. Since it&#8217;s on the web, loading times above 2 seconds are unacceptable. Also, these are not enormous files with small keys (we&#8217;ll spend more time on that later) so 45GB of bandwidth data is a whole lot different than 45GB of movie files or MP3s. </p>
<p>To accomplish this, we decided that we needed a data warehouse. After numerous false starts and blind alleys, we decided to make our own system from scratch using <a href="http://www.mysql.com/">MySQL</a>. We considered commercial products, and pre-built open source solutions, but they just didn&#8217;t seem to fit our needs properly. The data warehouse project commenced with phase 1.</p>
<p><b>Phase 1:  MySQL Cluster with Read Shards, Large Tables</b><br />
Our first implementation was relatively simple. We planned to have a <a href="http://dev.mysql.com/doc/refman/5.1/en/mysql-cluster.html">MySQL cluster</a> for writing all the data, with the data split into 100 tables. The ID of the hardware mod 100 would determine the table name that we would write to. Then we&#8217;d have between 5 and 20 read databases, each replicating a different table, for load reasons. Then all we have to do is index the data properly, and add code to our applications to pull data from the correct read database node, and we&#8217;ll be fine.</p>
<p>Bad news:  MySQL cluster isn&#8217;t designed for data with huge numbers of large keys. MySQL cluster stores all indexes and keys in memory on the cluster controller multiple times. As mentioned before, our data had 12 bytes of key, and 8 bytes of data. This means that we could only get about 2 million rows into the data warehouse before MySQL would lock up and quit working with the ever helpful error message &#8220;Unknown error: 157.&#8221;  Even more disturbing, deleting items from MySQL cluster didn&#8217;t free up memory, as the indexes had to be rebuilt before that would happen. We upgraded everything to MySQL 5.1.6, but per the <a href="http://dev.mysql.com/doc/refman/5.1/en/">MySQL manual</a>, &#8220;Beginning with MySQL 5.1.6, it is possible to store the non-indexed columns of NDB tables on disk, rather than in RAM as with previous versions of MySQL Cluster.&#8221;  Unfortunately, it&#8217;s the indexes that are causing us problems, so the upgrade didn&#8217;t help.</p>
<p><b>Phase 2: MySQL Cluster with Read Shards, Small Tables</b><br />
Since MySQL cluster couldn&#8217;t handle a small number of really big tables, how about a really big number of small tables?  We tried making hundreds of tables per day, and removing the indexes on tables older than a certain time, but that quickly ran up against operating system limitations on the number of files in a folder. When we switched operating systems to alleviate this problem, we ran into MySQL&#8217;s limitation of roughly 21,000 tables per database. Nothing could get past that, so we had to move away from the cluster entirely.</p>
<p><b>Phase 3: Large MySQL box with Read Shards, Large Tables</b><br />
We then moved on to one single MySQL box with enormous hard drives and multiple read shards. This looked promising at first, but the box simply couldn&#8217;t handle the amount of inserts and updates, and the slave servers were locking up too often. We thought that if we partitioned the tables, MySQL could handle the inserts better. This, naturally, broke replication in a different way. This was mainly because we had too many tables now that each partition was getting its own file, so MySQL would be constantly opening all these table files to perform the updates, and would quickly run out of memory and begin to swap. We just had to decrease the number of tables per server. We decided to abandon the centralized master server idea, and built out 5 pairs of master/slave servers.</p>
<p><b>Phase 4: 5 Pairs of Master/Slave Servers, Large Grouped Tables</b><br />
This plan really seemed like it was going to work. We actually had a working data warehouse for almost 2 weeks without any errors. We were close to breaking out the champagne, but there was one feature we still hadn&#8217;t implemented.</p>
<p>The time came to add the tracking of bandwidth for virtual dedicated racks as well. To accomplish this, we changed the MySQL <a href="http://dev.mysql.com/doc/refman/5.1/en/insert.html"><tt>INSERT</tt></a> statement to <a href="http://dev.mysql.com/doc/refman/5.1/en/insert-on-duplicate.html"><tt>INSERT... ON DUPLICATE KEY UPDATE</tt></a>. For those that don&#8217;t immediately recognize the terminology, the <tt>ON DUPLICATE KEY UPDATE</tt> syntax is designed so that if a particular database key already exists in the database, simply change the <tt>INSERT</tt> statement into an <a href="http://dev.mysql.com/doc/refman/5.1/en/update.html"><tt>UPDATE</tt></a> statement. The <tt>UPDATE</tt> portion is defined at the end of the clause. Since the key to our data is the large &#8220;object ID, date time, data type&#8221; combination, adding the duplicate syntax allowed us to issue multiple <tt>INSERT</tt> statements for the same data, and have it continually update with new values. This was especially handy for virtual racks with thousands of servers. </p>
<p>MySQL threw us another curve ball when we tried this. There was a known issue with the <tt>ON DUPLICATE UPDATE</tt> syntax and replication using binary logs. Namely, the <tt>UPDATE</tt> would remain an <tt>INSERT</tt> in the log somehow, so we&#8217;d get duplicate key errors thrown on the slave, when the master was still working fine. Each time this happened, it would require stopping both servers, re-synching the tables, clearing the logs, restarting replication, and restarting the data transfer processes. This was unacceptable, so we had to move once more.</p>
<p><b>Phase 5: 10 Individual Machines</b><br />
Since we already had 10 identical database machines, we decided to make them all independent and ignorant of each other. We stayed with the item group theory, leaving multiple bandwidth items per table. With 25 different items per table, we were only going to have 1,000,000 rows per table per month, which still maintains our speed. However, the index size problem bit us again. These tables were simply too large to have 3/4 of their columns indexed. </p>
<p>Finally we thought we had the answer. We would split up each of these tables by month. That way, each table would max out at 1,000,000 rows, so the indexes wouldn&#8217;t be unmanageable. Remember that we&#8217;ve already split the connection points from one, to five, to ten. We&#8217;ve also broken the tables up from one large table, to one per object, and now one per group of objects. In order to cut down on the complexity of the application layer code, we decided to use merge tables to keep the table name consistent. That way we can simply select from &#8220;the table&#8221; rather than &#8220;the table from March.&#8221;  When we did this, we almost immediately began getting mysterious deadlocks on the servers. The <tt>INSERT</tt> statements would conflict with any <tt>SELECT</tt> statements using the same table, and the two threads would just hang indefinitely. Oddly, the table was never actually locked, it seemed that there was some sort of &#8220;offsetting lock&#8221; happening, where both threads were deadlocked in a race condition. The table could still be used, but the application we had inserting the data would be hung, so it was causing unacceptable delays in data inserts.</p>
<p><b>Phase 6:  10 Individual Machines, Small Individual Tables</b><br />
Finally we decided that enough was enough, we were going to roll our own scaled storage solution. Clustering didn&#8217;t work, throwing hardware at the problem unfortunately didn&#8217;t work, and even the fancy new features for merged tables and partitioned tables didn&#8217;t work. We simply decided that we were going to keep the old &#8220;grouped tables&#8221; model, as well as creating a new table for every month without merge tables. This way, we keep the number of tables relatively low, and the number of rows per table low. Plus, as a bonus, by controlling the table names ourselves we could ensure that MySQL wouldn&#8217;t open too many files. All inserts went into this month&#8217;s table, and all reads would come out of whatever specific month they needed. A <a href="http://en.wikipedia.org/wiki/Cron">cron job</a> was set up to periodically issue <a href="http://dev.mysql.com/doc/refman/5.1/en/flush.html"><tt>FLUSH TABLES</tt></a> on all 10 data warehouse nodes, and we had our completed product!  It&#8217;s been months now since we had a major database failure, we can generate any bandwidth graphs you want in less than a second, and other developers are starting to create their own table groups. </p>
<p>Each object&#8217;s data resides completely on two of our data warehouse nodes, so the data is redundantly stored in the event of a node going down. The application code has been written with extensive <a href="http://en.wikipedia.org/wiki/Factory_method_pattern">factory patterns</a> and <a href="http://en.wikipedia.org/wiki/Object-relational_mapping">ORM</a> so that all a developer has to do is create a new group type, a new data tracking object, and add data to it. The code automatically selects the applicable nodes to write the data to, creates the tables if they don&#8217;t exist, and writes the data to the tables. Similarly, a &#8220;get data&#8221; command will randomly select one location for the data, and retrieve the proper data, using only the tables that are necessary. </p>
<p><b>But Wait, There&#8217;s More!</b><br />
All 6 phases above were happening simultaneously with other systems. The raw data itself needed to be stored, buffered, transferred, and translated into a format suitable for the data warehouse. Since almost a quarter of our servers are in other parts of the country, we had to have redundant data storage and transfer solutions to make sure the raw data got to where it needed to be. For this data, the rules were different. </p>
<p>First of all, there are two layers of raw data. Each city has a local bandwidth polling database. We use <a href="http://rtg.sourceforge.net/"><i>rtgpoll</i></a> to poll the bandwidth data. Since <i>rtgpoll</i> is designed to write to a different table for each data type, we kept the data like that. For ease of data management, we created a script that would keep a rotating two-day cycle of tables, one for today and one for yesterday, with a merge table that encompassed them both. We could get away with the merge table on this layer because there are far fewer tables, far fewer rows, and different indexes. Since the interface isn&#8217;t important at this layer, we could index only the date time and get the performance we wanted by making our transfer scripts to the global buffer date-based.</p>
<p>The global buffer server is the same box we attempted to use in phase 3 and 4, above. It has the exact same table structure as the datacenter buffers, with the rotating tables living under a merge table. This data is replicated out to a slave server, to prevent read/write contention. At this layer, we have no <tt>ON DUPLICATE KEY</tt> statements being executed, and no partitions, plus our merge tables are much smaller, so everything works out. These tables act as a permanent raw data archive in the event of a system failure or a bandwidth dispute with a customer.</p>
<p>The scripts that pull data out of the datacenter buffers also inserts data into a queue for each of the data warehouse nodes. We store a lookup table in memcache that will translate a raw interface ID into the data warehouse nodes that interface&#8217;s data needs to be inserted into. That raw row is then inserted into the queues for the nodes it belongs to.</p>
<p>Finally, a set of scripts runs on the data warehouse nodes, constantly pulling any new data out of their queues on the global buffer slave. The data is translated from raw interface data to match up to our customer accounts, then inserted into the local data warehouse database, ready to be selected out to make graphs, reports, or billing. </p>
<p><b>All Powered by Tracking Object</b><br />
The entire system is interfaced from our application code using the tracking object system. The tracking objects are a series of PHP classes that link a particular object in our existing production database to that object&#8217;s various data points in the data warehouse. Using ORM and factory patterns, we were able to abstract tracking objects to the point where any object in our database could have an associated &#8220;trackingObject&#8221; member variable. Servers, Virtual Dedicated Racks, Cloud Computing Instances, and other systems can simply call the <a href="http://sldn.softlayer.com/wiki/index.php/SoftLayer_Metric_Tracking_Object::getBandwidthData">getBandwidthData()</a> method on their tracking object, and the tracking object system will automatically select the correct database, select the correct table, and pull the correct fields, formatting them as a collection of generic &#8220;bandwidth data&#8221; objects. Other metrics, like CPU and memory usage for servers and Cloud Computing Instances, can just as easily be retrieved.</p>
<p>Similarly, most of our back-end systems use the tracking objects to add data to the data warehouse. The developers don&#8217;t touch the warehouse directly, they simply load whatever object they have new data for, and pass an array of raw data objects to our internal addData() function, which automatically determines database node, write table, and data structure. The tracking object system is completely transparent to the other developers, and it means new tracking objects or data warehouse nodes can be created seamlessly without changing existing code. </p>
<p>By centralizing the reading and writing into these classes, the data warehouse can be extended infinitely. A new type of data can be added as easily as adding a new data warehouse data type class to the file system, as well as a row to the database. As long as that class has the data structure properly defined, new tracking objects can be created for that data type, and data can begin being recorded immediately. Creating a new tracking object will automatically choose two or more database nodes to store the data on. Creating new nodes takes the current tracking object count into consideration, so the nodes stay balanced. </p>
<p>So far the system has <b>33,115,715,147 rows</b> in <b>683,460 tables</b> spread over <b>10 databases</b>. We have hundreds of customers who view their bandwidth graphs every day, and a handful that systematically pull the graphs every hour. Load tests suggest that performance doesn&#8217;t degrade until we hit 500 simultaneous graph requests, and even then we still come in under 2 seconds per graph. With the scaling potential and the single point of access for developers, we should be able to use this system indefinitely. </p>
]]></content:encoded>
			<wfw:commentRss>http://sldn.softlayer.com/09/2009/building-the-data-warehouse/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CloudLayer Storage backend API is now available</title>
		<link>http://sldn.softlayer.com/07/2009/cloudlayer-storage-backend-api-is-now-available/</link>
		<comments>http://sldn.softlayer.com/07/2009/cloudlayer-storage-backend-api-is-now-available/#comments</comments>
		<pubDate>Mon, 20 Jul 2009 23:15:54 +0000</pubDate>
		<dc:creator>Kevin Laude</dc:creator>
				<category><![CDATA[Features]]></category>
		<category><![CDATA[News]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[CloudLayer Storage]]></category>

		<guid isPermaLink="false">http://sldn.softlayer.com/?p=108</guid>
		<description><![CDATA[We&#8217;ve opened up the backend API that powers our CloudLayer Storage systems for y&#8217;all. Those of you who want more control over your cloud storage accounts and content should definitely check this out.
We&#8217;ve got instructions conveniently hosted on our cloud systems:
CloudLayer&#8482; Storage API v.1 Documentation (1.3MB)
This is a bit of a departure from our standard [...]]]></description>
			<content:encoded><![CDATA[<p>We&#8217;ve opened up the backend API that powers our <a href="http://www.softlayer.com/cloudlayer_storage.html">CloudLayer Storage</a> systems for y&#8217;all. Those of you who want more control over your cloud storage accounts and content should definitely check this out.</p>
<p>We&#8217;ve got instructions conveniently hosted on our cloud systems:</p>
<p><a href="https://storage.cloudlayer.com/v1/public/A8C742DC-757A-11DE-B0D6-EBF676FC7253/7C9CC9CF16BA73EEA686D190BF49C29F8C3709CF">CloudLayer&trade; Storage API v.1 Documentation</a> (1.3MB)</p>
<p>This is a bit of a departure from our standard API. It only covers manipulation of CloudLayer Storage accounts, and is accessed via REST-full URLs. Head dev honcho Nathan gave us a rundown of <a href="http://sldn.softlayer.com/07/2009/79/">how to access it in curl</a> a while back. It&#8217;s incredibly powerful and gives you complete control over what you host and share on the cloud. Give it a try and let us know what you think!</p>
]]></content:encoded>
			<wfw:commentRss>http://sldn.softlayer.com/07/2009/cloudlayer-storage-backend-api-is-now-available/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Guess who&#8217;s coming to HostingCon!</title>
		<link>http://sldn.softlayer.com/07/2009/guess-whos-coming-to-hostingcon/</link>
		<comments>http://sldn.softlayer.com/07/2009/guess-whos-coming-to-hostingcon/#comments</comments>
		<pubDate>Mon, 13 Jul 2009 18:53:18 +0000</pubDate>
		<dc:creator>Kevin Laude</dc:creator>
				<category><![CDATA[News]]></category>
		<category><![CDATA[HostingCon]]></category>

		<guid isPermaLink="false">http://sldn.softlayer.com/?p=100</guid>
		<description><![CDATA[Every year I get the same question from my customers, &#8220;Hey Klaude, are we going to see you at HostingCon this year?&#8221;. Every year I respond with the same thing, &#8220;I have no idea. I&#8217;ll ask!&#8221;. Every year I hear from my management, &#8220;Not this year, Kevin.&#8221; after I ask if I can go. Representing [...]]]></description>
			<content:encoded><![CDATA[<p>Every year I get the same question from my customers, &#8220;Hey Klaude, are we going to see you at <a href="http://www.hostingcon.com/">HostingCon</a> this year?&#8221;. Every year I respond with the same thing, &#8220;I have no idea. I&#8217;ll ask!&#8221;. Every year I hear from my management, &#8220;Not this year, Kevin.&#8221; after I ask if I can go. Representing SoftLayer at the big trade shows is a coveted job amongst the SoftLayer enlisted, especially for an event like HostingCon.</p>
<p>This year I was asked the same thing I&#8217;m asked every year, but this time it was suggested that I could probably tag along with the cool kids if I gave a talk or ran a session. That&#8217;s a pretty good idea. I pitched it to my boss, and to my surprise he agreed. That&#8217;s great! Now all I have to do is schedule a presentation, and I&#8217;m set! A month or so full of research and agonizing over minutia has led to a talk I&#8217;ll be giving with Ilya Baimetov from <a href="http://www.parallels.com/">Parallels</a> about providing services with APIs. Our slot is at 3:00PM on Wednesday, August 12th. Stop on by if you&#8217;re in the Washington DC area, want to see a giant collection of businesses in the hosting industry, and want to visit the guys who run your favorite dedicated and cloud hosting company. When not speaking you&#8217;ll find me at the SoftLayer booth giving API demos and free hugs. </p>
<p>SoftLayer is well represented in the <a href="http://www.hostingcon.com/2009/attend/schedule.php">HostingCon event schedule</a>. Our CFO, Mike Jones, is headlining Monday&#8217;s keynote &#8220;Surviving the Financial Crisis&#8221;, and CTO Nathan Day is participating in Tuesday&#8217;s general discussion &#8220;Offering Cloud Services to Your Customers&#8221;. The event runs form Monday, August 10 to Wednesday, August 12 at the <a href="http://www.gaylordhotels.com/gaylord-national/">Gaylord National Resort and Convention Center</a> in National Harbor, Maryland. We&#8217;d love to meet you. Drop on by and say hi!</p>
]]></content:encoded>
			<wfw:commentRss>http://sldn.softlayer.com/07/2009/guess-whos-coming-to-hostingcon/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using CURL to access CloudLayer Storage</title>
		<link>http://sldn.softlayer.com/07/2009/79/</link>
		<comments>http://sldn.softlayer.com/07/2009/79/#comments</comments>
		<pubDate>Fri, 10 Jul 2009 19:57:56 +0000</pubDate>
		<dc:creator>Nathan Day</dc:creator>
				<category><![CDATA[Implementations]]></category>
		<category><![CDATA[Tips and Tricks]]></category>
		<category><![CDATA[CloudLayer Storage]]></category>
		<category><![CDATA[curl]]></category>

		<guid isPermaLink="false">http://sldn.softlayer.com/?p=79</guid>
		<description><![CDATA[CloudLayer Storage is billed as providing &#8220;anytime, anywhere access to your data&#8221;.  This isn’t just referring to human interfaces, but also includes automated interfaces.
One easy way to automate access to CloudLayer Storage is through curl.  Curl is available as a command-line tool in most every operating system and is typically used for transferring [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.softlayer.com/cloudlayer_storage.html">CloudLayer Storage</a> is billed as providing &#8220;anytime, anywhere access to your data&#8221;.  This isn’t just referring to human interfaces, but also includes automated interfaces.</p>
<p>One easy way to automate access to CloudLayer Storage is through <a href="http://curl.haxx.se/">curl</a>.  Curl is available as a command-line tool in most every operating system and is typically used for transferring files.  In this post I’ll show some examples on how to use curl to add, get, delete, or otherwise manipulate files in CloudLayer Storage.  Note that this isn’t using the SoftLayer API, but instead interfaces directly with CloudLayer Storage.</p>
<p>Upload a file named &#8220;DSC1012.jpg&#8221; to an account owned by username &#8220;user@example.com&#8221; with a password of &#8220;PaSsWoRd&#8221;:</p>
<p><code style="display: block; margin: 5px; padding: 5px; border: 1px solid #aaaaaa; background-color: #eeeeee"># curl –F filename=@DSC1012.jpg –u user@example.com:PaSsWoRd \<br />
https://storage.cloudlayer.com/v1/files/</code></p>
<p>The command will return some XML tags.  The items of interest are &#8220;FileID&#8221; and &#8220;lockID&#8221;.  These values are important for future operations on the file.</p>
<p><code style="display: block; margin: 5px; padding: 5px; border: 1px solid #aaaaaa; background-color: #eeeeee"><br />
&lt;fileID&gt;102C9C28-65C3-11DE-1234-2BE68BA216C2&lt;/fileID&gt;<br />
&lt;lockID&gt;6CDCEEB2-6B38-11DE-A510-123F439A2728&lt;/lockID&gt;<br />
&lt;lockDuration&gt;120&lt;/lockDuration&gt;<br />
</code></p>
<p>The lock is to protect a file form reading or being manipulated during the upload process.  The lock will expire in &#8220;lockDuration&#8221; seconds or the user can disable the lock manually.</p>
<p>Here is how to disable the lock using the lockID  and the fileID generated from the upload operation:</p>
<p><code style="display: block; margin: 5px; padding: 5px; border: 1px solid #aaaaaa; background-color: #eeeeee"># curl –d \<br />
   'action=unlock&#038;lockid=6CDCEEB2-6B38-11DE-A510-123F439A2728' \<br />
   –u user@example.com:PaSsWoRd \<br />
   https://storage.cloudlayer.com/v1/files/102C9C28-65C3-11DE-1234-2BE68BA216C2/lock</code></p>
<p>If you ever lose track of the FileID, you can use this command to retrieve a listing of the files and containers (directories) in an account along with the FileIDs which are listed as an &#8220;oid&#8221; XML tag.</p>
<p><code style="display: block; margin: 5px; padding: 5px; border: 1px solid #aaaaaa; background-color: #eeeeee"># curl –u user@example.com:PaSsWoRd \<br />
https://storage.cloudlayer.com/v1/files/list</code></p>
<p>To get the list of files in a container, just append the container oid to the URL.</p>
<p><code style="display: block; margin: 5px; padding: 5px; border: 1px solid #aaaaaa; background-color: #eeeeee"># curl –u user@example.com:PaSsWoRd \<br />
https://storage.cloudlayer.com/v1/files/list?oid=37D0F2AC-08FC-11DE-1234-3FA3A91CD1B4</code></p>
<p>To retrieve the file from CloudLayer Storage, use the FileID to retrieve it.</p>
<p><code style="display: block; margin: 5px; padding: 5px; border: 1px solid #aaaaaa; background-color: #eeeeee"># curl  -u user@example.com:PaSsWoRd \<br />
https://storage.cloudlayer.com/v1/files/37D0F2AC-08FC-11DE-1234-3FA3A91CD1B4/ -o outputfilename</code></p>
<p>Alternatively, you could use &#8220;<a href="http://www.gnu.org/software/wget/">wget</a>&#8221; to retrieve the file</p>
<p><code style="display: block; margin: 5px; padding: 5px; border: 1px solid #aaaaaa; background-color: #eeeeee"># wget –http-user=user@example.com -–http-password=PaSsWoRd  \<br />
https://storage.cloudlayer.com/v1/files/37D0F2AC-08FC-11DE-1234-3FA3A91CD1B4/ -O outputfilename</code></p>
<p>To delete a file just add the POST form variable &#8220;action&#8221; with the value &#8220;delete&#8221;.</p>
<p><code style="display: block; margin: 5px; padding: 5px; border: 1px solid #aaaaaa; background-color: #eeeeee"># curl –d 'action=delete' –u user@example.com:PaSsWoRd \<br />
https://storage.cloudlayer.com/v1/files/37D0F2AC-08FC-11DE-1234-3FA3A91CD1B4/</code></p>
<p>Each of the commands listed above return data in XML format.  If you would prefer json format, add a query parameter &#8220;output=json&#8221; to the query string.</p>
<p><code style="display: block; margin: 5px; padding: 5px; border: 1px solid #aaaaaa; background-color: #eeeeee"># curl –u user@example.com:PaSsWoRd \<br />
https://storage.cloudlayer.com/v1/files/list?output=json</code></p>
<p>In order to create a public URL for a file, just send a POST variable of &#8220;action=create&#8221; to the &#8220;token&#8221; endpoint.</p>
<p><code style="display: block; margin: 5px; padding: 5px; border: 1px solid #aaaaaa; background-color: #eeeeee"># curl -d 'action=create' -u user@example.com:PaSsWoRd \<br />
https://storage.cloudlayer.com/v1/files/37D0F2AC-08FC-11DE-1234-3FA3A91CD1B4/token/</code></p>
<p>The long string &#8220;37D0F2&#8230;&#8221; is the oid (a.k.a FileID) of the file that you can get from the XML returned when the file was uploaded, or retrived using the file listing example above.</p>
<p>In the XML (or JSON) data that is returned, there will be a &#8220;token&#8221;.</p>
<p><code style="display: block; margin: 5px; padding: 5px; border: 1px solid #aaaaaa; background-color: #eeeeee">&lt;token&gt;B2891F7B054EF2DF764801E1CFF0079057291234&lt;/token&gt;</code></p>
<p>That token can be combined with the oid to create a URL that anyone can use to retrieve the file.</p>
<p>The URL looks like this:<br />
https://storage.cloudlayer.com/v1/public/{oid}/{token}</p>
<p>In our example it would be:<br />
https://storage.cloudlayer.com/v1/public/37D0F2AC-08FC-11DE-1234-3FA3A91CD1B4/B2891F7B054EF2DF764801E1CFF0079057291234</p>
<p>If you are accessing CloudLayer Storage from inside a SoftLayer datacenter, you can access the storage over the SoftLayer private network (no bandwidth fees!).  Just use &#8220;scs.service.softlayer.com&#8221; instead of &#8220;storage.cloudlayer.com&#8221;. </p>
<p>You can use the information above in conjunction with the curl libraries in <a href="http://www.php.net/curl">PHP</a>, <a href="http://curlpp.org/">C++</a>, or one of many other programming languages with <a href="http://curl.haxx.se/libcurl/bindings.html">curl bindings</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://sldn.softlayer.com/07/2009/79/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>API v1 is going dark on August 1. Migrate your apps, everyone!</title>
		<link>http://sldn.softlayer.com/05/2009/api-v1-is-going-dark-on-august-1-migrate-your-apps-everyone/</link>
		<comments>http://sldn.softlayer.com/05/2009/api-v1-is-going-dark-on-august-1-migrate-your-apps-everyone/#comments</comments>
		<pubDate>Thu, 28 May 2009 16:10:10 +0000</pubDate>
		<dc:creator>Kevin Laude</dc:creator>
				<category><![CDATA[News]]></category>
		<category><![CDATA[API]]></category>

		<guid isPermaLink="false">http://sldn.softlayer.com/?p=72</guid>
		<description><![CDATA[If you haven&#8217;t done so yet, please migrate your apps and scripts based on version 1 of the SoftLayer API to version 3. Version 3 is chock full of tools and methods that touch every single facet of your servers, your account, and our business. If you&#8217;ve been following threads on our forums since last [...]]]></description>
			<content:encoded><![CDATA[<p>If you haven&#8217;t done so yet, please migrate your apps and scripts based on version 1 of the SoftLayer API to <a href="http://sldn.softlayer.com/wiki/index.php/The_SoftLayer_API">version 3</a>. Version 3 is chock full of tools and methods that touch every single facet of your servers, your account, and our business. If you&#8217;ve been following threads on <a href="http://forums.softlayer.com/">our forums</a> since last March then you&#8217;re likely using our latest API and don&#8217;t need to migrate anything. We&#8217;ve sent notices to those of you who have recently used API version 1. Check out the <a href="http://sldn.softlayer.com/wiki/index.php/Migrating_API_v1_applications_to_v3">migration page</a> on our wiki for some tips on how to update from version 1 to version 3. </p>
<p>We plan to turn the old API off on August 1, 2009. Please post to our forums if you need help migrating or open a support ticket if you&#8217;d like to work one-on-one. Thanks, everyone!</p>
]]></content:encoded>
			<wfw:commentRss>http://sldn.softlayer.com/05/2009/api-v1-is-going-dark-on-august-1-migrate-your-apps-everyone/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The start of something good</title>
		<link>http://sldn.softlayer.com/02/2009/the-start-of-something-good/</link>
		<comments>http://sldn.softlayer.com/02/2009/the-start-of-something-good/#comments</comments>
		<pubDate>Fri, 06 Feb 2009 17:18:42 +0000</pubDate>
		<dc:creator>Kevin Laude</dc:creator>
				<category><![CDATA[Implementations]]></category>
		<category><![CDATA[News]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://sldn.softlayer.com/?p=62</guid>
		<description><![CDATA[I&#8217;ve been working with quite a few PHP users on our forums over the past few months. One thing I love is the sheer variety of tasks you guys are accomplishing. One thing I don&#8217;t really love is how y&#8217;all use the sample code we provided when we launched our new API last year. Our [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been working with quite a few PHP users on our <a href="http://forums.softlayer.com/">forums</a> over the past few months. One thing I love is the sheer variety of tasks you guys are accomplishing. One thing I don&#8217;t really love is how y&#8217;all use the <a href="htp://sldn.softlayer.com/wiki/index.php/Migrating_API_v1_applications_to_v3#Examples">sample code</a> we provided when we launched our new API last year. Our examples work great for API v1 to API v3 migrations, but those simple functions don&#8217;t really do our current API justice. </p>
<p>To that end I&#8217;ve written a new PHP API client. This small library will let you take real advantage of the features our API has to offer (like <a href="htp://sldn.softlayer.com/wiki/index.php/Object_mask">object masks</a>, <a href="http://sldn.softlayer.com/wiki/index.php/Using_Result_Limits_in_the_SoftLayer_API">result limits</a>, proper exception catching, and the like) in both SOAP and XML-RPC. Please <a href="http://github.com/softlayer/softlayer-api-php-client/tree/master">download it</a> from our new presence on the <a href="http://github.com/">github</a> social code hosting site. Come check us out at:</p>
<p><a href="http://github.com/softlayer/"><b>http://github.com/softlayer/</b></a></p>
<p>Right now all that&#8217;s up there is our PHP API client. We&#8217;ll put more client libraries and projects up as we make them. We&#8217;ve got a a few in the works right now. If you&#8217;ve already got a github account come find us! We love to meet those who want to use and modify our work. If you have a favorite language that you want to see a client library for please let us know and we&#8217;ll see what we can do. The next language on my hit list is Python 2.6. See y&#8217;all next time!</p>
]]></content:encoded>
			<wfw:commentRss>http://sldn.softlayer.com/02/2009/the-start-of-something-good/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP Memory Management in Foreach</title>
		<link>http://sldn.softlayer.com/01/2009/php-memory-management-in-foreach/</link>
		<comments>http://sldn.softlayer.com/01/2009/php-memory-management-in-foreach/#comments</comments>
		<pubDate>Thu, 15 Jan 2009 20:53:45 +0000</pubDate>
		<dc:creator>Daniel McAloon</dc:creator>
				<category><![CDATA[Tips and Tricks]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://sldn.softlayer.com/?p=49</guid>
		<description><![CDATA[code { display: block; background:#dddddd; border: 1px solid #999999; padding: 5px; }
Many developers, even experienced ones, are confused by the way PHP handles arrays in foreach loops.  In the standard foreach loop, PHP makes a copy of the array that is used in the loop.  The copy is discarded immediately after the loop [...]]]></description>
			<content:encoded><![CDATA[<style type="text/css">code { display: block; background:#dddddd; border: 1px solid #999999; padding: 5px; }</style>
<p>Many developers, even experienced ones, are confused by the way PHP handles arrays in <a href="http://us3.php.net/foreach">foreach loops</a>.  In the standard foreach loop, PHP makes a copy of the array that is used in the loop.  The copy is discarded immediately after the loop finishes.  This is transparent in the operation of a simple foreach loop.  For example:</p>
<p><code><span style="color: #000000"><span style="color: #0000BB">$set&nbsp;</span><span style="color: #007700">=&nbsp;array(</span><span style="color: #DD0000">"apple"</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">"banana"</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">"coconut"</span><span style="color: #007700">);<br />foreach&nbsp;(&nbsp;</span><span style="color: #0000BB">$set&nbsp;</span><span style="color: #007700">AS&nbsp;</span><span style="color: #0000BB">$item&nbsp;</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;</span><span style="color: #DD0000">"{$item}\n"</span><span style="color: #007700">;<br />}</span></span><br />
</code></p>
<p>This outputs:</p>
<pre>apple
banana
coconut</pre>
<p>Even though the copy is created, the developer doesn’t notice, because the original array isn’t referenced within the loop or after the loop finishes.  However, when you attempt to modify the items in a loop, you find that they are unmodified when you finish:</p>
<p><code><span style="color: #000000"><span style="color: #0000BB">$set&nbsp;</span><span style="color: #007700">=&nbsp;array(</span><span style="color: #DD0000">"apple"</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">"banana"</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">"coconut"</span><span style="color: #007700">);<br />foreach&nbsp;(&nbsp;</span><span style="color: #0000BB">$set&nbsp;</span><span style="color: #007700">AS&nbsp;</span><span style="color: #0000BB">$item&nbsp;</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$item&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">strrev&nbsp;</span><span style="color: #007700">(</span><span style="color: #0000BB">$item</span><span style="color: #007700">);<br />}<br /></span><span style="color: #0000BB">print_r</span><span style="color: #007700">(</span><span style="color: #0000BB">$set</span><span style="color: #007700">);</span></span><br />
</code></p>
<p>This outputs:</p>
<pre>Array
(
    [0] => apple
    [1] => banana
    [2] => coconut
)</pre>
<p>There are no changes from the original, even though you clearly assigned a value to $item.  This is because you are operating on $item as it appears in the copy of $set being worked on.  You can override this by grabbing $item by reference, like so:</p>
<p><code><span style="color: #000000"><span style="color: #0000BB">$set&nbsp;</span><span style="color: #007700">=&nbsp;array(</span><span style="color: #DD0000">"apple"</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">"banana"</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">"coconut"</span><span style="color: #007700">);<br />foreach&nbsp;(&nbsp;</span><span style="color: #0000BB">$set&nbsp;</span><span style="color: #007700">AS&nbsp;&amp;</span><span style="color: #0000BB">$item&nbsp;</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$item&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">strrev</span><span style="color: #007700">(</span><span style="color: #0000BB">$item</span><span style="color: #007700">);<br />}<br /></span><span style="color: #0000BB">print_r</span><span style="color: #007700">(</span><span style="color: #0000BB">$set</span><span style="color: #007700">);</span></span><br />
</code></p>
<p>This outputs:</p>
<pre>Array
(
    [0] => elppa
    [1] => ananab
    [2] => tunococ
)</pre>
<p>As you can see, when $item is operated on by-reference, the changes made to $item are made to the members of the original $set.  Using $item by reference also prevents PHP from creating the array copy.  To test this, first we’ll show a quick script demonstrating the copy:</p>
<p><code><span style="color: #000000"><span style="color: #0000BB">$set&nbsp;</span><span style="color: #007700">=&nbsp;array(</span><span style="color: #DD0000">"apple"</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">"banana"</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">"coconut"</span><span style="color: #007700">);<br />foreach&nbsp;(&nbsp;</span><span style="color: #0000BB">$set&nbsp;</span><span style="color: #007700">AS&nbsp;</span><span style="color: #0000BB">$item&nbsp;</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$set</span><span style="color: #007700">[]&nbsp;=&nbsp;</span><span style="color: #0000BB">ucfirst</span><span style="color: #007700">(</span><span style="color: #0000BB">$item</span><span style="color: #007700">);<br />}<br /></span><span style="color: #0000BB">print_r</span><span style="color: #007700">(</span><span style="color: #0000BB">$set</span><span style="color: #007700">);</span></span><br />
</code></p>
<p>This outputs:</p>
<pre>Array
(
    [0] => apple
    [1] => banana
    [2] => coconut
    [3] => Apple
    [4] => Banana
    [5] => Coconut
)</pre>
<p>In this example, PHP copied $set and used it to loop over, but when $set was used inside the loop, PHP added the variables to the original array, not the copied array.  Basically, PHP is only using the copied array for the execution of the loop and the assignment of $item.  Because of this, the loop above only executes 3 times, and each time it appends another value to the end of the original $set, leaving the original $set with 6 elements, but never entering an infinite loop.</p>
<p>However, what if we had used $item by reference, as I mentioned before?  A single character added to the above test:</p>
<p><code><span style="color: #000000"><span style="color: #0000BB">$set&nbsp;</span><span style="color: #007700">=&nbsp;array(</span><span style="color: #DD0000">"apple"</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">"banana"</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">"coconut"</span><span style="color: #007700">);<br />foreach&nbsp;(&nbsp;</span><span style="color: #0000BB">$set&nbsp;</span><span style="color: #007700">AS&nbsp;&amp;</span><span style="color: #0000BB">$item&nbsp;</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$set</span><span style="color: #007700">[]&nbsp;=&nbsp;</span><span style="color: #0000BB">ucfirst</span><span style="color: #007700">(</span><span style="color: #0000BB">$item</span><span style="color: #007700">);<br />}<br /></span><span style="color: #0000BB">print_r</span><span style="color: #007700">(</span><span style="color: #0000BB">$set</span><span style="color: #007700">);</span></span><br />
</code></p>
<p>Results in an infinite loop.  Note this actually is an infinite loop, you’ll have to either kill the script yourself or wait for your OS to run out of memory.  I added the following line to my script so PHP would run out of memory very quickly, I suggest you do the same if you’re going to be running these infinite loop tests:</p>
<p><code><span style="color: #000000"><span style="color: #0000BB">ini_set</span><span style="color: #007700">(</span><span style="color: #DD0000">"memory_limit"</span><span style="color: #007700">,</span><span style="color: #DD0000">"1M"</span><span style="color: #007700">);</span></span><br />
</code></p>
<p>So in this previous example with the infinite loop, we see the reason why PHP was written to create a copy of the array to loop over.  When a copy is created and used only by the structure of the loop construct itself, the array stays static throughout the execution of the loop, so you’ll never run into issues.</p>
<p>But wait, there’s more.  PHP fails to create a copy of the array if a reference is used at all.  We know that referencing $item will cause the infinite loop scenario above, but if $set is referenced anywhere else in the script, even the non-referencing foreach format will break:</p>
<p><code><span style="color: #000000"><span style="color: #0000BB">$set&nbsp;</span><span style="color: #007700">=&nbsp;array(</span><span style="color: #DD0000">"apple"</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">"banana"</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">"coconut"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$a&nbsp;</span><span style="color: #007700">=&nbsp;&amp;</span><span style="color: #0000BB">$set</span><span style="color: #007700">;<br />foreach&nbsp;(&nbsp;</span><span style="color: #0000BB">$set&nbsp;</span><span style="color: #007700">AS&nbsp;</span><span style="color: #0000BB">$item&nbsp;</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$set</span><span style="color: #007700">[]&nbsp;=&nbsp;</span><span style="color: #0000BB">ucfirst</span><span style="color: #007700">(</span><span style="color: #0000BB">$item</span><span style="color: #007700">);<br />}</span></span><br />
</code></p>
<p>Results in an infinite loop, even though $item isn’t by reference.  Using $a instead of $set gives identical results.  </p>
<p>This is not to say that $item is implicitly used by reference if $set is referenced.  See this example:</p>
<p><code><span style="color: #000000"><span style="color: #0000BB">$set&nbsp;</span><span style="color: #007700">=&nbsp;array(</span><span style="color: #DD0000">"apple"</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">"banana"</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">"coconut"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$a&nbsp;</span><span style="color: #007700">=&nbsp;&amp;</span><span style="color: #0000BB">$set</span><span style="color: #007700">;<br />foreach&nbsp;(&nbsp;</span><span style="color: #0000BB">$a&nbsp;</span><span style="color: #007700">AS&nbsp;</span><span style="color: #0000BB">$item&nbsp;</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$item&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">ucfirst</span><span style="color: #007700">(</span><span style="color: #0000BB">$item</span><span style="color: #007700">);<br />}<br /></span><span style="color: #0000BB">print_r</span><span style="color: #007700">(</span><span style="color: #0000BB">$set</span><span style="color: #007700">);</span></span><br />
</code></p>
<p>This outputs:</p>
<pre>Array
(
    [0] => apple
    [1] => banana
    [2] => coconut
)</pre>
<p>$set is unchanged from the original values, because even though $set is referenced by $a, and $set has not been copied, $item is still given only lexical scope in relation to the loop, and will not pass modifications back to $set.  You will still have to assign it by reference to make changes to the original array:</p>
<p><code><span style="color: #000000"><span style="color: #0000BB">$set&nbsp;</span><span style="color: #007700">=&nbsp;array(</span><span style="color: #DD0000">"apple"</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">"banana"</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">"coconut"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$a&nbsp;</span><span style="color: #007700">=&nbsp;&amp;</span><span style="color: #0000BB">$set</span><span style="color: #007700">;<br />foreach&nbsp;(&nbsp;</span><span style="color: #0000BB">$a&nbsp;</span><span style="color: #007700">AS&nbsp;&amp;</span><span style="color: #0000BB">$item&nbsp;</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$item&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">strrev</span><span style="color: #007700">(</span><span style="color: #0000BB">$item</span><span style="color: #007700">);<br />}<br /></span><span style="color: #0000BB">print_r</span><span style="color: #007700">(</span><span style="color: #0000BB">$set</span><span style="color: #007700">);</span></span><br />
</code></p>
<p>This outputs:</p>
<pre>Array
(
    [0] => elppa
    [1] => ananab
    [2] => tunococ
)</pre>
<p>All of these examples also work in associative arrays using the foreach ( $set AS $key => $item ) syntax.  $key can never be used by-reference it always comes from the array the loop construct is using, and cannot be modified.  So the tricks used to modify array items in-position won’t work for modifying the keys.  You can create new keys in the array, however, and unset the existing ones, like so:</p>
<p><code><span style="color: #000000"><span style="color: #0000BB">$set&nbsp;</span><span style="color: #007700">=&nbsp;array(</span><span style="color: #DD0000">"apple"</span><span style="color: #007700">=&gt;</span><span style="color: #DD0000">"red"</span><span style="color: #007700">,</span><span style="color: #DD0000">"banana"</span><span style="color: #007700">=&gt;</span><span style="color: #DD0000">"yellow"</span><span style="color: #007700">,</span><span style="color: #DD0000">"coconut"</span><span style="color: #007700">=&gt;</span><span style="color: #DD0000">"brown"</span><span style="color: #007700">);<br />foreach&nbsp;(&nbsp;</span><span style="color: #0000BB">$set&nbsp;</span><span style="color: #007700">AS&nbsp;</span><span style="color: #0000BB">$key&nbsp;</span><span style="color: #007700">=&gt;&nbsp;</span><span style="color: #0000BB">$item&nbsp;</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$set</span><span style="color: #007700">[</span><span style="color: #0000BB">ucfirst</span><span style="color: #007700">(</span><span style="color: #0000BB">$key</span><span style="color: #007700">)]&nbsp;=&nbsp;</span><span style="color: #0000BB">$item</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;unset(</span><span style="color: #0000BB">$set</span><span style="color: #007700">[</span><span style="color: #0000BB">$key</span><span style="color: #007700">]);<br />}<br /></span><span style="color: #0000BB">print_r</span><span style="color: #007700">(</span><span style="color: #0000BB">$set</span><span style="color: #007700">);</span></span><br />
</code></p>
<p>This outputs:</p>
<pre>Array
(
    [Apple] => red
    [Banana] => yellow
    [Coconut] => brown
)</pre>
<p>However, as you may have already noticed, this array was copied before the loop began.  If you were using the array in a situation where it couldn’t be copied, you will run into errors:</p>
<p><code><span style="color: #000000"><span style="color: #0000BB">$set&nbsp;</span><span style="color: #007700">=&nbsp;array(</span><span style="color: #DD0000">"apple"</span><span style="color: #007700">=&gt;</span><span style="color: #DD0000">"red"</span><span style="color: #007700">,</span><span style="color: #DD0000">"banana"</span><span style="color: #007700">=&gt;</span><span style="color: #DD0000">"yellow"</span><span style="color: #007700">,</span><span style="color: #DD0000">"coconut"</span><span style="color: #007700">=&gt;</span><span style="color: #DD0000">"brown"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$a&nbsp;</span><span style="color: #007700">=&nbsp;&amp;</span><span style="color: #0000BB">$set</span><span style="color: #007700">;<br />foreach&nbsp;(&nbsp;</span><span style="color: #0000BB">$set&nbsp;</span><span style="color: #007700">AS&nbsp;</span><span style="color: #0000BB">$key&nbsp;</span><span style="color: #007700">=&gt;&nbsp;</span><span style="color: #0000BB">$item&nbsp;</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$set</span><span style="color: #007700">[</span><span style="color: #0000BB">ucfirst</span><span style="color: #007700">(</span><span style="color: #0000BB">$key</span><span style="color: #007700">)]&nbsp;=&nbsp;</span><span style="color: #0000BB">$item</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;unset(</span><span style="color: #0000BB">$set</span><span style="color: #007700">[</span><span style="color: #0000BB">$key</span><span style="color: #007700">]);<br />}<br /></span><span style="color: #0000BB">print_r</span><span style="color: #007700">(</span><span style="color: #0000BB">$set</span><span style="color: #007700">);</span></span><br />
</code></p>
<p>This outputs:</p>
<pre>Array
(
)</pre>
<p>Because the array was referenced and not copied, you get vastly unpredictable results when attempting to alter the physical structure of the array, especially using unset().  Without the unset() call in this example, you operate on the original array and loop through the original array, so you get the same infinite-loop generating code as before, but since we’re specifying the key for $set it doesn’t continue forever:</p>
<p><code><span style="color: #000000"><span style="color: #0000BB">$set&nbsp;</span><span style="color: #007700">=&nbsp;array(</span><span style="color: #DD0000">"apple"</span><span style="color: #007700">=&gt;</span><span style="color: #DD0000">"red"</span><span style="color: #007700">,</span><span style="color: #DD0000">"banana"</span><span style="color: #007700">=&gt;</span><span style="color: #DD0000">"yellow"</span><span style="color: #007700">,</span><span style="color: #DD0000">"coconut"</span><span style="color: #007700">=&gt;</span><span style="color: #DD0000">"brown"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$a&nbsp;</span><span style="color: #007700">=&nbsp;&amp;</span><span style="color: #0000BB">$set</span><span style="color: #007700">;<br />foreach&nbsp;(&nbsp;</span><span style="color: #0000BB">$set&nbsp;</span><span style="color: #007700">AS&nbsp;</span><span style="color: #0000BB">$key&nbsp;</span><span style="color: #007700">=&gt;&nbsp;</span><span style="color: #0000BB">$item&nbsp;</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$set</span><span style="color: #007700">[</span><span style="color: #0000BB">ucfirst</span><span style="color: #007700">(</span><span style="color: #0000BB">$key</span><span style="color: #007700">)]&nbsp;=&nbsp;</span><span style="color: #0000BB">$item</span><span style="color: #007700">;<br />}<br /></span><span style="color: #0000BB">print_r</span><span style="color: #007700">(</span><span style="color: #0000BB">$set</span><span style="color: #007700">);</span></span><br />
</code></p>
<p>This outputs:</p>
<pre>Array
(
    [apple] => red
    [banana] => yellow
    [coconut] => brown
    [Apple] => red
    [Banana] => yellow
    [Coconut] => brown
)</pre>
<p>You can prove that it’s still possible to enter an infinite loop by adding a $set[] inside your loop:</p>
<p><code><span style="color: #000000"><span style="color: #0000BB">$set&nbsp;</span><span style="color: #007700">=&nbsp;array(</span><span style="color: #DD0000">"apple"</span><span style="color: #007700">=&gt;</span><span style="color: #DD0000">"red"</span><span style="color: #007700">,</span><span style="color: #DD0000">"banana"</span><span style="color: #007700">=&gt;</span><span style="color: #DD0000">"yellow"</span><span style="color: #007700">,</span><span style="color: #DD0000">"coconut"</span><span style="color: #007700">=&gt;</span><span style="color: #DD0000">"brown"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$a&nbsp;</span><span style="color: #007700">=&nbsp;&amp;</span><span style="color: #0000BB">$set</span><span style="color: #007700">;<br />foreach&nbsp;(&nbsp;</span><span style="color: #0000BB">$set&nbsp;</span><span style="color: #007700">AS&nbsp;</span><span style="color: #0000BB">$key&nbsp;</span><span style="color: #007700">=&gt;&nbsp;</span><span style="color: #0000BB">$item&nbsp;</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$set</span><span style="color: #007700">[</span><span style="color: #0000BB">ucfirst</span><span style="color: #007700">(</span><span style="color: #0000BB">$key</span><span style="color: #007700">)]&nbsp;=&nbsp;</span><span style="color: #0000BB">$item</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$set</span><span style="color: #007700">[]&nbsp;=&nbsp;</span><span style="color: #0000BB">$item</span><span style="color: #007700">;<br />}<br /></span><span style="color: #0000BB">print_r</span><span style="color: #007700">(</span><span style="color: #0000BB">$set</span><span style="color: #007700">);</span></span><br />
</code></p>
<p>This results in an infinite loop.</p>
<p>One interesting thing you can do with the $key => $item syntax when the array is copied is modify the original array structure without fear of causing loop issues:</p>
<p><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br />$set&nbsp;</span><span style="color: #007700">=&nbsp;array(</span><span style="color: #DD0000">"apple"</span><span style="color: #007700">=&gt;</span><span style="color: #DD0000">"red"</span><span style="color: #007700">,</span><span style="color: #DD0000">"banana"</span><span style="color: #007700">=&gt;</span><span style="color: #DD0000">"yellow"</span><span style="color: #007700">,</span><span style="color: #DD0000">"coconut"</span><span style="color: #007700">=&gt;</span><span style="color: #DD0000">"brown"</span><span style="color: #007700">);<br />foreach&nbsp;(&nbsp;</span><span style="color: #0000BB">$set&nbsp;</span><span style="color: #007700">AS&nbsp;</span><span style="color: #0000BB">$key&nbsp;</span><span style="color: #007700">=&gt;&nbsp;</span><span style="color: #0000BB">$item&nbsp;</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$set</span><span style="color: #007700">[]&nbsp;=&nbsp;</span><span style="color: #0000BB">ucfirst</span><span style="color: #007700">(</span><span style="color: #0000BB">$item</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;unset(</span><span style="color: #0000BB">$set</span><span style="color: #007700">[</span><span style="color: #0000BB">$key</span><span style="color: #007700">]);<br />}<br /></span><span style="color: #0000BB">print_r</span><span style="color: #007700">(</span><span style="color: #0000BB">$set</span><span style="color: #007700">); </span></span><br />
</code></p>
<p>This outputs:</p>
<pre>Array
(
    [0] => Red
    [1] => Yellow
    [2] => Brown
)</pre>
<p>As you can see from this example, the array was copied for use in the loop construct.  References to $set within the loop still refer to the outer version of $set, so the unset() call and the $set[] addition work on the original, leaving us with a nicely upper-cased version of the original, without keys.  </p>
<p>This knowledge is useful for developers who are trying to plug memory holes in PHP applications.  If you foreach through an array of objects that can be 50MB in size, you create an entire copy of the structure in memory for no reason other than to power the loop.  If your loop doesn’t modify the structure of the array or add to it at all, it would be vastly more efficient to add the “cheat” of $a = &$array; right before your array to prevent PHP from making a copy.  </p>
<p>This knowledge is also hopefully useful for programmers who cannot figure out why arrays are behaving like they are.  Basically, if you don’t use references, the loop executes once for each member in the original array, regardless of what you do to the original.  </p>
<p>NOTE:  These tests were performed on PHP version 5.2.5.  5.2.0 and earlier perform differently.  Run these tests yourself under controlled circumstances before relying on PHP to behave in any particular way.</p>
]]></content:encoded>
			<wfw:commentRss>http://sldn.softlayer.com/01/2009/php-memory-management-in-foreach/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
