disk_buffer_pool.cpp 21.5 KB
Newer Older
羽飞's avatar
羽飞 已提交
1 2 3 4 5 6 7 8 9 10 11
/* Copyright (c) 2021 Xie Meiyi(xiemeiyi@hust.edu.cn) and OceanBase and/or its affiliates. All rights reserved.
miniob is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
         http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details. */

//
12
// Created by Meiyi & Longda on 2021/4/13.
羽飞's avatar
羽飞 已提交
13 14 15 16
//
#include <errno.h>
#include <string.h>

17
#include "storage/default/disk_buffer_pool.h"
L
Longda 已提交
18
#include "common/lang/mutex.h"
羽飞's avatar
羽飞 已提交
19
#include "common/log/log.h"
L
Longda 已提交
20
#include "common/os/os.h"
羽飞's avatar
羽飞 已提交
21
#include "common/io/io.h"
羽飞's avatar
羽飞 已提交
22 23

using namespace common;
羽飞's avatar
羽飞 已提交
24
using namespace std;
羽飞's avatar
羽飞 已提交
25

羽飞's avatar
羽飞 已提交
26 27 28 29 30 31 32 33 34 35 36
static const int MEM_POOL_ITEM_NUM = 20;

////////////////////////////////////////////////////////////////////////////////

string BPFileHeader::to_string() const
{
  stringstream ss;
  ss << "pageCount:" << page_count
     << ", allocatedCount:" << allocated_pages;
  return ss.str();
}
L
Longda 已提交
37

38
////////////////////////////////////////////////////////////////////////////////
羽飞's avatar
羽飞 已提交
39

羽飞's avatar
羽飞 已提交
40
BPFrameManager::BPFrameManager(const char *name) : allocator_(name)
L
Longda 已提交
41 42
{}

羽飞's avatar
羽飞 已提交
43
RC BPFrameManager::init(int pool_num)
L
Longda 已提交
44
{
L
Longda Feng 已提交
45
  int ret = allocator_.init(false, pool_num);
羽飞's avatar
羽飞 已提交
46 47 48
  if (ret == 0) {
    return RC::SUCCESS;
  }
羽飞's avatar
羽飞 已提交
49
  return RC::NOMEM;
L
Longda 已提交
50 51
}

羽飞's avatar
羽飞 已提交
52
RC BPFrameManager::cleanup()
L
Longda 已提交
53
{
羽飞's avatar
羽飞 已提交
54
  if (frames_.count() > 0) {
羽飞's avatar
羽飞 已提交
55
    return RC::INTERNAL;
L
Longda 已提交
56 57
  }

羽飞's avatar
羽飞 已提交
58 59 60 61
  frames_.destroy();
  return RC::SUCCESS;
}

62
int BPFrameManager::purge_frames(int count, std::function<RC(Frame *frame)> purger)
L
Longda 已提交
63
{
64 65 66 67 68 69 70 71 72
  std::lock_guard<std::mutex> lock_guard(lock_);

  std::vector<Frame *> frames_can_purge;
  if (count <= 0) {
    count = 1;
  }
  frames_can_purge.reserve(count);

  auto purge_finder = [&frames_can_purge, count](const FrameId &frame_id, Frame *const frame) {
羽飞's avatar
羽飞 已提交
73
    if (frame->can_purge()) {
74 75 76 77 78
      frame->pin();
      frames_can_purge.push_back(frame);
      if (frames_can_purge.size() >= static_cast<size_t>(count)) {
        return false;  // false to break the progress
      }
羽飞's avatar
羽飞 已提交
79
    }
L
Longda Feng 已提交
80
    return true;  // true continue to look up
羽飞's avatar
羽飞 已提交
81
  };
82

羽飞's avatar
羽飞 已提交
83
  frames_.foreach_reverse(purge_finder);
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
  LOG_INFO("purge frames find %ld pages total", frames_can_purge.size());

  /// 当前还在frameManager的锁内,而 purger 是一个非常耗时的操作
  /// 他需要把脏页数据刷新到磁盘上去,所以这里会极大地降低并发度
  int freed_count = 0;
  for (Frame *frame : frames_can_purge) {
    RC rc = purger(frame);
    if (RC::SUCCESS == rc) {
      free_internal(frame->frame_id(), frame);
      freed_count++;
    } else {
      frame->unpin();
      LOG_WARN("failed to purge frame. frame_id=%s, rc=%s", 
               to_string(frame->frame_id()).c_str(), strrc(rc));
    }
  }
  LOG_INFO("purge frame done. number=%d", freed_count);
  return freed_count;
羽飞's avatar
羽飞 已提交
102
}
L
Longda 已提交
103

羽飞's avatar
羽飞 已提交
104 105
Frame *BPFrameManager::get(int file_desc, PageNum page_num)
{
106
  FrameId frame_id(file_desc, page_num);
羽飞's avatar
羽飞 已提交
107
  std::lock_guard<std::mutex> lock_guard(lock_);
108 109 110 111 112
  return get_internal(frame_id);
}

Frame *BPFrameManager::get_internal(const FrameId &frame_id)
{
羽飞's avatar
羽飞 已提交
113 114
  Frame *frame = nullptr;
  (void)frames_.get(frame_id, frame);
115 116 117
  if (frame != nullptr) {
    frame->pin();
  }
羽飞's avatar
羽飞 已提交
118
  return frame;
L
Longda 已提交
119 120
}

羽飞's avatar
羽飞 已提交
121
Frame *BPFrameManager::alloc(int file_desc, PageNum page_num)
L
Longda 已提交
122
{
123
  FrameId frame_id(file_desc, page_num);
羽飞's avatar
羽飞 已提交
124 125

  std::lock_guard<std::mutex> lock_guard(lock_);
126 127 128
  Frame *frame = get_internal(frame_id);
  if (frame != nullptr) {
    return frame;
羽飞's avatar
羽飞 已提交
129 130 131 132
  }

  frame = allocator_.alloc();
  if (frame != nullptr) {
133 134
    ASSERT(frame->pin_count() == 0, "got an invalid frame that pin count is not 0. frame=%s", 
           to_string(*frame).c_str());
135
    frame->set_page_num(page_num);
136
    frame->pin();
羽飞's avatar
羽飞 已提交
137 138 139
    frames_.put(frame_id, frame);
  }
  return frame;
L
Longda 已提交
140 141
}

羽飞's avatar
羽飞 已提交
142
RC BPFrameManager::free(int file_desc, PageNum page_num, Frame *frame)
L
Longda 已提交
143
{
144
  FrameId frame_id(file_desc, page_num);
L
Longda 已提交
145

羽飞's avatar
羽飞 已提交
146
  std::lock_guard<std::mutex> lock_guard(lock_);
147 148 149 150 151
  return free_internal(frame_id, frame);
}

RC BPFrameManager::free_internal(const FrameId &frame_id, Frame *frame)
{
羽飞's avatar
羽飞 已提交
152
  Frame *frame_source = nullptr;
羽飞's avatar
羽飞 已提交
153
  [[maybe_unused]] bool found = frames_.get(frame_id, frame_source);
154 155 156
  ASSERT(found && frame == frame_source && frame->pin_count() == 1,
         "failed to free frame. found=%d, frameId=%s, frame_source=%p, frame=%p, pinCount=%d, lbt=%s",
         found, to_string(frame_id).c_str(), frame_source, frame, frame->pin_count(), lbt());
L
Longda 已提交
157

158
  frame->unpin();
羽飞's avatar
羽飞 已提交
159 160 161
  frames_.remove(frame_id);
  allocator_.free(frame);
  return RC::SUCCESS;
L
Longda 已提交
162 163
}

羽飞's avatar
羽飞 已提交
164
std::list<Frame *> BPFrameManager::find_list(int file_desc)
L
Longda 已提交
165
{
羽飞's avatar
羽飞 已提交
166 167 168
  std::lock_guard<std::mutex> lock_guard(lock_);

  std::list<Frame *> frames;
169
  auto fetcher = [&frames, file_desc](const FrameId &frame_id, Frame *const frame) -> bool {
羽飞's avatar
羽飞 已提交
170
    if (file_desc == frame_id.file_desc()) {
171
      frame->pin();
羽飞's avatar
羽飞 已提交
172 173 174 175
      frames.push_back(frame);
    }
    return true;
  };
L
Longda Feng 已提交
176
  frames_.foreach (fetcher);
羽飞's avatar
羽飞 已提交
177
  return frames;
L
Longda 已提交
178 179
}

羽飞's avatar
羽飞 已提交
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
////////////////////////////////////////////////////////////////////////////////
BufferPoolIterator::BufferPoolIterator()
{}
BufferPoolIterator::~BufferPoolIterator()
{}
RC BufferPoolIterator::init(DiskBufferPool &bp, PageNum start_page /* = 0 */)
{
  bitmap_.init(bp.file_header_->bitmap, bp.file_header_->page_count);
  if (start_page <= 0) {
    current_page_num_ = 0;
  } else {
    current_page_num_ = start_page;
  }
  return RC::SUCCESS;
}

bool BufferPoolIterator::has_next()
{
羽飞's avatar
羽飞 已提交
198
  return bitmap_.next_setted_bit(current_page_num_ + 1) != -1;
羽飞's avatar
羽飞 已提交
199 200 201 202
}

PageNum BufferPoolIterator::next()
{
羽飞's avatar
羽飞 已提交
203
  PageNum next_page = bitmap_.next_setted_bit(current_page_num_ + 1);
羽飞's avatar
羽飞 已提交
204 205 206 207 208 209 210 211 212 213 214 215 216
  if (next_page != -1) {
    current_page_num_ = next_page;
  }
  return next_page;
}

RC BufferPoolIterator::reset()
{
  current_page_num_ = 0;
  return RC::SUCCESS;
}

////////////////////////////////////////////////////////////////////////////////
羽飞's avatar
羽飞 已提交
217
DiskBufferPool::DiskBufferPool(BufferPoolManager &bp_manager, BPFrameManager &frame_manager)
L
Longda Feng 已提交
218 219
    : bp_manager_(bp_manager), frame_manager_(frame_manager)
{}
羽飞's avatar
羽飞 已提交
220

L
Longda 已提交
221 222
DiskBufferPool::~DiskBufferPool()
{
羽飞's avatar
羽飞 已提交
223
  close_file();
224
  LOG_INFO("disk buffer pool exit");
L
Longda 已提交
225 226
}

羽飞's avatar
羽飞 已提交
227
RC DiskBufferPool::open_file(const char *file_name)
羽飞's avatar
羽飞 已提交
228
{
229 230
  int fd = open(file_name, O_RDWR);
  if (fd < 0) {
羽飞's avatar
羽飞 已提交
231 232 233
    LOG_ERROR("Failed to open file %s, because %s.", file_name, strerror(errno));
    return RC::IOERR_ACCESS;
  }
234
  LOG_INFO("Successfully open buffer pool file %s.", file_name);
羽飞's avatar
羽飞 已提交
235

羽飞's avatar
羽飞 已提交
236 237
  file_name_ = file_name;
  file_desc_ = fd;
羽飞's avatar
羽飞 已提交
238

羽飞's avatar
羽飞 已提交
239
  RC rc = RC::SUCCESS;
羽飞's avatar
羽飞 已提交
240
  rc = allocate_frame(BP_HEADER_PAGE, &hdr_frame_);
羽飞's avatar
羽飞 已提交
241 242
  if (rc != RC::SUCCESS) {
    LOG_ERROR("failed to allocate frame for header. file name %s", file_name_.c_str());
羽飞's avatar
羽飞 已提交
243
    close(fd);
羽飞's avatar
羽飞 已提交
244 245
    file_desc_ = -1;
    return rc;
羽飞's avatar
羽飞 已提交
246
  }
羽飞's avatar
羽飞 已提交
247

248 249 250
  hdr_frame_->set_file_desc(fd);
  hdr_frame_->access();

羽飞's avatar
羽飞 已提交
251
  if ((rc = load_page(BP_HEADER_PAGE, hdr_frame_)) != RC::SUCCESS) {
L
Longda 已提交
252
    LOG_ERROR("Failed to load first page of %s, due to %s.", file_name, strerror(errno));
羽飞's avatar
羽飞 已提交
253
    purge_frame(BP_HEADER_PAGE, hdr_frame_);
羽飞's avatar
羽飞 已提交
254
    close(fd);
羽飞's avatar
羽飞 已提交
255 256
    file_desc_ = -1;
    return rc;
羽飞's avatar
羽飞 已提交
257 258
  }

羽飞's avatar
羽飞 已提交
259
  file_header_ = (BPFileHeader *)hdr_frame_->data();
L
Longda 已提交
260

羽飞's avatar
羽飞 已提交
261 262
  LOG_INFO("Successfully open %s. file_desc=%d, hdr_frame=%p, file header=%s",
           file_name, file_desc_, hdr_frame_, file_header_->to_string().c_str());
羽飞's avatar
羽飞 已提交
263 264 265
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
266
RC DiskBufferPool::close_file()
羽飞's avatar
羽飞 已提交
267
{
羽飞's avatar
羽飞 已提交
268 269 270
  RC rc = RC::SUCCESS;
  if (file_desc_ < 0) {
    return rc;
羽飞's avatar
羽飞 已提交
271 272
  }

273 274
  hdr_frame_->unpin();

羽飞's avatar
羽飞 已提交
275
  // TODO: 理论上是在回放时回滚未提交事务,但目前没有undo log,因此不下刷数据page,只通过redo log回放
276 277 278
  rc = purge_all_pages();
  if (rc != RC::SUCCESS) {
    LOG_ERROR("failed to close %s, due to failed to purge pages. rc=%s", file_name_.c_str(), strrc(rc));
羽飞's avatar
羽飞 已提交
279
    return rc;
羽飞's avatar
羽飞 已提交
280 281
  }

282
  disposed_pages_.clear();
L
Longda 已提交
283

羽飞's avatar
羽飞 已提交
284 285
  if (close(file_desc_) < 0) {
    LOG_ERROR("Failed to close fileId:%d, fileName:%s, error:%s", file_desc_, file_name_.c_str(), strerror(errno));
羽飞's avatar
羽飞 已提交
286 287
    return RC::IOERR_CLOSE;
  }
羽飞's avatar
羽飞 已提交
288 289 290 291
  LOG_INFO("Successfully close file %d:%s.", file_desc_, file_name_.c_str());
  file_desc_ = -1;

  bp_manager_.close_file(file_name_.c_str());
羽飞's avatar
羽飞 已提交
292 293 294
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
295
RC DiskBufferPool::get_this_page(PageNum page_num, Frame **frame)
羽飞's avatar
羽飞 已提交
296
{
羽飞's avatar
羽飞 已提交
297
  RC rc = RC::SUCCESS;
298
  *frame = nullptr;
羽飞's avatar
羽飞 已提交
299

羽飞's avatar
羽飞 已提交
300
  Frame *used_match_frame = frame_manager_.get(file_desc_, page_num);
L
Longda 已提交
301
  if (used_match_frame != nullptr) {
302
    used_match_frame->access();
羽飞's avatar
羽飞 已提交
303
    *frame = used_match_frame;
L
Longda 已提交
304
    return RC::SUCCESS;
羽飞's avatar
羽飞 已提交
305 306
  }

307 308
  std::scoped_lock lock_guard(lock_); // 直接加了一把大锁,其实可以根据访问的页面来细化提高并行度

羽飞's avatar
羽飞 已提交
309
  // Allocate one page and load the data into this page
羽飞's avatar
羽飞 已提交
310
  Frame *allocated_frame = nullptr;
311 312
  rc = allocate_frame(page_num, &allocated_frame);
  if (rc != RC::SUCCESS) {
羽飞's avatar
羽飞 已提交
313 314 315 316
    LOG_ERROR("Failed to alloc frame %s:%d, due to failed to alloc page.", file_name_.c_str(), page_num);
    return rc;
  }

317 318 319 320
  allocated_frame->set_file_desc(file_desc_);
  // allocated_frame->pin(); // pined in manager::get
  allocated_frame->access();

羽飞's avatar
羽飞 已提交
321 322
  if ((rc = load_page(page_num, allocated_frame)) != RC::SUCCESS) {
    LOG_ERROR("Failed to load page %s:%d", file_name_.c_str(), page_num);
羽飞's avatar
羽飞 已提交
323
    purge_frame(page_num, allocated_frame);
羽飞's avatar
羽飞 已提交
324 325 326 327
    return rc;
  }

  *frame = allocated_frame;
羽飞's avatar
羽飞 已提交
328 329 330
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
331
RC DiskBufferPool::allocate_page(Frame **frame)
羽飞's avatar
羽飞 已提交
332
{
羽飞's avatar
羽飞 已提交
333
  RC rc = RC::SUCCESS;
羽飞's avatar
羽飞 已提交
334

335 336
  lock_.lock();
  
羽飞's avatar
羽飞 已提交
337
  int byte = 0, bit = 0;
羽飞's avatar
羽飞 已提交
338
  if ((file_header_->allocated_pages) < (file_header_->page_count)) {
羽飞's avatar
羽飞 已提交
339
    // There is one free page
羽飞's avatar
羽飞 已提交
340
    for (int i = 0; i < file_header_->page_count; i++) {
羽飞's avatar
羽飞 已提交
341 342
      byte = i / 8;
      bit = i % 8;
羽飞's avatar
羽飞 已提交
343 344 345
      if (((file_header_->bitmap[byte]) & (1 << bit)) == 0) {
        (file_header_->allocated_pages)++;
        file_header_->bitmap[byte] |= (1 << bit);
L
Longda 已提交
346
        // TODO,  do we need clean the loaded page's data?
L
Longda Feng 已提交
347
        hdr_frame_->mark_dirty();
348 349

        lock_.unlock();
羽飞's avatar
羽飞 已提交
350
        return get_this_page(i, frame);
羽飞's avatar
羽飞 已提交
351 352 353 354
      }
    }
  }

羽飞's avatar
羽飞 已提交
355 356
  if (file_header_->page_count >= BPFileHeader::MAX_PAGE_NUM) {
    LOG_WARN("file buffer pool is full. page count %d, max page count %d",
357 358 359
        file_header_->page_count, BPFileHeader::MAX_PAGE_NUM);
    lock_.unlock();
    return RC::BUFFERPOOL_NOBUF;
羽飞's avatar
羽飞 已提交
360 361 362
  }

  PageNum page_num = file_header_->page_count;
羽飞's avatar
羽飞 已提交
363
  Frame *allocated_frame = nullptr;
羽飞's avatar
羽飞 已提交
364
  if ((rc = allocate_frame(page_num, &allocated_frame)) != RC::SUCCESS) {
羽飞's avatar
羽飞 已提交
365
    LOG_ERROR("Failed to allocate frame %s, due to no free page.", file_name_.c_str());
366
    lock_.unlock();
羽飞's avatar
羽飞 已提交
367
    return rc;
羽飞's avatar
羽飞 已提交
368 369
  }

羽飞's avatar
羽飞 已提交
370 371 372
  LOG_INFO("allocate new page. file=%s, pageNum=%d, pin=%d",
           file_name_.c_str(), page_num, allocated_frame->pin_count());

羽飞's avatar
羽飞 已提交
373 374
  file_header_->allocated_pages++;
  file_header_->page_count++;
羽飞's avatar
羽飞 已提交
375 376 377

  byte = page_num / 8;
  bit = page_num % 8;
羽飞's avatar
羽飞 已提交
378 379
  file_header_->bitmap[byte] |= (1 << bit);
  hdr_frame_->mark_dirty();
羽飞's avatar
羽飞 已提交
380

381 382
  allocated_frame->set_file_desc(file_desc_);
  allocated_frame->access();
羽飞's avatar
羽飞 已提交
383
  allocated_frame->clear_page();
384
  allocated_frame->set_page_num(file_header_->page_count - 1);
羽飞's avatar
羽飞 已提交
385

L
Longda 已提交
386
  // Use flush operation to extension file
387
  if ((rc = flush_page_internal(*allocated_frame)) != RC::SUCCESS) {
羽飞's avatar
羽飞 已提交
388
    LOG_WARN("Failed to alloc page %s , due to failed to extend one page.", file_name_.c_str());
L
Longda 已提交
389 390
    // skip return false, delay flush the extended page
    // return tmp;
羽飞's avatar
羽飞 已提交
391 392
  }

393
  lock_.unlock();
L
Longda 已提交
394

395
  *frame = allocated_frame;
羽飞's avatar
羽飞 已提交
396 397 398
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
399
RC DiskBufferPool::dispose_page(PageNum page_num)
羽飞's avatar
羽飞 已提交
400
{
401 402 403 404 405 406 407 408
  std::scoped_lock lock_guard(lock_);
  Frame *used_frame = frame_manager_.get(file_desc_, page_num);
  if (used_frame != nullptr) {
    ASSERT("the page try to dispose is in use. frame:%s", to_string(*used_frame).c_str());
    frame_manager_.free(file_desc_, page_num, used_frame);
  } else {
    LOG_WARN("failed to fetch the page while disposing it. pageNum=%d", page_num);
    return RC::NOTFOUND;
羽飞's avatar
羽飞 已提交
409 410
  }

411
  hdr_frame_->mark_dirty();
羽飞's avatar
羽飞 已提交
412
  file_header_->allocated_pages--;
羽飞's avatar
羽飞 已提交
413
  char tmp = 1 << (page_num % 8);
羽飞's avatar
羽飞 已提交
414
  file_header_->bitmap[page_num / 8] &= ~tmp;
羽飞's avatar
羽飞 已提交
415 416 417
  return RC::SUCCESS;
}

418 419 420 421 422 423
RC DiskBufferPool::unpin_page(Frame *frame)
{
  frame->unpin();
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
424
RC DiskBufferPool::purge_frame(PageNum page_num, Frame *buf)
羽飞's avatar
羽飞 已提交
425
{
426 427 428
  if (buf->pin_count() != 1) {
    LOG_INFO("Begin to free page %d of %d(file id), but it's pin count > 1:%d.",
        buf->page_num(), buf->file_desc(), buf->pin_count());
L
Longda 已提交
429 430 431
    return RC::LOCKED_UNLOCK;
  }

432 433
  if (buf->dirty()) {
    RC rc = flush_page_internal(*buf);
L
Longda 已提交
434
    if (rc != RC::SUCCESS) {
435
      LOG_WARN("Failed to flush page %d of %d(file desc) during purge page.", buf->page_num(), buf->file_desc());
L
Longda 已提交
436 437 438 439
      return rc;
    }
  }

440
  LOG_DEBUG("Successfully purge frame =%p, page %d of %d(file desc)", buf, buf->page_num(), buf->file_desc());
羽飞's avatar
羽飞 已提交
441
  frame_manager_.free(file_desc_, page_num, buf);
L
Longda 已提交
442
  return RC::SUCCESS;
羽飞's avatar
羽飞 已提交
443
}
L
Longda 已提交
444

羽飞's avatar
羽飞 已提交
445
RC DiskBufferPool::purge_page(PageNum page_num)
羽飞's avatar
羽飞 已提交
446
{
447
  std::scoped_lock lock_guard(lock_);
羽飞's avatar
羽飞 已提交
448
  Frame *used_frame = frame_manager_.get(file_desc_, page_num);
L
Longda 已提交
449
  if (used_frame != nullptr) {
羽飞's avatar
羽飞 已提交
450
    return purge_frame(page_num, used_frame);
羽飞's avatar
羽飞 已提交
451
  }
L
Longda 已提交
452

羽飞's avatar
羽飞 已提交
453 454 455
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
456
RC DiskBufferPool::purge_all_pages()
羽飞's avatar
羽飞 已提交
457
{
羽飞's avatar
羽飞 已提交
458
  std::list<Frame *> used = frame_manager_.find_list(file_desc_);
459 460

  std::scoped_lock lock_guard(lock_);
L
Longda 已提交
461 462
  for (std::list<Frame *>::iterator it = used.begin(); it != used.end(); ++it) {
    Frame *frame = *it;
463 464

    purge_frame(frame->page_num(), frame);
羽飞's avatar
羽飞 已提交
465 466 467 468
  }
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
469
RC DiskBufferPool::check_all_pages_unpinned()
羽飞's avatar
羽飞 已提交
470
{
羽飞's avatar
羽飞 已提交
471
  std::list<Frame *> frames = frame_manager_.find_list(file_desc_);
472 473 474 475 476 477 478 479 480 481

  std::scoped_lock lock_guard(lock_);
  for (Frame *frame : frames) {
    frame->unpin();
    if (frame->page_num() == BP_HEADER_PAGE && frame->pin_count() > 1) {
      LOG_WARN("This page has been pinned. file desc=%d, pageNum:%d, pin count=%d",
          file_desc_, frame->page_num(), frame->pin_count());
    } else if (frame->page_num() != BP_HEADER_PAGE && frame->pin_count() > 0) {
      LOG_WARN("This page has been pinned. file desc=%d, pageNum:%d, pin count=%d",
          file_desc_, frame->page_num(), frame->pin_count());
羽飞's avatar
羽飞 已提交
482 483
    }
  }
羽飞's avatar
羽飞 已提交
484
  LOG_INFO("all pages have been checked of file desc %d", file_desc_);
羽飞's avatar
羽飞 已提交
485 486 487
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
488
RC DiskBufferPool::flush_page(Frame &frame)
489 490 491 492 493 494
{
  std::scoped_lock lock_guard(lock_);
  return flush_page_internal(frame);
}

RC DiskBufferPool::flush_page_internal(Frame &frame)
羽飞's avatar
羽飞 已提交
495 496 497 498
{
  // The better way is use mmap the block into memory,
  // so it is easier to flush data to file.

499
  Page &page = frame.page();
羽飞's avatar
羽飞 已提交
500 501 502
  s64_t offset = ((s64_t)page.page_num) * sizeof(Page);
  if (lseek(file_desc_, offset, SEEK_SET) == offset - 1) {
    LOG_ERROR("Failed to flush page %lld of %d due to failed to seek %s.", offset, file_desc_, strerror(errno));
羽飞's avatar
羽飞 已提交
503 504 505
    return RC::IOERR_SEEK;
  }

羽飞's avatar
羽飞 已提交
506
  if (writen(file_desc_, &page, sizeof(Page)) != 0) {
羽飞's avatar
羽飞 已提交
507
    LOG_ERROR("Failed to flush page %lld of %d due to %s.", offset, file_desc_, strerror(errno));
羽飞's avatar
羽飞 已提交
508 509
    return RC::IOERR_WRITE;
  }
510
  frame.clear_dirty();
羽飞's avatar
羽飞 已提交
511
  LOG_DEBUG("Flush block. file desc=%d, pageNum=%d, pin count=%d", file_desc_, page.page_num, frame.pin_count());
羽飞's avatar
羽飞 已提交
512 513 514 515

  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
516 517 518 519 520 521 522 523 524 525 526 527 528
RC DiskBufferPool::flush_all_pages()
{
  std::list<Frame *> used = frame_manager_.find_list(file_desc_);
  for (Frame *frame : used) {
    RC rc = flush_page(*frame);
    if (rc != RC::SUCCESS) {
      LOG_WARN("failed to flush all pages");
      return rc;
    }
  }
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
529 530 531 532 533 534
RC DiskBufferPool::recover_page(PageNum page_num)
{
  int byte = 0, bit = 0;
  byte = page_num / 8;
  bit = page_num % 8;

535
  std::scoped_lock lock_guard(lock_);
羽飞's avatar
羽飞 已提交
536 537 538 539 540 541 542 543 544
  if (!(file_header_->bitmap[byte] & (1 << bit))) {
    file_header_->bitmap[byte] |= (1 << bit);
    file_header_->allocated_pages++;
    file_header_->page_count++;
    hdr_frame_->mark_dirty();
  }
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
545
RC DiskBufferPool::allocate_frame(PageNum page_num, Frame **buffer)
羽飞's avatar
羽飞 已提交
546
{
547 548
  auto purger = [this](Frame *frame) {
    if (!frame->dirty()) {
羽飞's avatar
羽飞 已提交
549 550
      return RC::SUCCESS;
    }
羽飞's avatar
羽飞 已提交
551

552 553 554 555 556
    RC rc = RC::SUCCESS;
    if (frame->file_desc() == file_desc_) {
      rc = this->flush_page_internal(*frame);
    } else {
      rc = bp_manager_.flush_page(*frame);
羽飞's avatar
羽飞 已提交
557 558
    }

559 560
    if (rc != RC::SUCCESS) {
      LOG_ERROR("Failed to aclloc block due to failed to flush old block. rc=%s", strrc(rc));
羽飞's avatar
羽飞 已提交
561
    }
562 563
    return rc;
  };
L
Longda 已提交
564

565 566 567 568 569 570 571
  while (true) {
    Frame *frame = frame_manager_.alloc(file_desc_, page_num);
    if (frame != nullptr) {
      *buffer = frame;
      return RC::SUCCESS;
    }

572
    LOG_TRACE("frames are all allocated, so we should purge some frames to get one free frame");
573
    (void)frame_manager_.purge_frames(1/*count*/, purger);
羽飞's avatar
羽飞 已提交
574
  }
575
  return RC::BUFFERPOOL_NOBUF;
羽飞's avatar
羽飞 已提交
576 577
}

羽飞's avatar
羽飞 已提交
578
RC DiskBufferPool::check_page_num(PageNum page_num)
羽飞's avatar
羽飞 已提交
579
{
羽飞's avatar
羽飞 已提交
580 581 582
  if (page_num >= file_header_->page_count) {
    LOG_ERROR("Invalid pageNum:%d, file's name:%s", page_num, file_name_.c_str());
    return RC::BUFFERPOOL_INVALID_PAGE_NUM;
羽飞's avatar
羽飞 已提交
583
  }
羽飞's avatar
羽飞 已提交
584 585 586
  if ((file_header_->bitmap[page_num / 8] & (1 << (page_num % 8))) == 0) {
    LOG_ERROR("Invalid pageNum:%d, file's name:%s", page_num, file_name_.c_str());
    return RC::BUFFERPOOL_INVALID_PAGE_NUM;
羽飞's avatar
羽飞 已提交
587 588 589 590
  }
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
591
RC DiskBufferPool::load_page(PageNum page_num, Frame *frame)
羽飞's avatar
羽飞 已提交
592
{
593
  s64_t offset = ((s64_t)page_num) * BP_PAGE_SIZE;
羽飞's avatar
羽飞 已提交
594
  if (lseek(file_desc_, offset, SEEK_SET) == -1) {
L
Longda Feng 已提交
595
    LOG_ERROR("Failed to load page %s:%d, due to failed to lseek:%s.", file_name_.c_str(), page_num, strerror(errno));
羽飞's avatar
羽飞 已提交
596 597 598

    return RC::IOERR_SEEK;
  }
羽飞's avatar
羽飞 已提交
599

600 601
  Page &page = frame->page();
  int ret = readn(file_desc_, &page, BP_PAGE_SIZE);
羽飞's avatar
羽飞 已提交
602
  if (ret != 0) {
羽飞's avatar
羽飞 已提交
603 604
    LOG_ERROR("Failed to load page %s, file_desc:%d, page num:%d, due to failed to read data:%s, ret=%d, page count=%d",
              file_name_.c_str(), file_desc_, page_num, strerror(errno), ret, file_header_->allocated_pages);
羽飞's avatar
羽飞 已提交
605
    return RC::IOERR_READ;
羽飞's avatar
羽飞 已提交
606 607 608 609
  }
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
610 611 612 613 614
int DiskBufferPool::file_desc() const
{
  return file_desc_;
}
////////////////////////////////////////////////////////////////////////////////
615
BufferPoolManager::BufferPoolManager(int memory_size /* = 0 */)
羽飞's avatar
羽飞 已提交
616
{
617 618
  if (memory_size <= 0) {
    memory_size = MEM_POOL_ITEM_NUM * DEFAULT_ITEM_NUM_PER_POOL * BP_PAGE_SIZE;
619
  }
620
  const int pool_num = std::max(memory_size / BP_PAGE_SIZE / DEFAULT_ITEM_NUM_PER_POOL, 1);
621
  frame_manager_.init(pool_num);
622 623
  LOG_INFO("buffer pool manager init with memory size %d, page num: %d, pool num: %d",
           memory_size, pool_num * DEFAULT_ITEM_NUM_PER_POOL, pool_num);
羽飞's avatar
羽飞 已提交
624 625 626 627 628 629
}

BufferPoolManager::~BufferPoolManager()
{
  std::unordered_map<std::string, DiskBufferPool *> tmp_bps;
  tmp_bps.swap(buffer_pools_);
L
Longda Feng 已提交
630

羽飞's avatar
羽飞 已提交
631 632
  for (auto &iter : tmp_bps) {
    delete iter.second;
羽飞's avatar
羽飞 已提交
633
  }
羽飞's avatar
羽飞 已提交
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655
}

RC BufferPoolManager::create_file(const char *file_name)
{
  int fd = open(file_name, O_RDWR | O_CREAT | O_EXCL, S_IREAD | S_IWRITE);
  if (fd < 0) {
    LOG_ERROR("Failed to create %s, due to %s.", file_name, strerror(errno));
    return RC::SCHEMA_DB_EXIST;
  }

  close(fd);

  /**
   * Here don't care about the failure
   */
  fd = open(file_name, O_RDWR);
  if (fd < 0) {
    LOG_ERROR("Failed to open for readwrite %s, due to %s.", file_name, strerror(errno));
    return RC::IOERR_ACCESS;
  }

  Page page;
656
  memset(&page, 0, BP_PAGE_SIZE);
羽飞's avatar
羽飞 已提交
657 658 659 660 661 662 663 664 665 666 667

  BPFileHeader *file_header = (BPFileHeader *)page.data;
  file_header->allocated_pages = 1;
  file_header->page_count = 1;

  char *bitmap = file_header->bitmap;
  bitmap[0] |= 0x01;
  if (lseek(fd, 0, SEEK_SET) == -1) {
    LOG_ERROR("Failed to seek file %s to position 0, due to %s .", file_name, strerror(errno));
    close(fd);
    return RC::IOERR_SEEK;
羽飞's avatar
羽飞 已提交
668
  }
羽飞's avatar
羽飞 已提交
669

670
  if (writen(fd, (char *)&page, BP_PAGE_SIZE) != 0) {
羽飞's avatar
羽飞 已提交
671 672 673 674 675 676 677
    LOG_ERROR("Failed to write header to file %s, due to %s.", file_name, strerror(errno));
    close(fd);
    return RC::IOERR_WRITE;
  }

  close(fd);
  LOG_INFO("Successfully create %s.", file_name);
羽飞's avatar
羽飞 已提交
678 679 680
  return RC::SUCCESS;
}

L
Longda Feng 已提交
681
RC BufferPoolManager::open_file(const char *_file_name, DiskBufferPool *&_bp)
羽飞's avatar
羽飞 已提交
682
{
羽飞's avatar
羽飞 已提交
683
  std::string file_name(_file_name);
L
Longda Feng 已提交
684

685
  std::scoped_lock lock_guard(lock_);
羽飞's avatar
羽飞 已提交
686 687 688 689
  if (buffer_pools_.find(file_name) != buffer_pools_.end()) {
    LOG_WARN("file already opened. file name=%s", _file_name);
    return RC::BUFFERPOOL_OPEN;
  }
羽飞's avatar
羽飞 已提交
690

羽飞's avatar
羽飞 已提交
691 692 693 694 695 696
  DiskBufferPool *bp = new DiskBufferPool(*this, frame_manager_);
  RC rc = bp->open_file(_file_name);
  if (rc != RC::SUCCESS) {
    LOG_WARN("failed to open file name");
    delete bp;
    return rc;
羽飞's avatar
羽飞 已提交
697
  }
羽飞's avatar
羽飞 已提交
698 699 700

  buffer_pools_.insert(std::pair<std::string, DiskBufferPool *>(file_name, bp));
  fd_buffer_pools_.insert(std::pair<int, DiskBufferPool *>(bp->file_desc(), bp));
701
  LOG_DEBUG("insert buffer pool into fd buffer pools. fd=%d, bp=%p, lbt=%s", bp->file_desc(), bp, lbt());
羽飞's avatar
羽飞 已提交
702 703 704 705 706 707 708
  _bp = bp;
  return RC::SUCCESS;
}

RC BufferPoolManager::close_file(const char *_file_name)
{
  std::string file_name(_file_name);
709

羽飞's avatar
羽飞 已提交
710
  lock_.lock();
711

羽飞's avatar
羽飞 已提交
712 713
  auto iter = buffer_pools_.find(file_name);
  if (iter == buffer_pools_.end()) {
羽飞's avatar
羽飞 已提交
714 715
    LOG_TRACE("file has not opened: %s", _file_name);
    lock_.unlock();
羽飞's avatar
羽飞 已提交
716
    return RC::INTERNAL;
羽飞's avatar
羽飞 已提交
717
  }
羽飞's avatar
羽飞 已提交
718 719

  int fd = iter->second->file_desc();
720 721 722 723 724 725 726 727 728 729 730
  if (0 == fd_buffer_pools_.erase(fd)) {
    int count = 0;
    for (auto fd_iter = fd_buffer_pools_.begin(); fd_iter != fd_buffer_pools_.end(); ++fd_iter) {
      if (fd_iter->second == iter->second) {
        fd_buffer_pools_.erase(fd_iter);
        count = 1;
        break;
      }
    }
    ASSERT(count == 1, "the buffer pool was not erased from fd buffer pools.");
  }
羽飞's avatar
羽飞 已提交
731 732 733

  DiskBufferPool *bp = iter->second;
  buffer_pools_.erase(iter);
羽飞's avatar
羽飞 已提交
734 735
  lock_.unlock();
  
羽飞's avatar
羽飞 已提交
736
  delete bp;
羽飞's avatar
羽飞 已提交
737 738
  return RC::SUCCESS;
}
羽飞's avatar
羽飞 已提交
739 740 741 742

RC BufferPoolManager::flush_page(Frame &frame)
{
  int fd = frame.file_desc();
743 744

  std::scoped_lock lock_guard(lock_);
羽飞's avatar
羽飞 已提交
745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767
  auto iter = fd_buffer_pools_.find(fd);
  if (iter == fd_buffer_pools_.end()) {
    LOG_WARN("unknown buffer pool of fd %d", fd);
    return RC::INTERNAL;
  }

  DiskBufferPool *bp = iter->second;
  return bp->flush_page(frame);
}

static BufferPoolManager *default_bpm = nullptr;
void BufferPoolManager::set_instance(BufferPoolManager *bpm)
{
  if (default_bpm != nullptr && bpm != nullptr) {
    LOG_ERROR("default buffer pool manager has been setted");
    abort();
  }
  default_bpm = bpm;
}
BufferPoolManager &BufferPoolManager::instance()
{
  return *default_bpm;
}