LCOV - code coverage report
Current view: top level - funk - fd_funk_rec.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 37 37 100.0 %
Date: 2025-03-20 12:08:36 Functions: 22 1573 1.4 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_funk_fd_funk_rec_h
       2             : #define HEADER_fd_src_funk_fd_funk_rec_h
       3             : 
       4             : /* This provides APIs for managing funk records.  It is generally not
       5             :    meant to be included directly.  Use fd_funk.h instead. */
       6             : 
       7             : #include "fd_funk_txn.h" /* Includes fd_funk_base.h */
       8             : 
       9             : /* FD_FUNK_REC_{ALIGN,FOOTPRINT} describe the alignment and footprint of
      10             :    a fd_funk_rec_t.  ALIGN will be a power of 2, footprint will be a
      11             :    multiple of align.  These are provided to facilitate compile time
      12             :    declarations. */
      13             : 
      14             : #define FD_FUNK_REC_ALIGN     (64UL)
      15             : 
      16             : /* FD_FUNK_REC_FLAG_* are flags that can be bit-ored together to specify
      17             :    how records are to be interpreted.  The 5 most significant bytes of a
      18             :    rec's flag are reserved to be used in conjunction with the ERASE flag.
      19             : 
      20             :    - ERASE indicates a record in an in-preparation transaction should be
      21             :    erased if and when the in-preparation transaction is published. If
      22             :    set on a published record, it serves as a tombstone.
      23             :    If set, there will be no value resources used by this record. */
      24             : 
      25   698659569 : #define FD_FUNK_REC_FLAG_ERASE (1UL<<0)
      26             : 
      27             : /* FD_FUNK_REC_IDX_NULL gives the map record idx value used to represent
      28             :    NULL.  This value also set a limit on how large rec_max can be. */
      29             : 
      30  4313313654 : #define FD_FUNK_REC_IDX_NULL (ULONG_MAX)
      31             : 
      32             : /* A fd_funk_rec_t describes a funk record. */
      33             : 
      34             : struct __attribute__((aligned(FD_FUNK_REC_ALIGN))) fd_funk_rec {
      35             : 
      36             :   /* These fields are managed by the funk's rec_map */
      37             : 
      38             :   fd_funk_xid_key_pair_t pair;     /* Transaction id and record key pair */
      39             :   ulong                  map_next; /* Internal use by map */
      40             :   ulong                  map_hash; /* Internal use by map */
      41             : 
      42             :   /* These fields are managed by funk.  TODO: Consider using record
      43             :      index compression here (much more debatable than in txn itself). */
      44             : 
      45             :   ulong prev_idx;  /* Record map index of previous record */
      46             :   ulong next_idx;  /* Record map index of next record */
      47             :   uint  txn_cidx;  /* Compressed transaction map index (or compressed FD_FUNK_TXN_IDX if this is in the last published) */
      48             :   uint  tag;       /* Internal use only */
      49             :   ulong flags;     /* Flags that indicate how to interpret a record */
      50             : 
      51             :   /* Note: use of uint here requires FD_FUNK_REC_VAL_MAX to be at most
      52             :      UINT_MAX. */
      53             : 
      54             :   uint  val_sz;    /* Num bytes in record value, in [0,val_max] */
      55             :   uint  val_max;   /* Max byte  in record value, in [0,FD_FUNK_REC_VAL_MAX], 0 if erase flag set or val_gaddr is 0 */
      56             :   ulong val_gaddr; /* Wksp gaddr on record value if any, 0 if erase flag set or val_max is 0
      57             :                       If non-zero, the region [val_gaddr,val_gaddr+val_max) will be a current fd_alloc allocation (such that it is
      58             :                       has tag wksp_tag) and the owner of the region will be the record.  IMPORTANT! HAS NO GUARANTEED ALIGNMENT! */
      59             : 
      60             :   /* Padding to FD_FUNK_REC_ALIGN here  */
      61             : };
      62             : 
      63             : typedef struct fd_funk_rec fd_funk_rec_t;
      64             : 
      65             : FD_STATIC_ASSERT( sizeof(fd_funk_rec_t) == 2U*FD_FUNK_REC_ALIGN, record size is wrong );
      66             : 
      67             : /* fd_funk_rec_map allows for indexing records by their (xid,key) pair.
      68             :    It is used to store all records of the last published transaction and
      69             :    the records being updated for a transaction that is in-preparation.
      70             :    Published records are stored under the pair (root,key).  (This is
      71             :    done so that publishing a transaction doesn't require updating all
      72             :    transaction id of all the records that were not updated by the
      73             :    publish.) */
      74             : 
      75             : #define MAP_NAME              fd_funk_rec_map
      76             : #define MAP_T                 fd_funk_rec_t
      77             : #define MAP_KEY_T             fd_funk_xid_key_pair_t
      78             : #define MAP_KEY               pair
      79  2188670778 : #define MAP_KEY_EQ(k0,k1)     fd_funk_xid_key_pair_eq((k0),(k1))
      80   647463048 : #define MAP_KEY_HASH(k0,seed) fd_funk_xid_key_pair_hash((k0),(seed))
      81     4018065 : #define MAP_KEY_COPY(kd,ks)   fd_funk_xid_key_pair_copy((kd),(ks))
      82 51950125056 : #define MAP_NEXT              map_next
      83             : #define MAP_HASH              map_hash
      84             : #define MAP_MAGIC             (0xf173da2ce77ecdb0UL) /* Firedancer rec db version 0 */
      85             : #define MAP_IMPL_STYLE        1
      86             : #define MAP_MEMOIZE           1
      87             : #include "../util/tmpl/fd_map_giant.c"
      88             : 
      89             : FD_PROTOTYPES_BEGIN
      90             : 
      91             : FD_FN_PURE ulong fd_funk_rec_map_list_idx( fd_funk_rec_t const * join, fd_funk_xid_key_pair_t const * key );
      92             : 
      93             : void fd_funk_rec_map_set_key_cnt( fd_funk_rec_t * join, ulong key_cnt );
      94             : 
      95             : /* fd_funk_rec_idx_is_null returns 1 if idx is FD_FUNK_REC_IDX_NULL and
      96             :    0 otherwise. */
      97             : 
      98  4304941248 : FD_FN_CONST static inline int fd_funk_rec_idx_is_null( ulong idx ) { return idx==FD_FUNK_REC_IDX_NULL; }
      99             : 
     100             : /* Accessors */
     101             : 
     102             : /* fd_funk_rec_cnt returns the number of records in the record map.
     103             :    Assumes map==fd_funk_rec_map( funk, fd_funk_wksp( funk ) ) where funk
     104             :    is a current local join.  See fd_funk.h for fd_funk_rec_max. */
     105             : 
     106           3 : FD_FN_PURE static inline ulong fd_funk_rec_cnt( fd_funk_rec_t const * map ) { return fd_funk_rec_map_key_cnt( map ); }
     107             : 
     108             : /* fd_funk_rec_is_full returns 1 if the record map is full (i.e. the
     109             :    maximum of records that can be concurrently tracked has been reached)
     110             :    and 0 otherwise.  Note that this includes all the records in the last
     111             :    published transactions and records being updated by in-preparation
     112             :    transactions.  Assumes funk is a current local join and
     113             :    map==fd_funk_rec_map( funk, fd_funk_wksp( funk ) ). */
     114             : 
     115    33484209 : FD_FN_PURE static inline int fd_funk_rec_is_full( fd_funk_rec_t const * map ) { return fd_funk_rec_map_is_full( map ); }
     116             : 
     117             : /* fd_funk_rec_query queries the in-preparation transaction pointed to
     118             :    by txn for the record whose key matches the key pointed to by key.
     119             :    If txn is NULL, the query will be done for the funk's last published
     120             :    transaction.  Returns a pointer to current record on success and NULL
     121             :    on failure.  Reasons for failure include txn is neither NULL nor a
     122             :    pointer to a in-preparation transaction, key is NULL or not a record
     123             :    in the given transaction.
     124             : 
     125             :    The returned pointer is in the caller's address space and, if the
     126             :    return value is non-NULL, the lifetime of the returned pointer is the
     127             :    lesser of the current local join, the key is removed from the
     128             :    transaction, the lifetime of the in-preparation transaction (txn is
     129             :    non-NULL) or the next successful publication (txn is NULL).
     130             : 
     131             :    Assumes funk is a current local join (NULL returns NULL), txn is NULL
     132             :    or points to an in-preparation transaction in the caller's address
     133             :    space, key points to a record key in the caller's address space (NULL
     134             :    returns NULL), and no concurrent operations on funk, txn or key.
     135             :    funk retains no interest in key.  The funk retains ownership of any
     136             :    returned record.  The record value metadata will be updated whenever
     137             :    the record value modified.
     138             : 
     139             :    This is reasonably fast O(1).
     140             : 
     141             :    Important safety tip!  This function can encounter records
     142             :    that have the ERASE flag set (i.e. are tombstones of erased
     143             :    records). fd_funk_rec_query will still return the record in this
     144             :    case, and the application should check for the flag. */
     145             : 
     146             : FD_FN_PURE fd_funk_rec_t const *
     147             : fd_funk_rec_query( fd_funk_t *               funk,
     148             :                    fd_funk_txn_t const *     txn,
     149             :                    fd_funk_rec_key_t const * key );
     150             : 
     151             : 
     152             : /* fd_funk_rec_query_global is the same as fd_funk_rec_query but will
     153             :    query txn's ancestors for key from youngest to oldest if key is not
     154             :    part of txn.  As such, the txn of the returned record may not match
     155             :    txn but will be the txn of most recent ancestor with the key
     156             :    otherwise. *txn_out is set to the transaction where the record was
     157             :    found.
     158             : 
     159             :    This is reasonably fast O(in_prep_ancestor_cnt).
     160             : 
     161             :    Important safety tip!  This function can encounter records
     162             :    that have the ERASE flag set (i.e. are tombstones of erased
     163             :    records). fd_funk_rec_query_global will return a NULL in this case
     164             :    but still set *txn_out to the relevant transaction. This behavior
     165             :    differs from fd_funk_rec_query. */
     166             : FD_FN_PURE fd_funk_rec_t const *
     167             : fd_funk_rec_query_global( fd_funk_t *               funk,
     168             :                           fd_funk_txn_t const *     txn,
     169             :                           fd_funk_rec_key_t const * key,
     170             :                           fd_funk_txn_t const **    txn_out );
     171             : 
     172             : /* fd_funk_rec_query_safe is a query that is safe in the presence of
     173             :    concurrent writes. The result data is copied into a buffer
     174             :    allocated by the given valloc and should be freed with the same
     175             :    valloc. NULL is returned if the query fails. The query is always
     176             :    against the root transaction. */
     177             : 
     178             : void *
     179             : fd_funk_rec_query_safe( fd_funk_t *               funk,
     180             :                         fd_funk_rec_key_t const * key,
     181             :                         fd_valloc_t               valloc,
     182             :                         ulong *                   result_len );
     183             : 
     184             : void *
     185             : fd_funk_rec_query_xid_safe( fd_funk_t *               funk,
     186             :                             fd_funk_rec_key_t const * key,
     187             :                             fd_funk_txn_xid_t const * xid,
     188             :                             fd_valloc_t               valloc,
     189             :                             ulong *                   result_len );
     190             : 
     191             : /* fd_funk_rec_test tests the record pointed to by rec.  Returns
     192             :    FD_FUNK_SUCCESS (0) if rec appears to be a live unfrozen record in
     193             :    funk and a FD_FUNK_ERR_* (negative) otherwise.  Specifically:
     194             : 
     195             :      FD_FUNK_ERR_INVAL - bad inputs (NULL funk, NULL rec, rec is clearly
     196             :        not from funk, etc)
     197             : 
     198             :      FD_FUNK_ERR_KEY - the record did not appear to be a live record.
     199             :        Specifically rec's (xid,key) did not resolve to itself.
     200             : 
     201             :      FD_FUNK_ERR_XID - memory corruption was detected in testing rec
     202             : 
     203             :      FD_FUNK_ERR_FROZEN - rec is part of a frozen transaction
     204             : 
     205             :    If fd_funk_rec_test returns SUCCESS, modify and remove are guaranteed
     206             :    to succeed immediately after return.  The value returned by test will
     207             :    stable for the same lifetime as a modify.
     208             : 
     209             :    Assumes funk is a current local join (NULL returns NULL).
     210             : 
     211             :    This is a reasonably fast O(1). */
     212             : 
     213             : FD_FN_PURE int
     214             : fd_funk_rec_test( fd_funk_t *           funk,
     215             :                   fd_funk_rec_t const * rec );
     216             : 
     217             : /* fd_funk_rec_{pair,xid,key} returns a pointer in the local address
     218             :    space of the {(transaction id,record key) pair,transaction id,record
     219             :    key} of a live record.  Assumes rec points to a live record in the
     220             :    caller's address space.  The lifetime of the returned pointer is the
     221             :    same as rec.  The value at the pointer will be constant for its
     222             :    lifetime. */
     223             : 
     224   371482986 : FD_FN_CONST static inline fd_funk_xid_key_pair_t const * fd_funk_rec_pair( fd_funk_rec_t const * rec ) { return &rec->pair;    }
     225  2082749121 : FD_FN_CONST static inline fd_funk_txn_xid_t const *      fd_funk_rec_xid ( fd_funk_rec_t const * rec ) { return rec->pair.xid; }
     226  1182153372 : FD_FN_CONST static inline fd_funk_rec_key_t const *      fd_funk_rec_key ( fd_funk_rec_t const * rec ) { return rec->pair.key; }
     227             : 
     228             : /* fd_funk_rec_txn returns the in-preparation transaction to which the
     229             :    live record rec belongs or NULL if rec belongs to the last published
     230             :    transaction.
     231             : 
     232             :    fd_funk_rec_{next,prev} returns the {next,prev} record
     233             :    ({younger,older} record) of the set of records to which rec belongs
     234             :    or NULL if rec is the {youngest,oldest}.
     235             : 
     236             :    fd_funk_txn_rec_{head,tail} returns the {head,tail} record
     237             :    ({oldest,youngest} record) of the in-preparation transaction to which
     238             :    rec belongs or NULL if rec_next is the {youngest,oldest} in that
     239             :    transaction.
     240             : 
     241             :    All pointers are in the caller's address space.  These are all a fast
     242             :    O(1) but not fortified against memory data corruption. */
     243             : 
     244             : FD_FN_PURE static inline fd_funk_txn_t const *     /* Lifetime as described in fd_funk_txn_query */
     245             : fd_funk_rec_txn( fd_funk_rec_t const * rec,        /* Assumes live funk record, funk current local join */
     246   288876249 :                  fd_funk_txn_t const * txn_map ) { /* Assumes == fd_funk_txn_map( funk, fd_funk_wksp( funk ) ) */
     247   288876249 :   ulong txn_idx = fd_funk_txn_idx( rec->txn_cidx );
     248   288876249 :   if( fd_funk_txn_idx_is_null( txn_idx ) ) return NULL; /* TODO: consider branchless */
     249    83677293 :   return txn_map + txn_idx;
     250   288876249 : }
     251             : 
     252             : FD_FN_PURE static inline fd_funk_rec_t const *      /* Lifetime as described in fd_funk_rec_query */
     253             : fd_funk_rec_next( fd_funk_rec_t const * rec,        /* Assumes live funk record, funk current local join */
     254   567620916 :                   fd_funk_rec_t const * rec_map ) { /* Assumes == fd_funk_rec_map( funk, fd_funk_wksp( funk ) ) */
     255   567620916 :   ulong rec_idx = rec->next_idx;
     256   567620916 :   if( fd_funk_rec_idx_is_null( rec_idx ) ) return NULL; /* TODO: consider branchless */
     257   522504174 :   return rec_map + rec_idx;
     258   567620916 : }
     259             : 
     260             : FD_FN_PURE static inline fd_funk_rec_t const *      /* Lifetime as described in fd_funk_rec_query */
     261             : fd_funk_rec_prev( fd_funk_rec_t const * rec,        /* Assumes live funk record, funk current local join */
     262   283810458 :                   fd_funk_rec_t const * rec_map ) { /* Assumes == fd_funk_rec_map( funk, fd_funk_wksp( funk ) ) */
     263   283810458 :   ulong rec_idx = rec->prev_idx;
     264   283810458 :   if( fd_funk_rec_idx_is_null( rec_idx ) ) return NULL; /* TODO: consider branchless */
     265   261252087 :   return rec_map + rec_idx;
     266   283810458 : }
     267             : 
     268             : FD_FN_PURE static inline fd_funk_rec_t const *          /* Lifetime as described in fd_funk_rec_query */
     269             : fd_funk_txn_rec_head( fd_funk_txn_t const * txn,        /* Assumes an in-preparation transaction, funk current local join */
     270   110022453 :                       fd_funk_rec_t const * rec_map ) { /* Assumes == fd_funk_rec_map( funk, fd_funk_wksp( funk ) ) */
     271   110022453 :   ulong rec_head_idx = txn->rec_head_idx;
     272   110022453 :   if( fd_funk_rec_idx_is_null( rec_head_idx ) ) return NULL; /* TODO: consider branchless */
     273   102035463 :   return rec_map + rec_head_idx;
     274   110022453 : }
     275             : 
     276             : FD_FN_PURE static inline fd_funk_rec_t const *          /* Lifetime as described in fd_funk_rec_query */
     277             : fd_funk_txn_rec_tail( fd_funk_txn_t const * txn,        /* Assumes an in-preparation transaction, funk current local join */
     278    82622811 :                       fd_funk_rec_t const * rec_map ) { /* Assumes == fd_funk_rec_map( funk, fd_funk_wksp( funk ) ) */
     279    82622811 :   ulong rec_tail_idx = txn->rec_tail_idx;
     280    82622811 :   if( fd_funk_rec_idx_is_null( rec_tail_idx ) ) return NULL; /* TODO: consider branchless */
     281    82622811 :   return rec_map + rec_tail_idx;
     282    82622811 : }
     283             : 
     284             : /* fd_funk_rec_modify returns rec as a non-const rec if rec is currently
     285             :    safe to modify the val / discard a change to the record for an
     286             :    in-preparation transaction (incl discard an erase) / erase a
     287             :    published record / etc.  Reasons for NULL include NULL funk, NULL
     288             :    rec, rec does not appear to be a live record, or the transaction to
     289             :    which rec belongs is frozen.
     290             : 
     291             :    The returned pointer is in the caller's address space and, if the
     292             :    return value is non-NULL, the lifetime of the returned pointer is the
     293             :    the lesser of the current local join, the key has been removed from
     294             :    the transaction, the transaction becomes frozen due to birth of an
     295             :    in-preparation child, (for a key part of an in-preparation
     296             :    transaction) the lifetime of in-preparation transaction, (for a key
     297             :    part of the last published transaction) the next successful
     298             :    publication.
     299             : 
     300             :    Assumes funk is a current local join (NULL returns NULL), rec is a
     301             :    pointer in the caller's address space to a fd_funk_rec_t (NULL
     302             :    returns NULL), and no concurrent operations on funk or rec.  The funk
     303             :    retains ownership of rec.  The record value metadata will be updated
     304             :    whenever the record value modified.
     305             : 
     306             :    This is a reasonably fast O(1). */
     307             : 
     308             : fd_funk_rec_t *
     309             : fd_funk_rec_modify( fd_funk_t *           funk,
     310             :                     fd_funk_rec_t const * rec );
     311             : 
     312             : /* Returns 1 if the record has been modified in its transaction
     313             :    compared to the prior incarnation of the record with the same
     314             :    key (or there is no prior incarnation). Returns -1 if rec is part
     315             :    of a published transaction. Return 0 otherwise. */
     316             : 
     317             : int
     318             : fd_funk_rec_is_modified( fd_funk_t *           funk,
     319             :                          fd_funk_rec_t const * rec );
     320             : 
     321             : /* TODO: Consider instead doing something like: modify_init, modify_fini and
     322             :    preventing forking the txn if records are being modified instead of
     323             :    the long laundry list of lifetime constraints? */
     324             : 
     325             : /* fd_funk_rec_insert inserts a new record whose key will be the same
     326             :    as the record key pointed to by key to the in-preparation transaction
     327             :    pointed to by txn.  If txn is NULL, the record will be inserted into
     328             :    the last published transaction.
     329             : 
     330             :    Returns a pointer to the new record on success and NULL on failure.
     331             :    If opt_err is non-NULL, on return, *opt_err will indicate the result
     332             :    of the operation.
     333             : 
     334             :      FD_FUNK_SUCCESS - success
     335             : 
     336             :      FD_FUNK_ERR_INVAL - failed due to bad inputs (NULL funk, NULL key,
     337             :        txn was neither NULL nor pointer to an in-preparation
     338             :        transaction)
     339             : 
     340             :      FD_FUNK_ERR_REC - failed due to too many records in the func,
     341             :        increase rec_max
     342             : 
     343             :      FD_FUNK_ERR_FROZEN - txn is a transaction that is a parent of an
     344             :        in-preparation transaction.
     345             : 
     346             :      FD_FUNK_ERR_KEY - key referred to an record that is already present
     347             :        in the transaction.
     348             : 
     349             :    The returned pointer is in the caller's address space and, if the
     350             :    return value is non-NULL, the lifetime of the returned pointer is the
     351             :    lesser of the current local join, the record is removed, the txn's
     352             :    lifetime (only applicable if txn is non-NULL) or the next successful
     353             :    publication (only applicable if txn is NULL).
     354             : 
     355             :    Note, if this insert is for a record that in txn with the ERASE flag
     356             :    set, the ERASE flag of the record will be cleared and it will return
     357             :    that record.
     358             : 
     359             :    Assumes funk is a current local join (NULL returns NULL), txn is NULL
     360             :    or points to an in-preparation transaction in the caller's address
     361             :    space, key points to a record key in the caller's address space (NULL
     362             :    returns NULL), and no concurrent operations on funk, txn or key.
     363             :    funk retains no interest in key or opt_err.  The funk retains
     364             :    ownership of txn and any returned record.  The record value metadata
     365             :    will be updated whenever the record value modified.
     366             : 
     367             :    This is a reasonably fast O(1) and fortified against memory
     368             :    corruption.
     369             : 
     370             :    Note that when a record is newly created, it is initially created
     371             :    with a NULL value.  If intending to modify the value in the most
     372             :    recent ancestor version of the record, a record can be loaded with
     373             :    the data via:
     374             : 
     375             :      fd_funk_val_copy( rec, fd_funk_val_const( orig_rec ), fd_funk_val_sz( orig_rec ), 0UL, alloc, wksp, NULL );
     376             : 
     377             :      // Note: could use fd_funk_val_max( orig_rec ) or some other
     378             :      // intelligence about planned changes via sz_est instead of 0UL
     379             : 
     380             :    This is O(orig_rec) size.  If the caller doesn't have the
     381             :    original record lying around, it can be found via:
     382             : 
     383             :      fd_funk_rec_t const * orig_rec = fd_funk_rec_query_global( funk, txn_parent, key, NULL );
     384             : 
     385             :    This is O(ancestor depth to orig rec) and accounts for that the
     386             :    previous version of the record might not be in txn's parent. */
     387             : 
     388             : fd_funk_rec_t const *
     389             : fd_funk_rec_insert( fd_funk_t *               funk,
     390             :                     fd_funk_txn_t *           txn,
     391             :                     fd_funk_rec_key_t const * key,
     392             :                     int *                     opt_err );
     393             : 
     394             : /* fd_funk_rec_remove removes the live record pointed to by rec from
     395             :    the funk.  Returns FD_FUNK_SUCCESS (0) on success and a FD_FUNK_ERR_*
     396             :    (negative) on failure.  Reasons for failure include:
     397             : 
     398             :      FD_FUNK_ERR_INVAL - bad inputs (NULL funk, NULL rec, rec is
     399             :        obviously not from funk, etc)
     400             : 
     401             :      FD_FUNK_ERR_KEY - the record did not appear to be a live record.
     402             :        Specifically, a record query of funk for rec's (xid,key) pair did
     403             :        not return rec.
     404             : 
     405             :    The record will cease to exist in that transaction and any of
     406             :    transaction's subsequently created descendants (again, assuming no
     407             :    subsequent insert of key).  This type of remove can be done on a
     408             :    published record (assuming the last published transaction is
     409             :    unfrozen). A tombstone is left in funk to track removals as they
     410             :    are published or cancelled.
     411             : 
     412             :    Any information in an erased record is lost.
     413             : 
     414             :    Assumes funk is a current local join (NULL returns ERR_INVAL) and rec
     415             :    points to a record in the caller's address space (NULL returns
     416             :    ERR_INVAL).  As the funk still has ownership of rec before and after
     417             :    the call if live, the user doesn't need to, for example, match
     418             :    inserts with removes.
     419             : 
     420             :    This is a reasonably fast O(1) and fortified against memory corruption.
     421             : 
     422             :    IMPORTANT SAFETY TIP!  DO NOT CAST AWAY CONST FROM A FD_FUNK_REC_T TO
     423             :    USE THIS FUNCTION (E.G. PASS A RESULT DIRECTLY FROM QUERY).  USE A
     424             :    LIVE RESULT FROM FD_FUNK_REC_MODIFY! */
     425             : 
     426             : int
     427             : fd_funk_rec_remove( fd_funk_t *     funk,
     428             :                     fd_funk_rec_t * rec,
     429             :                     ulong           erase_data );
     430             : 
     431             : 
     432             : /* When a record is erased there is metadata stored in the five most
     433             :    significant bytes of a record.  These are helpers to make setting
     434             :    and getting these values simple. The caller is responsible for doing
     435             :    a check on the flag of the record before using the value of the erase
     436             :    data. The 5 least significant bytes of the erase data parameter will
     437             :    be used and set into the erase flag. */
     438             : 
     439             : void
     440             : fd_funk_rec_set_erase_data( fd_funk_rec_t * rec, ulong erase_data );
     441             : 
     442             : ulong
     443             : fd_funk_rec_get_erase_data( fd_funk_rec_t const * rec );
     444             : 
     445             : /* Remove a list of tombstones from funk, thereby freeing up space in
     446             :    the main index. All the records must be removed and published
     447             :    beforehand. Reasons for failure include:
     448             : 
     449             :      FD_FUNK_ERR_INVAL - bad inputs (NULL funk, NULL rec, rec is
     450             :        obviously not from funk, etc)
     451             : 
     452             :      FD_FUNK_ERR_KEY - the record did not appear to be a removed record.
     453             :        Specifically, a record query of funk for rec's (xid,key) pair did
     454             :        not return rec. Also, the record was never published.
     455             : */
     456             : int
     457             : fd_funk_rec_forget( fd_funk_t *      funk,
     458             :                     fd_funk_rec_t ** recs,
     459             :                     ulong recs_cnt );
     460             : 
     461             : /* fd_funk_rec_write_prepare combines several operations into one
     462             :    convenient package. There are 3 basic cases:
     463             : 
     464             :    1. If the given record key already exists in the transaction, the
     465             :    record is returned in modifiable form. This is equivalent to
     466             :    fd_funk_rec_query combined with fd_funk_rec_modify.
     467             : 
     468             :    2. If the record key is entirely new (not present in the
     469             :    transaction or any of its ancestors), a new record is inserted and
     470             :    returned in modifiable form. This is equivalent to
     471             :    fd_funk_rec_insert combined with fd_funk_rec_modify. Note that if
     472             :    the do_create argument is false, a NULL will be returned in this case.
     473             : 
     474             :    3. Otherwise, the record is copied from the ancestor transaction
     475             :    into the given transaction. This is returned in modifiable
     476             :    form. This is equivalent to fd_funk_rec_query_global,
     477             :    fd_funk_rec_insert, fd_funk_val_copy, and fd_funk_rec_modify.
     478             : 
     479             :    In all cases, the record is grown to min_val_size if it is less
     480             :    than this size, padding with zeros if necessary.
     481             : 
     482             :    The irec argument is the previous incarnation of the record if
     483             :    known (i.e. the result of fd_funk_rec_query_global( funk, txn, key
     484             :    ) ). This allows the elimination of the query in some cases. Use
     485             :    NULL if this value is unavailable. */
     486             : fd_funk_rec_t *
     487             : fd_funk_rec_write_prepare( fd_funk_t *               funk,         /* Funky database */
     488             :                            fd_funk_txn_t *           txn,          /* Write the record into this transaction */
     489             :                            fd_funk_rec_key_t const * key,          /* Key of new/modified record */
     490             :                            ulong                     min_val_size, /* Minimum value size of writable record */
     491             :                            int                       do_create,    /* Can create new record */
     492             :                            fd_funk_rec_t const *     irec,         /* Prior result of fd_funk_rec_query_global if known */
     493             :                            int *                     opt_err );    /* Optional error code return */
     494             : 
     495             : /* Misc */
     496             : 
     497             : /* fd_funk_rec_verify verifies the record map.  Returns FD_FUNK_SUCCESS
     498             :    if the record map appears intact and FD_FUNK_ERR_INVAL if not (logs
     499             :    details).  Meant to be called as part of fd_funk_verify.  As such, it
     500             :    assumes funk is non-NULL, fd_funk_{wksp,txn_map,rec_map} have been
     501             :    verified to work and the txn_map has been verified. */
     502             : 
     503             : int
     504             : fd_funk_rec_verify( fd_funk_t * funk );
     505             : 
     506             : FD_PROTOTYPES_END
     507             : 
     508             : #endif /* HEADER_fd_src_funk_fd_funk_rec_h */

Generated by: LCOV version 1.14