void ngx_http_tfs_rc_server_expire(ngx_http_tfs_rc_ctx_t *ctx) { ngx_queue_t *q, *kp_q; ngx_rbtree_node_t *node; ngx_http_tfs_rcs_info_t *rc_info_node; if (ngx_queue_empty(&ctx->sh->queue)) { return; } q = ngx_queue_last(&ctx->sh->queue); rc_info_node = ngx_queue_data(q, ngx_http_tfs_rcs_info_t, queue); kp_q = &rc_info_node->kp_queue; ngx_queue_remove(q); ngx_queue_remove(kp_q); node = (ngx_rbtree_node_t *) ((u_char *) rc_info_node - offsetof(ngx_rbtree_node_t, color)); ngx_rbtree_delete(&ctx->sh->rbtree, node); ngx_http_tfs_rc_server_destroy_node(ctx, rc_info_node); }
static ngx_int_t ngx_http_tfs_create_info_node(ngx_http_tfs_t *t, ngx_http_tfs_rc_ctx_t *rc_ctx, u_char *data, ngx_str_t appkey) { u_char *p; size_t n; uint32_t len; ngx_int_t rc; ngx_rbtree_node_t *node; ngx_http_tfs_rcs_info_t *rc_info_node; rc_info_node = NULL; n = offsetof(ngx_rbtree_node_t, color) + sizeof(ngx_http_tfs_rcs_info_t); node = ngx_slab_alloc_locked(rc_ctx->shpool, n); if (node == NULL) { ngx_http_tfs_expire_and_alloc(node, n); } rc_info_node = (ngx_http_tfs_rcs_info_t *) &node->color; node->key = ngx_murmur_hash2(appkey.data, appkey.len); rc_info_node->appkey.data = ngx_slab_alloc_locked(rc_ctx->shpool, appkey.len); if (rc_info_node->appkey.data == NULL) { ngx_http_tfs_rc_server_expire(rc_ctx); rc_info_node->appkey.data = ngx_slab_alloc_locked(rc_ctx->shpool, appkey.len); if (rc_info_node->appkey.data == NULL) { goto login_error; } } ngx_memcpy(rc_info_node->appkey.data, appkey.data, appkey.len); rc_info_node->appkey.len = appkey.len; /* parse session id */ len = *((uint32_t *) data); p = data + sizeof(uint32_t); if (len <= 0) { rc_info_node->session_id.len = 0; goto login_error; } rc_info_node->session_id.len = len - 1; rc_info_node->session_id.data = ngx_slab_alloc_locked(rc_ctx->shpool, len); if (rc_info_node->session_id.data == NULL) { ngx_http_tfs_rc_server_expire(rc_ctx); rc_info_node->session_id.data = ngx_slab_alloc_locked(rc_ctx->shpool, rc_info_node->session_id.len); if (rc_info_node->session_id.data == NULL) { goto login_error; } } ngx_memcpy(rc_info_node->session_id.data, p, rc_info_node->session_id.len); p += rc_info_node->session_id.len + 1; /* parse rc info */ rc = ngx_http_tfs_parse_rc_info(rc_info_node, rc_ctx, p); if (rc == NGX_ERROR) { goto login_error; } t->rc_info_node = rc_info_node; ngx_rbtree_insert(&rc_ctx->sh->rbtree, node); ngx_queue_insert_head(&rc_ctx->sh->queue, &rc_info_node->queue); ngx_queue_insert_tail(&rc_ctx->sh->kp_queue, &rc_info_node->kp_queue); return NGX_OK; login_error: ngx_http_tfs_rc_server_destroy_node(rc_ctx, rc_info_node); t->rc_info_node = NULL; return NGX_ERROR; }
ngx_int_t ngx_http_tfs_parse_keepalive_message(ngx_http_tfs_t *t) { u_char *p, update; uint16_t type; ngx_str_t err_msg; ngx_int_t rc; ngx_queue_t *q, *queue; ngx_rbtree_node_t *node; ngx_http_tfs_header_t *header; ngx_http_tfs_rc_ctx_t *rc_ctx; ngx_http_tfs_rcs_info_t *rc_info; ngx_http_tfs_peer_connection_t *tp; header = (ngx_http_tfs_header_t *) t->header; tp = t->tfs_peer; type = header->type; switch (type) { case NGX_HTTP_TFS_STATUS_MESSAGE: ngx_str_set(&err_msg, "keepalive rc"); return ngx_http_tfs_status_message(&tp->body_buffer, &err_msg, t->log); } p = tp->body_buffer.pos; update = *p; p++; if (!update) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, t->log, 0, "rc keepalive, update flag: %d", update); } else { ngx_log_error(NGX_LOG_WARN, t->log, 0, "rc keepalive, update flag: %d", update); } rc_ctx = t->main_conf->rc_ctx; queue = &rc_ctx->sh->kp_queue; if (ngx_queue_empty(queue)) { return NGX_ERROR; } q = t->curr_ka_queue; if (q == NULL) { return NGX_ERROR; } t->curr_ka_queue = ngx_queue_next(q); if (update == NGX_HTTP_TFS_NO) { return NGX_OK; } /* FIXME: do not consider rc_info_node being expired, it hardly occurs * e.g. a single rc_info_node occupys nearly 2KB space, * 10MB for tfs_rcs_zone can hold at least 5000 rc_infos. */ rc_info = ngx_queue_data(q, ngx_http_tfs_rcs_info_t, kp_queue); /* update info node */ /* FIXME: sth terrible may happen here if someone has get the rc_info before lock */ ngx_shmtx_lock(&rc_ctx->shpool->mutex); rc = ngx_http_tfs_update_info_node(t, rc_ctx, rc_info, p); /* rc_info has been destroyed, remove from queue and rbtree */ if (rc == NGX_ERROR) { ngx_queue_remove(&rc_info->queue); ngx_queue_remove(&rc_info->kp_queue); node = (ngx_rbtree_node_t *) ((u_char *) rc_info - offsetof(ngx_rbtree_node_t, color)); ngx_rbtree_delete(&rc_ctx->sh->rbtree, node); ngx_http_tfs_rc_server_destroy_node(rc_ctx, rc_info); } ngx_shmtx_unlock(&rc_ctx->shpool->mutex); return rc; }