disk_buffer_pool.cpp 16.1 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 22 23

using namespace common;

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

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

羽飞's avatar
羽飞 已提交
34
BPFrameManager::BPFrameManager(const char *name) : MemPoolSimple<Frame>(name)
L
Longda 已提交
35 36 37 38 39 40 41 42
{}

static bool match_purge(void *item, void *arg)
{
  Frame *frame = (Frame *)item;
  return frame->can_purge();
}

羽飞's avatar
羽飞 已提交
43
Frame *BPFrameManager::begin_purge()
L
Longda 已提交
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
{
  return MemPoolSimple<Frame>::find(match_purge, nullptr);
}

struct MatchFilePage {
  MatchFilePage(int file_desc, PageNum page_num)
  {
    this->file_desc = file_desc;
    this->page_num = page_num;
  }
  int file_desc;
  PageNum page_num;
};

static bool match_file_page(void *item, void *arg)
{
  Frame *frame = (Frame *)item;
  MatchFilePage *file_page = (MatchFilePage *)arg;

羽飞's avatar
羽飞 已提交
63
  if (frame->file_desc() == file_page->file_desc && frame->page_num() == file_page->page_num)
L
Longda 已提交
64 65 66 67 68
    return true;

  return false;
}

羽飞's avatar
羽飞 已提交
69
Frame *BPFrameManager::get(int file_desc, PageNum page_num)
L
Longda 已提交
70 71 72 73 74 75 76 77 78 79
{
  MatchFilePage file_page(file_desc, page_num);
  return MemPoolSimple<Frame>::find(match_file_page, &file_page);
}

static bool match_file(void *item, void *arg)
{
  Frame *frame = (Frame *)item;
  int *file_desc = (int *)arg;

羽飞's avatar
羽飞 已提交
80
  if (frame->file_desc() == *file_desc)
L
Longda 已提交
81 82 83 84 85
    return true;

  return false;
}

羽飞's avatar
羽飞 已提交
86
std::list<Frame *> BPFrameManager::find_list(int file_desc)
L
Longda 已提交
87 88 89 90
{
  return find_all(match_file, &file_desc);
}

羽飞's avatar
羽飞 已提交
91 92
DiskBufferPool::DiskBufferPool(BufferPoolManager &bp_manager, BPFrameManager &frame_manager)
  : bp_manager_(bp_manager), frame_manager_(frame_manager)
羽飞's avatar
羽飞 已提交
93 94 95
{
}

L
Longda 已提交
96 97
DiskBufferPool::~DiskBufferPool()
{
羽飞's avatar
羽飞 已提交
98
  close_file();
L
Longda 已提交
99 100 101
  LOG_INFO("Exit");
}

羽飞's avatar
羽飞 已提交
102
RC DiskBufferPool::open_file(const char *file_name)
羽飞's avatar
羽飞 已提交
103
{
羽飞's avatar
羽飞 已提交
104
  int fd;
羽飞's avatar
羽飞 已提交
105 106 107 108 109 110
  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
羽飞 已提交
111 112
  file_name_ = file_name;
  file_desc_ = fd;
羽飞's avatar
羽飞 已提交
113

羽飞's avatar
羽飞 已提交
114 115 116 117
  RC rc = RC::SUCCESS;
  rc = allocate_frame(&hdr_frame_);
  if (rc != RC::SUCCESS) {
    LOG_ERROR("failed to allocate frame for header. file name %s", file_name_.c_str());
羽飞's avatar
羽飞 已提交
118
    close(fd);
羽飞's avatar
羽飞 已提交
119 120
    file_desc_ = -1;
    return rc;
羽飞's avatar
羽飞 已提交
121
  }
羽飞's avatar
羽飞 已提交
122 123 124 125 126 127

  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 已提交
128
    LOG_ERROR("Failed to load first page of %s, due to %s.", file_name, strerror(errno));
羽飞's avatar
羽飞 已提交
129 130
    hdr_frame_->pin_count_ = 0;
    purge_frame(hdr_frame_);
羽飞's avatar
羽飞 已提交
131
    close(fd);
羽飞's avatar
羽飞 已提交
132 133
    file_desc_ = -1;
    return rc;
羽飞's avatar
羽飞 已提交
134 135
  }

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

羽飞's avatar
羽飞 已提交
138
  LOG_INFO("Successfully open %s. file_desc=%d, hdr_frame=%p", file_name, file_desc_, hdr_frame_);
羽飞's avatar
羽飞 已提交
139 140 141
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
142
RC DiskBufferPool::close_file()
羽飞's avatar
羽飞 已提交
143
{
羽飞's avatar
羽飞 已提交
144 145 146
  RC rc = RC::SUCCESS;
  if (file_desc_ < 0) {
    return rc;
羽飞's avatar
羽飞 已提交
147 148
  }

羽飞's avatar
羽飞 已提交
149 150 151 152 153
  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
羽飞 已提交
154 155
  }

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

羽飞's avatar
羽飞 已提交
158 159
  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
羽飞 已提交
160 161
    return RC::IOERR_CLOSE;
  }
羽飞's avatar
羽飞 已提交
162 163 164 165
  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
羽飞 已提交
166 167 168
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
169
RC DiskBufferPool::get_this_page(PageNum page_num, Frame **frame)
羽飞's avatar
羽飞 已提交
170
{
羽飞's avatar
羽飞 已提交
171
  RC rc = RC::SUCCESS;
羽飞's avatar
羽飞 已提交
172

羽飞's avatar
羽飞 已提交
173
  Frame *used_match_frame = frame_manager_.get(file_desc_, page_num);
L
Longda 已提交
174
  if (used_match_frame != nullptr) {
羽飞's avatar
羽飞 已提交
175 176
    used_match_frame->pin_count_++;
    used_match_frame->acc_time_ = current_time();
羽飞's avatar
羽飞 已提交
177

羽飞's avatar
羽飞 已提交
178
    frame_manager_.mark_modified(used_match_frame);
L
Longda 已提交
179

羽飞's avatar
羽飞 已提交
180
    *frame = used_match_frame;
L
Longda 已提交
181
    return RC::SUCCESS;
羽飞's avatar
羽飞 已提交
182 183 184
  }

  // Allocate one page and load the data into this page
羽飞's avatar
羽飞 已提交
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
  Frame *allocated_frame = nullptr;
  if ((rc = allocate_frame(&allocated_frame)) != RC::SUCCESS) {
    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;
    purge_frame(allocated_frame);
    return rc;
  }

  *frame = allocated_frame;
羽飞's avatar
羽飞 已提交
203 204 205
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
206
RC DiskBufferPool::allocate_page(Frame **frame)
羽飞's avatar
羽飞 已提交
207
{
羽飞's avatar
羽飞 已提交
208
  RC rc = RC::SUCCESS;
羽飞's avatar
羽飞 已提交
209 210

  int byte = 0, bit = 0;
羽飞's avatar
羽飞 已提交
211
  if ((file_header_->allocated_pages) < (file_header_->page_count)) {
羽飞's avatar
羽飞 已提交
212
    // There is one free page
羽飞's avatar
羽飞 已提交
213
    for (int i = 0; i < file_header_->page_count; i++) {
羽飞's avatar
羽飞 已提交
214 215
      byte = i / 8;
      bit = i % 8;
羽飞's avatar
羽飞 已提交
216 217 218
      if (((file_header_->bitmap[byte]) & (1 << bit)) == 0) {
        (file_header_->allocated_pages)++;
        file_header_->bitmap[byte] |= (1 << bit);
L
Longda 已提交
219
        // TODO,  do we need clean the loaded page's data?
羽飞's avatar
羽飞 已提交
220 221
	hdr_frame_->mark_dirty();
        return get_this_page(i, frame);
羽飞's avatar
羽飞 已提交
222 223 224 225
      }
    }
  }

羽飞's avatar
羽飞 已提交
226 227 228 229
  Frame *allocated_frame = nullptr;
  if ((rc = allocate_frame(&allocated_frame)) != RC::SUCCESS) {
    LOG_ERROR("Failed to allocate frame %s, due to no free page.", file_name_.c_str());
    return rc;
羽飞's avatar
羽飞 已提交
230 231
  }

羽飞's avatar
羽飞 已提交
232 233 234
  PageNum page_num = file_header_->page_count;
  file_header_->allocated_pages++;
  file_header_->page_count++;
羽飞's avatar
羽飞 已提交
235 236 237

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

羽飞's avatar
羽飞 已提交
241 242 243 244 245 246
  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
羽飞 已提交
247

L
Longda 已提交
248
  // Use flush operation to extension file
羽飞's avatar
羽飞 已提交
249 250
  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 已提交
251 252
    // skip return false, delay flush the extended page
    // return tmp;
羽飞's avatar
羽飞 已提交
253 254
  }

羽飞's avatar
羽飞 已提交
255
  *frame = allocated_frame;
羽飞's avatar
羽飞 已提交
256 257 258
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
259
RC DiskBufferPool::unpin_page(Frame *frame)
羽飞's avatar
羽飞 已提交
260
{
羽飞's avatar
羽飞 已提交
261 262 263 264 265 266 267
  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 已提交
268 269 270
    }
  }

羽飞's avatar
羽飞 已提交
271 272 273 274
  return RC::SUCCESS;
}

/**
L
Longda 已提交
275 276
 * 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
羽飞 已提交
277 278
 * @return
 */
羽飞's avatar
羽飞 已提交
279
RC DiskBufferPool::dispose_page(PageNum page_num)
羽飞's avatar
羽飞 已提交
280
{
羽飞's avatar
羽飞 已提交
281
  RC rc = purge_page(page_num);
L
Longda 已提交
282
  if (rc != RC::SUCCESS) {
羽飞's avatar
羽飞 已提交
283
    LOG_INFO("Dispose page %s:%d later, due to this page is being used", file_name_.c_str(), page_num);
羽飞's avatar
羽飞 已提交
284

羽飞's avatar
羽飞 已提交
285
    disposed_pages.insert(page_num);
L
Longda 已提交
286
    return rc;
羽飞's avatar
羽飞 已提交
287 288
  }

羽飞's avatar
羽飞 已提交
289 290
  hdr_frame_->dirty_ = true;
  file_header_->allocated_pages--;
羽飞's avatar
羽飞 已提交
291
  char tmp = 1 << (page_num % 8);
羽飞's avatar
羽飞 已提交
292
  file_header_->bitmap[page_num / 8] &= ~tmp;
羽飞's avatar
羽飞 已提交
293 294 295
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
296
RC DiskBufferPool::purge_frame(Frame *buf)
羽飞's avatar
羽飞 已提交
297
{
羽飞's avatar
羽飞 已提交
298
  if (buf->pin_count_ > 0) {
羽飞's avatar
羽飞 已提交
299
    LOG_INFO("Begin to free page %d of %d(file id), but it's pinned, pin_count:%d.",
羽飞's avatar
羽飞 已提交
300
	     buf->page_num(), buf->file_desc_, buf->pin_count_);
L
Longda 已提交
301 302 303
    return RC::LOCKED_UNLOCK;
  }

羽飞's avatar
羽飞 已提交
304 305
  if (buf->dirty_) {
    RC rc = flush_page(*buf);
L
Longda 已提交
306
    if (rc != RC::SUCCESS) {
羽飞's avatar
羽飞 已提交
307
      LOG_WARN("Failed to flush page %d of %d(file desc) during purge page.", buf->page_num(), buf->file_desc_);
L
Longda 已提交
308 309 310 311
      return rc;
    }
  }

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

羽飞's avatar
羽飞 已提交
317 318 319 320 321 322
/**
 * dispose_page will delete the data of the page of pageNum
 * force_page will flush the page of pageNum
 * @param pageNum
 * @return
 */
羽飞's avatar
羽飞 已提交
323
RC DiskBufferPool::purge_page(PageNum page_num)
羽飞's avatar
羽飞 已提交
324
{
羽飞's avatar
羽飞 已提交
325
  Frame *used_frame = frame_manager_.get(file_desc_, page_num);
L
Longda 已提交
326
  if (used_frame != nullptr) {
羽飞's avatar
羽飞 已提交
327
    return purge_frame(used_frame);
羽飞's avatar
羽飞 已提交
328
  }
L
Longda 已提交
329

羽飞's avatar
羽飞 已提交
330 331 332
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
333
RC DiskBufferPool::purge_all_pages()
羽飞's avatar
羽飞 已提交
334
{
羽飞's avatar
羽飞 已提交
335
  std::list<Frame *> used = frame_manager_.find_list(file_desc_);
L
Longda 已提交
336 337
  for (std::list<Frame *>::iterator it = used.begin(); it != used.end(); ++it) {
    Frame *frame = *it;
羽飞's avatar
羽飞 已提交
338
    if (frame->pin_count_ > 0) {
羽飞's avatar
羽飞 已提交
339
      LOG_WARN("The page has been pinned, file_desc:%d, pagenum:%d, pin_count=%d",
羽飞's avatar
羽飞 已提交
340
	       frame->file_desc_, frame->page_.page_num, frame->pin_count_);
羽飞's avatar
羽飞 已提交
341
      continue;
L
Longda 已提交
342
    }
羽飞's avatar
羽飞 已提交
343 344
    if (frame->dirty_) {
      RC rc = flush_page(*frame);
羽飞's avatar
羽飞 已提交
345
      if (rc != RC::SUCCESS) {
羽飞's avatar
羽飞 已提交
346
        LOG_ERROR("Failed to flush all pages' of %s.", file_name_.c_str());
羽飞's avatar
羽飞 已提交
347 348 349
        return rc;
      }
    }
羽飞's avatar
羽飞 已提交
350
    frame_manager_.free(frame);
羽飞's avatar
羽飞 已提交
351 352 353 354
  }
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
355
RC DiskBufferPool::check_all_pages_unpinned()
羽飞's avatar
羽飞 已提交
356
{
羽飞's avatar
羽飞 已提交
357
  std::list<Frame *> frames = frame_manager_.find_list(file_desc_);
羽飞's avatar
羽飞 已提交
358
  for (auto & frame : frames) {
羽飞's avatar
羽飞 已提交
359 360 361 362 363 364
    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
羽飞 已提交
365 366
    }
  }
羽飞's avatar
羽飞 已提交
367
  LOG_INFO("all pages have been checked of file desc %d", file_desc_);
羽飞's avatar
羽飞 已提交
368 369 370
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
371
RC DiskBufferPool::flush_page(Frame &frame)
羽飞's avatar
羽飞 已提交
372 373 374 375
{
  // The better way is use mmap the block into memory,
  // so it is easier to flush data to file.

羽飞's avatar
羽飞 已提交
376 377 378 379
  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
羽飞 已提交
380 381 382
    return RC::IOERR_SEEK;
  }

羽飞's avatar
羽飞 已提交
383 384
  if (write(file_desc_, &page, sizeof(Page)) != sizeof(Page)) {
    LOG_ERROR("Failed to flush page %lld of %d due to %s.", offset, file_desc_, strerror(errno));
羽飞's avatar
羽飞 已提交
385 386
    return RC::IOERR_WRITE;
  }
羽飞's avatar
羽飞 已提交
387 388
  frame.dirty_ = false;
  LOG_DEBUG("Flush block. file desc=%d, page num=%d", file_desc_, page.page_num);
羽飞's avatar
羽飞 已提交
389 390 391 392

  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
393
RC DiskBufferPool::allocate_frame(Frame **buffer)
羽飞's avatar
羽飞 已提交
394
{
羽飞's avatar
羽飞 已提交
395
  Frame *frame = frame_manager_.alloc();
L
Longda 已提交
396 397 398
  if (frame != nullptr) {
    *buffer = frame;
    return RC::SUCCESS;
羽飞's avatar
羽飞 已提交
399 400
  }

羽飞's avatar
羽飞 已提交
401
  frame = frame_manager_.begin_purge();
L
Longda 已提交
402
  if (frame == nullptr) {
羽飞's avatar
羽飞 已提交
403 404 405 406
    LOG_ERROR("All pages have been used and pinned.");
    return RC::NOMEM;
  }

羽飞's avatar
羽飞 已提交
407 408
  if (frame->dirty_) {
    RC rc = bp_manager_.flush_page(*frame);
羽飞's avatar
羽飞 已提交
409
    if (rc != RC::SUCCESS) {
L
Longda 已提交
410
      LOG_ERROR("Failed to aclloc block due to failed to flush old block.");
羽飞's avatar
羽飞 已提交
411 412 413 414
      return rc;
    }
  }

羽飞's avatar
羽飞 已提交
415
  frame_manager_.mark_modified(frame);
L
Longda 已提交
416 417

  *buffer = frame;
羽飞's avatar
羽飞 已提交
418 419 420
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
421
RC DiskBufferPool::check_page_num(PageNum page_num)
羽飞's avatar
羽飞 已提交
422
{
羽飞's avatar
羽飞 已提交
423 424 425
  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
羽飞 已提交
426
  }
羽飞's avatar
羽飞 已提交
427 428 429
  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
羽飞 已提交
430 431 432 433
  }
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
434
RC DiskBufferPool::load_page(PageNum page_num, Frame *frame)
羽飞's avatar
羽飞 已提交
435
{
羽飞's avatar
羽飞 已提交
436 437 438 439 440 441 442 443 444 445 446
  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;
  }
  if (read(file_desc_, &(frame->page_), sizeof(Page)) != sizeof(Page)) {
    LOG_ERROR("Failed to load page %s:%d, due to failed to read data:%s.",
	      file_name_.c_str(), page_num, strerror(errno));
    return RC::IOERR_READ;
羽飞's avatar
羽飞 已提交
447 448 449 450
  }
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
451
RC DiskBufferPool::get_page_count(int *page_count)
羽飞's avatar
羽飞 已提交
452
{
羽飞's avatar
羽飞 已提交
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
  *page_count = file_header_->allocated_pages;
  return RC::SUCCESS;
}
int DiskBufferPool::file_desc() const
{
  return file_desc_;
}
////////////////////////////////////////////////////////////////////////////////
BufferPoolManager::BufferPoolManager()
{
  frame_manager_.init(true/*dynamic*/, MEM_POOL_ITEM_NUM);
}

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
羽飞 已提交
473
  }
羽飞's avatar
羽飞 已提交
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
}

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
羽飞 已提交
508
  }
羽飞's avatar
羽飞 已提交
509 510 511 512 513 514 515 516 517

  if (write(fd, (char *)&page, sizeof(Page)) != sizeof(Page)) {
    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
羽飞 已提交
518 519 520
  return RC::SUCCESS;
}

羽飞's avatar
羽飞 已提交
521
RC BufferPoolManager::open_file(const char *_file_name, DiskBufferPool *& _bp)
羽飞's avatar
羽飞 已提交
522
{
羽飞's avatar
羽飞 已提交
523 524 525 526 527 528
  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
羽飞 已提交
529

羽飞's avatar
羽飞 已提交
530 531 532 533 534 535
  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
羽飞 已提交
536
  }
羽飞's avatar
羽飞 已提交
537 538 539 540 541 542 543 544 545 546 547 548 549 550

  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
羽飞 已提交
551
  }
羽飞's avatar
羽飞 已提交
552 553 554 555 556 557 558

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

  DiskBufferPool *bp = iter->second;
  buffer_pools_.erase(iter);
  delete bp;
羽飞's avatar
羽飞 已提交
559 560
  return RC::SUCCESS;
}
羽飞's avatar
羽飞 已提交
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587

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