363 lines
9.2 KiB
C++
363 lines
9.2 KiB
C++
#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::PrefetchResult, StorageReadInterface::DataBlock> 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<common::crc::Crc32_ZLIB>(
|
||
reinterpret_cast<char*>(&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<common::crc::Crc32_ZLIB>(
|
||
reinterpret_cast<char*>(&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<char*>(&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<char*>(&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<common::crc::Crc32_ZLIB>(reinterpret_cast<char*>(&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<const char *, size_t> 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<const char*, size_t> 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<const char*, size_t> 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;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|