文章目录
  1. 1. Yum Compotents
    1. 1.1. Yum 服务器(repository仓库)
    2. 1.2. Yum客户端
  2. 2. YUM Client process
  3. 3. Client code analysis
  4. 4. appendix (rpm/lib/rpmvercmp.c)

Yum 工作原理

Yum Compotents

Yum 服务器(repository仓库)

  1. 数据:rpm包
  2. 元数据:rpm包的属性,包括大小,版本,依赖关系,通过createrepo命令生成,保存在repodata中

所有要发行的rpm包都放在yum服务器以供下载,rpm包根据kernel版本号,cpu版本号分别编译发布,yum服务器只要提供简单的下载。Yum服务器最重要的环节就是整理出每个rpm包的基本信息即元数据metadata,yum服务器上提供了createrepo工具用于把rpm包的基本概要信息做成一张清单—-元数据

1
2
3
4
5
$ createrepo -o /var/www/yum/centos/5/i386/ /var/www/yum/centos/5/i386
3/3 - rpm_test-0.0.1-3.noarch.rpm
Saving Primary metadata
Saving file lists metadata
Saving other metadata

在createrepo之后会在/var/www/yum/centos/5/i386/生成下面的目录和文件

1
2
3
4
5
6
$ tree repodata/
repodata/
|-- filelists.xml.gz
|-- other.xml.gz
|-- primary.xml.gz
`-- repomd.xml

Filelists.xml记录了rpm包列表,版本号,配置信息
Primary.xml记录了rpm包的依赖信息

Yum客户端

Client每次调用yum install或search都去解析/etc/yum.repo.d下面所有以.repo结尾的配置文件,这些文件指定了yum服务器的地址。Yum定期更新yum服务器上rpm包的清单,把清单保存到yum的本地cache里面,默认在/var/cache/yum。根据清单信息描述,来确定安装包的名字版本号,所需要的依赖包,再去下载rpm包。
本地yum cache /var/cache/yum,每个repo记录的cache

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/var/cache/yum/
|-- base
| |-- cachecookie
| |-- mirrorlist.txt
| |-- packages
| |-- primary.xml.gz
| |-- primary.xml.gz.sqlite
| `-- repomd.xml
|-- epel
| |-- 76c4dcbfaf075e55d5876839eb11c4f33b3a2495-primary.sqlite
| |-- cachecookie
| |-- mirrorlist.txt
| |-- packages
| `-- repomd.xml
|-- firefoxbug
| |-- cachecookie
| |-- packages
| |-- primary.xml.gz
| |-- primary.xml.gz.sqlite
| `-- repomd.xml
|-- timedhosts.txt
|-- updates
| |-- cachecookie
| |-- mirrorlist.txt
| |-- packages
| |-- primary.sqlite
| `-- repomd.xml

我的本地机器的cache

1
2
3
4
5
6
7
8
9
[root@mthz3mpi001 qa_os_centos6.5_x86_64]# pwd
/var/cache/yum/x86_64/6/qa_os_centos6.5_x86_64
[root@mthz3mpi001 qa_os_centos6.5_x86_64]# ll
total 15728
-rw------- 1 root root 0 Jan 8 01:34 cachecookie
drwx------ 2 root root 4096 Jan 7 03:06 packages
-rw------- 1 root root 1470397 Oct 25 15:01 primary.xml.gz
-rw------- 1 root root 14625792 Jan 6 03:19 primary.xml.gz.sqlite
-rw------- 1 root root 1214 Oct 25 15:01 repomd.xml

primary.xml.gz就是yum服务器上的”清单”,但是这里以sqlite方式存储了,可以查看sqlite的db
每次安装yum包都会来查询这个sqlite的DB
timedhosts.txt这个文件记录着所有源地址访问所需要的时间,可以查到哪些源的地址比较慢

YUM Client process

  1. 获取仓库元数据
    Yum会先将仓库的元数据缓存于本地的/var/cache/yum
  2. 安装程序包
    Yum 分析本地的元数据文件,结合本地系统环境(已经安装的包)做出要安装的程序决策
  3. 获取程序包
    根据决策联系yum仓库,下载各程序包缓存于本地后,一并安装

Client code analysis

before code

RPM package names are made up of 5 parts: the package name, epoch, version, release, architecture. This format is commonly referred to as the acronym NEVRA. And the format for the whole string is n-e:v-r.a (i.e foo-0:1.2.3-el5)
In a word, yum compare just compare E.V.R
e.g a sample using labelCompare:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import rpm
# t1 and t2 are tuples of (version, release)
# return 1: a is newer than b

# 0: a and b are the same version

# -1: b is newer than a

def compare(t1, t2):
v1, r1 = t1
v2, r2 = t2
return rpm.labelCompare(('1', v1, r1), ('1', v2, r2))

t1 = ['foo','1.2.5']
t2 = ['foo','1.2.1']
t3 = ['foo','1.2.1']

print compare(t1,t2)
print compare(t2,t3)
print compare(t2,t1)

result:

1
2
3
4
[root@hugwang3 yumtest]# python cmp.py
1
0
-1

最后贴上rpm版本比较的源码

appendix (rpm/lib/rpmvercmp.c)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
include "system.h"
#include <rpmlib.h>
#include "debug.h"

/* compare alpha and numeric segments of two versions */
/* return 1: a is newer than b */
/* 0: a and b are the same version */
/* -1: b is newer than a */
int rpmvercmp(const char * a, const char * b)
{
char oldch1, oldch2;
char * str1, * str2;
char * one, * two;
int rc;
int isnum;

/* easy comparison to see if versions are identical */
if (!strcmp(a, b)) return 0;
str1 = alloca(strlen(a) + 1);
str2 = alloca(strlen(b) + 1);

strcpy(str1, a);
strcpy(str2, b);

one = str1;
two = str2;

/* loop through each version segment of str1 and str2 and compare them */
/*@-branchstate@*/
/*@-boundsread@*/
while (*one && *two) {
while (*one && !xisalnum(*one)) one++;
while (*two && !xisalnum(*two)) two++;

/* If we ran to the end of either, we are finished with the loop */
if (!(*one && *two)) break;

str1 = one;
str2 = two;
/* grab first completely alpha or completely numeric segment */
/* leave one and two pointing to the start of the alpha or numeric */
/* segment and walk str1 and str2 to end of segment */
if (xisdigit(*str1)) {
while (*str1 && xisdigit(*str1)) str1++;
while (*str2 && xisdigit(*str2)) str2++;
isnum = 1;
} else {
while (*str1 && xisalpha(*str1)) str1++;
while (*str2 && xisalpha(*str2)) str2++;
isnum = 0;
}

/* save character at the end of the alpha or numeric segment */
/* so that they can be restored after the comparison */
/*@-boundswrite@*/
oldch1 = *str1;
*str1 = '\0';
oldch2 = *str2;
*str2 = '\0';
/*@=boundswrite@*/

/* this cannot happen, as we previously tested to make sure that */
/* the first string has a non-null segment */
if (one == str1) return -1; /* arbitrary */

/* take care of the case where the two version segments are */
/* different types: one numeric, the other alpha (i.e. empty) */
/* numeric segments are always newer than alpha segments */
/* XXX See patch #60884 (and details) from bugzilla #50977. */
if (two == str2) return (isnum ? 1 : -1);

if (isnum) {
/* this used to be done by converting the digit segments */
/* to ints using atoi() - it's changed because long */
/* digit segments can overflow an int - this should fix that. */

/* throw away any leading zeros - it's a number, right? */
while (*one == '0') one++;
while (*two == '0') two++;
/* whichever number has more digits wins */
if (strlen(one) > strlen(two)) return 1;
if (strlen(two) > strlen(one)) return -1;
}

/* strcmp will return which one is greater - even if the two */
/* segments are alpha or if they are numeric. don't return */
/* if they are equal because there might be more segments to */
/* compare */
rc = strcmp(one, two);
if (rc) return (rc < 1 ? -1 : 1);

/* restore character that was replaced by null above */
/*@-boundswrite@*/
*str1 = oldch1;
one = str1;
*str2 = oldch2;
two = str2;
/*@=boundswrite@*/
}
/*@=branchstate@*/
/*@=boundsread@*/

/* this catches the case where all numeric and alpha segments have */
/* compared identically but the segment sepparating characters were */
/* different */
/*@-boundsread@*/
if ((!*one) && (!*two)) return 0;

/* whichever version still has characters left over wins */
if (!*one) return -1; else return 1;
/*@=boundsread@*/
}
文章目录
  1. 1. Yum Compotents
    1. 1.1. Yum 服务器(repository仓库)
    2. 1.2. Yum客户端
  2. 2. YUM Client process
  3. 3. Client code analysis
  4. 4. appendix (rpm/lib/rpmvercmp.c)