-10 +

req_limit module 源码分析

先来看看各个结构体是怎么样一个组织的:

红黑树设计到的数据结构和对外的接口方法:

  1. //rbtree 节点
  2. typedef struct ngx_rbtree_node_s ngx_rbtree_node_t;
  3. struct ngx_rbtree_node_s {
  4. ngx_rbtree_key_t key;
  5. ngx_rbtree_node_t *left;
  6. ngx_rbtree_node_t *right;
  7. ngx_rbtree_node_t *parent;
  8. u_char color;
  9. u_char data;
  10. };
  11. //想红黑树种插入一个节点
  12. void ngx_rbtree_insert(ngx_rbtree_t *tree, ngx_rbtree_node_t *node);
  13. //删除红黑树种的一个节点
  14. void ngx_rbtree_delete(ngx_rbtree_t *tree, ngx_rbtree_node_t *node);
  15. void ngx_rbtree_insert_value(ngx_rbtree_node_t *root, ngx_rbtree_node_t *node,
  16. ngx_rbtree_node_t *sentinel);
  17. void ngx_rbtree_insert_timer_value(ngx_rbtree_node_t *root,
  18. ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);

注意红黑树中 ngx_rbtree_node_t 是必须要使用到的节点,所以在使用时一般把它置于结构体的第一个,这样可以做强制类型转换,就可以使用接口函数了。

  1. ...
  2. //这里是让 ngx_rbtree_node_t->color 和 ngx_http_limit_req_node_t->color 重合
  3. //ngx_http_limit_req_node_t->data 保存 key 的值
  4. size = offsetof(ngx_rbtree_node_t, color)
  5. + offsetof(ngx_http_limit_req_node_t, data)
  6. + key->len;
  7. ngx_http_limit_req_expire(ctx, 1);
  8. node = ngx_slab_alloc_locked(ctx->shpool, size);
  9. ...

双向队列的使用:

  1. typedef struct ngx_queue_s ngx_queue_t;
  2. struct ngx_queue_s {
  3. ngx_queue_t *prev;
  4. ngx_queue_t *next;
  5. };
  6. // 找出中位元素
  7. ngx_queue_t *ngx_queue_middle(ngx_queue_t *queue);
  8. // 排序双向队列,cmp 和 java 的 compare 接口类似
  9. void ngx_queue_sort(ngx_queue_t *queue,
  10. ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *));

使用的事只需要结构体中包含 ngx_queue_t 即可。

共享内存的使用,第一步先向系统申请:

  1. ... ...
  2. /**
  3. * 分配 shared memory
  4. */
  5. shm_zone = ngx_shared_memory_add(cf, &name, size,
  6. &ngx_http_limit_req_module);
  7. if (shm_zone == NULL) {
  8. return NGX_CONF_ERROR;
  9. }
  10. if (shm_zone->data) {
  11. ctx = shm_zone->data;
  12. ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  13. "%V \"%V\" is already bound to key \"%V\"",
  14. &cmd->name, &name, &ctx->key.value);
  15. return NGX_CONF_ERROR;
  16. }
  17. //挂载初始化函数
  18. shm_zone->init = ngx_http_limit_req_init_zone;
  19. shm_zone->data = ctx;

在初始化函数中:

  1. ... ...
  2. // 这里直接将共享内存的首地址赋值给 ngx_slab_pool_t,
  3. ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
  4. if (shm_zone->shm.exists) {
  5. ctx->sh = ctx->shpool->data;
  6. return NGX_OK;
  7. }
  8. ... ...

分配器的接口:

  1. void ngx_slab_init(ngx_slab_pool_t *pool);
  2. void *ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size);
  3. void *ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size);
  4. void *ngx_slab_calloc(ngx_slab_pool_t *pool, size_t size);
  5. void *ngx_slab_calloc_locked(ngx_slab_pool_t *pool, size_t size);
  6. void ngx_slab_free(ngx_slab_pool_t *pool, void *p);
  7. void ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p);

关于我

85 后程序员, 比较熟悉 Java,JVM,Golang 相关技术栈, 关注 Liunx kernel,目前痴迷于分布式系统的设计和实践。 研究包括但不限于 Docker Kubernetes eBPF 等相关技术。

Blog

Code

Life

Archive

0 comments
Anonymous
Markdown is supported

Be the first person to leave a comment!