84 lines
2.5 KiB
C++
84 lines
2.5 KiB
C++
#include "LowToHighLevelBlock.h"
|
|
|
|
using boost::optional;
|
|
using boost::none;
|
|
using cpputils::unique_ref;
|
|
using cpputils::make_unique_ref;
|
|
using cpputils::Data;
|
|
namespace DataUtils = cpputils::DataUtils;
|
|
using std::unique_lock;
|
|
using std::mutex;
|
|
|
|
namespace blockstore {
|
|
namespace lowtohighlevel {
|
|
|
|
optional<unique_ref<LowToHighLevelBlock>> LowToHighLevelBlock::TryCreateNew(BlockStore2 *baseBlockStore, const BlockId &blockId, Data data) {
|
|
bool success = baseBlockStore->tryCreate(blockId, data);
|
|
if (!success) {
|
|
return none;
|
|
}
|
|
|
|
return make_unique_ref<LowToHighLevelBlock>(blockId, std::move(data), baseBlockStore);
|
|
}
|
|
|
|
unique_ref<LowToHighLevelBlock> LowToHighLevelBlock::Overwrite(BlockStore2 *baseBlockStore, const BlockId &blockId, Data data) {
|
|
baseBlockStore->store(blockId, data); // TODO Does it make sense to not store here, but only write back in the destructor of LowToHighLevelBlock? Also: What about tryCreate?
|
|
return make_unique_ref<LowToHighLevelBlock>(blockId, std::move(data), baseBlockStore);
|
|
}
|
|
|
|
optional<unique_ref<LowToHighLevelBlock>> LowToHighLevelBlock::Load(BlockStore2 *baseBlockStore, const BlockId &blockId) {
|
|
optional<Data> loadedData = baseBlockStore->load(blockId);
|
|
if (loadedData == none) {
|
|
return none;
|
|
}
|
|
return make_unique_ref<LowToHighLevelBlock>(blockId, std::move(*loadedData), baseBlockStore);
|
|
}
|
|
|
|
LowToHighLevelBlock::LowToHighLevelBlock(const BlockId &blockId, Data data, BlockStore2 *baseBlockStore)
|
|
:Block(blockId),
|
|
_baseBlockStore(baseBlockStore),
|
|
_data(std::move(data)),
|
|
_dataChanged(false),
|
|
_mutex() {
|
|
}
|
|
|
|
LowToHighLevelBlock::~LowToHighLevelBlock() {
|
|
unique_lock<mutex> lock(_mutex);
|
|
_storeToBaseBlock();
|
|
}
|
|
|
|
const void *LowToHighLevelBlock::data() const {
|
|
return _data.data();
|
|
}
|
|
|
|
void LowToHighLevelBlock::write(const void *source, uint64_t offset, uint64_t count) {
|
|
ASSERT(offset <= size() && offset + count <= size(), "Write outside of valid area"); //Also check offset < size() because of possible overflow in the addition
|
|
std::memcpy(_data.dataOffset(offset), source, count);
|
|
_dataChanged = true;
|
|
}
|
|
|
|
void LowToHighLevelBlock::flush() {
|
|
unique_lock<mutex> lock(_mutex);
|
|
_storeToBaseBlock();
|
|
}
|
|
|
|
size_t LowToHighLevelBlock::size() const {
|
|
return _data.size();
|
|
}
|
|
|
|
void LowToHighLevelBlock::resize(size_t newSize) {
|
|
_data = DataUtils::resize(_data, newSize);
|
|
_dataChanged = true;
|
|
}
|
|
|
|
void LowToHighLevelBlock::_storeToBaseBlock() {
|
|
if (_dataChanged) {
|
|
_baseBlockStore->store(blockId(), _data);
|
|
_dataChanged = false;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|