From 9e68742946adf889862d5829d5aa9571a0e30638 Mon Sep 17 00:00:00 2001 From: "Constantin P." <papizh.konstantin@demlabs.net> Date: Sat, 8 Jun 2024 23:56:17 +0700 Subject: [PATCH 1/5] Solution refined --- modules/chain/CMakeLists.txt | 8 - modules/chain/dap_chain.c | 6 +- modules/chain/dap_chain_cell.c | 324 ++++++++++++++----------- modules/chain/include/dap_chain_cell.h | 1 - modules/net/dap_chain_net.c | 2 +- 5 files changed, 193 insertions(+), 148 deletions(-) diff --git a/modules/chain/CMakeLists.txt b/modules/chain/CMakeLists.txt index 5e2c10d1c..689e6c69b 100644 --- a/modules/chain/CMakeLists.txt +++ b/modules/chain/CMakeLists.txt @@ -4,11 +4,6 @@ project (dap_chain) file(GLOB DAP_CHAIN_SRCS *.c) file(GLOB DAP_CHAIN_HEADERS include/*.h) -if (WIN32) - file (GLOB MMAN_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/../../dap-sdk/3rdparty/mman/*) - list(APPEND DAP_CHAIN_SRCS ${MMAN_SRCS}) -endif() - add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_SRCS} ${DAP_CHAIN_HEADERS}) if(BUILD_CELLFRAME_SDK_TESTS) @@ -21,9 +16,6 @@ endif() target_link_libraries(${PROJECT_NAME} dap_chain_common dap_global_db dap_notify_srv dap_stream ${GLIB_LDFLAGS}) target_include_directories(${PROJECT_NAME} INTERFACE . include/ ${GLIB_INCLUDE_DIRS}) target_include_directories(${PROJECT_NAME} PUBLIC include) -if (WIN32) - target_include_directories(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../../dap-sdk/3rdparty/mman/) -endif() if (INSTALL_SDK) set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "${DAP_CHAIN_HEADERS}") diff --git a/modules/chain/dap_chain.c b/modules/chain/dap_chain.c index 2bec84dd2..4bd3de572 100644 --- a/modules/chain/dap_chain.c +++ b/modules/chain/dap_chain.c @@ -111,7 +111,7 @@ dap_chain_t *dap_chain_create(const char *a_chain_net_name, const char *a_chain_ .name = dap_strdup(a_chain_name), .net_name = dap_strdup(a_chain_net_name), #ifdef DAP_OS_WINDOWS // TODO - .is_mapped = false, + .is_mapped = true, #else .is_mapped = dap_config_get_item_bool_default(g_config, "ledger", "mapped", true), #endif @@ -610,7 +610,9 @@ int dap_chain_load_all(dap_chain_t *a_chain) const char l_suffix[] = ".dchaincell"; size_t l_suffix_len = strlen(l_suffix); if (!strncmp(l_filename + strlen(l_filename) - l_suffix_len, l_suffix, l_suffix_len)) { - dap_chain_cell_t *l_cell = dap_chain_cell_create_fill2(a_chain, l_filename); + uint64_t l_cell_id_uint64 = 0; + sscanf(l_filename, "%"DAP_UINT64_FORMAT_x".dchaincell", &l_cell_id_uint64); + dap_chain_cell_t *l_cell = dap_chain_cell_create_fill(a_chain, (dap_chain_cell_id_t){ .uint64 = l_cell_id_uint64 }); l_ret += dap_chain_cell_load(a_chain, l_cell); if (DAP_CHAIN_PVT(a_chain)->need_reorder) { const char *l_filename_backup = dap_strdup_printf("%s.unsorted", l_cell->file_storage_path); diff --git a/modules/chain/dap_chain_cell.c b/modules/chain/dap_chain_cell.c index 7034d04aa..8e3e2f65a 100644 --- a/modules/chain/dap_chain_cell.c +++ b/modules/chain/dap_chain_cell.c @@ -31,7 +31,7 @@ #include "dap_strfuncs.h" #include "dap_file_utils.h" #ifdef DAP_OS_WINDOWS -#include "mman.h" +#include <winternl.h> #else #include <sys/mman.h> #endif @@ -55,6 +55,32 @@ typedef struct dap_chain_cell_file_header dap_chain_cell_id_t cell_id; } DAP_ALIGN_PACKED dap_chain_cell_file_header_t; +#ifdef DAP_OS_WINDOWS +typedef NTSTATUS (*pfn_NtCreateSection)( + OUT PHANDLE SectionHandle, IN ACCESS_MASK DesiredAccess, + IN OPTIONAL POBJECT_ATTRIBUTES ObjectAttributes, + IN OPTIONAL PLARGE_INTEGER MaximumSize, IN ULONG SectionPageProtection, + IN ULONG AllocationAttributes, IN OPTIONAL HANDLE FileHandle); +static pfn_NtCreateSection pfnNtCreateSection; + +typedef enum _SECTION_INHERIT { ViewShare = 1, ViewUnmap = 2 } SECTION_INHERIT; +typedef NTSTATUS (*pfn_NtMapViewOfSection) ( + IN HANDLE SectionHandle, IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, + IN ULONG_PTR ZeroBits, IN SIZE_T CommitSize, + IN OUT OPTIONAL PLARGE_INTEGER SectionOffset, IN OUT PSIZE_T ViewSize, + IN SECTION_INHERIT InheritDisposition, IN ULONG AllocationType, + IN ULONG Win32Protect); +static pfn_NtMapViewOfSection pfnNtMapViewOfSection; + +typedef NTSTATUS (*pfn_NtUnmapViewOfSection) ( + IN HANDLE ProcessHandle, IN PVOID BaseAddress); +static pfn_NtUnmapViewOfSection pfnNtUnmapViewOfSection; + +typedef NTSTATUS (*pfn_NtExtendSection) ( + IN HANDLE SectionHandle, IN PLARGE_INTEGER NewSectionSize); +static pfn_NtExtendSection pfnNtExtendSection; +#endif + static bool s_debug_more = false; /** @@ -65,10 +91,91 @@ static bool s_debug_more = false; int dap_chain_cell_init(void) { s_debug_more = dap_config_get_item_bool_default(g_config, "chain", "debug_more", false); +#ifdef DAP_OS_WINDOWS + if ( dap_config_get_item_bool_default(g_config, "ledger", "mapped", true) ) { + HMODULE ntdll = GetModuleHandle("ntdll.dll"); + if ( !ntdll ) + return log_it(L_CRITICAL, "Ntdll error"), -1; + pfnNtCreateSection = (pfn_NtCreateSection) GetProcAddress(ntdll, "NtCreateSection"); + pfnNtMapViewOfSection = (pfn_NtMapViewOfSection) GetProcAddress(ntdll, "NtMapViewOfSection"); + pfnNtExtendSection = (pfn_NtExtendSection) GetProcAddress(ntdll, "NtExtendSection"); + pfnNtUnmapViewOfSection = (pfn_NtUnmapViewOfSection)GetProcAddress(ntdll, "NtUnmapViewOfSection"); + } + +#endif //s_cells_path = dap_config_get_item_str(g_config,"resources","cells_storage"); return 0; } +DAP_STATIC_INLINE int s_cell_file_write_header(dap_chain_cell_t *a_cell) +{ + dap_chain_cell_file_header_t l_hdr = { + .signature = DAP_CHAIN_CELL_FILE_SIGNATURE, + .version = DAP_CHAIN_CELL_FILE_VERSION, + .type = DAP_CHAIN_CELL_FILE_TYPE_RAW, + .chain_id = a_cell->chain->id, + .chain_net_id = a_cell->chain->net_id, + .cell_id = a_cell->id + }; + return (int)fwrite(&l_hdr, sizeof(l_hdr), 1, a_cell->file_storage); +} + +DAP_STATIC_INLINE int s_cell_map_new_volume(dap_chain_cell_t *a_cell, size_t a_fpos) { + int l_fildes = fileno(a_cell->file_storage); +#ifdef DAP_OS_WINDOWS + HANDLE hSection = NULL; + if ( !a_fpos ) { + //if (a_cell->map_range_bounds) + // NtClose( (HANDLE)a_cell->map_range_bounds->data ); + LARGE_INTEGER SectionSize = { + .QuadPart = ( fseek(a_cell->file_storage, 0, SEEK_END), ftell(a_cell->file_storage) ) + }; + + NTSTATUS err = pfnNtCreateSection(&hSection, SECTION_MAP_READ|SECTION_EXTEND_SIZE|SECTION_MAP_WRITE, + NULL, &SectionSize, PAGE_READWRITE, SEC_RESERVE, + (HANDLE)_get_osfhandle(l_fildes)); + if ( !NT_SUCCESS(err) ) { + log_it(L_ERROR, "NtCreateSection() failed, status %lx", err); + return -1; + } + a_cell->map_range_bounds = dap_list_append(a_cell->map_range_bounds, hSection); + } +#endif + size_t l_map_size = dap_page_roundup(DAP_MAPPED_VOLUME_LIMIT), +#ifdef DAP_OS_WINDOWS + l_volume_start = a_fpos ? dap_64k_rounddown(a_fpos) : 0, +#else + l_volume_start = a_fpos ? dap_page_rounddown(a_fpos) : 0, +#endif + l_offset = a_fpos - l_volume_start; +#ifdef DAP_OS_WINDOWS + hSection = (HANDLE)a_cell->map_range_bounds->data; + a_cell->map = NULL; + int err = 0; + if ( !NT_SUCCESS ( err = pfnNtMapViewOfSection(hSection, GetCurrentProcess(), + (HANDLE)&a_cell->map, 0, 0, + &l_volume_start, &l_map_size, + ViewUnmap, MEM_RESERVE, + PAGE_WRITECOPY) ) ) + { + log_it(L_ERROR, "NtMapViewOfSection() failed, status %lx", err); + NtClose(hSection); + return -1; + } +#else + if ( MAP_FAILED == (a_cell->map = mmap(NULL, l_map_size, PROT_READ|PROT_WRITE, + MAP_PRIVATE, fileno(a_cell->file_storage), l_volume_start)) ) { + log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X" cannot be mapped, errno %d", + a_cell->file_storage_path, a_cell->id.uint64, errno); + return -1; + } +#endif + a_cell->map_pos = a_cell->map + l_offset; + a_cell->map_range_bounds = dap_list_append(a_cell->map_range_bounds, a_cell->map); + a_cell->map_range_bounds = dap_list_append(a_cell->map_range_bounds, a_cell->map_end = a_cell->map + l_map_size); + return 0; +} + /** * @brief dap_chain_cell_find_by_id * get dap_chain_cell_t object by cell (shard) id @@ -103,77 +210,53 @@ dap_chain_cell_t * dap_chain_cell_create_fill(dap_chain_t * a_chain, dap_chain_c pthread_rwlock_unlock(&a_chain->cell_rwlock); return l_cell; } - char file_storage_path[MAX_PATH]; +#define CLEANUP_AND_RET return ({ fclose(l_file); DAP_DELETE(l_cell); pthread_rwlock_unlock(&a_chain->cell_rwlock); NULL; }) + char file_storage_path[MAX_PATH]; snprintf(file_storage_path, MAX_PATH, "%s/%0"DAP_UINT64_FORMAT_x".dchaincell", DAP_CHAIN_PVT(a_chain)->file_storage_dir, a_cell_id.uint64); - char *l_map = NULL; - size_t l_size = 0; - FILE *l_file = fopen(file_storage_path, "r+b"); - if ( l_file ) { - if ( a_chain->is_mapped ) { - fseek(l_file, 0, SEEK_END); - l_size = ftell(l_file); - fseek(l_file, 0, SEEK_SET); - if ( MAP_FAILED == (l_map = mmap(NULL, l_size ? l_size : dap_page_roundup(DAP_MAPPED_VOLUME_LIMIT), PROT_READ|PROT_WRITE, MAP_PRIVATE, fileno(l_file), 0)) ) { - log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X" cannot be mapped, errno %d", file_storage_path, a_cell_id.uint64, errno); - fclose(l_file); - pthread_rwlock_unlock(&a_chain->cell_rwlock); - return NULL; - } - } - } else if (errno == ENOENT) { - if ( !(l_file = fopen(file_storage_path, "w+b")) ) { - log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X" cannot be opened, error %d", - file_storage_path, a_cell_id.uint64, errno); - pthread_rwlock_unlock(&a_chain->cell_rwlock); - return NULL; - } - if ( a_chain->is_mapped && MAP_FAILED == (l_map = mmap(NULL, l_size = dap_page_roundup(DAP_MAPPED_VOLUME_LIMIT), PROT_READ|PROT_WRITE, MAP_PRIVATE, fileno(l_file), 0)) ) { - log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X" cannot be mapped, error %d", - file_storage_path, a_cell_id.uint64, errno); - fclose(l_file); - pthread_rwlock_unlock(&a_chain->cell_rwlock); - return NULL; - } + FILE *l_file = fopen(file_storage_path, "a+b"); + if ( !l_file ) { + log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X" cannot be opened, error %d", + file_storage_path, a_cell_id.uint64, errno); + CLEANUP_AND_RET; } - - l_cell = DAP_NEW_Z(dap_chain_cell_t); + if ( !(l_cell = DAP_NEW_Z(dap_chain_cell_t)) ) + CLEANUP_AND_RET; *l_cell = (dap_chain_cell_t) { .id = a_cell_id, - .map = l_map, - .map_pos = l_map, - .map_end = l_map ? l_map + l_size : NULL, - .file_storage = l_file, .chain = a_chain, + .file_storage = l_file, .storage_rwlock = PTHREAD_RWLOCK_INITIALIZER }; - memcpy(l_cell->file_storage_path, file_storage_path, sizeof(file_storage_path)); - if (l_map) { - l_cell->map_range_bounds = dap_list_append(l_cell->map_range_bounds, l_map); - l_cell->map_range_bounds = dap_list_append(l_cell->map_range_bounds, l_cell->map_end); + size_t l_size = ( fseek(l_file, 0, SEEK_END), ftell(l_file) ); + if ( l_size < sizeof(dap_chain_cell_file_header_t) ) { + if (l_size) { + log_it(L_INFO, "Possibly corrupt cell storage 0x%016"DAP_UINT64_FORMAT_X" \"%s\", rewriting it", + a_cell_id.uint64, file_storage_path); + l_file = freopen(file_storage_path, "w+b", l_file); + } + if ( !s_cell_file_write_header(l_cell) ) { + log_it(L_ERROR, "Can't init file storage for cell 0x%016"DAP_UINT64_FORMAT_X" \"%s\", errno %d", + a_cell_id.uint64, file_storage_path, errno); + CLEANUP_AND_RET; + } + log_it(L_NOTICE, "Initialized file storage for cell 0x%016"DAP_UINT64_FORMAT_X" \"%s\"", + a_cell_id.uint64, file_storage_path); + fflush(l_file); } + + if ( a_chain->is_mapped && s_cell_map_new_volume(l_cell, 0) ) { + CLEANUP_AND_RET; + } +#undef CLEANUP_AND_RET + memcpy(l_cell->file_storage_path, file_storage_path, sizeof(file_storage_path)); debug_if (s_debug_more && a_chain->is_mapped, L_DEBUG, "Mapped volume size is %lu", (size_t)(l_cell->map_end - l_cell->map)); HASH_ADD(hh, a_chain->cells, id, sizeof(dap_chain_cell_id_t), l_cell); pthread_rwlock_unlock(&a_chain->cell_rwlock); return l_cell; } -/** - * @brief dap_chain_cell_create_fill2 - * set l_cell->file_storage_path and l_cell->id.uint64 from name of chain. - * For example, 0.dchaincell. 0 - chain id, dchaincell - name of file - * @param a_chain - chain object - * @param a_filename - chain filename, for example "0.dchaincell" - * @return dap_chain_cell_t* - */ -dap_chain_cell_t * dap_chain_cell_create_fill2(dap_chain_t * a_chain, const char *a_filename) -{ - uint64_t l_cell_id_uint64; - sscanf(a_filename, "%"DAP_UINT64_FORMAT_x".dchaincell", &l_cell_id_uint64); - return dap_chain_cell_create_fill(a_chain, (dap_chain_cell_id_t){ .uint64 = l_cell_id_uint64}); -} - /** * @brief * close a_cell->file_storage file object @@ -188,13 +271,24 @@ void dap_chain_cell_close(dap_chain_cell_t *a_cell) a_cell->file_storage = NULL; } if (a_cell->chain->is_mapped) { - for (dap_list_t *l_iter = a_cell->map_range_bounds; l_iter; l_iter = l_iter->next) { + dap_list_t *l_iter = a_cell->map_range_bounds; +#ifdef DAP_OS_WINDOWS + l_iter = l_iter->next; +#endif + for (; l_iter; l_iter = l_iter->next) { if (l_iter->next) { debug_if(s_debug_more, L_DEBUG, "Unmap volume %p (%lu bytes)", l_iter->data, (size_t)(l_iter->next->data - l_iter->data)); +#ifdef DAP_OS_WINDOWS + pfnNtUnmapViewOfSection(GetCurrentProcess(), l_iter->data); +#else munmap(l_iter->data, (size_t)(l_iter->next->data - l_iter->data)); +#endif l_iter = l_iter->next; } } +#ifdef DAP_OS_WINDOWS + NtClose(a_cell->map_range_bounds->data); +#endif dap_list_free(a_cell->map_range_bounds); } } @@ -251,15 +345,12 @@ int dap_chain_cell_load(dap_chain_t *a_chain, dap_chain_cell_t *a_cell) { if (!a_cell) return -1; - fseek(a_cell->file_storage, 0, SEEK_END); - size_t l_size = ftell(a_cell->file_storage); - fseek(a_cell->file_storage, 0, SEEK_SET); - if ( l_size < sizeof(dap_chain_cell_file_header_t) || (a_chain->is_mapped && !a_cell->map_pos) ) { + size_t l_size = ( fseek(a_cell->file_storage, 0, SEEK_END), ftell(a_cell->file_storage) ), l_pos = 0; + if ( l_size <= sizeof(dap_chain_cell_file_header_t) ) { log_it(L_INFO, "Chain cell \"%s\" is yet empty", a_cell->file_storage_path); return -1; } int l_ret = 0; - size_t l_full_size = 0; dap_chain_cell_file_header_t *l_hdr = NULL; if (a_chain->is_mapped) { l_hdr = (dap_chain_cell_file_header_t*)a_cell->map; @@ -271,7 +362,6 @@ int dap_chain_cell_load(dap_chain_t *a_chain, dap_chain_cell_t *a_cell) DAP_DELETE(l_hdr); return -2; } - l_full_size += sizeof(dap_chain_cell_file_header_t); } if (l_hdr->signature != DAP_CHAIN_CELL_FILE_SIGNATURE) { log_it(L_ERROR, "Wrong signature in chain \"%s\", possible file corrupt", a_cell->file_storage_path); @@ -286,16 +376,23 @@ int dap_chain_cell_load(dap_chain_t *a_chain, dap_chain_cell_t *a_cell) return -4; } + l_pos += sizeof(dap_chain_cell_file_header_t); uint64_t q = 0; if (a_chain->is_mapped) { a_cell->map_pos = a_cell->map + sizeof(dap_chain_cell_file_header_t); - for (uint64_t l_el_size = 0; a_cell->map_pos < a_cell->map_end && ( l_el_size = *(uint64_t*)a_cell->map_pos ); ++q, a_cell->map_pos += l_el_size) { - dap_hash_fast_t l_atom_hash = {}; + for ( uint64_t l_el_size = 0; l_pos < l_size; ++q, l_pos += l_el_size + sizeof(uint64_t) ) { + size_t space_left = (size_t)( a_cell->map_end - a_cell->map_pos ); + if ( space_left < sizeof(uint64_t) || (space_left - sizeof(uint64_t)) < *(uint64_t*)a_cell->map_pos ) + if ( !s_cell_map_new_volume(a_cell, l_pos) ) + break; + l_el_size = *(uint64_t*)a_cell->map_pos; + dap_hash_fast_t l_atom_hash; dap_chain_atom_ptr_t l_atom = (dap_chain_atom_ptr_t)(a_cell->map_pos += sizeof(uint64_t)); dap_hash_fast(l_atom, l_el_size, &l_atom_hash); a_chain->callback_atom_add(a_chain, l_atom, l_el_size, &l_atom_hash); + a_cell->map_pos += l_el_size; } - fseek(a_cell->file_storage, a_cell->map_pos - a_cell->map, SEEK_SET); + fseek(a_cell->file_storage, l_pos, SEEK_SET); } else { DAP_DELETE(l_hdr); size_t l_read = 0; @@ -312,7 +409,7 @@ int dap_chain_cell_load(dap_chain_t *a_chain, dap_chain_cell_t *a_cell) l_ret = -5; break; } - l_full_size += sizeof(uint64_t) + ( l_read = fread((void*)l_element, 1, l_el_size, a_cell->file_storage) ); + l_pos += sizeof(uint64_t) + ( l_read = fread((void*)l_element, 1, l_el_size, a_cell->file_storage) ); if (l_read != l_el_size) { log_it(L_ERROR, "Read only %lu of %zu bytes, stop cell loading", l_read, l_el_size); DAP_DELETE(l_element); @@ -327,75 +424,25 @@ int dap_chain_cell_load(dap_chain_t *a_chain, dap_chain_cell_t *a_cell) } ++q; } - fseek(a_cell->file_storage, l_full_size, SEEK_SET); + fseek(a_cell->file_storage, l_pos, SEEK_SET); } log_it(L_INFO, "Loaded %lu atoms in cell %s", q, a_cell->file_storage_path); return l_ret; } -static int s_file_write_header(dap_chain_cell_t *a_cell) -{ - if (!a_cell->file_storage) { - log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X" not opened", - a_cell->file_storage_path, a_cell->id.uint64); - return -2; - } else { - fseek(a_cell->file_storage, 0L, SEEK_END); - if (ftell(a_cell->file_storage) >= (ssize_t)sizeof(dap_chain_cell_file_header_t)) { - log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X" is already not empty!", - a_cell->file_storage_path, a_cell->id.uint64); - return -3; - } - } - dap_chain_cell_file_header_t l_hdr = { - .signature = DAP_CHAIN_CELL_FILE_SIGNATURE, - .version = DAP_CHAIN_CELL_FILE_VERSION, - .type = DAP_CHAIN_CELL_FILE_TYPE_RAW, - .chain_id = { .uint64 = a_cell->id.uint64 }, - .chain_net_id = a_cell->chain->net_id - }; - - if(fwrite(&l_hdr, sizeof(l_hdr), 1, a_cell->file_storage) == 1) { - log_it(L_NOTICE, "Initialized file storage for cell 0x%016"DAP_UINT64_FORMAT_X" ( %s )", - a_cell->id.uint64, a_cell->file_storage_path); - fflush(a_cell->file_storage); - if (a_cell->chain->is_mapped) - a_cell->map_pos = a_cell->map + sizeof(l_hdr); - return 0; - } - log_it(L_ERROR, "Can't init file storage for cell 0x%016"DAP_UINT64_FORMAT_X" ( %s )", - a_cell->id.uint64, a_cell->file_storage_path); - return -1; -} - -static int s_file_atom_add(dap_chain_cell_t *a_cell, dap_chain_atom_ptr_t a_atom, uint64_t a_atom_size) +static int s_cell_file_atom_add(dap_chain_cell_t *a_cell, dap_chain_atom_ptr_t a_atom, uint64_t a_atom_size) { if (!a_atom || !a_atom_size) { log_it(L_CRITICAL, "Invalid arguments"); return -1; } if (a_cell->chain->is_mapped) { - size_t l_pos = ftell(a_cell->file_storage); + size_t l_pos = ( fseek(a_cell->file_storage, 0, SEEK_END), ftell(a_cell->file_storage) ); debug_if (s_debug_more, L_DEBUG, "Before filling volume for atom size %lu, stream pos of %s is %lu, map pos is %lu, space left in map %lu", a_atom_size, a_cell->file_storage_path, l_pos, (size_t)(a_cell->map_pos - a_cell->map), (size_t)(a_cell->map_end - a_cell->map_pos)); - if ( a_atom_size > (size_t)(a_cell->map_end - a_cell->map_pos) ) { - size_t l_map_size = dap_page_roundup(DAP_MAPPED_VOLUME_LIMIT), - l_volume_start = dap_page_rounddown(l_pos), - l_offset = l_pos - l_volume_start; - debug_if (s_debug_more, L_DEBUG, "Need to enlarge map of %s, current stream pos is %lu, map pos is %lu, offset of new map is %lu", - a_cell->file_storage_path, ftell(a_cell->file_storage), (size_t)(a_cell->map_end - a_cell->map_pos), l_offset); - if ( MAP_FAILED == (a_cell->map = mmap(NULL, l_map_size, PROT_READ|PROT_WRITE, - MAP_PRIVATE, fileno(a_cell->file_storage), l_volume_start)) ) - { - log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X" cannot be mapped, errno %d", - a_cell->file_storage_path, a_cell->id.uint64, errno); - fclose(a_cell->file_storage); + if ( a_atom_size + sizeof(uint64_t) > (size_t)(a_cell->map_end - a_cell->map_pos) ) + if ( s_cell_map_new_volume(a_cell, l_pos) ) return -2; - } - a_cell->map_pos = a_cell->map + l_offset; - a_cell->map_range_bounds = dap_list_append(a_cell->map_range_bounds, a_cell->map); - a_cell->map_range_bounds = dap_list_append(a_cell->map_range_bounds, a_cell->map_end = a_cell->map + l_map_size); - } } debug_if (s_debug_more && a_cell->chain->is_mapped, L_DEBUG, "Before writing an atom of size %lu, stream pos of %s is %lu and pos is %lu, space left in map %lu", @@ -447,13 +494,12 @@ ssize_t dap_chain_cell_file_append(dap_chain_cell_t *a_cell, const void *a_atom, if (!a_atom || !a_atom_size) { a_cell->file_storage = freopen(a_cell->file_storage_path, "w+b", a_cell->file_storage); debug_if (s_debug_more,L_DEBUG, "Rewinding file %s", a_cell->file_storage_path); - if (a_cell->chain->is_mapped && a_cell->map_range_bounds) { - a_cell->map = a_cell->map_pos = a_cell->map_range_bounds->data; - a_cell->map_end = a_cell->map_range_bounds->next->data; - } - if ( s_file_write_header(a_cell) ) { + bool was_mapped = a_cell->chain->is_mapped; + a_cell->chain->is_mapped = false; + if ( !s_cell_file_write_header(a_cell) ) { log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X": can't fill header", a_cell->file_storage_path, a_cell->id.uint64); + a_cell->chain->is_mapped = was_mapped; pthread_rwlock_unlock(&a_cell->storage_rwlock); return -2; } @@ -465,14 +511,15 @@ ssize_t dap_chain_cell_file_append(dap_chain_cell_t *a_cell, const void *a_atom, l_atom && l_atom_size; l_atom = a_cell->chain->callback_atom_iter_get(l_atom_iter, DAP_CHAIN_ITER_OP_NEXT, &l_atom_size)) { - if (s_file_atom_add(a_cell, l_atom, l_atom_size)) { + if ( s_cell_file_atom_add(a_cell, l_atom, l_atom_size) ) { l_err = true; break; } else { - l_total_res += l_atom_size + sizeof(uint64_t); + l_total_res += sizeof(uint64_t) + l_atom_size; ++l_count; } } + a_cell->chain->is_mapped = was_mapped; a_cell->chain->callback_atom_iter_delete(l_atom_iter); debug_if (s_debug_more && a_cell->chain->is_mapped,L_DEBUG, "After rewriting file %s, stream pos is %lu and map pos is %lu", a_cell->file_storage_path, ftell(a_cell->file_storage), @@ -481,13 +528,7 @@ ssize_t dap_chain_cell_file_append(dap_chain_cell_t *a_cell, const void *a_atom, debug_if (s_debug_more && a_cell->chain->is_mapped,L_DEBUG, "Before appending an atom of size %lu, stream pos of %s is %lu, map pos is %lu", a_atom_size, a_cell->file_storage_path, ftell(a_cell->file_storage), (size_t)(a_cell->map_pos - a_cell->map)); - if ( !ftell(a_cell->file_storage) && s_file_write_header(a_cell) ) { - log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X": can't fill header", - a_cell->file_storage_path, a_cell->id.uint64); - pthread_rwlock_unlock(&a_cell->storage_rwlock); - return -3; - } - if (s_file_atom_add(a_cell, a_atom, a_atom_size)) { + if ( s_cell_file_atom_add(a_cell, a_atom, a_atom_size) ) { log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X": can't save atom!", a_cell->file_storage_path, a_cell->id.uint64); pthread_rwlock_unlock(&a_cell->storage_rwlock); @@ -502,6 +543,17 @@ ssize_t dap_chain_cell_file_append(dap_chain_cell_t *a_cell, const void *a_atom, if (l_total_res) { fflush(a_cell->file_storage); +#ifdef DAP_OS_WINDOWS + if (a_cell->chain->is_mapped) { + LARGE_INTEGER SectionSize = (LARGE_INTEGER) { .QuadPart = ftell(a_cell->file_storage) }; + HANDLE hSection = (HANDLE)a_cell->map_range_bounds->data; + NTSTATUS err = pfnNtExtendSection(hSection, &SectionSize); + if ( !NT_SUCCESS(err) ) { + log_it(L_ERROR, "NtExtendSection() failed, status %lx", err); + return -4; + } + } +#endif log_it(L_DEBUG, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X": saved %zu atoms (%zu bytes)", a_cell->file_storage_path, a_cell->id.uint64, l_count, l_total_res); if (l_err) { diff --git a/modules/chain/include/dap_chain_cell.h b/modules/chain/include/dap_chain_cell.h index 2c52cce17..5c132c684 100644 --- a/modules/chain/include/dap_chain_cell.h +++ b/modules/chain/include/dap_chain_cell.h @@ -74,7 +74,6 @@ typedef struct dap_chain_cell_decl{ int dap_chain_cell_init(void); dap_chain_cell_t *dap_chain_cell_create_fill(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id); -dap_chain_cell_t *dap_chain_cell_create_fill2(dap_chain_t *a_chain, const char *a_filename); dap_chain_cell_t *dap_chain_cell_find_by_id(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id); void dap_chain_cell_close(dap_chain_cell_t *a_cell); void dap_chain_cell_delete(dap_chain_cell_t *a_cell); diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c index f5e39df6e..a2046030f 100644 --- a/modules/net/dap_chain_net.c +++ b/modules/net/dap_chain_net.c @@ -2195,7 +2195,7 @@ bool s_net_load(void *a_arg) log_it(L_WARNING, "No purge callback for chain %s, can't reload it with correct order", l_chain->name); } } else { - dap_chain_save_all( l_chain ); + //dap_chain_save_all( l_chain ); log_it (L_NOTICE, "Initialized chain files"); } l_chain->atom_num_last = l_chain->callback_count_atom(l_chain); -- GitLab From 4705ffb032c60c439ac23951cc09fdbae4e120e8 Mon Sep 17 00:00:00 2001 From: "Constantin P." <papizh.konstantin@demlabs.net> Date: Sat, 8 Jun 2024 23:59:37 +0700 Subject: [PATCH 2/5] Sub up --- dap-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dap-sdk b/dap-sdk index 063776950..392b1c81f 160000 --- a/dap-sdk +++ b/dap-sdk @@ -1 +1 @@ -Subproject commit 063776950c5bce0a5179eee970a5def10edffa41 +Subproject commit 392b1c81fa0bd58e2c617ce6a379e403f72b3dd2 -- GitLab From f04d8f55b1d77a722256dc93ec71ca46445a8e85 Mon Sep 17 00:00:00 2001 From: "Constantin P." <papizh.konstantin@demlabs.net> Date: Mon, 10 Jun 2024 14:24:06 +0700 Subject: [PATCH 3/5] ... --- modules/chain/dap_chain.c | 6 +----- modules/chain/dap_chain_cell.c | 15 +++------------ modules/chain/include/dap_chain_cell.h | 4 +++- modules/net/dap_chain_ledger.c | 6 +----- modules/net/dap_chain_net.c | 2 +- modules/type/dag/dap_chain_cs_dag.c | 4 ++-- 6 files changed, 11 insertions(+), 26 deletions(-) diff --git a/modules/chain/dap_chain.c b/modules/chain/dap_chain.c index 4bd3de572..45e255e3c 100644 --- a/modules/chain/dap_chain.c +++ b/modules/chain/dap_chain.c @@ -110,11 +110,7 @@ dap_chain_t *dap_chain_create(const char *a_chain_net_name, const char *a_chain_ .net_id = a_chain_net_id, .name = dap_strdup(a_chain_name), .net_name = dap_strdup(a_chain_net_name), -#ifdef DAP_OS_WINDOWS // TODO - .is_mapped = true, -#else .is_mapped = dap_config_get_item_bool_default(g_config, "ledger", "mapped", true), -#endif .cell_rwlock = PTHREAD_RWLOCK_INITIALIZER, .atom_notifiers = NULL }; @@ -614,7 +610,7 @@ int dap_chain_load_all(dap_chain_t *a_chain) sscanf(l_filename, "%"DAP_UINT64_FORMAT_x".dchaincell", &l_cell_id_uint64); dap_chain_cell_t *l_cell = dap_chain_cell_create_fill(a_chain, (dap_chain_cell_id_t){ .uint64 = l_cell_id_uint64 }); l_ret += dap_chain_cell_load(a_chain, l_cell); - if (DAP_CHAIN_PVT(a_chain)->need_reorder) { + if (!DAP_CHAIN_PVT(a_chain)->need_reorder) { const char *l_filename_backup = dap_strdup_printf("%s.unsorted", l_cell->file_storage_path); if (remove(l_filename_backup) == -1) { log_it(L_ERROR, "File %s doesn't exist", l_filename_backup); diff --git a/modules/chain/dap_chain_cell.c b/modules/chain/dap_chain_cell.c index 8e3e2f65a..d0afa1263 100644 --- a/modules/chain/dap_chain_cell.c +++ b/modules/chain/dap_chain_cell.c @@ -41,7 +41,7 @@ #define DAP_CHAIN_CELL_FILE_SIGNATURE 0xfa340bef153eba48 #define DAP_CHAIN_CELL_FILE_TYPE_RAW 0 #define DAP_CHAIN_CELL_FILE_TYPE_COMPRESSED 1 -#define DAP_MAPPED_VOLUME_LIMIT (1 << 28) // 256 MB for now, may be should be configurable? +#define DAP_MAPPED_VOLUME_LIMIT (1 << 20) // 256 MB for now, may be should be configurable? /** * @struct dap_chain_cell_file_header */ @@ -355,6 +355,7 @@ int dap_chain_cell_load(dap_chain_t *a_chain, dap_chain_cell_t *a_cell) if (a_chain->is_mapped) { l_hdr = (dap_chain_cell_file_header_t*)a_cell->map; } else { + fseek(a_cell->file_storage, 0, SEEK_SET); l_hdr = DAP_NEW(dap_chain_cell_file_header_t); if ( fread(l_hdr, 1, sizeof(*l_hdr), a_cell->file_storage) != sizeof(*l_hdr) ) { log_it(L_ERROR,"Can't read chain header \"%s\"", a_cell->file_storage_path); @@ -383,7 +384,7 @@ int dap_chain_cell_load(dap_chain_t *a_chain, dap_chain_cell_t *a_cell) for ( uint64_t l_el_size = 0; l_pos < l_size; ++q, l_pos += l_el_size + sizeof(uint64_t) ) { size_t space_left = (size_t)( a_cell->map_end - a_cell->map_pos ); if ( space_left < sizeof(uint64_t) || (space_left - sizeof(uint64_t)) < *(uint64_t*)a_cell->map_pos ) - if ( !s_cell_map_new_volume(a_cell, l_pos) ) + if ( s_cell_map_new_volume(a_cell, l_pos) ) break; l_el_size = *(uint64_t*)a_cell->map_pos; dap_hash_fast_t l_atom_hash; @@ -567,13 +568,3 @@ ssize_t dap_chain_cell_file_append(dap_chain_cell_t *a_cell, const void *a_atom, return l_total_res; } -/** - * @brief - * return dap_chain_cell_file_append(a_cell, NULL, 0); - * @param a_cell dap_chain_cell_t - * @return - */ -ssize_t dap_chain_cell_file_update(dap_chain_cell_t *a_cell) -{ - return dap_chain_cell_file_append(a_cell, NULL, 0); -} diff --git a/modules/chain/include/dap_chain_cell.h b/modules/chain/include/dap_chain_cell.h index 5c132c684..afc9d2192 100644 --- a/modules/chain/include/dap_chain_cell.h +++ b/modules/chain/include/dap_chain_cell.h @@ -79,5 +79,7 @@ void dap_chain_cell_close(dap_chain_cell_t *a_cell); void dap_chain_cell_delete(dap_chain_cell_t *a_cell); void dap_chain_cell_delete_all(dap_chain_t *a_chain); int dap_chain_cell_load(dap_chain_t *a_chain, dap_chain_cell_t *a_cell); -ssize_t dap_chain_cell_file_update(dap_chain_cell_t *a_cell); ssize_t dap_chain_cell_file_append(dap_chain_cell_t *a_cell,const void *a_atom, size_t a_atom_size); +DAP_STATIC_INLINE ssize_t dap_chain_cell_file_update(dap_chain_cell_t *a_cell) { + return dap_chain_cell_file_append(a_cell, NULL, 0); +} diff --git a/modules/net/dap_chain_ledger.c b/modules/net/dap_chain_ledger.c index af4225190..320d0e811 100644 --- a/modules/net/dap_chain_ledger.c +++ b/modules/net/dap_chain_ledger.c @@ -584,12 +584,8 @@ static dap_ledger_t * dap_ledger_handle_new(void) l_ledger_pvt->threshold_txs_free_timer = dap_interval_timer_create(s_threshold_free_timer_tick, (dap_timer_callback_t)s_threshold_txs_free, l_ledger); l_ledger_pvt->threshold_emissions_free_timer = dap_interval_timer_create(s_threshold_free_timer_tick, - (dap_timer_callback_t) s_threshold_emission_free, l_ledger); -#ifdef DAP_OS_WINDOWS - l_ledger_pvt->mapped = false; -#else + (dap_timer_callback_t) s_threshold_emission_free, l_ledger); l_ledger_pvt->mapped = dap_config_get_item_bool_default(g_config, "ledger", "mapped", true); -#endif return l_ledger; } diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c index a2046030f..6b50fce03 100644 --- a/modules/net/dap_chain_net.c +++ b/modules/net/dap_chain_net.c @@ -2177,7 +2177,7 @@ bool s_net_load(void *a_arg) l_net->pub.fee_addr = c_dap_chain_addr_blank; if (!dap_chain_load_all(l_chain)) { log_it (L_NOTICE, "Loaded chain files"); - if (DAP_CHAIN_PVT(l_chain)->need_reorder) { + if (!DAP_CHAIN_PVT(l_chain)->need_reorder) { log_it(L_DAP, "Reordering chain files for chain %s", l_chain->name); if (l_chain->callback_atom_add_from_treshold) while (l_chain->callback_atom_add_from_treshold(l_chain, NULL)) diff --git a/modules/type/dag/dap_chain_cs_dag.c b/modules/type/dag/dap_chain_cs_dag.c index 5b047189d..2f3055ca7 100644 --- a/modules/type/dag/dap_chain_cs_dag.c +++ b/modules/type/dag/dap_chain_cs_dag.c @@ -347,8 +347,8 @@ static void s_dap_chain_cs_dag_purge(dap_chain_t *a_chain) } HASH_ITER(hh, l_dag_pvt->events_lasts_unlinked, l_event_current, l_event_tmp) { HASH_DEL(l_dag_pvt->events_lasts_unlinked, l_event_current); - if (!a_chain->is_mapped && !l_event_current->mapped_region) - DAP_DELETE(l_event_current->event); + //if (!a_chain->is_mapped && !l_event_current->mapped_region) + // DAP_DELETE(l_event_current->event); DAP_DELETE(l_event_current); } HASH_ITER(hh, l_dag_pvt->events_treshold, l_event_current, l_event_tmp) { -- GitLab From 8b8c830510f7fc7540fb2d452ea5b33201a23782 Mon Sep 17 00:00:00 2001 From: "Constantin P." <papizh.konstantin@demlabs.net> Date: Tue, 11 Jun 2024 13:08:07 +0700 Subject: [PATCH 4/5] ... --- modules/chain/dap_chain.c | 10 +++++++++- modules/chain/dap_chain_cell.c | 15 ++++++++++++++- modules/net/dap_chain_net.c | 7 ++++--- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/modules/chain/dap_chain.c b/modules/chain/dap_chain.c index 45e255e3c..d0171a36e 100644 --- a/modules/chain/dap_chain.c +++ b/modules/chain/dap_chain.c @@ -610,7 +610,14 @@ int dap_chain_load_all(dap_chain_t *a_chain) sscanf(l_filename, "%"DAP_UINT64_FORMAT_x".dchaincell", &l_cell_id_uint64); dap_chain_cell_t *l_cell = dap_chain_cell_create_fill(a_chain, (dap_chain_cell_id_t){ .uint64 = l_cell_id_uint64 }); l_ret += dap_chain_cell_load(a_chain, l_cell); - if (!DAP_CHAIN_PVT(a_chain)->need_reorder) { + if ( DAP_CHAIN_PVT(a_chain)->need_reorder ) { +#ifdef DAP_OS_WINDOWS + strcat(l_cell->file_storage_path, ".new"); + if (remove(l_cell->file_storage_path) == -1) { + log_it(L_ERROR, "File %s doesn't exist", l_cell->file_storage_path); + } + *(l_cell->file_storage_path + strlen(l_cell->file_storage_path) - 4) = '\0'; +#else const char *l_filename_backup = dap_strdup_printf("%s.unsorted", l_cell->file_storage_path); if (remove(l_filename_backup) == -1) { log_it(L_ERROR, "File %s doesn't exist", l_filename_backup); @@ -619,6 +626,7 @@ int dap_chain_load_all(dap_chain_t *a_chain) log_it(L_ERROR, "Couldn't rename %s to %s", l_cell->file_storage_path, l_filename_backup); } DAP_DELETE(l_filename_backup); +#endif } } } diff --git a/modules/chain/dap_chain_cell.c b/modules/chain/dap_chain_cell.c index d0afa1263..0167d9c88 100644 --- a/modules/chain/dap_chain_cell.c +++ b/modules/chain/dap_chain_cell.c @@ -41,7 +41,7 @@ #define DAP_CHAIN_CELL_FILE_SIGNATURE 0xfa340bef153eba48 #define DAP_CHAIN_CELL_FILE_TYPE_RAW 0 #define DAP_CHAIN_CELL_FILE_TYPE_COMPRESSED 1 -#define DAP_MAPPED_VOLUME_LIMIT (1 << 20) // 256 MB for now, may be should be configurable? +#define DAP_MAPPED_VOLUME_LIMIT ( 1 << 28 ) // 256 MB for now, may be should be configurable? /** * @struct dap_chain_cell_file_header */ @@ -291,6 +291,16 @@ void dap_chain_cell_close(dap_chain_cell_t *a_cell) #endif dap_list_free(a_cell->map_range_bounds); } +#ifdef DAP_OS_WINDOWS + char *l_new = strstr(a_cell->file_storage_path, ".new"); + if (l_new) { + char *l_orig = dap_strdup(a_cell->file_storage_path); + *l_new = '\0'; + remove(a_cell->file_storage_path); + rename(l_orig, a_cell->file_storage_path); + DAP_DELETE(l_orig); + } +#endif } /** @@ -493,6 +503,9 @@ ssize_t dap_chain_cell_file_append(dap_chain_cell_t *a_cell, const void *a_atom, bool l_err = false; pthread_rwlock_wrlock(&a_cell->storage_rwlock); if (!a_atom || !a_atom_size) { +#ifdef DAP_OS_WINDOWS + strcat(a_cell->file_storage_path, ".new"); +#endif a_cell->file_storage = freopen(a_cell->file_storage_path, "w+b", a_cell->file_storage); debug_if (s_debug_more,L_DEBUG, "Rewinding file %s", a_cell->file_storage_path); bool was_mapped = a_cell->chain->is_mapped; diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c index 1ccf77513..4e71dd369 100644 --- a/modules/net/dap_chain_net.c +++ b/modules/net/dap_chain_net.c @@ -2172,19 +2172,20 @@ bool s_net_load(void *a_arg) l_net->pub.fee_addr = c_dap_chain_addr_blank; if (!dap_chain_load_all(l_chain)) { log_it (L_NOTICE, "Loaded chain files"); - if (!DAP_CHAIN_PVT(l_chain)->need_reorder) { + if ( DAP_CHAIN_PVT(l_chain)->need_reorder ) { log_it(L_DAP, "Reordering chain files for chain %s", l_chain->name); - if (l_chain->callback_atom_add_from_treshold) + if (l_chain->callback_atom_add_from_treshold) { while (l_chain->callback_atom_add_from_treshold(l_chain, NULL)) log_it(L_DEBUG, "Added atom from treshold"); + } dap_chain_save_all(l_chain); DAP_CHAIN_PVT(l_chain)->need_reorder = false; if (l_chain->callback_purge) { + dap_chain_net_decree_purge(l_net); l_chain->callback_purge(l_chain); dap_ledger_purge(l_net->pub.ledger, false); l_net->pub.fee_value = uint256_0; l_net->pub.fee_addr = c_dap_chain_addr_blank; - dap_chain_net_decree_purge(l_net); dap_chain_load_all(l_chain); } else log_it(L_WARNING, "No purge callback for chain %s, can't reload it with correct order", l_chain->name); -- GitLab From ced69bd2a14b34ffd444de5d06692cfef3baffa1 Mon Sep 17 00:00:00 2001 From: Constantin P <papizh.konstantin@demlabs.net> Date: Tue, 11 Jun 2024 17:35:57 +0700 Subject: [PATCH 5/5] Pointer arithmetics fixed --- modules/chain/dap_chain_cell.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/modules/chain/dap_chain_cell.c b/modules/chain/dap_chain_cell.c index 0167d9c88..31dba0eee 100644 --- a/modules/chain/dap_chain_cell.c +++ b/modules/chain/dap_chain_cell.c @@ -356,8 +356,8 @@ int dap_chain_cell_load(dap_chain_t *a_chain, dap_chain_cell_t *a_cell) if (!a_cell) return -1; size_t l_size = ( fseek(a_cell->file_storage, 0, SEEK_END), ftell(a_cell->file_storage) ), l_pos = 0; - if ( l_size <= sizeof(dap_chain_cell_file_header_t) ) { - log_it(L_INFO, "Chain cell \"%s\" is yet empty", a_cell->file_storage_path); + if ( l_size < sizeof(dap_chain_cell_file_header_t) ) { + log_it(L_ERROR, "Chain cell \"%s\" is corrupt, create new file", a_cell->file_storage_path); return -1; } int l_ret = 0; @@ -386,8 +386,15 @@ int dap_chain_cell_load(dap_chain_t *a_chain, dap_chain_cell_t *a_cell) if (!a_chain->is_mapped) DAP_DELETE(l_hdr); return -4; } - l_pos += sizeof(dap_chain_cell_file_header_t); + if (a_chain->is_mapped) + a_cell->map_pos += l_pos; + if (l_size == l_pos) { + fseek(a_cell->file_storage, l_pos, SEEK_END); + return 0; + } + + uint64_t q = 0; if (a_chain->is_mapped) { a_cell->map_pos = a_cell->map + sizeof(dap_chain_cell_file_header_t); -- GitLab