Browse Source

Add html export of readme

Seth Falcon 14 years ago
parent
commit
9972f34591
2 changed files with 367 additions and 11 deletions
  1. 356 0
      README.html
  2. 11 11
      README.org

+ 356 - 0
README.html

@@ -0,0 +1,356 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+               "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+lang="en" xml:lang="en">
+<head>
+<title>README</title>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
+<meta name="generator" content="Org-mode"/>
+<meta name="generated" content="2010-09-05 17:17:09 PDT"/>
+<meta name="author" content="Seth Falcon"/>
+<meta name="description" content=""/>
+<meta name="keywords" content=""/>
+<style type="text/css">
+ <!--/*--><![CDATA[/*><!--*/
+  html { font-family: Times, serif; font-size: 12pt; }
+  .title  { text-align: center; }
+  .todo   { color: red; }
+  .done   { color: green; }
+  .tag    { background-color: #add8e6; font-weight:normal }
+  .target { }
+  .timestamp { color: #bebebe; }
+  .timestamp-kwd { color: #5f9ea0; }
+  p.verse { margin-left: 3% }
+  pre {
+	border: 1pt solid #AEBDCC;
+	background-color: #F3F5F7;
+	padding: 5pt;
+	font-family: courier, monospace;
+        font-size: 90%;
+        overflow:auto;
+  }
+  table { border-collapse: collapse; }
+  td, th { vertical-align: top; }
+  dt { font-weight: bold; }
+  div.figure { padding: 0.5em; }
+  div.figure p { text-align: center; }
+  textarea { overflow-x: auto; }
+  .linenr { font-size:smaller }
+  .code-highlighted {background-color:#ffff00;}
+  .org-info-js_info-navigation { border-style:none; }
+  #org-info-js_console-label { font-size:10px; font-weight:bold;
+                               white-space:nowrap; }
+  .org-info-js_search-highlight {background-color:#ffff00; color:#000000;
+                                 font-weight:bold; }
+  /*]]>*/-->
+</style>
+<script type="text/javascript">
+<!--/*--><![CDATA[/*><!--*/
+ function CodeHighlightOn(elem, id)
+ {
+   var target = document.getElementById(id);
+   if(null != target) {
+     elem.cacheClassElem = elem.className;
+     elem.cacheClassTarget = target.className;
+     target.className = "code-highlighted";
+     elem.className   = "code-highlighted";
+   }
+ }
+ function CodeHighlightOff(elem, id)
+ {
+   var target = document.getElementById(id);
+   if(elem.cacheClassElem)
+     elem.className = elem.cacheClassElem;
+   if(elem.cacheClassTarget)
+     target.className = elem.cacheClassTarget;
+ }
+/*]]>*///-->
+</script>
+
+</head>
+<body>
+<div id="content">
+
+<h1 class="title">README</h1>
+
+
+<div id="table-of-contents">
+<h2>Table of Contents</h2>
+<div id="text-table-of-contents">
+<ul>
+<li><a href="#sec-1">1 pidq - A Process Pool Library for Erlang </a>
+<ul>
+<li><a href="#sec-1_1">1.1 Use pidq to manage pools of processes (pids). </a></li>
+<li><a href="#sec-1_2">1.2 Motivation </a></li>
+<li><a href="#sec-1_3">1.3 Usage and API </a>
+<ul>
+<li><a href="#sec-1_3_1">1.3.1 Startup configuration </a></li>
+<li><a href="#sec-1_3_2">1.3.2 Getting and returning pids </a></li>
+<li><a href="#sec-1_3_3">1.3.3 Other things you can do </a></li>
+</ul>
+</li>
+<li><a href="#sec-1_4">1.4 Details </a></li>
+</ul>
+</li>
+</ul>
+</div>
+</div>
+
+<div id="outline-container-1" class="outline-2">
+<h2 id="sec-1"><span class="section-number-2">1</span> pidq - A Process Pool Library for Erlang </h2>
+<div class="outline-text-2" id="text-1">
+
+
+
+</div>
+
+<div id="outline-container-1_1" class="outline-3">
+<h3 id="sec-1_1"><span class="section-number-3">1.1</span> Use pidq to manage pools of processes (pids). </h3>
+<div class="outline-text-3" id="text-1_1">
+
+
+<ul>
+<li>
+Protect the pids from being used concurrently.  The main pidq
+interface is <code>pidq:take_pid/0</code> and <code>pidq:return_pid/2</code>.  The pidq
+server will keep track of which pids are <b>in use</b> and which are
+<b>free</b>.
+
+</li>
+<li>
+Maintain the size of the pid pool.  Specify a maximum number of pids
+in the pool.  Trigger pid creation when the free count drops below a
+minimum level or when a pid is marked as failing.
+
+</li>
+<li>
+Organize pids by type and randomly load-balance pids by type.  This
+is useful when the pids represent client processes connected to a
+particular node in a cluster (think database read slaves).  Separate
+pools are maintained for each type and a request for a pid will
+randomly select a type.
+
+</li>
+</ul>
+</div>
+
+</div>
+
+<div id="outline-container-1_2" class="outline-3">
+<h3 id="sec-1_2"><span class="section-number-3">1.2</span> Motivation </h3>
+<div class="outline-text-3" id="text-1_2">
+
+
+<p>
+The need for the pidq kit arose while writing an Erlang-based
+application that uses <a href="https://wiki.basho.com/display/RIAK/">Riak</a> for data storage.  When using the Erlang
+protocol buffer client for Riak, one should avoid accessing a given
+client concurrently.  This is because each client is associated with a
+unique client ID that corresponds to an element in an object's vector
+clock.  Concurrent action from the same client ID defeats the vector
+clock.  For some further explaination, see <sup><a class="footref" name="fnr.1" href="#fn.1">1</a></sup> and <sup><a class="footref" name="fnr.2" href="#fn.2">2</a></sup>.
+</p>
+<p>
+I wanted to avoid spinning up a new client for each request in the
+application.  Riak's protocol buffer client is a <code>gen_server</code> process
+and my intuition is that one doesn't want to pay for the startup time
+for every request you send to an app.  This suggested a pool of
+clients with some management to avoid concurrent use of a given
+client.  On top of that, it seemed convenient to add the ability to
+load balance between clients connected to different nodes in the Riak
+cluster.  The load-balancing is a secondary feature; even if you end
+up setting up <a href="http://haproxy.1wt.eu/">HAProxy</a> for that aspect, you might still want the client
+pooling.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-1_3" class="outline-3">
+<h3 id="sec-1_3"><span class="section-number-3">1.3</span> Usage and API </h3>
+<div class="outline-text-3" id="text-1_3">
+
+
+
+</div>
+
+<div id="outline-container-1_3_1" class="outline-4">
+<h4 id="sec-1_3_1"><span class="section-number-4">1.3.1</span> Startup configuration </h4>
+<div class="outline-text-4" id="text-1_3_1">
+
+
+<p>
+The idea is that you would wire up pidq to be a supervised process in
+your application.  When you start pidq, you specify a module and
+function to use for creating new pids.  You also specify the
+properties for each pool that you want pidq to manage, including the
+arguments to pass to the pid starter function.
+</p>
+<p>
+An example configuration looks like this:
+</p>
+
+
+
+<pre class="src src-erlang"><span style="color: #FF6400;">Pool1</span> = [{<span style="color: #D8FA3C;">name</span>, <span style="color: #61CE3C;">"node1"</span>},
+         {<span style="color: #D8FA3C;">max_pids</span>, 10},
+         {<span style="color: #D8FA3C;">min_free</span>, 2},
+         {<span style="color: #D8FA3C;">init_size</span>, 5}
+         {<span style="color: #D8FA3C;">pid_starter_args</span>, <span style="color: #FF6400;">Args1</span>}],
+
+<span style="color: #FF6400;">Pool2</span> = [{<span style="color: #D8FA3C;">name</span>, <span style="color: #61CE3C;">"node2"</span>},
+         {<span style="color: #D8FA3C;">max_pids</span>, 100},
+         {<span style="color: #D8FA3C;">min_free</span>, 2},
+         {<span style="color: #D8FA3C;">init_size</span>, 50}
+         {<span style="color: #D8FA3C;">pid_starter_args</span>, <span style="color: #FF6400;">Args2</span>}],
+
+<span style="color: #FF6400;">Config</span> = [{<span style="color: #D8FA3C;">pid_starter</span>, {<span style="color: #FF6400;">M</span>, <span style="color: #FF6400;">F</span>}},
+          {<span style="color: #D8FA3C;">pid_stopper</span>, {<span style="color: #FF6400;">M</span>, <span style="color: #FF6400;">F</span>}},
+          {<span style="color: #D8FA3C;">pools</span>, [<span style="color: #FF6400;">Pool1</span>, <span style="color: #FF6400;">Pool2</span>]}]
+
+<span style="color: #AEAEAE; font-style: italic;">% </span><span style="color: #AEAEAE; font-style: italic;">either call this directly, or wire this
+</span><span style="color: #AEAEAE; font-style: italic;">% </span><span style="color: #AEAEAE; font-style: italic;">call into your application's supervisor  
+</span><span style="color: #8DA6CE;">pidq</span>:<span style="color: #8DA6CE;">start</span>(<span style="color: #FF6400;">Config</span>)
+
+</pre>
+
+
+
+<p>
+Each pool has a unique name, a maximum number of pids, an initial
+number of pids, and a minimum free pids count.  When pidq starts, it
+will create pids to match the <code>init_size</code> value.  If there are <code>min_free</code>
+pids or fewer, pidq will add a pid as long as that doesn't bring the
+total used + free count over <code>max_pids</code>.
+</p>
+<p>
+Specifying a <code>pid_stopper</code> function is optional.  If not specified,
+<code>exit(pid, kill)</code> will be used to shutdown pids in the case of error,
+pidq shutdown, or pool removal.  The function specified will be passed
+a pid as returned by the <code>pid_starter</code> function.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-1_3_2" class="outline-4">
+<h4 id="sec-1_3_2"><span class="section-number-4">1.3.2</span> Getting and returning pids </h4>
+<div class="outline-text-4" id="text-1_3_2">
+
+
+<p>
+Once started, the main interaction you will have with pidq is through
+two functions, <code>take_pid/0</code> and <code>return_pid/2</code>.
+</p>
+<p>
+Call <code>pidq:take_pid()</code> to obtain a pid from the pool.  When you are done
+with it, return it to the pool using <code>pidq:return_pid(Pid, ok)</code>.  If
+you encountered an error using the pid, you can pass <code>fail</code> as the
+second argument.  In this case, pidq will permently remove that pid
+from the pool and start a new pid to replace it.
+</p>
+</div>
+
+</div>
+
+<div id="outline-container-1_3_3" class="outline-4">
+<h4 id="sec-1_3_3"><span class="section-number-4">1.3.3</span> Other things you can do </h4>
+<div class="outline-text-4" id="text-1_3_3">
+
+
+<p>
+You can get the status for the system via <code>pidq:status()</code>.  This will
+return some informational details about the pools being managed.
+</p>
+<p>
+You can also add or remove new pools while pidq is running using
+<code>pidq:add_pool/1</code> and <code>pidq:remove_pool/1</code>.  Each pid 
+</p>
+</div>
+</div>
+
+</div>
+
+<div id="outline-container-1_4" class="outline-3">
+<h3 id="sec-1_4"><span class="section-number-3">1.4</span> Details </h3>
+<div class="outline-text-3" id="text-1_4">
+
+
+<p>
+pidq is implemented as a <code>gen_server</code>.  Server state consists of a dict
+of pools keyed by pool name.  Each pool keeps track of its parameters,
+a free list, and an in-use list.  Since our motivating use-case is
+Riak's pb client, we opt to reuse a given client as much as possible
+to avoid unnecessary vector clock growth.  So pids are taken from the
+head of the free list and returned to the head of the free list.
+</p>
+<p>
+It is an error to add a pool with a name that already exists.
+</p>
+<p>
+Pool removal has two forms:
+</p>
+<ul>
+<li>
+<b>graceful</b> pids in the free list are killed (using exit(pid, kill)
+unless a <code>pid_stopper</code> is specified in the pool parameters.  No pids
+will be handed out from this pool's free list.  As pids are
+returned, they are shut down.  When the pool is empty, it is
+removed.
+
+</li>
+<li>
+<b>immediate</b> all pids in free and in-use lists are shut down; the
+pool is removed.
+
+
+
+</li>
+</ul>
+
+
+<pre class="src src-erlang"><span style="color: #7fffd4;">-spec</span>(<span style="color: #8DA6CE;">take_pid</span>() -&gt; <span style="color: #94bff3;">pid</span>()).
+
+<span style="color: #7fffd4;">-spec</span>(<span style="color: #8DA6CE;">return_pid</span>(<span style="color: #94bff3;">pid</span>(), <span style="color: #D8FA3C;">ok</span> | <span style="color: #D8FA3C;">fail</span>) -&gt; <span style="color: #D8FA3C;">ignore</span>).
+
+<span style="color: #7fffd4;">-spec</span>(<span style="color: #8DA6CE;">status</span>() -&gt; [<span style="color: #8DA6CE;">term</span>()]).
+
+<span style="color: #7fffd4;">-type</span>(<span style="color: #8DA6CE;">pid_type_opt</span>() ::
+      {<span style="color: #D8FA3C;">name</span>, <span style="color: #8DA6CE;">string</span>()} |
+      {<span style="color: #D8FA3C;">max_pids</span>, <span style="color: #8DA6CE;">int</span>()} |
+      {<span style="color: #D8FA3C;">min_free</span>, <span style="color: #8DA6CE;">int</span>()} |
+      {<span style="color: #D8FA3C;">init_size</span>, <span style="color: #8DA6CE;">int</span>()} |
+      {<span style="color: #D8FA3C;">pid_starter_args</span>, [<span style="color: #8DA6CE;">term</span>()]}).
+
+<span style="color: #7fffd4;">-type</span>(<span style="color: #8DA6CE;">pid_type_spec</span>() :: [<span style="color: #8DA6CE;">pid_type_opt</span>()]).
+<span style="color: #7fffd4;">-spec</span>(<span style="color: #8DA6CE;">add_type</span>(<span style="color: #8DA6CE;">pid_type_spec</span>()) -&gt; <span style="color: #D8FA3C;">ok</span> | {<span style="color: #D8FA3C;">error</span>, <span style="color: #FF6400;">Why</span>}).
+<span style="color: #7fffd4;">-spec</span>(<span style="color: #8DA6CE;">remove_type</span>(<span style="color: #8DA6CE;">string</span>()) -&gt; <span style="color: #D8FA3C;">ok</span> | {<span style="color: #D8FA3C;">error</span>, <span style="color: #FF6400;">Why</span>}).
+</pre>
+
+
+
+
+
+
+</div>
+</div>
+</div>
+<div id="footnotes">
+<h2 class="footnotes">Footnotes: </h2>
+<div id="text-footnotes">
+<p class="footnote"><sup><a class="footnum" name="fn.1" href="#fnr.1">1</a></sup> <a href="http://lists.basho.com/pipermail/riak-users_lists.basho.com/2010-September/001900.html">http://lists.basho.com/pipermail/riak-users_lists.basho.com/2010-September/001900.html</a>
+</p>
+<p class="footnote"><sup><a class="footnum" name="fn.2" href="#fnr.2">2</a></sup> <a href="http://lists.basho.com/pipermail/riak-users_lists.basho.com/2010-September/001904.html">http://lists.basho.com/pipermail/riak-users_lists.basho.com/2010-September/001904.html</a>
+</p>
+</div>
+</div>
+<div id="postamble">
+<p class="author"> Author: Seth Falcon
+</p>
+<p class="date"> Date: 2010-09-05 17:17:09 PDT</p>
+<p class="creator">HTML generated by org-mode 7.01trans in emacs 23</p>
+</div>
+</div>
+</body>
+</html>

+ 11 - 11
README.org

@@ -4,8 +4,8 @@
 
 - Protect the pids from being used concurrently.  The main pidq
   interface is =pidq:take_pid/0= and =pidq:return_pid/2=.  The pidq
-  server will keep track of which pids are _in use_ and which are
-  _free_.
+  server will keep track of which pids are *in use* and which are
+  *free*.
 
 - Maintain the size of the pid pool.  Specify a maximum number of pids
   in the pool.  Trigger pid creation when the free count drops below a
@@ -28,7 +28,7 @@ clock.  Concurrent action from the same client ID defeats the vector
 clock.  For some further explaination, see [1] and [2].
 
 I wanted to avoid spinning up a new client for each request in the
-application.  Riak's protocol buffer client is a gen_server process
+application.  Riak's protocol buffer client is a =gen_server= process
 and my intuition is that one doesn't want to pay for the startup time
 for every request you send to an app.  This suggested a pool of
 clients with some management to avoid concurrent use of a given
@@ -78,14 +78,14 @@ An example configuration looks like this:
 
 Each pool has a unique name, a maximum number of pids, an initial
 number of pids, and a minimum free pids count.  When pidq starts, it
-will create pids to match the init_size value.  If there are min_free
+will create pids to match the =init_size= value.  If there are =min_free=
 pids or fewer, pidq will add a pid as long as that doesn't bring the
-total used + free count over max_pids.
+total used + free count over =max_pids=.
 
-Specifying a pid_stopper function is optional.  If not specified,
+Specifying a =pid_stopper= function is optional.  If not specified,
 =exit(pid, kill)= will be used to shutdown pids in the case of error,
 pidq shutdown, or pool removal.  The function specified will be passed
-a pid as returned by the pid_starter function.
+a pid as returned by the =pid_starter= function.
 
 *** Getting and returning pids
 
@@ -108,7 +108,7 @@ You can also add or remove new pools while pidq is running using
 
 ** Details
 
-pidq is implemented as a gen_server.  Server state consists of a dict
+pidq is implemented as a =gen_server=.  Server state consists of a dict
 of pools keyed by pool name.  Each pool keeps track of its parameters,
 a free list, and an in-use list.  Since our motivating use-case is
 Riak's pb client, we opt to reuse a given client as much as possible
@@ -119,13 +119,13 @@ It is an error to add a pool with a name that already exists.
 
 Pool removal has two forms:
 
-- _graceful_ pids in the free list are killed (using exit(pid, kill)
-  unless a pid_stopper is specified in the pool parameters.  No pids
+- *graceful* pids in the free list are killed (using exit(pid, kill)
+  unless a =pid_stopper= is specified in the pool parameters.  No pids
   will be handed out from this pool's free list.  As pids are
   returned, they are shut down.  When the pool is empty, it is
   removed.
 
-- _immediate_ all pids in free and in-use lists are shut down; the
+- *immediate* all pids in free and in-use lists are shut down; the
   pool is removed.