2010-02-10 00:30:32 +01:00
// recstore.h
/*
* Copyright ( C ) 2010 10 gen 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 < http : //www.gnu.org/licenses/>.
*/
# 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 " ) ;
}
}