İçeriğe geç
academia.sh

Ders 03 / 14

Paket Yöneticileri

Paketler birbirini gerektirdiğinde aynı bildirim dört strateji altında 4 ayrı küme verir ve bunların yalnız 3'ü tutarlıdır; kısıtlar sıkılaştığında iki geri izlemeli strateji çözüm bulamaz ve tutarlı küme sayısı 0'a iner, kilit dosyası ise dördünü de 1'e indirir.

İçindekiler

Önceki dersin ölçümünde her paket kendi aralığından bağımsız seçildi; seçimler birbirine hiç bakmadı. O varsayım tabloyu okunur kıldı ama gerçeği eksik bıraktı: kurulan paketlerin de kendi bildirimleri vardır ve bunlar birbiriyle çelişebilir.

Bu ders o kısıtları tabloya koyar. Sorusu iki katmanlıdır: aynı bildirim, paket gerekleri de hesaba katıldığında hangi kümeleri veriyor, ve bir strateji çelişkili bir küme seçtiğinde bu nereden görülüyor? Yanıtın ikinci yarısı ilkinden önemli çıkacak.

Paket Yöneticisi Ne Yapar

Paket yöneticisi bir araç sınıfının adıdır ve bu kurs hiçbir ürün adı yazmaz; davranışları burada modellenmiştir. Yaptığı iş dört adıma ayrılır: bildirimi okumak, depodan aday sürümleri toplamak, adaylar arasından bir küme seçmek, seçilen kümeyi siteye kurmak. Bu dersin ilgilendiği adım üçüncüsüdür.

Dördüncü adımın nereye yazdığı ilk derste kuruldu: yalıtılmış bir sitede kurulum yalnız o projenin gördüğünü değiştirir, paylaşılan bir sitede ise komşuların gördüğünü de. Bu ders sitenin yalıtılmış olduğunu varsayar ve o eksene bir daha dönmez; buradaki bütün ayrı sonuçlar tek bir sitenin içinde doğar.

Üçüncü adımın tek başına bir adı vardır: çözümleme (resolution). Girdisi bir aralık listesi ve bir aday havuzudur; çıktısı her paket için tam bir sürümdür. Arada duran şey, paket yöneticisinin çözümleme stratejisidir ve önceki derste gösterildiği gibi bu strateji bildirimde yazmaz.

Sürüm numarasının bölümlerinin ne anlattığı ve anlamlı sürümleme, Sürüm Kontrolüne Giriş kursundaki etiketleme dersinde kuruldu; burada tekrarlanmaz. Buradaki soru sürüm numarasının ne söylediği değil, aralıkların birlikte hangi kümeleri mümkün kıldığıdır.

Gerek Tablosu ve Tutarlılık

Kurguya tek bir ekleme yapılır: bir gerek tablosu. Tablo, her paket sürümünün hangi paketten hangi aralığı istediğini yazar. Depo ve projenin bildirimi ortak tanımdan birebir gelir ve değişmez; eklenen şey paketlerin kendi istekleridir.

Tablonun kurguda kurduğu gerilim tek cümleyle okunur: olcum’un yeni sürümleri ortak’ın yeni sürümlerini ister, rapor’un yeni sürümü ise ortak’ın eski sürümlerini. İkisini de en yeni haliyle isteyen bir kurulum, ortak için aynı anda iki ayrı şey istemiş olur.

Buradan ölçümün ikinci kavramı doğar. Bir küme tutarlıdır ancak ve ancak seçilen her sürümün gereği, kümedeki öbür seçimlerce karşılanıyorsa. Tutarlılık kurulumun başarısıyla aynı şey değildir: tutarsız bir küme de siteye kurulabilir, çünkü kurulum bir dosya yazmadır ve gerek tablosunu okumak zorunda değildir.

Dört Strateji

Ölçüm dört strateji karşılaştırır. İlk ikisi bağımsız seçicidir: her paketi kendi aralığının bir ucundan alır ve gerek tablosuna hiç bakmaz — önceki dersin iki stratejisi budur. Kalan ikisi geri izlemelidir: bir sürüm seçer, kısıtları sınar, tutmadığında geri döner ve başka bir sürüm dener.

Geri izlemeli iki stratejinin farkı yalnız arama sırasıdır: hangi paketin sürümüne önce karar verildiği. Aynı bildirim, aynı gerek tablosu, aynı depo — değişen tek şey sıradır. Bu fark ölçümün en önemli satırını üretecek.

Ölçümün varsayımları:

  • OB24 — Depo, bildirim ve aralık kuralı ortak tanımdan birebir alınır; ders ikisinin de davranışını değiştirmez. Eklenen tek şey gerek tablosudur.
  • OB25 — Gerek tablosu kurgudur ve kâhinin parçasıdır: hangi sürümün neyi istediğini biz yazdık, bu yüzden her kümenin tutarlı olup olmadığı ölçmeden bilinir.
  • OB26 — Bir paket sürümü en çok bir gerek taşır ve gerek bir aralıktır. Zincirin derinliği bir düzeydir; daha derin zincirler sayıyı büyütür, kuralı değiştirmez.
  • OB27 — Bağımsız stratejiler gerek tablosunu okumaz. Kurdukları küme tutarsız olabilir ve kurulum yine tamamlanır.
  • OB28 — Geri izleme, arama sırasındaki her pakete adayları strateji yönünde dener ve kısmi kümeyi her adımda sınar. İlk tutarlı tam kümeyi döndürür.
  • OB29 — Kısmi kümenin sınanmasında yalnız iki ucu da seçilmiş gerekler denetlenir; hedefi henüz seçilmemiş bir gerek o adımda ihlal sayılmaz.
  • OB30 — İki arama sırası denenir: olcum, ortak, rapor ve rapor, ortak, olcum. Sıra bir yapılandırma ayrıntısıdır; proje onu bildirimde yazmaz.
  • OB31 — Sıkı gerek tablosu, aynı depoda olcum’un bütün uygun sürümlerinin ortak’ın en yeni sürümünü, rapor’un bütün uygun sürümlerinin ise daha eskisini istemesiyle türetilir. Kesişimi boş olan bir bildirim kümesini modeller.
  • OB32 — Çözüm bulunamadığında geri izleme None döndürür ve bu bir hata değil, ölçümün bir sonucudur: tutarlı küme sayısı sıfırdır.
  • OB33 — Kilit, tutarlı kümelerden birinin — geri izlemeli en yeni stratejisinin sonucunun — kopyasıdır. Kilit varken çözümleme çağrılmaz.
  • OB34 — Sürüm numaraları kurgu paketlerin kurgu sürümleridir.
  • OB35Gerçek kurulum yapılmaz, gerçek paket indirilmez; çözümleme bir sözlük döndürür.
  • OB36 — Süre ölçülmez. Sayılan şey ayrı küme, ayrı tutarlı küme ve kilitli kurulumun verdiği ayrı sonuç sayısıdır.

Ölçüm

"""Cozumleme stratejileri: ayni bildirim, ayri kume; cakisma dogdugunda ne oluyor."""

DEPO = {
    "olcum": [(1, 0), (1, 1), (1, 2), (2, 0)],
    "rapor": [(0, 9), (1, 0), (1, 1)],
    "ortak": [(3, 0), (3, 1), (3, 2), (4, 0)],
}
BILDIRIM = {"olcum": ((1, 0), (2, 0)), "rapor": ((1, 0), (2, 0)),
            "ortak": ((3, 0), (4, 0))}
PAKETLER = ("olcum", "ortak", "rapor")

# Paketlerin kendi bagimliliklari: surum -> (hedef paket, alt, ust)
GEREK = {
    ("olcum", (1, 0)): ("ortak", (3, 0), (4, 0)),
    ("olcum", (1, 1)): ("ortak", (3, 1), (4, 0)),
    ("olcum", (1, 2)): ("ortak", (3, 2), (4, 0)),
    ("rapor", (0, 9)): ("ortak", (3, 0), (3, 1)),
    ("rapor", (1, 0)): ("ortak", (3, 0), (4, 0)),
    ("rapor", (1, 1)): ("ortak", (3, 0), (3, 2)),
}
# Ayni depo, daha sikici bir gerek tablosu: olcum'un uc surumu de yeni ortak istiyor.
SIKI = dict(GEREK)
SIKI[("olcum", (1, 0))] = ("ortak", (3, 2), (4, 0))
SIKI[("olcum", (1, 1))] = ("ortak", (3, 2), (4, 0))
SIKI[("rapor", (1, 0))] = ("ortak", (3, 0), (3, 2))


def uygun(paket):
    alt, ust = BILDIRIM[paket]
    return [s for s in DEPO[paket] if alt <= s < ust]


def coz(strateji="en yeni"):
    """Bagimsiz secim: her paket kendi araliginin ucundan alinir."""
    secim = {}
    for paket in sorted(BILDIRIM):
        adaylar = uygun(paket)
        secim[paket] = adaylar[-1] if strateji == "en yeni" else adaylar[0]
    return secim


def tutarli(secim, gerek):
    """Secilen surumlerin gerekleri, secilmis olan paketlerce karsilaniyor mu."""
    for paket, surum in secim.items():
        k = gerek.get((paket, surum))
        if k is None:
            continue
        hedef, alt, ust = k
        if hedef in secim and not alt <= secim[hedef] < ust:
            return False
    return True


def geri_izle(sira, gerek, strateji="en yeni"):
    """Cakisma dogdugunda geri donup baska surum dener; sira arama sirasidir."""
    def ilerle(i, secim):
        if i == len(sira):
            return dict(secim)
        paket = sira[i]
        adaylar = uygun(paket)
        if strateji == "en yeni":
            adaylar = adaylar[::-1]
        for surum in adaylar:
            secim[paket] = surum
            if tutarli(secim, gerek):
                sonuc = ilerle(i + 1, secim)
                if sonuc is not None:
                    return sonuc
            del secim[paket]
        return None
    return ilerle(0, {})


def yazim(secim):
    if secim is None:
        return f"{'çözüm yok':>23s}"
    return " ".join(f"{'.'.join(map(str, secim[p])):>7s}" for p in PAKETLER)


def kur(kilit_dosyasi, islev, gerek):
    """Kilit varsa cozumleme yapilmaz; yoksa karari strateji verir."""
    return dict(kilit_dosyasi) if kilit_dosyasi else islev(gerek)


STRATEJILER = (
    ("bağımsız, en yeni", lambda g: coz("en yeni")),
    ("bağımsız, en eski", lambda g: coz("en eski")),
    ("geri izlemeli, en yeni", lambda g: geri_izle(("olcum", "ortak", "rapor"), g)),
    ("geri izlemeli, rapor önce", lambda g: geri_izle(("rapor", "ortak", "olcum"), g)),
)


def tablo(baslik, gerek):
    print(f"{baslik:<26s} {'olcum':>7s} {'ortak':>7s} {'rapor':>7s}  tutarlı")
    kumeler, saglam = [], []
    for ad, islev in STRATEJILER:
        secim = islev(gerek)
        durum = secim is not None and tutarli(secim, gerek)
        if secim is not None:
            kumeler.append(tuple(sorted(secim.items())))
            if durum:
                saglam.append(tuple(sorted(secim.items())))
        print(f"{ad:<26s} {yazim(secim)}  {'evet' if durum else 'hayır':>7s}")
    print(f"dört strateji: {len(set(kumeler))} ayrı küme, "
          f"{len(set(saglam))} ayrı tutarlı küme")


tablo("gerek tablosu", GEREK)
print()
tablo("sıkı gerek tablosu", SIKI)
print()
kilit_dosyasi = geri_izle(("olcum", "ortak", "rapor"), GEREK)
kilitli = {tuple(sorted(kur(kilit_dosyasi, islev, GEREK).items()))
           for _, islev in STRATEJILER}
print("kilide yazılan küme:      " + yazim(kilit_dosyasi))
print(f"kilit dosyası varken dört strateji: {len(kilitli)} ayrı küme")
gerek tablosu                olcum   ortak   rapor  tutarlı
bağımsız, en yeni              1.2     3.2     1.1    hayır
bağımsız, en eski              1.0     3.0     1.0     evet
geri izlemeli, en yeni         1.2     3.2     1.0     evet
geri izlemeli, rapor önce      1.1     3.1     1.1     evet
dört strateji: 4 ayrı küme, 3 ayrı tutarlı küme

sıkı gerek tablosu           olcum   ortak   rapor  tutarlı
bağımsız, en yeni              1.2     3.2     1.1    hayır
bağımsız, en eski              1.0     3.0     1.0    hayır
geri izlemeli, en yeni                   çözüm yok    hayır
geri izlemeli, rapor önce                çözüm yok    hayır
dört strateji: 2 ayrı küme, 0 ayrı tutarlı küme

kilide yazılan küme:          1.2     3.2     1.0
kilit dosyası varken dört strateji: 1 ayrı küme

Dört Strateji, Dört Küme

Üst tablonun dört satırı 4 ayrı küme veriyor ve dördü de aynı bildirimden çıkıyor. Bu, önceki dersin iki kümesinin üstüne iki tane daha ekliyor; eklenen ikisi bağımsız seçimin ulaşamayacağı kümeler.

İlk satır kursun bu dersteki asıl bulgusudur. Bağımsız en yeni stratejisi 1.2 / 3.2 / 1.1 kümesini seçiyor ve bu küme tutarsız: rapor 1.1, ortak için 3.2’den eskisini istiyor, ama kümede ortak 3.2 var. Buna karşın kurulum tamamlanıyor. Hiçbir hata iletisi doğmuyor, çünkü bağımsız strateji gerek tablosunu hiç okumadı. Sonuç, sitede duran ve birbirini istemeyen üç paket.

İkinci satır bağımsız en eski stratejisinin tesadüfen tutarlı bir küme kurduğunu gösteriyor. Tesadüf sözcüğü burada tam yerindedir: strateji yine gerek tablosunu okumadı, yalnızca aralıkların alt uçları çakışmadı. Aynı strateji başka bir tabloyla tutarsız bir küme kurardı — nitekim alt tabloda kuruyor.

Son iki satır geri izlemeli stratejileri veriyor ve ikisi de tutarlı, ama ayrı: 1.2 / 3.2 / 1.0 ile 1.1 / 3.1 / 1.1. İkisi arasında tek fark arama sırasıdır — hangi paketin sürümüne önce karar verildiği. Bildirim aynı, depo aynı, kısıtlar aynı; yine de iki ayrı meşru kurulum. Bu satır, çözümleyicinin kendisinin bir ayrı sonuç ekseni olduğunu söylüyor: aracı değiştirmek, bildirimi değiştirmeden kurulumu değiştirebilir.

Toplam: dört strateji, 4 ayrı küme, bunların 3’ü tutarlı.

Çakışma Nereye Yazılır

Alt tablo kısıtları sıkılaştırıyor: bu tabloda olcum’un bütün uygun sürümleri ortak’ın en yenisini, rapor’un bütün uygun sürümleri ise daha eskisini istiyor. İki isteğin kesişimi boş.

Geri izlemeli iki strateji de çözüm yok döndürüyor. Tutarlı küme sayısı 0. Bu bir başarısızlık gibi görünür ve bir anlamda öyledir — ama ölçümün asıl bulgusu üstteki iki satırdadır: bağımsız stratejiler yine bir küme döndürüyor. Aynı çelişki, okuyan araca göre ya bir ret ya sessiz bir kurulum üretiyor.

İkisi arasındaki fark, hatanın nerede görüneceğidir. Ret, çözümleme anında görünür ve elde bir bilgi bırakır: bu bildirim kümesi çelişkilidir, ya bir aralık gevşetilecek ya bir paket değiştirilecektir. Sessiz kurulum ise hiçbir şey bırakmaz; çelişki siteye kurulur ve ancak çalışma zamanında, çelişen iki paketin karşılaştığı satırda ortaya çıkar. Ve o satıra her koşumda uğranmaz.

Ölçünün diliyle: ret 0 ayrı sonuç üretir ve sıfır, sayılabilir bir yanıttır. Sessiz kurulum 1 ayrı sonuç üretir ama o sonucun geçerli olup olmadığını ölçmez. Bir çözümleyicinin çözemediğini söylemesi, çözemediğini söylememesinden bilgi açısından üstündür.

Çözümleyicinin Kendisi Yeniden Üretilebilir mi

Ölçüm dört stratejiyi karşılaştırdı, ama her stratejinin kendi içinde kaç sonuç verdiğini de sormak gerekir. Modeldeki dört stratejinin dördü de belirlenimcidir: aday listesi depodan sıralı gelir, arama sırası sabittir, hiçbir yerde rastgelelik yoktur. Aynı strateji aynı girdiyle çağrıldığında 1 ayrı sonuç verir.

Bu, bir çözümleyiciden istenecek en temel özelliktir ve kendiliğinden gelmez. Aday havuzu birden çok kaynaktan toplanıyorsa hangi kaynağın önce yanıtladığı sıraya karışabilir; bir önbellek ısındığında aynı sorgu ayrı bir liste döndürebilir; paralel indirme kurulum sırasını değiştirebilir. Bunların hiçbiri stratejinin kuralını değiştirmez, ama hepsi girdisini değiştirir — ve girdisi değişen bir kural ayrı bir küme verir.

Bu yüzden bir çözümleyicinin sözü iki katmanlıdır. Birinci katman kuraldır: hangi aday seçilir. İkinci katman kuralın girdisidir: adayların hangi düzende, hangi kaynaktan ve hangi anda toplandığı. Yeniden üretilebilir bir kurulum ikisini birden sabitlemeyi gerektirir, ve ikinci katmanı yazıya geçiren belge kilit dosyasıdır.

Kilidin Bu Tablodaki Yeri

Son iki satır önceki dersin sonucunu bu tablonun üstüne koyuyor. Tutarlı kümelerden biri — geri izlemeli en yeni stratejisinin bulduğu 1.2 / 3.2 / 1.0 — kilide yazıldığında dört strateji de aynı kümeyi kuruyor: 1 ayrı sonuç.

Kilidin burada kapattığı eksen yenidir. Önceki derste kapatılanlar strateji yönü ve deponun zamanıydı; burada kapatılan çözümleyicinin kendisi. Kilit yazıldıktan sonra hangi paket yöneticisinin kullanıldığı sonucu değiştirmiyor, çünkü çözümlenecek bir şey kalmadı.

Bu, kilidin ne kadar iş yaptığını da sınırlıyor. Kilit, kilidi üreten çözümleyicinin kararını taşır; iyi bir kararı da kötü bir kararı da aynı sadakatle. Üstteki tabloda üç tutarlı kümeden hangisinin kilide yazıldığı, kilide bakılarak anlaşılmaz — kilit yalnız seçileni yazar, seçme gerekçesini değil.

Özet

  • Paket yöneticisi bir araç sınıfıdır; işi bildirimi okumak, aday toplamak, bir küme seçmek ve kurmaktır. Ayrı sonucu üreten adım seçme adımıdır.
  • Paketlerin kendi gerekleri hesaba katıldığında aynı bildirim dört strateji altında 4 ayrı küme verir ve bunların 3’ü tutarlıdır.
  • Bağımsız seçim gerek tablosunu okumaz: 1.2 / 3.2 / 1.1 kümesi tutarsız olduğu halde kurulur ve hiçbir uyarı üretmez.
  • İki geri izlemeli strateji ayrı arama sırası yüzünden iki ayrı tutarlı küme verir; çözümleyicinin kendisi bir ayrı sonuç eksenidir.
  • Kesişimi boş kısıtlarda geri izleme 0 tutarlı küme döndürür; ret çözümleme anında bilgi bırakır, sessiz kurulum ise çelişkiyi çalışma zamanına erteler.
  • Kilit dosyası dört stratejiyi 1 ayrı sonuca indirir, ama yazdığı kararın hangi gerekçeyle seçildiğini taşımaz.

Sonraki Adım

Bu dersin bütün kümeleri tek bir yorumlayıcı varsayıldığı için karşılaştırılabildi. O varsayım da tıpkı önceki iki varsayım gibi yazılı değildi. Sonraki ders onu ölçüme sokar: aynı proje, aynı bildirim, ayrı yorumlayıcı sürümleri. Sorulacak olan şudur — çözümleme yorumlayıcıya göre kaç ayrı küme veriyor, ve bir yorumlayıcıda üretilmiş kilit dosyası bir başkasında ne yapı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