#include "LoggingExcept.hh" #include "StorageManager.hh" namespace logging { StorageManager::StorageManager( peripheral::IMemoryAccess & _memory, std::pmr::memory_resource & _allocator, bool _auto_sync ) : memory(_memory), mem_op_exec(_memory), allocator(&_allocator), feedback_load_block( &*this, &StorageManager::on_load_block, allocator), feedback_write_bckt(&*this, &StorageManager::on_write_block, allocator), blocks_limit((memory.getCapacity() - sizeof(ControlBlock)) / block_size()), block_write_op(NOPE), block_load_op(NO_LOAD), auto_cache_sync(_auto_sync), buffer_in_ready(false), feedback_init_backet( &*this, &StorageManager::on_init_backet, allocator ), finish_commit( true ) { if( not blocks_limit ) throw out_of_range(blocks_limit); //Смысла нет при нулевом значении. if( auto_cache_sync ) sync_timer.start(sync_buffer_period); load_control_block(); } bool StorageManager::commit( const char * data, size_t length ) { bool append = true; if( !finish_commit ) return false; if( length > buffer_in.allowed_space() ) throw max_allowed_size(length); if( not buffer_in_ready ) return false; /* ** Заполняем буфер и двигаем указатель до тех пор, пока может поместиться сообщение. ** В случае заполнения, передаем его на запись в долговременную память. */ if( not drop_buffer_to_storage && buffer_in.free_space() >= length ) { buffer_in.fill(data, length); buffer_in.update_crc(); information_block_is_dirty = true; } else { append = false; drop_buffer_to_storage = true; } return append; } std::pair StorageManager::prefetch_block( BlockId block_id ) { PrefetchResult result = IDLE_STATE; if( block_id >= blocks_count() ) { result = OUT_OF_BOUND; } else if( block_load_op == logging::StorageManager::NO_LOAD and fetch_parameters.block != block_id ) { fetch_parameters.block = block_id; fetch_parameters.result = IN_PROGRESS; result = IN_PROGRESS; load_block( block_id ); } else { result = fetch_parameters.result; if( result == COMPLETE ) { fetch_parameters.result = IDLE_STATE; fetch_parameters.block = -1; } } return { result, buffer_out.data() }; } StorageReadInterface::DataBlock StorageManager::read_buffered_block() { return buffer_out.serialize(); } void StorageManager::read_block_async( size_t, prefetch_result &, const char *, size_t & ) {} void StorageManager::process() { if( block_write_op == NOPE ) { if( drop_buffer_to_storage ) { mux_block_operation(INSERT_AND_MOVE); } else if( auto_cache_sync && sync_timer.delayElapsed() && information_block_is_dirty ) { mux_block_operation(SYNC); } } mem_op_exec.process(); } void StorageManager::get_block_hash_async( size_t, prefetch_result & , uint32_t & ) {} size_t StorageManager::blocks_count() { return blocks_limit; } size_t StorageManager::allocated_bytes() { return memory.getCapacity(); } size_t StorageManager::block_size() { return buffer_in.size(); } void StorageManager::set_cache_synchronize_period( unsigned long long _period ) { sync_buffer_period = _period; sync_timer.start(sync_buffer_period); } void StorageManager::flush_local() { buffer_in.reset(); buffer_out.reset(); } void StorageManager::on_load_block( MemoryOperationExecutor::OPERATION_RESULT res ) { //Если все прошло успешно, то тогда мы пытаемся проверить заголовок. if( res == MemoryOperationExecutor::DONE ) { switch (block_load_op) { case logging::StorageManager::LOAD_CONTROL: { uint32_t s_crc = common::crc::crcCalc( reinterpret_cast(&control_block), sizeof(ControlBlock) - sizeof(control_block.check_summ) ); bool eql_crc = s_crc == control_block.check_summ; bool eql_mgk_k = control_block.magick_key == MAGICK_KEY; bool eql_bckt_s = buffer_in.size() == control_block.bucket_size; bool coursor_in_range = control_block.coursor <= blocks_limit; if( not(eql_crc && eql_mgk_k && eql_bckt_s && coursor_in_range) ) { control_block.magick_key = MAGICK_KEY; control_block.bucket_size = buffer_in.size(); control_block.coursor = 0x0; control_block.check_summ = common::crc::crcCalc( reinterpret_cast(&control_block), sizeof(ControlBlock) - sizeof(control_block.check_summ) ); //reset backet: buffer_in.reset(); buffer_in_ready = true; } else { control_block.number_of_power_on += 1; init_backet(); } sync_control_block(); } break; case logging::StorageManager::LOAD_INFO: { if( not buffer_out.check() ) buffer_out.reset(); fetch_parameters.result = COMPLETE; } break; default: { throw logic_error(); } break; } block_load_op = logging::StorageManager::NO_LOAD; } } /* Асинхронная подгрузка информационного заголовка в оперативную память.*/ void StorageManager::load_control_block() { if( mem_op_exec.execute_task( MemoryOperationExecutor::READ_OP, reinterpret_cast(&control_block), INFOHEADER_BASE, sizeof(ControlBlock), &feedback_load_block) ) block_load_op = logging::StorageManager::LOAD_CONTROL; } /* Синхронизировать блок управления в оперативной памяти и ПЗУ. */ void StorageManager::sync_control_block() { mem_op_exec.execute_task( MemoryOperationExecutor::WRITE_OP, reinterpret_cast(&control_block), INFOHEADER_BASE, sizeof(ControlBlock), nullptr ); } void StorageManager::mux_block_operation( BLOCK_WRITE_OPERATION action ) { block_write_op = action; send_block(); } void StorageManager::on_write_block( MemoryOperationExecutor::OPERATION_RESULT res ) { sync_timer.start(sync_buffer_period); information_block_is_dirty = false; drop_buffer_to_storage = false; switch (block_write_op) { case logging::StorageManager::SYNC: {} break; case logging::StorageManager::INSERT_AND_MOVE: { buffer_in.reset(); control_block.coursor = (control_block.coursor + 1) >= blocks_count() ? 0 : control_block.coursor + 1; control_block.check_summ = common::crc::crcCalc(reinterpret_cast(&control_block), sizeof(ControlBlock) - sizeof(control_block.check_summ)); sync_control_block(); } break; default: { throw logic_error(); } break; } block_write_op = NOPE; } void StorageManager::send_block() { finish_commit = false; std::pair sp = buffer_in.serialize(); finish_commit = true; mem_op_exec.execute_task( MemoryOperationExecutor::WRITE_OP, sp.first, in_memory_placement(control_block.coursor), sp.second, &feedback_write_bckt ); } void StorageManager::load_block( BlockId block_id ) { std::pair sp = buffer_out.serialize(); if( mem_op_exec.execute_task( MemoryOperationExecutor::READ_OP, sp.first, in_memory_placement(block_id), sp.second, &feedback_load_block ) ) block_load_op = logging::StorageManager::LOAD_INFO; } size_t StorageManager::in_memory_placement( BlockId block_id ) { size_t place = sizeof(ControlBlock); if( block_id < blocks_limit ) place += block_id * buffer_in.size(); else throw out_of_range( block_id ); return place; } void StorageManager::on_init_backet( MemoryOperationExecutor::OPERATION_RESULT res) { if( res == MemoryOperationExecutor::DONE ) { if( not buffer_in.check() ) buffer_in.reset(); buffer_in_ready = true; } block_load_op = logging::StorageManager::NO_LOAD; } void StorageManager::init_backet() { std::pair sp = buffer_in.serialize(); if( mem_op_exec.execute_task( MemoryOperationExecutor::READ_OP, sp.first, in_memory_placement( control_block.coursor ), sp.second, &feedback_init_backet ) ) block_load_op = logging::StorageManager::INIT_BACKET; } StorageManager::PowerOnNumber StorageManager::power_on() const { return control_block.number_of_power_on; } bool StorageManager::storage_ready() const { return buffer_in_ready; } }