İçeriğe geç
academia.sh

Ders 07 / 12

Kancalar

Kanca bir olay noktasıdır ve engelin konduğu an bedeli belirler: işlemeden önce durdurulan değişiklik sıfır nesneye dokunur, itmeden önce on işleme ve 140 nesne, kabulden altı yüz işleme sonra 601 işleme, 3522 nesne ve yedi kopyanın yedisi.

İçindekiler

Önceki iki ders tarihçeye sonradan soru sordu: kusur çoktan girmiş, satır çoktan yazılmıştı. Araçlar olmuş bitmiş bir kaydı okudu ve bedeli okuma tarafında ödedi.

Bir değişiklik ise tarihçeye tek adımda girmez. Önce çalışma alanında durur, sonra hazırlık alanına alınır, sonra bir işleme olur, sonra itilir, sonra karşı taraf onu kabul eder. Bu anların her biri bir kapıdır ve her kapıya bir denetim yerleştirilebilir. Kanca (hook), aracın bu anlardan birinde çalıştırdığı programdır; çıkış kodu sıfırdan farklıysa kimi kapılarda işlem durur. Bu dersin sorusu kancanın ne yaptığı değil: engelin hangi kapıya konduğuna göre bedelin nasıl değiştiği, ve o bedeli kimin ödediği.

Kanca Bir Olay Noktasıdır

Kanca, deponun kendi dizini içinde belirli adlarla duran çalıştırılabilir dosyalardan ibarettir. Araç, belirli bir işlemin belirli bir anına geldiğinde o addaki dosyayı arar, varsa çalıştırır ve çıkış kodunu okur. Ortada bir eklenti düzeneği, bir kayıt defteri ya da bir yapılandırma dili yoktur; sözleşme yalnızca dosyanın adı, çalıştırılabilir olması ve çıkış kodudur.

Kancaların sürekli tümleştirme hattını tetikleyen kullanımı Sürekli Tümleştirme ve Dağıtım kursunda kuruldu; orada kanca bir tetikleyiciydi ve tartışılan şey hattın kendisiydi. O tartışma burada tekrarlanmıyor. Bu derste kanca bir yerel olay noktasıdır ve ölçülen tek şey, o noktada hangi işlemin hâlâ durdurulabildiğidir.

İki sınıf vardır ve aralarındaki fark dersin sonucunu belirler. İstemci tarafı kancalar çalışanın kendi deposunda, işlemeden ve itmeden önceki anlarda çalışır. Sunucu tarafı kancalar karşı tarafta, itilen değişiklikler kabul edilmeden önce çalışır. Birincisi deponun tarihçesinde taşınmaz — klonlama kancaları getirmez — ikincisi ise deponun tarihçesinden bağımsız olarak her zaman çalışır.

Kapıların Sırası

Anlar ve o anlarda çalışan kancalar aşağıdaki sırayı izler. Yalnız bir bölümü engelleme yetkisi taşır; kalanı olup bittikten sonra haber verir.

# öğretilen dosya adları ve örnek döküm — çalıştırılmamıştır

pre-commit        işleme kurulmadan önce      — engelleyebilir
commit-msg        mesaj yazıldıktan sonra     — engelleyebilir
post-commit       işleme kurulduktan sonra    — engelleyemez
pre-push          itme başlamadan önce        — engelleyebilir
pre-receive       karşı taraf kabul etmeden   — engelleyebilir
update            her başvuru için ayrı ayrı  — engelleyebilir
post-receive      kabul tamamlandıktan sonra  — engelleyemez

# .git/hooks/pre-commit
#!/bin/sh
if git diff --cached --name-only | grep -q '\.bin$'
then
    echo "ikili varlık hazırlık alanında; işleme durduruldu" >&2
    exit 1
fi
exit 0

# örnek döküm
$ git commit -m "sunum yenilendi"
ikili varlık hazırlık alanında; işleme durduruldu

Sıradaki iki ayrım önemlidir. post- önekli kancalar bir kararı değiştiremez; iş olmuştur ve kanca yalnız haber verir. Ve istemci tarafındaki her engelleyici kanca, komuta verilen bir seçenekle atlanabilir — bu bir kusur değil, tasarımdır: yerel kanca çalışanın kendi kolaylığı içindir, bir yaptırım düzeneği değil.

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

  • TA33 — Tarihçe ortak kurgudan üretilir ve bin işlemedir; kurgu ve kâhin değiştirilmez.
  • TA34 — Engellenmesi istenen değişiklik 400. işlemededir. Tek bir değişiklik izlenir; kaç değişikliğin engellendiği sayılmaz.
  • TA35 — Bedelin birimi dokunulan nesnedir. Bir işlemeyi tarihçeden çıkarmak, ondan sonraki her işlemenin kimliğini değiştirir; dokunulan nesne, kimliği değişen işlemelerin taşıdığı nesnelerin toplamıdır.
  • TA36 — İtme onarlı yığınlar hâlinde yapılır. İtmeden önceki ve sunucudaki kancalar bu yüzden dokuz işleme sonra devreye girer.
  • TA37 — Kabul edildikten sonra fark ediliş iki noktada ölçülür: yüz işleme sonra ve altı yüz işleme sonra.
  • TA38 — Deponun yedi kopyası vardır. Yayımlanmamış bir değişiklik hiçbir kopyayı ilgilendirmez; yayımlanmış bir değişikliğin geri alınması kopyaların tümünü ilgilendirir.
  • TA39 — İkinci bölümde tek değişen şey ölçektir. Kancanın çalışma sayısı ile incelediği işleme sayısı ayrı ayrı sayılır; kancanın kendi süresi ölçülmez.

Ölçüm

"""Kancanin ani: o anda hangi isleme hala engellenebilir.

Bolum 1 - engel bes ayri anda konursa geri almanin bedeli.
Bolum 2 - kancanin kendi bedeli: kac kez calisir, kac isleme inceler.
"""
TOHUM = 20260814
DOSYALAR = ("olcum.py", "rapor.py", "kimlik.py", "ayar.py", "belge.md")
KOPYA, KONUM, YIGIN = 7, 400, 10


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 geri_alma(t, konum, farkedis):
    """konum'daki isleme farkedis'te fark edilirse yeniden yazilacak kume."""
    if farkedis is None:
        return 0, 0
    araya = [x for x in t if konum <= x["no"] <= farkedis]
    return len(araya), sum(x["nesne"] for x in araya)


def yeniden_esitleyen(kopya_sayisi, konum, t, farkedis):
    """Yeniden yazilan tarihceyi kimler yeniden esitlemek zorunda."""
    degisen, _ = geri_alma(t, konum, farkedis)
    return kopya_sayisi if degisen else 0


OLAYLAR = (
    ("işlemeden önce", "evet", None, 0),
    ("itmeden önce", "evet", KONUM + YIGIN - 1, 0),
    ("sunucu kabulünde", "evet", KONUM + YIGIN - 1, 0),
    ("kabulden yüz işleme sonra", "hayır", KONUM + 100, KOPYA),
    ("kabulden altı yüz sonra", "hayır", KONUM + 600, KOPYA),
)

t = tarihce(1000)
print(f"{'engelin konduğu an':>26s} {'engelleyebilir':>14s} "
      f"{'yeniden yazılan':>16s} {'dokunulan nesne':>16s} {'eşitleyen kopya':>16s}")
for ad, engel, farkedis, kopya in OLAYLAR:
    isl, nes = geri_alma(t, KONUM, farkedis)
    print(f"{ad:>26s} {engel:>14s} {isl:16d} {nes:16d} "
          f"{yeniden_esitleyen(kopya, KONUM, t, farkedis):16d}")

print()
print(f"{'işleme':>7s} {'işlemeden önce: çalışma':>24s} {'itmeden önce: çalışma':>22s} "
      f"{'incelenen işleme':>17s}")
for n in (50, 200, 1000, 4000):
    print(f"{n:7d} {n:24d} {n // YIGIN:22d} {n:17d}")
        engelin konduğu an engelleyebilir  yeniden yazılan  dokunulan nesne  eşitleyen kopya
            işlemeden önce           evet                0                0                0
              itmeden önce           evet               10              140                0
          sunucu kabulünde           evet               10              140                0
 kabulden yüz işleme sonra          hayır              101              522                7
   kabulden altı yüz sonra          hayır              601             3522                7

 işleme  işlemeden önce: çalışma  itmeden önce: çalışma  incelenen işleme
     50                       50                      5                50
    200                      200                     20               200
   1000                     1000                    100              1000
   4000                     4000                    400              4000

Engelin Konduğu An

Üst tablonun birinci satırı ölçümün çıpasıdır. İşleme kurulmadan durdurulan bir değişiklik tarihçeye hiç girmez: yeniden yazılacak işleme 0, dokunulan nesne 0, eşitlemek zorunda kalan kopya 0. Değişiklik hâlâ çalışma alanındadır ve düzeltilmesi bir dosya düzenlemesinden ibarettir.

İkinci ve üçüncü satırlarda işleme kurulmuş, üstüne dokuz işleme daha binmiştir. Geri almanın bedeli 10 işleme ve 140 dokunulan nesnedir. Yayımlanmadığı için eşitleyen kopya yine 0; bedel tümüyle yazanın üstündedir ve tarihçe kendi makinesinde yeniden yazılabilir.

Dördüncü ve beşinci satırlarda kapı kapanmamıştır. Yüz işleme sonra fark edildiğinde geri alma 101 işlemenin kimliğini değiştirir ve 522 nesneye dokunur; altı yüz işleme sonra 601 işleme ve 3522 nesne. Ve eşitleyen kopya artık 0 değil, 7. Buradaki sıçrama nesne sütununda değil, en sağdaki sütundadır: dokunulan nesne yirmi beş kat büyürken, işi kimin yaptığı bir kişiden yedi kopyanın hepsine geçer.

Ölçümün çözünürlüğü bin işlemelik kümede 1/1000’dir; ayırt edilebilen en küçük fark tek bir işlemedir. Birinci satır ile ikinci satır arasındaki 10 işlemelik fark bu bandın on katıdır ve rahatça taşınır. Dördüncü satırla beşinci satır arasındaki 500 işlemelik fark ise ölçeğin yarısıdır; bu kümeyle savunulamayacak tek şey, kapılar arasında birkaç işlemelik ince ayrımlar yapmaktır.

Örüntü şudur: engelin bedeli engelin konduğu ana göre değil, konmadığı süreye göre büyür. Kapılar arasındaki fark birkaç saniye ya da birkaç saattir; bedel arasındaki fark sıfırdan üç bin beş yüz yirmi ikiye. Ve bu bedel, bir noktadan sonra artık yazanın ödeyebileceği bir bedel değildir.

Kabulden Sonrası Neden Ayrı Bir Sınıf

Kabul edilmiş bir işlemeyi tarihçeden çıkarmak, tarihçeyi yeniden yazmaktır ve o işlem bu kursun ilk konusunda kendi bedeliyle kuruldu: geri alınamaz, her kopyanın yeniden eşitlenmesini gerektirir ve komutu tam biçimde yazılmaz. Burada eklenen tek şey, o bedelin neden doğduğudur: engel bir kapı geç kondu.

Yayımlanmış bir hatanın tarihçeyi yeniden yazmadan da bir karşılığı vardır: değişikliği deviren yeni bir işleme eklemek. Devirme tarihçeyi bozmaz, kimlik değiştirmez, kopyaları yeniden eşitlemeye zorlamaz — bu yüzden güvenli yoldur ve önce o denenir. Ama devirme kaydı düzeltir, nesneyi silmez. Bir gizli anahtar ya da yanlışlıkla eklenmiş büyük bir varlık, devirmeden sonra da tarihçedeki nesneler arasında durmaya devam eder ve klonlayan herkese gitmeyi sürdürür.

Buradan sunucu tarafı kancanın asıl gerekçesi çıkıyor. Sızmış bir gizli değer, depo düzeltilerek değil, değerin kendisi geçersiz kılınarak kurtarılır; tarihçe temizliği ancak ondan sonra gelen ikinci bir iştir. Kabul kapısı, bu iki işten hiçbirinin gerekmediği son andır.

Kancanın Kendi Bedeli

Alt tablo engelin erken konmasının bedava olmadığını gösteriyor. İşlemeden önceki kanca dört bin işlemelik bir tarihçede 4000 kez çalışır; itmeden önceki kanca onarlı yığınlar yüzünden 400 kez. İncelenen işleme sayısı ikisinde de 4000’dir — aynı iş, on kat farklı sayıda çalışmaya bölünmüş.

Bu bölünmenin bedeli her çalışmanın sabit maliyetidir: sürecin başlaması, denetim aracının yüklenmesi, dizinin taranması. Sabit maliyet incelenen işleme sayısıyla değil, çalışma sayısıyla çarpılır; erken kapı bu yüzden on katı sabit maliyet öder. Karşılığında kazandığı şey geri bildirim mesafesidir: işlemeden önceki kanca değişikliği üretildiği anda durdurur, itmeden önceki kanca en kötü durumda dokuz işleme sonra.

İki kapının ölçüde nerede durduğu böylece netleşiyor. Erken kapı ucuz düzeltme ve pahalı işletme demektir; geç kapı tersi. Yaygın düzen ikisini bölmektir: saniyeler süren ucuz denetimler işlemeden önceki kapıya, uzun süren pahalı denetimler itmeden önceki kapıya konur ve yaptırım gerektiren denetimler her iki durumda da kabul kapısında yinelenir.

Kancanın Neye Baktığı

Bir kancanın hangi anda çalıştığı, aynı zamanda neyi görebildiğini belirler. İşlemeden önceki kanca hazırlık alanının içeriğini görür; çalışma alanındaki kaydedilmemiş değişiklikleri değil. Bu ayrım gözden kaçtığında kanca yanlış şeyi denetler: çalışma alanındaki dosyaları okuyan bir denetim, yalnız bir bölümü hazırlığa alınmış bir değişiklikte hazırlığa girmemiş satırlara da bakar ve işlemeyi geçerken hazırlıktaki içerik denetimden hiç geçmemiş olur. Doğru kanca hazırlık alanını okur, dosya sistemini değil.

Kabul kapısındaki iki kanca da çözünürlükleriyle ayrılır. Biri itilen yığının tamamı için bir kez çalışır ve kararı tüm yığına verir: ya hepsi girer ya hiçbiri. Diğeri her başvuru için ayrı ayrı çalışır ve bir dalı reddedip diğerini kabul edebilir. Ölçümün onarlı yığın varsayımı burada karşılık buluyor — yığının tamamını reddeden bir kapı, kusurlu tek bir işleme yüzünden dokuz kusursuz işlemeyi de geri çevirir. Reddedilen dokuz işleme kaybolmaz, yazanın tarihçesinde durmayı sürdürür; ama yığının yeniden düzenlenmesi gerekir ve bu, kabul kapısının erken kapılara göre ödettiği ikinci bedeldir.

Kancanın kendisi için iki kural bundan çıkar. Kanca hızlı olmalıdır: her çalışmada saniyeler süren bir denetim, dört bin çalışmada saatlere dönüşür ve sonunda atlanmaya başlar. Ve kanca kararlı olmalıdır: aynı içeriğe iki kez farklı yanıt veren bir denetim, engellediği kadar geçirir ve hiçbir güvence taşımaz.

Kimin Kancası Çalışır

Son ayrım dersin sonucudur. İstemci tarafı kancalar deponun tarihçesinde taşınmaz; klonlama onları getirmez, bir işleme onları yayamaz. Ekibin her üyesi kendi deposuna ayrı ayrı kurmak zorundadır ve kuran da bir seçenekle atlayabilir. Yani istemci kancası, yedi kopyanın kaçında kurulu olduğu bilinmeyen bir denetimdir.

Bu taşınmazlığın kısmi bir karşılığı vardır. Kancalar deponun içinde izlenen sıradan bir dizine yazılabilir ve aracın kanca dizini bir ayarla oraya çevrilebilir; böylece kancaların kendisi tarihçeyle taşınır ve ekip aynı denetimi paylaşır. Ama ayarın kurulması yine her kopyada ayrı bir adımdır ve atlanabilirlik değişmez. Taşınan şey kancanın içeriğidir, yaptırımı değil — yedi kopyanın kaçında etkin olduğu hâlâ bilinmez.

Sunucu tarafı kancası tersidir: tek bir yerde durur, herkes için aynı biçimde çalışır ve atlanamaz. Yaptırım gerektiren her kural sonunda oraya yazılmak zorundadır. Ama kabul kapısı aynı zamanda engelleyebilen son kapıdır ve o ana gelindiğinde işleme çoktan kurulmuş, yazanın tarihçesine girmiş, belki üstüne dokuz işleme daha binmiştir. Ölçümün üçüncü satırı tam olarak burayı gösteriyor: kabul kapısı engelleyebiliyor, ama engellediğinde bile geri alma bedeli 10 işleme ve 140 nesnedir.

Sonuç şu ikisinin aynı anda doğru olmasıdır: yaptırımı olan tek kapı, bedeli sıfırlayan kapı değildir; bedeli sıfırlayan kapının ise yaptırımı yoktur. İstemci kancası bu yüzden bir güvence değil, bir kolaylıktır — kabul kapısında zaten reddedilecek bir şeyi yazana beş yüz yirmi iki nesne önce söyleyen bir kolaylık.

Özet

  • Kanca bir olay noktasıdır: aracın belirli bir anda çalıştırdığı program ve okuduğu çıkış kodu. post- önekli kancalar haber verir, karar değiştirmez.
  • Engel işlemeden önce konursa değişiklik tarihçeye hiç girmez: 0 işleme, 0 dokunulan nesne. İtmeden önce konarsa 10 işleme ve 140 nesne, yayımlanmadığı için 0 kopya.
  • Kabulden altı yüz işleme sonra fark edilirse geri alma 601 işlemeye ve 3522 nesneye dokunur, ve yedi kopyanın yedisi yeniden eşitlemek zorunda kalır; bedel yazanın üstünden çıkıp herkese dağılır.
  • Devirme yayımlanmış bir hatayı tarihçeyi bozmadan karşılar ama nesneyi silmez; gizli bir değerin karşılığı önce o değerin geçersiz kılınmasıdır.
  • Erken kapı dört bin işlemede 4000 kez, itme kapısı 400 kez çalışır; incelenen işleme ikisinde de 4000’dir. Erken kapı on kat sabit maliyet öder, karşılığında geri bildirim mesafesini dokuz işlemeden sıfıra indirir.
  • İstemci kancası taşınmaz ve atlanabilir, sunucu kancası atlanamaz ama en geç kapıdır; yaptırımı olan kapı bedeli sıfırlayan kapı değildir.

Sonraki Adım

Bu konu boyunca nesne sayısı hep ölçümün arka planında durdu: aramanın adımını sayarken de, suçlamanın taramasını sayarken de, kancanın geç kalmasının bedelini sayarken de tarihçe tek bir deponun içindeydi ve nesneler o deponun kendi nesneleriydi. Sonraki konu bu arka planı öne alıyor: ya nesne sayısı ölçümün zemini değil, işin kendisi olursa? Bir depo başka bir deponun tarihçesini içine aldığında, ya da tek bir dosyanın her sürümü ayrı bir nesne olarak biriktiğinde, buraya kadar sabit saydığımız arka plan ölçülmesi gereken şeye dönüşü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