disk_buffer_pool.cpp 18.9 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
{
羽飞's avatar
羽飞 已提交
40 41 42 43 44
  int ret =  allocator_.init(false, pool_num);
  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 60 61 62 63 64 65 66 67 68 69
  Frame *frame_can_purge = nullptr;
  auto purge_finder = [&frame_can_purge](const BPFrameId &frame_id, Frame * const frame) {
    if (frame->can_purge()) {
      frame_can_purge = frame;
      return false; // false to break the progress
    }
    return true; // true continue to look up
  };
  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 90 91 92 93 94 95 96 97
  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);
    return nullptr; // should use get
  }

  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 109 110 111
  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",
             file_desc, page_num, frame_source, frame);
    return RC::GENERIC_ERROR;
  }
L
Longda 已提交
112

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

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

  std::list<Frame *> frames;
  auto fetcher = [&frames, file_desc](const BPFrameId &frame_id, Frame * const frame) -> bool {
    if (file_desc == frame_id.file_desc()) {
      frames.push_back(frame);
    }
    return true;
  };
  frames_.foreach(fetcher);
  return frames;
L
Longda 已提交
131 132
}

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

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

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

////////////////////////////////////////////////////////////////////////////////
羽飞's avatar
羽飞 已提交
170 171
DiskBufferPool::DiskBufferPool(BufferPoolManager &bp_manager, BPFrameManager &frame_manager)
  : bp_manager_(bp_manager), frame_manager_(frame_manager)
羽飞's avatar
羽飞 已提交
172 173 174
{
}

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

羽飞's avatar
羽飞 已提交
181
RC DiskBufferPool::open_file(const char *file_name)
羽飞's avatar
羽飞 已提交
182
{
羽飞's avatar
羽飞 已提交
183
  int fd;
羽飞's avatar
羽飞 已提交
184 185 186 187 188 189
  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
羽飞 已提交
190 191
  file_name_ = file_name;
  file_desc_ = fd;
羽飞's avatar
羽飞 已提交
192

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

  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 已提交
207
    LOG_ERROR("Failed to load first page of %s, due to %s.", file_name, strerror(errno));
羽飞's avatar
羽飞 已提交
208
    hdr_frame_->pin_count_ = 0;
羽飞's avatar
羽飞 已提交
209
    purge_frame(BP_HEADER_PAGE, hdr_frame_);
羽飞's avatar
羽飞 已提交
210
    close(fd);
羽飞's avatar
羽飞 已提交
211 212
    file_desc_ = -1;
    return rc;
羽飞's avatar
羽飞 已提交
213 214
  }

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

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

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

羽飞's avatar
羽飞 已提交
228 229 230 231 232
  hdr_frame_->pin_count_--;
  if ((rc = purge_all_pages()) != RC::SUCCESS) {
    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
羽飞 已提交
233 234
  }

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

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

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

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

羽飞's avatar
羽飞 已提交
257
    *frame = used_match_frame;
L
Longda 已提交
258
    return RC::SUCCESS;
羽飞's avatar
羽飞 已提交
259 260 261
  }

  // Allocate one page and load the data into this page
羽飞's avatar
羽飞 已提交
262
  Frame *allocated_frame = nullptr;
羽飞's avatar
羽飞 已提交
263
  if ((rc = allocate_frame(page_num, &allocated_frame)) != RC::SUCCESS) {
羽飞's avatar
羽飞 已提交
264 265 266 267 268 269 270 271 272 273 274
    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
羽飞 已提交
275
    purge_frame(page_num, allocated_frame);
羽飞's avatar
羽飞 已提交
276 277 278 279
    return rc;
  }

  *frame = allocated_frame;
羽飞's avatar
羽飞 已提交
280 281 282
  return RC::SUCCESS;
}

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

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

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

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

羽飞's avatar
羽飞 已提交
316 317
  file_header_->allocated_pages++;
  file_header_->page_count++;
羽飞's avatar
羽飞 已提交
318 319 320

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

羽飞's avatar
羽飞 已提交
324 325 326 327 328 329
  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
羽飞 已提交
330

L
Longda 已提交
331
  // Use flush operation to extension file
羽飞's avatar
羽飞 已提交
332 333
  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 已提交
334 335
    // skip return false, delay flush the extended page
    // return tmp;
羽飞's avatar
羽飞 已提交
336 337
  }

羽飞's avatar
羽飞 已提交
338
  *frame = allocated_frame;
羽飞's avatar
羽飞 已提交
339 340 341
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
342
RC DiskBufferPool::unpin_page(Frame *frame)
羽飞's avatar
羽飞 已提交
343
{
羽飞's avatar
羽飞 已提交
344 345
  assert(frame->pin_count_ >= 1);

羽飞's avatar
羽飞 已提交
346 347 348 349 350 351 352
  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 已提交
353 354 355
    }
  }

羽飞's avatar
羽飞 已提交
356 357 358 359
  return RC::SUCCESS;
}

/**
L
Longda 已提交
360 361
 * 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
羽飞 已提交
362 363
 * @return
 */
羽飞's avatar
羽飞 已提交
364
RC DiskBufferPool::dispose_page(PageNum page_num)
羽飞's avatar
羽飞 已提交
365
{
羽飞's avatar
羽飞 已提交
366
  RC rc = purge_page(page_num);
L
Longda 已提交
367
  if (rc != RC::SUCCESS) {
羽飞's avatar
羽飞 已提交
368
    LOG_INFO("Dispose page %s:%d later, due to this page is being used", file_name_.c_str(), page_num);
羽飞's avatar
羽飞 已提交
369

羽飞's avatar
羽飞 已提交
370
    disposed_pages.insert(page_num);
L
Longda 已提交
371
    return rc;
羽飞's avatar
羽飞 已提交
372 373
  }

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

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

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

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

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

羽飞's avatar
羽飞 已提交
415 416 417
  return RC::SUCCESS;
}

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

羽飞's avatar
羽飞 已提交
440
RC DiskBufferPool::check_all_pages_unpinned()
羽飞's avatar
羽飞 已提交
441
{
羽飞's avatar
羽飞 已提交
442
  std::list<Frame *> frames = frame_manager_.find_list(file_desc_);
羽飞's avatar
羽飞 已提交
443
  for (auto & frame : frames) {
羽飞's avatar
羽飞 已提交
444 445 446 447 448 449
    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",
	       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, page num:%d, pin count=%d",
	       file_desc_, frame->page_num(), frame->pin_count_);
羽飞's avatar
羽飞 已提交
450 451
    }
  }
羽飞's avatar
羽飞 已提交
452
  LOG_INFO("all pages have been checked of file desc %d", file_desc_);
羽飞's avatar
羽飞 已提交
453 454 455
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
456
RC DiskBufferPool::flush_page(Frame &frame)
羽飞's avatar
羽飞 已提交
457 458 459 460
{
  // The better way is use mmap the block into memory,
  // so it is easier to flush data to file.

羽飞's avatar
羽飞 已提交
461 462 463 464
  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
羽飞 已提交
465 466 467
    return RC::IOERR_SEEK;
  }

羽飞's avatar
羽飞 已提交
468
  if (writen(file_desc_, &page, sizeof(Page)) != 0) {
羽飞's avatar
羽飞 已提交
469
    LOG_ERROR("Failed to flush page %lld of %d due to %s.", offset, file_desc_, strerror(errno));
羽飞's avatar
羽飞 已提交
470 471
    return RC::IOERR_WRITE;
  }
羽飞's avatar
羽飞 已提交
472 473
  frame.dirty_ = false;
  LOG_DEBUG("Flush block. file desc=%d, page num=%d", file_desc_, page.page_num);
羽飞's avatar
羽飞 已提交
474 475 476 477

  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
478 479 480 481 482 483 484 485 486 487 488 489 490
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
羽飞 已提交
491
RC DiskBufferPool::allocate_frame(PageNum page_num, Frame **buffer)
羽飞's avatar
羽飞 已提交
492
{
羽飞's avatar
羽飞 已提交
493 494 495 496 497 498
  while (true) {
    Frame *frame = frame_manager_.alloc(file_desc_, page_num);
    if (frame != nullptr) {
      *buffer = frame;
      return RC::SUCCESS;
    }
羽飞's avatar
羽飞 已提交
499

羽飞's avatar
羽飞 已提交
500 501 502 503
    frame = frame_manager_.begin_purge();
    if (frame == nullptr) {
      LOG_ERROR("All pages have been used and pinned.");
      return RC::NOMEM;
羽飞's avatar
羽飞 已提交
504 505
    }

羽飞's avatar
羽飞 已提交
506 507 508 509 510 511 512
    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 已提交
513

羽飞's avatar
羽飞 已提交
514 515 516
    frame_manager_.free(frame->file_desc(), frame->page_num(), frame);
  }
  return RC::INTERNAL;
羽飞's avatar
羽飞 已提交
517 518
}

羽飞's avatar
羽飞 已提交
519
RC DiskBufferPool::check_page_num(PageNum page_num)
羽飞's avatar
羽飞 已提交
520
{
羽飞's avatar
羽飞 已提交
521 522 523
  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
羽飞 已提交
524
  }
羽飞's avatar
羽飞 已提交
525 526 527
  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
羽飞 已提交
528 529 530 531
  }
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
532
RC DiskBufferPool::load_page(PageNum page_num, Frame *frame)
羽飞's avatar
羽飞 已提交
533
{
羽飞's avatar
羽飞 已提交
534 535 536 537 538 539 540
  s64_t offset = ((s64_t)page_num) * sizeof(Page);
  if (lseek(file_desc_, offset, SEEK_SET) == -1) {
    LOG_ERROR("Failed to load page %s:%d, due to failed to lseek:%s.",
	      file_name_.c_str(), page_num, strerror(errno));

    return RC::IOERR_SEEK;
  }
羽飞's avatar
羽飞 已提交
541 542 543 544 545

  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",
	      file_name_.c_str(), page_num, strerror(errno), ret, file_header_->allocated_pages);
羽飞's avatar
羽飞 已提交
546
    return RC::IOERR_READ;
羽飞's avatar
羽飞 已提交
547 548 549 550
  }
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
551
RC DiskBufferPool::get_page_count(int *page_count)
羽飞's avatar
羽飞 已提交
552
{
羽飞's avatar
羽飞 已提交
553 554 555 556 557 558 559 560 561 562
  *page_count = file_header_->allocated_pages;
  return RC::SUCCESS;
}
int DiskBufferPool::file_desc() const
{
  return file_desc_;
}
////////////////////////////////////////////////////////////////////////////////
BufferPoolManager::BufferPoolManager()
{
羽飞's avatar
羽飞 已提交
563
  frame_manager_.init(MEM_POOL_ITEM_NUM);
羽飞's avatar
羽飞 已提交
564 565 566 567 568 569 570 571 572
}

BufferPoolManager::~BufferPoolManager()
{
  std::unordered_map<std::string, DiskBufferPool *> tmp_bps;
  tmp_bps.swap(buffer_pools_);
  
  for (auto &iter : tmp_bps) {
    delete iter.second;
羽飞's avatar
羽飞 已提交
573
  }
羽飞's avatar
羽飞 已提交
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607
}

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

羽飞's avatar
羽飞 已提交
610
  if (writen(fd, (char *)&page, sizeof(Page)) != 0) {
羽飞's avatar
羽飞 已提交
611 612 613 614 615 616 617
    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
羽飞 已提交
618 619 620
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
621
RC BufferPoolManager::open_file(const char *_file_name, DiskBufferPool *& _bp)
羽飞's avatar
羽飞 已提交
622
{
羽飞's avatar
羽飞 已提交
623 624 625 626 627 628
  std::string file_name(_file_name);
  
  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
羽飞 已提交
629

羽飞's avatar
羽飞 已提交
630 631 632 633 634 635
  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
羽飞 已提交
636
  }
羽飞's avatar
羽飞 已提交
637 638 639 640 641 642 643 644 645 646 647 648 649 650

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

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

  DiskBufferPool *bp = iter->second;
  buffer_pools_.erase(iter);
  delete bp;
羽飞's avatar
羽飞 已提交
659 660
  return RC::SUCCESS;
}
羽飞's avatar
羽飞 已提交
661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687

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;
}