#pragma once #ifndef MESSMER_BLOCKSTORE_IMPLEMENTATIONS_COMPRESSING_COMPRESSEDBLOCK_H_ #define MESSMER_BLOCKSTORE_IMPLEMENTATIONS_COMPRESSING_COMPRESSEDBLOCK_H_ #include "../../interface/Block.h" #include "../../interface/BlockStore.h" #include #include #include namespace blockstore { class BlockStore; namespace compressing { template class CompressingBlockStore; template class CompressedBlock final: public Block { public: static boost::optional> TryCreateNew(BlockStore *baseBlockStore, const Key &key, cpputils::Data decompressedData); static cpputils::unique_ref Decompress(cpputils::unique_ref baseBlock); CompressedBlock(cpputils::unique_ref baseBlock, cpputils::Data decompressedData); ~CompressedBlock(); const void *data() const override; void write(const void *source, uint64_t offset, uint64_t size) override; void flush() override; size_t size() const override; void resize(size_t newSize) override; cpputils::unique_ref releaseBaseBlock(); private: void _compressToBaseBlock(); cpputils::unique_ref _baseBlock; cpputils::Data _decompressedData; std::mutex _mutex; bool _dataChanged; DISALLOW_COPY_AND_ASSIGN(CompressedBlock); }; template boost::optional>> CompressedBlock::TryCreateNew(BlockStore *baseBlockStore, const Key &key, cpputils::Data decompressedData) { cpputils::Data compressed = Compressor::Compress(decompressedData); auto baseBlock = baseBlockStore->tryCreate(key, std::move(compressed)); if (baseBlock == boost::none) { //TODO Test this code branch return boost::none; } return cpputils::make_unique_ref>(std::move(*baseBlock), std::move(decompressedData)); } template cpputils::unique_ref> CompressedBlock::Decompress(cpputils::unique_ref baseBlock) { cpputils::Data decompressed = Compressor::Decompress((byte*)baseBlock->data(), baseBlock->size()); return cpputils::make_unique_ref>(std::move(baseBlock), std::move(decompressed)); } template CompressedBlock::CompressedBlock(cpputils::unique_ref baseBlock, cpputils::Data decompressedData) : Block(baseBlock->key()), _baseBlock(std::move(baseBlock)), _decompressedData(std::move(decompressedData)), _dataChanged(false) { } template CompressedBlock::~CompressedBlock() { std::unique_lock lock(_mutex); _compressToBaseBlock(); } template const void *CompressedBlock::data() const { return _decompressedData.data(); } template void CompressedBlock::write(const void *source, uint64_t offset, uint64_t size) { std::memcpy((uint8_t*)_decompressedData.dataOffset(offset), source, size); _dataChanged = true; } template void CompressedBlock::flush() { std::unique_lock lock(_mutex); _compressToBaseBlock(); return _baseBlock->flush(); } template size_t CompressedBlock::size() const { return _decompressedData.size(); } template void CompressedBlock::resize(size_t newSize) { _decompressedData = cpputils::DataUtils::resize(std::move(_decompressedData), newSize); _dataChanged = true; } template cpputils::unique_ref CompressedBlock::releaseBaseBlock() { std::unique_lock lock(_mutex); _compressToBaseBlock(); return std::move(_baseBlock); } template void CompressedBlock::_compressToBaseBlock() { if (_dataChanged) { cpputils::Data compressed = Compressor::Compress(_decompressedData); _baseBlock->resize(compressed.size()); _baseBlock->write(compressed.data(), 0, compressed.size()); _dataChanged = false; } } } } #endif