← haandevENTR

Silme iki olaydır

Silme iki olaydır: geçersiz ilan etmek ve geri kazanmak. Birincisine silen karar verir; ikincisine en eski aktif okuyucu karar verir.

Öz

Silme iki ayrı olaydır: bir kayıt geçersiz ilan edilir ve kapladığı alan geri kazanılır. Dosya sistemlerinde ikinci olay çoğunlukla kimseyi beklemez. Çok sürümlü veritabanlarında ise hâlâ kullanımda olan en eski snapshot'a bağlıdır; bu çizgiye vacuum ufku (vacuum horizon) denir. Aynı çizgi farklı sistemlerde farklı adlarla karşımıza çıkar, ve bir okuyucu onu geride tuttuğunda bedeli yazan, depolama ya da okuyucu öder. Fikir, çok sürümlü eşzamanlılık denetimi (Reed, 1978; Bernstein ve Goodman, 1983) ve bellek geri kazanımı (McKenney ve Slingwine, 1998) literatürünün ortak bir yapısıdır; Veri dillerinin anatomisi yazısındaki tezin silme tarafındaki karşılığıdır: dosya sistemiyle veritabanı arasındaki fark bir tür farkı değil, derece farkıdır.

1. Silme ve geri kazanım

Bir depolama sisteminde silme iki olaydan oluşur:

  1. Geçersiz ilan etmek. Sistem, kaydın artık geçerli olmadığını metadata'sına yazar. Bu hemen olur.
  2. Geri kazanım. Kaydın kapladığı alan yeniden kullanıma açılır. Bu birinci olaydan sonra, bazen çok sonra olur.

Veri dillerinin anatomisi yazısının diliyle: diskte yalnızca baytlar vardır; dosya ve satır, o baytlara verilmiş isimlerdir. Bir kaydı geçersiz ilan etmek bir ismi geri çekmektir ve anlıktır; baytların ne zaman serbest kalacağına ise isimlendiren programın okuyucularına verdiği vaat karar verir.

DOSYA SİSTEMİ · FAT32, NTFSkayıtcanlıboş, ama baytlar hâlâ oradayeni verigeçersiz ilan = alan boşüzerine yazıldıMVCC VERİTABANI · POSTGRESQL, INNODBsürümcanlıölü, silinemezgeri kazanılabiliren eski okuyucugeçersiz ilan edildiufuk geçerzaman →
Bir kaydı geçersiz ilan etmek iki sistemde de anlıktır. Dosya sisteminde alan aynı anda boşa çıkar; MVCC veritabanında ise silmeden önce başlamış en eski okuyucuyu bekler.

2. Dosya sistemlerinde silme

FAT32'de silinen bir dosyanın dizin girdisinin ilk baytı 0xE5 olarak işaretlenir ve cluster'ları serbest bırakılır (Microsoft, 2000); NTFS'te dosyanın MFT kaydındaki "kullanımda" bayrağı temizlenir. İki durumda da içerik diskte kalır; kurtarma araçlarının çalışmasının nedeni budur (Carrier, 2005). SSD'lerde TRIM boş blokları kontrolcüye bildirir ve kurtarmayı büyük ölçüde imkânsız kılar (King ve Vidas, 2011).

Bunların ortak noktası: alan, geçersiz ilan edildiği anda yeniden kullanılabilir. Geri kazanım hiçbir okuyucuyu beklemez; verinin fiziksel olarak gidip gitmediği yalnızca üzerine ne zaman yeni bir şey yazılacağına bağlıdır.

3. Okuyucuyu bekleyen geri kazanım

Bir istisna var. POSIX'te açık bir dosya silindiğinde (unlink) dizinden kaybolur, ama onu açık tutan son süreç kapatana kadar alanı serbest bırakılmaz. df ile du arasındaki bilindik tutarsızlık buradan gelir. Windows ise aynı durumda genellikle silmeyi reddeder.

İki durumda da geri kazanım bir okuyucuya bağlıdır. Dosya sistemlerinde istisna olan şey, çok sürümlü veritabanlarında kuraldır; çünkü dosya sistemi okuyucularına zayıf bir tutarlılık vaadi verir, veritabanı ise her okuyucuya tutarlı bir görünüm vaat eder.

4. Çok sürümlü eşzamanlılık denetimi

Çok sürümlü eşzamanlılık denetimi (MVCC), okuma ve yazmaların birbirini kilitlemeden ilerlemesini sağlar (Reed, 1978; Bernstein ve Goodman, 1983). Bir transaction başladığında veritabanının o anki tutarlı durumunun bir snapshot'ını alır ve bütün okumalarını o snapshot üzerinden yapar. Bir kayıt güncellendiğinde ya da silindiğinde veritabanı mevcut sürümün üzerine yazmaz; yeni bir sürüm oluşturur ve eskisini tutar. Güncellemeden önce alınmış bir snapshot, kaydı eski haliyle görmeye devam etmek zorundadır.

Dolayısıyla bir MVCC veritabanında her güncelleme ve her silme, geçersiz ilan edilmiş ama henüz geri kazanılamayan bir sürüm bırakır. PostgreSQL bunlara dead tuple, InnoDB undo record, Cassandra tombstone der. PostgreSQL'de bunları temizleyen sürecin adı vacuum'dur.

İsim, Stonebraker'ın (1987) POSTGRES depolama sistemi tasarımına dayanır. Kayıtların üzerine hiç yazılmıyordu ve eski sürümler "vacuum cleaner" adlı bir süreçle arşiv depolamasına taşınıyordu. Amaç geçmişi silmek değil, geçmiş sürümleri sorgulayabilmekti (time travel). Özellik performans ve depolama maliyeti gerekçesiyle PostgreSQL 6.2'de (1997) kaldırıldı, ve vacuum eski sürümleri arşivleyen bir süreçten onların alanını geri kazanan bir sürece dönüştü.

Aynı ayrım, Veri dillerinin anatomisi'nin özyinelemeli yorumlama yığını örneği olarak kullandığı SQLite'ta aynı anda iki düzeyde görülür. Dosya sistemi için bir SQLite veritabanı tek bir dosyadır; içeriden bakınca tablolar ve satırlar barındırır. SQLite'ta bir satır silindiğinde baytları dosyadan çıkarılmaz: alan sayfa içinde boş olarak işaretlenir, tamamen boşalan sayfalar dosyanın freelist'ine girer. Yapı, FAT32'nin bir dizin girdisini işaretleyip cluster'larını serbest bırakmasıyla aynıdır, yalnızca bir düzey yukarıda, bir dosyanın içinde. PRAGMA secure_delete açık değilse silinen içerik dosyada kalır, ve dosya ancak SQLite'ın kendi VACUUM komutu onu yeniden yazdığında küçülür.

5. Vacuum ufku

Vacuum her ölü sürümü temizleyemez, yalnızca hiçbir aktif snapshot'ın artık göremeyeceği sürümleri temizleyebilir. O çizgiye vacuum ufku denir. Terimin iki parçası vardır:

İkisini ayrı tutmak pratikte önemlidir. Vacuum'un yetişememesi bir konfigürasyon sorunudur; ne sıklıkla çalıştığı, kaç worker'ı olduğu ve maliyet limitleriyle ilgilidir. Kımıldamayan bir ufuk ise konfigürasyon sorunu değildir: vacuum ne kadar sık çalışırsa çalışsın, ufkun ötesindeki hiçbir şeyi temizleyemez.

Biçimsel olarak:

ufuk = min { s : s, aktif bir okuyucunun snapshot'ı }

Tanımın belirleyici öğesi min'dir. Ufuk okuyucuların ortalaması değil, minimumudur. Bu yüzden uzun süren tek bir okuyucu, diğerlerinin ne kadar sürdüğünden bağımsız olarak ufku belirler. Sistemdeki okuyucuların ezici çoğunluğunun milisaniyeler içinde bitmesi hiçbir şeyi değiştirmez.

ufukburada oluşan her ölü sürüm silinemezen eski okuyucuidle in transaction, hâlâ açıkdiğer okuyucularher biri milisaniyeler sürer; hiçbiri ufku kaydırmazCum 18:40Cmt · PazPzt 09:00
Ufuk bir ortalama değil, bir minimumdur. Binlerce kısa okuyucu onu kaydırmaz; Cuma akşamı açık bırakılmış tek bir okuyucu onu bütün hafta sonu boyunca yerinde tutar.

6. Bir örnek: boşta bırakılmış bir transaction

Cuma günü saat 18:40'ta bir analist rapor için veritabanına bağlanır, bir transaction başlatır, tek bir SELECT çalıştırır ve istemciyi kapatmadan işi bırakır. PostgreSQL'de oturum idle in transaction durumunda kalır. Transaction kilit tutmaz, hiçbir şey yazmaz ve kaynak tüketmez; ama snapshot'ı aktif olduğu için ufku 18:40'a çiviler.

Hafta sonu boyunca orders tablosundaki her güncelleme yeni bir sürüm oluşturur ve eskisini geride bırakır. Autovacuum takvimine uygun çalışır ama hiçbirini temizleyemez, çünkü 18:40'ta alınmış bir snapshot ilke olarak onları hâlâ görebilir. Pazartesi sabahı tablo 30 GB'tan 210 GB'a çıkmıştır; satır sayısı ise neredeyse değişmemiştir.

VACUUM (VERBOSE) çıktısı (PostgreSQL 15 ve sonrası) bunu doğrudan gösterir:

tuples: 0 removed, 1204117 remain, 1198320 are dead but not yet removable
removable cutoff: 88213410, which was 4120331 XIDs old when operation ended

"Dead but not yet removable", temizlenecek sürümlerin bulunduğunu ama ufkun onların silinmesini engellediğini söyler.

7. Başka sistemlerde aynı çizgi

Aynı yapı, bir kaydın birden fazla sürümünü aynı anda tutan ya da okuyucular hâlâ kullanıyor olabilirken paylaşılan veriyi serbest bırakmak zorunda olan her sistemde vardır. Farklı sistemlerde ve makalelerde farklı adlarla geçer: PostgreSQL'de xmin horizon, TiDB'de GC safe point, Hekaton'da en eski aktif transaction'ın yönettiği garbage collection (Diaconu vd., 2013), bellek içi MVCC sistemleri üzerine çalışmalarda ise en sık low watermark (Böttcher vd., 2019).

SistemÇizginin adıOkuyucu sayılan
Linux (POSIX)açık file descriptordosyayı açık tutan süreçler
SQLite (WAL modu)checkpointWAL dosyasındaki frame'lere hâlâ ihtiyaç duyan açık okuma transaction'ları
PostgreSQLxmin horizon, removable cutoffaçık transaction'lar, hot_standby_feedback gönderen standby'lar, replication slot'lar, prepared transaction'lar
MySQL InnoDBpurge, read viewaçık read view'lar
Oracleundo retentionuzun süren sorgular
TiDBGC safe point6.1'den beri en fazla tidb_gc_max_wait_time süresince açık transaction'lar; öncesinde yalnızca tidb_gc_life_time süresi
CockroachDBGC threshold, gc.ttlsecondsTTL içindeki zaman damgaları; yedekler ve changefeed'ler için protected timestamp'ler
Cassandratombstone, gc_grace_secondssilmeyi henüz almamış replikalar
Delta Lake, IcebergVACUUM, snapshot expiryeski sürümleri okuyan sorgular, eşzamanlı yazanlar
Kafkalog retention, retention.msyok: retention süresini aşan segment, tüketiciler nerede olursa olsun silinir
Linux çekirdeği (RCU)grace periodokuma tarafı kritik bölgesinin içindeki CPU'lar
Kilitsiz veri yapılarıepoch, hazard pointerhâlâ referans tutan thread'ler

Tablodaki sistemler, Veri dillerinin anatomisi'nin dosya sistemi, veritabanı ve mesaj kuyruğu adlı ayrı kategorilere ayırdığı sistemlerdir; oysa hepsi aynı baytlar üzerinde çalışan isimlendirme programlarıdır. Dolayısıyla silme kuralları birbirinden bağımsız icat edilmiş mekanizmalar değil, aynı soruna farklı derinliklerde verilmiş cevaplardır. Hepsi aynı soruyu sorar: en eski aktif okuyucu hangisi? Farklı olan, neyin okuyucu sayıldığıdır. Pratikteki ufuk sorunlarının önemli bir kısmı, operatörün okuyucu olarak düşünmediği bileşenlerden gelir: tüketicisi ortadan kalkmış bir replication slot, iki fazlı commit'in ortasında yarım bırakılmış bir PREPARE TRANSACTION, uzun süren bir yedek. Hiçbiri pg_stat_activity'de uzun süren bir sorgu olarak görünmez.

Cassandra'da yapı başka bir biçim alır. Bir tombstone'un geri kazanımını geciktiren şey bir okuyucu değil, silmeyi henüz almamış bir replikadır. Tombstone, her replika repair ile hizaya getirilmeden kaldırılırsa, silmeyi kaçırmış replika eski veriyi hâlâ tutar ve bir sonraki senkronizasyonda silinmiş kayıt yeniden ortaya çıkar. Buna data resurrection denir. Yapı yine aynıdır: geçersiz ilan edilmiş bir kayıt, bundan haberi olmayan son taraf da haberdar olana kadar geri kazanılamaz.

8. Bedeli kim öder

Bir okuyucu ufku geride tuttuğunda sistemin üç seçeneği vardır, ve her biri bedeli farklı bir tarafa yükler.

Silmeyi engellemek. Okuyucu işini bitirene kadar silme kabul edilmez. Windows'un açık dosyalara uyguladığı kural budur. Okuyucunun tutarlılığı ve depolama korunur; bedeli yazan öder.

Geri kazanımı ertelemek. Silme kabul edilir, ama okuyucu işini bitirene kadar alan geri kazanılmaz. Linux'un açık dosyalara, PostgreSQL ve InnoDB'nin eski sürümlere uyguladığı kural budur. Okuyucu ve yazan etkilenmez; bedeli depolama öder.

Okuyucuyu sonlandırmak. Belli bir eşikten sonra eski sürümler okuyucuya rağmen geri kazanılır, ve onlara ihtiyaç duyan okuma başarısız olur. Oracle'ın undo alanı tükendiğinde verdiği ORA-01555: snapshot too old hatası da, TiDB'nin GC safe point'in gerisinde kalmış bir transaction için verdiği GC life time is shorter than transaction duration hatası da bu kuralın sonuçlarıdır. Depolama ve yazan korunur; bedeli okuyucu öder.

BEDELİ YAZAN ÖDERsilme bekler ya da başarısız olurWindows, açık dosyalar · Oracle RETENTION GUARANTEEBEDELİ DEPOLAMA ÖDERgeri kazanım beklerLinux unlink · PostgreSQL · InnoDBBEDELİ OKUYUCU ÖDEReski sürümler gider, okuyucu hata alırOracle ORA-01555 · TiDB · Kafka · feedback'siz standbybedel yer değiştirir;ortadan kalkmaz
Bir okuyucu ufku geride tuttuğunda birileri bedel öder. Oracle'da bir ayar yazanla okuyucu arasında seçim yapar; PostgreSQL standby'ında hot_standby_feedback okuyucuyla depolama arasında seçim yapar. Hiçbir ayar bedeli ortadan kaldırmaz.

Oracle bu seçimi bir konfigürasyon ayarı olarak sunar. Undo tablespace'inde RETENTION GUARANTEE etkinse, UNDO_RETENTION içindeki undo'nun üzerine asla yazılmaz; undo alanı tükendiğinde bunun yerine yeni DML başarısız olmaya başlar (genellikle ORA-30036 ile). Bedel okuyucudan yazana geçer. Üç seçenek tek bir sistem içindeki alternatiflerdir: bedel ortadan kaldırılamaz, yalnızca bir taraftan diğerine aktarılabilir.

Uzun okumalar bir replikaya gönderildiğinde de aynı ikilem geri gelir. PostgreSQL'de hot_standby_feedback kapalıyken, primary'den gelen bir temizlik kaydı çalışan bir sorgunun hâlâ ihtiyaç duyduğu sürümleri kaldıracaksa, standby max_standby_streaming_delay kadar bekler ve sonra sorguyu iptal eder (canceling statement due to conflict with recovery); bedeli okuyucu öder. Açıkken standby en eski snapshot'ını primary'ye bildirir ve primary'nin ufkunu geride tutar; bedeli primary'nin depolaması öder. Okuyucuyu başka bir sunucuya taşımak ufku taşımaz.

9. Gözlenen ve ilan edilen ufuklar

Sistemler ufku nasıl belirlediklerine göre de iki gruba ayrılır.

Gözlenen ufuk. Sistem aktif okuyucuları izler ve ufku gerçekten var olan en eskisinden hesaplar. PostgreSQL, InnoDB ve RCU bu gruptadır. Yaklaşım doğruluğu garanti eder: hiçbir okuyucu, işini bitirmeden geri kazanılmış bir sürümle karşılaşmaz. Karşılığında depolamanın bir üst sınırı yoktur; tek bir okuyucu ufku süresiz olarak geride tutabilir.

İlan edilen ufuk. Sistem okuyucuları izlemez; bunun yerine sabit bir saklama süresi tanımlar. Cassandra'nın gc_grace_seconds ayarı (varsayılan 864.000 saniye, yani 10 gün), Delta Lake'in VACUUM için varsayılan 7 günlük saklama süresi (delta.deletedFileRetentionDuration), Iceberg'ün varsayılan 5 günlük snapshot yaşı (history.expire.max-snapshot-age-ms) ve Kafka'nın varsayılan 7 günlük retention.ms değeri bu gruptadır. Yaklaşım depolama için öngörülebilir bir üst sınır verir, ama doğruluğu her okuyucunun ve replikanın bu süreye uymasına bağlar. gc_grace_seconds'tan uzun süre repair edilmeden kapalı kalan bir Cassandra replikası silinmiş veriyi geri getirebilir. Saklama süresinden kısa bir süreyle çalıştırılan bir Delta Lake VACUUM'u, eski dosyaları okuyan sorguları ya da eşzamanlı yazanları bozabilir; Delta Lake bu yüzden böyle bir çalıştırmayı varsayılan olarak reddeder (spark.databricks.delta.retentionDurationCheck.enabled).

Melez. Bazı sistemler ikisini birleştirir: okuyucuları gözlerler, ama ne kadar bekleyeceklerine bir tavan koyarlar. TiDB 6.1'den önce açık transaction'lar GC safe point'i hiç etkilemiyordu; ufku yalnızca ilan edilen tidb_gc_life_time süresi (10 dakika, hem varsayılan hem minimum) belirliyordu. 6.1'den beri açık transaction'lar safe point'i geride tutabiliyor, ama en fazla tidb_gc_max_wait_time kadar; bu aşıldığında safe point zorla ileri alınıyor. Tavana kadar gözlenen ufuk doğruluğu korur; tavan da depolamayı korur. Tavanı aşan okuyucu, ilan edilen ufukta olduğu gibi bedeli öder.

Bu ayrım, bedeli kimin ödeyeceği seçiminin mimarideki karşılığıdır. Gözlenen ufuk bedeli depolamaya yükler; ilan edilen ufuk ise sözleşmeye uymayan okuyucuya.

10. Üç kutup, üç silme kuralı

Veri dillerinin anatomisi, sistem kategorilerini keskin sınıflar olarak değil, gerçek sistemlerin arasında konumlandığı üç ideal kutup olarak tanımlamıştı: isimlendirmeyi asgaride tutan ideal dosya sistemi; isimlendirmeyi azamiye çıkarıp katı tutarlılık vaat eden ideal veritabanı; ve isimlendirmeyi zamana bağlayan ideal mesaj kuyruğu. Geri kazanım kuralları üç kutba birebir oturur.

okuyucuyu gözlerİDEAL VERİTABANIİDEAL DOSYA SİSTEMİbeklemezİDEAL MESAJ KUYRUĞUsüre ilan ederPostgreSQLInnoDBSQLite (WAL)TiDB ≥ 6.1TiDB < 6.1CassandraDelta LakeIcebergKafkaLinux, açık dosyalarNTFSFAT32Renk = sistemin kendine verdiği etiket:dosya sistemiveritabanı, tablomesaj kuyruğu
Veri dillerinin anatomisi yazısındaki spektrum; konum bu kez bir sistemin silinen veriyi nasıl geri kazandığını gösteriyor. Cassandra, Delta Lake ve Iceberg veritabanı etiketini taşısa da kuyruk gibi geri kazanır; TiDB 6.1'de veritabanı köşesine doğru kaydı. Yerleşimler niteldir ve tartışmaya açıktır.

Gerçek sistemler kutupların arasında durur, ve geri kazanım kuralları konumlarını izler. Linux'un açık dosyaların okuyucularını beklemesi, dosya sistemi kutbundan veritabanına doğru atılmış bir adımdır. Cassandra ve Delta Lake kendilerine veritabanı deseler de geri kazanımda kuyruk kutbunun kuralını izler: bir süre ilan ederler. TiDB'nin 6.1'deki değişikliği, aynı sistemin o kutuptan veritabanına doğru kayması olarak okunabilir. WAL modundaki SQLite tek bir dosyanın içinde veritabanı kutbunun kuralını izler: açık bir okuma transaction'ı, checkpoint'in WAL dosyasını sıfırlamasını engeller, ve her zaman okuyucusu olan bir sistemde WAL dosyası sınırsızca büyüyebilir.

Veri dillerinin anatomisi, "bu bir veritabanı mı?" sorusunun yerine "baytlara ne derinlikte isim veriyor ve o isimlere ne vaat ediyor?" sorusunu koymayı önermişti. Geri kazanım, bu sorunun ikinci yarısının en somut ölçüsüdür: bir sistemin okuyucularına ne vaat ettiği, silinen baytları ne zaman bırakabileceğine karar verir.

11. Geçici neden, kalıcı etki

Ufku geride tutan transaction kapandığında ufuk ilerler ve bir sonraki vacuum geçişi birikmiş ölü sürümleri temizler. Ama bu, tablonun diskte kapladığı alanı azaltmaz.

PostgreSQL'de vacuum geri kazandığı alanı işletim sistemine iade etmez; yalnızca tablonun sayfaları içinde yeniden kullanılabilir olarak işaretler. Dosya ancak tablonun sonundaki tamamen boş sayfalar kadar küçülebilir. Örnekteki tablo ölü sürümler temizlendikten sonra da yaklaşık 210 GB yer kaplar, ve sequential scan'ler o sayfaları okumaya devam eder. Alanı gerçekten geri almak için VACUUM FULL (tabloyu yeniden yazar ve baştan sona bir ACCESS EXCLUSIVE kilit tutar) ya da pg_repack gibi bir araç gerekir. pg_repack tabloyu online olarak yeniden yazar ve exclusive kilidi yalnızca başta ve sonda kısa süreliğine alır; karşılığında tablo ve indekslerinin boyutunun yaklaşık iki katı boş disk alanı ister.

Etki tabloyla da sınırlı kalmaz:

Dolayısıyla ufku izlemek, uzun süren sorguları izlemekle aynı şey değildir. Uzun okuma bittiğinde neden ortadan kalkar, ama etki kalır.

12. Teşhis ve önleme

PostgreSQL'de ufku neyin geride tuttuğunu bulmak için okuyucu sayılan her kaynağın ayrı ayrı kontrol edilmesi gerekir:

-- Açık transaction'lar
SELECT pid, usename, state, xact_start, age(backend_xmin) AS xmin_age
FROM pg_stat_activity
WHERE backend_xmin IS NOT NULL
ORDER BY age(backend_xmin) DESC;

-- Replication slot'lar (aktif olmayanlar dahil)
SELECT slot_name, active, xmin, catalog_xmin
FROM pg_replication_slots;

-- Prepared transaction'lar
SELECT gid, prepared, owner FROM pg_prepared_xacts;

-- Feedback gönderen standby'lar
SELECT application_name, backend_xmin FROM pg_stat_replication;

InnoDB'de karşılık gelen gösterge, SHOW ENGINE INNODB STATUS çıktısındaki History list length değeridir. Sürekli artan bir değer, purge'ün bir read view tarafından geride tutulduğu anlamına gelir.

Gözlenen ufku olan bir sistemde temel çare, okuyucuların ne kadar sürebileceğini sınırlamaktır; yani ilan edilen ufuk yaklaşımını okuyucu tarafında uygulamak. PostgreSQL'de ilgili ayarlar şunlardır:

Tüketicisi ortadan kalkmış replication slot'lar da izlenmeli ve silinmelidir; slot'lar tüketicileriyle birlikte kaldırılmaz.

Bu önlemlerin hepsi bedelin bir kısmını depolamadan okuyucuya aktarır. Burada da bedel ortadan kaldırılamaz; yalnızca kimin üstleneceğine önceden karar verilebilir.

13. İtirazlar ve sınırlar

  1. Uzun okumalar meşrudur. Ay sonu raporları, yedekler ve mantıksal replikasyonun ilk kopyası saatler sürebilir. Sorun uzun okumaların kendisi değil, depolama üzerindeki etkilerinin çoğunlukla görünmez kalmasıdır.
  2. Sistemleri karşılaştırmak ölçek farklarını gizler. RCU'da bir grace period mikrosaniyelerle, Cassandra'da gc_grace_seconds günlerle ölçülür; birinde okuyucu bir CPU, ötekinde bir replikadır. Benzerlik bir eşdeğerlik değil, aynı yapının farklı ölçeklerde yinelenmesidir.
  3. Dosya sistemleri yapıya yalnızca kısmen uyar. FAT32 ve NTFS'te geri kazanım hiçbir okuyucuya bağlı değildir; verinin fiziksel olarak gidip gitmediği yalnızca üzerine yazılmaya bağlıdır. Okuyucuyu bekleyen geri kazanım, dosya sistemlerinde yalnızca POSIX unlink semantiği gibi sınırlı durumlarda görülür. Dolayısıyla dosya sistemleri veritabanlarının bir eşdeğeri değil, iki olay arasındaki ayrımın en yalın örneğidir. Kısmi uyum, Veri dillerinin anatomisi'ndeki spektrumla örtüşür: dosya sistemleri okuyucularına en az vaat eden kutba yakın durur, bu yüzden okuyucuya bağlı geri kazanımı en az uygulayan sistemlerdir.
  4. Kutuplarla örtüşmek, kutuplardan türetmek değildir. Geri kazanım kurallarının üç kutba oturması, kuralların kutuplardan türetilebileceği anlamına gelmez. Veri dillerinin anatomisi'nin sınırlar bölümünde belirtildiği gibi, isimlendirme çerçevesi performans özelliklerini açıklamaz; aynı kutba yakın iki sistemin geri kazanım maliyeti, depolama yapılarına göre çok farklı olabilir.
  5. Varsayılanlar sürüme bağlıdır. Parametre adları, varsayılanlar ve hata mesajları sürümden sürüme değişir; burada verilen değerler Ekim 2026 itibarıyla güncel dokümantasyona dayanır.

14. Sonuç

Depolama sistemlerinde silme iki ayrı olaydan oluşur: bir kaydı geçersiz ilan etmek ve alanını geri kazanmak. Dosya sistemlerinde ikinci olay çoğunlukla hiçbir okuyucuya bağlı değildir. Çok sürümlü veritabanlarında hâlâ kullanımda olan en eski snapshot'a bağlıdır, ve o çizginin adı vacuum ufkudur.

Ufuk bir minimum olduğu için onu en uzun süren okuyucu belirler. Bir okuyucu onu geride tuttuğunda bedeli yazan, depolama ya da okuyucu öder. Hangisinin üstleneceği bir tasarım kararıdır; karar açıkça verilmezse sistemin varsayılanı geçerli olur.

Veri dillerinin anatomisi, diskte yalnızca baytlar olduğunu, dosya, satır ve mesajın o baytlara verilmiş isimler olduğunu savunmuştu. Silme bu tezin öbür yüzüdür: bir ismi geri çekmek anlıktır; baytları serbest bırakmak ise isimlendiren programın okuyucularına verdiği vaada bağlıdır. Dosya sistemiyle veritabanı arasındaki derece farkı en açık biçimde bu vaatte görünür.

Silme iki olaydır: birincisine silen karar verir, ikincisine en eski aktif okuyucu.

Kaynaklar

Bu blogda

Dosya sistemleri

Çok sürümlü eşzamanlılık denetimi

Bellek geri kazanımı

Ürün dokümantasyonu