LCOV - code coverage report
Current view: top level - funk - fd_funk_rec.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 38 38 100.0 %
Date: 2025-01-08 12:08:44 Functions: 23 1507 1.5 %

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

Generated by: LCOV version 1.14