Alert

์ด ๊ธ€์€ Claude Code์˜ ๋„์›€์„ ๋ฐ›์•„ ์ž‘์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค

TL;DR

  • shell script ๋™์‹œ์„ฑ ๋ฌธ์ œ๋Š” cron ์ค‘๋ณต ์‹คํ–‰ยท๊ณต์œ  ํŒŒ์ผ ๋™์‹œ ์ˆ˜์ •์—์„œ ๋ฐœ์ƒ
  • flock์€ ํŒŒ์ผ์— ์ž ๊ธˆ์„ ๊ฑธ์–ด ํ•œ ๋ฒˆ์— ํ•˜๋‚˜๋งŒ ์ž„๊ณ„ ๊ตฌ์—ญ์— ์ง„์ž…์‹œํ‚ค๋Š” ๋„๊ตฌ
  • flock์€ advisory lock โ€” ๋ชจ๋‘๊ฐ€ ํ˜ธ์ถœํ•ด์•ผ ์˜๋ฏธ๊ฐ€ ์žˆ๊ณ  ๊ฐ•์ œ ์ฐจ๋‹จ์€ ์•„๋‹˜
  • ์ž ๊ธˆ ์†Œ์œ ์ž๋Š” ํ”„๋กœ์„ธ์Šค๊ฐ€ ์•„๋‹ˆ๋ผ open file description(OFD), ์ถฉ๋Œ ํŒ์ •์€ inode ๋‹จ์œ„
  • ํ”„๋กœ์„ธ์Šค ์ข…๋ฃŒ ์‹œ FD๊ฐ€ ๋‹ซํžˆ๋ฉฐ ์ž ๊ธˆ ์ž๋™ ํ•ด์ œ โ€” stale lock ์œ„ํ—˜์ด ๋‚ฎ์Œ
  • ์ด์‹์„ฑ ํ™˜๊ฒฝ์—์„  mkdirยทset -o noclobberยทln์˜ ์›์ž์„ฑ์œผ๋กœ ๋Œ€์ฒด

1. ์™œ ํ•„์š”ํ•œ๊ฐ€ โ€” shell script์˜ ๋™์‹œ์„ฑ ๋ฌธ์ œ

์—ฌ๋Ÿฌ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๊ฐ™์€ ์ž์›์„ ๋™์‹œ์— ๊ฑด๋“œ๋ฆฌ๋ฉด ์˜ˆ์ธก ๋ชป ํ•œ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜จ๋‹ค. shell script์—์„œ ๊ฐ€์žฅ ํ”ํ•œ ๋‘ ์ƒํ™ฉ์€ ์ด๋ ‡๋‹ค.

  • cron ์ค‘๋ณต ์‹คํ–‰: 5๋ถ„๋งˆ๋‹ค ๋„๋Š” ์ž‘์—…์ด ํ•œ ๋ฒˆ์— 5๋ถ„์„ ๋„˜๊ธฐ๋ฉด, ์ด์ „ ์‹คํ–‰์ด ์•ˆ ๋๋‚ฌ๋Š”๋ฐ ์ƒˆ ์‹คํ–‰์ด ๋˜ ๋œฌ๋‹ค. ๋ฐฑ์—…์ด ๊ฒน์ณ ๋Œ๊ฑฐ๋‚˜ ๊ฐ™์€ ํŒŒ์ผ์„ ๋™์‹œ์— ์จ์„œ ๊นจ์ง„๋‹ค.
  • ๊ณต์œ  ํŒŒ์ผ ๋™์‹œ ์ˆ˜์ •: ๋‘ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๊ฐ™์€ ํŒŒ์ผ์— ๋ง๋ถ™์ด๊ฑฐ๋‚˜ ์นด์šดํ„ฐ๋ฅผ ์˜ฌ๋ฆฌ๋ฉด, ์ฝ๊ณ  ์“ฐ๋Š” ์‚ฌ์ด์— ๋ผ์–ด๋“ค์–ด ๊ฐฑ์‹ ์ด ์œ ์‹ค๋œ๋‹ค.

์นด์šดํ„ฐ ์ฆ๊ฐ€๋งŒ ๋ด๋„ ์›์ž์ ์ด์ง€ ์•Š๋‹ค.

# ๋‘ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋™์‹œ์— ๋Œ๋ฉด ๊ฐฑ์‹ ์ด ์œ ์‹ค๋  ์ˆ˜ ์žˆ๋‹ค
count=$(cat counter.txt)            # ๋‘˜ ๋‹ค "10"์„ ์ฝ๊ณ 
echo $((count + 1)) > counter.txt   # ๋‘˜ ๋‹ค "11"์„ ์“ด๋‹ค โ†’ 12๊ฐ€ ์•„๋‹ˆ๋ผ 11

์ด๋ ‡๊ฒŒ โ€œ๋™์‹œ์— ๋“ค์–ด์˜ค๋ฉด ์•ˆ ๋˜๋Š” ๊ตฌ๊ฐ„โ€์„ ์ž„๊ณ„ ๊ตฌ์—ญ(critical section)์ด๋ผ ๋ถ€๋ฅธ๋‹ค. ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ํ”„๋กœ์„ธ์Šค๋งŒ ๋“ค์–ด๊ฐ€๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ๋™์‹œ์„ฑ ์ฒ˜๋ฆฌ์˜ ํ•ต์‹ฌ์ด๋‹ค. ์ž‘์—…์„ ๋ณ‘๋ ฌ๋กœ ๋Œ๋ฆฌ๋Š” ์ชฝ์€ Job Control์—์„œ ๋‹ค๋ค˜๊ณ , ์ด ๊ธ€์€ ๋ฐ˜๋Œ€๋กœ ๊ฒน์น˜์ง€ ์•Š๊ฒŒ ๋ง‰๋Š” ์ชฝ์„ ๋‹ค๋ฃฌ๋‹ค.


2. ์ž ๊ธˆ์˜ ๊ธฐ๋ณธ ์•„์ด๋””์–ด

์ž„๊ณ„ ๊ตฌ์—ญ์„ ํ•œ ๋ฒˆ์— ํ•˜๋‚˜๋งŒ ํ†ต๊ณผ์‹œํ‚ค๋ ค๋ฉด ์ž ๊ธˆ(lock)์„ ์“ด๋‹ค. ๋“ค์–ด๊ฐ€๊ธฐ ์ „์— ์ž ๊ธˆ์„ ์žก๊ณ , ๋‚˜์˜ฌ ๋•Œ ํ‘ผ๋‹ค. ์ด๋ฏธ ๋ˆ„๊ฐ€ ์žก๊ณ  ์žˆ์œผ๋ฉด ๊ธฐ๋‹ค๋ฆฌ๊ฑฐ๋‚˜ ํฌ๊ธฐํ•œ๋‹ค.

shell์—๋Š” ์–ธ์–ด ์ฐจ์›์˜ ๋ฎคํ…์Šค๊ฐ€ ์—†์œผ๋‹ˆ, ํŒŒ์ผ์‹œ์Šคํ…œ์˜ ์›์ž์  ์—ฐ์‚ฐ์„ ์ž ๊ธˆ์œผ๋กœ ๋นŒ๋ ค ์“ด๋‹ค. ๋Œ€ํ‘œ๊ฐ€ flock์ด๊ณ , ๊ทธ ๋ฐ–์— mkdirยทnoclobberยทln์˜ ์›์ž์„ฑ์„ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค(7๋ฒˆ).


3. flock โ€” ์“ฐ๋Š” ๋ฒ•

flock์€ ํŒŒ์ผ์— ์ž ๊ธˆ์„ ๊ฑธ์–ด ํ•œ ๋ฒˆ์— ํ•œ ํ”„๋กœ์„ธ์Šค๋งŒ ์ž„๊ณ„ ๊ตฌ์—ญ์— ๋“ค์–ด๊ฐ€๊ฒŒ ํ•œ๋‹ค. ์ž ๊ธˆ์€ ์ž ๊ธˆ์šฉ FD๋กœ ๊ทธ ํŒŒ์ผ์— ๊ฑธ๋ฆฌ๊ณ , ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋๋‚˜ FD๊ฐ€ ๋‹ซํžˆ๋ฉด ์ž๋™์œผ๋กœ ํ’€๋ฆฐ๋‹ค.

FD๋ฅผ ์ง์ ‘ ์—ฌ๋Š” ํ˜•ํƒœ
exec {lock_fd}>/var/lock/myjob.lock   # ์ž ๊ธˆ์šฉ FD ์—ด๊ธฐ
if ! flock -n "$lock_fd"; then
    echo "์ด๋ฏธ ์‹คํ–‰ ์ค‘" >&2
    exit 1
fi
# --- ์—ฌ๊ธฐ๋ถ€ํ„ฐ ํ•œ ๋ฒˆ์— ํ•˜๋‚˜๋งŒ ---
long_running_job
# ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋๋‚˜๋ฉด FD๊ฐ€ ๋‹ซํžˆ๋ฉฐ ์ž ๊ธˆ ํ•ด์ œ

์ž ๊ธˆ ํŒŒ์ผ ์ด๋ฆ„์˜ .lock ํ™•์žฅ์ž๋Š” ์ˆœ์ „ํžˆ ๊ด€ํ–‰์ด๋‹ค. flock์€ ํ™•์žฅ์ž๋ฅผ ๋ณด์ง€ ์•Š๊ณ  ์•„๋ฌด ํŒŒ์ผ์—๋‚˜(์‹ฌ์ง€์–ด ๋””๋ ‰ํ„ฐ๋ฆฌ์—๋„) ๊ฑธ ์ˆ˜ ์žˆ๋‹ค. ์ž ๊ธˆ์˜ ์˜๋ฏธ๋Š” ์ด๋ฆ„์ด ์•„๋‹ˆ๋ผ flock๊ณผ inode์—์„œ ๋‚˜์˜จ๋‹ค.

์„œ๋ธŒ์…ธ ๋ธ”๋ก ํ˜•ํƒœ
(
    flock -n 9 || { echo "์ด๋ฏธ ์‹คํ–‰ ์ค‘"; exit 1; }
    long_running_job
) 9>/var/lock/myjob.lock
๋ช…๋ น์„ ๊ฐ์‹ธ๋Š” ํ˜•ํƒœ โ€” cron์— ์ข‹๋‹ค

flock์€ ์ž ๊ธˆ์„ ์žก์€ ์ฑ„ ๋ช…๋ น ํ•˜๋‚˜๋ฅผ ์‹คํ–‰ํ•ด ์ฃผ๊ธฐ๋„ ํ•œ๋‹ค. crontab์— ๊ทธ๋Œ€๋กœ ๋„ฃ๊ธฐ ์ข‹๋‹ค.

# job.sh๊ฐ€ ์ด๋ฏธ ๋Œ๊ณ  ์žˆ์œผ๋ฉด ์ด๋ฒˆ ์‹คํ–‰์€ ๊ฑด๋„ˆ๋›ด๋‹ค
flock -n /var/lock/myjob.lock /path/to/job.sh
 
# crontab ์˜ˆ์‹œ โ€” 5๋ถ„๋งˆ๋‹ค, ๊ฒน์น˜๋ฉด skip
# */5 * * * * /usr/bin/flock -n /var/lock/myjob.lock /path/to/job.sh

์ž์ฃผ ์“ฐ๋Š” ์˜ต์…˜:

์˜ต์…˜์˜๋ฏธ
-n์ž ๊ฒจ ์žˆ์œผ๋ฉด ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ์ฆ‰์‹œ ์‹คํŒจ (๋…ผ๋ธ”๋กœํ‚น)
-w N์ตœ๋Œ€ N์ดˆ ๊ธฐ๋‹ค๋ฆฐ ๋’ค ์‹คํŒจ
-x๋ฐฐํƒ€ ์ž ๊ธˆ (์“ฐ๊ธฐ, ๊ธฐ๋ณธ๊ฐ’)
-s๊ณต์œ  ์ž ๊ธˆ (์ฝ๊ธฐ, ์—ฌ๋Ÿฟ์ด ๋™์‹œ์— ๊ฐ€๋Šฅ)
-u์ž ๊ธˆ ํ•ด์ œ (๋ณดํ†ต FD๊ฐ€ ๋‹ซํžˆ๋ฉฐ ์ž๋™ ํ•ด์ œ๋ผ ์ƒ๋žต)

exec์™€ ๋™์  FD({fd}>) ๋ฌธ๋ฒ• ์ž์ฒด๋Š” ์ด ๊ธ€์—์„œ ๋‹ค๋ค˜๋‹ค.

FDํ˜• vs ๋ž˜ํผํ˜• โ€” ์–ธ์ œ ๋ญ˜ ์“ฐ๋‚˜

์œ„ ์„ธ ํ˜•ํƒœ๋Š” ์ž ๊ธˆ์„ ๋ˆ„๊ฐ€ ๋“ค๊ณ  ์–ด๋””๊นŒ์ง€ ๋ณดํ˜ธํ•˜๋А๋ƒ๊ฐ€ ๋‹ค๋ฅด๋‹ค.

  • ๋ž˜ํผํ˜• flock -n lock command: flock์ด ์ง์ ‘ ํŒŒ์ผ์„ ์—ด๊ณ  ์ž ๊ทผ ๋’ค command๋ฅผ ์ž์‹์œผ๋กœ ์‹คํ–‰ํ•˜๊ณ , ๋๋‚˜๋ฉด ํ‘ผ๋‹ค. โ€œ๋ช…๋ น ํ•˜๋‚˜๋ฅผ ํ†ต์งธ๋กœ ์ž ๊ธˆ ์•„๋ž˜โ€ โ€” cron์— ๊ฐ€์žฅ ์ž˜ ๋งž๊ณ  ๊ฐ„๋‹จํ•˜๋‹ค.
  • FDํ˜• exec {fd}>lock; flock -n "$fd": ์ง€๊ธˆ ๋„๋Š” ์…ธ ํ”„๋กœ์„ธ์Šค ์ž์‹ ์ด ์ž ๊ธˆ์„ ๋“ ๋‹ค. ์™ธ๋ถ€ ๋ช…๋ น์„ ๊ฐ์‹ธ๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ์Šคํฌ๋ฆฝํŠธ ์ค‘๊ฐ„์˜ ํ•œ ๊ตฌ๊ฐ„์„ ์ž ๊ทธ๊ณ  ๊ฐ™์€ ํ”„๋กœ์„ธ์Šค์—์„œ ์…ธ ๋กœ์ง์„ ์ด์–ด๊ฐˆ ๋•Œ ์“ด๋‹ค. ์ž์‹์„ ์•ˆ ๋„์šฐ๊ณ , ํ•œ ๋ฒˆ ์—ฐ ์ž ๊ธˆ์„ ์—ฌ๋Ÿฌ ๋‹จ๊ณ„์— ๊ฑธ์ณ ๋“ค๊ณ  ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค.

4. advisory lock โ€” ๊ถŒ๊ณ ์ผ ๋ฟ, ๊ฐ•์ œ๊ฐ€ ์•„๋‹ˆ๋‹ค

flock์—์„œ ๊ฐ€์žฅ ์ž์ฃผ ์˜คํ•ดํ•˜๋Š” ์ง€์ ์ด๋‹ค. flock์ด ๊ฑฐ๋Š” ์ž ๊ธˆ์€ advisory lock(๊ถŒ๊ณ ์  ์ž ๊ธˆ)์ด๋‹ค. ์ปค๋„์ด โ€œ์ด ํŒŒ์ผ์€ ์ž ๊ฒผ์œผ๋‹ˆ ์•„๋ฌด๋„ ๋ชป ๊ฑด๋“œ๋ฆฐ๋‹คโ€๊ณ  ๊ฐ•์ œํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ, flock์„ ํ˜ธ์ถœํ•œ ์ชฝ๋ผ๋ฆฌ๋งŒ ์„œ๋กœ ์–‘๋ณดํ•˜๋Š” ์•ฝ์†์ด๋‹ค.

# A: ์ œ๋Œ€๋กœ ์ž ๊ทธ๊ณ  ๋“ค์–ด๊ฐ„ ํ”„๋กœ์„ธ์Šค
exec {fd}>/var/lock/data.lock
flock "$fd"
echo "์ˆ˜์ • ์ค‘" >> data.txt
 
# B: flock์„ ์•ˆ ๋ถ€๋ฅด๊ณ  ๊ทธ๋ƒฅ ์“ฐ๋Š” ํ”„๋กœ์„ธ์Šค
echo "๋ผ์–ด๋“ค๊ธฐ" >> data.txt   # ๋ง‰ํžˆ์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋ƒฅ ์จ์ง„๋‹ค.

์ฆ‰ ์ž ๊ธˆ์€ ๋ชจ๋‘๊ฐ€ ๊ฐ™์€ ์ž ๊ธˆ ํŒŒ์ผ์— flock์„ ํ˜ธ์ถœํ•  ๋•Œ๋งŒ ํšจ๋ ฅ์ด ์žˆ๋‹ค. ํ•œ ๋ช…์ด๋ผ๋„ ํ˜‘์กฐํ•˜์ง€ ์•Š์œผ๋ฉด ๊ทธ๋Œ€๋กœ ๋šซ๋ฆฐ๋‹ค. ๊ทธ๋ž˜์„œ โ€œ์ด ์ž์›์€ ์ด ์ž ๊ธˆ์œผ๋กœ ๋ณดํ˜ธํ•œ๋‹คโ€๋Š” ๊ทœ์น™์„ ์ฝ”๋“œ ์ „์ฒด๊ฐ€ ์ง€์ผœ์•ผ ํ•œ๋‹ค.

advisory vs mandatory

  • advisory(๊ถŒ๊ณ ): ์ฐธ์—ฌ์ž๊ฐ€ ์ž๋ฐœ์ ์œผ๋กœ ์ž ๊ธˆ์„ ํ™•์ธํ•œ๋‹ค. flock๊ณผ POSIX fcntl ์ž ๊ธˆ์ด ์—ฌ๊ธฐ ์†ํ•˜๊ณ , ์œ ๋‹‰์Šค ์ž ๊ธˆ์€ ์‚ฌ์‹ค์ƒ ์ „๋ถ€ ๊ถŒ๊ณ ์ ์ด๋‹ค.
  • mandatory(๊ฐ•์ œ): ์ปค๋„์ด read/write ์ž์ฒด๋ฅผ ๋ง‰๋Š”๋‹ค. Linux์—๋„ ์žˆ์—ˆ์ง€๋งŒ ๊ตฌํ˜„์ด ๋ถˆ์•ˆ์ •ํ•˜๊ณ  ์œ„ํ—˜ํ•ด ์‚ฌ์‹ค์ƒ ํ๊ธฐ๋๋‹ค(์ปค๋„ 5.15๋ถ€ํ„ฐ ์ œ๊ฑฐ ๊ฐ€๋Šฅ, ๊ธฐ๋ณธ ๋น„๊ถŒ์žฅ). ํ˜„์‹ค์ ์œผ๋กœ ์…ธ ์Šคํฌ๋ฆฝํŠธ์˜ ์ž ๊ธˆ์€ ์ „๋ถ€ advisory๋ผ๊ณ  ๋ณด๋ฉด ๋œ๋‹ค.

advisory๋ผ๋Š” ์‚ฌ์‹ค์˜ ์‹ค๋ฌด์  ํ•จ์˜๋Š” ๋‘˜์ด๋‹ค.

  • ์ž ๊ธˆ ํŒŒ์ผ๊ณผ ์‹ค์ œ ๋ณดํ˜ธ ๋Œ€์ƒ์€ ๋‹ค๋ฅธ ํŒŒ์ผ์ด์–ด๋„ ๋œ๋‹ค. ํ”ํžˆ ์ž‘์—… ํŒŒ์ผ์ด ์•„๋‹ˆ๋ผ ๋ณ„๋„์˜ .lock ํŒŒ์ผ์— flock์„ ๊ฑด๋‹ค. ์ž ๊ธˆ์€ ์•ฝ์†์ผ ๋ฟ์ด๋ผ ์–ด๋””์— ๊ฑธ๋“  ์ฐธ์—ฌ์ž๋งŒ ๊ฐ™์œผ๋ฉด ๋œ๋‹ค.
  • ์ž ๊ธˆ ํŒŒ์ผ์€ ๋‚ด์šฉ์ด ๋น„์–ด ์žˆ์–ด๋„ ๋œ๋‹ค. flock์€ ๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋‹ˆ๋ผ โ€œ์—ด๋ฆฐ ํŒŒ์ผโ€ ์ƒํƒœ์— ๊ฑฐ๋Š” ๊ฒƒ์ด๋ผ ๋นˆ ํŒŒ์ผ๋กœ ์ถฉ๋ถ„ํ•˜๋‹ค.

5. ์ปค๋„์€ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋‚˜ โ€” OFD์™€ inode

flock์˜ ๋™์ž‘์„ ์ •ํ™•ํžˆ ์ดํ•ดํ•˜๋ ค๋ฉด lock์˜ owner๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์•Œ์•„์•ผ ํ•œ๋‹ค. ๋‹ต์€ ํ”„๋กœ์„ธ์Šค๋„ FD ๋ฒˆํ˜ธ๋„ ์•„๋‹Œ open file description(OFD)์ด๋‹ค.

open ํšŸ์ˆ˜๋งŒํผ OFD๊ฐ€ ์ƒ๊ธด๋‹ค
P1: exec {fd1}>/tmp/lock   open() โ”€โ”
P2: exec {fd2}>/tmp/lock   open() โ”€โ”ผโ”€โ–บ  OFD_1 / OFD_2 / OFD_3  โ”€โ”€โ–บ  inode (the lock file)
P3: exec {fd3}>/tmp/lock   open() โ”€โ”˜     three separate OFDs         shared by all three

open()์„ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ์ปค๋„์€ OFD(struct file)๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ ๋‹ค. ์„ธ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๊ฐ™์€ ๊ฒฝ๋กœ๋ฅผ ์—ด์–ด๋„ OFD๋Š” 3๊ฐœ๊ฐ€ ์ƒ๊ธฐ๊ณ , ์…‹ ๋‹ค ๊ฐ™์€ inode๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค. ์ด ์‹œ์ ์—” lock์ด ํ•˜๋‚˜๋„ ์—†๋‹ค. open๊ณผ lock์€ ๋ณ„๊ฐœ์˜ ์—ฐ์‚ฐ์ด๋‹ค.

inode์™€ struct file์˜ ์ •์ฒด

file descriptor๋Š” ์‚ฌ์‹ค 3๋‹จ์œผ๋กœ ์—ฐ๊ฒฐ๋œ๋‹ค. ์ด ๊ทธ๋ฆผ์„ ์žก์œผ๋ฉด ์œ„ ๋™์ž‘์ด ๋˜๋ ทํ•ด์ง„๋‹ค.

fd (per process)  โ”€โ”€โ–บ  open file description (struct file)  โ”€โ”€โ–บ  inode (struct inode)

  fd 3 โ”€โ”
  fd 4 โ”€โ”ดโ”€โ–บ  struct file  โ€” one per open() call
                f_pos     : file offset
                f_flags   : status flags  (O_APPEND, O_NONBLOCK, ...)
                f_count   : reference count  (raised by fork / dup)
                f_inode   : โ”€โ”€โ–บ  struct inode  โ€” one per file
                                   i_ino    : inode number
                                   i_mode   : type & permissions
                                   i_size   : size
                                   i_flctx  : lock list  (flock records live here)
  • inode: the file ์ž์ฒด์˜ metadata. typeยทpermissionยทsizeยทtimestampยทlink countยทdata block ์œ„์น˜์— ๋”ํ•ด lock list(i_flctx)๋ฅผ ํ’ˆ๋Š”๋‹ค. ํ•œ file๋‹น ํ•˜๋‚˜์ด๊ณ , ๊ฐ™์€ ๊ฒฝ๋กœ๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ์—ด์–ด๋„ inode๋Š” ํ•˜๋‚˜๋‹ค.
  • struct file (open file description): open() ํ•œ ๋ฒˆ์„ ํ‘œํ˜„ํ•œ๋‹ค. file offsetยทaccess modeยทstatus flagsยทinode pointerยทreference count๋ฅผ ๊ฐ€์ง„๋‹ค. fork/dup์€ ์ƒˆ๋กœ ๋งŒ๋“ค์ง€ ์•Š๊ณ  reference count๋งŒ ์˜ฌ๋ฆฐ๋‹ค.

flock์˜ lock record๋Š” ์ด ์ค‘ inode์— ๋งค๋‹ฌ๋ฆฐ lock list(i_flctx)์— ๋“ค์–ด๊ฐ€๊ณ , ๊ฐ record๊ฐ€ ์ž๊ธฐ owner OFD๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค. ๊ทธ๋ž˜์„œ lock์€ disk์— ์ €์žฅ๋˜์ง€ ์•Š๋Š”, ๊ทธ file(inode)์— ๋ถ™์€ runtime metadata๋‹ค. โ€œ๋ˆ„๊ฐ€ ์ž ๊ฐ”๋‚˜โ€๋Š” record ์•ˆ์˜ OFD๋กœ ์‹๋ณ„๋œ๋‹ค. lock์ด inode๋ณ„๋กœ ๋…๋ฆฝ์ด๋ผ, ํ•œ file์˜ lock์€ ๋‹ค๋ฅธ file์— ์ „ํ˜€ ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค.

flock์€ inode์˜ lock list์— OFD๋ฅผ owner๋กœ ์ ๋Š”๋‹ค

P1์ด flock -n "$fd1"(exclusive)์„ ํ˜ธ์ถœํ•˜๋ฉด ์ปค๋„์€ ์ด๋ ‡๊ฒŒ ์ฒ˜๋ฆฌํ•œ๋‹ค.

  1. fd1 โ†’ P1์˜ OFD_1๋กœ ํ•ด์„
  2. ๊ทธ OFD๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” inode์˜ flock lock list๋ฅผ ํ™•์ธ
  3. ์ถฉ๋Œํ•˜๋Š” lock์ด ์—†์œผ๋ฉด owner๊ฐ€ OFD_1์ธ lock record๋ฅผ inode์— ์ถ”๊ฐ€ํ•˜๊ณ  0 ๋ฐ˜ํ™˜

์ด์ œ P2๊ฐ€ flock -n "$fd2"๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด:

  1. fd2 โ†’ P2์˜ OFD_2๋กœ ํ•ด์„
  2. inode์˜ lock list์—์„œ OFD_1์ด ์†Œ์œ ํ•œ exclusive lock์„ ๋ฐœ๊ฒฌ
  3. ๊ทธ ์ž ๊ธˆ์˜ ์†Œ์œ  OFD๊ฐ€ ๋‚ด OFD์™€ ๋‹ค๋ฅด๋ฏ€๋กœ ์ถฉ๋Œ โ†’ -n์ด๋ผ ์ฆ‰์‹œ ์‹คํŒจ(flock์ด 0์ด ์•„๋‹Œ ์ฝ”๋“œ๋กœ ์ข…๋ฃŒ) โ†’ โ€œ์ด๋ฏธ ์‹คํ–‰ ์ค‘โ€

-n์ด ์—†์œผ๋ฉด P2๋Š” wait queue์—์„œ ์ž ๋“ค๊ณ , P1์ด ํ’€๋ฉด ๊นจ์–ด๋‚˜ ๋‹ค์‹œ ์‹œ๋„ํ•œ๋‹ค.

์™œ โ€œOFD๊ฐ€ ๋‹ค๋ฅด๋ฉด ์ถฉ๋Œโ€์ธ๊ฐ€

flock์˜ ์ถฉ๋Œ ๊ทœ์น™์€ ํ•œ ์ค„์ด๋‹ค. ๊ฐ™์€ inode์—, ๋‹ค๋ฅธ OFD๊ฐ€ ์†Œ์œ ํ•œ, ํ˜ธํ™˜๋˜์ง€ ์•Š๋Š” lock์ด ์žˆ์œผ๋ฉด ์ถฉ๋Œ์ด๋‹ค.

held \ requestedshared (s)exclusive (x)
shared (s)OKconflict
exclusive (x)conflictconflict

์˜ˆ๋ฅผ ๋“ค์–ด P1์ด shared(-s)๋กœ ์žก๊ณ  ์žˆ์–ด๋„ P2๊ฐ€ exclusive(-x)๋ฅผ ์š”์ฒญํ•˜๋ฉด ์ถฉ๋Œํ•ด ๋ง‰ํžŒ๋‹ค. exclusive๋Š” ๋…์ ์„ ์š”๊ตฌํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋ฐ˜๋Œ€๋กœ ๋‘˜ ๋‹ค shared๋ฉด ์—ฌ๋Ÿฌ reader๊ฐ€ ๋™์‹œ์— ๋“ค์–ด๊ฐ„๋‹ค.

  • ์„ธ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๊ฐ์ž open โ†’ OFD๊ฐ€ ์…‹์œผ๋กœ ๊ฐˆ๋ฆผ โ†’ ์„œ๋กœ ๋‚จ์ด๋ผ ๊ฒฝํ•ฉํ•œ๋‹ค. ์ด๊ฒŒ ์˜๋„ํ•œ mutual exclusion์ด๋‹ค.
  • ํ•œ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์—ด๊ณ  fork/dupํ•˜๋ฉด ์ž์‹์€ ๊ฐ™์€ OFD๋ฅผ ๋ฌผ๋ ค๋ฐ›๋Š”๋‹ค. ์ด๋•Œ flock์€ ๊ฐ™์€ owner๋กœ ๋ณด๊ณ  ์ถฉ๋Œ์‹œํ‚ค์ง€ ์•Š๋Š”๋‹ค. ๋‘˜์€ ํ•˜๋‚˜์˜ lock์„ ๊ณต์œ ํ•œ๋‹ค.
lock ํ•ด์ œ ์‹œ์ 
  • ๋ช…์‹œ์  flock -u, ๋˜๋Š”
  • OFD๊ฐ€ ์†Œ๋ฉธํ•  ๋•Œ โ€” ๊ทธ OFD๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋งˆ์ง€๋ง‰ fd๊ฐ€ ๋‹ซํž ๋•Œ. ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ •์ƒ ์ข…๋ฃŒํ•˜๋“  kill -9๋กœ ์ฃฝ๋“  ์ปค๋„์ด fd๋ฅผ ์ „๋ถ€ ๋‹ซ์•„ OFD๊ฐ€ ์ •๋ฆฌ๋˜๋ฉฐ lock๋„ ์‚ฌ๋ผ์ง„๋‹ค. flock์ด crash์— ๊ฐ•ํ•œ ์ด์œ ๋‹ค. lock file์€ ๋‚จ์•„๋„ lock ์ž์ฒด๋Š” ํ’€๋ฆฐ๋‹ค.
  • ๋‹จ, dup์œผ๋กœ ๋ณต์ œํ•œ fd๊ฐ€ ๋‚จ์•„ ์žˆ์œผ๋ฉด OFD reference count๊ฐ€ 0์ด ์•„๋‹ˆ๋ผ lock์€ ์œ ์ง€๋œ๋‹ค.

6. flock์˜ ํ•จ์ •

  • inode ๊ธฐ์ค€์ด๋ผ ์ž ๊ธˆ ํŒŒ์ผ์„ ์ง€์šฐ๋ฉด ์•ˆ ๋œ๋‹ค. ๋ˆ„๊ฐ€ rmํ•˜๊ณ  ๋‹ค๋ฅธ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ƒˆ๋กœ ๋งŒ๋“ค๋ฉด inode๊ฐ€ ๋ฐ”๋€Œ์–ด, ์˜› inode๋ฅผ ์žก์€ ์ž ๊ธˆ๊ณผ ์ƒˆ inode๋ฅผ ์—ฐ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์„œ๋กœ ๋ชป ๋ง‰๋Š”๋‹ค. ์ž ๊ธˆ ํŒŒ์ผ์€ ๊ณ ์ •ํ•ด ๋‘๊ณ  ์ง€์šฐ์ง€ ์•Š๋Š”๋‹ค.
  • >๋Š” ๋งค๋ฒˆ ์ž˜๋ผ๋‚ธ๋‹ค. ์ž ๊ธˆ์—” ๋ฌดํ•ดํ•˜์ง€๋งŒ, ์ž ๊ธˆ ํŒŒ์ผ์— PID ๊ฐ™์€ ๋‚ด์šฉ์„ ๋‚จ๊ธฐ๋ ค๋ฉด >(O_TRUNC) ๋Œ€์‹  <>๋กœ ์—ด์–ด ์ž๋ฅด์ง€ ์•Š๋Š”๋‹ค. ๋ฆฌ๋‹ค์ด๋ ‰์…˜ ์—ฐ์‚ฐ์ž๋ณ„ open ํ”Œ๋ž˜๊ทธ๋Š” Bash Shell Script 2์— ์ •๋ฆฌ๋ผ ์žˆ๋‹ค.
  • ๋„คํŠธ์›Œํฌ ํŒŒ์ผ์‹œ์Šคํ…œ ์ฃผ์˜. ์˜ค๋ž˜๋œ NFS์—์„œ๋Š” flock์ด ๋กœ์ปฌ์—์„œ๋งŒ ๋™์ž‘ํ•˜๊ฑฐ๋‚˜ ์ œ๋Œ€๋กœ ์•ˆ ๊ฑธ๋ฆด ์ˆ˜ ์žˆ๋‹ค. ๋ถ„์‚ฐ ํ™˜๊ฒฝ์˜ ์ž ๊ธˆ์€ ์ „์šฉ ๋„๊ตฌ(RedisยทetcdยทConsul ๋“ฑ)๊ฐ€ ์•ˆ์ „ํ•˜๋‹ค.
  • ์„œ๋ธŒ์…ธ ๋ธ”๋ก์˜ ๋ณ€์ˆ˜๋Š” ๋ฐ–์œผ๋กœ ์•ˆ ๋‚˜์˜จ๋‹ค. ( flock ...; ... ) 9>lock ์•ˆ์—์„œ ๋ฐ”๊พผ ๋ณ€์ˆ˜๋Š” ์„œ๋ธŒ์…ธ์ด ๋๋‚˜๋ฉด ์‚ฌ๋ผ์ง„๋‹ค. ๊ฒฐ๊ณผ๋Š” ํŒŒ์ผ์ด๋‚˜ stdout์œผ๋กœ ๋นผ๋‚ธ๋‹ค.

7. flock ์—†์ด โ€” ์ด์‹์„ฑ ์žˆ๋Š” ๋Œ€์•ˆ

flock์€ Linux์˜ util-linux ๋„๊ตฌ๋ผ macOS์—” ๊ธฐ๋ณธ ํƒ‘์žฌ๋˜์ง€ ์•Š๋Š”๋‹ค. ์–‘์ชฝ์—์„œ ๋„๋Š” ์ž ๊ธˆ์ด ํ•„์š”ํ•˜๋ฉด ํŒŒ์ผ์‹œ์Šคํ…œ ์ž์ฒด์˜ ์›์ž์  ์—ฐ์‚ฐ์„ ์“ด๋‹ค. ํ•ต์‹ฌ์€ โ€œ์ด๋ฏธ ์žˆ์œผ๋ฉด ์‹คํŒจํ•˜๋Š”, ์ƒ์„ฑ๊ณผ ๊ฒ€์‚ฌ๊ฐ€ ํ•œ ๋ฒˆ์— ์ผ์–ด๋‚˜๋Š”โ€ ์—ฐ์‚ฐ์ด๋‹ค.

mkdir โ€” ๋””๋ ‰ํ„ฐ๋ฆฌ ์ƒ์„ฑ์˜ ์›์ž์„ฑ
lockdir=/tmp/myjob.lock.d
if mkdir "$lockdir" 2>/dev/null; then
    trap 'rmdir "$lockdir"' EXIT
    long_running_job
else
    echo "์ด๋ฏธ ์‹คํ–‰ ์ค‘"; exit 1
fi

mkdir์€ ์ด๋ฏธ ์žˆ์œผ๋ฉด ์‹คํŒจํ•œ๋‹ค. ์ƒ์„ฑ๊ณผ ์กด์žฌ ๊ฒ€์‚ฌ๊ฐ€ ํ•œ ์—ฐ์‚ฐ์ด๋ผ ๊ฒฝ์Ÿ์ด ๋ผ์–ด๋“ค ํ‹ˆ์ด ์—†๋‹ค.

set -o noclobber โ€” >์˜ O_EXCL
lockfile=/tmp/myjob.lock
if ( set -o noclobber; echo "$$" > "$lockfile" ) 2>/dev/null; then
    trap 'rm -f "$lockfile"' EXIT
    long_running_job
else
    echo "์ด๋ฏธ ์‹คํ–‰ ์ค‘"; exit 1
fi

noclobber๋ฅผ ์ผœ๋ฉด >๊ฐ€ ๊ธฐ์กด ํŒŒ์ผ์„ ๋ฎ์–ด์“ฐ์ง€ ์•Š๊ณ  ์‹คํŒจํ•œ๋‹ค. ๋‚ด๋ถ€์ ์œผ๋กœ O_CREAT|O_EXCL์ด๋ผ ์›์ž์ ์ด๋‹ค. ๋ค์œผ๋กœ PID๋ฅผ ์ ์–ด ๋‘๋ฉด ๋ˆ„๊ฐ€ ์žก์•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

ln์œผ๋กœ ํ•˜๋“œ๋งํฌ๋ฅผ ๊ฑฐ๋Š” ๋ฐฉ๋ฒ•(ln ์ž„์‹œํŒŒ์ผ ์ž ๊ธˆํŒŒ์ผ)๋„ ์›์ž์ ์ด๋ผ, ์˜ค๋ž˜๋œ NFS์—์„œ๊นŒ์ง€ ๋™์ž‘์ด ํ•„์š”ํ•  ๋•Œ ์“ด๋‹ค.

๊ณตํ†ต ํ•œ๊ณ„ โ€” stale lock

flock๊ณผ ๋‹ฌ๋ฆฌ ์ด ๋ฐฉ๋ฒ•๋“ค์€ ์ž ๊ธˆ์ด ํŒŒ์ผ์ด๋‚˜ ๋””๋ ‰ํ„ฐ๋ฆฌ์˜ ์กด์žฌ ์ž์ฒด๋‹ค. ํ”„๋กœ์„ธ์Šค๊ฐ€ kill -9๋กœ ์ฃฝ์œผ๋ฉด trap์ด ๋ชป ๋Œ์•„ ์ž ๊ธˆ์ด ๋‚จ๋Š”๋‹ค. ๋‹ค์Œ ์‹คํ–‰์ด ์˜์˜ ๋ง‰ํž ์ˆ˜ ์žˆ๋‹ค. ๋ณด์™„์ฑ…์€ ๋‘ ๊ฐ€์ง€๋‹ค. ์ž ๊ธˆ์— PID๋ฅผ ์ ๊ณ  ๊ทธ PID๊ฐ€ ์‚ด์•„ ์žˆ๋Š”์ง€(kill -0 "$pid") ํ™•์ธํ•ด ์ฃฝ์—ˆ์œผ๋ฉด ํšŒ์ˆ˜ํ•˜๊ฑฐ๋‚˜, ์ž ๊ธˆ ํŒŒ์ผ์ด ๋„ˆ๋ฌด ์˜ค๋ž˜๋˜๋ฉด ํšŒ์ˆ˜ํ•œ๋‹ค.

๋ฐฉ๋ฒ•์ด์‹์„ฑํฌ๋ž˜์‹œ ์‹œ ์ž๋™ ํ•ด์ œ๋น„๊ณ 
flockLinux ์ค‘์‹ฌOFD๊ฐ€ ๋‹ซํžˆ๋ฉฐ ํ’€๋ฆผ. ๊ฐ€์žฅ ๊ฒฌ๊ณ ํ•˜์ง€๋งŒ macOS ์—†์Œ
mkdir๋†’์ŒX์–ด๋””์„œ๋‚˜ ๋™์ž‘, stale ์œ„ํ—˜
noclobber >๋†’์ŒXPID ๊ธฐ๋ก์ด ์‰ฌ์›€, stale ์œ„ํ—˜
ln ํ•˜๋“œ๋งํฌ๋†’์ŒX์˜ค๋ž˜๋œ NFS์—์„œ๋„ ์›์ž์ , stale ์œ„ํ—˜

8. ์‹ค์ „ ํŒจํ„ด ๋ชจ์Œ

cron ์ค‘๋ณต ๋ฐฉ์ง€ (ํ•œ ์ค„)
# ์ด์ „ ์‹คํ–‰์ด ์•ˆ ๋๋‚ฌ์œผ๋ฉด ์ด๋ฒˆ์€ ์กฐ์šฉํžˆ ๊ฑด๋„ˆ๋›ด๋‹ค
# */5 * * * * /usr/bin/flock -n /var/lock/sync.lock /home/me/sync.sh

cron ์Šคํฌ๋ฆฝํŠธ์—” ๊ฑฐ์˜ ๊ณต์‹์ฒ˜๋Ÿผ ์“ฐ์ธ๋‹ค.

๊ธฐ๋‹ค๋ ธ๋‹ค ์‹คํ–‰ (ํƒ€์ž„์•„์›ƒ)
# ์ตœ๋Œ€ 30์ดˆ ๊ธฐ๋‹ค๋ ธ๋‹ค๊ฐ€ ๋ชป ์žก์œผ๋ฉด ํฌ๊ธฐ
flock -w 30 /var/lock/job.lock /path/to/job.sh
์ž ๊ธˆ ํŒŒ์ผ ์œ„์น˜
  • ์žฌ๋ถ€ํŒ… ๋•Œ ๋น„์›Œ๋„ ๋˜๋Š” ์งง์€ ์ž ๊ธˆ: /run(๋˜๋Š” /var/run), /tmp
  • ์‹œ์Šคํ…œ ์„œ๋น„์Šค: /var/lock
  • ์‚ฌ์šฉ์ž ๋‹จ์œ„: $XDG_RUNTIME_DIR
๊ด€์ฐฐ โ€” ์ง€๊ธˆ ๊ฑธ๋ฆฐ ์ž ๊ธˆ ๋ณด๊ธฐ

Linux์—์„  ํ˜„์žฌ ๊ฑธ๋ฆฐ ์ž ๊ธˆ์„ ์ง์ ‘ ํ™•์ธํ•œ๋‹ค.

cat /proc/locks      # FLOCK ADVISORY WRITE ... ํ˜•ํƒœ๋กœ ์ถœ๋ ฅ
lslocks              # ์‚ฌ๋žŒ์ด ์ฝ๊ธฐ ์ข‹์€ ํ‘œ

ADVISORY๋ผ๊ณ  ์ฐํžˆ๋Š” ๋ฐ์„œ flock์ด ๊ถŒ๊ณ ์  ์ž ๊ธˆ์ž„์ด ํ•œ ๋ฒˆ ๋” ํ™•์ธ๋œ๋‹ค.

/proc/locks๋Š” flock๋งŒ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒŒ ์•„๋‹ˆ๋‹ค

์ปค๋„์ด ๋“ค๊ณ  ์žˆ๋Š” ๋ชจ๋“  ํŒŒ์ผ ์ž ๊ธˆ์ด ๋‚˜์˜ค๊ณ , ํƒ€์ž… ์นธ์œผ๋กœ ์ข…๋ฅ˜๊ฐ€ ๊ฐˆ๋ฆฐ๋‹ค.

  • FLOCK โ€” flock() (BSD ์ž ๊ธˆ)
  • POSIX โ€” fcntl(F_SETLK)ยทlockf
  • OFDLCK โ€” open file description lock (์ตœ์‹  POSIX)

ํ•œ ํ–‰์˜ ๋Œ€๋žต์  ํ˜•์‹์€ 1: FLOCK ADVISORY WRITE 12345 08:01:1234567 0 EOF ๊ผด์ด๋‹ค. ์ˆœ์„œ๋Œ€๋กœ ๋ฒˆํ˜ธ, ํƒ€์ž…, ๊ถŒ๊ณ /๊ฐ•์ œ, ๋ชจ๋“œ(WRITE=exclusiveยทREAD=shared), PID, major:minor:inode, ์‹œ์ž‘ยท๋ offset์ด๋‹ค. flock ํ–‰์€ ํ•ญ์ƒ ADVISORY์ด๊ณ  inode ์นธ์œผ๋กœ ์–ด๋А ํŒŒ์ผ์ธ์ง€ ์‹๋ณ„๋œ๋‹ค.