本文仅用于作业提交。
二、LRU REPLACER
lru_replacer.h
/**
* lru_replacer.h
*
* Functionality: The buffer pool manager must maintain a LRU list to collect
* all the pages that are unpinned and ready to be swapped. The simplest way to
* implement LRU is a FIFO queue, but remember to dequeue or enqueue pages when
* a page changes from unpinned to pinned, or vice-versa.
*/
#pragma once
#include <memory>
#include <unordered_map>
#include <mutex>
#include "buffer/replacer.h"
using namespace std;
namespace scudb {
template <typename T> class LRUReplacer : public Replacer<T> {
struct Node {
Node() {};
Node(T val) : val(val) {};
T val;
shared_ptr<Node> prev;
shared_ptr<Node> next;
};
public:
// do not change public interface
LRUReplacer();
~LRUReplacer();
void Remove(shared_ptr<Node>& p);
void Ins(shared_ptr<Node>& p, const T& v);
void Insert(const T &value);
bool Victim(T &value);
bool Erase(const T &value);
size_t Size();
private:
shared_ptr<Node> head;
shared_ptr<Node> tail;
unordered_map<T,shared_ptr<Node>> map;
mutable mutex latch;
// add your member variables here
};
} // namespace cmudb
其中包含的private参数:
head:头指针
tail:尾指针
head和tail都会在构造时初始化
map:一个由指定类型T对应于指针的映射
其中包含的函数接口:
构造函数和析构函数:
LRUReplacer();
~LRUReplacer();
对于节点的删除:
void Remove(shared_ptr<Node>& p);
对于在节点p后插入映射值为v的节点:
void Ins(shared_ptr<Node>& p, const T& v);
以上两个基本函数在以下函数被调用:
插入函数:
void Insert(const T &value);
去除尾节点:
bool Victim(T &value);
删除函数:
bool Erase(const T &value);
返回全体的数据数量:
size_t Size();
lru_replacer.cpp:
主要的函数如下:
对于节点的删除:
template<typename T> void LRUReplacer<T>::Remove(shared_ptr<Node>& p)//去除p节点,并把原先p之前的节点和原先p之后的节点相连
{
shared_ptr<Node> p1 = p->prev;
shared_ptr<Node> p2 = p->next;
p->next->prev = p1;
p->prev->next = p2;
}
对于在节点p后插入映射值为v的节点:
template<typename T> void LRUReplacer<T>::Ins(shared_ptr<Node>& p,const T &v)//在p节点后增加一个映射值为v的节点
{
shared_ptr<Node> p1;
p->next->prev = p1;
p1->next = p->next;
p1->prev = p;
p->next = p1;
map[v] = p1;
}
插入函数:
插入时如果发现原数据存在,那么先覆盖它,之后把需要插入的节点调整到head之后。
template <typename T> void LRUReplacer<T>::Insert(const T& v) {
lock_guard<mutex> lck(latch);
shared_ptr<Node> cur;
if (map.find(v) == map.end())//如果并没有在已有数据中找到
cur = make_shared<Node>(v);
else {//如果在已有数据中找到,那么先替代原节点
cur = map[v];
shared_ptr<Node> pre = cur->prev;
pre->next = cur->next;
shared_ptr<Node> suc = cur->next;
suc->prev = pre;
}//之后插入把需要插入的节点安排在head之后
shared_ptr<Node> fir = head->next;
cur->prev = head;
cur->next = head->next;
fir->prev = cur;
head->next = cur;
map[v] = cur;
return;
}
去尾函数:
找到最后一个节点(非tail节点),之后把前一个节点和tail拼接,然后删除的节点映射从map删除。
//去尾函数
template <typename T> bool LRUReplacer<T>::Victim(T& v) {
//lock_guard<mutex> lck(latch);
//如果map非空,说明有节点可以去掉,之后记录倒数第二个节点(不包含尾节点)的信息,然后把该节点和尾结点去掉,需要删除的节点的map映射对应抹去
if (!(map.empty())) {
shared_ptr<Node> endone = tail->prev;
tail->prev = tail->prev->prev;
endone->prev->next = tail;
map.erase(endone->val);
v = endone->val;
return true;
}
return false;
}
删除函数:
//删除函数
template <typename T> bool LRUReplacer<T>::Erase(const T& v) {
//lock_guard<mutex> lck(latch);
//如果找到对应项,那么就把对应项的前后两个节点拼接,之后删除
if (map.find(v) != map.end()) {
shared_ptr<Node> cur = map[v];
shared_ptr<Node> p = cur->prev;
shared_ptr<Node> n = cur->next;
cur->next->prev = p;
cur->prev->next = n;
}
return map.erase(v);
}
完整代码如下:
/**
* LRU implementation
*/
#include "buffer/lru_replacer.h"
#include "page/page.h"
namespace scudb {
template <typename T> LRUReplacer<T>::LRUReplacer() {
head = make_shared<Node>();
tail = make_shared<Node>();
head->next = tail;
tail->prev = head;
}
template <typename T> LRUReplacer<T>::~LRUReplacer() {}
template<typename T> void LRUReplacer<T>::Remove(shared_ptr<Node>& p)//去除p节点,并把原先p之前的节点和原先p之后的节点相连
{
shared_ptr<Node> p1 = p->prev;
shared_ptr<Node> p2 = p->next;
p->next->prev = p1;
p->prev->next = p2;
}
template<typename T> void LRUReplacer<T>::Ins(shared_ptr<Node>& p,const T &v)//在p节点后增加一个映射值为v的节点
{
shared_ptr<Node> p1;
p->next->prev = p1;
p1->next = p->next;
p1->prev = p;
p->next = p1;
map[v] = p1;
}
/*
* Insert value into LRU
*/
//插入函数
template <typename T> void LRUReplacer<T>::Insert(const T& v) {
lock_guard<mutex> lck(latch);
shared_ptr<Node> cur;
if (map.find(v) == map.end())//如果并没有在已有数据中找到
cur = make_shared<Node>(v);
else {//如果在已有数据中找到,那么先删除原节点
cur = map[v];
Remove(cur);
map.erase(v);
}//之后插入把需要插入的节点安排在head之后
Ins(head, v);
return;
}
/* If LRU is non-empty, pop the head member from LRU to argument "value", and
* return true. If LRU is empty, return false
*/
//去尾函数
template <typename T> bool LRUReplacer<T>::Victim(T& v) {
//lock_guard<mutex> lck(latch);
//如果map非空,说明有节点可以去掉,之后记录倒数第二个节点(不包含尾节点)的信息,然后把该节点和尾结点去掉,需要删除的节点的map映射对应抹去
if (!(map.empty())) {
shared_ptr<Node> endone = tail->prev;
Remove(endone);
return true;
}
return false;
}
/*
* Remove value from LRU. If removal is successful, return true, otherwise
* return false
*/
//删除函数
template <typename T> bool LRUReplacer<T>::Erase(const T& v) {
//lock_guard<mutex> lck(latch);
//如果找到对应项,那么就把对应项的前后两个节点拼接,之后删除
if (map.find(v) != map.end()) {
shared_ptr<Node> cur = map[v];
Remove(cur);
}
return map.erase(v);
}
template <typename T> size_t LRUReplacer<T>::Size() {
//lock_guard<mutex> lck(latch);
return map.size();
}
template class LRUReplacer<Page*>;
// test only
template class LRUReplacer<int>;
} // namespace cmudb