Line data Source code
1 : /*
2 : Generate prototypes, inlines and implementations for multi-sorted views
3 : with a bounded compile-time number of columns and a bounded run-time
4 : fixed row capacity.
5 :
6 : A multi-sorted view is an iterator into an underlying table that
7 : traverses the table in a particular multi-sorted ordering. A multi-sort
8 : is characterized by sorting multiple columns simultaneously, creating a
9 : hierarchical order of data.
10 :
11 : This API is an extension of the fd_treap API. As such methods included
12 : in fd_treap.c also included in the template will have the same
13 : specification, unless noted otherwise.
14 :
15 : This API is designed for ultra tight coupling with pools, treaps,
16 : heaps, maps, other tables, etc. Likewise, a live table can be persisted
17 : beyond the lifetime of the creating process, used concurrently in
18 : many common operations, used inter-process, relocated in memory,
19 : naively serialized/deserialized, moved between hosts, supports index
20 : compression for cache and memory bandwidth efficiency, etc.
21 :
22 : Typical usage:
23 :
24 : struct myrow {
25 : ulong col1;
26 : uint col2;
27 :
28 : struct {
29 : ulong parent;
30 : ulong left;
31 : ulong right;
32 : ulong prio;
33 : ulong next;
34 : ulong prev;
35 :
36 : ... these fields back one of up to MY_TABLE_MAX_SORT_KEY_CNT
37 : ... active treaps. See fd_treap.c for restrictions, lifetimes, etc.
38 :
39 : } treaps[ MY_TABLE_MAX_SORT_KEY_CNT ]; // technically LIVE_TABLE_TREAP[ MY_TABLE_MAX_SORT_KEY_CNT ]
40 :
41 : struct {
42 : ulong prev;
43 : ulong next;
44 : } dlist; // technically LIVE_TABLE_DLIST
45 :
46 : ulong sort_keys; // technically LIVE_TABLE_SORT_KEYS
47 : };
48 : typedef struct myrow myrow_t;
49 :
50 : static int col1_lt( void const * a, void const * b ) { return *(ulong *)a < *(ulong *)b; }
51 : static int col2_lt( void const * a, void const * b ) { return *(uint *)a < *(uint *)b; }
52 :
53 : #define LIVE_TABLE_NAME my_table
54 : #define LIVE_TABLE_COLUMN_CNT (MY_TABLE_MAX_COLUMN_CNT)
55 : #define LIVE_TABLE_MAX_SORT_KEY_CNT (MY_TABLE_MAX_SORT_KEY_CNT)
56 : #define LIVE_TABLE_COLUMNS LIVE_TABLE_COL_ARRAY( \
57 : LIVE_TABLE_COL_ENTRY("Column One", col1, col1_lt), \
58 : LIVE_TABLE_COL_ENTRY("Column Two", col2, col2_lt) )
59 : #define LIVE_TABLE_ROW_T myrow_t
60 : #include "fd_gui_live_table_tmpl.c"
61 :
62 : ... LIVE_TABLE_COL_ENTRY accepts 3 arguments. The name of the table
63 : ... column as a const cstr, the member of myrow_t which corresponds
64 : ... to the column being added, and a pure function that accepts two
65 : ... columns (as void* to members of myrow_t) and returns true if the
66 : ... first compares less than the second. The provided member may be
67 : ... a nested member but may not use a field that is accessed through
68 : ... a pointer dereference (due to an incompatibility with clang's
69 : ... __builtin_offsetof)
70 :
71 : ... OK: LIVE_TABLE_COL_ENTRY("Column One", col1.a.b.c, col1_lt)
72 : ... NOT OK: LIVE_TABLE_COL_ENTRY("Column One", col1->a.c, col1_lt)
73 :
74 : ... LIVE_TABLE_MAX_SORT_KEY_CNT must be greater than or equal to 2.
75 :
76 : will declare the following APIs as a header-only style library in the
77 : compilation unit:
78 :
79 : // These methods have the same behavior as their counterparts in
80 : // fd_treap.c. The main difference is that there are up to
81 : // LIVE_TABLE_MAX_SORT_KEY_CNT treaps actively maintained by
82 : // mytable, and callers should not make any assumptions about a
83 : // given treap being used or unused.
84 :
85 : ulong mytable_align ( void );
86 : ulong mytable_footprint( ulong rows_max );
87 : void * mytable_new ( void * shmem, ulong rows_max, ulong seed );
88 : mytable_t * mytable_join ( void * shtable );
89 : void * mytable_leave ( mytable_t * join );
90 : void * mytable_delete ( void * shtable );
91 :
92 : ulong mytable_idx_null ( void );
93 : myrow_t * mytable_ele_null ( void );
94 : myrow_t const * mytable_ele_null_const( void );
95 :
96 : int mytable_idx_is_null( ulong i );
97 : int mytable_ele_is_null( myrow_t const * e );
98 :
99 : ulong mytable_idx ( myrow_t const * e, myrow_t const * pool );
100 : ulong mytable_idx_fast( myrow_t const * e, myrow_t const * pool );
101 :
102 : myrow_t * mytable_ele ( ulong i, myrow_t * pool );
103 : myrow_t * mytable_ele_fast( ulong i, myrow_t * pool );
104 :
105 : myrow_t const * mytable_ele_const ( ulong i, myrow_t const * pool );
106 : myrow_t const * mytable_ele_fast_const( ulong i, myrow_t const * pool );
107 :
108 : ulong mytable_ele_max( mytable_t const * table );
109 : ulong mytable_ele_cnt( mytable_t const * table );
110 : ulong mytable_col_cnt( void );
111 :
112 : myrow_t * mytable_idx_insert( mytable_t * table, ulong n, myrow_t * pool );
113 : void mytable_idx_remove( mytable_t * table, ulong d, myrow_t * pool );
114 :
115 : myrow_t * mytable_ele_insert( mytable_t * table, myrow_t * n, myrow_t * pool );
116 : void mytable_ele_remove( mytable_t * table, myrow_t * d, myrow_t * pool );
117 :
118 : void mytable_seed( myrow_t * pool, ulong ele_max, ulong seed );
119 :
120 : int mytable_verify( mytable_t const * table, myrow_t const * pool );
121 :
122 : // mytable_verify_sort_key checks that a sort key doesn't contain
123 : // duplicate columns and that all sort directions are valid
124 : int mytable_verify_sort_key( mytable_sort_key_t const * sort_key );
125 :
126 : // A sort key is a structure used to define multi-column sorting
127 : // behavior. It consists of:
128 : // - An array of LIVE_TABLE_COLUMN_CNT column indices,
129 : // specifying which columns are sorted.
130 : // - An array of corresponding sort directions (null, asc, or
131 : // desc), defining the sorting order.
132 : //
133 : // Rows are sorted by prioritizing earlier columns in the sort key,
134 : // with each column sorted according to its specified direction.
135 : // These directions are:
136 : // - null ( 0): No sorting applied to the column.
137 : // - asc ( 1): Sort the column in ascending order.
138 : // - desc (-1): Sort the column in descending order.
139 : //
140 : // e.g.
141 : //
142 : // mytable_sort_key_t my_sort_key = { .col = { 0, 1, 2 }, .dir = { 0, 1, 0 } };
143 : //
144 : // The position of a column in col determined the precedence of the
145 : // column. Earlier columns are considered first when sorting, which
146 : // increases the visual impact of their sort.
147 : //
148 : // Also note that two sort keys may have different column orderings
149 : // but still be isomorphic (i.e. always result in the same sort).
150 : // For example, the following sort key is isomorphic with the key
151 : // above.
152 : //
153 : // mytable_sort_key_t my_sort_key = { .col = { 1, 0, 2 }, .dir = { 1, 0, 0 } };
154 : //
155 : // mytable_lt compares two myrow_t according to the specified sort key.
156 :
157 : int mytable_lt( mytable_sort_key_t const * sort_key, myrow_t const * e0, myrow_t const * e1 );
158 :
159 : // mytable_sort_key_remove removes sort_key from the collection of
160 : // sort_keys maintained by mytable.
161 :
162 : void mytable_sort_key_remove( mytable_t * join, mytable_sort_key_t const * sort_key );
163 :
164 : // mytable_fwd_iter_{init,done,next,idx,ele,ele_const} provide an
165 : // in-order iterator from smallest to largest value. Typical
166 : // usage:
167 : //
168 : // for( mytable_fwd_iter_t iter = mytable_fwd_iter_init( table, pool );
169 : // !mytable_fwd_iter_done( iter );
170 : // iter = mytable_fwd_iter_next( iter, pool ) ) {
171 : // ulong i = mytable_fwd_iter_idx( iter );
172 : // ... or myrow_t * e = mytable_fwd_iter_ele ( iter, pool );
173 : // ... or myrow_t const * e = mytable_fwd_iter_ele_const( iter, pool );
174 : //
175 : // ... process i (or e) here
176 : //
177 : // ... Do not remove the element the iterator is currently
178 : // ... pointing to, and do not change the element's parent,
179 : // ... left, right, or prio here. It is fine to run other
180 : // ... iterations concurrently. Other fields are free to
181 : // ... modify (from the table's POV, the application manages
182 : // ... concurrency for other fields).
183 : // }
184 : //
185 : // pool is a pointer in the caller's address space to the ele_max
186 : // linearly addressable storage region backing the table.
187 :
188 : int mytable_fwd_iter_done ( mytable_fwd_iter_t iter );
189 : ulong mytable_fwd_iter_idx ( mytable_fwd_iter_t iter );
190 : mytable_fwd_iter_t mytable_fwd_iter_init ( mytable_t * join, mytable_sort_key_t const * sort_key, myrow_t * pool );
191 : mytable_fwd_iter_t mytable_fwd_iter_next ( mytable_t * join, mytable_sort_key_t const * sort_key, mytable_fwd_iter_t iter, myrow_t * pool );
192 : myrow_t * mytable_fwd_iter_ele ( mytable_t * join, mytable_sort_key_t const * sort_key, mytable_fwd_iter_t iter, myrow_t * pool );
193 : myrow_t const * mytable_fwd_iter_ele_const( mytable_t * join, mytable_sort_key_t const * sort_key, mytable_fwd_iter_t iter, myrow_t * pool );
194 : */
195 :
196 : #ifndef LIVE_TABLE_NAME
197 : #error "need to define LIVE_TABLE_NAME"
198 : #endif
199 :
200 : #ifndef LIVE_TABLE_COLUMN_CNT
201 : #error "need to define LIVE_TABLE_COLUMN_CNT"
202 : #endif
203 : FD_STATIC_ASSERT( LIVE_TABLE_COLUMN_CNT >= 1UL, "Expected 1+ live table columns" );
204 :
205 : #ifndef LIVE_TABLE_MAX_SORT_KEY_CNT
206 : #define LIVE_TABLE_MAX_SORT_KEY_CNT (1024UL)
207 : #endif
208 : FD_STATIC_ASSERT( LIVE_TABLE_MAX_SORT_KEY_CNT >= 2UL, "Requires at least 2 sort keys" );
209 :
210 : #ifndef LIVE_TABLE_ROW_T
211 : #error "need to define LIVE_TABLE_ROW_T"
212 : #endif
213 :
214 : #ifndef LIVE_TABLE_IDX_T
215 0 : #define LIVE_TABLE_IDX_T ulong
216 : #endif
217 :
218 : #ifndef LIVE_TABLE_COLUMNS
219 : #error "need to define LIVE_TABLE_COLUMNS"
220 : #endif
221 :
222 : #ifndef LIVE_TABLE_SORT_KEYS
223 : #define LIVE_TABLE_SORT_KEYS sort_keys
224 : #endif
225 :
226 : #ifndef LIVE_TABLE_TREAP
227 0 : #define LIVE_TABLE_TREAP treaps
228 : #endif
229 :
230 : #ifndef LIVE_TABLE_DLIST
231 : #define LIVE_TABLE_DLIST dlist
232 : #endif
233 :
234 0 : #define LIVE_TABLE_(n) FD_EXPAND_THEN_CONCAT3(LIVE_TABLE_NAME,_,n)
235 :
236 : #include <stddef.h> // offsetof
237 :
238 : #define LIVE_TABLE_COL_ENTRY(col_id, field, lt_func) \
239 : (LIVE_TABLE_(private_column_t)){ .col_name = col_id, .off = offsetof( LIVE_TABLE_ROW_T , field ), .lt = lt_func }
240 :
241 0 : #define LIVE_TABLE_COL_ARRAY(...) { __VA_ARGS__ }
242 :
243 : #ifndef LIVE_TABLE_IMPL_STYLE
244 : #define LIVE_TABLE_IMPL_STYLE 0
245 : #endif
246 :
247 : #if LIVE_TABLE_IMPL_STYLE==0
248 : #define LIVE_TABLE_STATIC static FD_FN_UNUSED
249 : #else
250 : #define LIVE_TABLE_STATIC
251 : #endif
252 :
253 : #include "../../util/log/fd_log.h" /* failure logs */
254 : #include "../../util/bits/fd_bits.h"
255 : #include "../../util/math/fd_stat.h"
256 :
257 : /* LIVE_TABLE_FOR_ACTIVE( join, i ) { ... } runs the body for each
258 : active sort key slot i in increasing order. */
259 :
260 : #define LIVE_TABLE_FOR_ACTIVE( join, i ) \
261 0 : for( ulong _w=0UL; _w<(LIVE_TABLE_MAX_SORT_KEY_CNT+63UL)/64UL; _w++ ) \
262 0 : for( ulong _bits=(join)->active_bits[ _w ], i=(_w<<6)+(ulong)fd_ulong_find_lsb_w_default( _bits, 0 ); _bits; \
263 0 : _bits&=_bits-1UL, i=(_w<<6)+(ulong)fd_ulong_find_lsb_w_default( _bits, 0 ) )
264 :
265 : #if LIVE_TABLE_IMPL_STYLE!=2 /* need structures, prototypes and inlines */
266 : struct LIVE_TABLE_(private_column) {
267 : char * col_name; /* cstr */
268 : ulong off;
269 : int (* const lt)(void const * a, void const * b);
270 : };
271 : typedef struct LIVE_TABLE_(private_column) LIVE_TABLE_(private_column_t);
272 :
273 : struct LIVE_TABLE_(sort_key) {
274 : ulong col[ LIVE_TABLE_COLUMN_CNT ];
275 : int dir[ LIVE_TABLE_COLUMN_CNT ];
276 : };
277 : typedef struct LIVE_TABLE_(sort_key) LIVE_TABLE_(sort_key_t);
278 :
279 : /* Global state is ugly. We only have one type of treap and they all
280 : share the same static comparison function, but we need that function
281 : to change dynamically. The simplest way to do this is to have the
282 : function reference changing global state. Not ideal but the
283 : alternative is to change the implementation of the treap template.
284 :
285 : This variable never needs to be shared across compile units. All of
286 : the functions in this template do not retain interest in this
287 : variable after each call. */
288 : static ulong LIVE_TABLE_(private_active_sort_key_idx) = ULONG_MAX;
289 :
290 : static int
291 0 : LIVE_TABLE_(private_row_lt)(LIVE_TABLE_ROW_T const * a, LIVE_TABLE_ROW_T const * b) {
292 0 : FD_TEST( LIVE_TABLE_(private_active_sort_key_idx) < LIVE_TABLE_MAX_SORT_KEY_CNT );
293 :
294 0 : LIVE_TABLE_(sort_key_t) const * active_sort_key = &((LIVE_TABLE_(sort_key_t) *)(a->LIVE_TABLE_SORT_KEYS))[ LIVE_TABLE_(private_active_sort_key_idx) ];
295 :
296 0 : for( ulong i=0UL; i<LIVE_TABLE_COLUMN_CNT; i++ ) {
297 0 : if( FD_LIKELY( active_sort_key->dir[ i ]==0 ) ) continue;
298 :
299 0 : LIVE_TABLE_(private_column_t) cols[ LIVE_TABLE_COLUMN_CNT ] = LIVE_TABLE_COLUMNS;
300 :
301 0 : void * col_a = ((uchar *)a) + cols[ active_sort_key->col[ i ] ].off;
302 0 : void * col_b = ((uchar *)b) + cols[ active_sort_key->col[ i ] ].off;
303 0 : int a_lt_b = cols[ active_sort_key->col[ i ] ].lt(col_a, col_b);
304 0 : int b_lt_a = cols[ active_sort_key->col[ i ] ].lt(col_b, col_a);
305 :
306 0 : if( FD_UNLIKELY( !(a_lt_b || b_lt_a) ) ) continue; /* equal */
307 0 : return fd_int_if( active_sort_key->dir[ i ]==1, a_lt_b, !a_lt_b );
308 0 : }
309 :
310 0 : return 0; /* all columns equal */
311 0 : }
312 :
313 : #define TREAP_NAME LIVE_TABLE_(private_treap)
314 : #define TREAP_T LIVE_TABLE_ROW_T
315 : #define TREAP_QUERY_T void * /* query isn't used */
316 : #define TREAP_CMP(q,e) (__extension__({ (void)(q); (void)(e); -1; })) /* which means we don't need to give a real
317 : implementation to cmp either */
318 0 : #define TREAP_LT(e0,e1) (LIVE_TABLE_(private_row_lt)( (e0), (e1) ))
319 0 : #define TREAP_IDX_T LIVE_TABLE_IDX_T
320 : #define TREAP_OPTIMIZE_ITERATION 1
321 0 : #define TREAP_PARENT LIVE_TABLE_TREAP[ LIVE_TABLE_(private_active_sort_key_idx) ].parent
322 0 : #define TREAP_LEFT LIVE_TABLE_TREAP[ LIVE_TABLE_(private_active_sort_key_idx) ].left
323 0 : #define TREAP_RIGHT LIVE_TABLE_TREAP[ LIVE_TABLE_(private_active_sort_key_idx) ].right
324 0 : #define TREAP_NEXT LIVE_TABLE_TREAP[ LIVE_TABLE_(private_active_sort_key_idx) ].next
325 0 : #define TREAP_PREV LIVE_TABLE_TREAP[ LIVE_TABLE_(private_active_sort_key_idx) ].prev
326 : /* Priorities depend only on (row, seed), identical across sort keys,
327 : and treap operations only ever read them, so all sort keys share
328 : slot 0's prio to reduce cache misses. */
329 0 : #define TREAP_PRIO LIVE_TABLE_TREAP[ 0 ].prio
330 : #define TREAP_IMPL_STYLE LIVE_TABLE_IMPL_STYLE
331 : #include "../../util/tmpl/fd_treap.c"
332 :
333 : #define DLIST_NAME LIVE_TABLE_(private_dlist)
334 : #define DLIST_ELE_T LIVE_TABLE_ROW_T
335 0 : #define DLIST_PREV LIVE_TABLE_DLIST.prev
336 0 : #define DLIST_NEXT LIVE_TABLE_DLIST.next
337 : #include "../../util/tmpl/fd_dlist.c"
338 :
339 : struct LIVE_TABLE_() {
340 : LIVE_TABLE_(private_dlist_t) * dlist;
341 :
342 : LIVE_TABLE_(private_treap_t) * treaps [ LIVE_TABLE_MAX_SORT_KEY_CNT ];
343 : void * treaps_shmem[ LIVE_TABLE_MAX_SORT_KEY_CNT ];
344 :
345 : /* Bit i set when sort key slot i holds a treap, so insert and remove
346 : visit only the active slots instead of scanning every slot. */
347 : ulong active_bits[ (LIVE_TABLE_MAX_SORT_KEY_CNT+63UL)/64UL ];
348 :
349 : ulong count;
350 : ulong max_rows;
351 : ulong evict_idx;
352 : LIVE_TABLE_(sort_key_t) sort_keys[ LIVE_TABLE_MAX_SORT_KEY_CNT ];
353 : };
354 : typedef struct LIVE_TABLE_() LIVE_TABLE_(t);
355 :
356 : typedef LIVE_TABLE_(private_treap_fwd_iter_t) LIVE_TABLE_(fwd_iter_t);
357 :
358 : FD_FN_PURE static inline int
359 0 : LIVE_TABLE_(private_is_active)( LIVE_TABLE_(t) const * join, ulong i ) { return (int)((join->active_bits[ i>>6 ]>>(i&63UL)) & 1UL); }
360 :
361 : static inline void
362 0 : LIVE_TABLE_(private_set_active)( LIVE_TABLE_(t) * join, ulong i, int active ) {
363 0 : join->active_bits[ i>>6 ] = fd_ulong_if( active, join->active_bits[ i>>6 ] | (1UL<<(i&63UL)), join->active_bits[ i>>6 ] & ~(1UL<<(i&63UL)) );
364 0 : }
365 :
366 : FD_PROTOTYPES_BEGIN
367 :
368 : LIVE_TABLE_STATIC void LIVE_TABLE_(seed)( LIVE_TABLE_ROW_T * pool, ulong rows_max, ulong seed );
369 :
370 : LIVE_TABLE_STATIC FD_FN_CONST ulong LIVE_TABLE_(align) ( void );
371 : LIVE_TABLE_STATIC FD_FN_CONST ulong LIVE_TABLE_(footprint)( ulong rows_max );
372 : LIVE_TABLE_STATIC void * LIVE_TABLE_(new) ( void * shmem, ulong rows_max );
373 : LIVE_TABLE_STATIC LIVE_TABLE_(t) * LIVE_TABLE_(join) ( void * shtable );
374 : LIVE_TABLE_STATIC void * LIVE_TABLE_(leave) ( LIVE_TABLE_(t) * join );
375 : LIVE_TABLE_STATIC void * LIVE_TABLE_(delete) ( void * shtable );
376 :
377 : LIVE_TABLE_STATIC LIVE_TABLE_ROW_T * LIVE_TABLE_(idx_insert)( LIVE_TABLE_(t) * join, ulong pool_idx, LIVE_TABLE_ROW_T * pool );
378 : LIVE_TABLE_STATIC void LIVE_TABLE_(idx_remove)( LIVE_TABLE_(t) * join, ulong pool_idx, LIVE_TABLE_ROW_T * pool );
379 :
380 : LIVE_TABLE_STATIC FD_FN_PURE LIVE_TABLE_(fwd_iter_t) LIVE_TABLE_(fwd_iter_next)( LIVE_TABLE_(fwd_iter_t) iter, LIVE_TABLE_ROW_T const * pool );
381 : LIVE_TABLE_STATIC LIVE_TABLE_(fwd_iter_t) LIVE_TABLE_(fwd_iter_init)( LIVE_TABLE_(t) * join, LIVE_TABLE_(sort_key_t) const * sort_key, LIVE_TABLE_ROW_T * pool );
382 :
383 : LIVE_TABLE_STATIC int LIVE_TABLE_(verify)( LIVE_TABLE_(t) const * table, LIVE_TABLE_ROW_T const * pool );
384 : LIVE_TABLE_STATIC int LIVE_TABLE_(verify_sort_key)( LIVE_TABLE_(sort_key_t) const * sort_key );
385 :
386 : LIVE_TABLE_STATIC void
387 : LIVE_TABLE_(sort_key_remove)( LIVE_TABLE_(t) * join, LIVE_TABLE_(sort_key_t) const * sort_key );
388 :
389 : /* inlines */
390 :
391 0 : FD_FN_CONST static inline ulong LIVE_TABLE_(idx_null) ( void ) { return LIVE_TABLE_(private_treap_idx_null)(); }
392 0 : FD_FN_CONST static inline LIVE_TABLE_ROW_T * LIVE_TABLE_(ele_null) ( void ) { return LIVE_TABLE_(private_treap_ele_null)(); }
393 0 : FD_FN_CONST static inline LIVE_TABLE_ROW_T const * LIVE_TABLE_(ele_null_const)( void ) { return LIVE_TABLE_(private_treap_ele_null_const)(); }
394 :
395 0 : FD_FN_CONST static inline int LIVE_TABLE_(idx_is_null)( ulong i ) { return LIVE_TABLE_(private_treap_idx_is_null)( i ); }
396 0 : FD_FN_CONST static inline int LIVE_TABLE_(ele_is_null)( LIVE_TABLE_ROW_T const * e ) { return LIVE_TABLE_(private_treap_ele_is_null)( e ); }
397 :
398 : FD_FN_CONST static inline ulong
399 0 : LIVE_TABLE_(idx)( LIVE_TABLE_ROW_T const * e, LIVE_TABLE_ROW_T const * pool ) { return LIVE_TABLE_(private_treap_idx)( e, pool ); }
400 :
401 : FD_FN_CONST static inline LIVE_TABLE_ROW_T *
402 0 : LIVE_TABLE_(ele)( ulong i, LIVE_TABLE_ROW_T * pool ) { return LIVE_TABLE_(private_treap_ele)( i, pool ); }
403 :
404 : FD_FN_CONST static inline LIVE_TABLE_ROW_T const *
405 0 : LIVE_TABLE_(ele_const)( ulong i, LIVE_TABLE_ROW_T const * pool ) { return LIVE_TABLE_(private_treap_ele_const)( i, pool ); }
406 :
407 : FD_FN_CONST static inline ulong
408 0 : LIVE_TABLE_(idx_fast)( LIVE_TABLE_ROW_T const * e, LIVE_TABLE_ROW_T const * pool ) { return LIVE_TABLE_(private_treap_idx_fast)( e, pool ); }
409 :
410 0 : FD_FN_CONST static inline LIVE_TABLE_ROW_T * LIVE_TABLE_(ele_fast) ( ulong i, LIVE_TABLE_ROW_T * pool ) { return LIVE_TABLE_(private_treap_ele_fast)( i, pool ); }
411 0 : FD_FN_CONST static inline LIVE_TABLE_ROW_T const * LIVE_TABLE_(ele_fast_const)( ulong i, LIVE_TABLE_ROW_T const * pool ) { return LIVE_TABLE_(private_treap_ele_fast_const)( i, pool ); }
412 :
413 : FD_FN_PURE static inline LIVE_TABLE_(fwd_iter_t)
414 0 : LIVE_TABLE_(fwd_iter_next)( LIVE_TABLE_(fwd_iter_t) iter, LIVE_TABLE_ROW_T const * pool ) { return LIVE_TABLE_(private_treap_fwd_iter_next)( iter, pool ); }
415 :
416 : FD_FN_CONST static inline LIVE_TABLE_ROW_T *
417 0 : LIVE_TABLE_(fwd_iter_ele)( LIVE_TABLE_(fwd_iter_t) iter, LIVE_TABLE_ROW_T * pool ) { return LIVE_TABLE_(private_treap_fwd_iter_ele)( iter, pool ); }
418 :
419 : FD_FN_CONST static inline LIVE_TABLE_ROW_T const *
420 0 : LIVE_TABLE_(fwd_iter_ele_const)( LIVE_TABLE_(fwd_iter_t) iter, LIVE_TABLE_ROW_T const * pool ) { return LIVE_TABLE_(private_treap_fwd_iter_ele_const)( iter, pool ); }
421 :
422 : FD_FN_CONST static inline int
423 0 : LIVE_TABLE_(fwd_iter_done)( LIVE_TABLE_(fwd_iter_t) iter ) { return LIVE_TABLE_(private_treap_fwd_iter_done)( iter ); }
424 :
425 : FD_FN_CONST static inline ulong
426 0 : LIVE_TABLE_(fwd_iter_idx)( LIVE_TABLE_(fwd_iter_t) iter ) { return LIVE_TABLE_(private_treap_fwd_iter_idx)( iter ); }
427 :
428 : static inline LIVE_TABLE_ROW_T *
429 0 : LIVE_TABLE_(ele_insert)( LIVE_TABLE_(t) * join, LIVE_TABLE_ROW_T * row, LIVE_TABLE_ROW_T * pool ) { return LIVE_TABLE_(idx_insert)( join, (ulong)(row - pool), pool ); }
430 :
431 : static inline void
432 0 : LIVE_TABLE_(ele_remove)( LIVE_TABLE_(t) * join, LIVE_TABLE_ROW_T * row, LIVE_TABLE_ROW_T * pool ) { LIVE_TABLE_(idx_remove)( join, (ulong)(row - pool), pool ); }
433 :
434 0 : FD_FN_PURE static inline ulong LIVE_TABLE_(ele_cnt)( LIVE_TABLE_(t) * join ) { return join->count; }
435 0 : FD_FN_PURE static inline ulong LIVE_TABLE_(ele_max)( LIVE_TABLE_(t) * join ) { return join->max_rows; }
436 0 : FD_FN_PURE static inline ulong LIVE_TABLE_(col_cnt)( void ) { return LIVE_TABLE_COLUMN_CNT; }
437 :
438 : FD_FN_PURE static inline ulong
439 0 : LIVE_TABLE_(active_sort_key_cnt)( LIVE_TABLE_(t) * join ) {
440 0 : ulong count = 0UL;
441 0 : for( ulong w=0UL; w<(LIVE_TABLE_MAX_SORT_KEY_CNT+63UL)/64UL; w++ ) count += (ulong)fd_ulong_popcnt( join->active_bits[ w ] );
442 0 : return count;
443 0 : }
444 :
445 : FD_FN_CONST static inline ulong
446 0 : LIVE_TABLE_(col_name_to_idx)( LIVE_TABLE_(t) * join, char const * col_name ) {
447 0 : (void)join;
448 0 : LIVE_TABLE_(private_column_t) cols[ LIVE_TABLE_COLUMN_CNT ] = LIVE_TABLE_COLUMNS;
449 0 : for( ulong i=0; i < LIVE_TABLE_COLUMN_CNT; i++ ) {
450 0 : if( FD_UNLIKELY( strcmp( cols[ i ].col_name, col_name ) ) ) continue;
451 0 : return i;
452 0 : }
453 0 : return ULONG_MAX;
454 0 : }
455 :
456 : FD_FN_CONST static inline char const *
457 0 : LIVE_TABLE_(col_idx_to_name)( LIVE_TABLE_(t) * join, ulong col_idx ) {
458 0 : (void)join;
459 0 : if( FD_UNLIKELY( col_idx>=LIVE_TABLE_COLUMN_CNT ) ) return NULL;
460 0 : LIVE_TABLE_(private_column_t) cols[ LIVE_TABLE_COLUMN_CNT ] = LIVE_TABLE_COLUMNS;
461 0 : return cols[ col_idx ].col_name;
462 0 : }
463 :
464 : static inline void
465 0 : LIVE_TABLE_(private_sort_key_print)( LIVE_TABLE_(sort_key_t) const * sort_key ) {
466 0 : char out[ 4096 ];
467 0 : char * p = fd_cstr_init( out );
468 :
469 0 : p = fd_cstr_append_printf( p, "cols: %lu", sort_key->col[ 0 ] );
470 0 : for( ulong i=1UL; i<LIVE_TABLE_COLUMN_CNT; i++ ) {
471 0 : p = fd_cstr_append_printf( p, ",%lu", sort_key->col[ i ] );
472 0 : }
473 0 : p = fd_cstr_append_printf( p, "\ndir: %d", sort_key->dir[ 0 ] );
474 0 : for( ulong i=1UL; i<LIVE_TABLE_COLUMN_CNT; i++ ) {
475 0 : p = fd_cstr_append_printf( p, ",%d", sort_key->dir[ i ] );
476 0 : }
477 0 : fd_cstr_fini( p );
478 0 : FD_LOG_WARNING(( "%s", out ));
479 0 : }
480 :
481 : static inline void
482 0 : LIVE_TABLE_(private_sort_key_create)( LIVE_TABLE_(t) * join, ulong sort_key_idx, LIVE_TABLE_(sort_key_t) const * sort_key, LIVE_TABLE_ROW_T * pool ) {
483 0 : join->sort_keys[ sort_key_idx ] = *sort_key;
484 :
485 0 : LIVE_TABLE_(private_active_sort_key_idx) = sort_key_idx;
486 0 : join->treaps[ sort_key_idx ] = LIVE_TABLE_(private_treap_join)( LIVE_TABLE_(private_treap_new)( join->treaps_shmem[ sort_key_idx ], join->max_rows ) );
487 0 : LIVE_TABLE_(private_set_active)( join, sort_key_idx, 1 );
488 : #if FD_TMPL_USE_HANDHOLDING
489 : FD_TEST( sort_key_idx<LIVE_TABLE_MAX_SORT_KEY_CNT );
490 : FD_TEST( join->treaps[ sort_key_idx ] );
491 : FD_TEST( !LIVE_TABLE_(private_treap_verify)( join->treaps[ sort_key_idx ], pool ) );
492 : #endif
493 :
494 0 : for( LIVE_TABLE_(private_dlist_iter_t) iter = LIVE_TABLE_(private_dlist_iter_fwd_init)( join->dlist, pool );
495 0 : !LIVE_TABLE_(private_dlist_iter_done)( iter, join->dlist, pool );
496 0 : iter = LIVE_TABLE_(private_dlist_iter_fwd_next)( iter, join->dlist, pool ) ) {
497 0 : ulong pool_idx = LIVE_TABLE_(private_dlist_iter_idx)( iter, join->dlist, pool );
498 0 : LIVE_TABLE_(private_treap_idx_insert)( join->treaps[ sort_key_idx ], pool_idx, pool );
499 0 : }
500 :
501 : #if FD_TMPL_USE_HANDHOLDING
502 : FD_TEST( !LIVE_TABLE_(private_treap_verify)( join->treaps[ sort_key_idx ], pool ) );
503 : #endif
504 0 : }
505 :
506 : static inline ulong
507 0 : LIVE_TABLE_(private_query_sort_key)( LIVE_TABLE_(t) * join, LIVE_TABLE_(sort_key_t) const * sort_key ) {
508 0 : LIVE_TABLE_FOR_ACTIVE( join, i ) {
509 0 : ulong j = 0UL;
510 0 : ulong k = 0UL;
511 :
512 0 : for(;;) {
513 : /* columns with dir=0 don't actually count, they're ignored */
514 0 : while( FD_UNLIKELY( j<LIVE_TABLE_COLUMN_CNT && join->sort_keys[ i ].dir[ j ]==0 ) ) j++;
515 0 : while( FD_UNLIKELY( k<LIVE_TABLE_COLUMN_CNT && sort_key->dir[ k ]==0 ) ) k++;
516 :
517 0 : if( FD_UNLIKELY( j==LIVE_TABLE_COLUMN_CNT || k==LIVE_TABLE_COLUMN_CNT ) ) {
518 0 : if( FD_LIKELY( j==LIVE_TABLE_COLUMN_CNT && k==LIVE_TABLE_COLUMN_CNT ) ) return i;
519 0 : break;
520 0 : }
521 :
522 0 : if( FD_UNLIKELY( join->sort_keys[ i ].col[ j ]!=sort_key->col[ k ] || join->sort_keys[ i ].dir[ j ]!=sort_key->dir[ k ] ) ) break;
523 :
524 0 : j++;
525 0 : k++;
526 0 : }
527 0 : }
528 :
529 0 : return ULONG_MAX;
530 0 : }
531 :
532 0 : static inline int LIVE_TABLE_(lt) ( LIVE_TABLE_(sort_key_t) const * sort_key, LIVE_TABLE_ROW_T const * e0, LIVE_TABLE_ROW_T const * e1 ) {
533 0 : LIVE_TABLE_(private_column_t) cols[ LIVE_TABLE_COLUMN_CNT ] = LIVE_TABLE_COLUMNS;
534 0 : for( ulong i=0UL; i<LIVE_TABLE_COLUMN_CNT; i++ ) {
535 0 : if( FD_LIKELY( sort_key->dir[ i ]==0 ) ) continue;
536 :
537 0 : void * col_a = ((uchar *)e0) + cols[ sort_key->col[ i ] ].off;
538 0 : void * col_b = ((uchar *)e1) + cols[ sort_key->col[ i ] ].off;
539 0 : int a_lt_b = cols[ sort_key->col[ i ] ].lt( col_a, col_b );
540 0 : int b_lt_a = cols[ sort_key->col[ i ] ].lt( col_b, col_a );
541 :
542 0 : if( FD_UNLIKELY( !(a_lt_b || b_lt_a) ) ) continue;
543 0 : return fd_int_if( sort_key->dir[ i ]==1, a_lt_b, !a_lt_b );
544 0 : }
545 :
546 0 : return 0;
547 0 : }
548 :
549 : #endif /* LIVE_TABLE_IMPL_STYLE!=2 */
550 :
551 : #if LIVE_TABLE_IMPL_STYLE!=1 /* need implementations */
552 :
553 : LIVE_TABLE_STATIC ulong
554 0 : LIVE_TABLE_(align)(void) {
555 0 : ulong a = 1UL;
556 0 : a = fd_ulong_max( a, alignof(LIVE_TABLE_(t)) );
557 0 : a = fd_ulong_max( a, LIVE_TABLE_(private_treap_align)() );
558 0 : a = fd_ulong_max( a, LIVE_TABLE_(private_dlist_align)() );
559 0 : a = fd_ulong_max( a, 128UL );
560 0 : FD_TEST( fd_ulong_pow2_up( a )==a );
561 0 : return a;
562 0 : }
563 :
564 : LIVE_TABLE_STATIC ulong
565 0 : LIVE_TABLE_(footprint)( ulong max_rows ) {
566 0 : ulong l = FD_LAYOUT_INIT;
567 0 : l = FD_LAYOUT_APPEND( l, alignof(LIVE_TABLE_(t)), sizeof(LIVE_TABLE_(t)) );
568 0 : l = FD_LAYOUT_APPEND( l, LIVE_TABLE_(private_dlist_align)(), LIVE_TABLE_(private_dlist_footprint)() );
569 0 : for( ulong i=0UL; i<LIVE_TABLE_MAX_SORT_KEY_CNT; i++ ) l = FD_LAYOUT_APPEND( l, LIVE_TABLE_(private_treap_align)(), LIVE_TABLE_(private_treap_footprint)( max_rows ) );
570 0 : return FD_LAYOUT_FINI( l, LIVE_TABLE_(align)() );
571 0 : }
572 :
573 : LIVE_TABLE_STATIC void *
574 0 : LIVE_TABLE_(new)( void * shmem, ulong max_rows ) {
575 0 : if( !shmem ) {
576 0 : FD_LOG_WARNING(( "NULL shmem" ));
577 0 : return NULL;
578 0 : }
579 :
580 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, LIVE_TABLE_(align)() ) ) ) {
581 0 : FD_LOG_WARNING(( "misaligned shmem" ));
582 0 : return NULL;
583 0 : }
584 :
585 0 : FD_SCRATCH_ALLOC_INIT( l, shmem );
586 0 : LIVE_TABLE_(t) * _table = FD_SCRATCH_ALLOC_APPEND( l, alignof(LIVE_TABLE_(t)), sizeof(LIVE_TABLE_(t)) );
587 0 : void * _dlist = FD_SCRATCH_ALLOC_APPEND( l, LIVE_TABLE_(private_dlist_align)(), LIVE_TABLE_(private_dlist_footprint)() );
588 0 : for( ulong i=0; i<LIVE_TABLE_MAX_SORT_KEY_CNT; i++ ) _table->treaps_shmem[ i ] = FD_SCRATCH_ALLOC_APPEND( l, LIVE_TABLE_(private_treap_align)(), LIVE_TABLE_(private_treap_footprint)( max_rows ) );
589 0 : FD_SCRATCH_ALLOC_FINI( l, LIVE_TABLE_(align)() );
590 :
591 0 : _table->dlist = LIVE_TABLE_(private_dlist_join)( LIVE_TABLE_(private_dlist_new)( _dlist ) );
592 0 : _table->max_rows = max_rows;
593 0 : _table->count = 0UL;
594 0 : _table->evict_idx = 0UL;
595 0 : for( ulong w=0UL; w<(LIVE_TABLE_MAX_SORT_KEY_CNT+63UL)/64UL; w++ ) _table->active_bits[ w ] = 0UL;
596 :
597 0 : LIVE_TABLE_(private_column_t) cols[ LIVE_TABLE_COLUMN_CNT ] = LIVE_TABLE_COLUMNS;
598 0 : FD_STATIC_ASSERT( LIVE_TABLE_COLUMN_CNT == sizeof(cols)/sizeof(LIVE_TABLE_(private_column_t)), column count is wrong );
599 :
600 : /* live_table_treap_new( ... ) not called since all treaps start as inactive */
601 :
602 0 : return _table;
603 0 : }
604 :
605 : FD_PROTOTYPES_END
606 :
607 : LIVE_TABLE_STATIC void
608 0 : LIVE_TABLE_(seed)( LIVE_TABLE_ROW_T * pool, ulong rows_max, ulong seed ) {
609 0 : ulong idx_null = LIVE_TABLE_(private_treap_idx_null)();
610 0 : for( ulong row=0UL; row<rows_max; row++ ) {
611 0 : ulong r = fd_ulong_hash( row ^ seed ) & idx_null;
612 0 : pool[ row ].LIVE_TABLE_TREAP[ 0 ].prio = (LIVE_TABLE_IDX_T)(r - (ulong)(r==idx_null));
613 0 : }
614 0 : }
615 :
616 : LIVE_TABLE_STATIC LIVE_TABLE_(t) *
617 0 : LIVE_TABLE_(join)( void * shtable ) {
618 0 : if( !shtable ) {
619 0 : FD_LOG_WARNING(( "NULL shtable" ));
620 0 : return NULL;
621 0 : }
622 :
623 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shtable, LIVE_TABLE_(align)() ) ) ) {
624 0 : FD_LOG_WARNING(( "misaligned shtable" ));
625 0 : return NULL;
626 0 : }
627 :
628 0 : return (LIVE_TABLE_(t) *)shtable;
629 0 : }
630 :
631 : LIVE_TABLE_STATIC void *
632 0 : LIVE_TABLE_(leave)( LIVE_TABLE_(t) * join ) {
633 0 : if( FD_UNLIKELY( !join ) ) {
634 0 : FD_LOG_WARNING(( "NULL join" ));
635 0 : return NULL;
636 0 : }
637 :
638 0 : LIVE_TABLE_(private_dlist_delete)( LIVE_TABLE_(private_dlist_leave)( join->dlist ) );
639 0 : LIVE_TABLE_FOR_ACTIVE( join, i ) {
640 0 : LIVE_TABLE_(private_active_sort_key_idx) = i;
641 0 : FD_TEST( LIVE_TABLE_(private_treap_delete)( LIVE_TABLE_(private_treap_leave)( join->treaps[ i ] ) ) );
642 0 : }
643 :
644 0 : return (void *)join;
645 0 : }
646 :
647 : LIVE_TABLE_STATIC void *
648 0 : LIVE_TABLE_(delete)( void * shtable ) {
649 0 : LIVE_TABLE_(t) * table = (LIVE_TABLE_(t) *)shtable;
650 :
651 0 : if( FD_UNLIKELY( !table ) ) {
652 0 : FD_LOG_WARNING(( "NULL shtable" ));
653 0 : return NULL;
654 0 : }
655 :
656 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)table, alignof(LIVE_TABLE_(t)) ) ) ) {
657 0 : FD_LOG_WARNING(( "misaligned shtable" ));
658 0 : return NULL;
659 0 : }
660 :
661 0 : return (void *)table;
662 0 : }
663 :
664 : LIVE_TABLE_STATIC void
665 0 : LIVE_TABLE_(idx_remove)( LIVE_TABLE_(t) * join, ulong pool_idx, LIVE_TABLE_ROW_T * pool ) {
666 : #if FD_TMPL_USE_HANDHOLDING
667 : FD_TEST( !LIVE_TABLE_(private_treap_idx_is_null)( pool_idx ) );
668 : FD_TEST( join->count >= 1UL );
669 : #endif
670 : /* remove from all active treaps */
671 0 : LIVE_TABLE_FOR_ACTIVE( join, i ) {
672 0 : LIVE_TABLE_(private_active_sort_key_idx) = i;
673 0 : LIVE_TABLE_(private_treap_idx_remove)( join->treaps[ i ], pool_idx, pool );
674 0 : }
675 0 : LIVE_TABLE_(private_dlist_idx_remove)( join->dlist, pool_idx, pool );
676 0 : join->count--;
677 0 : }
678 :
679 : LIVE_TABLE_STATIC LIVE_TABLE_ROW_T *
680 0 : LIVE_TABLE_(idx_insert)( LIVE_TABLE_(t) * join, ulong pool_idx, LIVE_TABLE_ROW_T * pool ) {
681 0 : pool[ pool_idx ].LIVE_TABLE_SORT_KEYS = (ulong)(&join->sort_keys);
682 : #if FD_TMPL_USE_HANDHOLDING
683 : FD_TEST( !LIVE_TABLE_(private_treap_idx_is_null)( pool_idx ) );
684 : #endif
685 : /* insert into all active treaps */
686 0 : LIVE_TABLE_FOR_ACTIVE( join, i ) {
687 0 : LIVE_TABLE_(private_active_sort_key_idx) = i;
688 0 : LIVE_TABLE_(private_treap_idx_insert)( join->treaps[ i ], pool_idx, pool );
689 0 : }
690 0 : LIVE_TABLE_(private_dlist_idx_push_tail)( join->dlist, pool_idx, pool );
691 0 : join->count++;
692 :
693 0 : return pool + pool_idx;
694 0 : }
695 :
696 : LIVE_TABLE_STATIC void
697 0 : LIVE_TABLE_(sort_key_remove)( LIVE_TABLE_(t) * join, LIVE_TABLE_(sort_key_t) const * sort_key ) {
698 0 : ulong sort_key_idx = LIVE_TABLE_(private_query_sort_key)( join, sort_key );
699 0 : if( FD_UNLIKELY( sort_key_idx==ULONG_MAX ) ) return;
700 :
701 0 : LIVE_TABLE_(private_active_sort_key_idx) = sort_key_idx;
702 : #if FD_TMPL_USE_HANDHOLDING
703 : FD_TEST( sort_key_idx<LIVE_TABLE_MAX_SORT_KEY_CNT );
704 : FD_TEST( join->treaps[ sort_key_idx ] );
705 : #endif
706 0 : LIVE_TABLE_(private_set_active)( join, sort_key_idx, 0 );
707 0 : LIVE_TABLE_(private_treap_delete)( LIVE_TABLE_(private_treap_leave)( join->treaps[ sort_key_idx ] ) );
708 0 : join->treaps[ sort_key_idx ] = NULL;
709 0 : }
710 :
711 : LIVE_TABLE_STATIC LIVE_TABLE_(fwd_iter_t)
712 0 : LIVE_TABLE_(fwd_iter_init)( LIVE_TABLE_(t) * join, LIVE_TABLE_(sort_key_t) const * sort_key, LIVE_TABLE_ROW_T * pool ) {
713 0 : ulong sort_key_idx = LIVE_TABLE_(private_query_sort_key)( join, sort_key );
714 0 : if( FD_UNLIKELY( sort_key_idx==ULONG_MAX ) ) {
715 0 : for( ulong w=0UL; w<(LIVE_TABLE_MAX_SORT_KEY_CNT+63UL)/64UL; w++ ) {
716 0 : ulong free = ~join->active_bits[ w ];
717 0 : if( FD_LIKELY( !free ) ) continue;
718 0 : sort_key_idx = (w<<6)+(ulong)fd_ulong_find_lsb( free );
719 0 : break;
720 0 : }
721 0 : if( FD_UNLIKELY( sort_key_idx>=LIVE_TABLE_MAX_SORT_KEY_CNT ) ) sort_key_idx = ULONG_MAX; /* pad bits of the last word */
722 0 : if( FD_UNLIKELY( sort_key_idx==ULONG_MAX ) ) {
723 : /* Cache is full. Evict the next slot in round-robin order. */
724 0 : sort_key_idx = join->evict_idx;
725 0 : join->evict_idx = (join->evict_idx + 1UL) % LIVE_TABLE_MAX_SORT_KEY_CNT;
726 0 : LIVE_TABLE_(sort_key_remove)( join, &join->sort_keys[ sort_key_idx ] );
727 0 : }
728 0 : LIVE_TABLE_(private_sort_key_create)( join, sort_key_idx, sort_key, pool );
729 0 : }
730 0 : LIVE_TABLE_(private_active_sort_key_idx) = sort_key_idx;
731 : #if FD_TMPL_USE_HANDHOLDING
732 : FD_TEST( sort_key_idx!=ULONG_MAX );
733 : FD_TEST( LIVE_TABLE_(private_is_active)( join, sort_key_idx ) );
734 : #endif
735 0 : return LIVE_TABLE_(private_treap_fwd_iter_init)( join->treaps[ sort_key_idx ], pool );
736 0 : }
737 :
738 : LIVE_TABLE_STATIC int
739 0 : LIVE_TABLE_(verify_sort_key)( LIVE_TABLE_(sort_key_t) const * key ) {
740 0 : LIVE_TABLE_(sort_key_t) tmp_key[ 1 ];
741 0 : fd_memcpy( tmp_key, key, sizeof(LIVE_TABLE_(sort_key_t)) );
742 0 : fd_sort_up_ulong_insert( tmp_key->col, LIVE_TABLE_COLUMN_CNT );
743 :
744 0 : for( ulong j=0UL; j<LIVE_TABLE_COLUMN_CNT; j++ ) {
745 0 : if( FD_UNLIKELY( tmp_key->col[ j ]!=j || tmp_key->dir[ j ] > 1 || tmp_key->dir[ j ] < -1 ) ) {
746 0 : return 0;
747 0 : }
748 0 : }
749 :
750 0 : return 1;
751 0 : }
752 :
753 : LIVE_TABLE_STATIC int
754 0 : LIVE_TABLE_(verify)( LIVE_TABLE_(t) const * join, LIVE_TABLE_ROW_T const * pool ) {
755 0 : ulong prev_sk_idx = LIVE_TABLE_(private_active_sort_key_idx);
756 0 : LIVE_TABLE_FOR_ACTIVE( join, i ) {
757 0 : LIVE_TABLE_(private_active_sort_key_idx) = i;
758 0 : if( FD_UNLIKELY( LIVE_TABLE_(private_treap_verify)( join->treaps[ i ], pool ) ) ) {
759 0 : FD_LOG_CRIT(("failed verify"));
760 0 : }
761 :
762 0 : if( FD_UNLIKELY( !LIVE_TABLE_(verify_sort_key)( &join->sort_keys[ i ] ) ) ) {
763 0 : LIVE_TABLE_(private_sort_key_print)( &join->sort_keys[ i ] );
764 0 : FD_LOG_CRIT(( "bad sort key %lu", i ));
765 0 : }
766 0 : }
767 0 : LIVE_TABLE_(private_active_sort_key_idx) = prev_sk_idx;
768 0 : return 0;
769 0 : }
770 :
771 : #endif /* LIVE_TABLE_IMPL_STYLE!=1 */
772 :
773 : #undef LIVE_TABLE_NAME
774 : #undef LIVE_TABLE_COLUMN_CNT
775 : #undef LIVE_TABLE_MAX_SORT_KEY_CNT
776 : #undef LIVE_TABLE_ROW_T
777 : #undef LIVE_TABLE_IDX_T
778 : #undef LIVE_TABLE_COLUMNS
779 : #undef LIVE_TABLE_SORT_KEYS
780 : #undef LIVE_TABLE_TREAP
781 : #undef LIVE_TABLE_DLIST
782 : #undef LIVE_TABLE_
783 : #undef LIVE_TABLE_COL_ENTRY
784 : #undef LIVE_TABLE_COL_ARRAY
785 : #undef LIVE_TABLE_IMPL_STYLE
786 : #undef LIVE_TABLE_STATIC
787 : #undef LIVE_TABLE_FOR_ACTIVE
|