Newer
Older
/*
* Authors:
* Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
* DeM Labs Inc. https://demlabs.net
* Kelvin Project https://github.com/kelvinblockchain
* Copyright (c) 2017-2019
* All rights reserved.
This file is part of DAP (Distributed Applications Platform) the open source project
DAP (Distributed Applications Platform) is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DAP is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with any DAP based project. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dap_chain.h"
#include "dap_chain_cell.h"
#include "dap_chain_cs.h"
#include "dap_common.h"
#include "dap_config.h"
#include "dap_strfuncs.h"
#define DAP_CHAIN_CELL_FILE_VERSION 1
#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?
/**
* @struct dap_chain_cell_file_header
*/
typedef struct dap_chain_cell_file_header
{
uint64_t signature;
uint32_t version;
uint8_t type;
dap_chain_id_t chain_id;
dap_chain_net_id_t chain_net_id;
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
* @return
*/
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");
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
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;
LARGE_INTEGER Offset = {
.QuadPart = l_volume_start
};
if ( !NT_SUCCESS ( err = pfnNtMapViewOfSection(hSection, GetCurrentProcess(),
(HANDLE)&a_cell->map, 0, 0,
&Offset, &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
* @param a_chain dap_chain_t object
* @param a_cell_id dap_chain_cell_id_t cell (shard) id
* @return dap_chain_cell_t*
*/
dap_chain_cell_t * dap_chain_cell_find_by_id(dap_chain_t * a_chain, dap_chain_cell_id_t a_cell_id)
if (!a_chain->cells)
return NULL;
dap_chain_cell_t *l_cell = NULL;
pthread_rwlock_rdlock(&a_chain->cell_rwlock);
HASH_FIND(hh, a_chain->cells, &a_cell_id, sizeof(dap_chain_cell_id_t), l_cell);
pthread_rwlock_unlock(&a_chain->cell_rwlock);
return l_cell;
* @brief
* a_cell_id if < 0 then not used
* @param a_chain dap_chain_t object
* @param a_cell_id dap_chain_cell_id_t cell (shard) id
* @return dap_chain_cell_t*
*/
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 * l_cell = NULL;
pthread_rwlock_wrlock(&a_chain->cell_rwlock);
HASH_FIND(hh, a_chain->cells, &a_cell_id, sizeof(dap_chain_cell_id_t), l_cell);
if (l_cell) {
pthread_rwlock_unlock(&a_chain->cell_rwlock);
return l_cell;
}
#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);
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;
if ( !(l_cell = DAP_NEW_Z(dap_chain_cell_t)) )
CLEANUP_AND_RET;
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
* close a_cell->file_storage file object
* @param a_cell dap_chain_cell_t object
*/
void dap_chain_cell_close(dap_chain_cell_t *a_cell)
{
if(!a_cell)
return;
if(a_cell->file_storage) {
fclose(a_cell->file_storage);
a_cell->file_storage = NULL;
}
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) {
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));
#ifdef DAP_OS_WINDOWS
NtClose(a_cell->map_range_bounds->data);
#endif
#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
* @brief
* free chain cell objects
* @param a_cell dap_chain_cell_t object
*/
void dap_chain_cell_delete(dap_chain_cell_t *a_cell)
{
if(!a_cell)
return;
dap_chain_cell_close(a_cell);
if (a_cell->chain->cells) {
dap_chain_cell_t *l_cell = NULL;
dap_chain_cell_id_t l_cell_id = {
.uint64 = a_cell->id.uint64
};
pthread_rwlock_wrlock(&a_cell->chain->cell_rwlock);
HASH_FIND(hh, a_cell->chain->cells, &l_cell_id, sizeof(dap_chain_cell_id_t), l_cell);
if (l_cell)
HASH_DEL(a_cell->chain->cells, l_cell);
pthread_rwlock_unlock(&a_cell->chain->cell_rwlock);
}
a_cell->chain = NULL;
pthread_rwlock_destroy(&a_cell->storage_rwlock);
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
void dap_chain_cell_delete_all_and_free_file(dap_chain_t *a_chain) {
if (!a_chain)
return;
pthread_rwlock_wrlock(&a_chain->cell_rwlock);
dap_chain_cell_t *l_cell, *l_tmp;
HASH_ITER(hh, a_chain->cells, l_cell, l_tmp) {
char *l_fsp = dap_strdup(l_cell->file_storage_path);
dap_chain_cell_id_t l_cell_id = l_cell->id;
dap_chain_cell_close(l_cell);
dap_chain_cell_t * l_cell_nh = DAP_NEW_Z(dap_chain_cell_t);
FILE *l_file = fopen(l_fsp, "w+b");
if ( !l_file ) {
log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X" cannot be opened, error %d",
l_fsp, l_cell_id.uint64, errno);
}
*l_cell_nh = (dap_chain_cell_t) {
.id = l_cell_id,
.chain = a_chain,
.file_storage = l_file
};
if ( !s_cell_file_write_header(l_cell_nh)) {
log_it(L_ERROR, "Can't init file storage for cell 0x%016"DAP_UINT64_FORMAT_X" \"%s\", errno %d",
l_cell_id.uint64, l_fsp, errno);
} else {
log_it(L_NOTICE, "Reinitialized file storage for cell 0x%016"DAP_UINT64_FORMAT_X" \"%s\"",
l_cell_id.uint64, l_fsp);
}
dap_chain_cell_close(l_cell_nh);
DAP_DELETE(l_fsp);
HASH_DEL(a_chain->cells, l_cell);
pthread_rwlock_destroy(&l_cell->storage_rwlock);
DAP_DELETE(l_cell);
}
pthread_rwlock_unlock(&a_chain->cell_rwlock);
}
void dap_chain_cell_delete_all(dap_chain_t *a_chain) {
if (!a_chain)
return;
pthread_rwlock_wrlock(&a_chain->cell_rwlock);
dap_chain_cell_t *l_cell, *l_tmp;
HASH_ITER(hh, a_chain->cells, l_cell, l_tmp) {
dap_chain_cell_close(l_cell);
HASH_DEL(a_chain->cells, l_cell);
pthread_rwlock_destroy(&l_cell->storage_rwlock);
DAP_DELETE(l_cell);
}
pthread_rwlock_unlock(&a_chain->cell_rwlock);
* load cell file, which is pointed in a_cell_file_path variable, for example "0.dchaincell"
* @param a_chain dap_chain_t object
* @param a_cell_file_path contains name of chain, for example "0.dchaincell"
int dap_chain_cell_load(dap_chain_t *a_chain, dap_chain_cell_t *a_cell)
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_ERROR, "Chain cell \"%s\" is corrupt, create new file", a_cell->file_storage_path);
int l_ret = 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;
} else {
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);
fclose(a_cell->file_storage);
DAP_DELETE(l_hdr);
return -2;
}
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);
fclose(a_cell->file_storage);
if (!a_chain->is_mapped) DAP_DELETE(l_hdr);
fclose(a_cell->file_storage);
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) {
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; l_pos < l_size; ++q, l_pos += l_el_size + sizeof(uint64_t), a_chain->load_progress = (int)((double)l_pos/l_size * 100 + 0.5)) {
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);
} else {
DAP_DELETE(l_hdr);
size_t l_read = 0;
uint64_t l_el_size = 0;
while ((l_read = fread(&l_el_size, 1, sizeof(l_el_size), a_cell->file_storage)) && !feof(a_cell->file_storage)) {
if (l_read != sizeof(l_el_size) || l_el_size == 0) {
log_it(L_ERROR, "Corrupted element size %zu, chain %s is damaged", l_el_size, a_cell->file_storage_path);
l_ret = -4;
break;
}
dap_chain_atom_ptr_t l_element = DAP_NEW_SIZE(dap_chain_atom_ptr_t, l_el_size);
if (!l_element) {
log_it(L_CRITICAL, "Memory allocation error");
l_ret = -5;
break;
}
l_pos += sizeof(uint64_t) + ( l_read = fread((void*)l_element, 1, l_el_size, a_cell->file_storage) );
a_chain->load_progress = (int)((double)l_pos/l_size * 100 + 0.5);
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);
l_ret = -6;
break;
}
dap_hash_fast_t l_atom_hash = {};
dap_hash_fast(l_element, l_el_size, &l_atom_hash);
dap_chain_atom_verify_res_t l_res = a_chain->callback_atom_add(a_chain, l_element, l_el_size, &l_atom_hash);
if (l_res != ATOM_ACCEPT && l_res != ATOM_FORK) {
log_it(L_INFO, "Loaded %lu atoms in cell %s", q, a_cell->file_storage_path);
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;
}
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 + sizeof(uint64_t) > (size_t)(a_cell->map_end - a_cell->map_pos) )
if ( s_cell_map_new_volume(a_cell, l_pos) )
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",
a_atom_size, a_cell->file_storage_path, ftell(a_cell->file_storage),
(size_t)(a_cell->map_pos - a_cell->map), (size_t)(a_cell->map_end - a_cell->map_pos));
if (fwrite(&a_atom_size, sizeof(a_atom_size), 1, a_cell->file_storage) != 1) {
log_it (L_ERROR, "Can't write atom data size from cell 0x%016"DAP_UINT64_FORMAT_X" in \"%s\"",
a_cell->id.uint64,
a_cell->file_storage_path);
return -2;
}
if (fwrite(a_atom, a_atom_size, 1, a_cell->file_storage) != 1) {
log_it (L_ERROR, "Can't write data from cell 0x%016"DAP_UINT64_FORMAT_X" to the file \"%s\"",
debug_if (s_debug_more && a_cell->chain->is_mapped, L_DEBUG, "After writing an atom of size %lu, stream pos of %s is %lu and map shift is %lu",
a_atom_size, a_cell->file_storage_path, ftell(a_cell->file_storage),
(size_t)(a_cell->map_pos - a_cell->map));
/**
* @brief s_cell_file_append
* add atoms to selected chain
* @param a_cell - cell object. Contains file path to cell storage data, for example - "0.dchaincell"
* a_cell->chain contains
* name - "zerochain"
* net_name - "kelvin-testnet"
* filepath - "C:\\Users\\Public\\Documents\\cellframe-node\\var\\lib\\network\\kelvin-testnet\\zerochain\\/0.dchaincell"
* @param a_atom
* @param a_atom_size
* @return
*/
ssize_t dap_chain_cell_file_append(dap_chain_cell_t *a_cell, const void *a_atom, size_t a_atom_size)
if(!a_cell)
return -1;
if (!a_atom && !a_cell->chain) {
log_it(L_WARNING,"Chain not found for cell 0x%016"DAP_UINT64_FORMAT_X" ( %s )",
a_cell->id.uint64, a_cell->file_storage_path);
return -1;
}
size_t l_total_res = 0, l_count = 0;
bool l_err = false;
pthread_rwlock_wrlock(&a_cell->storage_rwlock);
#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;
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);
pthread_rwlock_unlock(&a_cell->storage_rwlock);
dap_chain_atom_iter_t *l_atom_iter = a_cell->chain->callback_atom_iter_create(a_cell->chain, a_cell->id, NULL);
dap_chain_atom_ptr_t l_atom;
uint64_t l_atom_size = 0;
for (l_atom = a_cell->chain->callback_atom_iter_get(l_atom_iter, DAP_CHAIN_ITER_OP_FIRST, &l_atom_size);
l_atom = a_cell->chain->callback_atom_iter_get(l_atom_iter, DAP_CHAIN_ITER_OP_NEXT, &l_atom_size))
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),
(size_t)(a_cell->map_pos - a_cell->map));
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));
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);
return -4;
}
debug_if (s_debug_more && a_cell->chain->is_mapped, L_DEBUG,"After 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_end - a_cell->map_pos));
++l_count;
l_total_res = a_atom_size + sizeof(uint64_t);
#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) {
log_it(L_WARNING, "Not all data was saved due to writing error!");
} else {
log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X": nothing saved!",
a_cell->file_storage_path, a_cell->id.uint64);
pthread_rwlock_unlock(&a_cell->storage_rwlock);