2014-12-09 17:19:59 +01:00
# include <cstring>
# include <fstream>
# include <boost/filesystem.hpp>
2015-03-12 14:27:51 +01:00
# include "OnDiskBlock.h"
# include "OnDiskBlockStore.h"
# include "../../utils/FileDoesntExistException.h"
2015-07-22 13:42:07 +02:00
# include <messmer/cpp-utils/assert/assert.h>
2014-12-09 17:19:59 +01:00
using std : : istream ;
using std : : ostream ;
using std : : ifstream ;
using std : : ofstream ;
using std : : ios ;
2015-04-25 02:48:41 +02:00
using cpputils : : Data ;
2015-07-20 18:57:48 +02:00
using cpputils : : make_unique_ref ;
using cpputils : : unique_ref ;
using boost : : optional ;
using boost : : none ;
2014-12-09 17:19:59 +01:00
namespace bf = boost : : filesystem ;
namespace blockstore {
namespace ondisk {
2015-04-18 14:47:12 +02:00
OnDiskBlock : : OnDiskBlock ( const Key & key , const bf : : path & filepath , Data data )
2015-10-17 21:10:26 +02:00
: Block ( key ) , _filepath ( filepath ) , _data ( std : : move ( data ) ) , _dataChanged ( false ) , _mutex ( ) {
2014-12-09 17:19:59 +01:00
}
OnDiskBlock : : ~ OnDiskBlock ( ) {
2015-03-05 22:16:57 +01:00
flush ( ) ;
2014-12-09 17:19:59 +01:00
}
2015-03-04 20:47:02 +01:00
const void * OnDiskBlock : : data ( ) const {
2014-12-09 17:19:59 +01:00
return _data . data ( ) ;
}
2015-03-04 20:47:02 +01:00
void OnDiskBlock : : write ( const void * source , uint64_t offset , uint64_t size ) {
2015-07-22 13:42:07 +02:00
ASSERT ( offset < = _data . size ( ) & & offset + size < = _data . size ( ) , " Write outside of valid area " ) ; //Also check offset < _data->size() because of possible overflow in the addition
2015-03-04 20:47:02 +01:00
std : : memcpy ( ( uint8_t * ) _data . data ( ) + offset , source , size ) ;
2015-03-05 22:16:57 +01:00
_dataChanged = true ;
2014-12-09 17:19:59 +01:00
}
size_t OnDiskBlock : : size ( ) const {
return _data . size ( ) ;
}
2015-07-21 14:50:52 +02:00
optional < unique_ref < OnDiskBlock > > OnDiskBlock : : LoadFromDisk ( const bf : : path & rootdir , const Key & key ) {
2015-01-24 22:08:41 +01:00
auto filepath = rootdir / key . ToString ( ) ;
2014-12-09 17:19:59 +01:00
try {
//If it isn't a file, Data::LoadFromFile() would usually also crash. We still need this extra check
//upfront, because Data::LoadFromFile() doesn't crash if we give it the path of a directory
//instead the path of a file.
2015-04-25 02:48:41 +02:00
//TODO Data::LoadFromFile now returns boost::optional. Do we then still need this?
2014-12-09 17:19:59 +01:00
if ( ! bf : : is_regular_file ( filepath ) ) {
2015-07-21 14:50:52 +02:00
return none ;
2014-12-09 17:19:59 +01:00
}
2015-04-25 02:48:41 +02:00
boost : : optional < Data > data = Data : : LoadFromFile ( filepath ) ;
if ( ! data ) {
2015-07-21 14:50:52 +02:00
return none ;
2015-04-25 02:48:41 +02:00
}
2015-07-21 14:50:52 +02:00
return make_unique_ref < OnDiskBlock > ( key , filepath , std : : move ( * data ) ) ;
2014-12-09 17:19:59 +01:00
} catch ( const FileDoesntExistException & e ) {
2015-07-21 14:50:52 +02:00
return none ;
2014-12-09 17:19:59 +01:00
}
}
2015-07-20 18:57:48 +02:00
optional < unique_ref < OnDiskBlock > > OnDiskBlock : : CreateOnDisk ( const bf : : path & rootdir , const Key & key , Data data ) {
2015-01-24 22:08:41 +01:00
auto filepath = rootdir / key . ToString ( ) ;
2014-12-09 17:19:59 +01:00
if ( bf : : exists ( filepath ) ) {
2015-07-20 18:57:48 +02:00
return none ;
2014-12-09 17:19:59 +01:00
}
2015-07-20 18:57:48 +02:00
auto block = make_unique_ref < OnDiskBlock > ( key , filepath , std : : move ( data ) ) ;
2015-04-18 14:47:12 +02:00
block - > _storeToDisk ( ) ;
2015-07-20 18:57:48 +02:00
return std : : move ( block ) ;
2014-12-09 17:19:59 +01:00
}
2015-02-22 00:29:21 +01:00
void OnDiskBlock : : RemoveFromDisk ( const bf : : path & rootdir , const Key & key ) {
auto filepath = rootdir / key . ToString ( ) ;
2015-07-22 13:42:07 +02:00
ASSERT ( bf : : is_regular_file ( filepath ) , " Block not found on disk " ) ;
2015-02-22 00:29:21 +01:00
bf : : remove ( filepath ) ;
}
2014-12-09 17:19:59 +01:00
void OnDiskBlock : : _fillDataWithZeroes ( ) {
_data . FillWithZeroes ( ) ;
2015-04-15 14:51:41 +02:00
_dataChanged = true ;
2014-12-09 17:19:59 +01:00
}
void OnDiskBlock : : _storeToDisk ( ) const {
_data . StoreToFile ( _filepath ) ;
}
void OnDiskBlock : : flush ( ) {
2015-10-05 18:54:16 +02:00
std : : unique_lock < std : : mutex > lock ( _mutex ) ;
2015-03-05 22:16:57 +01:00
if ( _dataChanged ) {
_storeToDisk ( ) ;
_dataChanged = false ;
}
2014-12-09 17:19:59 +01:00
}
}
}