FreeBSD/contrib/subversion/subversion/libsvn_subr/cache-membuffer.c
/* This function implements the cache insertion / eviction strategy for L2.
 *
 * If necessary, enlarge the insertion window of CACHE->L2 until it is at
 * least TO_FIT_IN->SIZE bytes long. TO_FIT_IN->SIZE must not exceed the
 * data buffer size allocated to CACHE->L2.  IDX is the item index of
 * TO_FIT_IN and is given for performance reasons.
 *
 * Return TRUE if enough room could be found or made.  A FALSE result
 * indicates that the respective item shall not be added.
 */
This function implements the cache insertion / eviction strategy for L2.
If necessary, enlarge the insertion window of CACHE->L2 until it is at
least TO_FIT_IN->SIZE bytes long. TO_FIT_IN->SIZE must not exceed the
data buffer size allocated to CACHE->L2.  IDX is the item index of
TO_FIT_IN and is given for performance reasons.

Return TRUE if enough room could be found or made.  A FALSE result
indicates that the respective item shall not be added.
This function implements the cache insertion / eviction strategy for L2 . If necessary enlarge the insertion window of CACHE - > L2 until it is at least TO_FIT_IN - > SIZE bytes long . TO_FIT_IN - > SIZE must not exceed the data buffer size allocated to CACHE - > L2 . IDX is the item index of TO_FIT_IN and is given for performance reasons . Return TRUE if enough room could be found or made . A FALSE result indicates that the respective item shall not be added .
static svn_boolean_t
ensure_data_insertable_l2(svn_membuffer_t *cache,
                          entry_t *to_fit_in)
{
  entry_t *entry;
  apr_size_t moved_size = 0;
  apr_size_t moved_count = 0;
  apr_uint64_t drop_hits = 0;
  apr_uint64_t drop_hits_limit = (to_fit_in->hit_count + 1)
                               * (apr_uint64_t)to_fit_in->priority;
  while (1)
    {
      apr_uint64_t end = cache->l2.next == NO_INDEX
                       ? cache->l2.start_offset + cache->l2.size
                       : get_entry(cache, cache->l2.next)->offset;
      if (end >= to_fit_in->size + cache->l2.current_data)
        return TRUE;
      if (moved_size > 4 * to_fit_in->size && moved_count > 7)
        return FALSE;
      if (drop_hits > drop_hits_limit)
        return FALSE;
      if (cache->l2.next == NO_INDEX)
        {
          cache->l2.current_data = cache->l2.start_offset;
          cache->l2.next = cache->l2.first;
        }
      else
        {
          svn_boolean_t keep;
          entry = get_entry(cache, cache->l2.next);
          if (to_fit_in->priority < SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY)
            {
              if (   entry->priority > to_fit_in->priority
                  || entry->hit_count > to_fit_in->hit_count)
                return FALSE;
            }
          if (entry->priority <= SVN_CACHE__MEMBUFFER_LOW_PRIORITY)
            {
              keep = FALSE;
            }
          else
            {
              keep = to_fit_in->priority == entry->priority
                   ? entry->hit_count >= to_fit_in->hit_count
                   : entry->priority > to_fit_in->priority;
            }
          if (keep)
            {
              moved_size += entry->size;
              moved_count++;
              move_entry(cache, entry);
            }
          else
            {
              if (entry->priority > SVN_CACHE__MEMBUFFER_LOW_PRIORITY)
                drop_hits += entry->hit_count * (apr_uint64_t)entry->priority;
              drop_entry(cache, entry);
            }
        }
    }
}
static svn_boolean_t ensure_data_insertable_l2 ( svn_membuffer_t * cache , entry_t * to_fit_in ) { entry_t * entry ; apr_size_t moved_size = 0 ; apr_size_t moved_count = 0 ; apr_uint64_t drop_hits = 0 ; apr_uint64_t drop_hits_limit = ( to_fit_in -> hit_count + 1 ) * ( apr_uint64_t ) to_fit_in -> priority ; while ( 1 ) { apr_uint64_t end = cache -> l2 . next == NO_INDEX ? cache -> l2 . start_offset + cache -> l2 . size : get_entry ( cache , cache -> l2 . next ) -> offset ; if ( end >= to_fit_in -> size + cache -> l2 . current_data ) return TRUE ; if ( moved_size > 4 * to_fit_in -> size && moved_count > 7 ) return FALSE ; if ( drop_hits > drop_hits_limit ) return FALSE ; if ( cache -> l2 . next == NO_INDEX ) { cache -> l2 . current_data = cache -> l2 . start_offset ; cache -> l2 . next = cache -> l2 . first ; } else { svn_boolean_t keep ; entry = get_entry ( cache , cache -> l2 . next ) ; if ( to_fit_in -> priority < SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY ) { if ( entry -> priority > to_fit_in -> priority || entry -> hit_count > to_fit_in -> hit_count ) return FALSE ; } if ( entry -> priority <= SVN_CACHE__MEMBUFFER_LOW_PRIORITY ) { keep = FALSE ; } else { keep = to_fit_in -> priority == entry -> priority ? entry -> hit_count >= to_fit_in -> hit_count : entry -> priority > to_fit_in -> priority ; } if ( keep ) { moved_size += entry -> size ; moved_count ++ ; move_entry ( cache , entry ) ; } else { if ( entry -> priority > SVN_CACHE__MEMBUFFER_LOW_PRIORITY ) drop_hits += entry -> hit_count * ( apr_uint64_t ) entry -> priority ; drop_entry ( cache , entry ) ; } } } }
This function implements the cache insertion / eviction strategy for L2.
This function implements the cache insertion / eviction strategy for L2 .
/* accumulated size of the entries that have been removed to make
   * room for the new one.
   */ /* count the number of entries that got moved.  A single large entry
   * being moved is not enough to reject an insertion.
   */ /* accumulated "worth" of items dropped so far */ /* estimated "worth" of the new entry */ /* This loop will eventually terminate because every cache entry
   * would get dropped eventually:
   *
   * - the incoming entry is small enough to fit into L2
   * - every iteration either frees parts of L2 or counts the moved size
   * - eventually, we either moved too many items with too much total size
   *   to accept the new entry, or made enough room in L2 for the new entry
   *
   * Low-prio items get rejected even sooner.
   */ /* first offset behind the insertion window
       */ /* leave function as soon as the insertion window is large enough
       */ /* Don't be too eager to cache data.  If a lot of data has been moved
       * around, the current item has probably a relatively low priority.
       * We must also limit the effort spent here (if even in case of faulty
       * heuristics).  Therefore, give up after some time.
       */ /* if the net worth (in weighted hits) of items removed is already
       * larger than what we want to insert, reject TO_FIT_IN because it
       * still does not fit in. */ /* try to enlarge the insertion window
       */ /* We reached the end of the data buffer; restart at the beginning.
           * Due to the randomized nature of our LFU implementation, very
           * large data items may require multiple passes. Therefore, SIZE
           * should be restricted to significantly less than data_size.
           */ /* Low prio items can only be accepted only if the current
               * entry is of even lower prio and has fewer hits.
               */ /* Be quick to remove low-prio entries - even if the incoming
               * one is low-prio as well.  This makes room for more important
               * data and replaces existing data with newly read information.
               */ /* If the existing data is the same prio as the incoming data,
               * drop the existing entry if it had seen fewer (probably 0)
               * hits than the entry coming in from L1.  In case of different
               * priorities, keep the current entry of it has higher prio.
               * The new entry may still find room by ousting other entries.
               */ /* keepers or destroyers? */ /* Moving entries around is not for free -> track costs. */ /* Drop the entry from the end of the insertion window.
               * Count the "hit importance" such that we are not sacrificing
               * too much of the high-hit contents.  However, don't count
               * low-priority hits because higher prio entries will often
               * provide the same data but in a further stage of processing.
               */ /* This will never be reached. But if it was, "can't insert" was the
   * right answer. */