zoukankan      html  css  js  c++  java
  • NGINX(一)内存结构

    ngx_buf_t和ngx_chain_t是nginx中操作内存的重要手段, 很多的数据都需要通过这个结构进行保存. 其中ngx_buf_t中保存一块可用内存, ngx_chain_t则是将内存块连接起来,组成一个链表, 操作这两个数据结构函数并不多, 下面进行了详解.

    基本数据结构

    typedef struct ngx_chain_s       ngx_chain_t;
    typedef struct ngx_buf_s         ngx_buf_t;
        
    struct ngx_buf_s {
    	/*当前读取buffer位置*/
    	u_char          *pos; 
    	/*实际占用buffer的最后位置*/
    	u_char          *last;
    	/*当前读取文件位置*/
    	off_t            file_pos;
    	/*文件最后位置*/
    	off_t            file_last;
    	
    	/*buffer开始位置*/
    	u_char          *start;
    	/*buffer结束位置*/	
    	u_char          *end;
    	/*内存标记*/
    	ngx_buf_tag_t    tag;
    	/*文件句柄*/
    	ngx_file_t      *file;
    	ngx_buf_t       *shadow;
    	
    	/*1表示内存可以修改*/
    	unsigned         temporary:1;
    	/*1表示内存不可以修改*/
    	unsigned         memory:1;
    
    	/*1表示操作内容通过mmap()函数映射不可修改*/
    	unsigned         mmap:1;
    	/*1表示内存可以回收*/
    	unsigned         recycled:1;
    	/*1表示操作内容在文件中*/
    	unsigned         in_file:1;
    	/*1表示立即将内容发送出去*/
    	unsigned         flush:1;
    	/*1表示立即将内容同步发送出去*/
    	unsigned         sync:1;
    	/*标记chain是否为最后一块buf*/
    	unsigned         last_buf:1;
    	/*标记chain中是否为最后一个chain,最后一块buf并不表示是最后一个chain,但最后一个chain一定是最后一块buf*/
    	unsigned         last_in_chain:1;
    
    	unsigned         last_shadow:1;
    	unsigned         temp_file:1;
    
    	/* STUB */ int   num;
    };
    
    struct ngx_chain_s {
    	ngx_buf_t    *buf;
    	ngx_chain_t  *next;
    };
    

    操作函数

    创建一个buf很简单, 直接在内存池中分配一块内存, 然后分配size大小空间, 给ngx_buf_t各个字段进行赋值即可.

    ngx_buf_t *
    ngx_create_temp_buf(ngx_pool_t *pool, size_t size)
    {
    	ngx_buf_t *b;
    
    	b = ngx_calloc_buf(pool);
    	if (b == NULL) {
    		return NULL;
    	}
    
    	b->start = ngx_palloc(pool, size);
    	if (b->start == NULL) {
    		return NULL;
    	}
    
    	b->pos = b->start;
    	b->last = b->start;
    	b->end = b->last + size;
    	b->temporary = 1;
    
    	return b;
    }
    

    创建一个buf链表节点, 首先检查内存池pool->chain缓存中是否为空, 不为空直接取出使用, 为空重新分配.

    ngx_chain_t *
    ngx_alloc_chain_link(ngx_pool_t *pool)
    {
    	ngx_chain_t  *cl;
    
    	cl = pool->chain;
    
    	if (cl) {
    		pool->chain = cl->next;
    		return cl;
    	}
    
    	cl = ngx_palloc(pool, sizeof(ngx_chain_t));
    	if (cl == NULL) {
    		return NULL;
    	}
    
    	return cl;
    }
    

    直接创建一个ngx_buf_t链表

    ngx_chain_t *
    ngx_create_chain_of_bufs(ngx_pool_t *pool, ngx_bufs_t *bufs)
    {
    	u_char       *p;
    	ngx_int_t     i;
    	ngx_buf_t    *b;
    	ngx_chain_t  *chain, *cl, **ll;
    
    	/*首先分配所有buf需要的一整块内存, 没有循环分配小内存, 显然为了提高速度, 处处体现了作者对代码质量和性能的要求之高*/
    	p = ngx_palloc(pool, bufs->num * bufs->size);
    	if (p == NULL) {
    		return NULL;
    	}
    	
    	/*这里用一个二级指针保存第一个节点指针地址, 同样也保存后面节点指针地址, 为什么这么干, 每次保存下上次节点也可以实现, 
    	 *这么干少了一次循环内的判断, 否则我们需要判断出第一次循环, 并给chain赋值
    	 */
    	ll = &chain;
    
    	for (i = 0; i < bufs->num; i++) {
    
    		b = ngx_calloc_buf(pool);
    		if (b == NULL) {
    			return NULL;
    		}
    
    		b->pos = p;
    		b->last = p;
    		b->temporary = 1;
    
    		b->start = p;
    		p += bufs->size;
    		b->end = p;
    
    		cl = ngx_alloc_chain_link(pool);
    		if (cl == NULL) {
    			return NULL;
    		}
    
    		cl->buf = b;
    		/*ll保存的上一个节点指针的指针, 赋值相当于给上一个节点next指针赋值*/
    		*ll = cl;
    		/*取本节点next指针地址, 用于下次循环赋值使用*/
    		ll = &cl->next;
    	}
    
    	*ll = NULL;
    
    	return chain;
    }
    

    buf链表添加或者copy, 我觉得这里叫append(附加)可能更好, 因为只是将in链表复制到chain链表后面, 可以看到这里用到了和上面同样的二级指针进行操作.

    ngx_int_t
    ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in)
    {
    	ngx_chain_t  *cl, **ll;
    
    	ll = chain;
    
    	for (cl = *chain; cl; cl = cl->next) {
    		ll = &cl->next;
    	}
    
    	while (in) {
    		cl = ngx_alloc_chain_link(pool);
    		if (cl == NULL) {
    			return NGX_ERROR;
    		}
    
    		cl->buf = in->buf;
    		*ll = cl;
    		ll = &cl->next;
    		in = in->next;
    	}
    
    	*ll = NULL;
    
    	return NGX_OK;
    }
    

    更新链表函数功能是回收busy和out链表中闲置资源, 如果tag标志位与传入的一致, 则链表回收到free链表中, 否则直接释放会pool中, 多用于过滤模块

    void
    ngx_chain_update_chains(ngx_pool_t *p, ngx_chain_t **free, ngx_chain_t **busy,
    	ngx_chain_t **out, ngx_buf_tag_t tag)
    {
    	ngx_chain_t  *cl;
    
    	if (*busy == NULL) {
    		*busy = *out;
    
    	} else {
    		for (cl = *busy; cl->next; cl = cl->next) { /* void */ }
    
    		cl->next = *out;
    	}
    
    	*out = NULL;
    
    	while (*busy) {
    		cl = *busy;
    
    		if (ngx_buf_size(cl->buf) != 0) {
    			break;
    		}
    
    		if (cl->buf->tag != tag) {
    			*busy = cl->next;
    			ngx_free_chain(p, cl);
    			continue;
    		}
    
    		cl->buf->pos = cl->buf->start;
    		cl->buf->last = cl->buf->start;
    
    		*busy = cl->next;
    		cl->next = *free;
    		*free = cl;
    	}
    }
    
  • 相关阅读:
    jetty插件配置
    连接Oracle时ORA-12541 TNS 无监听程序
    查看表结构
    判断时间差,返回1或2或3
    template_共享模板
    template_showpost
    template_homepage
    tensorflow解决Fizz Buzz 的问题
    神经网络——项目二CNN手写数字识别
    神经网络——项目一 手写数字识别
  • 原文地址:https://www.cnblogs.com/ourroad/p/4838794.html
Copyright © 2011-2022 走看看