古黑币3 个
成长值6372 点
金币525 个
精华贴3 个
今生相逢便是缘分,何苦去怨恨,何苦去仇视。
我是一个非常精密的存储介质,虽然具有坚固冰冷的外表,让人有种冷酷到底的感觉,但是你们却不知道我的内心是非常脆弱的~
4 s p: S8 H o2 |. j# ~. z
8 }( q5 k s4 h 我知道CPU和内存是计算机的核心,毕竟所有的运算最后都得通过他们俩来完成,CPU从内存里要取一条指令,做计算,然后再写回内存,如此周而复始。
0 l' w, @7 |0 o! b+ ?
8 [' g+ `1 B5 R% c- f8 Q' w 但是这俩货却瞧不起我,说这是什么年代了,还在用机械式操作,读写数据的时候,还得一个磁头在多个盘片上滑来滑去,找来找去,速度慢的要死。
" G8 F3 Q+ ?! }3 B7 g3 g6 S$ V3 Y: p; A* _( U. B
# c3 f9 ]. M* D$ m! v 内存说:“CPU比我快100倍,比你快100万倍,整个系统的速度都被你给拖慢了。”#j318:" g; H2 L1 n& V; c. m, J, a
% x. D0 D) L0 g+ }/ y S 他俩还嘲笑我很娇气,得真空、密闭、不能有浮尘、运行时不能震动,一动就坏了。但这俩二货总是会忘记他俩的最大问题,所以我只用一句就把他们俩给噎死:你们俩断电了怎么办?; V; h: S4 j; g% D$ R& M
- j {( M7 `) Y* I 还有我的容量都是按TB,甚至PB来算的,就你们俩那点容量,还笑我?还有,没有我来存储程序,你们从哪儿得到程序,难道要像牵牛星(如下图)一样,手工拨动一排开关来输入程序吗?8 i( S" P9 n% a- P. J
+ w4 `; m4 L: P! b5 ^$ z
" G- `& i8 `; r; D1 p
其实我也很纳闷,为什么你们人类造不出来一个能够断电存储的,大容量的,访问速度快的,当然还要便宜的硬盘来,你们不都上天了吗?要登陆火星了吗?这些基础的材料怎么还无法突破?#j331:& n0 n7 i5 s o9 {% d
6 s/ r2 C, i! {; i
我憧憬着这么一天的来临,如果能制造出来了,CPU就可以直接访问硬盘了,内存就一边凉快去吧。
, L6 }! p2 k ~0 C+ h4 D5 }* |% ~/ A6 V9 I# y- O- ~+ {2 g0 `
在制造出来之前,你们必须得容忍CPU-内存-硬盘之间的速度不匹配,并且想出办法来解决这种速度的不匹配,比如用缓存、直接内存访问、多进程/线程切换等等方法。
0 A, g! I1 i4 ~/ | . i# q6 F/ O3 m8 Y8 \
我 的 内 部 结 构
- N# j$ \ c6 R0 N. X, c h- t% b- x
& e' N" Y6 y6 W0 I7 A# ~- k
看到没有,我有很多个盘片像串糖葫芦一样被串在一个主轴上,主轴带着他们疯狂的旋转。# _3 M' Z5 G+ k$ `
" r4 o7 P% v( P9 t: I: L
每个盘片都有很多一圈一圈的磁道,每个磁道又分为一个一个的扇区。) K' e9 W3 C" t$ D- M0 }. l5 r
: g+ y- A- M% v9 z4 U$ }
多个盘片上的同一位置的磁道组成了一个柱面(需要发挥一下你的想象力)
6 T6 f. W4 o& W; N% V! @0 ^) Y' I9 w* S- S
最后每个盘片上都有可以读写数据的磁头。
& l$ {* [" f( W' A; I7 j 0 E. o2 J6 s1 r0 M
所以,如果你想访问我的数据,可以说:把0柱面,0磁头,1扇区的数据给我拿来。
7 C' l; P. _+ a$ `
3 d$ D% |; H" P% u 我就把磁头挪到您指定的柱面,对每个磁盘来讲其实就是指定的磁道,所以这叫“寻道时间”9 Z6 a) i- ^% Q3 f# F
- W! M0 O, \" D) G+ E, n1 t
然后再旋转磁盘,让磁头指向您指定的扇区,这才能开始读取数据,这叫“旋转时间”,转速快的硬盘能更快的旋转到特定扇区,所以性能会更好些。
' p: H- B. I6 ^5 q% ]2 L; B4 c+ B! n( m [
什 么 是 文 件 , P$ Y$ P7 E* h6 ?) |0 R
- e' _8 T- x9 { 当然,对于绝大部分人来说,都不想去了解什么柱面,磁头,扇区这些非人的术语,所以我为懒人们专门提供了一个叫做逻辑块的方式,你看到磁盘就是有一个个“块”组成的,编号为1,2,3,..n。
/ J6 e: b% a% {- a4 j
! ~/ q3 @% N- x& {- v 想取哪一块就取哪一块,比如你说:把第1024号的“块"的数据给我取过来,我在内部就把1024转化成柱面,磁头,扇区,按照上面说的方法寻道,旋转,读取数据。
6 v$ T# h; E. H; _: R9 R+ d. N2 N" `/ A* I" h- x7 q9 V; D: f
但是这还远远不够,比方说你想写个文档,输入了很多字和图片,最后想存到我这个硬盘上,你该怎么操作?#j321:4 m4 |# ^* p8 \0 b) o
8 f9 q$ j: X) r1 k, D
一种方法是这样的:- q$ W a9 g7 [& r& Z- y
0 |. o5 D0 y$ R* |( j 你:硬盘,给我找20个空闲的磁盘块,我想存我的文档。
% w1 D% ?6 }7 b; J2 a
r' e3 K5 C) Y8 F/ U) _ 我:空闲的磁盘块编号是1024,2048,2049,3000,......
0 t0 k( c0 x1 R2 B% B0 ^7 ~* H" l: y& R3 K8 X0 w# M/ z
你:把这些文字和图片存到这些磁盘块上。% K4 L" f% ]# V2 ~1 u* m" m2 d
, S7 t# T$ T% \) \9 H: r
我:好的,存完了,你得记住这些块啊,这样下次才能读取。2 ~1 ^+ s5 c! l5 f
. `1 H0 O$ h- `4 M$ I
你:拿一支笔把这些磁盘块编号都记到本子上。3 Z" b+ M6 Y5 s0 w* D
- m4 ~; N3 V2 h; D( ^ 过了几天......! U# l9 i$ }3 S; u" x3 F
" R' y& K$ p" l4 V: ~5 _6 `5 G
你:硬盘,把1024,2048,2049,3000这些数据给我取出来,我要编辑。8 Z2 o* o8 @0 C
3 f" N9 a2 X% A* R7 |
我:好的,这是你的数据。
+ j, L O. f& l0 L: T+ g& ~2 o9 ]
( @" H1 ^; C! ^. S 没有人喜欢这种方式,太折磨人了!
3 L6 x8 x) \9 M4 s: o 所以你们更喜欢这么做:0 r. ?4 `8 S! U% z) Y
! E0 B- k) O3 s3 z4 m8 d 打开word->新建一个文件->输入文字和图片->保存到:D盘\我的文档 目录下。5 p! H/ ^5 j- A! X6 m8 B3 j, V
+ ]* ^5 L7 q7 o' G! o 这个所谓的“文件”和“目录”就是我的杰作啊,你再也不需要和烦人的磁盘块打交道,只需要记住你的文件名和路径,一切工作交由我和操作系统老大来搞定。6 c! t5 n, V. H" O3 p
) s$ ]4 ]! {! Z1 e' Z) Q 我和老大商量好了,文件对人类来说是最小存储单位,你想存任何东西,无论多么小,非得建个文件不可。
. H( ?" R4 P& m( c' N
% {' z5 ~/ ^9 O 此外为了让这个世界整洁有序,多个文件可以放到一个目录(其实也是个特殊的文件)里,目录之上还可以有目录,形成一个树的结构。
% a2 Z* d" B6 p9 d; N3 Z: d% ]
& E( P9 b9 b$ y: E7 K 文件这个东西是个伟大的发明,我估计你们还得再用100年。#j346:7 w4 Y" G: m7 I7 u
/ e. Q. S6 [2 f5 ^% ] `- K
文 件 的 存 放 9 X# {" x7 k/ m1 B+ h) ~
2 ]. n* N7 v6 [8 z+ p 我日常的主要工作就是对目录和文件做操作,当然需要操作系统老大的配合,好吧,其实是老大在主导。$ U% } }: ^6 D
1 Z0 E* @, |$ x r
这其中最重要的一个问题怎么去记录各个文件都用到哪些磁盘块?
* k* G& d; Y$ E1 t. T; {/ l( G1 o* K/ z% P
内存给我支了一招:你可以采用连续记录的方式啊,就像这样。8 ~) u0 |* U. T3 m7 O5 Q
5 n4 E7 C; J \# a! q( E; F+ n
# G8 V K. ^8 b M% `
$ |' S9 H( e9 w9 [/ E" w 文件1占据磁盘块1-3
- B; I4 X) x$ A, z 文件2占据磁盘块8-12
! i/ y& i& ^0 o1 Y 文件3占据磁盘块15-20
- S9 r* u, R) B" |1 N( M
* s! D1 i3 }5 I6 Z0 ^4 l+ l \. Q 内存说:这种方法在随机访问文件是效率极好,因为你只要知道了开头和长度,就像数组一样可以随便访问,就像CPU访问我一样,只要给出地址,立刻就能定位到指定的位置。0 s. n# u v8 i3 b9 R, O! Y
8 |3 {7 A2 |3 a
我仔细想了想,内存出的是一个损招,比如说内存磁盘块4-7,以及13-14怎么没用?
8 E$ \1 E- S$ v3 a( c; @: Z- x
0 |; K( t* e8 B: _ 那是因为之前那里也有文件,后来被删除了,留下了空洞,如果之后没有大小合适的文件过来,他们就永远空在那里了。 x2 \* T2 U7 l7 M) P
, E. C. p, t2 ^1 h# r* t 对我来说这是严重的浪费,这是我不能容忍的。* |$ f, e2 ~% R) I
) }1 ?4 n" m. N
我说:“小样你以为我看不出来啊,你不就是嫉妒我容量大,让我浪费一点嘛”!) j. J- f+ C6 A5 a$ }- g
, G! f% P; t' {* T4 B# ^ 内存坏笑了一下又说:不喜欢也没关系嘛,试试采用链式啊:
9 O) W) A6 p0 Q9 G ^
: ^$ q2 a* a$ f! ^6 Z+ o
; Z9 O# s, i/ b; m8 @2 p$ Y j8 |* j. }6 Q+ b
这个文件从第一块磁盘开始,形成一个链1->9->18->8->3,每一块空闲的磁盘都会得到充分的利用,效率非常高。! ^( q+ c* n4 B3 r! z0 _
4 y: s4 x% @& F2 a5 M
我心想:这些码农说的数据结构和算法还真是有用啊,这里也用上链表了。可是这种方式随机的访问效果太差,每次都得从第一块开始,沿着绳子往后找,太痛苦了。) Z+ ?! Z0 d2 v% X0 ?; o3 a
* o; |5 i1 L) B& X 现在内存已经嘲笑我慢了,用这种很慢的办法,还不得笑死我?操作系统老大说:“别听内存在那里BB了,用索引式!”9 c/ O# e& M% [" E: ?* _
0 L$ |( q% W% L+ L1 }
4 {. K$ \% K( R2 J b5 Y# d
3 d* G5 \! H5 n3 { 例如第16号磁盘块专门用来存放文件属性以及该文件所使用的磁盘块。
+ p1 X7 ^! S0 x
2 C; m- x* S5 A 老大把这个磁盘块叫做inode,通过它可以轻松的找到这个文件所使用的所有磁盘块,无论是顺序访问还是随机访问都很快。% R2 O- t1 {$ c* V8 i) b
/ ^6 I; l8 N' {( q2 g
唯一的缺点是得用额外的磁盘块单独存放inode。
! I* G& R/ U' m7 ]! j; P; n( `; X8 ^- K) U2 M X0 z o
我觉得挺好,没有十全十美的东西,折中达到平衡最重要!就是它了!#j325:& _1 d/ L' b) z2 \3 { Y
7 `, p- v6 l" c0 x 我问老大:每个文件都需要有个inode来描述,每个目录是不是也需要一个?
0 ?7 |' V( f1 b z2 l: X2 ?* _* K- E M: R& }
”这是自然,和文件一样,每个目录也是一个inode,其中有目录的属性,还有存放这个目录内容的磁盘块号,在磁盘块中才真正的存放着目录下的内容“。
* P6 j8 v4 r; a9 J9 k& j- \( P, u4 k( V. }- }3 E
, N7 R$ S; M) V1 v- p6 \
4 r7 U( k: A3 r7 { “举个例子来说吧:有人要读取/tmp/test.log这个文件,查找次序是这样的:根目录inode->根目录磁盘块->tmp目录inode->tmp目录磁盘块->test.log的inode->读取磁盘块”
0 E! T6 P; M# y- k Q7 X
7 y0 \- m* @. X* M5 D ~+ S
, q+ i! w1 l- Z. T9 j' e: `" H, K! ?3 A& \$ h; `5 x7 y
内存说:“卧槽!这也太绕了吧,比CPU访问我的数据麻烦多了,硬盘,你要小心点,这要是操作不当的很容易出乱子的。”#j340:4 D% t _; P u: ]
% N& T( v8 v* ]/ Z
我心想内存这次没坑我,他提醒的对,这操作确实有点复杂,读数据的时候还行,如果是修改,尤其是删除就很容易出事,例如想删除上面的文件/tmp/test.log,需要这些步骤:9 r& o. H* N, x$ H
: h7 v7 [2 @" B# _6 ~0 D (1)在目录中删除文件$ D& L% F4 c- r/ q; {2 L
(2)释放inode到空闲的节点池,这样可以复用
" L, S6 R6 w0 v+ K* [& M" P (3)将磁盘块释放到空闲的磁盘块池7 Z9 Z* V9 k7 U1 V" @
7 e( C* r2 o2 r# H6 l, m. `; [ 在操作某一步的时候出现系统崩溃,那我这些个目录和文件就凌乱了,可能会出现空间无法释放的情况。1 E5 R+ c% b/ G: a" M6 Q; f9 ~* j
; c ^) ~& X# Q/ A3 N 系统老大说:“这确实比较烦,不过也能解决,听说过数据库是怎么办的吗:记录日志!”
8 ]1 b; V2 _" W
% K' {! Y& ]! A- n6 {# N* Q ”就是把要做的事记录下来?“
/ _+ P' z& C E1 e4 S1 w1 T- D$ }9 S# x' q; Y9 O
“是的,在做操作之前,记录要做的事情,形成日志,把他们成功写入磁盘以后再正式动手操作,等到所有步骤都搞完,才可以擦除日志项。你想想,如果执行到某一步崩溃,系统重启时检查日志项,就知道哪些没做,哪些已经做了,对于没做的日志,重新来一遍就是了”。0 D9 f; j6 i& `2 J' H- K
8 e3 j) X2 V; }& G" c& X! ?: M
其实说的很轻松,实施起来还是挺难的,重新执行就意味着那些操作一定是可以重复执行,并且不会带来破坏才行。
: ]( x2 G7 U" I4 |
! a9 P$ ?) I/ U* [+ r管 理 空 闲 块
. @5 H3 I0 q1 d3 C" Y( g4 y: \5 }1 h( a0 Q
目录和文件的存储问题解决了,接下来我需要一个大管家,把那些没有使用的、空白的、数量上亿的磁盘块给管理起来,只有这样,新的文件来的时候,才能分配空间存储。
/ t( `0 p n8 n2 v$ G9 ?% y% ^4 M9 x8 Y- \8 N
操作系统老大给我推荐了两位,第一位主张是链式大法好,无非就是把空闲磁盘块组成一个链表(又是链表!),但是我心里盘算了一下:如果磁盘块号是32位的,每个块都得花费我32位的空间,如果我有5亿个空闲块,那仅仅为了记录他们就要占用接近2G的磁盘空间!这浪费可是有点大啊。$ z l& r' k$ `& d0 v& X
7 |" r- L% O( r" C: x5 }: q2 M6 J! a
还有一位主张位图法,这个方法更简单,对每个磁盘块,如果已经被使用,那就标记为1,没被使用就是0。这样整个磁盘块就形成了一个由0和1组成的一个大位图。
. m5 e3 Z1 j5 @! a0 d0 x' _- \ ?" [9 O) q" A! N& i
9 T4 d1 q$ F6 `9 A. L% D: o' x) g, Y; K* x7 g! U' T! W( g
由于每个磁盘块只用一个位来表示,非常节省空间,这个方案我喜欢!#j327:
/ k u9 V. G' X
2 d# O# T; Z8 Q1 s3 Y# t文 件 系 统
2 S, h) ~, \" N: [* ?" C" w8 B/ @
. R4 i* @, m! E- J 扯了这么多,是时候看一看全局了,在你们程序员的眼中,其实我是长这个样子的(拿Linux ext2为例):
/ p* H0 V2 Y" o; T9 \
& x5 j) E2 _* p* g G8 E4 f; d, q) z% E1 e b$ q
% I" Z* ~/ N! o. S
我这个硬盘主要由MBR(Master Boot Record)和各个磁盘分区组成。 b6 ^5 U2 V8 ]3 Y5 W1 l+ E% p
- d* U4 z6 w# T7 W* N7 d5 R
MBR中的有引导代码和磁盘分区表,分区表中记录了每个分区的起始位置,以及哪个磁盘分区是活动分区,这样系统就会找到它,然后装载这个分区中的引导块,并执行之。/ Q+ o; q8 B) C! O% Z! O
& x1 s4 I! {/ N- ]+ r
引导块将会装载存存储在本分区的操作系统。需要注意的是,每个分区都有一个引导块,不管这个分区有没有操作系统,这是各大厂商的约定,是一种标准。
6 ~. k6 k4 p9 E: ]7 ?; X& A! u. H$ o% [
每个分区除了必须的引导块之外,又被分成多个块组。
; z0 q- u3 ?3 j) T! H; E
% d0 |# n* \1 x/ s2 \, k& ] 在每个块组中你能看到熟悉的磁盘块位图和inode位图,不用解释估计你也知道是干嘛的。还有inode表(当然是存放文件和目录的inode了)和真正的数据块。
+ \+ N& W. S4 g! N" W j* l' c9 p! K, Y9 X" E" y
对了,我的磁盘分区表只有64个字节,而每个分区项占用16个字节,所以只能容纳4个分区。如果你想用多于4个分区,你就需要把其中一个设为扩展分区,然后在其中继续划分成逻辑分区,想划几个就划分几个。6 \7 @2 Q- }* ^7 t' b
" y& ? g- ]- B* e5 E$ m4 J1 ^ 一般情况下,大家都喜欢把我划分成一个主分区+一个扩展分区,在扩展分区中再需要划分。
6 g% {1 r- u( Q2 L, W# I# j; o$ V
|
|