// recstore.h /* * Copyright (C) 2010 10gen Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #pragma once #include "../util/file.h" namespace mongo { using boost::uint32_t; using boost::uint64_t; /* Current version supports only consistent record sizes within a store. */ class BasicRecStore { struct RecStoreHeader { uint32_t version; uint32_t recsize; uint64_t leof; // logical eof, actual file might be prealloc'd further uint64_t firstDeleted; // 0 = no deleted recs uint32_t cleanShutdown; // 0 = clean char reserved[8192-8-8-4-4-4]; // we want our records page-aligned in the file if they are a multiple of a page's size -- so we make this 8KB with that goal RecStoreHeader() { version = 65; recsize = 0; leof = sizeof(RecStoreHeader); firstDeleted = 0; cleanShutdown = 1; memset(reserved, 0, sizeof(reserved)); } }; public: BasicRecStore(int _fileNumber) : fileNumber(_fileNumber) { } ~BasicRecStore(); void init(const char *fn, unsigned recsize); fileofs insert(const char *buf, unsigned len); void update(fileofs o, const char *buf, unsigned len); void remove(fileofs o, unsigned len); void get(fileofs o, char *buf, unsigned len); int fileNumber; // this goes in DiskLoc::a string filename; private: void writeHeader(); File f; fileofs len; RecStoreHeader h; // h.reserved is wasteful here; fix later. void write(fileofs ofs, const char *data, unsigned len) { f.write(ofs, data, len); massert( 10380 , "basicrecstore write io error", !f.bad()); } }; /* --- implementation --- */ inline BasicRecStore::~BasicRecStore() { h.cleanShutdown = 0; if( f.is_open() ) { writeHeader(); f.fsync(); } } inline void BasicRecStore::writeHeader() { write(0, (const char *) &h, 28); // update header in file for new leof uassert( 10115 , "file io error in BasicRecStore [1]", !f.bad()); } inline fileofs BasicRecStore::insert(const char *buf, unsigned reclen) { if( h.firstDeleted ) { uasserted(11500, "deleted not yet implemented recstoreinsert"); } massert( 10381 , "bad len", reclen == h.recsize); fileofs ofs = h.leof; h.leof += reclen; if( h.leof > len ) { // grow the file. we grow quite a bit to avoid excessive file system fragmentations len += (len / 8) + h.recsize; uassert( 10116 , "recstore file too big for 32 bit", len <= 0x7fffffff || sizeof(std::streamoff) > 4 ); write(len, "", 0); } writeHeader(); write(ofs, buf, reclen); uassert( 10117 , "file io error in BasicRecStore [2]", !f.bad()); return ofs; } /* so far, it's ok to read or update a subset of a record */ inline void BasicRecStore::update(fileofs o, const char *buf, unsigned len) { assert(o <= h.leof && o >= sizeof(RecStoreHeader)); write(o, buf, len); } inline void BasicRecStore::get(fileofs o, char *buf, unsigned len) { assert(o <= h.leof && o >= sizeof(RecStoreHeader)); f.read(o, buf, len); massert( 10382 , "basicrestore::get I/O error", !f.bad()); } inline void BasicRecStore::remove(fileofs o, unsigned len) { uasserted(11501, "not yet implemented recstoreremove"); } }