29 Sep 2012
Squid源码分析(五)之业务逻辑分析
Squid源码分析(五)之业务逻辑分析
NOTE: 原创文章,转载请注明:转载自 blog.miaohong.org 本文链接地址: http://blog.miaohong.org/2012/09/29/squid_cache_5.html
收到请求后,根据请求的URL和method 进行hash生成键值, 在全局哈希表store_table 中进行查找, 若命中则调用storeClientCopy 拷贝数据; 若没有命中则转发后端服务器,在调用storeAppend把数据交给squid存储系统并转发给用户.
对于命中:
storeClientCopy --- > storeClientCopy2 --- > storeClientCopy3 --- > stmemCopy / storeClientFileRead --- > storeRead
那好,我们看storeRead
void
storeRead(storeIOState * sio, char *buf, size_t size, squid_off_t offset, STRCB * callback, void *callback_data)
{
SwapDir *SD = &Config.cacheSwap.swapDirs[sio->swap_dirn];
(SD->obj.read) (SD, sio, buf, size, offset, callback, callback_data);
}
上面红色字段的read回调在哪里赋值的呢。Ok, 我们前面已经分析了
sd->obj.create = storeUfsCreate;
sd->obj.open = storeUfsOpen;
sd->obj.close = storeUfsClose;
sd->obj.read = storeUfsRead;
sd->obj.write = storeUfsWrite;
sd->obj.unlink = storeUfsUnlink;
sd->obj.recycle = storeUfsRecycle;
至此,会根据不同的文件系统类型进行相关调用,后续分析见上面了。
对于未命中:
对于storeAppend而言,该函数非常重要的完成了几个业务
/* Append incoming data from a primary server to an entry. */
void
storeAppend(StoreEntry * e, const char *buf, int len)
{
MemObject *mem = e->mem_obj;
assert(mem != NULL);
assert(len >= 0);
assert(e->store_status == STORE_PENDING);
mem->refresh_timestamp = squid_curtime;
if (len) {
debug(20, 5) ("storeAppend: appending %d bytes for '%s'\n",
len,
storeKeyText(e->hash.key));
storeGetMemSpace(len);
stmemAppend(&mem->data_hdr, buf, len);
mem->inmem_hi += len;
}
if (EBIT_TEST(e->flags, DELAY_SENDING))
return;
InvokeHandlers(e);
storeSwapOut(e);
}
storeGetMemSpace ---- 内存判断,以便是否启动替换机制
stmemAppend ----- 将数据拷贝到_MemObject的data_hdr中
InvokeHandlers ---- 通过_MemObject的client找到客户端,并将数据发送给所有客户端
storeSwapOut ----- 数据存盘
上面四个业务非常重要 我们跟踪看一下storeSwapOut
void
storeSwapOut(StoreEntry * e)
{
MemObject *mem = e->mem_obj;
int swapout_able;
squid_off_t swapout_size;
size_t swap_buf_len;
if (mem == NULL)
return;
/* should we swap something out to disk? */
debug(20, 7) ("storeSwapOut: %s\n", storeUrl(e));
debug(20, 7) ("storeSwapOut: store_status = %s\n",
storeStatusStr[e->store_status]);
if (EBIT_TEST(e->flags, ENTRY_ABORTED)) {
assert(EBIT_TEST(e->flags, RELEASE_REQUEST));
storeSwapOutFileClose(e);
return;
}
if (EBIT_TEST(e->flags, ENTRY_SPECIAL)) {
debug(20, 3) ("storeSwapOut: %s SPECIAL\n", storeUrl(e));
return;
}
debug(20, 7) ("storeSwapOut: mem->inmem_lo = %" PRINTF_OFF_T "\n",
mem->inmem_lo);
debug(20, 7) ("storeSwapOut: mem->inmem_hi = %" PRINTF_OFF_T "\n",
mem->inmem_hi);
debug(20, 7) ("storeSwapOut: swapout.queue_offset = %" PRINTF_OFF_T "\n",
mem->swapout.queue_offset);
if (mem->swapout.sio)
debug(20, 7) ("storeSwapOut: storeOffset() = %" PRINTF_OFF_T "\n",
storeOffset(mem->swapout.sio));
assert(mem->inmem_hi >= mem->swapout.queue_offset);
/*
* Grab the swapout_size and check to see whether we're going to defer
* the swapout based upon size
*/
swapout_size = mem->inmem_hi - mem->swapout.queue_offset;
if ((e->store_status != STORE_OK) && (swapout_size < store_maxobjsize)) {
/*
* NOTE: the store_maxobjsize here is the max of optional
* max-size values from 'cache_dir' lines. It is not the
* same as 'maximum_object_size'. By default, store_maxobjsize
* will be set to -1. However, I am worried that this
* deferance may consume a lot of memory in some cases.
* It would be good to make this decision based on reply
* content-length, rather than wait to accumulate huge
* amounts of object data in memory.
*/
debug(20, 5) ("storeSwapOut: Deferring starting swapping out\n");
return;
}
swapout_able = storeSwapOutMaintainMemObject(e);
#if SIZEOF_SQUID_OFF_T <= 4
if (mem->inmem_hi > 0x7FFF0000) {
debug(20, 0) ("WARNING: preventing squid_off_t overflow for %s\n", storeUrl(e));
storeAbort(e);
return;
}
#endif
if (!swapout_able)
return;
debug(20, 7) ("storeSwapOut: swapout_size = %" PRINTF_OFF_T "\n",
swapout_size);
if (swapout_size == 0) {
if (e->store_status == STORE_OK)
storeSwapOutFileClose(e);
return; /* Nevermore! */
}
if (e->store_status == STORE_PENDING) {
/* wait for a full block to write */
if (swapout_size < SM_PAGE_SIZE)
return;
/*
* Wait until we are below the disk FD limit, only if the
* next server-side read won't be deferred.
*/
if (storeTooManyDiskFilesOpen() && !fwdCheckDeferRead(-1, e))
return;
}
/* Ok, we have stuff to swap out. Is there a swapout.sio open? */
if (e->swap_status == SWAPOUT_NONE && !EBIT_TEST(e->flags, ENTRY_FWD_HDR_WAIT)) {
assert(mem->swapout.sio == NULL);
assert(mem->inmem_lo == 0);
if (storeCheckCachable(e))
storeSwapOutStart(e);
else {
/* Now that we know the data is not cachable, free the memory
* to make sure the forwarding code does not defer the connection
*/
storeSwapOutMaintainMemObject(e);
return;
}
/* ENTRY_CACHABLE will be cleared and we'll never get here again */
}
if (NULL == mem->swapout.sio)
return;
do {
/*
* Evil hack time.
* We are paging out to disk in page size chunks. however, later on when
* we update the queue position, we might not have a page (I *think*),
* so we do the actual page update here.
*/
if (mem->swapout.memnode == NULL) {
/* We need to swap out the first page */
mem->swapout.memnode = mem->data_hdr.head;
} else {
/* We need to swap out the next page */
mem->swapout.memnode = mem->swapout.memnode->next;
}
/*
* Get the length of this buffer. We are assuming(!) that the buffer
* length won't change on this buffer, or things are going to be very
* strange. I think that after the copy to a buffer is done, the buffer
* size should stay fixed regardless so that this code isn't confused,
* but we can look at this at a later date or whenever the code results
* in bad swapouts, whichever happens first. :-)
*/
swap_buf_len = mem->swapout.memnode->len;
debug(20, 3) ("storeSwapOut: swap_buf_len = %d\n", (int) swap_buf_len);
assert(swap_buf_len > 0);
debug(20, 3) ("storeSwapOut: swapping out %d bytes from %" PRINTF_OFF_T "\n",
(int) swap_buf_len, mem->swapout.queue_offset);
mem->swapout.queue_offset += swap_buf_len;
storeWrite(mem->swapout.sio, stmemNodeGet(mem->swapout.memnode), swap_buf_len, stmemNodeFree);
/* the storeWrite() call might generate an error */
if (e->swap_status != SWAPOUT_WRITING)
break;
swapout_size = mem->inmem_hi - mem->swapout.queue_offset;
if (e->store_status == STORE_PENDING)
if (swapout_size < SM_PAGE_SIZE)
break;
} while (swapout_size > 0);
if (NULL == mem->swapout.sio)
/* oops, we're not swapping out any more */
return;
if (e->store_status == STORE_OK) {
/*
* If the state is STORE_OK, then all data must have been given
* to the filesystem at this point because storeSwapOut() is
* not going to be called again for this entry.
*/
assert(mem->inmem_hi == mem->swapout.queue_offset);
storeSwapOutFileClose(e);
}
}
squid有个MaintainMemObject周期执行事件,显然此处不是,所以
/* start swapping object to disk */
static void
storeSwapOutStart(StoreEntry * e)
{
generic_cbdata *c;
MemObject *mem = e->mem_obj;
int swap_hdr_sz = 0;
tlv *tlv_list;
char *buf;
assert(mem);
/* Build the swap metadata, so the filesystem will know how much
* metadata there is to store
*/
debug(20, 5) ("storeSwapOutStart: Begin SwapOut '%s' to dirno %d, fileno %08X\n",
storeUrl(e), e->swap_dirn, e->swap_filen);
e->swap_status = SWAPOUT_WRITING;
tlv_list = storeSwapMetaBuild(e);
buf = storeSwapMetaPack(tlv_list, &swap_hdr_sz);
storeSwapTLVFree(tlv_list);
mem->swap_hdr_sz = (size_t) swap_hdr_sz;
/* Create the swap file */
c = cbdataAlloc(generic_cbdata);
c->data = e;
mem->swapout.sio = storeCreate(e, storeSwapOutFileNotify, storeSwapOutFileClosed, c);
if (NULL == mem->swapout.sio) {
e->swap_status = SWAPOUT_NONE;
cbdataFree(c);
xfree(buf);
storeLog(STORE_LOG_SWAPOUTFAIL, e);
return;
}
storeLockObject(e); /* Don't lock until after create, or the replacement
* code might get confused */
/* Pick up the file number if it was assigned immediately */
e->swap_filen = mem->swapout.sio->swap_filen;
e->swap_dirn = mem->swapout.sio->swap_dirn;
/* write out the swap metadata */
cbdataLock(mem->swapout.sio);
storeWrite(mem->swapout.sio, buf, mem->swap_hdr_sz, xfree);
}
继续跟踪
void
storeWrite(storeIOState * sio, char *buf, size_t size, FREE * free_func)
{
SwapDir *SD = &Config.cacheSwap.swapDirs[sio->swap_dirn];
squid_off_t offset = sio->write_offset;
sio->write_offset += size;
(SD->obj.write) (SD, sio, buf, size, offset, free_func);
}
好的,又回到了上面的分析了,开始写盘。