<figureclass="highlight plain"><table><tr><tdclass="gutter"><pre><spanclass="line">1</span><br><spanclass="line">2</span><br><spanclass="line">3</span><br><spanclass="line">4</span><br><spanclass="line">5</span><br><spanclass="line">6</span><br><spanclass="line">7</span><br><spanclass="line">8</span><br><spanclass="line">9</span><br><spanclass="line">10</span><br><spanclass="line">11</span><br><spanclass="line">12</span><br><spanclass="line">13</span><br><spanclass="line">14</span><br><spanclass="line">15</span><br><spanclass="line">16</span><br><spanclass="line">17</span><br><spanclass="line">18</span><br><spanclass="line">19</span><br><spanclass="line">20</span><br><spanclass="line">21</span><br><spanclass="line">22</span><br><spanclass="line">23</span><br><spanclass="line">24</span><br><spanclass="line">25</span><br><spanclass="line">26</span><br><spanclass="line">27</span><br><spanclass="line">28</span><br><spanclass="line">29</span><br><spanclass="line">30</span><br><spanclass="line">31</span><br><spanclass="line">32</span><br></pre></td><tdclass="code"><pre><spanclass="line">lfu-log-factor 10</span><br><spanclass="line">lfu-decay-time 1</span><br><spanclass="line">```</span><br><spanclass="line">`lfu-log-factor` 可以调整计数器counter的增长速度,lfu-log-factor越大,counter增长的越慢。</span><br><spanclass="line"></span><br><spanclass="line">`lfu-decay-time`是一个以分钟为单位的数值,可以调整counter的减少速度</span><br><spanclass="line">这里有个问题是 8 位大小够计么,访问一次加 1 的话的确不够,不过大神就是大神,才不会这么简单的加一。往下看代码</span><br><spanclass="line">```C</span><br><spanclass="line">/* Low level key lookup API, not actually called directly from commands</span><br><spanclass="line"> * implementations that should instead rely on lookupKeyRead(),</span><br><spanclass="line"> * lookupKeyWrite() and lookupKeyReadWithFlags(). */</span><br><spanclass="line">robj *lookupKey(redisDb *db, robj *key, int flags) {</span><br><spanclass="line"> dictEntry *de = dictFind(db->dict,key->ptr);</span><br><spanclass="line"> if (de) {</span><br><spanclass="line"> robj *val = dictGetVal(de);</span><br><spanclass="line"></span><br><spanclass="line">/* Update the access time for the ageing algorithm.</span><br><spanclass="line"> * Don't do it if we have a saving child, as this will trigger</span><br><spanclass="line"> * a copy on write madness. */</span><br><spanclass="line"> if (!hasActiveChildProcess() && !(flags & LOOKUP_NOTOUCH)){</span><br><spanclass="line"> if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {</span><br><spanclass="line">// 当淘汰策略是 LFU 时,就会调用这个updateLFU</span><br><spanclass="line"> updateLFU(val);</span><br><spanclass="line">} else {</span><br><spanclass="line"> val->lru = LRU_CLOCK();</span><br><spanclass="line">}</span><br><spanclass="line">}</span><br><spanclass="line"> return val;</span><br><spanclass="line">} else {</span><br><spanclass="line"> return NULL;</span><br><spanclass="line">}</span><br><spanclass="line">}</span><br></pre></td></tr></table></figure>
<figureclass="highlight c"><table><tr><tdclass="gutter"><pre><spanclass="line">1</span><br><spanclass="line">2</span><br><spanclass="line">3</span><br><spanclass="line">4</span><br><spanclass="line">5</span><br><spanclass="line">6</span><br><spanclass="line">7</span><br><spanclass="line">8</span><br></pre></td><tdclass="code"><pre><spanclass="line"><spanclass="comment">/* Update LFU when an object is accessed.</span></span><br><spanclass="line"><spanclass="comment"> * Firstly, decrement the counter if the decrement time is reached.</span></span><br><spanclass="line"><spanclass="comment"> * Then logarithmically increment the counter, and update the access time. */</span></span><br><spanclass="line"><spanclass="function"><spanclass="keyword">void</span><spanclass="title">updateLFU</span><spanclass="params">(robj *val)</span></span>{</span><br><spanclass="line"><spanclass="keyword">unsigned</span><spanclass="keyword">long</span> counter = LFUDecrAndReturn(val);</span><br><spanclass="line"> counter = LFULogIncr(counter);</span><br><spanclass="line"> val->lru = (LFUGetTimeInMinutes()<<<spanclass="number">8</span>) | counter;</span><br><spanclass="line">}</span><br></pre></td></tr></table></figure>
<figureclass="highlight c"><table><tr><tdclass="gutter"><pre><spanclass="line">1</span><br><spanclass="line">2</span><br><spanclass="line">3</span><br><spanclass="line">4</span><br><spanclass="line">5</span><br><spanclass="line">6</span><br><spanclass="line">7</span><br><spanclass="line">8</span><br><spanclass="line">9</span><br><spanclass="line">10</span><br><spanclass="line">11</span><br><spanclass="line">12</span><br><spanclass="line">13</span><br><spanclass="line">14</span><br><spanclass="line">15</span><br><spanclass="line">16</span><br><spanclass="line">17</span><br><spanclass="line">18</span><br><spanclass="line">19</span><br><spanclass="line">20</span><br><spanclass="line">21</span><br></pre></td><tdclass="code"><pre><spanclass="line"><spanclass="comment">/* If the object decrement time is reached decrement the LFU counter but</span></span><br><spanclass="line"><spanclass="comment"> * do not update LFU fields of the object, we update the access time</span></span><br><spanclass="line"><spanclass="comment"> * and counter in an explicit way when the object is really accessed.</span></span><br><spanclass="line"><spanclass="comment"> * And we will times halve the counter according to the times of</span></span><br><spanclass="line"><spanclass="comment"> * elapsed time than server.lfu_decay_time.</span></span><br><spanclass="line"><spanclass="comment"> * Return the object frequency counter.</span></span><br><spanclass="line"><spanclass="comment"> *</span></span><br><spanclass="line"><spanclass="comment"> * This function is used in order to scan the dataset for the best object</span></span><br><spanclass="line"><spanclass="comment"> * to fit: as we check for the candidate, we incrementally decrement the</span></span><br><spanclass="line"><spanclass="comment"> * counter of the scanned objects if needed. */</span></span><br><spanclass="line"><spanclass="function"><spanclass="keyword">unsigned</span><spanclass="keyword">long</span><spanclass="title">LFUDecrAndReturn</span><spanclass="params">(robj *o)</span></span>{</span><br><spanclass="line"><spanclass="comment">// 右移 8 位,拿到上次衰减时间</span></span><br><spanclass="line"><spanclass="keyword">unsigned</span><spanclass="keyword">long</span> ldt = o->lru >><spanclass="number">8</span>;</span><br><spanclass="line"><spanclass="comment">// 对 255 做与操作,拿到 counter 值</span></span><br><spanclass="line"><spanclass="keyword">unsigned</span><spanclass="keyword">long</span> counter = o->lru &<spanclass="number">255</span>;</span><br><spanclass="line"><spanclass="comment">// 根据lfu_decay_time来算出过了多少个衰减周期</span></span><br><spanclass="line"><spanclass="keyword">unsigned</span><spanclass="keyword">long</span> num_periods = server.lfu_decay_time ? LFUTimeElapsed(ldt) / server.lfu_decay_time : <spanclass="number">0</span>;</span><br><spanclass="line"><spanclass="keyword">if</span> (num_periods)</span><br><spanclass="line"> counter = (num_periods > counter) ? <spanclass="number">0</span> : counter - num_periods;</span><br><spanclass="line"><spanclass="keyword">return</span> counter;</span><br><spanclass="line">}</span><br></pre></td></tr></table></figure>
<figureclass="highlight c"><table><tr><tdclass="gutter"><pre><spanclass="line">1</span><br><spanclass="line">2</span><br><spanclass="line">3</span><br><spanclass="line">4</span><br><spanclass="line">5</span><br><spanclass="line">6</span><br><spanclass="line">7</span><br><spanclass="line">8</span><br><spanclass="line">9</span><br><spanclass="line">10</span><br><spanclass="line">11</span><br><spanclass="line">12</span><br><spanclass="line">13</span><br><spanclass="line">14</span><br><spanclass="line">15</span><br><spanclass="line">16</span><br></pre></td><tdclass="code"><pre><spanclass="line"><spanclass="comment">/* Logarithmically increment a counter. The greater is the current counter value</span></span><br><spanclass="line"><spanclass="comment"> * the less likely is that it gets really implemented. Saturate it at 255. */</span></span><br><spanclass="line"><spanclass="function"><spanclass="keyword">uint8_t</span><spanclass="title">LFULogIncr</span><spanclass="params">(<spanclass="keyword">uint8_t</span> counter)</span></span>{</span><br><spanclass="line"><spanclass="comment">// 最大值就是 255,到顶了就不加了</span></span><br><spanclass="line"><spanclass="keyword">if</span> (counter == <spanclass="number">255</span>) <spanclass="keyword">return</span><spanclass="number">255</span>;</span><br><spanclass="line"><spanclass="comment">// 生成个随机小数</span></span><br><spanclass="line"><spanclass="keyword">double</span> r = (<spanclass="keyword">double</span>)rand()/RAND_MAX;</span><br><spanclass="line"><spanclass="comment">// 减去个基础值,LFU_INIT_VAL = 5,防止刚进来就被逐出</span></span><br><spanclass="line"><spanclass="keyword">double</span> baseval = counter - LFU_INIT_VAL;</span><br><spanclass="line"><spanclass="comment">// 如果是小于 0,</span></span><br><spanclass="line"><spanclass="keyword">if</span> (baseval <<spanclass="number">0</span>) baseval = <spanclass="number">0</span>;</span><br><spanclass="line"><spanclass="comment">// 如果 baseval 是 0,那么 p 就是 1了,后面 counter 直接加一,如果不是的话,得看系统参数lfu_log_factor,这个越大,除出来的 p 越小,那么 counter++的可能性也越小,这样子就把前面的疑问给解决了,不是直接+1 的</span></span><br><spanclass="line"><spanclass="keyword">double</span> p = <spanclass="number">1.0</span>/(baseval*server.lfu_log_factor+<spanclass="number">1</span>);</span><br><spanclass="line"><spanclass="keyword">if</span> (r < p) counter++;</span><br><spanclass="line"><spanclass="keyword">return</span> counter;</span><br><spanclass="line">}</span><br></pre></td></tr></table></figure>
<figureclass="highlight plain"><table><tr><tdclass="gutter"><pre><spanclass="line">1</span><br><spanclass="line">2</span><br><spanclass="line">3</span><br><spanclass="line">4</span><br><spanclass="line">5</span><br><spanclass="line">6</span><br><spanclass="line">7</span><br><spanclass="line">8</span><br><spanclass="line">9</span><br><spanclass="line">10</span><br><spanclass="line">11</span><br><spanclass="line">12</span><br><spanclass="line">13</span><br><spanclass="line">14</span><br><spanclass="line">15</span><br><spanclass="line">16</span><br><spanclass="line">17</span><br><spanclass="line">18</span><br><spanclass="line">19</span><br><spanclass="line">20</span><br><spanclass="line">21</span><br><spanclass="line">22</span><br><spanclass="line">23</span><br><spanclass="line">24</span><br><spanclass="line">25</span><br><spanclass="line">26</span><br><spanclass="line">27</span><br><spanclass="line">28</span><br><spanclass="line">29</span><br><spanclass="line">30</span><br><spanclass="line">31</span><br><spanclass="line">32</span><br></pre></td><tdclass="code"><pre><spanclass="line">lfu-log-factor 10</span><br><spanclass="line">lfu-decay-time 1</span><br><spanclass="line">```</span><br><spanclass="line">`lfu-log-factor` 可以调整计数器counter的增长速度,lfu-log-factor越大,counter增长的越慢。</span><br><spanclass="line"></span><br><spanclass="line">`lfu-decay-time`是一个以分钟为单位的数值,可以调整counter的减少速度</span><br><spanclass="line">这里有个问题是 8 位大小够计么,访问一次加 1 的话的确不够,不过大神就是大神,才不会这么简单的加一。往下看代码</span><br><spanclass="line">```C</span><br><spanclass="line">/* Low level key lookup API, not actually called directly from commands</span><br><spanclass="line"> * implementations that should instead rely on lookupKeyRead(),</span><br><spanclass="line"> * lookupKeyWrite() and lookupKeyReadWithFlags(). */</span><br><spanclass="line">robj *lookupKey(redisDb *db, robj *key, int flags) {</span><br><spanclass="line"> dictEntry *de = dictFind(db->dict,key->ptr);</span><br><spanclass="line"> if (de) {</span><br><spanclass="line"> robj *val = dictGetVal(de);</span><br><spanclass="line"></span><br><spanclass="line">/* Update the access time for the ageing algorithm.</span><br><spanclass="line"> * Don't do it if we have a saving child, as this will trigger</span><br><spanclass="line"> * a copy on write madness. */</span><br><spanclass="line"> if (!hasActiveChildProcess() && !(flags & LOOKUP_NOTOUCH)){</span><br><spanclass="line"> if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {</span><br><spanclass="line">// 当淘汰策略是 LFU 时,就会调用这个updateLFU</span><br><spanclass="line"> updateLFU(val);</span><br><spanclass="line">} else {</span><br><spanclass="line"> val->lru = LRU_CLOCK();</span><br><spanclass="line">}</span><br><spanclass="line">}</span><br><spanclass="line"> return val;</span><br><spanclass="line">} else {</span><br><spanclass="line"> return NULL;</span><br><spanclass="line">}</span><br><spanclass="line">}</span><br></pre></td></tr></table></figure>
<figureclass="highlight c"><table><tr><tdclass="gutter"><pre><spanclass="line">1</span><br><spanclass="line">2</span><br><spanclass="line">3</span><br><spanclass="line">4</span><br><spanclass="line">5</span><br><spanclass="line">6</span><br><spanclass="line">7</span><br><spanclass="line">8</span><br></pre></td><tdclass="code"><pre><spanclass="line"><spanclass="comment">/* Update LFU when an object is accessed.</span></span><br><spanclass="line"><spanclass="comment"> * Firstly, decrement the counter if the decrement time is reached.</span></span><br><spanclass="line"><spanclass="comment"> * Then logarithmically increment the counter, and update the access time. */</span></span><br><spanclass="line"><spanclass="function"><spanclass="keyword">void</span><spanclass="title">updateLFU</span><spanclass="params">(robj *val)</span></span>{</span><br><spanclass="line"><spanclass="keyword">unsigned</span><spanclass="keyword">long</span> counter = LFUDecrAndReturn(val);</span><br><spanclass="line"> counter = LFULogIncr(counter);</span><br><spanclass="line"> val->lru = (LFUGetTimeInMinutes()<<<spanclass="number">8</span>) | counter;</span><br><spanclass="line">}</span><br></pre></td></tr></table></figure>
<figureclass="highlight c"><table><tr><tdclass="gutter"><pre><spanclass="line">1</span><br><spanclass="line">2</span><br><spanclass="line">3</span><br><spanclass="line">4</span><br><spanclass="line">5</span><br><spanclass="line">6</span><br><spanclass="line">7</span><br><spanclass="line">8</span><br><spanclass="line">9</span><br><spanclass="line">10</span><br><spanclass="line">11</span><br><spanclass="line">12</span><br><spanclass="line">13</span><br><spanclass="line">14</span><br><spanclass="line">15</span><br><spanclass="line">16</span><br><spanclass="line">17</span><br><spanclass="line">18</span><br><spanclass="line">19</span><br><spanclass="line">20</span><br><spanclass="line">21</span><br></pre></td><tdclass="code"><pre><spanclass="line"><spanclass="comment">/* If the object decrement time is reached decrement the LFU counter but</span></span><br><spanclass="line"><spanclass="comment"> * do not update LFU fields of the object, we update the access time</span></span><br><spanclass="line"><spanclass="comment"> * and counter in an explicit way when the object is really accessed.</span></span><br><spanclass="line"><spanclass="comment"> * And we will times halve the counter according to the times of</span></span><br><spanclass="line"><spanclass="comment"> * elapsed time than server.lfu_decay_time.</span></span><br><spanclass="line"><spanclass="comment"> * Return the object frequency counter.</span></span><br><spanclass="line"><spanclass="comment"> *</span></span><br><spanclass="line"><spanclass="comment"> * This function is used in order to scan the dataset for the best object</span></span><br><spanclass="line"><spanclass="comment"> * to fit: as we check for the candidate, we incrementally decrement the</span></span><br><spanclass="line"><spanclass="comment"> * counter of the scanned objects if needed. */</span></span><br><spanclass="line"><spanclass="function"><spanclass="keyword">unsigned</span><spanclass="keyword">long</span><spanclass="title">LFUDecrAndReturn</span><spanclass="params">(robj *o)</span></span>{</span><br><spanclass="line"><spanclass="comment">// 右移 8 位,拿到上次衰减时间</span></span><br><spanclass="line"><spanclass="keyword">unsigned</span><spanclass="keyword">long</span> ldt = o->lru >><spanclass="number">8</span>;</span><br><spanclass="line"><spanclass="comment">// 对 255 做与操作,拿到 counter 值</span></span><br><spanclass="line"><spanclass="keyword">unsigned</span><spanclass="keyword">long</span> counter = o->lru &<spanclass="number">255</span>;</span><br><spanclass="line"><spanclass="comment">// 根据lfu_decay_time来算出过了多少个衰减周期</span></span><br><spanclass="line"><spanclass="keyword">unsigned</span><spanclass="keyword">long</span> num_periods = server.lfu_decay_time ? LFUTimeElapsed(ldt) / server.lfu_decay_time : <spanclass="number">0</span>;</span><br><spanclass="line"><spanclass="keyword">if</span> (num_periods)</span><br><spanclass="line"> counter = (num_periods > counter) ? <spanclass="number">0</span> : counter - num_periods;</span><br><spanclass="line"><spanclass="keyword">return</span> counter;</span><br><spanclass="line">}</span><br></pre></td></tr></table></figure>
<figureclass="highlight c"><table><tr><tdclass="gutter"><pre><spanclass="line">1</span><br><spanclass="line">2</span><br><spanclass="line">3</span><br><spanclass="line">4</span><br><spanclass="line">5</span><br><spanclass="line">6</span><br><spanclass="line">7</span><br><spanclass="line">8</span><br><spanclass="line">9</span><br><spanclass="line">10</span><br><spanclass="line">11</span><br><spanclass="line">12</span><br><spanclass="line">13</span><br><spanclass="line">14</span><br><spanclass="line">15</span><br><spanclass="line">16</span><br></pre></td><tdclass="code"><pre><spanclass="line"><spanclass="comment">/* Logarithmically increment a counter. The greater is the current counter value</span></span><br><spanclass="line"><spanclass="comment"> * the less likely is that it gets really implemented. Saturate it at 255. */</span></span><br><spanclass="line"><spanclass="function"><spanclass="keyword">uint8_t</span><spanclass="title">LFULogIncr</span><spanclass="params">(<spanclass="keyword">uint8_t</span> counter)</span></span>{</span><br><spanclass="line"><spanclass="comment">// 最大值就是 255,到顶了就不加了</span></span><br><spanclass="line"><spanclass="keyword">if</span> (counter == <spanclass="number">255</span>) <spanclass="keyword">return</span><spanclass="number">255</span>;</span><br><spanclass="line"><spanclass="comment">// 生成个随机小数</span></span><br><spanclass="line"><spanclass="keyword">double</span> r = (<spanclass="keyword">double</span>)rand()/RAND_MAX;</span><br><spanclass="line"><spanclass="comment">// 减去个基础值,LFU_INIT_VAL = 5,防止刚进来就被逐出</span></span><br><spanclass="line"><spanclass="keyword">double</span> baseval = counter - LFU_INIT_VAL;</span><br><spanclass="line"><spanclass="comment">// 如果是小于 0,</span></span><br><spanclass="line"><spanclass="keyword">if</span> (baseval <<spanclass="number">0</span>) baseval = <spanclass="number">0</span>;</span><br><spanclass="line"><spanclass="comment">// 如果 baseval 是 0,那么 p 就是 1了,后面 counter 直接加一,如果不是的话,得看系统参数lfu_log_factor,这个越大,除出来的 p 越小,那么 counter++的可能性也越小,这样子就把前面的疑问给解决了,不是直接+1 的</span></span><br><spanclass="line"><spanclass="keyword">double</span> p = <spanclass="number">1.0</span>/(baseval*server.lfu_log_factor+<spanclass="number">1</span>);</span><br><spanclass="line"><spanclass="keyword">if</span> (r < p) counter++;</span><br><spanclass="line"><spanclass="keyword">return</span> counter;</span><br><spanclass="line">}</span><br></pre></td></tr></table></figure>