{"id":5886,"date":"2012-06-09T18:23:37","date_gmt":"2012-06-09T23:23:37","guid":{"rendered":"http:\/\/bobbeaty.com\/wp\/?p=5886"},"modified":"2012-06-10T17:44:42","modified_gmt":"2012-06-10T22:44:42","slug":"adding-a-flexible-sized-key-templated-trie-to-dkit","status":"publish","type":"post","link":"https:\/\/bobbeaty.com\/wp\/archives\/5886","title":{"rendered":"Adding a Flexible Sized Key Templated Trie to DKit"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/bobbeaty.com\/wp\/wp-content\/uploads\/2012\/03\/DKit.jpg\" alt=\"DKit Laboratory\" title=\"DKit.jpg\" border=\"0\" width=\"150\" height=\"98\" style=\"float:right;\" \/><\/p>\n<p>Today I spent a good chunk of time writing a 64-bit key <a href=\"http:\/\/en.wikipedia.org\/wiki\/Trie\">trie<\/a> as the next basic component of re-writing the exchange feeds in a lot better component library than I had previously written. The purpose of the trie is to have a lockless storage mechanism that has very fast insertion and access methods. The last version I'd written was based on a <em>specific<\/em> element being stored - a pointer to a Message. In this version I wanted to be able to store <em>any<\/em> template type - including pointers, and handle the disposal as needed.<\/p>\n<p>I've made adjustments like this for the <tt>dkit::pool<\/tt> where I handled plain-old-datatypes as well as pointers, and disposed of the pointer values properly. I needed to be able to do the same thing for the trie.<\/p>\n<p>The second improvement this time around is to stop trying to make the trie do <em>everything<\/em> associated with processing of its contents. In the past, I'd had the trie scan the Messages for symbol limits, values, etc. This was <strong><em>very<\/em><\/strong> inefficient, as it was all in the trie, and therefore <strong><em>very<\/em><\/strong> specific. I needed to move away from this and use functors that could be passed into the trie, and then operated on each of the valid elements in the trie. This is a <em>far<\/em> better scheme as it allows the user to make <em>any<\/em> processing on the Nodes in the trie, and this is far more flexible than trying to implement the methods in the trie itself.<\/p>\n<p>The solution to this was to define a class within the templates trie so that I could create functors like this:<\/p>\n<pre class=\"cpp\" style=\"font-family:monospace;\">  <span style=\"color: #0000ff;\">class<\/span> counter <span style=\"color: #008080;\">:<\/span> <span style=\"color: #0000ff;\">public<\/span> dkit<span style=\"color: #008080;\">::<\/span><span style=\"color: #007788;\">trie<\/span><span style=\"color: #000080;\">&lt;<\/span>blob <span style=\"color: #000040;\">*<\/span>, dkit<span style=\"color: #008080;\">::<\/span><span style=\"color: #007788;\">uint64_key<\/span><span style=\"color: #000080;\">&gt;<\/span><span style=\"color: #008080;\">::<\/span><span style=\"color: #007788;\">functor<\/span>\n  <span style=\"color: #008000;\">&#123;<\/span>\n    <span style=\"color: #0000ff;\">public<\/span><span style=\"color: #008080;\">:<\/span>\n      counter<span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #008000;\">&#41;<\/span> <span style=\"color: #008080;\">:<\/span> _cnt<span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #0000dd;\">0<\/span><span style=\"color: #008000;\">&#41;<\/span> <span style=\"color: #008000;\">&#123;<\/span> <span style=\"color: #008000;\">&#125;<\/span>\n      <span style=\"color: #0000ff;\">virtual<\/span> ~counter<span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #008000;\">&#41;<\/span> <span style=\"color: #008000;\">&#123;<\/span> <span style=\"color: #008000;\">&#125;<\/span>\n      <span style=\"color: #0000ff;\">virtual<\/span> <span style=\"color: #0000ff;\">bool<\/span> process<span style=\"color: #008000;\">&#40;<\/span>\n          <span style=\"color: #0000ff;\">volatile<\/span> dkit<span style=\"color: #008080;\">::<\/span><span style=\"color: #007788;\">trie<\/span><span style=\"color: #000080;\">&lt;<\/span>blob <span style=\"color: #000040;\">*<\/span>, dkit<span style=\"color: #008080;\">::<\/span><span style=\"color: #007788;\">uint64_key<\/span><span style=\"color: #000080;\">&gt;<\/span><span style=\"color: #008080;\">::<\/span><span style=\"color: #007788;\">Node<\/span> <span style=\"color: #000040;\">&amp;<\/span> aNode <span style=\"color: #008000;\">&#41;<\/span>\n      <span style=\"color: #008000;\">&#123;<\/span>\n        <span style=\"color: #000040;\">++<\/span>_cnt<span style=\"color: #008080;\">;<\/span>\n        <span style=\"color: #0000ff;\">return<\/span> <span style=\"color: #0000ff;\">true<\/span><span style=\"color: #008080;\">;<\/span>\n      <span style=\"color: #008000;\">&#125;<\/span>\n      <span style=\"color: #0000ff;\">uint64_t<\/span> getCount<span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #008000;\">&#41;<\/span> <span style=\"color: #008000;\">&#123;<\/span> <span style=\"color: #0000ff;\">return<\/span> _cnt<span style=\"color: #008080;\">;<\/span> <span style=\"color: #008000;\">&#125;<\/span>\n    <span style=\"color: #0000ff;\">private<\/span><span style=\"color: #008080;\">:<\/span>\n      <span style=\"color: #0000ff;\">uint64_t<\/span>     _cnt<span style=\"color: #008080;\">;<\/span>\n  <span style=\"color: #008000;\">&#125;<\/span><span style=\"color: #008080;\">;<\/span><\/pre>\n<p>They are easy to create, and you can apply them to all the elements in the trie with a simple call:<\/p>\n<pre class=\"cpp\" style=\"font-family:monospace;\">    counter    worker<span style=\"color: #008080;\">;<\/span>\n    m.<span style=\"color: #007788;\">apply<\/span><span style=\"color: #008000;\">&#40;<\/span>worker<span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008080;\">;<\/span><\/pre>\n<p>The final improvement was to switch from loop-based indexing into the trie to recursion-based accessing. There are a few reasons for this - but the most is flexibility and code simplicity. When you have a fixed key length, and you use looping to traverse the trie, you have a fixed series of nested for loops. This seems all well and good, but it makes for a very <em>fixed<\/em> structure and the code isn't all the easy to read.<\/p>\n<p>By going with a better class structure for building the trie, we're able to take advantage of recursion, and then the only parameter to the \"depth\" of the trie, and the corresponding size of the key, is the number of <em>branches<\/em> used in the construction of the tree in the trie. If we put the parameter in the creation method then there's a single point where we stop creating branches, and instead make the leaf nodes. From this point, the same code that traverses a 64-bit key trie works for a 128-bit trie.<\/p>\n<p>At least insofar as the movement in the trie.<\/p>\n<p>Once I got it all working, the next thing was to look at the recursion vs. looping design. I wanted to make sure that I had the most performant design. What I found was that the recursion was about 25% <em>faster<\/em> than the looping structure. I'm guessing it's due to tail-recursion optimization by the compiler, but I'm not positive. I repeated the tests, and the difference is real, that's good enough for me.<\/p>\n<p>Once it was all done, I wondered how hard it might be to make the key size <em>another<\/em> parameter in the template. Well\u2026 since we're using recursion, and therefore, the size of the key space is only used in one space, the solution was pretty simple. Start by defining the different sizes we'll accept:<\/p>\n<pre class=\"cpp\" style=\"font-family:monospace;\">  <span style=\"color: #0000ff;\">namespace<\/span> dkit <span style=\"color: #008000;\">&#123;<\/span>\n  <span style=\"color: #0000ff;\">enum<\/span> trie_key_size <span style=\"color: #008000;\">&#123;<\/span>\n    uint16_key <span style=\"color: #000080;\">=<\/span> <span style=\"color: #0000dd;\">2<\/span>,\n    uint32_key <span style=\"color: #000080;\">=<\/span> <span style=\"color: #0000dd;\">4<\/span>,\n    uint64_key <span style=\"color: #000080;\">=<\/span> <span style=\"color: #0000dd;\">8<\/span>,\n    uint128_key <span style=\"color: #000080;\">=<\/span> <span style=\"color: #0000dd;\">16<\/span>,\n  <span style=\"color: #008000;\">&#125;<\/span><span style=\"color: #008080;\">;<\/span>\n  <span style=\"color: #008000;\">&#125;<\/span>      <span style=\"color: #666666;\">\/\/ end of namespace dkit<\/span><\/pre>\n<p>and then we convert this to the test we need in the branch creation:<\/p>\n<pre class=\"cpp\" style=\"font-family:monospace;\">  <span style=\"color: #0000ff;\">enum<\/span> <span style=\"color: #008000;\">&#123;<\/span>\n    eLastBranch <span style=\"color: #000080;\">=<\/span> <span style=\"color: #008000;\">&#40;<\/span>N <span style=\"color: #000040;\">-<\/span> <span style=\"color: #0000dd;\">2<\/span><span style=\"color: #008000;\">&#41;<\/span>\n  <span style=\"color: #008000;\">&#125;<\/span><span style=\"color: #008080;\">;<\/span><\/pre>\n<p>In the code, we then have:<\/p>\n<pre class=\"cpp\" style=\"font-family:monospace;\">  <span style=\"color: #0000ff;\">virtual<\/span> <span style=\"color: #0000ff;\">volatile<\/span> Node <span style=\"color: #000040;\">*<\/span>getOrCreateNodeForKey<span style=\"color: #008000;\">&#40;<\/span> <span style=\"color: #0000ff;\">const<\/span> <span style=\"color: #0000ff;\">uint8_t<\/span> aKey<span style=\"color: #008000;\">&#91;<\/span><span style=\"color: #008000;\">&#93;<\/span>,\n                                                <span style=\"color: #0000ff;\">uint16_t<\/span> aStep <span style=\"color: #008000;\">&#41;<\/span>\n  <span style=\"color: #008000;\">&#123;<\/span>\n    <span style=\"color: #0000ff;\">volatile<\/span> Node   <span style=\"color: #000040;\">*<\/span>n <span style=\"color: #000080;\">=<\/span> <span style=\"color: #0000ff;\">NULL<\/span><span style=\"color: #008080;\">;<\/span>\n&nbsp;\n    <span style=\"color: #666666;\">\/\/ get the index we're working on (re-used a few times)<\/span>\n    <span style=\"color: #0000ff;\">uint8_t<\/span>     idx <span style=\"color: #000080;\">=<\/span> aKey<span style=\"color: #008000;\">&#91;<\/span>aStep<span style=\"color: #008000;\">&#93;<\/span><span style=\"color: #008080;\">;<\/span>\n    Component   <span style=\"color: #000040;\">*<\/span>curr <span style=\"color: #000080;\">=<\/span> __sync_or_and_fetch<span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #000040;\">&amp;<\/span>kids<span style=\"color: #008000;\">&#91;<\/span>idx<span style=\"color: #008000;\">&#93;<\/span>, <span style=\"color: #208080;\">0x0<\/span><span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008080;\">;<\/span>\n    <span style=\"color: #0000ff;\">if<\/span> <span style=\"color: #008000;\">&#40;<\/span>curr <span style=\"color: #000080;\">==<\/span> <span style=\"color: #0000ff;\">NULL<\/span><span style=\"color: #008000;\">&#41;<\/span> <span style=\"color: #008000;\">&#123;<\/span>\n      <span style=\"color: #666666;\">\/\/ create a new Branch or Leaf for this part of the trie<\/span>\n      <span style=\"color: #0000ff;\">bool<\/span>    createBranch <span style=\"color: #000080;\">=<\/span> <span style=\"color: #0000ff;\">true<\/span><span style=\"color: #008080;\">;<\/span>\n      <span style=\"color: #0000ff;\">if<\/span> <span style=\"color: #008000;\">&#40;<\/span>aStep <span style=\"color: #000080;\">&lt;<\/span> eLastBranch<span style=\"color: #008000;\">&#41;<\/span> <span style=\"color: #008000;\">&#123;<\/span>\n        curr <span style=\"color: #000080;\">=<\/span> <span style=\"color: #0000dd;\">new<\/span> Branch<span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008080;\">;<\/span>\n      <span style=\"color: #008000;\">&#125;<\/span> <span style=\"color: #0000ff;\">else<\/span> <span style=\"color: #008000;\">&#123;<\/span>\n        curr <span style=\"color: #000080;\">=<\/span> <span style=\"color: #0000dd;\">new<\/span> Leaf<span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008080;\">;<\/span>\n        createBranch <span style=\"color: #000080;\">=<\/span> <span style=\"color: #0000ff;\">false<\/span><span style=\"color: #008080;\">;<\/span>\n      <span style=\"color: #008000;\">&#125;<\/span>\n      <span style=\"color: #666666;\">\/\/ throw a runtime exception if we couldn't make it<\/span>\n      <span style=\"color: #0000ff;\">if<\/span> <span style=\"color: #008000;\">&#40;<\/span>curr <span style=\"color: #000080;\">==<\/span> <span style=\"color: #0000ff;\">NULL<\/span><span style=\"color: #008000;\">&#41;<\/span> <span style=\"color: #008000;\">&#123;<\/span>\n        <span style=\"color: #0000ff;\">if<\/span> <span style=\"color: #008000;\">&#40;<\/span>createBranch<span style=\"color: #008000;\">&#41;<\/span> <span style=\"color: #008000;\">&#123;<\/span>\n          <span style=\"color: #0000ff;\">throw<\/span> std<span style=\"color: #008080;\">::<\/span><span style=\"color: #007788;\">runtime_error<\/span><span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #FF0000;\">&quot;[Branch::getOrCreateNodeForKey] &quot;<\/span>\n                   <span style=\"color: #FF0000;\">&quot;Unable to create new Branch for the trie!&quot;<\/span><span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008080;\">;<\/span>\n        <span style=\"color: #008000;\">&#125;<\/span> <span style=\"color: #0000ff;\">else<\/span> <span style=\"color: #008000;\">&#123;<\/span>\n          <span style=\"color: #0000ff;\">throw<\/span> std<span style=\"color: #008080;\">::<\/span><span style=\"color: #007788;\">runtime_error<\/span><span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #FF0000;\">&quot;[Branch::getOrCreateNodeForKey] &quot;<\/span>\n                   <span style=\"color: #FF0000;\">&quot;Unable to create new Leaf for the trie!&quot;<\/span><span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008080;\">;<\/span>\n        <span style=\"color: #008000;\">&#125;<\/span>\n      <span style=\"color: #008000;\">&#125;<\/span>\n      <span style=\"color: #666666;\">\/\/ see if we can put this new one in the right place<\/span>\n      <span style=\"color: #0000ff;\">if<\/span> <span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #000040;\">!<\/span>__sync_bool_compare_and_swap<span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #000040;\">&amp;<\/span>kids<span style=\"color: #008000;\">&#91;<\/span>idx<span style=\"color: #008000;\">&#93;<\/span>, <span style=\"color: #0000ff;\">NULL<\/span>, curr<span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008000;\">&#41;<\/span> <span style=\"color: #008000;\">&#123;<\/span>\n        <span style=\"color: #666666;\">\/\/ someone beat us to it! Delete what we just made...<\/span>\n        <span style=\"color: #0000dd;\">delete<\/span> curr<span style=\"color: #008080;\">;<\/span>\n        <span style=\"color: #666666;\">\/\/ ...and get what is there now<\/span>\n        curr <span style=\"color: #000080;\">=<\/span> __sync_or_and_fetch<span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #000040;\">&amp;<\/span>kids<span style=\"color: #008000;\">&#91;<\/span>idx<span style=\"color: #008000;\">&#93;<\/span>, <span style=\"color: #208080;\">0x0<\/span><span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008080;\">;<\/span>\n      <span style=\"color: #008000;\">&#125;<\/span>\n    <span style=\"color: #008000;\">&#125;<\/span>\n&nbsp;\n    <span style=\"color: #666666;\">\/\/ now pass down to that next branch the request to fill<\/span>\n    <span style=\"color: #0000ff;\">if<\/span> <span style=\"color: #008000;\">&#40;<\/span>curr <span style=\"color: #000040;\">!<\/span><span style=\"color: #000080;\">=<\/span> <span style=\"color: #0000ff;\">NULL<\/span><span style=\"color: #008000;\">&#41;<\/span> <span style=\"color: #008000;\">&#123;<\/span>\n      n <span style=\"color: #000080;\">=<\/span> curr<span style=\"color: #000040;\">-<\/span><span style=\"color: #000080;\">&gt;<\/span>getOrCreateNodeForKey<span style=\"color: #008000;\">&#40;<\/span>aKey, <span style=\"color: #008000;\">&#40;<\/span>aStep <span style=\"color: #000040;\">+<\/span> <span style=\"color: #0000dd;\">1<\/span><span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008080;\">;<\/span>\n    <span style=\"color: #008000;\">&#125;<\/span>\n&nbsp;\n    <span style=\"color: #666666;\">\/\/ return what we have dug out of the tree<\/span>\n    <span style=\"color: #0000ff;\">return<\/span> n<span style=\"color: #008080;\">;<\/span>\n  <span style=\"color: #008000;\">&#125;<\/span><\/pre>\n<p>This little test allows us to place the key size as a parameter to the template, and that makes it <em>very<\/em> easy to make different sized keys. For convenience, I added in the convenience methods to deal with the different sized keys from the contained values. It's not strictly necessary, but it'll make using the template class a lot nicer.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today I spent a good chunk of time writing a 64-bit key trie as the next basic component of re-writing the exchange feeds in a lot better component library than I had previously written. The purpose of the trie is to have a lockless storage mechanism that has very fast insertion and access methods. The [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,4],"tags":[],"class_list":["post-5886","post","type-post","status-publish","format-standard","hentry","category-coding","category-open-source-software"],"_links":{"self":[{"href":"https:\/\/bobbeaty.com\/wp\/wp-json\/wp\/v2\/posts\/5886","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bobbeaty.com\/wp\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bobbeaty.com\/wp\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bobbeaty.com\/wp\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bobbeaty.com\/wp\/wp-json\/wp\/v2\/comments?post=5886"}],"version-history":[{"count":2,"href":"https:\/\/bobbeaty.com\/wp\/wp-json\/wp\/v2\/posts\/5886\/revisions"}],"predecessor-version":[{"id":5888,"href":"https:\/\/bobbeaty.com\/wp\/wp-json\/wp\/v2\/posts\/5886\/revisions\/5888"}],"wp:attachment":[{"href":"https:\/\/bobbeaty.com\/wp\/wp-json\/wp\/v2\/media?parent=5886"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bobbeaty.com\/wp\/wp-json\/wp\/v2\/categories?post=5886"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bobbeaty.com\/wp\/wp-json\/wp\/v2\/tags?post=5886"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}