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