İçeriğe geç
academia.sh

Ders 10 / 12

Çoklu Çalışma Ağacı

Ek çalışma ağacı nesne deposunu paylaşır ve 0 nesne kopyalar: bin işlemelik tarihçede dört dal için klon düzeni 22560 nesne yazarken ağaç düzeni 5640'ta kalır, kazanılan 16920 nesnenin 11466'sı ikilidir.

İçindekiler

Önceki ders klon bedelini üçte bire indirdi ama bedeli ortadan kaldırmadı: tabloda hâlâ klon yazıyordu ve klon her yapıldığında yeniden ödeniyordu. Bu, bir varsayımı da beraberinde taşır — aynı depoda iki dal üzerinde birlikte çalışmak için ikinci bir kopya gerektiği varsayımını.

Varsayım doğru değildir. Deponun iki bileşeni vardır ve ayrı ayrı çoğaltılabilirler: bir nesne deposu ve bir çalışma ağacı. Klon ikisini birden kopyalar. Bu dersin sorusu şudur: nesne deposu tek bırakılıp çalışma ağacı çoğaltılırsa, dal başına klonla karşılaştırıldığında kaç nesne kopyalanmamış olur?

Bir Nesne Deposu, Birden Çok Ağaç

Çalışma ağacı (worktree), deponun bir işlemesinin dosya sistemine yazılmış hâlidir. Çoklu çalışma ağacı, aynı nesne deposuna bağlı birden çok çalışma ağacı kurmayı sağlayan düzendir. Ek ağaç bir dizin olarak açılır, içine deponun dizini değil ana depoyu gösteren küçük bir dosya konur ve ağaç o andan itibaren nesnelerini ana depodan okur.

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

git worktree add ../agac-rapor rapor
git worktree add --detach ../agac-inceleme <işleme-kimliği>
git worktree list
git worktree remove ../agac-rapor
git worktree prune

add yeni dizini açar ve verilen dalı orada çıkarır. --detach bir dalı değil doğrudan bir işlemeyi çıkarır; ağaç ayrık HEAD durumunda durur ve bu, geçici bir inceleme için istenen durumdur. list bütün ağaçları ve her birinin hangi dalda olduğunu bildirir. remove ağacı kaldırır, prune ise dizini elle silinmiş ağaçların yönetim kaydını temizler.

Bir kısıt baştan bilinmelidir: bir dal aynı anda yalnız bir ağaçta çıkarılabilir. Aynı dalı ikinci bir ağaçta çıkarmaya çalışmak reddedilir. Kısıt keyfî değildir — iki ağaç aynı dala işleme yazsaydı, dalın hangi ucu gösterdiği ağaca göre değişirdi ve başvuru tekliğini kaybederdi.

Neyin Paylaşıldığı

Ayrım tek cümleyle kurulur: tarihçeye ait olan paylaşılır, çalışmaya ait olan ağaca özeldir.

Paylaşılan taraf nesne deposu ve başvurulardır. Bir ağaçta yazılan işleme nesne olarak deponun içine düşer ve o andan itibaren öbür ağaçlardan erişilebilir — hiçbir aktarım gerekmez. Dallar, etiketler ve referans günlüğü de ortaktır.

Ağaca özel taraf çalışma durumudur: HEAD başvurusu, hazırlık alanı ve çalışma alanındaki dosyalar. Her ağaç kendi HEAD’ini tutar, dolayısıyla ayrı bir dalda durabilir; her ağaç kendi hazırlık alanını tutar, dolayısıyla birinde hazırlanmış bir değişiklik öbüründe görünmez. Kaydedilmemiş bir değişiklik ağacın içinde kalır ve paylaşılmaz.

Yapılandırma ikisinin arasında durur. Deponun yapılandırma dosyası ortaktır ve bir ağaçta yapılan değişiklik hepsini etkiler; bir ayarı yalnız bir ağaca özel kılmak ayrıca açılması gereken bir seçenektir. Depo öznitelikleri de ortaktır — sonraki dersin konusu olan o dosya işlenen bir dosyadır ve tarihçeye aittir, dolayısıyla bütün ağaçlarda aynı kuralı uygular.

Bu ayrım ölçümün kurgusunu doğrudan verir: ek bir ağaç nesne kopyalamaz, yalnız yönetim kaydı yazar ve çalışma alanına dosyaları çıkarır. Klon ise nesne deposunun tamamını kopyalar.

Ölçümün Varsayımları

  • BD14 — Ölçüm ortak kurgunun dört ölçeğini kullanır. Aynı iş, aynı sayıda dal üzerinde, iki ayrı düzende yapılır; üretilen işleme ve nesne kümesi ikisinde de aynıdır.
  • BD15 — Klon düzeninde her dal için ayrı bir klon açılır ve her klon nesne deposunun tamamını kopyalar; kısmi klon ve sığ klon bu ölçümde kullanılmaz.
  • BD16 — Ağaç düzeninde nesne deposu tektir; ek ağaç 0 nesne kopyalar. Yazdığı tek şey ağaç başına 3 yönetim kaydıdır ve bu kayıtlar nesne değildir, ayrı sayılır.
  • BD17 — Çalışma alanına çıkarılan dosyalar iki düzende de aynıdır; dört dal her iki düzende de dört dosya kümesi materyalize eder. Bu yüzden ölçüm dışıdır.
  • BD18 — “Kopyalanmayan ikili”, kazanılan nesnenin ikili gövdelerden gelen payıdır; önceki dersin nesne türü ayrımıyla aynı sayımdır.
  • BD19 — Birinci ve ikinci bölümün birimi dokunulan nesnedir. Üçüncü bölümün birimi adımdır ve bir adım, bir dalın ucunu bir kopyadan öbürüne taşıyan tek bir getirmedir.

Ölçüm

"""Coklu calisma agaci: nesne paylasiminin dal basina klona gore kazandirdigi.

Bolum 1 - dort agac, dort olcekte: klon duzeni ve agac duzeni nesnesi.
Bolum 2 - agac sayisi buyurken kazanc (1000 islemelik tarihce).
Bolum 3 - bir agacta yazilan islemeye obur agactan erisim: birim adim.
"""
TOHUM = 20260814
DOSYALAR = ("olcum.py", "rapor.py", "kimlik.py", "ayar.py", "belge.md")
OLCEKLER = (50, 200, 1000, 4000)
AGACLAR = (1, 2, 4, 8)
YONETIM_KAYDI = 3   # ek agac basina yazilan yonetim kaydi; nesne kopyalamaz


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 klon_duzeni(t, agac):
    """Dal basina klon: her dal kendi nesne deposunu kopyalar."""
    return agac * klon_bedeli(t)


def agac_duzeni(t, agac):
    """Coklu calisma agaci: tek nesne deposu, ek agaclar nesne kopyalamaz."""
    return klon_bedeli(t)


def erisim_adimi(agac, duzen):
    """Bir agacta yazilan islemeye obur agaclardan erisim: getirme adimi."""
    return 0 if duzen == "agac" else agac - 1


print("isleme  klon nesnesi  4 klon nesnesi  4 agac nesnesi  kazanilan nesne"
      "  kopyalanmayan ikili")
for n in OLCEKLER:
    t = tarihce(n)
    k, a = klon_duzeni(t, 4), agac_duzeni(t, 4)
    ikili = 3 * (klon_bedeli(t) - klon_bedeli(t, False))
    print(f"{n:6d} {klon_bedeli(t):13d} {k:15d} {a:15d} {k - a:16d} {ikili:20d}")
print()
t = tarihce(1000)
print("agac  klon duzeni nesne  agac duzeni nesne  kazanilan nesne  ek agac basina nesne"
      "  yonetim kaydi")
for agac in AGACLAR:
    k, a = klon_duzeni(t, agac), agac_duzeni(t, agac)
    ek = (k - klon_bedeli(t)) // (agac - 1) if agac > 1 else 0
    print(f"{agac:4d} {k:18d} {a:18d} {k - a:16d} {ek:21d} "
          f"{(agac - 1) * YONETIM_KAYDI:14d}")
print()
print("agac  klon duzeninde getirme adimi  agac duzeninde getirme adimi")
for agac in AGACLAR:
    print(f"{agac:4d} {erisim_adimi(agac, 'klon'):29d} "
          f"{erisim_adimi(agac, 'agac'):29d}")
print()
print(f"tek nesne deposu {klon_bedeli(t)} nesne; dort agac ayni depoyu paylasiyor, "
      f"ek agaclarin kopyaladigi nesne {agac_duzeni(t, 4) - klon_bedeli(t)}")
print(f"ayni is dort klonla yapilsaydi kopyalanan nesne "
      f"{klon_duzeni(t, 4) - klon_bedeli(t)}")
isleme  klon nesnesi  4 klon nesnesi  4 agac nesnesi  kazanilan nesne  kopyalanmayan ikili
    50           380            1520             380             1140                  882
   200           920            3680             920             2760                 1638
  1000          5640           22560            5640            16920                11466
  4000         22600           90400           22600            67800                45990

agac  klon duzeni nesne  agac duzeni nesne  kazanilan nesne  ek agac basina nesne  yonetim kaydi
   1               5640               5640                0                     0              0
   2              11280               5640             5640                  5640              3
   4              22560               5640            16920                  5640              9
   8              45120               5640            39480                  5640             21

agac  klon duzeninde getirme adimi  agac duzeninde getirme adimi
   1                             0                             0
   2                             1                             0
   4                             3                             0
   8                             7                             0

tek nesne deposu 5640 nesne; dort agac ayni depoyu paylasiyor, ek agaclarin kopyaladigi nesne 0
ayni is dort klonla yapilsaydi kopyalanan nesne 16920

Paylaşımın Kazandırdığı

Birinci tablonun birimi dokunulan nesnedir. Bin işlemelik tarihçede dört dal üzerinde çalışmak, klon düzeninde 22560 nesne yazdırıyor; ağaç düzeninde toplam 5640’ta kalıyor. Kazanılan nesne 16920 — üç klonun tamamı. Dört bin işlemede aynı hesap 67800 nesne veriyor.

Kazancın nereden geldiği son sütunda yazılı. Bin işlemede kazanılan 16920 nesnenin 11466’sı ikili gövdelerden geliyor; önceki dersin 0,6777’lik payı buraya da aynen düşüyor. Bir depoda ikili varlık ne kadar çoksa, ikinci bir klon açmanın bedeli o kadar büyüktür — ve o bedelin tamamı, paylaşılan bir nesne deposuyla hiç ödenmez.

Küçük ölçeklerde de örüntü aynı ama büyüklükler yanıltıcı olabilir. Elli işlemelik tarihçede kazanç 1140 nesnedir; bu, dört bin işlemedeki 67800’ün yanında küçük görünür ama iki düzen arasındaki oran her satırda birebir aynıdır. Kazanç doğrudan (ağaç − 1) × klon çarpımıdır; ölçek yalnız çarpanı büyütür, ilişkiyi değiştirmez. Bu ölçekte ölçülebilen en küçük fark 1/50’dir ve tablodaki hiçbir sayı o çözünürlüğün altında bir iddiaya dayanmıyor.

İkinci tablo aynı şeyi ağaç sayısıyla veriyor ve orta sütun sabit kalıyor: iki ağaç, dört ağaç, sekiz ağaç — hepsinde 5640. Ek ağaç başına kopyalanan nesne her satırda 0’dır; sağdaki 5640, klon düzeninin ek kopya başına ödediğidir. Ağaç düzeninde ödenen tek şey sağ sondaki yönetim kaydıdır: sekiz ağaç için 21 kayıt. Bunlar nesne değildir ve tarihçeye girmezler.

Buradan çıkan ölçüt tek cümledir: çalışma ağacı sayısı nesne deposunu büyütmez. Klon düzeninde bedel ağaç sayısıyla doğrusal büyür, ağaç düzeninde sabittir. Bu, kursta ölçülen bedeller arasında ölçekten tamamen bağımsız olan tek örüntüdür: ikili arama ölçekle yavaş büyüyordu, yeniden yazma oranı sabitti ama toplamı büyüyordu; burada ek kopyanın nesne bedeli her ölçekte ve her ağaç sayısında sıfırdır.

Görünürlük ve Getirme Adımı

Üçüncü tablonun birimi adımdır ve ölçtüğü şey nesne değil, erişimdir.

Klon düzeninde bir dala yazılan işleme, o klonun nesne deposunda durur. Öbür kopyaların ona erişmesi için bir getirme gerekir; dört kopyalı bir düzende bir işlemenin hepsine ulaşması 3 adımdır, sekiz kopyalıda 7. Ağaç düzeninde bu sayı her satırda 0’dır — işleme zaten ortak nesne deposundadır ve öbür ağaç onu yazıldığı anda görür.

Bu, düzenin nesne sayısından bağımsız ikinci kazancıdır ve pratikte daha çok fark eder. Bir ağaçta bir düzeltme yazılıp öbür ağaçta hemen sınanabilir; kiraz toplama, karşılaştırma ve birleştirme işlemleri ağaçlar arasında ağa çıkmadan yapılır. Klon düzeninde aynı işler bir uzak depo turu ister.

Sınır da aynı yerden gelir. Ortak nesne deposu, ortak bir hata yüzeyi demektir: bir ağaçta yapılan çöp toplama bütün ağaçları ilgilendirir ve bir ağaçta bozulan depo hepsini birden etkiler. Klon düzeninde kopyalar birbirinden yalıtılmıştır ve bu yalıtım, ödenen 16920 nesnenin karşılığında alınan tek şeydir.

Üçüncü Düzen: Tek Ağaçta Geçiş

Ölçüm iki düzeni karşılaştırdı ama pratikte en yaygın olanı üçüncüsüdür: tek çalışma ağacı ve dallar arasında geçiş. Bu düzen 0 ek nesne kopyalar — ağaç düzeniyle aynı — ve 0 getirme adımı ister. Nesne birimiyle bakıldığında en ucuz düzendir.

Ödediği bedel başka bir yerdedir. Her geçiş çalışma alanındaki dosyaları yeniden yazar; kaydedilmemiş bir değişiklik varsa geçiş ya engellenir ya da değişiklik taşınır. Dallanma ve İşbirliği kursunda bu durum tek tek sayılmıştı: hangi değişikliğin taşındığı, hangisinin engellendiği ve hangisinin geride kaldığı orada ölçüldü, burada tekrarlanmıyor. Zula, bu engeli aşmanın standart yoludur — kaydedilmemiş değişikliği bir kenara alır ve geçişten sonra geri açar.

Çoklu çalışma ağacının çözdüğü şey tam olarak budur: geçiş yoktur. İki dal aynı anda, iki ayrı dizinde açıktır; birinde bir sınama sürerken öbüründe düzenleme yapılabilir. Zula gerekmez, çünkü kaydedilmemiş değişikliğin yerini bırakması gerekmez.

Buna karşılık her ağaç kendi çalışma durumunu materyalize eder ve bu yalnız dosyalarla sınırlı değildir. Bağımlılık dizinleri, derleme çıktıları ve önbellekler ağaç başına yeniden oluşur; bunlar tarihçeye ait olmadıkları için ölçümün dışındadır ama diskte gerçekten yer kaplarlar ve dört ağaçlı bir düzende dört kez üretilirler. Nesne birimiyle kazanılan 16920, bu maliyeti kapsamaz. İki düzen arasındaki seçim bu yüzden tek sayıdan çıkmaz: ölçülen nesne kazancı gerçek ve büyüktür, ölçülmeyen çalışma durumu ise ağaç sayısıyla büyür.

Ağacın Kaldırılması ve Kurtarma

Bir çalışma ağacı silindiğinde nesneler silinmez — nesneler ağaca ait değildi. Kaybolabilecek tek şey o ağaçta kaydedilmemiş olandır: çalışma alanındaki değişiklikler ve hazırlık alanının içeriği. remove komutu ağaçta kaydedilmemiş değişiklik varsa reddeder; dizinin elle silinmesi hiçbir şey sormaz. Bu iki yol arasındaki fark, uyarının olup olmamasıdır.

İkinci kayıp yolu daha sessizdir. Ayrık HEAD durumundaki bir ağaçta yazılan işleme hiçbir dala bağlı değildir; ağaç kaldırıldığında o işleme erişilemez hâle gelir ve çöp toplama penceresi kapandığında düşer. Kurtarma yolu: referans günlüğü ortaktır, dolayısıyla işlemenin ucu pencere kapanmadan başka bir ağaçtan okunabilir ve bir dala bağlanabilir. Daha ucuz yolu, o ağacı --detach ile değil bir dal adıyla açmaktır — dal bir başvurudur ve başvuru, ağacın ömründen bağımsızdır.

Çıkarılabilir bir ortamda ya da geçici olarak bağlanan bir dizinde duran ağaç için ayrı bir önlem vardır: ağaç kilitlenir. Kilitli bir ağacın yönetim kaydı, dizin erişilemez olduğunda bile temizlenmez; aksi hâlde temizleme işlemi ağacı yok sayar ve o ağaçtaki dal başka bir yerde çıkarılabilir hâle gelir. Kilit, kaybı değil yanlış tanıyı önler.

Üçüncüsü yönetim kaydının kendisidir: dizini elle silinmiş bir ağacın kaydı depoda kalır ve o dalı başka bir ağaçta çıkarmayı engellemeye devam eder. prune bu kayıtları temizler ve hiçbir nesneye dokunmaz.

Özet

  • Depo iki bileşendir: nesne deposu ve çalışma ağacı. Klon ikisini birden kopyalar; çoklu çalışma ağacı yalnız ikincisini çoğaltır.
  • Nesne deposu, dallar, etiketler ve referans günlüğü paylaşılır; HEAD, hazırlık alanı ve çalışma alanı ağaca özeldir. Bir dal aynı anda yalnız bir ağaçta çıkarılabilir.
  • Bin işlemelik tarihçede dört dal için klon düzeni 22560 nesne yazar, ağaç düzeni 5640’ta kalır; kazanılan 16920 nesnenin 11466’sı ikili gövdelerden gelir.
  • Ek ağaç başına kopyalanan nesne her ölçekte 0’dır; ağaç düzeninde ödenen tek şey ağaç başına 3 yönetim kaydıdır ve nesne deposu ağaç sayısıyla büyümez.
  • Adım biriminde: bir işlemenin bütün kopyalara ulaşması klon düzeninde 3 ve 7 getirme ister, ağaç düzeninde 0; karşılığında kaybedilen şey kopyalar arasındaki yalıtımdır.

Sonraki Adım

Ölçüm bir varsayımı ölçüm dışı bıraktı: çalışma alanına çıkarılan dosyaların iki düzende de aynı olduğu varsayımını. Bu, dosyaların nasıl yazıldığının bir tercih olmadığını söylüyordu — oysa çıkarma sırasında dosyaya uygulanan bir dönüşüm katmanı vardır ve nesne deposundaki damla ile çalışma alanındaki dosya birbirinin aynısı olmak zorunda değildir. Sonraki ders bu katmanı ölçer: satır sonu dönüşümü ayarlanmadığında hangi işleme, hangi dosyada, gerçekten hiçbir şey değiştirmediği hâlde yeni bir nesne yazar?

İ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