sars.c (21677B)
1 /* Copyright (C) 2022, 2023 |Méso|Star> (contact@meso-star.com) 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 3 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 16 #define _POSIX_C_SOURCE 200809L /* mmap support */ 17 #define _DEFAULT_SOURCE 1 /* MAP_POPULATE support */ 18 #define _BSD_SOURCE 1 /* MAP_POPULATE for glibc < 2.19 */ 19 20 #include "sars.h" 21 #include "sars_c.h" 22 #include "sars_log.h" 23 24 #include <rsys/algorithm.h> 25 #include <rsys/cstr.h> 26 #include <rsys/hash.h> 27 28 #include <unistd.h> /* sysconf support */ 29 30 #include <errno.h> 31 #include <sys/mman.h> /* mmap */ 32 #include <sys/stat.h> /* fstat */ 33 34 /******************************************************************************* 35 * Helper functions 36 ******************************************************************************/ 37 static INLINE int 38 is_stdin(FILE* stream) 39 { 40 struct stat stream_buf; 41 struct stat stdin_buf; 42 ASSERT(stream); 43 CHK(fstat(fileno(stream), &stream_buf) == 0); 44 CHK(fstat(STDIN_FILENO, &stdin_buf) == 0); 45 return stream_buf.st_dev == stdin_buf.st_dev; 46 } 47 48 static INLINE res_T 49 check_sars_create_args(const struct sars_create_args* args) 50 { 51 /* Nothing to check. Only return RES_BAD_ARG if args is NULL */ 52 return args ? RES_OK : RES_BAD_ARG; 53 } 54 55 static INLINE res_T 56 check_sars_load_args(const struct sars_load_args* args) 57 { 58 if(!args || !args->path) return RES_BAD_ARG; 59 return RES_OK; 60 } 61 62 static INLINE res_T 63 check_sars_load_stream_args 64 (struct sars* sars, 65 const struct sars_load_stream_args* args) 66 { 67 if(!args || !args->stream || !args->name) return RES_BAD_ARG; 68 if(args->memory_mapping && is_stdin(args->stream)) { 69 log_err(sars, 70 "%s: unable to use memory mapping on data loaded from stdin\n", 71 args->name); 72 return RES_BAD_ARG; 73 } 74 return RES_OK; 75 } 76 77 static void 78 reset_sars(struct sars* sars) 79 { 80 ASSERT(sars); 81 sars->pagesize = 0; 82 sars->nnodes = 0; 83 darray_band_purge(&sars->bands); 84 } 85 86 static res_T 87 read_band 88 (struct sars* sars, 89 struct band* band, 90 FILE* stream) 91 { 92 size_t iband; 93 res_T res = RES_OK; 94 ASSERT(sars && band); 95 96 band->sars = sars; 97 iband = (size_t)(band - darray_band_cdata_get(&sars->bands)); 98 99 /* Read band definition */ 100 #define READ(Var, Name) { \ 101 if(fread((Var), sizeof(*(Var)), 1, stream) != 1) { \ 102 log_err(sars, "%s: band %lu: could not read the %s.\n", \ 103 sars_get_name(sars), (unsigned long)iband, (Name)); \ 104 res = RES_IO_ERR; \ 105 goto error; \ 106 } \ 107 } (void)0 108 READ(&band->low, "band lower bound"); 109 READ(&band->upp, "band upper bound"); 110 #undef READ 111 112 /* Check band description */ 113 if(band->low < 0 || band->low >= band->upp) { 114 log_err(sars, 115 "%s: band %lu: invalid band range [%g, %g[.\n", 116 sars_get_name(sars), (unsigned long)iband, band->low, band->upp); 117 res = RES_BAD_ARG; 118 goto error; 119 } 120 121 exit: 122 return res; 123 error: 124 goto exit; 125 } 126 127 static res_T 128 map_data 129 (struct sars* sars, 130 const int fd, /* File descriptor */ 131 const size_t filesz, /* Overall filesize */ 132 const char* data_name, 133 const off_t offset, /* Offset of the data into file */ 134 const size_t map_len, 135 void** out_map) /* Lenght of the data to map */ 136 { 137 void* map = NULL; 138 res_T res = RES_OK; 139 ASSERT(sars && filesz && data_name && map_len && out_map); 140 ASSERT(IS_ALIGNED((size_t)offset, (size_t)sars->pagesize)); 141 142 if((size_t)offset + map_len > filesz) { 143 log_err(sars, "%s: the %s to map exceed the file size\n", 144 sars_get_name(sars), data_name); 145 res = RES_IO_ERR; 146 goto error; 147 } 148 149 map = mmap(NULL, map_len, PROT_READ, MAP_PRIVATE|MAP_POPULATE, fd, offset); 150 if(map == MAP_FAILED) { 151 log_err(sars, "%s: could not map the %s -- %s\n", 152 sars_get_name(sars), data_name, strerror(errno)); 153 res = RES_IO_ERR; 154 goto error; 155 } 156 157 exit: 158 *out_map = map; 159 return res; 160 error: 161 if(map == MAP_FAILED) map = NULL; 162 goto exit; 163 } 164 165 static res_T 166 map_file(struct sars* sars, FILE* stream) 167 { 168 size_t filesz; 169 size_t map_len; 170 size_t iband; 171 size_t nbands; 172 off_t offset; 173 res_T res = RES_OK; 174 ASSERT(sars && stream); 175 176 /* Compute the length in bytes of the k to map for each band/quadrature point */ 177 map_len = ALIGN_SIZE(sars->nnodes * sizeof(float)*2, sars->pagesize); 178 179 /* Compute the offset toward the 1st list of radiative coefficients */ 180 offset = ftell(stream); 181 offset = (off_t)ALIGN_SIZE((uint64_t)offset, sars->pagesize); 182 183 /* Retrieve the overall filesize */ 184 fseek(stream, 0, SEEK_END); 185 filesz = (size_t)ftell(stream); 186 187 nbands = sars_get_bands_count(sars); 188 FOR_EACH(iband, 0, nbands) { 189 struct band* band = NULL; 190 191 band = darray_band_data_get(&sars->bands) + iband; 192 band->map_len = map_len; 193 194 /* Mapping per band radiative coefficients */ 195 res = map_data(sars, fileno(stream), filesz, "radiative coefficients", 196 offset, band->map_len, (void**)&band->k_list); 197 if(res != RES_OK) { 198 log_err(sars, 199 "%s: data mapping error for band %lu\n", 200 sars_get_name(sars), (unsigned long)iband); 201 res = RES_IO_ERR; 202 goto error; 203 } 204 205 offset = (off_t)((size_t)offset + map_len); 206 } 207 208 exit: 209 return res; 210 error: 211 goto exit; 212 } 213 214 static res_T 215 read_padding(FILE* stream, const size_t padding) 216 { 217 char chunk[1024]; 218 size_t remaining_nbytes = padding; 219 220 while(remaining_nbytes) { 221 const size_t nbytes = MMIN(sizeof(chunk), remaining_nbytes); 222 if(fread(chunk, 1, nbytes, stream) != nbytes) return RES_IO_ERR; 223 remaining_nbytes -= nbytes; 224 } 225 return RES_OK; 226 } 227 228 /* Return the size in bytes of the data layout and band descriptors */ 229 static INLINE size_t 230 compute_sizeof_header(struct sars* sars) 231 { 232 size_t sizeof_header = 0; 233 ASSERT(sars); 234 235 sizeof_header = 236 sizeof(uint64_t) /* pagesize */ 237 + sizeof(uint64_t) /* #bands */ 238 + sizeof(uint64_t) /* #nodes */ 239 + sizeof(double[2]) * sars_get_bands_count(sars); /* Bands */ 240 return sizeof_header; 241 } 242 243 static res_T 244 load_data 245 (struct sars* sars, 246 FILE* stream, 247 const char* data_name, 248 float** out_data) 249 { 250 float* data = NULL; 251 res_T res = RES_OK; 252 ASSERT(sars && stream && data_name && out_data); 253 254 data = MEM_ALLOC(sars->allocator, sizeof(float[2]/*ka and ks*/)*sars->nnodes); 255 if(!data) { 256 res = RES_MEM_ERR; 257 log_err(sars, "%s: could not allocate the %s -- %s\n", 258 sars_get_name(sars), data_name, res_to_cstr(res)); 259 goto error; 260 } 261 262 if(fread(data, sizeof(float[2]), sars->nnodes, stream) != sars->nnodes) { 263 res = RES_IO_ERR; 264 log_err(sars, "%s: could not read the %s -- %s\n", 265 sars_get_name(sars), data_name, res_to_cstr(res)); 266 goto error; 267 } 268 269 exit: 270 *out_data = data; 271 return res; 272 error: 273 if(data) { MEM_RM(sars->allocator, data); data = NULL; } 274 goto exit; 275 } 276 277 static res_T 278 load_file(struct sars* sars, FILE* stream) 279 { 280 size_t sizeof_header; 281 size_t sizeof_k_list; 282 size_t padding_bytes; 283 size_t iband; 284 size_t nbands; 285 res_T res = RES_OK; 286 ASSERT(sars && stream); 287 288 sizeof_header = compute_sizeof_header(sars); 289 sizeof_k_list = sizeof(float[2])*sars->nnodes; 290 291 padding_bytes = ALIGN_SIZE(sizeof_header, sars->pagesize) - sizeof_header; 292 if((res = read_padding(stream, padding_bytes)) != RES_OK) goto error; 293 294 /* Calculate the padding between the lists of radiative coefficients. Note 295 * that this padding is the same between each list */ 296 padding_bytes = ALIGN_SIZE(sizeof_k_list, sars->pagesize) - sizeof_k_list; 297 298 nbands = sars_get_bands_count(sars); 299 FOR_EACH(iband, 0, nbands) { 300 struct band* band = NULL; 301 302 band = darray_band_data_get(&sars->bands) + iband; 303 ASSERT(!band->k_list && band->sars == sars); 304 305 /* Loading per band scattering coefficients */ 306 res = load_data(sars, stream, "radiative coefficients", &band->k_list); 307 if(res != RES_OK) { 308 log_err(sars, 309 "%s: data loading error for band %lu\n", 310 sars_get_name(sars), (unsigned long)iband); 311 goto error; 312 } 313 314 if((res = read_padding(stream, padding_bytes)) != RES_OK) goto error; 315 } 316 317 exit: 318 return res; 319 error: 320 goto exit; 321 } 322 323 static res_T 324 load_stream(struct sars* sars, const struct sars_load_stream_args* args) 325 { 326 size_t iband; 327 uint64_t nbands; 328 res_T res = RES_OK; 329 ASSERT(sars && check_sars_load_stream_args(sars, args) == RES_OK); 330 331 reset_sars(sars); 332 333 res = str_set(&sars->name, args->name); 334 if(res != RES_OK) { 335 log_err(sars, "%s: unable to duplicate path to loaded data or stream name\n", 336 args->name); 337 goto error; 338 } 339 340 /* Read file header */ 341 #define READ(Var, Name) { \ 342 if(fread((Var), sizeof(*(Var)), 1, args->stream) != 1) { \ 343 log_err(sars, "%s: could not read the %s.\n", sars_get_name(sars), (Name));\ 344 res = RES_IO_ERR; \ 345 goto error; \ 346 } \ 347 } (void)0 348 READ(&sars->pagesize, "page size"); 349 READ(&nbands, "number of bands"); 350 READ(&sars->nnodes, "number of nodes"); 351 #undef READ 352 353 /* Check band description */ 354 if(!IS_ALIGNED(sars->pagesize, sars->pagesize_os)) { 355 log_err(sars, 356 "%s: invalid page size %lu. The page size attribute must be aligned on " 357 "the page size of the operating system (%lu).\n", 358 sars_get_name(sars), 359 (unsigned long)sars->pagesize, 360 (unsigned long)sars->pagesize_os); 361 res = RES_BAD_ARG; 362 goto error; 363 } 364 if(!nbands) { 365 log_err(sars, "%s: invalid number of bands %lu.\n", 366 sars_get_name(sars), (unsigned long)nbands); 367 res = RES_BAD_ARG; 368 goto error; 369 } 370 if(!sars->nnodes) { 371 log_err(sars, "%s: invalid number of nodes %lu.\n", 372 sars_get_name(sars), (unsigned long)sars->nnodes); 373 res = RES_BAD_ARG; 374 goto error; 375 } 376 377 /* Allocate the bands */ 378 res = darray_band_resize(&sars->bands, nbands); 379 if(res != RES_OK) { 380 log_err(sars, "%s: could not allocate the list of bands (#bands=%lu).\n", 381 sars_get_name(sars), (unsigned long)nbands); 382 goto error; 383 } 384 385 /* Read the band description */ 386 FOR_EACH(iband, 0, nbands) { 387 struct band* band = darray_band_data_get(&sars->bands) + iband; 388 res = read_band(sars, band, args->stream); 389 if(res != RES_OK) goto error; 390 if(iband > 0 && band[0].low < band[-1].upp) { 391 log_err(sars, 392 "%s: bands must be sorted in ascending order and must not " 393 "overlap (band %lu in [%g, %g[ nm; band %lu in [%g, %g[ nm).\n", 394 sars_get_name(sars), 395 (unsigned long)(iband-1), band[-1].low, band[-1].upp, 396 (unsigned long)(iband), band[ 0].low, band[ 0].upp); 397 res = RES_BAD_ARG; 398 goto error; 399 } 400 } 401 402 if(args->memory_mapping) { 403 res = map_file(sars, args->stream); 404 if(res != RES_OK) goto error; 405 } else { 406 res = load_file(sars, args->stream); 407 if(res != RES_OK) goto error; 408 } 409 410 exit: 411 return res; 412 error: 413 reset_sars(sars); 414 goto exit; 415 } 416 417 static INLINE int 418 cmp_band(const void* key, const void* item) 419 { 420 const struct band* band = item; 421 double wnum; 422 ASSERT(key && item); 423 wnum = *(double*)key; 424 425 if(wnum < band->low) { 426 return -1; 427 } else if(wnum >= band->upp) { 428 return +1; 429 } else { 430 return 0; 431 } 432 } 433 434 static INLINE void 435 hash_band 436 (struct sha256_ctx* ctx, 437 const struct sars_band* band, 438 const size_t nnodes) 439 { 440 sha256_ctx_update(ctx, (const char*)&band->lower, sizeof(band->lower)); 441 sha256_ctx_update(ctx, (const char*)&band->upper, sizeof(band->upper)); 442 sha256_ctx_update(ctx, (const char*)&band->id, sizeof(band->id)); 443 sha256_ctx_update(ctx, (const char*)band->k_list, sizeof(*band->k_list)*nnodes); 444 } 445 446 static void 447 release_sars(ref_T* ref) 448 { 449 struct sars* sars = NULL; 450 ASSERT(ref); 451 sars = CONTAINER_OF(ref, struct sars, ref); 452 if(sars->logger == &sars->logger__) logger_release(&sars->logger__); 453 str_release(&sars->name); 454 darray_band_release(&sars->bands); 455 MEM_RM(sars->allocator, sars); 456 } 457 458 /******************************************************************************* 459 * Exported functions 460 ******************************************************************************/ 461 res_T 462 sars_create 463 (const struct sars_create_args* args, 464 struct sars** out_sars) 465 { 466 struct sars* sars = NULL; 467 struct mem_allocator* allocator = NULL; 468 res_T res = RES_OK; 469 470 if(!out_sars) { res = RES_BAD_ARG; goto error; } 471 res = check_sars_create_args(args); 472 if(res != RES_OK) goto error; 473 474 allocator = args->allocator ? args->allocator : &mem_default_allocator; 475 sars = MEM_CALLOC(allocator, 1, sizeof(*sars)); 476 if(!sars) { 477 if(args->verbose) { 478 #define ERR_STR "Could not allocate the Star-Aerosol device.\n" 479 if(args->logger) { 480 logger_print(args->logger, LOG_ERROR, ERR_STR); 481 } else { 482 fprintf(stderr, MSG_ERROR_PREFIX ERR_STR); 483 } 484 #undef ERR_STR 485 } 486 res = RES_MEM_ERR; 487 goto error; 488 } 489 490 ref_init(&sars->ref); 491 sars->allocator = allocator; 492 sars->verbose = args->verbose; 493 sars->pagesize_os = (size_t)sysconf(_SC_PAGESIZE); 494 str_init(allocator, &sars->name); 495 darray_band_init(allocator, &sars->bands); 496 if(args->logger) { 497 sars->logger = args->logger; 498 } else { 499 setup_log_default(sars); 500 } 501 502 exit: 503 if(out_sars) *out_sars = sars ; 504 return res; 505 error: 506 if(sars) { SARS(ref_put(sars)); sars = NULL; } 507 goto exit; 508 } 509 510 res_T 511 sars_ref_get(struct sars* sars) 512 { 513 if(!sars) return RES_BAD_ARG; 514 ref_get(&sars->ref); 515 return RES_OK; 516 } 517 518 res_T 519 sars_ref_put(struct sars* sars) 520 { 521 if(!sars) return RES_BAD_ARG; 522 ref_put(&sars->ref, release_sars); 523 return RES_OK; 524 } 525 526 res_T 527 sars_load(struct sars* sars, const struct sars_load_args* args) 528 { 529 struct sars_load_stream_args stream_args = SARS_LOAD_STREAM_ARGS_NULL; 530 FILE* file = NULL; 531 res_T res = RES_OK; 532 533 if(!sars) { res = RES_BAD_ARG; goto error; } 534 res = check_sars_load_args(args); 535 if(res != RES_OK) goto error; 536 537 file = fopen(args->path, "r"); 538 if(!file) { 539 log_err(sars, "%s: error opening file `%s'.\n", FUNC_NAME, args->path); 540 res = RES_IO_ERR; 541 goto error; 542 } 543 544 stream_args.stream = file; 545 stream_args.name = args->path; 546 stream_args.memory_mapping = args->memory_mapping; 547 res = load_stream(sars, &stream_args); 548 if(res != RES_OK) goto error; 549 550 exit: 551 if(file) fclose(file); 552 return res; 553 error: 554 goto exit; 555 } 556 557 res_T 558 sars_load_stream(struct sars* sars, const struct sars_load_stream_args* args) 559 { 560 res_T res = RES_OK; 561 if(!sars) return RES_BAD_ARG; 562 res = check_sars_load_stream_args(sars, args); 563 if(res != RES_OK) return res; 564 return load_stream(sars, args); 565 } 566 567 res_T 568 sars_validate(const struct sars* sars) 569 { 570 size_t iband; 571 size_t nbands; 572 if(!sars) return RES_BAD_ARG; 573 574 nbands = sars_get_bands_count(sars); 575 FOR_EACH(iband, 0, nbands) { 576 struct sars_band band = SARS_BAND_NULL; 577 size_t inode; 578 size_t nnodes; 579 580 SARS(get_band(sars, iband, &band)); 581 582 /* Check band limits */ 583 if(band.lower != band.lower /* NaN? */ 584 || band.upper != band.upper) { /* NaN? */ 585 log_err(sars, 586 "%s: invalid limits for band %lu: [%g, %g[\n", 587 sars_get_name(sars), (unsigned long)iband, band.lower, band.upper); 588 return RES_BAD_ARG; 589 } 590 591 /* Check radiative coefficients */ 592 nnodes = sars_get_nodes_count(sars); 593 FOR_EACH(inode, 0, nnodes) { 594 const float ka = sars_band_get_ka(&band, inode); 595 const float ks = sars_band_get_ks(&band, inode); 596 if(ka != ka /* NaN? */ || ka < 0) { 597 log_err(sars, 598 "%s: invalid absorption coefficient for band %lu at node %lu: %g\n", 599 sars_get_name(sars), (unsigned long)iband, (unsigned long)inode, ka); 600 return RES_BAD_ARG; 601 } 602 if(ks != ks /* NaN? */ || ks < 0) { 603 log_err(sars, 604 "%s: invalid scattering coefficient for band %lu at node %lu: %g\n", 605 sars_get_name(sars), (unsigned long)iband, (unsigned long)inode, ka); 606 return RES_BAD_ARG; 607 } 608 } 609 } 610 return RES_OK; 611 } 612 613 size_t 614 sars_get_bands_count(const struct sars* sars) 615 { 616 ASSERT(sars); 617 return darray_band_size_get(&sars->bands); 618 } 619 620 size_t 621 sars_get_nodes_count(const struct sars* sars) 622 { 623 ASSERT(sars); 624 return sars->nnodes; 625 } 626 627 res_T 628 sars_get_band 629 (const struct sars* sars, 630 const size_t iband, 631 struct sars_band* sars_band) 632 { 633 const struct band* band = NULL; 634 res_T res = RES_OK; 635 636 if(!sars || !sars_band) { 637 res = RES_BAD_ARG; 638 goto error; 639 } 640 641 if(iband >= sars_get_bands_count(sars)) { 642 log_err(sars, "%s: invalid band index %lu.\n", 643 FUNC_NAME, (unsigned long)iband); 644 res = RES_BAD_ARG; 645 goto error; 646 } 647 648 band = darray_band_cdata_get(&sars->bands) + iband; 649 sars_band->lower = band->low; 650 sars_band->upper = band->upp; 651 sars_band->id = iband; 652 sars_band->k_list = band->k_list; 653 654 exit: 655 return res; 656 error: 657 goto exit; 658 } 659 660 res_T 661 sars_find_bands 662 (const struct sars* sars, 663 const double range[2], 664 size_t ibands[2]) 665 { 666 const struct band* bands = NULL; 667 const struct band* low = NULL; 668 const struct band* upp = NULL; 669 size_t nbands = 0; 670 res_T res = RES_OK; 671 672 if(!sars || !range || !ibands || range[0] > range[1]) { 673 res = RES_BAD_ARG; 674 goto error; 675 } 676 677 bands = darray_band_cdata_get(&sars->bands); 678 nbands = darray_band_size_get(&sars->bands); 679 680 low = search_lower_bound(range+0, bands, nbands, sizeof(*bands), cmp_band); 681 if(low) { 682 ibands[0] = (size_t)(low - bands); 683 } else { 684 /* The submitted range does not overlap any band */ 685 ibands[0] = SIZE_MAX; 686 ibands[1] = 0; 687 goto exit; 688 } 689 690 if(range[0] == range[1]) { /* No more to search */ 691 if(range[0] < low->low) { 692 /* The wavelength is not included in any band */ 693 ibands[0] = SIZE_MAX; 694 ibands[1] = 0; 695 } else { 696 ASSERT(range[0] < low->upp); 697 ibands[1] = ibands[0]; 698 } 699 goto exit; 700 } 701 702 upp = search_lower_bound(range+1, bands, nbands, sizeof(*bands), cmp_band); 703 704 /* The submitted range overlaps the remaining bands */ 705 if(!upp) { 706 ibands[1] = nbands - 1; 707 708 /* The upper band includes range[1] */ 709 } else if(upp->low <= range[1]) { 710 ibands[1] = (size_t)(upp - bands); 711 712 /* The upper band is greater than range[1] and therefre must be rejected */ 713 } else if(upp->low > range[1]) { 714 if(upp != bands) { 715 ibands[1] = (size_t)(upp - bands - 1); 716 } else { 717 ibands[0] = SIZE_MAX; 718 ibands[1] = 0; 719 } 720 } 721 722 exit: 723 return res; 724 error: 725 goto exit; 726 } 727 728 res_T 729 sars_band_compute_hash 730 (const struct sars* sars, 731 const size_t iband, 732 hash256_T hash) 733 { 734 struct sha256_ctx ctx; 735 struct sars_band band; 736 res_T res = RES_OK; 737 738 if(!sars || !hash) { 739 res = RES_BAD_ARG; 740 goto error; 741 } 742 743 res = sars_get_band(sars, iband, &band); 744 if(res != RES_OK) goto error; 745 746 sha256_ctx_init(&ctx); 747 hash_band(&ctx, &band, sars->nnodes); 748 sha256_ctx_finalize(&ctx, hash); 749 750 exit: 751 return res; 752 error: 753 goto exit; 754 } 755 756 res_T 757 sars_compute_hash(const struct sars* sars, hash256_T hash) 758 { 759 struct sha256_ctx ctx; 760 size_t i; 761 res_T res = RES_OK; 762 763 if(!sars || !hash) { 764 res = RES_BAD_ARG; 765 goto error; 766 } 767 768 sha256_ctx_init(&ctx); 769 sha256_ctx_update(&ctx, (const char*)&sars->pagesize, sizeof(sars->pagesize)); 770 sha256_ctx_update(&ctx, (const char*)&sars->nnodes, sizeof(sars->nnodes)); 771 FOR_EACH(i, 0, darray_band_size_get(&sars->bands)) { 772 struct sars_band band; 773 SARS(get_band(sars, i, &band)); 774 hash_band(&ctx, &band, sars->nnodes); 775 } 776 sha256_ctx_finalize(&ctx, hash); 777 778 exit: 779 return res; 780 error: 781 goto exit; 782 } 783 784 const char* 785 sars_get_name(const struct sars* sars) 786 { 787 ASSERT(sars); 788 return str_cget(&sars->name); 789 } 790 791 /******************************************************************************* 792 * Local functions 793 ******************************************************************************/ 794 void 795 band_release(struct band* band) 796 { 797 ASSERT(band); 798 if(!band->k_list) return; 799 800 if(!band->map_len) { 801 MEM_RM(band->sars->allocator, band->k_list); 802 } else if(band->k_list != MAP_FAILED) { 803 munmap(band->k_list, band->map_len); 804 } 805 } 806 807 res_T 808 band_copy(struct band* dst, const struct band* src) 809 { 810 ASSERT(dst && src); 811 812 dst->sars = src->sars; 813 dst->low = src->low; 814 dst->upp = dst->upp; 815 dst->map_len = src->map_len; 816 dst->k_list = NULL; 817 818 if(src->map_len) { 819 /* The k are mapped: copy the pointer */ 820 dst->k_list = src->k_list; 821 } else if(src->k_list != NULL) { 822 /* The k are loaded: duplicate thable contents */ 823 const size_t memsz = sizeof(*dst->k_list)*src->sars->nnodes*2/*ka & ks*/; 824 dst->k_list = MEM_ALLOC(src->sars->allocator, memsz); 825 if(!dst->k_list) return RES_MEM_ERR; 826 memcpy(dst->k_list, src->k_list, memsz); 827 } 828 return RES_OK; 829 } 830 831 res_T 832 band_copy_and_release(struct band* dst, struct band* src) 833 { 834 ASSERT(dst && src); 835 dst->sars = src->sars; 836 dst->low = src->low; 837 dst->upp = dst->upp; 838 dst->map_len = src->map_len; 839 dst->k_list = src->k_list; 840 return RES_OK; 841 }