学习《apache源代码全景分析》之存储段和存储段组摘录

1.当数据在过滤器中流动传递的时候,数据是以存储段组的形式组织的。每一个存储段组包含多个存储段,每一个存储段是一种数据类型的抽象。

2.存储段组包含多个存储段

   

 

struct apr_bucket 
{
    APR_RING_ENTRY(apr_bucket) link;
    const apr_bucket_type_t *type;
    apr_size_t length;
    apr_off_t start;
    void *data;
    void (*free)(void *e);
    apr_bucket_alloc_t *list;
};

3.存储段的内部数据结构

   

   在apr_bucket结构中,存储段的实际数据保存在data指针中,数据的长度由length进行标记。

4.所有的外部数据操作都是以存储段组为单位进行的,其数据结构定义在apr_buckets.h中:

    

   

5.在内存池中,所有的内存分配最终都由内存池分配子进行.

  存储段分配子为apr_bucket_alloc_t,其具体结构定义如下:

struct apr_bucket_alloc_t 
{
    apr_pool_t *pool;  //所有内存的来源内存池
    apr_allocator_t *alloctor;  //内存池的分配子
    node_header_t *freelist;  //用于保存回收的小于SAMLL_NODE_SIZE的结点
    apr_memnode_t *blocks;  //当前存储段所属的内存池结点
};


------------------
typedef struct node_header_t 
{
    apr_size_t size; //该内存的大小
    apr_bucket_alloc_t *alloc; //分配该内存块的存储段内存分配子
    apr_memnode_t *memnode; //记录该内存所在的内存结点
    struct node_header_t *next; //所有分配的存储段内存通过next指针形成链表
} node_header_t;

6.一旦分配成功,函数将为各个成员赋值,同时调整内存结点的first_avail指针指向实际的可用空间的起点,如下图:

    

7.存储段的内存使用函数apr_bucket_alloc进行分配。

  目前Apache支持多种类型的存储段,比如文件存储段等。分配的原则按照最大的存储段类型进行。

typedef union apr_bucket_structs apr_bucket_structs;
union apr_bucket_structs
{
    apr_bucket b; /*Bucket*/
    apr_bucket_heap heap;  /*Heap*/
    apr_bucket_pool pool;   /*pool*/
    apr_bucket_mmap mmap; /*mmap*/
    apr_bucket_file file;   /*file*/
};

8.释放存储段内存通过apr_bucket_free函数实现。

9.apr_bucket在Apache中定义如下:

struct apr_bucket
{
    APR_RING_ENTRY(apr_bucket) link;
    const apr_bucket_type_t *type;
    apr_size_t length;
    apr_off_t start;
    void *data;
    void (*free)(void *e);
    apr_bucket_alloc_t *list;
};

  通常情况下,存储段组用来保存的是一块连续的内存数据,而存储段组中的每一个存储段仅保存整个数据块的一小部分。

10.通用存储段接口和实际存储段的关系

     

apr_bucket_readapr_bucket_read函数用于从存储段中读取数据
apr_bucket_destroy将释放存储段引用的聂村,而不释放存储段本身的内存
apr_bucket_split使用split函数可以将一个存储段分割成两个存储单。
apr_bucket_copycopy函数可以接受一个存储段,并对其进行精确的复制
apr_bucket_setaside如果过滤器希望存储段组中的所有数据在下次过滤器调用的时候仍然可以使用,就要调用这个函数。

11.存储段类型包括11种数据:

堆存储段
内存池存储段
文件存储段
MMAP存储段
管道存储段
套接字存储段
持久存储段
临时存储段
刷新存储段
流中止(EOS)存储段

  (1) 堆存储段

typedef struct apr_bucket_heap apr_bucket_heap;
struct apr_bucket_heap
{
    apr_bucket_refcount refcount;
    char *base;
    apr_size_t alloc_len;    
    void (*free_func)(void *data);
};

   (2) 内存池存储段(Pool Bucket)

     内存池存储段的读取函数为pool_bucket_read.

struct apr_bucket_pool
{
    apr_bucket_heap heap;
    const char *base;
    apr_pool_t *pool;
    apr_bucket_alloc_t *list;
};

  (3) 文件存储段(file bucket)

    最重要的就是它的读取函数file_bucket_read.

typedef struct apr_bucket_file apr_bucket_file;
struct apr_bucket_file
{
    apr_bucket_refcount refcount;
    apr_file_t *fd;
    apr_pool_t *readpool;
#if APR_HAS_MMAP
    int can_mmap;
#endif /* APR_HAS_MMAP*/
};

  (4) MMAP存储段(MMAP bucket)

     读取数据由接口mmap_bucket_read完成。

typedef struct apr_bucket_mmap apr_bucket_mmap;
struct apr_bucket_mmap
{
    apr_bucket_refcount refcount;
    apr_mmap_t *mmap;
};

  (5) 套接字存储段(Socket Bucket)

   读取函数为socket_bucket_read.

  (6) 管道存储段(pipe bucket)

    读取函数为pipe_bucket_read;

  (7) 持久存储段(immortal bucket)

  (8) 临时存储段(transient bucket)

  (9) 刷新存储段(flush bucket)

  (10) 流中止(EOS)存储段

  (11) HTTP错误存储段

struct ap_bucket_error
{
    apr_bucket_refcount refcount;
    int status;
    const char *data;
};

12.不管是堆存储段还是文件存储段,都调用apr_bucket_read函数,而不是直接调用heap_bucket_read和file_bucket_read.

   apr_bucket_read本身实际是一个宏定义,如下所示:

#define apr_bucket_read(e,str,len,block) (e)->type->read(e, str, len, block)

13.存储段类型判断

    

14.存储段结点获取

    APR_BRIGADE_EMPTY、APR_BRIGADE_SENTINEL、APR_BRIGADE_FIRST、APR_BRIGADE_LAST、APR_BUCKET_NEXT、APR_BUCKET_PREV

15.存储段结点增加和删除

   (1) 存储段组头部插入结点(APR_BRIGADE_INSERT_HEAD)

   (2) 存储段组尾部插入结点(APR_BRIGADE_INSERT_TAIL)

   (3) 存储段组在指定存储段之前插入新的存储段(APR_BUCKET_INSERT_BEFORE)

   (4) 存储段组中在指定存储段之后插入一个新的存储段(APR_BUCKET_INSERT_AFTER)

   (5) 将一个存储段组追加到另一个存储段组的尾部(APR_BRIGADE_CONCAT)

   (6) 存储段结点移除(APR_BUCKET_REMOVE)

16.存储段组操作

    (1) 创建存储段组apr_brigade_create

    (2) 存储段组的销毁  apr_brigade_cleanup

    (3) 存储段组的分裂apr_brigade_split

       

 

    (4) 偏移分裂apr_brigade_partition

      

      

    (5) 行分裂apr_brigade_split_line

    (6) 统计存储段长度

        apr_brigade_length函数用以统计当前存储段组所有的存储段的长度。

    (7) 存储段转换 apr_brigade_flatten   用于将存储段组转换为字符串。

    (8) 将数据写入存储段组apr_bucket_write.

       

    (9) 一次向存储段组批量写入多个字符串数据apr_bucket_writev

    (10) 其余写入函数 apr_brigade_puts、apr_brigade_putc、apr_brigade_putstrs

    (11) ap_r*函数写入ap_rputc、ap_rputs、ap_rwrite、ap_rvputs、ap_vrprintf

17.存储段组和过滤器的关系

    

   ap_get_brigade函数正是用于获取下一个过滤器的存储段组内容。

       

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值