1*0Sigor@sysoev.ru 2*0Sigor@sysoev.ru /* 3*0Sigor@sysoev.ru * Copyright (C) Igor Sysoev 4*0Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 5*0Sigor@sysoev.ru */ 6*0Sigor@sysoev.ru 7*0Sigor@sysoev.ru #include <nxt_main.h> 8*0Sigor@sysoev.ru 9*0Sigor@sysoev.ru 10*0Sigor@sysoev.ru /* A cache time resolution is 10ms. */ 11*0Sigor@sysoev.ru #define \ 12*0Sigor@sysoev.ru nxt_cache_time(thr) \ 13*0Sigor@sysoev.ru (uint64_t) (nxt_thread_time(thr) * 100) 14*0Sigor@sysoev.ru 15*0Sigor@sysoev.ru 16*0Sigor@sysoev.ru static nxt_int_t nxt_cache_lvlhsh_test(nxt_lvlhsh_query_t *lhq, void *data); 17*0Sigor@sysoev.ru static nxt_work_handler_t nxt_cache_query_locked(nxt_cache_t *cache, 18*0Sigor@sysoev.ru nxt_cache_query_t *q, nxt_lvlhsh_query_t *lhq); 19*0Sigor@sysoev.ru static nxt_work_handler_t nxt_cache_node_hold(nxt_cache_t *cache, 20*0Sigor@sysoev.ru nxt_cache_query_t *q, nxt_lvlhsh_query_t *lhq); 21*0Sigor@sysoev.ru static nxt_work_handler_t nxt_cache_node_test(nxt_cache_t *cache, 22*0Sigor@sysoev.ru nxt_cache_query_t *q); 23*0Sigor@sysoev.ru 24*0Sigor@sysoev.ru static void nxt_cache_wait_handler(nxt_thread_t *thr, void *obj, void *data); 25*0Sigor@sysoev.ru static void nxt_cache_timeout_handler(nxt_thread_t *thr, void *obj, void *data); 26*0Sigor@sysoev.ru static void nxt_cache_wake_handler(nxt_thread_t *thr, void *obj, void *data); 27*0Sigor@sysoev.ru static ssize_t nxt_cache_release_locked(nxt_cache_t *cache, 28*0Sigor@sysoev.ru nxt_cache_query_t *q, u_char *buf, size_t size); 29*0Sigor@sysoev.ru 30*0Sigor@sysoev.ru static nxt_cache_node_t *nxt_cache_node_alloc(nxt_cache_t *cache); 31*0Sigor@sysoev.ru static void nxt_cache_node_free(nxt_cache_t *cache, nxt_cache_node_t *node, 32*0Sigor@sysoev.ru nxt_bool_t fast); 33*0Sigor@sysoev.ru static nxt_cache_query_wait_t *nxt_cache_query_wait_alloc(nxt_cache_t *cache, 34*0Sigor@sysoev.ru nxt_bool_t *slow); 35*0Sigor@sysoev.ru static void nxt_cache_query_wait_free(nxt_cache_t *cache, 36*0Sigor@sysoev.ru nxt_cache_query_wait_t *qw); 37*0Sigor@sysoev.ru 38*0Sigor@sysoev.ru 39*0Sigor@sysoev.ru /* STUB */ 40*0Sigor@sysoev.ru nxt_int_t nxt_cache_shm_create(nxt_mem_zone_t *pool); 41*0Sigor@sysoev.ru static void *nxt_cache_shm_alloc(void *data, size_t size, nxt_uint_t nalloc); 42*0Sigor@sysoev.ru /**/ 43*0Sigor@sysoev.ru 44*0Sigor@sysoev.ru 45*0Sigor@sysoev.ru nxt_int_t 46*0Sigor@sysoev.ru nxt_cache_shm_create(nxt_mem_zone_t *mz) 47*0Sigor@sysoev.ru { 48*0Sigor@sysoev.ru nxt_cache_t *cache; 49*0Sigor@sysoev.ru 50*0Sigor@sysoev.ru static const nxt_lvlhsh_proto_t proto nxt_aligned(64) = { 51*0Sigor@sysoev.ru NXT_LVLHSH_LARGE_SLAB, 52*0Sigor@sysoev.ru 0, 53*0Sigor@sysoev.ru nxt_cache_lvlhsh_test, 54*0Sigor@sysoev.ru (nxt_lvlhsh_alloc_t) nxt_cache_shm_alloc, 55*0Sigor@sysoev.ru (nxt_lvlhsh_free_t) nxt_mem_zone_free, 56*0Sigor@sysoev.ru }; 57*0Sigor@sysoev.ru 58*0Sigor@sysoev.ru cache = nxt_mem_zone_zalloc(mz, sizeof(nxt_cache_t)); 59*0Sigor@sysoev.ru 60*0Sigor@sysoev.ru if (cache == NULL) { 61*0Sigor@sysoev.ru return NXT_ERROR; 62*0Sigor@sysoev.ru } 63*0Sigor@sysoev.ru 64*0Sigor@sysoev.ru cache->proto = &proto; 65*0Sigor@sysoev.ru cache->pool = mz; 66*0Sigor@sysoev.ru 67*0Sigor@sysoev.ru cache->start_time = nxt_cache_time(nxt_thread()); 68*0Sigor@sysoev.ru 69*0Sigor@sysoev.ru return NXT_OK; 70*0Sigor@sysoev.ru } 71*0Sigor@sysoev.ru 72*0Sigor@sysoev.ru 73*0Sigor@sysoev.ru static void * 74*0Sigor@sysoev.ru nxt_cache_shm_alloc(void *data, size_t size, nxt_uint_t nalloc) 75*0Sigor@sysoev.ru { 76*0Sigor@sysoev.ru return nxt_mem_zone_align(data, size, size); 77*0Sigor@sysoev.ru } 78*0Sigor@sysoev.ru 79*0Sigor@sysoev.ru 80*0Sigor@sysoev.ru void 81*0Sigor@sysoev.ru nxt_cache_init(nxt_cache_t *cache) 82*0Sigor@sysoev.ru { 83*0Sigor@sysoev.ru static const nxt_lvlhsh_proto_t proto nxt_aligned(64) = { 84*0Sigor@sysoev.ru NXT_LVLHSH_LARGE_MEMALIGN, 85*0Sigor@sysoev.ru 0, 86*0Sigor@sysoev.ru nxt_cache_lvlhsh_test, 87*0Sigor@sysoev.ru nxt_lvlhsh_alloc, 88*0Sigor@sysoev.ru nxt_lvlhsh_free, 89*0Sigor@sysoev.ru }; 90*0Sigor@sysoev.ru 91*0Sigor@sysoev.ru cache->proto = &proto; 92*0Sigor@sysoev.ru 93*0Sigor@sysoev.ru cache->start_time = nxt_cache_time(nxt_thread()); 94*0Sigor@sysoev.ru } 95*0Sigor@sysoev.ru 96*0Sigor@sysoev.ru 97*0Sigor@sysoev.ru static nxt_int_t 98*0Sigor@sysoev.ru nxt_cache_lvlhsh_test(nxt_lvlhsh_query_t *lhq, void *data) 99*0Sigor@sysoev.ru { 100*0Sigor@sysoev.ru nxt_cache_node_t *node; 101*0Sigor@sysoev.ru 102*0Sigor@sysoev.ru node = data; 103*0Sigor@sysoev.ru 104*0Sigor@sysoev.ru if (nxt_str_eq(&lhq->key, node->key_data, node->key_len)) { 105*0Sigor@sysoev.ru return NXT_OK; 106*0Sigor@sysoev.ru } 107*0Sigor@sysoev.ru 108*0Sigor@sysoev.ru return NXT_DECLINED; 109*0Sigor@sysoev.ru } 110*0Sigor@sysoev.ru 111*0Sigor@sysoev.ru 112*0Sigor@sysoev.ru nxt_inline void 113*0Sigor@sysoev.ru nxt_cache_lock(nxt_cache_t *cache) 114*0Sigor@sysoev.ru { 115*0Sigor@sysoev.ru if (cache->shared) { 116*0Sigor@sysoev.ru nxt_thread_spin_lock(&cache->lock); 117*0Sigor@sysoev.ru } 118*0Sigor@sysoev.ru } 119*0Sigor@sysoev.ru 120*0Sigor@sysoev.ru 121*0Sigor@sysoev.ru nxt_inline void 122*0Sigor@sysoev.ru nxt_cache_unlock(nxt_cache_t *cache) 123*0Sigor@sysoev.ru { 124*0Sigor@sysoev.ru if (cache->shared) { 125*0Sigor@sysoev.ru nxt_thread_spin_unlock(&cache->lock); 126*0Sigor@sysoev.ru } 127*0Sigor@sysoev.ru } 128*0Sigor@sysoev.ru 129*0Sigor@sysoev.ru 130*0Sigor@sysoev.ru void 131*0Sigor@sysoev.ru nxt_cache_query(nxt_cache_t *cache, nxt_cache_query_t *q) 132*0Sigor@sysoev.ru { 133*0Sigor@sysoev.ru nxt_thread_t *thr; 134*0Sigor@sysoev.ru nxt_lvlhsh_query_t lhq; 135*0Sigor@sysoev.ru nxt_work_handler_t handler; 136*0Sigor@sysoev.ru 137*0Sigor@sysoev.ru thr = nxt_thread(); 138*0Sigor@sysoev.ru 139*0Sigor@sysoev.ru if (cache != NULL) { 140*0Sigor@sysoev.ru lhq.key_hash = nxt_murmur_hash2(q->key_data, q->key_len); 141*0Sigor@sysoev.ru lhq.replace = 0; 142*0Sigor@sysoev.ru lhq.key.len = q->key_len; 143*0Sigor@sysoev.ru lhq.key.data = q->key_data; 144*0Sigor@sysoev.ru lhq.proto = cache->proto; 145*0Sigor@sysoev.ru lhq.pool = cache->pool; 146*0Sigor@sysoev.ru 147*0Sigor@sysoev.ru q->now = nxt_cache_time(thr); 148*0Sigor@sysoev.ru 149*0Sigor@sysoev.ru nxt_cache_lock(cache); 150*0Sigor@sysoev.ru 151*0Sigor@sysoev.ru handler = nxt_cache_query_locked(cache, q, &lhq); 152*0Sigor@sysoev.ru 153*0Sigor@sysoev.ru nxt_cache_unlock(cache); 154*0Sigor@sysoev.ru 155*0Sigor@sysoev.ru } else { 156*0Sigor@sysoev.ru handler = q->state->nocache_handler; 157*0Sigor@sysoev.ru } 158*0Sigor@sysoev.ru 159*0Sigor@sysoev.ru handler(thr, q, NULL); 160*0Sigor@sysoev.ru } 161*0Sigor@sysoev.ru 162*0Sigor@sysoev.ru 163*0Sigor@sysoev.ru static nxt_work_handler_t 164*0Sigor@sysoev.ru nxt_cache_query_locked(nxt_cache_t *cache, nxt_cache_query_t *q, 165*0Sigor@sysoev.ru nxt_lvlhsh_query_t *lhq) 166*0Sigor@sysoev.ru { 167*0Sigor@sysoev.ru nxt_int_t ret; 168*0Sigor@sysoev.ru nxt_time_t expiry; 169*0Sigor@sysoev.ru nxt_cache_node_t *node; 170*0Sigor@sysoev.ru nxt_cache_query_state_t *state; 171*0Sigor@sysoev.ru 172*0Sigor@sysoev.ru if (q->hold) { 173*0Sigor@sysoev.ru return nxt_cache_node_hold(cache, q, lhq); 174*0Sigor@sysoev.ru } 175*0Sigor@sysoev.ru 176*0Sigor@sysoev.ru ret = nxt_lvlhsh_find(&cache->lvlhsh, lhq); 177*0Sigor@sysoev.ru 178*0Sigor@sysoev.ru state = q->state; 179*0Sigor@sysoev.ru 180*0Sigor@sysoev.ru if (ret != NXT_OK) { 181*0Sigor@sysoev.ru /* NXT_DECLINED */ 182*0Sigor@sysoev.ru return state->nocache_handler; 183*0Sigor@sysoev.ru } 184*0Sigor@sysoev.ru 185*0Sigor@sysoev.ru node = lhq->value; 186*0Sigor@sysoev.ru node->count++; 187*0Sigor@sysoev.ru q->node = node; 188*0Sigor@sysoev.ru 189*0Sigor@sysoev.ru expiry = cache->start_time + node->expiry; 190*0Sigor@sysoev.ru 191*0Sigor@sysoev.ru if (q->now < expiry) { 192*0Sigor@sysoev.ru return state->ready_handler; 193*0Sigor@sysoev.ru } 194*0Sigor@sysoev.ru 195*0Sigor@sysoev.ru q->stale = 1; 196*0Sigor@sysoev.ru 197*0Sigor@sysoev.ru return state->stale_handler; 198*0Sigor@sysoev.ru } 199*0Sigor@sysoev.ru 200*0Sigor@sysoev.ru 201*0Sigor@sysoev.ru static nxt_work_handler_t 202*0Sigor@sysoev.ru nxt_cache_node_hold(nxt_cache_t *cache, nxt_cache_query_t *q, 203*0Sigor@sysoev.ru nxt_lvlhsh_query_t *lhq) 204*0Sigor@sysoev.ru { 205*0Sigor@sysoev.ru nxt_int_t ret; 206*0Sigor@sysoev.ru nxt_bool_t slow; 207*0Sigor@sysoev.ru nxt_cache_node_t *node, *sentinel; 208*0Sigor@sysoev.ru nxt_work_handler_t handler; 209*0Sigor@sysoev.ru nxt_cache_query_wait_t *qw; 210*0Sigor@sysoev.ru nxt_cache_query_state_t *state; 211*0Sigor@sysoev.ru 212*0Sigor@sysoev.ru state = q->state; 213*0Sigor@sysoev.ru sentinel = nxt_cache_node_alloc(cache); 214*0Sigor@sysoev.ru 215*0Sigor@sysoev.ru if (nxt_slow_path(sentinel == NULL)) { 216*0Sigor@sysoev.ru return state->error_handler; 217*0Sigor@sysoev.ru } 218*0Sigor@sysoev.ru 219*0Sigor@sysoev.ru sentinel->key_data = q->key_data; 220*0Sigor@sysoev.ru sentinel->key_len = q->key_len; 221*0Sigor@sysoev.ru lhq->value = sentinel; 222*0Sigor@sysoev.ru 223*0Sigor@sysoev.ru /* 224*0Sigor@sysoev.ru * Try to insert an empty sentinel node to hold updating 225*0Sigor@sysoev.ru * process if there is no existent cache node in cache. 226*0Sigor@sysoev.ru */ 227*0Sigor@sysoev.ru ret = nxt_lvlhsh_insert(&cache->lvlhsh, lhq); 228*0Sigor@sysoev.ru 229*0Sigor@sysoev.ru if (ret == NXT_OK) { 230*0Sigor@sysoev.ru /* The sentinel node was successully added. */ 231*0Sigor@sysoev.ru 232*0Sigor@sysoev.ru q->node = sentinel; 233*0Sigor@sysoev.ru sentinel->updating = 1; 234*0Sigor@sysoev.ru return state->update_handler; 235*0Sigor@sysoev.ru } 236*0Sigor@sysoev.ru 237*0Sigor@sysoev.ru nxt_cache_node_free(cache, sentinel, 1); 238*0Sigor@sysoev.ru 239*0Sigor@sysoev.ru if (ret == NXT_ERROR) { 240*0Sigor@sysoev.ru return state->error_handler; 241*0Sigor@sysoev.ru } 242*0Sigor@sysoev.ru 243*0Sigor@sysoev.ru /* NXT_DECLINED: a cache node exists. */ 244*0Sigor@sysoev.ru 245*0Sigor@sysoev.ru node = lhq->value; 246*0Sigor@sysoev.ru node->count++; 247*0Sigor@sysoev.ru q->node = node; 248*0Sigor@sysoev.ru 249*0Sigor@sysoev.ru handler = nxt_cache_node_test(cache, q); 250*0Sigor@sysoev.ru if (handler != NULL) { 251*0Sigor@sysoev.ru return handler; 252*0Sigor@sysoev.ru } 253*0Sigor@sysoev.ru 254*0Sigor@sysoev.ru /* Add the node to a wait queue. */ 255*0Sigor@sysoev.ru 256*0Sigor@sysoev.ru qw = nxt_cache_query_wait_alloc(cache, &slow); 257*0Sigor@sysoev.ru if (nxt_slow_path(qw == NULL)) { 258*0Sigor@sysoev.ru return state->error_handler; 259*0Sigor@sysoev.ru } 260*0Sigor@sysoev.ru 261*0Sigor@sysoev.ru if (slow) { 262*0Sigor@sysoev.ru /* The node state may have been changed during slow allocation. */ 263*0Sigor@sysoev.ru 264*0Sigor@sysoev.ru handler = nxt_cache_node_test(cache, q); 265*0Sigor@sysoev.ru if (handler != NULL) { 266*0Sigor@sysoev.ru nxt_cache_query_wait_free(cache, qw); 267*0Sigor@sysoev.ru return handler; 268*0Sigor@sysoev.ru } 269*0Sigor@sysoev.ru } 270*0Sigor@sysoev.ru 271*0Sigor@sysoev.ru qw->query = q; 272*0Sigor@sysoev.ru qw->next = node->waiting; 273*0Sigor@sysoev.ru qw->busy = 0; 274*0Sigor@sysoev.ru qw->deleted = 0; 275*0Sigor@sysoev.ru qw->pid = nxt_pid; 276*0Sigor@sysoev.ru qw->engine = nxt_thread_event_engine(); 277*0Sigor@sysoev.ru qw->handler = nxt_cache_wake_handler; 278*0Sigor@sysoev.ru qw->cache = cache; 279*0Sigor@sysoev.ru 280*0Sigor@sysoev.ru node->waiting = qw; 281*0Sigor@sysoev.ru 282*0Sigor@sysoev.ru return nxt_cache_wait_handler; 283*0Sigor@sysoev.ru } 284*0Sigor@sysoev.ru 285*0Sigor@sysoev.ru 286*0Sigor@sysoev.ru static nxt_work_handler_t 287*0Sigor@sysoev.ru nxt_cache_node_test(nxt_cache_t *cache, nxt_cache_query_t *q) 288*0Sigor@sysoev.ru { 289*0Sigor@sysoev.ru nxt_time_t expiry; 290*0Sigor@sysoev.ru nxt_cache_node_t *node; 291*0Sigor@sysoev.ru nxt_cache_query_state_t *state; 292*0Sigor@sysoev.ru 293*0Sigor@sysoev.ru q->stale = 0; 294*0Sigor@sysoev.ru state = q->state; 295*0Sigor@sysoev.ru node = q->node; 296*0Sigor@sysoev.ru 297*0Sigor@sysoev.ru expiry = cache->start_time + node->expiry; 298*0Sigor@sysoev.ru 299*0Sigor@sysoev.ru if (q->now < expiry) { 300*0Sigor@sysoev.ru return state->ready_handler; 301*0Sigor@sysoev.ru } 302*0Sigor@sysoev.ru 303*0Sigor@sysoev.ru /* 304*0Sigor@sysoev.ru * A valid stale or empty sentinel cache node. 305*0Sigor@sysoev.ru * The sentinel node can be only in updating state. 306*0Sigor@sysoev.ru */ 307*0Sigor@sysoev.ru 308*0Sigor@sysoev.ru if (node->updating) { 309*0Sigor@sysoev.ru 310*0Sigor@sysoev.ru if (node->expiry != 0) { 311*0Sigor@sysoev.ru /* A valid stale cache node. */ 312*0Sigor@sysoev.ru 313*0Sigor@sysoev.ru q->stale = 1; 314*0Sigor@sysoev.ru 315*0Sigor@sysoev.ru if (q->use_stale) { 316*0Sigor@sysoev.ru return state->stale_handler; 317*0Sigor@sysoev.ru } 318*0Sigor@sysoev.ru } 319*0Sigor@sysoev.ru 320*0Sigor@sysoev.ru /* A sentinel node. */ 321*0Sigor@sysoev.ru return NULL; 322*0Sigor@sysoev.ru } 323*0Sigor@sysoev.ru 324*0Sigor@sysoev.ru /* A valid stale cache node is not being updated now. */ 325*0Sigor@sysoev.ru 326*0Sigor@sysoev.ru q->stale = 1; 327*0Sigor@sysoev.ru 328*0Sigor@sysoev.ru if (q->use_stale) { 329*0Sigor@sysoev.ru 330*0Sigor@sysoev.ru if (q->update_stale) { 331*0Sigor@sysoev.ru node->updating = 1; 332*0Sigor@sysoev.ru return state->update_stale_handler; 333*0Sigor@sysoev.ru } 334*0Sigor@sysoev.ru 335*0Sigor@sysoev.ru return state->stale_handler; 336*0Sigor@sysoev.ru } 337*0Sigor@sysoev.ru 338*0Sigor@sysoev.ru node->updating = 1; 339*0Sigor@sysoev.ru return state->update_handler; 340*0Sigor@sysoev.ru } 341*0Sigor@sysoev.ru 342*0Sigor@sysoev.ru 343*0Sigor@sysoev.ru static void 344*0Sigor@sysoev.ru nxt_cache_wait_handler(nxt_thread_t *thr, void *obj, void *data) 345*0Sigor@sysoev.ru { 346*0Sigor@sysoev.ru nxt_event_timer_t *ev; 347*0Sigor@sysoev.ru nxt_cache_query_t *cq; 348*0Sigor@sysoev.ru 349*0Sigor@sysoev.ru cq = obj; 350*0Sigor@sysoev.ru 351*0Sigor@sysoev.ru if (cq->timeout != 0) { 352*0Sigor@sysoev.ru 353*0Sigor@sysoev.ru ev = &cq->timer; 354*0Sigor@sysoev.ru 355*0Sigor@sysoev.ru if (ev->state == NXT_EVENT_TIMER_DISABLED) { 356*0Sigor@sysoev.ru ev->handler = nxt_cache_timeout_handler; 357*0Sigor@sysoev.ru nxt_event_timer_ident(ev, -1); 358*0Sigor@sysoev.ru 359*0Sigor@sysoev.ru nxt_event_timer_add(thr->engine, ev, cq->timeout); 360*0Sigor@sysoev.ru } 361*0Sigor@sysoev.ru } 362*0Sigor@sysoev.ru } 363*0Sigor@sysoev.ru 364*0Sigor@sysoev.ru 365*0Sigor@sysoev.ru static void 366*0Sigor@sysoev.ru nxt_cache_timeout_handler(nxt_thread_t *thr, void *obj, void *data) 367*0Sigor@sysoev.ru { 368*0Sigor@sysoev.ru nxt_cache_query_t *cq; 369*0Sigor@sysoev.ru nxt_event_timer_t *ev; 370*0Sigor@sysoev.ru 371*0Sigor@sysoev.ru ev = obj; 372*0Sigor@sysoev.ru 373*0Sigor@sysoev.ru cq = nxt_event_timer_data(ev, nxt_cache_query_t, timer); 374*0Sigor@sysoev.ru 375*0Sigor@sysoev.ru cq->state->timeout_handler(thr, cq, NULL); 376*0Sigor@sysoev.ru } 377*0Sigor@sysoev.ru 378*0Sigor@sysoev.ru 379*0Sigor@sysoev.ru static void 380*0Sigor@sysoev.ru nxt_cache_wake_handler(nxt_thread_t *thr, void *obj, void *data) 381*0Sigor@sysoev.ru { 382*0Sigor@sysoev.ru nxt_cache_t *cache; 383*0Sigor@sysoev.ru nxt_work_handler_t handler; 384*0Sigor@sysoev.ru nxt_cache_query_t *q; 385*0Sigor@sysoev.ru nxt_cache_query_wait_t *qw; 386*0Sigor@sysoev.ru 387*0Sigor@sysoev.ru qw = obj; 388*0Sigor@sysoev.ru q = qw->query; 389*0Sigor@sysoev.ru cache = qw->cache; 390*0Sigor@sysoev.ru 391*0Sigor@sysoev.ru nxt_cache_lock(cache); 392*0Sigor@sysoev.ru 393*0Sigor@sysoev.ru handler = nxt_cache_node_test(cache, q); 394*0Sigor@sysoev.ru 395*0Sigor@sysoev.ru if (handler != NULL) { 396*0Sigor@sysoev.ru nxt_cache_query_wait_free(cache, qw); 397*0Sigor@sysoev.ru 398*0Sigor@sysoev.ru } else { 399*0Sigor@sysoev.ru /* Wait again. */ 400*0Sigor@sysoev.ru qw->next = q->node->waiting; 401*0Sigor@sysoev.ru q->node->waiting = qw; 402*0Sigor@sysoev.ru } 403*0Sigor@sysoev.ru 404*0Sigor@sysoev.ru nxt_cache_unlock(cache); 405*0Sigor@sysoev.ru 406*0Sigor@sysoev.ru handler(thr, q, NULL); 407*0Sigor@sysoev.ru } 408*0Sigor@sysoev.ru 409*0Sigor@sysoev.ru 410*0Sigor@sysoev.ru nxt_int_t 411*0Sigor@sysoev.ru nxt_cache_update(nxt_cache_t *cache, nxt_cache_query_t *q) 412*0Sigor@sysoev.ru { 413*0Sigor@sysoev.ru nxt_int_t ret; 414*0Sigor@sysoev.ru nxt_cache_node_t *node; 415*0Sigor@sysoev.ru nxt_lvlhsh_query_t lhq; 416*0Sigor@sysoev.ru 417*0Sigor@sysoev.ru node = q->node; 418*0Sigor@sysoev.ru 419*0Sigor@sysoev.ru node->accessed = nxt_cache_time(nxt_thread()) - cache->start_time; 420*0Sigor@sysoev.ru 421*0Sigor@sysoev.ru node->updating = 0; 422*0Sigor@sysoev.ru node->count = 1; 423*0Sigor@sysoev.ru 424*0Sigor@sysoev.ru lhq.key_hash = nxt_murmur_hash2(node->key_data, node->key_len); 425*0Sigor@sysoev.ru lhq.replace = 1; 426*0Sigor@sysoev.ru lhq.key.len = node->key_len; 427*0Sigor@sysoev.ru lhq.key.data = node->key_data; 428*0Sigor@sysoev.ru lhq.value = node; 429*0Sigor@sysoev.ru lhq.proto = cache->proto; 430*0Sigor@sysoev.ru lhq.pool = cache->pool; 431*0Sigor@sysoev.ru 432*0Sigor@sysoev.ru nxt_cache_lock(cache); 433*0Sigor@sysoev.ru 434*0Sigor@sysoev.ru ret = nxt_lvlhsh_insert(&cache->lvlhsh, &lhq); 435*0Sigor@sysoev.ru 436*0Sigor@sysoev.ru if (nxt_fast_path(ret != NXT_OK)) { 437*0Sigor@sysoev.ru 438*0Sigor@sysoev.ru nxt_queue_insert_head(&cache->expiry_queue, &node->link); 439*0Sigor@sysoev.ru 440*0Sigor@sysoev.ru node = lhq.value; 441*0Sigor@sysoev.ru 442*0Sigor@sysoev.ru if (node != NULL) { 443*0Sigor@sysoev.ru /* A replaced node. */ 444*0Sigor@sysoev.ru 445*0Sigor@sysoev.ru nxt_queue_remove(&node->link); 446*0Sigor@sysoev.ru 447*0Sigor@sysoev.ru if (node->count != 0) { 448*0Sigor@sysoev.ru node->deleted = 1; 449*0Sigor@sysoev.ru 450*0Sigor@sysoev.ru } else { 451*0Sigor@sysoev.ru // delete cache node 452*0Sigor@sysoev.ru } 453*0Sigor@sysoev.ru } 454*0Sigor@sysoev.ru } 455*0Sigor@sysoev.ru 456*0Sigor@sysoev.ru nxt_cache_unlock(cache); 457*0Sigor@sysoev.ru 458*0Sigor@sysoev.ru return ret; 459*0Sigor@sysoev.ru } 460*0Sigor@sysoev.ru 461*0Sigor@sysoev.ru 462*0Sigor@sysoev.ru void 463*0Sigor@sysoev.ru nxt_cache_release(nxt_cache_t *cache, nxt_cache_query_t *q) 464*0Sigor@sysoev.ru { 465*0Sigor@sysoev.ru u_char *p, *data; 466*0Sigor@sysoev.ru size_t size; 467*0Sigor@sysoev.ru ssize_t ret; 468*0Sigor@sysoev.ru nxt_thread_t *thr; 469*0Sigor@sysoev.ru u_char buf[1024]; 470*0Sigor@sysoev.ru 471*0Sigor@sysoev.ru thr = nxt_thread(); 472*0Sigor@sysoev.ru q->now = nxt_cache_time(thr); 473*0Sigor@sysoev.ru 474*0Sigor@sysoev.ru p = buf; 475*0Sigor@sysoev.ru size = sizeof(buf); 476*0Sigor@sysoev.ru 477*0Sigor@sysoev.ru for ( ;; ) { 478*0Sigor@sysoev.ru nxt_cache_lock(cache); 479*0Sigor@sysoev.ru 480*0Sigor@sysoev.ru ret = nxt_cache_release_locked(cache, q, p, size); 481*0Sigor@sysoev.ru 482*0Sigor@sysoev.ru nxt_cache_unlock(cache); 483*0Sigor@sysoev.ru 484*0Sigor@sysoev.ru if (ret == 0) { 485*0Sigor@sysoev.ru return; 486*0Sigor@sysoev.ru } 487*0Sigor@sysoev.ru 488*0Sigor@sysoev.ru size = nxt_abs(ret); 489*0Sigor@sysoev.ru 490*0Sigor@sysoev.ru data = nxt_malloc(size); 491*0Sigor@sysoev.ru 492*0Sigor@sysoev.ru if (data == NULL) { 493*0Sigor@sysoev.ru /* TODO: retry */ 494*0Sigor@sysoev.ru return; 495*0Sigor@sysoev.ru } 496*0Sigor@sysoev.ru 497*0Sigor@sysoev.ru if (ret < 0) { 498*0Sigor@sysoev.ru p = data; 499*0Sigor@sysoev.ru continue; 500*0Sigor@sysoev.ru } 501*0Sigor@sysoev.ru 502*0Sigor@sysoev.ru if (p != data) { 503*0Sigor@sysoev.ru nxt_memcpy(data, p, size); 504*0Sigor@sysoev.ru } 505*0Sigor@sysoev.ru 506*0Sigor@sysoev.ru nxt_thread_work_queue_add(thr, &thr->work_queue.main, 507*0Sigor@sysoev.ru cache->delete_handler, data, NULL, thr->log); 508*0Sigor@sysoev.ru } 509*0Sigor@sysoev.ru } 510*0Sigor@sysoev.ru 511*0Sigor@sysoev.ru 512*0Sigor@sysoev.ru static ssize_t 513*0Sigor@sysoev.ru nxt_cache_release_locked(nxt_cache_t *cache, nxt_cache_query_t *q, 514*0Sigor@sysoev.ru u_char *buf, size_t size) 515*0Sigor@sysoev.ru { 516*0Sigor@sysoev.ru ssize_t ret; 517*0Sigor@sysoev.ru nxt_cache_node_t *node; 518*0Sigor@sysoev.ru 519*0Sigor@sysoev.ru node = q->node; 520*0Sigor@sysoev.ru node->count--; 521*0Sigor@sysoev.ru 522*0Sigor@sysoev.ru if (node->count != 0) { 523*0Sigor@sysoev.ru return 0; 524*0Sigor@sysoev.ru } 525*0Sigor@sysoev.ru 526*0Sigor@sysoev.ru if (!node->deleted) { 527*0Sigor@sysoev.ru /* 528*0Sigor@sysoev.ru * A cache node is locked whilst its count is non zero. 529*0Sigor@sysoev.ru * To minimize number of operations the node's place in expiry 530*0Sigor@sysoev.ru * queue can be updated only if the node is not currently used. 531*0Sigor@sysoev.ru */ 532*0Sigor@sysoev.ru node->accessed = q->now - cache->start_time; 533*0Sigor@sysoev.ru 534*0Sigor@sysoev.ru nxt_queue_remove(&node->link); 535*0Sigor@sysoev.ru nxt_queue_insert_head(&cache->expiry_queue, &node->link); 536*0Sigor@sysoev.ru 537*0Sigor@sysoev.ru return 0; 538*0Sigor@sysoev.ru } 539*0Sigor@sysoev.ru 540*0Sigor@sysoev.ru ret = 0; 541*0Sigor@sysoev.ru #if 0 542*0Sigor@sysoev.ru 543*0Sigor@sysoev.ru ret = cache->delete_copy(cache, node, buf, size); 544*0Sigor@sysoev.ru 545*0Sigor@sysoev.ru if (ret < 0) { 546*0Sigor@sysoev.ru return ret; 547*0Sigor@sysoev.ru } 548*0Sigor@sysoev.ru 549*0Sigor@sysoev.ru #endif 550*0Sigor@sysoev.ru 551*0Sigor@sysoev.ru nxt_cache_node_free(cache, node, 0); 552*0Sigor@sysoev.ru 553*0Sigor@sysoev.ru return ret; 554*0Sigor@sysoev.ru } 555*0Sigor@sysoev.ru 556*0Sigor@sysoev.ru 557*0Sigor@sysoev.ru static nxt_cache_node_t * 558*0Sigor@sysoev.ru nxt_cache_node_alloc(nxt_cache_t *cache) 559*0Sigor@sysoev.ru { 560*0Sigor@sysoev.ru nxt_queue_link_t *link; 561*0Sigor@sysoev.ru nxt_cache_node_t *node; 562*0Sigor@sysoev.ru 563*0Sigor@sysoev.ru link = nxt_queue_first(&cache->free_nodes); 564*0Sigor@sysoev.ru 565*0Sigor@sysoev.ru if (nxt_fast_path(link != nxt_queue_tail(&cache->free_nodes))) { 566*0Sigor@sysoev.ru cache->nfree_nodes--; 567*0Sigor@sysoev.ru nxt_queue_remove(link); 568*0Sigor@sysoev.ru 569*0Sigor@sysoev.ru node = nxt_queue_link_data(link, nxt_cache_node_t, link); 570*0Sigor@sysoev.ru nxt_memzero(node, sizeof(nxt_cache_node_t)); 571*0Sigor@sysoev.ru 572*0Sigor@sysoev.ru return node; 573*0Sigor@sysoev.ru } 574*0Sigor@sysoev.ru 575*0Sigor@sysoev.ru nxt_cache_unlock(cache); 576*0Sigor@sysoev.ru 577*0Sigor@sysoev.ru node = cache->alloc(cache->data, sizeof(nxt_cache_node_t)); 578*0Sigor@sysoev.ru 579*0Sigor@sysoev.ru nxt_cache_lock(cache); 580*0Sigor@sysoev.ru 581*0Sigor@sysoev.ru return node; 582*0Sigor@sysoev.ru } 583*0Sigor@sysoev.ru 584*0Sigor@sysoev.ru 585*0Sigor@sysoev.ru static void 586*0Sigor@sysoev.ru nxt_cache_node_free(nxt_cache_t *cache, nxt_cache_node_t *node, nxt_bool_t fast) 587*0Sigor@sysoev.ru { 588*0Sigor@sysoev.ru if (fast || cache->nfree_nodes < 32) { 589*0Sigor@sysoev.ru nxt_queue_insert_head(&cache->free_nodes, &node->link); 590*0Sigor@sysoev.ru cache->nfree_nodes++; 591*0Sigor@sysoev.ru return; 592*0Sigor@sysoev.ru } 593*0Sigor@sysoev.ru 594*0Sigor@sysoev.ru nxt_cache_unlock(cache); 595*0Sigor@sysoev.ru 596*0Sigor@sysoev.ru cache->free(cache->data, node); 597*0Sigor@sysoev.ru 598*0Sigor@sysoev.ru nxt_cache_lock(cache); 599*0Sigor@sysoev.ru } 600*0Sigor@sysoev.ru 601*0Sigor@sysoev.ru 602*0Sigor@sysoev.ru static nxt_cache_query_wait_t * 603*0Sigor@sysoev.ru nxt_cache_query_wait_alloc(nxt_cache_t *cache, nxt_bool_t *slow) 604*0Sigor@sysoev.ru { 605*0Sigor@sysoev.ru nxt_cache_query_wait_t *qw; 606*0Sigor@sysoev.ru 607*0Sigor@sysoev.ru qw = cache->free_query_wait; 608*0Sigor@sysoev.ru 609*0Sigor@sysoev.ru if (nxt_fast_path(qw != NULL)) { 610*0Sigor@sysoev.ru cache->free_query_wait = qw->next; 611*0Sigor@sysoev.ru cache->nfree_query_wait--; 612*0Sigor@sysoev.ru 613*0Sigor@sysoev.ru *slow = 0; 614*0Sigor@sysoev.ru return qw; 615*0Sigor@sysoev.ru } 616*0Sigor@sysoev.ru 617*0Sigor@sysoev.ru nxt_cache_unlock(cache); 618*0Sigor@sysoev.ru 619*0Sigor@sysoev.ru qw = cache->alloc(cache->data, sizeof(nxt_cache_query_wait_t)); 620*0Sigor@sysoev.ru *slow = 1; 621*0Sigor@sysoev.ru 622*0Sigor@sysoev.ru nxt_cache_lock(cache); 623*0Sigor@sysoev.ru 624*0Sigor@sysoev.ru return qw; 625*0Sigor@sysoev.ru } 626*0Sigor@sysoev.ru 627*0Sigor@sysoev.ru 628*0Sigor@sysoev.ru static void 629*0Sigor@sysoev.ru nxt_cache_query_wait_free(nxt_cache_t *cache, nxt_cache_query_wait_t *qw) 630*0Sigor@sysoev.ru { 631*0Sigor@sysoev.ru if (cache->nfree_query_wait < 32) { 632*0Sigor@sysoev.ru qw->next = cache->free_query_wait; 633*0Sigor@sysoev.ru cache->free_query_wait = qw; 634*0Sigor@sysoev.ru cache->nfree_query_wait++; 635*0Sigor@sysoev.ru return; 636*0Sigor@sysoev.ru } 637*0Sigor@sysoev.ru 638*0Sigor@sysoev.ru nxt_cache_unlock(cache); 639*0Sigor@sysoev.ru 640*0Sigor@sysoev.ru cache->free(cache->data, qw); 641*0Sigor@sysoev.ru 642*0Sigor@sysoev.ru nxt_cache_lock(cache); 643*0Sigor@sysoev.ru } 644