README.html 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  3. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  4. <html xmlns="http://www.w3.org/1999/xhtml"
  5. lang="en" xml:lang="en">
  6. <head>
  7. <title>README</title>
  8. <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
  9. <meta name="generator" content="Org-mode"/>
  10. <meta name="generated" content="2010-09-08 23:24:52 PDT"/>
  11. <meta name="author" content="Seth Falcon"/>
  12. <meta name="description" content=""/>
  13. <meta name="keywords" content=""/>
  14. <style type="text/css">
  15. <!--/*--><![CDATA[/*><!--*/
  16. html { font-family: Times, serif; font-size: 12pt; }
  17. .title { text-align: center; }
  18. .todo { color: red; }
  19. .done { color: green; }
  20. .tag { background-color: #add8e6; font-weight:normal }
  21. .target { }
  22. .timestamp { color: #bebebe; }
  23. .timestamp-kwd { color: #5f9ea0; }
  24. p.verse { margin-left: 3% }
  25. pre {
  26. border: 1pt solid #AEBDCC;
  27. background-color: #F3F5F7;
  28. padding: 5pt;
  29. font-family: courier, monospace;
  30. font-size: 90%;
  31. overflow:auto;
  32. }
  33. table { border-collapse: collapse; }
  34. td, th { vertical-align: top; }
  35. dt { font-weight: bold; }
  36. div.figure { padding: 0.5em; }
  37. div.figure p { text-align: center; }
  38. textarea { overflow-x: auto; }
  39. .linenr { font-size:smaller }
  40. .code-highlighted {background-color:#ffff00;}
  41. .org-info-js_info-navigation { border-style:none; }
  42. #org-info-js_console-label { font-size:10px; font-weight:bold;
  43. white-space:nowrap; }
  44. .org-info-js_search-highlight {background-color:#ffff00; color:#000000;
  45. font-weight:bold; }
  46. /*]]>*/-->
  47. </style>
  48. <script type="text/javascript">
  49. <!--/*--><![CDATA[/*><!--*/
  50. function CodeHighlightOn(elem, id)
  51. {
  52. var target = document.getElementById(id);
  53. if(null != target) {
  54. elem.cacheClassElem = elem.className;
  55. elem.cacheClassTarget = target.className;
  56. target.className = "code-highlighted";
  57. elem.className = "code-highlighted";
  58. }
  59. }
  60. function CodeHighlightOff(elem, id)
  61. {
  62. var target = document.getElementById(id);
  63. if(elem.cacheClassElem)
  64. elem.className = elem.cacheClassElem;
  65. if(elem.cacheClassTarget)
  66. target.className = elem.cacheClassTarget;
  67. }
  68. /*]]>*///-->
  69. </script>
  70. </head>
  71. <body>
  72. <div id="content">
  73. <h1 class="title">README</h1>
  74. <div id="table-of-contents">
  75. <h2>Table of Contents</h2>
  76. <div id="text-table-of-contents">
  77. <ul>
  78. <li><a href="#sec-1">1 pidq - A Process Pool Library for Erlang </a>
  79. <ul>
  80. <li><a href="#sec-1_1">1.1 Use pidq to manage pools of processes (pids). </a></li>
  81. <li><a href="#sec-1_2">1.2 Motivation </a></li>
  82. <li><a href="#sec-1_3">1.3 Usage and API </a>
  83. <ul>
  84. <li><a href="#sec-1_3_1">1.3.1 Startup configuration </a></li>
  85. <li><a href="#sec-1_3_2">1.3.2 Getting and returning pids </a></li>
  86. <li><a href="#sec-1_3_3">1.3.3 Other things you can do </a></li>
  87. </ul>
  88. </li>
  89. <li><a href="#sec-1_4">1.4 Details </a>
  90. <ul>
  91. <li><a href="#sec-1_4_1">1.4.1 Pool management </a></li>
  92. </ul>
  93. </li>
  94. </ul>
  95. </li>
  96. </ul>
  97. </div>
  98. </div>
  99. <div id="outline-container-1" class="outline-2">
  100. <h2 id="sec-1"><span class="section-number-2">1</span> pidq - A Process Pool Library for Erlang </h2>
  101. <div class="outline-text-2" id="text-1">
  102. <p>
  103. <b>Note:</b> this is all work very much in progress. If you are
  104. interested, drop me a note. Right now, it is really just a readme
  105. and no working code.
  106. </p>
  107. </div>
  108. <div id="outline-container-1_1" class="outline-3">
  109. <h3 id="sec-1_1"><span class="section-number-3">1.1</span> Use pidq to manage pools of processes (pids). </h3>
  110. <div class="outline-text-3" id="text-1_1">
  111. <ul>
  112. <li>
  113. Protect the pids from being used concurrently. The main pidq
  114. interface is <code>pidq:take_pid/0</code> and <code>pidq:return_pid/2</code>. The pidq
  115. server will keep track of which pids are <b>in use</b> and which are
  116. <b>free</b>.
  117. </li>
  118. <li>
  119. Maintain the size of the pid pool. Specify a maximum number of pids
  120. in the pool. Trigger pid creation when the free count drops below a
  121. minimum level or when a pid is marked as failing.
  122. </li>
  123. <li>
  124. Organize pids by type and randomly load-balance pids by type. This
  125. is useful when the pids represent client processes connected to a
  126. particular node in a cluster (think database read slaves). Separate
  127. pools are maintained for each type and a request for a pid will
  128. randomly select a type.
  129. </li>
  130. </ul>
  131. </div>
  132. </div>
  133. <div id="outline-container-1_2" class="outline-3">
  134. <h3 id="sec-1_2"><span class="section-number-3">1.2</span> Motivation </h3>
  135. <div class="outline-text-3" id="text-1_2">
  136. <p>
  137. The need for the pidq kit arose while writing an Erlang-based
  138. application that uses <a href="https://wiki.basho.com/display/RIAK/">Riak</a> for data storage. When using the Erlang
  139. protocol buffer client for Riak, one should avoid accessing a given
  140. client concurrently. This is because each client is associated with a
  141. unique client ID that corresponds to an element in an object's vector
  142. clock. Concurrent action from the same client ID defeats the vector
  143. 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>.
  144. </p>
  145. <p>
  146. I wanted to avoid spinning up a new client for each request in the
  147. application. Riak's protocol buffer client is a <code>gen_server</code> process
  148. and my intuition is that one doesn't want to pay for the startup time
  149. for every request you send to an app. This suggested a pool of
  150. clients with some management to avoid concurrent use of a given
  151. client. On top of that, it seemed convenient to add the ability to
  152. load balance between clients connected to different nodes in the Riak
  153. cluster. The load-balancing is a secondary feature; even if you end
  154. up setting up <a href="http://haproxy.1wt.eu/">HAProxy</a> for that aspect, you might still want the client
  155. pooling.
  156. </p>
  157. </div>
  158. </div>
  159. <div id="outline-container-1_3" class="outline-3">
  160. <h3 id="sec-1_3"><span class="section-number-3">1.3</span> Usage and API </h3>
  161. <div class="outline-text-3" id="text-1_3">
  162. </div>
  163. <div id="outline-container-1_3_1" class="outline-4">
  164. <h4 id="sec-1_3_1"><span class="section-number-4">1.3.1</span> Startup configuration </h4>
  165. <div class="outline-text-4" id="text-1_3_1">
  166. <p>
  167. The idea is that you would wire up pidq to be a supervised process in
  168. your application. When you start pidq, you specify a module and
  169. function to use for creating new pids. You also specify the
  170. properties for each pool that you want pidq to manage, including the
  171. arguments to pass to the pid starter function.
  172. </p>
  173. <p>
  174. An example configuration looks like this:
  175. </p>
  176. <pre class="src src-erlang"><span style="color: #FF6400;">Pool1</span> = [{<span style="color: #D8FA3C;">name</span>, <span style="color: #61CE3C;">"node1"</span>},
  177. {<span style="color: #D8FA3C;">max_pids</span>, 10},
  178. {<span style="color: #D8FA3C;">min_free</span>, 2},
  179. {<span style="color: #D8FA3C;">init_size</span>, 5}
  180. {<span style="color: #D8FA3C;">pid_starter_args</span>, <span style="color: #FF6400;">Args1</span>}],
  181. <span style="color: #FF6400;">Pool2</span> = [{<span style="color: #D8FA3C;">name</span>, <span style="color: #61CE3C;">"node2"</span>},
  182. {<span style="color: #D8FA3C;">max_pids</span>, 100},
  183. {<span style="color: #D8FA3C;">min_free</span>, 2},
  184. {<span style="color: #D8FA3C;">init_size</span>, 50}
  185. {<span style="color: #D8FA3C;">pid_starter_args</span>, <span style="color: #FF6400;">Args2</span>}],
  186. <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>}},
  187. {<span style="color: #D8FA3C;">pid_stopper</span>, {<span style="color: #FF6400;">M</span>, <span style="color: #FF6400;">F</span>}},
  188. {<span style="color: #D8FA3C;">pools</span>, [<span style="color: #FF6400;">Pool1</span>, <span style="color: #FF6400;">Pool2</span>]}]
  189. <span style="color: #AEAEAE; font-style: italic;">% </span><span style="color: #AEAEAE; font-style: italic;">either call this directly, or wire this
  190. </span><span style="color: #AEAEAE; font-style: italic;">% </span><span style="color: #AEAEAE; font-style: italic;">call into your application's supervisor
  191. </span><span style="color: #8DA6CE;">pidq</span>:<span style="color: #8DA6CE;">start</span>(<span style="color: #FF6400;">Config</span>)
  192. </pre>
  193. <p>
  194. Each pool has a unique name, a maximum number of pids, an initial
  195. number of pids, and a minimum free pids count. When pidq starts, it
  196. will create pids to match the <code>init_size</code> value. If there are <code>min_free</code>
  197. pids or fewer, pidq will add a pid as long as that doesn't bring the
  198. total used + free count over <code>max_pids</code>.
  199. </p>
  200. <p>
  201. Specifying a <code>pid_stopper</code> function is optional. If not specified,
  202. <code>exit(pid, kill)</code> will be used to shutdown pids in the case of error,
  203. pidq shutdown, or pool removal. The function specified will be passed
  204. a pid as returned by the <code>pid_starter</code> function.
  205. </p>
  206. </div>
  207. </div>
  208. <div id="outline-container-1_3_2" class="outline-4">
  209. <h4 id="sec-1_3_2"><span class="section-number-4">1.3.2</span> Getting and returning pids </h4>
  210. <div class="outline-text-4" id="text-1_3_2">
  211. <p>
  212. Once started, the main interaction you will have with pidq is through
  213. two functions, <code>take_pid/0</code> and <code>return_pid/2</code>.
  214. </p>
  215. <p>
  216. Call <code>pidq:take_pid()</code> to obtain a pid from the pool. When you are done
  217. with it, return it to the pool using <code>pidq:return_pid(Pid, ok)</code>. If
  218. you encountered an error using the pid, you can pass <code>fail</code> as the
  219. second argument. In this case, pidq will permently remove that pid
  220. from the pool and start a new pid to replace it.
  221. </p>
  222. </div>
  223. </div>
  224. <div id="outline-container-1_3_3" class="outline-4">
  225. <h4 id="sec-1_3_3"><span class="section-number-4">1.3.3</span> Other things you can do </h4>
  226. <div class="outline-text-4" id="text-1_3_3">
  227. <p>
  228. You can get the status for the system via <code>pidq:status()</code>. This will
  229. return some informational details about the pools being managed.
  230. </p>
  231. <p>
  232. You can also add or remove new pools while pidq is running using
  233. <code>pidq:add_pool/1</code> and <code>pidq:remove_pool/1</code>. Each pid
  234. </p>
  235. </div>
  236. </div>
  237. </div>
  238. <div id="outline-container-1_4" class="outline-3">
  239. <h3 id="sec-1_4"><span class="section-number-3">1.4</span> Details </h3>
  240. <div class="outline-text-3" id="text-1_4">
  241. <p>
  242. pidq is implemented as a <code>gen_server</code>. Server state consists of:
  243. </p>
  244. <ul>
  245. <li>
  246. A dict of pools keyed by pool name.
  247. </li>
  248. <li>
  249. A dict mapping in use pids to their pool name.
  250. </li>
  251. <li>
  252. A dict mapping consumer process pids to the pid they are using.
  253. </li>
  254. <li>
  255. A module and function to use for starting new pids.
  256. </li>
  257. </ul>
  258. <p>Each pool keeps track of its parameters, such as max pids to allow,
  259. initial pids to start, number of pids in use, and a list of free pids.
  260. </p>
  261. <p>
  262. Since our motivating use-case is Riak's pb client, we opt to reuse a
  263. given client as much as possible to avoid unnecessary vector clock
  264. growth; pids are taken from the head of the free list and returned
  265. to the head of the free list.
  266. </p>
  267. <p>
  268. pidq is a system process and traps exits. Before giving out a pid, it
  269. links to the requesting consumer process. This way, if the consumer
  270. process crashes, pidq can recover the pid. When the pid is returned,
  271. the requesting process will be unlinked. Since the state of the pid
  272. is unknown in the case of a crashing consumer, we will destroy the pid
  273. and add a fresh one to the pool.
  274. </p>
  275. <p>
  276. The pid starter MFA should use spawn<sub>link</sub> so that pidq will be linked
  277. to the pids (is it confusing that we've taken the term "pid" and
  278. turned it into a noun of this system?). This way, when pids crash,
  279. pidq will be notified and can refill the pool with new pids.
  280. </p>
  281. <p>
  282. Also note that an alternative to a consumer explicitly returning a pid
  283. is for the consumer to exit normally. pidq will receive the normal
  284. exit and can reclaim the pid. In fact, we might want to implement pid
  285. return as "fake death" by sending pidq exit(PidqPid, normal).
  286. </p>
  287. </div>
  288. <div id="outline-container-1_4_1" class="outline-4">
  289. <h4 id="sec-1_4_1"><span class="section-number-4">1.4.1</span> Pool management </h4>
  290. <div class="outline-text-4" id="text-1_4_1">
  291. <p>
  292. It is an error to add a pool with a name that already exists.
  293. </p>
  294. <p>
  295. Pool removal has two forms:
  296. </p>
  297. <ul>
  298. <li>
  299. <b>graceful</b> pids in the free list are killed (using exit(pid, kill)
  300. unless a <code>pid_stopper</code> is specified in the pool parameters. No pids
  301. will be handed out from this pool's free list. As pids are
  302. returned, they are shut down. When the pool is empty, it is
  303. removed.
  304. </li>
  305. <li>
  306. <b>immediate</b> all pids in free and in-use lists are shut down; the
  307. pool is removed.
  308. </li>
  309. </ul>
  310. <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>()).
  311. <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>).
  312. <span style="color: #7fffd4;">-spec</span>(<span style="color: #8DA6CE;">status</span>() -&gt; [<span style="color: #8DA6CE;">term</span>()]).
  313. <span style="color: #7fffd4;">-type</span>(<span style="color: #8DA6CE;">pid_type_opt</span>() ::
  314. {<span style="color: #D8FA3C;">name</span>, <span style="color: #8DA6CE;">string</span>()} |
  315. {<span style="color: #D8FA3C;">max_pids</span>, <span style="color: #8DA6CE;">int</span>()} |
  316. {<span style="color: #D8FA3C;">min_free</span>, <span style="color: #8DA6CE;">int</span>()} |
  317. {<span style="color: #D8FA3C;">init_size</span>, <span style="color: #8DA6CE;">int</span>()} |
  318. {<span style="color: #D8FA3C;">pid_starter_args</span>, [<span style="color: #8DA6CE;">term</span>()]}).
  319. <span style="color: #7fffd4;">-type</span>(<span style="color: #8DA6CE;">pid_type_spec</span>() :: [<span style="color: #8DA6CE;">pid_type_opt</span>()]).
  320. <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>}).
  321. <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>}).
  322. </pre>
  323. </div>
  324. </div>
  325. </div>
  326. </div>
  327. <div id="footnotes">
  328. <h2 class="footnotes">Footnotes: </h2>
  329. <div id="text-footnotes">
  330. <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>
  331. </p>
  332. <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>
  333. </p>
  334. </div>
  335. </div>
  336. <div id="postamble">
  337. <p class="author"> Author: Seth Falcon
  338. </p>
  339. <p class="date"> Date: 2010-09-08 23:24:52 PDT</p>
  340. <p class="creator">HTML generated by org-mode 7.01trans in emacs 23</p>
  341. </div>
  342. </div>
  343. </body>
  344. </html>