config root man

Current Path : /usr/src/usr.sbin/nscd/

FreeBSD hs32.drive.ne.jp 9.1-RELEASE FreeBSD 9.1-RELEASE #1: Wed Jan 14 12:18:08 JST 2015 root@hs32.drive.ne.jp:/sys/amd64/compile/hs32 amd64
Upload File :
Current File : //usr/src/usr.sbin/nscd/cacheplcs.c

/*-
 * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD: release/9.1.0/usr.sbin/nscd/cacheplcs.c 194104 2009-06-13 13:07:56Z des $");

#include <sys/time.h>

#include <assert.h>
#include <stdlib.h>
#include <string.h>

#include "cacheplcs.h"
#include "debug.h"

static void cache_fifo_policy_update_item(struct cache_policy_ *,
	struct cache_policy_item_ *);
static void cache_lfu_policy_add_item(struct cache_policy_ *,
	struct cache_policy_item_ *);
static struct cache_policy_item_ * cache_lfu_policy_create_item(void);
static void cache_lfu_policy_destroy_item(struct cache_policy_item_ *);
static struct cache_policy_item_ *cache_lfu_policy_get_first_item(
	struct cache_policy_ *);
static struct cache_policy_item_ *cache_lfu_policy_get_last_item(
	struct cache_policy_ *);
static struct cache_policy_item_ *cache_lfu_policy_get_next_item(
	struct cache_policy_ *, struct cache_policy_item_ *);
static struct cache_policy_item_ *cache_lfu_policy_get_prev_item(
	struct cache_policy_ *, struct cache_policy_item_ *);
static void cache_lfu_policy_remove_item(struct cache_policy_ *,
	struct cache_policy_item_ *);
static void cache_lfu_policy_update_item(struct cache_policy_ *,
	struct cache_policy_item_ *);
static void cache_lru_policy_update_item(struct cache_policy_ *,
	struct cache_policy_item_ *);
static void cache_queue_policy_add_item(struct cache_policy_ *,
	struct cache_policy_item_ *);
static struct cache_policy_item_ * cache_queue_policy_create_item(void);
static void cache_queue_policy_destroy_item(struct cache_policy_item_ *);
static struct cache_policy_item_ *cache_queue_policy_get_first_item(
	struct cache_policy_ *);
static struct cache_policy_item_ *cache_queue_policy_get_last_item(
	struct cache_policy_ *);
static struct cache_policy_item_ *cache_queue_policy_get_next_item(
	struct cache_policy_ *, struct cache_policy_item_ *);
static struct cache_policy_item_ *cache_queue_policy_get_prev_item(
	struct cache_policy_ *, struct cache_policy_item_ *);
static void cache_queue_policy_remove_item(struct cache_policy_ *,
	struct cache_policy_item_ *);
static void destroy_cache_queue_policy(struct cache_queue_policy_ *);
static struct cache_queue_policy_ *init_cache_queue_policy(void);

/*
 * All cache_queue_policy_XXX functions below will be used to fill
 * the cache_queue_policy structure. They implement the most functionality of
 * LRU and FIFO policies. LRU and FIFO policies are actually the
 * cache_queue_policy_ with cache_update_item function changed.
 */
static struct cache_policy_item_ *
cache_queue_policy_create_item(void)
{
	struct cache_queue_policy_item_ *retval;

	TRACE_IN(cache_queue_policy_create_item);
	retval = calloc(1,
		sizeof(*retval));
	assert(retval != NULL);

	TRACE_OUT(cache_queue_policy_create_item);
	return ((struct cache_policy_item_ *)retval);
}

static void
cache_queue_policy_destroy_item(struct cache_policy_item_ *item)
{

	TRACE_IN(cache_queue_policy_destroy_item);
	assert(item != NULL);
	free(item);
	TRACE_OUT(cache_queue_policy_destroy_item);
}

static void
cache_queue_policy_add_item(struct cache_policy_ *policy,
	struct cache_policy_item_ *item)
{
	struct cache_queue_policy_ *queue_policy;
	struct cache_queue_policy_item_ *queue_item;

	TRACE_IN(cache_queue_policy_add_item);
	queue_policy = (struct cache_queue_policy_ *)policy;
	queue_item = (struct cache_queue_policy_item_ *)item;
	TAILQ_INSERT_TAIL(&queue_policy->head, queue_item, entries);
	TRACE_OUT(cache_queue_policy_add_item);
}

static void
cache_queue_policy_remove_item(struct cache_policy_ *policy,
	struct cache_policy_item_ *item)
{
	struct cache_queue_policy_ *queue_policy;
	struct cache_queue_policy_item_	*queue_item;

	TRACE_IN(cache_queue_policy_remove_item);
	queue_policy = (struct cache_queue_policy_ *)policy;
	queue_item = (struct cache_queue_policy_item_ *)item;
	TAILQ_REMOVE(&queue_policy->head, queue_item, entries);
	TRACE_OUT(cache_queue_policy_remove_item);
}

static struct cache_policy_item_ *
cache_queue_policy_get_first_item(struct cache_policy_ *policy)
{
	struct cache_queue_policy_ *queue_policy;

	TRACE_IN(cache_queue_policy_get_first_item);
	queue_policy = (struct cache_queue_policy_ *)policy;
	TRACE_OUT(cache_queue_policy_get_first_item);
	return ((struct cache_policy_item_ *)TAILQ_FIRST(&queue_policy->head));
}

static struct cache_policy_item_ *
cache_queue_policy_get_last_item(struct cache_policy_ *policy)
{
	struct cache_queue_policy_ *queue_policy;

	TRACE_IN(cache_queue_policy_get_last_item);
	queue_policy = (struct cache_queue_policy_ *)policy;
	TRACE_OUT(cache_queue_policy_get_last_item);
	return ((struct cache_policy_item_ *)TAILQ_LAST(&queue_policy->head,
		cache_queue_policy_head_));
}

static struct cache_policy_item_ *
cache_queue_policy_get_next_item(struct cache_policy_ *policy,
	struct cache_policy_item_ *item)
{
	struct cache_queue_policy_ *queue_policy;
	struct cache_queue_policy_item_	*queue_item;

	TRACE_IN(cache_queue_policy_get_next_item);
	queue_policy = (struct cache_queue_policy_ *)policy;
	queue_item = (struct cache_queue_policy_item_ *)item;

	TRACE_OUT(cache_queue_policy_get_next_item);
	return ((struct cache_policy_item_ *)TAILQ_NEXT(queue_item, entries));
}

static struct cache_policy_item_ *
cache_queue_policy_get_prev_item(struct cache_policy_ *policy,
	struct cache_policy_item_ *item)
{
	struct cache_queue_policy_ *queue_policy;
	struct cache_queue_policy_item_	*queue_item;

	TRACE_IN(cache_queue_policy_get_prev_item);
	queue_policy = (struct cache_queue_policy_ *)policy;
	queue_item = (struct cache_queue_policy_item_ *)item;

	TRACE_OUT(cache_queue_policy_get_prev_item);
	return ((struct cache_policy_item_ *)TAILQ_PREV(queue_item,
		cache_queue_policy_head_, entries));
}

/*
 * Initializes cache_queue_policy_ by filling the structure with the functions
 * pointers, defined above
 */
static struct cache_queue_policy_ *
init_cache_queue_policy(void)
{
	struct cache_queue_policy_	*retval;

	TRACE_IN(init_cache_queue_policy);
	retval = calloc(1,
		sizeof(*retval));
	assert(retval != NULL);

	retval->parent_data.create_item_func = cache_queue_policy_create_item;
	retval->parent_data.destroy_item_func = cache_queue_policy_destroy_item;

	retval->parent_data.add_item_func = cache_queue_policy_add_item;
	retval->parent_data.remove_item_func = cache_queue_policy_remove_item;

	retval->parent_data.get_first_item_func =
		cache_queue_policy_get_first_item;
	retval->parent_data.get_last_item_func =
		cache_queue_policy_get_last_item;
	retval->parent_data.get_next_item_func =
		cache_queue_policy_get_next_item;
	retval->parent_data.get_prev_item_func =
		cache_queue_policy_get_prev_item;

	TAILQ_INIT(&retval->head);
	TRACE_OUT(init_cache_queue_policy);
	return (retval);
}

static void
destroy_cache_queue_policy(struct cache_queue_policy_ *queue_policy)
{
	struct cache_queue_policy_item_	*queue_item;

	TRACE_IN(destroy_cache_queue_policy);
	while (!TAILQ_EMPTY(&queue_policy->head)) {
		queue_item = TAILQ_FIRST(&queue_policy->head);
		TAILQ_REMOVE(&queue_policy->head, queue_item, entries);
		cache_queue_policy_destroy_item(
			(struct cache_policy_item_ *)queue_item);
	}
	free(queue_policy);
	TRACE_OUT(destroy_cache_queue_policy);
}

/*
 * Makes cache_queue_policy_ behave like FIFO policy - we don't do anything,
 * when the cache element is updated. So it always stays in its initial
 * position in the queue - that is exactly the FIFO functionality.
 */
static void
cache_fifo_policy_update_item(struct cache_policy_ *policy,
	struct cache_policy_item_ *item)
{

	TRACE_IN(cache_fifo_policy_update_item);
	/* policy and item arguments are ignored */
	TRACE_OUT(cache_fifo_policy_update_item);
}

struct cache_policy_ *
init_cache_fifo_policy(void)
{
	struct cache_queue_policy_ *retval;

	TRACE_IN(init_cache_fifo_policy);
	retval = init_cache_queue_policy();
	retval->parent_data.update_item_func = cache_fifo_policy_update_item;

	TRACE_OUT(init_cache_fifo_policy);
	return ((struct cache_policy_ *)retval);
}

void
destroy_cache_fifo_policy(struct cache_policy_ *policy)
{
	struct cache_queue_policy_	*queue_policy;

	TRACE_IN(destroy_cache_fifo_policy);
	queue_policy = (struct cache_queue_policy_ *)policy;
	destroy_cache_queue_policy(queue_policy);
	TRACE_OUT(destroy_cache_fifo_policy);
}

/*
 * Makes cache_queue_policy_ behave like LRU policy. On each update, cache
 * element is moved to the end of the queue - so it would be deleted in last
 * turn. That is exactly the LRU policy functionality.
 */
static void
cache_lru_policy_update_item(struct cache_policy_ *policy,
	struct cache_policy_item_ *item)
{
	struct cache_queue_policy_ *queue_policy;
	struct cache_queue_policy_item_ *queue_item;

	TRACE_IN(cache_lru_policy_update_item);
	queue_policy = (struct cache_queue_policy_ *)policy;
	queue_item = (struct cache_queue_policy_item_ *)item;

	TAILQ_REMOVE(&queue_policy->head, queue_item, entries);
	TAILQ_INSERT_TAIL(&queue_policy->head, queue_item, entries);
	TRACE_OUT(cache_lru_policy_update_item);
}

struct cache_policy_ *
init_cache_lru_policy(void)
{
	struct cache_queue_policy_ *retval;

	TRACE_IN(init_cache_lru_policy);
	retval = init_cache_queue_policy();
	retval->parent_data.update_item_func = cache_lru_policy_update_item;

	TRACE_OUT(init_cache_lru_policy);
	return ((struct cache_policy_ *)retval);
}

void
destroy_cache_lru_policy(struct cache_policy_ *policy)
{
	struct cache_queue_policy_	*queue_policy;

	TRACE_IN(destroy_cache_lru_policy);
	queue_policy = (struct cache_queue_policy_ *)policy;
	destroy_cache_queue_policy(queue_policy);
	TRACE_OUT(destroy_cache_lru_policy);
}

/*
 * LFU (least frequently used) policy implementation differs much from the
 * LRU and FIFO (both based on cache_queue_policy_). Almost all cache_policy_
 * functions are implemented specifically for this policy. The idea of this
 * policy is to represent frequency (real number) as the integer number and
 * use it as the index in the array. Each array's element is
 * the list of elements. For example, if we have the 100-elements
 * array for this policy, the elements with frequency 0.1 (calls per-second)
 * would be in 10th element of the array.
 */
static struct cache_policy_item_ *
cache_lfu_policy_create_item(void)
{
	struct cache_lfu_policy_item_ *retval;

	TRACE_IN(cache_lfu_policy_create_item);
	retval = calloc(1,
		sizeof(*retval));
	assert(retval != NULL);

	TRACE_OUT(cache_lfu_policy_create_item);
	return ((struct cache_policy_item_ *)retval);
}

static void
cache_lfu_policy_destroy_item(struct cache_policy_item_ *item)
{

	TRACE_IN(cache_lfu_policy_destroy_item);
	assert(item != NULL);
	free(item);
	TRACE_OUT(cache_lfu_policy_destroy_item);
}

/*
 * When placed in the LFU policy queue for the first time, the maximum
 * frequency is assigned to the element
 */
static void
cache_lfu_policy_add_item(struct cache_policy_ *policy,
	struct cache_policy_item_ *item)
{
	struct cache_lfu_policy_ *lfu_policy;
	struct cache_lfu_policy_item_ *lfu_item;

	TRACE_IN(cache_lfu_policy_add_item);
	lfu_policy = (struct cache_lfu_policy_ *)policy;
	lfu_item = (struct cache_lfu_policy_item_ *)item;

	lfu_item->frequency = CACHELIB_MAX_FREQUENCY - 1;
	TAILQ_INSERT_HEAD(&(lfu_policy->groups[CACHELIB_MAX_FREQUENCY - 1]),
		lfu_item, entries);
	TRACE_OUT(cache_lfu_policy_add_item);
}

/*
 * On each update the frequency of the element is recalculated and, if it
 * changed, the element would be moved to the another place in the array.
 */
static void
cache_lfu_policy_update_item(struct cache_policy_ *policy,
	struct cache_policy_item_ *item)
{
	struct cache_lfu_policy_ *lfu_policy;
	struct cache_lfu_policy_item_ *lfu_item;
	int index;

	TRACE_IN(cache_lfu_policy_update_item);
	lfu_policy = (struct cache_lfu_policy_ *)policy;
	lfu_item = (struct cache_lfu_policy_item_ *)item;

	/*
	 * We calculate the square of the request_count to avoid grouping of
	 * all elements at the start of the array (for example, if array size is
	 * 100 and most of its elements has frequency below the 0.01, they
	 * all would be grouped in the first array's position). Other
	 * techniques should be used here later to ensure, that elements are
	 * equally distributed  in the array and not grouped in its beginning.
	 */
	if (lfu_item->parent_data.last_request_time.tv_sec !=
		lfu_item->parent_data.creation_time.tv_sec) {
		index = ((double)lfu_item->parent_data.request_count *
			(double)lfu_item->parent_data.request_count /
			(lfu_item->parent_data.last_request_time.tv_sec -
			    lfu_item->parent_data.creation_time.tv_sec + 1)) *
			    CACHELIB_MAX_FREQUENCY;
		if (index >= CACHELIB_MAX_FREQUENCY)
			index = CACHELIB_MAX_FREQUENCY - 1;
	} else
		index = CACHELIB_MAX_FREQUENCY - 1;

	TAILQ_REMOVE(&(lfu_policy->groups[lfu_item->frequency]), lfu_item,
		entries);
	lfu_item->frequency = index;
	TAILQ_INSERT_HEAD(&(lfu_policy->groups[index]), lfu_item, entries);

	TRACE_OUT(cache_lfu_policy_update_item);
}

static void
cache_lfu_policy_remove_item(struct cache_policy_ *policy,
	struct cache_policy_item_ *item)
{
	struct cache_lfu_policy_ *lfu_policy;
	struct cache_lfu_policy_item_ *lfu_item;

	TRACE_IN(cache_lfu_policy_remove_item);
	lfu_policy = (struct cache_lfu_policy_ *)policy;
	lfu_item = (struct cache_lfu_policy_item_ *)item;

	TAILQ_REMOVE(&(lfu_policy->groups[lfu_item->frequency]), lfu_item,
		entries);
	TRACE_OUT(cache_lfu_policy_remove_item);
}

static struct cache_policy_item_ *
cache_lfu_policy_get_first_item(struct cache_policy_ *policy)
{
	struct cache_lfu_policy_ *lfu_policy;
	struct cache_lfu_policy_item_ *lfu_item;
	int i;

	TRACE_IN(cache_lfu_policy_get_first_item);
	lfu_item = NULL;
	lfu_policy = (struct cache_lfu_policy_ *)policy;
	for (i = 0; i < CACHELIB_MAX_FREQUENCY; ++i)
		if (!TAILQ_EMPTY(&(lfu_policy->groups[i]))) {
			lfu_item = TAILQ_FIRST(&(lfu_policy->groups[i]));
			break;
		}

	TRACE_OUT(cache_lfu_policy_get_first_item);
	return ((struct cache_policy_item_ *)lfu_item);
}

static struct cache_policy_item_ *
cache_lfu_policy_get_last_item(struct cache_policy_ *policy)
{
	struct cache_lfu_policy_ *lfu_policy;
	struct cache_lfu_policy_item_ *lfu_item;
	int i;

	TRACE_IN(cache_lfu_policy_get_last_item);
	lfu_item = NULL;
	lfu_policy = (struct cache_lfu_policy_ *)policy;
	for (i = CACHELIB_MAX_FREQUENCY - 1; i >= 0; --i)
		if (!TAILQ_EMPTY(&(lfu_policy->groups[i]))) {
			lfu_item = TAILQ_LAST(&(lfu_policy->groups[i]),
				cache_lfu_policy_group_);
			break;
		}

	TRACE_OUT(cache_lfu_policy_get_last_item);
	return ((struct cache_policy_item_ *)lfu_item);
}

static struct cache_policy_item_ *
cache_lfu_policy_get_next_item(struct cache_policy_ *policy,
	struct cache_policy_item_ *item)
{
	struct cache_lfu_policy_ *lfu_policy;
	struct cache_lfu_policy_item_ *lfu_item;
	int i;

	TRACE_IN(cache_lfu_policy_get_next_item);
	lfu_policy = (struct cache_lfu_policy_ *)policy;
	lfu_item = TAILQ_NEXT((struct cache_lfu_policy_item_ *)item, entries);
	if (lfu_item == NULL)
	{
		for (i = ((struct cache_lfu_policy_item_ *)item)->frequency + 1;
			i < CACHELIB_MAX_FREQUENCY; ++i) {
			if (!TAILQ_EMPTY(&(lfu_policy->groups[i]))) {
			    lfu_item = TAILQ_FIRST(&(lfu_policy->groups[i]));
			    break;
			}
		}
	}

	TRACE_OUT(cache_lfu_policy_get_next_item);
	return ((struct cache_policy_item_ *)lfu_item);
}

static struct cache_policy_item_ *
cache_lfu_policy_get_prev_item(struct cache_policy_ *policy,
	struct cache_policy_item_ *item)
{
	struct cache_lfu_policy_ *lfu_policy;
	struct cache_lfu_policy_item_ *lfu_item;
	int i;

	TRACE_IN(cache_lfu_policy_get_prev_item);
	lfu_policy = (struct cache_lfu_policy_ *)policy;
	lfu_item = TAILQ_PREV((struct cache_lfu_policy_item_ *)item,
		cache_lfu_policy_group_, entries);
	if (lfu_item == NULL)
	{
		for (i = ((struct cache_lfu_policy_item_ *)item)->frequency - 1;
			i >= 0; --i)
			if (!TAILQ_EMPTY(&(lfu_policy->groups[i]))) {
				lfu_item = TAILQ_LAST(&(lfu_policy->groups[i]),
					cache_lfu_policy_group_);
				break;
		}
	}

	TRACE_OUT(cache_lfu_policy_get_prev_item);
	return ((struct cache_policy_item_ *)lfu_item);
}

/*
 * Initializes the cache_policy_ structure by filling it with appropriate
 * functions pointers
 */
struct cache_policy_ *
init_cache_lfu_policy(void)
{
	int i;
	struct cache_lfu_policy_ *retval;

	TRACE_IN(init_cache_lfu_policy);
	retval = calloc(1,
		sizeof(*retval));
	assert(retval != NULL);

	retval->parent_data.create_item_func = cache_lfu_policy_create_item;
	retval->parent_data.destroy_item_func = cache_lfu_policy_destroy_item;

	retval->parent_data.add_item_func = cache_lfu_policy_add_item;
	retval->parent_data.update_item_func = cache_lfu_policy_update_item;
	retval->parent_data.remove_item_func = cache_lfu_policy_remove_item;

	retval->parent_data.get_first_item_func =
		cache_lfu_policy_get_first_item;
	retval->parent_data.get_last_item_func =
		cache_lfu_policy_get_last_item;
	retval->parent_data.get_next_item_func =
		cache_lfu_policy_get_next_item;
	retval->parent_data.get_prev_item_func =
		cache_lfu_policy_get_prev_item;

	for (i = 0; i < CACHELIB_MAX_FREQUENCY; ++i)
		TAILQ_INIT(&(retval->groups[i]));

	TRACE_OUT(init_cache_lfu_policy);
	return ((struct cache_policy_ *)retval);
}

void
destroy_cache_lfu_policy(struct cache_policy_ *policy)
{
	int i;
	struct cache_lfu_policy_ *lfu_policy;
	struct cache_lfu_policy_item_ *lfu_item;

	TRACE_IN(destroy_cache_lfu_policy);
	lfu_policy = (struct cache_lfu_policy_ *)policy;
	for (i = 0; i < CACHELIB_MAX_FREQUENCY; ++i) {
		while (!TAILQ_EMPTY(&(lfu_policy->groups[i]))) {
			lfu_item = TAILQ_FIRST(&(lfu_policy->groups[i]));
			TAILQ_REMOVE(&(lfu_policy->groups[i]), lfu_item,
				entries);
			cache_lfu_policy_destroy_item(
				(struct cache_policy_item_ *)lfu_item);
		}
	}
	free(policy);
	TRACE_OUT(destroy_cache_lfu_policy);
}

Man Man