---
title: 'Durum Dosyası'
source: 'https://academia.sh/tr/kurslar/kod-olarak-altyapi/durum-dosyasi'
course: 'Kod Olarak Altyapı'
language: tr
updated: '2026-08-17T18:09:07+00:00'
license: 'CC BY-SA 4.0'
---

# Durum Dosyası

Kaydın gerçeğe bağlandığı yer: durum dosyası olmadan eşlemenin okuma maliyeti ve hiç eşlenemeyen kalemler, durumun kalem başına tuttuğu bilgi, silinen kaynak ile kaydın kapsamadığı kaynağın ayrımı ve durumun kaybının bedeli.

Plan ile uygulamanın sonucu arasındaki fark ölçüldü: plan bir kalemi gösteriyor, uygulama başka
bir sonuç üretiyordu. O karşılaştırmanın sessiz bir dayanağı vardı. Plan, "bu kaynak zaten var"
ya da "bu kaynak yok" diyebilmek için gerçeğin bir yerde yazılı olduğunu varsayıyordu. O yazılı
hâl nerede duruyor?

Bu ders o dosyayı gerçekten yazar, gerçekten okur ve olmadığında ne yapılamadığını sayar.

## Tanım, Uygulama ve İki Çıktı

Kurgu bir **bölgesel ölçüm ağı** kullanılacak: üç ortam, her ortamda sayaç okumalarını toplayan
iki makine, bir kuyruk, bir veri deposu, bir nesne deposu, bir alt ağ ve ağ kuralları. Ağ da,
sağlayıcı da modeldir; hiçbir gerçek altyapıya dokunulmaz.

Bir uygulama iki şey üretir: sağlayıcı tarafında **kaynaklar**, kendi tarafında **durum dosyası**.
Aşağıdaki betik üçünü de diske yazar.

```js
// uygula.mjs — kurgu "bolgesel olcum agi": tanimi kurar, uygulamayi modeller,
// saglayicidaki gercegi ve durum dosyasini diske yazar. Ucu de modeldir.
import { writeFileSync } from "node:fs";

const ortamlar = ["deneme", "hazirlik", "uretim"];
const tanim = [];
const ekle = (tur, ad, ortam, alanlar, bagimli = []) =>
  tanim.push({ ad, tur, ortam, alanlar, bagimli });

ortamlar.forEach((o, i) => {
  ekle("alt_ag", `alt_ag_${o}`, o, { blok: `10.${i}.0.0/16` });
  ekle("kuyruk", `okuma_kuyrugu_${o}`, o, { saklama_saat: 24, bolum: 4 });
  ekle("veri_deposu", `olcum_deposu_${o}`, o, { boyut_gb: 200, yedek: true });
  ekle("nesne_deposu", `arsiv_${o}`, o, { sinif: "seyrek" });
  for (const n of [1, 2])
    ekle("makine", `toplayici_${o}_${n}`, o, { cekirdek: 2, bellek_gb: 8 },
      [`alt_ag_${o}`, `okuma_kuyrugu_${o}`]);
  for (const kapi of [443, 5671, 9100])
    ekle("guvenlik_kurali", null, o, { yon: "giris", kapi }, [`alt_ag_${o}`]);
  ekle("yol_tablosu_girdisi", null, o, { hedef: "0.0.0.0/0", gecit: "kenar" }, [`alt_ag_${o}`]);
});
// Uretimde yedek toplayici icin ikinci 9100 kurali: tanimda iki kez gecen ayni kalem.
ekle("guvenlik_kurali", null, "uretim", { yon: "giris", kapi: 9100 }, ["alt_ag_uretim"]);

// Saglayicinin, tanimda verilmeyen alanlara kendiliginden koydugu degerler.
const varsayilan = {
  makine: { disk_gb: 40, izleme: "acik" }, kuyruk: { sifreleme: "acik" },
  veri_deposu: { bakim_penceresi: "pazar" }, nesne_deposu: { surum_tut: false },
  alt_ag: { ipv6: false }, guvenlik_kurali: {}, yol_tablosu_girdisi: {},
};
const adsiz = new Set(["guvenlik_kurali", "yol_tablosu_girdisi"]);

const kimlikler = tanim.map((_, i) => `kyn-${String(i + 1).padStart(4, "0")}`);
const adDizini = new Map(tanim.map((k, i) => [k.ad, kimlikler[i]]));

const gercek = [], durum = [];
tanim.forEach((k, i) => {
  const alanlar = { ...varsayilan[k.tur], ...k.alanlar };
  const ustAd = k.bagimli.find((b) => b.startsWith("alt_ag")) ?? null;
  gercek.push({
    kimlik: kimlikler[i], tur: k.tur, alanlar,
    etiket: adsiz.has(k.tur) ? {} : { ad: k.ad, ortam: k.ortam },
    ust: ustAd ? adDizini.get(ustAd) : null,
  });
  durum.push({
    kayit_adi: k.ad ?? `${k.tur}.${k.ortam}[${i}]`, tur: k.tur, ortam: k.ortam,
    kimlik: kimlikler[i], alanlar, bagimli: k.bagimli, saglayici_surumu: "3.4.0",
  });
});

writeFileSync("tanim.json", JSON.stringify(tanim, null, 1));
writeFileSync("saglayici.json", JSON.stringify(gercek, null, 1));
writeFileSync("durum.json", JSON.stringify(
  { bicim_surumu: 4, seri: 1, kalemler: durum }, null, 1));

const alanSayisi = durum.reduce((t, k) => t + Object.keys(k.alanlar).length, 0);
const tanimAlan = tanim.reduce((t, k) => t + Object.keys(k.alanlar).length, 0);
const kenar = durum.reduce((t, k) => t + k.bagimli.length, 0);
console.log(`tanim: ${tanim.length} kalem, ${tanimAlan} alan degeri`);
console.log(`durum.json: ${durum.length} kalem, ${alanSayisi} alan degeri, ` +
  `${kenar} bagimlilik kenari, ${alanSayisi - tanimAlan} alan yalniz durumda`);
console.log(`kalem basina kayit: kimlik 1, alan ${(alanSayisi / durum.length).toFixed(1)}, ` +
  `bagimlilik ${(kenar / durum.length).toFixed(1)}, saglayici surumu 1`);
console.log(`ornek kalem: ${JSON.stringify(durum[4])}`);
```

**DM1.** Sağlayıcı kimlikleri uygulama sırasına göre veriyor; modelde kimlik `kyn-0001`den
başlayarak sırayla atanır. **DM2.** Güvenlik kuralı ile yol tablosu girdisi **etiket taşımayan**
türlerdir; sağlayıcı bu kalemlere yalnız kimlik verir. **DM3.** Sağlayıcı, tanımda verilmeyen
alanlara varsayılan koyar ve bu değerler uygulamanın yanıtında geri döner.

```sh
node uygula.mjs
```

```
tanim: 31 kalem, 56 alan degeri
durum.json: 31 kalem, 80 alan degeri, 25 bagimlilik kenari, 24 alan yalniz durumda
kalem basina kayit: kimlik 1, alan 2.6, bagimlilik 0.8, saglayici surumu 1
ornek kalem: {"kayit_adi":"toplayici_deneme_1","tur":"makine","ortam":"deneme","kimlik":"kyn-0005","alanlar":{"disk_gb":40,"izleme":"acik","cekirdek":2,"bellek_gb":8},"bagimli":["alt_ag_deneme","okuma_kuyrugu_deneme"],"saglayici_surumu":"3.4.0"}
```

İlk sayı çifti ilginç: tanım 56 alan değeri yazıyor, durum 80 tutuyor. Aradaki **24 alan
yalnızca durumda var**; onları tanım yazmadı, sağlayıcı koydu. Kaydın "ne istediği" ile gerçeğin
"ne olduğu" daha uygulamanın ilk saniyesinde ayrışıyor ve durum dosyası bu ayrımın tutulduğu tek
yer.

## Elle Müdahaleden Sonra

Uygulamanın üzerinden zaman geçti. Bir gece nöbetinde birileri sağlayıcı arayüzünden altyapıya
dokundu.

```js
// mudahale.mjs — saglayicidaki gercege elle dokunulmasini modeller: iki kalem silinir,
// dort kalem kayit disi acilir, bir alan degistirilir. Durum dosyasina dokunulmaz.
import { readFileSync, writeFileSync } from "node:fs";
const g = JSON.parse(readFileSync("saglayici.json", "utf8"));

const kimlikle = (ad) => g.find((k) => k.etiket.ad === ad).kimlik;
const altHazirlik = kimlikle("alt_ag_hazirlik"), altUretim = kimlikle("alt_ag_uretim");
const sil = (kosul) => { const i = g.findIndex(kosul); const [k] = g.splice(i, 1); return k.kimlik; };
const s1 = sil((k) => k.etiket.ad === "arsiv_deneme");
const s2 = sil((k) => k.tur === "yol_tablosu_girdisi" && k.ust === altHazirlik);

g.push({ kimlik: "kyn-9001", tur: "makine", alanlar: { cekirdek: 4, bellek_gb: 16, disk_gb: 40 },
  etiket: { ad: "gecici_toplayici", ortam: "uretim" }, ust: altUretim });
g.push({ kimlik: "kyn-9002", tur: "nesne_deposu", alanlar: { sinif: "sicak", surum_tut: false },
  etiket: { ad: "elle_arsiv", ortam: "uretim" }, ust: null });
g.push({ kimlik: "kyn-9003", tur: "guvenlik_kurali", alanlar: { yon: "giris", kapi: 22 },
  etiket: {}, ust: altUretim });
g.push({ kimlik: "kyn-9004", tur: "guvenlik_kurali", alanlar: { yon: "giris", kapi: 443 },
  etiket: {}, ust: altUretim });

const m = g.find((k) => k.etiket.ad === "toplayici_uretim_1");
m.alanlar.bellek_gb = 16;

writeFileSync("saglayici.json", JSON.stringify(g, null, 1));
console.log(`silinen: ${s1}, ${s2} | kayit disi acilan: 4 | elle degisen alan: 1`);
console.log(`saglayicidaki kalem sayisi: ${g.length}`);
```

```sh
node uygula.mjs > /dev/null   # duzenek bastan kurulur
node mudahale.mjs
```

```
silinen: kyn-0004, kyn-0020 | kayit disi acilan: 4 | elle degisen alan: 1
saglayicidaki kalem sayisi: 33
```

## Durum Olmadan Eşleme

Şimdi soru şu: durum dosyası hiç olmasaydı, kayıt ile gerçeği eşlemek için ne gerekirdi? Tek yol
sağlayıcıyı taramak ve mantıksal adları etiketlerle eşleştirmektir.

```js
// eslesme.mjs — durum dosyasina bakmadan, kaydi gercege eslemeye calisir.
import { readFileSync } from "node:fs";
const tanim = JSON.parse(readFileSync("tanim.json", "utf8"));
const gercek = JSON.parse(readFileSync("saglayici.json", "utf8"));
const adsiz = new Set(["guvenlik_kurali", "yol_tablosu_girdisi"]);

const turler = [...new Set(gercek.map((k) => k.tur))];
let liste = turler.length;                       // her tur icin bir listeleme
let ayrinti = gercek.filter((k) => adsiz.has(k.tur)).length;  // adsizlarin her adayi okunur

// Adiyla esleme: liste yaniti etiketi tasidigi icin ek okuma gerektirmez.
const adDizini = new Map(gercek.filter((k) => k.etiket.ad).map((k) => [k.etiket.ad, k]));
const kullanilan = new Set();
let adla = 0, adlaYok = 0;
for (const k of tanim.filter((k) => k.ad)) {
  const bul = adDizini.get(k.ad);
  if (bul) { adla++; kullanilan.add(bul.kimlik); } else adlaYok++;
}

// Adsizlar: yalniz icerik ve bagli olduklari alt ag ile ayirt edilebilir.
const imza = (tur, ust, alanlar) =>
  `${tur}|${ust}|${Object.keys(alanlar).sort().map((a) => `${a}=${alanlar[a]}`).join(",")}`;
const gImza = new Map();
for (const k of gercek.filter((k) => adsiz.has(k.tur)))
  gImza.set(imza(k.tur, k.ust, k.alanlar), (gImza.get(imza(k.tur, k.ust, k.alanlar)) ?? 0) + 1);
const tImza = new Map();
for (const k of tanim.filter((k) => adsiz.has(k.tur))) {
  const ust = adDizini.get(k.bagimli.find((b) => b.startsWith("alt_ag")))?.kimlik ?? null;
  const i = imza(k.tur, ust, k.alanlar);
  tImza.set(i, (tImza.get(i) ?? 0) + 1);
}
let tekil = 0, belirsiz = 0, adsizYok = 0;
for (const [i, adet] of tImza) {
  const g = gImza.get(i) ?? 0;
  if (g === 0) adsizYok += adet;
  else if (adet === 1 && g === 1) tekil++;
  else belirsiz += adet;
}
const sahipsiz = gercek.filter((k) => !kullanilan.has(k.kimlik) && !adsiz.has(k.tur)).length;
const sahipsizAdsiz = [...gImza].reduce((t, [i, g]) => t + Math.max(0, g - (tImza.get(i) ?? 0)), 0);

console.log(`durumsuz esleme — okuma: ${liste} listeleme + ${ayrinti} ayrinti = ${liste + ayrinti}`);
console.log(`  adiyla eslesen: ${adla}/${tanim.filter((k) => k.ad).length}`);
console.log(`  icerikle tekil eslesen: ${tekil}/${tanim.filter((k) => adsiz.has(k.tur)).length}`);
console.log(`  hic eslenemeyen (adsiz, imzasi cakisiyor): ${belirsiz}`);
console.log(`  kayitta var gercekte yok: ${adlaYok + adsizYok} -> silinmis mi, hic olusturulmamis mi: ayirt edilemez`);
console.log(`  gercekte var kayitta yok: ${sahipsiz} adli + ${sahipsizAdsiz} adsiz`);
```

**DM4.** Tür başına bir listeleme bir okuma sayılır; etiket listede döner, adsız kalemin alanları
ise ancak ayrıntı okumasıyla görülür.

```sh
node eslesme.mjs
```

```
durumsuz esleme — okuma: 7 listeleme + 14 ayrinti = 21
  adiyla eslesen: 17/18
  icerikle tekil eslesen: 9/13
  hic eslenemeyen (adsiz, imzasi cakisiyor): 3
  kayitta var gercekte yok: 2 -> silinmis mi, hic olusturulmamis mi: ayirt edilemez
  gercekte var kayitta yok: 2 adli + 2 adsiz
```

Yirmi bir okumadan sonra elde kalan tablo eksiktir. Otuz bir kalemin 26'sı eşleşti, **3 kalem hiç
eşlenemedi**. Üçü de adı olmayan kaynak: üretimdeki iki 9100 kuralı birbirinin tıpatıp aynısı,
443 kuralının ise sağlayıcıda iki karşılığı var — biri tanımdan, biri elden. İçerikleri aynı olan
iki kalem arasında hangi kimliğin hangi kayıt satırına ait olduğunu söyleyecek bir bilgi yok.

İkinci kayıp daha ağırdır: eksik iki kalem için "silinmiş" ile "hiç oluşturulmamış" ayrımı
yapılamıyor. Kayıt ikisini de aynı biçimde görür ve ikisine de aynı kararı verir — oluştur.
Silinen kaynağın silindiği hiçbir zaman öğrenilmez, yalnız yeniden yaratılır.

## Durum Dosyası Neyi Tutuyor

Örnek kalem, durumun kalem başına dört ayrı bilgi tuttuğunu gösteriyor: **kimlik**
(`kyn-0005`), **alan değerleri** (dördü; ikisi tanımdan, ikisi sağlayıcı varsayılanından),
**bağımlılık** (iki kayıt adı) ve **sağlayıcı sürümü** (`3.4.0`). Otuz bir kalem için toplam:
31 kimlik, 80 alan değeri, 25 bağımlılık kenarı, 31 sürüm damgası.

Bu dört kalemin her biri ayrı bir işi yapar. Kimlik eşlemeyi tekilleştirir. Alan değerleri
sapmanın karşılaştırma tabanıdır — sağlayıcının koyduğu varsayılan da kaydedildiği için,
varsayılan sağlayıcı sürümüyle değişirse fark görünür olur. Bağımlılık kenarı silme sırasını
verir; kayıt dosyasındaki metinden değil, uygulanmış hâlden okunur. Sürüm damgası ise aynı
tanımın farklı sağlayıcı sürümünde farklı sonuç ürettiğini saptamayı sağlar.

## Durumla Karşılaştırma

```js
// durum-oku.mjs — durum dosyasindaki kimlikleri saglayicidaki gercekle karsilastirir.
import { readFileSync } from "node:fs";
const d = JSON.parse(readFileSync("durum.json", "utf8"));
const gercek = new Map(JSON.parse(readFileSync("saglayici.json", "utf8")).map((k) => [k.kimlik, k]));

let okuma = 1, eslesen = 0;                      // 1: durum dosyasinin kendisi
const silinen = [], sapan = [];
for (const k of d.kalemler) {
  okuma++;                                       // kimlikle tek kalem okumasi
  const g = gercek.get(k.kimlik);
  if (!g) { silinen.push(`${k.kayit_adi} (${k.kimlik})`); continue; }
  eslesen++;
  for (const [alan, deger] of Object.entries(k.alanlar))
    if (g.alanlar[alan] !== deger) sapan.push(`${k.kayit_adi}.${alan} ${deger} -> ${g.alanlar[alan]}`);
}
const durumKimlikleri = new Set(d.kalemler.map((k) => k.kimlik));
const kayitDisi = [...gercek.values()].filter((g) => !durumKimlikleri.has(g.kimlik));

console.log(`durumla karsilastirma — okuma: 1 durum dosyasi + ${okuma - 1} kimlik = ${okuma}`);
console.log(`  eslesen: ${eslesen}/${d.kalemler.length}, hic eslenemeyen: 0`);
console.log(`  silinmis (durumda kimlik var, saglayicida yok): ${silinen.length} -> ${silinen.join("; ")}`);
console.log(`  sapan alan: ${sapan.length} -> ${sapan.join("; ")}`);
console.log(`  kaydin kapsamadigi (saglayicida var, durumda yok): ${kayitDisi.length} -> ` +
  kayitDisi.map((g) => g.etiket.ad ?? `${g.tur}/${g.kimlik}`).join(", "));
```

```sh
node durum-oku.mjs
```

```
durumla karsilastirma — okuma: 1 durum dosyasi + 31 kimlik = 32
  eslesen: 29/31, hic eslenemeyen: 0
  silinmis (durumda kimlik var, saglayicida yok): 2 -> arsiv_deneme (kyn-0004); yol_tablosu_girdisi.hazirlik[19] (kyn-0020)
  sapan alan: 1 -> toplayici_uretim_1.bellek_gb 8 -> 16
  kaydin kapsamadigi (saglayicida var, durumda yok): 4 -> gecici_toplayici, elle_arsiv, guvenlik_kurali/kyn-9003, guvenlik_kurali/kyn-9004
```

Okuma sayısı 21'den 32'ye çıktı — durum eşlemeyi **ucuzlatmıyor**, kesinleştiriyor. Kazanılan üç
sayı şudur: eşlenemeyen kalem 3'ten 0'a indi, iki silinmiş kalem adıyla ve kimliğiyle bulundu,
bir sapmış alan (`bellek_gb` 8 yerine 16) ortaya çıktı. Bu üçü durumsuz eşlemede görünmüyordu.

Dördüncü sayı kaydın **kapsamını** verir: sağlayıcıdaki 33 kalemin 4'ü hiçbir kaydın içinde
değil. İki makine ve nesne deposu adlarıyla, iki güvenlik kuralı yalnız kimlikleriyle duruyor.
Kayıt bunları ne planlar, ne siler, ne de sapma sayar; altyapının bu bölümü kaydın dışındadır ve
orada olduğu ancak kimse bakmadan silinmediği sürece bilinir.

## Durumun Kaybı

Durum dosyası, altyapının kendisi kadar kritik bir kayıttır. Kaybının bedeli sayılabilir.

```js
// kayip.mjs — durum dosyasi kaybolursa neyin geri kazanilabildigini sayar.
import { readFileSync, rmSync, existsSync } from "node:fs";
const d = JSON.parse(readFileSync("durum.json", "utf8"));
const kayip = { kimlik: d.kalemler.length, kenar: 0, surum: 0, alan: 0 };
for (const k of d.kalemler) {
  kayip.kenar += k.bagimli.length;
  kayip.surum += k.saglayici_surumu ? 1 : 0;
  kayip.alan += Object.keys(k.alanlar).length;
}
rmSync("durum.json");
console.log(`durum.json silindi; dosya duruyor mu: ${existsSync("durum.json")}`);
console.log(`kaybolan bilgi: ${kayip.kimlik} kimlik, ${kayip.alan} alan degeri, ` +
  `${kayip.kenar} bagimlilik kenari, ${kayip.surum} saglayici surumu`);
console.log(`geriye kalan tek yol: durumsuz esleme`);
```

```sh
node uygula.mjs > /dev/null && node mudahale.mjs > /dev/null   # duzenek bastan kurulur
node kayip.mjs
```

```
durum.json silindi; dosya duruyor mu: false
kaybolan bilgi: 31 kimlik, 80 alan degeri, 25 bagimlilik kenari, 31 saglayici surumu
geriye kalan tek yol: durumsuz esleme
```

Dosya gittiğinde altyapı gitmez; **yönetilebilirliği** gider. Geriye kalan tek yol yukarıdaki
durumsuz eşlemedir ve onun tavanı bellidir: 26 kalem tek tek içe aktarılarak geri kazanılabilir,
3 kalem hiçbir biçimde eşlenemez. İki silinmiş kalemin silinmiş olduğu bilgisi de dosyayla
birlikte gitmiştir. Kayıt yeniden kurulana kadar her uygulama, var olan kaynakları yeniden
oluşturmayı planlar.

**DM5.** Durum dosyası tek bir çalışma dizininde, düz metin olarak duruyor. Bu, kaydın kendi
riskinin ikinci yüzüdür: dosya 80 alan değerini olduğu gibi tutar. Değişkenle verilen bir
bağlantı dizesi ya da erişim ölçütü tanımda gizlenmiş olsa bile uygulama sonrası hâliyle burada
yazılıdır ve dosyayı okuyabilen herkes onu okur. **DM6.** Dosyayı yazan tek şey uygulamadır;
elle düzeltilmesi durumu gerçekten uzaklaştırır, çünkü sağlayıcı tarafında karşılığı yoktur.

## Özet

- Uygulama iki çıktı üretti: sağlayıcıdaki 31 kaynak ve bunların kaydı olan durum dosyası; tanım
  56 alan değeri yazarken durum 80 tuttu, 24 alanı sağlayıcı koydu.
- Durum olmadan eşleme 21 okuma sürdü ve 3 kalem hiç eşlenemedi; üçü de adı olmayan kaynaktı,
  imzaları birbirinin aynısıydı.
- Durum olmadan "silinmiş" ile "hiç oluşturulmamış" ayrılamıyor; durumla iki silinmiş kalem
  kimliğiyle bulundu ve bir sapmış alan ortaya çıktı.
- Durum kalem başına dört bilgi tutuyor: kimlik, alan değerleri, bağımlılık, sağlayıcı sürümü —
  31 kalem için 31 kimlik, 80 alan, 25 kenar, 31 sürüm damgası.
- Sağlayıcıdaki 33 kalemin 4'ü kaydın dışında kaldı; kayıt onları ne planlıyor ne sayıyor.
- Durumun kaybında 26 kalem içe aktarmayla geri gelir, 3 kalem gelmez; kayıp altyapıyı yok
  etmez, yönetilemez kılar.

## Sonraki Adım

Bu dersin tamamı tek bir kişinin tek bir dizinde çalıştığını varsaydı. Durum dosyası yerel
diskte duruyordu ve ona aynı anda tek bir süreç dokunuyordu. Ekipte iki kişi aynı ortama aynı
anda uygulama başlattığında bu varsayım düşer: ikisi de aynı durumu okur, ikisi de değiştirir,
ikincisi birincinin yazdığının üstüne yazar. Sonraki ders iki eşzamanlı uygulamayı gerçekten
koşturur, kilitsiz durumda kaybolan yazmayı sayar, kilitle bekleme turlarını ölçer ve kilidi
bırakmadan düşen sürecin ardında bıraktığı artık kilidi ele alır.
