Harold's Blog -- 个人技术笔记

所有原创文章  |  个人分享(公开)  |  关于
22 Aug 2012

Squid源码分析(一)之基础存储路径

NOTE: 原创文章,转载请注明:转载自 blog.miaohong.org 本文链接地址: http://blog.miaohong.org/2012/08/22/squid_cache_1.html

目录

main ---- > storeFsInit

关于storeFsInit 这个函数,其实是做了2步:

其一:建立替换算法

其二:建立fs

void
storeFsInit(void)
{
    storeReplSetup();
    storeFsSetup();
}

首先跟踪storeFsSetup 注意该函数是由./store_modules.sh ufs aufs coss null diskd 自动生成,需要编译后才有该函数。

void storeFsSetup(void)
{
    storeFsAdd("ufs", storeFsSetup_ufs);
    storeFsAdd("aufs", storeFsSetup_aufs);
    storeFsAdd("coss", storeFsSetup_coss);
    storeFsAdd("null", storeFsSetup_null);
    storeFsAdd("diskd", storeFsSetup_diskd);
}

对于storeFsAdd,这里有一个非常重要的storefs_list全局变量,它保存了全部的fs信息。看该函数下面最后一句的回调

void
storeFsAdd(const char *type, STSETUP * setup)
{
    int i;
    /* find the number of currently known storefs types */
    for (i = 0; storefs_list && storefs_list[i].typestr; i++) {
    assert(strcmp(storefs_list[i].typestr, type) != 0);
    }
    /* add the new type */
    storefs_list = xrealloc(storefs_list, (i + 2) * sizeof(storefs_entry_t));
    memset(&storefs_list[i + 1], 0, sizeof(storefs_entry_t));
    storefs_list[i].typestr = type;
    /* Call the FS to set up capabilities and initialize the FS driver */
    setup(&storefs_list[i]);
}

我们跟踪ufs系统看看,

void
storeFsSetup_ufs(storefs_entry_t * storefs)
{
    assert(!ufs_initialised);
    storefs->parsefunc = storeUfsDirParse;
    storefs->reconfigurefunc = storeUfsDirReconfigure;
    storefs->donefunc = storeUfsDirDone;
    ufs_state_pool = memPoolCreate("UFS IO State data", sizeof(ufsstate_t));
    ufs_initialised = 1;
}

可以看出该函数是用来填充storefs_list全局变量相对ufs部分的,并置ufs_initialised = 1; 其中 storefs->parsefunc = storeUfsDirParse;比较重要。

我们继续跟踪storeAufsDirParse (注意storeAufsDirParse 是在parse_cachedir函数中调用)

/*
 * storeUfsDirParse
 *
 * Called when a *new* fs is being setup.
 */
static void
storeUfsDirParse(SwapDir * sd, int index, char *path)
{
    int i;
    int size;
    int l1;
    int l2;
    ufsinfo_t *ufsinfo;

    i = GetInteger();
    size = i << 10;        /* Mbytes to kbytes */
    if (size <= 0)
    fatal("storeUfsDirParse: invalid size value");
    i = GetInteger();
    l1 = i;
    if (l1 <= 0)
    fatal("storeUfsDirParse: invalid level 1 directories value");
    i = GetInteger();
    l2 = i;
    if (l2 <= 0)
    fatal("storeUfsDirParse: invalid level 2 directories value");

    ufsinfo = xmalloc(sizeof(ufsinfo_t));
    if (ufsinfo == NULL)
    fatal("storeUfsDirParse: couldn't xmalloc() ufsinfo_t!\n");

    sd->index = index;
    sd->path = xstrdup(path);
    sd->max_size = size;
    sd->fsdata = ufsinfo;
    ufsinfo->l1 = l1;
    ufsinfo->l2 = l2;
    ufsinfo->swaplog_fd = -1;
    ufsinfo->map = NULL;   /* Debugging purposes */
    ufsinfo->suggest = 0;
    ufsinfo->open_files = 0;
    sd->checkconfig = storeUfsCheckConfig;
    sd->init = storeUfsDirInit;
    sd->newfs = storeUfsDirNewfs;
    sd->dump = storeUfsDirDump;
    sd->freefs = storeUfsDirFree;
    sd->dblcheck = storeUfsCleanupDoubleCheck;
    sd->statfs = storeUfsDirStats;
    sd->maintainfs = storeUfsDirMaintain;
    sd->checkobj = storeUfsDirCheckObj;
    sd->checkload = storeUfsDirCheckLoadAv;
    sd->refobj = storeUfsDirRefObj;
    sd->unrefobj = storeUfsDirUnrefObj;
    sd->callback = NULL;
    sd->sync = NULL;
    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;
    sd->log.open = storeUfsDirOpenSwapLog;
    sd->log.close = storeUfsDirCloseSwapLog;
    sd->log.write = storeUfsDirSwapLog;
    sd->log.clean.start = storeUfsDirWriteCleanStart;
    sd->log.clean.nextentry = storeUfsDirCleanLogNextEntry;
    sd->log.clean.done = storeUfsDirWriteCleanDone;

    parse_cachedir_options(sd, options, 1);

    /* Initialise replacement policy stuff */
    sd->repl = createRemovalPolicy(Config.replPolicy);
}

该函数较长,其主要就是填充_SwapDir结构体(非常重要,另外分析)

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;

重点看上面几句,其表示了关于存储IO的回调函数设置。

我们看看storeUfsRead

void
storeUfsRead(SwapDir * SD, storeIOState * sio, char *buf, size_t size, squid_off_t offset, STRCB * callback, void *callback_data)
{
    ufsstate_t *ufsstate = (ufsstate_t *) sio->fsstate;

    assert(sio->read.callback == NULL);
    assert(sio->read.callback_data == NULL);
    sio->read.callback = callback;
    sio->read.callback_data = callback_data;
    cbdataLock(callback_data);
    debug(79, 3) ("storeUfsRead: dirno %d, fileno %08X, FD %d\n",
    sio->swap_dirn, sio->swap_filen, ufsstate->fd);
    sio->offset = offset;
    ufsstate->flags.reading = 1;
    file_read(ufsstate->fd,
    buf,
    size,
    (off_t) offset,
    storeUfsReadDone,
    sio);
}

ufs是调用file_read

file_read - diskHandleRead - FD_READ_METHOD

#define FD_READ_METHOD(fd, buf, len) (*fd_table[fd].read_method)(fd, buf, len)

注意fd_table是一个全局变量,它以文件fd为索引。

其中read_method 是在下面 fd_open 中赋值的

void
fd_open(int fd, unsigned int type, const char *desc)
{
    fde *F;
    assert(fd >= 0);
    F = &fd_table[fd];
    if (F->flags.open) {
    debug(51, 1) ("WARNING: Closing open FD %4d\n", fd);
    fd_close(fd);
    }
    assert(!F->flags.open);
    debug(51, 3) ("fd_open FD %d %s\n", fd, desc);
    F->type = type;
    F->flags.open = 1;
    commOpen(fd);
#ifdef _SQUID_MSWIN_
    F->win32.handle = _get_osfhandle(fd);
    switch (type) {
    case FD_SOCKET:
    case FD_PIPE:
    F->read_method = &socket_read_method;
    F->write_method = &socket_write_method;
    break;
    case FD_FILE:
    case FD_LOG:
    F->read_method = &file_read_method;
    F->write_method = &file_write_method;
    break;
    default:
    fatalf("fd_open(): unknown FD type - FD#: %i, type: %u, desc %s\n", fd, type, desc);
    }
#else
    F->read_method = &default_read_method;
    F->write_method = &default_write_method;
#endif
    fdUpdateBiggest(fd, 1);
    if (desc)
    fd_note(fd, desc);
    Number_FD++;
}

所以就进入了file_read_method, 在调用系统 _read

int
file_read_method(int fd, char *buf, int len)
{
    return (_read(fd, buf, len));
}