# [CMU 15-445/645] Project#1 Buffer Pool Manager

## 概要

The first programming project is to implement a buffer pool in your storage manager. The buffer pool is responsible for moving physical pages back and forth from main memory to disk. It allows a DBMS to support databases that are larger than the amount of memory that is available to the system. The buffer pool's operations are transparent to other parts in the system. For example, the system asks the buffer pool for a page using its unique identifier (page_id_t) and it does not know whether that page is already in memory or whether the system has to go retrieve it from disk.

Your implementation will need to be thread-safe. Multiple threads will be accessing the internal data structures at the same and thus you need to make sure that their critical sections are protected with latches (these are called "locks" in operating systems).

## 项目规范

For each of the following components, we are providing you with stub classes that contain the API that you need to implement. You should not modify the signatures for the pre-defined functions in these classes. If you modify the signatures, the test code that we use for grading will break and you will get no credit for the project. You also should not add additional classes in the source code for these components. These components should be entirely self-contained.

If a class already contains data members, you should not remove them. For example, the BufferPoolManager contains DiskManager and Replacer objects. These are required to implement the functionality that is needed by the rest of the system. On the other hand, you may need to add data members to these classes in order to correctly implement the required functionality. You can also add additional helper functions to these classes. The choice is yours.

You are allowed to use any built-in C++17 containers in your project unless specified otherwise. It is up to you to decide which ones you want to use. Note that these containers are not thread-safe and that you will need to include latches in your implementation to protect them. You may not bring in additional third-party dependencies (e.g. boost).

## TASK #1 - LRU REPLACEMENT POLICY

### 概述

This component is responsible for tracking page usage in the buffer pool. You will implement a new sub-class called LRUReplacer in src/include/buffer/lru_replacer.h and its corresponding implementation file in src/buffer/lru_replacer.cpp. LRUReplacer extends the abstract Replacer class (src/include/buffer/replacer.h), which contains the function specifications.

The size of the LRUReplacer is the same as buffer pool since it contains placeholders for all of the frames in the BufferPoolManager. However, not all the frames are considered as in the LRUReplacer. The LRUReplacer is initialized to have no frame in it. Then, only the newly unpinned ones will be considered in the LRUReplacer.

Leetcode习题：146. LRU 缓存机制 可以学习到LRU的基本写法。

### 要求

LRUReplacer 要求我们实现以下几个成员函数：

• Victim(T*) : 当 LRUReplacer 为空时返回 false ，否则从 LRUReplacer 中找出最近最近最久未使用的对象并将其内容存储在输出内容中
• Pin(T) : 当 BufferPoolManager 将一个页固定在页框中后，调用该函数。该函数会将容纳这个页的页框从 LRUReplacer 中删除。
• Unpin(T) : 当一个页面的 pin_count 变成0的时候会调用这个方法。 这个方法会将没有固定页的页框加入到 LRUReplacer 中。
• Size() : 返回 LRUReplacer 中的页框数。

### 实现

• Victim(T*) : 假设双向链表尾是需要被淘汰的，那么我们直接从双向链表尾取出队尾元素并赋值给输出参数即可。然后更新LRU列表。
• Pin(T) : 通过unordered_map找到该元素并在list中删除。
• Unpin(T) : 这里有比较坑的点，一般LRU访问某个元素后，会将该元素提至链表头，但这里不需要，并且当LRU列表满了之后，不需要任何操作，因此这两种情况我们可以直接return掉，剩下的直接添加到链表头，并在unordered_map中添加就行
• Size() : 返回 LRUReplacer 中的页框数。
• 线程安全：我在这里是直接使用了std::scope_lock以及std::mutex来保证线程安全。

## TASK #2 - BUFFER POOL MANAGER

### 概述

Next, you need to implement the buffer pool manager in your system (BufferPoolManager). The BufferPoolManager is responsible for fetching database pages from the DiskManager and storing them in memory. The BufferPoolManager can also write dirty pages out to disk when it is either explicitly instructed to do so or when it needs to evict a page to make space for a new page.

To make sure that your implementation works correctly with the rest of the system, we will provide you with some of the functions already filled in. You will also not need to implement the code that actually reads and writes data to disk (this is called the DiskManager in our implementation). We will provide that functionality for you.

All in-memory pages in the system are represented by Page objects. The BufferPoolManager does not need to understand the contents of these pages. But it is important for you as the system developer to understand that Page objects are just containers for memory in the buffer pool and thus are not specific to a unique page. That is, each Page object contains a block of memory that the DiskManager will use as a location to copy the contents of a physical page that it reads from disk. The BufferPoolManager will reuse the same Page object to store data as it moves back and forth to disk. This means that the same Page object may contain a different physical page throughout the life of the system. The Page object's identifer (page_id) keeps track of what physical page it contains; if a Page object does not contain a physical page, then its page_id must be set to INVALID_PAGE_ID.

Each Page object also maintains a counter for the number of threads that have "pinned" that page. Your BufferPoolManager is not allowed to free a Page that is pinned. Each Page object also keeps track of whether it is dirty or not. It is your job to record whether a page was modified before it is unpinned. Your BufferPoolManager must write the contents of a dirty Page back to disk before that object can be reused.

### 实现

• FetchPageImpl(page_id)
• NewPageImpl(page_id)
• UnpinPageImpl(page_id, is_dirty)
• FlushPageImpl(page_id)
• DeletePageImpl(page_id)
• FlushAllPagesImpl()

/**
* Unpin the target page from the buffer pool.
* @param page_id id of page to be unpinned
* @param is_dirty true if the page should be marked as dirty, false otherwise
* @return false if the page pin count is <= 0 before this call, true otherwise
*/


## 测试

### 本地

• LRUReplacer: test/buffer/lru_replacer_test.cpp

• BufferPoolManager: test/buffer/buffer_pool_manager_test.cpp

# LRUReplacer
cd build
make lru_replacer_test
./test/lru_replacer_test
# BufferPoolManager
cd build
make buffer_pool_manager_test
./test/buffer_pool_manager_test


### 在线

• src/include/buffer/lru_replacer.h
• src/buffer/lru_replacer.cpp
• src/include/buffer/buffer_pool_manager.h
• src/buffer/buffer_pool_manager.cpp

zip -r p1_submission.zip \
src/include/buffer/lru_replacer.h \
src/buffer/lru_replacer.cpp \
src/include/buffer/buffer_pool_manager.h \
src/buffer/buffer_pool_manager.cpp