---
title: 'Sistem Yönetimi'
source: 'https://academia.sh/tr/kurslar/sistem-yonetimi'
language: tr
updated: '2026-08-17T04:41:57+00:00'
license: 'CC BY-SA 4.0'
lessons: 22
outcomes:
    - 'Süreçleri izler, önceliklendirir ve sinyallerle yönetirken aracın ne göremediğini sayar'
    - 'Servisleri tanımlar ve yeniden başlatma politikasının hangi arızayı gizlediğini ölçer'
    - 'Disk, dosya sistemi ve takma yapılandırmasını iki ayrı doluluk sınırını ayırarak değiştirir'
---

# Sistem Yönetimi

Süreç izleme, sinyaller, servis birimleri, günlükler ve depolama araçlarının çıktısından çıkarılan tanının sistemin gerçek durumuyla karşılaştırılması.

## Süreç Yönetimi

Süreç listeleme ve aramanın örnekleme aralığına bağlılığı, iş denetimi, sinyallerin isteğe dönüşmesi, öncelik değerinin görülebilir etkisi ve kaynak sınırlarının gizlediği neden.

### Süreç Listeleme ve Arama

Source: https://academia.sh/tr/kurslar/sistem-yonetimi/surec-listeleme-ve-arama

Yirmi dört süreçlik kurgu bir sunucuda gerçekte 14 süreç ağır: örnekleme aralığı 15 saniyeye çıkınca araç 3'ünü, 30 ve 60 saniyede 5'ini kaçırıyor; tek bakış 5–7, ömür ortalaması 7 yanlış tanı veriyor ve ada göre seçim en iyi durumda 9 sürece yanlış dokunuyor.

Kabuk Programlama kursu bir betiği araca dönüştürdü: argüman arayüzü kazandı, hatalarda
durdu, arkasını topladı ve bir zamanlayıcıya verildi. Betik yazmak bir şeyi *yaptırmaktır*.
Sistem yönetimi başka bir işle başlar — önce **ne olduğunu görmek**. Ve görmenin kendi
hataları vardır.

Bu kurs o hataları sayar. İşletim Sistemi Kavramları kursu süreci, çizelgeleyiciyi ve
bağlam değiştirmeyi **mekanizma olarak** ölçmüştü; orada ölçülen şey soyutlamanın bedeliydi.
Burada mekanizma yeniden kurulmaz: ölçülen şey **operatörün o mekanizmadan ne görebildiğidir.**

#### Kursun Ölçüsü

Her derste üç sayı yan yana durur. Birincisi **kâhin (oracle)**: sistemin gerçek durumu.
Kurguyu biz ürettiğimiz için hangi sürecin gerçekten ağır olduğunu biliyoruz. İkincisi
**araç çıktısı**: aracın gösterdiği. Üçüncüsü **yanlış tanı (false diagnosis)** sayısı:
çıktıdan çıkarılan sonucun kâhinle kaç kez çeliştiği.

Kuralın kendisi tek cümledir: **bir komutun sayısı gösterdiği satır değil, o satırlardan
çıkarılan tanının kaç kez yanlış olduğudur.** Tanısı sınanmayan bir çıktı ölçülmemiş sayılır.

- **SY1.** Gözlem penceresi **600 saniyedir**. Bütün süreler modeldeki saniyedir; gerçek zaman
  ölçülmez.
- **SY2.** Kurgu sunucuda **24 süreç** vardır. Her sürecin gerçek işlemci kullanımı tek bir
  sayı değil, bir **zaman dizisidir**.
- **SY3.** Üç desen vardır: **düz** (sürekli düşük), **ani** (altmış saniyede bir, beş saniyelik
  sıçrama), **ağır** (sürekli yüksek).
- **SY4.** Bir süreç, pencere boyunca kullanımı bir kez bile **50**'yi aştıysa **ağır** sayılır.
  Kâhin bu tanımı bütün 600 saniyeye bakarak uygular; araç yalnız baktığı anlara bakar.
- **SY5.** İzleme aracı `aralık` saniyede bir bakar ve süreç başına **gördüğü en yüksek** değeri
  saklar. Bakışlar arasında olan biteni bilmez.
- **SY6.** Yanlış tanı sayısı, kaçırılan ağır süreçler ile ağır sanılan hafif süreçlerin
  toplamıdır.
- **SY7.** İkinci tohum **20260219**'dur. Ayrılan tanı sayısı aynı büyüklük düzeninde kalmazsa
  sonuç kurguya bağlıdır ve öyle yazılır.

#### Süreç Tablosunu Okumak

Süreç listesini veren komut `ps`, sürekli tazelenen görünümü veren komut `top` ya da onun
etkileşimli türevleridir. `ps` bir **anlık kesittir**; verdiği liste, komutun koştuğu andaki
süreç tablosudur. Aşağıdaki döküm **örnektir**, bu sayfa için üretilmiştir ve çalıştırılmamıştır:

```text
$ ps -eo pid,user,ni,pcpu,pmem,etime,comm --sort=-pcpu
    PID USER       NI %CPU %MEM   ELAPSED COMMAND
   1128 uygulama    0 71.2  3.1  00:10:00 kuyruk-isleyici
   1043 izleme      5 68.4  1.2  00:10:00 olcum-toplayici
   1014 uygulama   -3 64.9  2.8  00:10:00 rapor-uretici
   1092 kok         0  6.1  0.4  00:10:00 yedek-gorevi
   1071 yedek      10  3.0  0.2  00:10:00 onbellek-temizleyici
```

Sütunların çoğu kendini anlatır; ikisi anlatmaz. `NI`, dersin dördüncüsünde ölçülecek olan
**öncelik değeridir**. `%CPU` ise en yanıltıcı sütundur: `ps` bu değeri sürecin **doğumundan
beri** geçen süreye böler, yani bir **ömür ortalamasıdır**. On saat çalışmış bir süreç, son
beş dakikada çekirdeği tek başına tüketse bile bu sütunda düşük görünür.

`top` aynı sütunu başka türlü hesaplar: iki tazeleme arasında geçen kısa aralığı temsil eder.
İki komut aynı makinede aynı anda çalıştırıldığında aynı süreç için farklı sayılar verir ve
**ikisi de doğrudur**; farklı zaman aralıklarını ölçüyorlar. Bu ayrım bu dersin ölçtüğü şeyin
tam olarak kaynağıdır.

#### Kurgu Sunucu

Ölçüm, gerçek bir komuta değil, kursun ortak tanımına dayanır. Gerçek bir sunucuda koşan
komutun çıktısı yeniden üretilemez: makine başka, yük başka, saat başka. Kurgu sunucuyu biz
ürettiğimiz için kâhini biliyoruz.

```python
"""M03/K03 ortak tanim: kurgu bir sunucu , araclarin urettigi metin ve o metinden
cikarilan taninin KAHINLE karsilastirilmasi. Hicbir gercek komut cagrilmaz.
"""
TOHUM = 20260218
IKINCI_TOHUM = 20260219
DONEM = 600                      # gozlem penceresi: 600 saniye


def uretec(tohum):
    d = tohum

    def sonraki(n):
        nonlocal d
        d = (d * 1103515245 + 12345) % 2147483648
        return d % n
    return sonraki


KULLANICI = ("kok", "uygulama", "yedek", "izleme")
KOMUT = ("veri-alici", "rapor-uretici", "yedek-gorevi", "olcum-toplayici",
         "kuyruk-isleyici", "onbellek-temizleyici")


def surecler(tohum=TOHUM, sayi=24):
    """Her surec: gercek islemci kullanimi bir ZAMAN DIZISIDIR , tek sayi degil."""
    r = uretec(tohum)
    liste = []
    for i in range(sayi):
        tur = r(10)
        desen = "duz" if tur < 5 else ("ani" if tur < 8 else "agir")
        liste.append({"pid": 1000 + i * 7 + r(5),
                      "kullanici": KULLANICI[r(len(KULLANICI))],
                      "komut": KOMUT[r(len(KOMUT))], "desen": desen,
                      "oncelik": r(11) - 5, "bellek": 20 + r(400),
                      "sinyal_yok_sayar": r(10) < 2})
    return liste


def kullanim(surec, saniye):
    """Gercek islemci kullanimi , saniye saniye. Kahin bunu bilir; arac bilmez."""
    d = surec["desen"]
    if d == "duz":
        return 3 + (surec["pid"] + saniye) % 4
    if d == "agir":
        return 60 + (surec["pid"] + saniye) % 25
    faz = (saniye + surec["pid"]) % 60          # ani: 60 saniyede bir 5 saniyelik sicrama
    return 88 + faz if faz < 5 else 2 + faz % 3


S = surecler()
print("kurgu sunucu:", len(S), "surec |",
      {d: sum(1 for s in S if s["desen"] == d) for d in ("duz", "ani", "agir")})
print("gercekte esigi asan surec:",
      sum(1 for s in S if max(kullanim(s, t) for t in range(DONEM)) >= 50))
```

```
kurgu sunucu: 24 surec | {'duz': 10, 'ani': 7, 'agir': 7}
gercekte esigi asan surec: 14
```

**Kâhin 14'tür.** Yedi süreç sürekli ağırdır, yedisi ise altmış saniyede bir sıçrar ve
sıçradığında eşiği fazlasıyla aşar. Toplam 24 sürecin 14'ü, eşiği pencerenin bir yerinde
geçiyor. Bundan sonraki her sayı bu 14'e göre okunur.

#### Örnekleme Aralığı Tanıyı Belirliyor

İzleme aracının tek ayarı vardır: ne sıklıkla bakacağı. Aralığı büyütmek çıktıyı küçültür ve
yükü azaltır. Bunun tanıya ne yaptığı ölçülebilir.

```python
# Ilk blogun uzerine: S, kullanim, DONEM, IKINCI_TOHUM, surecler oradan gelir.
def ornekle(surecler_, aralik, pencere=DONEM):
    """`aralik` saniyede bir bakan izleme araci. Doner: surec basina gorulen en yuksek."""
    goruldu = {s["pid"]: 0 for s in surecler_}
    bakis = 0
    for t in range(0, pencere, aralik):
        bakis += 1
        for s in surecler_:
            goruldu[s["pid"]] = max(goruldu[s["pid"]], kullanim(s, t))
    return {"bakis": bakis, "goruldu": goruldu}


def gercek_en_yuksek(surecler_, pencere=DONEM):
    return {s["pid"]: max(kullanim(s, t) for t in range(pencere)) for s in surecler_}


def tani_agir_surec(olcum, esik=50):
    """Ciktidan cikarilan tani: hangi surecler agir."""
    return {p for p, v in olcum.items() if v >= esik}


ARALIK = (1, 5, 15, 30, 60)


def supur(surecler_):
    gercek = tani_agir_surec(gercek_en_yuksek(surecler_))
    satir = []
    for a in ARALIK:
        o = ornekle(surecler_, a)
        t = tani_agir_surec(o["goruldu"])
        satir.append((a, o["bakis"], len(t), len(gercek - t),
                      len(gercek - t) + len(t - gercek)))
    return len(gercek), satir


kahin, satirlar = supur(S)
print("aralik  bakis  uretilen satir  gorulen agir  kacirilan  yanlis tani")
for a, bakis, gor, kacan, yanlis in satirlar:
    print(f"{a:6d}  {bakis:5d}  {bakis * len(S):14d}  {gor:12d}"
          f"  {kacan:9d}  {yanlis:11d}")
print("kahin (gercekte agir):", kahin, "| toplam surec:", len(S))
print()
kahin2, satirlar2 = supur(surecler(IKINCI_TOHUM))
print("ikinci tohum", IKINCI_TOHUM, "- kahin:", kahin2)
print("  yanlis tani:", {a: y for a, _, _, _, y in satirlar2})
print("  ilk tohum  :", {a: y for a, _, _, _, y in satirlar})
```

```
aralik  bakis  uretilen satir  gorulen agir  kacirilan  yanlis tani
     1    600           14400            14          0            0
     5    120            2880            14          0            0
    15     40             960            11          3            3
    30     20             480             9          5            5
    60     10             240             9          5            5
kahin (gercekte agir): 14 | toplam surec: 24

ikinci tohum 20260219 - kahin: 12
  yanlis tani: {1: 0, 5: 0, 15: 5, 30: 6, 60: 7}
  ilk tohum  : {1: 0, 5: 0, 15: 3, 30: 5, 60: 5}
```

Bir ve beş saniyede bir bakan araç 14 ağır sürecin 14'ünü de görüyor: **yanlış tanı sıfır.**
Aralık 15 saniyeye çıktığında **3**, 30 ve 60 saniyede **5** süreç kaçıyor. Kaçanlar hep aynı
sınıftır — altmış saniyede bir, beş saniye boyunca yükselenler. Otuz saniyede bir bakan bir
araç, beş saniyelik bir sıçramayı yakalamak zorunda değildir; çoğu zaman yakalamaz.

**Araç yalan söylemiyor.** Baktığı anda o süreç gerçekten hafifti. Yanlış olan şey çıktı değil,
çıktıdan çıkarılan tanıdır: "listede yok, demek ki sorun değil."

İkinci sütun ikinci iddiayı taşır. Aralık 1'de araç **14.400 satır** üretiyor, aralık 60'ta
**240**. Satır sayısı altmış katına çıkarken yanlış tanı 5'ten 0'a iniyor — ama bu iki sayının
ilişkisi doğrusal değildir: **2.880 satır da 14.400 satır kadar iyi tanı veriyor.** Beş
saniyeden sonra eklenen her satır tanıya hiçbir şey katmıyor.

İkinci tohumda kâhin 12'ye düşüyor ve yanlış tanı 5, 6, 7 çıkıyor. Sayılar aynı değil; **yön ve
büyüklük düzeni aynı** — sıfırdan başlıyor, aralıkla birlikte tek haneli bir bandın içinde
büyüyor. Ayakta kalan sonuç şudur: **aralığı büyütmek kaçırılan süreç üretir.** Kaç tanesinin
kaçacağı kurguya bağlıdır.

#### Tek Bakış ile Ömür Ortalaması

Örnekleme aralığı çok bakışın sorunudur. Operatörün en sık yaptığı şey ise **tek bakıştır**:
bir kez `ps` çalıştırmak. Bunun ve `ps` sütununun kendi ortalamasının bedeli ayrı ölçülür.

```python
# Onceki bloklarin uzerine: S, kullanim, DONEM ve tani_agir_surec oradan gelir.
GERCEK = tani_agir_surec({s["pid"]: max(kullanim(s, t) for t in range(DONEM))
                          for s in S})


def anlik(surecler_, t):
    """Tek bakista okunan deger: o anda ne kullaniyordu."""
    return {s["pid"]: kullanim(s, t) for s in surecler_}


def omur_ortalamasi(surecler_, pencere=DONEM):
    """Surecin dogumundan beri ortalamasi. Sicramayi seyreltir."""
    return {s["pid"]: sum(kullanim(s, t) for t in range(pencere)) // pencere
            for s in surecler_}


okumalar = [(f"anlik t={t:<3d}       ", anlik(S, t)) for t in (0, 3, 30, 300)]
okumalar.append(("omur ortalamasi   ", omur_ortalamasi(S)))
print("okuma bicimi        gorulen agir  kacirilan  yanlis tani")
for ad, olcum in okumalar:
    t_ = tani_agir_surec(olcum)
    print(f"  {ad}{len(t_):10d}  {len(GERCEK - t_):9d}"
          f"  {len(t_ - GERCEK) + len(GERCEK - t_):11d}")
print("kahin:", len(GERCEK), "agir surec |", len(S), "surecin icinde")
```

```
okuma bicimi        gorulen agir  kacirilan  yanlis tani
  anlik t=0                  9          5            5
  anlik t=3                  8          6            6
  anlik t=30                 7          7            7
  anlik t=300                9          5            5
  omur ortalamasi            7          7            7
kahin: 14 agir surec | 24 surecin icinde
```

Tek bakış, bakılan ana göre **5 ile 7 arasında** yanlış tanı veriyor. Aynı makine, aynı 600
saniye, aynı komut: yanıt hangi saniyede çalıştırıldığına bağlı. Bu, "sorunu görmek için `ps`
çalıştırdım, bir şey yoktu" cümlesinin ölçüsüdür.

Asıl sonuç son satırdadır. **Ömür ortalaması, en kötü tek bakış kadar yanlış:** 7 yanlış tanı.
Ortalama almak sıçramayı yok etmiyor, seyreltiyor — beş saniyelik bir sıçrama 600 saniyeye
bölündüğünde eşiğin çok altına iniyor. Daha uzun bir pencereye bakmak burada daha iyi bir tanı
vermiyor; **hangi ölçünün alındığı, ne kadar veri toplandığından önce gelir.**

#### Ada Göre Aramanın Bedeli

Süreç aramanın iki yolu vardır. Listeyi metin olarak süzmek — `ps` çıktısını `grep` ile
daraltmak — aramayı yapan sürecin kendisini de yakalar ve kalıbı bozuk yazıldığında ilgisiz
satırları getirir. İkinci yol, süreç tablosunu doğrudan sorgulayan `pgrep` ve eşi `pkill`'dir:

```text
$ pgrep -a -u uygulama kuyruk-isleyici
1128 /opt/kuyruk/kuyruk-isleyici --pay 3
1135 /opt/kuyruk/kuyruk-isleyici --pay 4
```

Bu döküm de **örnektir ve çalıştırılmamıştır.** `pgrep` metin süzmeye göre daha kesindir:
kendini listelemez, kullanıcıya ve oturuma göre daraltılabilir. Ama kesin olan şey
**eşleşmedir**, tanı değil. Ada göre seçmek, "bu adı taşıyan süreçler sorunludur" varsayımını
sessizce kabul eder.

```python
# Onceki bloklarin uzerine: S ve GERCEK oradan gelir.
ad_tablosu = {}
for s in S:
    ad_tablosu.setdefault(s["komut"], [0, 0])
    ad_tablosu[s["komut"]][0] += 1
    ad_tablosu[s["komut"]][1] += 1 if s["pid"] in GERCEK else 0

print("komut adi              eslesen  gercekte agir  ada gore yanlis dokunus")
for k in sorted(ad_tablosu):
    toplam, agir = ad_tablosu[k]
    print(f"  {k:20s} {toplam:7d}  {agir:13d}  {min(agir, toplam - agir):23d}")
print("toplam yanlis dokunus (en iyi durumda):",
      sum(min(a, t - a) for t, a in ad_tablosu.values()))
print("tek bir ada gore secim en cok kac agir sureci yakalar:",
      max(a for _, a in ad_tablosu.values()), "/", len(GERCEK))
```

```
komut adi              eslesen  gercekte agir  ada gore yanlis dokunus
  kuyruk-isleyici            6              3                        3
  olcum-toplayici            5              2                        2
  onbellek-temizleyici       2              1                        1
  rapor-uretici              5              4                        1
  veri-alici                 1              1                        0
  yedek-gorevi               5              3                        2
toplam yanlis dokunus (en iyi durumda): 9
tek bir ada gore secim en cok kac agir sureci yakalar: 4 / 14
```

Hiçbir komut adı ağır süreçlerle örtüşmüyor. `kuyruk-isleyici` adını taşıyan altı süreçten
üçü ağır, üçü değil; adı seçen bir operatör ya üç masum süreci de kapsar ya da üç ağır süreci
dışarıda bırakır. En iyi durumda bile **9 sürece yanlış dokunulur** ve tek bir ad ağır
süreçlerin en çok **4'ünü** yakalar — kâhin 14'tür.

Bunun nedeni kurgu değil, yapının kendisidir: **komut adı bir kimlik değil, bir etikettir.**
Aynı program birden çok örnekle koşar, örneklerin yükü birbirinden bağımsızdır. Adla seçmek
hızlıdır ve bu hız, dersin üçüncü dersinde sinyal gönderirken bedele dönüşür.

#### Özet

- Kursun ölçüsü üç sayıdır: kâhin, araç çıktısı ve yanlış tanı sayısı. Bir komutun değeri
  gösterdiği satır sayısı değil, o satırlardan çıkarılan tanının kaç kez yanlış olduğudur.
- Kurgu sunucudaki 24 sürecin **14'ü** gerçekte ağırdır; bu kâhindir ve dersin bütün sayıları
  ona göre okunur.
- Örnekleme aralığı 15 saniyeye çıktığında araç **3**, 30 ve 60 saniyede **5** ağır süreci
  kaçırır. Kaçanlar altmış saniyede bir sıçrayanlardır; araç baktığı anda haklıdır.
- Aralık 1 saniyede **14.400**, 60 saniyede **240** satır üretir; ama 2.880 satır 14.400 satır
  kadar iyi tanı verir. Daha çok satır bir yerden sonra tanıya hiçbir şey katmaz.
- Tek bakış bakılan ana göre **5 ile 7** arasında yanlış tanı verir; sürecin doğumundan beri
  alınan ömür ortalaması **7** yanlış tanıyla en kötü tek bakış kadar kötüdür.
- Ada göre arama en iyi durumda **9 sürece yanlış dokunur** ve tek bir ad ağır süreçlerin en
  çok **4'ünü** yakalar; komut adı bir kimlik değil etikettir.

#### Sonraki Adım

Bu ders süreçlere dışarıdan baktı: liste, sütun, arama. Süreçlerin bir de operatörle kurdukları
bağ vardır — hangi terminale bağlılar, hangi oturuma aitler, oturum kapandığında ne olur.
Sonraki ders bu bağı ölçer: bir betik arka plana alındığında ve oturum kapatıldığında hangi
süreçlerin hayatta kaldığı, `jobs` çıktısının gösterdiğiyle hiç örtüşmeyebilir.

### Ön Plan ve Arka Plan İşleri

Source: https://academia.sh/tr/kurslar/sistem-yonetimi/on-plan-ve-arka-plan-isleri

Oturum kapandığında kabuğun 13 işinden `&` ile arka plana alınanların tamamı ölüyor, disown edilenlerin 9'u ölüyor, nohup ve ayrı oturum 13'ünü de yaşatıyor; `jobs` 13 satır gösterirken gerçekte ilerleyen iş sayısı 8.

Önceki ders süreçlere makinenin dışından baktı: hangileri var, hangileri ağır. Süreçlerin bir
de operatörle kurdukları bağ vardır. Bir betik bir uçterminden başlatıldığında yalnız bir
süreç doğmaz; o süreç bir **süreç öbeğine**, öbek bir **oturuma**, oturum bir **denetleyen
uçtermine** bağlanır. Uçtermin kapandığında bu zincir boyunca olaylar yürür.

Kabuk Programlama kursu iş denetimini kullanım düzeyinde kurmuştu: `&`, `wait`, çıkış kodu.
Bu ders o tarafı tekrarlamaz. Ölçtüğü şey tek bir sorudur: **oturum kapandığında hangi
süreçler hayatta kalır** ve `jobs` çıktısı bunu ne kadar önceden söyler.

#### Oturum, Öbek ve Denetleyen Uçtermin

Boru hattındaki komutlar tek bir **süreç öbeğine** konur; kabuk sinyalleri öbek başına
gönderir, tek tek süreçlere değil. Bir uçterminden açılan kabuk ve onun bütün çocukları aynı
**oturumu** paylaşır, oturumun başında kabuk durur ve o uçtermin oturumun **denetleyen
uçterminidir**. Bu üç kimlik listelenebilir:

```text
$ ps -eo pid,ppid,pgid,sid,tty,stat,comm
    PID    PPID    PGID     SID TTY      STAT COMMAND
   1000     998    1000    1000 pts/4    Ss   bash
   1014    1000    1014    1000 pts/4    R    rapor-uretici
   1021    1000    1014    1000 pts/4    R    olcum-toplayici
   1043    1000    1043    1000 pts/4    T    yedek-gorevi
   1092       1    1092    1092 ?        Ss   kuyruk-isleyici
```

Bu döküm **örnektir ve çalıştırılmamıştır.** Okunacak üç şey var. İlk iki süreç aynı `PGID`
değerini taşıyor: bir boru hattının iki ucu. Son sürecin `SID` değeri kendi süreç numarasına
eşit ve `TTY` sütunu boş — o süreç **ayrı bir oturumdadır** ve hiçbir uçtermine bağlı
değildir. Üçüncü sürecin durumu `T`: **durdurulmuş.**

Uçtermin kapandığında iki ayrı olay yürür ve ikisi de öldürebilir. Birincisi **kapanma
sinyalidir**: çekirdek onu oturumun başına iletir, kabuk da kendi işlerine yayar. İkincisi
daha sessizdir — uçtermin yok olduğu için ona yazmaya çalışan süreç bir **girdi/çıktı hatası**
alır ve çoğu program bu hatada durur. İkinci olay hiçbir sinyal kaydı bırakmaz.

- **SY8.** Kurgu sunucunun 24 sürecinin bir bölümü operatörün kabuğundan başlatılmıştır;
  gerisi başka oturumlara aittir.
- **SY9.** Her sürecin iki ek özelliği vardır: çıktısı hâlâ uçtermine gidiyor mu (`yazar`) ve
  uçterminden girdi bekliyor mu (`okur`).
- **SY10.** Beş ayrılma yöntemi ölçülür: **ön plan**, **arka plan** (`&`), **disown**,
  **nohup** ve **ayrı oturum**.
- **SY11.** Bir yöntem üç şeyi belirler: süreç oturumda mı, kabuk ona kapanma sinyali
  gönderir mi, süreç o sinyali yok sayar mı. Yönlendirme yapan yöntemler `yazar` özelliğini
  de kapatır.
- **SY12.** Hayatta kalma kuralı: oturum dışındaki süreçlere hiçbir olay ulaşmaz; oturum
  içindekiler önce sinyalle, sonra yazma hatasıyla elenir.
- **SY13.** Yaygın beklenti şudur: ön plandaki iş ölür, öteki dört yöntemin hepsi işi
  yaşatır. Yanlış tanı, bu beklenti ile gerçeğin ayrıldığı süreç sayısıdır.
- **SY14.** İkinci tohum **20260219**'dur.

```python
# --- ortak tanim, birinci dersteki bicimiyle: kurgu sunucu ve kahin
TOHUM, IKINCI_TOHUM = 20260218, 20260219
KULLANICI = ("kok", "uygulama", "yedek", "izleme")
KOMUT = ("veri-alici", "rapor-uretici", "yedek-gorevi", "olcum-toplayici",
         "kuyruk-isleyici", "onbellek-temizleyici")


def uretec(tohum):
    d = tohum

    def sonraki(n):
        nonlocal d
        d = (d * 1103515245 + 12345) % 2147483648
        return d % n
    return sonraki


def surecler(tohum=TOHUM, sayi=24):
    r = uretec(tohum)
    liste = []
    for i in range(sayi):
        tur = r(10)
        desen = "duz" if tur < 5 else ("ani" if tur < 8 else "agir")
        liste.append({"pid": 1000 + i * 7 + r(5),
                      "kullanici": KULLANICI[r(len(KULLANICI))],
                      "komut": KOMUT[r(len(KOMUT))], "desen": desen,
                      "oncelik": r(11) - 5, "bellek": 20 + r(400),
                      "sinyal_yok_sayar": r(10) < 2})
    return liste


# --- bu dersin katmani: oturum bagi
YONTEM = ("on plan", "arka plan", "disown", "nohup", "ayri oturum")


def oturum_dagit(surecler_, tohum=TOHUM):
    """Kabugun kendi isleri makinenin geri kalanindan ayrilir.
    `yazar`: ciktisi hala uctermine gidiyor. `okur`: ucterminden girdi bekliyor."""
    r = uretec(tohum)
    for s in surecler_:
        s["kabuk_isi"] = r(10) < 5
        s["yazar"] = r(10) < 6
        s["okur"] = r(10) < 3
    return surecler_


def uygula(surec, yontem):
    """Bir yontem, surecin uc ozelligini belirler. Kalani surecin kendisinden gelir."""
    oturumda = yontem != "ayri oturum"
    kabuk_gonderir = yontem in ("on plan", "arka plan")
    korumali = yontem in ("nohup", "ayri oturum")
    return {"oturumda": oturumda, "kabuk_gonderir": kabuk_gonderir,
            "yok_sayar": korumali or surec["sinyal_yok_sayar"],
            "yazar": surec["yazar"] and not korumali}


def hayatta_mi(d):
    """Ucterminin kapanmasi IKI ayri olay uretir , ikisi de oldurebilir."""
    if not d["oturumda"]:
        return True                          # oturum disinda: hicbiri ulasmaz
    if d["kabuk_gonderir"] and not d["yok_sayar"]:
        return False                         # birinci olay: kapanma sinyali
    if d["yazar"]:
        return False                         # ikinci olay: uctermin gidince yazma hatasi
    return True


S = oturum_dagit(surecler())
KABUK = [s for s in S if s["kabuk_isi"]]
print("toplam surec:", len(S), "| kabugun isi:", len(KABUK),
      "| baska oturuma ait:", len(S) - len(KABUK))
print("kabuk isleri: sinyali yok sayan", sum(1 for s in KABUK if s["sinyal_yok_sayar"]),
      "| uctermine yazan", sum(1 for s in KABUK if s["yazar"]),
      "| ucterminden okuyan", sum(1 for s in KABUK if s["okur"]))
```

```
toplam surec: 24 | kabugun isi: 13 | baska oturuma ait: 11
kabuk isleri: sinyali yok sayan 4 | uctermine yazan 9 | ucterminden okuyan 5
```

#### İşi Arka Plana Almak

İş denetiminin komutları kabuğun kendi komutlarıdır ve süreç tablosunda görünmezler. `&`
komutu arka planda başlatır, `Ctrl+Z` ön plandaki işi **durdurur**, `bg` durdurulmuş işi arka
planda sürdürür, `fg` ön plana geri getirir. `jobs` kabuğun iş tablosunu listeler:

```text
$ jobs -l
[1]-  1014 Running                 ./rapor-uretici --gun 7 &
[2]+  1043 Stopped                 ./yedek-gorevi --tam
[3]   1021 Running                 ./olcum-toplayici | ./ozet &
```

Bu döküm de **örnektir ve çalıştırılmamıştır.** İşlere `%1`, `%2` gibi belirteçlerle atıf
yapılır; `fg %2` ikinci işi ön plana alır. Köşeli parantez içindeki sayı süreç numarası
değildir — kabuğun kendi sayacıdır ve başka bir kabukta anlamı yoktur.

`jobs` tablosunun iki sınırı vardır ve ikisi de bu dersin ölçtüğü şeyi üretir. Birincisi,
tablo **yalnız bu kabuğun işlerini** taşır: başka bir oturumdan başlatılan ya da servis
yöneticisinin başlattığı hiçbir süreç burada görünmez. İkincisi, tablo **şu andaki bağı**
gösterir, gelecekteki sonucu değil.

Bu iki sınırın pratik sonucu şudur: bir işin oturumdan gerçekten ayrıldığını doğrulamanın yolu
`jobs` değildir. Doğrulama **ikinci bir oturum açıp** süreci orada aramaktır; `ps` çıktısında
`TTY` sütununun boş, `PPID` sütununun `1` olması ayrılmanın kanıtıdır. `jobs` çıktısı bu
soruya hiçbir zaman yanıt veremez, çünkü sorulan şey tam olarak `jobs` çıktısının kapsamı
dışındadır.

Kabuk Programlama kursunda kurulan çıkış kodu sözleşmesi burada da geçerlidir: `wait %1` işin
bitmesini bekler ve onun çıkış kodunu döndürür. Bir iş sinyalle sonlandırıldığında kod
**128 artı sinyal numarası** olur; arka plandaki bir işin sessizce ölüp ölmediği bu koddan
anlaşılır. Kod okunmadan `wait` çağrılmazsa bilgi kaybolur — kabuk kapandığında iş tablosu da
gider.

Süreci oturumdan ayırmanın üç yolu vardır. `disown` işi kabuğun tablosundan siler; kabuk artık
ona kapanma sinyali göndermez. `nohup` komutu süreci kapanma sinyalini yok sayacak biçimde
başlatır ve çıktısını bir dosyaya yönlendirir. `setsid` süreci **yeni bir oturuma** koyar;
oturumun denetleyen uçtermini yoktur, dolayısıyla kapanacak bir uçtermin de yoktur. Üç yöntem
aynı işi yapmaz ve fark ölçülebilir.

#### Beş Yöntem, Bir Kapanma

```python
# Onceki blogun uzerine: KABUK, YONTEM, uygula, hayatta_mi oradan gelir.
# Yaygin beklenti: on planda birakilan is olur, otekilerin hepsi yasar.
BEKLENTI = {"on plan": False, "arka plan": True, "disown": True,
            "nohup": True, "ayri oturum": True}

print("yontem       uygulanan  beklenen  gercekte  olen  yanlis tani")
for y in YONTEM:
    gercek = {s["pid"] for s in KABUK if hayatta_mi(uygula(s, y))}
    beklenen = {s["pid"] for s in KABUK} if BEKLENTI[y] else set()
    print(f"  {y:11s} {len(KABUK):9d}  {len(beklenen):8d}  {len(gercek):8d}"
          f"  {len(KABUK) - len(gercek):4d}  {len(beklenen ^ gercek):11d}")
print("kahin: her satirda `gercekte` sutunu , kurguyu biz urettik")
```

```
yontem       uygulanan  beklenen  gercekte  olen  yanlis tani
  on plan            13         0         0    13            0
  arka plan          13        13         0    13           13
  disown             13        13         4     9            9
  nohup              13        13        13     0            0
  ayri oturum        13        13        13     0            0
kahin: her satirda `gercekte` sutunu , kurguyu biz urettik
```

İkinci satır bu dersin ana sonucudur. **`&` hiçbir şey yaşatmıyor:** arka plana alınan 13 işin
13'ü de ölüyor, yanlış tanı **13**. Ampersan işi arka plana alır, oturumdan çıkarmaz; kabuk
kapanma sinyalini kendi işlerine yayarken arka plandakileri de kapsar. "Arkasına `&` koydum,
çıkışta sürer" cümlesi kurgudaki her iş için yanlıştır.

Üçüncü satır daha ince bir sonuç verir. `disown` kapanma sinyalini gerçekten engelliyor — ama
13 işten yalnız **4'ü** hayatta kalıyor, **9'u** ölüyor. Ölenler ikinci olayın kurbanıdır:
çıktıları hâlâ uçtermine gidiyordu ve uçtermin yok olunca ilk yazma denemesinde durdular.
`disown` **sinyali keser, akışı kesmez.** Bu, iki ayrı olayı tek bir önlemle karşılamaya
çalışmanın bedelidir.

Son iki satırda yanlış tanı sıfırdır. `nohup` iki olayı birden karşılar: sinyali yok saydırır
**ve** çıktıyı dosyaya yönlendirir. Ayrı oturum ise sorunu ortadan kaldırır; kapanacak bir bağ
yoktur. Kalıcı işler için doğru düzen budur — ya ayrı bir oturum, ya da işi hiç kabuktan
başlatmayıp bir servis birimi hâline getirmek. İkincisi bu kursun sonraki konusudur.

Kabuklar arasında ayrıntı değişebilir; bazı kabuklarda kapanma sinyalinin işlere yayılması bir
seçenekle denetlenir. Ölçülen şey **yaygın davranıştır** ve yaygın davranışta `&` tek başına
bir koruma değildir.

#### Listede Duran, İlerlemeyen İş

Ayrılma sorununun bir eşi vardır. Arka plandaki bir süreç **uçterminden okumaya** kalkarsa
çekirdek onu durdurur; süreç ölmez, bekler. Durdurulmuş süreç `ps` çıktısında `T` durumuyla,
`jobs` çıktısında "Stopped" olarak görünür. İkisi de sürecin var olduğunu doğrular; hiçbiri
ilerleme olmadığını söylemez.

```python
# Onceki bloklarin uzerine: KABUK, uygula, hayatta_mi, oturum_dagit, surecler.
duran = [s for s in KABUK if s["okur"]]
print("arka plana alinan is icinde ucterminden okumaya calisan:", len(duran))
print("  bunlar DURDURULUR: `jobs` listeler , `ps` gosterir , ilerleme sifirdir")
print("  `jobs` satiri:", len(KABUK), "| gercekte ilerleyen:", len(KABUK) - len(duran),
      "| yanlis tani:", len(duran))
print()
for tohum in (TOHUM, IKINCI_TOHUM):
    S2 = oturum_dagit(surecler(tohum), tohum)
    K2 = [s for s in S2 if s["kabuk_isi"]]
    d = {y: len({s["pid"] for s in K2} ^ {s["pid"] for s in K2
                                          if hayatta_mi(uygula(s, y))})
         for y in ("arka plan", "disown", "nohup")}
    print(f"tohum {tohum}: kabuk isi {len(K2):2d} | yanlis tani {d}"
          f" | duran {sum(1 for s in K2 if s['okur'])}")
```

```
arka plana alinan is icinde ucterminden okumaya calisan: 5
  bunlar DURDURULUR: `jobs` listeler , `ps` gosterir , ilerleme sifirdir
  `jobs` satiri: 13 | gercekte ilerleyen: 8 | yanlis tani: 5

tohum 20260218: kabuk isi 13 | yanlis tani {'arka plan': 13, 'disown': 9, 'nohup': 0} | duran 5
tohum 20260219: kabuk isi 11 | yanlis tani {'arka plan': 11, 'disown': 6, 'nohup': 0} | duran 2
```

`jobs` **13 satır** gösteriyor, gerçekte ilerleyen iş **8**. Beş iş bir parola ya da onay
bekliyor ve kimse onlara yazamıyor; listede varlar, ilerlemede yoklar. Yanlış tanı **5**.
Bunun pratik karşılığı, arka plana alınacak her işin girdisinin de kapatılmasıdır — çıktı
yönlendirmesi tek başına yetmez. Girdisi boş bir dosyaya bağlanan bir süreç durdurulmaz;
okuma denemesi hemen dosya sonu döndürür ve süreç kendi hata yolundan ilerler. Durmanın
kendisi de görünür bir olay değildir: iş tablosundaki durum alanı dışında hiçbir yere yazılmaz.

İkinci tohumda kabuğun işi 11'e, duran iş 2'ye iniyor; `&` için yanlış tanı yine **bütün
işler**, `disown` için 9 yerine **6**, `nohup` için yine **0**. Sayılar kurguya bağlıdır;
**sıralama ve yön değişmiyor** — `&` en kötü, `disown` yarım koruma, `nohup` ve ayrı oturum
tam koruma.

#### Öksüz ve Zombi Süreçler

Oturum kapandığında hayatta kalan süreçlerin ana süreci ölmüştür. Çekirdek bunları
**öksüz** bırakmaz: ana süreç numaralarını yeniden bağlar ve `ps` çıktısında `PPID` sütunu
`1` olur. Öksüzlük bir arıza değildir; ayrılma yöntemlerinin üçü de bu yolla çalışır.

Asıl karışıklığı yaratan durum bunun tersidir. Bir süreç bittiğinde çıkış kodu, ana süreç onu
**toplayana** kadar süreç tablosunda saklanır. Ana süreç bu toplamayı yapmazsa çocuk **zombi**
durumunda kalır: kodu yürütmüyor, bellek tutmuyor, ama tablo girdisi duruyor. `ps` çıktısında
durumu `Z`, komut adı köşeli parantez içindedir.

Zombiye sinyal göndermenin hiçbir etkisi yoktur — sinyal, kodu yürüten bir sürece iletilir ve
zombi kod yürütmez. Kabuk Programlama kursunda `wait` ile toplanan şey tam olarak budur;
toplamayan bir ana süreç yazıldığında sonuç zombi birikmesidir. Çözüm zombileri sonlandırmak
değil, **ana süreci** düzeltmek ya da sonlandırmaktır; ana süreç gidince zombiler yeniden
bağlanır ve orada toplanırlar.

Birikmenin bedeli sayılabilir bir kaynaktır: her zombi bir süreç tablosu girdisi ve bir süreç
numarası tutar. Yeterince biriktiğinde yeni süreç yaratılamaz. Bu sınırın hangi hata
iletisiyle göründüğü bu konunun beşinci dersinin konusudur.

Kalıcı işler için `nohup` ve `setsid` doğru araçlardır ama tek seçenek değildir. **Uçtermin
çoklayıcı (terminal multiplexer)** sınıfındaki araçlar oturumu kendileri taşır: iş, bağlantı
koptuğunda ölmez, çünkü işin bağlı olduğu uçtermin operatörünkü değil çoklayıcınınkidir.
Aradaki fark ölçüm değil, sahiplik farkıdır — çoklayıcının kendisi kapandığında aynı iki olay
yeniden yürür.

#### Özet

- Bir süreç üç kimliğe bağlıdır: süreç öbeği, oturum ve denetleyen uçtermin. Kabuk sinyalleri
  süreç öbeğine gönderir; `ps` çıktısında `PGID`, `SID` ve `TTY` sütunları bu bağı gösterir.
- Uçtermin kapandığında iki ayrı olay yürür: kapanma sinyali ve uçtermine yazmaya çalışan
  sürecin aldığı girdi/çıktı hatası. İkinci olay hiçbir sinyal kaydı bırakmaz.
- `&` oturumdan ayırmaz: arka plana alınan **13 işin 13'ü** ölüyor, yanlış tanı **13**.
- `disown` sinyali keser ama akışı kesmez; 13 işten **4'ü** kalıyor, **9'u** çıktısı uçtermine
  gittiği için ölüyor. `nohup` ve ayrı oturum iki olayı birden karşılar, yanlış tanı **0**.
- `jobs` **13 satır** gösterirken gerçekte ilerleyen iş **8**'dir; uçterminden okumaya çalışan
  5 iş durdurulmuştur ve listede çalışıyor görünür.

#### Sonraki Adım

Bu ders bir sinyalin süreçlere nasıl ulaştığını kenardan gördü: kapanma sinyali kabuktan
işlere yayıldı, kimileri onu yok saydı. Yok saymanın kendisi henüz ölçülmedi. Sonraki ders
sinyalleri doğrudan ele alır ve tek bir cümleyi sayar: sonlandırma isteği bir **istektir**
ve komutun hatasız dönmesi hedefin bittiği anlamına gelmez.

### Sinyaller

Source: https://academia.sh/tr/kurslar/sistem-yonetimi/sinyaller

Yedi ağır sürece sonlandırma isteği gönderildiğinde 2'si kabul ediyor, 5'i yok sayıyor; zorlayan sinyalde 7/7 bitiyor ama 2 sürecin temizliği yarıda kesiliyor. Komut her durumda 0 döndürdüğü için beklemeden verilen tanı yedi hedefin yedisinde de yanlış.

Önceki ders bir sinyalin kenarından geçti: uçtermin kapandığında kapanma sinyali oturumun
başına iletildi, kabuk onu kendi işlerine yaydı ve işlerin bir bölümü sinyali **yok saydı**.
Yok saymanın kendisi ölçülmedi. Bu ders sinyalleri doğrudan ele alır.

Ölçtüğü cümle tektir: **sonlandırma isteği bir istektir.** Komutun hatasız dönmesi hedefin
bittiği anlamına gelmez ve aradaki fark sayılabilir.

#### Sinyal Nedir, Ne Değildir

Sinyal, çekirdeğin bir sürece ilettiği **kesme bildirimidir**. İçinde veri taşımaz; yalnız
kimliği vardır. Süreç bir sinyali aldığında üç şeyden biri olur: sürecin o sinyal için
tanımladığı **işleyici** çalışır, sinyal **yok sayılır**, ya da sinyalin **varsayılan eylemi**
uygulanır. Varsayılan eylem sinyalden sinyale değişir — sonlandırmak, durdurmak, sürdürmek ya
da hiçbir şey yapmamak.

Kabuk Programlama kursundaki `trap` tam olarak birinci seçeneği kurar: betiğin sinyal
işleyicisini tanımlar. Buradaki fark bakış yönüdür — orada sinyali **alan** taraf yazıldı,
burada **gönderen** taraf ölçülür.

| Sinyal | Varsayılan eylem | Yakalanabilir mi | Ne için |
|---|---|---|---|
| `SIGHUP` | sonlandır | evet | denetleyen uçtermin gitti; birçok servis bunu yeniden okuma isteği sayar |
| `SIGINT` | sonlandır | evet | uçterminden kesme (`Ctrl+C`) |
| `SIGQUIT` | sonlandır ve döküm al | evet | uçterminden çıkış isteği |
| `SIGTERM` | sonlandır | evet | **sonlandırma isteği** — nazik biçim, varsayılan |
| `SIGKILL` | sonlandır | **hayır** | **zorlayan sinyal** — süreç söz sahibi değildir |
| `SIGSTOP` | durdur | **hayır** | süreci dondurur |
| `SIGCONT` | sürdür | evet | durdurulmuş süreci sürdürür |
| `SIGUSR1`, `SIGUSR2` | sonlandır | evet | anlamı programın kendi sözleşmesindedir |
| `SIGPIPE` | sonlandır | evet | okuyan ucu kapanmış boru hattına yazma |
| `SIGCHLD` | yok say | evet | bir çocuk süreç bitti ya da durdu |

İki satır ötekilerden ayrıdır. `SIGKILL` ve `SIGSTOP` **yakalanamaz, yok sayılamaz ve
engellenemez**; kararı çekirdek verir, süreç haberdar bile olmaz. Bunun bedeli tam olarak
budur: zorlayan sinyalle ölen bir süreç, kendi kapanış yordamını **hiç çalıştıramaz**.

Sinyallerin numaraları da vardır ama numaralar her mimaride aynı değildir. Taşınabilir yazım
**adla** yapılır: `kill -TERM` yazılır, sayı yazılmaz.

#### Sinyal Göndermek

Sinyal gönderen komutun adı `kill`'dir ve adı yanıltıcıdır: komut süreç öldürmez, sinyal
iletir. Hangi sinyalin iletildiği seçeneğe bağlıdır, seçenek verilmezse sonlandırma isteği
gönderilir.

```text
$ kill -TERM 1128
$ echo $?
0
$ kill -0 1128           # sinyal gonderme , yalnizca ulasilabilir mi diye bak
$ echo $?
0
$ pkill -TERM -u uygulama kuyruk-isleyici
$ kill -TERM -1014       # eksi isaretli sayi: sinyal SUREC OBEGINE gider
```

Bu döküm **örnektir ve çalıştırılmamıştır.** Dört ayrıntı taşıyor. `kill -0` hiçbir sinyal
göndermez; yalnız hedefin var olup olmadığını ve ona sinyal gönderme yetkisinin bulunup
bulunmadığını sınar — doğrulamanın aracı budur. `pkill` hedefi ada ve kullanıcıya göre seçer;
birinci dersteki ölçü burada geçerlidir, ad bir kimlik değil etikettir. Eksi işaretli sayı
hedefi **süreç öbeğine** çevirir: bir boru hattının tek üyesine değil, tamamına gönderir.
`killall` da ada göre çalışır ve davranışı sistemler arasında değişebildiği için, taşınabilir
betiklerde `pkill` yeğlenir.

En kritik ayrıntı ikinci satırdadır. `kill` komutunun çıkış kodu **sinyalin iletilip
iletilmediğini** bildirir. Hedefin sinyali nasıl karşıladığı, işleyicisinin ne yaptığı, sürecin
bitip bitmediği bu koda **hiç yansımaz**. Kodu 0 gören operatörün "iş bitti" demesi, ölçülmemiş
bir tanıdır.

- **SY15.** Hedef küme, kurgu sunucudaki **sürekli ağır** desenli süreçlerdir.
- **SY16.** Süreçlerin bir bölümü sonlandırma isteğini **yok sayar**; ortak tanımdaki
  `sinyal_yok_sayar` alanı bunu taşır. Zorlayan sinyal yok sayılamaz.
- **SY17.** İsteği kabul eden bir süreç **hemen bitmez**: önce kendi temizliğini yapar.
  Temizlik süresi süreç başına **0 ile 39 saniye** arasındadır.
- **SY18.** `kill` komutunun çıkış kodu her denemede **0**'dır; sinyal iletildi demektir.
- **SY19.** Beklemeden verilen tanı şudur: "komut döndü, hedefler bitti." Yanlış tanı sayısı,
  o anda gerçekte bitmemiş hedeflerin sayısıdır.
- **SY20.** Zorlayan sinyal bütün hedefleri bitirir; isteği kabul edip temizliği süren
  süreçlerin temizliği **yarıda kesilir**.
- **SY21.** İkinci tohum **20260219**'dur.

```python
# --- ortak tanim, birinci dersteki bicimiyle
TOHUM, IKINCI_TOHUM = 20260218, 20260219
KULLANICI = ("kok", "uygulama", "yedek", "izleme")
KOMUT = ("veri-alici", "rapor-uretici", "yedek-gorevi", "olcum-toplayici",
         "kuyruk-isleyici", "onbellek-temizleyici")


def uretec(tohum):
    d = tohum

    def sonraki(n):
        nonlocal d
        d = (d * 1103515245 + 12345) % 2147483648
        return d % n
    return sonraki


def surecler(tohum=TOHUM, sayi=24):
    r = uretec(tohum)
    liste = []
    for i in range(sayi):
        tur = r(10)
        desen = "duz" if tur < 5 else ("ani" if tur < 8 else "agir")
        liste.append({"pid": 1000 + i * 7 + r(5),
                      "kullanici": KULLANICI[r(len(KULLANICI))],
                      "komut": KOMUT[r(len(KOMUT))], "desen": desen,
                      "oncelik": r(11) - 5, "bellek": 20 + r(400),
                      "sinyal_yok_sayar": r(10) < 2})
    return liste


# --- bu dersin katmani: sinyal ve temizlik
def sinyal_gonder(surecler_, sinyal, hedefler):
    """Ortak tanim: `sonlandir` yoksayilabilir , `zorla` yoksayilamaz."""
    biten, direnen = [], []
    for s in surecler_:
        if s["pid"] not in hedefler:
            continue
        if sinyal == "zorla" or not s["sinyal_yok_sayar"]:
            biten.append(s["pid"])
        else:
            direnen.append(s["pid"])
    return {"biten": len(biten), "direnen": len(direnen),
            "direnen_pid": sorted(direnen)}


S = surecler()
HEDEF = {s["pid"] for s in S if s["desen"] == "agir"}
print("hedef:", len(HEDEF), "agir surec")
print("sonlandir:", sinyal_gonder(S, "sonlandir", HEDEF))
print("zorla    :", sinyal_gonder(S, "zorla", HEDEF))
```

```
hedef: 7 agir surec
sonlandir: {'biten': 2, 'direnen': 5, 'direnen_pid': [1014, 1043, 1092, 1108, 1128]}
zorla    : {'biten': 7, 'direnen': 0, 'direnen_pid': []}
```

Yedi ağır sürecin yalnız **2'si** sonlandırma isteğini kabul ediyor, **5'i** direniyor.
Zorlayan sinyalde **7'sinin 7'si** bitiyor. Direnen süreçlerin listesi çıktıda görünmez —
`kill` komutu bu bilgiyi vermez, veremez. Bu, kursun ortak tanımının ikinci bağlayıcı
okumasıdır.

#### Beklemenin Ölçüsü

Yukarıdaki iki satır sinyalin nihai sonucudur. Operatör ise sonucu değil, **bir andaki durumu**
görür. Sonlandırma isteğini kabul eden süreç hemen bitmez; açık dosyalarını kapatır, tamponunu
boşaltır, kilidini bırakır. O sırada süreç hâlâ listede durur.

```python
# Onceki blogun uzerine: S, HEDEF, uretec, TOHUM oradan gelir.
def temizlik_ata(surecler_, tohum=TOHUM):
    """Sonlandirma istegini kabul eden surec hemen bitmez: once temizlik yapar."""
    r = uretec(tohum)
    for s in surecler_:
        s["temizlik"] = r(40)              # saniye
    return surecler_


def sonlandirma_denemesi(surecler_, hedefler, bekleme):
    """Istek gonderildi , `bekleme` saniye sonra bakildi. `kill` cikis kodu her
    durumda 0: sinyal ILETILDI demek , hedef BITTI demek degil."""
    biten, temizleniyor, yok_sayan = [], [], []
    for s in surecler_:
        if s["pid"] not in hedefler:
            continue
        if s["sinyal_yok_sayar"]:
            yok_sayan.append(s["pid"])
        elif s["temizlik"] <= bekleme:
            biten.append(s["pid"])
        else:
            temizleniyor.append(s["pid"])
    return len(biten), len(temizleniyor), len(yok_sayan)


temizlik_ata(S)
print("hedef:", len(HEDEF), "surec | `kill` cikis kodu her satirda 0")
print("bekleme  biten  temizleniyor  yok sayan  hayatta  yanlis tani")
for b in (0, 1, 5, 10, 30, 60):
    biten, tmz, yok = sonlandirma_denemesi(S, HEDEF, b)
    print(f"{b:7d}  {biten:5d}  {tmz:12d}  {yok:9d}  {tmz + yok:7d}"
          f"  {len(HEDEF) - biten:11d}")
```

```
hedef: 7 surec | `kill` cikis kodu her satirda 0
bekleme  biten  temizleniyor  yok sayan  hayatta  yanlis tani
      0      0             2          5        7            7
      1      0             2          5        7            7
      5      0             2          5        7            7
     10      1             1          5        6            6
     30      2             0          5        5            5
     60      2             0          5        5            5
```

İlk satır dersin en sert sayısıdır. Komut döndüğü anda hedeflerin **hiçbiri** bitmemiştir;
yanlış tanı **7/7**. Beş süreç isteği yok saydı, ikisi de henüz temizliğini bitirmedi. Çıkış
kodu yine de 0'dır — komut işini yapmıştır, sinyal iletilmiştir.

İkinci okuma bekleme sütunundadır. Beş saniye beklemek hiçbir şey değiştirmiyor; onuncu
saniyede **1**, otuzuncu saniyede **2** süreç bitiyor. Otuzdan sonra hiçbir şey değişmiyor:
kalan **5** süreç isteği yok sayıyor ve **ne kadar beklenirse beklensin bitmeyecek**. Beklemek
temizliği tamamlar, direnci çözmez. Bu ayrım doğru yordamı belirler.

Doğru sıra dört adımdır: **isteği gönder**, **bekle**, `kill -0` ile **doğrula**, ancak hâlâ
duranı **zorla**. Servis yöneticileri de bunu yapar ve bekleme süresi birim tanımında ayarlanır
bir değerdir; o taraf bu kursun sonraki konusudur.

Bekleme süresinin seçimi bu tabloya bakılarak yapılır ve iki yönde de bedeli vardır. Kısa
seçilirse temizliğini sürdüren süreçler gereksiz yere zorlanır; tabloda beş saniyede zorlamak,
onuncu ve otuzuncu saniyede kendiliğinden bitecek iki süreci kesmek demektir. Uzun seçilirse
direnen süreçler boşuna beklenir: otuzuncu saniyeden sonra tabloda hiçbir sütun değişmez,
altmış saniye beklemek yalnız arızayı uzatır. Ölçülmüş bir eşik yoksa seçilen süre bir varsayım
olarak kalır ve o varsayım her iki yönde de yanlış tanı üretir.

#### Ulaşmayan ve Bekleyen Sinyal

Direnç, sinyalin işe yaramamasının tek nedeni değildir. Üç durum daha vardır ve üçü de aynı
görüntüyü üretir: komut 0 döndürür, hedef durur.

Birincisi **bekleyen sinyaldir**. Durdurulmuş bir sürece gönderilen sonlandırma isteği hemen
işlenmez; süreç kod yürütmediği için sinyal **bekler**. Önceki dersteki durdurulmuş işler tam
olarak bu durumdadır: istek iletilir, kuyruğa yazılır ve süreç `SIGCONT` ile sürdürülene kadar
orada kalır. Zorlayan sinyal bu kuralın dışındadır; onu çekirdek uygular ve sürecin kod
yürütmesini beklemez. Bir işi gerçekten durdurmanın taşınabilir yolu bu yüzden önce sürdürüp
sonra istek göndermektir.

İkincisi **engellenmiş sinyaldir**. Bir süreç kritik bir bölüme girerken belirli sinyalleri
geçici olarak engelleyebilir; engel kalkana kadar sinyal bekler. Dışarıdan bakan operatör
engellenmiş sinyal ile yok sayılmış sinyali ayırt edemez — ikisinde de hiçbir şey olmaz.

Üçüncüsü **yanlış hedeftir**. Süreç numaraları yeniden kullanılır: bir süreç bittikten sonra
aynı numara başka bir sürece verilebilir. Numarayı bir dosyadan okuyup gönderen betikler bu
yüzden numarayı doğrulamadan kullanmamalıdır; `kill -0` ile varlığı sınamak yeterli değildir,
sınanan şey numaranın **kime** ait olduğudur.

Bu üç durumun ortak sonucu şudur: sinyal göndermek bir olay değil, bir **istektir** ve isteğin
sonucu yalnız hedefe bakarak öğrenilir. Bir kapanış yordamının doğru yazılmış olması da
gönderen tarafı ilgilendirir — servislerin yeniden yapılandırılmasında `SIGHUP` kullanılması
bu yüzden yaygındır: servis yeniden başlatılmadan yapılandırmasını yeniden okur ve açık
bağlantıları düşürmez. Aynı sinyalin başka bir programda varsayılan eylemi sonlandırmaktır;
anlamı sinyalin değil, **programın sözleşmesinindir**.

#### Zorlamanın Bedeli

Bekleme adımını atlayıp doğrudan zorlayan sinyali göndermek çekici bir kısayoldur: sonuç
kesindir, hedeflerin hepsi biter. Kesinliğin bir bedeli vardır ve o da sayılabilir.

```python
# Onceki bloklarin uzerine: S, HEDEF, sonlandirma_denemesi, sinyal_gonder,
# temizlik_ata, surecler, IKINCI_TOHUM.
z = sinyal_gonder(S, "zorla", HEDEF)
kesilen = [s["pid"] for s in S if s["pid"] in HEDEF
           and not s["sinyal_yok_sayar"] and s["temizlik"] > 0]
print("dogrudan zorlayan sinyal:", z["biten"], "/", len(HEDEF), "bitti")
print("  yarida kesilen temizlik:", len(kesilen), "surec")
print("dogru sira (istek , bekle , dogrula , zorla):")
biten, tmz, yok = sonlandirma_denemesi(S, HEDEF, 30)
print("  30 saniye sonra kendiliginden biten:", biten,
      "| zorlanmasi gereken:", tmz + yok)
print()
for tohum in (TOHUM, IKINCI_TOHUM):
    S2 = temizlik_ata(surecler(tohum), tohum)
    H2 = {s["pid"] for s in S2 if s["desen"] == "agir"}
    g = sinyal_gonder(S2, "sonlandir", H2)
    b0 = sonlandirma_denemesi(S2, H2, 0)[0]
    b30 = sonlandirma_denemesi(S2, H2, 30)[0]
    print(f"tohum {tohum}: hedef {len(H2)} | istegi kabul eden {g['biten']}"
          f" | 0 sn sonra biten {b0} | 30 sn sonra biten {b30}"
          f" | yanlis tani {len(H2) - b0}")
```

```
dogrudan zorlayan sinyal: 7 / 7 bitti
  yarida kesilen temizlik: 2 surec
dogru sira (istek , bekle , dogrula , zorla):
  30 saniye sonra kendiliginden biten: 2 | zorlanmasi gereken: 5

tohum 20260218: hedef 7 | istegi kabul eden 2 | 0 sn sonra biten 0 | 30 sn sonra biten 2 | yanlis tani 7
tohum 20260219: hedef 5 | istegi kabul eden 5 | 0 sn sonra biten 0 | 30 sn sonra biten 4 | yanlis tani 5
```

Doğrudan zorlamak **7/7** sonuç veriyor ve **2 sürecin temizliği yarıda kesiliyor**. Kesilen
temizlik soyut bir kayıp değildir: tamponu boşaltmamış bir süreç yazdığını sanan veriyi
kaybeder, kilidini bırakmamış bir süreç geride bir kilit dosyası bırakır, geçici dizinini
silmemiş bir süreç onu diskte bırakır. Bu üç sonucun hiçbiri `kill` çıktısında görünmez ve
üçü de sonraki çalıştırmada başka bir arıza olarak ortaya çıkar.

Bekleyerek yapılan sıralamada aynı iki süreç kendiliğinden bitiyor ve yalnız **5** hedef
zorlanıyor. Fark iki süreçlik değildir; **iki temiz kapanışlıktır.**

İkinci tohumda hedef sayısı 5'e iniyor ve isteği kabul edenlerin sayısı 2 yerine **5** oluyor
— kompozisyon tamamen değişiyor. Değişmeyen tek şey ilk sütundur: **her iki tohumda da komut
döndüğü anda biten hedef sayısı 0'dır** ve beklemeden verilen tanı bütün hedeflerde yanlıştır.
Kaç sürecin direneceği kurguya bağlıdır; komutun dönmesinin hiçbir şey söylemediği değildir.

Modelin dışında kalan bir sınır da not edilmelidir: zorlayan sinyal burada her hedefi
bitiriyor, ama gerçek bir sistemde çekirdek çağrısının içinde kesilemez uykuda bekleyen bir
süreç ona da yanıt vermez. O durumda süreç `D` durumunda görünür ve tek çare bekleyişin
nedenini gidermektir.

#### Özet

- Sinyal veri taşımayan bir kesme bildirimidir; süreç onu yakalayabilir, yok sayabilir ya da
  varsayılan eyleme bırakabilir. `SIGKILL` ve `SIGSTOP` yakalanamaz, engellenemez.
- `kill` komutunun çıkış kodu sinyalin **iletildiğini** bildirir, hedefin bittiğini değil.
  Doğrulamanın aracı `kill -0`'dır.
- Yedi ağır hedeften sonlandırma isteğini yalnız **2'si** kabul ediyor, **5'i** yok sayıyor;
  zorlayan sinyalde **7/7** bitiyor.
- Komut döndüğü anda biten hedef sayısı **0**'dır: yanlış tanı **7/7**. Onuncu saniyede 1,
  otuzuncu saniyede 2 süreç biter; otuzdan sonra hiçbir şey değişmez.
- Doğrudan zorlamak **2 sürecin temizliğini yarıda keser**; beklemeli sırada aynı iki süreç
  temiz kapanır ve yalnız 5 hedef zorlanır. Doğru sıra istek, bekleme, doğrulama, zorlamadır.

#### Sonraki Adım

Bu ders süreci durdurmayı ölçtü. Durdurmak her zaman doğru yanıt değildir: ağır bir süreç
gerekli bir iş yapıyor olabilir ve istenen şey onu bitirmek değil, **yavaşlatmaktır**. Sonraki
ders öncelik değerini ele alır ve tek bir soruyu sayar: bir sürecin önceliğini değiştirmenin
gerçekten görülebilir etkisi ne kadardır ve değişen sütun ile değişen davranış aynı şey midir.

### Süreç Öncelikleri

Source: https://academia.sh/tr/kurslar/sistem-yonetimi/surec-oncelikleri

En çok işleyen sürecin öncelik değeri en düşükten en yükseğe çekildiğinde payı 41.878 birimden 0'a iniyor, ama toplam iş 237.906'dan 238.244'e ve yük 3,97'den 3,97'ye gidiyor: boşalan kapasitenin yüzde 94'ü öteki ağır süreçlere, hafif süreçlere yüzde 0'ı gidiyor.

Önceki ders süreci durdurmayı ölçtü. Durdurmak her zaman doğru yanıt değildir: ağır bir süreç
gerekli bir iş yapıyor olabilir ve istenen şey onu bitirmek değil, **yavaşlatmaktır**. Bunun
için tasarlanmış bir düğme vardır ve süreç tablosunun bir sütununda durur.

Bu ders o düğmeyi ölçer. Soru şudur: bir sürecin önceliğini değiştirmenin **görülebilir**
etkisi ne kadardır ve değişen sütun ile değişen davranış aynı şey midir.

#### Öncelik Değeri

Süreç tablosundaki `NI` sütunu **öncelik değerini (nice value)** taşır. Ölçeği terstir:
**değer büyüdükçe sürecin önceliği düşer.** Aralık `-20` ile `19` arasındadır; `-20` en
saldırgan, `19` en geri çekilmiş süreçtir. Varsayılan `0`'dır.

Yanındaki `PRI` sütunu farklı bir şeydir. `NI` operatörün **girdisidir**; `PRI` çizelgeleyicinin
o girdiden ve sürecin geçmiş davranışından **hesapladığı** değerdir. Operatör `PRI` sütununu
doğrudan yazamaz. İkisini karıştırmak, girdi ile sonucu karıştırmaktır.

```text
$ nice -n 10 ./yedek-gorevi --tam &
$ renice -n 5 -p 1043
1043 (process ID) old priority 0, new priority 5
$ renice -n 5 -u yedek
$ ps -eo pid,ni,pri,comm --sort=ni
    PID  NI PRI COMMAND
   1014  -5  24 kuyruk-isleyici
   1128   0  19 rapor-uretici
   1043   5  14 olcum-toplayici
   1071  10   9 yedek-gorevi
```

Bu döküm **örnektir ve çalıştırılmamıştır.** `nice` değeri süreç **başlarken** verir, `renice`
**çalışan** bir süreci değiştirir; `-u` seçeneği bir kullanıcının bütün süreçlerini kapsar.
Bir kural burada gizlidir: yetkisiz bir kullanıcı öncelik değerini yalnız **artırabilir**, yani
kendi sürecini yalnız geri çekebilir. Geri alma yetkisi olağan durumda yoktur — 10'a çekilen bir
süreç, yetkisiz kullanıcı tarafından 5'e döndürülemez; tek istisna, sürecin öncelik değeri için
ayrılmış bir kaynak sınırı taşımasıdır. Bu, dikkatsiz bir `renice` çağrısının kalıcı
olabileceği anlamına gelir.

İşletim Sistemi Kavramları kursu çizelgeleyici yordamlarını birbiriyle karşılaştırmıştı; o
karşılaştırma burada tekrarlanmaz. Buradaki soru yordamın hangisi olduğu değil, **operatörün
elindeki tek düğmenin çıktıda ne kadar göründüğüdür.**

- **SY22.** Kurgu sunucunun **4 çekirdeği** vardır; saniyelik kapasite **400 birimdir**.
- **SY23.** Süreçlerin toplam talebi kapasiteyi aşar; sistem doymuştur.
- **SY24.** Öncelik değeri bir **ağırlığa** çevrilir: her birim ağırlığı yaklaşık dörtte bir
  oranında değiştirir. `0` değerinin ağırlığı **1024**'tür.
- **SY25.** Kapasite ağırlığa göre bölüşülür, ama **hiçbir süreç istediğinden fazlasını almaz**.
  Doyan süreçlerin artığı kalanlar arasında yeniden bölüşülür.
- **SY26.** Kâhin, pencere boyunca **gerçekten yapılan toplam iştir**. Kapasite sabit olduğu
  için bu sayının üst sınırı da sabittir.
- **SY27.** Çözünürlük toplam işin **yüzde 1'idir**. Bunun altındaki fark ölçülmemiş sayılır.
- **SY28.** Tanı şudur: "en çok işleyen sürecin önceliğini düşürmek sistemin yükünü azaltır."
  Yanlış tanı, bu cümlenin ayakta kalmadığı deneme sayısıdır.
- **SY29.** İkinci tohum **20260219**'dur.

```python
# --- ortak tanim, birinci dersteki bicimiyle
TOHUM, IKINCI_TOHUM, DONEM = 20260218, 20260219, 600
KULLANICI = ("kok", "uygulama", "yedek", "izleme")
KOMUT = ("veri-alici", "rapor-uretici", "yedek-gorevi", "olcum-toplayici",
         "kuyruk-isleyici", "onbellek-temizleyici")


def uretec(tohum):
    d = tohum

    def sonraki(n):
        nonlocal d
        d = (d * 1103515245 + 12345) % 2147483648
        return d % n
    return sonraki


def surecler(tohum=TOHUM, sayi=24):
    r = uretec(tohum)
    liste = []
    for i in range(sayi):
        tur = r(10)
        desen = "duz" if tur < 5 else ("ani" if tur < 8 else "agir")
        liste.append({"pid": 1000 + i * 7 + r(5),
                      "kullanici": KULLANICI[r(len(KULLANICI))],
                      "komut": KOMUT[r(len(KOMUT))], "desen": desen,
                      "oncelik": r(11) - 5, "bellek": 20 + r(400),
                      "sinyal_yok_sayar": r(10) < 2})
    return liste


def kullanim(surec, saniye):
    d = surec["desen"]
    if d == "duz":
        return 3 + (surec["pid"] + saniye) % 4
    if d == "agir":
        return 60 + (surec["pid"] + saniye) % 25
    faz = (saniye + surec["pid"]) % 60
    return 88 + faz if faz < 5 else 2 + faz % 3


# --- bu dersin katmani: oncelik degeri kapasiteyi nasil bolusturur
CEKIRDEK, KAPASITE = 4, 400


def agirlik(oncelik):
    """Oncelik degeri BUYUDUKCE pay KUCULUR. Her birim yaklasik dortte bir."""
    a = 1024
    for _ in range(abs(oncelik)):
        a = a * 5 // 4 if oncelik < 0 else a * 4 // 5
    return a


def pay_dagit(surecler_, saniye, kapasite=KAPASITE):
    """Talep kapasiteyi asarsa pay AGIRLIGA gore bolusulur; kimse istediginden
    fazlasini almaz. Cizelgeleyicinin kendisi baska bir kursta olculdu."""
    talep = {s["pid"]: kullanim(s, saniye) for s in surecler_}
    pay = {p: 0 for p in talep}
    bekleyen, kalan = list(surecler_), kapasite
    while bekleyen and kalan > 0:
        toplam = sum(agirlik(s["oncelik"]) for s in bekleyen)
        doyan = [s for s in bekleyen
                 if kalan * agirlik(s["oncelik"]) // toplam >= talep[s["pid"]]]
        if not doyan:
            for s in bekleyen:
                pay[s["pid"]] = kalan * agirlik(s["oncelik"]) // toplam
            break
        for s in doyan:
            pay[s["pid"]] = talep[s["pid"]]
            kalan -= talep[s["pid"]]
            bekleyen.remove(s)
    return pay


def pencere_payi(surecler_, pencere=DONEM):
    toplam = {s["pid"]: 0 for s in surecler_}
    for t in range(pencere):
        for p, v in pay_dagit(surecler_, t).items():
            toplam[p] += v
    return toplam


S = surecler()
print("cekirdek:", CEKIRDEK, "| kapasite:", KAPASITE,
      "| t=0 talebi:", sum(kullanim(s, 0) for s in S))
print("oncelik  ", "  ".join(f"{o:4d}" for o in (-5, -3, 0, 3, 5, 10, 19)))
print("agirlik  ", "  ".join(f"{agirlik(o):4d}" for o in (-5, -3, 0, 3, 5, 10, 19)))
EN_AGIR = max(S, key=lambda s: sum(kullanim(s, t) for t in range(DONEM)))
print("en cok isleyen surec:", EN_AGIR["pid"], EN_AGIR["komut"],
      "| oncelik degeri", EN_AGIR["oncelik"])
```

```
cekirdek: 4 | kapasite: 400 | t=0 talebi: 736
oncelik     -5    -3     0     3     5    10    19
agirlik   3125  2000  1024   524   335   108    12
en cok isleyen surec: 1014 kuyruk-isleyici | oncelik degeri -5
```

Ağırlık tablosu ölçeğin ne kadar sert olduğunu gösteriyor: `-5` ile `19` arasında ağırlık
**3125**'ten **12**'ye, yani 260 kat düşüyor. Talep 736, kapasite 400 — sistem doymuş
durumdadır ve öncelik değerinin bir anlamı ancak bu koşulda vardır. Doymamış bir sistemde
herkes istediğini alır ve ağırlıkların hiçbir etkisi olmaz.

#### Önceliği Düşürmenin Görülebilir Etkisi

En çok işleyen süreç `1014`'tür ve öncelik değeri şu anda `-5`, yani en saldırgan uçtadır.
Operatörün alışılmış hamlesi onu geri çekmektir.

```python
# Onceki blogun uzerine: S, EN_AGIR, pencere_payi, DONEM oradan gelir.
import copy


def yeniden_oncelikle(surecler_, pid, yeni):
    k = copy.deepcopy(surecler_)
    for s in k:
        if s["pid"] == pid:
            s["oncelik"] = yeni
    return k


HEDEF = EN_AGIR["pid"]
TABAN = pencere_payi(S)
TOPLAM_TABAN = sum(TABAN.values())
print("yeni oncelik  hedefin payi  degisim  otekilerin payi  toplam is   yuk")
for y in (-5, -4, -3, 0, 5, 10, 19):
    p = pencere_payi(yeniden_oncelikle(S, HEDEF, y))
    toplam = sum(p.values())
    print(f"{y:12d}  {p[HEDEF]:12d}  {p[HEDEF] - TABAN[HEDEF]:7d}"
          f"  {toplam - p[HEDEF]:15d}  {toplam:9d}"
          f"  {toplam / DONEM / 100:5.2f}")
print("kahin: kapasite", KAPASITE * DONEM, "birim | taban kullanimi", TOPLAM_TABAN)
```

```
yeni oncelik  hedefin payi  degisim  otekilerin payi  toplam is   yuk
          -5         41878        0           196028     237906   3.97
          -4         37372    -4506           200460     237832   3.96
          -3         31462   -10416           206434     237896   3.96
           0         17668   -24210           220318     237986   3.97
           5          6120   -35758           231974     238094   3.97
          10          1830   -40048           236342     238172   3.97
          19             0   -41878           238244     238244   3.97
kahin: kapasite 240000 birim | taban kullanimi 237906
```

İkinci sütun operatörü ikna eder. Tek bir adımlık değişiklik — `-5`'ten `-4`'e — hedefin payını
**4.506 birim** düşürüyor; uca kadar çekildiğinde pay **41.878'den 0'a** iniyor. Araç çıktısında
bu sütun gerçekten değişir, `NI` sütunu her denemede yeni değeri gösterir ve `%CPU` sütununda
hedef listenin dibine düşer. Yapılan işin görüldüğü tek yer burasıdır.

Son iki sütun tanıyı bozar. **Toplam iş** 237.906'dan 238.244'e gidiyor — **338 birimlik**,
yani yüzde 0,14'lük bir fark. Çözünürlük yüzde 1 olduğu için bu fark **ölçülmemiş sayılır**.
**Yük** sütunu yedi satırın altısında **3,97**, birinde 3,96: hiç değişmemiştir. Sistem doymuş
durumdaydı ve doymuş kaldı.

Nedeni tek cümlelik bir gözlemdir: **öncelik değeri işi azaltmaz, işi bölüştürür.** Kapasite
kaç birimse o kadar iş yapılır; kimin yaptığı değişir, ne kadar yapıldığı değişmez. Yükten
şikâyet eden bir operatörün `renice` ile aradığı şey ise tam olarak "ne kadar yapıldığı"dır.

#### Boşalan Kapasite Kime Gidiyor

Hedefin bıraktığı 41.878 birim yok olmadı; başka süreçlere gitti. Hangilerine gittiği,
`renice` hamlesinin gerçekten kime yaradığını söyler.

```python
# Onceki bloklarin uzerine: S, HEDEF, TABAN, TOPLAM_TABAN, yeniden_oncelikle.
son = pencere_payi(yeniden_oncelikle(S, HEDEF, 19))
bosalan = TABAN[HEDEF] - son[HEDEF]
kazanc = {d: 0 for d in ("duz", "ani", "agir")}
for s in S:
    if s["pid"] != HEDEF:
        kazanc[s["desen"]] += son[s["pid"]] - TABAN[s["pid"]]
print("hedeften bosalan is:", bosalan, "birim | nereye gitti:")
for d in ("duz", "ani", "agir"):
    print(f"  {d:5s} desenli surecler: {kazanc[d]:6d}"
          f"  ({round(100 * kazanc[d] / bosalan):3d} yuzde)")
print("toplam is degisimi:", sum(son.values()) - TOPLAM_TABAN, "birim |",
      f"{100 * (sum(son.values()) - TOPLAM_TABAN) / TOPLAM_TABAN:.2f} yuzde")
print("`NI` sutunu kac denemede degisti: 6 / 6 | yuk kac denemede dustu: 0 / 6")
print()
for tohum in (TOHUM, IKINCI_TOHUM):
    S2 = surecler(tohum)
    h = max(S2, key=lambda s: sum(kullanim(s, t) for t in range(DONEM)))["pid"]
    t0, t1 = pencere_payi(S2), pencere_payi(yeniden_oncelikle(S2, h, 19))
    print(f"tohum {tohum}: hedefin payi {t0[h]:6d} -> {t1[h]:5d}"
          f" | toplam is {sum(t0.values()):6d} -> {sum(t1.values()):6d}"
          f" | yuk {sum(t0.values()) / DONEM / 100:.2f} ->"
          f" {sum(t1.values()) / DONEM / 100:.2f}")
```

```
hedeften bosalan is: 41878 birim | nereye gitti:
  duz   desenli surecler:      0  (  0 yuzde)
  ani   desenli surecler:   2774  (  7 yuzde)
  agir  desenli surecler:  39442  ( 94 yuzde)
toplam is degisimi: 338 birim | 0.14 yuzde
`NI` sutunu kac denemede degisti: 6 / 6 | yuk kac denemede dustu: 0 / 6

tohum 20260218: hedefin payi  41878 ->     0 | toplam is 237906 -> 238244 | yuk 3.97 -> 3.97
tohum 20260219: hedefin payi  43200 -> 12786 | toplam is 239078 -> 239450 | yuk 3.98 -> 3.99
```

Boşalan kapasitenin **yüzde 94'ü öteki ağır süreçlere** gidiyor. Hafif desenli süreçlere
gidenin oranı **yüzde 0'dır** — tam olarak sıfır birim. Bunun nedeni açıktır ve önceliğin
gerçek kuralını verir: hafif süreçler zaten doyuyordu. Az isteyen bir süreç, doymuş bir
sistemde bile istediğini alır; ona verilecek fazla bir şey yoktur.

Sonuç, `renice` hamlesinin ne zaman işe yaradığını belirler. **Öncelik değeri yalnız
çekişenler arasında bir şey değiştirir.** Yavaş açılan bir kabuk, geciken bir bağlantı ya da
takılan bir düzenleyici genellikle az isteyen süreçlerdir ve onların sorunu öncelik değil,
başka bir kaynaktır. Ağır bir toplu işi geri çekmek ise gerçekten işe yarar — ama kazanan,
operatörün önemsediği süreç değil, **öteki ağır süreçler** olur.

Yanlış tanı sayısı son satırlarda duruyor: `NI` sütunu **6 denemenin 6'sında** değişti, yük
**6 denemenin 0'ında** düştü. "Önceliği düşürdüm, yük azaldı" cümlesi altı denemenin
**altısında** yanlıştır. İkinci tohumda hedefin payı 43.200'den 12.786'ya iniyor, toplam iş
239.078'den 239.450'ye çıkıyor ve yük 3,98'den 3,99'a gidiyor: pay büyük ölçüde değişiyor,
**yük yine değişmiyor.** Payın ne kadar düşeceği kurguya bağlıdır; yükün değişmemesi değildir.

İşlemci önceliğinin hiç işe yaramadığı bir durum daha vardır ve ölçüm dışında kalır: darboğaz
işlemci değilse `renice` hiçbir şeye dokunmaz. Diske ya da ağa bağlı bekleyen bir süreç zaten
çekirdek istemiyordur. Girdi/çıktı önceliği için ayrı bir araç, `ionice` vardır; katı zamanlama
sınıfları ise `chrt` ile ayarlanır ve yanlış kullanıldığında bir sürecin sistemi tamamen
kilitlemesine yol açabilir. Darboğazın hangisi olduğunun ayrımı bu kursun günlükler konusunda
ölçülür.

#### Kalıtım ve Doğru Kullanım

Öncelik değerinin ölçülmeyen ama belirleyici bir özelliği vardır: **çocuk süreçler onu
devralır.** Çatallanan her süreç ana sürecin değeriyle doğar. Bunun pratik sonucu, bir ağacın
tamamını geri çekmenin tek çağrıyla yapılabilmesidir — sarmalayıcı betik `nice` ile
başlatıldığında altındaki bütün adımlar aynı değerle koşar. Aynı özellik ters yönde de
işler: bir zamanlayıcının ya da servis yöneticisinin verdiği değer, oradan başlayan her şeye
yapışır ve etkileşimli oturumda ölçülen davranış orada yeniden üretilmez.

Ölçümden çıkan üç kullanım kuralı vardır.

**Değeri başlangıçta ver.** `renice` çalışan bir sürecin o ana kadarki payını geri getirmez;
yalnız bundan sonrasını değiştirir. Uzun bir toplu iş, çekişmeye girdikten sonra değil,
başlarken geri çekilmelidir. Bir işin geri çekilmiş başlatılması `nice` ile tek satırdır ve
kalıtım sayesinde alt adımları da kapsar.

**Yararlanacak tarafın çekişiyor olduğunu doğrula.** Ölçümün en keskin sayısı buydu: hafif
süreçlere giden pay **sıfır**. Bir sürecin yavaşlığı öncelikten geliyorsa o süreç çekirdek
için sıraya girmiş olmalıdır. Sıraya girmemiş bir sürece öncelik vermek hiçbir sayıyı
değiştirmez.

**Yükü öncelikle çözmeye çalışma.** Yük, yapılan işin toplamıdır; öncelik o toplamı
bölüştürür. Yükü gerçekten azaltan şeyler başkadır: işi azaltmak, işi zamana yaymak, kapasite
eklemek ya da işi durdurmak. İlk üçü bu kursun kapsamı dışındadır; dördüncüsü önceki dersin
konusuydu ve bedeli oradaki tabloda ölçüldü.

Bir uyarı da ters uçtan gelir. Öncelik değerini negatife çekmek yalnız yetkili kullanıcının
yapabileceği bir işlemdir ve etkisi bu tablonun aynadaki görüntüsüdür: kayırılan süreç pay
kazanır, kaybeden **öteki her şeydir**. Sistem yönetim araçlarının kendisi geri çekilmiş
değerlerle koşuyorsa, arıza anında operatörün kabuğu da yavaşlar.

#### Özet

- `NI` sütunu operatörün girdisi olan öncelik değerini, `PRI` sütunu çizelgeleyicinin ondan
  hesapladığı değeri taşır; ölçek terstir ve yetkisiz kullanıcı değeri yalnız artırabilir.
- Öncelik değeri bir ağırlığa çevrilir: `-5` ağırlığı **3125**, `19` ağırlığı **12**'dir.
  Ağırlıkların anlamı yalnız **doymuş** bir sistemde vardır.
- En çok işleyen sürecin değeri uca çekildiğinde payı **41.878'den 0'a** iner; bu, araç
  çıktısında görülen tek değişikliktir.
- Toplam iş **237.906'dan 238.244'e** gider (yüzde 0,14, çözünürlüğün altında) ve yük yedi
  denemede de **3,97** kalır. Öncelik işi azaltmaz, bölüştürür.
- Boşalan 41.878 birimin **yüzde 94'ü öteki ağır süreçlere**, hafif süreçlere **yüzde 0'ı**
  gider; hafif süreçler zaten doyuyordu.
- "Önceliği düşürdüm, yük azaldı" tanısı altı denemenin **altısında** yanlıştır: `NI` sütunu
  6/6 değişir, yük 0/6 düşer.

#### Sonraki Adım

Öncelik bir sürecin **ne kadar hızlı** koşacağını etkiler, **ne kadar tüketebileceğini**
sınırlamaz. Sınırlamanın kendi mekanizması vardır: süreç başına konan kaynak kısıtları.
Sonraki ders bu kısıtları ölçer ve şu soruyu sorar: bir sınır aşıldığında ortaya çıkan hata
iletisi, sınırın hangisi olduğunu söylüyor mu — yoksa iki ayrı neden aynı cümleyle mi
görünüyor.

### Kaynak Sınırları

Source: https://academia.sh/tr/kurslar/sistem-yonetimi/kaynak-sinirlari

Sekiz ayrı arıza nedeni üç hata iletisine ve bir sessizliğe çöküyor: 60 olayın 13'ü hiçbir ileti üretmiyor, yalnız iletiye bakan tanı 21 kez, yalnız sınır okuyan tanı 29 kez, ikisini birleştiren tanı 13 kez yanılıyor.

Öncelik bir sürecin **ne kadar hızlı** koşacağını etkiler, **ne kadar tüketebileceğini**
sınırlamaz. Önceki dersin tablosunda geri çekilen süreç yine de dilediği kadar dosya açabilir,
dilediği kadar çocuk üretebilir, dilediği kadar bellek isteyebilirdi. Tüketimi sınırlamanın
kendi mekanizması vardır.

Bu ders o mekanizmayı ve sınırın aşıldığında ortaya çıkan arızayı ölçer. Soru şudur: hata
iletisi, sınırın hangisi olduğunu söylüyor mu — yoksa ayrı nedenler aynı cümleyle mi görünüyor.

#### Süreç Başına Kısıt

Her sürecin bir kaynak sınırı kümesi vardır ve her sınırın **iki** değeri bulunur. **Yumuşak
sınır** yürürlükte olan değerdir; süreç onu katı sınıra kadar kendisi yükseltebilir. **Katı
sınır** tavandır ve yalnız ayrıcalıklı bir süreç tarafından yükseltilebilir. Sınırlar kabuğun
`ulimit` yerleşiğiyle okunur ve yazılır:

```text
$ ulimit -a                # kurgudaki sunucunun sinirlari , ornek dokum
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
file size               (blocks, -f) unlimited
open files                      (-n) 1024
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 4096
virtual memory          (kbytes, -v) unlimited
$ ulimit -Hn               # kati sinir
4096
$ ulimit -Sn 2048          # yumusak siniri kati sinira kadar yukselt
$ cat /proc/1014/limits
Limit                     Soft Limit  Hard Limit  Units
Max open files            2048        4096        files
Max processes             4096        8192        processes
```

Bu döküm **örnektir ve çalıştırılmamıştır.** İki okuma yolu görünüyor: `ulimit` **çağıran
kabuğun** sınırlarını verir, `/proc` altındaki dosya ise **belirli bir sürecin** sınırlarını.
İkisi aynı şey değildir ve fark, bu dersteki tanı hatalarının bir bölümünün kaynağıdır.

Kritik kural **kalıtımdır**: sınırlar çatallanma anında ana süreçten devralınır ve kabuğun
yerleşiğiyle sonradan değiştirilemez. Bunun üç sonucu vardır. Birincisi, bir kabukta `ulimit` ile
yükseltilen sınır yalnız **o kabuğun bundan sonraki çocuklarını** kapsar. İkincisi, servis
yöneticisinin başlattığı bir süreç operatörün kabuğundan hiçbir şey devralmaz; onun sınırları
birim tanımında yazılır. Üçüncüsü, çalışan bir sürecin sınırını sonradan yükseltmek yerleşik
bir kabuk komutuyla yapılamaz — süreç yeniden başlatılmalıdır. "Sınırı yükselttim ama servis
hâlâ aynı hatayı veriyor" cümlesinin ölçüsü budur.

Süreç başına kısıt tek kısıt türü değildir. Bir süreç öbeğinin **toplamına** konan kısıtlar
ayrı bir mekanizmadır; ad alanı ve denetim grubu bu kursta ele alınmaz ve **Çekirdek
Arayüzleri ve İzolasyon** kursuna bırakılır. Buradaki her sayı **tek bir sürecin** sınırıdır.

- **SY30.** Gözlem penceresinde **60 arıza olayı** görülür.
- **SY31.** Arızaların **sekiz ayrı nedeni** vardır ve nedenler eşit sıklıkta değildir;
  göreli sıklıkları modelde sabittir.
- **SY32.** Sekiz neden **üç hata iletisi** ve **bir sessizlik** üretir. Her ileti **iki ayrı
  nedene** karşılık gelir.
- **SY33.** Dosya boyutu ve işlemci zamanı sınırları hiçbir ileti üretmez: süreç sinyalle
  öldürülür ve geriye yalnız bir çıkış kodu kalır.
- **SY34.** Nedenlerin altısı **süreç başına** sınırdır; ikisi (sistem geneli tanıtıcı ve boş
  bellek) süreç başına değildir ve sürecin kendi sınır okumasında görünmez.
- **SY35.** Birinci tanı yolu **yalnız hata iletisidir**. İletiden çıkarılabilecek en iyi tanı,
  o iletiyi üreten nedenlerin **en sık görülenidir**.
- **SY36.** İkinci tanı yolu **sınır okumasıdır**: sayacın hâlâ sınırında oturup oturmadığına
  bakılır.
- **SY37.** Olayların bir bölümü **geçicidir**: bakıldığında sayaç geri düşmüştür ve okuma
  hiçbir şey göstermez. Kanıt kendiliğinden yok olmuştur.
- **SY38.** İkinci tohum **20260219**'dur.

```python
# --- ortak tanim, birinci dersteki bicimiyle
TOHUM, IKINCI_TOHUM = 20260218, 20260219
KULLANICI = ("kok", "uygulama", "yedek", "izleme")
KOMUT = ("veri-alici", "rapor-uretici", "yedek-gorevi", "olcum-toplayici",
         "kuyruk-isleyici", "onbellek-temizleyici")


def uretec(tohum):
    d = tohum

    def sonraki(n):
        nonlocal d
        d = (d * 1103515245 + 12345) % 2147483648
        return d % n
    return sonraki


def surecler(tohum=TOHUM, sayi=24):
    r = uretec(tohum)
    liste = []
    for i in range(sayi):
        tur = r(10)
        desen = "duz" if tur < 5 else ("ani" if tur < 8 else "agir")
        liste.append({"pid": 1000 + i * 7 + r(5),
                      "kullanici": KULLANICI[r(len(KULLANICI))],
                      "komut": KOMUT[r(len(KOMUT))], "desen": desen,
                      "oncelik": r(11) - 5, "bellek": 20 + r(400),
                      "sinyal_yok_sayar": r(10) < 2})
    return liste


# --- bu dersin katmani: sekiz neden , uc ileti , bir sessizlik
# (ad, ileti, surec basina sinir mi)
NEDEN = (
    ("surec sayisi siniri",      "kaynak gecici olarak kullanilamiyor", True),
    ("is parcacigi siniri",      "kaynak gecici olarak kullanilamiyor", True),
    ("surec basina tanitici siniri", "cok fazla acik dosya",            True),
    ("sistem geneli tanitici siniri", "cok fazla acik dosya",           False),
    ("adres uzayi siniri",       "bellek ayrilamadi",                   True),
    ("sistemde bos bellek yok",  "bellek ayrilamadi",                   False),
    ("dosya boyutu siniri",      "",                                    True),
    ("islemci zamani siniri",    "",                                    True),
)
SIKLIK = (5, 2, 8, 1, 4, 1, 2, 3)      # nedenlerin goreli sikligi
HAVUZ = [i for i, w in enumerate(SIKLIK) for _ in range(w)]


def arizalar(surecler_, tohum=TOHUM, sayi=60):
    """Pencere boyunca gorulen ariza olaylari. Kahin: her olayin GERCEK nedeni."""
    r = uretec(tohum)
    olay = []
    for _ in range(sayi):
        s = surecler_[r(len(surecler_))]
        ad, ileti, surec_basina = NEDEN[HAVUZ[r(len(HAVUZ))]]
        olay.append({"pid": s["pid"], "neden": ad, "ileti": ileti,
                     "surec_basina": surec_basina,
                     "gecici": r(10) < 4})     # bakildiginda sayac geri dusmus
    return olay


S = surecler()
OLAY = arizalar(S)
print("ariza olayi:", len(OLAY), "| farkli neden:", len({o["neden"] for o in OLAY}))
sayim = {}
for o in OLAY:
    sayim.setdefault(o["ileti"] or "(ileti yok , sinyalle olduruldu)", []).append(o["neden"])
print("ileti                                  olay  kac farkli neden")
for i, n in sorted(sayim.items()):
    print(f"  {i:38s} {len(n):4d}  {len(set(n)):16d}")
```

```
ariza olayi: 60 | farkli neden: 8
ileti                                  olay  kac farkli neden
  (ileti yok , sinyalle olduruldu)         13                 2
  bellek ayrilamadi                        12                 2
  cok fazla acik dosya                     19                 2
  kaynak gecici olarak kullanilamiyor      16                 2
```

Tablo dersin yapısını tek bakışta veriyor. Sekiz neden dört satıra çökmüş; **her satır iki
ayrı nedeni taşıyor.** En üstteki satırda ileti yoktur: **13 olay** hiçbir metin üretmemiştir.
Dosya boyutu sınırını aşan süreç `SIGXFSZ`, işlemci zamanı sınırını aşan süreç `SIGXCPU` alır;
işleyici tanımlanmamışsa süreç sessizce ölür ve geriye yalnız 128 artı sinyal numarası biçiminde
bir çıkış kodu kalır. **Arızanın metni yoktur, yalnız bir sayı vardır.**

#### İletinin Gizlediği Neden

İleti bir nedeni gösteriyor gibi durur, ama gösterdiği şey nedenin ait olduğu **çifttir**.
"Kaynak geçici olarak kullanılamıyor" iletisi hem süreç sayısı sınırından hem de iş parçacığı
sınırından gelebilir; ikisi de çatallanmanın başarısız olması demektir ve çekirdek ikisini
ayırt eden bir metin üretmez.

```python
# Onceki blogun uzerine: OLAY, NEDEN oradan gelir.
# Iletiden cikarilabilecek EN IYI tani: her iletinin en sik nedeni.
ILETI_TANISI = {"kaynak gecici olarak kullanilamiyor": "surec sayisi siniri",
                "cok fazla acik dosya": "surec basina tanitici siniri",
                "bellek ayrilamadi": "adres uzayi siniri",
                "": "bilinmiyor"}


def iletiyle_tani(olaylar):
    return sum(1 for o in olaylar if ILETI_TANISI[o["ileti"]] != o["neden"])


def sinirla_tani(olaylar):
    """Ileti + `ulimit` okumasi: hangi sayac sinirinda oturuyor. Sayac hala
    sinirindaysa neden okunur; olay geciciyse sayac geri dusmustur."""
    return sum(1 for o in olaylar if o["gecici"])


def birlesik_tani(olaylar):
    """Once sinir okunur; sayac geri dusmusse iletiye donulur."""
    return sum(1 for o in olaylar
               if o["gecici"] and ILETI_TANISI[o["ileti"]] != o["neden"])


print("tani yolu                             yanlis tani  /", len(OLAY))
print(f"  yalniz hata iletisi                    {iletiyle_tani(OLAY):9d}")
print(f"  yalniz sinir okumasi                   {sinirla_tani(OLAY):9d}")
print(f"  sinir okumasi , yoksa ileti            {birlesik_tani(OLAY):9d}")
print("  bunlarin icinde gecici olay          ",
      f"{sum(1 for o in OLAY if o['gecici']):9d}")
print("kahin: her olayin gercek nedeni biliniyor , kurguyu biz urettik")
print()
print("neden                            olay  iletiden dogru cikar mi")
for ad, ileti, _ in NEDEN:
    n = sum(1 for o in OLAY if o["neden"] == ad)
    print(f"  {ad:32s} {n:3d}  {'evet' if ILETI_TANISI[ileti] == ad else 'hayir'}")
```

```
tani yolu                             yanlis tani  / 60
  yalniz hata iletisi                           21
  yalniz sinir okumasi                          29
  sinir okumasi , yoksa ileti                   13
  bunlarin icinde gecici olay                  29
kahin: her olayin gercek nedeni biliniyor , kurguyu biz urettik

neden                            olay  iletiden dogru cikar mi
  surec sayisi siniri               13  evet
  is parcacigi siniri                3  hayir
  surec basina tanitici siniri      16  evet
  sistem geneli tanitici siniri      3  hayir
  adres uzayi siniri                10  evet
  sistemde bos bellek yok            2  hayir
  dosya boyutu siniri                3  hayir
  islemci zamani siniri             10  hayir
```

Alt tablo hangi nedenlerin iletiden okunabildiğini söylüyor: **sekiz nedenin üçü** doğru
çıkarılabiliyor, beşi çıkarılamıyor. Çıkarılamayanlar iki sınıftır — bir çiftin daha seyrek
üyesi olanlar ve hiç ileti üretmeyenler. **İşlemci zamanı sınırı tek başına 60 olayın
10'unu** oluşturuyor ve hakkında yazılmış tek bir kelime yok.

Yalnız iletiye bakan tanı **21 kez** yanılıyor. Bu, gerçekte olabilecek en iyi ileti tabanlı
tanıdır: her ileti için en sık nedeni seçtik. Operatör dağılımı bilmiyorsa daha da kötüsünü
seçer.

#### Kanıt Kendiliğinden Yok Oluyor

Doğru tepki iletiye güvenmemek ve sınırı okumaktır: sürecin sayaçlarına bakılır, hangisinin
tavana dayandığı görülür. Bu yolun kendi zaafı vardır ve tabloda duruyor.

**Yalnız sınır okuyan tanı 29 kez yanılıyor** — ileti tabanlı tanıdan **daha kötü**. Nedeni
tek kelimeyle söylenebilir: **geçicilik**. Başarısız bir ayırma denemesi sayacı yükseltmez;
denemenin ardından sayaç geri düşer. Operatör olaydan sonra baktığında bütün sayaçlar sınırın
altındadır ve okuma "her şey yolunda" der. Altmış olayın **29'u** bu durumdadır.

Bu, kursun ikinci iddiasının bu dersteki karşılığıdır: **daha ayrıntılı bir tanı yolu, tek
başına daha iyi tanı vermez.** Sınır okuması iletiden çok daha zengin bir kanıttır — sayı
verir, tavanı verir, oranı verir — ama kanıt olay anında yaşar ve sonrasında kaybolur.

İki yolu birleştiren tanı **13 kez** yanılıyor: sınır okuması işe yaradığında ondan, geri
düşmüş sayaçta iletiden yararlanıyor. Kalan 13 olay, hem kanıtı kaybolmuş hem de iletisi
yanıltıcı olan olaylardır ve bu sayı **indirilemez** — çünkü geriye bakan hiçbir okuma o anki
sayacı geri getiremez. Tek çözüm, olayı **olduğu anda** yakalamaktır: sınıra yaklaşmayı bir
eşikten izlemek, arızayı bekleyip sonra bakmak değil.

```python
# Onceki bloklarin uzerine: arizalar, surecler ve uc tani yolu.
for tohum in (TOHUM, IKINCI_TOHUM):
    O2 = arizalar(surecler(tohum), tohum)
    gecici = sum(1 for o in O2 if o["gecici"])
    print(f"tohum {tohum}: olay {len(O2)} | ileti {iletiyle_tani(O2):2d}"
          f" | sinir {sinirla_tani(O2):2d} | birlesik {birlesik_tani(O2):2d}"
          f" | gecici {gecici:2d}"
          f" | sessiz {sum(1 for o in O2 if not o['ileti']):2d}")
```

```
tohum 20260218: olay 60 | ileti 21 | sinir 29 | birlesik 13 | gecici 29 | sessiz 13
tohum 20260219: olay 60 | ileti 15 | sinir 25 | birlesik  5 | gecici 25 | sessiz  7
```

İkinci tohumda bütün sayılar düşüyor: ileti 21 yerine **15**, sınır 29 yerine **25**, birleşik
13 yerine **5**. Sayıların kendisi kurguya bağlıdır. Ayakta kalan şey **sıralamadır**:
her iki tohumda da **birleşik yol en iyi, yalnız sınır okuması en kötüdür** ve ileti tabanlı
tanı ikisinin arasında kalır. Bir tanı yolunun zenginliği, tek başına sıralamadaki yerini
belirlemiyor.

Sınırların pratik yönetimi bu ölçümden çıkar. Sınırlar arıza çıksın diye değil, **bir sürecin
makineyi tüketmesini engellesin** diye konur; iyi bir sınır aşıldığında arızayı sınırlar ama
nedenini gizler. O yüzden sınır koymak ile **sınıra yaklaşmayı izlemek** birlikte yapılır.
Süreç başına sınır ayrıca kaba bir araçtır: aynı kullanıcının bütün süreçlerini kapsayan bir
süreç sayısı sınırı, tek bir hatalı betiği durdururken oturum açmayı da engelleyebilir.

#### Sınırın Dışındaki Ölüm

Ölçülen sekiz nedenin hepsi bir sınırın aşılmasıydı ve hepsinde ölen ya da başarısız olan
süreç, **sınırı aşan sürecin kendisiydi**. Sınırların dışında kalan bir ölüm biçimi daha
vardır ve tanıyı bambaşka bir yönden bozar.

Sistemin belleği gerçekten tükendiğinde çekirdek bir **kurban** seçer ve onu zorlayan sinyalle
öldürür. Seçim, belleği tüketen sürece göre değil, bir puanlamaya göre yapılır; puanlamada
sürecin o anki bellek tutumu ağır basar. Sonuç, çoğu zaman **en çok bellek tutan sürecin**
ölmesidir — ki bu, belleği kaçıran süreç olmak zorunda değildir. Sızıntıyı yapan küçük bir
süreç, sızıntının bastırdığı sistemde büyük ve masum bir sürecin ölümüne yol açar. Ölen
sürecin kendi çıktısında hiçbir iz kalmaz; olayın tek kaydı sistem günlüğündedir.

İkinci bir sessizleştirici, dökümün kendisidir. Yukarıdaki örnek dökümde çekirdek dosyası
boyutu sınırı **sıfırdır** ve bu yaygın bir varsayılan yapılandırmadır. Sıfır olduğunda,
sinyalle ölen bir süreç arkasında incelenebilecek hiçbir şey bırakmaz. Bu dersin ilk
tablosundaki **13 sessiz olay** için elde kalan tek şey çıkış kodudur; döküm sınırı sıfır
olduğu sürece o kod da tek başına kalır.

İki gözlem aynı yere çıkar. Bir arızanın nedenini olaydan **sonra** bulmak, kanıtın olaydan
sonra da var olmasına bağlıdır: sayaç sınırında kalmalı, döküm yazılmalı, ölüm bir yere
kaydedilmelidir. Üçünün de varsayılan davranışı kanıtı **saklamamaktır**. Sınır koymanın
yanına konması gereken şey bu yüzden bir sayı değil, bir kayıt yoludur — arıza anındaki
durumu yazan bir kanca ya da eşik izleme. Ölümün nereye kaydedildiği ve o kaydın ne kadar
yaşadığı kursun günlükler konusunda ölçülür.

#### Özet

- Her sınırın yumuşak ve katı iki değeri vardır; sınırlar çatallanma anında devralınır ve
  çalışan bir sürecin sınırı kabuktan sonradan değiştirilemez.
- Sekiz arıza nedeni **üç hata iletisine ve bir sessizliğe** çöküyor; her ileti **iki ayrı
  nedene** karşılık geliyor ve **13 olay** hiçbir metin üretmiyor.
- İletiden yalnız **üç neden** doğru çıkarılabiliyor; işlemci zamanı sınırı tek başına 60
  olayın 10'unu oluşturuyor ve hakkında hiçbir metin yok.
- Üç tanı yolunun yanlış tanı sayısı: yalnız ileti **21**, yalnız sınır okuması **29**,
  ikisinin birleşimi **13**. Daha zengin kanıt tek başına daha iyi tanı vermiyor.
- Sınır okumasının zaafı geçiciliktir: 60 olayın **29'unda** sayaç bakıldığında geri düşmüştür.
  Kalan 13 yanlış tanı geriye bakan hiçbir okumayla indirilemez.
- İkinci tohumda sayılar 15, 25 ve 5'e iniyor; ayakta kalan sonuç sıralamadır — birleşik yol
  en iyi, yalnız sınır okuması en kötüdür.

#### Sonraki Adım

Bu konu boyunca süreçlere operatörün penceresinden bakıldı: listelenen, aranan, arka plana
alınan, sinyal gönderilen, önceliği değiştirilen ve sınırlanan tek tek süreçler. Hepsinin
ortak bir zaafı vardı — operatör oradayken çalışıyorlardı. Bir sunucunun asıl işi ise kimse
bakmıyorken sürer. Kursun sonraki konusu bu işi kalıcı bir nesneye bağlayan katmanı ele alır:
servis yöneticisi, birimler ve aralarındaki bağımlılıklar. Orada ölçülecek ilk şey, bir birimin
"çalışıyor" görünmesinin ne anlama geldiğidir.

## Servisler ve Önyükleme

Birim ve bağımlılık modeli, görünen durum ile sağlıklı olmanın farkı, yeniden başlatma politikasının gizlediği arıza, önyükleme zinciri ve önyükleyici parametreleri.

### Servis Yöneticisi Modeli

Source: https://academia.sh/tr/kurslar/sistem-yonetimi/servis-yoneticisi-modeli

Birim, hedef ve bağımlılık kavramları kurulur; birim listesinin verdiği tanı ile bağımlılık çizgesinin verdiği tanı dört ayrıntı düzeyinde karşılaştırılır ve yanlış tanı sayılır.

Süreç yönetimi konusu tek tek süreçlere baktı: hangisi gerçekten ağır, hangisi sonlandırma
isteğine yanıt veriyor, hangisi konulan kaynak sınırına takılıyor. Bir sunucudaki süreçlerin
çoğunu ise operatör başlatmaz. Makine açılır, başında kimse yokken onlarca program ayağa kalkar,
biri çökerse yerine yenisi konur, sabah bakıldığında her şey yerli yerinde görünür. Bunu yapan
şey bir **servis yöneticisi**dir ve yönettiği nesne sürecin kendisi değil, sürecin tanımıdır.

Bu ders o tanımı ve tanımların arasındaki grafiği kurar. Sorusu şudur: yöneticinin bastığı liste,
sistemin gerçek yapısını ne kadarıyla gösterir? Liste altı satır basar ve altı satırın hepsi
doğrudur. Ölçülen şey, o altı doğru satırdan çıkarılan tanının kaç kez yanlış olduğudur.

#### Birim, Hedef ve İki Tür Kenar

Servis yöneticisinin yönettiği nesneye **birim** (service unit) denir. Birim bir metin dosyasıdır:
hangi programın hangi kullanıcıyla çalıştırılacağını, çalışmazsa ne yapılacağını ve hangi başka
birimlere ihtiyaç duyduğunu söyler. Yönetici bu dosyaları okur, aralarındaki ilişkiyi bir grafiğe
çevirir ve grafiği izleyerek süreçleri başlatır. Bu ayrım kursun geri kalanını taşır: **birim
dosyası diskte durur, süreç bellekte koşar.** Dosyayı değiştirmek koşan süreci değiştirmez, süreci
öldürmek dosyayı silmez, birim "yüklü" olup hiç çalışmamış olabilir.

Servis dışında başka birim türleri de vardır ve hepsi aynı grafikte durur: takma noktasını
temsil eden birim, ağ yuvası dinleyip gelen bağlantıda bir servisi uyandıran birim, zamanlanmış
görevi taşıyan birim, bir dosya yolunu gözleyen birim. Bu konu yalnız servis birimlerini ölçer;
diğer türler adlandırılır ve geçilir.

Birimleri tek tek saymak yerine öbek olarak anmak gerektiğinde **hedef** (target) kullanılır. Hedef
kendisi bir iş yapmaz, bir süreç başlatmaz; bir isimdir ve altında toplanmış birimleri temsil eder.
"Ağ hazır", "çok kullanıcılı sistem hazır", "kapanış" gibi aşamalar hedeflerle adlandırılır.
Bir hedefe geçmek, altındaki birimleri etkinleştirmek demektir. Hedefin iş yapmaması, bir hedefe
"ulaşıldı" bildiriminin ne kadar bilgi taşıdığı sorusunu doğurur; bu soru önyükleme dersinde
ölçülür.

Grafikteki kenarlar iki türlüdür ve karıştırılmaları bu dersin ölçtüğü hatadır. **Gerektirme
kenarı**, bir birimin başka bir birim olmadan işe yaramayacağını söyler: gereken birim durursa
gerektiren birim de durur. **Sıralama kenarı** ise yalnız zaman söyler: bu birim şundan sonra
başlasın. Sıralama kenarı bağımlılık kurmaz. İki birim arasında sıralama olup gerektirme
olmayabilir, gerektirme olup sıralama olmayabilir. Komut adları ve birim dosyası sözdizimi servis
yöneticisine ve dağıtıma göre değişir; buradaki model yaygın davranışı anlatır.

Gerektirmenin bir de zayıf biçimi vardır ve adı **isteme**dir: istenen birim başlatılmaya
çalışılır, başlatılamazsa isteyen birim yine de çalışmaya devam eder. Zayıf kenar, çökme
yayılmasını durdurduğu için yaygın olarak tercih edilir; karşılığında grafikteki bir kenarın
kırılmasını sessizleştirir. Kurgu sunucunun grafiğinde zayıf kenar yoktur, çünkü bu dersin ölçtüğü
karıştırma sıralama ile gerektirme arasındadır. Üç kenar türünün de aynı ağaçta, aynı biçimde
basılması bir sonraki bölümün konusudur.

Süreçlerin birbirinden yalıtılması, kaynak muhasebesinin çekirdek tarafında nasıl tutulduğu ve
denetim grubu ile ad alanı mekanizmaları **bu kursta anlatılmaz**; bunlar M03/K05 Çekirdek
Arayüzleri ve İzolasyon kursuna bırakılmıştır. Burada birim, yöneticinin muhasebe defterindeki bir
kayıttır.

Yöneticinin grafiğe ihtiyaç duymasının nedeni yalnız muhasebe değildir. Grafik olmadan birimleri
sırayla, birbirini bekleterek başlatmak gerekir; grafikle birlikte, aralarında kenar bulunmayan
birimler aynı anda başlatılabilir. Bu ayrım önyükleme süresini belirler ve `04` dersinde katman
katman sayılır.

#### Kurgu Sunucunun Birim Grafiği

Kurs boyunca aynı kurgu sunucu kullanılır. Altı birimi vardır: `veri-alma` dışarıdan veri alır,
`kuyruk` aldığı veriyi biriktirir, `isleme` kuyruktan okur, `rapor` işlenmiş veriden çıktı üretir,
`olcum` veri alma hattının sayaçlarını toplar, `yedek` ise kimseye bağlı olmadan çalışır.

**SV1 — birim bir tanımdır**, çalışan sürecin kendisi değil. **SV2 — gerektirme kenarı geçişlidir:**
`rapor` `isleme`'yi gerektiriyor ve `isleme` `kuyruk`'u gerektiriyorsa `rapor` dolaylı olarak
`kuyruk`'a da bağlıdır. **SV3 — sıralama kenarı geçişli sayılmaz** ve bağımlılık üretmez. **SV4 —
`rapor` yalnız `yedek`'ten sonra başlar** ama onu gerektirmez; **SV5 — `olcum` yalnız `kuyruk`'tan
sonra başlar** ama onu gerektirmez. **SV6 — grafik döngüsüzdür.** **SV7 — bir birimi durdurmak,
onu gerektiren bütün birimleri durdurur.** **SV8 — grafikte zayıf isteme kenarı yoktur;** yalnız
gerektirme ve sıralama vardır. **SV9 — bütün birimler aynı yöneticiye aittir** ve tek makinededir;
uzaktaki bir düğüme uzanan kenar yoktur. **SV10 — ölçüm boyunca grafik değişmez;** birim dosyası
eklenmez, silinmez ve yeniden okunmaz.

Bu varsayımların sonuncusu gerçek bir sistemde her zaman tutmaz ve tutmadığında ne olduğu ileride
ayrıca ele alınır. Ölçünün geri kalanı sabit bir grafiğe dayanır: kâhin, bu grafiğin kendisidir.

Yöneticinin birim listesi grafiği göstermez; birimleri alfabetik sırayla, her birini tek satırda
basar. Aşağıdaki döküm bu makinede çalıştırılmamıştır, biçimi göstermek için yazılmış bir
örnektir:

```text
UNIT               LOAD    ACTIVE   SUB      DESCRIPTION
isleme.service     loaded  active   running  Isleme birimi
kuyruk.service     loaded  active   running  Kuyruk birimi
olcum.service      loaded  active   running  Olcum toplayici
rapor.service      loaded  active   running  Rapor ureteci
veri-alma.service  loaded  active   running  Veri alma birimi
yedek.service      loaded  active   running  Yedek gorevi
```

Altı satır, altı birim, sıfır kenar. Bu listeye bakan operatörün elindeki tek bilgi hangi
birimlerin var olduğudur. "Şu birimi durdurursam ne olur" sorusunun cevabı listede yoktur ve
listeden çıkarılamaz.

#### Grafiği Basan Komut ve Bastığı Yön

Servis yöneticileri bağımlılıkları ağaç biçiminde basan bir komut sunar. Bu komutun iki yönü
vardır ve ikisi farklı soruyu cevaplar. Öntanımlı yön **aşağı doğrudur**: bir birimin çalışmak için
neye ihtiyaç duyduğunu gösterir. Ters yön ise **yukarı doğrudur**: o birime kimlerin ihtiyaç
duyduğunu gösterir. Operatörün "bunu durdurursam ne kırılır" sorusunun cevabı yalnız ters yöndedir,
oysa parametresiz çağrı aşağı yönü basar. Aşağıdaki iki döküm çalıştırılmamıştır; komutun iki
yönünün ne bastığını göstermek için yazılmıştır:

```text
$ systemctl list-dependencies rapor.service
rapor.service
* +-isleme.service
*   +-kuyruk.service
*     +-veri-alma.service

$ systemctl list-dependencies --reverse veri-alma.service
veri-alma.service
* +-kuyruk.service
* | +-isleme.service
* |   +-rapor.service
* +-olcum.service
```

İkinci döküm dört birim listeliyor ve doğru sayı bu. Ama ağaç, gerektirme kenarı ile sıralama
kenarını ve zayıf isteme kenarını **aynı biçimde** basar; hangi satırın hangi tür kenardan geldiği
ağacın kendisinden okunmaz. Ağaçta görünen bir birim durduğunda gerçekten duracak mıdır, yoksa
yalnız sonra mı başlayacaktır — bunun cevabı birim dosyalarına bakmayı gerektirir. Bir sonraki
bölümün ölçtüğü şey tam olarak bu belirsizliğin bedelidir.

#### Dört Okuma, Dört Tanı

Aynı grafik dört ayrıntı düzeyinde okunabilir. **Düz liste** yalnız birimleri verir. **Doğrudan**
okuma, her birim için onu doğrudan gerektiren birimleri sayar. **Geçişli grafik** zinciri sonuna
kadar izler. **Sıralama dahil** okuma ise sıralama kenarlarını da gerektirme sayar. Kâhin,
gerektirme kenarları üzerinden hesaplanan geçişli sonuçtur; ölçü, her okumanın kaç birimde bu
sonuçtan ayrıldığıdır.

```python
BIRIM = {
    "veri-alma": {"gerektirir": [], "yeniden": "her zaman"},
    "kuyruk":    {"gerektirir": ["veri-alma"], "yeniden": "her zaman"},
    "isleme":    {"gerektirir": ["kuyruk"], "yeniden": "arizada"},
    "rapor":     {"gerektirir": ["isleme"], "yeniden": "hayir"},
    "olcum":     {"gerektirir": ["veri-alma"], "yeniden": "her zaman"},
    "yedek":     {"gerektirir": [], "yeniden": "hayir"},
}
SONRA = {"rapor": ["yedek"], "olcum": ["kuyruk"]}      # yalniz siralama


def bagimli_olanlar(birim, birimler=None):
    birimler = BIRIM if birimler is None else birimler
    dogrudan = [a for a, v in birimler.items() if birim in v["gerektirir"]]
    hepsi = set(dogrudan)
    for d in dogrudan:
        hepsi |= bagimli_olanlar(d, birimler)
    return hepsi


def siralamayla(birim):
    """Siralama kenarini da bagimlilik sayan okuma."""
    dogrudan = [a for a, v in BIRIM.items()
                if birim in v["gerektirir"] or birim in SONRA.get(a, [])]
    hepsi = set(dogrudan)
    for d in dogrudan:
        hepsi |= siralamayla(d)
    return hepsi


kahin = {b: len(bagimli_olanlar(b)) for b in BIRIM}
tanilar = {
    "duz liste": {b: 0 for b in BIRIM},
    "dogrudan": {b: sum(1 for v in BIRIM.values() if b in v["gerektirir"])
                 for b in BIRIM},
    "gecisli grafik": dict(kahin),
    "siralama dahil": {b: len(siralamayla(b)) for b in BIRIM},
}
print("birim       kahin  dogrudan  duz liste")
for b in BIRIM:
    print(f"  {b:10s} {kahin[b]:5d}  {tanilar['dogrudan'][b]:8d}"
          f"  {tanilar['duz liste'][b]:9d}")
print("  kahin toplami:", sum(kahin.values()))
print()
print("okuma            cikti satiri  yanlis tani")
for ad, t in tanilar.items():
    yanlis = sum(1 for b in kahin if t[b] != kahin[b])
    print(f"  {ad:14s} {sum(t.values()):12d}  {yanlis:11d}")
```

```
birim       kahin  dogrudan  duz liste
  veri-alma      4         2          0
  kuyruk         2         1          0
  isleme         1         1          0
  rapor          0         0          0
  olcum          0         0          0
  yedek          0         0          0
  kahin toplami: 7

okuma            cikti satiri  yanlis tani
  duz liste                 0            3
  dogrudan                  4            2
  gecisli grafik            7            0
  siralama dahil            9            2
```

#### Üç Sayı ve İkinci İddia

Üç sayı yan yana duruyor. **Kâhin:** grafiğin gerçek durumu, altı birim üzerinden **7** bağımlılık
ilişkisi; `veri-alma` durursa dördü birden durur. **Araç çıktısı:** düz liste **0** satır kenar
basıyor, doğrudan okuma **4**, geçişli grafik **7**, sıralama dahil okuma **9**. **Yanlış tanı:**
düz listede **3**, doğrudan okumada **2**, geçişli grafikte **0**, sıralama dahil okumada yine
**2**.

Sıralama dahil okuma en çok satırı basıyor ve tanısı geçişli grafikten kötü. Fazladan iki satır,
`kuyruk` durduğunda `olcum`'un da duracağını ve `yedek` durduğunda `rapor`'un da duracağını
söylüyor; ikisi de yanlış. Bu, kursun ikinci iddiasının ilk ödemesidir: **daha çok çıktı daha iyi
tanı demek değildir.** Doğru sayıya götüren şey satır sayısı değil, hangi kenar türünün sayıldığı.

Düz listeden çıkan **3** yanlış tanı da aynı yerden geliyor. Liste hiçbir kenar göstermediği için
her birim için "durdurursam yalnız o durur" cevabı üretiliyor; bu cevap `veri-alma`, `kuyruk` ve
`isleme` için yanlış, kalan üçü için tesadüfen doğru. Tesadüf sözcüğü burada gevşek kullanılmıyor:
`rapor`, `olcum` ve `yedek` için cevabın tutmasının nedeni okumanın iyi olması değil, o birimlerin
grafiğin ucunda durmasıdır. Aynı okuma, uçları daha az olan bir grafikte daha çok yanılır.
**Tanısı sınanmayan çıktı ölçülmemiş sayılır**; liste doğru, listeden çıkarılan sonuç değil.

Doğrudan okumanın **2** yanlışı ise farklı bir kusurdan geliyor. Bu okuma kenarları görüyor ama
zinciri bir adımda kesiyor: `veri-alma` için **2**, gerçek değer **4**; `kuyruk` için **1**, gerçek
değer **2**. Yanlış yön burada hep aynı, hep **eksik sayma**. Sıralama dahil okumanın yanlış yönü
ise hep **fazla sayma**. İki hata türü aynı sütunda toplandığı için sayı eşitlenebiliyor, oysa
işletim sonuçları birbirinin tersi: eksik sayan operatör hazırlıksız yakalanır, fazla sayan
operatör gereksiz iş yapar.

Buradan çıkan çalışma alışkanlığı tek cümleyle yazılabilir: bir birimi durdurmadan önce **ters
yönlü bağımlılık ağacı** okunur ve ağaçtaki her satırın gerektirme mi sıralama mı olduğu birim
dosyasından doğrulanır. İki adımdan biri atlandığında hata yönü bellidir. Ağaç okunmazsa eksik
sayılır ve beklenmedik birimler durur; ağaç okunup kenar türü doğrulanmazsa fazla sayılır ve
gereksiz bakım penceresi açılır. Ölçüde ikisi de **yanlış tanı** olarak aynı sütuna düşüyor.

#### Grafik Bir Anlık Kopyadır

Birim dosyaları diskte tek bir dizinde durmaz. Paketin kurduğu tanım bir dizinde, yerel olarak
yazılan tanım başka bir dizinde, çalışma zamanında üretilen tanım üçüncü bir dizindedir ve aynı
adlı dosya bu dizinler arasında birbirini **gölgeler**. Gölgelemenin yanında bir de ek parça
dosyaları vardır: bunlar dosyanın tamamının yerine geçmez, yalnız birkaç satır ekler ya da tek bir
ayarı değiştirir. Sonuçta bir birimin etkin tanımı tek bir dosyada değil, birkaç dosyanın
birleşimindedir; hangi satırın nereden geldiğini ancak birleşik tanımı basan komut söyler. Bir
birimin dosyasını açıp okumak, o birimin gerçekte hangi ayarlarla çalıştığını görmek anlamına
gelmez.

Bundan daha çok tuzağa düşüren ikinci bir gerçek var: yönetici bu dosyaları her komutta yeniden
okumaz. Açılışta okur, grafiği belleğe kurar ve o kopyayla çalışır. Diskteki dosyayı değiştirmek
bellekteki grafiği değiştirmez; değişiklik ancak yöneticiye yeniden okuması söylendiğinde grafiğe
girer. Bu yüzden "dosyayı düzelttim ama davranış değişmedi" gözlemi bir arıza değil, beklenen
sonuçtur. Durum çıktısı da bu iki hâli ayırmaz: diskteki dosya ile bellekteki tanım birbirinden
farklıyken de birim "çalışıyor" görünür. Kâhin ile araç çıktısı arasındaki fark burada kenar
sayısında değil **zamanda** açılıyor; grafik, diskin bir anlık kopyasıdır ve kopyanın ne zaman
alındığı çıktıda yazmaz.

#### İkinci Tohum

Sayılar tek bir grafiğe bağlı olabilir. Aynı ölçü, tohumlu bir üreteçle kurulan yirmi rastgele
altı birimlik grafik üzerinde iki tohumla tekrarlandığında toplam yanlış tanı düz listede **60** ve
**69**, doğrudan okumada **16** ve **21**, geçişli grafikte **0** ve **0**, sıralama dahil okumada
**52** ve **36** çıkıyor. Büyüklük düzeni korunuyor: geçişli grafik iki tohumda da hatasız,
sıralamayı bağımlılık sayan okuma iki tohumda da düz listeye yakın bir hata üretiyor. Tek tek
sayılar kurguya bağlıdır; **sıralama gerektirme değildir** sonucu değildir.

Bir noktanın altı çizilmeye değer. Geçişli grafik okuması iki tohumda da **sıfır** yanlış tanı
veriyor ve bu, kurgunun bir özelliği değil tanımın bir sonucudur: kâhin zaten geçişli kapanışla
tanımlanmıştı. Ölçünün anlamı, doğru okumanın hatasız çıkmasında değil, **yanlış okumaların
büyüklüğünde** yatıyor. Kırk grafiğin toplamında yalnız kenar türünü karıştırmanın bedeli
seksen sekiz yanlış tanı; aynı kırk grafikte hiç kenar okumamanın bedeli yüz yirmi dokuz. İki
sayının birbirine bu kadar yakın olması, sıralama kenarını bağımlılık saymanın grafiği hiç
okumamaktan çok daha iyi olmadığını söylüyor.

#### Özet

- Servis yöneticisinin nesnesi **birim**dir; birim çalışan süreç değil, sürecin tanımıdır. **Hedef**
  birimleri öbekleyen bir addır ve kendisi iş yapmaz.
- Grafikte iki tür kenar vardır: **gerektirme** kenarı bağımlılık kurar ve geçişlidir, **sıralama**
  kenarı yalnız zaman söyler ve bağımlılık kurmaz.
- Kurgu sunucuda altı birim ve **7** bağımlılık ilişkisi var; `veri-alma` durursa dört birim daha
  durur.
- Düz birim listesi **0** kenar gösterir ve altı birimin **3**'ünde yanlış tanı üretir; doğrudan
  bağımlılık sütunu bunu **2**'ye indirir, geçişli grafik **0**'a indirir.
- Sıralama kenarlarını bağımlılık sayan okuma **9** satır basıp yine **2** yanlış tanı verir: en çok
  çıktıyı basan okuma en iyi tanıyı vermiyor.
- Ad alanı ve denetim grubu bu kursta anlatılmaz; M03/K05 Çekirdek Arayüzleri ve İzolasyon kursuna
  bırakılmıştır.

#### Sonraki Adım

Bu ders grafiği kurdu ve grafiğin listede görünmediğini saydı. Sıradaki soru daha da rahatsız
edicidir: listede görünen tek şey olan **durum sözcüğü** ne kadar güvenilir? Bir birimin karşısında
"çalışıyor" yazması, o birimin çalıştığı anlamına gelir; sağlıklı olduğu anlamına gelmez. Sonraki
ders aynı kurgu sunucuda arıza döngüsüne giren bir birimin durum sözcüğünü ölçer ve altmış çöküşün
kaçının hangi bakış aralığında görüldüğünü sayar.

### Servis Durumu ve Denetimi

Source: https://academia.sh/tr/kurslar/sistem-yonetimi/servis-durumu-ve-denetimi

Başlatma, durdurma ve etkinleştirmenin ayrı eksenler olduğu kurulur; arıza döngüsündeki bir birimin durum sözcüğü ile gerçek durumu karşılaştırılır ve altmış çöküşün kaç yoklamada görüldüğü sayılır.

Önceki ders birim grafiğini kurdu ve grafiğin birim listesinde görünmediğini saydı. Listede
görünen tek bilgi vardı: her satırın karşısındaki **durum sözcüğü**. Altı satırın altısında
"çalışıyor" yazıyordu ve bu, listeye bakan için rahatlatıcı bir görüntüydü. Bu ders o sözcüğün ne
söylediğini ve neyi söylemediğini ölçer.

Cevap kısa biçimiyle şudur: durum sözcüğü, yöneticinin **şu anda** birimin sürecini ayakta
gördüğünü söyler. Bu bilgi doğrudur ve yanıltıcıdır. Doğrudur, çünkü yönetici gerçekten bir süreç
görüyor. Yanıltıcıdır, çünkü gördüğü süreç on saniye önce doğmuş, ondan öncekinin cesedi çoktan
kaldırılmış olabilir. Ölçülen şey, "çalışıyor" sözcüğünden çıkarılan **sağlıklı** tanısının kaç kez
yanlış olduğudur.

#### Etkinleştirme ile Başlatma Ayrı Eksenlerdir

Servis yöneticisinin en çok karıştırılan iki eylemi **başlatma** ile **etkinleştirme**dir ve
aralarındaki fark bir eksen farkıdır. Başlatma şimdiyi değiştirir: birimin süreci hemen ayağa
kaldırılır, sistem yeniden açıldığında bu kararın izi kalmaz. Etkinleştirme geleceği değiştirir:
birim bir hedefin altına bağlanır ve o hedefe her ulaşıldığında başlatılır, ama etkinleştirmenin
kendisi hiçbir süreç başlatmaz. Durdurma ile etkisizleştirme de aynı biçimde ayrılır.

İki eksen dört bileşim üretir ve dördü de gerçekte görülür. Bir birim **etkin ve çalışıyor**
olabilir: beklenen hâl. **Etkin ama çalışmıyor** olabilir: açılışta başlatılacak, şu an duruyor.
**Etkin değil ama çalışıyor** olabilir: elle başlatılmış, sistem yeniden açıldığında geri gelmez.
**Etkin değil ve çalışmıyor** olabilir: kapalı. Üçüncü bileşim en pahalı olanıdır, çünkü bugün
sorunsuz görünen bir sunucu ilk yeniden açılışta o birimi kaybeder ve kaybın nedeni aylar önce
verilmiş bir karardır.

Bu iki ekseni tek satırda gösteren komut, birim durumunu birkaç ayrı alanla basar. Aşağıdaki döküm
çalıştırılmamıştır; alanların ne anlattığını göstermek için yazılmış bir örnektir:

```text
$ systemctl status veri-alma.service
* veri-alma.service - Veri alma birimi
     Loaded: loaded (/etc/systemd/system/veri-alma.service; enabled)
     Active: active (running)
   Main PID: <surec numarasi>
      Tasks: 3
```

`Loaded` alanı birim dosyasının bulunup okunduğunu söyler ve parantez içindeki sözcük
etkinleştirme eksenini taşır. `Active` alanı şimdiki hâli söyler; parantez içindeki ikinci sözcük
daha ince bir alt durumdur ve servisin kendi yaşam döngüsünden gelir. Bu iki alan birbirinden
bağımsızdır. Birinin değeri diğerini belirlemez, aynı çıktı satırında yan yana durmaları
belirlediklerini düşündürür.

Etkinleştirmenin nasıl çalıştığı bu bağımsızlığı açıklar. Yönetici bir birimi etkinleştirdiğinde
yaptığı şey, birim dosyasını bir hedefin "istenenler" dizinine bağlamaktır. Ortada yeni bir süreç
yoktur, çalışan hiçbir şey değişmez; yalnız diskte bir bağ oluşur. Bu yüzden etkinleştirme komutu
çalışan bir birimi durdurmaz, etkisizleştirme komutu da onu öldürmez. İkisini aynı anda yapmak
isteyen operatör iki ayrı komut vermek zorundadır ve bu iki komuttan birini unutmak, üçüncü
bileşimin en yaygın üretim yoludur.

Denetim eylemlerinin listesi bu ikisiyle bitmiyor. **Yeniden başlatma** birimi durdurup başlatır ve
süreç kimliği değişir. **Yeniden yükleme**, süreci öldürmeden yapılandırmayı yeniden okumasını
ister; bunu yapabilmek birimin desteklemesine bağlıdır ve desteklemeyen bir birimde komut
sessizce yeniden başlatmaya dönüşebilir ya da hiçbir şey yapmaz. **Maskeleme** ise en sert olanıdır:
birim adı boş bir tanıma bağlanır ve birim artık ne elle ne de bir bağımlılık üzerinden
başlatılabilir. Maskelenmiş bir birimi başlatmayı deneyen başka bir birim başarısız olur ve hata
iletisi maskeyi değil, "birim başlatılamadı"yı söyler. Maskeleme unutulduğunda haftalar sonra
anlaşılan bir arıza bırakır.

#### Komutun Dönmesi Hazır Olmak Değildir

Süreç yönetimi konusunda sonlandırma sinyali için kurulan cümle burada da geçerlidir: **komutun
dönmesi işin bittiği anlamına gelmez.** Başlatma komutu verildiğinde yöneticinin beklediği şey,
birimin türüne göre değişir. En yalın birim türünde yönetici, ana süreç çatallandığı anda
birimi "başlatıldı" sayar; program o anda kendi kodunu çalıştırmaya bile başlamamıştır. O anda süreç henüz yapılandırmasını
okumamış, dinleme yuvasını açmamış, veritabanı bağlantısını kurmamış olabilir. Komut başarıyla
döner, durum "çalışıyor" olur ve servis birkaç saniye daha isteğe cevap veremez.

Bu boşluğu kapatmanın yolu, birimin hazır olduğunu yöneticiye kendisinin bildirmesidir; bildirim
destekleyen birim türlerinde yönetici "başlatıldı" demeden önce bildirimi bekler ve bağımlılık
zincirindeki sonraki birim de o ana kadar başlatılmaz. Bildirim yoksa zincir erken ilerler:
`kuyruk`, `veri-alma` daha hazır değilken başlatılır ve ilk denemesinde bağlanamaz. Görünen tabloda
iki birim de "çalışıyor" yazar. Bu boşluk bu derste ölçülmüyor; ölçülen şey arızanın kendisinin
görünmezliği. İkisinin ortak kökü aynı: **yöneticinin bildiği tek şey sürecin var olduğudur.**

#### Ölçüm: Arıza Döngüsündeki Birim

Kurgu sunucunun altı birimi, altısı da arızalı hâle sokuluyor: her biri düzenli aralıklarla
çöküyor. Farklı olan tek şey birimlerin **yeniden başlatma politikası**. `veri-alma`, `kuyruk` ve
`olcum` için politika "her zaman", `isleme` için "arızada", `rapor` ve `yedek` için "hayır".
Gözlem penceresi 600 saniye, çöküş aralığı 10 saniye.

**SV11 — gözlem penceresi 600 saniyedir** ve bütün süreler modeldeki saniyedir. **SV12 — altı
birimin altısı da bu pencerede arızalıdır**; kâhin bunu bilir. **SV13 — yeniden başlatma anlıktır**
ve başarısız olmaz. **SV14 — "hayır" politikalı birim ilk çöküşten sonra durur** ve durumu
"arızalı" olur. **SV15 — yeniden başlatılan birimin durumu "çalışıyor" kalır.** **SV16 — durum
sözcüğünden çıkarılan tanı yalnız iki değer alır:** "çalışıyor" görülürse sağlıklı, "arızalı"
görülürse arızalı. **SV17 — birim her çöküşte 2 saniye ayakta değildir**, çöküş anı her dönemde
tohumlu üreteçle seçilir. **SV18 — yoklama anlıktır** ve yoklandığı saniyedeki hâli görür. **SV19 —
yoklamanın maliyeti yoktur**; sistemi yavaşlatmaz ve ölçtüğü şeyi değiştirmez. **SV20 — durum
sorgusu gecikmesizdir**; sorulan saniyedeki gerçek hâli döndürür, araç kendisi yanılmaz.

Son iki varsayım kasıtlı olarak aracın lehinedir. Gerçek bir sistemde yoklamanın kendi maliyeti
vardır ve durum sorgusu bir önceki taramanın önbelleğinden dönebilir. Model bunları sıfırlıyor;
dolayısıyla aşağıdaki yanlış tanı sayıları, aracın **en iyi hâlinde** ürettiği alt sınırdır.

```python
TOHUM = 20260218
DONEM = 600
BIRIM = {
    "veri-alma": {"gerektirir": [], "yeniden": "her zaman"},
    "kuyruk":    {"gerektirir": ["veri-alma"], "yeniden": "her zaman"},
    "isleme":    {"gerektirir": ["kuyruk"], "yeniden": "arizada"},
    "rapor":     {"gerektirir": ["isleme"], "yeniden": "hayir"},
    "olcum":     {"gerektirir": ["veri-alma"], "yeniden": "her zaman"},
    "yedek":     {"gerektirir": [], "yeniden": "hayir"},
}


def uretec(tohum):
    d = tohum

    def sonraki(n):
        nonlocal d
        d = (d * 1103515245 + 12345) % 2147483648
        return d % n
    return sonraki


def ariza_dongusu(birim, sure=DONEM, aralik=10, birimler=None):
    """`her zaman` politikasi arizayi gizler: servis hep 'calisiyor' gorunur."""
    birimler = BIRIM if birimler is None else birimler
    p = birimler[birim]["yeniden"]
    if p == "hayir":
        return {"politika": p, "yeniden_baslatma": 0, "gorunen_durum": "arizali",
                "gorunmez_sure": 0}
    if p == "arizada":
        return {"politika": p, "yeniden_baslatma": sure // aralik,
                "gorunen_durum": "calisiyor", "gorunmez_sure": sure}
    return {"politika": p, "yeniden_baslatma": sure // aralik,
            "gorunen_durum": "calisiyor", "gorunmez_sure": sure}


def olu_araliklar(tohum=TOHUM, sure=DONEM, donem=10, olu=2):
    """Birim her donemde bir kez cokuyor ve `olu` saniye ayakta degil."""
    r = uretec(tohum)
    return [(t + r(donem - olu + 1), olu) for t in range(0, sure, donem)]


def yoklama(araliklar, adim, sure=DONEM):
    """`adim` saniyede bir durum soran operator."""
    bakis = gordu = 0
    for t in range(0, sure, adim):
        bakis += 1
        if any(b <= t < b + u for b, u in araliklar):
            gordu += 1
    return {"bakis": bakis, "gordu": gordu, "yanlis": bakis - gordu}


print("birim      politika    yeniden  gorunen durum  gorunmez sure  tani")
yanlis_tani = 0
for b in BIRIM:
    a = ariza_dongusu(b)
    dogru = a["gorunen_durum"] == "arizali"
    yanlis_tani += 0 if dogru else 1
    print(f"  {b:10s} {a['politika']:10s} {a['yeniden_baslatma']:8d}"
          f"  {a['gorunen_durum']:13s}  {a['gorunmez_sure']:13d}"
          f"  {'dogru' if dogru else 'YANLIS'}")
print("  kahin: 6 birimin 6'si arizali | yanlis tani:", yanlis_tani)
print()
A = olu_araliklar()
print("gercek cokme:", len(A), "| toplam olu saniye:", sum(u for _, u in A))
print("yoklama araligi  bakis  arizali goren  yanlis tani")
for adim in (1, 5, 15, 30, 60):
    y = yoklama(A, adim)
    print(f"  {adim:14d}  {y['bakis']:5d}  {y['gordu']:13d}  {y['yanlis']:11d}")
```

```
birim      politika    yeniden  gorunen durum  gorunmez sure  tani
  veri-alma  her zaman        60  calisiyor                600  YANLIS
  kuyruk     her zaman        60  calisiyor                600  YANLIS
  isleme     arizada          60  calisiyor                600  YANLIS
  rapor      hayir             0  arizali                    0  dogru
  olcum      her zaman        60  calisiyor                600  YANLIS
  yedek      hayir             0  arizali                    0  dogru
  kahin: 6 birimin 6'si arizali | yanlis tani: 4

gercek cokme: 60 | toplam olu saniye: 120
yoklama araligi  bakis  arizali goren  yanlis tani
               1    600            120          480
               5    120             21           99
              15     40              7           33
              30     20              2           18
              60     10              0           10
```

#### Üç Sayı

**Kâhin:** altı birimin altısı arızalı; "her zaman" politikalı bir birim 600 saniyede **60 kez**
yeniden başlıyor ve toplam **120 saniye** ayakta değil. **Araç çıktısı:** dört birimin karşısında
**"çalışıyor"**, iki birimin karşısında "arızalı" yazıyor; en sık yoklamada bile arızalı hâl
**120** bakışta görülüyor, en seyrek yoklamada **0** bakışta. **Yanlış tanı:** durum sözcüğünden
çıkarılan sağlık tanısı altı birimin **4**'ünde yanlış; saniyede bir bakan operatör **480**,
altmış saniyede bir bakan operatör **10** kez yanlış tanı koyuyor.

Ortak tanımın dördüncü okuması bu tablodadır: **yeniden başlatma politikası arızayı gizliyor.**
"Her zaman" politikalı birim altmış kez ölüp altmış kez dirildiği hâlde durumu hiç değişmiyor;
arıza **600 saniye boyunca görünmez** kalıyor. Politikası "hayır" olan birim ise ilk çöküşte
"arızalı" oluyor ve doğru tanı veriyor. Sonuç ters yönde okunmalı: **daha dayanıklı yapılandırılmış
birim daha az görünür arıza üretiyor**, çünkü dayanıklılık burada görünürlüğün pahasına satın
alınmış.

Tablonun en rahatsız edici satırı `isleme` satırıdır. Politikası "her zaman" değil, "arızada";
yani sözde daha ölçülü bir seçim yapılmış. Sonuç aynı: **60** yeniden başlatma, **"çalışıyor"**
durumu, **600** saniye görünmezlik. İki politika arasındaki fark bu koşumda hiç görünmüyor, çünkü
birim hep hatayla çıkıyor. Farkın nerede ortaya çıktığı ve hangi arıza türünün hangi politikada
kaybolduğu bir sonraki dersin ölçüsüdür.

#### Daha Sık Bakmak Yetmiyor

Yoklama taraması ikinci iddiayı ödüyor. Saniyede bir bakan operatör 600 bakış yapıyor ve bunun
**120**'sinde arızalı hâli yakalıyor; beş saniyede bir bakan 120 bakışta **21**, on beş saniyede
bir bakan 40 bakışta **7**, otuz saniyede bir bakan 20 bakışta **2**, altmış saniyede bir bakan 10
bakışta **0** yakalıyor. Bakış sayısı altmış kat arttığında yakalanan arıza sayısı da artıyor;
oranı ise düşüyor. Yakalanan oran saniyelik yoklamada beşte bir, altmış saniyelik yoklamada sıfır.

Sayının böyle davranmasının nedeni, arızanın **dar bir pencerede** olması. Birim her on saniyede
bir çöküyor ve yalnız 2 saniye ayakta değil; geri kalan 8 saniyede yönetici gerçekten çalışan bir
süreç görüyor. Yoklama bu 2 saniyelik pencereye rastlamak zorunda. Seyrek bakan operatör yalnız
"az görmüyor", çoğu koşumda **hiç görmüyor** ve elindeki bütün kanıt "çalışıyor" diyor. **Geç
bakan az görür.**

Buradan çıkan sonuç, yoklama aralığını kısaltmak değildir. Saniyede bir bakmak bile 480 yanlış
tanı bırakıyor. Durum sözcüğü, kaç kez sorulursa sorulsun, **yeniden başlatma sayısını**
taşımıyor; taşıyan alan başka. Bir birimin kaç kez yeniden başlatıldığı ve en son ne zaman
başladığı yöneticinin ayrı alanlarında durur ve doğru soru budur: "çalışıyor mu" değil, **"ne
zamandan beri çalışıyor"**. Altmış saniyeden kısa bir çalışma süresi, altmış kez yeniden başlamış
bir birimin tek görünür izidir.

Aynı komutun tam çıktısı bu alanları zaten basıyor; sorun alanların olmaması değil, gözün ilk
satıra takılması. Aşağıdaki döküm çalıştırılmamıştır; arıza döngüsündeki bir birimin çıktısında
kanıtın nerede durduğunu göstermek için yazılmıştır:

```text
* kuyruk.service - Kuyruk birimi
     Loaded: loaded (/etc/systemd/system/kuyruk.service; enabled)
     Active: active (running) since <cok kisa sure once>
   Main PID: <surec numarasi>
     Status: "hazir"
   <zaman damgasi> sunucu systemd[1]: kuyruk.service: Main process exited
   <zaman damgasi> sunucu systemd[1]: kuyruk.service: Scheduled restart job
```

Üçüncü satır hem "çalışıyor" diyor hem o çalışmanın **ne zamandan beri** sürdüğünü
söylüyor, son iki satır ise sürecin çıktığını ve yeniden başlatmanın çizelgelendiğini söylüyor. Üçü aynı çıktıda,
üçü de doğru. Yanlış tanı, çıktının eksikliğinden değil, hangi satırın okunduğundan doğuyor. Bir
birimin sağlığını "çalışıyor" sözcüğüyle değil **çalışma süresiyle** okumak, bu dersteki 480 yanlış
tanının hepsini ortadan kaldırır; çünkü altmış kez yeniden başlayan bir birimin çalışma süresi
hiçbir bakışta on saniyeyi geçmez.

Bu, kursun ikinci iddiasının ters yüzüdür ve iki cümlede toplanabilir. Daha çok çıktı tanıyı
düzeltmiyor, çünkü ayırt eden şey satır sayısı değil. Daha az ama **doğru alan** okumak tanıyı
düzeltiyor, çünkü ayırt eden şey ölçünün kendisi.

#### İkinci Tohum

Çöküş anları tohumlu seçildiği için tablo tohuma bağlı olabilir. Ölçü ikinci tohumla
(`20260219`) tekrarlandığında yakalanan arıza sayıları şöyle çıkıyor: saniyelik yoklamada iki
tohumda da **120**, beş saniyede iki tohumda da **21**, on beş saniyede **7** ve **8**, otuz
saniyede **2** ve **3**, altmış saniyede **0** ve **3**. Sık yoklama iki tohumda aynı; seyrek
yoklamada sonuç **kurguya bağlıdır** ve öyle yazılmalıdır. Altmış saniyelik yoklamanın sıfır
çıkması bu koşuma özgüdür, üç çıkması da öyle. Tohumdan bağımsız olan şey oranın yönü: bakış
seyrekleştikçe yakalanan pay düşüyor ve hiçbir tohumda 120'yi geçmiyor.

#### Özet

- **Etkinleştirme** geleceği, **başlatma** şimdiyi değiştirir; iki eksen dört bileşim üretir ve
  "etkin değil ama çalışıyor" bileşimi ilk yeniden açılışta kaybedilir.
- Durum çıktısındaki yüklenme, etkinleştirme ve etkinlik alanları birbirinden bağımsızdır; yan
  yana basılmaları birbirini belirlediklerini düşündürür.
- Arıza döngüsündeki altı birimin altısı arızalıyken **4**'ü "çalışıyor" görünüyor: yeniden
  başlatma politikası arızayı gizliyor.
- "Her zaman" politikalı birim 600 saniyede **60 kez** yeniden başlıyor, toplam **120 saniye**
  ayakta değil ve arıza **600 saniye görünmez** kalıyor.
- Yoklama sıklaştıkça yakalanan arıza artıyor ama yakalanan **oran** düşüyor: 1 saniyede 120/600,
  60 saniyede 0/10. Saniyelik yoklama bile **480** yanlış tanı bırakıyor.
- Doğru soru "çalışıyor mu" değil **"ne zamandan beri çalışıyor"**; yeniden başlatma sayısı durum
  sözcüğünde değil ayrı alanlarda durur.

#### Sonraki Adım

Bu ders politikanın gizlediğini saydı ama politikayı kimin koyduğuna bakmadı. Politika birim
dosyasında tek satırdır ve o satırı yazan kişi genellikle "servis hep ayakta olsun" diye
düşünmüştür. Sonraki ders birim dosyasını baştan yazar ve üç politikanın — "hayır", "arızada", "her
zaman" — hangi arıza türünü gizlediğini dokuz bileşim üzerinde sayar. Aynı derste, gizlemeyi
kırmanın yolu olan **başlatma sınırı** ölçülür: görünmez sürenin 600 saniyeden kaça indiği tablo
hâlinde çıkar.

### Yeni Servis Tanımlama

Source: https://academia.sh/tr/kurslar/sistem-yonetimi/yeni-servis-tanimlama

Birim dosyasının bölümleri ve alanları kurulur; üç yeniden başlatma politikasının üç çıkış türünde ne gizlediği dokuz bileşimde sayılır ve başlatma sınırının görünmez süreyi kaça indirdiği taranır.

Önceki ders yeniden başlatma politikasının arızayı gizlediğini saydı: altı birimin dördü
"çalışıyor" görünürken altısı da arızalıydı. Tablonun bir satırı açıkta kalmıştı. `isleme`
biriminin politikası "arızada"ydı, yani "her zaman"dan daha ölçülü bir seçim, ama sonuç aynıydı:
altmış yeniden başlatma, altı yüz saniye görünmezlik. İki politika arasındaki fark o koşumda hiç
ortaya çıkmadı.

Bu ders farkı ortaya çıkarır. Bunun için önce politikanın yazıldığı yere, **birim dosyasına**
bakılır; sonra üç politika üç ayrı çıkış türüyle çarpılır ve dokuz bileşimde hangi arızanın
kaybolduğu sayılır. Sonunda gizlemeyi kıran mekanizma ölçülür: **başlatma sınırı**.

#### Birim Dosyasının Bölümleri

Birim dosyası bölümlere ayrılmış düz bir metindir ve servis birimlerinde üç bölüm bulunur. Birinci
bölüm birimi grafiğe yerleştirir: açıklaması, neyi gerektirdiği, neyden sonra başlayacağı burada
yazılır. İkinci bölüm birimin nasıl çalıştırılacağını söyler: hangi komut, hangi kullanıcı, hangi
çalışma dizini, hangi ortam değişkenleri, birim türü ve yeniden başlatma politikası. Üçüncü bölüm
etkinleştirmenin ne anlama geldiğini söyler: bu birim hangi hedefin altına bağlanacak. Üçüncü
bölümü yazmayan bir birim dosyası kurulabilir ve elle başlatılabilir, ama etkinleştirilemez;
önceki dersteki "etkin değil ama çalışıyor" bileşiminin bir üretim yolu budur.

Aşağıdaki dosya kurgu sunucunun `veri-alma` birimini tanımlar. Çalıştırılmamıştır; alanların
yerleşimini göstermek için yazılmıştır ve alan adları servis yöneticisine göre değişir:

```text
[Unit]
Description=Veri alma birimi
After=network.target

[Service]
Type=notify
ExecStart=/usr/local/bin/veri-alma --yapilandirma /etc/veri-alma.conf
User=uygulama
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
```

İki alan bu dersin konusuyla doğrudan ilgili. `Type` alanı yöneticinin birimi ne zaman
"başlatıldı" sayacağını belirler; bildirim bekleyen tür, önceki derste anlatılan hazır olma
boşluğunu kapatır. `Restart` alanı ise yeniden başlatma politikasıdır ve bu dersin ölçtüğü
şeydir. `RestartSec` yeniden başlatmadan önce beklenecek süreyi verir; sıfıra yakın bir değer,
çöken bir birimi saniyede birkaç kez diriltip işlemciyi meşgul eder.

Dosya yazıldıktan sonra yöneticiye yeniden okuması söylenmezse hiçbir şey değişmez; grafiğin
bellekteki kopyası eski kalır. Bu, birinci derste kurulan noktanın uygulamadaki karşılığıdır.
Dosyadaki bir sözdizim hatası da yazma anında değil, yeniden okuma ya da başlatma anında görünür;
yönetici hatalı satırı atlar ve birimi eksik tanımla yükler. Yazdıktan sonra birimin **birleşik
tanımını** basan komutla ne yüklendiğini görmek, dosyayı bir kez daha okumaktan daha bilgilendirici
olur.

#### Birim Türü Ne Zaman "Başlatıldı" Denileceğini Belirler

`Type` alanı küçük görünür ve zincirin tamamını etkiler. En yalın türde yönetici, ana süreç
çatallandığı anda birimi başlatılmış sayar; bu an, programın kendi kodunu çalıştırmaya
başlamasından da öncedir. Çatallanan türde süreç
kendini arka plana atar, ilk süreç sonlanır ve yönetici asıl süreci bir kimlik dosyasından ya da
süreç ağacından bulur; bu tür, yönetici ile programın birbirine yalan söylemesine en açık olanıdır.
Tek seferlik türde birim bir iş yapar ve çıkar; çıkması arıza değildir ve bu tür, az aşağıda tanımlanan
"çıktı" durumunun meşru sahibidir. Bildirim yapan türde ise program hazır olduğunda
yöneticiye açıkça haber verir ve zincir ancak o zaman ilerler.

Türün yanlış seçilmesi, hiçbir hata iletisi üretmeden yanlış davranış üretir. Kendini arka plana
atan bir programı en yalın türle tanımlamak, yöneticinin arka plana atılmadan önceki kısa ömürlü
süreci izlemesine ve o süreç çıkınca birimi çökmüş saymasına yol açar. Yeniden başlatma politikası
"her zaman" ise sonuç, ikinci derste ölçülen döngünün ta kendisidir: birim saniyede bir yeniden
başlar, durum hep "çalışıyor" görünür.

#### Elle Çalışan Komut Birim Olarak Çalışmıyor

Birim dosyası yazanların en sık karşılaştığı arıza, komutun kabukta çalışıp birim olarak
çalışmamasıdır. Nedeni tek cümlede toplanır: **yönetici bir kabuk değildir.** Oturum açılırken
okunan yapılandırma dosyaları okunmaz, arama yolu operatörünkinden farklıdır, çalışma dizini
belirtilmemişse kök dizindir, ortam değişkenleri boştur, kullanıcı belirtilmemişse süreç yönetici
ile aynı ayrıcalıkla çalışır. Kabuk genişletmesi de yoktur: yıldız, tırnak ve borulama beklenildiği
gibi işlemez, çünkü komut satırı bir kabuğa verilmez.

Bunun sonucu, arızanın **yanlış yerde aranmasıdır**. Program dosya bulamadığı için çıkar, hata
iletisi "dosya yok" der ve operatör dosyayı arar; dosya yerindedir, eksik olan çalışma dizinidir.
Doğru alışkanlık, birim dosyasında yolları mutlak yazmak, çalışma dizinini ve kullanıcıyı açıkça
belirtmek, gereken ortam değişkenlerini ayrı bir dosyadan okutmaktır. Birimin ürettiği çıktının
nereye gittiği ve orada nasıl bulunacağı bu konunun değil, günlükler konusunun sorusudur.

#### Üç Politika, Üç Çıkış Türü

Bir sürecin çalışmayı bırakmasının tek yolu yok. **Temiz çıkış**: süreç kendi kendine, başarı
bildiren bir çıkış koduyla sonlanır. **Hatalı çıkış**: sıfırdan farklı bir kodla sonlanır.
**Sinyalle sonlanma**: dışarıdan gelen bir sinyalle ya da çekirdeğin müdahalesiyle öldürülür.
Yeniden başlatma politikaları bu üç türü ayırır ve ayırdıkları yer birbirinden farklıdır.

Politika **"hayır"** hiçbir durumda yeniden başlatmaz. Politika **"arızada"** hatalı çıkışta ve
sinyalle sonlanmada yeniden başlatır, temiz çıkışta başlatmaz. Politika **"her zaman"** üçünde de
yeniden başlatır. Aradaki fark ancak temiz çıkış varken görünür ve tam olarak orada tehlikelidir:
uzun ömürlü olması beklenen bir servisin sıfır koduyla çıkması bir arızadır, ama "arızada"
politikası onu arıza saymaz.

**SV21 — birim uzun ömürlü olmak üzere tasarlanmıştır**; her çıkış, kodu ne olursa olsun bir
arızadır. **SV22 — dokuz bileşimin dokuzunda da birim gerçekte arızalıdır**; kâhin bunu bilir.
**SV23 — çöküş aralığı 8 ile 12 saniye arasında tohumlu seçilir.** **SV24 — yeniden başlatma
anlıktır** ve başarısız olmaz. **SV25 — temiz çıkışta yeniden başlatılmayan birimin durumu
"çıktı"dır**, arızalı değil. **SV26 — hatalı çıkışta ya da sinyalle sonlanmada yeniden
başlatılmayan birimin durumu "arızalı"dır.** **SV27 — yeniden başlatılan birimin durumu
"çalışıyor"dur.** **SV28 — operatörün tanısı üç durum sözcüğünden üretilir:** "çalışıyor" ise
sağlıklı, "çıktı" ise normal bitti, "arızalı" ise arızalı.

```python
TOHUM = 20260218
DONEM = 600
POLITIKA = ("hayir", "arizada", "her zaman")
CIKIS = ("temiz", "hata", "sinyal")


def uretec(tohum):
    d = tohum

    def sonraki(n):
        nonlocal d
        d = (d * 1103515245 + 12345) % 2147483648
        return d % n
    return sonraki


def yeniden_baslar(politika, cikis):
    if politika == "her zaman":
        return True
    if politika == "arizada":
        return cikis in ("hata", "sinyal")
    return False


def cokme_anlari(tohum=TOHUM, sure=DONEM, en_az=8, en_cok=12):
    """Birim duzensiz arayla cokuyor; aralik tohumlu secilir."""
    r = uretec(tohum)
    t, liste = 0, []
    while True:
        t += en_az + r(en_cok - en_az + 1)
        if t >= sure:
            return liste
        liste.append(t)


def kosum(politika, cikis, anlar, sinir=0, pencere=100, sure=DONEM):
    """`sinir` kadar yeniden baslatma `pencere` saniyede asilirsa yonetici vazgecer."""
    if not yeniden_baslar(politika, cikis):
        return {"yeniden": 0, "durum": "cikti" if cikis == "temiz" else "arizali",
                "gorunmez": sure if cikis == "temiz" else 0}
    yapilan = []
    for t in anlar:
        if sinir and sum(1 for x in yapilan if x >= t - pencere) >= sinir:
            return {"yeniden": len(yapilan), "durum": "arizali", "gorunmez": t}
        yapilan.append(t)
    return {"yeniden": len(yapilan), "durum": "calisiyor", "gorunmez": sure}


A = cokme_anlari()
print("kahin: birim", DONEM, "saniyede", len(A), "kez cokuyor")
print()
print("politika    cikis   yeniden  gorunen durum  operatorun tanisi  dogru mu")
yanlis = 0
for p in POLITIKA:
    for c in CIKIS:
        k = kosum(p, c, A)
        tani = {"calisiyor": "saglikli", "cikti": "normal bitti",
                "arizali": "arizali"}[k["durum"]]
        dogru = tani == "arizali"
        yanlis += 0 if dogru else 1
        print(f"  {p:10s} {c:7s} {k['yeniden']:7d}  {k['durum']:13s}"
              f"  {tani:17s}  {'evet' if dogru else 'HAYIR'}")
print("  yanlis tani:", yanlis, "/ 9")
print()
print("baslatma siniri  yeniden  gorunen durum  gorunmez sure  yanlis tani")
for sinir in (0, 20, 10, 5, 3):
    k = kosum("her zaman", "hata", A, sinir=sinir)
    yt = len([t for t in range(0, DONEM, 10) if t < k["gorunmez"]])
    print(f"  {'yok' if sinir == 0 else str(sinir):15s} {k['yeniden']:7d}"
          f"  {k['durum']:13s}  {k['gorunmez']:13d}  {yt:11d}")
```

```
kahin: birim 600 saniyede 60 kez cokuyor

politika    cikis   yeniden  gorunen durum  operatorun tanisi  dogru mu
  hayir      temiz         0  cikti          normal bitti       HAYIR
  hayir      hata          0  arizali        arizali            evet
  hayir      sinyal        0  arizali        arizali            evet
  arizada    temiz         0  cikti          normal bitti       HAYIR
  arizada    hata         60  calisiyor      saglikli           HAYIR
  arizada    sinyal       60  calisiyor      saglikli           HAYIR
  her zaman  temiz        60  calisiyor      saglikli           HAYIR
  her zaman  hata         60  calisiyor      saglikli           HAYIR
  her zaman  sinyal       60  calisiyor      saglikli           HAYIR
  yanlis tani: 7 / 9

baslatma siniri  yeniden  gorunen durum  gorunmez sure  yanlis tani
  yok                  60  calisiyor                600           60
  20                   60  calisiyor                600           60
  10                   10  arizali                  106           11
  5                     5  arizali                   62            7
  3                     3  arizali                   41            5
```

#### Her Politika Ne Gizliyor

Dokuz bileşimin **7**'sinde operatörün tanısı yanlış. Gizlenenler politikaya göre farklı yerlerde
duruyor.

Politika **"hayır"** üç çıkış türünün yalnız **1**'ini gizliyor: temiz çıkışı. Hatalı çıkışta ve
sinyalle sonlanmada birim "arızalı" görünüyor ve tanı doğru çıkıyor. En az gizleyen politika,
hiçbir dayanıklılık sunmayan politika. Politika **"arızada"** **3** türün üçünü de gizliyor ama iki
farklı biçimde: hata ve sinyal durumunda birimi diriltip "çalışıyor" gösteriyor, temiz çıkışta ise
diriltmeyip "çıktı" gösteriyor. İkinci biçim daha sinsidir, çünkü "çıktı" durumu tek seferlik
görevler için normal bir sonuçtur ve gözden kaçar. Politika **"her zaman"** **3** türün üçünü de
aynı biçimde gizliyor: hepsi "çalışıyor".

Sonuç ters sıralanıyor. Dayanıklılık arttıkça görünürlük azalıyor ve ikisi arasında hiçbir ayar
kendiliğinden denge kurmuyor. "Her zaman" politikası bir sunucuyu ayakta tutmanın en dolaysız yolu
ve aynı zamanda arızayı en iyi saklayan seçenek.

Tablonun ikinci okuması, politika seçiminin **çıkış türü bilgisi olmadan** yapılamayacağını
söylüyor. "Arızada" politikası, programın arızayı sıfırdan farklı bir kodla bildirdiği varsayımına
dayanır. Bu varsayım her programda tutmaz: yapılandırmasını okuyamayan bir program hata basıp sıfır
koduyla çıkabilir, kapanma yolunda bir hata yutulmuş olabilir, sarmalayıcı bir betik kendi çıkış
kodunu döndürüp asıl programınkini gizleyebilir. Çıkış kodu sözleşmesi M03/K02 Kabuk Programlama
kursunda kurulmuştu; burada o sözleşmenin bozulmasının bedeli, dokuz bileşimin iki satırında
"normal bitti" olarak görünüyor.

Buradan çıkan seçim kuralı üç maddedir. Uzun ömürlü servis için "her zaman" seçilir ve yanına
mutlaka bir tavan konur. Tek seferlik görev için "hayır" seçilir; o birimin çıkması gerçekten
normaldir. "Arızada" ancak programın çıkış kodu sözleşmesine uyduğu doğrulanmışsa seçilir ve
doğrulama, koda bakmayı ya da programı bilerek bozup çıkış kodunu okumayı gerektirir.

#### Başlatma Sınırı Gizlemeyi Kırıyor

Servis yöneticileri bu tuzağı kapatmak için ikinci bir mekanizma taşır: **başlatma sınırı**. Bir
birim belirlenen pencere içinde belirlenen sayıdan çok yeniden başlatılırsa yönetici denemeyi
bırakır ve birimi arızalı işaretler. Sınır, dayanıklılığın kapatılması değil, dayanıklılığın bir
**tavanı** olmasıdır.

Tarama tablosu tavanın etkisini gösteriyor. Yüz saniyelik pencerede sınır **yok**sa birim 600
saniye boyunca **60** kez yeniden başlıyor ve hiç arızalı görünmüyor: on saniyede bir bakan
operatör **60** kez yanlış tanı koyuyor. Sınır **20** iken tablo değişmiyor, çünkü kurgudaki çöküş
hızı yüz saniyelik pencerede yirmiyi hiç bulmuyor: konulan sınır, sınır olmamakla aynı. Sınır
**10** olduğunda birim 106. saniyede vazgeçiliyor ve yanlış tanı **11**'e düşüyor. Sınır **5**
iken görünmez süre **62** saniye, yanlış tanı **7**; sınır **3** iken **41** saniye ve **5**.

Sınır **20** satırı ayrıca bir uyarı taşıyor. Yapılandırmaya konmuş, çıktıda görünen, doğru
sözdizimle yazılmış bir sınır burada hiçbir şey yapmıyor. Kâhinle karşılaştırılmadığı sürece bir
ayarın etkili olup olmadığı yapılandırmadan okunamaz; **ayar var olmakla iş görmek aynı şey
değildir.** Sınırın etkili olması, çöküş hızının pencere içinde sınırı geçmesine bağlıdır ve çöküş
hızı yapılandırmada yazmaz.

Aradaki kazanç büyük: görünmez süre 600 saniyeden 41 saniyeye, yanlış tanı 60'tan 5'e iniyor.
Bedeli de açık: sınıra takılan birim artık kendi kendine geri gelmez. Sınır 3 iken kırk saniyelik
bir dalgalanma servisi kalıcı olarak durdurur. **Sınırın doğru değeri, arızanın görünür olmasıyla
servisin ayakta kalması arasındaki takasın nereye konduğudur** ve bu takas ortama göre değişir,
tek doğru sayısı yoktur.

**SV29 — başlatma sınırı penceresi 100 saniyedir.** **SV30 — sınıra takılan birim elle
başlatılana kadar arızalı kalır.** **SV31 — operatör on saniyede bir yokluyor;** yanlış tanı,
vazgeçme anından önceki yoklamaların sayısıdır.

#### Üç Sayı ve İkinci Tohum

**Kâhin:** birim 600 saniyede **60** kez çöküyor ve dokuz bileşimin dokuzunda da arızalı. **Araç
çıktısı:** dokuz bileşimde beş kez "çalışıyor", iki kez "çıktı", iki kez "arızalı"; başlatma sınırı
taramasında yeniden başlatma sayısı 60, 60, 10, 5, 3. **Yanlış tanı:** politika tablosunda **7**;
sınır taramasında sınır yokken **60**, sınır 10 iken **11**, sınır 5 iken **7**, sınır 3 iken
**5**.

İkinci tohumla (`20260219`) çöküş anları yeniden üretildiğinde çöküş sayısı yine **60** çıkıyor ve
görünmez süreler şöyle oluyor: sınır yokken **600** ve **600**, sınır 10 iken **106** ve **107**,
sınır 5 iken **62** ve **56**, sınır 3 iken **41** ve **36**. Büyüklük düzeni iki tohumda da aynı.
Tek tek saniyeler kurguya bağlıdır; sınır konduğunda görünmez sürenin bir büyüklük düzeni azalması
değildir. Dokuz bileşimlik tablo tohumdan hiç etkilenmiyor, çünkü orada sayılan şey çöküş anları
değil politikanın kararı; o tablo yalnız modelin kendisine bağlıdır.

#### Özet

- Birim dosyası üç bölümdür: grafiğe yerleştirme, çalıştırma ve etkinleştirme. Üçüncü bölümü
  olmayan birim elle başlatılır ama etkinleştirilemez.
- Bir sürecin sonlanmasının üç türü vardır — temiz çıkış, hatalı çıkış, sinyalle sonlanma — ve
  politikalar bu türleri farklı yerlerde ayırır.
- Dokuz bileşimin **7**'sinde durum sözcüğünden çıkarılan tanı yanlış: "hayır" bir türü, "arızada"
  ve "her zaman" üç türü de gizliyor.
- Temiz çıkışı arıza saymayan "arızada" politikası, uzun ömürlü bir servisin sessizce durmasını
  **normal bitti** diye gösterir.
- **Başlatma sınırı** gizlemeyi kırar: görünmez süre 600 saniyeden sınır 3 ile **41** saniyeye,
  yanlış tanı **60**'tan **5**'e iner.
- Sınırın bedeli, takılan birimin kendi kendine geri gelmemesidir; doğru değer ortama göre
  belirlenen bir takastır.

#### Sonraki Adım

Buraya kadar tek bir birim ölçüldü: kendi başına çöken, kendi başına dirilen bir birim. Kurgu
sunucuda birimler yalnız kendileri değil; birinci derste kurulan grafik hâlâ orada duruyor ve bir
birimi yeniden başlatmak yalnız onu ilgilendirmiyor. Sonraki ders makinenin açılmasıyla başlayan
zinciri — ürün yazılımından önyükleyiciye, çekirdekten ilk sürece ve hedeflere — kurar ve bir
birimi yeniden başlatmanın kaç birimi durdurup başlattığını sayar. Komut tek satır basıyor;
kâhinin sayısı beş.

### Önyükleme Süreci

Source: https://academia.sh/tr/kurslar/sistem-yonetimi/onyukleme-sureci

Ürün yazılımından ilk sürece ve hedeflere uzanan devir zinciri kurulur; bir birimi yeniden başlatmanın kaç birimi durdurup başlattığı ve açılışta başarısız olan birimin kaç birimi hiç başlatmadığı sayılır.

Önceki ders tek bir birimi ölçtü: kendi başına çöken, politikasına göre dirilen ya da diriltilmeyen
bir birim. O ölçümde birim yalnızdı. Kurgu sunucuda ise birimler birinci derste kurulan grafiğin
düğümleridir ve grafik hâlâ oradadır. Bir birimi yeniden başlatmak yalnız onu ilgilendirmez.

Bu ders grafiğin **zaman içinde** nasıl işletildiğine bakar. Makine açıldığında bu grafik baştan
sona bir kez yürütülür; bir birim elle yeniden başlatıldığında grafiğin bir parçası yeniden
yürütülür. İki durumda da yöneticinin bastığı satır sayısı ile gerçekte olan iş birbirinden
farklıdır. Ölçülen şey, yeniden başlatma komutunun çıktısından çıkarılan tanının kaç kez yanlış
olduğudur.

#### Ürün Yazılımından İlk Sürece

Bir makinenin açılması tek bir olay değil, bir **devir zinciridir**. Her halka kendinden sonrakini
belleğe alır, denetimi ona bırakır ve sahneden çekilir. Halkaların hiçbiri kendinden öncekini
denetleyemez; bu yüzden zincirin başındaki bir hata sonundaki araçlarla görülemez.

İlk halka **ürün yazılımıdır**. Anakart üzerindeki kalıcı bellekte durur, güç verildiğinde
çalışır, donanımı sayar ve sınar, sonra önceden belirlenmiş bir sırayla açılış aygıtlarına bakar.
Bulduğu ilk uygun aygıttaki kodu belleğe alıp çalıştırır. Ürün yazılımının aygıt sırası bir
yapılandırma değeridir ve bu değer işletim sisteminin içinden görünmez.

İkinci halka **önyükleyicidir**. Görevi bir çekirdek seçmek, onu diskten belleğe okumak, yanına
geçici bir kök dosya sistemi almak ve çekirdeğe geçirilecek parametreleri hazırlamaktır.
Önyükleyicinin kendisi de birden çok parçadan oluşabilir; ilk parça çok küçüktür, yalnız ikinci
parçayı okuyacak kadar yer kaplar. Önyükleyicinin ayrıntısı bir sonraki dersin konusudur.

Üçüncü halka **çekirdektir**. Belleğe alınır, kendini açar, aygıtları tanır ve yanında getirilen
geçici kök dosya sistemini kullanarak asıl kök dosya sistemini takar. Geçici kök gereklidir, çünkü
asıl kökü takmak için gereken sürücüler çoğu zaman o kökün içindedir; sıralama sorununu çözen şey
bu ara katmandır. Kök takıldıktan sonra çekirdek son işini yapar ve **ilk süreci** çalıştırır.
İlk süreç, süreç ağacının kökündeki tek süreçtir; sistemin sonuna kadar yaşar ve öldüğünde sistem
durur.

Dördüncü halka **ilk süreçtir** ve çoğu sistemde bu süreç servis yöneticisidir. Yönetici birim
dosyalarını okur, grafiği kurar ve **varsayılan hedefe** ulaşmak için gereken birimleri
etkinleştirir. Devir zinciri burada biter, birim grafiği burada başlar.

Zincirin tanı açısından önemli özelliği, her halkanın kendi kanıtını **başka bir yere** yazmasıdır.
Ürün yazılımının bulguları ekranda kalır ve hiçbir dosyaya düşmez. Önyükleyicinin ilettiği hata
yalnız o an görünür. Çekirdeğin açılış iletileri bellekte bir halka tampona yazılır ve kök dosya
sistemi takılana kadar hiçbir yere kaydedilemez; tampon dolarsa en eski iletiler üzerine yazılır.
Kalıcı kayıt ancak kök takıldıktan ve günlük birimi çalıştıktan sonra başlar. Bu yüzden zincirin
ilk üç halkasında olan bir arıza, sistem açılmadığı sürece **hiçbir dosyada iz bırakmaz.**
Günlüklerin nasıl toplandığı ve nasıl döndürüldüğü bir sonraki konunun sorusudur; buradaki nokta
yalnız şu: kanıtın var olması, kaydedilmiş olmasını gerektirir.

#### Hedefler ve Katmanlar

Önyükleme, birim grafiğinin bir kez baştan yürütülmesidir. Yönetici varsayılan hedefi alır, o
hedefin gerektirdiği ve istediği birimleri bulur, onların gerektirdiklerini bulur ve grafiği geriye
doğru açar. Sonuçta ortaya bir **katman** yapısı çıkar: aralarında kenar bulunmayan birimler aynı
katmandadır ve aynı anda başlatılabilir.

Katman sayısı önyükleme süresinin alt sınırını belirler. Altı birim art arda başlatılsaydı altı
birimlik bir bekleme olurdu; katmanlara ayrıldığında bekleme katman sayısı kadardır. Bu, birinci
derste "yönetici neden grafiğe ihtiyaç duyar" sorusunun cevabıydı.

Servis yöneticileri açılışın ne kadar sürdüğünü ve hangi birimin ne kadar beklettiğini basan bir
çözümleme komutu sunar. Bu komutun çıktısı sık yanlış okunur ve yanlış okumanın kaynağı yine
grafiktir: bir birimin karşısında yazan süre, o birimin **kendi işinin** süresi değil, başlatma
isteğinin verilmesiyle hazır sayılması arasındaki süredir. Gerektirdiği birimleri bekleyerek geçen
zaman da bu sürenin içindedir. Sıralamada en üstte görünen birim çoğu zaman en yavaş birim değil,
**en derin katmandaki** birimdir. Bu çıktıya dayanarak birim eniyilemeye kalkışan operatör, yanlış
birimi eniyiler. Önyükleme süresinin gerçek sayıları donanıma ve yapılandırmaya bağlıdır ve burada
yazılmaz; yazılabilecek olan, sıralamanın **neyi sıraladığıdır**.

**SV32 — varsayılan hedef altı birimin altısını da ister.** **SV33 — bir birim, gerektirdiği bütün
birimler başlamadan başlamaz.** **SV34 — aynı katmandaki birimler aynı anda başlar** ve birbirini
beklemez. **SV35 — sıralama kenarları katman hesabına girmez;** yalnız gerektirme kenarları girer.
**SV36 — bir birimi yeniden başlatmak, onu gerektiren bütün birimleri durdurup yeniden
başlatır.** **SV37 — yeniden başlatma komutu tek satır basar** ve yalnız adı verilen birimi anar.
**SV38 — açılışta başarısız olan bir birim, kendisini gerektiren birimlerin hiç başlamamasına yol
açar.** **SV39 — açılış özeti başarısız birim sayısını yalnız gerçekten denenip başarısız olanlar
üzerinden verir;** hiç denenmeyen birimler bu sayıya girmez. **SV40 — grafik önyükleme boyunca
değişmez.**

Bu varsayımların ölçüden önce yazılmasının nedeni, hepsinin çıktıda görünmemesidir. Yönetici
katmanları da, atlanan birimleri de biliyor; bastığı satırlarda bunların hiçbiri yok.

#### Komutun Bastığı Satır

Yeniden başlatma komutu başarılı olduğunda hiçbir şey basmaz; başarısızlıkta tek satırlık bir hata
basar. Açılıştan sonra sistemin bütününü soran komut da tek sözcükle cevap verir. Aşağıdaki
dökümler çalıştırılmamıştır; çıktının hangi bilgiyi taşıdığını göstermek için yazılmıştır:

```text
$ systemctl restart veri-alma.service
$ systemctl is-system-running
degraded
$ systemctl --failed
  UNIT               LOAD    ACTIVE  SUB     DESCRIPTION
* veri-alma.service  loaded  failed  failed  Veri alma birimi

1 loaded units listed.
```

Birinci komut sessizce döndü ve bu sessizlik "yalnız istenen oldu" diye okunur. İkinci komut
sistemin bütünü hakkında tek sözcük verir ve o sözcük hangi birimin bozuk olduğunu söylemez.
Üçüncü komut başarısız birimleri listeler; son satır sayıyı yazar. Üç çıktının hiçbiri, o bir
birime bağlı dört birimin de durmuş olduğunu söylemez. Bağlı birimler "başarısız" değildir, "etkin
değil" durumundadır ve bu listeye girmezler. Aradaki fark bir durum sözcüğü farkıdır ve tanıyı
tersine çevirir.

```python
BIRIM = {
    "veri-alma": {"gerektirir": [], "yeniden": "her zaman"},
    "kuyruk":    {"gerektirir": ["veri-alma"], "yeniden": "her zaman"},
    "isleme":    {"gerektirir": ["kuyruk"], "yeniden": "arizada"},
    "rapor":     {"gerektirir": ["isleme"], "yeniden": "hayir"},
    "olcum":     {"gerektirir": ["veri-alma"], "yeniden": "her zaman"},
    "yedek":     {"gerektirir": [], "yeniden": "hayir"},
}


def bagimli_olanlar(birim, birimler=None):
    birimler = BIRIM if birimler is None else birimler
    dogrudan = [a for a, v in birimler.items() if birim in v["gerektirir"]]
    hepsi = set(dogrudan)
    for d in dogrudan:
        hepsi |= bagimli_olanlar(d, birimler)
    return hepsi


def yeniden_baslatma_zinciri(birim):
    """Bir birimi yeniden baslatmak kac birimi daha durdurup baslatir."""
    etkilenen = bagimli_olanlar(birim)
    return {"birim": birim, "etkilenen": len(etkilenen),
            "etkilenen_ad": sorted(etkilenen)}


def katman(birim):
    """Onyuklemede birimin kacinci dalgada baslayabilecegi."""
    g = BIRIM[birim]["gerektirir"]
    return 0 if not g else 1 + max(katman(x) for x in g)


def onyukleme(basarisiz):
    """Bir birim acilista basarisiz olursa hangi birimler hic baslamaz."""
    atlanan = bagimli_olanlar(basarisiz)
    baslayan = [b for b in BIRIM if b != basarisiz and b not in atlanan]
    return {"baslayan": len(baslayan), "atlanan": len(atlanan), "bildirilen": 1}


print("birim      katman  arac ciktisi  kahin(duran ve basayan)  tani dogru mu")
yanlis = 0
for b in BIRIM:
    z = yeniden_baslatma_zinciri(b)
    kahin = 1 + z["etkilenen"]
    dogru = kahin == 1
    yanlis += 0 if dogru else 1
    print(f"  {b:10s} {katman(b):6d} {'1 birim':>13s}  {kahin:23d}"
          f"  {'evet' if dogru else 'HAYIR'}")
print("  yanlis tani:", yanlis, "/ 6 | gizlenen birim:",
      sum(len(bagimli_olanlar(b)) for b in BIRIM))
print("  veri-alma zinciri:", yeniden_baslatma_zinciri("veri-alma"))
print()
print("acilista basarisiz  baslayan  hic baslamayan  bildirilen hata")
for b in BIRIM:
    o = onyukleme(b)
    print(f"  {b:18s} {o['baslayan']:8d}  {o['atlanan']:14d}  {o['bildirilen']:15d}")
```

```
birim      katman  arac ciktisi  kahin(duran ve basayan)  tani dogru mu
  veri-alma       0       1 birim                        5  HAYIR
  kuyruk          1       1 birim                        3  HAYIR
  isleme          2       1 birim                        2  HAYIR
  rapor           3       1 birim                        1  evet
  olcum           1       1 birim                        1  evet
  yedek           0       1 birim                        1  evet
  yanlis tani: 3 / 6 | gizlenen birim: 7
  veri-alma zinciri: {'birim': 'veri-alma', 'etkilenen': 4, 'etkilenen_ad': ['isleme', 'kuyruk', 'olcum', 'rapor']}

acilista basarisiz  baslayan  hic baslamayan  bildirilen hata
  veri-alma                 1               4                1
  kuyruk                    3               2                1
  isleme                    4               1                1
  rapor                     5               0                1
  olcum                     5               0                1
  yedek                     5               0                1
```

#### Üç Sayı

**Kâhin:** `veri-alma` biriminin yeniden başlatılması **4** birimi daha durdurup başlatır —
`isleme`, `kuyruk`, `olcum` ve `rapor`. Kendisiyle birlikte kesinti gören birim sayısı **5**. Altı
birim üzerinde toplam **7** birim gizlice etkileniyor. **Araç çıktısı:** komut her birim için tek
satır basıyor ve o satırda yalnız **1 birim** anılıyor. **Yanlış tanı:** altı birimin **3**'ünde
"yalnız bu birim etkilendi" tanısı yanlış; `veri-alma` için sayı beş kat, `kuyruk` için üç kat,
`isleme` için iki kat eksik.

Ortak tanımın üçüncü okuması buradadır: **bir birimi yeniden başlatmak dördünü daha durduruyor** ve
zincir çıktıda görünmez. Yanlış tanının yönü hep aynı, hep **eksik sayma**. Bu yön işletimde
belirli bir hataya karşılık gelir: kısa bir bakım için `veri-alma` yeniden başlatılır, rapor
üretimi de aynı anda kesilir, kesintinin nedeni raporun kendi günlüğünde görünmez ve arıza başka
yerde aranır.

Katman sütunu ikinci bir şey söylüyor. `veri-alma` ve `yedek` sıfırıncı katmanda, `kuyruk` ve
`olcum` birinci, `isleme` ikinci, `rapor` üçüncü katmanda. Grafiğin derinliği dört. Yeniden
başlatmanın etkilediği birim sayısıyla katman derinliği aynı şey değil: `olcum` birinci katmanda
olduğu hâlde hiçbir birimi etkilemiyor, çünkü onu gerektiren kimse yok. **Derinlik ile etki
birbirinden bağımsız iki ölçüdür** ve ikisini karıştırmak, grafiğin dibindeki birimleri gereksizce
tehlikeli saymaya yol açar.

#### Açılışta Başarısız Olan Birim

İkinci tablo aynı grafiği önyükleme yönünde okuyor. `veri-alma` açılışta başlatılamazsa yalnız
**1** birim başlar, **4** birim hiç denenmez ve açılış özeti **1** başarısız birim bildirir.
Bildirilen sayı doğrudur — gerçekten bir birim başarısız oldu — ama sistemin durumunu anlatmaz.
Dört birim başarısız olmadı; **hiç denenmedi** ve denenmedikleri için haklarında hiçbir kayıt
üretilmedi.

Bu, kursun üçüncü iddiasının bu dersteki biçimi: **kanıt kendiliğinden yok oluyor.** Bir birim
çalışıp hata verseydi geriye bir hata kaydı kalırdı. Hiç başlatılmayan birim hiçbir şey yazmaz.
Açılıştan sonra bakan operatörün elinde tek bir başarısızlık bildirimi ve sessiz dört birim vardır;
sessizlik, sağlıkla aynı biçimde görünür.

Doğru okuma yolu, açılış özetindeki sayıya değil, **beklenen birim kümesiyle başlayan birim
kümesinin farkına** bakmaktır. Bu fark grafikten hesaplanır ve hiçbir komut tek başına basmaz.
Tablonun son üç satırı da bunu doğruluyor: `rapor`, `olcum` ve `yedek` başarısız olduğunda hiçbir
birim atlanmıyor ve bildirilen sayı bir kez doğru oluyor. Aynı bildirim, aynı biçim, farklı anlam.

#### Kapanış Aynı Grafiğin Ters Yönüdür

Açılış grafiği ileri yönde yürütüyorsa kapanış aynı grafiği geri yönde yürütür. Önce en üstteki
birimler durdurulur, sonra onların gerektirdikleri. Sıra tersine çevrilmezse veri yazan bir birim,
altındaki depolama birimi çoktan sökülmüşken kapanmaya çalışır.

Kapanışın kendi zaman sınırı vardır ve bu sınır bir tanı kaynağıdır. Yönetici bir birime durma
isteği gönderir, belirli bir süre bekler, birim durmazsa zorlayan sinyali gönderir. Süreç yönetimi
konusunda kurulan ayrım burada da geçerlidir: **istek ile zorlama farklı şeylerdir** ve ikisi
arasındaki pencere, birimin verisini diske yazmak için elindeki tek süredir. Sınır kısa
tutulduğunda kapanış hızlanır ve yarım yazılmış dosyalar üretir; uzun tutulduğunda tek bir takılmış
birim bütün makinenin kapanmasını dakikalarca bekletir. Bu, ayakta kalma ile görünürlük takasının
kapanış tarafındaki karşılığıdır.

#### Kurtarma Hedefleri ve Bir Sonraki Halka

Varsayılan hedef tek seçenek değildir. Sistem yöneticileri için iki küçük hedef daha vardır:
biri bütün dosya sistemlerini takıp yalnız en temel servislerle tek bir kabuk verir, diğeri hiçbir
dosya sistemi takmaz ve neredeyse hiçbir birimi başlatmaz. Bu hedeflere geçmenin iki yolu var. Sistem çalışıyorken yöneticiye hedef
değiştirmesi söylenebilir; sistem hiç açılmıyorsa tek yol, **önyükleme parametresiyle** hedefi
baştan belirlemektir.

İkinci yol bu konunun sınırını gösteriyor. Bu derse kadar anlatılan her şey, ilk süreç ayağa
kalktıktan sonrası içindi. İlk süreç hiç ayağa kalkmıyorsa ne birim listesi vardır ne durum
sorgusu; elde yalnız önyükleyicinin sunduğu düzenleme satırı kalır. Zincirin sonundaki araçlarla
zincirin başındaki hata görülemez.

#### İkinci Tohum

Bu dersin sayıları tohumlu bir üreteçten değil, sabit birim grafiğinden geliyor. Ölçünün grafiğe
bağlı olup olmadığını görmek için aynı hesap, tohumlu üreteçle kurulan yirmişer rastgele altı
birimlik grafik üzerinde iki tohumla tekrarlandı. Gizlenen birim toplamı `20260218` ile **124**,
`20260219` ile **132**; yanlış tanı sayısı 120 birim üzerinden **64** ve **68**. Büyüklük düzeni
korunuyor ve oran her iki tohumda da yarının biraz üstünde: rastgele bir grafikte bir birimi
yeniden başlatmanın başka birimleri etkilemesi kural, istisna değil. Tek tek sayılar kurguya
bağlıdır; **komut çıktısının etkilenen birim sayısını taşımaması** kurguya bağlı değildir.

Rastgele grafiklerin oranı sabit birim grafiğinden yüksek çıkıyor: kurgu sunucuda altı birimin
üçünde yanlış tanı varken rastgele grafiklerde yüz yirmi birimin altmış dördünde ve altmış
sekizinde var. Fark, kurgu sunucunun grafiğinin ince bir zincir olmasından geliyor; kenar
yoğunluğu arttıkça etkilenen birim sayısı da artıyor. Gerçek bir sunucuda birim sayısı yüzlerle
ölçülür ve grafik burada çizilenden çok daha yoğundur. Ölçünün gerçek sistemdeki karşılığı bu
yüzden **daha kötü** olmayı bekler, daha iyi olmayı değil.

#### Özet

- Önyükleme bir **devir zinciridir**: ürün yazılımı, önyükleyici, çekirdek ve geçici kök, sonra
  ilk süreç. Her halka kendinden sonrakini yükler ve çekilir; sonraki halka öncekini denetleyemez.
- İlk süreç çoğu sistemde servis yöneticisidir; varsayılan hedeften geriye doğru grafiği açar ve
  birimleri **katman katman** başlatır.
- Kurgu sunucuda grafiğin derinliği dört katmandır; derinlik ile etki farklı ölçülerdir.
- `veri-alma` yeniden başlatıldığında **4** birim daha durup başlıyor, kesinti gören birim sayısı
  **5**, komut çıktısı **1 birim** diyor; altı birimin **3**'ünde tanı yanlış.
- Açılışta `veri-alma` başarısız olursa **4** birim hiç denenmez ve özet yalnız **1** başarısızlık
  bildirir; denenmeyen birim hiçbir kayıt bırakmaz.
- Doğru okuma, özetteki sayıya değil **beklenen küme ile başlayan küme arasındaki farka** bakmaktır.

#### Sonraki Adım

Devir zincirinin dört halkasından üçü bu derste birim grafiğine bağlandı. Geriye ikinci halka
kaldı: **önyükleyici**. Hangi çekirdeğin yükleneceğini, yanında hangi geçici kökün geleceğini ve
çekirdeğe hangi parametrelerin geçirileceğini o belirler. Sonraki ders önyükleyici
yapılandırmasının nasıl okunacağını, bir parametre değişikliğinin gerçekten etkili olup olmadığının
nasıl sınanacağını ve yapılandırmayı bozan işlemlerin neden geri alınamaz olduğunu ele alır. Aynı
derste yirmi dört parametre değişikliğinin kaçının gerçekten iş gördüğü sayılır; üretici komutun
cevabı yirmi dördü de.

### Önyükleyiciler

Source: https://academia.sh/tr/kurslar/sistem-yonetimi/onyukleyiciler

Önyükleyici yapılandırmasının parçaları, çekirdek seçimi ve önyükleme parametreleri kurulur; yirmi dört parametre değişikliğinin kaçının gerçekten iş gördüğü üç doğrulama yöntemiyle sayılır ve geri alınamaz işlemlerin güvenli sınama yolu gösterilir.

Önceki ders devir zincirinin dört halkasını kurdu ve zincirin sonundaki araçlarla zincirin
başındaki hatanın görülemediğini söyledi. Bu ders ikinci halkaya, **önyükleyiciye** döner. Hangi
çekirdeğin yükleneceğini, yanında hangi geçici kökün geleceğini ve çekirdeğe hangi parametrelerin
geçirileceğini o belirler.

Buradaki değişikliklerin bir özelliği vardır ve konunun tamamını biçimlendirir: **etkileri ancak
bir sonraki açılışta görülür.** Yapılandırmayı yazan komut başarıyla döner, sistem çalışmaya devam
eder, hiçbir şey değişmiş görünmez. Değişikliğin doğru olup olmadığı saatler ya da haftalar sonra,
makine yeniden açıldığında anlaşılır. Ölçülen şey, "yapılandırma yazıldı" çıktısından çıkarılan
"değişiklik etkili" tanısının kaç kez yanlış olduğudur.

#### Önyükleyici Girdisi Nelerden Oluşur

Önyükleyici, aralarından seçim yapılabilecek bir **girdi** listesi tutar. Her girdi dört parçadan
oluşur: bir ad, bir çekirdek görüntüsü, o çekirdeğin yanında yüklenecek geçici kök dosya sistemi ve
çekirdeğe geçirilecek parametre dizgisi. Aynı makinede birden çok girdi bulunması olağandır; yeni
bir çekirdek kurulduğunda eskisi silinmez, listeye yeni bir girdi eklenir. Bu, en ucuz geri dönüş
yoludur: yeni çekirdek açılmazsa menüden eski girdi seçilir.

Ürün yazılımının iki tarzı, girdilerin nerede durduğunu belirler. Bir tarzda önyükleyicinin ilk
parçası diskin en başındaki tek bir sektöre yazılır; o sektöre sığmayan geri kalanı diskte başka
bir yerdedir ve ilk parça onu adresiyle bulur. Diğer tarzda ürün yazılımı bir dosya sistemi
okuyabilir; girdiler ayrı bir önyükleme bölümünde düz dosyalar olarak durur ve seçim ürün
yazılımının kendi menüsünden yapılabilir. İki tarz aynı makinede yan yana bulunabilir ve bu, hangi
yapılandırmanın gerçekten okunduğu sorusunu üretir.

Girdinin nasıl göründüğünü aşağıdaki döküm gösterir. Çalıştırılmamıştır; parçaların yerleşimini
göstermek için yazılmış bir örnektir ve dosya biçimi önyükleyiciye göre değişir:

```text
title    Kurgu sunucu
linux    /vmlinuz-kurgu
initrd   /initrd-kurgu.img
options  root=UUID=<kok-aygit-kimligi> ro quiet
```

`linux` satırı çekirdek görüntüsünü, `initrd` satırı geçici kökü, `options` satırı parametre
dizgisini verir. Kök aygıt burada aygıt adıyla değil **kalıcı bir kimlikle** yazılmıştır; aygıt
adları açılıştan açılışa değişebilir, kimlik değişmez. Aygıt adına dayanan bir girdi, makineye
ikinci bir disk takıldığında açılmaz duruma gelebilir ve nedeni yapılandırmada görünmez.

#### Parametreler Ne Yapar

Parametre dizgisi çekirdeğe iletilir ve çekirdek tanımadığı parametreleri kendi kullanmaz, ilk
sürece geçirir. Bu davranış konunun en önemli tuzağını üretir: **yanlış yazılmış bir parametre hata
vermez.** Çekirdek onu tanımaz, ilk süreç de tanımaz, ikisi de sessizce yoluna devam eder. Dizgi
çalışan sistemin çekirdek komut satırında görünür, göründüğü için de "uygulandı" sanılır.

Parametrelerin işlevleri birkaç öbekte toplanır. Bazıları kök aygıtı ve takma kipini söyler.
Bazıları açılış iletilerinin ne kadarının ekrana basılacağını ayarlar. Bazıları bir donanım
sürücüsünü devre dışı bırakır. Bazıları da ilk sürece hangi hedefe gitmesi gerektiğini söyler;
önceki derste anılan kurtarma hedeflerine ulaşmanın yolu budur. Aynı işi iki farklı parametreyle
söylemek mümkündür ve ikisi çeliştiğinde hangisinin kazanacağı sıraya bağlıdır — bu da sessiz bir
yanlış davranış kaynağıdır.

Çalışan bir sistemde hangi parametrelerle açıldığı, çekirdeğin sunduğu bir dosyadan okunur.
Aşağıdaki döküm çalıştırılmamıştır; okumanın ne döndürdüğünü göstermek için yazılmıştır:

```text
$ cat /proc/cmdline
BOOT_IMAGE=/vmlinuz-kurgu root=UUID=<kok-aygit-kimligi> ro quiet gereksiz=deger
```

Satırın sonundaki `gereksiz=deger` uydurma bir parametredir; çekirdek onu tanımaz, ilk süreç de
tanımaz, hiçbiri yakınmaz ve dizgi olduğu gibi burada durur. Bu satırı doğrulama olarak kullanan
operatör, uydurma parametreyi de uygulanmış sayar. Ölçümdeki **komut satırı okuması** yöntemi tam
olarak bu okumadır ve yanılma nedeni de tam olarak budur: dosya değişikliğin **iletildiğini**
gösterir, **iş gördüğünü** göstermez.

#### Menü ve Zaman Aşımı

Önyükleyicinin geri dönüş değeri, tuttuğu girdi listesi kadar menüsünü göstermesine de bağlıdır.
Menü bir zaman aşımı süresiyle gelir: o süre içinde tuşa basılmazsa varsayılan girdi açılır. Süre
sıfıra çekildiğinde menü hiç görünmez ve açılış birkaç saniye kısalır. Kazanılan birkaç saniyenin
karşılığı, arıza anında elde kalan tek düzeltme yolunun kapanmasıdır: menü görünmüyorsa eski girdi
seçilemez, tek seferlik düzenleme yapılamaz.

Bu takas uzaktaki bir sunucuda bir kez daha keskinleşir. Konsola erişimi olmayan bir makinede menü
zaten kullanılamaz; oradaki geri dönüş yolu menü değil, **bir sonraki açılışta bir kez** geçerli
olacak biçimde işaretlenmiş bir girdidir. Böyle bir girdi bir kez denenir, açılış başarılıysa
kalıcı yapılır, başarısızsa makine kendiliğinden eski girdiye döner. Bu düzenek ölçümdeki "tek
seferlik" satırın gerçek karşılığıdır.

#### Yıkıcı Sınır

Bu dersin bazı işlemleri **geri alınamaz** ve o işlemlerin komutları burada çalıştırılabilir tam
biçimde yazılmaz. Sınırı çizen ölçüt şudur: işlemin sonucu, sistem bir daha açılmadan
düzeltilemiyorsa komut tam yazılmaz.

Üç işlem bu sınırın içindedir. Birincisi, önyükleyicinin ilk parçasını diskin baştaki sektörüne
**yazmak**: yanlış aygıt adı verildiğinde o aygıtın bölümleme tablosunun bulunduğu alan ezilir ve
diskteki bütün bölümler adressiz kalır. İkincisi, önyükleyici yapılandırmasını bir üreticiyle
**yeniden oluşturmak**: üretici mevcut dosyanın üzerine yazar, elle yapılmış değişiklikler kaybolur
ve eski dosya geri gelmez. Üçüncüsü, kullanılmayan sanılan bir **çekirdek girdisini silmek**:
silinen girdi tek çalışan girdiyse geri dönüş yolu ortadan kalkar.

Üçünün ortak yanı, hatanın **o an görünmemesidir**. Komut başarıyla döner, sistem çalışmaya devam
eder, arıza bir sonraki açılışta ortaya çıkar. O anda elde durum sorgusu, birim listesi ve günlük
yoktur; yalnız ekranda duran bir hata iletisi vardır.

Bu işlemlerin güvenli sınama yolu üç maddedir. **Yapılandırma dosyasının bir kopyası alınır** ve
kopya, aynı makinede geri yüklenebilecek bir yerde tutulur. **Değişiklik kalıcı yazılmadan önce
önyükleyici menüsünde tek seferlik denenir**; menüde yapılan düzenleme diske yazılmaz, yalnız o
açılış için geçerlidir. **Yeni girdi eklenir, eski girdi silinmez** ve yeni girdi bir kez
açıldıktan sonra kalıcı yapılır. Sanal bir makinede anlık görüntü alıp deneme yapmak, bu üç
maddenin hepsini birden karşılayan dördüncü yoldur.

#### Ölçüm: Yirmi Dört Değişiklik

Önyükleyici yapılandırmasına yirmi dört değişiklik yapılıyor. Her değişikliğin gerçek sonucu dört
türden biri: **geçerli** (istenen etkiyi yapar), **yazım hatalı** (tanınmaz, sessizce yok sayılır),
**çelişen** (tanınır ama başka bir parametreyle çakışıp farklı davranış üretir) ve **açılmaz**
(sistem bir daha açılmaz). Üç doğrulama yöntemi karşılaştırılıyor: üreticinin çıktısına bakmak,
açılıştan sonra çekirdek komut satırını okumak ve parametrenin değiştirmesi beklenen davranışı
gerçekten sınamak.

**SV41 — üretici komutu yirmi dört değişikliğin hepsini başarıyla yazar** ve hiçbirinde uyarı
vermez. **SV42 — değişikliğin türü tohumlu üreteçle seçilir.** **SV43 — yazım hatalı parametre
çekirdek komut satırında görünür** ama hiçbir etki yapmaz. **SV44 — çelişen parametre de görünür**
ve beklenenden başka bir etki yapar. **SV45 — açılmaz duruma düşüren değişiklik komut satırında hiç
görünmez**, çünkü sistem açılmamıştır. **SV46 — komut satırı okuması yalnız dizginin varlığına
bakar.** **SV47 — davranış sınaması parametrenin gerçek etkisini ölçer** ve yanılmaz. **SV48 —
açılmayan bir önyükleme sistem günlüğüne hiçbir satır yazmaz.** **SV49 — kalıcı yazmada açılmayan
her deneme harici ortamla kurtarma gerektirir.** **SV50 — tek seferlik denemede açılmayan deneme
kurtarma gerektirmez;** bir yeniden başlatma eski girdiye döner.

```python
TOHUM = 20260218
TUR = ("gecerli", "yazim-hatasi", "celisen", "acilmaz")


def uretec(tohum):
    d = tohum

    def sonraki(n):
        nonlocal d
        d = (d * 1103515245 + 12345) % 2147483648
        return d % n
    return sonraki


def duzenlemeler(tohum=TOHUM, sayi=24):
    """Onyukleyici yapilandirmasina yapilan degisiklikler ve GERCEK sonuclari."""
    r = uretec(tohum)
    liste = []
    for i in range(sayi):
        a = r(100)
        tur = (TUR[0] if a < 50 else TUR[1] if a < 70
               else TUR[2] if a < 88 else TUR[3])
        liste.append({"no": i + 1, "tur": tur, "acilir": tur != "acilmaz",
                      "etkili": tur == "gecerli",
                      "satirda_gorunur": tur != "acilmaz"})
    return liste


def tani(d, yontem):
    """Uc dogrulama yonteminin 'degisiklik etkili mi' cevabi."""
    if yontem == "uretici ciktisi":
        return True
    if yontem == "komut satiri okumasi":
        return d["satirda_gorunur"]
    return d["etkili"]


def kurtarma(liste, kalici):
    """Kalici yazmada acilmayan her deneme harici ortamla kurtarma ister."""
    acilmayan = [d for d in liste if not d["acilir"]]
    return {"acilmayan": len(acilmayan),
            "kurtarma": len(acilmayan) if kalici else 0, "gunluk_satiri": 0}


D = duzenlemeler()
print("kahin:", len(D), "duzenleme |",
      {t: sum(1 for d in D if d["tur"] == t) for t in TUR})
print()
print("dogrulama yontemi      etkili der  gercekte etkili  yanlis tani")
for y in ("uretici ciktisi", "komut satiri okumasi", "davranis sinamasi"):
    der = sum(1 for d in D if tani(d, y))
    yt = sum(1 for d in D if tani(d, y) != d["etkili"])
    print(f"  {y:22s} {der:10d}  {sum(1 for d in D if d['etkili']):15d}  {yt:11d}")
print()
print("yazma bicimi  acilmayan  kurtarma olayi  geriye kalan gunluk satiri")
for kalici, ad in ((True, "kalici"), (False, "tek seferlik")):
    k = kurtarma(D, kalici)
    print(f"  {ad:12s} {k['acilmayan']:9d}  {k['kurtarma']:14d}"
          f"  {k['gunluk_satiri']:25d}")
```

```
kahin: 24 duzenleme | {'gecerli': 11, 'yazim-hatasi': 8, 'celisen': 2, 'acilmaz': 3}

dogrulama yontemi      etkili der  gercekte etkili  yanlis tani
  uretici ciktisi                24               11           13
  komut satiri okumasi           21               11           10
  davranis sinamasi              11               11            0

yazma bicimi  acilmayan  kurtarma olayi  geriye kalan gunluk satiri
  kalici               3               3                          0
  tek seferlik         3               0                          0
```

#### Üç Sayı

**Kâhin:** yirmi dört değişikliğin **11**'i gerçekten iş görüyor; **8**'i yazım hatalı, **2**'si
çelişen, **3**'ü sistemi açılmaz duruma düşürüyor. **Araç çıktısı:** üretici komutu **24**
değişikliğin hepsini yazdığını bildiriyor; çekirdek komut satırı okuması **21** değişikliği
"uygulanmış" gösteriyor; davranış sınaması **11** diyor. **Yanlış tanı:** üretici çıktısına
güvenen **13** kez, komut satırı okumasına güvenen **10** kez yanılıyor; davranış sınamasında
yanlış tanı **0**.

Ortadaki satır kursun ikinci iddiasının bu dersteki biçimidir. Komut satırı okuması üretici
çıktısından **daha ayrıntılıdır**: gerçekten sisteme bakar, gerçekten dizgiyi görür, gerçekten
yirmi bir satır üretir. Yanlış tanısı yalnız üçte bir azalıyor ve azalmanın tamamı, açılmayan üç
denemenin kendiliğinden dışarıda kalmasından geliyor. Yazım hatalı sekiz değişiklik ile çelişen iki
değişikliği bu yöntem **hâlâ etkili sayıyor**, çünkü ikisi de komut satırında görünüyor. Görünmek
ile iş görmek arasındaki farkı yalnız üçüncü yöntem kapatıyor.

Üçüncü yöntemin pahalı olduğu doğrudur ve kolayına kaçılmasının nedeni budur. Bir parametrenin
gerçekten iş gördüğünü sınamak, o parametrenin değiştirmesi beklenen davranışı ayrı ayrı ölçmeyi
gerektirir: sürücü devre dışı bırakıldıysa aygıtın gerçekten görünmediğini, ileti düzeyi
kısıldıysa iletilerin gerçekten azaldığını, hedef değiştirildiyse gerçekten o hedefe gidildiğini
görmek gerekir. Yirmi dört değişiklik için yirmi dört ayrı sınama demektir. Buna karşılık üretici
çıktısına bakmak tek satır okumaktır. Ölçünün söylediği şey, ucuz yöntemin **on üç** yanlış tanı
bırakması ve bu on üçün **onunun** davranış sınanmadıkça hiç fark edilmeyecek olmasıdır; kalan
**üçü** ise bir sonraki açılışta en sert biçimde fark edilir. **Tanısı sınanmayan çıktı ölçülmemiş
sayılır.**

Bu dağılım, çalışma sırasının nasıl kurulacağını da söylüyor. Açılmaz duruma düşüren üç değişiklik
en pahalı olanlardır ve onları yakalayan şey davranış sınaması değil, **tek seferlik denemedir**;
bir kez açılıp geri dönen makine üçünü de bedelsiz açığa çıkarır. Sessizce etkisiz kalan on
değişikliği ise yalnız davranış sınaması yakalar ve bu sınama açılıştan sonra, sistem ayaktayken
yapılabilir. İki yöntem birbirinin yerine geçmez; biri açılışı, diğeri etkiyi sınar. Yalnız
birini yapan operatör, ölçünün yarısını yapmış olur.

#### Kanıt Nerede Kalıyor

İkinci tablo kursun üçüncü iddiasını ödüyor. Kalıcı yazmada üç deneme sistemi açılmaz duruma
düşürüyor ve üçü de harici ortamla kurtarma gerektiriyor. Tek seferlik denemede aynı üç deneme
yine açılmıyor, ama kurtarma olayı **0**: bir yeniden başlatma eski girdiye döndürüyor.

İki satırın ortak sütunu daha çarpıcı. Her iki durumda da geriye kalan günlük satırı **0**.
Açılmayan bir önyükleme sistem günlüğüne hiçbir şey yazmaz, çünkü günlüğü tutan birim henüz
çalışmamış ve çoğu yapılandırmada günlüğün yazılacağı dosya sistemi henüz takılmamıştır. Kanıt
yalnız ekranda kalır; ekranda kalan kanıt bir sonraki açılışta silinir. **Geç bakan az görür;**
burada geç bakan hiç görmez.

Bu yüzden önyükleyici denemesinin doğru yeri, kanıtın kaydedilebildiği bir yerdir: konsolu
kaydedilen bir sanal makine, uzaktan erişilen bir konsol ya da yanında bir kişi bulunan bir
makine. Kanıt üretmeyen bir deneme, sonucu ne olursa olsun **ölçülmemiş sayılır**.

Kurtarma sütununun aradaki farkı da tek başına anlatmaya yetiyor. Kalıcı yazmada üç kurtarma
olayının her biri, makineye fiziksel ya da konsol düzeyinde erişim, harici bir ortamdan açılış ve
elle düzeltme demektir; uzaktaki bir sunucuda bu, bir insanın makinenin başına gitmesi anlamına
gelir. Tek seferlik denemede aynı üç arıza, yalnız bir yeniden başlatma kadar sürer. Değişikliğin
içeriği ikisinde de aynı, kâhin ikisinde de aynı; farklı olan tek şey **denemenin nasıl
yazıldığı**. Yanlış tanının bedeli, tanının kendisinden çok onu üreten yönteme bağlı.

#### İkinci Tohum

Değişiklik türleri tohumlu seçildiği için dağılım tohuma bağlı. İkinci tohumla (`20260219`) yirmi
dört değişiklik **12** geçerli, **5** yazım hatalı, **5** çelişen ve **2** açılmaz çıkıyor. Yanlış
tanı sayıları üretici çıktısında **13** ve **12**, komut satırı okumasında **10** ve **10**,
davranış sınamasında **0** ve **0**. Büyüklük düzeni korunuyor ve yöntemlerin sırası her iki
tohumda aynı. Açılmaz duruma düşen deneme sayısı **3** ve **2**; bu sayı küçük olduğu için
kurguya bağlıdır ve tek bir koşumdan genellenmez. Genellenebilecek olan, **açılmayan denemenin
günlük satırının her koşumda sıfır olması**.

#### Özet

- Önyükleyici girdisi dört parçadır: ad, çekirdek görüntüsü, geçici kök ve parametre dizgisi. Yeni
  çekirdek eski girdiyi silmez; menüdeki eski girdi en ucuz geri dönüş yoludur.
- Kök aygıt kalıcı kimlikle yazılır; aygıt adları açılıştan açılışa değişebilir.
- Yanlış yazılmış bir parametre hata vermez, çekirdek komut satırında görünür ve göründüğü için
  uygulanmış sanılır.
- Yirmi dört değişikliğin **11**'i iş görüyor; üretici çıktısına güvenmek **13**, komut satırı
  okuması **10**, davranış sınaması **0** yanlış tanı üretiyor. Daha ayrıntılı okuma tanıyı
  yalnız üçte bir düzeltiyor.
- Açılmayan önyükleme sistem günlüğüne **0** satır bırakır; kanıt ekranda kalır ve bir sonraki
  açılışta silinir.
- Kalıcı yazma açılmayan üç denemede **3** kurtarma olayı üretir, tek seferlik deneme **0**;
  değişiklik kalıcı yazılmadan önce menüde denenir ve eski girdi silinmez.

#### Sonraki Adım

Bu konu birim modelini kurdu, durum sözcüğünün ne sakladığını saydı, politikanın gizlediğini
ölçtü, önyükleme zincirini çıkardı ve zincirin başındaki değişikliklerin nasıl sınanacağını
gösterdi. Beş dersin ortak sonucu tek cümledir: **servis yöneticisinin bastığı satır, sistemin
durumunun bir izdüşümüdür ve izdüşüm her zaman kayıp taşır.** Son derste kaybın en sert biçimi
görüldü: kanıtın hiç yazılmaması. Sıradaki konu tam olarak buradan başlar ve yazılan kanıtı
inceler — sistem günlüğü ile servis günlüklerinin nasıl toplandığını, nasıl sorgulandığını ve
döndürme yüzünden nasıl kendiliğinden yok olduğunu ölçer.

## Günlükler ve Tanılama

Sistem ve servis günlükleri, kimlik doğrulama izi, döndürmenin sildiği kanıt, yük ortalamasının gecikmesi ve darboğaz türlerinin ayrılması.

### Günlük Mimarisi

Source: https://academia.sh/tr/kurslar/sistem-yonetimi/gunluk-mimarisi

Sistem günlüğü ile servis günlükleri arasındaki ayrım: bir kaydın nereden geldiği, hangi düzeyle damgalandığı ve tek bir birim dosyasına bakan tanının kaç kez yanlış çıktığı.

Önceki konu makinenin açılışını baştan sona izledi: ürün yazılımı önyükleyiciyi, önyükleyici
çekirdeği, çekirdek de ilk süreci çağırdı ve servis yöneticisi birimleri bağımlılık sırasına
göre ayağa kaldırdı. O zincirin her adımı bir iş yaptı, ama hiçbiri yaptığı işi operatörün
gözü önünde yapmadı. Makine açıldıktan sonra geriye kalan tek tanık yazılı izdir.

Bu konu o izi ele alır. İlk soru mimaridir: bir satır **günlüğe (log)** nasıl girer, onu kim
damgalar, hangi adrese yazılır ve o adresi açan kişi neyi göremez. Sorunun son parçası
kursun kuralına bağlanır: bir günlüğün değeri kaç satır tuttuğu değil, o satırlardan
çıkarılan tanının kaç kez yanlış çıktığıdır.

Konunun kapsamı tek makinedir. Birden çok makinenin kayıtlarını tek bir yerde toplayan
hatlar, göstergeleri saklayan depolar ve eşik aşıldığında haber veren uyarı zincirleri
Gözlemlenebilirlik ve İşletim ile Güvenlik Operasyonları ve Olay Müdahalesi kurslarında
ölçüldü; burada tekrarlanmaz. Buradaki soru daha önce gelir: makinenin kendi diskinde ve
kendi belleğinde duran kayıt, o makinede ne olduğunu söylemeye yeter mi.

#### Günlüğün Üç Kaynağı

Tek bir makinede günlük satırları üç ayrı yerden doğar ve üçü aynı yola girmez.

Birincisi **çekirdektir**. Çekirdek kendi iletilerini bellekte dairesel bir tampona yazar;
tampon dolduğunda en eski satır düşer. Aygıt tanıma, blok aygıtı hatası ve bellek baskısı
uyarıları buradan gelir. Bu tampon disk değildir: yeniden başlatma onu boşaltır, dolayısıyla
bir önceki açılışın çekirdek iletileri kalıcı bir kopya alınmadıysa kayıptır.

İkincisi **servis yöneticisidir**. Bir birim başlatıldığında yöneticinin ona verdiği standart
çıktı ve standart hata birer boru hattıdır; birim o iki akışa ne yazarsa yönetici yakalar,
birim adıyla damgalar ve **sistem günlüğüne (journal)** koyar. Programın günlük yazmak için
özel bir kütüphaneye ihtiyacı yoktur; ekrana yazması yeterlidir. Kabuk Programlama kursunda
kurulan standart çıktı ve standart hata ayrımı burada işletim tarafında karşılığını bulur:
veri birinci akıştan, tanı iletisi ikinci akıştan gelir ve yönetici ikisini farklı düzeyle
damgalayabilir.

Üçüncüsü **uygulamanın kendisidir**. Bir program kendi seçtiği bir dosyaya kendi biçiminde
yazabilir. Bu dosya servis yöneticisinin görüş alanı dışındadır: birim durdurulsa da dosya
kalır, birim adıyla damgalanmaz, düzeyleri yöneticinin düzeyleriyle aynı olmak zorunda
değildir. Aynı olayın hem sistem günlüğünde hem de uygulamanın kendi dosyasında iki ayrı
biçimde durması olağan bir durumdur.

Üç kaynağın ortak yanı şudur: hiçbiri diğerinin ne yazdığını bilmez. Ayrımın pratik sonucu,
bir olayın izinin **tek bir adreste bulunacağının garantisi olmamasıdır**.

#### Kalıcılık: Bellekte mi, Diskte mi

Sistem günlüğünün nereye yazıldığı bir yapılandırma kararıdır ve varsayılan davranış
dağıtıma göre değişebilir. Üç seçenek vardır. Günlük **yalnız bellekte** tutulabilir; bu
durumda yeniden başlatma bütün geçmişi siler ve makine kendini toparladıktan sonra arızanın
izi kalmaz. Günlük **diske** yazılabilir; geçmiş açılışlar sorgulanabilir hâle gelir, ama
dosya sınırsız büyümez ve bir boyut ya da süre sınırına ulaştığında en eskisini atar.
Üçüncü seçenek ikisinin karışımıdır: dizin varsa diske, yoksa belleğe.

Bu karar tanıyı doğrudan belirler. Bellekte tutulan bir günlükte, kendini yeniden başlatarak
kurtaran bir servisin arıza kaydı **kendi kurtulmasıyla birlikte silinir**. Servisler
konusunda ölçülen durum burada ikinci kez karşımıza çıkar: "her zaman" politikalı bir birim
altı yüz saniyede altmış kez yeniden başlıyor ve "çalışıyor" görünüyordu; o birimin makineyi
de yeniden başlatan bir arızası varsa, geriye ne durum kalır ne kayıt.

Diske yazılan günlükte ise sınır boyuttur. Sınıra ulaşan dosyanın eski kısmının atılmasına
**döndürme (rotation)** denir ve bu konunun üçüncü dersinin tamamı onun ne sildiğini sayar.
Şimdilik tek cümle yeter: kanıtın ömrü, kanıtı üreten olayın ömründen kısa olabilir.

Dördüncü bir ayrım da erişimdir. Günlük dosyaları da sıradan dosyalardır ve Linux'a Giriş
kursunda kurulan izin modeline uyarlar; kimlik olaylarını tutan dosyalar çoğunlukla
ayrıcalıksız kullanıcıya kapalıdır. Bir kaydın var olması, onu okuyabildiğiniz anlamına
gelmez.

#### Zaman Damgası ve Sıra

Bir günlük satırının en çok güvenilen alanı zamandır, oysa en kırılgan alanı da odur. İki
ayrı saat vardır: makinenin açılışından beri geçen süreyi sayan **tek yönlü sayaç** ve
takvim saatini gösteren **duvar saati**. Birincisi geriye gitmez. İkincisi gider: saat
sunucusuyla eşitleme, elle düzeltme ve yaz saati geçişi duvar saatini ileri ya da geri
atlatabilir.

Sonucu şudur: duvar saatine göre sıralanmış bir günlükte, gerçekte önce olan bir olay sonra
olan bir olayın **altında** görünebilir. Nedensellik bir arıza incelemesinin ana aracıdır ve
tersine dönmüş iki satır, tanıyı doğrudan tersine çevirir. Bu yüzden yapılandırılmış
kayıtlar duvar saatinin yanında tek yönlü sayacı ve monoton artan bir **sıra numarası** da
tutar; sıralama yapılırken sayaca güvenmek duvar saatine güvenmekten daha sağlamdır.

Bu dersin ölçüsünde ve sonraki derslerde zaman, ortak tanımın **model saniyesidir**: gözlem
penceresi altı yüz saniyedir ve bütün süreler o pencerenin içinde sayılır. Gerçek bir zaman
damgası hiçbir yerde yazılmaz, çünkü gerçek zaman damgası makineye bağlıdır ve yeniden
üretilemez.

#### Düzey, Alan ve Biçim

Her kaydın bir **düzeyi** vardır. Yaygın sıralama, hata ayıklama iletilerinden acil durum
iletilerine kadar uzanan sekiz basamaktır; bu konuda üç basamak yeter: `bilgi`, `uyari`,
`hata`. Düzey kaydı yazan tarafın kendi beyanıdır, bağımsız bir ölçüm değildir. Bir program
ölümcül bir durumu `bilgi` düzeyiyle yazarsa, düzeye göre süzen her araç o satırı atar.

Düzeyin ikinci sorunu eşiktir. Bir sistem günlüğü çoğunlukla bir alt sınırla çalışır:
belirlenen düzeyin altındaki satırlar yazılmaz. Hata ayıklama düzeyini kapalı tutmak günlüğü
küçültür, ama arıza anında en çok işe yarayacak ayrıntı da tam olarak orada durur. Eşiği
arızadan sonra açmak geçmişi geri getirmez; eşik, olay olurken neyin yazıldığını belirler.
Bu, kursun üçüncü iddiasının en yalın biçimidir: **geç bakan az görür.**

Yapılandırılmış kayıt ile düz metin arasındaki fark da burada belirir. Düz metin satırı tek
bir dizedir; okumak için ayrıştırmak gerekir. Yapılandırılmış kayıt alanlardan oluşur: birim
adı, düzey, süreç kimliği, zaman. Alanlar sorgulanabilir olduğu için süzme işi metin
eşlemeye değil alan karşılaştırmasına dayanır. Bu ayrım bir sonraki derste ölçülecek olan
şeyi belirler: metin eşleyen bir süzgeç ile alan bilen bir süzgeç aynı soruya farklı yanıt
verir.

#### Aynı Olayın İki Adresi

Sistem günlüğü, bütün birimlerin kayıtlarını zaman sırasına göre tek bir akışta tutar.
Aşağıdaki döküm örnektir ve çalıştırılmamıştır; köşeli parantez içindeki sayı açılıştan
sonra geçen saniyedir.

```text
# ornek dokum , calistirilmis degildir
[  461.250] isleme[1043]: hata: kuyruk yaniti alinamadi
[  461.400] isleme[1043]: bilgi: yeniden deneme 1/5
[  463.100] olcum[1092]: uyari: ornekleme penceresi asildi
[  466.050] veri-alma[1014]: hata: akis kapandi
```

Aynı olaylar birim başına ayrılmış dosyalarda saklanırsa görüntü değişir. `isleme` biriminin
kendi dosyası şöyle görünür; bu döküm de örnektir ve çalıştırılmamıştır.

```text
# ornek dokum , calistirilmis degildir
[  461.250] hata: kuyruk yaniti alinamadi
[  461.400] bilgi: yeniden deneme 1/5
[  527.500] hata: kuyruk yaniti alinamadi
```

İkinci dökümde `olcum` ve `veri-alma` satırları yoktur. Kaybolan şey satır değil, **satırlar
arasındaki komşuluktur**: `isleme` biriminin hatasından beş saniye sonra `veri-alma`
biriminin akışının kapandığı bilgisi yalnız birleşik akışta durur.

İki dökümün ikinci farkı damgadır. Birleşik akışta her satırın önünde birim adı vardır;
birim dosyasında yoktur, çünkü dosyanın adı zaten birimi belirtir. Bu, dosya küçükken
tasarruf gibi görünür, ama iki dosya birleştirildiğinde satırların hangisinin nereden
geldiği kaybolur. Bir arıza incelemesinde farklı kaynaklardan gelen dökümleri tek zaman
ekseninde birleştirmek olağan bir adımdır; damgasız satırlar bu adımda kimliksiz kalır.

Üçüncü fark ise servis yöneticisinin damgayı **kendisinin** koymasıdır. Birim adı, süreç
kimliği ve düzey satırın içeriğinden değil, yöneticinin bildiği bağlamdan gelir. Program
kendi dosyasına yazdığında bu bağlam yoktur: aynı olayın uygulamanın kendi dosyasındaki
karşılığında birim adı bulunmaz, süreç kimliği programın yazmayı seçtiği kadardır ve düzey
programın kendi ölçeğine göre işaretlenir. Aynı olay, iki adreste iki farklı doğrulukta
temsil edilir.

#### Ölçülen Şey: Tek Dosyaya Bakan Tanı

Ölçü, ortak tanımın günlük üretecinin üzerine kurulur. Kurgunun varsayımları şunlardır:
gözlem penceresi altı yüz saniye, günlük 4000 satır ve düzey ağırlıkları ortak tanımdan
gelir (**GN1**); kayıtlar altı birime dağılır (**GN2**); komşuluk penceresi beş saniyedir
(**GN3**); operatör açtığı tek dosyaya bakarak karar verir (**GN4**).

Kâhin, altı birimin gerçekte kaç hata yazdığıdır; kurguyu biz ürettiğimiz için biliniyor.
Araç çıktısı, operatörün açtığı **tek bir** birim dosyasıdır. Tanı, o dosyaya bakarak
verilen "hata kaynağı bu birimdir" kararıdır.

```python
TOHUM = 20260218
DONEM = 600                      # gozlem penceresi: 600 saniye


def uretec(tohum):
    d = tohum

    def sonraki(n):
        nonlocal d
        d = (d * 1103515245 + 12345) % 2147483648
        return d % n
    return sonraki


BIRIM = {
    "veri-alma":      {"gerektirir": [], "yeniden": "her zaman"},
    "kuyruk":         {"gerektirir": ["veri-alma"], "yeniden": "her zaman"},
    "isleme":         {"gerektirir": ["kuyruk"], "yeniden": "arizada"},
    "rapor":          {"gerektirir": ["isleme"], "yeniden": "hayir"},
    "olcum":          {"gerektirir": ["veri-alma"], "yeniden": "her zaman"},
    "yedek":          {"gerektirir": [], "yeniden": "hayir"},
}


def gunluk_uret(tohum=TOHUM, satir=4000):
    r = uretec(tohum)
    kayit = []
    for i in range(satir):
        agirlik = r(100)
        duzey = "hata" if agirlik < 3 else ("uyari" if agirlik < 12 else "bilgi")
        kayit.append({"sira": i, "saniye": i * (DONEM / satir),
                      "duzey": duzey, "birim": list(BIRIM)[r(len(BIRIM))]})
    return kayit


def birim_hatalari(kayitlar):
    d = {b: 0 for b in BIRIM}
    for k in kayitlar:
        if k["duzey"] == "hata":
            d[k["birim"]] += 1
    return d


def tek_gunluk_tanisi(kayitlar):
    """GN4: yalniz TEK bir birim dosyasina bakan operator: 'kaynak bu birim'."""
    d = birim_hatalari(kayitlar)
    suclu = max(d, key=lambda b: d[b])
    return {"gercek_kaynak": suclu, "sessiz_dosya": sum(1 for b in d if d[b] == 0),
            "denenen": len(d), "yanlis_tani": sum(1 for b in d if b != suclu)}


def komsu_hata(kayitlar, aralik=5.0):
    """GN3: bes saniye icinde BASKA bir birimden hata gelen hatalar."""
    h = [k for k in kayitlar if k["duzey"] == "hata"]
    return sum(1 for i, a in enumerate(h)
               if any(abs(b["saniye"] - a["saniye"]) <= aralik
                      and b["birim"] != a["birim"] for j, b in enumerate(h) if i != j))


for tohum in (TOHUM, 20260219):
    G = gunluk_uret(tohum)
    d = birim_hatalari(G)
    print("tohum", tohum, "| satir", len(G), "| hata", sum(d.values()),
          "| birim basina", list(d.values()))
    print("  ", tek_gunluk_tanisi(G), "| komsu hata", komsu_hata(G))
```

```
tohum 20260218 | satir 4000 | hata 86 | birim basina [28, 0, 31, 0, 27, 0]
   {'gercek_kaynak': 'isleme', 'sessiz_dosya': 3, 'denenen': 6, 'yanlis_tani': 5} | komsu hata 50
tohum 20260219 | satir 4000 | hata 163 | birim basina [0, 50, 0, 51, 0, 62]
   {'gercek_kaynak': 'yedek', 'sessiz_dosya': 3, 'denenen': 6, 'yanlis_tani': 5} | komsu hata 135
```

#### Çıktının Söylediği ile Sistemin Gerçeği

Üç sayı yan yana durur. **Kâhin:** 4000 satırlık pencerede 86 hata var ve bunların 31'i
`isleme` birimine ait; gerçek kaynak odur. **Araç çıktısı:** altı birim dosyasının içeriği,
sırasıyla 28, 0, 31, 0, 27 ve 0 hata. **Yanlış tanı: 5.** Operatör altı dosyadan birini
açar ve "hata kaynağı bu birimdir" der; altı denemenin beşinde yanılır.

Bu beş yanılgının üçü aynı türden değildir. Üç dosya **tamamen sessizdir**: hiç hata satırı
tutmaz. O dosyayı açan operatör "burada sorun yok" sonucuna varır ve bu sonuç, kendi birimi
için doğru olsa bile **sistem hakkında yanlıştır** — sistemde 86 hata vardır. Kalan iki
dosya hata gösterir ama en çoğunu göstermez; oradaki operatör soruna bakar, yanlış birimi
suçlar. Sessizlik ile masumiyet aynı şey değildir.

İkinci sayı komşuluğu ölçer: 86 hatanın **50'sinin** beş saniye içinde başka bir birimden
gelen bir hata komşusu vardır. Bu 50 satırın hiçbiri, tek bir birim dosyasında komşusuyla
birlikte görünmez. Birim başına ayrılmış dosyalar satır kaybetmez; **sıra** kaybeder ve
sıranın kendisi bir kanıttır.

Buradan mimari bir karar çıkar: birim başına dosya, tek bir birimi derinlemesine incelerken
işe yarar; bir arızanın nereden başladığını bulmak içinse **birleşik ve zaman sıralı** akış
gerekir. İki adresten birini seçmek zorunlu değildir, ama hangisine bakıldığının tanıyı
belirlediği bilinmelidir.

Ölçünün sınırı da açıkça durmalıdır. Kâhin burada kurgunun kendisidir; gerçek bir makinede
hangi birimin gerçekten kaynak olduğunu bilen bir taraf yoktur, tanıyı sınayan tek şey
sonradan yapılan onarımın işe yarayıp yaramamasıdır. Kurgunun sağladığı şey, "altıda beş"
sayısının nereden geldiğinin görülebilmesidir: sayı, aracın kusurundan değil, **bakılan
adresin seçiminden** doğar. Aynı 4000 satır birleşik akışta okunsaydı hata dağılımı tek
sorguyla görünürdü ve yanlış tanı sıfıra inerdi. Araç yalan söylemiyor; eksik olan şey
sorunun sorulduğu yerdir.

Operasyonel sonuç iki maddedir. Birincisi, bir arıza incelemesine birim dosyasından değil
**birleşik akıştan** başlanır; birim dosyası, kaynağın hangi birim olduğu belirlendikten
sonra ayrıntı için açılır. İkincisi, sessiz bir dosya kanıt sayılmaz: o birimin hiç kayıt
yazmaması, birimin sağlıklı olduğunu değil, yalnız **yazmadığını** gösterir. Bir birimin
sustuğu bir arıza ile hiç sorun yaşamadığı bir pencere, günlük tarafından aynı biçimde
temsil edilir.

#### İkinci Tohum

İkinci tohumla kurgu değişir: hata sayısı 163'e çıkar, hatalar farklı birimlere dağılır ve
gerçek kaynak `yedek` olur. Yanlış tanı sayısı **yine 5**, sessiz dosya sayısı **yine 3**
kalır; iki tohumda da yalnız üç birim hata yazar. Komşu hata oranı ise değişir: ilk tohumda
86 hatanın 50'si, ikincisinde 163 hatanın 135'i komşuludur. Oranın kendisi **kurguya
bağlıdır**; kurguya bağlı olmayan şey, tek dosyaya bakan tanının altıda beş yanılması ve
komşuluğun tek dosyada hiç görünmemesidir.

#### Özet

- Günlük satırları üç ayrı kaynaktan doğar: çekirdeğin dairesel tamponu, servis
  yöneticisinin yakaladığı standart çıktı ve standart hata, uygulamanın kendi dosyası.
- Düzey, kaydı yazanın beyanıdır; bağımsız bir ölçüm değildir. Yanlış damgalanmış bir satırı
  düzeye göre süzen her araç atar.
- Kâhin 86 hatanın gerçek kaynağını bilir; tek bir birim dosyasına bakan tanı altı denemenin
  **beşinde** yanılır, üç dosya ise tamamen sessizdir.
- 86 hatanın **50'si** beş saniye içinde başka bir birimden gelen bir hataya komşudur; bu
  komşuluk yalnız birleşik ve zaman sıralı akışta görünür.
- Birim başına ayrılmış dosyalar satır kaybetmez, sıra kaybeder; sıra da bir kanıttır.

#### Sonraki Adım

Bu derste bakılan kayıtların hepsi servislerin kendi ürettiği iletilerdi. Bir makinede
ayrıca kimin ne zaman girdiğini, hangi hesabın hangi yetkiyi istediğini ve hangi isteğin
reddedildiğini tutan ayrı bir olay kümesi vardır. O kayıtlar aynı sistem günlüğüne düşer ama
farklı okunur: sorulan soru "hangi birim bozuldu" değil, "kim yaptı" sorusudur. Sonraki ders
kimlik doğrulama günlüklerini ele alır ve metin eşleyen bir süzgecin bu soruya verdiği
yanıtın kaç satırda yanlış olduğunu sayar.

### Kimlik Doğrulama Günlükleri

Source: https://academia.sh/tr/kurslar/sistem-yonetimi/kimlik-dogrulama-gunlukleri

Oturum açma, yetki isteği ve oturum kapanışı olaylarının izi: kimlik doğrulama ile yetkilendirmenin ayrımı, metin eşleyen süzgeçlerin kaç satırda yanıldığı ve saldırının en önemli satırının neden başarısız değil başarılı satır olduğu.

Önceki ders bir kaydın nereden geldiğini ve hangi adrese yazıldığını kurdu; ölçtüğü şey,
tek bir birim dosyasına bakan tanının altı denemenin beşinde yanılmasıydı. Orada sorulan
soru "hangi birim bozuldu" sorusuydu. Bir makinede aynı sistem günlüğüne düşen ama bambaşka
bir soruya hizmet eden ikinci bir olay kümesi vardır: kim girdi, ne istedi, verildi mi.

Bu ders o kümeyi ele alır. Kayıtların kendisi sıradandır; zor olan, onlardan çıkarılan
tanıdır. Bir arıza incelemesinde günlük satırının doğruluğu tartışılmaz, ama bir güvenlik
incelemesinde satırın **hangi olayı** temsil ettiği tartışılır ve iki farklı olay çoğunlukla
birbirine çok benzeyen iki satır üretir.

Farkın bir nedeni de kaydı yazan tarafın konumudur. Servis günlüklerini yazan program kendi
iç durumunu bilir; ne yaptığını doğru anlatabilir. Kimlik olaylarını yazan taraf ise
karşısındakini **bilmez**: gelen isteğin arkasında kimin durduğu, tam olarak ölçmeye
çalıştığı şeydir. Bu yüzden kimlik günlüğü bir gözlem kaydı değil, bir **karar kaydıdır**:
sistemin verdiği kararı yazar, kararın doğru olup olmadığını yazmaz.

#### İki Ayrı Soru, Tek Dosya

**Kimlik doğrulama (authentication)** bir tek soruya yanıt verir: bu istek gerçekten iddia
ettiği hesaba mı ait. Yanıt bir parolayla, bir anahtarla ya da başka bir kanıtla verilir ve
sonucu ikilidir. **Yetkilendirme (authorization)** ise ondan sonra gelir: kimliği kanıtlanmış
hesabın istediği işlemi yapmaya hakkı var mı.

Ayrım önemlidir, çünkü iki başarısızlık türü bambaşka şeyler anlatır. Kimlik doğrulama
başarısızlığı "bu kişi olduğunu kanıtlayamadı" demektir; parolayı yanlış yazan bir kullanıcı
da, parola deneyen bir saldırgan da bu satırı üretir. Yetkilendirme başarısızlığı ise "bu
kişi olduğunu kanıtladı, ama bu işlemi yapamaz" demektir; burada hesabın kime ait olduğu
şüpheli değildir, istenen iş fazladır. Birinci satır kimliğin dışarıdan zorlandığını, ikinci
satır içerideki bir yapılandırma eksiğini ya da bir yetki aşımı denemesini gösterir.

Üçüncü bir olay türü daha vardır: **oturum** açılışı ve kapanışı. Oturum, kimlik
doğrulamanın kabul edilmesinden sonra başlayan ve kapanana kadar süren bağlamdır. Kapanış
kaydının eksik olması olağan bir durumdur: bağlantı koparsa, süreç zorla sonlandırılırsa ya
da makine yeniden başlarsa açılış kaydı vardır, kapanış kaydı yoktur. Açık oturum sayısını
günlükten çıkaran bir tanı, bu yüzden gerçekten açık olan oturum sayısından **fazla** sayar.

Bu kayıtların değiştirilmeye karşı korunması, imzalanması ve bağımsız bir denetim izine
dönüştürülmesi ayrı bir konudur ve Yönetişim, Risk ve Uyumluluk kursunda ele alınmıştır;
burada tekrarlanmaz. Buradaki soru daha dar: makinenin kendi kimlik günlüğünde duran
satırlardan hangi tanı çıkar.

#### Yetki Yükseltmenin Bıraktığı İz

Bir hesabın kendi yetkisinin ötesinde bir iş yapması için araya bir yükseltme adımı girer:
istek yapılır, kural kümesine bakılır, kabul ya da ret kaydı yazılır. Kaydın taşıdığı
alanlar isteği yapan hesap, hedeflenen kimlik ve çalıştırılmak istenen komuttur.

Bu satırın söylemediği şey **nedendir**. Kabul kaydı, kuralın hangi maddesinin isteği
kabul ettiğini yazmaz; ret kaydı da hangi maddenin engellediğini yazmaz. İki farklı
yapılandırma hatası — kuralın hiç bulunmaması ile kuralın bulunup daha dar bir kuralla
gölgelenmesi — aynı ret satırını üretir. Tanı bu iki durumu ayırmak isterse günlüğe değil
yapılandırmaya bakmak zorundadır. Günlük olayın **olduğunu** söyler; **niçin** olduğunu
söylemez.

İkinci eksik komutun kendisidir. Kayıt çalıştırılmak istenen komutu yazar, ama komutun ne
yaptığını yazmaz. Bir kabuk çağıran tek satırlık bir komut kaydedilir; o kabukta yapılan
işler kaydedilmez, çünkü onlar ayrı bir sürecin içindedir. Kabuk Programlama kursunda
kurulan alt süreç modeli burada bir günlük sınırına dönüşür: yükseltme kaydı bir **kapıyı**
gösterir, kapının ardında yapılanları değil.

Üçüncü eksik zamandır. Yükseltilmiş yetki çoğunlukla bir süre boyunca yeniden sorulmadan
geçerli kalır. O süre içinde yapılan ikinci ve üçüncü istekler yeni bir kimlik doğrulama
kaydı üretmez. Günlükten "hesap kaç kez kimliğini kanıtladı" sorusunun yanıtı okunabilir;
"hesap kaç kez yükseltilmiş yetkiyle iş yaptı" sorusunun yanıtı okunamaz. İki soruyu aynı
sayıyla yanıtlamak, bu dersin ölçtüğü türden bir yanlış tanıdır.

#### Satırlar Nasıl Görünür

Kimlik olayları çoğunlukla ayrı bir dosyada toplanır; dosyanın adı dağıtıma göre değişir ve
aynı satırlar sistem günlüğünde de bulunabilir. Aşağıdaki döküm örnektir ve
çalıştırılmamıştır.

```text
# ornek dokum , calistirilmis degildir
[  301.020] sshd[1207]: giris basarisiz: hesap yedek, kaynak uzak
[  301.900] sshd[1207]: giris basarisiz: hesap yedek, kaynak uzak
[  318.400] sudo[1214]: yetki dogrulama basarisiz: hesap uygulama, komut yedek-gorevi
[  342.000] sshd[1207]: giris basarili: hesap yedek, kaynak uzak
```

Dört satırın üçü "basarisiz" sözcüğünü taşır, ama üçü aynı olayı anlatmaz. İlk ikisi uzak
bir kaynaktan gelen kimlik doğrulama başarısızlığıdır; üçüncüsü yerel bir hesabın yetkisi
olmayan bir komutu istemesidir. Metin eşleyen bir süzgeç üçünü de aynı kovaya atar.

```text
# ornek dokum , calistirilmis degildir
$ grep basarisiz /var/log/auth.log
[  301.020] sshd[1207]: giris basarisiz: hesap yedek, kaynak uzak
[  318.400] sudo[1214]: yetki dogrulama basarisiz: hesap uygulama, komut yedek-gorevi
```

Alan bilen bir sorgu ise olayın türünü, hesabı ve kaynağı ayrı ayrı kısıtlayabilir; önceki
derste kurulan yapılandırılmış kayıt ile düz metin ayrımının pratik karşılığı budur.

Metin süzgecinin bir kırılganlığı daha vardır. Süzgeç, kaydı yazan programın seçtiği
sözcüğe bağımlıdır; aynı olayı başka bir sözcükle yazan bir program süzgeçten sessizce
düşer. İki program aynı makinede aynı olayı iki farklı ifadeyle yazıyorsa, tek bir örüntüyle
arayan operatör birinin kayıtlarını hiç görmez ve o eksikliği fark ettiren bir uyarı da
oluşmaz. Alan üzerinden yapılan sorgu bu bağımlılığı ortadan kaldırmaz, ama bağımlılığı
metnin gövdesinden **alan adına** taşır ve alan adı, ileti metnine göre çok daha yavaş
değişir.

#### Ölçülen Şey: Üç Süzgeç ve Bir Alan

Ölçü, ortak tanımın üretecinin üzerine kurulmuş bir kimlik günlüğüyle yapılır. Kurgunun
varsayımları: makinede beş hesap bulunur (**GN5**); arka planda 560 olay üretilir ve olay
türlerinin ağırlıkları sabittir (**GN6**); saldırı üç yüzüncü saniyede başlar, kırk
başarısız uzak giriş ve iki saniye sonra bir başarılı uzak giriş içerir (**GN7**); alan
bilen süzgecin eşiği on başarısız giriş, penceresi altmış saniyedir (**GN8**).

Kâhin, kurguya yerleştirilen saldırıdır: kırk başarısız satır ve dizinin sonundaki **bir
başarılı uzak giriş** — toplam 41 satır. Araç çıktısı, dört ayrı süzgecin döndürdüğü satır
kümesidir. Yanlış tanı, boşuna okunan satır ile hiç okunmayan saldırı satırının toplamıdır.

```python
TOHUM = 20260218
DONEM = 600                      # gozlem penceresi: 600 saniye


def uretec(tohum):
    d = tohum

    def sonraki(n):
        nonlocal d
        d = (d * 1103515245 + 12345) % 2147483648
        return d % n
    return sonraki


HESAP = ("kok", "uygulama", "yedek", "izleme", "operator")     # GN5


def kimlik_gunlugu(tohum=TOHUM, arka=560, deneme=40, hedef="yedek", bas=300):
    """GN6 arka plan olaylari + GN7 KAHIN: bas saniyesinde baslayan parola deneme
    dizisi ve sonundaki BASARILI giris. Saldiri satirlari isaretlidir."""
    r = uretec(tohum)
    kayit = []
    for _ in range(arka):
        t = r(100)
        h = HESAP[r(len(HESAP))]
        uzak = r(10) < 4
        if t < 6:
            tur, sonuc = "giris", "basarisiz"          # parola yanlis yazildi
        elif t < 18:
            tur, sonuc = "yetki", "basarisiz"          # kimlik dogru , yetki yok
        elif t < 26:
            tur, sonuc = "oturum", "kapandi"
        elif t < 34:
            tur, sonuc = "yetki", "basarili"
        else:
            tur, sonuc = "giris", "basarili"
        kayit.append({"saniye": r(DONEM), "hesap": h, "tur": tur, "sonuc": sonuc,
                      "kaynak": "uzak" if uzak else "yerel", "saldiri": False})
    for i in range(deneme):
        kayit.append({"saniye": bas + i, "hesap": hedef, "tur": "giris",
                      "sonuc": "basarisiz", "kaynak": "uzak", "saldiri": True})
    kayit.append({"saniye": bas + deneme + 2, "hesap": hedef, "tur": "giris",
                  "sonuc": "basarili", "kaynak": "uzak", "saldiri": True})
    kayit.sort(key=lambda k: k["saniye"])
    return kayit


def hesap_penceresi(kayitlar, esik=10, pencere=60):
    """GN8 alan bilen suzgec: bir hesabin pencere icinde esik kadar basarisiz uzak
    girisi ve o kumeden sonraki pencerede yer alan basarili uzak girisler."""
    secili = set()
    for h in HESAP:
        d = [i for i, k in enumerate(kayitlar) if k["hesap"] == h
             and k["tur"] == "giris" and k["sonuc"] == "basarisiz"
             and k["kaynak"] == "uzak"]
        oburu = set()
        for i in d:
            pen = [j for j in d
                   if 0 <= kayitlar[j]["saniye"] - kayitlar[i]["saniye"] <= pencere]
            if len(pen) >= esik:
                oburu.update(pen)
        if not oburu:
            continue
        son = max(kayitlar[j]["saniye"] for j in oburu)
        oburu.update(j for j, k in enumerate(kayitlar)
                     if k["hesap"] == h and k["tur"] == "giris"
                     and k["sonuc"] == "basarili" and k["kaynak"] == "uzak"
                     and 0 <= k["saniye"] - son <= pencere)
        secili |= oburu
    return [kayitlar[j] for j in sorted(secili)]


def olc(kayitlar, eslesen):
    """Yanlis tani = bosuna okunan satir + hic okunmayan saldiri satiri."""
    gercek = sum(1 for k in kayitlar if k["saldiri"])
    dogru = sum(1 for k in eslesen if k["saldiri"])
    giris = sum(1 for k in eslesen if k["saldiri"] and k["sonuc"] == "basarili")
    return {"eslesen": len(eslesen), "dogru": dogru, "girisi_buldu": giris,
            "yanlis_tani": (len(eslesen) - dogru) + (gercek - dogru)}


SUZGEC = (
    ("basarisiz", lambda k: k["sonuc"] == "basarisiz"),
    ("giris basarisiz", lambda k: k["tur"] == "giris" and k["sonuc"] == "basarisiz"),
    ("uzak giris basarisiz", lambda k: k["tur"] == "giris"
     and k["sonuc"] == "basarisiz" and k["kaynak"] == "uzak"),
)

for tohum in (TOHUM, 20260219):
    K = kimlik_gunlugu(tohum)
    print("tohum", tohum, "| satir", len(K), "| saldiri satiri",
          sum(1 for k in K if k["saldiri"]))
    for ad, f in SUZGEC:
        print(f"  {ad:22s}", olc(K, [k for k in K if f(k)]))
    print(f"  {'hesap penceresi':22s}", olc(K, hesap_penceresi(K)))
```

```
tohum 20260218 | satir 601 | saldiri satiri 41
  basarisiz              {'eslesen': 153, 'dogru': 40, 'girisi_buldu': 0, 'yanlis_tani': 114}
  giris basarisiz        {'eslesen': 67, 'dogru': 40, 'girisi_buldu': 0, 'yanlis_tani': 28}
  uzak giris basarisiz   {'eslesen': 51, 'dogru': 40, 'girisi_buldu': 0, 'yanlis_tani': 12}
  hesap penceresi        {'eslesen': 43, 'dogru': 41, 'girisi_buldu': 1, 'yanlis_tani': 2}
tohum 20260219 | satir 601 | saldiri satiri 41
  basarisiz              {'eslesen': 156, 'dogru': 40, 'girisi_buldu': 0, 'yanlis_tani': 117}
  giris basarisiz        {'eslesen': 79, 'dogru': 40, 'girisi_buldu': 0, 'yanlis_tani': 40}
  uzak giris basarisiz   {'eslesen': 60, 'dogru': 40, 'girisi_buldu': 0, 'yanlis_tani': 21}
  hesap penceresi        {'eslesen': 47, 'dogru': 41, 'girisi_buldu': 1, 'yanlis_tani': 6}
```

#### Çıktının Söylediği ile Sistemin Gerçeği

Üç sayı yan yana durur. **Kâhin:** 601 satırlık günlükte saldırıya ait **41** satır var.
**Araç çıktısı:** en kaba süzgeç **153** satır döndürüyor, en dar metin süzgeci **51**, alan
bilen süzgeç **43**. **Yanlış tanı:** sırasıyla **114**, **28**, **12** ve **2**.

Sayılar süzgeç daraldıkça iyileşiyor, ama iyileşmenin kaynağı satır sayısı değildir.
"Basarisiz" sözcüğünü arayan süzgeç 153 satır getirir; bunların yalnız 40'ı saldırıya
aittir, kalan 113 satır yetkilendirme reddi ve dağınık parola hatasıdır. Olay türünü
sınırlayan ikinci süzgeç yanlış tanıyı 28'e, kaynağı da sınırlayan üçüncüsü 12'ye indirir.
Üçünün ortak yanı vardır: **hiçbiri 41 satırın 40'ından fazlasını bulamaz.**

Alan bilen süzgeç 43 satır döndürür ve saldırının 41 satırının **41'ini** de içerir; fazladan
gelen iki satır aynı hesabın penceredeki başka kayıtlarıdır. Yanlış tanı 2'ye iner. Kazancı
sağlayan şey daha çok satır okumak değil, satırların **hangi alana göre** gruplandığıdır:
tek tek satırlar değil, aynı hesabın altmış saniyelik penceredeki yoğunluğu sorgulanır.

İki yanılgı türünün ağırlığı da aynı değildir. Boşuna okunan satır zaman kaybettirir; hiç
okunmayan saldırı satırı tanıyı yanlış yönlendirir. Ölçüde ikisi tek sayıda toplanıyor, ama
operasyonel karşılıkları ayrıdır. Kaba süzgecin 114 yanlış tanısının 113'ü birinci türdendir:
sonuç doğru yönü gösterir, yalnız pahalıdır. Üç metin süzgecinin ortak **1** eksiği ise
ikinci türdendir ve pahalı olmakla kalmaz, sonucu değiştirir.

Süzgecin daralmasının bir sınırı da vardır. Kaynağı "uzak" olarak sınırlayan üçüncü süzgeç,
saldırı yerel bir oturumdan gelseydi hiçbir şey bulamazdı; daraltma her zaman iyileştirmez,
yalnız bu kurguda iyileştirir. Bir süzgecin doğruluğu kendi mantığından değil, aradığı şeyin
gerçekte nerede durduğundan gelir.

#### Kanıtın En Önemli Satırı

Çıktının son sütunu asıl noktayı taşır. Üç metin süzgecinin `girisi_buldu` değeri **0**,
alan bilen süzgecin değeri **1**'dir. Kırk başarısız denemenin ardından gelen o tek
**başarılı** giriş satırı, olayın sonucunu belirleyen satırdır: denemeler başarısız kaldıysa
olay bir gürültüdür, sonuncusu başarılıysa olay bir ihlaldir. Başarısızlığı arayan hiçbir
süzgeç onu getirmez, çünkü o satır başarısız değildir.

Bu, kursun kuralının kimlik günlüklerindeki biçimidir. "Kaç başarısız giriş var" sorusunun
yanıtı ne kadar doğru olursa olsun, tanıyı belirleyen soru değildir. Doğru soru şudur: **bu
deneme dizisinden sonra o hesapla giriş yapılabildi mi.** Aynı ayrım oturum kayıtlarında da
işler: açık kalmış oturumları saymak yerine, hangi açılışın kapanışı olmadığı sorulur.

Sorunun biçimi süzgecin biçimini de belirler. Başarısızlığı arayan bir süzgeç bir **sayaç**
üretir; sayaç bir eşikle karşılaştırılır ve eşik hep tartışmalıdır. Diziyi arayan bir süzgeç
ise bir **örüntü** üretir: aynı hesap, aynı kaynak, dar bir pencere ve sonunda değişen bir
sonuç. Ölçüdeki `hesap_penceresi` işlevi tam olarak bunu yapar; yanlış tanıyı 12'den 2'ye
indiren şey daha akıllı bir eşik değil, sorunun sayaçtan örüntüye çevrilmesidir.

Örüntünün bir bedeli vardır. Sayaç tek geçişte hesaplanır; örüntü, her hesap için pencere
taraması gerektirir ve günlük büyüdükçe pahalılaşır. Kayıtlar alanlara ayrılmış biçimde
duruyorsa bu tarama sorgu tarafında yapılabilir; yalnız düz metin varsa önce ayrıştırma
gerekir. Önceki derste kurulan biçim ayrımının bedeli burada ödenir: **düz metin, sorunun
sayaç olarak sorulmasını dayatır.**

#### İkinci Tohum

İkinci tohumla arka plan gürültüsü değişir; saldırı 41 satır olarak kalır çünkü kurguya öyle
yerleştirilmiştir. Kaba süzgeç 156 satır getirip **117** yanlış tanı üretir, olay türünü
sınırlayan süzgeç **40**, kaynağı da sınırlayan **21**, alan bilen süzgeç **6** verir.
Sayılar büyür, sıralama değişmez ve `girisi_buldu` sütunu yine yalnız alan bilen süzgeçte
**1**'dir. Yanlış tanı sayılarının kesin değeri **kurguya bağlıdır**; kurguya bağlı olmayan
şey, metin eşlemenin başarılı satırı yapısal olarak kaçırmasıdır.

#### Özet

- Kimlik doğrulama başarısızlığı ile yetkilendirme başarısızlığı iki ayrı olaydır; metin
  eşleyen bir süzgeç ikisini tek kovaya atar.
- Oturum kapanış kaydının eksik olması olağandır; açık oturum sayısını günlükten çıkaran
  tanı gerçekte açık olandan fazla sayar.
- Kâhin 41 saldırı satırı barındırır; kaba süzgeç 153 satır getirip **114**, alan bilen
  süzgeç 43 satır getirip **2** yanlış tanı üretir.
- Üç metin süzgecinin hiçbiri saldırının **başarılı** giriş satırını bulamaz; alan bilen
  süzgeç onu bulur ve tanıyı ihlal ile gürültü arasında ayıran satır odur.
- Kazanç satır sayısını değiştirmekten değil, satırları hesap ve zaman penceresine göre
  gruplamaktan gelir.

#### Sonraki Adım

Bu dersin süzgeçleri elinde bütün günlük varken çalıştı: 601 satırın hepsi okunabiliyordu.
Gerçek bir makinede bu varsayım her zaman geçerli değildir, çünkü günlük dosyaları
sınırsız büyümez. Dosya belirli bir boyuta ulaştığında eskisi atılır ve atılan kısım geri
gelmez. Sonraki ders süzme ile döndürmeyi birlikte ele alır ve 4000 satırlık bir günlükteki
86 hatanın döndürme boyutu küçüldükçe kaça düştüğünü sayar.

### Günlük Filtreleme ve Döndürme

Source: https://academia.sh/tr/kurslar/sistem-yonetimi/gunluk-filtreleme-ve-dondurme

Düzey, birim ve zaman süzgeçleri ile döndürme politikasının birlikte ölçülmesi: 4000 satırda 86 hata varken 1000 satırlık dosyada 19, 200 satırlık dosyada 5 hata kalıyor ve altı inceleme sorusunun kaçının yanıtsız kaldığı sayılıyor.

Önceki iki ders elinde bütün günlük varken çalıştı: 4000 satır da, 601 satır da eksiksizdi
ve süzgeçler bu bütünün üzerinde koştu. Bu varsayım bir makinede sınırlı bir süre geçerlidir.
Günlük dosyaları sınırsız büyümez; disk sonludur ve dolan bir disk, günlüğün kendisinden
daha büyük bir arızadır.

Bu ders iki mekanizmayı birlikte ele alır. Birincisi **süzme**: elinizdeki satırlardan bir
alt küme seçmek. İkincisi **döndürme (rotation)**: elinizdeki satırların bir kısmını kalıcı
olarak atmak. İkisi yüzeyde benzer görünür — ikisinden sonra da daha az satır kalır — ama
biri geri alınabilir, öteki alınamaz. Ölçülen şey, ikisinin tanıya verdiği zarardır.

#### Süzmenin Düşürdüğü Bağlam

Üç süzgeç türü vardır ve üçü farklı bir eksen boyunca keser. **Düzey süzgeci** yalnız
belirli bir önem derecesinin üstündekileri bırakır. **Birim süzgeci** yalnız bir servisin
kayıtlarını bırakır; önceki derste ölçülen şey buydu, komşuluk kaybını üretir. **Zaman
süzgeci** bir aralığın dışını atar.

Düzey süzgeci en sık kullanılan ve en aldatıcı olanıdır. 4000 satırlık bir günlükte hata
sayısı 86'dır; hatalarla sınırlanmış bir görüntü 4000 satırı 86'ya indirir ve okunabilir
hâle getirir. Düşen 3914 satırın içinde ise hatanın **öncesi** vardır. Bir servisin hataya
gitmeden önce yazdığı uyarı, hatanın kendisinden daha çok şey söyleyebilir: yeniden deneme
sayısı, zaman aşımı süresi, kuyruk doluluğu. Düzey süzgeci bunları görünmez yapar.

Zaman süzgecinin tuzağı farklıdır. Bir arıza fark edildiğinde inceleme çoğunlukla fark
edilme anından geriye doğru dar bir pencereyle başlar. Arızanın kendisi o pencerede olabilir,
ama arızayı **başlatan** olay dışarıda kalabilir. Pencereyi genişletmek satır sayısını
artırır ve okumayı zorlaştırır; bu, kursun ikinci iddiasının bir yüzüdür: daha çok satır
daha iyi tanı demek değildir, ama daha az satır da her zaman daha net tanı vermez.

Süzmenin belirleyici özelliği geri alınabilirliğidir. Süzgeç yanlış seçildiyse komut yeniden
çalıştırılır. Kayıp yoktur, yalnız zaman geçmiştir.

Süzgecin nasıl kurulduğu da biçime bağlıdır. Yapılandırılmış kayıtta üç eksen ayrı ayrı
verilebilir; düz metinde metin eşleme ile satır seçilir ve zaman kısıtı metnin kendisinden
ayrıştırılır. Aşağıdaki iki döküm örnektir ve çalıştırılmamıştır.

```text
# ornek dokum , calistirilmis degildir
$ journalctl -u isleme -p warning --since -10min
$ grep -E 'hata|uyari' /var/log/isleme/isleme.log | tail -n 40
```

İki satır aynı işi yapmaz. Birincisi birimi, düzeyi ve zaman aralığını **alan olarak**
kısıtlar; ikincisi ileti metninde iki sözcük arar ve zaman kısıtı yerine son kırk satırı
alır. İkincisi, "uyari" sözcüğünü kullanmayan bir programın satırlarını sessizce atar ve
"son kırk satır" kaç saniyeyi kapsadığını söylemez.

#### Döndürme: Geri Alınamayan Kesme

Döndürme bir dosyanın büyümesini sınırlayan mekanizmadır. Dosya belirlenen boyuta ya da yaşa
ulaştığında yeniden adlandırılır, yerine yenisi açılır ve elde tutulan eski kopya sayısı
aşıldığında en eskisi **silinir**. Sıkıştırma, silinme anını geciktirir; kaldırmaz. Bir
**saklama politikası** bu üç parametreden oluşur: eşik, tutulan kopya sayısı ve sıkıştırma.

Sistem günlüğünün kendi sınırı da benzer çalışır: toplam boyut ya da süre sınırı aşıldığında
en eski kayıtlar atılır. Ayrımın adı önemli değildir; sonuç aynıdır. Aşağıdaki döküm
örnektir ve çalıştırılmamıştır.

```text
# ornek dokum , calistirilmis degildir
$ ls -1 /var/log/isleme/
isleme.log
isleme.log.1
isleme.log.2.gz
```

Buradaki soru şudur: dosya sınırı, arızanın süresinden kısaysa ne olur. Yanıt, kursun
üçüncü iddiasıdır: **kanıt kendiliğinden yok olur.** Kimse silmez, kimse karar vermez;
politika çalışır ve kanıt gider.

Bu kaybın en sinsi yanı sessizliğidir. Silinen satırların yerine bir işaret bırakılmaz;
dosyanın başında "buradan öncesi atıldı" diyen bir satır yoktur. Operatör dosyayı açtığında
gördüğü şey, eksik bir kaydın değil, **kısa bir geçmişin** görüntüsüdür. Süzgeçte durum
farklıdır: süzgeci kendisi yazdığı için neyi dışarıda bıraktığını bilir. Döndürmede seçimi
yapan taraf operatör değildir ve seçim, arıza olmadan çok önce, bir yapılandırma dosyasına
yazılmıştır.

#### Ölçülen Şey: Kalan Kanıt ve Yanıtsız Soru

Ölçü iki parçalıdır. Birinci parça kalan kanıt oranıdır: dosya boyutu küçüldükçe pencerenin
başındaki hataların kaçı hayatta kalıyor. İkinci parça, bir arıza incelemesinde gerçekten
sorulan **altı soruya** verilen yanıtların kaçının yanlış çıktığıdır: toplam hata sayısı,
ilk hatanın saniyesi, ilk hatanın birimi, son hatanın saniyesi, pencerenin ilk yarısındaki
hata sayısı ve hiç hata yazmayan birim sayısı. Kâhin, tam günlükten okunan yanıtlardır.

Kurgunun varsayımları: döndürülmüş dosya her zaman **son** satırları tutar ve atılan kısım
geri gelmez (**GN9**); sınanan boyutlar 4000, 2000, 1000, 500 ve 200 satırdır (**GN10**);
inceleme soru kümesi yukarıdaki altı sorudur (**GN11**); öncül uyarı penceresi beş saniye
ve öncülün aynı birimden gelmesi gerekir (**GN12**); satır hızı pencere boyunca sabittir
(**GN13**).

```python
TOHUM = 20260218
DONEM = 600                      # gozlem penceresi: 600 saniye


def uretec(tohum):
    d = tohum

    def sonraki(n):
        nonlocal d
        d = (d * 1103515245 + 12345) % 2147483648
        return d % n
    return sonraki


BIRIM = {
    "veri-alma":      {"gerektirir": [], "yeniden": "her zaman"},
    "kuyruk":         {"gerektirir": ["veri-alma"], "yeniden": "her zaman"},
    "isleme":         {"gerektirir": ["kuyruk"], "yeniden": "arizada"},
    "rapor":          {"gerektirir": ["isleme"], "yeniden": "hayir"},
    "olcum":          {"gerektirir": ["veri-alma"], "yeniden": "her zaman"},
    "yedek":          {"gerektirir": [], "yeniden": "hayir"},
}


def gunluk_uret(tohum=TOHUM, satir=4000):
    r = uretec(tohum)
    kayit = []
    for i in range(satir):
        agirlik = r(100)
        duzey = "hata" if agirlik < 3 else ("uyari" if agirlik < 12 else "bilgi")
        kayit.append({"sira": i, "saniye": i * (DONEM / satir),
                      "duzey": duzey, "birim": list(BIRIM)[r(len(BIRIM))]})
    return kayit


def dondur(kayitlar, boyut):
    """GN9: dosya `boyut` satirda dolar ve eskisi silinir. Geriye ne kaldi."""
    return kayitlar[-boyut:] if boyut < len(kayitlar) else list(kayitlar)


def kanit_orani(kayitlar, kalan, duzey="hata"):
    tum = [k for k in kayitlar if k["duzey"] == duzey]
    kalanlar = [k for k in kalan if k["duzey"] == duzey]
    return {"toplam": len(tum), "kalan": len(kalanlar),
            "oran": round(len(kalanlar) / len(tum), 4) if tum else 0.0}


def onculu_hata(kayitlar, aralik=5.0):
    """GN12: kendinden onceki bes saniyede AYNI birimden uyari gelmis hatalar."""
    u = [k for k in kayitlar if k["duzey"] == "uyari"]
    h = [k for k in kayitlar if k["duzey"] == "hata"]
    return sum(1 for a in h
               if any(a["birim"] == b["birim"]
                      and 0 <= a["saniye"] - b["saniye"] <= aralik for b in u))


def yanitlar(kayitlar):
    """GN11: inceleme sorulari , dosyada duran satirlardan yanitlanir."""
    h = [k for k in kayitlar if k["duzey"] == "hata"]
    if not h:
        return {"toplam": 0, "ilk": None, "ilk_birim": None, "son": None,
                "ilk_yari": 0, "sessiz_birim": len(BIRIM)}
    d = {b: sum(1 for k in h if k["birim"] == b) for b in BIRIM}
    return {"toplam": len(h), "ilk": round(h[0]["saniye"], 1),
            "ilk_birim": h[0]["birim"], "son": round(h[-1]["saniye"], 1),
            "ilk_yari": sum(1 for k in h if k["saniye"] < DONEM / 2),
            "sessiz_birim": sum(1 for b in d if d[b] == 0)}


for tohum in (TOHUM, 20260219):
    G = gunluk_uret(tohum)
    K = yanitlar(G)
    print("tohum", tohum, "| satir", len(G), "| uyari",
          sum(1 for k in G if k["duzey"] == "uyari"), "| hata", K["toplam"])
    print("  duzey suzgeci: onculu uyarisi gizlenen hata", onculu_hata(G), "/", K["toplam"])
    print("  kahin:", K)
    print("  boyut  kalan  hata  kanit orani  yanlis yanit  ilk hata")
    for boyut in (4000, 2000, 1000, 500, 200):        # GN10
        kalan = dondur(G, boyut)
        ko = kanit_orani(G, kalan)
        Y = yanitlar(kalan)
        print(f"  {boyut:5d}  {len(kalan):5d}  {ko['kalan']:4d}  {ko['oran']:11.4f}"
              f"  {sum(1 for a in K if Y[a] != K[a]):12d}  {Y['ilk']}")
```

```
tohum 20260218 | satir 4000 | uyari 408 | hata 86
  duzey suzgeci: onculu uyarisi gizlenen hata 63 / 86
  kahin: {'toplam': 86, 'ilk': 6.1, 'ilk_birim': 'isleme', 'son': 598.0, 'ilk_yari': 44, 'sessiz_birim': 3}
  boyut  kalan  hata  kanit orani  yanlis yanit  ilk hata
   4000   4000    86       1.0000             0  6.1
   2000   2000    42       0.4884             3  314.2
   1000   1000    19       0.2209             4  461.2
    500    500    12       0.1395             4  527.5
    200    200     5       0.0581             4  573.4
tohum 20260219 | satir 4000 | uyari 314 | hata 163
  duzey suzgeci: onculu uyarisi gizlenen hata 99 / 163
  kahin: {'toplam': 163, 'ilk': 1.3, 'ilk_birim': 'rapor', 'son': 594.0, 'ilk_yari': 80, 'sessiz_birim': 3}
  boyut  kalan  hata  kanit orani  yanlis yanit  ilk hata
   4000   4000   163       1.0000             0  1.3
   2000   2000    83       0.5092             3  301.8
   1000   1000    35       0.2147             3  451.5
    500    500    12       0.0736             3  528.1
    200    200     3       0.0184             5  578.2
```

#### Çıktının Söylediği ile Sistemin Gerçeği

Üç sayı yan yana durur. **Kâhin:** altı yüz saniyelik pencerede **86** hata oldu; ilki
altıncı saniyede, `isleme` biriminde. **Araç çıktısı:** 1000 satırlık dosyada **19** hata
görünüyor, 200 satırlıkta **5**. **Yanlış tanı:** altı sorunun 1000 satırda **4'ü**, 200
satırda yine **4'ü** yanlış yanıtlanıyor.

Kalan kanıt oranı döndürme boyutuyla birlikte düşer: 2000 satırda 0,4884, 1000 satırda
**0,2209**, 500 satırda 0,1395, 200 satırda **0,0581**. Dosyayı yarıya indirmek kanıtın
yarısını değil, yarısından fazlasını götürür; kayıtlar zaman içinde düzgün dağılmadığı için
kayıp doğrusal değildir.

Asıl zarar sayıda değil, sayının **inandırıcılığındadır**. 200 satırlık dosyayı açan operatör
beş hata görür ve beş hatanın hepsi gerçektir; hiçbiri uydurma değildir. Ondan çıkardığı
"bu pencerede beş hata oldu" cümlesi ise yanlıştır. Araç yalan söylemiyor; dosya yalan
söylemiyor. Yanlış olan, **eksik bir dosyadan tam bir sonuç çıkarmaktır.**

Altı sorunun tablosu bunu ayrıntılandırır. Tam dosyada altı yanıtın altısı doğrudur. 2000
satırda üç yanıt bozulur: toplam hata sayısı, ilk hatanın saniyesi ve pencerenin ilk
yarısındaki hata sayısı. 1000 satırdan itibaren ilk hatanın **birimi** de yanlış çıkar:
gerçek ilk hata `isleme` birimindeyken dosyada kalan ilk hata başka bir birime aittir.
İnceleme "arıza nerede başladı" sorusuna yanlış birimi işaret ederek yanıt verir ve bu
yanıtın yanlış olduğunu gösteren hiçbir belirti dosyada yoktur.

Dikkat çeken bir ayrıntı, yanlış yanıt sayısının 1000'den sonra **artmamasıdır**: dörtte
kalır. Bunun nedeni, kalan iki sorunun — son hatanın saniyesi ve sessiz birim sayısı —
pencerenin sonuna yakın kayıtlardan yanıtlanabilmesidir. Döndürme her soruyu eşit ölçüde
vurmaz: **geçmişe bakan sorular önce ölür, şimdiye bakan sorular sağ kalır.**

Bir başka ayrıntı da kanıt oranının **hata sayısını** değil hata **oranını** koruyabilmesidir.
200 satırlık dosyada beş hata vardır ve bu, satır başına düşen hata bakımından tam günlükteki
orana yakındır. Yalnız orana bakan bir tanı hiçbir tuhaflık görmez: dosya sağlıklı bir
sistemin sağlıklı bir kesiti gibi durur. Kaybolan şey oran değil, **süredir**; olayın ne
kadar sürdüğü, ne zaman başladığı ve nasıl yayıldığı yalnız uzun pencereden okunur.

Süzmenin ölçüsü de aynı çıktıdadır. 86 hatanın **63'ünün** kendinden önceki beş saniye
içinde aynı birimden gelmiş bir uyarısı vardır. Yalnız hataları gösteren bir görüntü bu 63
öncülün hepsini gizler; satırlar dosyada durur, ama bakılan yerde durmaz. Süzmenin farkı
şudur: süzgeci gevşetmek 63 satırı geri getirir, döndürmeyi gevşetmek geçmişte silinmiş
satırı geri getirmez.

#### Dosya Kaç Saniyelik Geçmiş Tutuyor

Döndürme eşiği satır cinsindendir, oysa incelemenin sorduğu şey zamandır. İkisi arasındaki
çeviri satır hızıyla yapılır ve bu kurguda hız sabit alınmıştır (**GN13**): altı yüz
saniyede 4000 satır, yani satır başına 0,15 saniye. Buradan her eşiğin tuttuğu geçmiş doğrudan çıkar. 2000 satırlık
bir dosya 300 saniyelik, 1000 satırlık dosya 150 saniyelik, 200 satırlık dosya yalnız 30
saniyelik geçmiş tutar.

Çıktının son sütunu bu hesabı doğrular. 1000 satırlık dosyada görülen ilk hata 461,2.
saniyededir; dosyanın kapsadığı pencere 450. saniyede başlar. 200 satırlık dosyada ilk hata
573,4. saniyededir; pencere 570'te başlamıştır. Gerçek ilk hata ise 6,1. saniyededir ve
hiçbir küçük dosyada bulunmaz.

Bu çeviri, eşiği seçerken sorulacak soruyu belirler. "Kaç satır tutalım" sorusunun anlamlı
bir yanıtı yoktur; anlamlı soru "kaç saniyelik geçmiş gerekiyor" sorusudur ve satır hızı
biliniyorsa aradaki dönüşüm bir çarpmadır. Satır hızı sabit de değildir: arıza anında
servisler daha çok yazar, dolayısıyla dosya tam olarak en çok kanıt üretilen anda **daha
hızlı** dolar ve daha hızlı döner. Kanıtın yoğunlaştığı an, kanıtın en hızlı silindiği andır.

#### Politikanın Ne Anlama Geldiği

Buradan işletim tarafında iki karar çıkar. Birincisi, döndürme eşiği bir depolama kararı
gibi görünse de aslında bir **inceleme kararıdır**: eşik, arızanın en uzun makul süresinden
kısa olmamalıdır. Kalan kanıt oranı bunun ölçüsüdür ve önceden hesaplanabilir; günlük satır
hızı biliniyorsa, bir eşiğin kaç saniyelik geçmişi tuttuğu bir bölme işlemidir.

İkincisi, "her ihtimale karşı hepsini sakla" bir çözüm değildir. Disk dolarsa yazma
başarısız olur ve o başarısızlık, kaybedilen kanıttan daha ağır bir arızadır. Depolama
konusu bu sınırın iki ayrı biçimde geldiğini gösterecektir. Doğru karar, hangi sorunun
yanıtlanabilir kalması gerektiğine önceden karar vermek ve eşiği o soruya göre seçmektir.

Üçüncü bir karar da döndürmenin **ne zaman** yapıldığıdır. Zamana bağlı döndürme sabit
aralıklarla çalışır ve dosya küçük kalsa bile döndürür; boyuta bağlı döndürme dosya
dolduğunda çalışır ve sessiz bir makinede hiç dönmeyebilir. İkisi bir arada
kullanıldığında, önce hangisi tetiklenirse o kazanır. Sonuç şudur: bir eşiğin tuttuğu
geçmiş, makinenin ne kadar konuşkan olduğuna göre değişir ve yoğun bir günde beklenenden
kısa olur.

Dördüncü karar döndürmenin nasıl yapıldığıdır. Dosya yeniden adlandırılıp yerine yenisi
açılırsa, dosyayı hâlâ açık tutan bir süreç eski dosyaya yazmayı sürdürür ve yeni dosya boş
kalır; bu yüzden döndürme sonrasında yazan tarafa dosyayı yeniden açmasını söyleyen bir
sinyal gönderilir. Süreç yönetimi konusunda kurulan sinyal modeli burada bir günlük
mekanizmasının parçasıdır. Sinyal gönderilmezse arıza sessizdir: dosyalar döner, boyut
sınırı çalışır, ama kayıtlar artık kimsenin bakmadığı bir dosyaya düşer.

#### İkinci Tohum

İkinci tohumda günlük daha gürültülüdür: 163 hata ve 314 uyarı çıkar. Kanıt oranı benzer
biçimde düşer — 1000 satırda 0,2147, 200 satırda 0,0184. Yanlış yanıt sayısı 2000, 1000 ve
500 satırda **3**, 200 satırda **5** olur. Kesin değerler **kurguya bağlıdır**; kurguya
bağlı olmayan şey, kalan kanıt oranının döndürme boyutuyla birlikte hızla düşmesi ve
geçmişe bakan soruların önce yanıtsız kalmasıdır.

#### Özet

- Süzme geri alınabilir, döndürme alınamaz; ikisi de satır azaltır ama biri kayıp üretmez.
- 4000 satırda 86 hata varken 1000 satırlık dosyada **19** (0,2209), 200 satırlıkta **5**
  (0,0581) hata kalır; kayıp doğrusal değildir.
- Altı inceleme sorusundan 1000 satırda **4'ü** yanlış yanıtlanır ve bunlardan biri "arıza
  nerede başladı" sorusudur; yanlışlığın hiçbir belirtisi dosyada yoktur.
- Döndürme soruları eşit vurmaz: geçmişe bakan sorular önce ölür, şimdiye bakan sorular sağ
  kalır.
- 86 hatanın **63'ünün** aynı birimden gelen bir uyarı öncülü vardır; düzey süzgeci onları
  gizler, ama süzgeci gevşetmek geri getirir.

#### Sonraki Adım

Bu derste ölçülen kayıp geçmişe aitti: silinmiş satır geri gelmiyordu. Bir makinenin
durumunu anlatan ikinci veri türü ise satır değil sayıdır — yük, bellek, disk doluluğu — ve
orada kayıp başka bir biçimde ortaya çıkar. Bu sayılar tek bir ana ait değildir; geçmiş bir
pencereyi ortalayarak üretilirler ve ortalama, sıçramayı yumuşatır. Sonraki ders sistem
sağlığı ölçümlerini ele alır ve yük ortalamasının gecikmeli bir gösterge olduğunu sayıyla
gösterir: anlık yük 7,36 iken altmış saniyelik ortalama 6,22'de kalır.

### Sistem Sağlığı Ölçümleri

Source: https://academia.sh/tr/kurslar/sistem-yonetimi/sistem-sagligi-olcumleri

Yük ortalaması, bellek ve disk göstergelerinin ne söylediği ve ne söylemediği: anlık yük 7,36 iken altmış saniyelik ortalama 6,22'de kalıyor, eşiği 54 saniye boyunca aşan gerçek yükü ortalanmış gösterge hiç göstermiyor.

Önceki ders geçmişe ait bir kaybı ölçtü: döndürülen bir günlükte silinen satır geri
gelmiyordu. Bir makinenin durumu hakkında konuşan ikinci veri türü satır değil sayıdır. Yük,
bellek, disk doluluğu; her biri tek bir sayı olarak sunulur ve o sayı bir arıza sırasında
ilk bakılan yerdir.

Bu ders o sayıların nasıl üretildiğini ele alır. Ortaya çıkan sorun döndürmedekiyle aynı
ailedendir ama farklı bir mekanizmadan gelir: satır silinmez, **sayı ortalanır**. Ortalama
alan bir gösterge geçmişi bugüne karıştırır ve sıçrama, ortalamanın içinde erir. Ölçülen şey,
o erimenin tanıyı kaç saniye boyunca yanlış tuttuğudur.

Bir ayrım baştan yapılmalıdır. Günlük satırı bir **olayı** kaydeder: olmuş bir şeyin izi
diskte durur ve sonradan okunabilir. Sağlık göstergesi ise bir **durumu** okur: okunduğu
anda üretilir ve okunmadığı an için hiçbir iz bırakmaz. Bir günlüğün eksikliği döndürmeyle
açıklanır; bir göstergenin eksikliğinin açıklaması yoktur, çünkü kaydedilmemiş bir an,
hiç olmamış bir andan ayırt edilemez.

#### Yük Ortalaması Neyi Sayar

**Yük ortalaması (load average)** çalışmaya hazır ya da kesintisiz bekleyen süreçlerin
sayısının bir zaman aralığındaki ortalamasıdır. İki noktası hemen belirtilmelidir. Birincisi,
bu bir yüzde değildir: işlemci doluluğunu değil, **sıraya girmiş iş miktarını** anlatır.
İkincisi, bir yük ortalaması hep bir pencereyle birlikte gelir; tek başına "yük" diye bir
sayı yoktur. Yaygın sunum üç pencereyi yan yana koyar ve üçü aynı anı üç farklı geçmişle
anlatır.

Sayının yorumu çekirdek sayısına bağlıdır. Aynı sayı, tek çekirdekli bir makinede doygunluk,
çok çekirdekli bir makinede rahatlık anlamına gelebilir. Bu yüzden mutlak bir eşik yoktur;
eşik makineye göre kurulur ve kurulurken **çekirdek sayısına bölünmüş** biçimi kullanılır.

Sayıya giren şeyin kapsamı da yanıltıcı olabilir. Yük ortalaması yalnız işlemci bekleyen
süreçleri değil, kesintisiz girdi/çıktı beklemesinde duran süreçleri de sayar. Sonuç şudur:
işlemcisi neredeyse boş, ama diski tıkanmış bir makinede yük ortalaması yüksek okunur ve
"işlemci yetmiyor" tanısı üretir. Bir sonraki dersin ayırmaya çalıştığı üç darboğaz türü,
bu tek sayının içinde toplanmış durumdadır.

Üçüncü ve bu dersin ölçtüğü nokta ise şudur: yük ortalaması **gecikmeli bir göstergedir.**
Değeri, bakılan andaki durumu değil, o ana kadarki pencerenin ortalamasını verir. Bir sıçrama
başladığında gösterge yavaş yükselir; sıçrama bittiğinde yavaş iner. Aradaki fark, ortalamanın
kaçırdığı gerçektir.

Aşağıdaki döküm örnektir ve çalıştırılmamıştır; üç sayı sırasıyla bir, beş ve on beş dakikalık
pencerelerdir.

```text
# ornek dokum , calistirilmis degildir
$ uptime
 yuk ortalamasi: 6.22, 6.19, 6.08
```

#### Ölçülen Şey: Ortalamanın Bastırdığı Sıçrama

Ölçü ortak tanımın süreç kurgusunun üzerine kurulur. Kurgunun varsayımları: yük, yirmi dört
sürecin saniye saniye kullanımının toplamıdır ve yüze bölünerek sunulur (**GN14**); ölçüm
yalnız pencerenin dolduğu altmışıncı saniyeden sonrası için yapılır (**GN15**); eşik,
gerçek yükün en yoğun yüzde onunu ayıran değerdir (**GN16**); sınanan ortalama pencereleri
15, 60 ve 300 saniyedir (**GN17**); süreç başına bellek pencere boyunca sabittir (**GN18**).

Kâhin, her saniyedeki **gerçek** yüktür; kurguyu biz ürettiğimiz için saniye saniye
biliniyor. Araç çıktısı, aynı yükün belirli bir pencereyle ortalanmış hâlidir. Tanı, "sistem
şu anda en yoğun durumunda" kararıdır. Yanlış tanı, göstergenin bu kararı kaçırdığı saniye
sayısıdır.

```python
TOHUM = 20260218
DONEM = 600                      # gozlem penceresi: 600 saniye


def uretec(tohum):
    d = tohum

    def sonraki(n):
        nonlocal d
        d = (d * 1103515245 + 12345) % 2147483648
        return d % n
    return sonraki


KULLANICI = ("kok", "uygulama", "yedek", "izleme")
KOMUT = ("veri-alici", "rapor-uretici", "yedek-gorevi", "olcum-toplayici",
         "kuyruk-isleyici", "onbellek-temizleyici")


def surecler(tohum=TOHUM, sayi=24):
    """Her surec: gercek islemci kullanimi bir ZAMAN DIZISIDIR , tek sayi degil."""
    r = uretec(tohum)
    liste = []
    for i in range(sayi):
        tur = r(10)
        if tur < 5:
            desen = "duz"                      # surekli dusuk kullanim
        elif tur < 8:
            desen = "ani"                      # kisa ve yuksek sicramalar
        else:
            desen = "agir"                     # surekli yuksek kullanim
        liste.append({
            "pid": 1000 + i * 7 + r(5),
            "kullanici": KULLANICI[r(len(KULLANICI))],
            "komut": KOMUT[r(len(KOMUT))],
            "desen": desen,
            "oncelik": r(11) - 5,
            "bellek": 20 + r(400),
            "sinyal_yok_sayar": r(10) < 2,     # bazi surecler sonlandirmayi yoksayar
        })
    return liste


def kullanim(surec, saniye):
    """Gercek islemci kullanimi , saniye saniye. Kahin bunu bilir; arac bilmez."""
    d = surec["desen"]
    if d == "duz":
        return 3 + (surec["pid"] + saniye) % 4
    if d == "agir":
        return 60 + (surec["pid"] + saniye) % 25
    # ani: her 60 saniyede bir 5 saniyelik sicrama
    faz = (saniye + surec["pid"]) % 60
    return 88 + faz if faz < 5 else 2 + faz % 3


def gercek_yuk(surecler_, saniye):
    return sum(kullanim(s, saniye) for s in surecler_)


def yuk_ortalamasi(surecler_, saniye, pencere=60):
    """Yuk ortalamasi GECIKMELI bir gostergedir: gecmis pencereyi ortalar."""
    bas = max(0, saniye - pencere)
    dilim = range(bas, saniye + 1)
    return round(sum(gercek_yuk(surecler_, t) for t in dilim) / len(list(dilim)) / 100, 2)


def bellek_payi(surecler_):
    """GN18: arac 'en cok bellek kullanan bes surec' listeler. Ne kadarini acikliyor."""
    b = sorted((s["bellek"] for s in surecler_), reverse=True)
    kum, kac = 0, 0
    for v in b:
        kum, kac = kum + v, kac + 1
        if kum / sum(b) >= 0.20:
            break
    return {"toplam": sum(b), "en_buyuk_pay": round(b[0] / sum(b), 4),
            "ilk_bes_pay": round(sum(b[:5]) / sum(b), 4), "yuzde_20_icin": kac}


for tohum in (TOHUM, 20260219):
    S = surecler(tohum)
    ara = range(60, DONEM)                     # GN15: pencere dolduktan sonrasi
    anlik = {t: gercek_yuk(S, t) / 100 for t in ara}
    sirali = sorted(anlik.values())
    esik = sirali[int(len(sirali) * 0.9)]      # GN16 kahin: en yogun yuzde on
    print("tohum", tohum,
          f"| anlik yuk {min(anlik.values()):.2f}-{max(anlik.values()):.2f}"
          f" | esik {esik:.2f} | esigi asan saniye"
          f" {sum(1 for v in anlik.values() if v >= esik)}")
    print("  saniye 0/60/300 anlik:", [round(anlik.get(t, gercek_yuk(S, t) / 100), 2)
                                       for t in (0, 60, 300)],
          "| ortalama(60):", [yuk_ortalamasi(S, t) for t in (0, 60, 300)])
    print("  pencere  en dusuk  en yuksek  esigi asan  kacirilan  yanlis alarm")
    for p in (15, 60, 300):                    # GN17
        seri = {t: yuk_ortalamasi(S, t, p) for t in ara}
        kacan = sum(1 for t in ara if anlik[t] >= esik and seri[t] < esik)
        fazla = sum(1 for t in ara if seri[t] >= esik and anlik[t] < esik)
        print(f"  {p:7d}  {min(seri.values()):8.2f}  {max(seri.values()):9.2f}"
              f"  {sum(1 for v in seri.values() if v >= esik):10d}"
              f"  {kacan:9d}  {fazla:12d}")
    print("  bellek:", bellek_payi(S))
```

```
tohum 20260218 | anlik yuk 5.36-7.80 | esik 7.15 | esigi asan saniye 54
  saniye 0/60/300 anlik: [7.36, 7.31, 7.36] | ortalama(60): [7.36, 6.25, 6.22]
  pencere  en dusuk  en yuksek  esigi asan  kacirilan  yanlis alarm
       15      5.62       6.80           0         54             0
       60      6.18       6.25           0         54             0
      300      6.13       6.29           0         54             0
  bellek: {'toplam': 4876, 'en_buyuk_pay': 0.0779, 'ilk_bes_pay': 0.3659, 'yuzde_20_icin': 3}
tohum 20260219 | anlik yuk 4.04-6.29 | esik 6.04 | esigi asan saniye 54
  saniye 0/60/300 anlik: [4.33, 4.33, 4.33] | ortalama(60): [4.33, 4.85, 4.85]
  pencere  en dusuk  en yuksek  esigi asan  kacirilan  yanlis alarm
       15      4.52       5.23           0         54             0
       60      4.83       4.90           0         54             0
      300      4.80       4.88           0         54             0
  bellek: {'toplam': 5444, 'en_buyuk_pay': 0.0755, 'ilk_bes_pay': 0.3611, 'yuzde_20_icin': 3}
```

#### Çıktının Söylediği ile Sistemin Gerçeği

Üç sayı yan yana durur. **Kâhin:** gerçek yük 5,36 ile 7,80 arasında dalgalanıyor ve
**54 saniye** boyunca 7,15 eşiğinin üstünde kalıyor. **Araç çıktısı:** altmış saniyelik
ortalama 6,18 ile 6,25 arasında; eşiği **hiç** aşmıyor. **Yanlış tanı: 54.** Sistemin en
yoğun olduğu her saniyede gösterge "olağan" diyor.

Yanlış alarm sayısı sıfırdır ve bu, göstergenin sessiz kalmasını daha da tehlikeli yapar.
Gösterge gürültülü olsaydı operatör ona güvenmemeyi öğrenirdi; bu gösterge yanılmıyor,
yalnız **hiç konuşmuyor.** Ortalanmış bir seri yanlış alarm üretmez, çünkü sıçramaları
zaten üretmez.

Eşiğin nereden geldiği de açıkça durmalıdır. Burada eşik dışarıdan seçilmiş bir sayı değil,
gerçek yükün en yoğun yüzde onunu ayıran değerdir; yani tanım gereği 54 saniye onu aşar.
Ölçülen şey eşiğin doğru seçilip seçilmediği değil, **aynı olayı ortalanmış bir seriden
görmenin mümkün olup olmadığıdır.** Yanıt olumsuzdur ve eşiği düşürmek durumu düzeltmez:
eşik ortalamanın bandının içine indirildiğinde gösterge bu kez sürekli aşar ve hiçbir
saniyeyi diğerinden ayırt edemez.

Şablonun ikinci satırı gecikmeyi doğrudan gösterir. Sıfırıncı saniyede anlık yük 7,36'dır ve
ortalama da 7,36'dır: pencere henüz dolmadığı için ikisi aynıdır. Altmışıncı saniyede anlık
7,31 iken ortalama 6,25'e düşmüştür, üç yüzüncü saniyede anlık yine **7,36** iken ortalama
**6,22**'dedir. Aynı andaki iki sayı arasındaki fark bir hata değildir; ikisi farklı şeyleri
ölçer. Sorun, ikisinin aynı ad altında sunulmasıdır.

Pencere genişliğinin etkisi de tablodan okunur. Anlık yükün genişliği 2,44 birimdir
(5,36'dan 7,80'e). On beş saniyelik ortalamada bu genişlik 1,18'e, altmış saniyelikte
**0,07'ye** iner. Üç yüz saniyelik pencerede 0,16'ya çıkar, ama eşiği yine hiç aşmaz;
genişlemenin nedeni pencere uzunluğu değil, pencerenin dolmadığı ilk saniyelerdir. Altmış
saniyelik pencerenin en düz seriyi vermesinin nedeni ise kurgudaki sıçramaların altmış
saniyelik dönemle yinelenmesidir: pencere, dönemin tam bir katını kapsadığında sıçramayı
her seferinde aynı ölçüde seyreltir.

Bu, gerçek makinelerde de karşılaşılan bir durumdur. Yinelenen bir iş — zamanlanmış bir
görev, bir toplu aktarım, bir önbellek temizliği — ortalama penceresiyle aynı ritimde
çalışıyorsa göstergede hiç iz bırakmaz. Görünmezliğin nedeni işin küçük olması değil,
**ritmin örtüşmesidir.**

Buradan çıkan kural şudur: yük ortalaması bir **sıçrama** göstergesi değil, bir **eğilim**
göstergesidir. "Şu anda ne oluyor" sorusuna yanıt vermez; "son bir dakikada genel gidiş
neydi" sorusuna verir. Süreç yönetimi konusunda örnekleme aralığı için ölçülen şey burada
ortalama penceresi için tekrarlanır: gösterge yalan söylemiyor, sorulan soru başka.

#### Üç Pencere Yan Yana

Yük ortalamasının üç pencereyle sunulmasının bir nedeni vardır: tek bir sayı düzeyi verir,
üç sayı **yönü** verir. Kısa pencere uzundan büyükse yük artıyordur; küçükse azalıyordur;
üçü birbirine yakınsa durum durağandır. Bu okuma, ortalamanın gecikmesini ortadan
kaldırmaz, ama gecikmenin işaretini görünür kılar.

Yönün kendisi de tanıyı belirler. Yükselen bir eğilimde asıl soru "şu anki değer eşiği aştı
mı" değil, "bu hızla ne zaman aşacak" sorusudur. Düşen bir eğilimde yüksek bir değer,
geçmiş bir olayın kalıntısıdır ve ona tepki vermek, çoktan bitmiş bir arızayı kovalamak
demektir. Bu ikinci durum operasyonda sık görülür: gösterge yüksek okunur, inceleme başlar
ve incelemenin sonuna gelindiğinde gösterge kendiliğinden inmiştir; kimse ne olduğunu
öğrenemez.

Üç pencereli okumanın sınırı da ölçüde durur. Kurgudaki sıçramalar beş saniye sürüyor;
en kısa pencere on beş saniye. Beş saniyelik bir olay, on beş saniyelik ortalamada
üçte birine iner ve üç pencerenin hiçbirinde yön değiştirecek kadar iz bırakmaz. Yön
okuması, olayın **en kısa pencereden uzun** sürmesini gerektirir.

Kısa süren olayları görmenin yolu ortalamayı okumak değil, ortalanmamış bir sayacı okumaktır:
çalıştırılabilir süreç sayısı, bağlam değiştirme sayısı ve kesme sayısı her okumada anlık
değer verir. Bu sayaçlar gürültülüdür ve tek bir okumaları yanıltıcıdır, ama gecikmezler.
Gecikmesiz ve gürültülü bir sayaç ile gecikmeli ve düzgün bir ortalama arasındaki seçim, bu
dersin asıl kararıdır; ikisini birden veren bir gösterge yoktur.

#### Bellek ve Disk Göstergeleri

Bellek göstergesinin tuzağı farklıdır. Bir araç "en çok bellek kullanan beş süreç" listeler
ve o liste okunması en kolay çıktıdır. Ölçüde bu listenin ne kadarını açıkladığı sayılıyor:
en büyük süreç toplam belleğin yalnız **yüzde 7,79'unu** tutuyor, ilk beş süreç birlikte
**yüzde 36,59'unu**. Kalan on dokuz süreç yüzde 63'ü tutuyor ve hiçbiri listede yok.
"En büyük süreci sonlandır" kararı toplamın yüzde sekizinden azını geri kazandırır; yüzde
yirmi boşaltmak için **üç** süreç gerekir. Liste yanlış değildir; yalnız sorulan soruyu
yanıtlamaz. "Belleği kim tüketiyor" sorusunun yanıtı bu kurguda tek bir ad değil, uzun bir
kuyruktur.

İkinci tuzak, işletim sisteminin boş belleği boş bırakmamasıdır. Okunmuş dosyalar önbellekte
tutulur ve gerektiğinde bırakılır; bu bellek "kullanılıyor" görünür ama baskı üretmez. Yalnız
kullanılan yüzdeye bakan bir tanı, sağlıklı bir makineyi dolu sanır. Ayırt edici gösterge
kullanım yüzdesi değil, **geri kazanılabilir olmayan** kısımdır.

Üçüncü tuzak, süreç başına raporlanan belleğin toplanamaz olmasıdır. Paylaşılan kütüphaneler
ve paylaşılan sayfalar her sürecin kendi satırında ayrı ayrı sayılır; süreç satırlarını
toplayan bir hesap, makinede olandan fazla bellek bulur. Süreç listesinden çıkarılan toplam,
sistem düzeyindeki toplamla karşılaştırılmadan kullanılmamalıdır.

Disk tarafında da benzer bir ikilik vardır ve bu konunun kapsamını aşar. Doluluk yüzdesi tek
bir sayıdır, oysa bir dosya sisteminde birbirinden bağımsız **iki** sınır tükenir ve ikisi
aynı hata iletisini üretir. Depolama konusu bu ayrımı ölçecek; şimdilik bilinmesi gereken,
doluluk yüzdesinin düşük olmasının yazmanın başarılı olacağını **garanti etmediğidir.**

Disk göstergesinin bir başka özelliği de ölçüm anına duyarsız olmasıdır. Yük saniyeler içinde
değişir, doluluk saatler içinde. Bu, disk göstergesini daha güvenilir yapmaz; yalnız farklı
bir gecikme türü verir. Dolan bir diskte tehlikeli olan mevcut yüzde değil, **doluşun
hızıdır**; tek bir okumadan hız çıkarılamaz ve iki okuma arasındaki fark alınmadıkça
gösterge, arızaya kaç saat kaldığını söylemez.

#### İkinci Tohum

İkinci tohumda kurgunun yük düzeyi düşer: anlık yük 4,04 ile 6,29 arasında dalgalanır ve
eşik 6,04'e iner. Sayılar değişse de yapı aynı kalır — gerçek yük eşiği yine **54 saniye**
boyunca aşar, ortalanmış göstergeler eşiği yine **hiç** aşmaz ve yanlış tanı yine **54**
olur. Altmış saniyelik ortalamanın genişliği 0,07 birimde kalır. Eşiğin ve yükün mutlak
değeri **kurguya bağlıdır**; kurguya bağlı olmayan şey, ortalamanın sıçramayı tümüyle
bastırması ve yanlış alarm sayısının sıfır olmasıdır.

#### Özet

- Yük ortalaması bir yüzde değil, sıraya girmiş iş miktarının bir pencere boyunca
  ortalamasıdır; yorumu çekirdek sayısına bağlıdır.
- Gerçek yük eşiği **54 saniye** boyunca aşarken altmış saniyelik ortalama onu **hiç**
  aşmıyor; yanlış tanı 54, yanlış alarm 0.
- Anlık yükün 2,44 birimlik genişliği altmış saniyelik ortalamada **0,07**'ye iner; pencereyi
  büyütmek göstergeyi yatıştırır ve yatışmış gösterge sıçrama gösteremez.
- En çok bellek kullanan süreç toplamın yalnız yüzde 7,79'unu tutar; ilk beş süreç yüzde
  36,59'unu tutar, yüzde yirmi boşaltmak için üç süreç gerekir.
- Yük ortalaması bir eğilim göstergesidir; "şu anda ne oluyor" sorusuna yanıt veremez ve
  vermeye zorlandığında sessiz kalır.

#### Sonraki Adım

Bu dersin göstergeleri sistemin bütününü tek sayıya indiriyordu ve indirgeme sıçramayı
yiyordu. Bir başarım sorunu incelenirken sorulan soru daha da özeldir: yavaşlığın nedeni
işlemci mi, disk mi, bellek mi. Üç neden çoğu araç çıktısında birbirine çok benzer görünür
ve ayrıntı düzeyini yükseltmek benzerliği azaltmaz. Sonraki ders üç darboğaz türünü ayırmayı
ele alır ve dört kat daha çok satır üreten bir görüntünün yanlış tanı sayısını hiç
değiştirmediğini, üç satırlık bir görüntünün ise değiştirdiğini sayar.

### Başarım Sorunlarının İzi

Source: https://academia.sh/tr/kurslar/sistem-yonetimi/basarim-sorunlarinin-izi

İşlemci, girdi/çıktı ve bellek darboğazlarının ayrılması: dört kat daha çok satır üreten bir görüntü 18 olayın yine 12'sinde yanılıyor, üç satırlık bir görüntü 2'ye iniyor ve aynı üç ölçünün okunma sırası kalan iki yanılgıyı da kaldırıyor.

Önceki ders bir makinenin durumunu tek sayılara indiren göstergeleri ele aldı ve
indirgemenin sıçramayı yediğini ölçtü. Orada kalan bir açık vardı: yük ortalaması işlemci
bekleyen süreçlerle diski bekleyen süreçleri **aynı sayının içinde** topluyordu. Bir makine
yavaşladığında sorulan soru tam olarak o toplamı ayırmayı gerektirir: yavaşlığın nedeni
işlemci mi, disk mi, bellek mi.

Bu ders üç darboğaz türünü ayırmayı ele alır. Beklenen çözüm daha ayrıntılı bir çıktıdır:
daha çok sütun, daha çok satır, daha ince ayrıntı. Ölçülen şey bu beklentinin doğru olup
olmadığıdır ve kursun ikinci iddiası burada ödenir: **daha çok çıktı daha iyi tanı demek
değildir.**

Beklentinin nereden geldiği de anlaşılırdır. Bir arıza karşısında elde olan tek denetim
düğmesi çoğunlukla ayrıntı düzeyidir: daha uzun liste, daha ince kırılım, daha sık
örnekleme. Bunların hepsi çıktıyı büyütür ve büyüyen çıktı, çabanın arttığı duygusunu verir.
Ölçü bu duyguyu sınar ve sonuç açıktır: çabanın yönü yanlışsa miktarı sonucu değiştirmez.

#### Üç Darboğaz ve Ortak Belirtileri

Bir makinenin yavaşlaması üç mekanizmadan doğabilir ve üçü kullanıcıya aynı görünür.

**İşlemci darboğazında** çalıştırılabilir süreç sayısı işlemci sayısını aşar; süreçler
sıraya girer, her biri kendi payını bekler. İşlemci meşgul yüzdesi yüksektir ve bu yüksekliğin
karşılığı gerçek iştir.

**Girdi/çıktı darboğazında** süreçler işlemciyi değil diski bekler. Beklerken kesintisiz
bekleme durumundadırlar; işlemciyi tüketmezler ama sayılırlar. İşlemci tarafında görünen şey
**bekleme** payıdır: işlemci boştur, ama boş olmasının nedeni yapacak iş kalmaması değil,
verinin gelmemesidir. Meşguliyeti bekleme payını da içine katarak raporlayan bir görüntü,
bu durumu işlemci darboğazından ayıramaz.

**Bellek darboğazında** fiziksel bellek yetmez ve sayfalar takas alanına taşınır.
Buradaki tuzak iki katlıdır. Birincisi, takas hareketi kendisi bir disk işidir; yoğun takas
**girdi/çıktı beklemesi üretir** ve bellek darboğazı disk darboğazı gibi görünür. İkincisi,
bellek göstergeleri baskı anında değil, baskı geçtikten sonra da yüksek kalır: takasa çıkmış
sayfalar geri çağrılmadıkça orada durur.

Dördüncü bir olasılık daha vardır ve bu üçlünün dışında kalır: darboğaz makinenin kendisinde
değil, beklediği bir karşı tarafta olabilir. Bir ağ isteğini bekleyen süreç de yavaştır, ama
üç ölçünün hiçbirinde iz bırakmaz; işlemci boş, disk boş, bellek rahattır. Bu ders o durumu
ölçmez ve o durum, üç ölçünün "hepsi olağan" dediği hâlde makinenin yavaş olduğu tek
senaryodur. Ağ tarafındaki tanı bir sonraki kursun konusudur.

İşletim Sistemi Kavramları kursu sayfalı belleğin ve çizelgelemenin mekanizmasını kurdu;
burada tekrarlanmaz. Buradaki soru mekanizma değil, **operatörün hangi çıktıdan hangi
mekanizmayı okuyabildiğidir.** Aynı ayrım kursun açılışında kurulmuştu: bir soyutlamanın
bedelini ölçmekle, operatörün o soyutlamayı görüp göremediğini ölçmek iki ayrı iştir.

#### Beş Görüntü

Ölçüde beş ayrı görüntü karşılaştırılıyor ve her biri farklı sayıda satır üretiyor.

**A — süreç listesi.** Yirmi dört satır, tek anlamlı sütun: süreç başına işlemci yüzdesi.
En yaygın ilk bakıştır.

**B — iş parçacığı ayrıntısı.** Aynı liste, iş parçacığı düzeyinde açılmış: doksan altı
satır. Dört kat daha çok çıktı, **aynı sütunlar**. Ayrıntı düzeyi yükselmiştir, ölçü
kümesi değişmemiştir.

**C — A artı bekleme sütunu.** Yine yirmi dört satır, ama listeye süreç başına girdi/çıktı
bekleme payı eklenmiş. Satır sayısı A ile aynı, ölçü kümesi bir birim büyük.

**D — üç sistem ölçüsü.** Üç satır: işlemci meşguliyeti, bekleme payı, takas hareketi. Süreç
başına hiçbir ayrıntı yok.

**E — aynı üç ölçü, farklı okuma sırası.** D ile birebir aynı üç satır; tek fark, hangi
ölçünün önce sorulduğudur. D bekleme payına önce bakar, E takas hareketine.

Aşağıdaki döküm örnektir ve çalıştırılmamıştır; D görüntüsünün taşıdığı üç ölçüyü gösterir.

```text
# ornek dokum , calistirilmis degildir
$ vmstat 1 1
 r  b   takas    bos  ...  si  so  ...  us  sy  id  wa
 4  6  102400  81920  ...  38  44  ...  61  12   5  22
```

#### Bu Üç Ölçü Nereden Okunur

Üç ölçünün her biri ayrı bir sayaçtan gelir ve hangi araçla okundukları ikincil bir
sorudur; önemli olan sayacın kendisidir.

**İşlemci meşguliyeti** çekirdeğin tuttuğu zaman kovalarından hesaplanır: kullanıcı kipinde
geçen süre, çekirdek kipinde geçen süre, boşta geçen süre ve bekleyerek geçen süre. Bu
kovalar açılıştan beri artan **birikimli** sayaçlardır; anlık yüzde, iki okuma arasındaki
farktan çıkar. Tek bir okuma açılıştan beri olan ortalamayı verir ve o ortalama, bir arıza
sırasında neredeyse hiçbir şey söylemez. Bu, önceki dersteki gecikme sorununun başka bir
biçimidir: sayacın kendisi gecikmez, ama tek okuma **her şeyi ortalar**.

**Bekleme payı** aynı kovalardan birinin adıdır ve tam olarak "işlemci boştaydı, ama en az
bir süreç diski bekliyordu" anlamına gelir. İki uyarı gerekir. Birincisi, bu bir süre
ölçüsüdür, bir kuyruk ölçüsü değil; kaç sürecin beklediğini söylemez. İkincisi, işlemci
gerçekten meşgulse bekleme payı **düşük okunur**, çünkü işlemcinin boş kaldığı zaman yoktur.
Yani işlemci ve disk aynı anda darboğaza girdiğinde bekleme payı sorunun büyüklüğünü
küçümser.

**Takas hareketi** iki yönlü sayılır: belleğe geri okunan sayfa ve diske yazılan sayfa.
Ayrım önemlidir. Diske yazma tek başına baskı kanıtı değildir; işletim sistemi uzun süredir
dokunulmamış sayfaları rahatken de dışarı taşıyabilir. Baskının kanıtı, sayfaların
**geri okunmasıdır**: kullanılan bir sayfa dışarı atıldı ve hemen geri istendi. Yalnız takas
alanının dolu görünmesine bakan bir tanı, geçmişte olmuş ve bitmiş bir baskıyı şimdiki
zamanda arar.

#### Ölçülen Şey: Satır Sayısı mı, Ölçü Kümesi mi

Kurgunun varsayımları: on sekiz olay üretilir ve her olayın tek bir gerçek nedeni vardır
(**GN19**); üç ölçünün bantları nedenden türetilir (**GN20**); takas hareketi altmışın
üstüne çıktığında bellek baskısı girdi/çıktı beklemesi de üretir (**GN21**); görüntülerin
olay başına satır sayıları 24, 96, 24, 3 ve 3'tür (**GN22**); karar eşikleri işlemci için
60, bekleme için 25, takas için 20'dir (**GN23**).

Kâhin, kurguya yerleştirilen on sekiz olayın gerçek darboğaz nedenidir. Araç çıktısı, beş
görüntünün ürettiği satır sayısıdır. Tanı, her görüntünün kendi ölçülerinden çıkardığı
nedendir; yanlış tanı, gerçek nedenden farklı çıkan tanı sayısıdır.

```python
TOHUM = 20260218


def uretec(tohum):
    d = tohum

    def sonraki(n):
        nonlocal d
        d = (d * 1103515245 + 12345) % 2147483648
        return d % n
    return sonraki


NEDEN = ("islemci", "girdi-cikti", "bellek")


def darbogazlar(tohum=TOHUM, sayi=18):
    """GN19 KAHIN: her olayin tek gercek darbogazi. GN20: uc olcu nedenden
    turetiliyor. GN21: takas 60'i asinca bellek baskisi bekleme de uretir."""
    r = uretec(tohum)
    olay = []
    for i in range(sayi):
        n = NEDEN[r(3)]
        if n == "islemci":
            islemci, takas, bekleme = 78 + r(18), r(3), 2 + r(4)
        elif n == "girdi-cikti":
            islemci, takas, bekleme = 74 + r(20), r(3), 46 + r(28)
        else:
            islemci, takas = 52 + r(30), 34 + r(40)
            bekleme = 30 + r(20) if takas >= 60 else 6 + r(9)
        olay.append({"no": i + 1, "neden": n, "islemci": islemci,
                     "bekleme": bekleme, "takas": takas})
    return olay


def gorunum_a(o):
    """GN23 esikleri. Surec listesi , tek olcu: islemci yuzdesi."""
    return "islemci" if o["islemci"] >= 60 else "bellek"


def gorunum_c(o):
    """Ayni liste , bir sutun daha: bekleme."""
    if o["bekleme"] >= 25:
        return "girdi-cikti"
    return "islemci" if o["islemci"] >= 60 else "bellek"


def gorunum_d(o):
    """Uc sistem olcusu , bekleme once okunuyor."""
    if o["bekleme"] >= 25:
        return "girdi-cikti"
    return "bellek" if o["takas"] >= 20 else "islemci"


def gorunum_e(o):
    """Ayni uc olcu , takas once okunuyor."""
    if o["takas"] >= 20:
        return "bellek"
    return "girdi-cikti" if o["bekleme"] >= 25 else "islemci"


GORUNUM = (("A surec listesi", gorunum_a, 24),        # GN22: satir/olay
           ("B iplik ayrintisi", gorunum_a, 96),
           ("C A + bekleme sutunu", gorunum_c, 24),
           ("D uc sistem olcusu", gorunum_d, 3),
           ("E ayni uc olcu , takas once", gorunum_e, 3))

for tohum in (TOHUM, 20260219):
    O = darbogazlar(tohum)
    print("tohum", tohum, "| olay", len(O), "|",
          {n: sum(1 for o in O if o["neden"] == n) for n in NEDEN})
    print("  gorunum                       satir/olay  toplam satir  yanlis tani")
    for ad, f, satir in GORUNUM:
        y = sum(1 for o in O if f(o) != o["neden"])
        print(f"  {ad:28s} {satir:10d} {satir * len(O):13d} {y:12d}/{len(O)}")
```

```
tohum 20260218 | olay 18 | {'islemci': 4, 'girdi-cikti': 4, 'bellek': 10}
  gorunum                       satir/olay  toplam satir  yanlis tani
  A surec listesi                      24           432           12/18
  B iplik ayrintisi                    96          1728           12/18
  C A + bekleme sutunu                 24           432            8/18
  D uc sistem olcusu                    3            54            2/18
  E ayni uc olcu , takas once           3            54            0/18
tohum 20260219 | olay 18 | {'islemci': 7, 'girdi-cikti': 6, 'bellek': 5}
  gorunum                       satir/olay  toplam satir  yanlis tani
  A surec listesi                      24           432           11/18
  B iplik ayrintisi                    96          1728           11/18
  C A + bekleme sutunu                 24           432            5/18
  D uc sistem olcusu                    3            54            2/18
  E ayni uc olcu , takas once           3            54            0/18
```

#### Çıktının Söylediği ile Sistemin Gerçeği

Üç sayı yan yana durur. **Kâhin:** on sekiz olayın dördü işlemci, dördü girdi/çıktı, onu
bellek kaynaklıdır. **Araç çıktısı:** görüntüler sırasıyla 432, 1728, 432, 54 ve 54 satır
üretiyor. **Yanlış tanı:** 12, 12, 8, 2 ve 0.

Birinci satır ile ikinci satır karşılaştırıldığında iddia ödenmiş olur. B görüntüsü A'nın
tam **dört katı** satır üretiyor — 432 yerine 1728 — ve yanlış tanı sayısı **hiç
değişmiyor**: on ikide kalıyor. Ayrıntı düzeyini yükseltmek okunacak metni büyüttü, tanıyı
zerre kadar düzeltmedi. Sebep açıktır: iş parçacığı kırılımı aynı ölçünün daha ince
dilimlenmiş hâlidir ve bir ölçünün daha ince dilimlenmesi, o ölçünün göremediği şeyi
göremez.

Üçüncü satır ayrımı yapan şeyi gösterir. C görüntüsü B'nin dörtte biri kadar satır üretir —
A ile aynı, 432 — ama yanlış tanı 12'den **8'e** iner. Kazancı sağlayan şey satır sayısı
değil, listeye eklenen **tek bir sütundur**: bekleme payı. Dört yanlış tanının düzelmesi,
girdi/çıktı darboğazlarının işlemci darboğazından ayrılabilmesinden gelir.

Dördüncü satır bunu uca taşır. D görüntüsü **54 satır** üretir; B'nin otuz ikide biri.
Yanlış tanı **2'ye** iner. Süreç başına hiçbir ayrıntı taşımayan üç satır, süreç başına
doksan altı satır taşıyan görüntüden altı kat daha iyi tanı verir. Ölçünün adı budur:
**ayıran şey satır sayısı değil, hangi ölçüye bakıldığıdır.**

C ile D arasındaki fark ayrıca ölçeğin yerini gösterir. C süreç başına bakar ve "hangi
süreç" sorusunu yanıtlayabilir; D sistem geneline bakar ve o soruyu yanıtlayamaz. Yine de
D daha az yanılır, çünkü sorulan soru "hangi süreç" değil "hangi kaynak" sorusudur. İki
soru sık sık birbirine karıştırılır: yavaşlığın kaynağını bulmadan en çok kaynak tüketen
süreci aramak, çoğu zaman **kurbanı** bulmakla sonuçlanır. Bellek baskısı altındaki bir
makinede en çok bekleyen süreç, baskıyı yaratan süreç değildir; en çok etkilenendir.

Görüntü seçiminin bir de sıra sonucu vardır. Doğru sıralama önce sistem geneline, sonra
sürece bakmaktır: D "bellek" der, ardından süreç listesi belleğe göre sıralanır ve suçlu
aranır. Ters sıralama — önce süreç listesi, sonra sistem ölçüsü — ölçüde A satırıyla
temsil ediliyor ve on sekiz olayın on ikisinde yanlış yola sapıyor.

#### Kalan İki Yanılgı ve Okuma Sırası

Beşinci satır kalan payı ödüyor. E görüntüsü D ile **birebir aynı üç ölçüyü** taşır; tek
fark, hangisinin önce sorulduğudur. D bekleme payına önce bakar ve yüksek beklemeyi
gördüğünde "girdi/çıktı" der. E takas hareketine önce bakar ve yüksek takası gördüğünde
"bellek" der. Yanlış tanı D'de 2, E'de **0**.

Farkı üreten olaylar, takası altmışın üzerine çıkan bellek darboğazlarıdır. Orada takas
hareketinin kendisi disk işi yarattığı için bekleme payı da yükselir; iki ölçü aynı anda
yüksektir ve hangisinin önce okunduğu tanıyı belirler. Bekleme payı bir **sonuçtur**, takas
hareketi bir **nedendir**; sonucu önce okuyan sıralama nedeni gölgeler.

Buradan işletim tarafında bir kural çıkar: aynı anda yüksek okunan iki ölçü arasında
nedensel yön bilinmiyorsa, ölçü kümesini büyütmek yetmez. Yalnız üç sayıya bakan bir
operatör bile, yanlış sırayla bakarsa on sekiz olayın ikisinde yanılır. Ölçü kümesi
tanının **tavanını** belirler; okuma sırası o tavana ulaşıp ulaşılmayacağını belirler.

Sıralamanın hangi ölçüyle başlayacağına karar vermenin genel bir yolu vardır: zincirde
**en yukarıdaki** ölçü önce okunur. Takas hareketi bellek baskısının doğrudan sonucudur ve
başka bir nedenden doğmaz; bekleme payı ise hem disk yavaşlığından hem takastan hem de
sıradan bir toplu okumadan doğabilir. Birden çok nedeni olan bir ölçü, tek nedeni olan bir
ölçüden **sonra** okunur. Bu kural kurguya özgü değildir; birbirini besleyen göstergelerin
bulunduğu her ölçü kümesinde işler.

Karar ağacının bir maliyeti de vardır. Üç ölçüyü sabit bir sırayla okuyan bir yordam,
gerçekte iki darboğazın **aynı anda** bulunduğu durumu tek bir nedene indirger; ilk eşleşen
dalda durur ve ikinci nedeni hiç raporlamaz. Ölçüde bu görünmez, çünkü kurguda her olayın
tek bir gerçek nedeni vardır. Gerçek bir makinede tanının tek bir ada indirgenmesi, kendisi
bir yanlış tanı türüdür.

Ölçünün sınırı da açıkça yazılmalıdır. E'nin sıfırı kurgunun tam ayrılabilir olmasından
gelir; gerçek bir makinede üç ölçünün her olayı ayırması beklenmez. Anlamlı olan sıfır
değil, **12'den 0'a inen sıradır**: satır sayısını dört katına çıkarmak hiçbir şey
kazandırmadı, doğru ölçüyü eklemek dört yanılgı, ölçü kümesini daraltıp doğrultmak on
yanılgı, sıralamayı düzeltmek kalan iki yanılgıyı kaldırdı.

#### İkinci Tohum

İkinci tohumda olayların dağılımı değişir: yedi işlemci, altı girdi/çıktı, beş bellek. A ve
B görüntüleri yine **birbirinin aynı** sayıyı verir — on birer yanlış tanı — ve satır sayısı
farkı yine hiçbir şey değiştirmez. C **5'e**, D **2'ye**, E **0'a** iner. Mutlak sayılar
**kurguya bağlıdır**; kurguya bağlı olmayan şey, satır sayısını dört katına çıkarmanın
yanlış tanıyı hiç değiştirmemesi ve üç satırlık görüntünün doksan altı satırlık görüntüyü
her iki tohumda da geçmesidir.

#### Özet

- Üç darboğaz türü aynı belirtiyi üretir; bellek baskısı takas yüzünden girdi/çıktı
  beklemesi de yaratır ve disk darboğazı gibi görünür.
- Satır sayısını dört katına çıkarmak (432'den 1728'e) yanlış tanı sayısını **hiç
  değiştirmiyor**: her iki tohumda da aynı kalıyor.
- Listeye tek bir doğru sütun eklemek yanlış tanıyı 12'den **8'e**, süreç ayrıntısını atıp
  üç sistem ölçüsüne inmek **2'ye** indiriyor.
- Aynı üç ölçünün okunma sırasını değiştirmek kalan iki yanılgıyı da kaldırıyor; bekleme
  payı bir sonuçtur, takas hareketi bir nedendir.
- Tanıyı belirleyen şey çıktının hacmi değil, ölçü kümesi ve o kümenin okunma sırasıdır.

#### Sonraki Adım

Bu konu boyunca ölçülen şey, bir makinenin kendi hakkında ürettiği metnin ve sayının
gerçeği ne kadar taşıdığıydı: birim dosyasına bakan tanı altıda beş yanıldı, döndürme 86
hatanın 81'ini sildi, ortalanmış gösterge 54 saniyelik sıçramayı hiç göstermedi ve dört kat
çıktı hiçbir yanılgıyı düzeltmedi. Bütün bu ölçülerin sessiz varsayımı, verinin diske
yazılabildiğiydi. Sonraki konu o varsayımı kaldırır ve depolamaya iner: blok aygıtları,
bölümler, dosya sistemleri ve bir dosya sisteminin birbirinden bağımsız tükenen iki sınırı.
Orada disk yüzde bir dolu olduğu hâlde yazmanın başarısız olduğu durum sayıyla gösterilir.

## Depolama

Blok aygıtları ve bölümler, dosya sistemi aileleri, dosya düğümü tükenmesi, takma seçenekleri, mantıksal birim ve anlık görüntü, takas alanı ve disk genişletme.

### Blok Aygıtları ve Bölümler

Source: https://academia.sh/tr/kurslar/sistem-yonetimi/blok-aygitlari-ve-bolumler

Bölüm listesi bir harita değildir: aygıtta 3.702.784 boş sektör görünürken en büyük bitişik boşluk 2.881.536 sektördür ve listeden çıkarılan on iki yerleştirme kararının altısı yanlış çıkar.

Günlükler konusu bir darboğazın hangi göstergeden okunacağını ayırdı ve girdi/çıktı
beklemesini bir sayıya indirdi. O sayının altında bir aygıt duruyor ve bu konu oraya iniyor:
baytların gerçekten yazıldığı yere. Depolama, sistem yönetiminde arızanın en sessiz
göründüğü katmandır; bir sürecin durduğu görülür, bir servisin çalışmadığı görülür, ama bir
diskin dolduğu çoğu zaman ancak yazma başarısız olduğunda görülür.

İlk soru en alttakidir. Bir dosya sistemi aygıtın tamamına değil, aygıtın bir parçasına
kurulur; o parçanın nerede başlayıp nerede bittiğini küçük bir tablo söyler. Bu ders o
tabloyu okur ve tablonun **söylemediği** şeyi sayar.

#### Aygıt, Sektör ve Bölüm

**Blok aygıtı (block device)**, sabit boyutlu birimler hâlinde okunup yazılan bir depolama
birimidir. En küçük adreslenebilir birime **sektör** denir; aygıt, sıfırdan başlayarak
numaralanmış sektörlerin bir dizisidir ve bu dizinin dışında bir yapısı yoktur. İçindeki
düzenin tamamı, aygıtın ilk sektörlerinde duran bir veri yapısından okunur.

Sektörün iki boyutu vardır ve ikisi aynı olmak zorunda değildir. Aygıtın dışarıya
gösterdiği **mantıksal sektör** ile içeride gerçekten tek seferde okunup yazılan **fiziksel
sektör** ayrı sayılardır; yaygın kurulumda mantıksal sektör 512 bayt, fiziksel sektör 4096
bayttır. Yani aygıt 512 baytlık adresler kabul eder ama 512 bayt yazmak istendiğinde 4096
baytlık bir bloğu okuyup değiştirip geri yazar. Bu ayrım hizalama bölümünde sayılacak farkın
kaynağıdır ve bölümleme tablosunun hiçbir yerinde durmaz; aygıtın kendi bildirimidir.

O veri yapısı **bölümleme tablosudur (partition table)**. Tablo, her **bölüm (partition)**
için başlangıç sektörünü, bitiş sektörünü ve bir tür etiketini tutar. Tablonun tuttuğu şey
budur ve bundan fazlası değildir: bölümün içinde ne olduğunu, dolu mu boş mu olduğunu, hatta
içinde bir dosya sistemi bulunup bulunmadığını tablo bilmez. Bir bölüm, aygıtın gövdesine
çizilmiş bir aralıktan ibarettir.

İki tablo biçimi yaygındır. Eski biçim dört birincil bölümle sınırlıdır ve fazlasını ancak
bir bölümün içine iç içe girdiler koyarak taşır; sonraki biçim yüzlerce girdiye izin verir,
her bölüme değişmez bir kimlik verir ve tablonun bir kopyasını aygıtın sonunda tutar.
Aradaki fark bir üstünlük sıralaması değil, bir kapasite farkıdır ve hangisinin kullanıldığı
aygıtın kendisine bakılarak öğrenilir.

Bölümleri listeleyen araçlar okuma yapar ve tehlikesizdir: `lsblk` aygıt ağacını verir,
`blkid` bölümlerin kimliklerini ve tür etiketlerini yazar, `parted` sektör biriminde bir
tablo döker. Aşağıdaki döküm `parted` çıktısının biçimini gösteren bir **örnek dökümdür**;
çalıştırılmamıştır ve bu derste hiçbir sayı iddiası buradan gelmez.

```text
Model: kurgu blok aygiti
Disk /dev/sdb: 12582912s
Sector size (logical/physical): 512B/4096B
Partition Table: gpt

Number  Start     End       Size      File system  Name
 1      2048s     1048575s  1046528s  ext4         kok
 2      1048576s  3344383s  2295808s  ext4         veri
 3      3753984s  4636671s  882688s   ext4         gunluk
 4      4636672s  6383615s  1746944s  linux-swap   takas
```

Dökümde dikkat çeken şey, dördüncü satırın bittiği yer ile bir sonraki bölümün başladığı yer
arasındaki boşluğun **yazılmamış** olmasıdır. Araç bölümleri listeler; aralarda kalanı
listelemez.

#### Neden Bölümlenir

Bir aygıta tek bir dosya sistemi kurmak da bir seçenektir ve bölümleme onun karşısındaki
seçenektir. Ayrımın gerekçesi kapasite değil, **arızanın yayılmasını sınırlamaktır**.
Kurgu sunucuda günlük yazan birimler ile ölçüm dosyası üreten birimler aynı aygıtı
paylaşıyor; ikisi de aynı dosya sistemine yazarsa, günlük döndürme bir kez aksadığında
dolan alan yalnız günlükleri değil, kök dosya sistemini de doldurur ve sistem oturum
açamayacak duruma gelir. Ayrı bölüm, dolmayı kendi sınırının içinde tutar.

İkinci gerekçe farklı takma seçenekleridir: bir bölüm salt okunur, bir başkası program
çalıştırmaya kapalı takılabilir. Üçüncüsü, bir bölümün dosya sistemi türünün diğerinden
bağımsız seçilebilmesidir. Bedeli de vardır ve ölçülebilir: her bölümün boşluğu yalnız
kendisine yarar. Yukarıdaki yerleşimde günlük bölümü dolarken ayrılmış bölümde 1.320.960
sektörlük yer boş durabilir ve bu iki sayı birbirine aktarılamaz. Bölümleme, esneklikten
vazgeçip yalıtım satın alır; sonraki derslerden biri bu ödünleşmeyi gevşeten bir katmanı
ölçecek.

#### Bölüm Listesi Bir Harita Değildir

Bölüm listesinden boş alan hesaplamanın tek yolu çıkarma işlemidir: aygıtın sektör sayısından
bölümlerin toplamı düşülür. Bu işlem doğru bir toplam verir ve yanlış bir tanı üretir, çünkü
boş alan tek parça değildir.

- **DP1** — Kurgu aygıt **12.582.912 sektörlüktür**; bütün ölçüler sektör cinsindendir ve
  hiçbir gerçek aygıtın boyutu yazılmaz.
- **DP2** — Bölümler **2048 sektörlük** bir kata hizalanır. İlk 2048 sektör bölümleme
  tablosuna ayrılmıştır ve bölüm olarak kullanılamaz.
- **DP3** — Yerleşim, ortak tanımın üretecinden **20260218** tohumuyla üretilir; altı bölüm
  kurgu sunucunun kök, veri, günlük, takas, yedek ve ayrılmış alanlarını taşır.
- **DP4** — Araç çıktısı **bölüm listesidir**; boşluk haritası çıktıda yoktur. Tanı yalnız
  listeden kurulur.
- **DP5** — Bir yerleştirme kararı iki sorudan oluşur: istenen boyut **sığar mı** ve o
  boyuttan **kaç tane** sığar.

```python
"""M03/K03 depolama: kurgu blok aygitinin bolum yerlesimi ve bosluk haritasi."""
TOHUM = 20260218
HIZA = 2048                  # bolumler bu sektor katinda baslar
AYGIT = 12582912             # kurgu aygitin sektor sayisi
AD = ("kok", "veri", "gunluk", "takas", "yedek", "ayrilmis")


def uretec(tohum):
    d = tohum

    def sonraki(n):
        nonlocal d
        d = (d * 1103515245 + 12345) % 2147483648
        return d % n
    return sonraki


def yerlesim(tohum=TOHUM):
    """Kahin: bolumlerin gercek baslangici ve boyutu , sektor cinsinden."""
    r = uretec(tohum)
    b, imlec = [], HIZA
    for ad in AD:
        boyut = (r(900) + 300) * HIZA
        b.append({"ad": ad, "bas": imlec, "boyut": boyut})
        imlec += boyut + r(4) * 100 * HIZA
    return b


def bosluklar(b, aygit=AYGIT):
    """Kahin: bolumler arasinda ve sonda kalan BITISIK bos araliklar."""
    g, imlec = [], 0
    for x in sorted(b, key=lambda z: z["bas"]):
        if x["bas"] > imlec:
            g.append(x["bas"] - imlec)
        imlec = x["bas"] + x["boyut"]
    if imlec < aygit:
        g.append(aygit - imlec)
    return g


def tani(b, istek, aygit=AYGIT):
    """Arac ciktisi bolum LISTESIDIR. Listeden cikarilan tani: bos alan ,
    aygit eksi bolumlerin toplami."""
    g = bosluklar(b, aygit)
    toplam_bos = aygit - sum(x["boyut"] for x in b)
    yanlis, satir = 0, []
    for s in istek:
        arac_sigar, gercek_sigar = s <= toplam_bos, s <= max(g)
        arac_adet, gercek_adet = toplam_bos // s, sum(x // s for x in g)
        yanlis += (arac_sigar != gercek_sigar) + (arac_adet != gercek_adet)
        satir.append((s, arac_sigar, gercek_sigar, arac_adet, gercek_adet))
    return {"toplam_bos": toplam_bos, "en_buyuk": max(g), "bosluk": len(g),
            "satir": satir, "yanlis": yanlis}


B = yerlesim()
print("bolum      baslangic     boyut       bitis")
for x in B:
    print(f"  {x['ad']:9s} {x['bas']:9d} {x['boyut']:9d} {x['bas'] + x['boyut']:11d}")
print("kullanilan sektor:", sum(x["boyut"] for x in B), "| bos sektor:",
      AYGIT - sum(x["boyut"] for x in B))
print("bitisik bosluk sayisi:", len(bosluklar(B)), "| bosluklar:", bosluklar(B))
print()
ISTEK = (204800, 614400, 1228800, 2457600, 3072000, 3686400)
print("istenen  arac: sigar  gercek: sigar  arac: adet  gercek: adet")
for s, a, ge, aa, ga in tani(B, ISTEK)["satir"]:
    print(f"{s:7d}  {str(a):11s}  {str(ge):13s}  {aa:10d}  {ga:12d}")
print()
for tohum in (TOHUM, 20260219):
    t2 = tani(yerlesim(tohum), ISTEK)
    print(f"tohum {tohum}: bos {t2['toplam_bos']:8d}  en buyuk bitisik {t2['en_buyuk']:8d}"
          f"  bosluk {t2['bosluk']:2d}  yanlis tani {t2['yanlis']:2d} / 12")
```

```
bolum      baslangic     boyut       bitis
  kok            2048   1046528     1048576
  veri        1048576   2295808     3344384
  gunluk      3753984    882688     4636672
  takas       4636672   1746944     6383616
  yedek       6793216   1587200     8380416
  ayrilmis    8380416   1320960     9701376
kullanilan sektor: 8880128 | bos sektor: 3702784
bitisik bosluk sayisi: 4 | bosluklar: [2048, 409600, 409600, 2881536]

istenen  arac: sigar  gercek: sigar  arac: adet  gercek: adet
 204800  True         True                   18            18
 614400  True         True                    6             4
1228800  True         True                    3             2
2457600  True         True                    1             1
3072000  True         False                   1             0
3686400  True         False                   1             0

tohum 20260218: bos  3702784  en buyuk bitisik  2881536  bosluk  4  yanlis tani  6 / 12
tohum 20260219: bos  3633152  en buyuk bitisik  1787904  bosluk  7  yanlis tani  6 / 12
```

Üç sayı yan yana. **Kâhin:** boş alan dört parçadır — 2048, 409.600, 409.600 ve 2.881.536
sektör; en büyük bitişik boşluk **2.881.536 sektördür**. **Araç çıktısı:** bölüm listesi,
toplamı 8.880.128 sektör olan altı satır; buradan çıkarılan boş alan **3.702.784 sektör**.
**Yanlış tanı:** on iki karardan **altısı** yanlış.

Yanlışların dağılımı da öğreticidir. İki karar "sığar" derken sığmıyor: 3.072.000 ve
3.686.400 sektörlük bölümler toplam boş alanın altında kalıyor ama hiçbir bitişik aralığa
girmiyor. Dört karar ise adette yanılıyor: araç 614.400 sektörlük altı bölüm sığdığını
söylüyor, gerçekte dördü sığıyor. Toplam doğru, tanı yanlış.

İkinci tohumla üretilen yerleşimde boş alan 3.633.152 sektöre, en büyük bitişik boşluk
1.787.904 sektöre iniyor ve boşluk sayısı yediye çıkıyor; yanlış tanı yine **6**. Sayının
aynı kalması rastlantıdır, aynı büyüklük düzeninde kalması değil: boşluk sayısı arttıkça
toplamdan çıkarılan tanı bozulmaya devam ediyor.

#### Hizalama

Bölümün nerede başladığı, içine kurulacak dosya sisteminin başarımını belirler. Dosya
sistemi 4096 baytlık bloklarla çalışır ve bir blok sekiz sektördür; aygıtın kendi fiziksel
bloğu da sekiz sektördür ve sıfırdan itibaren sayılır. Bölüm sekizin katı olmayan bir
sektörde başlarsa, dosya sisteminin her bloğu iki fiziksel bloğa yayılır.

- **DP6** — Sıralı yazmada dokunulan fiziksel blok sayısı, hizasızlıkta yalnız bir artar;
  bloklar zaten peş peşedir.
- **DP7** — Rastgele tek blok yazmada hizasız bir blok iki fiziksel bloğa dokunur ve
  ikisinin de değişmeyen bölümü korunmak zorunda olduğu için önce okunup sonra yazılır: dört
  işlem.

```python
"""Hizalama: dosya sistemi blogu ile aygit blogu ayni sinira oturuyor mu."""
SEKTOR_BLOKTA = 8            # 4096 baytlik blok , 512 baytlik 8 sektor
BLOK_SAYISI = 512            # yazilan dosya sistemi blogu
BOLUM_BOYUTU = 1048576       # alti yerlesimde de ayni , sektor


def maliyet(bas, blok=BLOK_SAYISI, s=SEKTOR_BLOKTA):
    kayma = bas % s
    return {"hizali": kayma == 0,
            "sirali": blok + (1 if kayma else 0),
            "rastgele": blok * (4 if kayma else 1)}


print("baslangic  bolum boyutu  hizali  sirali islem  rastgele islem")
yanlis = 0
for bas in (63, 2048, 2049, 2052, 2056, 4096):
    m = maliyet(bas)
    yanlis += not m["hizali"]
    print(f"{bas:9d}  {BOLUM_BOYUTU:12d}  {str(m['hizali']):6s}"
          f"  {m['sirali']:12d}  {m['rastgele']:14d}")
print("arac ciktisindaki bolum boyutu alti yerlesimde de ayni:", BOLUM_BOYUTU)
print("bu boyuttan cikarilan 'ayni yerlesim' tanisi kac kez yanlis:", yanlis, "/ 6")
```

```
baslangic  bolum boyutu  hizali  sirali islem  rastgele islem
       63       1048576  False            513            2048
     2048       1048576  True             512             512
     2049       1048576  False            513            2048
     2052       1048576  False            513            2048
     2056       1048576  True             512             512
     4096       1048576  True             512             512
arac ciktisindaki bolum boyutu alti yerlesimde de ayni: 1048576
bu boyuttan cikarilan 'ayni yerlesim' tanisi kac kez yanlis: 3 / 6
```

Altı yerleşimin bölüm boyutu aynıdır ve araç çıktısında bu boyut görünür; başlangıç sektörü
de görünür ama okunmaz, çünkü bir sayının sekize bölünüp bölünmediği listeye bakılırken
sorulmaz. Sıralı yazmanın maliyeti hizasızlıkta 512'den 513'e çıkıyor, yani ölçülemez bir
fark; rastgele yazmanınki 512'den **2048'e** çıkıyor. Sıralı bir sınamayla verilen "fark yok"
tanısı, altı yerleşimin **üçünde** yanlıştır. Bu, kursun ikinci iddiasının depolamadaki
karşılığıdır: sınamayı çoğaltmak değil, doğru yükü sınamak ayırır.

Tablodaki 2056 satırı, hizalamanın 2048'e özgü olmadığını gösteriyor: sekizin katı olan her
başlangıç hizalıdır. Bölümleme araçlarının 2048 sektörü öntanımlı seçmesinin nedeni sekiz
değil, çok daha büyük iç birimlerle çalışan aygıtlarda da hizalı kalmaktır; 2048, olası iç
birim boylarının hepsine bölünen bir sayıdır. Araçlar bu kararı sessizce almaz, uyarı da
üretirler ve `lsblk` hizalama sapmasını ayrı bir sütunda yazar. Uyarı çıktıda durur; okunması
bir alışkanlık meselesidir ve okunmadığında ortaya çıkan fark, ölçüldüğü ana kadar hiçbir
yerde görünmez.

#### Bölümleme Tablosunu Değiştirmek

Tabloyu okuyan araçlar tehlikesizdir; yazan araçlar geri alınamaz. Bir bölümü silmek veya
sınırını değiştirmek, tablodaki başlangıç ve bitiş değerlerini üzerine yazar; bölümün
içindeki veri silinmez ama ona nasıl ulaşılacağı bilgisi kaybolur ve tablo yeniden
yazılmadan içerik erişilebilir hâle gelmez. Bu yüzden tablo yazan komutlar bu derste
**çalıştırılabilir tam biçimde verilmez**.

Değişiklik zorunluysa üç önlem ölçülebilir bir güvenlik sağlar. Birincisi, tablonun metin
biçiminde **dökümünü almaktır**; `sfdisk --dump` gibi bir okuma komutu tabloyu bir dosyaya
yazar ve aynı dosya geri yüklenerek eski yerleşim kurulabilir. İkincisi **kuru çalışmadır**:
tablo yazan araçların çoğu, değişikliği uygulamadan sonucu gösteren bir seçenek taşır ve bu
seçenek çalıştırılmadan önce çıktının okunması gerekir. Üçüncüsü, denemenin **ayrı bir
aygıtta** yapılmasıdır; bir dosyayı **geri döngü aygıtı (loop device)** olarak bağlamak, bölümleme
alıştırmasını gerçek veriden uzakta yapmayı sağlar.

Bir de sıralama kuralı vardır: tabloyu değiştiren bir komut döndüğünde çekirdek eski
yerleşimi bellekte tutuyor olabilir. Bu durumda `lsblk` yeni tabloyu gösterirken takılı
dosya sistemleri eski sınırlarla çalışmaya devam eder. Komutun dönmesi değişikliğin
geçtiği anlamına gelmez; bu, süreç yönetimi konusunda sinyaller için kurulan cümlenin
depolamadaki eşidir.

#### Özet

- Blok aygıtı numaralanmış sektörlerin bir dizisidir; içindeki düzenin tamamı, ilk
  sektörlerde duran bölümleme tablosundan okunur ve tablo yalnız başlangıç, bitiş ve tür
  bilgisini taşır.
- Bölüm listesinden çıkarılan boş alan bir toplamdır, harita değildir: 3.702.784 boş
  sektörün en büyük bitişik boşluğu 2.881.536 sektördür ve boş alan dört parçaya bölünmüştür.
- On iki yerleştirme kararının altısı yalnız listeye bakıldığında yanlış çıkıyor; ikisi
  sığmayanı sığar sanıyor, dördü sığan adedini fazla sayıyor. İkinci tohumda boşluk sayısı
  yediye çıkıyor ve yanlış tanı yine 6 oluyor.
- Bölüm başlangıcının sekiz sektörün katı olması sıralı yazmada 512 yerine 513 işlem
  farkı üretiyor, rastgele yazmada 512 yerine 2048; aynı bölüm boyutunu gösteren çıktıdan
  çıkarılan "fark yok" tanısı altı yerleşimin üçünde yanlış.
- Bölümleme tablosunu yazan komutlar geri alınamaz; ölçülebilir üç önlem tablonun dökümünü
  almak, kuru çalışma seçeneğini okumak ve denemeyi ayrı bir aygıtta yapmaktır.

#### Sonraki Adım

Bu ders bölümün içine hiç bakmadı: tablo için bir bölüm, başlangıcı ve bitişi olan bir
aralıktan ibaretti. Oysa o aralığa bir dosya sistemi kurulduğu anda, bir daha kolay
değiştirilemeyecek kararlar alınır — kaç dosya tutulabileceği, meta verinin ne kadar yer
kaplayacağı ve okunan verinin bozulmuşsa fark edilip edilmeyeceği. Sonraki ders dosya sistemi
ailelerinin bu kararları nasıl farklı verdiğini ölçer ve sağlama taşımayan bir
tasarımın bozuk veriyi kaç kez sessizce döndürdüğünü sayar.

### Dosya Sistemleri

Source: https://academia.sh/tr/kurslar/sistem-yonetimi/dosya-sistemleri

Aynı dosyaları taşıyan dizin üç iç düzende 449.985.000, 125.312 ve 59.800 karşılaştırmaya mal oluyor; sağlama taşımayan tasarımda bozuk bloğa dokunan 54 okumanın 54'ü hatasız dönüyor.

Önceki ders bölümü aygıtın gövdesine çizilmiş bir aralık olarak bıraktı: başlangıcı, bitişi
ve bir tür etiketi olan, içi hakkında hiçbir şey söylenmeyen bir parça. O aralığın içine bir
düzen kurulduğu anda birkaç karar alınır ve bu kararların çoğu sonradan değiştirilemez.

Bu dersin sorusu şudur: aynı bölümde, aynı dosyalarla, farklı tasarımlar hangi noktalarda
ayrışır. Ölçülecek iki eksen var — bir dizinde ad aramanın maliyeti ve bozulmuş bir bloğun
okuma sırasında fark edilip edilmediği. İkisi de sayılabilir ve ikisi de araç çıktısında
görünmez.

#### Bir Dosya Sistemi Ne Tutar

Bir **dosya sistemi (file system)** dört ayrı defteri aynı bölümün içinde tutar. Birincisi
**ad defteridir**: dizin girdileri, adı bir kimliğe bağlar. İkincisi **meta veri
defteridir**: her dosyanın boyutu, izinleri, sahibi, zaman damgaları ve içeriğinin hangi
bloklarda durduğu. Üçüncüsü **alan defteridir**: hangi blokların dolu, hangilerinin boş
olduğu. Dördüncüsü **tutarlılık defteridir**: bir güncelleme yarıda kalırsa diskteki
yapıların birbiriyle uyumlu kalmasını sağlayan kayıt.

Bu dört defterin nasıl tutulacağı tasarımdan tasarıma değişir ve fark buradan doğar.
Karşılaşılan aileler arasında XFS, Btrfs, ZFS ve genişletilmiş dosya sistemi ailesi
sayılabilir; bu ders adları değil, aralarındaki **eksenleri** ölçer. Eksenler dörttür: meta
veri defterinin boyutu biçimlendirme anında mı sabitlenir yoksa gerektikçe mi büyür; ad
defteri sıralı bir liste midir yoksa aranabilir bir yapı mıdır; alan defteri blok blok mu
yoksa bitişik aralıklar hâlinde mi tutulur; okunan bloğun bozulmadığı sınanır mı.

Hangi ailenin öntanımlı olarak kurulacağı dağıtıma göre değişir ve bu ders bir aileyi
diğerine üstün saymaz. Ölçülen şey seçimin **bedelidir**, sıralaması değil. Bir eksende ucuz
olan tasarım başka bir eksende pahalıdır ve hangi eksenin ağır bastığı iş yükünün kendisine
bağlıdır; iş yükü değiştiğinde karar da eskir, ama dosya sistemi yerinde durmaya devam eder.

Kurulmuş bir bölümün hangi tasarımı taşıdığı okunarak öğrenilir. `lsblk -f` her bölümün tür
etiketini ve kimliğini yazar, `blkid` aynı bilgiyi tek tek verir. Aşağıdaki döküm biçimi
gösteren bir **örnek dökümdür**; çalıştırılmamıştır ve bu derste hiçbir sayı iddiası buradan
gelmez.

```text
NAME   FSTYPE      FSVER  LABEL   UUID                       MOUNTPOINT
sdb
├─sdb1 ext4        1.0    kok     11111111-1111-1111-1111-1  /
├─sdb2 xfs                veri    22222222-2222-2222-2222-2  /veri
├─sdb3 ext4        1.0    gunluk  33333333-3333-3333-3333-3  /gunluk
└─sdb4 swap        1      takas   44444444-4444-4444-4444-4  [SWAP]
```

Dökümdeki kimlik alanı sonraki derslerde işe yarayacak: bir bölümün adı değişebilir, kimliği
değişmez.

#### Biçimlendirme Anında Sabitlenen Sayılar

Bir bölüme dosya sistemi kurmak, o bölümün başına bir üstbilgi yazıp defterlerin yerini
ayırmaktır. Bu işlem bir dizi sayıyı sabitler ve sabitlenenlerin çoğu sonradan
değiştirilemez ya da ancak dosya sistemi boşaltılarak değiştirilebilir.

Sabitlenen ilk sayı **blok boyudur**: dosya sisteminin ayırdığı en küçük birim. İkincisi
**meta veri kaydı sayısıdır**; sabit tablo tutan tasarımlarda bu sayı biçimlendirme anında
belirlenir ve dosya sistemi büyütülmedikçe artmaz. Üçüncüsü **dizinin iç düzenidir** ve
aşağıda ölçülüyor. Dördüncüsü **sağlamanın hangi defterleri kapsadığıdır**.
Beşincisi **tutarlılık kaydının kipidir**: yalnız meta veri mi günlüğe alınacak yoksa veri
de mi. İşletim Sistemi Kavramları kursundaki dosya sistemi soyutlaması dersi günlüklü
düzenin yazma çarpanını ölçmüştü; o ölçüm burada tekrarlanmaz.

Bir de alan defterinin biçimi vardır. Blok listesi tutan bir tasarımda her blok için bir
kayıt gerekir; bitişik aralık tutan bir tasarımda peş peşe uzanan yüz blok tek kayıttır.
İkincisi büyük ve parçalanmamış dosyalarda çok daha az meta veri üretir, parçalanma
arttıkça kazancı erir. Hangi biçimin seçileceği dosya boyu dağılımına bağlıdır ve bu
dağılım biçimlendirme anında bilinmez; karar tahminle verilir.

Yıkıcı komut sınırı burada başlıyor: bir bölümü biçimlendiren komut, o bölümdeki her şeyi
**geri alınamaz biçimde** siler ve yanlış bölüm adı yazılırsa uyarı vermeden çalışabilir.
Bu ders biçimlendirme komutunu çalıştırılabilir tam biçimde vermez. Güvenli sınama yolu,
bir dosyayı geri döngü aygıtı olarak bağlayıp denemeyi orada yapmaktır.

#### Aynı Dizin, Üç İç Düzen

Kurgu sunucunun `/veri` bölümünde ölçüm toplayıcı birimin ürettiği dosyalar tek bir dizinde
birikiyor. Dizin bir tablodur ve o tablonun iç düzeni bir tasarım kararıdır. İşletim Sistemi
Kavramları kursundaki dosya sistemi soyutlaması dersi bir dizini okumayı **tek adım** saymış
ve girdi sayısının adım sayısını değiştirmediğini varsaymıştı. Bu ders o varsayımın bedelini
ödüyor.

- **DP8** — Ölçülen iş yeni bir dosya oluşturmaktır. Her oluşturma önce bir **aramadır**:
  aynı ad dizinde var mı. Sayılan şey bu aramadaki karşılaştırmalardır.
- **DP9** — Sıralı liste düzeninde arama baştan sona gider. Karma tabanlı düzende ad bir
  kovaya düşer ve yalnız o kovadaki adlarla karşılaştırılır; kova sayısı **4096'dır** ve
  biçimlendirme anında sabitlenmiştir. Ağaç düzeninde bir dal **200 ad** taşır ve arama,
  ağacın derinliği kadar adımda biter.
- **DP10** — Karşılaştırma sayısı ölçülür; gerçek zaman ölçülmez.

```python
"""Dizin arama: ayni dosyalari tasiyan dizin , uc farkli ic duzen."""
KOVA = 4096          # karma tabanli dizindeki kova sayisi
DAL = 200            # B-agaci dugumunun tasidigi ad sayisi


def kurma_maliyeti(n, duzen):
    """Her yeni ad once ARANIR (var mi diye). Toplam karsilastirma."""
    if duzen == "dogrusal":
        return n * (n - 1) // 2
    if duzen == "karma":
        return sum(i // KOVA + 1 for i in range(n))
    derinlik, toplam = 1, 0
    for i in range(1, n + 1):
        if i > DAL ** derinlik:
            derinlik += 1
        toplam += derinlik
    return toplam


DUZEN = ("dogrusal", "karma", "agac")
OLCEK = (1000, 5000, 10000, 30000, 100000)
TABAN = {d: kurma_maliyeti(1000, d) for d in DUZEN}

print("dosya sayisi  ", "  ".join(f"{d:>12s}" for d in DUZEN))
for n in OLCEK:
    print(f"{n:12d}  ", "  ".join(f"{kurma_maliyeti(n, d):12d}" for d in DUZEN))
print()
print("1000 dosyadan dogrusal olceklenen tahmin ile gercek")
print("dosya sayisi  duzen         tahmin       gercek   sapma kat  yanlis tani")
yanlis = 0
for n in OLCEK:
    for d in DUZEN:
        tahmin = TABAN[d] * n // 1000
        gercek = kurma_maliyeti(n, d)
        kat = gercek / tahmin
        y = kat > 2
        yanlis += y
        print(f"{n:12d}  {d:10s} {tahmin:12d} {gercek:12d}  {kat:10.2f}  {str(y):>11s}")
print("yanlis tani:", yanlis, "/", len(OLCEK) * len(DUZEN))
```

```
dosya sayisi       dogrusal         karma          agac
        1000         499500          1000          1800
        5000       12497500          5904          9800
       10000       49995000         17712         19800
       30000      449985000        125312         59800
      100000     4999950000       1271200        259800

1000 dosyadan dogrusal olceklenen tahmin ile gercek
dosya sayisi  duzen         tahmin       gercek   sapma kat  yanlis tani
        1000  dogrusal         499500       499500        1.00        False
        1000  karma              1000         1000        1.00        False
        1000  agac               1800         1800        1.00        False
        5000  dogrusal        2497500     12497500        5.00         True
        5000  karma              5000         5904        1.18        False
        5000  agac               9000         9800        1.09        False
       10000  dogrusal        4995000     49995000       10.01         True
       10000  karma             10000        17712        1.77        False
       10000  agac              18000        19800        1.10        False
       30000  dogrusal       14985000    449985000       30.03         True
       30000  karma             30000       125312        4.18         True
       30000  agac              54000        59800        1.11        False
      100000  dogrusal       49950000   4999950000      100.10         True
      100000  karma            100000      1271200       12.71         True
      100000  agac             180000       259800        1.44        False
yanlis tani: 6 / 15
```

Üç sayı yan yana. **Kâhin:** 30.000 dosyayı tek dizinde oluşturmak sıralı listede
**449.985.000**, karma tabanlı düzende **125.312**, ağaç düzeninde **59.800**
karşılaştırmadır. **Araç çıktısı:** üç dizin de `ls` ile aynı 30.000 adı verir ve dizin
girdisi sayısı her üçünde eşittir; iç düzen çıktıda yoktur. **Yanlış tanı:** küçük bir
dizinde ölçüp doğrusal ölçekleyen tahmin, on beş durumun **altısında** iki katından fazla
sapıyor.

Tabloda üstünlük yok, eğri farkı var. Bin dosyada ağaç düzeni karma düzenden **pahalıdır**
(1800'e karşı 1000); yüz bin dosyada beş kat **ucuzdur**. Karma tabanlı düzenin de bir sınırı
görünüyor: kova sayısı biçimlendirme anında sabitlendiği için zincirler uzuyor ve 100.000
dosyada maliyet doğrusal tahminin 12,71 katına çıkıyor. Sabitlenen her sayı, ölçek büyüdükçe
ödenen bir borçtur.

#### Sağlama Toplamı Olan ve Olmayan Okuma

İkinci eksen okumanın doğruluğudur. Bir blok diskte kendiliğinden bozulabilir; yazıldığı gibi
kalmadığı hâlde aygıt onu hatasız döndürür. Tasarım bunu sınamıyorsa bozulma **sessizdir**:
uygulama yanlış baytı doğru sanır.

- **DP11** — Ortak tanımın `/veri` dosya sistemi 30.000 dosya taşır ve her dosya bir blok
  tutar. Dosya düğümü tablosu **2048 bloktur**; bir bloğa 16 dosya düğümü sığar.
- **DP12** — Bir dosyayı okumak iki bloğa dokunur: kendi veri bloğu ve dosya düğümünün
  bulunduğu tablo bloğu.
- **DP13** — **40 blok** bozulur; hangileri olduğu üreteçle seçilir. Sağlama taşıyan
  bir tasarım bozulmayı okuma anında yakalar, taşımayan yakalamaz.

```python
"""Saglama toplami: bozulan blok okuma sirasinda yakalaniyor mu."""
TOHUM = 20260218
BLOK = 4096
DOSYA = 30000                 # ortak tanimin /veri dosya sistemi
DUGUM_BLOKTA = 16             # 4096 baytlik bloga 16 dosya dugumu (256 bayt)
META = 2048                   # 32768 dugumluk tablo , blok cinsinden
BOZUK = 40


def uretec(tohum):
    d = tohum

    def sonraki(n):
        nonlocal d
        d = (d * 1103515245 + 12345) % 2147483648
        return d % n
    return sonraki


def bozulanlar(tohum=TOHUM, adet=BOZUK, veri=DOSYA, meta=META):
    """Kahin: hangi bloklar gercekten bozuldu. Ilk `veri` tanesi veri blogu."""
    r = uretec(tohum)
    return {r(veri + meta) for _ in range(adet)}


def okuma(tasarim, bozuk, veri=DOSYA):
    """Her dosya kendi veri blogunu ve dugum tablosundaki blogunu okur."""
    veri_saglama, meta_saglama = tasarim
    yakalanan = sessiz = 0
    for i in range(veri):
        vb = i in bozuk
        mb = (veri + i // DUGUM_BLOKTA) in bozuk
        if (vb and veri_saglama) or (mb and meta_saglama):
            yakalanan += 1
        elif vb or mb:
            sessiz += 1
    return {"yakalanan": yakalanan, "sessiz": sessiz}


TASARIM = {"saglama yok": (False, False), "meta saglamali": (False, True),
           "veri+meta saglamali": (True, True)}
B = bozulanlar()
print("bozulan blok:", len(B), "| veri blogu:", sum(1 for x in B if x < DOSYA),
      "| meta veri blogu:", sum(1 for x in B if x >= DOSYA))
print("kahin: bozuk bloga dokunan okuma:", okuma((True, True), B)["yakalanan"],
      "/", DOSYA)
print()
print("tasarim               hatayla donen  sessizce bozuk donen  yanlis tani")
for ad, t in TASARIM.items():
    o = okuma(t, B)
    print(f"  {ad:20s} {o['yakalanan']:13d}  {o['sessiz']:20d}  {o['sessiz']:11d}")
ek = -(-(DOSYA + META) * 4 // BLOK)
print("saglama toplami deposu:", ek, "blok |", round(ek / (DOSYA + META) * 100, 3),
      "yuzde")
print()
for tohum in (TOHUM, 20260219):
    b2 = bozulanlar(tohum)
    print(f"tohum {tohum}: saglamasiz sessiz {okuma((False, False), b2)['sessiz']:4d}"
          f"  meta saglamali {okuma((False, True), b2)['sessiz']:4d}"
          f"  tam saglamali {okuma((True, True), b2)['sessiz']:4d}")
```

```
bozulan blok: 40 | veri blogu: 38 | meta veri blogu: 2
kahin: bozuk bloga dokunan okuma: 54 / 30000

tasarim               hatayla donen  sessizce bozuk donen  yanlis tani
  saglama yok                      0                    54           54
  meta saglamali                  16                    38           38
  veri+meta saglamali             54                     0            0
saglama toplami deposu: 32 blok | 0.1 yuzde

tohum 20260218: saglamasiz sessiz   54  meta saglamali   38  tam saglamali    0
tohum 20260219: saglamasiz sessiz   70  meta saglamali   38  tam saglamali    0
```

Üç sayı yan yana. **Kâhin:** 40 blok bozuldu ve bunlara dokunan okuma sayısı **54'tür** —
38 dosya kendi veri bloğundan, 16 dosya iki bozuk tablo bloğundan etkileniyor. **Araç
çıktısı:** sağlama taşımayan tasarımda okuma çağrılarının hepsi **hatasız** dönüyor;
hiçbir araç bir şey bildirmiyor. **Yanlış tanı:** o tasarımda **54 okuma** bozuk baytı doğru
sanıyor; meta veri sağlaması eklendiğinde 38'e iniyor, veri de sağlandığında **sıfır** oluyor.

Bedeli tabloda: 32.048 bloğun sağlama 32 blok yer tutuyor, yani yüzde 0,1. Yer
maliyeti küçük, işlem maliyeti ise her okumaya eklenen bir hesaptır ve bu ders onu saymaz.
İkinci tohumda bozuk blok dağılımı değişiyor, sessiz okuma 54 yerine 70 çıkıyor; sıralama
değişmiyor. Sayının kendisi kurguya bağlı, **sıfırla arasındaki fark değil**.

Buradaki asıl sonuç şudur: sağlama olmayan bir tasarımda "hata yok" çıktısı, "veri
doğru" demek değildir. Bozulma ancak bir tutarlılık denetimi çalıştırıldığında ya da veri
kullanıldığında ortaya çıkar; ikisi de okumadan sonradır. Kursun üçüncü iddiası burada da
işliyor — geç bakan az görür.

Tutarlılık denetimi de bedava değildir ve ne yaptığına dikkat etmek gerekir. `fsck` sınıfı
araçlar defterleri baştan sona gezip birbirleriyle uyumlu olup olmadıklarına bakar; buldukları
uyumsuzluğu **onararak** çıkarlar ve onarım bazen bir dosyayı sahipsiz kayıtların toplandığı
bir dizine taşımak demektir. Bu iş takılı bir dosya sisteminde yapılamaz: araç çalışırken
dosya sistemi değişmemelidir, aksi hâlde araç kendi okuduğu defteri geçersiz kılar. Bu yüzden
takılı bir dosya sisteminde onarım komutu **çalıştırılabilir tam biçimde verilmez**; sınama,
dosya sistemi ayrıldıktan sonra ya da yalnız rapor üreten seçenekle yapılır.

Denetimin bulabildiği şeyin sınırı da vardır. Defterler arası uyumsuzluk bulunur; bir veri
bloğunun içeriğinin değişmiş olduğu bulunamaz, çünkü doğru içeriğin ne olduğunu söyleyen bir
kayıt yoktur. Tabloda sağlamanın satın aldığı şey tam olarak budur: doğru içeriğin ne
olduğunu bilmeye değil, **yanlış olduğunu anlamaya** yarayan 32 bloklu bir kayıt.

#### Özet

- Bir dosya sistemi ad defteri, meta veri defteri, alan defteri ve tutarlılık defterini aynı
  bölümde tutar; aileler arasındaki fark bu dört defterin nasıl tutulduğudur, bir üstünlük
  sıralaması değildir.
- 30.000 dosyayı tek dizinde oluşturmak sıralı listede 449.985.000, karma tabanlı düzende
  125.312, ağaç düzeninde 59.800 karşılaştırmadır; üç dizin de `ls` ile aynı listeyi verir.
- Küçük bir dizinde ölçüp doğrusal ölçekleyen tahmin on beş durumun altısında iki katından
  fazla sapıyor; karma düzende kova sayısının biçimlendirme anında sabitlenmesi 100.000
  dosyada tahmini 12,71 kat aşırıyor.
- Sağlama taşımayan tasarımda bozuk bloğa dokunan 54 okumanın 54'ü hatasız dönüyor;
  meta veri sağlamasıyla 38, veri sağlamasıyla 0 oluyor. Depolama bedeli 32 blok, yüzde 0,1.
- Biçimlendirme anında sabitlenen her sayı bir tavandır; bir sonraki ders o tavanlardan
  birine çarpmanın ne göründüğünü ölçer.

#### Sonraki Adım

Bu ders meta veri defterini bir tasarım ekseni olarak saydı ama içine bakmadı: bir dosyanın
adı dışındaki her şeyini taşıyan kaydın kendisi bir kaynaktır ve tükenebilir. Sonraki ders o
kaydı ölçer ve kursun en çarpıcı sayısını çıkarır — aynı dosya sisteminde blok doluluk
0,0125 iken yazma başarısız oluyor. Disk yüzde bir dolu ve sistem dolu; doluluk yüzdesine
bakan tanı burada kesinlikle yanılıyor.

### Dosya Düğümleri ve Meta Veri

Source: https://academia.sh/tr/kurslar/sistem-yonetimi/dosya-dugumleri-ve-meta-veri

Aynı dosya sisteminde blok doluluk 0,0125 iken dosya düğümü doluluğu 1,0000 ve yazma başarısız: disk yüzde bir dolu ve sistem dolu. Adı silinip tanıtıcısı açık kalan bir dosya 120.000 bloğu du çıktısından gizliyor.

Önceki ders meta veri defterini bir tasarım ekseni olarak saydı: sabit mi tutulur, gerektikçe
mi büyür. Bu ders o defterin içindeki tek kaydı alır ve onun bir **kaynak** olduğunu gösterir
— tükenebilen, tükendiğinde tuhaf bir arıza üreten bir kaynak.

Kurgu sunucunun `/veri` bölümü otuz bin ölçüm dosyası taşıyor ve bölümün doluluğu yüzde birin
biraz üzerinde. Bu ders o bölüme yeni bir dosya yazmayı deneyecek ve deneme başarısız
olacak. Aradaki çelişki bir hata değil, iki ayrı sınırın aynı hata iletisini üretmesidir.

#### Dosya Düğümünün Taşıdığı Kayıt

**Dosya düğümü (inode)**, bir dosyanın adı dışındaki her şeyini taşıyan kayıttır. İşletim
Sistemi Kavramları kursundaki dosya sistemi soyutlaması dersi bu kaydı tanımladı ve adın
dosyada değil dizinde durduğunu gösterdi; o tanım burada tekrarlanmaz. Eklenen tek şey
operatörün görebildikleridir.

Kayıt bir numarayla anılır ve o numara dosya sistemi içinde tekildir. `ls -i` numarayı
listeler, `stat` kaydın tamamını açar, `find` bir numaradan dosyanın adlarına geri gidebilir.
Kaydın alanları arasında en çok yanlış okunanı **bağ sayısıdır**: kaç dizin girdisi bu
kayda işaret ediyor. Bağ sayısı sıfıra düştüğünde ve kaydı açık tutan hiçbir süreç
kalmadığında blok listesi serbest bırakılır. İki koşul da gereklidir ve ikincisi bu dersin
ikinci ölçümünün konusudur.

Aşağıdaki döküm `stat` çıktısının biçimini gösteren bir **örnek dökümdür**; çalıştırılmamıştır
ve bu derste hiçbir sayı iddiası buradan gelmez.

```text
  File: /veri/olcum/2f9c.veri
  Size: 1731        Blocks: 8          IO Block: 4096   regular file
Device: 8,18        Inode: 1048604     Links: 1
Access: (0640/-rw-r-----)  Uid: (  997/  olcum)   Gid: (  997/  olcum)
```

Dökümde `Size` ile `Blocks` ayrı satırlarda durur ve ikisi ayrı şeyi söyler: birincisi
dosyanın bildirdiği bayt, ikincisi dosya sisteminin gerçekten ayırdığı yer. Bu ayrım ikinci
ölçümde altı yanlış okumanın kaynağı olacak.

#### İki Sınır, Tek Hata İletisi

Bir dosya sistemi iki ayrı kaynağı tüketir. Birincisi **bloktur**: içeriğin yazıldığı yer.
İkincisi **dosya düğümüdür**: her dosya için bir tane gerekir ve sabit tablo tutan
tasarımlarda toplam sayı biçimlendirme anında sabitlenmiştir. İkisinden biri bittiğinde yazma
aynı hata iletisiyle reddedilir.

- **DP14** — Ortak tanımın dosya sistemi **2.621.440 blok** ve **32.768 dosya düğümü**
  taşır; blok 4096 bayttır. Sayılar modeldendir, hiçbir gerçek aygıttan alınmamıştır.
- **DP15** — Küçük dosya iş yükünde boyutlar 1 ile 2000 bayt arasındadır; her dosya bir blok
  tutar. Büyük dosya iş yükünde üst sınır 2.000.000 bayttır.
- **DP16** — Uyarı kuralı doluluk **0,90** eşiğine bakar. Kural üç biçimde sınanır: yalnız
  blok yüzdesi, yalnız dosya düğümü yüzdesi, ikisi birlikte.
- **DP17** — Sınanan tanı tek sorudur: bu duruma yeni bir 1 KB dosya yazılabilir mi.

```python
"""M03/K03 ortak tanim (Bolum 6): iki ayri sinir , tek hata iletisi."""
TOHUM = 20260218
BLOK = 4096


def uretec(tohum):
    d = tohum

    def sonraki(n):
        nonlocal d
        d = (d * 1103515245 + 12345) % 2147483648
        return d % n
    return sonraki


def dosya_sistemi(tohum=TOHUM, dosya=30000, ust=2000,
                  dugum_sayisi=32768, blok_sayisi=2621440):
    r = uretec(tohum)
    boyutlar = [r(ust) + 1 for _ in range(dosya)]
    kullanilan_blok = sum(-(-b // BLOK) for b in boyutlar)
    return {"dosya": dosya, "kullanilan_blok": kullanilan_blok,
            "toplam_blok": blok_sayisi,
            "blok_doluluk": round(kullanilan_blok / blok_sayisi, 4),
            "kullanilan_dugum": dosya, "toplam_dugum": dugum_sayisi,
            "dugum_doluluk": round(dosya / dugum_sayisi, 4)}


def yazma_denemesi(fs, boyut):
    """Yeni dosya yazilabilir mi. Iki ayri sinir , tek hata iletisi."""
    blok_yeter = fs["kullanilan_blok"] + -(-boyut // BLOK) <= fs["toplam_blok"]
    dugum_yeter = fs["kullanilan_dugum"] + 1 <= fs["toplam_dugum"]
    return blok_yeter and dugum_yeter


for d in (30000, 32768):
    fs = dosya_sistemi(dosya=d)
    print(f"{d:6d} dosya | blok doluluk {fs['blok_doluluk']:.4f}"
          f" | dugum doluluk {fs['dugum_doluluk']:.4f}"
          f" | yeni 1 KB dosya: {yazma_denemesi(fs, 1024)}")
print()
KUCUK = [(d, 2000) for d in (4096, 12288, 20480, 28672, 32000, 32768)]
BUYUK = [(d, 2000000) for d in (2000, 4000, 6000, 8000, 10000, 12000)]
KURAL = {"yalniz blok yuzdesi": lambda f: f["blok_doluluk"] < 0.90,
         "yalniz dugum yuzdesi": lambda f: f["dugum_doluluk"] < 0.90,
         "ikisi birlikte": lambda f: f["blok_doluluk"] < 0.90
         and f["dugum_doluluk"] < 0.90}

print("is yuku  dosya  blok doluluk  dugum doluluk  yazilabilir")
for ad, yuk in (("kucuk", KUCUK), ("buyuk", BUYUK)):
    for d, ust in yuk:
        fs = dosya_sistemi(dosya=d, ust=ust)
        print(f"{ad:7s} {d:6d} {fs['blok_doluluk']:13.4f} {fs['dugum_doluluk']:14.4f}"
              f"  {yazma_denemesi(fs, 1024)}")
print()
print("kural                  kacirilan  yanlis uyari  yanlis tani")
for ad, k in KURAL.items():
    kacan = uyari = 0
    for _, yuk in (("kucuk", KUCUK), ("buyuk", BUYUK)):
        for d, ust in yuk:
            fs = dosya_sistemi(dosya=d, ust=ust)
            guvenli, gercek = k(fs), yazma_denemesi(fs, 1024)
            kacan += guvenli and not gercek
            uyari += (not guvenli) and gercek
    print(f"  {ad:20s} {kacan:9d}  {uyari:12d}  {kacan + uyari:11d}")
print()
for tohum in (TOHUM, 20260219):
    satir = []
    for ad, k in KURAL.items():
        y = 0
        for _, yuk in (("kucuk", KUCUK), ("buyuk", BUYUK)):
            for d, ust in yuk:
                fs = dosya_sistemi(tohum, d, ust)
                y += k(fs) != yazma_denemesi(fs, 1024)
        satir.append(f"{ad} {y}")
    print(f"tohum {tohum}: " + " | ".join(satir) + " / 12")
```

```
 30000 dosya | blok doluluk 0.0114 | dugum doluluk 0.9155 | yeni 1 KB dosya: True
 32768 dosya | blok doluluk 0.0125 | dugum doluluk 1.0000 | yeni 1 KB dosya: False

is yuku  dosya  blok doluluk  dugum doluluk  yazilabilir
kucuk     4096        0.0016         0.1250  True
kucuk    12288        0.0047         0.3750  True
kucuk    20480        0.0078         0.6250  True
kucuk    28672        0.0109         0.8750  True
kucuk    32000        0.0122         0.9766  True
kucuk    32768        0.0125         1.0000  False
buyuk     2000        0.1894         0.0610  True
buyuk     4000        0.3693         0.1221  True
buyuk     6000        0.5553         0.1831  True
buyuk     8000        0.7416         0.2441  True
buyuk    10000        0.9283         0.3052  True
buyuk    12000        1.1168         0.3662  False

kural                  kacirilan  yanlis uyari  yanlis tani
  yalniz blok yuzdesi          1             1            2
  yalniz dugum yuzdesi         1             1            2
  ikisi birlikte               0             2            2

tohum 20260218: yalniz blok yuzdesi 2 | yalniz dugum yuzdesi 2 | ikisi birlikte 2 / 12
tohum 20260219: yalniz blok yuzdesi 2 | yalniz dugum yuzdesi 2 | ikisi birlikte 2 / 12
```

Üç sayı yan yana. **Kâhin:** 32.768 dosyalı durumda dosya düğümü tablosu tamamen doludur ve
bloğun yüzde 98,75'i boştur; yazma **başarısızdır**. **Araç çıktısı:** doluluk sorulduğunda
gelen sayı **0,0125'tir** — yüzde bir. **Yanlış tanı:** on iki durumun **ikisinde** uyarı
kuralı yanılıyor ve bu iki yanlış, kural değiştirilerek yok edilmiyor.

Ortak tanımın iki satırı kursun en temiz örneğidir. Otuz bin dosyada blok doluluk **0,0114**,
dosya düğümü doluluğu **0,9155** ve yazma başarılı; 32.768 dosyada blok doluluk **0,0125**,
dosya düğümü doluluğu **1,0000** ve yazma başarısız. Aradaki fark 2768 dosyadır ve toplam
alanın binde biridir. **Disk yüzde bir dolu ve sistem dolu.**

Kural tablosu ikinci iddiayı ödüyor. Yalnız blok yüzdesine bakan kural bir arızayı kaçırıyor
ve bir kez yersiz uyarı veriyor. Yalnız dosya düğümü yüzdesine bakan kural da aynı sayıyı
veriyor — büyük dosya iş yükünde blok dolarken dosya düğümü yüzdesi 0,3662'de kalıyor. İkisi
birlikte kullanıldığında kaçırılan sıfıra iniyor, ama yersiz uyarı ikiye çıkıyor ve toplam
yine **2**. Sütun eklemek yanlış tanının **türünü** değiştirdi, sayısını değil. İkinci tohumda
üç kuralın üçü de yine 2 veriyor; sonuç kurguya değil, iki sınırın birbirinden bağımsız
oluşuna bağlı.

#### Adı Olmayan Dosya

İkinci ölçüm aynı dosya sisteminde ayrılan alanı üç ayrı yöntemle sayıyor. `df` dosya
sisteminin kendi defterini okur, `du` dizin ağacını gezip bulduğu dosyaların bloklarını
toplar, dosya listesinden elde edilen toplam ise bildirilen baytları toplar. Üçü de aynı
soruya cevap veriyor ve üçü aynı sayıyı vermiyor.

- **DP18** — Beş an sırayla geçilir: başlangıç, aynı dosyalara 200 ikinci ad verilmesi,
  40 seyrek dosyanın yazılması, 120.000 bloklu günlük dosyasının silinmesi ve o dosyayı açık
  tutan tanıtıcının kapanması.
- **DP19** — Aynı dosya düğümüne verilen ikinci ada **sabit bağ (hard link)** denir. **Seyrek
  dosya (sparse file)** 25.600 blokluk boyut bildirir, gerçekte 8 blok ayırır. Meta verinin
  kendi tuttuğu yer bu ölçümde sayılmaz; kâhin yalnız veri bloklarıdır.

```python
"""Ayrilan blok gercekte kac , hangi arac kacini goruyor."""
TOHUM = 20260218
BLOK = 4096
DOSYA = 30000
SEYREK = 40               # seyrek dosya sayisi
SEYREK_MANTIKSAL = 25600  # blok cinsinden bildirilen boyut
SEYREK_AYRILAN = 8        # gercekte ayrilan blok
GUNLUK_BLOK = 120000      # buyuk gunluk dosyasi
SERT_BAG = 200            # ayni dosyaya verilen ikinci adlar


def uretec(tohum):
    d = tohum

    def sonraki(n):
        nonlocal d
        d = (d * 1103515245 + 12345) % 2147483648
        return d % n
    return sonraki


def taban(tohum=TOHUM):
    r = uretec(tohum)
    return [r(2000) + 1 for _ in range(DOSYA)]


def durum(an, bayt):
    """an 0..4 . Kahin: dosya sisteminin gercekten ayirdigi veri blogu."""
    seyrek = an >= 2
    gunluk_var = an < 4                      # an 3'te silindi , tanitici acik
    ayrilan = DOSYA + GUNLUK_BLOK * gunluk_var + SEYREK * SEYREK_AYRILAN * seyrek
    # du: yalniz ADI OLAN dosyalari gezer , sert bagi bir kez sayar
    du = DOSYA + GUNLUK_BLOK * (an < 3) + SEYREK * SEYREK_AYRILAN * seyrek
    # dosya listesi toplami: bildirilen bayt , her ADI ayri sayar
    ls = sum(bayt) + sum(bayt[:SERT_BAG]) * (an >= 1)
    ls += GUNLUK_BLOK * BLOK * (an < 3)
    ls += SEYREK * SEYREK_MANTIKSAL * BLOK * seyrek
    return {"kahin": ayrilan, "df": ayrilan, "du": du, "ls": ls // BLOK}


AN = ("t0 baslangic", "t1 sert bag", "t2 seyrek dosya",
      "t3 gunluk silindi", "t4 tanitici kapandi")
BAYT = taban()
print("an                   kahin       df       du       ls toplami")
for i, ad in enumerate(AN):
    d = durum(i, BAYT)
    print(f"{ad:18s} {d['kahin']:8d} {d['df']:8d} {d['du']:8d} {d['ls']:15d}")
print()
print("arac        dogru okuma  yanlis okuma")
for arac in ("df", "du", "ls"):
    yanlis = sum(durum(i, BAYT)[arac] != durum(i, BAYT)["kahin"] for i in range(5))
    print(f"  {arac:9s} {5 - yanlis:11d}  {yanlis:12d}")
print("yanlis tani:", sum(durum(i, BAYT)[a] != durum(i, BAYT)["kahin"]
                          for i in range(5) for a in ("df", "du", "ls")), "/ 15")
print()
for tohum in (TOHUM, 20260219):
    b = taban(tohum)
    print(f"tohum {tohum}: t0 kahin {durum(0, b)['kahin']} ls {durum(0, b)['ls']}"
          f" | t3 kahin {durum(3, b)['kahin']} du {durum(3, b)['du']}"
          f" | t4 kahin {durum(4, b)['kahin']} ls {durum(4, b)['ls']}")
```

```
an                   kahin       df       du       ls toplami
t0 baslangic         150000   150000   150000          127313
t1 sert bag          150000   150000   150000          127361
t2 seyrek dosya      150320   150320   150320         1151361
t3 gunluk silindi    150320   150320    30320         1031361
t4 tanitici kapandi    30320    30320    30320         1031361

arac        dogru okuma  yanlis okuma
  df                  5             0
  du                  4             1
  ls                  0             5
yanlis tani: 6 / 15

tohum 20260218: t0 kahin 150000 ls 127313 | t3 kahin 150320 du 30320 | t4 kahin 30320 ls 1031361
tohum 20260219: t0 kahin 150000 ls 127292 | t3 kahin 150320 du 30320 | t4 kahin 30320 ls 1031339
```

Üç sayı yan yana. **Kâhin:** üçüncü anda gerçekten ayrılmış olan **150.320 bloktur**. **Araç
çıktısı:** `du` aynı anda **30.320** blok görüyor. **Yanlış tanı:** on beş okumanın **altısı**
yanlış — beşi dosya listesi toplamından, biri `du` çıktısından.

Üçüncü an operatörün en sık düştüğü tuzaktır. Günlük dosyası silinmiştir, `du` çıktısı 120.000
blok azalmıştır ve dizin ağacında o dosya yoktur; ama onu açık tutan süreç hâlâ çalıştığı için
bağ sayısı sıfıra düşmüş olsa bile bloklar serbest bırakılmamıştır. `df` doğruyu söylemeye
devam eder ve iki araç arasındaki **120.000 bloklu** fark açıklanmadıkça yer açma girişimi
sonuçsuz kalır. Çözüm silmek değil, dosyayı açık tutan süreci yeniden başlatmaktır; hangi
sürecin tuttuğu ise açık tanıtıcıları listeleyen bir araçla bulunur.

Dosya listesi toplamı beş anın beşinde de yanılıyor ve iki ayrı yönde yanılıyor. Başlangıçta
**eksik** sayıyor: otuz bin küçük dosyanın bildirdiği bayt toplamı 127.313 blok karşılığıdır,
gerçekte 150.000 blok ayrılmıştır çünkü 1731 baytlık bir dosya da tam bir blok tutar. Seyrek
dosyalar yazıldıktan sonra **fazla** sayıyor: 40 dosya 1.024.000 blokluk boyut bildiriyor,
gerçekte 320 blok tutuyor. İkinci tohumda bu iki sayı 127.292 ve 1.031.339 oluyor; yön
değişmiyor.

#### Tükenmiş Tabloyu Onarmak

Dosya düğümü tükendiğinde yapılabilecek üç şey vardır ve üçünün de bir bedeli vardır.
Birincisi **dosya silmektir**; bu, tablodaki kaydı geri verir ve tek satırlık ölçüm
dosyalarının bir arşive toplanması genellikle en hızlı çözümdür. İkincisi dosya sistemini
**büyütmektir**; sabit tablo tutan tasarımlarda büyütme tabloyu da genişletebilir, ama
oranı biçimlendirme anındaki karara bağlıdır. Üçüncüsü **yeniden biçimlendirmektir** ve bu,
bölümdeki her şeyi geri alınamaz biçimde siler.

Üçüncü yol bu derste çalıştırılabilir tam biçimde verilmez. Biçimlendirme komutu, dosya
düğümü sayısını belirleyen seçeneğiyle birlikte yazıldığında yanlış bir bölüm adıyla
çalıştırılırsa uyarı üretmeden bütün veriyi siler ve geri alınamaz. Güvenli sınama yolu
üç adımdır: hedef bölümün kimliğini `blkid` ile doğrulamak, denemeyi geri döngü aygıtı
olarak bağlanmış bir dosyada yapmak ve gerçek bölümde çalıştırmadan önce bölümün bir anlık
görüntüsünü almak.

Önlemin kendisi ise ölçmektir. Dosya düğümü doluluğu, blok doluluğuyla aynı sıklıkta
sorulmadığı sürece tablonun dolduğu an bir uyarıya değil, bir arızaya dönüşür; ve arıza
geldiğinde çıktıdaki tek sayı hâlâ yüzde bir olacaktır.

#### Özet

- Dosya düğümü, bir dosyanın adı dışındaki her şeyini taşıyan kayıttır; bağ sayısı sıfıra
  düşmesi tek başına yer boşaltmaz, kaydı açık tutan süreç de kalmamalıdır.
- Bir dosya sistemi iki ayrı kaynağı tüketir ve ikisi de aynı hata iletisini üretir: 30.000
  dosyada blok doluluk 0,0114 ve dosya düğümü doluluğu 0,9155 iken yazma başarılı, 32.768
  dosyada 0,0125 ve 1,0000 iken başarısız.
- Uyarı kuralı yalnız blok yüzdesine baktığında on iki durumda 2 yanlış tanı veriyor; yalnız
  dosya düğümü yüzdesine baktığında da 2, ikisi birlikte kullanıldığında da 2. Kaçırılan
  sıfıra iniyor, yersiz uyarı ikiye çıkıyor.
- Ayrılan alan üç yöntemle sayıldığında on beş okumanın altısı yanlış: dosya listesi toplamı
  beş anın beşinde yanılıyor, `du` ise adı silinip tanıtıcısı açık kalan 120.000 bloğu
  göremiyor.
- Tükenmiş tabloyu onarmanın üç yolundan biri yeniden biçimlendirmedir ve geri alınamaz;
  bu ders o komutu tam biçimde vermez, güvenli sınama yolu kimlik doğrulaması, geri döngü
  aygıtı ve anlık görüntüdür.

#### Sonraki Adım

Bu dersin ölçümleri tek bir varsayıma dayanıyordu: bakılan dizin gerçekten o dosya sisteminin
dizini. Oysa bir dosya sistemi ağaçta bir noktaya **takılır** ve o nokta takma öncesinde de
sonrasında da yazılabilir bir dizindir. Sonraki ders takma noktasını ölçer ve bir dosya
sistemi takılmadan önce oraya yazılan verinin nereye gittiğini, takıldıktan sonra hangi
araçların onu göremediğini sayar.

### Takma ve Kalıcı Takma

Source: https://academia.sh/tr/kurslar/sistem-yonetimi/takma-ve-kalici-takma

Aygıt adına yazılmış bir kalıcı takma girdisi altmış önyüklemenin yalnız on üçünde doğru dosya sistemini takıyor ve yirmi yedisinde sessizce yanlışını takıyor; erişim zamanını güncellemeyen bir takma seçeneği temizlik görevine 787 dosyayı yanlışlıkla sildiriyor.

Önceki ders bir dosya sisteminin iki sınırını ayırdı ve bütün ölçümlerini tek bir varsayımın
üzerine kurdu: bakılan dizin gerçekten o dosya sisteminin dizini. Bu varsayım bedava değildir.
Bir dosya sistemi ağaçta bir noktaya **takılır** ve o nokta takmadan önce de sonra da yazılabilir
bir dizindir.

Bu ders takmanın kendisini ve önyüklemede otomatik takmayı ölçer. İki sayı çıkacak: bir kalıcı
takma girdisinin kaç önyüklemede yanlış dosya sistemini takabileceği ve tek bir takma
seçeneğinin bir bakım görevine kaç dosyayı yanlışlıkla sildirebileceği. İkisi de hata iletisi
üretmez.

#### Takma Bir Ekleme İşlemidir

Bu sistemde her dosya sistemi ayrı bir harf altında değil, **tek bir ağacın** bir dalında
durur. **Takma (mount)**, bir blok aygıtındaki dosya sistemini bu ağacın bir noktasına
bağlamaktır; o noktaya **takma noktası (mount point)** denir ve takma noktası her zaman var
olan bir dizindir.

Takma çekirdekteki bir tabloya girdi ekler; aygıtta hiçbir şey değişmez. Aynı aygıt birden
çok noktaya takılabilir, bir nokta üst üste iki kez takılabilir ve takmayı kaldırmak veriyi
etkilemez. Takılı olanlar `findmnt` ile ağaç biçiminde, `mount` ile düz liste hâlinde
okunur. Aşağıdaki döküm `findmnt` çıktısının biçimini gösteren bir **örnek dökümdür**;
çalıştırılmamıştır ve bu derste hiçbir sayı iddiası buradan gelmez.

```text
TARGET   SOURCE    FSTYPE  OPTIONS
/        /dev/sdb1 ext4    rw,relatime
├─/veri  /dev/sdb2 xfs     rw,noatime,nodev
└─/gunluk
         /dev/sdb3 ext4    rw,relatime,noexec,nosuid
```

Takma noktasının takmadan önceki içeriği, dersin ilk tuzağıdır. `/veri` dizini boş olmak
zorunda değildir; içinde dosya varsa, aygıt oraya takıldığı anda o dosyalar **görünmez olur**.
Silinmezler, taşınmazlar ve altta kalan dosya sisteminde yer tutmaya devam ederler; yalnız
adlarına ulaşılamaz. Bunun en sık görülen biçimi şudur: bir birim, aygıt henüz takılmadan
çalışmaya başlar ve çıktısını takma noktasına yazar; aygıt sonradan takılır ve o veri kök
dosya sisteminin içinde gömülü kalır. `du` takma noktasını gezdiğinde onu göremez, çünkü artık
ağaçta yoktur; `df` kök dosya sisteminde açıklanamayan bir doluluk gösterir. İki çıktı arasındaki
bu fark, önceki dersteki adı silinmiş dosyanın ikizidir: ikisinde de görünen doluluk gerçek
tüketimi açıklamaz. Ama bulma yolu ayrıdır — burada takmayı geçici olarak kaldırıp aynı
dizine yeniden bakmak yeter.

#### Kalıcı Takma ve Aygıt Adı

Elle yapılan takma yeniden başlatmada kaybolur. Önyüklemede otomatik takma, aygıtı takma
noktasına, dosya sistemi türüne ve seçenek listesine bağlayan bir **kalıcı takma (persistent
mount)** girdisiyle tanımlanır. Girdinin ilk alanı aygıtı adlandırır ve bu alanın nasıl
yazıldığı bu bölümün ölçüsüdür.

Aygıt adları keşif sırasına göre verilir. Bir denetleyici diğerinden önce yanıt verirse adlar
yer değiştirir; bir aygıt eklendiğinde ya da arızalandığında sıra tümüyle kayar. Aygıtın
**kimliği** ise dosya sistemi kurulurken yazılır ve aygıt nereye takılırsa takılsın değişmez.

- **DP20** — Kurgu sunucuda **beş blok aygıtı** vardır; üçü aynı türde veri dosya sistemi,
  biri takas alanı, biri farklı türde bir dosya sistemi taşır.
- **DP21** — Her önyüklemede keşif sırası değişebilir; sıra ortak tanımın üretecinden
  çekilir ve adlar bu sıraya göre dağıtılır. **60 önyükleme** gözlenir.
- **DP22** — `/veri` girdisi `aygit-b` adına yazılmıştır ve tür alanı veri dosya sistemidir.
  Girdi doğru kimliği taktığında **doğru**, başka bir aygıtı aynı türde olduğu için sorunsuz
  taktığında **sessiz yanlış**, tür uyuşmadığı için başarısız olduğunda **gürültülü hata**
  sayılır.

```python
"""Onyuklemede aygit adi ile aygit kimligi ayni sey degil."""
TOHUM = 20260218
ONYUKLEME = 60           # gozlenen onyukleme sayisi
AYGIT = ({"kimlik": "k1", "tur": "ext4", "icerik": "kok"},
         {"kimlik": "k2", "tur": "ext4", "icerik": "veri"},
         {"kimlik": "k3", "tur": "ext4", "icerik": "gunluk"},
         {"kimlik": "k4", "tur": "swap", "icerik": "takas"},
         {"kimlik": "k5", "tur": "xfs",  "icerik": "yedek"})
AD = ("aygit-a", "aygit-b", "aygit-c", "aygit-d", "aygit-e")
KAYIT = {"ad": "aygit-b", "kimlik": "k2", "tur": "ext4"}   # /veri girdisi


def uretec(tohum):
    d = tohum

    def sonraki(n):
        nonlocal d
        d = (d * 1103515245 + 12345) % 2147483648
        return d % n
    return sonraki


def kesif_sirasi(r):
    """Aygitlar bulunma sirasina gore adlandirilir; sira degisebilir."""
    kalan, sira = list(AYGIT), []
    while kalan:
        sira.append(kalan.pop(r(len(kalan))))
    return sira


def onyukle(tohum=TOHUM, sayi=ONYUKLEME):
    r = uretec(tohum)
    ada_gore = {"dogru": 0, "sessiz_yanlis": 0, "gurultulu_hata": 0}
    kimlige_gore = {"dogru": 0, "sessiz_yanlis": 0, "gurultulu_hata": 0}
    for _ in range(sayi):
        secilen = dict(zip(AD, kesif_sirasi(r)))[KAYIT["ad"]]
        if secilen["kimlik"] == KAYIT["kimlik"]:
            ada_gore["dogru"] += 1
        elif secilen["tur"] == KAYIT["tur"]:
            ada_gore["sessiz_yanlis"] += 1
        else:
            ada_gore["gurultulu_hata"] += 1
        kimlige_gore["dogru"] += 1
    return ada_gore, kimlige_gore


A, K = onyukle()
print("kayit bicimi   dogru  sessiz yanlis  gurultulu hata  yanlis tani")
for ad, s in (("aygit adi", A), ("aygit kimligi", K)):
    print(f"  {ad:12s} {s['dogru']:6d}  {s['sessiz_yanlis']:13d}"
          f"  {s['gurultulu_hata']:14d}  {s['sessiz_yanlis']:11d}")
print("onyukleme sayisi:", ONYUKLEME)
print()
for tohum in (TOHUM, 20260219):
    a, _ = onyukle(tohum)
    print(f"tohum {tohum}: dogru {a['dogru']:3d}  sessiz yanlis"
          f" {a['sessiz_yanlis']:3d}  gurultulu hata {a['gurultulu_hata']:3d}")
```

```
kayit bicimi   dogru  sessiz yanlis  gurultulu hata  yanlis tani
  aygit adi        13             27              20           27
  aygit kimligi     60              0               0            0
onyukleme sayisi: 60

tohum 20260218: dogru  13  sessiz yanlis  27  gurultulu hata  20
tohum 20260219: dogru  10  sessiz yanlis  27  gurultulu hata  23
```

Üç sayı yan yana. **Kâhin:** `/veri` noktasına takılması gereken dosya sistemi her önyüklemede
aynı kimliktir. **Araç çıktısı:** takma tablosu her önyüklemede `/veri` için bir kaynak
gösterir ve gösterdiği ad **her seferinde `aygit-b`'dir**; tabloya bakan biri hiçbir fark
görmez. **Yanlış tanı:** altmış önyüklemenin **yirmi yedisinde** yanlış dosya sistemi hatasız
takılıyor.

Yirmi hatalı önyükleme aslında iyi haberdir: tür uyuşmadığı için takma başarısız olur, arıza
görülür ve düzeltilir. Tehlikeli olan yirmi yedi sessiz durumdur — birim çalışır, veri
yazılır, hiçbir günlük satırı üretilmez ve yazılan veri beklenen yerde durmaz. Kimliğe
yazılmış girdide bu sayı **sıfırdır**; ikinci tohumda doğru önyükleme 13 yerine 10 çıkıyor,
sessiz yanlış yine 27. Kimliğe yazmanın kazandırdığı şey bir başarım değil, bir **belirlilik**.

Kimlik yazmanın da bir maliyeti vardır ve saklanmaz: kimlik okunaksızdır, elle yazılması
hataya açıktır ve aygıt yeniden biçimlendirildiğinde değişir. Bu yüzden girdiler çoğunlukla
elle değil, aygıttan okunarak üretilir. Bir ara yol, dosya sistemine kurulurken verilen
etikettir; etiket okunabilir bir addır ve aygıt adı gibi keşif sırasına bağlı değildir,
ama iki aygıta aynı etiket verilirse belirlilik yine kaybolur.

Girdinin son alanları da tanıyı etkiler. Bir girdi başarısız olduğunda önyükleme durabilir ve
makine yalnız kurtarma kabuğuna açılır; bunu engelleyen seçenek arızayı görünmez kılar ve
sistem eksik dosya sistemiyle çalışmaya devam eder. İkisi arasındaki seçim bir tercihtir:
gürültülü durmak mı, sessiz eksik çalışmak mı.

#### Sessizce Anlam Değiştiren Seçenek

Seçenek listesi takmanın en az okunan alanıdır. Bir bölümü salt okunur takmak ya da program
çalıştırmaya kapatmak **gürültülü** sonuçlar üretir: yazma reddedilir, çalıştırma reddedilir,
hata iletisi görünür. Erişim zamanını güncellemeyen seçenek ise hiçbir şey reddetmez; yalnız
kaydedilen bir sayıyı dondurur.

- **DP23** — `/veri` bölümünde **2000 dosya** vardır; oluşturma, son yazma ve son okuma anları
  600 saniyelik pencerede üreteçten çekilir.
- **DP24** — Kaydedilen erişim zamanı seçeneğe bağlıdır: tam güncellemede gerçek okuma anı,
  gevşek güncellemede yalnız yazma anı, güncellemesiz seçenekte oluşturma anı yazılır.
- **DP25** — Temizlik görevi, kaydedilen erişim zamanı **300 saniyeden** eski olan dosyaları
  siler. Kâhin, dosyanın **gerçek** son okunma anıdır.

```python
"""Takma secenegi erisim zamanini degistiriyor , temizlik gorevi yanlis siliyor."""
TOHUM = 20260218
DONEM = 600
ESIK = 300
DOSYA = 2000


def uretec(tohum):
    d = tohum

    def sonraki(n):
        nonlocal d
        d = (d * 1103515245 + 12345) % 2147483648
        return d % n
    return sonraki


def dosyalar(tohum=TOHUM, sayi=DOSYA):
    """Kahin: her dosyanin GERCEK son okunma ani."""
    r = uretec(tohum)
    liste = []
    for _ in range(sayi):
        olusturma = r(400)
        son_yazma = olusturma + (r(DONEM - olusturma) if r(10) < 3 else 0)
        taban = max(olusturma, son_yazma)
        son_okuma = taban + (r(DONEM - taban) if r(10) < 6 else 0)
        liste.append({"olusturma": olusturma, "son_yazma": son_yazma,
                      "son_okuma": son_okuma})
    return liste


def kaydedilen(d, secenek):
    if secenek == "atime":
        return d["son_okuma"]
    if secenek == "relatime":
        return d["son_yazma"]
    return d["olusturma"]          # noatime: hic guncellenmez


def temizlik(liste, secenek, esik=ESIK):
    """Gorev , kaydedilen erisim zamani esikten eskiyse siler."""
    yanlis_silme = yanlis_koruma = silinen = 0
    for d in liste:
        sil = kaydedilen(d, secenek) < esik
        eski = d["son_okuma"] < esik           # kahin
        silinen += sil
        yanlis_silme += sil and not eski
        yanlis_koruma += eski and not sil
    return {"silinen": silinen, "yanlis_silme": yanlis_silme,
            "yanlis_koruma": yanlis_koruma,
            "yanlis": yanlis_silme + yanlis_koruma}


L = dosyalar()
print("kahin: gercekten eskimis dosya:", sum(d["son_okuma"] < ESIK for d in L),
      "/", DOSYA)
print()
print("secenek    silinen  yanlis silme  yanlis koruma  yanlis tani")
for s in ("atime", "relatime", "noatime"):
    t = temizlik(L, s)
    print(f"  {s:9s} {t['silinen']:7d}  {t['yanlis_silme']:12d}"
          f"  {t['yanlis_koruma']:13d}  {t['yanlis']:11d}")
print()
for tohum in (TOHUM, 20260219):
    l2 = dosyalar(tohum)
    print(f"tohum {tohum}: eskimis {sum(d['son_okuma'] < ESIK for d in l2):4d}"
          f"  atime {temizlik(l2, 'atime')['yanlis']:4d}"
          f"  relatime {temizlik(l2, 'relatime')['yanlis']:4d}"
          f"  noatime {temizlik(l2, 'noatime')['yanlis']:4d}")
```

```
kahin: gercekten eskimis dosya: 717 / 2000

secenek    silinen  yanlis silme  yanlis koruma  yanlis tani
  atime         717             0              0            0
  relatime     1204           487              0          487
  noatime      1504           787              0          787

tohum 20260218: eskimis  717  atime    0  relatime  487  noatime  787
tohum 20260219: eskimis  728  atime    0  relatime  502  noatime  821
```

Üç sayı yan yana. **Kâhin:** 2000 dosyanın **717'si** gerçekten üç yüz saniyeden beri
okunmamıştır. **Araç çıktısı:** güncellemesiz seçenekte dosyaların erişim zamanı okunduğunda
**1504'ü** eski görünür. **Yanlış tanı:** temizlik görevi **787 dosyayı** yanlışlıkla siler
ve tek bir hata iletisi üretmez.

Üç satır arasındaki fark bir tasarım ödünleşmesidir. Erişim zamanını her okumada güncellemek,
salt okuma iş yükünü bir yazma iş yüküne çevirir; her dosya okuması bir meta veri yazması
üretir. Gevşek güncelleme bu maliyeti düşürür ve 487 yanlış silme getirir; güncellemesiz
seçenek maliyeti sıfırlar ve 787 yanlış silme getirir. Yanlış koruma sütununun her üç satırda
da sıfır olması yanılgının **tek yönlü** olduğunu gösteriyor: kaydedilen zaman gerçeğin
gerisinde kalır, ilerisine geçmez. İkinci tohumda sayılar 502 ve 821 oluyor, sıralama
değişmiyor.

Buradan çıkan kural şudur: bir takma seçeneği, üzerinde çalışan görevlerin varsayımını
değiştirir. Seçenek listesi `findmnt` çıktısında görünür ve o listeye bakan biri hangi görevin
hangi alana güvendiğini bilmiyorsa, gördüğü satırdan hiçbir tanı çıkaramaz.

#### Hata Anında Salt Okunura Geçme

Takma seçeneklerinin bir bölümü işlemleri değil, **arıza davranışını** belirler. Bir dosya
sistemi kendi defterlerinde tutarsızlık ya da aygıttan hata algıladığında ne yapacağını takma
anında öğrenir: yok sayıp devam edebilir, kendini salt okunura çevirebilir ya da makineyi
durdurabilir. Yaygın öntanımlı davranış ortadakidir.

Salt okunura geçmenin operatör açısından tuhaf bir yanı vardır. Aygıt hâlâ takılıdır, ağaçta
görünür, okumalar çalışır ve `df` doluluk göstermeye devam eder; yalnız yazmalar reddedilir.
Yazan birimler bu reddi bir hata olarak alır ve yeniden başlatma politikası bu hatayı örter —
servisler konusunda ölçülen durum burada da geçerlidir ve tekrarlanmaz. Sonuç, çalışıyor
görünen ama hiçbir şey yazmayan bir sistemdir.

Bu geçişin kaydı yalnız bir yerde durur: sistem günlüğüne düşen tek bir satır. Satır, geçiş
anında yazılır ve sonra bir daha yazılmaz; günlük döndürüldüğünde ortadan kalkar. Günlükler
konusundaki üçüncü iddianın en pahalı örneği budur — arızanın tek kanıtı, kendisi kanıt
silen bir düzende tutuluyor. Takma tablosundaki seçenek listesinde ise `ro` ibaresi görünür
ve o ibare, dosya sisteminin bu duruma **sonradan** geçtiğini söylemez; girdiye salt okunur
yazılmış olsa da aynı görünürdü.

#### Yanlış Girdi ve Geri Dönüş

Kalıcı takma girdilerini tutan dosya, sistemin en az yazılan ve en çok zarar veren
dosyalarından biridir. Yanlış yazılmış bir satır önyüklemeyi durdurabilir; sistem uzaktaysa
ve konsol erişimi yoksa makine ulaşılamaz duruma gelir. Bu yüzden girdiyi yazan işlem tek
başına değil, üç adımlı bir yordamla yapılır.

Birincisi **söz dizimi ve hedef doğrulamasıdır**: `findmnt --verify` girdileri okur, aygıt
kimliklerinin karşılığı olup olmadığına bakar ve takma noktalarının var olup olmadığını
denetler; hiçbir şey takmaz. İkincisi **denemedir**: girdiler yeniden okunup henüz takılmamış
olanlar takılır ve sonuç aynı oturumda görülür. Üçüncüsü **geri dönüş yoludur**: değişiklik
yapılmadan önce dosyanın bir kopyası alınır ve yeniden başlatma, kurtarma kabuğuna erişimin
mümkün olduğu bir zamanda denenir.

Girdinin okunma sırası da bir tuzaktır. Takma noktaları iç içe olabilir ve içteki bir nokta,
dıştaki takılmadan önce takılamaz; sıra bozulduğunda içteki dosya sistemi kök dosya sistemi
üzerindeki bir dizine takılır ve beklenen yerde durmaz. Bağımlılığı çözen şey girdilerin
dosyadaki sırası değil, takma noktalarının yol derinliğidir; araçlar bu sıralamayı kendileri
yapar ama elle verilen bir takma komutu yapmaz.

Takmayı kaldırmak da düşünüldüğü kadar zararsız değildir. Bir dosya sistemi, üzerinde açık
tanıtıcısı olan bir süreç varken ayrılamaz ve zorlayan seçenekle ayrılması, o süreçlerin
yazmakta olduğu veriyi yarıda bırakır. Bu ders zorlayan ayırma komutunu tam biçimde vermez;
doğru sıra, önce dosya sistemini kullanan birimlerin durdurulması, sonra açık tanıtıcı
kalmadığının doğrulanması, en son ayırmadır.

#### Özet

- Takma, bir aygıttaki dosya sistemini tek ağacın bir noktasına bağlar; takma noktasının
  önceki içeriği silinmez, görünmez olur ve altta kalan dosya sisteminde yer tutmaya devam
  eder.
- Aygıt adları keşif sırasına göre verilir: `aygit-b` adına yazılmış bir kalıcı takma girdisi
  altmış önyüklemenin yalnız 13'ünde doğru dosya sistemini takıyor, 27'sinde sessizce
  yanlışını takıyor, 20'sinde gürültülü hata veriyor. Kimliğe yazıldığında yanlış tanı sıfır.
- Erişim zamanını güncellemeyen takma seçeneği hiçbir işlemi reddetmez; yalnız kaydedilen
  zamanı dondurur. 717 dosya gerçekten eskiyken görev 1504 dosya siliyor ve bunların 787'si
  yanlış silme.
- Yanılgı tek yönlüdür: kaydedilen erişim zamanı gerçeğin gerisinde kalır, ilerisine geçmez;
  bu yüzden yanlış koruma sütunu üç seçenekte de sıfırdır.
- Kalıcı takma girdisi yanlış yazıldığında önyükleme durabilir; doğrulama komutu, aynı
  oturumda deneme ve dosyanın kopyası bu riski ölçülebilir biçimde düşürür.

#### Sonraki Adım

Bu dersin bütün ölçümleri bir bölümün sınırlarının sabit olduğunu varsaydı: aygıtta çizilmiş
bir aralık ve içine kurulmuş bir dosya sistemi. Dolduğunda yapılabilecek tek şey silmekti.
Sonraki ders bu sabitliği kaldıran bir katman ekler — bölümü birimlerden oluşan bir havuza
çeviren, birimi çalışırken büyütebilen ve bir anın kopyasını tutabilen bir katman. O katmanın
da kendi sınırı vardır ve ölçülecek şey, anlık görüntünün dolduğu andır.

### Mantıksal Birim Yönetimi

Source: https://academia.sh/tr/kurslar/sistem-yonetimi/mantiksal-birim-yonetimi

Büyütme iki adımdır ve yirmi bir okumanın yedisi zincirin yanlış halkasını gösteriyor; 512 blok ayrılmış bir anlık görüntü 413. saniyede doluyor ve altmış saniyede bir bakan izleme o ana kadar 256 blokta duran bir sayı görüyor.

Önceki dersin bütün ölçümleri bir bölümün sınırlarının sabit olduğunu varsaydı: aygıta
çizilmiş bir aralık ve içine kurulmuş bir dosya sistemi. Bu varsayım altında dolan bir bölüm
için yapılabilecek tek şey silmekti; komşu bölümdeki boş yer erişilemez kalıyordu.

Bu ders o sabitliği kaldıran katmanı ölçer. Katman, bölümleri bir havuza toplar ve havuzdan
istenen boyutta parçalar keser; kesilen parça çalışırken büyütülebilir ve bir anının kopyası
tutulabilir. Kazanç gerçektir ve iki yeni yanlış tanı kaynağı getirir: zincirin hangi
halkasının büyüdüğü ve bir anın kopyasının ne kadar dayanacağı.

#### Üç Katman ve Aralarındaki Birim

Katman üç nesneden oluşur. **Fiziksel birim (physical volume)**, havuza katılmış bir blok
aygıtı ya da bölümdür. **Birim havuzu (volume group)**, bir ya da daha çok fiziksel birimin
tek bir alan olarak sunulmasıdır. **Mantıksal birim (logical volume)**, havuzdan kesilmiş ve
üzerine dosya sistemi kurulabilen parçadır.

Kesme işlemi bayt bayt değil, sabit boyutlu **ayırma birimleriyle (extent)** yapılır. Havuz
oluşturulurken bir ayırma biriminin boyu belirlenir; her mantıksal birim tam sayıda ayırma
birimi tutar ve büyütme de bu birimlerin katlarıyla olur. Bunun iki sonucu vardır: istenen
boyut yukarı yuvarlanır ve bir mantıksal birim, havuzdaki fiziksel birimlerin **birden
çoğuna** yayılabilir.

Yayılma katmanın hem gücü hem sessiz riskidir. Bir mantıksal birim iki fiziksel birime
yayılmışsa, ikisinden birinin arızalanması birimin tamamını kullanılamaz kılar; havuza aygıt
eklemek dayanıklılığı artırmaz, yalnız kapasiteyi artırır. Katmanın kendisi bir yedeklilik
düzeni değildir ve öyle olduğu varsayıldığında tanı en pahalı biçimde yanılır.

Üç katman üç araçla okunur: `pvs` fiziksel birimleri, `vgs` havuzları, `lvs` mantıksal
birimleri listeler. Aşağıdaki döküm `lvs` çıktısının biçimini gösteren bir **örnek dökümdür**;
çalıştırılmamıştır ve bu derste hiçbir sayı iddiası buradan gelmez.

```text
LV        VG      Attr       LSize   Pool Origin Data%  Meta%
veri      havuz-1 -wi-ao----  32.00g
veri-anlik havuz-1 swi-a-s---  2.00g       veri   41.30
gunluk    havuz-1 -wi-ao----   8.00g
```

İkinci satırdaki `Origin` ve `Data%` sütunları bu dersin ikinci ölçümünün konusudur: bir
anlık görüntünün kaynağı ve doluluğu.

#### Büyütme İki Adımdır

Bir mantıksal birimi büyütmek dosya sistemini büyütmez. Katman birime yeni ayırma birimleri
ekler; dosya sistemi ise kendi defterlerini eski sınıra göre tutmaya devam eder ve yeni alanı
görmez. İki adım ayrıdır, sıraları bağlayıcıdır ve aralarındaki boşlukta araçlar farklı
sayılar söyler.

- **DP26** — Zincir yedi aşamadan geçer: başlangıç, havuza fiziksel birim eklenmesi, mantıksal
  birimin büyütülmesi, dosya sisteminin büyütülmesi, yazmanın sürmesi, anlık görüntünün
  ayrılması ve anlık görüntünün düşmesi.
- **DP27** — Bütün sayılar bloktur; ayırma birimi bu ölçümde blok katıdır ve yuvarlama
  sayılmaz.
- **DP28** — Sorulan tanı tektir: **şu anda kaç blok daha yazılabilir.** Kâhin, dosya
  sisteminin kapasitesinden kullanılanın düşülmesidir.

```python
"""Buyutme iki adimdir; her arac zincirin farkli bir halkasini gosterir."""
ASAMA = (
    ("0 baslangic",              0, 4096, 4096, 3800),
    ("1 fiziksel birim eklendi", 8192, 4096, 4096, 3800),
    ("2 mantiksal birim buyudu", 4096, 8192, 4096, 3800),
    ("3 dosya sistemi buyudu",   4096, 8192, 8192, 3800),
    ("4 yazma surdu",            4096, 8192, 8192, 6000),
    ("5 anlik goruntu ayrildi",  3584, 8192, 8192, 6000),
    ("6 anlik goruntu dustu",    4096, 8192, 8192, 6000),
)


def okumalar(a):
    """Soru: su anda kac blok daha yazilabilir."""
    _, vg_bos, lv, fs, kullanilan = a
    return {"kahin": fs - kullanilan,
            "vgs": vg_bos + lv - kullanilan,     # havuzdaki bos yer yazilabilir sanilir
            "lvs": lv - kullanilan,              # birim boyutu yazilabilir sanilir
            "df": fs - kullanilan}


print("asama                      vg bos    lv    fs  kullanilan  kahin"
      "    vgs    lvs     df")
for a in ASAMA:
    o = okumalar(a)
    print(f"{a[0]:24s} {a[1]:7d} {a[2]:5d} {a[3]:5d} {a[4]:11d}"
          f" {o['kahin']:6d} {o['vgs']:6d} {o['lvs']:6d} {o['df']:6d}")
print()
print("arac  dogru okuma  yanlis okuma")
toplam = 0
for arac in ("vgs", "lvs", "df"):
    y = sum(okumalar(a)[arac] != okumalar(a)["kahin"] for a in ASAMA)
    toplam += y
    print(f"  {arac:3s} {len(ASAMA) - y:11d}  {y:12d}")
print("yanlis tani:", toplam, "/", len(ASAMA) * 3)
```

```
asama                      vg bos    lv    fs  kullanilan  kahin    vgs    lvs     df
0 baslangic                    0  4096  4096        3800    296    296    296    296
1 fiziksel birim eklendi    8192  4096  4096        3800    296   8488    296    296
2 mantiksal birim buyudu    4096  8192  4096        3800    296   8488   4392    296
3 dosya sistemi buyudu      4096  8192  8192        3800   4392   8488   4392   4392
4 yazma surdu               4096  8192  8192        6000   2192   6288   2192   2192
5 anlik goruntu ayrildi     3584  8192  8192        6000   2192   5776   2192   2192
6 anlik goruntu dustu       4096  8192  8192        6000   2192   6288   2192   2192

arac  dogru okuma  yanlis okuma
  vgs           1             6
  lvs           6             1
  df            7             0
yanlis tani: 7 / 21
```

Üç sayı yan yana. **Kâhin:** ikinci aşamada yazılabilir alan **296 bloktur** — mantıksal
birim ikiye katlanmış olmasına rağmen. **Araç çıktısı:** aynı aşamada `lvs` 4392, `vgs` 8488
blok gösteriyor. **Yanlış tanı:** yirmi bir okumanın **yedisi** yanlış.

Tablo, katmanın getirdiği asıl güçlüğü gösteriyor: aynı soruya üç ayrı katman cevap veriyor ve
yalnız en üstteki doğru. Havuzun boş yeri hiçbir zaman doğrudan yazılabilir alan değildir;
mantıksal birimin boyutu, dosya sistemi büyütülmediği sürece yazılabilir alan değildir.
İkinci aşamada duran bir işlem — büyütme komutu verilmiş, dosya sistemi büyütülmemiş — sistemi
"yer açıldı" sanılan ama açılmamış bir durumda bırakır ve dolan disk arızası **büyütme
yapıldıktan sonra** ortaya çıkar.

Sıralamanın kendisi de bağlayıcıdır. Büyütmede önce mantıksal birim, sonra dosya sistemi
büyütülür; küçültmede sıra terstir ve tersine çevrilmediğinde dosya sistemi kendi sınırının
dışında kalan bloklara işaret etmeye devam eder. Bu iki cümle arasındaki fark, geri
dönülemeyen bir veri kaybıdır.

#### Anlık Görüntü Nasıl Dolar

**Anlık görüntü (snapshot)**, bir mantıksal birimin belirli bir andaki hâlini okunabilir
tutan ikinci bir birimdir. Kopyalama işlemin başında yapılmaz; kaynaktaki bir blok ilk kez
üzerine yazıldığında **eski hâli** anlık görüntünün alanına taşınır. Bu yüzden anlık
görüntünün tükettiği yer, kaynağın boyutuyla değil, kaynakta **değişen blok sayısıyla**
orantılıdır.

Ayrılan alan bittiğinde anlık görüntü geçersizleşir ve düşer. Kaynak birim etkilenmez ve
çalışmaya devam eder; kaybolan şey, o anlık görüntüden alınmakta olan yedeğin geçerliliğidir.

- **DP29** — Kaynak mantıksal birim **4096 blok**, anlık görüntüye ayrılan alan **512
  bloktur**. Olağan yük her saniye **sıcak kümedeki 256 bloktan** ikisini yeniler.
- **DP30** — 400. ve 430. saniyeler arasında yedek görevi geniş bir tarama yapar ve her
  saniye **20 bloğa** dokunur; dokunulan bloklar birimin tamamından çekilir.
- **DP31** — İzleme aracı doluluğu `aralik` saniyede bir okur; eşiği aşan ilk okuma uyarıdır.
  Uyarı dolma anından **sonra** geliyorsa ya da hiç gelmiyorsa tanı yanlış sayılır.

```python
"""Anlik goruntu yazarken kopyalar; ayrilan yer dolunca gecersizlesir."""
TOHUM = 20260218
DONEM = 600
BIRIM_BLOK = 4096        # kaynak mantiksal birimin blok sayisi
AYRILAN = 512            # anlik goruntuye ayrilan blok
SICAK = 256              # olagan yukun dokundugu blok kumesi
PATLAMA = (400, 430)     # yedek gorevinin genis tarama yaptigi aralik


def uretec(tohum):
    d = tohum

    def sonraki(n):
        nonlocal d
        d = (d * 1103515245 + 12345) % 2147483648
        return d % n
    return sonraki


def kopyalanan(tohum=TOHUM):
    """Kahin: her saniye sonunda anlik goruntunun tuttugu blok sayisi."""
    r = uretec(tohum)
    goruldu, egri = set(), []
    for t in range(DONEM):
        if PATLAMA[0] <= t < PATLAMA[1]:
            for _ in range(20):
                goruldu.add(r(BIRIM_BLOK))
        else:
            for _ in range(2):
                goruldu.add(r(SICAK))
        egri.append(min(len(goruldu), AYRILAN))
    return egri


def dolma_ani(egri):
    for t, v in enumerate(egri):
        if v >= AYRILAN:
            return t
    return None


def tani(egri, aralik, esik):
    """Arac `aralik` saniyede bir bakar; esigi asan okuma uyari sayilir."""
    dolar = dolma_ani(egri)
    bakislar = [t for t in range(0, DONEM, aralik) if t < dolar]
    uyari = next((t for t in range(0, DONEM, aralik)
                  if egri[t] / AYRILAN >= esik), None)
    zamaninda = uyari is not None and uyari < dolar
    return {"son_okuma": egri[bakislar[-1]] if bakislar else 0,
            "uyari": uyari, "yanlis": not zamaninda}


E = kopyalanan()
D = dolma_ani(E)
print("kahin: anlik goruntu", D, "saniyede doluyor |", AYRILAN, "blok ayrildi")
print("egri:", [(t, E[t]) for t in (0, 60, 180, 300, 360, 400, 410, 420)])
print()
print("aralik  esik  dolmadan onceki son okuma  ilk uyari  yanlis tani")
yanlis = 0
for aralik in (10, 30, 60, 120, 300):
    for esik in (0.70, 0.90):
        s = tani(E, aralik, esik)
        yanlis += s["yanlis"]
        print(f"{aralik:6d}  {esik:.2f}  {s['son_okuma']:25d}"
              f"  {str(s['uyari']):>9s}  {str(s['yanlis']):>11s}")
print("yanlis tani:", yanlis, "/ 10")
print()
for tohum in (TOHUM, 20260219):
    e2 = kopyalanan(tohum)
    y = sum(tani(e2, a, s)["yanlis"] for a in (10, 30, 60, 120, 300)
            for s in (0.70, 0.90))
    print(f"tohum {tohum}: dolma ani {dolma_ani(e2)}  t=360 okumasi {e2[360]}"
          f"  yanlis tani {y} / 10")
```

```
kahin: anlik goruntu 413 saniyede doluyor | 512 blok ayrildi
egri: [(0, 2), (60, 122), (180, 256), (300, 256), (360, 256), (400, 276), (410, 466), (420, 512)]

aralik  esik  dolmadan onceki son okuma  ilk uyari  yanlis tani
    10  0.70                        466        410        False
    10  0.90                        466        410        False
    30  0.70                        256        420         True
    30  0.90                        256        420         True
    60  0.70                        256        420         True
    60  0.90                        256        420         True
   120  0.70                        256        480         True
   120  0.90                        256        480         True
   300  0.70                        256       None         True
   300  0.90                        256       None         True
yanlis tani: 8 / 10

tohum 20260218: dolma ani 413  t=360 okumasi 256  yanlis tani 8 / 10
tohum 20260219: dolma ani 413  t=360 okumasi 256  yanlis tani 8 / 10
```

Üç sayı yan yana. **Kâhin:** anlık görüntü **413. saniyede** doluyor. **Araç çıktısı:** altmış
saniyede bir bakan izleme, dolmadan önceki son okumasında **256 blok** görüyor — ayrılan alanın
tam yarısı. **Yanlış tanı:** on örnekleme ve eşik birleşiminin **sekizi** uyarıyı zamanında
üretemiyor.

Eğri bunun nedenini gösteriyor. İlk üç yüz saniyede doluluk 256'da duruyor, çünkü olağan yük
hep aynı sıcak kümeye dokunuyor ve o küme bir kez kopyalandıktan sonra yeni kopya
gerektirmiyor. Sayı üç yüz saniye boyunca kıpırdamıyor ve bakan kişiye **kararlı** görünüyor.
Sonra yedek görevi geniş tarama yapıyor ve doluluk on üç saniyede 256'dan 512'ye çıkıyor.
Eşiği düşürmek bu sorunu çözmüyor: tabloda 0,70 ile 0,90 eşikleri aynı sonucu veriyor, çünkü
sorun eşiğin yüksekliği değil, **iki bakış arasındaki mesafedir**. Süreç yönetimi konusundaki
örnekleme ölçümüyle aynı yapı burada da işliyor.

İkinci tohumda dolma anı da yanlış tanı sayısı da değişmiyor. Bunun nedeni yapısaldır: sıcak
küme her tohum altında doyar ve patlamanın genişliği tohumdan bağımsızdır. Sonuç kurguya değil,
yazarken kopyalamanın kendi davranışına bağlı.

Buradan çıkan tasarım kuralı şudur: anlık görüntüye ayrılacak alan, kaynağın boyutuna göre
değil, anlık görüntünün **yaşayacağı süre boyunca değişecek blok sayısına** göre seçilir. Uzun
süre tutulan bir anlık görüntü, kaynağın tamamı kadar yer isteyebilir.

Uygulamada üç önlem bu ölçümden doğrudan çıkıyor. Birincisi, anlık görüntünün **ömrünü
kısaltmaktır**: yedek alındıktan hemen sonra kaldırılan bir görüntü, hiçbir eşik aşılmadan
biter. İkincisi, doluluğu **olayla birlikte** okumaktır — yedek görevi başlarken ve biterken
alınan iki okuma, altmış saniyelik düzenli örneklemeden daha çok şey söyler. Üçüncüsü, anlık
görüntünün **çalışırken büyütülebilmesidir**: ayrılan alan tükenmeden önce havuzdan yeni
ayırma birimleri eklenebilir, ama tükendikten sonra eklenemez. Üçünün ortak yanı, kararı
örnekleme aralığına bırakmamaktır.

Bir de yanlış anlaşılan bir nokta vardır. Anlık görüntü bir yedek değildir; kaynağıyla aynı
fiziksel birimlerde durur ve kaynağın altındaki aygıt arızalandığında ikisi birlikte kaybolur.
Sağladığı şey **tutarlı bir okuma anıdır** — yedeği alan sürecin, veri değişmeye devam ederken
sabit bir görüntüden okumasını mümkün kılar. Yedeklemenin kendisi bu kursun dışındadır ve
başka bir yerde ölçülmüştür.

#### Küçültme ve Silme

Bu katmanın komutları arasında geri alınamaz olanlar açık uçlu değildir; adları bellidir. Bir
mantıksal birimi silen komut, o birimin ayırma birimlerini havuza geri verir ve içindeki
dosya sistemi bir daha kurulamaz. Bir mantıksal birimi küçülten komut, dosya sistemi önceden
küçültülmemişse dosya sisteminin son bloklarını havuza geri verir; dosya sistemi o blokları
kullanıyorsa veri kaybı sessiz ve kesin olur. Bu ders o iki komutu **çalıştırılabilir tam
biçimde vermez**.

Güvenli sınama yolu üç adımdır. Birincisi **kuru çalışmadır**: birim yönetimi araçları,
değişikliği uygulamadan sonucu bildiren bir seçenek taşır ve o seçeneğin çıktısı okunmadan
gerçek komut verilmez. İkincisi **anlık görüntüdür**: değişiklikten önce alınan bir anlık
görüntü, kaynak bozulduğunda geri dönüşü mümkün kılar — yeter ki ayrılan alan dolmadan
kullanılsın. Üçüncüsü **ayrı bir havuzda denemedir**: geri döngü aygıtlarından kurulmuş küçük
bir havuz, bütün zinciri gerçek veriden uzakta çalıştırmayı sağlar.

#### Özet

- Katman üç nesneden oluşur: havuza katılmış fiziksel birimler, onları tek alan olarak sunan
  birim havuzu ve havuzdan sabit boyutlu ayırma birimleriyle kesilen mantıksal birimler.
  Havuza aygıt eklemek kapasiteyi artırır, dayanıklılığı artırmaz.
- Büyütme iki adımdır ve araçlar arasındaki boşluk ölçülebilir: yedi aşamada yirmi bir okumanın
  yedisi yanlış; `vgs` altı kez, `lvs` bir kez yanılıyor, `df` hiç yanılmıyor.
- Mantıksal birim büyütülüp dosya sistemi büyütülmediğinde yazılabilir alan 296 blokta kalıyor
  ama `lvs` 4392, `vgs` 8488 gösteriyor.
- Anlık görüntü kaynağın boyutuyla değil, değişen blok sayısıyla dolar: 512 bloklu bir görüntü
  413. saniyede doluyor ve altmış saniyede bir bakan izleme o ana kadar 256 blokta duran bir
  sayı görüyor. On örnekleme ve eşik birleşiminin sekizi uyarıyı zamanında üretemiyor.
- Eşiği düşürmek bu kaçırmayı düzeltmiyor; ayıran şey iki bakış arasındaki mesafedir. Birim
  silme ve küçültme komutları geri alınamaz ve bu ders onları tam biçimde vermez.

#### Sonraki Adım

Bu ders depolamayı yalnız veri tutan bir katman olarak ele aldı. Oysa aynı blok aygıtının bir
bölümü hiç dosya tutmaz: bellek baskısı altında sayfaların atıldığı alandır. Sonraki ders o
alanı ölçer ve bir soruyu yanıtlar — takas kullanımı hangi göstergede ne kadar geç görünür.
Ölçüm tek yönlü çıkmayacak: bazı göstergeler baskıyı geç haber veriyor, biri baskı geçtikten
sonra da haber vermeye devam ediyor, biri de baskı hiç yokken bağırıyor.

### Takas Alanı

Source: https://academia.sh/tr/kurslar/sistem-yonetimi/takas-alani

Baskı 84 saniye sürüyor ama kullanılan takas göstergesi 272 saniye boyunca yersiz uyarı veriyor, boş bellek 451 saniye; takas alanı büyüdükçe kapatılabilirlik tanısı 44 yanlıştan 354 yanlışa çıkıyor.

Önceki dersler depolamayı yalnız veri tutan bir katman olarak ele aldı: bölümler, dosya
sistemleri, takma noktaları ve mantıksal birimler. Aynı blok aygıtının bir bölümü ise hiç
dosya tutmaz ve hiçbir takma noktasında görünmez. O bölüm, bellek yetmediğinde sayfaların
yazıldığı yerdir.

Bu dersin sorusu depolamanın değil, **görmenin** sorusudur: takas kullanımı hangi göstergede
ne kadar geç görünür. Cevap tek yönlü çıkmayacak. Bazı göstergeler baskıyı geç haber veriyor,
biri baskı geçtikten sonra da haber vermeye devam ediyor ve biri baskı hiç yokken bile bağırıyor.

#### Takas Alanı ve Ne Olmadığı

**Takas alanı (swap)**, fiziksel belleğe sığmayan sayfaların yazıldığı disk alanıdır. Bir
bölüm olabilir, bir dosya olabilir; ikisi de aynı biçimde biçimlendirilir ve aynı biçimde
etkinleştirilir. Dosya biçimi sonradan eklenip kaldırılabildiği için esnektir, bölüm biçimi
ise dosya sisteminin durumundan bağımsız olduğu için sadedir. Aradaki fark bir üstünlük
sıralaması değil, bir yönetim tercihidir.

Sayfalı belleğin mekanizması İşletim Sistemi Kavramları kursunda ölçüldü: sanal sayfanın
fiziksel sayfaya çevrilmesi, sayfa hatası ve sayfa değiştirme yordamı orada tanımlıdır ve
burada tekrarlanmaz. Bu ders yalnız operatörün görebildiğini sayar.

Görülebilen şey birkaç sayıdır: takas alanının toplam boyu, kullanılan bölümü, saniye başına
takasa yazılan ve takastan okunan sayfa, boş bellek ve kullanılabilir bellek. Bunlar
`swapon --show`, `free` ve bellek istatistiklerini tutan dosya üzerinden okunur. Aşağıdaki
döküm biçimi gösteren bir **örnek dökümdür**; çalıştırılmamıştır ve bu derste hiçbir sayı
iddiası buradan gelmez.

```text
NAME      TYPE       SIZE   USED PRIO
/dev/sdb4 partition  4G     1.2G   -2

               total        used        free      shared  buff/cache   available
Mem:            7.6G        4.1G        160M         88M        3.3G        3.1G
Swap:           4.0G        1.2G        2.8G
```

Dökümdeki `free` ile `available` sütunlarının ayrı olması bu dersin birinci ölçümünün
konusudur: biri geri alınabilir önbelleği boş saymaz, öteki sayar.

#### Dört Gösterge, Dört Ayrı Yanılma

Ölçüm, kurgu sunucuda 600 saniyelik bir pencerede yapılıyor. Rapor üreten birim iki yüzüncü
saniyeden itibaren yavaş yavaş büyüyor, üç yüz yirminci saniyede işini bitiriyor; dört yüz
sekseninci saniyede kısa ve sert bir sıçrama daha var.

- **DP32** — Fiziksel bellek **1200 sayfadır**, olağan yerleşik talep **900 sayfadır**. Baskı,
  talebin fiziksel belleği aştığı saniyedir ve kâhin bunu bilir.
- **DP33** — Takasa yazılan sayfa orada kalır; geri okunana kadar kullanılan takas **azalmaz**.
  Bu, ölçümün ekseni olan davranıştır.
- **DP34** — Önbellek boş belleği doldurur ve saniyede **dört sayfa** büyür. Kullanılabilir
  bellek, geri alınabilir önbelleği boş sayar.
- **DP35** — Uyarı eşiği **100 sayfadır**. Araç `aralik` saniyede bir bakar; iki bakış arasında
  operatörün inancı son okumadır.

```python
"""Takas kullanimi hangi gostergede ne kadar gec (ya da erken) gorunuyor."""
TOHUM = 20260218
DONEM = 600
FIZIKSEL = 1200          # fiziksel bellek , sayfa
TABAN = 900              # olagan yerlesik talep
ESIK = 100               # bellek uyari esigi , sayfa
GENLIK = 60              # talepteki dalgalanma


def uretec(tohum):
    d = tohum

    def sonraki(n):
        nonlocal d
        d = (d * 1103515245 + 12345) % 2147483648
        return d % n
    return sonraki


def talepler(tohum=TOHUM):
    """Kahin: her saniye gercekten istenen yerlesik sayfa sayisi."""
    r = uretec(tohum)
    liste = []
    for t in range(DONEM):
        if 200 <= t < 320:
            temel = TABAN + (t - 200) * 6      # rapor isi yavas yavas buyuyor
        elif 480 <= t < 495:
            temel = 1700                        # kisa ve sert sicrama
        else:
            temel = TABAN
        liste.append(temel + r(2 * GENLIK + 1) - GENLIK)
    return liste


def egriler(tohum=TOHUM):
    d_liste = talepler(tohum)
    kullanilan, hiz, bos, kullanilabilir, baski = [], [], [], [], []
    en_yuksek = onceki = 0
    for t, d in enumerate(d_liste):
        tasan = max(0, d - FIZIKSEL)
        yeni = abs(tasan - onceki)             # saniyede takasa giden ve donen sayfa
        onceki = tasan
        en_yuksek = max(en_yuksek, tasan)      # yazilan sayfa geri okunana kadar durur
        artan = FIZIKSEL - min(d, FIZIKSEL)
        onbellek = min(4 * t, artan)           # onbellek bos yeri doldurur
        kullanilan.append(en_yuksek)
        hiz.append(yeni)
        bos.append(artan - onbellek)
        kullanilabilir.append(artan)           # geri alinabilir onbellek sayilmaz
        baski.append(d > FIZIKSEL)
    return {"kullanilan": kullanilan, "hiz": hiz, "bos": bos,
            "kullanilabilir": kullanilabilir, "baski": baski}


KURAL = {"kullanilan takas": lambda e, i: e["kullanilan"][i] > 0,
         "takas hizi": lambda e, i: e["hiz"][i] > 0,
         "bos bellek": lambda e, i: e["bos"][i] < ESIK,
         "kullanilabilir bellek": lambda e, i: e["kullanilabilir"][i] < ESIK}


def say(e, kural, aralik):
    kacan = uyari = 0
    son = False
    for t in range(DONEM):
        if t % aralik == 0:
            son = kural(e, t)
        kacan += e["baski"][t] and not son
        uyari += son and not e["baski"][t]
    return kacan, uyari


E = egriler()
print("kahin: baski altindaki saniye:", sum(E["baski"]), "/", DONEM)
print("gosterge         t=100  t=240  t=300  t=330  t=485  t=560")
for ad in ("kullanilan", "hiz", "bos", "kullanilabilir"):
    print(f"  {ad:14s}", "  ".join(f"{E[ad][t]:5d}" for t in
                                   (100, 240, 300, 330, 485, 560)))
print()
print("gosterge               aralik  kacirilan  yanlis uyari  yanlis tani")
for ad, kural in KURAL.items():
    for aralik in (5, 30, 60, 120):
        kacan, uyari = say(E, kural, aralik)
        print(f"  {ad:21s} {aralik:6d}  {kacan:9d}  {uyari:12d}"
              f"  {kacan + uyari:11d}")
print()
for tohum in (TOHUM, 20260219):
    e = egriler(tohum)
    s = " | ".join(f"{ad.split()[0]} {sum(say(e, k, 5))}"
                   for ad, k in KURAL.items())
    print(f"tohum {tohum}: baski {sum(e['baski']):3d} saniye | aralik 5 : {s}")
```

```
kahin: baski altindaki saniye: 84 / 600
gosterge         t=100  t=240  t=300  t=330  t=485  t=560
  kullanilan         0      0    331    423    533    535
  hiz                0      0     57      0     61      0
  bos                0      0      0      0      0      0
  kullanilabilir   268    120      0    258      0    333

gosterge               aralik  kacirilan  yanlis uyari  yanlis tani
  kullanilan takas           5          1           272          273
  kullanilan takas          30         19           265          284
  kullanilan takas          60         49           265          314
  kullanilan takas         120         69           225          294
  takas hizi                 5          2            13           15
  takas hizi                30         19            25           44
  takas hizi                60         49            85          134
  takas hizi               120         69           105          174
  bos bellek                 5          0           451          451
  bos bellek                30          0           426          426
  bos bellek                60          0           396          396
  bos bellek               120          0           396          396
  kullanilabilir bellek      5          1            12           13
  kullanilabilir bellek     30         19            25           44
  kullanilabilir bellek     60         49            85          134
  kullanilabilir bellek    120         69           105          174

tohum 20260218: baski  84 saniye | aralik 5 : kullanilan 273 | takas 15 | bos 451 | kullanilabilir 13
tohum 20260219: baski  86 saniye | aralik 5 : kullanilan 271 | takas 16 | bos 469 | kullanilabilir 9
```

Üç sayı yan yana. **Kâhin:** pencerenin **84 saniyesinde** gerçek bellek baskısı var.
**Araç çıktısı:** adı doğrudan takası anan gösterge, kullanılan takas, üç yüz otuzuncu
saniyede **423'te**, dört yüz seksen beşincide **533**'te, beş yüz altmışıncıda **535**'te;
hiç inmiyor.
**Yanlış tanı:** o gösterge beş saniyede bir okunsa bile **272 saniye** yersiz uyarı veriyor;
toplamı **273**.

Dört göstergenin dört ayrı yanılma biçimi var. **Kullanılan takas** birikimlidir: bir sayfa
takasa yazıldıktan sonra geri okunmadıkça orada durur, bu yüzden gösterge baskı bittikten
sonra da yüksek kalır ve geçmişi bugün gibi gösterir; yersiz uyarısı 272 saniyeyi buluyor.
**Takas hızı** anlıktır ve beş saniyelik aralıkta yalnız 2 saniye kaçırıp 13 yersiz uyarı
veriyor; aralık altmışa çıktığında kaçırılan 49'a fırlıyor, çünkü sıçrama on beş saniye
sürüyor ve iki bakış arasına giriyor. **Boş bellek** neredeyse hep alarm veriyor — 451 saniye
— çünkü önbellek boş yeri doldurur ve boş bellek sağlıklı bir sistemde de sıfıra yakındır.
**Kullanılabilir bellek** beş saniyelik aralıkta 1 saniye kaçırıp 12 yersiz uyarı veriyor.

En düşük iki toplam 13 ve 15'tir ve ikisi de aynı örnekleme aralığına bağlıdır: aralık altmışa
çıktığında dördü de en az 134'e tırmanıyor. İkinci tohumda baskı 86 saniye sürüyor ve beş
saniyelik aralıktaki toplamlar 271, 16, 469 ve 9 çıkıyor; sıralama değişmiyor. Kursun kuralı
burada tam karşılığını buluyor: **ayıran şey kaç sayıya bakıldığı değil, hangi sayıya
bakıldığıdır.** Doğrudan takas miktarını sayan gösterge, takas baskısını bulmak için en kötüsü çıktı.

#### Kapatmanın Bedeli

Takas alanını devre dışı bırakmak tek satırlık bir komuttur ve tek satırlık bir riski vardır:
alandaki her sayfa fiziksel belleğe **geri okunmak** zorundadır. Yeterli yer yoksa işlem ya
başarısız olur ya da bellek yetersizliği nedeniyle bir sürecin sonlandırılmasıyla sonuçlanır.

- **DP36** — Kapatma, kullanılan takas kullanılabilir belleğe sığıyorsa mümkündür. Kâhin bu
  karşılaştırmayı her saniye yapar.
- **DP37** — Sınanan tanı yaygın olanıdır: **kullanım yüzdesi yarının altındaysa kapatılabilir.**

```python
"""Takas alanini kapatmak icin icindeki her sayfa bellege geri okunmalidir."""
TOHUM = 20260218
DONEM = 600
FIZIKSEL = 1200
TABAN = 900
GENLIK = 60


def uretec(tohum):
    d = tohum

    def sonraki(n):
        nonlocal d
        d = (d * 1103515245 + 12345) % 2147483648
        return d % n
    return sonraki


def talepler(tohum=TOHUM):
    r = uretec(tohum)
    liste = []
    for t in range(DONEM):
        if 200 <= t < 320:
            temel = TABAN + (t - 200) * 6
        elif 480 <= t < 495:
            temel = 1700
        else:
            temel = TABAN
        liste.append(temel + r(2 * GENLIK + 1) - GENLIK)
    return liste


def durum(tohum=TOHUM):
    kullanilan, kullanilabilir, en_yuksek = [], [], 0
    for d in talepler(tohum):
        en_yuksek = max(en_yuksek, max(0, d - FIZIKSEL))
        kullanilan.append(en_yuksek)
        kullanilabilir.append(FIZIKSEL - min(d, FIZIKSEL))
    return kullanilan, kullanilabilir


def sayim(boy, tohum=TOHUM):
    kul, uygun = durum(tohum)
    gercek = tani = yanlis = 0
    for t in range(DONEM):
        g = kul[t] <= uygun[t]              # kahin: sayfalar bellege geri sigar mi
        y = kul[t] / boy < 0.50             # tani: kullanim yarinin altinda
        gercek += g
        tani += y
        yanlis += g != y
    return gercek, tani, yanlis


print("takas boyu  kapatilabilir saniye  kapatilabilir GORUNEN  yanlis tani")
for boy in (512, 1024, 2048, 4096):
    g, t, y = sayim(boy)
    print(f"{boy:10d}  {g:20d}  {t:21d}  {y:11d}")
print("gozlem penceresi:", DONEM, "saniye")
print()
for tohum in (TOHUM, 20260219):
    print(f"tohum {tohum}: " + " | ".join(
        f"{boy} boyunda yanlis {sayim(boy, tohum)[2]}" for boy in (512, 4096)))
```

```
takas boyu  kapatilabilir saniye  kapatilabilir GORUNEN  yanlis tani
       512                   246                    290           44
      1024                   246                    483          237
      2048                   246                    600          354
      4096                   246                    600          354
gozlem penceresi: 600 saniye

tohum 20260218: 512 boyunda yanlis 44 | 4096 boyunda yanlis 354
tohum 20260219: 512 boyunda yanlis 45 | 4096 boyunda yanlis 355
```

Üç sayı yan yana. **Kâhin:** altı yüz saniyenin **246'sında** takas alanı güvenle
kapatılabilir. **Araç çıktısı:** 2048 sayfalık bir takas alanında doluluk hiçbir zaman
yüzde ellinin üstüne çıkmıyor, yani gösterge **600 saniyenin 600'ünde** "rahat" diyor.
**Yanlış tanı:** aynı kural 512 sayfalık alanda 44, 2048 ve üstünde **354** kez yanılıyor.
İkinci tohumda bu iki sayı 45 ve 355 oluyor.

Sonuç sezgiye ters ve tam da bu yüzden öğretici: **takas alanını büyütmek yüzdeye bakan tanıyı
kötüleştiriyor.** Aynı 533 sayfa, küçük bir alanda tamamına yakını, büyük bir alanda sekizde
biri görünür; sayfa sayısı değişmediği hâlde yüzde değişir. Yüzde bir orandır ve oranın
paydası burada operatörün seçtiği bir sayıdır. Doğru soru "takas ne kadar dolu" değil,
"içindeki sayfalar belleğe sığar mı" sorusudur ve o soruyu yanıtlayan sayı takas çıktısında
değil, bellek çıktısındadır.

#### Ne Kadar Olmalı ve Neye Dokunulmaz

Takas alanının boyutu bir doğruluk kararı değil, bir bütçe kararıdır ve iki uçtan da bedeli
vardır. Hiç takas alanı olmayan bir sistemde talep fiziksel belleği aştığı anda bir süreç
sonlandırılır; arıza serttir, hızlıdır ve tanısı kolaydır. Geniş takas alanı olan bir sistemde
aynı talep sonlandırma üretmez, ama sayfalar diske gider ve her geri okuma bir bekleme
ekler; arıza yumuşaktır, yavaştır ve tanısı zordur. Aradaki seçim, hangi arızanın yönetilebilir
olduğuna göre yapılır.

Bir de sayfa atma eğilimi vardır: çekirdek baskı uyguladığında sayfa önbelleğini mi yoksa az
kullanılan bellek sayfalarını mı önceleyeceğini belirleyen bir ayar taşır. Bu ayarı yükseltmek
en hafif baskıda bile sayfaların takasa yazılmasına yol açar; kullanılan takas göstergesi erken
yukarı çıkar ve yukarıdaki tablodaki yersiz uyarı sütunu daha da büyür.

Yıkıcı komut sınırı burada iki yerde geçerlidir. Birincisi, bir bölümü takas alanı olarak
biçimlendiren komut, o bölümdeki dosya sistemini **geri alınamaz biçimde** yok eder; yanlış
bölüm adı yazıldığında uyarı vermeden çalışır. İkincisi, baskı altındayken takas alanını
kapatmak süreç sonlandırmasına yol açabilir. Bu ders iki komutu da çalıştırılabilir tam
biçimde vermez. Güvenli sınama yolu, hedef bölümün kimliğini önceden doğrulamak, denemeyi
bir dosya üzerinde kurulmuş takas alanıyla yapmak ve kapatmayı yalnız kullanılan takasın
kullanılabilir belleğin altında olduğu bir anda denemektir.

#### Özet

- Takas alanı bir bölüm ya da dosya olabilir ve hiçbir takma noktasında görünmez; sayfalı
  belleğin mekanizması bu kursta tekrarlanmaz, ölçülen şey operatörün görebildiğidir.
- Altı yüz saniyelik pencerede gerçek bellek baskısı 84 saniyedir; kullanılan takas göstergesi
  beş saniyede bir okunsa bile 272 saniye yersiz uyarı verir, çünkü takasa yazılan sayfa geri
  okunana kadar orada kalır.
- Boş bellek 451 saniye yersiz uyarı veriyor, çünkü önbellek boş yeri doldurur; kullanılabilir
  bellek beş saniyelik aralıkta 1 kaçırma ve 12 yersiz uyarıyla en düşük toplamı veriyor.
- Takas hızı aynı aralıkta 2 saniye kaçırıp 13 yersiz uyarı veriyor, ama aralık altmışa
  çıktığında kaçırılan 49'a fırlıyor; dört göstergenin dördü de kaba örneklemede en az
  134'e tırmanıyor.
- Takas alanı 600 saniyenin 246'sında güvenle kapatılabilir; doluluk yüzdesine bakan kural
  512 sayfalık alanda 44, 2048 ve üstünde 354 kez yanılıyor — alanı büyütmek yüzdeye bakan
  tanıyı kötüleştiriyor.

#### Sonraki Adım

Bu konu boyunca depolama hep var olan bir şeydi: bir aygıt, üzerinde bölümler, içlerinde dosya
sistemleri. Kursun son dersi zincirin başına döner ve yeni bir aygıtın sisteme katılmasını
baştan sona izler — tanıma, bölümleme, biçimlendirme, takma, kalıcı hâle getirme ve
genişletme. Her adımda bir araç "tamam" der ve bir üst katman henüz haberdar değildir; ölçülecek
şey, zincirin kaç adımında "iş bitti" tanısının yanlış olduğudur. Ders aynı zamanda kursu
kapatır.

### Disk Ekleme ve Genişletme

Source: https://academia.sh/tr/kurslar/sistem-yonetimi/disk-ekleme-ve-genisletme

Yeni bir aygıtı sisteme katma zinciri dokuz adımdır ve kırk beş okumanın on üçü işin bittiğini söylerken bitmemiştir; aygıt adına yazılmış kalıcı girdi kırk önyüklemenin yalnız onunda doğru dosya sistemini takar.

Bu konu boyunca depolama hep var olan bir şeydi: bir aygıt, üzerinde bölümler, içlerinde
dosya sistemleri, üstlerinde takma noktaları. Kursun son dersi zincirin başına döner ve bir
aygıtın sisteme katılmasını baştan sona izler.

İzlenecek şey adımların kendisi değil, adımlar arasındaki **boşluktur**. Her adımda bir araç
"tamam" der ve bir üst katman henüz haberdar değildir. Ölçülecek sayı, zincirin kaç okumasında
"iş bitti" tanısının yanlış olduğudur.

#### Zincirin Halkaları

Yeni bir aygıt fiziksel olarak bağlandığında sistem onu kendiliğinden kullanmaz. Arada dokuz
adım vardır ve her adım bir öncekine bağlıdır.

Aygıt önce **tanınmalıdır**: çekirdek veri yolunu tarar ve aygıtı ağacına ekler. Sonra
**bölümlenir**; bölümleme tablosu aygıta yazılır, ama çekirdek eski tabloyu bellekte tutmaya
devam edebilir ve bir **yeniden okuma** gerekir. Ardından bölüme **dosya sistemi kurulur**.
Kurulan dosya sistemi ağaçta görünmez; **takılması** gerekir. Elle takma yeniden başlatmada
kaybolduğu için bir **kalıcı takma girdisi** yazılır. Son olarak veriyi üretecek birim yeni
yola **yazmaya başlamalıdır**; yolun değişmesi tek başına birimin yapılandırmasını değiştirmez.

- **DP38** — Zincir dokuz adımdır ve adımların sırası bu ölçümde sabittir; kalıcı takma girdisi
  elle takmadan **önce** yazılmıştır, çünkü yaygın uygulama budur.
- **DP39** — Kâhin, "yeni alan kalıcı olarak kullanımda" durumudur: dosya sistemi takılı,
  girdi kalıcı ve birim yeni yola yazıyor. Üçü birden sağlanmadan iş bitmemiştir.
- **DP40** — Beş araç okunur ve her biri zincirin tek bir halkasını görür: `lsblk` aygıtı,
  `blkid` dosya sistemini, `findmnt` ve `df` takmayı, girdi denetimi kalıcılığı.
- **DP41** — Doğrulama önyüklemesinde keşif sırası ortak tanımın üretecinden çekilir; **40
  önyükleme** gözlenir ve girdi iki biçimde yazılır.

```python
"""Yeni aygiti sisteme katma zinciri: her adimda hangi arac ne diyor."""
TOHUM = 20260218
ONYUKLEME = 40
ALAN = ("gorunur", "bolum", "cekirdek_okudu", "fs", "takili", "birim_yazar",
        "kalici")
ADIM = (
    ("0 aygit takildi",          0, 0, 0, 0, 0, 0, 0),
    ("1 yeniden tarandi",        1, 0, 0, 0, 0, 0, 0),
    ("2 bolum olusturuldu",      1, 1, 0, 0, 0, 0, 0),
    ("3 cekirdek tabloyu okudu", 1, 1, 1, 0, 0, 0, 0),
    ("4 dosya sistemi kuruldu",  1, 1, 1, 1, 0, 0, 0),
    ("5 kalici girdi yazildi",   1, 1, 1, 1, 0, 0, 1),
    ("6 elle takildi",           1, 1, 1, 1, 1, 0, 1),
    ("7 birim yeni yola yazar",  1, 1, 1, 1, 1, 1, 1),
    ("8 yeniden baslatildi",     1, 1, 1, 1, 1, 1, 1),
)
ARAC = {"lsblk": "gorunur", "blkid": "fs", "findmnt": "takili",
        "df": "takili", "girdi denetimi": "kalici"}


def durum(a):
    d = dict(zip(ALAN, a[1:]))
    d["kahin"] = d["takili"] and d["kalici"] and d["birim_yazar"]
    return d


print("adim                      ", "  ".join(f"{k:>14s}" for k in ARAC), " kahin")
for a in ADIM:
    d = durum(a)
    print(f"{a[0]:26s}", "  ".join(f"{str(bool(d[v])):>14s}" for v in ARAC.values()),
          f" {str(bool(d['kahin'])):>5s}")
print()
print("arac             dogru okuma  yanlis okuma")
toplam = 0
for arac, alan in ARAC.items():
    y = sum(bool(durum(a)[alan]) != bool(durum(a)["kahin"]) for a in ADIM)
    toplam += y
    print(f"  {arac:14s} {len(ADIM) - y:11d}  {y:12d}")
print("yanlis tani:", toplam, "/", len(ADIM) * len(ARAC))
print()


def uretec(tohum):
    d = tohum

    def sonraki(n):
        nonlocal d
        d = (d * 1103515245 + 12345) % 2147483648
        return d % n
    return sonraki


def dogrulama(tohum, girdi_bicimi, aygit=5, sayi=ONYUKLEME):
    """Kalici girdi aygit ADINA yazildiysa , kesif sirasi degisince kayar."""
    r = uretec(tohum)
    dogru = 0
    for _ in range(sayi):
        kalan, sira = list(range(aygit)), []
        while kalan:
            sira.append(kalan.pop(r(len(kalan))))
        dogru += 1 if girdi_bicimi == "kimlik" else sira[1] == 1
    return dogru


for tohum in (TOHUM, 20260219):
    print(f"tohum {tohum}: {ONYUKLEME} onyukleme |"
          f" ada yazili girdi dogru {dogrulama(tohum, 'ad'):3d}"
          f" | kimlige yazili girdi dogru {dogrulama(tohum, 'kimlik'):3d}")
```

```
adim                                lsblk           blkid         findmnt              df  girdi denetimi  kahin
0 aygit takildi                     False           False           False           False           False  False
1 yeniden tarandi                    True           False           False           False           False  False
2 bolum olusturuldu                  True           False           False           False           False  False
3 cekirdek tabloyu okudu             True           False           False           False           False  False
4 dosya sistemi kuruldu              True            True           False           False           False  False
5 kalici girdi yazildi               True            True           False           False            True  False
6 elle takildi                       True            True            True            True            True  False
7 birim yeni yola yazar              True            True            True            True            True   True
8 yeniden baslatildi                 True            True            True            True            True   True

arac             dogru okuma  yanlis okuma
  lsblk                    3             6
  blkid                    6             3
  findmnt                  8             1
  df                       8             1
  girdi denetimi           7             2
yanlis tani: 13 / 45

tohum 20260218: 40 onyukleme | ada yazili girdi dogru  10 | kimlige yazili girdi dogru  40
tohum 20260219: 40 onyukleme | ada yazili girdi dogru   6 | kimlige yazili girdi dogru  40
```

Üç sayı yan yana. **Kâhin:** iş **yedinci adımda** bitiyor; ondan önceki hiçbir durumda yeni
alan kalıcı olarak kullanımda değil. **Araç çıktısı:** `lsblk` birinci adımdan itibaren aygıtı
gösteriyor ve gösterdiği şey doğru — yalnız sorulan soruya cevap değil. **Yanlış tanı:** kırk
beş okumanın **on üçü** işin bittiğini söylüyor.

Dağılım zincirin biçimini veriyor. En alttaki araç en çok yanılıyor: `lsblk` altı kez, `blkid`
üç kez. En üsttekiler en az yanılıyor ama sıfır değil — `findmnt` ve `df` birer kez, çünkü
altıncı adımda dosya sistemi takılıdır ve birim hâlâ eski yola yazmaktadır. Girdi denetimi
iki kez yanılıyor, çünkü kalıcı girdi takmadan önce yazılmıştır ve dosya kâğıt üzerinde
doğrudur. **Hiçbir araç zincirin tamamını görmüyor** ve her biri kendi halkasında doğruyu
söylüyor.

Bu dağılımın pratik sonucu bir sıralama kuralıdır: doğrulama zincirin altından değil,
üstünden başlar. Önce birimin gerçekten yeni yola yazdığı, sonra takmanın kalıcı olduğu,
en son aygıtın göründüğü sorulur; ters sırada sorulduğunda ilk üç yanıt olumlu gelir ve
soru orada kesilir.

Son iki satır zincirin sekizinci adımını ölçüyor. Doğrulama önyüklemesinde girdi aygıt adına
yazılmışsa kırk önyüklemenin yalnız **onunda** doğru dosya sistemi takılıyor; ikinci tohumda
bu sayı **altıya** düşüyor. Kimliğe yazılmış girdide kırkın kırkı doğru. Yeniden başlatmadan
doğrulanmamış bir zincir, tamamlanmış sayılmaz.

#### Geri Alınamaz Adımlar

Zincirin dokuz adımından üçü geri alınamaz ve üçü de aynı yerde toplanıyor: aygıta yazan
adımlar. Bölümleme tablosunu yazmak eski yerleşimi siler, dosya sistemi kurmak bölümdeki her
şeyi siler, takas alanı olarak biçimlendirmek de aynı şeyi yapar. Üçünün ortak riski hedefin
yanlış seçilmesidir ve hiçbiri "emin misiniz" diye sormaz. Bu ders o komutları
**çalıştırılabilir tam biçimde vermez**.

Güvenli yol dört adımdır ve dördü de ölçülebilir. Birincisi **hedefi kimliğinden
doğrulamaktır**: `lsblk` ve `blkid` çıktısında hedef aygıtın boş olduğu, üzerinde takılı
dosya sistemi bulunmadığı ve beklenen boyutta olduğu okunur. İkincisi **kuru çalışmadır**:
bölümleme araçlarının uygulamadan gösteren seçeneği ve tablonun metin dökümü, değişikliğin
ne olacağını önceden yazdırır. Üçüncüsü **ayrı aygıtta denemedir**: bir dosyayı geri döngü
aygıtı olarak bağlamak, bütün zinciri gerçek veriden uzakta çalıştırmayı sağlar. Dördüncüsü
**anlık görüntüdür**: değişiklik mantıksal birim üzerindeyse, öncesinde alınan bir anlık
görüntü geri dönüşü mümkün kılar.

Genişletme yönü de aynı kurala uyar ve bir ek sıralaması vardır. Aygıt büyütüldüğünde çekirdek
yeni boyutu kendiliğinden görmez; bölüm büyütülmeden mantıksal birim, mantıksal birim
büyütülmeden dosya sistemi büyüyemez. Sıra yukarı doğru işler ve küçültmede tersine döner.
Tersine çevrilmediğinde ortaya çıkan şey bir hata iletisi değil, sessiz bir veri kaybıdır.

#### Özet

- Yeni bir aygıtı sisteme katmak dokuz adımlık bir zincirdir: tanıma, bölümleme, tablonun
  yeniden okunması, dosya sistemi kurulumu, kalıcı girdi, takma ve birimin yeni yola
  yönlendirilmesi.
- Beş araç zincirin beş ayrı halkasını görür ve hiçbiri tamamını görmez; kırk beş okumanın
  on üçü işin bittiğini söylerken bitmemiştir. En alttaki araç en çok yanılır: `lsblk` altı,
  `blkid` üç kez.
- Zincir yeniden başlatmayla doğrulanmadan tamamlanmış sayılmaz: aygıt adına yazılmış girdi
  kırk önyüklemenin onunda, ikinci tohumda altısında doğru dosya sistemini takıyor; kimliğe
  yazılmış girdide kırkın kırkı doğru.
- Zincirin üç adımı geri alınamaz ve hiçbiri onay istemez; güvenli yol hedefi kimliğinden
  doğrulamak, kuru çalışma çıktısını okumak, ayrı aygıtta denemek ve anlık görüntü almaktır.
- Genişletme aşağıdan yukarı, küçültme yukarıdan aşağı yapılır; sıranın tersine çevrilmesi
  hata iletisi değil, sessiz veri kaybı üretir.

#### Kurs Kapanışı

Bu kurs bir soruyu yirmi iki kez sordu: **çıktının söylediği ile sistemin gerçeği arasındaki
fark ne kadar.** Her derste üç sayı yan yana durdu — kâhin, aracın gösterdiği ve o gösterimden
çıkarılan tanının kaç kez yanlış olduğu. Kursun kuralı buydu: bir komutun sayısı gösterdiği
satır değil, o satırlardan çıkarılan tanının kaç kez yanlış olduğudur.

Aşağıdaki tablo yirmi iki dersin ölçüsünü tek yerde toplar. **Boş bırakılan satırlar
uydurulmamıştır**: her satır yalnız kendi kaynak dersinden yazılır.

| Ders | Kâhin | Araç çıktısı | Yanlış tanı |
|---|---|---|---|
| Süreç Listeleme ve Arama | 24 sürecin **14'ü** ağır | aralık 1/5/15/30/60 → 14, 14, 11, 9, 9 | **0, 0, 3, 5, 5**; ömür ortalaması sütunu **7** |
| Ön Plan ve Arka Plan İşleri | 13 işten `&` ile **0'ı**, ayırmayla **4'ü** yaşıyor | `jobs` **13 satır** | `&` **13**, ayırma **9**, uçtermini kesen yol **0** |
| Sinyaller | isteği kabul eden **2**, direnen **5**; zorlayanda **7/7** | çıkış kodu her denemede **0** | bekleme 0/10/30 saniye → **7, 6, 5** |
| Süreç Öncelikleri | toplam iş **237.906 → 238.244**, yük 3,97'de sabit | `NI` sütunu **6/6** değişti | **6/6**; boşalan payın yüzde **94'ü** öteki ağır süreçlere gidiyor |
| Kaynak Sınırları | **8 arıza nedeni** | **3 ileti + 1 sessizlik**, her ileti iki nedene | yalnız ileti **21**, yalnız sınır **29**, birleşik **13** |
| Servis Yöneticisi Modeli | 6 birim, **7** geçişli bağımlılık | düz **0** / doğrudan **4** / geçişli **7** / sıralı **9** satır | **3 / 2 / 0 / 2** — en çok satır basan okuma en iyi tanıyı vermiyor |
| Servis Durumu ve Denetimi | 6 birimin 6'sı arızalı, **60** yeniden başlatma | **4** birim "çalışıyor", görünmez süre **600** | **4/6**; yoklama 1/5/15/30/60 → **480/99/33/18/10** |
| Yeni Servis Tanımlama | **60** çöküş, 9 bileşimin 9'unda arızalı | 5 "çalışıyor", 2 "çıktı", 2 "arızalı" | **7/9**; başlatma sınırı yok/20/10/5/3 → görünmez süre **600/600/106/62/41** |
| Önyükleme Süreci | `veri-alma` → **4** etkilenen, kesinti gören **5** | "**1 birim**"; **4** birim hiç denenmiyor | **3/6** |
| Önyükleyiciler | 24 değişikliğin **11'i** iş görüyor | üretici **24**, komut satırı **21**, davranış sınaması **11** | **13 / 10 / 0**; kurtarma günlüğü ikisinde de **0** satır |
| Günlük Mimarisi | 4000 satırda 86 hata, gerçek kaynak **31** ile `isleme` | altı birim dosyası: 28, 0, 31, 0, 27, 0 | **5/6**; üç dosya **tamamen sessiz** |
| Kimlik Doğrulama Günlükleri | 601 satırda **41** saldırı satırı | dört süzgeç: 153, 67, 51, 43 satır | **114 / 28 / 12 / 2** |
| Günlük Filtreleme ve Döndürme | **86 hata**, ilki 6,1. saniyede | döndürmede kalan 86, 42, **19**, 12, **5** | altı sorudan **0/3/4/4/4**; oran 0,2209 ve **0,0581** |
| Sistem Sağlığı Ölçümleri | anlık yük eşiği **54 saniye** aşıyor | ortalama bant 6,18–6,25, eşiği **hiç** aşmıyor | **54**; yanlış alarm **0** |
| Başarım Sorunlarının İzi | **18 olay** (4/4/10) | beş görüntü: 432, **1728**, 432, 54, 54 satır | **12 / 12 / 8 / 2 / 0** — satır dörde katlanınca tanı **değişmiyor** |
| Blok Aygıtları ve Bölümler | boş alan dört parça, en büyük bitişik 2.881.536 sektör | bölüm listesi 3.702.784 boş sektör | 6 / 12 karar |
| Dosya Sistemleri | bozuk bloğa dokunan 54 okuma | sağlama toplamsız tasarımda 0 hata | 54 sessiz okuma |
| Dosya Düğümleri ve Meta Veri | 32.768 dosyada yazma başarısız | blok doluluk 0,0125 | 2 / 12 uyarı |
| Takma ve Kalıcı Takma | 717 dosya gerçekten eskimiş | 1504 dosya eski görünüyor | 787 yanlış silme |
| Mantıksal Birim Yönetimi | yazılabilir alan 296 blok | lvs 4392, vgs 8488 blok | 7 / 21 okuma |
| Takas Alanı | bellek baskısı 84 saniye | kullanılan takas 533'ün üstünde kalıyor | 272 yersiz uyarı |
| Disk Ekleme ve Genişletme | iş yedinci adımda bitiyor | lsblk birinci adımdan beri aygıtı gösteriyor | 13 / 45 okuma |

Depolama bölümünün yedi dersi tek bir örüntüyü tekrar tekrar gösterdi. Araçlar yalan
söylemiyor; her biri kendi katmanında doğruyu söylüyor ve sorulan soru o katmanın sorusu
değil. Bölüm listesi boşluk haritası değildir, doluluk yüzdesi yazılabilirlik değildir,
mantıksal birimin boyutu dosya sisteminin boyutu değildir, kullanılan takas bellek baskısı
değildir. Yanlış tanı bu boşluklarda doğuyor ve sayısı sütun eklemekle azalmıyor: dosya
düğümü ölçümünde üç ayrı uyarı kuralı da on iki durumda ikişer yanlış verdi, yalnız yanlışın
türü değişti.

İkinci bir örüntü zamanla ilgiliydi. Anlık görüntü dört yüz on üçüncü saniyede doldu ve
altmış saniyede bir bakan izleme o ana kadar kıpırdamayan bir sayı gördü; takas hızı iki
bakış arasına düştüğünde kaçırılan saniye 2'den 49'a çıktı. Kanıt kendiliğinden yok oluyor
ve depolamada bu, dolan bir alanın ya da düşen bir anlık görüntünün ardında hiçbir iz
bırakmamasıyla oluyor. Geç bakan az görür.

Kurs boyunca yıkıcı komutlar tam biçimde yazılmadı ve bu bir eksiklik değil, ölçümün bir
parçasıydı. Bölümleme tablosunu yazan, dosya sistemi kuran, mantıksal birim silen ve takas
alanı biçimlendiren komutların ortak yanı, hedefin yanlış seçilmesi hâlinde hiçbir uyarı
üretmemeleridir. Güvenli yol her derste aynı dört adımdı: hedefi kimliğinden doğrulamak,
kuru çalışma çıktısını okumak, denemeyi ayrı bir aygıtta yapmak ve geri dönüş noktası bırakmak.

Bir sonraki kurs, **Linux Ağ Yönetimi ve Sorun Giderme**, aynı soruyu tek makinenin dışına
taşır. Orada da bir arayüz listesi vardır ve listede görünen adres bağlantının kurulabildiği
anlamına gelmez; orada da bir yönlendirme tablosu vardır ve tablodaki satır paketin oraya
ulaştığını göstermez. Katmanlı tanı yöntemi, bu kursun katman katman ayırdığı depolama
zincirinin ağ üzerindeki karşılığıdır: fiziksel bağlantıdan uygulamaya doğru daralan bir
sorgu dizisi ve her katmanda "burada doğru, üstte değil" diyen bir araç. Ayrıca orada
kanıt daha da hızlı yok olur, çünkü paket geçip gider ve yakalanmadığı sürece hiçbir yerde
durmaz.

