lsquic_attq.c revision 0adf085a
1/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */ 2/* 3 * lsquic_attq.c -- Advisory Tick Time Queue 4 * 5 * This is a collection of connections kept in a binary heap, the top 6 * element having the minimum advsory time. To speed up removal, each 7 * element has an index it has in the heap array. The index is updated 8 * as elements are moved around in the array when heap is updated. 9 */ 10 11#include <assert.h> 12#include <stdlib.h> 13#ifdef WIN32 14#include <vc_compat.h> 15#endif 16#include <sys/queue.h> 17 18#include "lsquic.h" 19#include "lsquic_types.h" 20#include "lsquic_int_types.h" 21#include "lsquic_attq.h" 22#include "lsquic_packet_common.h" 23#include "lsquic_alarmset.h" 24#include "lsquic_malo.h" 25#include "lsquic_hash.h" 26#include "lsquic_conn.h" 27 28 29struct attq 30{ 31 struct malo *aq_elem_malo; 32 struct attq_elem **aq_heap; 33 unsigned aq_nelem; 34 unsigned aq_nalloc; 35}; 36 37 38struct attq * 39attq_create (void) 40{ 41 struct attq *q; 42 struct malo *malo; 43 44 malo = lsquic_malo_create(sizeof(struct attq_elem)); 45 if (!malo) 46 return NULL; 47 48 q = calloc(1, sizeof(*q)); 49 if (!q) 50 { 51 lsquic_malo_destroy(malo); 52 return NULL; 53 } 54 55 q->aq_elem_malo = malo; 56 return q; 57} 58 59 60void 61attq_destroy (struct attq *q) 62{ 63 lsquic_malo_destroy(q->aq_elem_malo); 64 free(q->aq_heap); 65 free(q); 66} 67 68 69 70#define AE_PARENT(i) ((i - 1) / 2) 71#define AE_LCHILD(i) (2 * i + 1) 72#define AE_RCHILD(i) (2 * i + 2) 73 74 75#ifndef NDEBUG 76static void 77attq_verify (struct attq *q) 78{ 79 unsigned i; 80 81 for (i = 0; i < q->aq_nelem; ++i) 82 { 83 assert(q->aq_heap[i]->ae_heap_idx == i); 84 if (AE_LCHILD(i) < q->aq_nelem) 85 assert(q->aq_heap[i]->ae_adv_time <= 86 q->aq_heap[AE_LCHILD(i)]->ae_adv_time); 87 if (AE_RCHILD(i) < q->aq_nelem) 88 assert(q->aq_heap[i]->ae_adv_time <= 89 q->aq_heap[AE_RCHILD(i)]->ae_adv_time); 90 } 91} 92#else 93#define attq_verify(q) 94#endif 95 96 97static void 98attq_swap (struct attq *q, unsigned a, unsigned b) 99{ 100 struct attq_elem *el; 101 102 el = q->aq_heap[ a ]; 103 q->aq_heap[ a ] = q->aq_heap[ b ]; 104 q->aq_heap[ b ] = el; 105 q->aq_heap[ a ]->ae_heap_idx = a; 106 q->aq_heap[ b ]->ae_heap_idx = b; 107} 108 109 110int 111attq_add (struct attq *q, struct lsquic_conn *conn, 112 lsquic_time_t advisory_time, enum ae_why why) 113{ 114 struct attq_elem *el, **heap; 115 unsigned n, i; 116 117 if (q->aq_nelem >= q->aq_nalloc) 118 { 119 if (q->aq_nalloc > 0) 120 n = q->aq_nalloc * 2; 121 else 122 n = 8; 123 heap = realloc(q->aq_heap, n * sizeof(q->aq_heap[0])); 124 if (!heap) 125 return -1; 126 q->aq_heap = heap; 127 q->aq_nalloc = n; 128 } 129 130 el = lsquic_malo_get(q->aq_elem_malo); 131 if (!el) 132 return -1; 133 el->ae_adv_time = advisory_time; 134 el->ae_why = why; 135 136 /* The only place linkage between conn and attq_elem occurs: */ 137 el->ae_conn = conn; 138 conn->cn_attq_elem = el; 139 140 el->ae_heap_idx = q->aq_nelem; 141 q->aq_heap[ q->aq_nelem++ ] = el; 142 143 i = q->aq_nelem - 1; 144 while (i > 0 && q->aq_heap[ AE_PARENT(i) ]->ae_adv_time >= 145 q->aq_heap[ i ]->ae_adv_time) 146 { 147 attq_swap(q, i, AE_PARENT(i)); 148 i = AE_PARENT(i); 149 } 150 151 attq_verify(q); 152 153 return 0; 154} 155 156 157struct lsquic_conn * 158attq_pop (struct attq *q, lsquic_time_t cutoff) 159{ 160 struct lsquic_conn *conn; 161 struct attq_elem *el; 162 163 if (q->aq_nelem == 0) 164 return NULL; 165 166 el = q->aq_heap[0]; 167 if (el->ae_adv_time >= cutoff) 168 return NULL; 169 170 conn = el->ae_conn; 171 attq_remove(q, conn); 172 return conn; 173} 174 175 176static void 177attq_heapify (struct attq *q, unsigned i) 178{ 179 unsigned smallest; 180 181 assert(i < q->aq_nelem); 182 183 if (AE_LCHILD(i) < q->aq_nelem) 184 { 185 if (q->aq_heap[ AE_LCHILD(i) ]->ae_adv_time < 186 q->aq_heap[ i ]->ae_adv_time) 187 smallest = AE_LCHILD(i); 188 else 189 smallest = i; 190 if (AE_RCHILD(i) < q->aq_nelem && 191 q->aq_heap[ AE_RCHILD(i) ]->ae_adv_time < 192 q->aq_heap[ smallest ]->ae_adv_time) 193 smallest = AE_RCHILD(i); 194 } 195 else 196 smallest = i; 197 198 if (smallest != i) 199 { 200 attq_swap(q, smallest, i); 201 attq_heapify(q, smallest); 202 } 203} 204 205 206void 207attq_remove (struct attq *q, struct lsquic_conn *conn) 208{ 209 struct attq_elem *el; 210 unsigned idx; 211 212 el = conn->cn_attq_elem; 213 idx = el->ae_heap_idx; 214 215 assert(q->aq_nelem > 0); 216 assert(q->aq_heap[idx] == el); 217 assert(conn->cn_attq_elem == el); 218 219 conn->cn_attq_elem = NULL; 220 221 q->aq_heap[ idx ] = q->aq_heap[ --q->aq_nelem ]; 222 q->aq_heap[ idx ]->ae_heap_idx = idx; 223 if (idx > 0 && q->aq_heap[ idx ]->ae_adv_time < 224 q->aq_heap[ AE_PARENT(idx) ]->ae_adv_time) 225 { 226 do 227 { 228 attq_swap(q, idx, AE_PARENT(idx)); 229 idx = AE_PARENT(idx); 230 } 231 while (idx > 0 && q->aq_heap[ idx ]->ae_adv_time < 232 q->aq_heap[ AE_PARENT(idx) ]->ae_adv_time); 233 } 234 else if (q->aq_nelem > 1 && idx < q->aq_nelem) 235 attq_heapify(q, idx); 236 lsquic_malo_put(el); 237 attq_verify(q); 238} 239 240 241unsigned 242attq_count_before (struct attq *q, lsquic_time_t cutoff) 243{ 244 unsigned level, total_count, level_count, i, level_max; 245 246 total_count = 0; 247 for (i = 0, level = 0;; ++level) 248 { 249 level_count = 0; 250 level_max = i + (1U << level); 251 for ( ; i < level_max && i < q->aq_nelem; ++i) 252 level_count += q->aq_heap[i]->ae_adv_time < cutoff; 253 total_count += level_count; 254 if (level_count < (1U << level)) 255 return total_count; 256 } 257 assert(0); 258 return total_count; 259} 260 261 262const struct attq_elem * 263attq_next (struct attq *q) 264{ 265 if (q->aq_nelem > 0) 266 return q->aq_heap[0]; 267 else 268 return NULL; 269} 270 271 272const char * 273lsquic_attq_why2str (enum ae_why why) 274{ 275 switch (why) 276 { 277 case AEW_PACER: 278 return "PACER"; 279 case AEW_MINI_EXPIRE: 280 return "MINI-EXPIRE"; 281 default: 282 why -= N_AEWS; 283 if ((unsigned) why < (unsigned) MAX_LSQUIC_ALARMS) 284 return lsquic_alid2str[why]; 285 return "UNKNOWN"; 286 } 287} 288