注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Tsecer的回音岛

Tsecer的博客

 
 
 

日志

 
 

linux下cron工具说明  

2013-05-10 22:47:18|  分类: linux知识 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
一、问题的起因
昨天在看findutil代码的时候,发现一个之前比较常用的locate命令也在这个安装包里,所以就大致看了一下locate工具的实现。在看代码的过程中,可以注意到locate并不会在查找的时候来遍历指定的搜索文件夹,而是直接打开一个指定的数据库文件(通过strace命令可以知道,默认路径为/var/lib/mlocate/mlocate.db)文件。
这一点没什么好说的,locate比find速度快的原因就在于它是通过直接读取数据库文件(这是一个文件)而不需要递归遍历所有的文件夹及子文件夹,所以它的系统调用很少,只是一个简单的open/read操作,相对于各种dir的open和readdir来说,这个已经是非常快速的实现了。
在这个locate的执行中,它的功能比较纯粹,当它希望打开的数据库不存在的时候它就不会执行任何的查找操作,直接返回查找失败。那么现在的问题就是这个数据库是谁来更新的?在findutils中看到了一个updatedb文件夹,很显然这个工具将会执行系统文件夹的扫描和更新工作。
执行ps查看系统,这个updatedb并没有作为守护任务存在,那么此时的很有可能就是作为一个crontab的一项来存在,所以首先需要再看一下crontab的实现。
二、crontab
在fedoracore发行版本中,这个cron软件包为cronie软件包,打开代码看一下,再结合该工具的说明手册,可以知道,对于cron来说,它会在下面一些文件夹中查找配置文件
/etc/cron.d/

/var/spool/cron/
两个文件夹中查找定时任务配置文件,
另外还会打开
/etc/crontab
文件来执行这个文件中的配置项。
其实更大的范围内想一下,文件夹其实也是文件,只是它的内容格式由操作系统来维护,就是一个“inode+文件名”的dentry结构,而文件则是完全由用户维护的内容和格式而已。
cronie源代码中对于各种配置文件的加载位于
cronie-1.4.8\src\database.c
文件
load_database(cron_db * old_db)

    if (syscron_stat.st_mtime)
        process_crontab("root", NULL, SYSCRONTAB, &new_db, old_db);

    if (!(dir = opendir(SYS_CROND_DIR))) {
        log_it("CRON", pid, "OPENDIR FAILED", SYS_CROND_DIR, errno);
    }
    else {
        while (NULL != (dp = readdir(dir))) {
            char tabname[MAXNAMLEN + 1];

            if (not_a_crontab(dp))
                continue;

            if (!glue_strings(tabname, sizeof tabname, SYS_CROND_DIR,
                    dp->d_name, '/'))
                continue;    /* XXX log? */

            process_crontab("root", NULL, tabname, &new_db, old_db);
        }
        closedir(dir);
    }

    /* we used to keep this dir open all the time, for the sake of
     * efficiency.  however, we need to close it in every fork, and
     * we fork a lot more often than the mtime of the dir changes.
     */

    if (!(dir = opendir(SPOOL_DIR))) {
        log_it("CRON", pid, "OPENDIR FAILED", SPOOL_DIR, errno);
    }
    else {

        is_local = cluster_host_is_local();

        while (is_local && NULL != (dp = readdir(dir))) {
            char fname[MAXNAMLEN + 1], tabname[MAXNAMLEN + 1];

            if (not_a_crontab(dp))
                continue;

            strncpy(fname, dp->d_name, MAXNAMLEN);

            if (!glue_strings(tabname, sizeof tabname, SPOOL_DIR, fname, '/'))
                continue;    /* XXX log? */

            process_crontab(fname, fname, tabname, &new_db, old_db);
        }
        closedir(dir);
    }
三、查找updatedb的调用位置
[root@Harry ~]# ll /var/spool/cron/
total 0
[root@Harry ~]# cat /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/

# For details see man 4 crontabs

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  *  command to be executed

[root@Harry ~]# ll /etc/cron.d
cron.d/     cron.daily/ cron.deny  
[root@Harry ~]# ll /etc/cron.d/
total 8
-rw-r--r--. 1 root root 113 2009-11-06 00:13 0hourly
-rw-r--r--. 1 root root 269 2013-05-10 22:00 smolt
[root@Harry ~]# cat /etc/cron.d/0hourly
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/
01 * * * * root run-parts /etc/cron.hourly
[root@Harry ~]# cat  /etc/cron.hourly/0anacron
#!/bin/bash
#in case file doesn't exist
if test -x /var/spool/anacron/cron.daily; then
    day=`cat /var/spool/anacron/cron.daily`
fi
if [ `date +%Y%m%d` = "$day" ]; then
    exit 0;
fi

# in case anacron is already running,
# there will be log (daemon won't be running twice).
if test -x /usr/bin/on_ac_power; then
    /usr/bin/on_ac_power &> /dev/null
    if test $? -eq 1; then
    exit 0
    fi
fi
/usr/sbin/anacron -s
anacron对于该命令的说明
       -s     Serialize execution of jobs.  Anacron will not start a  new  job
              before the previous one finished.

anacrontab的配置文件内容
[root@Harry ~]# cat  /etc/anacrontab
# /etc/anacrontab: configuration file for anacron

# See anacron(8) and anacrontab(5) for details.

SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
# the maximal random delay added to the base delay of the jobs
RANDOM_DELAY=45
# the jobs will be started during the following hours only
START_HOURS_RANGE=3-22

#period in days   delay in minutes   job-identifier   command
1    5    cron.daily        nice run-parts /etc/cron.daily
7    25    cron.weekly        nice run-parts /etc/cron.weekly
@monthly 45    cron.monthly        nice run-parts /etc/cron.monthly
[root@Harry ~]# cat /etc/cron.daily/mlocate.cron
#!/bin/sh
nodevs=$(< /proc/filesystems awk '$1 == "nodev" { print $2 }')
renice +19 -p $$ >/dev/null 2>&1
ionice -c2 -n7 -p $$ >/dev/null 2>&1
/usr/bin/updatedb -f "$nodevs"
[root@Harry ~]#
[root@Harry ~]# cat /var/spool/anacron/cron.
cron.daily    cron.monthly  cron.weekly  
[root@Harry ~]# cat /var/spool/anacron/cron.daily
20130501
[root@Harry ~]#
所以cron的执行方式就是执行之后在文件里写入上次执行的时间,下次运行的时候(每隔1分钟检测)看看是否隔天、隔月或者隔周,如果是则执行crontab中指定的内容。
四、crontab配置文件更新
当如果在配置文件中添加新的一项之后,此时需要重启cron吗?cron的手册中说明的是不需要,所以它的确是不需要。在cron的代码中,它通过两种方法来完成对于配置文件的监听,一种是大家都知道的轮询方法,那就是每隔一分钟比较一下文件夹或者文件的修改时间;另一种方法就是通过比较先进的inotify功能来侦听,这样当有文件被写入时,此时cron就会被唤醒,从而重新夹在配置文件,看是否有配置更新需要执行。
void set_cron_watched(int fd) {
    pid_t pid = getpid();
    int i;

    if (fd < 0) {
        inotify_enabled = 0;
        return;
    }

    for (i = 0; i < sizeof (wd) / sizeof (wd[0]); ++i) {
        int w;

        if (open(watchpaths[i], O_RDONLY | O_NONBLOCK, 0) != -1) {
            w = inotify_add_watch(fd, watchpaths[i],
                IN_CREATE | IN_CLOSE_WRITE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO |
                IN_MOVED_FROM | IN_MOVE_SELF | IN_DELETE | IN_DELETE_SELF);
            if (w < 0) {
                if (wd[i] != -1) {
                    log_it("CRON", pid, "This directory or file can't be watched",
                        watchpaths[i], errno);
                    log_it("CRON", pid, "INFO", "running without inotify support", 0);
                }
                inotify_enabled = 0;
                set_cron_unwatched(fd);
                return;
            }
            wd[i] = w;
        }
    }

    if (!inotify_enabled) {
        log_it("CRON", pid, "INFO", "running with inotify support", 0);
    }

    inotify_enabled = 1;
}
  评论这张
 
阅读(1461)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017