Skip to content

Write Durability

Won-Kyu Park edited this page Aug 28, 2026 · 2 revisions

์“ฐ๊ธฐ ๋‚ด๊ตฌ์„ฑ๊ณผ ์†์ƒ ๋ณต๊ตฌ

commit()์ด ๋„์ค‘์— ๋Š๊ธฐ๋ฉด ์–ด๋–ป๊ฒŒ ๋˜๋Š”๊ฐ€, ๋‹ค๋ฅธ ๋ฒ„์ „ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ์€ ์ด ๋ฌธ์ œ๋ฅผ ์–ด๋–ป๊ฒŒ ํ‘ธ๋Š”๊ฐ€, ์šฐ๋ฆฌ๋Š” ๋ฌด์—‡์„ ํ•ด์•ผ ํ•˜๋Š”๊ฐ€์— ๋Œ€ํ•œ ์ •๋ฆฌ๋‹ค.

๋ฐœ๋‹จ์€ ๋‹จ์ˆœํ•œ ์งˆ๋ฌธ์ด์—ˆ๋‹ค. ๋””์Šคํฌ๊ฐ€ ๊ฝ‰ ์ฐจ๊ธฐ ์ง์ „์— ์ปค๋ฐ‹์„ ํ•˜๋‹ค๊ฐ€ ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„์„ ์“ฐ๋Š” ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋‚˜๋ฉด, ๋ฒ„์ „ ํŒŒ์ผ์„ ์‚ด๋ฆด ์ˆ˜ ์žˆ๋‚˜?

์‚ด๋ฆด ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๊ณ  ์—†๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋Š”๋ฐ, ์ง€๊ธˆ ์ฝ”๋“œ๋Š” ๋‘˜ ๋‹ค ๋ชป ์‚ด๋ฆฐ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์‚ด๋ฆด ์ˆ˜ ์žˆ์—ˆ๋˜ ๊ฒฝ์šฐ๊ฐ€ ์ƒ๊ฐ๋ณด๋‹ค ๋งŽ๋‹ค๋Š” ๊ฒŒ ์ด ๋ฌธ์„œ๋ฅผ ์“ด ์ด์œ ๋‹ค.

ํ•œ๋ˆˆ์— ๋ณด๊ธฐ

  • commit()์€ ์˜› HEAD๋ฅผ ์ œ์ž๋ฆฌ์—์„œ ํŒŒ๊ดด์ ์œผ๋กœ ๋‹ค์‹œ ์“ด๋‹ค. ๋˜๋Œ๋ฆด ๊ธฐ๋ก์ด ์—†๋‹ค.
  • write() ํ•œ ๋ฒˆ์€ ์›์ž์ ์ด์ง€ ์•Š๋‹ค. ์ฝ”๋“œ ์ฃผ์„์ด ๊ทธ๋ ‡๋‹ค๊ณ  ์ „์ œํ•˜๊ณ  ์žˆ๋Š”๋ฐ ์‚ฌ์‹ค์ด ์•„๋‹ˆ๊ณ , ์‹ค์ธก์œผ๋กœ ๋ฐ˜๋ก€๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค.
  • ์ฝ”๋“œ ์ „์ฒด์— fsync๊ฐ€ ํ•˜๋‚˜๋„ ์—†๋‹ค. ๋‹ค๋งŒ ์ด๊ฑด RCS์™€ hg๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋ผ ํŠน๋ณ„ํžˆ ์ด์ƒํ•œ ๊ฑด ์•„๋‹ˆ๋‹ค.
  • ์ •๋ง ์ด์ƒํ•œ ๊ฑด ์šฐ๋ฆฌ๋งŒ ํŒŒ๊ดด์  ์ œ์ž๋ฆฌ ์“ฐ๊ธฐ๋ฅผ ํ•œ๋‹ค๋Š” ์ ์ด๋‹ค. RCSยทgitยทhg ์ค‘ ์–ด๋А ๊ฒƒ๋„ ์‚ด์•„์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋ฎ์–ด์“ฐ์ง€ ์•Š๋Š”๋‹ค.
  • ๋ฐ˜๋Œ€๋กœ ๋น„ํŠธ ํ”Œ๋ฆฝ ๊ด€์ ์—์„œ๋Š” ์šฐ๋ฆฌ๊ฐ€ RCS๋ณด๋‹ค ๋‚ซ๋‹ค. ์ปค๋ฐ‹ํ•  ๋•Œ ์˜› ๋ธ”๋ก์„ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š๊ณ , ํ•ด์‹œ ์ฒด์ธ์ด ์†์ƒ์„ ํƒ์ง€ํ•œ๋‹ค.

1. ์šฐ๋ฆฌ๊ฐ€ ์‹ค์ œ๋กœ ํ•˜๋Š” ์ผ

commit()์˜ ๋‘ ๋ฒˆ์งธ ์ดํ›„ ์ปค๋ฐ‹ ๊ฒฝ๋กœ๋‹ค.

# Single write() call: two separate writes would leave the file with an
# overwritten old HEAD but no new HEAD if the process dies in between.
self.stream.seek(self.head_info["start"])
self.stream.write(old_block_bytes + new_block_bytes)
self.stream.truncate()

์˜› HEAD๊ฐ€ ์žˆ๋˜ ์ž๋ฆฌ๋กœ ๋˜๋Œ์•„๊ฐ€์„œ, ๊ทธ๊ฒƒ์„ ๋ธํƒ€๋กœ ๊ฐ•๋“ฑํ•œ ๋ฐ”์ดํŠธ์™€ ์ƒˆ HEAD์˜ full text๋ฅผ ์ด์–ด ์“ด๋‹ค. ์ฃผ์„์€ write() ํ•œ ๋ฒˆ์ด๋ฉด ์ค‘๊ฐ„์— ์ฃฝ์–ด๋„ ์•ˆ์ „ํ•˜๋‹ค๋Š” ์ทจ์ง€์ธ๋ฐ, ๊ทธ๋ ‡์ง€ ์•Š๋‹ค. ๋ฒ„ํผ๊ฐ€ ๋ถ€๋ถ„์ ์œผ๋กœ flush๋  ์ˆ˜ ์žˆ๊ณ , ์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ๋œ๋‹ค.

2. ์‹ค์ธก: ์–ด๋””์„œ ๋Š๊ธฐ๋ฉด ์–ด๋–ป๊ฒŒ ๋˜๋Š”๊ฐ€

RLIMIT_FSIZE๋กœ ๋””์Šคํฌ ๋ถ€์กฑ์„ ํ‰๋‚ด ๋‚ด์„œ, 300์ค„ ํŒŒ์ผ์— ์„ธ ๋ฒˆ์งธ ๋ฒ„์ „์„ ์ปค๋ฐ‹ํ•˜๋‹ค๊ฐ€ ์ž˜๋ฆฌ๋Š” ์ง€์ ์„ ์˜ฎ๊ฒจ๊ฐ€๋ฉฐ ์ธก์ •ํ–ˆ๋‹ค.

๋Š๊ธด ์ง€์  commit() checkout 1.2 / 1.1 / 1.0 verify()
๋ธํƒ€ ~ ์ƒˆ HEAD ๋ณธ๋ฌธ ๋„์ค‘ OSError ์ „๋ถ€ ์˜ค๋‹ต (len 0 / 7 / 14) KeyError๋กœ ์ฃฝ์Œ
๋ณธ๋ฌธ ์™„๋ฃŒ ํ›„ hash ๋„์ค‘ OSError ์ „๋ถ€ ์ •์ƒ False (์ •์ƒ ํƒ์ง€)
์™„๋ฃŒ ์ •์ƒ ์ „๋ถ€ ์ •์ƒ True

์ฒซ ์ค„์ด ์ตœ์•…์ด๋‹ค. ์„ธ ๋ฒ„์ „์ด ๋™์‹œ์— ์˜ค๋‹ต์ด ๋œ๋‹ค. ์—ญ๋ธํƒ€ ๊ตฌ์กฐ๋ผ ๊ตฌ๋ฒ„์ „์€ ์ „๋ถ€ HEAD ๊ธฐ์ค€ ์ฒด์ธ์ด๊ณ , HEAD ํ•˜๋‚˜๊ฐ€ ๊นจ์ง€๋ฉด ๊ทธ ์ด์ „ ์ „์ฒด๊ฐ€ ๋ณต์› ๋ถˆ๊ฐ€๊ฐ€ ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์†์ƒ์„ ํƒ์ง€ํ•˜๋ผ๊ณ  ์žˆ๋Š” verify()๊ฐ€ KeyError๋กœ ์ฃฝ์—ˆ๋‹ค. ์ž˜๋ฆฐ ๋ธ”๋ก์€ text ํ•„๋“œ ์—†์ด ํŒŒ์‹ฑ๋˜๋Š”๋ฐ ๊ทธ๊ฑธ ๊ทธ๋Œ€๋กœ ์ธ๋ฑ์‹ฑํ•˜๊ณ  ์žˆ์—ˆ๋‹ค. ์ด๊ฑด PR #17์—์„œ ๊ณ ์ณค๋‹ค โ€” ์ด์ œ False๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

3. ์‚ด๋ฆด ์ˆ˜ ์žˆ์—ˆ๋˜ ๊ฒฝ์šฐ

๋ธํƒ€ ๋ธ”๋ก๊นŒ์ง€๋Š” ์˜จ์ „ํžˆ ์“ฐ์˜€๊ณ  ์ƒˆ HEAD๋ฅผ ์“ฐ๋‹ค๊ฐ€ ๋Š๊ธด ๊ฒฝ์šฐ๋ฅผ ๋ณด์ž. ์šฐ๋ฆฌ๋Š” RCS์˜ ci์™€ ๋‹ฌ๋ฆฌ ์ž‘์—… ํŒŒ์ผ์„ ์†Œ๋น„ํ•˜์ง€ ์•Š๊ณ  ๊ทธ๋Œ€๋กœ ๋‘”๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ ์ปค๋ฐ‹ํ•˜๋ ค๋˜ ๋‚ด์šฉ์€ ๋””์Šคํฌ์— ์‚ด์•„์žˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด ์˜จ์ „ํ•œ ๋ธํƒ€๋ฅผ ๊ทธ ๋‚ด์šฉ์— ์ ์šฉํ•˜๋ฉด ์ด์ „ ๋ฒ„์ „์ด ๋‚˜์˜จ๋‹ค. ์‹ค์ œ๋กœ ํ•ด๋ดค๋‹ค.

1.1 block (248B) parses: ver=1.1 is_delta=True has_text=True
recover 1.1 from working file + delta : True
recover 1.0 by chaining further back  : True

์™„์ „ํžˆ ๋ณต๊ตฌ๋œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ SimpleRCS๋Š” ๊ทธ ๋ณต๊ตฌ๋ฅผ ํ•˜์ง€ ์•Š๊ณ  checkout()์ด ์กฐ์šฉํžˆ ๋นˆ ๋ฌธ์ž์—ด์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๋ฐ์ดํ„ฐ๊ฐ€ ๋””์Šคํฌ์— ๋ฉ€์ฉกํžˆ ์žˆ๋Š”๋ฐ ๋ชป ๊บผ๋‚ด๋Š” ์ƒํ™ฉ์ด๋‹ค.

๋ธํƒ€๋ฅผ ์“ฐ๋‹ค๊ฐ€ ๋Š๊ธด ๊ฒฝ์šฐ๋Š” ๋‹ค๋ฅด๋‹ค. ์˜› HEAD์˜ full text๊ฐ€ ๋ฐ˜์ฏค ์ง€์›Œ์กŒ๊ณ  ๊ทธ๊ฒƒ์„ ๋˜์‚ด๋ฆด ์žฌ๋ฃŒ๊ฐ€ ์—†๋‹ค. ์ด๊ฑด ์ง„์งœ ์†์‹ค์ด๋‹ค.

4. ๋‹ค๋ฅธ ์‹œ์Šคํ…œ์€ ์–ด๋–ป๊ฒŒ ํ•˜๋Š”๊ฐ€

์†Œ์Šค๋ฅผ ์ง์ ‘ ์ฝ๊ณ  ํ™•์ธํ•œ ๊ฒƒ๋งŒ ์ ๋Š”๋‹ค.

๋ผ์ด๋ธŒ ๋ฐ์ดํ„ฐ ๋ณ€ํ˜• ์•ˆ์ „์žฅ์น˜ fsync
RCS ,v ์ „์ฒด๋ฅผ temp์— ๋‹ค์‹œ ์”€ temp + rename(), rename ๊ตฌ๊ฐ„ ์‹œ๊ทธ๋„ ์ฐจ๋‹จ, lock ํŒŒ์ผ. ์‹คํŒจํ•˜๋ฉด temp ์œ„์น˜๋ฅผ ์•Œ๋ ค์คŒ ์—†์Œ
CVS RCS ,v๋ฅผ ๊ทธ๋Œ€๋กœ ์”€ RCS ๊ฒƒ์„ ์ƒ์† ์—†์Œ
git ์—†์Œ โ€” object/pack ๋ถˆ๋ณ€ lockfile(O_CREAT|O_EXCL) + rename + atexitยท์‹œ๊ทธ๋„ ์ •๋ฆฌ ์„ค์ • ๊ฐ€๋Šฅ, ๊ธฐ๋ณธ๊ฐ’์ด loose object๋ฅผ ์ œ์™ธ
hg ์—†์Œ โ€” revlog append-only ํŠธ๋žœ์žญ์…˜ ์ €๋„์— append ์ง์ „ offset ๊ธฐ๋ก, ๋กค๋ฐฑ = truncate ์—†์Œ
SimpleRCS ์ œ์ž๋ฆฌ tail-rewrite ์—†์Œ ์—†์Œ

๋„ท ์ค‘ ์…‹์ด fsync๋ฅผ ์•ˆ ํ•œ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์•ˆ ํ•˜๋Š” ๊ฒŒ ํŠน๋ณ„ํ•œ ๊ฒŒ ์•„๋‹ˆ๋ผ๋Š” ๋œป์ด๋‹ค. ํŠน๋ณ„ํ•œ ๊ฑด ๋งˆ์ง€๋ง‰ ์ค„์ด๋‹ค.

hg์˜ ์ €๋„์ด ์ •์ˆ˜ ํ•˜๋‚˜์ธ ์ด์œ 

transaction.py:438์ด ์ €๋„์— ์“ฐ๋Š” ๊ฑด ์ด๊ฒŒ ์ „๋ถ€๋‹ค.

self._file.write(b"%s\0%d\n" % (file, offset))

ํŒŒ์ผ ์ด๋ฆ„๊ณผ append ์ง์ „์˜ ๊ธธ์ด. ๋กค๋ฐฑ์€ ๊ทธ ์˜คํ”„์…‹์œผ๋กœ truncateํ•˜๋ฉด ๋์ด๊ณ  ๋ฐ์ดํ„ฐ ๋ณต์‚ฌ๊ฐ€ 0์ด๋‹ค. revlog๊ฐ€ append-only๋ผ์„œ ๊ฐ€๋Šฅํ•œ ์ผ์ด๋‹ค. ๋ชจ๋“ˆ docstring์ด ์„ค๊ณ„ ์˜๋„๋ฅผ ๊ทธ๋Œ€๋กœ ๋งํ•œ๋‹ค.

As the whole repository is effectively log-structured, this should amount to simply truncating anything that isn't referenced in the changelog.

git์ด loose object๋ฅผ ๊ธฐ๋ณธ์ ์œผ๋กœ fsyncํ•˜์ง€ ์•Š๋Š” ์ด์œ 

content-addressed๋ผ ์ฐข์–ด์ง„ ์˜ค๋ธŒ์ ํŠธ๋Š” ์ž๊ธฐ ํ•ด์‹œ ๊ฒ€์ฆ์— ์‹คํŒจํ•ด์„œ ์Šค์Šค๋กœ ๋“œ๋Ÿฌ๋‚œ๋‹ค. ๊ทธ๋ƒฅ ๋ฒ„๋ฆฌ๋ฉด ๋˜๋‹ˆ fsyncํ•  ์ด์œ ๊ฐ€ ์—†๋‹ค. ๋ฐ˜๋ฉด refs์™€ index๋Š” fsyncํ•œ๋‹ค โ€” ์žƒ์œผ๋ฉด ๋„๋‹ฌ ๊ฐ€๋Šฅ์„ฑ์ด ์‚ฌ๋ผ์ง„๋‹ค.

์šฐ๋ฆฌ์—๊ฒŒ๋„ ํ•ด์‹œ ์ฒด์ธ์ด ์žˆ์–ด์„œ ํƒ์ง€๋Š” ๋œ๋‹ค. ์—†๋Š” ๊ฑด ๋ณต๊ตฌ์ด๊ณ , git๊ณผ ๊ฒฐ์ •์ ์œผ๋กœ ๋‹ค๋ฅธ ์ ์€ ์šฐ๋ฆฌ๋Š” ์ฐข์–ด์ง„ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฒ„๋ฆด ์ˆ˜๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๊ทธ๊ฒŒ ์ด์ „ ๋ฒ„์ „์˜ ์œ ์ผํ•œ ์‚ฌ๋ณธ์ด์—ˆ์œผ๋‹ˆ๊นŒ.

5. ๋ธํƒ€ ๋ฐฉํ–ฅ์ด๋ผ๋Š” ๊ฐˆ๋ฆผ๊ธธ

RCS๋Š” ํ•˜์ด๋ธŒ๋ฆฌ๋“œ๋‹ค

ํ”ํ•œ ์˜คํ•ด๊ฐ€ "RCS = reverse delta"์ธ๋ฐ, ์‹ค์ œ๋กœ๋Š” ๋‘˜ ๋‹ค ์“ด๋‹ค. ๋ธŒ๋žœ์น˜๋ฅผ ๋งŒ๋“  ,v๋ฅผ ์ง์ ‘ ์—ด์–ด๋ดค๋‹ค.

1.2      (trunk HEAD)  text @AAA / BBB-v2 / CCC@        <- full text
1.1      (trunk)       text @d2 1 / a2 1 / BBB@         <- reverse delta (1.2โ†’1.1)
1.1.1.1  (branch)      text @d2 1 / a2 1 / BBB-branch
                             a3 1 / DDD@                <- forward delta (1.1โ†’1.1.1.1)

trunk๋Š” reverse, ๋ธŒ๋žœ์น˜๋Š” forward๋‹ค. ์ด์œ ๊ฐ€ ์žˆ๋‹ค. trunk HEAD๋Š” ๋Š˜ ๋œจ๊ฑฐ์šด ์ฝ๊ธฐ ๋Œ€์ƒ์ด๋ผ reverse๋กœ ๋‘๋ฉด ๊ณต์งœ๋กœ O(1)์ด ๋˜๊ณ , ๋ธŒ๋žœ์น˜๋Š” ๋œ ์ฝํžˆ๋‹ˆ forward๋กœ ๋‘ฌ๋„ ๋œ๋‹ค. ๋Œ€์‹  RCS์˜ ๊ธด ๋ธŒ๋žœ์น˜๋Š” ์‹ค์ œ๋กœ ๋А๋ ค์ง„๋‹ค โ€” forward ์ฒด์ธ์ธ๋ฐ ์ค‘๊ฐ„ ์Šค๋ƒ…์ƒท ์žฅ์น˜๊ฐ€ ์—†์–ด์„œ๋‹ค.

hg๋Š” ๊ทธ forward ๋ฐฉ์‹์„ ์ „๋ฉด ์ ์šฉํ–ˆ๋‹ค

revlog.py:517์˜ deltaparent()๋Š” ํ•ญ์ƒ ์•ž์ชฝ ๋ฆฌ๋น„์ „์„ ๊ฐ€๋ฆฌํ‚จ๋‹ค. ์ƒˆ ๋ฆฌ๋น„์ „์€ ๋’ค์— ๋ถ™๊ธฐ๋งŒ ํ•˜๊ณ  ๊ธฐ์กด ๋ฐ์ดํ„ฐ๋Š” ์†๋Œ€์ง€ ์•Š๋Š”๋‹ค. ๋Œ€๊ฐ€๋Š” ์ฒด์ธ ๊ธธ์ด์ธ๋ฐ, ์ด๊ฑธ ์ค‘๊ฐ„ ์Šค๋ƒ…์ƒท๊ณผ format.maxchainlen์œผ๋กœ ๋ง‰๋Š” ๊ตฌ์กฐ๋‹ค.

์ด๋ก ์€ ๊ทธ๋Ÿฐ๋ฐ ์‹ค์ œ๋กœ ์žฌ๋ณด๋‹ˆ ํฅ๋ฏธ๋กœ์› ๋‹ค. 300์ค„ ํŒŒ์ผ์— 401๋ฒˆ ์ปค๋ฐ‹ํ•œ revlog:

revisions  : 401
  snapshot :   1 (0.25%)     <- lvl-0 ํ•˜๋‚˜๋ฟ
  deltas   : 400 (99.75%)
revision size : 20806        <- 401๊ฐœ ๋ฒ„์ „ ์ „์ฒด๊ฐ€ 20KB
tip chainlen  : 401

sparserevlog๊ฐ€ ์ผœ์ง„ ์ €์žฅ์†Œ์ธ๋ฐ๋„ ์ค‘๊ฐ„ ์Šค๋ƒ…์ƒท์ด ํ•˜๋‚˜๋„ ์•ˆ ์ƒ๊ฒผ๋‹ค. ์ˆœ์ฐจ ํŽธ์ง‘๋งŒ ํ•œ ์„ ํ˜• ํžˆ์Šคํ† ๋ฆฌ๋ผ ๋ธํƒ€๊ฐ€ ์ž‘์•„์„œ ํฌ๊ธฐ ํœด๋ฆฌ์Šคํ‹ฑ์ด "ํ•„์š” ์—†๋‹ค"๊ณ  ํŒ๋‹จํ•œ ๊ฒฐ๊ณผ๋‹ค. ์ฆ‰ tip์„ ์ฝ์œผ๋ ค๋ฉด ๋ธํƒ€ 401๊ฐœ๋ฅผ ์ ์šฉํ•ด์•ผ ํ•œ๋‹ค.

์„ธ ์ขŒํ‘œ

RCS       : O(ํŒŒ์ผ) ์žฌ์ž‘์„ฑ + ์›์ž์„ฑ        HEAD O(1)
hg        : append-only + ์Šค๋ƒ…์ƒท           HEAD ์ฒด์ธ walk (์‹ค์ธก 401)
SimpleRCS : O(tail) ์žฌ์ž‘์„ฑ + ์•ˆ์ „์žฅ์น˜ ์—†์Œ  HEAD O(1)

RCS์˜ ์ „์ฒด ์žฌ์ž‘์„ฑ์€ ๋‚ญ๋น„๊ฐ€ ์•„๋‹ˆ๋ผ ์›์ž์„ฑ์˜ ๋Œ€๊ฐ€๋‹ค. ์–ด์ฐจํ”ผ ์˜› HEAD๋ฅผ ๋ธํƒ€๋กœ ๊ฐ•๋“ฑํ•ด์•ผ ํ•œ๋‹ค๋ฉด โ€” ํŒŒ์ผ ์ค‘๊ฐ„์„ ๊ฑด๋“œ๋ฆฌ๋Š” ์ผ์ด๋‹ค โ€” ํ†ต์งธ๋กœ ์ƒˆ๋กœ ์“ฐ๊ณ  renameํ•˜๋Š” ๊ฒŒ ๊ฐ€์žฅ ๋‹จ์ˆœํ•˜๊ณ , ํฌ๋ž˜์‹œ ์•ˆ์ „์„ฑ์ด ๋”ฐ๋ผ์˜จ๋‹ค.

SimpleRCS๋Š” ๊ทธ O(ํŒŒ์ผ)์„ O(tail)๋กœ ์ค„์ธ ์ตœ์ ํ™”์ธ๋ฐ, ์ค„์ด๋ฉด์„œ ์•ˆ์ „์„ฑ๋„ ๊ฐ™์ด ๋ฒ„๋ ธ๋‹ค. ์†๋„ ์ด๋“์€ ์ง„์งœ์ง€๋งŒ ๊ณต์งœ๊ฐ€ ์•„๋‹ˆ์—ˆ๋‹ค.

6. ๊ทธ๋Ÿฐ๋ฐ ์ถ•์„ ๋ฐ”๊พธ๋ฉด ์ˆœ์œ„๊ฐ€ ๋’ค์ง‘ํžŒ๋‹ค

์ง€๊ธˆ๊นŒ์ง€๋Š” ํฌ๋ž˜์‹œ ์•ˆ์ „์„ฑ ์ถ•์ด์—ˆ๋‹ค. ๋ฉ”๋ชจ๋ฆฌ ์˜ค๋ฅ˜ ์ถ•์—์„œ๋Š” ์ด์•ผ๊ธฐ๊ฐ€ ๋‹ฌ๋ผ์ง„๋‹ค.

RCS์˜ donerewrite()๋Š” ์ปค๋ฐ‹๋งˆ๋‹ค ์ด๊ฑธ ํ•œ๋‹ค.

fro_spew (from, frew);   /* ์˜› ,v ์ „์ฒด๋ฅผ ์ƒˆ ํŒŒ์ผ๋กœ ๋ณต์‚ฌ */
...
chnamemod (...);         /* rename */

fro_spew_partial์€ mmap/๋ฉ”๋ชจ๋ฆฌ ๊ฒฝ๋กœ์—์„œ ์ „์ฒด๋ฅผ ํ†ต๊ณผ์‹œํ‚จ๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ:

  1. ์ปค๋ฐ‹ ํ•œ ๋ฒˆ์— ์ „์ฒด ์ด๋ ฅ์ด RAM์„ ํ†ต๊ณผํ•œ๋‹ค
  2. ๋น„ํŠธ ํ•˜๋‚˜๊ฐ€ ๋’ค์ง‘ํžŒ๋‹ค
  3. ์†์ƒ๋œ ๋‚ด์šฉ์ด temp์— ์“ฐ์ธ๋‹ค
  4. rename()์ด ์›์ž์ ์œผ๋กœ ์„ค์น˜ํ•˜๋ฉฐ ๋ฉ€์ฉกํ–ˆ๋˜ ์›๋ณธ์„ ์ง€์šด๋‹ค
  5. RCS์—๋Š” ๋ฌด๊ฒฐ์„ฑ ๊ฒ€์‚ฌ๊ฐ€ ์—†์œผ๋‹ˆ ์•„๋ฌด๋„ ๋ชจ๋ฅธ๋‹ค

integrity ํ•„๋“œ๊ฐ€ ๊ตฌ์กฐ์ฒด์— ์žˆ๊ธด ํ•œ๋ฐ(base.h:587) ํŒŒ์‹ฑํ•ด์„œ ๊ทธ๋Œ€๋กœ ๋‹ค์‹œ ์“ธ ๋ฟ ๊ฒ€์ฆํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ์—†๋‹ค.

์—ฌ๊ธฐ์„œ ์›์ž์„ฑ์ด ๋…์œผ๋กœ ์ž‘์šฉํ•œ๋‹ค. ์ค‘๊ฐ„ ์ƒํƒœ๊ฐ€ ์—†์œผ๋‹ˆ "๋ญ”๊ฐ€ ์ด์ƒํ•˜๋‹ค"๋Š” ์‹ ํ˜ธ๊ฐ€ ์—†๊ณ , ์ด์ „ ํŒŒ์ผ์€ ์ด๋ฏธ ์‚ฌ๋ผ์กŒ๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ 10๋…„ ์ „ ๋ฆฌ๋น„์ „๋„ ์ปค๋ฐ‹ํ•  ๋•Œ๋งˆ๋‹ค RAM์„ ๋‹ค์‹œ ํ†ต๊ณผํ•˜๋ฏ€๋กœ ๋…ธ์ถœ์ด ์ปค๋ฐ‹ ์ˆ˜์— ๋น„๋ก€ํ•ด ๋ˆ„์ ๋œ๋‹ค. ๋ถˆ์•ˆ์ •ํ•œ ๋จธ์‹ ์—์„œ RCS ํŒŒ์ผ์ด ๋ฌด๋”๊ธฐ๋กœ ๊นจ์ง€๋Š” ๊ฒŒ ์ •ํ™•ํžˆ ์ด ๋ชจ์–‘์ด๋‹ค.

์ปค๋ฐ‹๋‹น RAM ํ†ต๊ณผ ๋ฒ”์œ„ ๋ฌด๊ฒฐ์„ฑ ๊ฒ€์‚ฌ ์†์ƒ ์‹œ
RCS ์ด๋ ฅ ์ „์ฒด ์—†์Œ ์กฐ์šฉํžˆ ์˜๊ตฌ ์†์ƒ, ์›๋ณธ ์†Œ์‹ค
SimpleRCS tail๋งŒ ํ•ด์‹œ ์ฒด์ธ ๋‚˜๋จธ์ง€ ๋ธ”๋ก ๋ฌด์‚ฌ, verify()๊ฐ€ ํƒ์ง€
hg ์ƒˆ ๋ธํƒ€๋งŒ revlog ๋…ธ๋“œ ํ•ด์‹œ ํƒ์ง€ ๊ฐ€๋Šฅ
git ์ƒˆ ์˜ค๋ธŒ์ ํŠธ๋งŒ ์ „๋ฉด content-addressed git fsck, ์†์ƒ๋ถ„๋งŒ ํ๊ธฐ

์šฐ๋ฆฌ tail-rewrite๋Š” ํฌ๋ž˜์‹œ์— ์•ฝํ•˜์ง€๋งŒ ๋น„ํŠธ ํ”Œ๋ฆฝ ๋…ธ์ถœ ๋ฉด์ ์€ RCS์˜ 1/N์ด๋‹ค. ์˜ค๋ž˜๋œ ๋ธ”๋ก์€ ์ปค๋ฐ‹ํ•  ๋•Œ ์ฝ์ง€๋„ ์“ฐ์ง€๋„ ์•Š๋Š”๋‹ค.

์ •๋ฆฌํ•˜๋ฉด ๋ณด์žฅ์˜ ์ข…๋ฅ˜๋ฅผ ๋‚˜๋ˆ  ๋ด์•ผ ํ•œ๋‹ค.

  • ํƒ์ง€๋Š” ํ•ด์‹œ๊ฐ€ ์žˆ์œผ๋ฉด ๊ฐ€๋Šฅํ•˜๋‹ค. ์ด๊ฑด ์ด๋ฏธ ๊ฐ–๊ณ  ์žˆ๋‹ค.
  • ๋ณต๊ตฌ๋Š” ์ค‘๋ณต ์—†์ด๋Š” ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค. ํ•ด์‹œ๋Š” "๊นจ์กŒ๋‹ค"๊นŒ์ง€๋งŒ ๋งํ•œ๋‹ค.
  • ๋…ธ์ถœ ๋ฉด์  ์ถ•์†Œ๋Š” ์„ค๊ณ„๋กœ ๊ฐ€๋Šฅํ•˜๋‹ค. ์†๋Œ€์ง€ ์•Š๋Š” ๋ฐ์ดํ„ฐ๋Š” ๊นจ์ง€์ง€ ์•Š๋Š”๋‹ค.

7. ์„ ํƒ์ง€

A. ์ €๋„ (๊ถŒ์žฅ)

ํŒŒ๊ดด์  ์“ฐ๊ธฐ ์ „์— .srcs.journal์— [head_start][์˜› HEAD ๋ธ”๋ก ์›๋ณธ ๋ฐ”์ดํŠธ]๋ฅผ ์“ฐ๊ณ  flush, ์„ฑ๊ณตํ•˜๋ฉด unlink. ์—ด ๋•Œ ์ €๋„์ด ์žˆ์œผ๋ฉด ๋ณต์›ํ•œ๋‹ค.

hg๋Š” append-only๋ผ undo๊ฐ€ ์ •์ˆ˜ ํ•˜๋‚˜๋กœ ๋๋‚˜์ง€๋งŒ ์šฐ๋ฆฌ๋Š” ๋ฎ์–ด์“ฐ๋ฏ€๋กœ ์˜› ๋ฐ”์ดํŠธ๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ๋น„์šฉ์€ ์ปค๋ฐ‹๋‹น ์ด์ „ full text ํฌ๊ธฐ์˜ ์ถ”๊ฐ€ ์“ฐ๊ธฐ ํ•œ ๋ฒˆ์ด๊ณ , tail-rewrite ์„ค๊ณ„๋Š” ๊ทธ๋Œ€๋กœ ์œ ์ง€๋œ๋‹ค.

์ฃผ์˜: ์ €๋„์€ ์“ฐ๊ธฐ ์–‘์„ ๋Š˜๋ฆฌ๋ฏ€๋กœ ยง6์˜ ๋น„ํŠธ ํ”Œ๋ฆฝ ๋…ธ์ถœ๋„ ํ•จ๊ป˜ ๋Š˜๋ฆฐ๋‹ค. RCS์˜ ์ „์ฒด ์žฌ์ž‘์„ฑ๋ณด๋‹ค๋Š” ์—ฌ์ „ํžˆ ํ›จ์”ฌ ์ž‘์ง€๋งŒ ๊ณต์งœ๋Š” ์•„๋‹ˆ๋‹ค. ์ €๋„ ์ž์ฒด์— ํ•ด์‹œ๋ฅผ ๋ถ™์ด๋ฉด "์ €๋„์ด ๊นจ์กŒ๋Š”์ง€"๋ฅผ ํŒ๋ณ„ํ•  ์ˆ˜ ์žˆ์–ด์„œ, ์†์ƒ๋œ ์ €๋„๋กœ ๋ฉ€์ฉกํ•œ ํŒŒ์ผ์„ ๋ฎ์–ด์“ฐ๋Š” ์ตœ์•…์€ ๋ง‰์„ ์ˆ˜ ์žˆ๋‹ค.

B. RCS์‹ temp + rename

๊ฐ€์žฅ ํ™•์‹คํ•˜๊ณ  ๊ตฌํ˜„๋„ ๋‹จ์ˆœํ•˜๋‹ค. ๋Œ€์‹  ์ปค๋ฐ‹๋งˆ๋‹ค O(ํŒŒ์ผ ํฌ๊ธฐ) I/O์— ์ผ์‹œ์ ์œผ๋กœ 2๋ฐฐ ๊ณต๊ฐ„์ด ํ•„์š”ํ•˜๋‹ค. tail-rewrite๊ฐ€ ์กด์žฌํ•˜๋Š” ์ด์œ ๋ฅผ ์ •๋ฉด์œผ๋กœ ๋ถ€์ •ํ•˜๊ณ , ๋ฌด์—‡๋ณด๋‹ค ๋””์Šคํฌ๊ฐ€ ๊ฝ‰ ์ฐฌ ์ƒํ™ฉ์—์„œ ์ œ์ผ ๋จผ์ € ์‹คํŒจํ•œ๋‹ค โ€” ์ด ๋…ผ์˜์˜ ์ถœ๋ฐœ์ ์ด ๋ฐ”๋กœ ๊ทธ ์ƒํ™ฉ์ด์—ˆ๋‹ค. ยง6๊นŒ์ง€ ๊ฐ์•ˆํ•˜๋ฉด ๋น„ํŠธ ํ”Œ๋ฆฝ ๋…ธ์ถœ๋„ ์ตœ์•…์ด๋‹ค.

C. append-only ์ „ํ™˜

๋ธํƒ€ ๋ฐฉํ–ฅ์„ forward๋กœ ๋’ค์ง‘์œผ๋ฉด ๊ตฌ์กฐ์ ์œผ๋กœ ์•ˆ์ „ํ•ด์ง€๊ณ  ๋ณต๊ตฌ๊ฐ€ truncate๋กœ ๋๋‚œ๋‹ค. ๋Œ€์‹  HEAD ์ฝ๊ธฐ O(1)์„ ์žƒ๋Š”๋‹ค. hg ์‹ค์ธก์ด ๋ณด์—ฌ์ฃผ๋“ฏ tip์„ ์ฝ๋Š” ๋ฐ ์ฒด์ธ ์ „์ฒด๋ฅผ ๊ฑธ์–ด์•ผ ํ•  ์ˆ˜ ์žˆ๋‹ค.

hg๊ฐ€ ์ด ์„ ํƒ์„ ํ•œ ๊ฑด ๋ถ„์‚ฐ VCS๋ผ ์ž„์˜ ๋ฆฌ๋น„์ „ ์ ‘๊ทผ๊ณผ push/pull ๋ณ‘ํ•ฉ์„ ๊ฐ๋‹นํ•ด์•ผ ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด์ง€, ์•ˆ์ „์„ฑ๋งŒ ๋ณด๊ณ  ๊ณ ๋ฅธ ๊ฒŒ ์•„๋‹ˆ๋‹ค. ์œ„ํ‚ค์ฒ˜๋Ÿผ HEAD๋ฅผ ์••๋„์ ์œผ๋กœ ์ž์ฃผ ์ฝ๋Š” ์›Œํฌ๋กœ๋“œ์—์„œ๋Š” ์†ํ•ด๋‹ค.

commit(snapshot=True)๊ฐ€ ์ด๋ฏธ ์˜› HEAD๋ฅผ full text๋กœ ๋‚จ๊ธฐ๋Š” ๊ฒฝ๋กœ๋ผ ์žฌ๋ฃŒ๊ฐ€ ์•„์˜ˆ ์—†์ง€๋Š” ์•Š๋‹ค. ๋‹ค๋งŒ ๊ทธ๊ฒƒ์„ ์จ๋„ ์˜› HEAD ๋ธ”๋ก์„ ์ œ์ž๋ฆฌ์—์„œ ๋‹ค์‹œ ์“ฐ๋Š” ๊ฑด ๋งˆ์ฐฌ๊ฐ€์ง€๋ผ append-only๊ฐ€ ๋˜์ง€๋Š” ์•Š๋Š”๋‹ค.

์–ด๋А ์ชฝ์ด๋“  ๊ฐ™์ด ํ•  ๋งŒํ•œ ๊ฒƒ

  • posix_fallocate ์‚ฌ์ „ ์˜ˆ์•ฝ. statvfs๋กœ ์—ฌ์œ ๋ฅผ ์žฌ๋Š” ๊ฒƒ๊ณผ ๋‹ฌ๋ฆฌ ๊ฒฝํ•ฉ์ด ์—†๊ณ , ENOSPC๋ฅผ ํŒŒ์ผ์„ ๊ฑด๋“œ๋ฆฌ๊ธฐ ์ „์— ์žก๋Š”๋‹ค. ๊ฐ’์‹ธ๊ณ  A์™€ ์ž˜ ๋งž๋Š”๋‹ค โ€” ํ”ํ•œ ์‹คํŒจ(๋””์Šคํฌ ๋ถ€์กฑ)๋Š” ์‹œ์ž‘์กฐ์ฐจ ์•ˆ ํ•˜๊ณ , ๋“œ๋ฌธ ์‹คํŒจ(์ „์›ยทSIGKILL)๋Š” ์ €๋„๋กœ ๋ณต๊ตฌ.
  • ํŒŒ๊ดด์  ์“ฐ๊ธฐ ๊ตฌ๊ฐ„ ์‹œ๊ทธ๋„ ์ฐจ๋‹จ. RCS๊ฐ€ rename ์ฃผ๋ณ€์—์„œ ํ•˜๋Š” IGNOREINTS/RESTOREINTS์™€ ๊ฐ™์€ ๊ฒƒ์ด๋‹ค. signal.pthread_sigmask ๋ช‡ ์ค„๋กœ Ctrl-C์— ๋ฐ˜์ฏค ์“ฐ์ธ ํŒŒ์ผ์ด ๋‚˜์˜ค๋Š” ๊ฑธ ๋ง‰์„ ์ˆ˜ ์žˆ๋‹ค.
  • ์ž‘์—… ํŒŒ์ผ ๊ธฐ๋ฐ˜ ๋ณต๊ตฌ ๊ฒฝ๋กœ. ยง3์—์„œ ๋ณด๋“ฏ ๋ธํƒ€๊ฐ€ ์˜จ์ „ํ•˜๋ฉด ์™„์ „ ๋ณต๊ตฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค. ์ง€๊ธˆ์€ ๊ทธ ๋ฐ์ดํ„ฐ๊ฐ€ ๋””์Šคํฌ์— ์žˆ๋Š”๋ฐ๋„ ์•ˆ ์“ฐ๊ณ  ์žˆ๋‹ค.

8. ๊ถŒ์žฅ

์ด ์ ˆ์€ ๋’ค์ง‘ํ˜”๋‹ค. ์‹ค์ œ๋กœ ๊ตฌํ˜„๋œ ๊ฒƒ์€ B(temp + rename)์ด๊ณ , A(์ €๋„)์™€ ์‹œ๊ทธ๋„ ์ฐจ๋‹จ์€ ํ๊ธฐ๋๋‹ค. ๊ฒฐ์ •์  ๊ทผ๊ฑฐ๋Š” ยง5์˜ ํ‘œ์— ๋น ์ ธ ์žˆ๋˜ ์‚ฌ์‹ค ํ•˜๋‚˜๋‹ค โ€” RCS๊ฐ€ ์ „์ฒด๋ฅผ ์žฌ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ HEAD๋ฅผ ํŒŒ์ผ ์•ž์— ๋‘๊ธฐ ๋•Œ๋ฌธ์ด๊ณ , HEAD๊ฐ€ ๋’ค์ธ ์šฐ๋ฆฌ๋Š” ๋ฐ”๋€Œ์ง€ ์•Š๋Š” ๋ถ€๋ถ„์ด prefix๋กœ ๋‚จ์•„ ์›์‹œ ๋ฐ”์ดํŠธ ๋ณต์‚ฌ๋กœ ๋๋‚œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด B์˜ ๋น„์šฉ ๋…ผ๊ฑฐ๊ฐ€ ๋ฌด๋„ˆ์ง€๊ณ (์ธก์ •: ์œ„ํ‚ค ๊ทœ๋ชจ์—์„œ fsync๊ฐ€ ๋น„์šฉ์„ ์ง€๋ฐฐ), ยง6์˜ ๋น„ํŠธ ํ”Œ๋ฆฝ ๋…ผ๊ฑฐ๋„ ํ•จ๊ป˜ ๋ฌด๋„ˆ์ง„๋‹ค(์žฌ์ง๋ ฌํ™”๊ฐ€ ์—†์œผ๋ฏ€๋กœ). ์ „์ฒด ๋…ผ์˜์™€ ๊ตฌํ˜„ ๊ฒฐ๊ณผ๋Š” Plan-Atomic-Commit์— ์žˆ๋‹ค.

์•„๋ž˜๋Š” ๊ทธ ๊ด€์ฐฐ์„ ํ•˜๊ธฐ ์ „์˜ ํŒ๋‹จ์ด๋ฉฐ, ๊ธฐ๋ก์œผ๋กœ ๋‚จ๊ธด๋‹ค.

A + fallocate + ์‹œ๊ทธ๋„ ์ฐจ๋‹จ.

์šฐ๋ฆฌ ์›Œํฌ๋กœ๋“œ๋Š” HEAD๋ฅผ ์••๋„์ ์œผ๋กœ ์ž์ฃผ ์ฝ๋Š” ์œ„ํ‚ค ํŽ˜์ด์ง€๋‹ค. reverse delta์™€ HEAD O(1)์€ ๊ทธ ์›Œํฌ๋กœ๋“œ์— ๋งž๋Š” ์„ ํƒ์ด๋ฏ€๋กœ ์œ ์ง€ํ•œ๋‹ค. ๋Œ€์‹  RCS๊ฐ€ rename์œผ๋กœ ๊ณต์งœ๋กœ ์–ป๋˜ ์›์ž์„ฑ์„, ์šฐ๋ฆฌ๋Š” ์ค„์—ฌ๋†“์€ ์“ฐ๊ธฐ ๊ตฌ๊ฐ„์— ์ €๋„๋กœ ๋˜๋Œ๋ ค์ค€๋‹ค.

C๋Š” ์‚ฌ์‹ค์ƒ ๋‹ค๋ฅธ ์ €์žฅ ์—”์ง„์ด๋ผ ๋ณ„๋„ ๋…ผ์˜๊ฐ€ ํ•„์š”ํ•˜๊ณ , B๋Š” ์ด ๋…ผ์˜์˜ ์ถœ๋ฐœ์ ์ด๋˜ ์ƒํ™ฉ์—์„œ ๊ฐ€์žฅ ๋จผ์ € ์‹คํŒจํ•œ๋‹ค.

์žฌํ˜„

  • ๋Š๊น€ ์ง€์  ์‹ค์ธก: RLIMIT_FSIZE๋ฅผ base + N์œผ๋กœ ๊ฑธ๊ณ  ์ปค๋ฐ‹ํ•œ ๋’ค ํŒŒ์ผ ์ƒํƒœ๋ฅผ ํ™•์ธ. SIGXFSZ๋ฅผ ๋ฌด์‹œํ•ด์•ผ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ฃฝ์ง€ ์•Š๊ณ  OSError๋ฅผ ๋ฐ›๋Š”๋‹ค.
  • RCS ๋ธํƒ€ ๋ฐฉํ–ฅ: ci/co๋กœ ๋ธŒ๋žœ์น˜๋ฅผ ๋งŒ๋“  ๋’ค ,v๋ฅผ ์ง์ ‘ ์—ด์–ด๋ณธ๋‹ค.
  • hg revlog: ์†Œ์Šค ํŠธ๋ฆฌ์—์„œ PYTHONPATH=<hg์†Œ์Šค> python3 <hg์†Œ์Šค>/hg๋กœ ๋ฐ”๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. hg debugrevlog / hg debugdeltachain์ด ์Šค๋ƒ…์ƒท ์ˆ˜์™€ ์ฒด์ธ ๊ธธ์ด๋ฅผ ๋ณด์—ฌ์ค€๋‹ค.

๊ด€๋ จ

  • Storage Format โ€” ๋ธ”๋ก ๋ ˆ์ด์•„์›ƒ๊ณผ ์—ญ๋ธํƒ€ ๊ตฌ์กฐ
  • Wiki Backend Design โ€” ์ €์žฅ ๋ฐฑ์—”๋“œ ์„ ํƒ๊ณผ ๋ฒค์น˜๋งˆํฌ
  • PR #17 โ€” verify()๊ฐ€ ์ž˜๋ฆฐ ๋ธ”๋ก์— ์ฃฝ๋˜ ๋ฌธ์ œ

Clone this wiki locally