#include <sys/cdefs.h>
#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);
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_item_ *queue_item;
TRACE_IN(cache_queue_policy_get_next_item);
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_item_ *queue_item;
TRACE_IN(cache_queue_policy_get_prev_item);
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));
}
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);
}
static void
cache_fifo_policy_update_item(struct cache_policy_ *policy,
struct cache_policy_item_ *item)
{
TRACE_IN(cache_fifo_policy_update_item);
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);
}
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);
}
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);
}
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);
}
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;
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);
}
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);
}