00001
00008 #include "file.h"
00009
00010 #include <fstream>
00011 #include <iostream>
00012 #include <memory>
00013 #include <string>
00014 #include <cstdio>
00015 #include <cassert>
00016
00017 #include "exceptions/file_exists_exception.h"
00018 #include "exceptions/file_not_found_exception.h"
00019 #include "exceptions/file_open_exception.h"
00020 #include "exceptions/invalid_page_exception.h"
00021 #include "file_iterator.h"
00022 #include "page.h"
00023
00024 namespace badgerdb {
00025
00026 File::StreamMap File::open_streams_;
00027 File::CountMap File::open_counts_;
00028
00029 File File::create(const std::string& filename) {
00030 return File(filename, true );
00031 }
00032
00033 File File::open(const std::string& filename) {
00034 return File(filename, false );
00035 }
00036
00037 void File::remove(const std::string& filename) {
00038 if (!exists(filename)) {
00039 throw FileNotFoundException(filename);
00040 }
00041 if (isOpen(filename)) {
00042 throw FileOpenException(filename);
00043 }
00044 std::remove(filename.c_str());
00045 }
00046
00047 bool File::isOpen(const std::string& filename) {
00048 if (!exists(filename)) {
00049 return false;
00050 }
00051 return open_counts_.find(filename) != open_counts_.end();
00052 }
00053
00054 bool File::exists(const std::string& filename) {
00055 std::fstream file(filename);
00056 if(file)
00057 {
00058 file.close();
00059 return true;
00060 }
00061
00062 return false;
00063 }
00064
00065 File::File(const File& other)
00066 : filename_(other.filename_),
00067 stream_(open_streams_[filename_]) {
00068 ++open_counts_[filename_];
00069 }
00070
00071 File& File::operator=(const File& rhs) {
00072
00073
00074 close();
00075 filename_ = rhs.filename_;
00076 openIfNeeded(false );
00077 return *this;
00078 }
00079
00080 File::~File() {
00081 close();
00082 }
00083
00084 Page File::allocatePage() {
00085 FileHeader header = readHeader();
00086 Page new_page;
00087 Page existing_page;
00088 if (header.num_free_pages > 0) {
00089 new_page = readPage(header.first_free_page, true );
00090 new_page.set_page_number(header.first_free_page);
00091 header.first_free_page = new_page.next_page_number();
00092 --header.num_free_pages;
00093
00094 if (header.first_used_page == Page::INVALID_NUMBER ||
00095 header.first_used_page > new_page.page_number()) {
00096
00097
00098 if (header.first_used_page > new_page.page_number()) {
00099 new_page.set_next_page_number(header.first_used_page);
00100 }
00101 header.first_used_page = new_page.page_number();
00102 } else {
00103
00104
00105 PageId next_page_number = Page::INVALID_NUMBER;
00106 for (FileIterator iter = begin(); iter != end(); ++iter) {
00107 next_page_number = (*iter).next_page_number();
00108 if (next_page_number > new_page.page_number() ||
00109 next_page_number == Page::INVALID_NUMBER) {
00110 existing_page = *iter;
00111 break;
00112 }
00113 }
00114 existing_page.set_next_page_number(new_page.page_number());
00115 new_page.set_next_page_number(next_page_number);
00116 }
00117
00118 assert((header.num_free_pages == 0) ==
00119 (header.first_free_page == Page::INVALID_NUMBER));
00120 } else {
00121 new_page.set_page_number(header.num_pages);
00122 if (header.first_used_page == Page::INVALID_NUMBER) {
00123 header.first_used_page = new_page.page_number();
00124 } else {
00125
00126
00127 for (FileIterator iter = begin(); iter != end(); ++iter) {
00128 if ((*iter).next_page_number() == Page::INVALID_NUMBER) {
00129 existing_page = *iter;
00130 break;
00131 }
00132 }
00133 assert(existing_page.isUsed());
00134 existing_page.set_next_page_number(new_page.page_number());
00135 }
00136 ++header.num_pages;
00137 }
00138 writePage(new_page.page_number(), new_page);
00139 if (existing_page.page_number() != Page::INVALID_NUMBER) {
00140
00141
00142 writePage(existing_page.page_number(), existing_page);
00143 }
00144 writeHeader(header);
00145
00146 return new_page;
00147 }
00148
00149 Page File::readPage(const PageId page_number) const {
00150 FileHeader header = readHeader();
00151 if (page_number >= header.num_pages) {
00152 throw InvalidPageException(page_number, filename_);
00153 }
00154 return readPage(page_number, false );
00155 }
00156
00157 Page File::readPage(const PageId page_number, const bool allow_free) const {
00158 Page page;
00159 stream_->seekg(pagePosition(page_number), std::ios::beg);
00160 stream_->read(reinterpret_cast<char*>(&page.header_), sizeof(page.header_));
00161 stream_->read(reinterpret_cast<char*>(&page.data_[0]), Page::DATA_SIZE);
00162 if (!allow_free && !page.isUsed()) {
00163 throw InvalidPageException(page_number, filename_);
00164 }
00165
00166 return page;
00167 }
00168
00169 void File::writePage(const Page& new_page) {
00170 PageHeader header = readPageHeader(new_page.page_number());
00171 if (header.current_page_number == Page::INVALID_NUMBER) {
00172
00173 throw InvalidPageException(new_page.page_number(), filename_);
00174 }
00175
00176
00177
00178 const PageId next_page_number = header.next_page_number;
00179 header = new_page.header_;
00180 header.next_page_number = next_page_number;
00181 writePage(new_page.page_number(), header, new_page);
00182 }
00183
00184 void File::deletePage(const PageId page_number) {
00185 FileHeader header = readHeader();
00186 Page existing_page = readPage(page_number);
00187 Page previous_page;
00188
00189
00190 if (page_number == header.first_used_page) {
00191 header.first_used_page = existing_page.next_page_number();
00192 } else {
00193
00194 for (FileIterator iter = begin(); iter != end(); ++iter) {
00195 previous_page = *iter;
00196 if (previous_page.next_page_number() == existing_page.page_number()) {
00197 previous_page.set_next_page_number(existing_page.next_page_number());
00198 break;
00199 }
00200 }
00201 }
00202
00203 existing_page.initialize();
00204 existing_page.set_next_page_number(header.first_free_page);
00205 header.first_free_page = page_number;
00206 ++header.num_free_pages;
00207 if (previous_page.isUsed()) {
00208 writePage(previous_page.page_number(), previous_page);
00209 }
00210 writePage(page_number, existing_page);
00211 writeHeader(header);
00212 }
00213
00214 FileIterator File::begin() {
00215 const FileHeader& header = readHeader();
00216 return FileIterator(this, header.first_used_page);
00217 }
00218
00219 FileIterator File::end() {
00220 return FileIterator(this, Page::INVALID_NUMBER);
00221 }
00222
00223 File::File(const std::string& name, const bool create_new) : filename_(name) {
00224 openIfNeeded(create_new);
00225
00226 if (create_new) {
00227
00228 FileHeader header = {1 , 0 ,
00229 0 , 0 };
00230 writeHeader(header);
00231 }
00232 }
00233
00234 void File::openIfNeeded(const bool create_new) {
00235 if (open_counts_.find(filename_) != open_counts_.end()) {
00236 ++open_counts_[filename_];
00237 stream_ = open_streams_[filename_];
00238 } else {
00239 std::ios_base::openmode mode =
00240 std::fstream::in | std::fstream::out | std::fstream::binary;
00241 const bool already_exists = exists(filename_);
00242 if (create_new) {
00243
00244 if (already_exists) {
00245 throw FileExistsException(filename_);
00246 }
00247
00248 mode = mode | std::fstream::trunc;
00249 } else {
00250
00251 if (!already_exists) {
00252 throw FileNotFoundException(filename_);
00253 }
00254 }
00255 stream_.reset(new std::fstream(filename_, mode));
00256 open_streams_[filename_] = stream_;
00257 open_counts_[filename_] = 1;
00258 }
00259 }
00260
00261 void File::close() {
00262 --open_counts_[filename_];
00263 stream_.reset();
00264 if (open_counts_[filename_] == 0) {
00265 open_streams_.erase(filename_);
00266 open_counts_.erase(filename_);
00267 }
00268 }
00269
00270 void File::writePage(const PageId page_number, const Page& new_page) {
00271 writePage(page_number, new_page.header_, new_page);
00272 }
00273
00274 void File::writePage(const PageId page_number, const PageHeader& header,
00275 const Page& new_page) {
00276 stream_->seekp(pagePosition(page_number), std::ios::beg);
00277 stream_->write(reinterpret_cast<const char*>(&header), sizeof(header));
00278 stream_->write(reinterpret_cast<const char*>(&new_page.data_[0]),
00279 Page::DATA_SIZE);
00280 stream_->flush();
00281 }
00282
00283 FileHeader File::readHeader() const {
00284 FileHeader header;
00285 stream_->seekg(0 , std::ios::beg);
00286 stream_->read(reinterpret_cast<char*>(&header), sizeof(header));
00287
00288 return header;
00289 }
00290
00291 void File::writeHeader(const FileHeader& header) {
00292 stream_->seekp(0 , std::ios::beg);
00293 stream_->write(reinterpret_cast<const char*>(&header), sizeof(header));
00294 stream_->flush();
00295 }
00296
00297 PageHeader File::readPageHeader(PageId page_number) const {
00298 PageHeader header;
00299 stream_->seekg(pagePosition(page_number), std::ios::beg);
00300 stream_->read(reinterpret_cast<char*>(&header), sizeof(header));
00301
00302 return header;
00303 }
00304
00305 }