您的位置:首页 > 其它

locate 工作原理

2016-03-27 21:11 239 查看
locate是Linux下实现快速查找文件的工具。

它的搜索速度要比find快很多,因为它在搜索时并没有去遍历文件系统查找,而是在一个索引数据库中进行查找。这个数据库文件在/var/lib/mlocate/mlocatedb(版本不同,会有所不同。有的版本位置是/var/lib/slocate/slocate.db,还有的是/var/cache/locate/locatedb)。此数据库中存储了系统的全部文件名和目录,locate命令就是在这个数据库内查找,所以速度非常快。但locate的查找并不是实时的,而是以数据库的更新为准。所以在查找前,可先运行”sudo updatadb”命令来更新数据库为最新。

整个locate工作其实是由四部分组成的:

/usr/bin/updatedb

/usr/bin/locate(mlocate)

/etc/updatedb.conf

/var/lib/mlocate/mlocate.db

updatedb主要用来更新数据库,这个工作可以通过crontab自动完成的;

mlocate/locate是完成查询功能的程序;

updatedb.conf用来配置数据库中要放入哪些目录和文件,排除哪些文件等;

mlocate.db则是存放文件信息的文件;

locate数据库格式

locate的所有查询操作全部在mlocate.db中进行的。对于mlocate.db,这是一个有一定格式的数据库文件,由文件头和数据组成,下面就结合locate源码详细讲解一下这个数据库的格式。

首先看一下使用hexdump打印出来的mlocate.db文件开始的一部分:

root@ubuntu:/etc# hexdump -c /var/lib/mlocate/mlocate.db | head -30

0000000 \0 m l o c a t e \0 \0 001 ) \0 001 \0 \0

0000010 / \0 p r u n e _ b i n d _ m o u

0000020 n t s \0 1 \0 \0 p r u n e f s \0 A

0000030 F S \0 A U T O F S \0 B I N F M T

0000040 _ M I S C \0 C I F S \0 C O D A \0

0000050 C U R L F T P F S \0 D E V F S \0

0000060 D E V P T S \0 D E V T M P F S \0

0000070 E C R Y P T F S \0 F T P F S \0 F

0000080 U S E . G L U S T E R F S \0 F U

0000090 S E . S S H F S \0 F U S E S M B

00000a0 \0 I S O 9 6 6 0 \0 L U S T R E \0

00000b0 M F S \0 N C P F S \0 N F S \0 N F

00000c0 S 4 \0 P R O C \0 R P C _ P I P E

00000d0 F S \0 S H F S \0 S M B F S \0 S Y

00000e0 S F S \0 T M P F S \0 U D F \0 U S

00000f0 B F S \0 V M H G F S \0 \0 p r u n

0000100 e n a m e s \0 \0 p r u n e p a t

0000110 h s \0 / h o m e / . e c r y p t

0000120 f s \0 / m e d i a \0 / t m p \0 /

0000130 v a r / s p o o l \0 \0 \0 \0 \0 \0 V

0000140 ~ 205 ٠024 D Ꞡ נ \0 \0 \0 \0 / \0 001 b i

0000150 n \0 001 b o o t \0 001 c d r o m \0 001

0000160 d e v \0 001 e t c \0 001 h o m e \0 \0

0000170 i n i t r d . i m g \0 \0 i n i t

0000180 r d . i m g . o l d \0 001 l i b \0

0000190 001 l o s t + f o u n d \0 001 m e d

00001a0 i a \0 001 m n t \0 001 o p t \0 001 p r

00001b0 o c \0 001 r o o t \0 001 r u n \0 001 s

00001c0 b i n \0 001 s r v \0 001 s y s \0 001 t

00001d0 m p \0 001 u s r \0 001 v a r \0 \0 v m

我已经将关键信息加粗显示,结合下面的介绍看的时候会更清楚。

1. 文件头

整个文件头包括header和配置块两部分。mlocate.db文件的最前面的部分由一个db_header结构体表示。

1)header

struct db_header
{
uint8_t magic[8];     /* See DB_MAGIC below */
uint32_t conf_size;       /* Configuration block size, in big endian */
uint8_t version;         /* File format version, see DB_VERSION* below */
uint8_t check_visibility; /* Check file visibility in locate(1) */
uint8_t pad[2];       /* 32-bit total alignment */
/* Followed by NUL-terminated path of the root of the database */
};


其中:

uint8_t magic[8]: 文件开始的8byte是magic number,其值是”\0mlocate”,这个魔数定义在宏DB_MAGIC中:

#define DB_MAGIC { '\0', 'm', 'l', 'o', 'c', 'a', 't', 'e' }


uint32_t conf_size: 接下来的4byte是配置文件的大小,以大端模式存放。

uint8_t version: 1byte保存文件格式版本,目前为0。

uint8_t check_visibility: 可见性标识,1byte。

uint8_t pad[2]: 2byte填充字节和以NUL结尾的根目录。

2)配置块

header后面接下来是配置块,其作用是当配置文件更新后确保过期数据库不会被updabedb使用,对locate没有影响。配置块是一系列由变量名和变量值组成的键值对,其实就是updatedb.conf配置文件中的变量和值。变量值可以由多个字符串组成,每个值以NUL为结束符,整个变量的结束则是由两个NUL字符表示。

当前定义的变量有:

prune_bind_mounts: 单值,PRUNE_BIND_MOUNTS的值;

prunefs: PRUNEFS的值,多字符串,表示排除的文件系统;

prunenames: PRUNENAMES的值,多字符串,表示排除的文件或目录名;

prunepaths: PRUNEPATHS的值,多字符串,排除的路径;

我在上面dump出来的图表中将一些关键部分加粗表示,将上面的图表结合updatedb.conf文件内容对照着看可以看的更清楚。

updatedb.conf文件内容:

root@ubuntu:/etc# cat updatedb.conf
PRUNE_BIND_MOUNTS="yes"
\# PRUNENAMES=".git .bzr .hg .svn"
PRUNEPATHS="/tmp /var/spool /media /home/.ecryptfs"
PRUNEFS="NFS nfs nfs4 rpc_pipefs afs binfmt_misc proc smbfs autofs iso9660 ncpfs coda devpts ftpfs devfs mfs shfs sysfs cifs lustre tmpfs usbfs udf fuse.glusterfs fuse.sshfs curlftpfs ecryptfs fusesmb devtmpfs vmhgfs"


2. 数据部分

文件头后面接下来就是数据库实际保存数据的部分,从这里一直到文件末尾描述了文件系统中的目录及内容,存放格式是“目录+目录内容”,目录后面紧跟着这个目录下的所有内容。

1)目录

每个目录有一段描述信息,由结构体db_directory表示:

/* Directory header */
struct db_directory
{
uint64_t time_sec; /* st_[cm]time of the directory in big endian */
uint32_t time_nsec;
uint8_t pad[4];       /* 64-bit total alignment */
/* Followed by NUL-terminated absolute path of the directory */
};


uint64_t time_sec: 8byte,表示目录的时间(以秒为单位),取最后修改时间和创建时间中较大值(也就是st_ctime和st_mtime中的最大值);

uint32_t time_nsec: 4byte,目录时间(以ns为单位)。如果未知,则设为0,其值小于1000000000;

uint8_t pad[4]: 4type填充值;

目录后面紧跟着一个以NUL字符结尾的字符串记录这个目录的路径。

2)内容

目录内容是一系列的文件节点,紧跟在目录路径后面,

每一项目录内容前面有一个db_entry结构体表示这条内容的类型:

/* Directory entry */
struct db_entry
{
uint8_t type;         /* See DBE_* below */
/* Followed by NUL-terminated name if tag != DBE_END */
};
enum
{
DBE_NORMAL      = 0,    /* A non-directory file */
DBE_DIRECTORY   = 1,    /* A directory */
DBE_END     = 2   /* End of directory contents; contains no name */
};


uint8_t type: 表示类型,根据下面的枚举可以看出来,有3种情况,0 - 非目录文件;1 - 子目录; 2 - 标识当前目录的结尾。

总结

mlocate.db文件中的内容基本上就是这些。

前面是整个文件的头部,有魔数、版本号等;

然后是配置块,其实就是把updatedb.conf配置文件中的内容放到了这里,以便updatedb在更新数据库时放弃可以过期的数据(这里要说了一下,mlocate与slocate一点重要的区别是,前者更新数据库的速度更快,因为mlocate中会有一个目录修改时间的判断,如果发现一个目录的时间没有更新,则不再遍历这个目录,直接将原数据库内容拷贝过来);

后面则是数据库的数据部分,由一个一个的目录及这个目录中的内容组成。locate进行搜索就是在这个部分进行查找并匹配,如果匹配成功则将这条内容打印出来。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: