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.
sonetiketinin 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.