<?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>Mission Data Blog &#187; System Administration</title>
	<atom:link href="http://www.missiondata.com/blog/category/system-administration/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.missiondata.com/blog</link>
	<description>Louisville-based Web Development &#038; Software Engineering</description>
	<lastBuildDate>Tue, 18 May 2010 14:24:23 +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>Showing progress using dd</title>
		<link>http://www.missiondata.com/blog/system-administration/87/showing-progress-using-dd/</link>
		<comments>http://www.missiondata.com/blog/system-administration/87/showing-progress-using-dd/#comments</comments>
		<pubDate>Wed, 16 Sep 2009 15:04:39 +0000</pubDate>
		<dc:creator>steveny</dc:creator>
				<category><![CDATA[System Administration]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://www.missiondata.com/blog/linux/87/showing-progress-using-dd/</guid>
		<description><![CDATA[One of the frustrating behaviors of dd is that it provides no feedback about what it is doing.  It does however provide a signal (USR1) that you can send to the process that will dump the current progress.  Open a new terminal (I use screen) and type:

while true; do kill -USR1 `pidof dd`; [...]]]></description>
			<content:encoded><![CDATA[<p>One of the frustrating behaviors of <a href="http://en.wikipedia.org/wiki/Dd_%28Unix%29">dd</a> is that it provides no feedback about what it is doing.  It does however provide a signal (USR1) that you can send to the process that will dump the current progress.  Open a new terminal (I use screen) and type:</p>
<pre>
<code>while true; do kill -USR1 `pidof dd`; sleep 2; done</code>
</pre>
<p>(NOTE: if `pidof dd` doesn&#8217;t work for you, just use the process id directly)</p>
<p>Switch back to the terminal where dd is running and you should see:</p>
<pre>
<code>9902751744 bytes (9.9 GB) copied, 732.883 s, 13.5 MB/s
9469+0 records in
9468+0 records out
9927917568 bytes (9.9 GB) copied, 734.914 s, 13.5 MB/s
9496+0 records in
9495+0 records out
9956229120 bytes (10 GB) copied, 736.941 s, 13.5 MB/s</code>
</pre>
<p>updating every couple of seconds.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.missiondata.com/blog/system-administration/87/showing-progress-using-dd/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Deploying a Subversion branch with Capistrano</title>
		<link>http://www.missiondata.com/blog/system-administration/84/deploying-an-svn-branch-with-capistrano/</link>
		<comments>http://www.missiondata.com/blog/system-administration/84/deploying-an-svn-branch-with-capistrano/#comments</comments>
		<pubDate>Wed, 30 Jan 2008 15:39:34 +0000</pubDate>
		<dc:creator>steveny</dc:creator>
				<category><![CDATA[System Administration]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.missiondata.com/blog/ruby/84/deploying-an-svn-branch-with-capistrano/</guid>
		<description><![CDATA[Capistrano is a tool for automating tasks via SSH on remote servers.  It has many uses, I (and many others) use it to deploy their (rails) applications.  The best I can tell there is no built in way to deploy a branch from your source code control system.  There are a couple [...]]]></description>
			<content:encoded><![CDATA[<p><a href='http://www.capify.org/'>Capistrano</a> is a tool for automating tasks via SSH on remote servers.  It has many uses, I (and many others) use it to deploy their (rails) applications.  The best I can tell there is no built in way to deploy a branch from your source code control system.  There are a couple <a href='http://blog.aisleten.com/2007/09/04/deploying-svn-tags-using-capistrano/'>ways of accomplishing</a> this.  I chose passing in the branch as a parameter to the Capistrano command:</p>
<pre>
<code>cap --set-before branch=testbranch  deploy</code>
</pre>
<p><span id="more-84"></span><br />
&#8230;where &#8216;testbranch&#8217; is the name of my subversion branch, and &#8216;deploy&#8217; is the action to take.  The &#8216;&#8211;set-before option&#8217; sets a variable before the recipes are loaded (<a href='http://osdir.com/ml/lang.ruby.capistrano.general/2006-11/msg00012.html'>sort of)</a>.  All you need to do to make this work you just need to set the repository URL correctly based on if the branch variable exists or not.  In my case, that is editing the top of deploy.rb in the config section of my rails app:</p>
<pre>
<code>if variables.include?(:branch)
  set :repository,  "http://svn.example.com/project/branches/#{branch}"
else
  set :repository,  "http://svn.example.com/project/trunk"
end</code>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.missiondata.com/blog/system-administration/84/deploying-an-svn-branch-with-capistrano/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#8216;cvs update: move away foo.bar; it is in the way&#8217;</title>
		<link>http://www.missiondata.com/blog/system-administration/81/cvs-update-move-away-foobar-it-is-in-the-way/</link>
		<comments>http://www.missiondata.com/blog/system-administration/81/cvs-update-move-away-foobar-it-is-in-the-way/#comments</comments>
		<pubDate>Thu, 26 Apr 2007 21:00:40 +0000</pubDate>
		<dc:creator>darrend</dc:creator>
				<category><![CDATA[System Administration]]></category>
		<category><![CDATA[CVS]]></category>
		<category><![CDATA[Utilities]]></category>

		<guid isPermaLink="false">http://www.missiondata.com/blog/utilities/81/cvs-update-move-away-foobar-it-is-in-the-way/</guid>
		<description><![CDATA[A client site still uses cvs, the ever trusty version control system. After what seemed a run of the mill merge I noticed this:
C lib/jt400_3_3.jar
cvs update: move away lib/jt400_3_3.jar; it is in the way
Very peculiar. That file hadn&#8217;t changed on the branch. I googled around and an explanation started to come together.
First, from the always [...]]]></description>
			<content:encoded><![CDATA[<p>A client site still uses cvs, the ever trusty version control system. After what seemed a run of the mill merge I noticed this:</p>
<pre><code class="console">C lib/jt400_3_3.jar
cvs update: move away lib/jt400_3_3.jar; it is in the way</code></pre>
<p>Very peculiar. That file hadn&#8217;t changed on the branch. I <a href="http://www.google.com/search?q=cvs+update+move+away">googled around</a> and an explanation started to come together.</p>
<p>First, from the always excellent <a href="http://mindprod.com/jgloss/cvs.html">Roedy Green’s Java &#038; Internet Glossary on Mindprod</a>:</p>
<blockquote><p>
CVS is disturbed by the appearance of repository files it did not put there. Your best bet is simply to delete the entire directory containing the offending file by hand, and re checkout or reupdate the directory to build the necessary entries. Then you can add the files safely.
</p></blockquote>
<p>Then, I found this <a href="http://mail.lon-capa.org/pipermail/lon-capa-admin/Week-of-Mon-20030915/000367.html">mailing list post</a>:</p>
<blockquote><p>
This means the file that CVS wants to checkout exists on the local machine but CVS never created the file in the past. This it isn&#8217;t CVS&#8217;s file and it complains rather than blindly overwriting.
</p></blockquote>
<p>The solution everywhere was the same: just blow away the directory and check it out again. Worked for me. Now I need to puzzle out how it happened in the first place&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.missiondata.com/blog/system-administration/81/cvs-update-move-away-foobar-it-is-in-the-way/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Mongrel vs. WEBrick</title>
		<link>http://www.missiondata.com/blog/system-administration/71/mongrel-vs-webrick/</link>
		<comments>http://www.missiondata.com/blog/system-administration/71/mongrel-vs-webrick/#comments</comments>
		<pubDate>Tue, 03 Apr 2007 16:08:13 +0000</pubDate>
		<dc:creator>steveny</dc:creator>
				<category><![CDATA[System Administration]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.missiondata.com/blog/ruby/71/mongrel-vs-webrick/</guid>
		<description><![CDATA[We had the need to hook up a simple ruby web process (non-rails) to our production apache server.  As Leslie Hensley pointed out, fcgi and scgi are on the way out, and mongrel + mod_proxy_balancer is the new way to go.  We use mongrel extensively in our rails deploys, but always just used [...]]]></description>
			<content:encoded><![CDATA[<p>We had the need to hook up a simple ruby web process (non-rails) to our production apache server.  As <a href="http://www.papermountain.org/">Leslie Hensley</a> pointed out, fcgi and scgi are on the way out, and <a href="http://mongrel.rubyforge.org/">mongrel</a> + <a href="http://mongrel.rubyforge.org/docs/apache.html">mod_proxy_balancer</a> is the new way to go.  We use mongrel extensively in our rails deploys, but always just used <a href="http://www.webrick.org/">WEBrick</a> to do simple serving.  To make a long story short, we had to ask ourselves&#8230;.is mongrel that much better (and in this case better == faster) than WEBrick?</p>
<p><span id="more-71"></span></p>
<p>At first I decided my test would just respond with the yamlized request (just like the <a href="http://mongrel.rubyforge.org/rdoc/index.html">mongrel sample</a> did).  This worked fine but there was a significant size difference in the two documents (WEBrick&#8217;s was much bigger).  In the end, I just decided to respond with a few bytes of text. </p>
<h3>The Code</h3>
<p><b>mongrel_service.rb:</b> </p>
<pre>
<code>require 'rubygems'
require 'mongrel'
require 'yaml'

class SimpleHandler &lt; Mongrel::HttpHandler
  def process(request, response)
    response.start do |head,out|
      head["Content-Type"] = "text/html"
      out &lt;&lt; "I am mongrel, hear me roar"
    end
  end
end

config = Mongrel::Configurator.new :host =&gt; "localhost", :port =&gt; 4000 do
  listener {uri "/", :handler =&gt; SimpleHandler.new}
  trap("INT") { stop }
  run
end

config.join</code>
</pre>
<p>
<b>webrick_service.rb:</b></p>
<pre>
<code>require 'webrick'
require 'yaml'
include WEBrick

class SimpleServlet &lt; HTTPServlet::AbstractServlet
  def do_GET(request, response)
    response["Content-Type"] = "text/html"
    response.body = "I am WEBrick, hear me roar"
  end
end

s = HTTPServer.new( :Port =&gt; 4001 )
s.mount("/", SimpleServlet)
trap('INT'){ s.shutdown }
s.start</code>
</pre>
<h3>The Test</h3>
<p>There are <a href="http://www.joedog.org/JoeDog/Siege">serveral</a> <a href="http://www.hpl.hp.com/research/linux/httperf/">good</a> benchmarking tools available, but I had <a href="http://en.wikipedia.org/wiki/ApacheBench">apache bench (ab)</a> handy, so that is what I used.  I just used the stock gem install of mongrel and the WEBrick that comes with ruby 1.8.4 (the one non-stock change I made was to comment out access logging for WEBrick since mongrel doesn&#8217;t log by default).</p>
<h3>The Results</h3>
<table border="1">
<tr>
<th>Total Requests</th>
<th>Concurrent Connections</th>
<th>WEBrick (seconds) </th>
<th>Mongrel (seconds) </th>
</tr>
<tr>
<td>1000</td>
<td>1</td>
<td>1.889523</td>
<td>0.365838</td>
</tr>
<tr>
<td>10000</td>
<td>10</td>
<td>19.443034</td>
<td>4.411788</td>
</tr>
<tr>
<td>10000</td>
<td>100</td>
<td>20.906522</td>
<td>4.174591</td>
</tr>
</table>
<h3>The Conclusion</h3>
<p>Looks like mongrel it is&#8230;.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.missiondata.com/blog/system-administration/71/mongrel-vs-webrick/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>iSeries SQL Performance</title>
		<link>http://www.missiondata.com/blog/system-administration/68/iseries-sql-performance/</link>
		<comments>http://www.missiondata.com/blog/system-administration/68/iseries-sql-performance/#comments</comments>
		<pubDate>Mon, 12 Mar 2007 01:08:10 +0000</pubDate>
		<dc:creator>Rich Rodriguez</dc:creator>
				<category><![CDATA[System Administration]]></category>
		<category><![CDATA[as400]]></category>
		<category><![CDATA[Utilities]]></category>

		<guid isPermaLink="false">http://www.missiondata.com/blog/utilities/68/iseries-sql-performance/</guid>
		<description><![CDATA[Our project has entered the stage where we start tuning the data access to improve performance. This project uses Hibernate to access a AS400/iSeries system via the JT400 JDBC driver.  My prior experience using the SQL Server
database introduced me to Microsoft&#8217;s Query Analyzer, which is a nice tool for identifying where you need to [...]]]></description>
			<content:encoded><![CDATA[<p>Our project has entered the stage where we start tuning the data access to improve performance. This project uses Hibernate to access a AS400/iSeries system via the JT400 JDBC driver.  My prior experience using the SQL Server<br />
database introduced me to Microsoft&#8217;s Query Analyzer, which is a nice tool for identifying where you need to index the database. A bit of searching turned up an IBM tool called <a title="Visual Explain" href="https://publib.boulder.ibm.com/iseries/v5r2/ic2924/index.htm?info/rzajq/rzajqmstvisexpl.htm">Visual Explain</a> that fits the same need. The sysadmin started the profiling tool against my connection, and I ran through a standard usage scenario in our application. Visual Explain showed each query, how long it took, the access strategy, and recommended indexes. This kind of tool is absolutely essential for database performance tuning.</p>
<p>The second important item we learned from this process is the performance difference between a true SQL index on the iSeries and a keyed logical index. From iSeries V4R2 on, SQL indexes have page sizes of 64k. By comparison, a DDS logical will max out at 32k, and will typically be much smaller. The performance is so much better that our customer is converting all all their DDS logical indexes to SQL, even if only their legacy RPG applications use it. <a title="DDS and SQL Performance" href="http://www-03.ibm.com/servers/eserver/iseries/db2/pdf/Performance_DDS_SQL.pdf">This IBM document</a> has a good discussion of this issue.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.missiondata.com/blog/system-administration/68/iseries-sql-performance/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Scary apache errors moving from prefork to worker</title>
		<link>http://www.missiondata.com/blog/system-administration/66/scary-apache-errors-moving-from-prefork-to-worker/</link>
		<comments>http://www.missiondata.com/blog/system-administration/66/scary-apache-errors-moving-from-prefork-to-worker/#comments</comments>
		<pubDate>Wed, 07 Mar 2007 20:52:52 +0000</pubDate>
		<dc:creator>steveny</dc:creator>
				<category><![CDATA[System Administration]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[solaris]]></category>

		<guid isPermaLink="false">http://www.missiondata.com/blog/uncategorized/66/scary-apache-errors-moving-from-prefork-to-worker/</guid>
		<description><![CDATA[We were helping a client push more data through their apache/tomcat web application running on a Solaris box and decided to switch from the process (prefork) to the threaded(worker) processing model.  When we fired up the new apache we started getting errors like these:

[emerg] (45)Deadlock situation detected/avoided: apr_proc_mutex_lock failed. Attempting to shutdown process gracefully.

Not [...]]]></description>
			<content:encoded><![CDATA[<p>We were helping a client push more data through their apache/tomcat web application running on a Solaris box and decided to switch from the process (prefork) to the threaded(worker) processing model.  When we fired up the new apache we started getting errors like these:</p>
<pre>
<code>[emerg] (45)Deadlock situation detected/avoided: apr_proc_mutex_lock failed. Attempting to shutdown process gracefully.</code>
</pre>
<p>Not good.  After a <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=32325">little digging</a> we found that the default AcceptMutex switched from pthread to fcntl between apache 2.0.49 and 2.0.52.</p>
<p>Adding:</p>
<pre>
<code>AcceptMutex pthread</code>
</pre>
<p>to httpd.conf cleared up the errors and we&#8217;ve had smooth sailing ever since.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.missiondata.com/blog/system-administration/66/scary-apache-errors-moving-from-prefork-to-worker/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>How to build the PHP rrdtool extension by hand</title>
		<link>http://www.missiondata.com/blog/system-administration/54/how-to-build-the-php-rrdtool-extention-by-hand/</link>
		<comments>http://www.missiondata.com/blog/system-administration/54/how-to-build-the-php-rrdtool-extention-by-hand/#comments</comments>
		<pubDate>Tue, 09 May 2006 12:17:28 +0000</pubDate>
		<dc:creator>carsonm</dc:creator>
				<category><![CDATA[System Administration]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://blogs.missiondata.com/?p=54</guid>
		<description><![CDATA[I think by now most sysadmin types know about rrdtool and the nice graphs it makes. I recently wanted to create some graphs by hand using PHP so I turned to the php-rrdtool extension. I found that it takes a little work to get it to compile but that could be because I&#8217;m not constantly [...]]]></description>
			<content:encoded><![CDATA[<p>I think by now most sysadmin types know about <a href="http://oss.oetiker.ch/rrdtool/">rrdtool</a> and the nice graphs it makes. I recently wanted to create some graphs by hand using PHP so I turned to the php-rrdtool extension. I found that it takes a little work to get it to compile but that could be because I&#8217;m not constantly recompiling PHP and just don&#8217;t know better. You can get this module as an rpm for fedora (php-rrdtool) but I like to compile php by hand so I couldn&#8217;t use it. I&#8217;m going to assume that you know how to compile PHP normally with whatever other items you want to include and that you have the rrdtool development libraries installed or have compiled and installed rrdtool from source.</p>
<h3>Step 1. Get the PHP rrdtool source</h3>
<p>Go to the contrib directory on the rrdtool distribution site:<br />
<a href="http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/pub/contrib/">http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/pub/contrib/</a></p>
<p>There are a number of files in this directory that mention rrd. You want the one named: <a href="http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/pub/contrib/php_rrdtool.tgz">php_rrdtool.tgz</a> <br/></p>
<p><span id="more-54"></span></p>
<h3>Step 2. Untar into the correct place</h3>
<p>Now that you have the source go into your php source directory and then into the ext directory. So you will be somewhere like this:</p>
<p>/usr/local/src/php-5.1.3/ext/</p>
<p>Now untar the source into this directory.</p>
<h3>Step 3. Recreate the php configuration file</h3>
<p>There is a warning that you will get if you do not have autoconf 2.13 installed on your system when you try to do this. It is easy enough to get this version if you have fedora so that is what I did. </p>
<p>One tricky part to this is that I had to remove the old configuration file first before the new one could be created.</p>
<ol>
<li>Change directory to your PHP source, if you are still in the ext directory just cd ..</li>
<li>Remove the existing configuration file</li>
<li>If you are using autoconf 2.13 run the following command: <br/> PHP_AUTOCONF=autoconf-2.13 ./buildconf &#8211;force<br/> If you are using whatever other autoconf you have installed just run: <br/> ./buildconf &#8211;force</li>
<li>You should now have a new configuration file that can be run with the &#8211;with-rrdtool option</li>
</ol>
<h3>Step 4. Test</h3>
<p>After compiling with rrdtool you should be able to use the phpinfo() function to list the installed extensions. If everything went right you should see rrdtool listed.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.missiondata.com/blog/system-administration/54/how-to-build-the-php-rrdtool-extention-by-hand/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>managing disk space with logrotate</title>
		<link>http://www.missiondata.com/blog/system-administration/48/managing-disk-space-with-logrotate/</link>
		<comments>http://www.missiondata.com/blog/system-administration/48/managing-disk-space-with-logrotate/#comments</comments>
		<pubDate>Thu, 27 Apr 2006 02:28:13 +0000</pubDate>
		<dc:creator>darrend</dc:creator>
				<category><![CDATA[System Administration]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[logrotate]]></category>
		<category><![CDATA[Utilities]]></category>

		<guid isPermaLink="false">http://blogs.missiondata.com/?p=48</guid>
		<description><![CDATA[At a customer site, the test and production linux servers for some intranet applications were slowly running out of disk space. The apps themselves were running fine, it was the logfiles generated by the apps that were the issue; logging that came in useful just in case something went wrong, but quickly aged. In one [...]]]></description>
			<content:encoded><![CDATA[<p>At a customer site, the test and production linux servers for some intranet applications were slowly running out of disk space. The apps themselves were running fine, it was the logfiles generated by the apps that were the issue; logging that came in useful just in case something went wrong, but quickly aged. In one particular case, a catalina.out file was several years old and was 11 gigabytes; 90% of it wasn&#8217;t really relevant any longer.</p>
<p>The solution to the problem of wrangling logfiles is probably already installed on your server: it&#8217;s <a href="http://iain.cx/src/logrotate/">logrotate</a>. Chances are logrotate is already configured in your system crontab as a daily task, and chances are it is configured to obey any configuration files found in the <tt>/etc/logrotate.d</tt> directory. If you find that directory, you are probably good to go.</p>
<p><span id="more-48"></span><br />
In <tt>/etc/logrotate.d</tt> you&#8217;ll find several short configuration files. Each configuration deals with 1 or 2 related logfiles that should be checked and possibly administered on a regular basis. Logrotate can do alot of things with a logfile: clear the target log, create a copy of it, compress the copy, keep <em>N</em> backup copies, and it can be configured to rotate the target logfile on a daily, weekly, or monthly basis.</p>
<p>For example, here is how my client handles a logfile generated by a log4j-enabled java rmi server:</p>
<pre>
<code> /appdir/log/java_rmi_log.txt {
    daily
    rotate 10
    copytruncate
    compress
    notifempty
    missingok
 }</code>
</pre>
<p>This configuration means<br />
<blockquote>On a <em>daily</em> basis <em>rotate</em>, <em>compress</em>, and retain up to <em>10</em> days worth of logs using the <em>copytruncate</em> method. But <em>notifempty</em>; if the log is empty don&#8217;t do anything. Finally, <em>missingok</em>, so no need to log an error anywhere if the target logfile isn&#8217;t found.
</p></blockquote>
<p>This is nigh on a <a href="http://en.wikipedia.org/wiki/Domain_Specific_Language">domain specific language</a> for logfile rotation, and like most DSLs I&#8217;ve come across it&#8217;s much easier to read than it is to remember when writing. Don&#8217;t worry, the <a href="http://www.die.net/doc/linux/man/man8/logrotate.8.html">man page for logrotate</a> lists all the details.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.missiondata.com/blog/system-administration/48/managing-disk-space-with-logrotate/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>accessing as400 databases with Ruby, Java, and the RubyJavaBridge</title>
		<link>http://www.missiondata.com/blog/system-administration/46/accessing-as400-databases-with-ruby-java-and-the-rubyjavabridge/</link>
		<comments>http://www.missiondata.com/blog/system-administration/46/accessing-as400-databases-with-ruby-java-and-the-rubyjavabridge/#comments</comments>
		<pubDate>Tue, 25 Apr 2006 04:13:27 +0000</pubDate>
		<dc:creator>darrend</dc:creator>
				<category><![CDATA[System Administration]]></category>
		<category><![CDATA[as400]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[Systems Integration]]></category>

		<guid isPermaLink="false">http://blogs.missiondata.com/?p=46</guid>
		<description><![CDATA[iSeries systems and Ruby are separate universes right now; I know of no native Ruby way to connect to an AS400 system. However, with the help of Java we can bridge the gap.
Probably the simplest example is connecting to an iSeries system using JDBC to select from some tables, and with the right libraries it [...]]]></description>
			<content:encoded><![CDATA[<p>iSeries systems and Ruby are separate universes right now; I know of no native Ruby way to connect to an AS400 system. However, with the help of Java we can bridge the gap.</p>
<p>Probably the simplest example is connecting to an iSeries system using JDBC to select from some tables, and with the right libraries it is straightforward. It&#8217;s also fun to be doing some nifty quick Ruby but with some preexisting and proven Java libraries.</p>
<p>Also, if you use Java and Ruby, definitely put arton&#8217;s <a href="http://arton.no-ip.info/collabo/backyard/?RubyJavaBridge">RubyJavaBridge</a> in your pocket; you&#8217;ll end up using it more than once.</p>
<p>What you&#8217;ll need:</p>
<ul>
<li>Ruby (well yea)
<li>Java (ok)
<li>access to an AS400 system (that&#8217;s the whole point here&#8230;)<br />For testing, I&#8217;ve been using a free account available from <a href="http://as400.holgerscherer.de/indexeng.html">Holger Scherer Software und Beratung</a>.
<li><tt>jt400.jar</tt> jdbc drivers from <a href="http://jt400.sourceforge.net/">JTOpen</a>, a great open-source Java library for AS400 access.
<li><a href="http://arton.no-ip.info/collabo/backyard/?RubyJavaBridge">RubyJavaBridge</a> is the keystone for this.
</ul>
<p>Installing the software is the hardest part of this exercise, but it&#8217;s more tedium than anything. Once you&#8217;ve got it all downloaded and running the fun can begin.</p>
<p><span id="more-46"></span></p>
<pre>
<code>require 'rjb'
Rjb::load('jtopen_5_0/lib/jt400.jar',['-Djdbc.drivers=com.ibm.as400.access.AS400JDBCDriver'])

DriverManager = Rjb::import('java.sql.DriverManager')

begin
  connection = DriverManager.getConnection('jdbc:as400://as400.holgerscherer.de','YOUR_USERNAME','YOUR_PASSWORD')
  statement = connection.prepareStatement("SELECT count(*) FROM SYSIBM.TABLES")
  result_set = statement.executeQuery

  while(result_set.next())
    puts result_set.getObject(1).toString
  end
ensure
  result_set.close if defined?(result_set) &amp;&amp; !statement.nil?
  statement.close if defined?(statement) &amp;&amp; !statement.nil?
  connection.close if defined?(connection) &amp;&amp; !connection.nil?
end</code>
</pre>
<pre>
<code class="console">$ ruby as400_rjb.rb
19138</code>
</pre>
<p>Very readable, I think. Java and Ruby actually play well together given half the chance and <a href="http://arton.no-ip.info/collabo/backyard/?RubyJavaBridge">arton&#8217;s fantastic bridge</a>.</p>
<p>Compare this with the pure Java implementation.</p>
<pre>
<code>import java.sql.*;

public class As400Jdbc
{
  public static void main(String args[])
  {
    Connection connection = null;
    try
    {
      connection = DriverManager.getConnection("jdbc:as400://as400.holgerscherer.de","USER","PASS");
      PreparedStatement statement = connection.prepareStatement("SELECT COUNT(*) FROM SYSIBM.TABLES");

      ResultSet resultSet = statement.executeQuery();

      while(resultSet.next())
      {
        System.out.println(resultSet.getObject(1));
      }
    }
    catch(SQLException e)
    {
      throw new RuntimeException(e);
    }
    finally
    {
      try{ if(connection!=null) connection.close(); }
      catch(SQLException e)
      {
        throw new RuntimeException(e);
      }
    }

  }
}</code>
</pre>
<pre>
<code class="console">$ javac As400Jdbc.java
$ java -cp jtopen_5_0/lib/jt400.jar:. -Djdbc.drivers=com.ibm.as400.access.AS400JDBCDriver As400Jdbc
19138</code>
</pre>
<p>The Ruby code and the Java code are nearly one-for-one so far, and that&#8217;s fine. Still, let&#8217;s see if we can&#8217;t pull the Java code more into Ruby&#8217;s world. The <code>begin...end</code> stuff gets tiresome; it would be nice if these Java classes could handle the resource allocation and disposal drudgery for us, using blocks.</p>
<pre>
<code>require 'rjb'
Rjb::load('/home/darren/dload/jtopen_5_0/lib/jt400.jar',['-Djdbc.drivers=com.ibm.as400.access.AS400JDBCDriver'])

DriverManager = Rjb::import('java.sql.DriverManager')
class &lt;&lt;DriverManager
  def with_connection(*args)
    begin
      connection = DriverManager.getConnection(*args)
      yield connection
    ensure
      connection.close
    end
  end
end

DriverManager.with_connection('jdbc:as400://as400.holgerscherer.de','USER_NAME','USER_PASS') do |conn|
  statement = conn.prepareStatement("SELECT count(*) FROM SYSIBM.TABLES")
  result_set = statement.executeQuery()
  result_set.next()
  puts result_set.getObject(1).toString
end</code>
</pre>
<p>I know I&#8217;m a geek because stuff like this makes me giggle. So many worlds are colliding here&#8211;Ruby, Java, AS400, DB2, the client system (Linux in this case)&#8211;and it all comes together so nicely. </p>
<p>I&#8217;m not saying I&#8217;d build an app out of this, but it will more than suffice for ad-hoc queries and quick scripts.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.missiondata.com/blog/system-administration/46/accessing-as400-databases-with-ruby-java-and-the-rubyjavabridge/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Long arguments and getops</title>
		<link>http://www.missiondata.com/blog/system-administration/17/17/</link>
		<comments>http://www.missiondata.com/blog/system-administration/17/17/#comments</comments>
		<pubDate>Tue, 07 Mar 2006 18:28:33 +0000</pubDate>
		<dc:creator>steveny</dc:creator>
				<category><![CDATA[System Administration]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[Utilities]]></category>

		<guid isPermaLink="false">http://blogs.missiondata.com/?p=17</guid>
		<description><![CDATA[I recently had a need to adapt a script that recrawls a site with nutch.  One of my design goals was to use the same command line options as the Fetchtool (one of the steps I had to take to recrawl a site).
It became apparent fairly quickly that bash&#8217;s built-in &#8216;getopts&#8217; didn&#8217;t support long [...]]]></description>
			<content:encoded><![CDATA[<p>I recently had a need to adapt a script that <a href="http://today.java.net/pub/a/today/2006/02/16/introduction-to-nutch-2.html">recrawls</a> a site with <a href="http://wiki.apache.org/nutch/">nutch</a>.  One of my design goals was to use the same command line options as the <a href="http://wiki.apache.org/nutch/DissectingTheNutchCrawler#head-35f305b76ece4e69fd33a02838f985f3d2cac0af">Fetchtool</a> (one of the steps I had to take to recrawl a site).</p>
<p>It became apparent fairly quickly that bash&#8217;s built-in &#8216;getopts&#8217; didn&#8217;t support long command line arguments, so I had to fall back on <a href="http://www.devdaily.com/unix/man/man1/getopt.1.shtml">getopt</a>.</p>
<p>Here is the portion of the script that parses the command line arguments:</p>
<pre>
<code>set -- `getopt -n$0 -u -a --longoptions="depth: adddays: topN:" "h" "$@"` || usage
[ $# -eq 0 ] &amp;&amp; usage

while [ $# -gt 0 ]
do
    case "$1" in
       --depth)   depth=$2;shift;;
       --adddays) adddays=$2;shift;;
       --topN)    topN=$2;shift;;
       -h)        usage;;
       --)        shift;break;;
       -*)        usage;;
       *)         break;;            #better be the crawl directory
    esac
    shift
done</code>
</pre>
<p>Deconstructing this bit by bit:</p>
<p><span id="more-17"></span></p>
<pre>
  <code>set -- `getopt -n$0 -u -a --longoptions="depth: adddays: topN:" "h" "$@"` || usage
[ $# -eq 0 ] &amp;&amp; usage
  </code>
</pre>
<p>&#8217;set &#8211;&#8217; unsets the existing postional parameters and sets them to the result of getopt.<br />
The call to getopts works like this:</p>
<ul>
<li> -n$0, sets the nicename to the name of the script (so warnings come back nicely from getopts)
<li> -a, allows long arguments to start with a singe &#8216;-&#8217; (they ususally have two (&#8217;&#8211;&#8217;)
<li> &#8211;longoptions=&#8221;depth: adddays: topN:&#8221;, sets the format of the long options.  In this case I have 3 (depth, adddays, and topN).  The<br />
trailing colon indicates I am expecting an additional argument. </p>
<li>  &#8220;h&#8221;, the short options (-h)
<li> &#8220;$@&#8221;, the arguments passed into the script
  </ul>
<p>The &#8216;||&#8217; at the end and the second line will call my usage statement if  an error comes back from getopt (a non-0 return code).  The next line make sure we get at least one argument back.</p>
<p>To help understand what goes on next, lets run that command at the shell:</p>
<pre>
  <code class="console"> $ getopt -nrecrawl.sh -u -a --longoptions="depth: adddays: topN:" "h" -depth 5 -adddays 10 -topN 3 -h -x
recrawl.sh: unrecognized option `-x'
 --depth 5 --adddays 10 --topN 3 -h --
  </code>
</pre>
<p>A few items of note.  The first is the warning message we get because &#8216;x&#8217; is an unknown option (notice it is prefaced by what we supplied to the -n argument).  The second is the result of the getopt operation on my command line parameters.</p>
<p>Now to interpret the results:</p>
<pre>
  <code>while [ $# -gt 0 ]
do
    case "$1" in
       --depth)   depth=$2;shift;;
...
       -h)        usage;;
       --)        shift;break;;
       -*)        usage;;
       *)         break;;            #better be the crawl directory
    esac
    shift
done
  </code>
</pre>
<p>The while loop loops through each of the arguments return from getopt.  If an argument requires an additional value, I use $2 to snag that value and assign it to a variable.  When we are done with an argument, we shift passed it and move on to the next one.  A few special cases exist:</p>
<ul>
<li>-*) matches any unkown option and prints the usage statement
<li> *) matchs any other argument (in this case it is our required directory)
<li> &#8211;) is the end marker from getopt
  </ul>
<p>The script then goes on to verify the parameters (like the directory exists) and does the crawl&#8230;.but that is for another day.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.missiondata.com/blog/system-administration/17/17/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
