Project: finder, src: BPTree.cc


B+ Tree ソースコード
#define _LARGEFILE64_SOURCE
#include "BPTree.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <cstdlib>
#include <assert.h>

// -------------------- ObjectStream クラスの実装 -------------------
BPTree::ObjectStream::ObjectStream(int fd, off_t offset) {
  this->fd = fd;
  this->header_offset = offset;
  this->footer_offset = offset + sizeof(header);
  lseek(fd, offset, SEEK_SET);
  read(fd, &header, sizeof(header));
  read(fd, &footer, sizeof(footer));
}

void BPTree::ObjectStream::append(const Serializer &obj) {
  off_t oftObj = lseek(fd, 0, SEEK_END);
  obj.writeObject(fd);
  off_t footerObj = lseek(fd, 0, SEEK_CUR), zero = 0;
  write(fd, &zero, sizeof(zero));

  if (header) {
    lseek(fd, header, SEEK_SET);
    write(fd, &oftObj, sizeof(oftObj));
  } else {
    lseek(fd, footer_offset, SEEK_SET);
    write(fd, &oftObj, sizeof(oftObj));
  }
  lseek(fd, header_offset, SEEK_SET);
  write(fd, &footerObj, sizeof(footerObj));
  footer_offset = footerObj;
  header = footerObj;
  footer = oftObj;
}

bool BPTree::ObjectStream::load(Serializer &obj) {
  // オブジェクトストリームは空
  if (footer == 0) return false;
  
  lseek(fd, footer, SEEK_SET);
  obj.readObject(fd);
  footer_offset = lseek(fd, 0, SEEK_CUR);
  read(fd, &footer, sizeof(footer)); 
  return true;
}

// ---------------- BPTree クラスの実装 --------------------
BPTree::BPTree(const std::string &filename, bool bTruncate) {
  int flags = O_RDWR | O_CREAT;
  if (bTruncate) {
    flags |= O_TRUNC;
  }
  int fd = open(filename.c_str(), flags, 0644);
  this->fd = fd;
  this->bptree = new BPTreeCore(fd);
  this->bCreate = true;
}

BPTree::BPTree(int fd) {
  this->fd = fd;
  this->bptree = new BPTreeCore(fd);
  this->bCreate = false;
}

BPTree::~BPTree() {
  delete bptree;
  bptree = 0;
  if (bCreate) {
    close(fd);
  }
}

void BPTree::append(const NGram &key, const Serializer &obj) {
  off_t offset;
  if (!bptree->find(key, &offset)) {
    // エントリがないので新たに header を作成する
    off_t newHeader = 0;
    offset = lseek(fd, 0, SEEK_END);
    write(fd, &newHeader, sizeof(newHeader)); //header
    write(fd, &newHeader, sizeof(newHeader)); //footer
    bptree->append(key, offset);
  }
  
  // header を読み込む
  BPTree::ObjectStream objStream(fd, offset);
  objStream.append(obj);
}

BPTree::ObjectStream BPTree::find(const NGram &key) {
  off_t offset;

  // エントリがなかった
  if (!bptree->find(key, &offset)) return BPTree::ObjectStream(false);

  // エントリを発見したので対応する ObjectStream を返す
  return BPTree::ObjectStream(fd, offset);
}