Line data Source code
1 : #include "fd_funk.h" 2 : 3 : void * 4 : fd_funk_val_truncate( fd_funk_rec_t * rec, 5 : fd_alloc_t * alloc, 6 : fd_wksp_t * wksp, 7 : ulong align, 8 : ulong sz, 9 23444985 : int * opt_err ) { 10 : 11 : /* Check input args */ 12 : 13 : #ifdef FD_FUNK_HANDHOLDING 14 : if( FD_UNLIKELY( (!rec) | (sz>FD_FUNK_REC_VAL_MAX) | (!alloc) | (!wksp) ) || /* NULL rec,too big,NULL alloc,NULL wksp */ 15 : FD_UNLIKELY( rec->flags & FD_FUNK_REC_FLAG_ERASE ) || /* Marked erase */ 16 : FD_UNLIKELY( !fd_ulong_is_pow2( align ) & (align != 0UL) ) ) { /* Align is not a power of 2 or == 0 */ 17 : fd_int_store_if( !!opt_err, opt_err, FD_FUNK_ERR_INVAL ); 18 : return NULL; 19 : } 20 : #endif 21 : 22 23444985 : ulong val_sz = (ulong)rec->val_sz; 23 23444985 : ulong val_max = (ulong)rec->val_max; 24 : 25 23444985 : if( FD_UNLIKELY( !sz ) ) { 26 : 27 : /* User asked to truncate to 0. Flush the any existing value. */ 28 : 29 158352 : fd_funk_val_flush( rec, alloc, wksp ); 30 : 31 158352 : fd_int_store_if( !!opt_err, opt_err, FD_FUNK_SUCCESS ); 32 158352 : return NULL; 33 : 34 23286633 : } else if( FD_LIKELY( sz > val_max ) ) { 35 : 36 : /* User requested to increase the value size. We presume they are 37 : asking for a specific size (as opposed to bumping up the size ala 38 : append) so we don't build in extra padding to amortize the cost 39 : of future truncates. Note that new_val_sz is at least 1 at this 40 : point but val_sz / val_gaddr could be zero / zero. */ 41 : 42 23286633 : ulong val_gaddr = rec->val_gaddr; 43 23286633 : uchar * val = val_max ? fd_wksp_laddr_fast( wksp, val_gaddr ) : NULL; /* TODO: branchless */ 44 : 45 : /* NOTE: if the align is 0, we use the default alignment for 46 : fd_alloc_malloc_at_least */ 47 23286633 : ulong new_val_max; 48 23286633 : uchar * new_val = fd_alloc_malloc_at_least( alloc, align, sz, &new_val_max ); 49 23286633 : if( FD_UNLIKELY( !new_val ) ) { /* Allocation failure! */ 50 0 : fd_int_store_if( !!opt_err, opt_err, FD_FUNK_ERR_MEM ); 51 0 : return NULL; 52 0 : } 53 : 54 23286633 : if( val_sz ) fd_memcpy( new_val, val, val_sz ); /* Copy the existing value */ 55 23286633 : fd_memset( new_val + val_sz, 0, new_val_max - val_sz ); /* Clear out trailing padding to be on the safe side */ 56 : 57 23286633 : rec->val_gaddr = fd_wksp_gaddr_fast( wksp, new_val ); 58 23286633 : rec->val_sz = (uint)sz; 59 23286633 : rec->val_max = (uint)fd_ulong_min( new_val_max, FD_FUNK_REC_VAL_MAX ); 60 : 61 23286633 : if( val ) fd_alloc_free( alloc, val ); /* Free the old value (if any) */ 62 : 63 23286633 : fd_int_store_if( !!opt_err, opt_err, FD_FUNK_SUCCESS ); 64 23286633 : return new_val; 65 : 66 23286633 : } else { 67 : 68 : /* Just set the new size */ 69 : 70 0 : rec->val_sz = (uint)sz; 71 : 72 0 : fd_int_store_if( !!opt_err, opt_err, FD_FUNK_SUCCESS ); 73 0 : return (uchar *)fd_wksp_laddr_fast( wksp, rec->val_gaddr ); 74 : 75 0 : } 76 23444985 : } 77 : 78 : int 79 12 : fd_funk_val_verify( fd_funk_t * funk ) { 80 12 : fd_wksp_t * wksp = fd_funk_wksp( funk ); 81 12 : ulong wksp_tag = funk->shmem->wksp_tag; 82 : 83 : /* At this point, rec_map has been extensively verified */ 84 : 85 12 : # define TEST(c) do { \ 86 0 : if( FD_UNLIKELY( !(c) ) ) { FD_LOG_WARNING(( "FAIL: %s", #c )); return FD_FUNK_ERR_INVAL; } \ 87 0 : } while(0) 88 : 89 : /* Iterate over all records in use */ 90 : 91 12 : fd_funk_all_iter_t iter[1]; 92 12 : for( fd_funk_all_iter_new( funk, iter ); !fd_funk_all_iter_done( iter ); fd_funk_all_iter_next( iter ) ) { 93 0 : fd_funk_rec_t const * rec = fd_funk_all_iter_ele_const( iter ); 94 : 95 : /* Make sure values look sane */ 96 : /* TODO: consider doing an alias analysis on allocated values? 97 : (tricky to do algo efficient in place) */ 98 : 99 0 : ulong val_sz = (ulong)rec->val_sz; 100 0 : ulong val_max = (ulong)rec->val_max; 101 0 : ulong val_gaddr = rec->val_gaddr; 102 : 103 0 : TEST( val_sz<=val_max ); 104 : 105 0 : if( rec->flags & FD_FUNK_REC_FLAG_ERASE ) { 106 0 : TEST( !val_max ); 107 0 : TEST( !val_gaddr ); 108 0 : } else { 109 0 : TEST( val_max<=FD_FUNK_REC_VAL_MAX ); 110 0 : if( !val_gaddr ) TEST( !val_max ); 111 0 : else { 112 0 : TEST( (0UL<val_max) & (val_max<=FD_FUNK_REC_VAL_MAX) ); 113 0 : TEST( fd_wksp_tag( wksp, val_gaddr )==wksp_tag ); 114 0 : } 115 0 : } 116 0 : } 117 : 118 12 : # undef TEST 119 : 120 12 : return FD_FUNK_SUCCESS; 121 12 : }