İçeriğe geç
academia.sh

Ders 08 / 12

Alt Modüller

Alt modül ana depoya bir tarihçe değil bir kimlik yazar: üç alt modül bir işlemeyi dört ayrı tarihçeye bağlar, 76 nesnelik 38 işleme 378 alt modül işlemesini içeri alır ve özyinelemeli klon 920 nesneden 4540'a çıkar.

İçindekiler

Buraya kadar tarihçe tek bir deponun içindeydi. İkili arama, suçlama ve yeniden yazma ölçüldü; nesne sayısı bu ölçümlerin arka planında durdu — bedeli belirleyen değişkendi ama ölçülen şeyin kendisi değildi.

Bu konuda arka plan öne geçiyor. Depo büyüdüğünde ve tek bir tarihçeye sığmayan parçalar taşımaya başladığında sorulan soru değişir: nesne sayısının kendisi iş olursa ne olur? İlk durum, bir deponun başka bir deponun tarihçesini içine alması. Bu dersin sorusu alt modülün nasıl kurulduğu değil — kurulumu iki komuttan ibarettir. Soru şudur: ana depoya yazılan tek bir kimlik, o depodaki bir işlemeyi kaç ayrı tarihçeye bağlar ve klon bedeli buna nasıl tepki verir?

Ana Depo Neyi Kaydeder

Alt modül (submodule), bir deponun çalışma ağacında duran ve kendi tarihçesi olan başka bir depodur. Ana depo onun dosyalarını kendi nesne deposuna kopyalamaz; kaydettiği tek şey alt modülün hangi işlemede durduğudur. Bu kayda sabitlenmiş sürüm (pinned version) denir ve ana depo ağacında bir dizin girdisi olarak durur.

İki dosya işin tamamıdır. .gitmodules alt modülün adını ve nereden getirileceğini bildirir; ağaç girdisi ise sabitlenmiş sürümün kimliğini tutar. Birincisi işlenen bir metin dosyasıdır, ikincisi her işlemede yeniden yazılabilen bir alandır.

# öğretilen komutlar ve dosya içeriği — örnek döküm, çalıştırılmamıştır

git submodule add <alt-modül-adresi> bilesenler/olcum-cekirdegi
git submodule update --init --recursive
git clone --recurse-submodules <ana-depo-adresi>

# .gitmodules
[submodule "bilesenler/olcum-cekirdegi"]
	path = bilesenler/olcum-cekirdegi
	url = <alt-modül-adresi>

--recurse-submodules seçeneği klonlamayı ana depoyla bitirmez: her alt modülü ayrı ayrı klonlar. Seçeneksiz klon alt modül dizinlerini boş bırakır; ana depo tarihçesi eksiksiz gelir ama çalışma ağacı çalışmaz. update --init sonradan aynı işi yapar.

Sabitlenmiş Sürümün İki Yüzü

Sabitlenmiş sürüm ana depoda ucuz, ana depo dışında pahalıdır ve dersin bütün gerilimi buradadır.

Ucuz yüzü: alt modülü ilerletmek ana depoda tek bir işlemedir. Ağaç girdisindeki kimlik değişir, yeni bir ağaç ve mesajı taşıyan bir damla yazılır — iki nesne. Alt modülde o aralıkta kaç işleme birikmiş olursa olsun, ana depoya yazılan nesne sayısı bundan bağımsızdır.

Pahalı yüzü: o iki nesne, alt modül tarihçesindeki bir işlemeyi ana depo tarihçesine bağlar. Ana depodaki bir işlemeyi yeniden üretmek artık tek bir tarihçeye erişmeyi değil, ana depo ile her alt modülün tarihçesine birden erişmeyi gerektirir. Üç alt modülü olan bir depoda, tek bir işlemenin ağacını kurmak için dört ayrı tarihçeden dört kimlik okunmalıdır.

Bu ikinci yüz ölçülebilir bir şeydir ve ölçüm iki soruyu ayırır: ana depoda yazılan nesne kaçtır, ve o yazımın bağladığı tarihçe ne kadardır.

Dalı Değil İşlemeyi İzler

Sabitlenmiş sürüm bir işleme kimliğidir, bir dal adı değil. Bunun doğrudan bir sonucu var: alt modül dizini klonlandıktan sonra hiçbir dalın üstünde durmaz — ayrık HEAD durumundadır. Ayrık HEAD, Dallanma ve İşbirliği kursunda tarihçenin dışına düşen işleme bağlamında kurulmuştu; burada bir kaza değil, alt modülün normal durumudur. Ana depo bir dalı sabitleyemez, çünkü dal hareket eder ve hareket eden bir başvuru sabitlenmiş sürüm olamaz.

# öğretilen komutlar — örnek döküm, çalıştırılmamıştır

git -C bilesenler/olcum-cekirdegi checkout ana
git -C bilesenler/olcum-cekirdegi pull
git add bilesenler/olcum-cekirdegi
git commit -m "Ölçüm çekirdeği sabitlenmiş sürümü ilerletildi"

git submodule update --remote bilesenler/olcum-cekirdegi
git submodule status

İlerletme dört adımdır ve dördü de elle yapılır: alt modülde bir dala geçilir, yeni işlemeler getirilir, ana depoda alt modül dizini hazırlık alanına alınır ve işlenir. Üçüncü adım atlanırsa alt modül dizini yeni bir işlemeyi gösterir ama ana depo hâlâ eskisini kaydeder; status çıktısı bunu bildirir, tarihçe bildirmez. --remote seçeneği ilk iki adımı .gitmodules dosyasında yazılı dala göre otomatikleştirir, ama üçüncü adımı yine yazan atar: ana depoya yazılmayan bir ilerletme yoktur.

Bu, alt modülü bir bağımlılık yöneticisinden ayıran yerdir. Bağımlılık yöneticisi bir aralık bildirir ve çözümü kendisi yapar; alt modül tek bir kimlik bildirir ve çözüm diye bir şey yoktur. Karşılığında alt modül tam tarihçeyi getirir: sabitlenmiş sürüme kadar olan her işleme oradadır, okunabilir ve üstünde arama yapılabilir.

Ölçümün Varsayımları

  • BD1 — Ana depo ortak kurgunun 200 işlemelik ölçeğidir; üç alt modülün her biri aynı kurgudan ayrı bir tohumla üretilmiş bağımsız bir tarihçedir. Alt modül tarihçeleri ana depoyla hiçbir nesne paylaşmaz.
  • BD2 — Sabitlenmiş sürümü ilerleten ana depo işlemeleri ayrı bir üreteçten seçilir; her ilerletme alt modülde 1 ile 20 arası işleme tüketir ve alt modülün sonunu aşamaz.
  • BD3 — Sabitlenmiş sürümü ilerleten işleme ana depoda 2 nesne yazar: yeni ağaç ve mesajı taşıyan damla. Bu sayı, alt modülde kaç işleme geçildiğinden bağımsızdır.
  • BD4 — “Kapsanan işleme”, alt modül tarihçesinde ana deponun ucuna kadar tüketilmiş işleme sayısıdır; ana depo tarihçesinde görünmez ama ana deponun ucundaki durumu yeniden üretmek için gereklidir.
  • BD5 — “Gereken kimlik”, ana depodaki tek bir işlemenin ağacını kurmak için okunması gereken kimlik sayısıdır: ana deponun kendi kimliği artı her alt modülün sabitlenmiş sürümü.
  • BD6 — Özyinelemeli klon her alt modülün tam tarihçesini getirir. Bedel dokunulan nesne birimiyle sayılır; ağ, saat ve disk ölçümün dışındadır.

Ölçüm

"""Alt moduller: sabitlenmis surumun bagladigi tarihce ve klon bedeli.

Bolum 1 - her alt modulun ilerletme sayisi ve klon nesnesi.
Bolum 2 - alt modul sayisi arttikca bagli tarihce ve ozyinelemeli klon.
"""
TOHUM = 20260814
DOSYALAR = ("olcum.py", "rapor.py", "kimlik.py", "ayar.py", "belge.md")
ANA_OLCEK = 200
ALT_MODULLER = (("olcum-cekirdegi", 300, TOHUM + 1),
                ("rapor-bicimi", 150, TOHUM + 2),
                ("kimlik-kitapligi", 80, TOHUM + 3))


def uretec(tohum):
    d = tohum % 2147483646 + 1

    def r(n):
        nonlocal d
        d = (d * 48271) % 2147483647
        return d % n
    return r


def tarihce(n, tohum=TOHUM):
    """n islemelik dogrusal tarihce; her isleme bir dosyaya dokunuyor."""
    r, liste = uretec(tohum), []
    for i in range(n):
        dosya = DOSYALAR[r(5)]
        ikili = r(11) == 0
        liste.append({"no": i + 1, "dosya": dosya, "ikili": ikili,
                      "nesne": 2 + (40 if ikili else 0)})
    return liste


def klon_bedeli(t, ikili_dahil=True):
    return sum(x["nesne"] for x in t if ikili_dahil or not x["ikili"])


def sabitlemeler(ana, alt, tohum):
    """Ana depodaki hangi islemeler sabitlenmis surumu ilerletiyor."""
    r, kayit, yer = uretec(tohum), [], 0
    for x in ana:
        ilerlet = r(12) == 0
        adim = 1 + r(20)
        if ilerlet and yer < len(alt):
            yer = min(yer + adim, len(alt))
            kayit.append({"ana_no": x["no"], "sabit": yer})
    return kayit


ana = tarihce(ANA_OLCEK)
print(f"ana depo {len(ana)} isleme, klon nesnesi {klon_bedeli(ana)}, "
      f"ikilisiz {klon_bedeli(ana, False)}")
print()
print("alt modul           isleme  ilerletme  kapsanan isleme  ana depoda nesne"
      "  klon nesnesi")
kayitlar = []
for ad, n, tohum in ALT_MODULLER:
    alt = tarihce(n, tohum)
    s = sabitlemeler(ana, alt, tohum + 100)
    kayitlar.append((ad, alt, s))
    print(f"  {ad:18s} {n:6d} {len(s):10d} {s[-1]['sabit']:16d} "
          f"{len(s) * 2:17d} {klon_bedeli(alt):13d}")
print()
print("alt modul sayisi  bagli tarihce  gereken kimlik  ana klon nesnesi"
      "  ozyinelemeli klon nesnesi   kat")
for k in range(len(ALT_MODULLER) + 1):
    ozyinelemeli = klon_bedeli(ana) + sum(klon_bedeli(a) for _, a, _ in kayitlar[:k])
    print(f"{k:16d} {k + 1:14d} {k + 1:15d} {klon_bedeli(ana):17d} "
          f"{ozyinelemeli:25d} {ozyinelemeli / klon_bedeli(ana):5.2f}")
print()
toplam_ilerletme = sum(len(s) for _, _, s in kayitlar)
toplam_kapsanan = sum(s[-1]["sabit"] for _, _, s in kayitlar)
print(f"sabitlemeyi ilerleten ana depo islemesi {toplam_ilerletme}, "
      f"ana depoya yazdigi nesne {toplam_ilerletme * 2}, "
      f"bagladigi alt modul islemesi {toplam_kapsanan}")
print(f"ana depo tarihcesi {len(ana)} isleme gorunuyor; "
      f"kapsadigi isleme {len(ana) + toplam_kapsanan}")
ana depo 200 isleme, klon nesnesi 920, ikilisiz 374

alt modul           isleme  ilerletme  kapsanan isleme  ana depoda nesne  klon nesnesi
  olcum-cekirdegi       300         18              161                36          2200
  rapor-bicimi          150         14              137                28           980
  kimlik-kitapligi       80          6               80                12           440

alt modul sayisi  bagli tarihce  gereken kimlik  ana klon nesnesi  ozyinelemeli klon nesnesi   kat
               0              1               1               920                       920  1.00
               1              2               2               920                      3120  3.39
               2              3               3               920                      4100  4.46
               3              4               4               920                      4540  4.93

sabitlemeyi ilerleten ana depo islemesi 38, ana depoya yazdigi nesne 76, bagladigi alt modul islemesi 378
ana depo tarihcesi 200 isleme gorunuyor; kapsadigi isleme 578

Bağlanan Tarihçe

Son iki satır dersin çekirdeğini veriyor. Ana depoda sabitlemeyi ilerleten 38 işleme var ve bu işlemeler ana depoya toplam 76 nesne yazıyor — iki yüz işlemelik tarihçenin 920 nesnesinin içinde küçük bir paydır. Aynı 38 işleme, alt modül tarihçelerinden 378 işlemeyi ana depoya bağlıyor.

Oran doğrudan okunur: ana depoya yazılan her 2 nesne, ortalama on alt modül işlemesini içeri alıyor. Bu, dersin ölçtüğü asimetridir. Ana depo tarihçesine bakan biri 200 işleme görür; ana deponun ucundaki durumu yeniden üretmek için gereken işleme sayısı 578’dir. Görünen tarihçe ile kapsanan tarihçe aynı şey değildir ve aradaki fark ana depoda hiçbir yerde yazılı değildir.

Bu asimetrinin bir tanı sonucu var. Ana depoda yürütülen bir arama yalnız ana deponun 200 işlemesini tarar; alt modüllerin 378 kapsanan işlemesi o taramanın dışındadır. Bir kusur alt modülde girmişse ana depodaki arama onu bulamaz — bulabileceği en dar aralık, kusuru içeri alan sabitleme işlemesidir. Aramanın ikinci turu alt modülün kendi tarihçesinde yeniden kurulmak zorundadır. Ana depoda daralan aralık iki işleme olsa bile, o iki işlemenin arasına sıkışmış alt modül işlemesi sayısı yirmiye kadar çıkabilir.

İkinci tablonun ilk iki sütunu aynı şeyi kimlik cinsinden söylüyor. Alt modül yokken bir işlemenin ağacını kurmak 1 kimlik ister ve 1 tarihçeye bakar. Üç alt modülle bu sayı 4’e çıkar. Dördü de bulunmak zorundadır: alt modüllerden biri erişilemezse ana depodaki işleme eksiksiz olarak durur ama yeniden üretilemez. Ana deponun tarihçesi bozulmamıştır; eksik olan başka bir tarihçedir.

Klon Bedelinin Toplanması

Alt tablonun sağ üç sütunu klon bedelini veriyor ve birim dokunulan nesnedir.

Ana depo tek başına 920 nesne. Alt modüller sırasıyla 2200, 980 ve 440 nesne getiriyor. Üçü de eklenince özyinelemeli klon 4540 nesneye çıkıyor — ana depo klonunun 4,93 katı. Ana depo tarihçesi bu sırada bir işleme bile büyümedi.

En büyük katkı ilk alt modülden geliyor ve nedeni tabloda yazılı: 300 işlemelik tarihçesi ana depodan büyük. Alt modülün boyu ana deponun boyuyla ilgisizdir; ana depo onu sabitleyen kimliği yazarken alt modülün büyüklüğüne bakmaz. Ana deposu küçük, klon bedeli büyük bir düzenlemenin önünde hiçbir engel yoktur.

Tablonun sağ sütunundaki kat sayısı doğrusal artmıyor: 3,39, sonra 4,46, sonra 4,93. Artış her adımda küçülüyor çünkü eklenen alt modüller giderek daha kısa. Sıra ters olsaydı sayılar başka görünürdü ama son satır aynı kalırdı — toplam, sıradan bağımsızdır. Kat sayısının kendisi de bir şey söylemiyor; söyleyen, alt modül tarihçelerinin toplamının ana depo tarihçesinden üç kattan fazla olmasıdır. Bu oran, ana depoya bakan hiçbir ölçümde görünmez.

Özyineleme bir katmanla da sınırlı değildir. Bir alt modülün kendi alt modülü varsa --recursive seçeneği onu da getirir ve bağlı tarihçe sayısı beşe, gereken kimlik sayısı beşe çıkar. Ölçüm bunu kurmuyor, ama düzenin kuralı değişmiyor: her katman ana depoya iki nesne yazar ve arkasına kendi tarihçesinin tamamını bağlar.

Buradan iki pratik sonuç çıkar. Birincisi: özyinelemeli olmayan klon ana depo tarihçesini eksiksiz getirir ve alt modüllerin hiçbir nesnesini getirmez; bu, tarihçeyi okumak isteyen biri için doğru seçimdir. İkincisi: çalışma ağacına ihtiyacı olan biri özyinelemeli klon yapmak zorundadır ve tabloda okunan katı öder. Aynı depoda iki ayrı bedel vardır ve hangisinin ödendiğini kullanılan seçenek belirler.

Kırılan Bağ ve Kurtarma

Sabitlenmiş sürüm bir kimliktir ve kimlik, işaret ettiği işleme erişilebilir olduğu sürece geçerlidir. Alt modülün yukarı deposunda tarihçe yeniden yazılırsa — konunun ilk dersinde ölçülen işlem — eski kimlikler artık hiçbir işlemeyi göstermez. Ana depodaki 38 ilerletme işlemesinden kaçının kırılacağı, yeniden yazmanın hangi noktadan başladığına bağlıdır.

Bu bir veri kaybı değildir ama ana depo tarihçesinin geçmiş noktalarını yeniden üretilemez hâle getirir ve kaybın kaydı ana depoda tutulmaz. Kurtarma yolu üç adımlıdır. Alt modülün eski işlemeleri hâlâ bir yerde duruyorsa — bir kopyada, bir yedek dalda ya da referans günlüğü penceresi kapanmamışsa — o işlemeler ayrı bir başvurudan geri getirilebilir ve kimlikler yeniden çözülür. Duruyorsa. İkinci yol, ana depoda sabitlenmiş sürümleri yeni kimliklere taşıyan bir düzeltme işlemesi yazmaktır; bu geçmişi kurtarmaz, yalnız ucu onarır. Üçüncüsü ve en ucuzu, kaybı hiç doğurmamaktır: alt modül olarak bağlanan bir depoda tarihçe yeniden yazılmadan önce, o depoyu sabitleyen ana depoların bilinmesi gerekir. Bağın yönü tek taraflıdır — alt modül kendisini kimin sabitlediğini bilmez.

Özet

  • Alt modül, ana depoya bir tarihçe değil bir kimlik yazar; kayıt .gitmodules dosyası ile ağaç girdisindeki sabitlenmiş sürümden ibarettir.
  • Sabitlenmiş sürümü ilerletmek ana depoda 2 nesne yazar ve bu sayı alt modülde kaç işleme geçildiğinden bağımsızdır; ölçümde 76 nesne, 378 alt modül işlemesini bağlar.
  • Ana depo tarihçesi 200 işleme görünür; ucundaki durumu yeniden üretmek için gereken işleme sayısı 578’dir ve bu fark ana depoda yazılı değildir.
  • Üç alt modülle bir işlemenin ağacını kurmak 4 ayrı tarihçeden 4 kimlik ister; biri erişilemezse işleme bozulmaz ama yeniden üretilemez.
  • Özyinelemeli klon 920 nesneden 4540 nesneye çıkar — 4,93 kat; özyinelemesiz klon ana depo tarihçesini eksiksiz getirir ve alt modülden 0 nesne alır.

Sonraki Adım

Alt modülde bedeli büyüten şey işleme sayısıydı: üç yüz işlemelik bir tarihçe, seksen işlemelik olandan beş kat fazla nesne getirdi. Bu, nesne sayısının işleme sayısını izlediği bir durumdur ve sezgiye uyar. Sonraki ders sezginin bozulduğu duruma bakar: aynı tarihçede işlemelerin onda birinden azı toplam nesnenin üçte ikisinden fazlasını üretirse, tarihçeyi ağırlaştıran şeyin ne olduğu sorusu yeniden sorulmak zorundadır — ve yanıt işleme sayısı değildir. O durumda depoyu bölmek çare olmaz, çünkü ağırlık işlemelerin dağılımından değil taşıdıkları nesnenin türünden gelir; tarihçeden çıkarılması gereken şey bir depo değil, bir dosya sınıfıdır.

İ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