2015-04-15 19:05:58 +02:00
# include "CachedBlock.h"
2015-04-18 14:47:12 +02:00
# include "NewBlock.h"
2015-04-16 14:10:44 +02:00
# include "CachingBlockStore.h"
2015-04-15 15:46:35 +02:00
# include "../../interface/Block.h"
2015-04-15 19:05:58 +02:00
# include <algorithm>
2015-06-21 17:43:31 +02:00
# include <messmer/cpp-utils/pointer/cast.h>
2015-07-22 13:42:07 +02:00
# include <messmer/cpp-utils/assert/assert.h>
2015-04-15 19:05:58 +02:00
2015-04-15 20:39:58 +02:00
using cpputils : : dynamic_pointer_move ;
2015-04-25 02:48:41 +02:00
using cpputils : : Data ;
2015-07-20 18:57:48 +02:00
using boost : : optional ;
using cpputils : : unique_ref ;
using cpputils : : make_unique_ref ;
using boost : : none ;
2015-04-15 15:46:35 +02:00
namespace blockstore {
2015-04-16 14:10:44 +02:00
namespace caching {
2015-04-15 15:46:35 +02:00
2015-07-21 18:19:34 +02:00
CachingBlockStore : : CachingBlockStore ( cpputils : : unique_ref < BlockStore > baseBlockStore )
2015-04-18 14:47:12 +02:00
: _baseBlockStore ( std : : move ( baseBlockStore ) ) , _cache ( ) , _numNewBlocks ( 0 ) {
2015-04-15 15:46:35 +02:00
}
2015-04-18 14:47:12 +02:00
Key CachingBlockStore : : createKey ( ) {
return _baseBlockStore - > createKey ( ) ;
}
2015-07-20 18:57:48 +02:00
optional < unique_ref < Block > > CachingBlockStore : : tryCreate ( const Key & key , Data data ) {
2015-10-14 14:40:45 +02:00
ASSERT ( _cache . pop ( key ) = = none , " Key already exists in cache " ) ;
2015-07-20 18:57:48 +02:00
//TODO Shouldn't we return boost::none if the key already exists?
2015-10-14 14:40:45 +02:00
//TODO Key can also already exist but not be in the cache right now.
2015-04-18 14:47:12 +02:00
+ + _numNewBlocks ;
2015-07-21 14:50:52 +02:00
return unique_ref < Block > ( make_unique_ref < CachedBlock > ( make_unique_ref < NewBlock > ( key , std : : move ( data ) , this ) , this ) ) ;
2015-04-15 15:46:35 +02:00
}
2015-07-21 14:50:52 +02:00
optional < unique_ref < Block > > CachingBlockStore : : load ( const Key & key ) {
optional < unique_ref < Block > > optBlock = _cache . pop ( key ) ;
2015-04-27 22:46:57 +02:00
//TODO an optional<> class with .getOrElse() would make this code simpler. boost::optional<>::value_or_eval didn't seem to work with unique_ptr members.
2015-07-21 14:50:52 +02:00
if ( optBlock ! = none ) {
return optional < unique_ref < Block > > ( make_unique_ref < CachedBlock > ( std : : move ( * optBlock ) , this ) ) ;
2015-04-27 22:46:57 +02:00
} else {
2015-07-21 14:50:52 +02:00
auto block = _baseBlockStore - > load ( key ) ;
if ( block = = none ) {
return none ;
} else {
return optional < unique_ref < Block > > ( make_unique_ref < CachedBlock > ( std : : move ( * block ) , this ) ) ;
2015-04-27 22:46:57 +02:00
}
2015-04-15 20:39:58 +02:00
}
2015-04-15 15:46:35 +02:00
}
2015-07-21 14:50:52 +02:00
void CachingBlockStore : : remove ( cpputils : : unique_ref < Block > block ) {
auto cached_block = dynamic_pointer_move < CachedBlock > ( block ) ;
2015-07-22 13:42:07 +02:00
ASSERT ( cached_block ! = none , " Passed block is not a CachedBlock " ) ;
2015-07-21 14:50:52 +02:00
auto baseBlock = ( * cached_block ) - > releaseBlock ( ) ;
2015-04-18 14:47:12 +02:00
auto baseNewBlock = dynamic_pointer_move < NewBlock > ( baseBlock ) ;
2015-07-21 14:50:52 +02:00
if ( baseNewBlock ! = none ) {
if ( ! ( * baseNewBlock ) - > alreadyExistsInBaseStore ( ) ) {
2015-04-18 14:47:12 +02:00
- - _numNewBlocks ;
}
2015-07-21 14:50:52 +02:00
( * baseNewBlock ) - > remove ( ) ;
2015-04-18 14:47:12 +02:00
} else {
_baseBlockStore - > remove ( std : : move ( baseBlock ) ) ;
}
2015-04-15 15:46:35 +02:00
}
2015-04-16 14:10:44 +02:00
uint64_t CachingBlockStore : : numBlocks ( ) const {
2015-04-18 14:47:12 +02:00
return _baseBlockStore - > numBlocks ( ) + _numNewBlocks ;
2015-04-15 15:46:35 +02:00
}
2015-07-21 14:50:52 +02:00
void CachingBlockStore : : release ( unique_ref < Block > block ) {
2015-04-27 22:46:57 +02:00
Key key = block - > key ( ) ;
_cache . push ( key , std : : move ( block ) ) ;
2015-04-15 19:05:58 +02:00
}
2015-07-20 18:57:48 +02:00
optional < unique_ref < Block > > CachingBlockStore : : tryCreateInBaseStore ( const Key & key , Data data ) {
2015-04-18 14:47:12 +02:00
auto block = _baseBlockStore - > tryCreate ( key , std : : move ( data ) ) ;
2015-07-20 18:57:48 +02:00
if ( block ! = none ) {
2015-04-18 14:47:12 +02:00
- - _numNewBlocks ;
}
return block ;
}
2015-07-21 14:50:52 +02:00
void CachingBlockStore : : removeFromBaseStore ( cpputils : : unique_ref < Block > block ) {
2015-04-18 14:47:12 +02:00
_baseBlockStore - > remove ( std : : move ( block ) ) ;
}
2015-10-14 14:40:45 +02:00
void CachingBlockStore : : flush ( ) {
_cache . flush ( ) ;
}
2015-04-15 15:46:35 +02:00
}
}