disk_buffer_pool.cpp 19.6 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 17
//
#include "disk_buffer_pool.h"
#include <errno.h>
#include <string.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 24

using namespace common;

羽飞's avatar
羽飞 已提交
25
static const PageNum BP_HEADER_PAGE = 0;
羽飞's avatar
羽飞 已提交
26
static const int MEM_POOL_ITEM_NUM = 128;
L
Longda 已提交
27

羽飞's avatar
羽飞 已提交
28 29 30 31 32 33 34
unsigned long current_time()
{
  struct timespec tp;
  clock_gettime(CLOCK_MONOTONIC, &tp);
  return tp.tv_sec * 1000 * 1000 * 1000UL + tp.tv_nsec;
}

羽飞's avatar
羽飞 已提交
35
BPFrameManager::BPFrameManager(const char *name) : allocator_(name)
L
Longda 已提交
36 37
{}

羽飞's avatar
羽飞 已提交
38
RC BPFrameManager::init(int pool_num)
L
Longda 已提交
39
{
L
Longda Feng 已提交
40
  int ret = allocator_.init(false, pool_num);
羽飞's avatar
羽飞 已提交
41 42 43 44
  if (ret == 0) {
    return RC::SUCCESS;
  }
  return RC::GENERIC_ERROR;
L
Longda 已提交
45 46
}

羽飞's avatar
羽飞 已提交
47
RC BPFrameManager::cleanup()
L
Longda 已提交
48
{
羽飞's avatar
羽飞 已提交
49 50
  if (frames_.count() > 0) {
    return RC::GENERIC_ERROR;
L
Longda 已提交
51 52
  }

羽飞's avatar
羽飞 已提交
53 54 55 56 57
  frames_.destroy();
  return RC::SUCCESS;
}

Frame *BPFrameManager::begin_purge()
L
Longda 已提交
58
{
羽飞's avatar
羽飞 已提交
59
  Frame *frame_can_purge = nullptr;
L
Longda Feng 已提交
60
  auto purge_finder = [&frame_can_purge](const BPFrameId &frame_id, Frame *const frame) {
羽飞's avatar
羽飞 已提交
61 62
    if (frame->can_purge()) {
      frame_can_purge = frame;
L
Longda Feng 已提交
63
      return false;  // false to break the progress
羽飞's avatar
羽飞 已提交
64
    }
L
Longda Feng 已提交
65
    return true;  // true continue to look up
羽飞's avatar
羽飞 已提交
66 67 68 69
  };
  frames_.foreach_reverse(purge_finder);
  return frame_can_purge;
}
L
Longda 已提交
70

羽飞's avatar
羽飞 已提交
71 72 73
Frame *BPFrameManager::get(int file_desc, PageNum page_num)
{
  BPFrameId frame_id(file_desc, page_num);
L
Longda 已提交
74

羽飞's avatar
羽飞 已提交
75 76 77 78
  std::lock_guard<std::mutex> lock_guard(lock_);
  Frame *frame = nullptr;
  (void)frames_.get(frame_id, frame);
  return frame;
L
Longda 已提交
79 80
}

羽飞's avatar
羽飞 已提交
81
Frame *BPFrameManager::alloc(int file_desc, PageNum page_num)
L
Longda 已提交
82
{
羽飞's avatar
羽飞 已提交
83 84 85 86 87 88 89
  BPFrameId frame_id(file_desc, page_num);

  std::lock_guard<std::mutex> lock_guard(lock_);
  Frame *frame = nullptr;
  bool found = frames_.get(frame_id, frame);
  if (found) {
    // assert (frame != nullptr);
L
Longda Feng 已提交
90
    return nullptr;  // should use get
羽飞's avatar
羽飞 已提交
91 92 93 94 95 96 97
  }

  frame = allocator_.alloc();
  if (frame != nullptr) {
    frames_.put(frame_id, frame);
  }
  return frame;
L
Longda 已提交
98 99
}

羽飞's avatar
羽飞 已提交
100
RC BPFrameManager::free(int file_desc, PageNum page_num, Frame *frame)
L
Longda 已提交
101
{
羽飞's avatar
羽飞 已提交
102
  BPFrameId frame_id(file_desc, page_num);
L
Longda 已提交
103

羽飞's avatar
羽飞 已提交
104 105 106 107 108
  std::lock_guard<std::mutex> lock_guard(lock_);
  Frame *frame_source = nullptr;
  bool found = frames_.get(frame_id, frame_source);
  if (!found || frame != frame_source) {
    LOG_WARN("failed to find frame or got frame not match. file_desc=%d, PageNum=%d, frame_source=%p, frame=%p",
L
Longda Feng 已提交
109 110 111 112
        file_desc,
        page_num,
        frame_source,
        frame);
羽飞's avatar
羽飞 已提交
113 114
    return RC::GENERIC_ERROR;
  }
L
Longda 已提交
115

羽飞's avatar
羽飞 已提交
116 117 118
  frames_.remove(frame_id);
  allocator_.free(frame);
  return RC::SUCCESS;
L
Longda 已提交
119 120
}

羽飞's avatar
羽飞 已提交
121
std::list<Frame *> BPFrameManager::find_list(int file_desc)
L
Longda 已提交
122
{
羽飞's avatar
羽飞 已提交
123 124 125
  std::lock_guard<std::mutex> lock_guard(lock_);

  std::list<Frame *> frames;
L
Longda Feng 已提交
126
  auto fetcher = [&frames, file_desc](const BPFrameId &frame_id, Frame *const frame) -> bool {
羽飞's avatar
羽飞 已提交
127 128 129 130 131
    if (file_desc == frame_id.file_desc()) {
      frames.push_back(frame);
    }
    return true;
  };
L
Longda Feng 已提交
132
  frames_.foreach (fetcher);
羽飞's avatar
羽飞 已提交
133
  return frames;
L
Longda 已提交
134 135
}

羽飞's avatar
羽飞 已提交
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
////////////////////////////////////////////////////////////////////////////////
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
羽飞 已提交
154
  return bitmap_.next_setted_bit(current_page_num_ + 1) != -1;
羽飞's avatar
羽飞 已提交
155 156 157 158
}

PageNum BufferPoolIterator::next()
{
羽飞's avatar
羽飞 已提交
159
  PageNum next_page = bitmap_.next_setted_bit(current_page_num_ + 1);
羽飞's avatar
羽飞 已提交
160 161 162 163 164 165 166 167 168 169 170 171 172
  if (next_page != -1) {
    current_page_num_ = next_page;
  }
  return next_page;
}

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

////////////////////////////////////////////////////////////////////////////////
羽飞's avatar
羽飞 已提交
173
DiskBufferPool::DiskBufferPool(BufferPoolManager &bp_manager, BPFrameManager &frame_manager)
L
Longda Feng 已提交
174 175
    : bp_manager_(bp_manager), frame_manager_(frame_manager)
{}
羽飞's avatar
羽飞 已提交
176

L
Longda 已提交
177 178
DiskBufferPool::~DiskBufferPool()
{
羽飞's avatar
羽飞 已提交
179
  close_file();
L
Longda 已提交
180 181 182
  LOG_INFO("Exit");
}

羽飞's avatar
羽飞 已提交
183
RC DiskBufferPool::open_file(const char *file_name)
羽飞's avatar
羽飞 已提交
184
{
羽飞's avatar
羽飞 已提交
185
  int fd;
羽飞's avatar
羽飞 已提交
186 187 188 189 190 191
  if ((fd = open(file_name, O_RDWR)) < 0) {
    LOG_ERROR("Failed to open file %s, because %s.", file_name, strerror(errno));
    return RC::IOERR_ACCESS;
  }
  LOG_INFO("Successfully open file %s.", file_name);

羽飞's avatar
羽飞 已提交
192 193
  file_name_ = file_name;
  file_desc_ = fd;
羽飞's avatar
羽飞 已提交
194

羽飞's avatar
羽飞 已提交
195
  RC rc = RC::SUCCESS;
羽飞's avatar
羽飞 已提交
196
  rc = allocate_frame(BP_HEADER_PAGE, &hdr_frame_);
羽飞's avatar
羽飞 已提交
197 198
  if (rc != RC::SUCCESS) {
    LOG_ERROR("failed to allocate frame for header. file name %s", file_name_.c_str());
羽飞's avatar
羽飞 已提交
199
    close(fd);
羽飞's avatar
羽飞 已提交
200 201
    file_desc_ = -1;
    return rc;
羽飞's avatar
羽飞 已提交
202
  }
羽飞's avatar
羽飞 已提交
203 204 205 206 207 208

  hdr_frame_->dirty_ = false;
  hdr_frame_->file_desc_ = fd;
  hdr_frame_->pin_count_ = 1;
  hdr_frame_->acc_time_ = current_time();
  if ((rc = load_page(BP_HEADER_PAGE, hdr_frame_)) != RC::SUCCESS) {
L
Longda 已提交
209
    LOG_ERROR("Failed to load first page of %s, due to %s.", file_name, strerror(errno));
羽飞's avatar
羽飞 已提交
210
    hdr_frame_->pin_count_ = 0;
羽飞's avatar
羽飞 已提交
211
    purge_frame(BP_HEADER_PAGE, hdr_frame_);
羽飞's avatar
羽飞 已提交
212
    close(fd);
羽飞's avatar
羽飞 已提交
213 214
    file_desc_ = -1;
    return rc;
羽飞's avatar
羽飞 已提交
215 216
  }

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

羽飞's avatar
羽飞 已提交
219
  LOG_INFO("Successfully open %s. file_desc=%d, hdr_frame=%p", file_name, file_desc_, hdr_frame_);
羽飞's avatar
羽飞 已提交
220 221 222
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
223
RC DiskBufferPool::close_file()
羽飞's avatar
羽飞 已提交
224
{
羽飞's avatar
羽飞 已提交
225 226 227
  RC rc = RC::SUCCESS;
  if (file_desc_ < 0) {
    return rc;
羽飞's avatar
羽飞 已提交
228 229
  }

羽飞's avatar
羽飞 已提交
230
  hdr_frame_->pin_count_--;
羽飞's avatar
羽飞 已提交
231 232
  // TODO: 理论上是在回放时回滚未提交事务,但目前没有undo log,因此不下刷数据page,只通过redo log回放
  if ((rc = purge_page(0)) != RC::SUCCESS) {
羽飞's avatar
羽飞 已提交
233 234 235
    hdr_frame_->pin_count_++;
    LOG_ERROR("Failed to close %s, due to failed to purge all pages.", file_name_.c_str());
    return rc;
羽飞's avatar
羽飞 已提交
236 237
  }

羽飞's avatar
羽飞 已提交
238
  disposed_pages.clear();
L
Longda 已提交
239

羽飞's avatar
羽飞 已提交
240 241
  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
羽飞 已提交
242 243
    return RC::IOERR_CLOSE;
  }
羽飞's avatar
羽飞 已提交
244 245 246 247
  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
羽飞 已提交
248 249 250
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
251
RC DiskBufferPool::get_this_page(PageNum page_num, Frame **frame)
羽飞's avatar
羽飞 已提交
252
{
羽飞's avatar
羽飞 已提交
253
  RC rc = RC::SUCCESS;
羽飞's avatar
羽飞 已提交
254

羽飞's avatar
羽飞 已提交
255
  Frame *used_match_frame = frame_manager_.get(file_desc_, page_num);
L
Longda 已提交
256
  if (used_match_frame != nullptr) {
羽飞's avatar
羽飞 已提交
257 258
    used_match_frame->pin_count_++;
    used_match_frame->acc_time_ = current_time();
羽飞's avatar
羽飞 已提交
259

羽飞's avatar
羽飞 已提交
260
    *frame = used_match_frame;
L
Longda 已提交
261
    return RC::SUCCESS;
羽飞's avatar
羽飞 已提交
262 263 264
  }

  // Allocate one page and load the data into this page
羽飞's avatar
羽飞 已提交
265
  Frame *allocated_frame = nullptr;
羽飞's avatar
羽飞 已提交
266
  if ((rc = allocate_frame(page_num, &allocated_frame)) != RC::SUCCESS) {
羽飞's avatar
羽飞 已提交
267 268 269 270 271 272 273 274 275 276 277
    LOG_ERROR("Failed to alloc frame %s:%d, due to failed to alloc page.", file_name_.c_str(), page_num);
    return rc;
  }

  allocated_frame->dirty_ = false;
  allocated_frame->file_desc_ = file_desc_;
  allocated_frame->pin_count_ = 1;
  allocated_frame->acc_time_ = current_time();
  if ((rc = load_page(page_num, allocated_frame)) != RC::SUCCESS) {
    LOG_ERROR("Failed to load page %s:%d", file_name_.c_str(), page_num);
    allocated_frame->pin_count_ = 0;
羽飞's avatar
羽飞 已提交
278
    purge_frame(page_num, allocated_frame);
羽飞's avatar
羽飞 已提交
279 280 281 282
    return rc;
  }

  *frame = allocated_frame;
羽飞's avatar
羽飞 已提交
283 284 285
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
286
RC DiskBufferPool::allocate_page(Frame **frame)
羽飞's avatar
羽飞 已提交
287
{
羽飞's avatar
羽飞 已提交
288
  RC rc = RC::SUCCESS;
羽飞's avatar
羽飞 已提交
289 290

  int byte = 0, bit = 0;
羽飞's avatar
羽飞 已提交
291
  if ((file_header_->allocated_pages) < (file_header_->page_count)) {
羽飞's avatar
羽飞 已提交
292
    // There is one free page
羽飞's avatar
羽飞 已提交
293
    for (int i = 0; i < file_header_->page_count; i++) {
羽飞's avatar
羽飞 已提交
294 295
      byte = i / 8;
      bit = i % 8;
羽飞's avatar
羽飞 已提交
296 297 298
      if (((file_header_->bitmap[byte]) & (1 << bit)) == 0) {
        (file_header_->allocated_pages)++;
        file_header_->bitmap[byte] |= (1 << bit);
L
Longda 已提交
299
        // TODO,  do we need clean the loaded page's data?
L
Longda Feng 已提交
300
        hdr_frame_->mark_dirty();
羽飞's avatar
羽飞 已提交
301
        return get_this_page(i, frame);
羽飞's avatar
羽飞 已提交
302 303 304 305
      }
    }
  }

羽飞's avatar
羽飞 已提交
306 307
  if (file_header_->page_count >= BPFileHeader::MAX_PAGE_NUM) {
    LOG_WARN("file buffer pool is full. page count %d, max page count %d",
L
Longda Feng 已提交
308 309
        file_header_->page_count,
        BPFileHeader::MAX_PAGE_NUM);
羽飞's avatar
羽飞 已提交
310 311 312 313
    return BUFFERPOOL_NOBUF;
  }

  PageNum page_num = file_header_->page_count;
羽飞's avatar
羽飞 已提交
314
  Frame *allocated_frame = nullptr;
羽飞's avatar
羽飞 已提交
315
  if ((rc = allocate_frame(page_num, &allocated_frame)) != RC::SUCCESS) {
羽飞's avatar
羽飞 已提交
316 317
    LOG_ERROR("Failed to allocate frame %s, due to no free page.", file_name_.c_str());
    return rc;
羽飞's avatar
羽飞 已提交
318 319
  }

羽飞's avatar
羽飞 已提交
320 321
  file_header_->allocated_pages++;
  file_header_->page_count++;
羽飞's avatar
羽飞 已提交
322 323 324

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

羽飞's avatar
羽飞 已提交
328 329 330 331 332 333
  allocated_frame->dirty_ = false;
  allocated_frame->file_desc_ = file_desc_;
  allocated_frame->pin_count_ = 1;
  allocated_frame->acc_time_ = current_time();
  allocated_frame->clear_page();
  allocated_frame->page_.page_num = file_header_->page_count - 1;
羽飞's avatar
羽飞 已提交
334

L
Longda 已提交
335
  // Use flush operation to extension file
羽飞's avatar
羽飞 已提交
336 337
  if ((rc = flush_page(*allocated_frame)) != RC::SUCCESS) {
    LOG_WARN("Failed to alloc page %s , due to failed to extend one page.", file_name_.c_str());
L
Longda 已提交
338 339
    // skip return false, delay flush the extended page
    // return tmp;
羽飞's avatar
羽飞 已提交
340 341
  }

羽飞's avatar
羽飞 已提交
342
  *frame = allocated_frame;
羽飞's avatar
羽飞 已提交
343 344 345
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
346
RC DiskBufferPool::unpin_page(Frame *frame)
羽飞's avatar
羽飞 已提交
347
{
L
Longda Feng 已提交
348
  ASSERT(frame->pin_count_ >= 1, "Page %d 's pin_count is smaller than 1", frame->page_num());
羽飞's avatar
羽飞 已提交
349 350 351 352 353 354 355
  if (--frame->pin_count_ == 0) {
    PageNum page_num = frame->page_num();
    auto pages_it = disposed_pages.find(page_num);
    if (pages_it != disposed_pages.end()) {
      LOG_INFO("Dispose file_desc:%d, page:%d", file_desc_, page_num);
      dispose_page(page_num);
      disposed_pages.erase(pages_it);
L
Longda 已提交
356 357 358
    }
  }

羽飞's avatar
羽飞 已提交
359 360 361 362
  return RC::SUCCESS;
}

/**
L
Longda 已提交
363 364
 * dispose_page will delete the data of the page of pageNum, free the page both from buffer pool and data file.
 * purge_page will purge the page of pageNum, free the page from buffer pool
羽飞's avatar
羽飞 已提交
365 366
 * @return
 */
羽飞's avatar
羽飞 已提交
367
RC DiskBufferPool::dispose_page(PageNum page_num)
羽飞's avatar
羽飞 已提交
368
{
羽飞's avatar
羽飞 已提交
369
  RC rc = purge_page(page_num);
L
Longda 已提交
370
  if (rc != RC::SUCCESS) {
羽飞's avatar
羽飞 已提交
371
    LOG_INFO("Dispose page %s:%d later, due to this page is being used", file_name_.c_str(), page_num);
羽飞's avatar
羽飞 已提交
372

羽飞's avatar
羽飞 已提交
373
    disposed_pages.insert(page_num);
L
Longda 已提交
374
    return rc;
羽飞's avatar
羽飞 已提交
375 376
  }

羽飞's avatar
羽飞 已提交
377 378
  hdr_frame_->dirty_ = true;
  file_header_->allocated_pages--;
羽飞's avatar
羽飞 已提交
379
  char tmp = 1 << (page_num % 8);
羽飞's avatar
羽飞 已提交
380
  file_header_->bitmap[page_num / 8] &= ~tmp;
羽飞's avatar
羽飞 已提交
381 382 383
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
384
RC DiskBufferPool::purge_frame(PageNum page_num, Frame *buf)
羽飞's avatar
羽飞 已提交
385
{
羽飞's avatar
羽飞 已提交
386
  if (buf->pin_count_ > 0) {
羽飞's avatar
羽飞 已提交
387
    LOG_INFO("Begin to free page %d of %d(file id), but it's pinned, pin_count:%d.",
L
Longda Feng 已提交
388 389 390
        buf->page_num(),
        buf->file_desc_,
        buf->pin_count_);
L
Longda 已提交
391 392 393
    return RC::LOCKED_UNLOCK;
  }

羽飞's avatar
羽飞 已提交
394 395
  if (buf->dirty_) {
    RC rc = flush_page(*buf);
L
Longda 已提交
396
    if (rc != RC::SUCCESS) {
羽飞's avatar
羽飞 已提交
397
      LOG_WARN("Failed to flush page %d of %d(file desc) during purge page.", buf->page_num(), buf->file_desc_);
L
Longda 已提交
398 399 400 401
      return rc;
    }
  }

羽飞's avatar
羽飞 已提交
402
  LOG_DEBUG("Successfully purge frame =%p, page %d of %d(file desc)", buf, buf->page_num(), buf->file_desc_);
羽飞's avatar
羽飞 已提交
403
  frame_manager_.free(file_desc_, page_num, buf);
L
Longda 已提交
404
  return RC::SUCCESS;
羽飞's avatar
羽飞 已提交
405
}
L
Longda 已提交
406

羽飞's avatar
羽飞 已提交
407 408 409 410 411 412
/**
 * dispose_page will delete the data of the page of pageNum
 * force_page will flush the page of pageNum
 * @param pageNum
 * @return
 */
羽飞's avatar
羽飞 已提交
413
RC DiskBufferPool::purge_page(PageNum page_num)
羽飞's avatar
羽飞 已提交
414
{
羽飞's avatar
羽飞 已提交
415
  Frame *used_frame = frame_manager_.get(file_desc_, page_num);
L
Longda 已提交
416
  if (used_frame != nullptr) {
羽飞's avatar
羽飞 已提交
417
    return purge_frame(page_num, used_frame);
羽飞's avatar
羽飞 已提交
418
  }
L
Longda 已提交
419

羽飞's avatar
羽飞 已提交
420 421 422
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
423
RC DiskBufferPool::purge_all_pages()
羽飞's avatar
羽飞 已提交
424
{
羽飞's avatar
羽飞 已提交
425
  std::list<Frame *> used = frame_manager_.find_list(file_desc_);
L
Longda 已提交
426 427
  for (std::list<Frame *>::iterator it = used.begin(); it != used.end(); ++it) {
    Frame *frame = *it;
羽飞's avatar
羽飞 已提交
428
    if (frame->pin_count_ > 0) {
羽飞's avatar
羽飞 已提交
429
      LOG_WARN("The page has been pinned, file_desc:%d, pagenum:%d, pin_count=%d",
L
Longda Feng 已提交
430 431 432
          frame->file_desc_,
          frame->page_.page_num,
          frame->pin_count_);
羽飞's avatar
羽飞 已提交
433
      continue;
L
Longda 已提交
434
    }
羽飞's avatar
羽飞 已提交
435 436
    if (frame->dirty_) {
      RC rc = flush_page(*frame);
羽飞's avatar
羽飞 已提交
437
      if (rc != RC::SUCCESS) {
羽飞's avatar
羽飞 已提交
438
        LOG_ERROR("Failed to flush all pages' of %s.", file_name_.c_str());
羽飞's avatar
羽飞 已提交
439 440 441
        return rc;
      }
    }
羽飞's avatar
羽飞 已提交
442
    frame_manager_.free(file_desc_, frame->page_.page_num, frame);
羽飞's avatar
羽飞 已提交
443 444 445 446
  }
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
447
RC DiskBufferPool::check_all_pages_unpinned()
羽飞's avatar
羽飞 已提交
448
{
羽飞's avatar
羽飞 已提交
449
  std::list<Frame *> frames = frame_manager_.find_list(file_desc_);
L
Longda Feng 已提交
450
  for (auto &frame : frames) {
羽飞's avatar
羽飞 已提交
451 452
    if (frame->page_num() == BP_HEADER_PAGE && frame->pin_count_ > 1) {
      LOG_WARN("This page has been pinned. file desc=%d, page num:%d, pin count=%d",
L
Longda Feng 已提交
453 454 455
          file_desc_,
          frame->page_num(),
          frame->pin_count_);
羽飞's avatar
羽飞 已提交
456 457
    } else if (frame->page_num() != BP_HEADER_PAGE && frame->pin_count_ > 0) {
      LOG_WARN("This page has been pinned. file desc=%d, page num:%d, pin count=%d",
L
Longda Feng 已提交
458 459 460
          file_desc_,
          frame->page_num(),
          frame->pin_count_);
羽飞's avatar
羽飞 已提交
461 462
    }
  }
羽飞's avatar
羽飞 已提交
463
  LOG_INFO("all pages have been checked of file desc %d", file_desc_);
羽飞's avatar
羽飞 已提交
464 465 466
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
467
RC DiskBufferPool::flush_page(Frame &frame)
羽飞's avatar
羽飞 已提交
468 469 470 471
{
  // The better way is use mmap the block into memory,
  // so it is easier to flush data to file.

羽飞's avatar
羽飞 已提交
472 473 474 475
  Page &page = frame.page_;
  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
羽飞 已提交
476 477 478
    return RC::IOERR_SEEK;
  }

羽飞's avatar
羽飞 已提交
479
  if (writen(file_desc_, &page, sizeof(Page)) != 0) {
羽飞's avatar
羽飞 已提交
480
    LOG_ERROR("Failed to flush page %lld of %d due to %s.", offset, file_desc_, strerror(errno));
羽飞's avatar
羽飞 已提交
481 482
    return RC::IOERR_WRITE;
  }
羽飞's avatar
羽飞 已提交
483 484
  frame.dirty_ = false;
  LOG_DEBUG("Flush block. file desc=%d, page num=%d", file_desc_, page.page_num);
羽飞's avatar
羽飞 已提交
485 486 487 488

  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
489 490 491 492 493 494 495 496 497 498 499 500 501
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
羽飞 已提交
502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
RC DiskBufferPool::recover_page(PageNum page_num)
{
  int byte = 0, bit = 0;
  byte = page_num / 8;
  bit = page_num % 8;

  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
羽飞 已提交
517
RC DiskBufferPool::allocate_frame(PageNum page_num, Frame **buffer)
羽飞's avatar
羽飞 已提交
518
{
羽飞's avatar
羽飞 已提交
519 520 521 522 523 524
  while (true) {
    Frame *frame = frame_manager_.alloc(file_desc_, page_num);
    if (frame != nullptr) {
      *buffer = frame;
      return RC::SUCCESS;
    }
羽飞's avatar
羽飞 已提交
525

羽飞's avatar
羽飞 已提交
526 527 528 529
    frame = frame_manager_.begin_purge();
    if (frame == nullptr) {
      LOG_ERROR("All pages have been used and pinned.");
      return RC::NOMEM;
羽飞's avatar
羽飞 已提交
530 531
    }

羽飞's avatar
羽飞 已提交
532 533 534 535 536 537 538
    if (frame->dirty_) {
      RC rc = bp_manager_.flush_page(*frame);
      if (rc != RC::SUCCESS) {
        LOG_ERROR("Failed to aclloc block due to failed to flush old block.");
        return rc;
      }
    }
L
Longda 已提交
539

羽飞's avatar
羽飞 已提交
540 541 542
    frame_manager_.free(frame->file_desc(), frame->page_num(), frame);
  }
  return RC::INTERNAL;
羽飞's avatar
羽飞 已提交
543 544
}

羽飞's avatar
羽飞 已提交
545
RC DiskBufferPool::check_page_num(PageNum page_num)
羽飞's avatar
羽飞 已提交
546
{
羽飞's avatar
羽飞 已提交
547 548 549
  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
羽飞 已提交
550
  }
羽飞's avatar
羽飞 已提交
551 552 553
  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
羽飞 已提交
554 555 556 557
  }
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
558
RC DiskBufferPool::load_page(PageNum page_num, Frame *frame)
羽飞's avatar
羽飞 已提交
559
{
羽飞's avatar
羽飞 已提交
560 561
  s64_t offset = ((s64_t)page_num) * sizeof(Page);
  if (lseek(file_desc_, offset, SEEK_SET) == -1) {
L
Longda Feng 已提交
562
    LOG_ERROR("Failed to load page %s:%d, due to failed to lseek:%s.", file_name_.c_str(), page_num, strerror(errno));
羽飞's avatar
羽飞 已提交
563 564 565

    return RC::IOERR_SEEK;
  }
羽飞's avatar
羽飞 已提交
566 567 568 569

  int ret = readn(file_desc_, &(frame->page_), sizeof(Page));
  if (ret != 0) {
    LOG_ERROR("Failed to load page %s:%d, due to failed to read data:%s, ret=%d, page count=%d",
L
Longda Feng 已提交
570 571 572 573 574
        file_name_.c_str(),
        page_num,
        strerror(errno),
        ret,
        file_header_->allocated_pages);
羽飞's avatar
羽飞 已提交
575
    return RC::IOERR_READ;
羽飞's avatar
羽飞 已提交
576 577 578 579
  }
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
580
RC DiskBufferPool::get_page_count(int *page_count)
羽飞's avatar
羽飞 已提交
581
{
羽飞's avatar
羽飞 已提交
582 583 584 585 586 587 588 589 590 591
  *page_count = file_header_->allocated_pages;
  return RC::SUCCESS;
}
int DiskBufferPool::file_desc() const
{
  return file_desc_;
}
////////////////////////////////////////////////////////////////////////////////
BufferPoolManager::BufferPoolManager()
{
羽飞's avatar
羽飞 已提交
592
  frame_manager_.init(MEM_POOL_ITEM_NUM);
羽飞's avatar
羽飞 已提交
593 594 595 596 597 598
}

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

羽飞's avatar
羽飞 已提交
600 601
  for (auto &iter : tmp_bps) {
    delete iter.second;
羽飞's avatar
羽飞 已提交
602
  }
羽飞's avatar
羽飞 已提交
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636
}

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;
  memset(&page, 0, sizeof(Page));

  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
羽飞 已提交
637
  }
羽飞's avatar
羽飞 已提交
638

羽飞's avatar
羽飞 已提交
639
  if (writen(fd, (char *)&page, sizeof(Page)) != 0) {
羽飞's avatar
羽飞 已提交
640 641 642 643 644 645 646
    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
羽飞 已提交
647 648 649
  return RC::SUCCESS;
}

L
Longda Feng 已提交
650
RC BufferPoolManager::open_file(const char *_file_name, DiskBufferPool *&_bp)
羽飞's avatar
羽飞 已提交
651
{
羽飞's avatar
羽飞 已提交
652
  std::string file_name(_file_name);
L
Longda Feng 已提交
653

羽飞's avatar
羽飞 已提交
654 655 656 657
  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
羽飞 已提交
658

羽飞's avatar
羽飞 已提交
659 660 661 662 663 664
  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
羽飞 已提交
665
  }
羽飞's avatar
羽飞 已提交
666 667 668 669 670 671 672 673 674 675 676 677 678 679

  buffer_pools_.insert(std::pair<std::string, DiskBufferPool *>(file_name, bp));
  fd_buffer_pools_.insert(std::pair<int, DiskBufferPool *>(bp->file_desc(), bp));
  _bp = bp;
  return RC::SUCCESS;
}

RC BufferPoolManager::close_file(const char *_file_name)
{
  std::string file_name(_file_name);
  auto iter = buffer_pools_.find(file_name);
  if (iter == buffer_pools_.end()) {
    LOG_WARN("file has not opened: %s", _file_name);
    return RC::INTERNAL;
羽飞's avatar
羽飞 已提交
680
  }
羽飞's avatar
羽飞 已提交
681 682 683 684 685 686 687

  int fd = iter->second->file_desc();
  fd_buffer_pools_.erase(fd);

  DiskBufferPool *bp = iter->second;
  buffer_pools_.erase(iter);
  delete bp;
羽飞's avatar
羽飞 已提交
688 689
  return RC::SUCCESS;
}
羽飞's avatar
羽飞 已提交
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716

RC BufferPoolManager::flush_page(Frame &frame)
{
  int fd = frame.file_desc();
  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;
}