学习《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_read | apr_bucket_read函數用于從存儲段中讀取數據 |
| apr_bucket_destroy | 將釋放存儲段引用的聶村,而不釋放存儲段本身的內存 |
| apr_bucket_split | 使用split函數可以將一個存儲段分割成兩個存儲單。 |
| apr_bucket_copy | copy函數可以接受一個存儲段,并對其進行精確的復制 |
| 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_MMAPint 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函數正是用于獲取下一個過濾器的存儲段組內容。
? ? ? ?
總結
以上是生活随笔為你收集整理的学习《apache源代码全景分析》之存储段和存储段组摘录的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 学习《apache源代码全景分析》之过滤
- 下一篇: 学习《apache源代码全景分析》之常用