void
ngx_buffer_cache_reset_stats(ngx_buffer_cache_t* cache)
{
	ngx_shmtx_lock(&cache->shpool->mutex);

	ngx_memzero(&cache->sh->stats, sizeof(cache->sh->stats));

	ngx_shmtx_unlock(&cache->shpool->mutex);
}
static ngx_int_t
ngx_http_vhost_traffic_status_dump_restore_add_node(ngx_event_t *ev,
     ngx_http_vhost_traffic_status_node_t *ovtsn, ngx_str_t *key)
{
    size_t                                 size;
    uint32_t                               hash;
    ngx_slab_pool_t                       *shpool;
    ngx_rbtree_node_t                     *node;
    ngx_http_vhost_traffic_status_ctx_t   *ctx;
    ngx_http_vhost_traffic_status_node_t  *vtsn;

    ctx = ev->data;

    if (key->len == 0) {
        return NGX_ERROR;
    }

    shpool = (ngx_slab_pool_t *) ctx->shm_zone->shm.addr;

    ngx_shmtx_lock(&shpool->mutex);

    /* find node */
    hash = ngx_crc32_short(key->data, key->len);

    node = ngx_http_vhost_traffic_status_node_lookup(ctx->rbtree, key, hash);

    /* copy node */
    if (node == NULL) {
        size = offsetof(ngx_rbtree_node_t, color)
               + offsetof(ngx_http_vhost_traffic_status_node_t, data)
               + key->len;

        node = ngx_slab_alloc_locked(shpool, size);
        if (node == NULL) {
            ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
                          "dump_restore_add_node::ngx_slab_alloc_locked() failed");

            ngx_shmtx_unlock(&shpool->mutex);
            return NGX_ERROR;
        }

        vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color;

        node->key = hash;

        *vtsn = *ovtsn;

        ngx_memcpy(vtsn->data, key->data, key->len);

        ngx_rbtree_insert(ctx->rbtree, node);
    }

    ngx_shmtx_unlock(&shpool->mutex);

    return NGX_OK;
}
/*
 *	添加缓存文件到红黑树和队列中,通过 ngx_http_file_cache_t 结构管理此节点
 */
static ngx_int_t
ngx_http_file_cache_add(ngx_http_file_cache_t *cache, ngx_http_cache_t *c)
{
    ngx_http_file_cache_node_t  *fcn;

    ngx_shmtx_lock(&cache->shpool->mutex);

	//	根据key在二叉树中查找,没有找到添加一个节点到cache中
    fcn = ngx_http_file_cache_lookup(cache, c->key);

    if (fcn == NULL) {

        fcn = ngx_slab_alloc_locked(cache->shpool,
                                    sizeof(ngx_http_file_cache_node_t));
        if (fcn == NULL) {
            ngx_shmtx_unlock(&cache->shpool->mutex);
            return NGX_ERROR;
        }

		//	设置node结点key
        ngx_memcpy((u_char *) &fcn->node.key, c->key, sizeof(ngx_rbtree_key_t));

        ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)],
                   NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t));

		//	当前结点插入到二叉树中
        ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node);

        fcn->uses = 1;
        fcn->count = 0;
        fcn->valid_msec = 0;
        fcn->error = 0;
        fcn->exists = 1;
        fcn->updating = 0;
        fcn->deleting = 0;
        fcn->uniq = 0;
        fcn->valid_sec = 0;
        fcn->body_start = 0;
        fcn->fs_size = c->fs_size;

        cache->sh->size += c->fs_size;

    } else {
        ngx_queue_remove(&fcn->queue);
    }

	//	设置过期时间(当前时间+不活跃时间)
    fcn->expire = ngx_time() + cache->inactive;

	//	插入到队列头部,先插入的在队列的尾部
    ngx_queue_insert_head(&cache->sh->queue, &fcn->queue);

    ngx_shmtx_unlock(&cache->shpool->mutex);

    return NGX_OK;
}
int
ngx_tcp_lua_ffi_shdict_incr(ngx_shm_zone_t *zone, u_char *key,
    size_t key_len, double *value, char **err)
{
    uint32_t                     hash;
    ngx_int_t                    rc;
    ngx_tcp_lua_shdict_ctx_t   *ctx;
    ngx_tcp_lua_shdict_node_t  *sd;
    double                       num;
    u_char                      *p;

    ctx = zone->data;
    hash = ngx_crc32_short(key, key_len);

    dd("looking up key %.*s in shared dict %.*s", (int) key_len, key,
       (int) ctx->name.len, ctx->name.data);

    ngx_shmtx_lock(&ctx->shpool->mutex);
#if 1
    ngx_tcp_lua_shdict_expire(ctx, 1);
#endif
    rc = ngx_tcp_lua_shdict_lookup(zone, hash, key, key_len, &sd);

    dd("shdict lookup returned %d", (int) rc);

    if (rc == NGX_DECLINED || rc == NGX_DONE) {
        ngx_shmtx_unlock(&ctx->shpool->mutex);
        *err = "not found";
        return NGX_ERROR;
    }

    /* rc == NGX_OK */

    if (sd->value_type != LUA_TNUMBER || sd->value_len != sizeof(double)) {
        ngx_shmtx_unlock(&ctx->shpool->mutex);
        *err = "not a number";
        return NGX_ERROR;
    }

    ngx_queue_remove(&sd->queue);
    ngx_queue_insert_head(&ctx->sh->queue, &sd->queue);

    dd("setting value type to %d", (int) sd->value_type);

    p = sd->data + key_len;

    num = *(double *) p;
    num += *value;

    ngx_memcpy(p, (double *) &num, sizeof(double));

    ngx_shmtx_unlock(&ctx->shpool->mutex);

    *value = num;
    return NGX_OK;
}
static ngx_inline void
ngx_http_push_stream_process_worker_message(void)
{
    ngx_http_push_stream_worker_msg_t      *worker_msg, *sentinel;
    ngx_slab_pool_t                        *shpool = (ngx_slab_pool_t *) ngx_http_push_stream_shm_zone->shm.addr;
    ngx_http_push_stream_worker_data_t     *workers_data = ((ngx_http_push_stream_shm_data_t *) ngx_http_push_stream_shm_zone->data)->ipc;
    ngx_http_push_stream_worker_data_t     *thisworker_data = workers_data + ngx_process_slot;


    sentinel = thisworker_data->messages_queue;
    while ((worker_msg = (ngx_http_push_stream_worker_msg_t *) ngx_queue_next(&sentinel->queue)) != sentinel) {
        if (worker_msg->pid == ngx_pid) {
            // everything is okay
            ngx_http_push_stream_respond_to_subscribers(worker_msg->channel, worker_msg->subscribers_sentinel, worker_msg->msg);
        } else {
            // that's quite bad you see. a previous worker died with an undelivered message.
            // but all its subscribers' connections presumably got canned, too. so it's not so bad after all.

            ngx_http_push_stream_pid_queue_t     *channel_worker_sentinel = &worker_msg->channel->workers_with_subscribers;
            ngx_http_push_stream_pid_queue_t     *channel_worker_cur = channel_worker_sentinel;

            ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "push stream module: worker %i intercepted a message intended for another worker process (%i) that probably died", ngx_pid, worker_msg->pid);

            // delete that invalid sucker
            while ((channel_worker_cur != NULL) && (channel_worker_cur = (ngx_http_push_stream_pid_queue_t *) ngx_queue_next(&channel_worker_cur->queue)) != channel_worker_sentinel) {
                if (channel_worker_cur->pid == worker_msg->pid) {
                    ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, "push stream module: reference to worker %i will be removed", worker_msg->pid);
                    ngx_shmtx_lock(&shpool->mutex);
                    ngx_queue_remove(&channel_worker_cur->queue);
                    ngx_slab_free_locked(shpool, channel_worker_cur);
                    ngx_shmtx_unlock(&shpool->mutex);
                    channel_worker_cur = NULL;
                    break;
                }
            }
        }

        // free worker_msg already sent
        ngx_shmtx_lock(&shpool->mutex);
        ngx_http_push_stream_free_worker_message_memory_locked(shpool, worker_msg);
        ngx_shmtx_unlock(&shpool->mutex);
    }
}
//free memory for a message. 
static ngx_inline void ngx_http_push_free_message_locked(ngx_http_push_msg_t *msg, ngx_slab_pool_t *shpool) {
	if(msg->buf->file!=NULL) {
		ngx_shmtx_unlock(&shpool->mutex);
		ngx_close_file(msg->buf->file->fd); //again, carest thou aboutst thine errorests?
		ngx_delete_file(msg->buf->file->name.data); //should I care about deletion errors?
		ngx_shmtx_lock(&shpool->mutex);
	}
	ngx_slab_free_locked(shpool, msg->buf); //separate block, remember?
	ngx_slab_free_locked(shpool, msg);
}
Example #7
0
static ngx_int_t ngx_http_sla_init_zone (ngx_shm_zone_t* shm_zone, void* data)
{
    ngx_str_t            name;
    ngx_http_sla_pool_t* pool     = shm_zone->data;
    ngx_http_sla_pool_t* old_pool = data;

    if (old_pool != NULL) {
        /* идет перезагрузка потомков, пытаемся сохранить старые данные, если пул не менялся */
        pool->shm_pool = old_pool->shm_pool;
        pool->shm_ctx  = old_pool->shm_ctx;

        ngx_shmtx_lock(&pool->shm_pool->mutex);
        pool->generation = pool->shm_ctx->generation;

        if (ngx_http_sla_compare_pools(pool, old_pool) == NGX_OK) {
            /* если пул не менялся, поколение не меняется */
            ngx_shmtx_unlock(&pool->shm_pool->mutex);
            return NGX_OK;
        }
    } else {
        /* первый запуск, аллокация shm */
        pool->shm_pool = (ngx_slab_pool_t*)shm_zone->shm.addr;
        pool->shm_ctx  = ngx_slab_alloc(pool->shm_pool, sizeof(ngx_http_sla_pool_shm_t) * NGX_HTTP_SLA_MAX_COUNTERS_LEN);
        if (pool->shm_ctx == NULL) {
            return NGX_ERROR;
        }

        ngx_shmtx_lock(&pool->shm_pool->mutex);
    }

    /* пул изменился или первый запуск */
    ngx_memzero(pool->shm_ctx, sizeof(ngx_http_sla_pool_shm_t) * NGX_HTTP_SLA_MAX_COUNTERS_LEN);

    ngx_str_set(&name, "all");
    ngx_http_sla_add_counter(pool, &name, 0);

    pool->generation++;
    pool->shm_ctx->generation = pool->generation;

    ngx_shmtx_unlock(&pool->shm_pool->mutex);

    return NGX_OK;
}
static ngx_int_t
ngx_http_req_status_write_filter(ngx_http_request_t *r, off_t bsent)
{
    off_t                                   bytes;
    ngx_uint_t                              i;
    ngx_msec_t                              td;
    ngx_http_req_status_ctx_t              *r_ctx;
    ngx_http_req_status_data_t             *data;
    ngx_http_req_status_zone_node_t        *pzn;
    ngx_http_req_status_main_conf_t        *rmcf;

    r_ctx = ngx_http_get_module_ctx(r, ngx_http_req_status_module);
    if (r_ctx == NULL || r_ctx->req_zones.nelts == 0){
        return NGX_DECLINED;
    }

    rmcf = ngx_http_get_module_main_conf(r, ngx_http_req_status_module);

    pzn = r_ctx->req_zones.elts;

    bytes = r->connection->sent - bsent;

    for (i = 0; i < r_ctx->req_zones.nelts; i++){
        data = &pzn[i].node->data;

        ngx_shmtx_lock(&pzn[i].zone->shpool->mutex);

        data->traffic += bytes;

        if (ngx_current_msec > pzn[i].node->last_traffic_start){

            td = ngx_current_msec - pzn[i].node->last_traffic_start;

            if (td >= rmcf->interval){
                data->bandwidth = pzn[i].node->last_traffic * 1000 / td;
                if (data->bandwidth > data->max_bandwidth){
                    data->max_bandwidth = data->bandwidth;
                }

                pzn[i].node->last_traffic = 0;
                pzn[i].node->last_traffic_start = ngx_current_msec;
            }
        }

        pzn[i].node->last_traffic += bytes;

        if (ngx_current_msec > pzn[i].node->last_traffic_update){
            pzn[i].node->last_traffic_update = ngx_current_msec;
        }

        ngx_shmtx_unlock(&pzn[i].zone->shpool->mutex);
    }

    return NGX_DECLINED;
}
static ngx_int_t
ngx_http_push_stream_registry_subscriber(ngx_http_request_t *r, ngx_http_push_stream_subscriber_t *worker_subscriber)
{
    ngx_http_push_stream_main_conf_t               *mcf = ngx_http_get_module_main_conf(r, ngx_http_push_stream_module);
    ngx_http_push_stream_loc_conf_t                *cf = ngx_http_get_module_loc_conf(r, ngx_http_push_stream_module);
    ngx_http_push_stream_shm_data_t                *data = mcf->shm_data;
    ngx_http_push_stream_worker_data_t             *thisworker_data = &data->ipc[ngx_process_slot];
    ngx_msec_t                                      connection_ttl = worker_subscriber->longpolling ? cf->longpolling_connection_ttl : cf->subscriber_connection_ttl;
    ngx_http_push_stream_module_ctx_t              *ctx = ngx_http_get_module_ctx(r, ngx_http_push_stream_module);
    ngx_slab_pool_t                                *shpool = mcf->shpool;

    // adding subscriber to worker list of subscribers
    ngx_queue_insert_tail(&thisworker_data->subscribers_queue, &worker_subscriber->worker_queue);

    ctx->longpolling = worker_subscriber->longpolling;
    ctx->subscriber = worker_subscriber;

    if ((connection_ttl != NGX_CONF_UNSET_MSEC) || (cf->ping_message_interval != NGX_CONF_UNSET_MSEC)) {

        if (connection_ttl != NGX_CONF_UNSET_MSEC) {
            if ((ctx->disconnect_timer = ngx_pcalloc(worker_subscriber->request->pool, sizeof(ngx_event_t))) == NULL) {
                return NGX_ERROR;
            }
        }

        if ((!ctx->longpolling) && (cf->ping_message_interval != NGX_CONF_UNSET_MSEC)) {
            if ((ctx->ping_timer = ngx_pcalloc(worker_subscriber->request->pool, sizeof(ngx_event_t))) == NULL) {
                return NGX_ERROR;
            }
        }

        if (ctx->disconnect_timer != NULL) {
            ctx->disconnect_timer->handler = ngx_http_push_stream_disconnect_timer_wake_handler;
            ctx->disconnect_timer->data = worker_subscriber->request;
            ctx->disconnect_timer->log = worker_subscriber->request->connection->log;
            ngx_http_push_stream_timer_reset(connection_ttl, ctx->disconnect_timer);
        }

        if (ctx->ping_timer != NULL) {
            ctx->ping_timer->handler = ngx_http_push_stream_ping_timer_wake_handler;
            ctx->ping_timer->data = worker_subscriber->request;
            ctx->ping_timer->log = worker_subscriber->request->connection->log;
            ngx_http_push_stream_timer_reset(cf->ping_message_interval, ctx->ping_timer);
        }
    }

    // increment global subscribers count
    ngx_shmtx_lock(&shpool->mutex);
    data->subscribers++;
    ngx_shmtx_unlock(&shpool->mutex);
    thisworker_data->subscribers++;

    return NGX_OK;
}
static ngx_int_t ngx_http_push_handle_subscriber_concurrency(ngx_http_request_t *r, ngx_http_push_channel_t *channel, ngx_http_push_loc_conf_t *loc_conf) {
	ngx_int_t                      max_subscribers = loc_conf->max_channel_subscribers;
	ngx_int_t                      current_subscribers;
	ngx_shmtx_lock(&ngx_http_push_shpool->mutex);
	current_subscribers = channel->subscribers;
	ngx_shmtx_unlock(&ngx_http_push_shpool->mutex);
	if(current_subscribers==0) { 
		//empty channels are always okay.
		return NGX_OK;
	}	
	
	if(max_subscribers!=0 && current_subscribers >= max_subscribers) {
		//max_channel_subscribers setting
		ngx_http_push_respond_status_only(r, NGX_HTTP_FORBIDDEN, NULL);
		return NGX_DECLINED;
	}
	
	//nonzero number of subscribers present
	switch(loc_conf->subscriber_concurrency) {
		case NGX_HTTP_PUSH_SUBSCRIBER_CONCURRENCY_BROADCAST:
			return NGX_OK;
		
		case NGX_HTTP_PUSH_SUBSCRIBER_CONCURRENCY_LASTIN:
			ngx_shmtx_lock(&ngx_http_push_shpool->mutex);
			//send "everyone" a 409 Conflict response.
			//in most reasonable cases, there'll be at most one subscriber on the
			//channel. However, since settings are bound to locations and not
			//specific channels, this assumption need not hold. Hence this broadcast.
			ngx_int_t rc = ngx_http_push_broadcast_status_locked(channel, NGX_HTTP_NOT_FOUND, &NGX_HTTP_PUSH_HTTP_STATUS_409, r->connection->log, ngx_http_push_shpool);
			ngx_shmtx_unlock(&ngx_http_push_shpool->mutex);

			return NGX_OK;
		
		case NGX_HTTP_PUSH_SUBSCRIBER_CONCURRENCY_FIRSTIN:
			ngx_http_push_respond_status_only(r, NGX_HTTP_NOT_FOUND, &NGX_HTTP_PUSH_HTTP_STATUS_409);
			return NGX_DECLINED;
		
		default:
			return NGX_ERROR;
	}
}
//free memory for a message. 
static ngx_inline void ngx_http_push_free_message_locked(ngx_http_push_msg_t *msg, ngx_slab_pool_t *shpool) {
	if(msg->buf->file!=NULL) {
		ngx_shmtx_unlock(&shpool->mutex);
		if(msg->buf->file->fd!=NGX_INVALID_FILE) {
			ngx_close_file(msg->buf->file->fd);
		}
		ngx_delete_file(msg->buf->file->name.data); //should I care about deletion errors? doubt it.
		ngx_shmtx_lock(&shpool->mutex);
	}
	ngx_slab_free_locked(shpool, msg->buf); //separate block, remember?
	ngx_slab_free_locked(shpool, msg);
}
static void ngx_http_push_subscriber_cleanup(ngx_http_push_subscriber_cleanup_t *data) {
	if(data->subscriber!=NULL) { //still queued up
		ngx_queue_remove(&data->subscriber->queue);
		ngx_pfree(ngx_http_push_pool, data->subscriber); //was there an error? oh whatever.
	}
	if(data->channel!=NULL) { //we're expected to decrement the subscriber count
		ngx_slab_pool_t            *shpool = (ngx_slab_pool_t *) ngx_http_push_shm_zone->shm.addr;
		ngx_shmtx_lock(&shpool->mutex);
		data->channel->subscribers--;
		ngx_shmtx_unlock(&shpool->mutex);
	}
}
Example #13
0
int ngx_shmap_flush_expired(ngx_shm_zone_t* zone, int attempts)
{
    ngx_queue_t                 *q, *prev;
    ngx_shmap_node_t  *sd;
    ngx_shmap_ctx_t   *ctx;
    ngx_time_t                  *tp;
    int                          freed = 0;
    ngx_rbtree_node_t           *node;
    uint64_t                     now;
	assert(zone != NULL);

    ctx = zone->data;

    ngx_shmtx_lock(&ctx->shpool->mutex);

    if (ngx_queue_empty(&ctx->sh->queue)) {
        return 0;
    }

    tp = ngx_timeofday();

    now = (uint64_t) tp->sec * 1000 + tp->msec;

    q = ngx_queue_last(&ctx->sh->queue);

    while (q != ngx_queue_sentinel(&ctx->sh->queue)) {
        prev = ngx_queue_prev(q);

        sd = ngx_queue_data(q, ngx_shmap_node_t, queue);

        if (sd->expires != 0 && sd->expires <= now) {
            ngx_queue_remove(q);

            node = (ngx_rbtree_node_t *)
                ((u_char *) sd - offsetof(ngx_rbtree_node_t, color));

            ngx_rbtree_delete(&ctx->sh->rbtree, node);
            ngx_slab_free_locked(ctx->shpool, node);
            freed++;

            if (attempts && freed == attempts) {
                break;
            }
        }

        q = prev;
    }

    ngx_shmtx_unlock(&ctx->shpool->mutex);

    return freed;
}
static ngx_int_t
ngx_http_limit_access_handler(ngx_http_request_t *r)
{
    ngx_int_t                              rc;
    ngx_http_limit_access_ctx_t           *ctx;
    ngx_http_limit_access_conf_t          *lacf;
    ngx_http_limit_access_hash_t          *hash;

    lacf = ngx_http_get_module_loc_conf(r, ngx_http_limit_access_module);

    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
            "limit_access_handler: %p, %d", lacf->shm_zone, lacf->limit_check);

    if (lacf->shm_zone == NULL || !lacf->limit_check) {
        return NGX_DECLINED;
    }

    ctx = lacf->shm_zone->data;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
            "limit_access_handler");

    ngx_shmtx_lock(&ctx->shpool->mutex);

    hash = ctx->sh;

    if (!hash->valid) {
        ngx_shmtx_unlock(&ctx->shpool->mutex);
        return NGX_DECLINED;
    }

    rc = 0;

    if (ctx->type == HASH_IP) {
        rc = ngx_http_limit_access_lookup_ip(r, ctx);
    }
    if (ctx->type == HASH_VARIABLE) {
        rc = ngx_http_limit_access_lookup_variable(r, ctx);
    }

    ngx_shmtx_unlock(&ctx->shpool->mutex);

    if (rc == 1) {

        ngx_log_error(lacf->limit_log_level, r->connection->log, 0,
                "access forbidden by limit_access");

        return NGX_HTTP_FORBIDDEN;
    }

    return NGX_DECLINED;
}
static ngx_int_t ngx_http_push_store_delete_channel(ngx_http_push_channel_t *channel, ngx_http_request_t *r) {
  ngx_http_push_msg_t            *msg, *sentinel;
  ngx_shmtx_lock(&ngx_http_push_shpool->mutex);
  sentinel = channel->message_queue; 
  msg = sentinel;
        
  while((msg=(ngx_http_push_msg_t *)ngx_queue_next(&msg->queue))!=sentinel) {
    //force-delete all the messages
    ngx_http_push_force_delete_message_locked(NULL, msg, ngx_http_push_shpool);
  }
  channel->messages=0;
  
  //410 gone
  ngx_shmtx_unlock(&ngx_http_push_shpool->mutex);
  
  ngx_http_push_store_publish(channel, NULL, NGX_HTTP_GONE, &NGX_HTTP_PUSH_HTTP_STATUS_410, r->connection->log);
  
  ngx_shmtx_lock(&ngx_http_push_shpool->mutex);
  ngx_http_push_delete_channel_locked(channel);
  ngx_shmtx_unlock(&ngx_http_push_shpool->mutex);
  return NGX_OK;
}
Example #16
0
void *
ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size)
{
    void  *p;

    ngx_shmtx_lock(&pool->mutex);

    p = ngx_slab_alloc_locked(pool, size);

    ngx_shmtx_unlock(&pool->mutex);

    return p;
}
static ngx_int_t
ngx_http_push_stream_send_response_channels_info_detailed(ngx_http_request_t *r, ngx_http_push_stream_requested_channel_t *requested_channels) {
    ngx_str_t                                *text;
    ngx_queue_t                               queue_channel_info;
    ngx_http_push_stream_main_conf_t         *mcf = ngx_http_get_module_main_conf(r, ngx_http_push_stream_module);
    ngx_slab_pool_t                          *shpool = mcf->shpool;
    ngx_http_push_stream_content_subtype_t   *subtype = ngx_http_push_stream_match_channel_info_format_and_content_type(r, 1);
    ngx_http_push_stream_channel_info_t      *channel_info;
    ngx_http_push_stream_channel_t           *channel = NULL;
    ngx_http_push_stream_requested_channel_t *requested_channel;
    ngx_queue_t                              *cur = &requested_channels->queue;
    ngx_uint_t                                qtd_channels = 0;

    ngx_queue_init(&queue_channel_info);

    ngx_shmtx_lock(&shpool->mutex);
    while ((cur = ngx_queue_next(cur)) != &requested_channels->queue) {
        requested_channel = ngx_queue_data(cur, ngx_http_push_stream_requested_channel_t, queue);

        // search for a existing channel with this id
        channel = ngx_http_push_stream_find_channel(requested_channel->id, r->connection->log, mcf);
        if ((channel != NULL) && ((channel_info = ngx_pcalloc(r->pool, sizeof(ngx_http_push_stream_channel_info_t))) != NULL)) {
            channel_info->id.data = channel->id.data;
            channel_info->id.len = channel->id.len;
            channel_info->published_messages = channel->last_message_id;
            channel_info->stored_messages = channel->stored_messages;
            channel_info->subscribers = channel->subscribers;

            ngx_queue_insert_tail(&queue_channel_info, &channel_info->queue);
            qtd_channels++;
        }
    }
    ngx_shmtx_unlock(&shpool->mutex);

    if (qtd_channels == 0) {
        return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_NOT_FOUND, NULL);
    }

    if (qtd_channels == 1) {
        channel_info = ngx_queue_data(ngx_queue_head(&queue_channel_info), ngx_http_push_stream_channel_info_t, queue);
        text = ngx_http_push_stream_channel_info_formatted(r->pool, subtype->format_item, &channel_info->id, channel_info->published_messages, channel_info->stored_messages, channel_info->subscribers);
        if (text == NULL) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate response buffer.");
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        return ngx_http_push_stream_send_response(r, text, subtype->content_type, NGX_HTTP_OK);
    }

    return ngx_http_push_stream_send_response_channels_info(r, &queue_channel_info);
}
static ngx_int_t
ngx_http_file_cache_add(ngx_http_file_cache_t *cache, ngx_http_cache_t *c)
{
    ngx_http_file_cache_node_t  *fcn;

    ngx_shmtx_lock(&cache->shpool->mutex);

    fcn = ngx_http_file_cache_lookup(cache, c->key);

    if (fcn == NULL) {

        fcn = ngx_slab_alloc_locked(cache->shpool,
                                    sizeof(ngx_http_file_cache_node_t));
        if (fcn == NULL) {
            ngx_shmtx_unlock(&cache->shpool->mutex);
            return NGX_ERROR;
        }

        ngx_memcpy((u_char *) &fcn->node.key, c->key, sizeof(ngx_rbtree_key_t));

        ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)],
                   NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t));

        ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node);

        fcn->uses = 1;
        fcn->count = 0;
        fcn->valid_msec = c->valid_msec;
        fcn->error = 0;
        fcn->exists = 1;
        fcn->updating = 0;
        fcn->deleting = 0;
        fcn->uniq = c->uniq;
        fcn->valid_sec = c->valid_sec;
        fcn->body_start = c->body_start;
        fcn->fs_size = c->fs_size;

        cache->sh->size += c->fs_size;

    } else {
        ngx_queue_remove(&fcn->queue);
    }

    fcn->expire = ngx_time() + cache->inactive;

    ngx_queue_insert_head(&cache->sh->queue, &fcn->queue);

    ngx_shmtx_unlock(&cache->shpool->mutex);

    return NGX_OK;
}
Example #19
0
void ngx_http_session_shm_free(void *p)
{
    ngx_http_session_list_t          *session_list;

    session_list = ngx_http_session_shm_zone->data;

    ngx_shmtx_lock(&session_list->shpool->mutex);

    ngx_slab_free_locked(session_list->shpool, p);

    ngx_shmtx_unlock(&session_list->shpool->mutex);

    return; 
}
Example #20
0
static ngx_int_t
ngx_http_session_manager(void)
{
    ngx_http_session_t             *session;
    ngx_http_session_list_t        *session_list;

    session_list = ngx_http_session_shm_zone->data;

    ngx_shmtx_lock(&session_list->shpool->mutex);

    session = session_list->new_chain_head;
    
    if (!session) {
        goto out;
    }

    while (session) {
        /* add timer to session */
        session->ev.handler = ngx_http_session_timeout_handler;
        session->ev.data = session;
        session->ev.log = session_list->log;

        if (session->timeout == 0) {
            session->timeout = 60;
        }

        session->timeout = session->timeout - (ngx_time() - session->est) * 1000;
        
        if (session->ev.timer_set) {
            ngx_del_timer(&session->ev);
        }

        ngx_add_timer(&session->ev, session->timeout);
        
        session_list->new_chain_head = session->new_chain_next;
        
        session->new_chain_next = NULL;
        session->wait = 0;
        session->reset = 0;
        
        session = session_list->new_chain_head;
    }

    session_list->new_chain_head = session_list->new_chain_tail = NULL;

out:
    ngx_shmtx_unlock(&session_list->shpool->mutex);

    return NGX_OK;
}
Example #21
0
static ngx_int_t
ngx_http_file_cache_lock(ngx_http_request_t *r, ngx_http_cache_t *c)
{
    ngx_msec_t                 now, timer;
    ngx_http_file_cache_t     *cache;

    if (!c->lock) {
        return NGX_DECLINED;
    }

    cache = c->file_cache;

    ngx_shmtx_lock(&cache->shpool->mutex);

    if (!c->node->updating) {
        c->node->updating = 1;
        c->updating = 1;
    }

    ngx_shmtx_unlock(&cache->shpool->mutex);

    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http file cache lock u:%d wt:%M",
                   c->updating, c->wait_time);

    if (c->updating) {
        return NGX_DECLINED;
    }

    c->waiting = 1;

    now = ngx_current_msec;

    if (c->wait_time == 0) {
        c->wait_time = now + c->lock_timeout;

        c->wait_event.handler = ngx_http_file_cache_lock_wait_handler;
        c->wait_event.data = r;
        c->wait_event.log = r->connection->log;
    }

    timer = c->wait_time - now;

    ngx_add_timer(&c->wait_event, (timer > 500) ? 500 : timer);

    r->main->blocked++;

    return NGX_AGAIN;
}
static void
ngx_http_limit_traffic_rate_filter_cleanup(void *data)
{
    ngx_http_limit_traffic_rate_filter_cleanup_t  *lircln = data;

    ngx_slab_pool_t             *shpool;
    ngx_rbtree_node_t           *node;
    ngx_http_limit_traffic_rate_filter_ctx_t   *ctx;
    ngx_http_limit_traffic_rate_filter_node_t  *lir;

    ctx = lircln->shm_zone->data;
    shpool = (ngx_slab_pool_t *) lircln->shm_zone->shm.addr;
    node = lircln->node;
    lir = (ngx_http_limit_traffic_rate_filter_node_t *) &node->color;

    ngx_shmtx_lock(&shpool->mutex);

    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, lircln->shm_zone->shm.log, 0,
                   "limit traffic rate cleanup: %08XD %d", node->key, lir->conn);

    lir->conn--;

    if (lir->conn == 0) {        
        ngx_queue_t *p = lir->rq_top.next;
        ngx_queue_t *c;
        ngx_http_limit_traffic_rate_filter_request_queue_t * tr;
        for(; p; ){
            c = p;
            p = ngx_queue_next(p);

            if(ngx_queue_next(c) && ngx_queue_prev(c)){
                ngx_queue_remove(c);
            }
            tr = ngx_queue_data(c, ngx_http_limit_traffic_rate_filter_request_queue_t, rq); 
            if (!tr->r){
                ngx_slab_free_locked(shpool, tr);
            }

            if(ngx_queue_last(&lir->rq_top) == p){
                break;
            }
        }

        ngx_rbtree_delete(ctx->rbtree, node);
        ngx_slab_free_locked(shpool, node);
    }

    ngx_shmtx_unlock(&shpool->mutex);
}
ngx_flag_t
ngx_buffer_cache_fetch(
	ngx_buffer_cache_t* cache,
	u_char* key,
	ngx_str_t* buffer,
	uint32_t* token)
{
	ngx_buffer_cache_entry_t* entry;
	ngx_buffer_cache_sh_t *sh = cache->sh;
	ngx_flag_t result = 0;
	uint32_t hash;

	hash = ngx_crc32_short(key, BUFFER_CACHE_KEY_SIZE);

	ngx_shmtx_lock(&cache->shpool->mutex);

	if (!sh->reset)
	{
		entry = ngx_buffer_cache_rbtree_lookup(&sh->rbtree, key, hash);
		if (entry != NULL && entry->state == CES_READY && 
			(cache->expiration == 0 || ngx_time() < (time_t)(entry->write_time + cache->expiration)))
		{
			result = 1;

			// update stats
			sh->stats.fetch_hit++;
			sh->stats.fetch_bytes += entry->buffer_size;

			// copy buffer pointer and size
			buffer->data = entry->start_offset;
			buffer->len = entry->buffer_size;
			*token = entry->write_time;

			// Note: setting the access time of the entry and cache to prevent it 
			//		from being freed while the caller uses the buffer
			sh->access_time = entry->access_time = ngx_time();
			(void)ngx_atomic_fetch_add(&entry->ref_count, 1);
		}
		else
		{
			// update stats
			sh->stats.fetch_miss++;
		}
	}

	ngx_shmtx_unlock(&cache->shpool->mutex);

	return result;
}
Example #24
0
void * ngx_http_session_shm_alloc(size_t size)
{
    ngx_http_session_list_t          *session_list;
    void                             *p;

    session_list = ngx_http_session_shm_zone->data;

    ngx_shmtx_lock(&session_list->shpool->mutex);

    p = ngx_slab_alloc_locked(session_list->shpool, size);

    ngx_shmtx_unlock(&session_list->shpool->mutex);

    return p;
}
Example #25
0
static void
ngx_http_file_cache_delete(ngx_http_file_cache_t *cache, ngx_queue_t *q,
    u_char *name)
{
    u_char                      *p;
    size_t                       len;
    ngx_path_t                  *path;
    ngx_http_file_cache_node_t  *fcn;

    fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue);

    if (fcn->exists) {
        cache->sh->size -= fcn->fs_size;

        path = cache->path;
        p = name + path->name.len + 1 + path->len;
        p = ngx_hex_dump(p, (u_char *) &fcn->node.key,
                         sizeof(ngx_rbtree_key_t));
        len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t);
        p = ngx_hex_dump(p, fcn->key, len);
        *p = '\0';

        fcn->count++;
        fcn->deleting = 1;
        ngx_shmtx_unlock(&cache->shpool->mutex);

        len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN;
        ngx_create_hashed_filename(path, name, len);

        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
                       "http file cache expire: \"%s\"", name);

        if (ngx_delete_file(name) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, ngx_errno,
                          ngx_delete_file_n " \"%s\" failed", name);
        }

        ngx_shmtx_lock(&cache->shpool->mutex);
        fcn->count--;
        fcn->deleting = 0;
    }

    if (fcn->count == 0) {
        ngx_queue_remove(q);
        ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
        ngx_slab_free_locked(cache->shpool, fcn);
    }
}
static ngx_int_t ngx_http_push_broadcast_locked(ngx_http_push_channel_t *channel, ngx_http_push_msg_t *msg, ngx_int_t status_code, const ngx_str_t *status_line, ngx_log_t *log, ngx_slab_pool_t *shpool) {
	//subscribers are queued up in a local pool. Queue heads, however, are located
	//in shared memory, identified by pid.
	ngx_http_push_pid_queue_t     *sentinel = &channel->workers_with_subscribers;
	ngx_http_push_pid_queue_t     *cur = sentinel;
	ngx_int_t                      received;
	received = channel->subscribers > 0 ? NGX_HTTP_PUSH_MESSAGE_RECEIVED : NGX_HTTP_PUSH_MESSAGE_QUEUED;

	if(msg!=NULL && received==NGX_HTTP_PUSH_MESSAGE_RECEIVED) {
		ngx_http_push_reserve_message_locked(channel, msg);
	}
	
	while((cur=(ngx_http_push_pid_queue_t *)ngx_queue_next(&cur->queue))!=sentinel) {
		pid_t           worker_pid  = cur->pid;
		ngx_int_t       worker_slot = cur->slot;
		ngx_http_push_subscriber_t *subscriber_sentinel= cur->subscriber_sentinel;
		
		ngx_shmtx_unlock(&shpool->mutex);
		if(worker_pid == ngx_pid) {
			//my subscribers
			ngx_http_push_respond_to_subscribers(channel, subscriber_sentinel, msg, status_code, status_line);
		}
		else {
			//some other worker's subscribers
			//interprocess communication breakdown
			if(ngx_http_push_send_worker_message(channel, subscriber_sentinel, worker_pid, worker_slot, msg, status_code, log) != NGX_ERROR) {
				ngx_http_push_alert_worker(worker_pid, worker_slot, log);
			}
			else {
				ngx_log_error(NGX_LOG_ERR, log, 0, "push module: error communicating with some other worker process");
			}
			
		}
		ngx_shmtx_lock(&shpool->mutex);
		/*
		each time all of a worker's subscribers are removed, so is the sentinel. 
		this is done to make garbage collection easier. Assuming we want to avoid
		placing the sentinel in shared memory (for now -- it's a little tricky
		to debug), the owner of the worker pool must be the one to free said sentinel.
		But channels may be deleted by different worker processes, and it seems unwieldy
		(for now) to do IPC just to delete one stinkin' sentinel. Hence a new sentinel
		is used every time the subscriber queue is emptied.
		*/
		cur->subscriber_sentinel = NULL; //think about it it terms of garbage collection. it'll make sense. sort of.
		
	}
	return received;
}
void
ngx_buffer_cache_get_stats(
	ngx_buffer_cache_t* cache,
	ngx_buffer_cache_stats_t* stats)
{
	ngx_buffer_cache_sh_t *sh = cache->sh;

	ngx_shmtx_lock(&cache->shpool->mutex);

	memcpy(stats, &sh->stats, sizeof(sh->stats));

	stats->entries = sh->entries_end - sh->entries_start;
	stats->data_size = sh->buffers_end - sh->buffers_start;

	ngx_shmtx_unlock(&cache->shpool->mutex);
}
Example #28
0
void
ngx_http_file_cache_free(ngx_http_request_t *r, ngx_temp_file_t *tf)
{
    ngx_http_cache_t       *c;
    ngx_http_file_cache_t  *cache;

    c = r->cache;

    if (c->updated) {
        return;
    }

    c->updated = 1;

    cache = c->file_cache;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http file cache free");

    ngx_shmtx_lock(&cache->shpool->mutex);

    c->node->count--;

    if (c->error) {
        c->node->valid_sec = c->valid_sec;
        c->node->valid_msec = c->valid_msec;
        c->node->error = c->error;
    }

    c->node->updating = 0;

    ngx_shmtx_unlock(&cache->shpool->mutex);

    if (c->temp_file) {
        if (tf && tf->file.fd != NGX_INVALID_FILE) {
            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "http file cache incomplete: \"%s\"",
                           tf->file.name.data);

            if (ngx_delete_file(tf->file.name.data) == NGX_FILE_ERROR) {
                ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
                              ngx_delete_file_n " \"%s\" failed",
                              tf->file.name.data);
            }
        }
    }
}
Example #29
0
static void
ngx_http_file_cache_lock_wait_handler(ngx_event_t *ev)
{
    ngx_uint_t                 wait;
    ngx_msec_t                 timer;
    ngx_http_cache_t          *c;
    ngx_http_request_t        *r;
    ngx_http_file_cache_t     *cache;

    r = ev->data;
    c = r->cache;

    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0,
                   "http file cache wait handler wt:%M cur:%M",
                   c->wait_time, ngx_current_msec);

    timer = c->wait_time - ngx_current_msec;

    if ((ngx_msec_int_t) timer <= 0) {
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
                       "http file cache lock timeout");
        c->lock = 0;
        goto wakeup;
    }

    cache = c->file_cache;
    wait = 0;

    ngx_shmtx_lock(&cache->shpool->mutex);

    if (c->node->updating) {
        wait = 1;
    }

    ngx_shmtx_unlock(&cache->shpool->mutex);

    if (wait) {
        ngx_add_timer(ev, (timer > 500) ? 500 : timer);
        return;
    }

wakeup:

    c->waiting = 0;
    r->main->blocked--;
    r->connection->write->handler(r->connection->write);
}
static ngx_int_t setup_default_servers(ngx_http_request_t *r, ngx_http_upstream_srv_conf_t *us)
{
    ngx_http_upstream_available_capacity_srv_conf_t *conf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_available_capacity_module);
    if (conf->server_list) return NGX_OK;
    
    ngx_slab_pool_t *shpool = (ngx_slab_pool_t *)us->shm_zone->shm.addr;
    ngx_shmtx_lock(&shpool->mutex);

    ngx_http_upstream_available_capacity_server_t *prev_server_conf = NULL;
	size_t i = 0;
    for (i = 0; i < us->servers->nelts; ++i) {
        ngx_http_upstream_server_t *servers = us->servers->elts;

        ngx_http_upstream_available_capacity_server_t *server_conf = ngx_slab_calloc_locked(shpool, sizeof(ngx_http_upstream_available_capacity_server_t));
        server_conf->server   = &servers[i];
        server_conf->capacity = 1;

        ngx_str_t server_address = ngx_string(server_conf->server->name.data);
        ngx_url_t url;
        ngx_memzero(&url, sizeof(ngx_url_t));
        size_t server_address_size = strlen((char *)server_address.data);
        url.url.len  = server_address_size;
        url.url.data = ngx_slab_alloc_locked(shpool, server_address_size);
        url.default_port = 80;
        ngx_cpystrn(url.url.data, server_address.data, server_address_size + 1);

        if (ngx_parse_url_slab(shpool, &url) != NGX_OK) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "cannot parse url : %s", server_address.data);
            return NGX_DECLINED;
        }
        server_conf->addr = *url.addrs;
        server_conf->next = NULL;

        if (prev_server_conf) {
            prev_server_conf->next = server_conf;
        } else {
            conf->server_list = server_conf;
        }
        prev_server_conf = server_conf;
    }

    conf->server_num        = us->servers->nelts;
    conf->search_start_peer = conf->server_list;

    ngx_shmtx_unlock(&shpool->mutex);
    return NGX_OK;
}