ceph/branches/riccardo/monitor2/include/lru.h

322 lines
6.4 KiB
C
Raw Normal View History

// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
/*
* Ceph - scalable distributed file system
*
* Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
*
* This is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software
* Foundation. See file COPYING.
*
*/
#ifndef __LRU_H
#define __LRU_H
#include <assert.h>
#include <iostream>
using namespace std;
#include "config.h"
class LRUObject {
private:
LRUObject *lru_next, *lru_prev;
bool lru_pinned;
class LRU *lru;
class LRUList *lru_list;
public:
LRUObject() {
lru_next = lru_prev = NULL;
lru_list = 0;
lru_pinned = false;
lru = 0;
}
// pin/unpin item in cache
void lru_pin();
void lru_unpin();
bool lru_is_expireable() { return !lru_pinned; }
friend class LRU;
friend class LRUList;
};
class LRUList {
private:
LRUObject *head, *tail;
__uint32_t len;
public:
LRUList() {
head = tail = 0;
len = 0;
}
__uint32_t get_length() { return len; }
LRUObject *get_head() {
return head;
}
LRUObject *get_tail() {
return tail;
}
void insert_head(LRUObject *o) {
o->lru_next = head;
o->lru_prev = NULL;
if (head) {
head->lru_prev = o;
} else {
tail = o;
}
head = o;
o->lru_list = this;
len++;
}
void insert_tail(LRUObject *o) {
o->lru_next = NULL;
o->lru_prev = tail;
if (tail) {
tail->lru_next = o;
} else {
head = o;
}
tail = o;
o->lru_list = this;
len++;
}
void remove(LRUObject *o) {
assert(o->lru_list == this);
if (o->lru_next)
o->lru_next->lru_prev = o->lru_prev;
else
tail = o->lru_prev;
if (o->lru_prev)
o->lru_prev->lru_next = o->lru_next;
else
head = o->lru_next;
o->lru_next = o->lru_prev = NULL;
o->lru_list = 0;
assert(len>0);
len--;
}
};
class LRU {
protected:
LRUList lru_top, lru_bot, lru_pintail;
__uint32_t lru_num, lru_num_pinned;
__uint32_t lru_max; // max items
double lru_midpoint;
friend class LRUObject;
//friend class MDCache; // hack
public:
LRU(int max = 0) {
lru_num = 0;
lru_num_pinned = 0;
lru_midpoint = .9;
lru_max = max;
}
__uint32_t lru_get_size() { return lru_num; }
__uint32_t lru_get_top() { return lru_top.get_length(); }
__uint32_t lru_get_bot() { return lru_bot.get_length(); }
__uint32_t lru_get_pintail() { return lru_pintail.get_length(); }
__uint32_t lru_get_max() { return lru_max; }
__uint32_t lru_get_num_pinned() { return lru_num_pinned; }
void lru_set_max(__uint32_t m) { lru_max = m; }
void lru_set_midpoint(float f) { lru_midpoint = f; }
// insert at top of lru
void lru_insert_top(LRUObject *o) {
//assert(!o->lru_in_lru);
//o->lru_in_lru = true;
assert(!o->lru);
o->lru = this;
lru_top.insert_head( o );
lru_num++;
if (o->lru_pinned) lru_num_pinned++;
lru_adjust();
}
// insert at mid point in lru
void lru_insert_mid(LRUObject *o) {
//assert(!o->lru_in_lru);
//o->lru_in_lru = true;
assert(!o->lru);
o->lru = this;
lru_bot.insert_head(o);
lru_num++;
if (o->lru_pinned) lru_num_pinned++;
}
// insert at bottom of lru
void lru_insert_bot(LRUObject *o) {
assert(!o->lru);
o->lru = this;
lru_bot.insert_tail(o);
lru_num++;
if (o->lru_pinned) lru_num_pinned++;
}
/*
// insert at bottom of lru
void lru_insert_pintail(LRUObject *o) {
assert(!o->lru);
o->lru = this;
assert(o->lru_pinned);
lru_pintail.insert_head(o);
lru_num++;
lru_num_pinned += o->lru_pinned;
}
*/
// adjust top/bot balance, as necessary
void lru_adjust() {
if (!lru_max) return;
unsigned toplen = lru_top.get_length();
unsigned topwant = (unsigned)(lru_midpoint * (double)lru_max);
while (toplen > 0 &&
toplen > topwant) {
// remove from tail of top, stick at head of bot
// FIXME: this could be way more efficient by moving a whole chain of items.
LRUObject *o = lru_top.get_tail();
lru_top.remove(o);
lru_bot.insert_head(o);
toplen--;
}
}
// remove an item
LRUObject *lru_remove(LRUObject *o) {
// not in list
//assert(o->lru_in_lru);
//if (!o->lru_in_lru) return o; // might have expired and been removed that way.
if (!o->lru) return o;
if (o->lru_list == &lru_top)
lru_top.remove(o);
else if (o->lru_list == &lru_bot)
lru_bot.remove(o);
else if (o->lru_list == &lru_pintail)
lru_pintail.remove(o);
else
assert(0);
lru_num--;
if (o->lru_pinned) lru_num_pinned--;
o->lru = 0;
return o;
}
// touch item -- move to head of lru
bool lru_touch(LRUObject *o) {
lru_remove(o);
lru_insert_top(o);
return true;
}
// touch item -- move to midpoint (unless already higher)
bool lru_midtouch(LRUObject *o) {
if (o->lru_list == &lru_top) return false;
lru_remove(o);
lru_insert_mid(o);
return true;
}
// touch item -- move to bottom
bool lru_bottouch(LRUObject *o) {
lru_remove(o);
lru_insert_bot(o);
return true;
}
// expire -- expire a single item
LRUObject *lru_get_next_expire() {
LRUObject *p;
// look through tail of bot
while (lru_bot.get_length()) {
p = lru_bot.get_tail();
if (!p->lru_pinned) return p;
// move to pintail
lru_bot.remove(p);
lru_pintail.insert_head(p);
}
// ok, try head then
while (lru_top.get_length()) {
p = lru_top.get_tail();
if (!p->lru_pinned) return p;
// move to pintail
lru_top.remove(p);
lru_pintail.insert_head(p);
}
// no luck!
return NULL;
}
LRUObject *lru_expire() {
LRUObject *p = lru_get_next_expire();
if (p)
return lru_remove(p);
return NULL;
}
void lru_status() {
dout(10) << "lru: " << lru_num << " items, " << lru_top.get_length() << " top, " << lru_bot.get_length() << " bot, " << lru_pintail.get_length() << " pintail" << endl;
}
};
inline void LRUObject::lru_pin()
{
lru_pinned = true;
if (lru) lru->lru_num_pinned++;
}
inline void LRUObject::lru_unpin() {
lru_pinned = false;
if (lru) {
lru->lru_num_pinned--;
// move from pintail -> bot
if (lru_list == &lru->lru_pintail) {
lru->lru_pintail.remove(this);
lru->lru_bot.insert_tail(this);
}
}
}
#endif