Iam, dum intervjuo, oni demandis min, kion vi faros, se vi trovos servon, kiu ne funkcias pro tio, ke la disko elĉerpiĝis?
Kompreneble, mi respondis, ke mi vidos, kio estas okupata de ĉi tiu loko kaj, se eble, mi purigos la lokon.
Tiam la intervjuanto demandis, kio se ne estas libera spaco sur la vando, sed vi ankaŭ ne vidas dosierojn, kiuj okupas la tutan spacon?
Al tio mi diris, ke oni ĉiam povas rigardi malfermitajn dosierpriskribilojn, ekzemple per la komando lsof, kaj kompreni, kiu aplikaĵo okupis la tutan disponeblan spacon, kaj tiam oni povas agi laŭ la cirkonstancoj, depende ĉu la datumoj estas bezonataj. .
La intervjuanto interrompis min je la lasta vorto, aldonante al sia demando: "Supoze, ke ni ne bezonas la datumojn, ĝi estas nur sencimiga protokolo, sed la aplikaĵo ne funkcias ĉar ĝi ne povas skribi sencimigon"?
"Bone," mi respondis, "ni povas malŝalti sencimigon en la aplika agordo kaj rekomenci ĝin."
La intervjuanto kontraŭis: "Ne, ni ne povas rekomenci la aplikaĵon, ni ankoraŭ havas gravajn datumojn konservitajn en memoro, kaj gravaj klientoj estas konektitaj al la servo mem, kiun ni ne povas devigi rekonekti."
“Bone,” mi diris, “se ni ne povas rekomenci la aplikaĵon kaj la datumoj ne gravas por ni, tiam ni povas simple forigi ĉi tiun malfermitan dosieron per la dosierpriskribilo, eĉ se ni ne vidas ĝin en la komando ls. sur la dosiersistemo."
La intervjuanto estis kontenta, sed mi ne estis.
Tiam mi pensis, kial la homo, kiu testas miajn sciojn, ne fosas pli profunde? Sed kio se la datumoj finfine gravas? Kio se ni ne povas rekomenci procezon, kaj la procezo skribas al la dosiersistemo sur diskparto kiu ne havas liberan spacon? Kio se ni ne povas perdi ne nur la datumojn, kiuj jam estis skribitaj, sed ankaŭ la datumojn, kiujn ĉi tiu procezo skribas aŭ provas skribi?
Tuzik
Komence de mia kariero, mi provis krei malgrandan aplikaĵon, kiu bezonis stoki uzantajn informojn. Kaj tiam mi pensis, kiel mi povas kongrui la uzanton al liaj datumoj. Ekzemple, mi havas Ivanov Ivan Ivanoviĉ, kaj li havas kelkajn informojn, sed kiel mi povas amikiĝi kun ili? Mi povas rekte atentigi, ke la hundo nomita "Tuzik" apartenas al tiu mem Ivano. Sed kio se li ŝanĝas sian nomon kaj anstataŭ Ivan fariĝos, ekzemple, Olja? Tiam montriĝos, ke nia Olja Ivanovna Ivanova ne plu havos hundon, kaj nia Tuzik ankoraŭ apartenos al la neekzistanta Ivano. Datumaro, kiu donis al ĉiu uzanto unikan identigilon (ID) helpis solvi ĉi tiun problemon, kaj mia Tuzik estis ligita al ĉi tiu identigilo, kiu, fakte, estis nur seria numero. Tiel, la posedanto de la aso havis identigilon numeron 2, kaj iam Ivano estis sub ĉi tiu identigilo, kaj tiam Olya fariĝis sub la sama identigilo. La problemo de homaro kaj bredado praktike estis solvita.
Dosiera priskribilo
La problemo de la dosiero kaj la programo, kiu funkcias kun ĉi tiu dosiero, estas proksimume la sama kiel tiu de nia hundo kaj viro. Supozu, ke mi malfermis dosieron nomitan ivan.txt kaj komencis skribi la vorton tuzik en ĝin, sed nur sukcesis skribi la unuan literon "t" en la dosiero, kaj ĉi tiu dosiero estis renomita de iu, ekzemple, al olya.txt. Sed la dosiero restas la sama, kaj mi ankoraŭ volas registri mian ason en ĝi. Ĉiufoje kiam dosiero estas malfermita per sistemvoko
En Linukso, la libc-biblioteko malfermas 3 priskribajn dosierojn por ĉiu ruliĝanta aplikaĵo (procezo), numeritaj 0,1,2. Pliaj informoj troveblas sur la ligiloj
- Dosierpriskribilo 0 nomiĝas STDIN kaj estas rilata al aplikaĵa enigo
- Dosierpriskribilo 1 nomiĝas STDOUT kaj estas uzata de aplikoj por eligi datumojn, kiel presi komandojn
- Dosiera priskribilo 2 nomiĝas STDERR kaj estas uzata de aplikaĵoj por eligi erarmesaĝojn.
Se en via programo vi malfermas iun dosieron por legi aŭ skribi, tiam plej verŝajne vi ricevos la unuan senpagan identigilon kaj ĝi estos numero 3.
La listo de dosierpriskribiloj povas esti vidita por ajna procezo se vi konas ĝian PID.
Ekzemple, ni malfermu la bash-konzolon kaj rigardu la PID de nia procezo
[user@localhost ]$ echo $$
15771
En la dua konzolo ni kuru
[user@localhost ]$ ls -lah /proc/15771/fd/
total 0
dr-x------ 2 user user 0 Oct 7 15:42 .
dr-xr-xr-x 9 user user 0 Oct 7 15:42 ..
lrwx------ 1 user user 64 Oct 7 15:42 0 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:42 1 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:42 2 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:42 255 -> /dev/pts/21
Vi povas sekure ignori dosierpriskribilon numeron 255 por la celoj de ĉi tiu artikolo; ĝi estis malfermita por siaj bezonoj de bash mem, kaj ne de la ligita biblioteko.
Nun ĉiuj 3 priskribaj dosieroj estas asociitaj kun la pseŭda fina aparato
[user@localhost ]$ echo "hello world" > /proc/15771/fd/0
Kaj en la unua konzolo ni vidos
[user@localhost ]$ hello world
Alidirekti kaj Pipo
Vi povas facile superregi ĉi tiujn 3 priskribajn dosierojn en iu ajn procezo, inkluzive en bash, ekzemple per tubo liganta du procezojn, vidu
[user@localhost ]$ cat /dev/zero | sleep 10000
Vi povas ruli ĉi tiun komandon mem per strace -f kaj vidu, kio okazas interne, sed mi rakontos al vi mallonge.
Nia gepatra bash-procezo kun PID 15771 analizas nian komandon kaj komprenas precize kiom da komandoj ni volas ruli, en nia kazo estas du el ili: kato kaj dormo. Bash scias, ke ĝi bezonas krei du infanajn procezojn, kaj kunfandi ilin en unu tubon. Entute, bash bezonos 2 infanajn procezojn kaj unu tubon.
Bash rulas sistemvokon antaŭ krei infanajn procezojn
Por la gepatra procezo, ŝajnas, ke jam ekzistas pipo, sed ankoraŭ ne ekzistas infanaj procezoj:
PID command
15771 bash
lrwx------ 1 user user 64 Oct 7 15:42 0 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:42 1 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:42 2 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:42 3 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct 7 15:42 4 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct 7 15:42 255 -> /dev/pts/21
Poste uzante la sistemvokon
PID command
15771 bash
lrwx------ 1 user user 64 Oct 7 15:42 0 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:42 1 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:42 2 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:42 3 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct 7 15:42 4 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct 7 15:42 255 -> /dev/pts/21
PID command
9004 bash
lrwx------ 1 user user 64 Oct 7 15:57 0 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:57 1 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:57 2 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:57 3 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct 7 15:57 4 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct 7 15:57 255 -> /dev/pts/21
PID command
9005 bash
lrwx------ 1 user user 64 Oct 7 15:57 0 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:57 1 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:57 2 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:57 3 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct 7 15:57 4 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct 7 15:57 255 -> /dev/pts/21
Ne forgesu, ke klono klonas la procezon kune kun ĉiuj dosierpriskribiloj, do ili estos samaj en la gepatra procezo kaj en la infanaj. La laboro de la gepatra procezo kun PID 15771 estas kontroli la infanajn procezojn, do ĝi simple atendas respondon de la infanoj.
Tial ĝi ne bezonas pipon, kaj ĝi fermas dosierpriskribilojn numeritajn 3 kaj 4.
En la unua infanbash procezo kun PID 9004, la sistemvoko
En la dua infana procezo kun PID 9005, bash uzas dup2 por ŝanĝi la dosierpriskribilon STDIN numeron 0. Nun ĉio, kion nia dua bash kun PID 9005 legos, estos legita el la pipo.
Post tio, dosierpriskribiloj numeritaj 3 kaj 4 ankaŭ estas fermitaj en la infanaj procezoj, ĉar ili ne plu estas uzataj.
Mi intence ignoras dosierpriskribilon 255; ĝi estas uzata por internaj celoj de bash mem kaj ankaŭ estos fermita en infanaj procezoj.
Poste, en la unua infana procezo kun PID 9004, bash komencas uzi sisteman vokon
En la dua infana procezo kun PID 9005, bash rulas la duan ruleblan, kiun ni specifis, en nia kazo /usr/bin/sleep.
La exec-sistemvoko ne fermas dosiertenilojn krom se ili estis malfermitaj kun la O_CLOEXEC-flago en la tempo kiam la malferma voko estis farita. En nia kazo, post lanĉo de la plenumeblaj dosieroj, ĉiuj aktualaj dosierpriskribiloj estos konservitaj.
Kontrolu en la konzolo:
[user@localhost ]$ pgrep -P 15771
9004
9005
[user@localhost ]$ ls -lah /proc/15771/fd/
total 0
dr-x------ 2 user user 0 Oct 7 15:42 .
dr-xr-xr-x 9 user user 0 Oct 7 15:42 ..
lrwx------ 1 user user 64 Oct 7 15:42 0 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:42 1 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:42 2 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:42 255 -> /dev/pts/21
[user@localhost ]$ ls -lah /proc/9004/fd
total 0
dr-x------ 2 user user 0 Oct 7 15:57 .
dr-xr-xr-x 9 user user 0 Oct 7 15:57 ..
lrwx------ 1 user user 64 Oct 7 15:57 0 -> /dev/pts/21
l-wx------ 1 user user 64 Oct 7 15:57 1 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct 7 15:57 2 -> /dev/pts/21
lr-x------ 1 user user 64 Oct 7 15:57 3 -> /dev/zero
[user@localhost ]$ ls -lah /proc/9005/fd
total 0
dr-x------ 2 user user 0 Oct 7 15:57 .
dr-xr-xr-x 9 user user 0 Oct 7 15:57 ..
lr-x------ 1 user user 64 Oct 7 15:57 0 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct 7 15:57 1 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:57 2 -> /dev/pts/21
[user@localhost ]$ ps -up 9004
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
user 9004 0.0 0.0 107972 620 pts/21 S+ 15:57 0:00 cat /dev/zero
[user@localhost ]$ ps -up 9005
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
user 9005 0.0 0.0 107952 360 pts/21 S+ 15:57 0:00 sleep 10000
Kiel vi povas vidi, la unika nombro de nia pipo estas la sama en ambaŭ procezoj. Tiel ni havas ligon inter du malsamaj procezoj kun la sama gepatro.
Por tiuj, kiuj ne konas la sistemvokojn, kiujn bash uzas, mi tre rekomendas ruli la komandojn per strace kaj vidi kio okazas interne, ekzemple jene:
strace -s 1024 -f bash -c "ls | grep hello"
Ni revenu al nia problemo kun malalta diskospaco kaj provante ŝpari datumojn sen rekomenci la procezon. Ni skribu malgrandan programon, kiu skribos proksimume 1 megabajton je sekundo al disko. Krome, se ial ni ne povis skribi datumojn al la disko, ni simple ignoros ĉi tion kaj provos skribi la datumojn denove en sekundo. En la ekzemplo mi uzas Python, vi povas uzi ajnan alian programlingvon.
[user@localhost ]$ cat openforwrite.py
import datetime
import time
mystr="a"*1024*1024+"n"
with open("123.txt", "w") as f:
while True:
try:
f.write(str(datetime.datetime.now()))
f.write(mystr)
f.flush()
time.sleep(1)
except:
pass
Ni rulu la programon kaj rigardu la dosierpriskribilojn
[user@localhost ]$ python openforwrite.py &
[1] 3762
[user@localhost ]$ ps axuf | grep [o]penforwrite
user 3762 0.0 0.0 128600 5744 pts/22 S+ 16:28 0:00 | _ python openforwrite.py
[user@localhost ]$ ls -la /proc/3762/fd
total 0
dr-x------ 2 user user 0 Oct 7 16:29 .
dr-xr-xr-x 9 user user 0 Oct 7 16:29 ..
lrwx------ 1 user user 64 Oct 7 16:29 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 7 16:29 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 7 16:29 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct 7 16:29 3 -> /home/user/123.txt
Kiel vi povas vidi, ni havas niajn 3 normajn dosierpriskribilojn kaj unu pli, kiun ni malfermis. Ni kontrolu la grandecon de dosiero:
[user@localhost ]$ ls -lah 123.txt
-rw-rw-r-- 1 user user 117M Oct 7 16:30 123.txt
La datumoj estas skribitaj, ni provas ŝanĝi la permesojn sur la dosiero:
[user@localhost ]$ sudo chown root: 123.txt
[user@localhost ]$ ls -lah 123.txt
-rw-rw-r-- 1 root root 168M Oct 7 16:31 123.txt
[user@localhost ]$ ls -lah 123.txt
-rw-rw-r-- 1 root root 172M Oct 7 16:31 123.txt
Ni vidas, ke la datumoj ankoraŭ estas skribitaj, kvankam nia uzanto ne havas permeson skribi al la dosiero. Ni provu forigi ĝin:
[user@localhost ]$ sudo rm 123.txt
[user@localhost ]$ ls 123.txt
ls: cannot access 123.txt: No such file or directory
Kie estas skribitaj la datumoj? Kaj ĉu ili entute estas skribitaj? Ni kontrolas:
[user@localhost ]$ ls -la /proc/3762/fd
total 0
dr-x------ 2 user user 0 Oct 7 16:29 .
dr-xr-xr-x 9 user user 0 Oct 7 16:29 ..
lrwx------ 1 user user 64 Oct 7 16:29 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 7 16:29 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 7 16:29 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct 7 16:29 3 -> /home/user/123.txt (deleted)
Jes, nia dosierpriskribilo ankoraŭ ekzistas kaj ni povas trakti ĉi tiun dosierpriskribilon kiel nian malnovan dosieron, ni povas legi, malplenigi kaj kopii ĝin.
Ni rigardu la grandecon de dosiero:
[user@localhost ]$ lsof | grep 123.txt
python 31083 user 3w REG 8,5 19923457 2621522 /home/user/123.txt
La dosiergrandeco estas 19923457. Ni provu forigi la dosieron:
[user@localhost ]$ truncate -s 0 /proc/31083/fd/3
[user@localhost ]$ lsof | grep 123.txt
python 31083 user 3w REG 8,5 136318390 2621522 /home/user/123.txt
Kiel vi povas vidi, la dosiergrandeco nur pliiĝas kaj nia trunko ne funkciis. Ni rigardu la sistemvokan dokumentadon
with open("123.txt", "w") as f:
ni devas meti
with open("123.txt", "a") as f:
Kontrolante kun la "w" flago
[user@localhost ]$ strace -e trace=open python openforwrite.py 2>&1| grep 123.txt
open("123.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
kaj kun la "a" flago
[user@localhost ]$ strace -e trace=open python openforwrite.py 2>&1| grep 123.txt
open("123.txt", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3
Programado de jam funkcianta procezo
Ofte programistoj, kiam ili kreas kaj testas programojn, uzas erarserĉilojn (ekzemple GDB) aŭ diversajn nivelojn de ensalutu en la aplikaĵo. Linukso disponigas la kapablon vere skribi kaj ŝanĝi jam funkciantan programon, ekzemple, ŝanĝi la valorojn de variabloj, agordi rompopunkton ktp., ktp.
Revenante al la originala demando pri ne sufiĉa diskospaco por skribi dosieron, ni provu simuli la problemon.
Ni kreu dosieron por nia diskparto, kiun ni montos kiel aparta disko:
[user@localhost ~]$ dd if=/dev/zero of=~/tempfile_for_article.dd bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB) copied, 0.00525929 s, 2.0 GB/s
[user@localhost ~]$
Ni kreu dosiersistemon:
[user@localhost ~]$ mkfs.ext4 ~/tempfile_for_article.dd
mke2fs 1.42.9 (28-Dec-2013)
/home/user/tempfile_for_article.dd is not a block special device.
Proceed anyway? (y,n) y
...
Writing superblocks and filesystem accounting information: done
[user@localhost ~]$
Muntu la dosiersistemon:
[user@localhost ~]$ sudo mount ~/tempfile_for_article.dd /mnt/
[sudo] password for user:
[user@localhost ~]$ df -h | grep mnt
/dev/loop0 8.7M 172K 7.9M 3% /mnt
Ni kreas dosierujon kun nia posedanto:
[user@localhost ~]$ sudo mkdir /mnt/logs
[user@localhost ~]$ sudo chown user: /mnt/logs
Ni malfermu la dosieron por skribi nur en nia programo:
with open("/mnt/logs/123.txt", "w") as f:
Lanĉo
[user@localhost ]$ python openforwrite.py
Ni atendas kelkajn sekundojn
[user@localhost ~]$ df -h | grep mnt
/dev/loop0 8.7M 8.0M 0 100% /mnt
Do, ni havas la problemon priskribitan komence de ĉi tiu artikolo. Libera spaco 0, 100% okupata.
Ni memoras, ke laŭ la kondiĉoj de la tasko, ni provas registri tre gravajn datumojn, kiuj ne povas esti perditaj. Kaj samtempe ni devas ripari la servon sen rekomenci la procezon.
Ni diru, ke ni ankoraŭ havas diskospacon, sed en alia diskparto, ekzemple en /home.
Ni provu "reprogrami sur la flugo" nian kodon.
Ni rigardu la PID de nia procezo, kiu manĝis la tutan diskospacon:
[user@localhost ~]$ ps axuf | grep [o]penfor
user 10078 27.2 0.0 128600 5744 pts/22 R+ 11:06 0:02 | _ python openforwrite.py
Konekti al la procezo per gdb
[user@localhost ~]$ gdb -p 10078
...
(gdb)
Ni rigardu la malfermitajn dosierpriskribilojn:
(gdb) shell ls -lah /proc/10078/fd/
total 0
dr-x------ 2 user user 0 Oct 8 11:06 .
dr-xr-xr-x 9 user user 0 Oct 8 11:06 ..
lrwx------ 1 user user 64 Oct 8 11:09 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:09 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:06 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct 8 11:09 3 -> /mnt/logs/123.txt
Ni rigardas la informojn pri dosierpriskribilo numero 3, kiu interesas nin
(gdb) shell cat /proc/10078/fdinfo/3
pos: 8189952
flags: 0100001
mnt_id: 482
Konsiderante, kian sistemvokon Python faras (vidu supre kie ni kuris strace kaj trovis la malfermitan vokon), kiam ni prilaboras nian kodon por malfermi dosieron, ni mem faras la samon nome de nia procezo, sed ni bezonas la O_WRONLY|O_CREAT| O_TRUNC bitoj anstataŭigas per nombra valoro. Por fari tion, malfermu la kernfontojn, ekzemple
#difini O_WRONLY 00000001
#define O_CREAT 00000100
#difini O_TRUNC 00001000
Ni kombinas ĉiujn valorojn en unu, ni ricevas 00001101
Ni rulas nian vokon de gdb
(gdb) call open("/home/user/123.txt", 00001101,0666)
$1 = 4
Do ni ricevis novan dosierpriskribilon kun numero 4 kaj novan malfermitan dosieron sur alia sekcio, ni kontrolas:
(gdb) shell ls -lah /proc/10078/fd/
total 0
dr-x------ 2 user user 0 Oct 8 11:06 .
dr-xr-xr-x 9 user user 0 Oct 8 11:06 ..
lrwx------ 1 user user 64 Oct 8 11:09 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:09 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:06 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct 8 11:09 3 -> /mnt/logs/123.txt
l-wx------ 1 user user 64 Oct 8 11:15 4 -> /home/user/123.txt
Ni memoras la ekzemplon kun pipo - kiel bash ŝanĝas dosierpriskribilojn, kaj ni jam lernis la sistemvokon dup2.
Ni provas anstataŭigi unu dosierpriskribilon per alia
(gdb) call dup2(4,3)
$2 = 3
Ni kontrolas:
(gdb) shell ls -lah /proc/10078/fd/
total 0
dr-x------ 2 user user 0 Oct 8 11:06 .
dr-xr-xr-x 9 user user 0 Oct 8 11:06 ..
lrwx------ 1 user user 64 Oct 8 11:09 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:09 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:06 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct 8 11:09 3 -> /home/user/123.txt
l-wx------ 1 user user 64 Oct 8 11:15 4 -> /home/user/123.txt
Ni fermas dosierpriskribilon 4, ĉar ni ne bezonas ĝin:
(gdb) call close (4)
$1 = 0
Kaj eliru gdb
(gdb) quit
A debugging session is active.
Inferior 1 [process 10078] will be detached.
Quit anyway? (y or n) y
Detaching from program: /usr/bin/python2.7, process 10078
Kontrolante la novan dosieron:
[user@localhost ~]$ ls -lah /home/user/123.txt
-rw-rw-r-- 1 user user 5.1M Oct 8 11:18 /home/user/123.txt
[user@localhost ~]$ ls -lah /home/user/123.txt
-rw-rw-r-- 1 user user 7.1M Oct 8 11:18 /home/user/123.txt
Kiel vi povas vidi, la datumoj estas skribitaj al nova dosiero, ni kontrolu la malnovan:
[user@localhost ~]$ ls -lah /mnt/logs/123.txt
-rw-rw-r-- 1 user user 7.9M Oct 8 11:08 /mnt/logs/123.txt
Neniuj datumoj estas perditaj, la aplikaĵo funkcias, protokoloj estas skribitaj al nova loko.
Ni iom kompliku la taskon
Ni imagu, ke la datumoj estas gravaj por ni, sed ni ne havas diskospacon en iu ajn el la sekcioj kaj ni ne povas konekti la diskon.
Kion ni povas fari estas alidirekti niajn datumojn ien, ekzemple al pipo, kaj siavice alidirekti datumojn de pipo al la reto per iu programo, ekzemple netcat.
Ni povas krei nomitan tubon per la komando mkfifo. Ĝi kreos pseŭdodosieron sur la dosiersistemo eĉ se ne estas libera spaco sur ĝi.
Rekomencu la aplikaĵon kaj kontrolu:
[user@localhost ]$ python openforwrite.py
[user@localhost ~]$ ps axuf | grep [o]pen
user 5946 72.9 0.0 128600 5744 pts/22 R+ 11:27 0:20 | _ python openforwrite.py
[user@localhost ~]$ ls -lah /proc/5946/fd
total 0
dr-x------ 2 user user 0 Oct 8 11:27 .
dr-xr-xr-x 9 user user 0 Oct 8 11:27 ..
lrwx------ 1 user user 64 Oct 8 11:28 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:28 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:27 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct 8 11:28 3 -> /mnt/logs/123.txt
[user@localhost ~]$ df -h | grep mnt
/dev/loop0 8.7M 8.0M 0 100% /mnt
Ne estas diskospaco, sed ni sukcese kreas nomitan tubon tie:
[user@localhost ~]$ mkfifo /mnt/logs/megapipe
[user@localhost ~]$ ls -lah /mnt/logs/megapipe
prw-rw-r-- 1 user user 0 Oct 8 11:28 /mnt/logs/megapipe
Nun ni devas iel envolvi ĉiujn datumojn, kiuj eniras ĉi tiun tubon al alia servilo per la reto; la sama netcat taŭgas por ĉi tio.
Sur la servilo remote-server.example.com ni lanĉas
[user@localhost ~]$ nc -l 7777 > 123.txt
Sur nia problema servilo ni lanĉas en aparta terminalo
[user@localhost ~]$ nc remote-server.example.com 7777 < /mnt/logs/megapipe
Nun ĉiuj datumoj, kiuj finiĝas en la tubo, aŭtomate iros al stdin en netcat, kiu sendos ĝin al la reto ĉe la haveno 7777.
Ĉio, kion ni devas fari, estas komenci skribi niajn datumojn en ĉi tiun nomitan tubon.
Ni jam havas la aplikaĵon funkciantan:
[user@localhost ~]$ ps axuf | grep [o]pen
user 5946 99.8 0.0 128600 5744 pts/22 R+ 11:27 169:27 | _ python openforwrite.py
[user@localhost ~]$ ls -lah /proc/5946/fd
total 0
dr-x------ 2 user user 0 Oct 8 11:27 .
dr-xr-xr-x 9 user user 0 Oct 8 11:27 ..
lrwx------ 1 user user 64 Oct 8 11:28 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:28 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:27 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct 8 11:28 3 -> /mnt/logs/123.txt
El ĉiuj flagoj, ni bezonas nur O_WRONLY ĉar la dosiero jam ekzistas kaj ni ne bezonas forigi ĝin.
[user@localhost ~]$ gdb -p 5946
...
(gdb) call open("/mnt/logs/megapipe", 00000001,0666)
$1 = 4
(gdb) shell ls -lah /proc/5946/fd
total 0
dr-x------ 2 user user 0 Oct 8 11:27 .
dr-xr-xr-x 9 user user 0 Oct 8 11:27 ..
lrwx------ 1 user user 64 Oct 8 11:28 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:28 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:27 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct 8 11:28 3 -> /mnt/logs/123.txt
l-wx------ 1 user user 64 Oct 8 14:20 4 -> /mnt/logs/megapipe
(gdb) call dup2(4,3)
$2 = 3
(gdb) shell ls -lah /proc/5946/fd
total 0
dr-x------ 2 user user 0 Oct 8 11:27 .
dr-xr-xr-x 9 user user 0 Oct 8 11:27 ..
lrwx------ 1 user user 64 Oct 8 11:28 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:28 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:27 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct 8 11:28 3 -> /mnt/logs/megapipe
l-wx------ 1 user user 64 Oct 8 14:20 4 -> /mnt/logs/megapipe
(gdb) call close(4)
$3 = 0
(gdb) shell ls -lah /proc/5946/fd
total 0
dr-x------ 2 user user 0 Oct 8 11:27 .
dr-xr-xr-x 9 user user 0 Oct 8 11:27 ..
lrwx------ 1 user user 64 Oct 8 11:28 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:28 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:27 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct 8 11:28 3 -> /mnt/logs/megapipe
(gdb) quit
A debugging session is active.
Inferior 1 [process 5946] will be detached.
Quit anyway? (y or n) y
Detaching from program: /usr/bin/python2.7, process 5946
Kontrolante la fora servilo remote-server.example.com
[user@localhost ~]$ ls -lah 123.txt
-rw-rw-r-- 1 user user 38M Oct 8 14:21 123.txt
La datumoj venas, ni kontrolas la problemservilon
[user@localhost ~]$ ls -lah /mnt/logs/
total 7.9M
drwxr-xr-x 2 user user 1.0K Oct 8 11:28 .
drwxr-xr-x 4 root root 1.0K Oct 8 10:55 ..
-rw-rw-r-- 1 user user 7.9M Oct 8 14:17 123.txt
prw-rw-r-- 1 user user 0 Oct 8 14:22 megapipe
La datumoj estas konservitaj, la problemo estas solvita.
Mi profitas por saluti miajn kolegojn el Degiro.
Aŭskultu podkastojn de Radio-T.
Bonan al ĉiuj.
Kiel hejmtasko, mi sugestas, ke vi pripensu, kio estos en la procezdosierpriskribiloj kato kaj dormo se vi rulas la jenan komandon:
[user@localhost ~]$ cat /dev/zero 2>/dev/null| sleep 10000
fonto: www.habr.com