<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="http://www.atlantageek.com/feed.xml" rel="self" type="application/atom+xml" /><link href="http://www.atlantageek.com/" rel="alternate" type="text/html" /><updated>2026-05-22T14:47:53+00:00</updated><id>http://www.atlantageek.com/feed.xml</id><title type="html">Atlantageek</title><subtitle>Yet Another Abandoned website</subtitle><entry><title type="html">Importing data with node.js into DB</title><link href="http://www.atlantageek.com/importing-data-with-nodejs-to-db/" rel="alternate" type="text/html" title="Importing data with node.js into DB" /><published>2019-01-28T00:00:00+00:00</published><updated>2019-01-28T00:00:00+00:00</updated><id>http://www.atlantageek.com/importing-data-with-nodejs-to-db</id><content type="html" xml:base="http://www.atlantageek.com/importing-data-with-nodejs-to-db/"><![CDATA[<h2 id="frustration">Frustration</h2>
<p>Node’s greatest strength is often the source of frustration for a node programmer.  Most recently I was attempting to write a simple node.js script that took a csv file, parsed it and inserted it into a postgresql db.  This is simple in ruby, python and many other scripting related languages but I soon hit a roadblock on node.js. The following script was my first attempt at importing the data.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//date,date_block_num,shop_id,item_id,item_price,item_cnt_day</span>
<span class="kd">const</span> <span class="nx">company</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">ACME</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">csvFilePath</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">acme.csv</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">Client</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">pg</span><span class="dl">'</span><span class="p">);</span>

<span class="kd">const</span> <span class="nx">csv</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">"</span><span class="s2">csvtojson</span><span class="dl">"</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Client</span><span class="p">({</span>
    <span class="na">host</span><span class="p">:</span> <span class="dl">'</span><span class="s1">localhost</span><span class="dl">'</span><span class="p">,</span>
    <span class="na">port</span><span class="p">:</span> <span class="mi">5432</span><span class="p">,</span>
    <span class="na">user</span><span class="p">:</span> <span class="dl">'</span><span class="s1">me</span><span class="dl">'</span><span class="p">,</span>
    <span class="na">password</span><span class="p">:</span> <span class="dl">'</span><span class="s1">secretpassword</span><span class="dl">'</span><span class="p">,</span>
    <span class="na">database</span><span class="p">:</span> <span class="dl">'</span><span class="s1">cooldb</span><span class="dl">'</span>
<span class="p">})</span>
<span class="nx">client</span><span class="p">.</span><span class="nx">connect</span><span class="p">();</span>


<span class="nx">csv</span><span class="p">().</span><span class="nx">fromFile</span><span class="p">(</span><span class="nx">csvFilePath</span><span class="p">)</span>
    <span class="p">.</span><span class="nx">subscribe</span><span class="p">((</span><span class="nx">json</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
        <span class="c1">//console.log(json);</span>
        <span class="kd">var</span> <span class="nx">dt</span> <span class="o">=</span> <span class="nx">json</span><span class="p">.</span><span class="nx">date</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="dl">'</span><span class="s1">.</span><span class="dl">'</span><span class="p">);</span>
        <span class="nx">client</span><span class="p">.</span><span class="nx">query</span><span class="p">(</span><span class="dl">"</span><span class="s2">INSERT into series(orgName,  cat1, cat2, cat3, cat4,cat5,dt, val, attr1)</span><span class="dl">"</span> <span class="o">+</span> 
                                <span class="dl">"</span><span class="s2"> values($1::text, $2,   $3,   $4,   $5,  $6,  $7, $8,   $9)</span><span class="dl">"</span><span class="p">,</span>
            <span class="p">[</span><span class="nx">company</span><span class="p">,</span> <span class="nx">json</span><span class="p">.</span><span class="nx">shop_id</span><span class="p">,</span> <span class="nx">json</span><span class="p">.</span><span class="nx">item_id</span><span class="p">,</span><span class="dl">''</span><span class="p">,</span><span class="dl">''</span><span class="p">,</span><span class="dl">''</span><span class="p">,</span> <span class="nx">dt</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">-</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">dt</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">-</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">dt</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">json</span><span class="p">.</span><span class="nx">item_cnt_day</span><span class="p">,</span> <span class="nx">json</span><span class="p">.</span><span class="nx">item_price</span><span class="p">]).</span><span class="nx">then</span><span class="p">((</span><span class="nx">result</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
                <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">-------------------</span><span class="dl">"</span><span class="p">);</span>

            <span class="p">}).</span><span class="k">catch</span><span class="p">(</span><span class="nx">e</span> <span class="o">=&gt;</span> <span class="p">{</span>
                <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">stack</span><span class="p">);</span>
            <span class="p">})</span>
    <span class="p">},</span> <span class="nx">onError</span><span class="p">,</span> <span class="nx">onComplete</span><span class="p">)</span>

<span class="kd">function</span> <span class="nx">onError</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">}</span>
<span class="kd">function</span> <span class="nx">onComplete</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">}</span>
</code></pre></div></div>

<p>Though its a little long the script is fairly simple.  It takes a csv file and inserts the data into a postgresql db.  Unfortunately it didnt work.  I would get the following error which is a fancy way of running out of memory on the stack for node.js</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
</code></pre></div></div>
<p>In other words the reading and processing of the csv file quickly ran much faster than the insertion of data into the db and soon the queue of records overwhelmend the memory for node.js</p>

<p>So how can we handle this.  How can we slow down the import of the data while the writing of the db runs ahead. The solution was to use streams.
Streams are streams of data that are divided into chunks.  There are 4 types of streams.  ReaderStream, WriterStream, TransformStream and DuplexStream.  A reader stream takes reads data from the source.  A writer stream takes input and processes the data. The writer stream normally has the ability to tell the reader stream to pause while it catches up.  A TransformStream is a combination of reader/writer streams where it takes input, modifies the data and then sends output. And then there are Duplex streams where the data is bidirectional.</p>

<p>So the final decision was to use an readerStream and a writerStream. The readerstream was easy enough. csv-stream allowed the creation of a reader stream but as far as I could tell there was no good writerStream for the database. Creating streams are not well documented and seems overly complex.  However there is a node package called <a href="https://github.com/rvagg/through2">thought2</a>  that simplifies the creation of a writeStream to a simple function.  You pass thought2() a function that has the signature of func(chunk, enc, callback)  Of these parameters the more important ones are chunk which contain the data being streamed and callback, a function that is called after the data in chunk is processed.  So our write stream would look like this.</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">dbStream</span> <span class="o">=</span> <span class="nx">through2</span><span class="p">.</span><span class="nx">obj</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">data</span><span class="p">,</span> <span class="nx">enc</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">var</span> <span class="nx">dt</span> <span class="o">=</span> <span class="nx">data</span><span class="p">.</span><span class="nx">date</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="dl">'</span><span class="s1">.</span><span class="dl">'</span><span class="p">);</span>
        <span class="kd">var</span> <span class="nx">formatted_dt</span> <span class="o">=</span> <span class="nx">dt</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">-</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">dt</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">-</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">dt</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
        <span class="nx">client</span><span class="p">.</span><span class="nx">query</span><span class="p">(</span><span class="dl">"</span><span class="s2">INSERT into series(orgName,  cat1, cat2,dt, val)</span><span class="dl">"</span> <span class="o">+</span>
                <span class="dl">"</span><span class="s2"> values($1::text, $2,   $3,   $4,   $5)</span><span class="dl">"</span><span class="p">,</span>
                <span class="p">[</span><span class="nx">company</span><span class="p">,</span> <span class="nx">data</span><span class="p">.</span><span class="nx">store</span><span class="p">,</span> <span class="nx">data</span><span class="p">.</span><span class="nx">item</span><span class="p">,</span><span class="nx">data</span><span class="p">.</span><span class="nx">date</span><span class="p">,</span> <span class="nx">data</span><span class="p">.</span><span class="nx">sales</span><span class="p">]).</span>
                <span class="nx">then</span><span class="p">((</span><span class="nx">result</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
                        <span class="nx">callback</span><span class="p">();</span>

                <span class="p">}).</span><span class="k">catch</span><span class="p">(</span><span class="nx">e</span> <span class="o">=&gt;</span> <span class="p">{</span>
                        <span class="nx">callback</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span>
                <span class="p">});</span>
<span class="p">})</span>
</code></pre></div></div>
<p>Here the function passed to through2 takes each row of data and Inserts the record into the db.  When insert is complete, the callback function is executed.</p>

<p>The Final script looks like the following:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">company</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">ACME</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">csvFilePath</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">acme.csv</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">Client</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">pg</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">fs</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">fs</span><span class="dl">'</span><span class="p">)</span>
<span class="kd">const</span> <span class="nx">util</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">util</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">stream</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">stream</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">Writable</span> <span class="o">=</span> <span class="nx">stream</span><span class="p">.</span><span class="nx">Writable</span> <span class="o">||</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">readable-stream</span><span class="dl">'</span><span class="p">).</span><span class="nx">Writable</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">through2</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">through2</span><span class="dl">'</span><span class="p">);</span>


<span class="nx">dbStream</span> <span class="o">=</span> <span class="nx">through2</span><span class="p">.</span><span class="nx">obj</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">data</span><span class="p">,</span> <span class="nx">enc</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">var</span> <span class="nx">dt</span> <span class="o">=</span> <span class="nx">data</span><span class="p">.</span><span class="nx">date</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="dl">'</span><span class="s1">.</span><span class="dl">'</span><span class="p">);</span>
        <span class="kd">var</span> <span class="nx">formatted_dt</span> <span class="o">=</span> <span class="nx">dt</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">-</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">dt</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">-</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">dt</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
        <span class="nx">client</span><span class="p">.</span><span class="nx">query</span><span class="p">(</span><span class="dl">"</span><span class="s2">INSERT into series(orgName,  cat1, cat2,dt, val)</span><span class="dl">"</span> <span class="o">+</span>
                <span class="dl">"</span><span class="s2"> values($1::text, $2,   $3,   $4,   $5)</span><span class="dl">"</span><span class="p">,</span>
                <span class="p">[</span><span class="nx">company</span><span class="p">,</span> <span class="nx">data</span><span class="p">.</span><span class="nx">store</span><span class="p">,</span> <span class="nx">data</span><span class="p">.</span><span class="nx">item</span><span class="p">,</span><span class="nx">data</span><span class="p">.</span><span class="nx">date</span><span class="p">,</span> <span class="nx">data</span><span class="p">.</span><span class="nx">sales</span><span class="p">]).</span>
                <span class="nx">then</span><span class="p">((</span><span class="nx">result</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
                        <span class="nx">callback</span><span class="p">();</span>

                <span class="p">}).</span><span class="k">catch</span><span class="p">(</span><span class="nx">e</span> <span class="o">=&gt;</span> <span class="p">{</span>
                        <span class="nx">callback</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span>
                <span class="p">});</span>
<span class="p">})</span>

<span class="kd">const</span> <span class="nx">csv</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">"</span><span class="s2">csvtojson</span><span class="dl">"</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Client</span><span class="p">({</span>
    <span class="na">host</span><span class="p">:</span> <span class="dl">'</span><span class="s1">localhost</span><span class="dl">'</span><span class="p">,</span>
    <span class="na">port</span><span class="p">:</span> <span class="mi">5432</span><span class="p">,</span>
    <span class="na">user</span><span class="p">:</span> <span class="dl">'</span><span class="s1">me</span><span class="dl">'</span><span class="p">,</span>
    <span class="na">password</span><span class="p">:</span> <span class="dl">'</span><span class="s1">secretpassword</span><span class="dl">'</span><span class="p">,</span>
    <span class="na">database</span><span class="p">:</span> <span class="dl">'</span><span class="s1">cooldb</span><span class="dl">'</span>
<span class="p">})</span>
<span class="nx">client</span><span class="p">.</span><span class="nx">connect</span><span class="p">();</span>


<span class="kd">var</span> <span class="nx">csvStream</span> <span class="o">=</span> <span class="nx">csv</span><span class="p">.</span><span class="nx">createStream</span><span class="p">({});</span>
<span class="nx">fs</span><span class="p">.</span><span class="nx">createReadStream</span><span class="p">(</span><span class="nx">csvFilePath</span><span class="p">).</span><span class="nx">pipe</span><span class="p">(</span><span class="nx">csvStream</span><span class="p">).</span><span class="nx">pipe</span><span class="p">(</span><span class="nx">dbStream</span><span class="p">)</span>
</code></pre></div></div>]]></content><author><name></name></author><category term="programming" /><category term="mysql" /><category term="mysql" /><summary type="html"><![CDATA[Frustration Node’s greatest strength is often the source of frustration for a node programmer. Most recently I was attempting to write a simple node.js script that took a csv file, parsed it and inserted it into a postgresql db. This is simple in ruby, python and many other scripting related languages but I soon hit a roadblock on node.js. The following script was my first attempt at importing the data.]]></summary></entry><entry><title type="html">Scheduled Events in Mysql</title><link href="http://www.atlantageek.com/scheduled-events-in-mysql/" rel="alternate" type="text/html" title="Scheduled Events in Mysql" /><published>2018-02-28T00:00:00+00:00</published><updated>2018-02-28T00:00:00+00:00</updated><id>http://www.atlantageek.com/scheduled-events-in-mysql</id><content type="html" xml:base="http://www.atlantageek.com/scheduled-events-in-mysql/"><![CDATA[<h2 id="justification">Justification</h2>
<p>There are many options for scheduling events.  Cron in Linux, scheduler in windows, every queueing systems has a built in schedule and then there are homegrown while loops. So why should you consider Mysql event.</p>
<ul>
  <li>Mysql is often already in your application</li>
  <li>Its OS agnostic. It works the same whether its linux or windows</li>
  <li>If the scheduled tasks is a db maintenance event it makes sense to store it on the db.</li>
</ul>

<p>In my paticular case a requirement to create a scheduled task that exports a db table to csv on a windows environment. After fumbling with mysql access on a dos shell (Im mostly a unix/bash guy) I looked for alternatives and came across mysql events.</p>

<h2 id="example-tasks">Example tasks</h2>
<p>Assume we have a table named workjobs that needs to be exported to a csv file every hour how would we do this.</p>

<p>First lets create the look at how to generate an outfile on in mysql</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">select</span> <span class="o">*</span> <span class="k">from</span> <span class="n">workjobs</span>
<span class="k">into</span> <span class="n">outfile</span> <span class="s1">'workjobs.csv'</span>
 <span class="n">fields</span> <span class="n">terminated</span> <span class="k">by</span> <span class="s1">','</span>
 <span class="n">enclosed</span> <span class="k">by</span> <span class="s1">'</span><span class="se">\"</span><span class="s1">'</span>
 <span class="n">lines</span> <span class="n">terminated</span> <span class="k">by</span> <span class="s1">'</span><span class="se">\n</span><span class="s1">'</span>
</code></pre></div></div>

<p>This command creates a csv file called workjobs.csv on the server.  On our windows server it drops the file in the data directory of the server.
Its unfortunate that this puts the file in the data directory but there are ways around this.  If we add a path to the file name it will put the file in a subdirectory in the data directory.</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">select</span> <span class="o">*</span> <span class="k">from</span> <span class="n">workjobs</span>
<span class="k">into</span> <span class="n">outfile</span> <span class="s1">'exported_files/workjobs.csv'</span>
 <span class="n">fields</span> <span class="n">terminated</span> <span class="k">by</span> <span class="s1">','</span>
 <span class="n">enclosed</span> <span class="k">by</span> <span class="s1">'</span><span class="se">\"</span><span class="s1">'</span>
 <span class="n">lines</span> <span class="n">terminated</span> <span class="k">by</span> <span class="s1">'</span><span class="se">\n</span><span class="s1">'</span>
</code></pre></div></div>
<p>Now we could share the exported_files folder with another machine or create the equivalent of a symbolic link to the folder to another location that is accessible to the user or webserver.</p>

<p>The task is still not scheduled though.  How do we handle that.</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">delimiter</span> <span class="err">$$</span>
<span class="k">create</span> <span class="n">event</span> <span class="n">job_dump</span> <span class="k">on</span> <span class="n">schedule</span> <span class="k">every</span> <span class="mi">1</span> <span class="n">hour</span> <span class="k">do</span>
  <span class="k">begin</span>
    <span class="k">select</span> <span class="o">*</span> <span class="k">from</span> <span class="n">workjobs</span>
      <span class="k">into</span> <span class="n">outfile</span> <span class="s1">'exported_files/workjobs.csv'</span>
        <span class="n">fields</span> <span class="n">terminated</span> <span class="k">by</span> <span class="s1">','</span>
        <span class="n">enclosed</span> <span class="k">by</span> <span class="s1">'</span><span class="se">\"</span><span class="s1">'</span>
        <span class="n">lines</span> <span class="n">terminated</span> <span class="k">by</span> <span class="s1">'</span><span class="se">\n</span><span class="s1">'</span><span class="p">;</span>

  <span class="k">end</span><span class="err">$$</span>
<span class="k">delimiter</span> <span class="o">|</span>
</code></pre></div></div>
<p>Here we created an event to run every hour. I put the sql in an unnecessary transaction. This is so the reader will have a starting point for more complex tasks.</p>

<p>For this task to be completed we needed a way to keep the workjobs.csv file from overwriting itself.  Normally this is done by adding a date/time stamp to the file name.  We do this by dynamically creating the sql statement and using the date_fomat command to create a file name.</p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">create</span> <span class="n">event</span> <span class="n">job_dump</span> <span class="k">on</span> <span class="n">schedule</span> <span class="k">every</span> <span class="mi">1</span> <span class="k">minute</span> <span class="k">do</span>
  <span class="k">begin</span>
    <span class="k">select</span> <span class="o">@</span><span class="n">myCommand</span> <span class="p">:</span><span class="o">=</span> <span class="n">concat</span><span class="p">(</span>
        <span class="nv">"select * from workjobs into outfile'"</span><span class="p">,</span> <span class="n">DATE_FORMAT</span><span class="p">(</span><span class="n">now</span><span class="p">(),</span><span class="nv">""</span><span class="s1">'exported_files/workjobs-%y%m%d-%H%i%s'</span><span class="p">),</span>
        <span class="nv">"'fields terminated by ',' enclosed by '</span><span class="se">\"</span><span class="nv">"</span><span class="s1">' lines terminated by '</span><span class="err">\</span><span class="n">n</span><span class="s1">'"
      );    
    prepare stmt from @MyCommand;
    execute stmt;
  end
</span></code></pre></div></div>

<p>Here we build the sql statement in @myCommand.  MySQL requires the filenames for ‘into outfile’ to be static so our work around is to dynamically create the sql command and then execute it.</p>]]></content><author><name></name></author><category term="programming" /><category term="mysql" /><category term="mysql" /><summary type="html"><![CDATA[Justification There are many options for scheduling events. Cron in Linux, scheduler in windows, every queueing systems has a built in schedule and then there are homegrown while loops. So why should you consider Mysql event. Mysql is often already in your application Its OS agnostic. It works the same whether its linux or windows If the scheduled tasks is a db maintenance event it makes sense to store it on the db.]]></summary></entry><entry><title type="html">nodejs-as-a-windows-service</title><link href="http://www.atlantageek.com/nodejs-as-a-windows-service/" rel="alternate" type="text/html" title="nodejs-as-a-windows-service" /><published>2014-03-28T00:00:00+00:00</published><updated>2014-03-28T00:00:00+00:00</updated><id>http://www.atlantageek.com/nodejs-as-a-windows-service</id><content type="html" xml:base="http://www.atlantageek.com/nodejs-as-a-windows-service/"><![CDATA[<p>To install node.js as a windows service you need three items.</p>
<ul>
  <li>NSSM http://nssm.cc/download</li>
  <li>node.js for windows . http://nodejs.org/download</li>
  <li>Your node.js application.</li>
</ul>

<p>Unzip your node.js code in a directory.  Let’s say its c:\helloworld\hi.js
Install both nssm and node.js for windows.  Let’s assume that node.js is in c:\Users\atlantageek\node.exe</p>

<p>Run ‘nssm install’ from the directory you installed nssm. A window will pop up.  On my version it looks similar to the following. 
*The path will be the path to node.js</p>
<ul>
  <li>Startup directory will be the path where the js code and modules are located.</li>
  <li>The options will be the actual js appliction file. For my example it will look like the following.</li>
</ul>

<p><img src="/img/posts/nssm.png" alt="nssm service installer" /></p>

<p>This is the very basic that you need.  You can also define Standard In and Standard Out redirection in the I/O tab.</p>

<p>Once the service is created. You can start and stop it from services manager thats built into windows.</p>]]></content><author><name></name></author><category term="programming" /><category term="windows" /><category term="node.js" /><summary type="html"><![CDATA[To install node.js as a windows service you need three items. NSSM http://nssm.cc/download node.js for windows . http://nodejs.org/download Your node.js application.]]></summary></entry><entry><title type="html">Cheatsheet for Flot</title><link href="http://www.atlantageek.com/cheatsheet-for-flot/" rel="alternate" type="text/html" title="Cheatsheet for Flot" /><published>2014-01-11T00:00:00+00:00</published><updated>2014-01-11T00:00:00+00:00</updated><id>http://www.atlantageek.com/cheatsheet-for-flot</id><content type="html" xml:base="http://www.atlantageek.com/cheatsheet-for-flot/"><![CDATA[<p>$.plot() is the main function</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>var plot = $.plot(placeholder,data,options)
</code></pre></div></div>

<p>Two ways to specifiy div tag</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>var plot = $.plot("#placeholder",data,options)
</code></pre></div></div>

<p>or</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>var plot = $("#placeholder").plot(data,options)
</code></pre></div></div>

<p>Data Format
How to format the data.
data = rawdata or multiple_rawdata or object or multiple objects
The most basic format is an array of arrays.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>var rawdata = [ [x1,y1], [x2,y2], [x3,y3], [x4,y4] ];
var rawdata = [ [0,10], [1,11], [2,12], [3,13] ];
</code></pre></div></div>

<p>Multiple Series are used if you want more than one line on your graph</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>multiple_rawdata = [rawdata,rawdata,rawdata];
</code></pre></div></div>

<p>The object looks like this:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>var object = {
		color: color or number
		data: rawdata
		label: string
		lines: specific lines options
		bars: specific bars options
		points: specific points options
		xaxis: number
		yaxis: number
		clickable: boolean
		hoverable: boolean
		shadowSize: number
		highlightColor: color or number
}
</code></pre></div></div>

<p>And multiple objects look like this:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>var object = [object1,object2,object3]
</code></pre></div></div>

<p>99% of the time you are just using the objects to link to a label</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[ { label: "Foo", data: [ [10, 1], [17, -14], [30, 5] ] },
  	{ label: "Bar", data: [ [11, 13], [19, 11], [30, -7] ] }
]
</code></pre></div></div>

<p>Options</p>

<p>Example of options</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>var options = {
	series: {
    	lines, points, bars: {
    	show: boolean
    	lineWidth: number
    	fill: boolean or number
    	fillColor: null or color/gradient
   	}
   	lines, bars: {
        	zero: boolean
    	}
    	points: {
        	radius: number
        	symbol: "circle" or function
    	}
    	bars: {
        	barWidth: number
        	align: "left", "right" or "center"
        	horizontal: boolean
    	}
    	lines: {
        	steps: boolean
    	}
    	shadowSize: number
    	highlightColor: color or number
   	}// Series Option
  	colors: [ color1, color2, ... ]
  	legend: {
  		show: boolean
  		labelFormatter: null or (fn: string, series object -&gt; string)
  		labelBoxBorderColor: color
  		noColumns: number
  		position: "ne" or "nw" or "se" or "sw"
  		margin: number of pixels or [x margin, y margin]
  		backgroundColor: null or color
  		backgroundOpacity: number between 0 and 1
  		container: null or jQuery object/DOM element/jQuery expression
  		sorted: null/false, true, "ascending", "descending", "reverse", or a comparator
 		},
 xaxis, yaxis: {
      show: null or true/false
      position: "bottom" or "top" or "left" or "right"
      mode: null or "time" ("time" requires jquery.flot.time.js plugin)
      timezone: null, "browser" or timezone (only makes sense for mode: "time")

      color: null or color spec
      tickColor: null or color spec
      font: null or font spec object

      min: null or number
      max: null or number
      autoscaleMargin: null or number

      transform: null or fn: number -&gt; number
      inverseTransform: null or fn: number -&gt; number

      ticks: null or number or ticks array or (fn: axis -&gt; ticks array)
      tickSize: number or array
      minTickSize: number or array
      tickFormatter: (fn: number, object -&gt; string) or string
      tickDecimals: null or number

      labelWidth: null or number
      labelHeight: null or number
      reserveSpace: null or true
      tickLength: null or number
      alignTicksWithAxis: null or number
   }
    grid: {
        show: boolean
        aboveData: boolean
        color: color
        backgroundColor: color/gradient or null
        margin: number or margin object
        labelMargin: number
        axisMargin: number
        markings: array of markings or (fn: axes -&gt; array of markings)
        borderWidth: number or object with "top", "right", "bottom" and "left" properties with different widths
        borderColor: color or null or object with "top", "right", "bottom" and "left" properties with different colors
        minBorderMargin: number or null
        clickable: boolean
        hoverable: boolean
        autoHighlight: boolean
        mouseActiveRadius: number
    }
    interaction: {
        redrawOverlayInterval: number or -1
    }
    margin: {
       top: top margin in pixels
        left: left margin in pixels
        bottom: bottom margin in pixels
        right: right margin in pixels
    }
    markings: [ { xaxis: { from: 0, to: 2 }, yaxis: { from: 10, to: 10 }, color: "#bb0000" }, ... ]
    hooks: {
        processOptions: function(plot, options)
        processRawData: function(plot, series, data, datapoints)
        processOffset: function(plot, offset)
        drawBackground: function(plot, canvasContext)
        drawSeries: function(plot, canvascontext, series)
        draw: function(plot, canvascontext)
        bindEvents: function(plot, eventHolder)
    	drawOverlay: function(plot, canvascontext)
    	shutdown function(plot, eventHolder)
	};
};
</code></pre></div></div>

<p>Methods</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>plot.hightlight(series, datapoint_index)
plot.unhighlight(series, datapoint_index)
plot.setData(data) - call draw after to update graph
plot.setupGrid() 
plot.draw() - redraw the plot canvas
triggerRedrawOverlay() - force redrawing of overlays
width()/height()
offset() - offset is used in calculating mouse position in graphs
pointOffset({x,y})- dataSpace -&gt; div x,y
resize() -&gt; force canvas to fit size of div
shutdown() -&gt; internal function to disable all event handlers
</code></pre></div></div>

<p>debugging functions</p>

<ul>
  <li>getData()</li>
  <li>getAxes()</li>
  <li>getPlaceholder()</li>
  <li>getCanvas()</li>
  <li>getPlotOffset()</li>
  <li>getOptions()</li>
</ul>]]></content><author><name></name></author><category term="programming" /><category term="appliance" /><summary type="html"><![CDATA[$.plot() is the main function var plot = $.plot(placeholder,data,options)]]></summary></entry><entry><title type="html">Casing Up the Raspberry Pi, Part I</title><link href="http://www.atlantageek.com/building-a-case-for-raspberrypi/" rel="alternate" type="text/html" title="Casing Up the Raspberry Pi, Part I" /><published>2014-01-08T00:00:00+00:00</published><updated>2014-01-08T00:00:00+00:00</updated><id>http://www.atlantageek.com/building-a-case-for-raspberrypi</id><content type="html" xml:base="http://www.atlantageek.com/building-a-case-for-raspberrypi/"><![CDATA[<h1 id="the-problem">The Problem</h1>
<p>Raspberry Pi is a great little computer but easily the biggest weakness of the board is its power and/or usb ports. Imagine getting your new raspbery pi, unboxing it, plugging it in with the usb charge you stole from your kid’s kindle, plugin your hdmi, keyboard and mouse and ….. nothing. Turns out a keyboard and a mouse can overwhelm your PI, and forget about that wifi adapter or the usb stick with all your rap mp3s. Youre just out of luck.</p>

<p>Eventually you will purchase a powered usb hub so your $35 computer is now $50 + stolen power supply.  Eventually your setup may look something like this.</p>

<p><img src="/img/posts/Raspberry-Pi-Nest.jpg" alt="Raspberry Pi Nest" /></p>

<p>Lovely isn’t it??!</p>

<p>This gets annoying quickly. After searching for a case that had an embedded usb hub I was disappointed to come up with nothing. There are 30 or more different commercially available cases and not a single one has a built in hub.  Theres a <a href="http://www.adafruit.com/blog/2012/10/19/raspberry-pi-case-with-an-integrated-usb-hub-piday-raspberrypi-raspberry_pi/">home built project</a> that looks cool. Or a year old <a href="http://www.raspberrypi.org/phpBB3/viewtopic.php?t=29667">empty promise</a>. So I decided to build my own case with the plan being that its as simple and easily reproducable as possible.</p>

<p>So I’ve been trying to think of an easy way to build this case. The issue with the raspberry pi is that unlike PC motherboards all ther ports are distributed around the board.</p>

<p><img src="/img/posts/RaspiModelB.png" alt="Raspberry Pi Nest" /></p>

<p>So the cases are built skin tight around the board.</p>

<p><img src="/img/posts/tightcase.jpg" alt="Raspberry Pi Nest" /></p>

<p>I wanted to do something different.  Not only did I want a usb hub but I was also inspired by RaspyFi, an excellent project, and wanted to embed the pi in a speaker. So at work’s white elephant party I was able to snag this speaker</p>

<p><img src="/img/posts/speaker.jpg" alt="Speaker" /></p>

<p>So Im not a wood worker. I don’t have the patience for the detailed work it requires, I never had the coordination for it, I dont want to fill up my garage with thousands of dollars of tools and last of all I like having all my fingers.  However I do have a few basic things like a drill and bits.</p>

<p>Looking at this project what I decided I want to do is to pull the ports off the raspberry pi and usb hub and put them on the back of the speaker.  So this would require some cabling which isnt a problem.  The other issue is I cant cut a square hole to save my life. After thinking about it the solution was obvious.</p>

<p>CE Tech and Leviton both do these media wall ports for in wall cabling</p>

<p><img src="/img/posts/hdmi.jpg" alt="hdmi port" /></p>

<p>They also sell these wall plates.</p>

<p><img src="/img/posts/plate.jpg" alt="wall plate" /></p>

<p>So you can see where Im going with this.</p>

<p><img src="/img/posts/sofar.jpg" alt="So far so good" /></p>

<p>Home Depot did not have the usb ports.  I’ve ordered a couple and when I get those I’ll finish the case and post a cost breakdown.</p>]]></content><author><name></name></author><category term="programming" /><category term="appliance" /><summary type="html"><![CDATA[The Problem Raspberry Pi is a great little computer but easily the biggest weakness of the board is its power and/or usb ports. Imagine getting your new raspbery pi, unboxing it, plugging it in with the usb charge you stole from your kid’s kindle, plugin your hdmi, keyboard and mouse and ….. nothing. Turns out a keyboard and a mouse can overwhelm your PI, and forget about that wifi adapter or the usb stick with all your rap mp3s. Youre just out of luck.]]></summary></entry><entry><title type="html">Setup Script Login</title><link href="http://www.atlantageek.com/setup-script-login/" rel="alternate" type="text/html" title="Setup Script Login" /><published>2014-01-01T00:00:00+00:00</published><updated>2014-01-01T00:00:00+00:00</updated><id>http://www.atlantageek.com/setup-script-login</id><content type="html" xml:base="http://www.atlantageek.com/setup-script-login/"><![CDATA[<p>A recent trend is to build small headless computer systems based on linux. This has come from the ability to run linux on very small computers (in size and power) for very utilitarian tasks (routers, NAS, data collection nodes). However these use cases make it inconvient to connect a keyboard, mouse and monitor to the linux machine. Often its because the device may not have a video out. Or the device’s use case  does not require a monitor/keyboard to be connected in its normal operations. So when maintenance and/or administrative processes are necessary you need to provide some sort of interface/UI. You can invest hours into developing a cool Web UI that a administrator uses once every 6 months but sometimes a menu driven terminal app could do the job.</p>

<p>So what are the reasons a terminal app would be preferred over a Web UI</p>
<ul>
  <li>You have administrative duties that need to be kept away from general users.</li>
  <li>You dont want anyone accidently accessing the screen during the appliance’s normal use.</li>
  <li>You have tasks that need to be completed before device is no the network (using keyboard/monitor )</li>
  <li>The tasks that are triggered may require a bit of time to complete (doing a backup.)</li>
  <li>You want something easily extendable.</li>
  <li>Your support team is getting tired of describing where the menu/dropdown/button is on the webpage</li>
  <li>Sometimes a simple question/answer text interface is best so the administrator can be lead through the configuration.</li>
</ul>

<p>This article will describe how to setup a menu driven idiot proof terminal app.</p>

<p>The first thing you need is a setup script. Download this <a href="/references/setup-wrapper.sh">script</a> as an example. When run from the command line the initial screen looks like this.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Thu Jan 2 00:35:02 EST 2014

Welcome to your Admin console, please select an action.
Please select action:
</code></pre></div></div>

 	1) Run Setup App
 	2) Update Application
 	3) Restart Server
 	4) Configure Server Time
 	5) Backup System
 	80) Change Password
 	90) exit
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ENTER YOUR SELECTION:
</code></pre></div></div>

<p>This is fine but you want this to be easy. You dont want the user having to go to a command line, find the script location and then run it.  A solution to this is for the script to be started as soon as the user logs into the system from the command line.  So first lets create a setup user and configure this script as his login shell.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cp setup-shell.sh /usr/local/bin #Copy shell script to /usr/local/bin
useradd setup -m -s /usr/local/bin/setup-shell.sh #create the setup user
    passwd setup   #Configure the password for the setup user.
</code></pre></div></div>

<p>Now when you login as the setup user you will be given a menu.  When you exit out of the script you will be thrown back to the login screen.</p>

<p>The last thing to do is give the setup user some privileges so that it can ‘restart a server’ or ‘configure the server time’. If you refer back to the script you’ll see that each command that needs root access is pre-pended with a ‘sudo’ command. We can list these commands in the sudoers file so that the setup user can only run the necessary commands.</p>

<p>Here is the sudoers file I’ve created to go with this setup_shell.sh script.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Cmnd_Aliases SETUPCMDS = /usr/bin/setup, /sbin/ifdown, /sbin/ifup, /usr/bin/yum, /sbin/service,/sbin/chkconfig, /bin/date
setup   ALL=NOPASSWORD SETUPCMDS
</code></pre></div></div>

<p>SETUPCMDS is a list of all the commands setup needs acces to.
the next line says that tue user setup can connect from any server (through telnet/ssh/putty) or the console and run any of the SETUPCMDS commands without typing in the password.</p>]]></content><author><name></name></author><category term="programming" /><category term="appliance" /><summary type="html"><![CDATA[A recent trend is to build small headless computer systems based on linux. This has come from the ability to run linux on very small computers (in size and power) for very utilitarian tasks (routers, NAS, data collection nodes). However these use cases make it inconvient to connect a keyboard, mouse and monitor to the linux machine. Often its because the device may not have a video out. Or the device’s use case does not require a monitor/keyboard to be connected in its normal operations. So when maintenance and/or administrative processes are necessary you need to provide some sort of interface/UI. You can invest hours into developing a cool Web UI that a administrator uses once every 6 months but sometimes a menu driven terminal app could do the job.]]></summary></entry><entry><title type="html">Useful Queries to admin postgres</title><link href="http://www.atlantageek.com/useful-queries-to-admin-postgres/" rel="alternate" type="text/html" title="Useful Queries to admin postgres" /><published>2013-12-31T00:00:00+00:00</published><updated>2013-12-31T00:00:00+00:00</updated><id>http://www.atlantageek.com/useful-queries-to-admin-postgres</id><content type="html" xml:base="http://www.atlantageek.com/useful-queries-to-admin-postgres/"><![CDATA[<p>Here are some of my favorite postgres queries to help administrate postgres.</p>

<h2 id="identify-slowest-running-queries">Identify slowest running queries.</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SELECT
  		pid,
 		current_timestamp - xact_start as xact_runtime,
 		query
FROM pg_stat_activity
ORDER BY xact_start;
</code></pre></div></div>

<h2 id="identify-existing-locks-in-postgres-good-for-finding-deadlocks">Identify existing locks in postgres, good for finding deadlocks.</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SELECT pg_class.relname,pg_locks.* 
FROM pg_class,pg_locks 
WHERE pg_class.relfilenode=pg_locks.relation;
</code></pre></div></div>

<h2 id="see-foreign-key-constraints">See foreign key constraints.</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SELECT c.constraint_name
		, x.table_schema as schema_name
		, x.table_name
		, x.column_name
		, y.table_schema as foreign_schema_name
		, y.table_name as foreign_table_name
		, y.column_name as foreign_column_name
FROM information_schema.referential_constraints c
	join information_schema.key_column_usage x
		on x.constraint_name = c.constraint_name
	join information_schema.key_column_usage y
		on y.ordinal_position = x.position_in_unique_constraint
		and y.constraint_name = c.unique_constraint_name
	order by c.constraint_name, x.ordinal_position;
</code></pre></div></div>

<h2 id="show-active-connections">Show active connections</h2>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SELECT count(*) 
FROM pg_stat_activity;
</code></pre></div></div>]]></content><author><name></name></author><category term="programming" /><category term="postgres" /><category term="postgresql" /><category term="databases" /><summary type="html"><![CDATA[Here are some of my favorite postgres queries to help administrate postgres.]]></summary></entry><entry><title type="html">Sharding a MultiTenant SaaS app</title><link href="http://www.atlantageek.com/sharding-a-multitenant-saas/" rel="alternate" type="text/html" title="Sharding a MultiTenant SaaS app" /><published>2013-12-30T00:00:00+00:00</published><updated>2013-12-30T00:00:00+00:00</updated><id>http://www.atlantageek.com/sharding-a-multitenant-saas</id><content type="html" xml:base="http://www.atlantageek.com/sharding-a-multitenant-saas/"><![CDATA[<p>You’ve finally got some traction with your SaaS project.  Lots of large customers and things are moving along rather well. A few of your customers complain that the system is not as fast as it use to be but that’s normal. You up the hardware, add a few indexes and things seem steady. 
All of a sudden your email/support staff is overwhelmed by customers complaining about 404 errors. You look and see that your web sessions are timing out and queries are starting to drag. Postgres Autovacuum is starting at the worse possible times and you are spending a lot of time babysitting your app instead of counting your money. You thought you had more time but now its obvious, its time to shard the database.</p>

<p>There are a few ways to shard the database. Some apps are sharded by time and others are sharded by grouping users. A multi-tenant app lends itself to being sharded by tenant. The idea being that each individual tenant would not want to share data with other tenant. (Notice I said tenant and not users. I assume that users who collaborate would be part of the same tenant.</p>

<p>There are also multiple solutions to how data is sharded. There are three approaches.</p>

<ul>
  <li>webserver</li>
  <li>app</li>
  <li>database partitioning</li>
</ul>

<p>Either solution requires several databases/tables for each shard.</p>

<p>Webserver would be assigning a tenant to a specific database/web server combination. This can work but its somewhat ugly. Basically when the user logs ont the app their server needs to be identified and all their work will be done on this server. nginx sticky-module comes in handy for this solution.</p>

<p>App level is a bit more messy. It requires the most code changes. When the customer logs in the database their db shard is determined and then all datarequests for this user goes through the tenant’s shard.</p>

<p>Database partitioning approach is probably the best approach. The goal here is to split up the data across multiple tables but with minimal code changes. This is done by a combination of partitioning and postgres db triggers.</p>

<p>The focus will be on the Database partitioning approach.</p>

<p>Unlike other approaches to sharding, the database partitioning approach does not shard the whole database. Instead you identify certain tables that are the culprit in the drop of the performance and then use partitioning on that table. Partitioning is only beneficial for large tables. If the table is larger than the memory of your database machine then its a canidate for partitioning.</p>

<p>To demonstrate a technique assume that we are working on an accounting application. The largest table is the transaction table. The job_transaction table looks like this</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CREATE SEQUENCE id_seq;
CREATE TABLE job_transactions (id int NOT NULL DEFAULT nextval('id_seq'), name varchar, description text, tenant_id integer);
ALTER TABLE job_transactions_seq owned by job_transactions.id;
</code></pre></div></div>

<p>The job_transactions tabe probably already exists.  rename the old table to something else and create a new empty table with the old name.  We will transfer the data later.</p>

<p>The data needs to be split accross multiple database tables so its time to create those.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CREATE TABLE job_Transactions0(CHECK ( (tenant_id % 0) = 0)) INHERITS (job_transactions);
CREATE TABLE job_Transactions1(CHECK ( (tenant_id % 1) = 0)) INHERITS (job_transactions);
CREATE TABLE job_Transactions2(CHECK ( (tenant_id % 2) = 0)) INHERITS (job_transactions);
</code></pre></div></div>

<p>So the data is split between these three tables. This uses the mod function to determine which partition. To truly leverage this functionality you might want to add tenant_id to all the indexes and all queries should have tenant_id as part of the query.</p>

<p>Now we need to create triggers so that any inserts into the job_transactiosn table will be put in the appropriate partition.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> CREATE OR REPLACE FUNCTION trace_insert()
 RETURNS TRIGGER AS $$
 BEGIN
   IF ((NEW.id % 3) = 0 ) THEN
      INSERT INTO job_transactions0 VALUES (NEW.*);
   ELSEIF ((NEW.id % 3) = 1 ) THEN
   IF INSERT INTO job_transactions1 VALUES (NEW.*);
   ELSEIF ((NEW.id % 3) = 2 ) THEN
      INSERT INTO job_transactions2 VALUES (NEW.*);
   ELSE
      RAISE EXCEPTION 'device_id out of range.  Fix the trace_insert_trigger() function!';
   END IF;
   RETURN NULL;
 END;
 $$
 LANGUAGE plpgsql;

 CREATE TRIGGER trace_insert_trigger
   BEFORE INSERT ON trace_refs
   FOR EACH ROW EXECUTE PROCEDURE trace_insert();
</code></pre></div></div>

<p>Now any inserts into the job_transactions table will be deployed the the child partitions.  And querying for data in the original table will cause the code to be requested to the individual transactions.</p>

<p>One note, the queries that have the  tenant_id will be fast. Those without must query multiple database tables and kill the whole performance improvements will be killed.</p>]]></content><author><name></name></author><category term="programming" /><category term="postgres" /><category term="postgresql" /><category term="databases" /><summary type="html"><![CDATA[You’ve finally got some traction with your SaaS project. Lots of large customers and things are moving along rather well. A few of your customers complain that the system is not as fast as it use to be but that’s normal. You up the hardware, add a few indexes and things seem steady. All of a sudden your email/support staff is overwhelmed by customers complaining about 404 errors. You look and see that your web sessions are timing out and queries are starting to drag. Postgres Autovacuum is starting at the worse possible times and you are spending a lot of time babysitting your app instead of counting your money. You thought you had more time but now its obvious, its time to shard the database.]]></summary></entry><entry><title type="html">Nodejs-and-LCDproc</title><link href="http://www.atlantageek.com/nodejs-add-lcdproc/" rel="alternate" type="text/html" title="Nodejs-and-LCDproc" /><published>2013-12-29T00:00:00+00:00</published><updated>2013-12-29T00:00:00+00:00</updated><id>http://www.atlantageek.com/nodejs-add-lcdproc</id><content type="html" xml:base="http://www.atlantageek.com/nodejs-add-lcdproc/"><![CDATA[<p><img src="/img/posts/IMG_20131230_003453.jpg" alt="LCD display of bitcoin price" /></p>

<p>I developed my first node.js module today.  Its called lcdproc-client and provides a client interface for lcdproc. For those not in the know, lcdproc is a tcp server that controls most lcd displays (not the monitors but the blocky text ones you see on media players.)</p>

<p>I wish these were more popular, In my opinion they should be on every desktop PC. On mine I wanted to display bitcoin prices  and I wanted to do it in either ruby or node.js. Ruby’s library didnt work and I couldnt find one for node.js.  I did find one that worked in Perl but I didnt want to write perl code. Plus I had an idea that I might use this for a later raspberry pi project and node.js works well on node.js. I did use the perl code to capture the protocol to figure out how it worked.</p>

<p>Anyway the <a href="https://npmjs.org/package/lcdproc-client">lcdproc-client</a> has been released so others can use lcdproc with node.js.  Also if you don’t have a lcd screen you can use the curses simulation by installing lcdproc and running the daemon with curses LCD simulation (LCDd -d lis).</p>

<p>Below is the code for the BTC display on the LCD.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>var Client = require('node-rest-client').Client;
var LcdClient = require('lcdproc-client').LcdClient;

lc = new LcdClient(13666,'localhost');

function get_bitcoin()
{
  console.log("Get Bitcoin");
  client = new Client();
  client.registerMethod("jsonMethod", "http://blockchain.info/ticker", "GET");
  client.methods.jsonMethod(function(data, response){
            // parsed response body as js object
    var obj = JSON.parse(data);
            buy = obj.USD['buy'];
            sell = obj.USD['sell'];
        lc.widget_val("first_line",1,1,"BTC " );
        lc.widget_val("second_line",1,2,"B:" + buy + " S:" + sell);
        });
}


lc.on('ready', function() {
  console.log("AAA");
  console.log("WIDTH: " + lc.width);
  console.log("HEIGHT: " + lc.height);
  lc.screen("bacon");
  lc.widget("first_line");
  lc.widget_val("first_line",1,1,"This is a line");
  lc.widget("second_line");
  lc.widget_val("second_line",1,2,"This is a second line");
  get_bitcoin();
  setInterval(get_bitcoin, 300000);
});
lc.init();
</code></pre></div></div>]]></content><author><name></name></author><category term="programming" /><category term="node.js" /><category term="raspberry pi" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Redesign of Wi-spy Web interface.</title><link href="http://www.atlantageek.com/redesign-wi-spy-web-interface/" rel="alternate" type="text/html" title="Redesign of Wi-spy Web interface." /><published>2013-08-18T02:46:21+00:00</published><updated>2013-08-18T02:46:21+00:00</updated><id>http://www.atlantageek.com/redesign-wi-spy-web-interface</id><content type="html" xml:base="http://www.atlantageek.com/redesign-wi-spy-web-interface/"><![CDATA[<p>So originally I wanted to build a web inteface for the wi-spy spectrum analyzer. I proved the concept with the first version.  You can watch the  <a href="http://www.youtube.com/watch?v=jj9u6VtkM3Y">short video</a>
yourself that goes over the design. The biggest problem with the application was that it required a lot of infrastructure.  It required a special verion of spec_Tool to collect the data, node.js to supply the web server and a redis daemon to act inbetween.  When I started adding code to store off historical data I realized I’d need another technology such as tokyo cabinet and the like. This proved even more difficult because I need a locking mechanism between the reader and the writer.</p>

<p>Finally I decided that it was time to get to the basics.  The latest version of this tool is written totally in C (spectool_red) htat will collect data, supply the web interface and store the historical data in tokyo cabinet.  This is really only one executable.  More details can be found <a href="https://github.com/atlantageek/websocketsa">here</a></p>]]></content><author><name>atlantageek</name></author><category term="Uncategorized" /><category term="rf" /><category term="websockets" /><summary type="html"><![CDATA[So originally I wanted to build a web inteface for the wi-spy spectrum analyzer. I proved the concept with the first version. You can watch the short video yourself that goes over the design. The biggest problem with the application was that it required a lot of infrastructure. It required a special verion of spec_Tool to collect the data, node.js to supply the web server and a redis daemon to act inbetween. When I started adding code to store off historical data I realized I’d need another technology such as tokyo cabinet and the like. This proved even more difficult because I need a locking mechanism between the reader and the writer.]]></summary></entry></feed>