Skip to content

Commit 4a04c19

Browse files
Add disk scheduler to P1 (#602)
* Add disk scheduler to P1. * Fix comment. * Fixed formatting. * Fixed more formatting and linting errors.
1 parent 606ef85 commit 4a04c19

File tree

6 files changed

+194
-8
lines changed

6 files changed

+194
-8
lines changed

src/buffer/buffer_pool_manager.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ namespace bustub {
2020

2121
BufferPoolManager::BufferPoolManager(size_t pool_size, DiskManager *disk_manager, size_t replacer_k,
2222
LogManager *log_manager)
23-
: pool_size_(pool_size), disk_manager_(disk_manager), log_manager_(log_manager) {
23+
: pool_size_(pool_size), disk_scheduler_(std::make_unique<DiskScheduler>(disk_manager)), log_manager_(log_manager) {
2424
// TODO(students): remove this line after you have implemented the buffer pool manager
2525
throw NotImplementedException(
2626
"BufferPoolManager is not implemented yet. If you have finished implementing BPM, please remove the throw "

src/include/buffer/buffer_pool_manager.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
#include "buffer/lru_k_replacer.h"
2121
#include "common/config.h"
2222
#include "recovery/log_manager.h"
23-
#include "storage/disk/disk_manager.h"
23+
#include "storage/disk/disk_scheduler.h"
2424
#include "storage/page/page.h"
2525
#include "storage/page/page_guard.h"
2626

@@ -92,9 +92,9 @@ class BufferPoolManager {
9292
* but all frames are currently in use and not evictable (in another word, pinned).
9393
*
9494
* First search for page_id in the buffer pool. If not found, pick a replacement frame from either the free list or
95-
* the replacer (always find from the free list first), read the page from disk by calling disk_manager_->ReadPage(),
96-
* and replace the old page in the frame. Similar to NewPage(), if the old page is dirty, you need to write it back
97-
* to disk and update the metadata of the new page
95+
* the replacer (always find from the free list first), read the page from disk by scheduling a read DiskRequest with
96+
* disk_scheduler_->Schedule(), and replace the old page in the frame. Similar to NewPage(), if the old page is dirty,
97+
* you need to write it back to disk and update the metadata of the new page
9898
*
9999
* In addition, remember to disable eviction and record the access history of the frame like you did for NewPage().
100100
*
@@ -180,8 +180,8 @@ class BufferPoolManager {
180180

181181
/** Array of buffer pool pages. */
182182
Page *pages_;
183-
/** Pointer to the disk manager. */
184-
DiskManager *disk_manager_ __attribute__((__unused__));
183+
/** Pointer to the disk sheduler. */
184+
std::unique_ptr<DiskScheduler> disk_scheduler_ __attribute__((__unused__));
185185
/** Pointer to the log manager. Please ignore this for P1. */
186186
LogManager *log_manager_ __attribute__((__unused__));
187187
/** Page table for keeping track of buffer pool pages. */

src/include/common/channel.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// BusTub
4+
//
5+
// channel.h
6+
//
7+
// Identification: src/include/common/channel.h
8+
//
9+
// Copyright (c) 2015-2023, Carnegie Mellon University Database Group
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#pragma once
14+
15+
#include <condition_variable> // NOLINT
16+
#include <mutex> // NOLINT
17+
#include <queue>
18+
#include <utility>
19+
20+
namespace bustub {
21+
22+
/**
23+
* Channels allow for safe sharing of data between threads.
24+
*/
25+
template <class T>
26+
class Channel {
27+
public:
28+
Channel() = default;
29+
~Channel() = default;
30+
31+
/**
32+
* @brief Inserts an element into a shared queue.
33+
*
34+
* @param element The element to be inserted.
35+
*/
36+
void Put(T element) {
37+
std::unique_lock<std::mutex> lk(m_);
38+
q_.push(std::move(element));
39+
lk.unlock();
40+
cv_.notify_all();
41+
}
42+
43+
/**
44+
* @brief Gets an element from the shared queue. If the queue is empty, blocks until an element is available.
45+
*/
46+
auto Get() -> T {
47+
std::unique_lock<std::mutex> lk(m_);
48+
cv_.wait(lk, [&]() { return !q_.empty(); });
49+
T element = std::move(q_.front());
50+
q_.pop();
51+
return element;
52+
}
53+
54+
private:
55+
std::mutex m_;
56+
std::condition_variable cv_;
57+
std::queue<T> q_;
58+
};
59+
} // namespace bustub
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// BusTub
4+
//
5+
// disk_scheduler.h
6+
//
7+
// Identification: src/include/storage/disk/disk_scheduler.h
8+
//
9+
// Copyright (c) 2015-2023, Carnegie Mellon University Database Group
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#pragma once
14+
15+
#include <future> // NOLINT
16+
#include <optional>
17+
#include <thread> // NOLINT
18+
19+
#include "common/channel.h"
20+
#include "storage/disk/disk_manager.h"
21+
22+
namespace bustub {
23+
24+
/**
25+
* @brief Represents a Write or Read request for the DiskManager to execute.
26+
*/
27+
struct DiskRequest {
28+
/** Flag indicating whether the request is a write or a read. */
29+
bool is_write_;
30+
31+
/**
32+
* Pointer to the start of the memory location where a page is either:
33+
* 1. being read into from disk (on a read).
34+
* 2. being written out to disk (on a write).
35+
*/
36+
char *data_;
37+
38+
/** ID of the page being read from / written to disk. */
39+
page_id_t page_id_;
40+
41+
/** Callback used to signal to the request issuer when the request has been completed. */
42+
std::promise<bool> &callback_;
43+
};
44+
45+
/**
46+
* @brief The DiskScheduler schedules disk read and write operations.
47+
*
48+
* A request is scheduled by calling DiskScheduler::Schedule() with an appropriate DiskRequest object. The scheduler
49+
* maintains a background worker thread that processes the scheduled requests using the disk manager. The background
50+
* thread is created in the DiskScheduler constructor and joined in its destructor.
51+
*/
52+
class DiskScheduler {
53+
public:
54+
explicit DiskScheduler(DiskManager *disk_manager);
55+
~DiskScheduler();
56+
57+
/**
58+
* TODO(P1): Add implementation
59+
*
60+
* @brief Schedules a request for the DiskManager to execute.
61+
*
62+
* @param r The request to be scheduled.
63+
*/
64+
void Schedule(DiskRequest r);
65+
66+
/**
67+
* TODO(P1): Add implementation
68+
*
69+
* @brief Background worker thread function that processes scheduled requests.
70+
*
71+
* The background thread needs to process requests while the DiskScheduler exists, i.e., this function should not
72+
* return until ~DiskScheduler() is called. At that point you need to make sure that the function does return.
73+
*/
74+
void StartWorkerThread();
75+
76+
private:
77+
/** Pointer to the disk manager. */
78+
DiskManager *disk_manager_ __attribute__((__unused__));
79+
/** A shared queue to concurrently schedule and process requests. When the DiskScheduler's destructor is called,
80+
* `std::nullopt` is put into the queue to signal to the background thread to stop execution. */
81+
Channel<std::optional<DiskRequest>> request_queue_;
82+
/** The background thread responsible for issuing scheduled requests to the disk manager. */
83+
std::optional<std::thread> background_thread_;
84+
};
85+
} // namespace bustub

src/storage/disk/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ add_library(
22
bustub_storage_disk
33
OBJECT
44
disk_manager.cpp
5-
disk_manager_memory.cpp)
5+
disk_manager_memory.cpp
6+
disk_scheduler.cpp)
67

78
set(ALL_OBJECT_FILES
89
${ALL_OBJECT_FILES} $<TARGET_OBJECTS:bustub_storage_disk>

src/storage/disk/disk_scheduler.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// BusTub
4+
//
5+
// disk_scheduler.cpp
6+
//
7+
// Identification: src/storage/disk/disk_scheduler.cpp
8+
//
9+
// Copyright (c) 2015-2023, Carnegie Mellon University Database Group
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "storage/disk/disk_scheduler.h"
14+
#include "common/exception.h"
15+
#include "storage/disk/disk_manager.h"
16+
17+
namespace bustub {
18+
19+
DiskScheduler::DiskScheduler(DiskManager *disk_manager) : disk_manager_(disk_manager) {
20+
// TODO(P1): remove this line after you have implemented the disk scheduler API
21+
throw NotImplementedException(
22+
"DiskScheduler is not implemented yet. If you have finished implementing the disk scheduler, please remove the "
23+
"throw exception line in `disk_scheduler.cpp`.");
24+
25+
// Spawn the background thread
26+
background_thread_.emplace([&] { StartWorkerThread(); });
27+
}
28+
29+
DiskScheduler::~DiskScheduler() {
30+
// Put a `std::nullopt` in the queue to signal to exit the loop
31+
request_queue_.Put(std::nullopt);
32+
if (background_thread_.has_value()) {
33+
background_thread_->join();
34+
}
35+
}
36+
37+
void DiskScheduler::Schedule(DiskRequest r) {}
38+
39+
void DiskScheduler::StartWorkerThread() {}
40+
41+
} // namespace bustub

0 commit comments

Comments
 (0)