İçeriğe geç
academia.sh

Ders 11 / 21

Etiketleme Düzeni

Katmanlı bir imaj deposunda etiket ölçülür: yirmi derlemenin kaç ayrı içerik özeti ürettiği ve aynı özete kaç etiketin işaret ettiği sayılır, etiket taşındığında dört katmanın gerçekten kaçının değiştiği hesaplanır ve bir dağıtımın kaynağına özetten geriye izlenebilme oranı üç ayrı kayıt disiplini altında ölçülür.

İçindekiler

Önceki ders üç temel adayını sabit içerikmiş gibi ele aldı. Oysa hiçbir temel içerikle seçilmez: bir adla çekilir. Aynı şey üretilen imaj için de geçerlidir — bir derleme yeni bir içerik üretir, ama dağıtım kaydında duran şey addır.

M22/K01’in yapı çıktısı depolarında taşınabilir etiket ile değişmez sürüm ayrımı ölçülmüştü; o sayım burada tekrarlanmaz. Buradaki soru bir katman aşağıdadır: imaj tek bir nesne değil, bir katman listesidir. Etiket bu listenin tamamına mı işaret eder, aynı listeye kaç ad birden işaret edebilir ve bir ad taşındığında listenin kaçıncı satırı gerçekten değişir?

IM31. Depo modeli iki defter tutar: imaj özeti → manifest ve etiket → imaj özeti. Erişim denetimi ve ağ katmanı modelin dışındadır. IM32. Derleme geçmişi kendi üretecimizden gelir; tohum 20260604 görünürdür, 20 derleme yapılır ve derlemelerin dörtte biri aynı kaynak sürümünden yeniden derlemedir. IM33. İmaj dört katmandır — önceki dersin küçültülmüş temeli üzerine bağımlılıklar, uygulama ve yapılandırma — ve toplamı 34,5 MB’dir.

Etiket Neye İşaret Eder

Etiket doğrudan bayta işaret etmez. Zincir üç düzeylidir: etiket bir imaj özetini gösterir, imaj özeti bir manifesti adresler, manifest de katman özetlerini sırayla listeler. Aynı adın aynı katman kümesini getirmesini sağlayan şey bu üç düzeydir.

IM34. Etiket düzeni şudur: her derlemeye bir değişmez sürüm etiketi (s-1, s-2, …) verilir; son her derlemede taşınır, kararli yalnız gecelik toplu işi temiz koşan derlemelere taşınır, dal-hazirlik her dördüncü derlemede taşınır. IM35. Derlemelerin dörtte üçü yapılandırma nesnesine kaynak sürümü alanını yazar; boru hattı dışında elle yapılanlar yazmaz.

// olcum-agi/imaj.mjs — katmanli imaj deposunda derleme gecmisi ve etiketler (model)
import { createHash } from "node:crypto";

export const uretec = (tohum) => () =>
  (tohum = (tohum * 1103515245 + 12345) % 2147483648) / 2147483648;
export const ozet = (s) => createHash("sha256").update(s).digest("hex").slice(0, 12);

// [ad, bayt, kaynaktan bagimsiz degisme olasiligi]. Uygulama katmani kaynaga baglidir.
export const KATMAN = [["temel", 10.5e6, 0.08], ["bagimliliklar", 16.0e6, 0.25],
  ["uygulama", 7.2e6, null], ["yapilandirma", 0.8e6, 0.30]];

export const gecmis = (n = 20, tohum = 20260604) => {
  const r = uretec(tohum);
  const surum = [1, 1, 1, 1];
  const liste = [];
  let kaynak = 1, gun = 0;
  for (let no = 1; no <= n; no++) {
    gun += 1 + Math.round(r() * 8);
    const yeniKaynak = r() > 0.25;      // dortte biri ayni kaynaktan yeniden derlemedir
    if (yeniKaynak) { kaynak += 1; surum[2] += 1; }
    KATMAN.forEach(([, , p], k) => { if (p !== null && r() < p) surum[k] += 1; });
    const katmanlar = KATMAN.map(([ad, bayt], k) => ({ ad, bayt, ozet: ozet(`${ad}@${surum[k]}`) }));
    liste.push({
      no, gun, kaynak: `k-${String(kaynak).padStart(3, "0")}`, katmanlar,
      imaj: ozet("manifest:" + katmanlar.map((k) => k.ozet).join("|")),
      kaynakYazildi: r() > 0.25,        // boru hatti disinda elle derlemeler alani yazmaz
      temizKostu: r() > 0.40,           // gecelik toplu is temiz kostu mu
    });
  }
  return liste;
};

// Etiket defteri: her derlemeye degismez surum etiketi, tasinabilir etiketler kosula bagli.
export const etiketle = (G) => {
  const defter = new Map();             // etiket -> imaj ozeti
  for (const d of G) {
    defter.set(`s-${d.no}`, d.imaj);
    defter.set("son", d.imaj);
    if (d.temizKostu) defter.set("kararli", d.imaj);
    if (d.no % 4 === 0) defter.set("dal-hazirlik", d.imaj);
  }
  return defter;
};

if (import.meta.url === `file://${process.argv[1]}`) {
  const G = gecmis();
  const gorulen = new Set();
  console.log("no".padEnd(4) + "gun".padEnd(5) + "kaynak".padEnd(8) + "imaj ozeti".padEnd(15) + "durum");
  for (const d of G) {
    const tekrar = gorulen.has(d.imaj);
    gorulen.add(d.imaj);
    console.log(String(d.no).padEnd(4) + String(d.gun).padEnd(5) + d.kaynak.padEnd(8) +
      d.imaj.padEnd(15) + (tekrar ? "tekrar" : "yeni"));
  }
  const defter = etiketle(G);
  const fanIn = new Map();
  for (const [etiket, imaj] of defter) fanIn.set(imaj, [...(fanIn.get(imaj) ?? []), etiket]);
  const cok = [...fanIn.entries()].sort((a, b) => b[1].length - a[1].length);
  console.log(`\n${G.length} derleme ${gorulen.size} ayri imaj ozeti uretti; ` +
    `${G.length - gorulen.size} derleme onceki bir ozeti yeniden uretti`);
  console.log(`${defter.size} etiket ${fanIn.size} ayri ozete isaret ediyor`);
  for (const [imaj, etiketler] of cok.slice(0, 3)) {
    console.log(`  ${imaj}: ${etiketler.length} etiket -> ${etiketler.join(", ")}`);
  }
  console.log(`kaynak alani yazilmis derleme: ${G.filter((d) => d.kaynakYazildi).length}/${G.length}`);
}
no  gun  kaynak  imaj ozeti     durum
1   7    k-002   1c8cb1388bf2   yeni
2   11   k-002   908c2c77fc0d   yeni
3   18   k-002   908c2c77fc0d   tekrar
4   25   k-003   d332a3b518f8   yeni
5   29   k-004   3d130b865763   yeni
6   33   k-005   9331a50e2dfd   yeni
7   41   k-006   286596c96b64   yeni
8   45   k-007   847e6e31dbfc   yeni
9   54   k-008   0542d8380547   yeni
10  60   k-009   17d20393c63f   yeni
11  66   k-010   86378989704b   yeni
12  73   k-010   86378989704b   tekrar
13  78   k-010   2f1382fedd1e   yeni
14  83   k-011   3d4cfae4fefc   yeni
15  88   k-011   774b1e11c564   yeni
16  91   k-012   8b84de0171eb   yeni
17  95   k-013   77d3df14dcdb   yeni
18  101  k-014   77112bd049c4   yeni
19  105  k-015   65de4c0ce42a   yeni
20  111  k-015   65de4c0ce42a   tekrar

20 derleme 17 ayri imaj ozeti uretti; 3 derleme onceki bir ozeti yeniden uretti
23 etiket 17 ayri ozete isaret ediyor
  65de4c0ce42a: 5 etiket -> son, kararli, dal-hazirlik, s-19, s-20
  908c2c77fc0d: 2 etiket -> s-2, s-3
  86378989704b: 2 etiket -> s-11, s-12
kaynak alani yazilmis derleme: 14/20

Yirmi derleme on yedi ayrı imaj özeti üretmiştir. Üç derleme, önceki bir derlemenin özetini yeniden üretmiştir: kaynak da katmanlar da değişmediği için manifest aynı çıkmıştır. Bu, önceki dersin belirlenimci derleme disiplininin görünür kanıtıdır — damga koyan bir derlemede yirmi derleme yirmi ayrı özet verirdi.

İkinci sayı ters yöndedir: 23 etiket 17 özete işaret eder. Bir özetin beş adı vardır — son, kararli, dal-hazirlik, s-19, s-20. İkisi değişmezdir, üçü bir sonraki derlemede başka bir özeti gösterecektir. Aynı nesneye beş addan bakılabilmesi bir kusur değil, deponun düzenidir; kusur, dağıtım kaydına bu adlardan hangisinin yazıldığının nesneyi belirleyip belirlemediğidir.

Etiket Taşındığında Ne Değişir

Etiket taşındığında yeni bir imaj adreslenir, ama imajın tamamı yeni değildir. Manifest bir katman listesidir ve iki manifest listenin bazı satırlarını paylaşabilir.

// olcum-agi/tasima.mjs — etiket tasindiginda kac katman gercekten degisti (model)
import { gecmis, KATMAN } from "./imaj.mjs";

const G = gecmis();
const TAM = KATMAN.reduce((t, [, b]) => t + b, 0);
const mb = (b) => (b / 1e6).toFixed(1) + " MB";

// Etiketin hedef aldigi derlemeler, sirayla.
const hedefler = {
  son: G,
  kararli: G.filter((d) => d.temizKostu),
  "dal-hazirlik": G.filter((d) => d.no % 4 === 0),
};

console.log("etiket".padEnd(15) + "tasima".padEnd(8) + "0 katman".padEnd(10) +
  "1 katman".padEnd(10) + "2+ katman".padEnd(11) + "yeni bayt".padEnd(11) + "tam bayt");
const ayrinti = [];
for (const [etiket, dizi] of Object.entries(hedefler)) {
  const dagilim = [0, 0, 0];
  let yeniToplam = 0;
  for (let i = 1; i < dizi.length; i++) {
    const eski = dizi[i - 1].katmanlar, yeni = dizi[i].katmanlar;
    const degisen = yeni.filter((k, j) => k.ozet !== eski[j].ozet);
    const bayt = degisen.reduce((t, k) => t + k.bayt, 0);
    yeniToplam += bayt;
    dagilim[Math.min(degisen.length, 2)] += 1;
    if (etiket === "kararli" && degisen.length !== 1) {   // 1 katman olagan hal; ozette var
      ayrinti.push(`s-${dizi[i - 1].no} -> s-${dizi[i].no}`.padEnd(16) +
        `${degisen.length}/4`.padEnd(8) +
        (degisen.map((k) => k.ad).join(", ") || "-").padEnd(39) + mb(bayt));
    }
  }
  const tasima = dizi.length - 1;
  console.log(etiket.padEnd(15) + String(tasima).padEnd(8) + String(dagilim[0]).padEnd(10) +
    String(dagilim[1]).padEnd(10) + String(dagilim[2]).padEnd(11) +
    mb(yeniToplam).padEnd(11) + mb(tasima * TAM));
}

console.log('\n"kararli" tasimalarinda bir katmandan baska sayida degisenler:');
console.log("tasima".padEnd(16) + "katman".padEnd(8) + "degisen".padEnd(39) + "yeni bayt");
for (const s of ayrinti) console.log(s);

// Katman basina: 19 "son" tasimasinin kacinda degisti?
const say = {};
for (let i = 1; i < G.length; i++)
  G[i].katmanlar.forEach((k, j) => {
    if (k.ozet !== G[i - 1].katmanlar[j].ozet) say[k.ad] = (say[k.ad] ?? 0) + 1;
  });
console.log("\nkatman basina degisim (19 tasimada): " +
  KATMAN.map(([ad]) => `${ad} ${say[ad] ?? 0}`).join(", "));
console.log(`tam imaj ${mb(TAM)}; degismez surum etiketi ${G.length}, tasinabilir etiket ` +
  `${Object.keys(hedefler).length}`);
etiket         tasima  0 katman  1 katman  2+ katman  yeni bayt  tam bayt
son            19      3         10        6          141.7 MB   655.5 MB
kararli        14      1         8         5          120.1 MB   483.0 MB
dal-hazirlik   4       0         0         4          58.5 MB    138.0 MB

"kararli" tasimalarinda bir katmandan baska sayida degisenler:
tasima          katman  degisen                                yeni bayt
s-2 -> s-3      0/4     -                                      0.0 MB
s-3 -> s-5      3/4     temel, uygulama, yapilandirma          18.5 MB
s-6 -> s-8      2/4     uygulama, yapilandirma                 8.0 MB
s-8 -> s-10     3/4     bagimliliklar, uygulama, yapilandirma  24.0 MB
s-16 -> s-17    2/4     uygulama, yapilandirma                 8.0 MB
s-18 -> s-20    2/4     uygulama, yapilandirma                 8.0 MB

katman basina degisim (19 tasimada): temel 1, bagimliliklar 2, uygulama 13, yapilandirma 7
tam imaj 34.5 MB; degismez surum etiketi 20, tasinabilir etiket 3

son etiketi on dokuz kez taşınmıştır. Bu on dokuz taşımanın onunda yalnız bir katman, üçünde hiçbir katman değişmiştir. Sıfır katmanlı taşıma etiketin taşındığı ama içeriğin aynı kaldığı durumdur: ad yeni bir özeti gösterir, özet aynı manifesti adresler, indirilecek bayt yoktur. Dışarıdan bakan tarafta ise “yeni bir imaj yayımlandı” görünür ve bir dağıtım tetiklenebilir.

Bayt sütunları taşımanın gerçek ağırlığını verir: on dokuz taşımada değişen toplam 141,7 MB, aynı on dokuz imajın toplam boyutu ise 655,5 MB. Katman paylaşımı taşımaların yükünün yüzde 78’ini ortadan kaldırmıştır. dal-hazirlik etiketi tersi uçtadır — dört taşımasının dördünde de iki ya da daha çok katman değişmiştir, çünkü arasında dört derleme birikmiştir. Etiketin taşınma sıklığı azaldıkça taşıma başına değişen katman sayısı artar.

Son satır değişimin nereden geldiğini gösterir: on dokuz taşımada uygulama katmanı 13, yapılandırma 7, bağımlılıklar 2, temel yalnız 1 kez değişmiştir. Bu, önceki dersin güncelleme ölçümüyle aynı yöne bakar — alt katmanlar seyrek değişir, üst katmanlar neredeyse her derlemede.

Özetten Kaynağa Geri Dönüş

Şimdiye kadar ölçülen her şey ileri yöndeydi: kaynaktan derlemeye, derlemeden özete, özetten etikete. Olay sırasında sorulan soru ters yöndedir — üretimde koşan bu nesne hangi kaynaktan geldi?

IM36. Yirmi dört dağıtım kurgudur; tohum 20260707 görünürdür ve istenen adın türü — taşınabilir etiket, değişmez sürüm etiketi ya da doğrudan özet — üreteçten gelir. Zincir iki halkadan oluşur: dağıtım kaydından imaj özetine, imaj özetinden kaynak sürümüne.

// olcum-agi/izlenebilirlik.mjs — bir dagitimin kaynagi ozetten geriye izlenebiliyor mu (model)
import { gecmis, uretec } from "./imaj.mjs";

const G = gecmis();
const r = uretec(20260707);
const ALAN_BAYT = 96;        // kaynak surumu + kosum kimligi + zaman damgasi (kurgu)
const TAM = 34.5e6;

// 24 dagitim: gun ve istenen ad. Ad ya tasinabilir etiket, ya surum etiketi, ya dogrudan ozettir.
const dagitimlar = [];
let gun = 3;
while (dagitimlar.length < 24) {
  gun += 1 + Math.round(r() * 7);
  const p = r();
  dagitimlar.push({ gun, tur: p < 0.60 ? "tasinabilir" : p < 0.85 ? "surum" : "ozet" });
}

// Etiket defteri gune gore ilerletilir: dagitim aninda cozulen sey o anki hedeftir.
const defter = new Map();
let sirada = 0;
for (const d of dagitimlar) {
  while (sirada < G.length && G[sirada].gun <= d.gun) {
    const b = G[sirada++];
    defter.set("son", b); defter.set(`s-${b.no}`, b);
    if (b.temizKostu) defter.set("kararli", b);
  }
  const surumEtiketleri = [...defter.keys()].filter((k) => k.startsWith("s-"));
  d.ad = d.tur === "tasinabilir" ? (r() < 0.6 ? "kararli" : "son")
    : d.tur === "surum" ? surumEtiketleri[surumEtiketleri.length - 1]
    : "ozet:dogrudan";
  d.hedef = d.tur === "ozet" ? defter.get("son") : defter.get(d.ad);
}

// Degismez surum etiketi, defter onu tasimayi reddettigi surece ozeti belirler; tasinabilir
// etiket belirlemez. Uc disiplin: (1) kayit yalniz istenen adi yazar, (2) cozulen ozeti de
// yazar, (3) ayrica her derleme kaynak alanini yazar.
const ozetiBelli = (d) => d.tur === "ozet" || d.tur === "surum";
const izlenebilir = (hepsindeOzet, hepsindeKaynak) =>
  dagitimlar.filter((d) => (hepsindeOzet || ozetiBelli(d)) &&
    (hepsindeKaynak || d.hedef.kaynakYazildi)).length;

const N = dagitimlar.length;
console.log("disiplin".padEnd(34) + "ozet biliniyor".padEnd(16) + "kaynak okunuyor");
console.log("kayitta yalniz istenen ad".padEnd(34) +
  `${dagitimlar.filter(ozetiBelli).length}/${N}`.padEnd(16) +
  `${izlenebilir(false, false)}/${N}`);
console.log("kayitta cozulen ozet de var".padEnd(34) + `${N}/${N}`.padEnd(16) +
  `${izlenebilir(true, false)}/${N}`);
console.log("ustune her derleme kaynagi yazar".padEnd(34) + `${N}/${N}`.padEnd(16) +
  `${izlenebilir(true, true)}/${N}`);

// Ters yon: ayni kaynak surumu kac ayri imaj ozeti uretti?
const kaynaktan = new Map();
for (const b of G) kaynaktan.set(b.kaynak, new Set([...(kaynaktan.get(b.kaynak) ?? []), b.imaj]));
const cokluk = [...kaynaktan.entries()].filter(([, s]) => s.size > 1);
console.log(`\ndagitim turu: tasinabilir ${dagitimlar.filter((d) => d.tur === "tasinabilir").length}, ` +
  `surum etiketi ${dagitimlar.filter((d) => d.tur === "surum").length}, ` +
  `dogrudan ozet ${dagitimlar.filter((d) => d.tur === "ozet").length}`);
console.log(`${kaynaktan.size} kaynak surumunun ${cokluk.length} tanesi birden cok imaj ozeti uretti: ` +
  cokluk.map(([k, s]) => `${k} -> ${s.size}`).join(", "));
console.log(`izlenebilirligin bedeli: imaj basina ${ALAN_BAYT} bayt, tam imajin ` +
  `${Math.round(TAM / ALAN_BAYT)}'te 1'i; dagitim kaydina ${N} x 1 alan`);
disiplin                          ozet biliniyor  kaynak okunuyor
kayitta yalniz istenen ad         14/24           9/24
kayitta cozulen ozet de var       24/24           17/24
ustune her derleme kaynagi yazar  24/24           24/24

dagitim turu: tasinabilir 10, surum etiketi 10, dogrudan ozet 4
14 kaynak surumunun 3 tanesi birden cok imaj ozeti uretti: k-002 -> 2, k-010 -> 2, k-011 -> 2
izlenebilirligin bedeli: imaj basina 96 bayt, tam imajin 359375'te 1'i; dagitim kaydina 24 x 1 alan

Üç satır bir merdivendir. Mevcut düzende yirmi dört dağıtımın dokuzunun kaynağı okunabilir. Kayıp iki yerdedir: on dağıtım taşınabilir bir adla yapıldığı için hangi özeti aldığı kayıtta yoktur, ve özeti bilinen dağıtımların bir bölümünde de hedef derleme kaynak alanını yazmamıştır. Kayda çözülen özetin de yazılması oranı 17/24’e çıkarır; kaynak alanının her derlemede yazılması 24/24 yapar.

Değişmez sürüm etiketiyle yapılan on dağıtımın özeti belirlemesi bir varsayıma dayanır: defterin s-N etiketini taşımayı reddetmesi. Bu reddetme bir özellik değil, deponun uyguladığı bir kuraldır — M22/K01’de ölçülen değişmezlik denetiminin buradaki karşılığıdır. Kural uygulanmazsa ilk satırdaki 14 de düşer ve merdivenin ilk basamağı dörde iner.

İkinci sonuç ters yöndedir. On dört kaynak sürümünün üçü birden çok imaj özeti üretmiştir: kaynak değişmeden bağımlılık ya da yapılandırma katmanı değişmiştir. Geriye izlenebilirlik kaynağa kadar götürür, kaynaktan ileriye tek bir nesneye götürmez.

Bu yalıtımın bedeli sayıyla küçüktür. Kaynak alanı imaj başına 96 bayttır — tam imajın 359 binde biri — ve dağıtım kaydına eklenen tek bir alandır. Ölçülen kazanç, 9/24’ten 24/24’e çıkan bir orandır. Yalıtımın delindiği yer ise etiket defterinin kendisidir: defter imajın içinde değil, deponun içindedir. İmaj taşınabilir bir çıktıdır, adı taşınabilir değildir; başka bir depoya kopyalanan imaj etiketlerini yanında götürmez, yalnız özetini götürür.

Özet

  • Etiket üç düzeyli bir zincirdir: etiket bir imaj özetini, imaj özeti bir manifesti, manifest de katman özetlerini gösterir. Etiket bayta değil, listeye işaret eder.
  • 20 derleme 17 ayrı imaj özeti üretmiştir; 3 derleme önceki bir özeti yeniden üretmiştir. Bu, belirlenimci derlemenin görünür kanıtıdır — damgalı derlemede sayı 20 olurdu.
  • 23 etiket 17 özete işaret eder; bir özetin beş adı vardır. Kusur çok adlılık değil, kayda yazılan adın nesneyi belirleyip belirlememesidir.
  • son etiketinin 19 taşımasının 10’unda tek katman, 3’ünde hiçbir katman değişmiştir. Değişen toplam 141,7 MB, aynı imajların toplamı 655,5 MB’dir: paylaşım yükün yüzde 78’ini kaldırır. Etiketin taşınma sıklığı azaldıkça taşıma başına değişen katman sayısı artar.
  • Dağıtımın kaynağına geri izlenebilme oranı kayıt disiplinine bağlıdır: 9/24, çözülen özet de yazılınca 17/24, kaynak alanı her derlemede yazılınca 24/24. Bedeli imaj başına 96 bayt ve kayda tek alandır.

Sonraki Adım

Bu dersin ölçümü bir şeyi sessizce varsaydı: manifestteki her satırın karşılığı bir yerde duruyor. O yer hiç ölçülmedi. On dokuz taşımada değişen 141,7 MB’nin karşılığında değişmeyen 513,8 MB vardır ve bu baytların kaç kopya olduğu katmanların paylaşılıp paylaşılmadığına bağlıdır.

Sonraki ders o yeri kurar ve sayar: aynı katmanı birden çok imaj referans ettiğinde depo gerçekte ne kadar büyüyor, bir imaj silindiğinde kaç katman gerçekten silinebiliyor, saklama kuralı katman referanslarına çarptığında ne oluyor ve yerelde zaten bulunan katman atlandığında indirilen bayt ne kadar düşüyor?

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat