LCOV - code coverage report
Current view: top level - vinyl - fd_vinyl_case_release.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 171 0.0 %
Date: 2025-12-07 04:58:33 Functions: 0 0 -

          Line data    Source code
       1           0 :   case FD_VINYL_REQ_TYPE_RELEASE: {
       2             : 
       3           0 :     ulong                  req_flags     = (ulong)req->flags;
       4           0 :     fd_vinyl_key_t const * req_key       = MAP_REQ_GADDR( req->key_gaddr,       fd_vinyl_key_t const, batch_cnt );
       5           0 :     ulong *                req_val_gaddr = MAP_REQ_GADDR( req->val_gaddr_gaddr, ulong,                batch_cnt );
       6           0 :     schar *                req_err       = MAP_REQ_GADDR( req->err_gaddr,       schar,                batch_cnt );
       7             : 
       8           0 :     int req_flag_modify = fd_vinyl_req_flag_modify( req_flags );
       9           0 :     int req_flag_ignore = fd_vinyl_req_flag_ignore( req_flags );
      10           0 :     int req_flag_erase  = fd_vinyl_req_flag_erase ( req_flags );
      11           0 :     int req_flag_by_key = fd_vinyl_req_flag_by_key( req_flags );
      12           0 :     int req_evict_prio  = fd_vinyl_req_evict_prio ( req_flags );
      13             : 
      14           0 :     if( FD_UNLIKELY( (!!batch_cnt) & ( ((!req_key      ) &   req_flag_by_key ) |
      15           0 :                                        ((!req_val_gaddr) & (!req_flag_by_key)) |
      16           0 :                                        ( !req_err                            ) ) ) ) {
      17           0 :       comp_err = FD_VINYL_ERR_INVAL;
      18           0 :       break;
      19           0 :     }
      20             : 
      21           0 :     for( ulong batch_idx=0UL; batch_idx<batch_cnt; batch_idx++ ) {
      22             : 
      23           0 : #     define DONE(err) do {                                  \
      24           0 :         int _err = (err);                                    \
      25           0 :         FD_COMPILER_MFENCE();                                \
      26           0 :         req_err[ batch_idx ] = (schar)_err;                  \
      27           0 :         FD_COMPILER_MFENCE();                                \
      28           0 :         quota_rem += (ulong) !_err;                          \
      29           0 :         fail_cnt  += (ulong)!!_err;                          \
      30           0 :         goto next_release; /* sigh ... can't use continue */ \
      31           0 :       } while(0)
      32             : 
      33             :       /* If a pair has been acquired, there is a non-zero ref count line
      34             :          holding it.  This line connects the meta element (with the
      35             :          bstream state at seq_present) to the data object (with the
      36             :          cached pair data).  Determine the line, meta element and data
      37             :          object associated with the acquire to release. */
      38             : 
      39           0 :       fd_vinyl_data_obj_t * obj;
      40           0 :       ulong                 line_idx;
      41           0 :       ulong                 ele_idx;
      42           0 :       ulong                 ver;
      43           0 :       long                  ref;
      44             : 
      45           0 :       if( FD_LIKELY( !req_flag_by_key ) ) { /* Release by val_gaddr */
      46             : 
      47           0 :         void * _obj = (void *)( req_val_gaddr[ batch_idx ]
      48           0 :                               + data_laddr0 - sizeof(fd_vinyl_bstream_phdr_t) - sizeof(fd_vinyl_data_obj_t) );
      49             : 
      50           0 :         if( FD_UNLIKELY( !fd_vinyl_data_is_valid_obj( _obj, vol, vol_cnt ) ) ) DONE( FD_VINYL_ERR_INVAL );
      51           0 :         obj = (fd_vinyl_data_obj_t *)_obj;
      52             : 
      53           0 :         if( FD_UNLIKELY( obj->rd_active ) ) DONE( FD_VINYL_ERR_INVAL );
      54             : 
      55           0 :         line_idx = obj->line_idx;
      56           0 :         if( FD_UNLIKELY( line_idx>=line_cnt ) || FD_UNLIKELY( obj!=line[ line_idx ].obj ) ) DONE( FD_VINYL_ERR_INVAL );
      57             : 
      58           0 :         ele_idx = line[ line_idx ].ele_idx;
      59           0 :         if( FD_UNLIKELY( ele_idx>=ele_max ) || FD_UNLIKELY( ele0[ ele_idx ].line_idx!=line_idx ) ) DONE( FD_VINYL_ERR_INVAL );
      60             :         /* FIXME: MAKE SURE ELE0[ ELE_IDX ] IS IN USE FOR DATA INTEGRITY! */
      61             : 
      62           0 :         ulong ctl = line[ line_idx ].ctl;
      63             : 
      64           0 :         ver = fd_vinyl_line_ctl_ver( ctl );
      65           0 :         ref = fd_vinyl_line_ctl_ref( ctl );
      66             : 
      67           0 :         if( FD_UNLIKELY( !ref ) ) DONE( FD_VINYL_ERR_INVAL ); /* Pair key exists and is cached ... but not acquired */
      68             : 
      69           0 :       } else { /* Release by key */
      70             : 
      71           0 :         fd_vinyl_key_t const * key = req_key + batch_idx;
      72             : 
      73           0 :         ulong memo = fd_vinyl_key_memo( meta_seed, key ); /* This can be slow which is why releasing by val_gaddr is preferred */
      74             : 
      75           0 :         ulong _ele_idx; /* avoid pointer escape */
      76           0 :         int   err     = fd_vinyl_meta_query_fast( ele0, ele_max, key, memo, &_ele_idx );
      77           0 :         ele_idx = _ele_idx; /* in [0,ele_max) */
      78             : 
      79           0 :         if( FD_UNLIKELY( err ) ) DONE( FD_VINYL_ERR_INVAL ); /* Pair key does not exist ... can't have been acquired */
      80             : 
      81           0 :         line_idx = ele0[ ele_idx ].line_idx;
      82             : 
      83           0 :         if( FD_UNLIKELY( line_idx>=line_cnt ) ) { /* Pair key exists but is not cached ... can't have been acquired */
      84           0 :           FD_CRIT( line_idx==ULONG_MAX, "corruption detected" );
      85           0 :           DONE( FD_VINYL_ERR_INVAL );
      86           0 :         }
      87             : 
      88           0 :         FD_CRIT( ele_idx==line[ line_idx ].ele_idx, "corruption detected" );
      89             : 
      90           0 :         obj = line[ line_idx ].obj;
      91             : 
      92           0 :         FD_ALERT( fd_vinyl_data_is_valid_obj( obj, vol, vol_cnt ), "corruption detected" );
      93           0 :         FD_CRIT ( obj->line_idx==line_idx,                         "corruption detected" );
      94           0 :         FD_CRIT ( !obj->rd_active,                                 "corruption detected" );
      95             : 
      96           0 :         ulong ctl = line[ line_idx ].ctl;
      97             : 
      98           0 :         ver = fd_vinyl_line_ctl_ver( ctl );
      99           0 :         ref = fd_vinyl_line_ctl_ref( ctl );
     100             : 
     101           0 :         if( FD_UNLIKELY( !ref ) ) DONE( FD_VINYL_ERR_INVAL ); /* Pair key exists and is cached ... but not acquired */
     102             : 
     103           0 :       }
     104             : 
     105             :       /* At this point, we are releasing an acquire of the object obj,
     106             :          cached at line line_idx with metadata at ele_idx. */
     107             : 
     108           0 :       fd_vinyl_bstream_phdr_t * phdr = fd_vinyl_data_obj_phdr( obj );
     109             : 
     110           0 :       if( FD_LIKELY( ref>0L ) ) {
     111             : 
     112             :         /* At this point, we are releasing an acquire for read.  If
     113             :            the client indicated they modified pair key, we don't have
     114             :            data integrity anymore and we CRIT.  Otherwise, we update
     115             :            line eviction priority and ref count to do the release. */
     116             : 
     117           0 :         if( FD_UNLIKELY( req_flag_modify ) ) FD_LOG_CRIT(( "client modified read only acquire" ));
     118             : 
     119           0 :         FD_CRIT( phdr->ctl==fd_vinyl_bstream_ctl( FD_VINYL_BSTREAM_CTL_TYPE_PAIR,
     120           0 :                                                   FD_VINYL_BSTREAM_CTL_STYLE_RAW,
     121           0 :                                                   (ulong)ele0[ ele_idx ].phdr.info.val_sz ),  "corruption detected" );
     122           0 :         FD_CRIT( fd_vinyl_key_eq( &phdr->key, &ele0[ ele_idx ].phdr.key ),                    "corruption detected" );
     123           0 :         FD_CRIT( !memcmp( &phdr->info, &ele0[ ele_idx ].phdr.info, sizeof(fd_vinyl_info_t) ), "corruption detected" );
     124             : 
     125           0 :         fd_vinyl_line_evict_prio( &vinyl->line_idx_lru, line, line_cnt, line_idx, req_evict_prio );
     126             : 
     127           0 :         line[ line_idx ].ctl = fd_vinyl_line_ctl( ver, ref-1L ); /* don't bump ver */
     128             : 
     129           0 :         DONE( FD_VINYL_SUCCESS );
     130           0 :       }
     131             : 
     132             :       /* At this point, we are releasing an acquire for modify */
     133             : 
     134           0 :       ulong phdr_ctl = phdr->ctl;
     135             : 
     136           0 :       int modifying_existing = (phdr_ctl!=ULONG_MAX);
     137             : 
     138           0 :       if( FD_LIKELY( req_flag_modify & (!req_flag_erase) ) ) {
     139             : 
     140             :         /* At this point, we are either finishing up modifying an
     141             :            existing pair (modifying_existing 1) or finishing up creating
     142             :            a new pair (modifying_existing 0).  Cache the object in the
     143             :            smallest size class that supports it.  Note that the client
     144             :            could have modified info so we only validate ctl and key
     145             :            (FIXME: consider validating memo too?). */
     146             : 
     147           0 :         FD_CRIT( (!modifying_existing) |
     148           0 :                  (phdr_ctl==fd_vinyl_bstream_ctl( FD_VINYL_BSTREAM_CTL_TYPE_PAIR,
     149           0 :                                                   FD_VINYL_BSTREAM_CTL_STYLE_RAW,
     150           0 :                                                   (ulong)ele0[ ele_idx ].phdr.info.val_sz )), "corruption detected" );
     151           0 :         FD_CRIT( fd_vinyl_key_eq( &phdr->key, &ele0[ ele_idx ].phdr.key ),                    "corruption detected" );
     152             : 
     153           0 :         ulong val_sz_after = (ulong)phdr->info.val_sz;
     154             : 
     155           0 :         if( FD_UNLIKELY( val_sz_after > fd_vinyl_data_obj_val_max( obj ) ) ) FD_LOG_CRIT(( "client overran memory" ));
     156             : 
     157           0 :         ulong szc_before = (ulong)obj->szc;
     158           0 :         ulong szc_after  = fd_vinyl_data_szc( val_sz_after );
     159             : 
     160           0 :         if( FD_UNLIKELY( szc_before!=szc_after ) ) {
     161             : 
     162           0 :           FD_CRIT( szc_after<szc_before, "corruption detected" );
     163             : 
     164           0 :           fd_vinyl_data_obj_t * obj_after = fd_vinyl_data_alloc( data, szc_after );
     165           0 :           if( FD_UNLIKELY( !obj_after ) ) FD_LOG_CRIT(( "increase data cache size" ));
     166             : 
     167           0 :           fd_vinyl_bstream_phdr_t * phdr_after = fd_vinyl_data_obj_phdr( obj_after );
     168             : 
     169           0 :           memcpy( phdr_after, phdr, sizeof(fd_vinyl_bstream_phdr_t) + val_sz_after );
     170             : 
     171           0 :           fd_vinyl_data_free( data, obj );
     172             : 
     173           0 :           obj  = obj_after;
     174           0 :           phdr = phdr_after;
     175             : 
     176           0 :         }
     177             : 
     178             :         /* Append to the updated pair key to the bstream.  If we are
     179             :            finishing up modifying an existing pair, this will create 1
     180             :            item of bstream garbage (the old version of the pair).  If we
     181             :            are finishing up creating a new pair, this will not create
     182             :            any garbage.  Note that this will zero out any pair zero
     183             :            padding region and populate footer hashes. */
     184             : 
     185           0 :         if( FD_LIKELY( modifying_existing ) ) {
     186             : 
     187           0 :           ulong val_esz_before = fd_vinyl_bstream_ctl_sz( ele0[ ele_idx ].phdr.ctl );
     188             : 
     189           0 :           accum_garbage_cnt++;
     190           0 :           accum_garbage_sz += fd_vinyl_bstream_pair_sz( val_esz_before );
     191             : 
     192           0 :         }
     193             : 
     194           0 :         phdr->ctl = fd_vinyl_bstream_ctl( FD_VINYL_BSTREAM_CTL_TYPE_PAIR, FD_VINYL_BSTREAM_CTL_STYLE_RAW, val_sz_after );
     195             :       /*phdr->key  already init */
     196             :       /*phdr->info already init */
     197             : 
     198           0 :         int   style_after;
     199           0 :         ulong val_esz_after;
     200           0 :         ulong seq_after = fd_vinyl_io_append_pair_inplace( io, vinyl->style, phdr, &style_after, &val_esz_after );
     201           0 :         append_cnt++;
     202             : 
     203             :         /* Update the line and meta to match.  Note that setting meta
     204             :            element ele_idx phdr.ctl to something other than ULONG_MAX
     205             :            marks a pair that was being created as no longer being
     206             :            created.  For a pair that already existed, we also need to
     207             :            update phdr.ctl to reflect that we might be storing this in
     208             :            the stream in a different format than it was stored in
     209             :            bstream before.  Since we are changing shared fields of meta
     210             :            element ele_idx, we need to use prepare / publish semantics. */
     211             : 
     212           0 :         line[ line_idx ].obj     = obj;             obj->line_idx = line_idx; obj->rd_active = (short)0;
     213             :       //line[ line_idx ].ele_idx ... already init
     214           0 :         line[ line_idx ].ctl     = fd_vinyl_line_ctl( ver+1L, 0L ); /* bump ver */
     215             : 
     216           0 :         fd_vinyl_line_evict_prio( &vinyl->line_idx_lru, line, line_cnt, line_idx, req_evict_prio );
     217             : 
     218           0 :         fd_vinyl_meta_prepare_fast( lock, lock_shift, ele_idx );
     219             : 
     220             :       //ele0[ ele_idx ].memo      = already init
     221           0 :         ele0[ ele_idx ].phdr.ctl  = fd_vinyl_bstream_ctl( FD_VINYL_BSTREAM_CTL_TYPE_PAIR, style_after, val_esz_after );
     222             :       //ele0[ ele_idx ].phdr.key  = already init
     223           0 :         ele0[ ele_idx ].phdr.info = phdr->info;
     224           0 :         ele0[ ele_idx ].seq       = seq_after;
     225             :       //ele0[ ele_idx ].line_idx  = already init
     226             : 
     227           0 :         fd_vinyl_meta_publish_fast( lock, lock_shift, ele_idx );
     228             : 
     229           0 :         DONE( FD_VINYL_SUCCESS );
     230             : 
     231           0 :       }
     232             : 
     233             :       /* At this point, we are either canceling a modification (modify
     234             :          0, erase d/c) or the modification is to erase the pair (modify
     235             :          1, erase 1).  If we are canceling the modification of an
     236             :          existing pair and the client indicated the cached pair info and
     237             :          cached pair val are still valid, (i.e. release-cancel of an
     238             :          acquire-for-modify of an existing pair), we revert the line
     239             :          state and adjust the line evict priority.  (This code path can
     240             :          be omitted if we don't trust the clients to report correctly.
     241             :          We do test at least the client is correctly reporting the info
     242             :          is not modified.)  Note that we might have put this in a larged
     243             :          sized obj when we acquired it for modify.  So we also move the
     244             :          object to the tightest location. */
     245             : 
     246           0 :       if( FD_LIKELY( modifying_existing & (!req_flag_modify) & (!req_flag_ignore) ) ) {
     247             : 
     248             :         /* FIXME: consider allowing the client to always clobber the
     249             :            pair info and just restore info from the meta cache? */
     250             : 
     251           0 :         if( FD_UNLIKELY( !( (phdr->ctl==fd_vinyl_bstream_ctl( FD_VINYL_BSTREAM_CTL_TYPE_PAIR,
     252           0 :                                                               FD_VINYL_BSTREAM_CTL_STYLE_RAW,
     253           0 :                                                               (ulong)ele0[ ele_idx ].phdr.info.val_sz ) ) &
     254           0 :                             (fd_vinyl_key_eq( &phdr->key, &ele0[ ele_idx ].phdr.key )                   ) &
     255           0 :                             (!memcmp( &phdr->info, &ele0[ ele_idx ].phdr.info, sizeof(fd_vinyl_info_t) )) ) ) )
     256           0 :           FD_LOG_CRIT(( "client clobbered pair info" ));
     257             : 
     258           0 :         ulong val_sz_before = (ulong)phdr->info.val_sz;
     259             : 
     260           0 :         ulong szc_after  = (ulong)obj->szc;
     261           0 :         ulong szc_before = fd_vinyl_data_szc( val_sz_before );
     262             : 
     263           0 :         if( FD_UNLIKELY( szc_before!=szc_after ) ) {
     264             : 
     265           0 :           FD_CRIT( szc_before<szc_after, "corruption detected" );
     266             : 
     267           0 :           fd_vinyl_data_obj_t * obj_before = fd_vinyl_data_alloc( data, szc_before );
     268           0 :           if( FD_UNLIKELY( !obj_before ) ) FD_LOG_CRIT(( "increase data cache size" ));
     269             : 
     270           0 :           fd_vinyl_bstream_phdr_t * phdr_before = fd_vinyl_data_obj_phdr( obj_before );
     271             : 
     272           0 :           memcpy( phdr_before, phdr, sizeof(fd_vinyl_bstream_phdr_t) + val_sz_before );
     273             : 
     274           0 :           fd_vinyl_data_free( data, obj );
     275             : 
     276           0 :           line[ line_idx ].obj = obj_before; obj_before->line_idx = line_idx; obj_before->rd_active = (short)0;
     277             : 
     278           0 :         }
     279             : 
     280           0 :         line[ line_idx ].ctl = fd_vinyl_line_ctl( ver-1UL, 0L ); /* revert ver */
     281             : 
     282           0 :         fd_vinyl_line_evict_prio( &vinyl->line_idx_lru, line, line_cnt, line_idx, req_evict_prio );
     283             : 
     284           0 :         DONE( FD_VINYL_SUCCESS );
     285             : 
     286           0 :       }
     287             : 
     288             :       /* At this point, we are canceling a modification of an existing
     289             :          pair that no longer has valid cached pair info or cached pair
     290             :          val, erasing an existing pair, canceling the creation of a new
     291             :          pair or erasing a pair in the process of being created (which
     292             :          we treat the same as cancelling the creation).
     293             : 
     294             :          Since there was nothing cached originally (canceling / erasing
     295             :          a pair being created), the cached data is no longer valid
     296             :          (cancel with ignore of an existing pair) or the the cached data
     297             :          is no longer needed (erase of an existing pair), we free the
     298             :          data obj, mark the line as empty, move the line to LRU
     299             :          position. */
     300             : 
     301             :       /* FIXME: INTEGRITY CHECKS ON PHDR HERE?  (TRICKY AS WE'D HAVE TO
     302             :          MAP OUT EXACTLY WHICH FIELDS CAN BE TRUSTED AT THIS POINT AND
     303             :          IT ISN'T OBVIOUS IT MATTERS) */
     304             : 
     305           0 :       fd_vinyl_data_free( data, obj );
     306             : 
     307           0 :       line[ line_idx ].obj     = NULL;
     308           0 :       line[ line_idx ].ele_idx = ULONG_MAX;                        ele0[ ele_idx ].line_idx = ULONG_MAX;
     309           0 :       line[ line_idx ].ctl     = fd_vinyl_line_ctl( ver+1UL, 0L ); /* bump ver */
     310             : 
     311           0 :       fd_vinyl_line_evict_prio( &vinyl->line_idx_lru, line, line_cnt, line_idx, FD_VINYL_LINE_EVICT_PRIO_LRU );
     312             : 
     313             :       /* If we are erasing an existing pair, append a dead block to
     314             :          the bstream.  This generates two pieces of bstream garbage (the
     315             :          old pair and the dead block itself).  Likewise, if we are
     316             :          erasing an existing pair or cancelling / erasing a pair
     317             :          creation, remove the element from the meta.  Note that
     318             :          req_flag_modify==1 implies req_flag_erase==1 but not vice versa
     319             :          at this point. */
     320             : 
     321           0 :       if( FD_LIKELY( req_flag_modify & modifying_existing ) ) {
     322             : 
     323           0 :         ulong val_esz_before = fd_vinyl_bstream_ctl_sz( ele0[ ele_idx ].phdr.ctl );
     324             : 
     325           0 :         accum_garbage_cnt += 2UL;
     326           0 :         accum_garbage_sz  += fd_vinyl_bstream_pair_sz( val_esz_before ) + FD_VINYL_BSTREAM_BLOCK_SZ;
     327             : 
     328           0 :         fd_vinyl_io_append_dead( io, &ele0[ ele_idx ].phdr, NULL, 0UL );
     329           0 :         append_cnt++;
     330           0 :         accum_dead_cnt++;
     331             : 
     332           0 :       }
     333             : 
     334           0 :       if( FD_LIKELY( req_flag_modify | (!modifying_existing) ) ) {
     335           0 :         fd_vinyl_meta_remove_fast( ele0, ele_max, lock, lock_shift, line, line_cnt, ele_idx );
     336             : 
     337           0 :         ulong pair_cnt = vinyl->pair_cnt;
     338           0 :         FD_CRIT( (0UL<pair_cnt) & (pair_cnt<=pair_max), "corruption detected" );
     339           0 :         vinyl->pair_cnt = pair_cnt - 1UL;
     340           0 :       }
     341             : 
     342           0 :       DONE( FD_VINYL_SUCCESS );
     343             : 
     344           0 :     next_release: /* silly language restriction */;
     345             : 
     346           0 : #     undef DONE
     347             : 
     348           0 :     } /* for batch_idx */
     349             : 
     350           0 :     comp_err = FD_VINYL_SUCCESS;
     351           0 :     break;
     352           0 :   }

Generated by: LCOV version 1.14