Başarısız olan dosya aktarımlarına devam edebilen programlar nereden veri eklemeye başlayacağını biliyor?


23

Bazı dosya kopyalama programları gibi rsyncve curlbaşarısız transferleri / kopyaları devam ettirme yeteneğine sahiptir.

Bu başarısızlıkların birçok nedeni olabileceğine dikkat çekerek, bazı durumlarda program "temizleme" işlemini yapabilir, bazı durumlarda program yapamaz.

Bu programlar devam ettiğinde, sadece başarılı bir şekilde transfer edilen dosya / verinin boyutunu hesaplıyor gibi görünüyor ve bir sonraki byte'ı kaynaktan okumaya ve dosya parçasına eklenmeye başlıyor.

örneğin, hedefe "yapan" dosya parçasının boyutu 1378 byte'tır, bu nedenle sadece orjinaldeki 1379 byte'tan okumaya başlar ve parçaya eklenir.

Sorum şu ki, baytların bitlerden oluştuğunu ve tüm dosyaların verilerini temiz bayt büyüklüğünde parçalara ayırmadığını bilmek, bu programlar veri eklemek için seçtikleri noktanın doğru olduğunu nasıl biliyorlar?

Hedef dosyayı yazarken, yalnızca temiz, iyi biçimlendirilmiş baytların temel blok aygıtına ulaşmasını sağlamak için programda, çekirdek veya dosya sistemi düzeyinde meydana gelen SQL veritabanlarına benzer bir tür tamponlama veya "işlem" olur.
Veya programlar en son baytın potansiyel olarak eksik olacağını varsayarlar, bu yüzden kötü olduğu varsayımıyla silerler, baytı tekrar kopyalarlar ve oradan eklemeye başlarlar?

Tüm verilerin bayt olarak temsil edilmediğini bilerek, bu tahminler yanlış görünüyor.

Bu programlar "devam ettiğinde" doğru yerden başladığını nereden biliyorlar?


21
"tüm dosyalar verilerini temiz bayt boyutlu parçalara ayırmaz" değil mi? Bir dosyaya bayttan daha az bir şeyi nasıl yazarsın?
muru

17
Bayttan daha az bir şey yazabilecek hiçbir sistem çağrısı olmadığını biliyorum ve diskin kendisinde olduğu gibi, bugün hiçbir diskin 512 bayttan (veya 4096 baytlık bloklar) daha az yazmadığını düşünüyorum.
muru

8
Hayır, minimumun bir bayt olduğunu söylüyorum. Sane uygulamaları 4KB veya 8KB'lık parçalar kullanıyor olacaktı: head -c 20480 /dev/zero | strace -e write tee foo >/dev/nullve ardından işletim sistemi onları tamponlayacak ve daha büyük boyutlarda diske gönderecek.
muru

9
@the_velour_fog: Nasıl bir bit yazıyorsunuz fwrite()?
psmears,

9
Tüm pratik amaçlar için, veriler olduğu bayt oluşur ve her şeyi en küçük birim olarak onlarla çalışır. Bazı sistemler (çoğunlukla sıkıştırma ile ilgili, örneğin gzip, h264) bireysel bitleri baytlardan çıkarır, ancak işletim sistemi ve bellek çalışması bayt düzeyindedir.
pjc50

Yanıtlar:


40

Netlik uğruna - gerçek mekanik daha iyi güvenlik sağlamak için daha karmaşıktır - diske yazma işlemini şöyle hayal edebilirsiniz:

  • uygulama bayt yazar (1)
  • çekirdek (ve / veya dosya sistemi IOSS) onları tamponlar
  • Arabellek dolduğunda, dosya sistemine temizlenir :
    • blok tahsis edilmiştir (2)
    • blok yazılmıştır (3)
    • dosya ve blok bilgileri güncellendi (4)

İşlem (1) de kesilirse, diskte hiçbir şey alamazsınız, dosya bozulmaz ve önceki blokta kesilir. 5000 byte gönderdiniz, diskte sadece 4096'sı var, 4096 ofsetinde aktarımı yeniden başlattınız.

(2) konumundaysa, hafıza dışında hiçbir şey olmaz. (1) ile aynı. (3) konumunda ise, veriler yazılır ancak hiç kimse bunu hatırlamaz . 9000 byte gönderdiniz, 4096 yazmış, 4096 yazmış ve kaybettiniz , gerisi daha yeni kayboldu. Transfer ofset 4096'da devam ediyor.

(4) konumundaysa, veriler şimdi diskte kaydedilmiş olmalıdır. Akıştaki sonraki baytlar kaybolabilir. 9000 bayt gönderdiniz, 8192 yazılmıştı, geri kalanı kayboldu, transfer 8192 ofsetinde devam etti.

Bu basitleştirilmiş bir işlemdir . Örneğin, 3-4. Aşamalardaki her bir "mantıksal" yazma "atomik" değildir, ancak hedef aygıta uygun alt-bloklara bölünmüş bloğun (örneğin, sabit disk (5)) ortaya çıkmasına neden olur. ) aynı zamanda bir önbellekleme mekanizmasına sahip olan ve son olarak da manyetik plaka üzerinde depolanan cihazın ana bilgisayar kontrol cihazına gönderilir . Bu alt sıra her zaman sistemin kontrolünde tam olarak bulunmaz, bu nedenle sabit diske veri gönderilmesi, aslında yazılmış ve tekrar okunabilir olacağının garantisi değildir.

Çeşitli dosya sistemleri uygulamak günlük kaydı , en hassas nokta, (4), olmadığından emin olmak için aslında meta-veri yazarak, savunmasız, bunu tahmin, işlemler aşaması (5) içinde ne olursa olsun sürekli çalışacaktır.

Sistem bir işlemin ortasında sıfırlanırsa, en yakın sağlam kontrol noktasına doğru yoluna devam edebilir. Yazılan veriler hâlâ (1) ile aynı şekilde kaybolmaktadır, ancak devam etmesi bununla ilgilenecektir. Hiçbir bilgi aslında kaybolmaz.


1
Harika bir açıklama. hepsi mantıklı geliyor. bu nedenle, bir işlem tümüyle güncellenen (4) dosya bloğu bilgisine gidiyorsa, tüm bu baytların iyi olduğunu bilirsiniz. o zaman önceki aşamada olan herhangi bir bayt ya diske girmedi ya da - yapsaydı - "hatırlanmayacaklardı" (onlara atıfta
bulunmazlardı

4
@the_velour_fog Ve sadece sondan bir önceki paragraf tamamlayacak - Bir dosya sistemini kullanıyorsanız gelmez günlük kaydı uygulamak, gerçekten başarısız ve bozuk dosyası üretmek için özgeçmiş neden "kırık" veri alabilir olmadan size bir hata veriyor. Bu geçmişte her zaman, özellikle de yüksek gecikmeli cihazlar (disketler gibi) için tasarlanmış dosya sistemlerinde meydana gelirdi. Dosya sistemi bu şekilde güvenilir olmasa bile, bundan kaçınmak için hala bazı hileler vardı, ancak telafi etmek için daha akıllı bir uygulamaya ve bazı sistemlerde yanlış olabilecek bazı varsayımlara ihtiyaç vardı.
Luaan

Bu cevap, dosya sistemlerinde günlük tutmanın kullanışlılığını gösterir. Bu sürece güvenilir çalışmıyor herşey aletlerin (aracılığıyla kullanıcı alanı uygulamaları dahil işlemsel semantik, fsync(hatta sözde "kurumsal" sürücüler de, çoğu zaman kırık)) ve sabit disk denetleyicisi. Pek fsyncçok dosya işlemi olmadan , sezgisel olarak sıralanan ve atomik olanların POSIX tarafından garanti edilmediği garanti edilmez : açılan dosyalar, O_APPENDvs. olmayanlardan farklı davranabilir. Geri kalan her şey çoğunlukla kabarıktır.
user1643723

11

Not: Kaynaklara rsyncveya başka bir dosya aktarım yardımcı programına bakmadım .

Bir dosyanın sonunu atlayan ve bu konumun bayt olarak konumunu alan bir C programı yazmak çok önemlidir.

Her iki işlem de standart C kütüphanesi işlevine yapılan tek bir çağrı ile yapılır lseek()( bayt cinsinden ölçülen lseek(fd, 0, SEEK_END)dosya tanıtıcısı için açılan dosyanın uzunluğunu döndürür fd).

Bu hedef dosya için yapıldıktan sonra, benzer bir çağrı için lseek()uygun pozisyona geçmek için kaynak dosyası üzerinde yapılabilir: lseek(fd, pos, SEEK_SET). Aktarım, kaynak dosyasının önceki bölümünün değişmemiş olarak tanımlandığı varsayılarak, bu noktada devam edebilir (farklı yardımcı programlar bunu farklı şekillerde yapabilir).

Diskte bir dosya parçalanmış olabilir , ancak dosya sistemi bir uygulamanın dosyayı sıralı bir bayt sırası olarak algılamasını sağlar.


Bitler ve baytlar hakkındaki yorumlardaki tartışmayla ilgili olarak: Diske yazılabilecek en küçük veri birimi bayt'tır . Tek bir bayt , diskte ayrılacak en az bir veri bloğu gerektirir . Bir bloğun boyutu dosya sisteminin türüne ve muhtemelen dosya sistemini başlatırken yönetici tarafından kullanılan parametrelere bağlıdır, ancak genellikle 512 bayt ile 4 KiB arasındadır. Yazma işlemleri çekirdek, altta yatan C kütüphanesi veya uygulamanın kendisi tarafından tamponlanabilir ve diske gerçek yazma, optimizasyon olarak uygun blok boyutunun katlarında olabilir.

Tek bitleri bir dosyaya yazmak mümkün değildir ve bir yazma işlemi başarısız olursa, dosyada "yarı yazılı bayt" bırakmaz.


teşekkürler, peki bir yazma işleminin başarısız olup olmadığını garanti eden nedir - yarı yazılmış bayt bırakmaz? Çekirdek tamponlama muru tanımlayan mıydı? - eğer bir işlem çekirdeğe 8 KB'lik bir yığın göndermenin ortasında yarıda kesilirse ve beklenmedik bir şekilde sonlandırılırsa - bu 8KB yığınının çekirdeğe asla erişemeyeceği - ancak çekirdeğe ve dosya sistemine ulaşmış olanların iyi olacağı varsayılabilir mi?
the_velour_fog

6
@the_velour_fog bu tür beklenmedik bir sonlandırma gerçekleşemez, çünkü işlem bir G / Ç sistemi çağrısının ortasında kesintisiz olacaktır (bu nedenle NFS dosyası için dosya sistemi erişim çağrıları üzerine sıkışmaz bir işlemin görülmesi olağandışı değildir). Ayrıca bakınız: unix.stackexchange.com/q/62697/70524
muru

2
Sistem tam olarak yanlış zamanda güç kaybederse sorun olabilir. Bu bazen bir dosyanın son yazma noktasında çöplerle sonuçlanabilir. Veritabanı tasarımında çok zor bir problem. Ancak yine de "geçerli" veya "geçersiz" olan en küçük normal birim bir disk bloğudur.
pjc50

1
@the_velour_fog " Yarım yazılı bayt " (ya da daha doğru olarak yarı yazılı bir bayt bloğu ) alamayacağınız kadar değil, yarı yazılı bloğun yazıldığı gibi kaydedilmesi (bütünüyle) ) - LSerni'nin cevabının (3) ve (4) adımlarına bakınız .
TripeHound

5

Bu temelde iki soru, çünkü kıvrılma ve rsync gibi programlar çok farklı.

Curl gibi HTTP istemcileri için geçerli dosyanın boyutunu kontrol ederler ve Content-Rangeistekleri ile birlikte bir başlık gönderirler . Sunucu, dosya dizisini (başarı 206) yerine durum kodunu (kısmi içerik) kullanarak göndermeye devam eder 200ve indirme devam eder veya başlığı yok sayar ve baştan başlar ve HTTP istemcisinin her şeyi yeniden indirmekten başka seçeneği yoktur tekrar.

Ayrıca, sunucu bir Content-Lengthbaşlık gönderebilir veya göndermeyebilir . Bazı indirmelerin yüzde göstermediğini ve dosya boyutunun olmadığını fark etmiş olabilirsiniz. Bunlar, sunucunun müşteriye uzunluğu söylemediği indirmelerdir, bu nedenle müşteri yalnızca indirdiği tutarı bilir, ancak kaç bayt izleyemez.

Content-RangeBaşlatma ve durdurma pozisyonuna sahip bir başlık kullanmak, bir indirme yöneticisi tarafından farklı kaynaklardan bir dosyayı aynı anda indirmek için kullanılır; bu, her bir yansıtmanın kendi başına ağ bağlantınızdan daha yavaş olması durumunda aktarımı hızlandırır.

Öte yandan, rsync artan dosya aktarımları için gelişmiş bir protokoldür. Hangi baytların aynı olduğunu tespit etmek için sunucudaki ve istemci tarafındaki dosyanın parçalarını sağlama toplamı oluşturur. O zaman sadece farklılıkları gönderir. Bu, yalnızca bir indirme işlemine devam edemeyeceği, ancak dosyayı yeniden indirmeden çok büyük bir dosyanın ortasında birkaç byte değiştirdiyseniz değiştirilen baytları da indirebileceği anlamına gelir.

Transferleri devam ettirmek için yapılan başka bir protokol, .torrentdosyanın dosyadaki bloklar için sağlama toplamlarının bir listesini içerdiği bittorrent'tir, böylece bloklar isteğe göre ve farklı kaynaklardan paralel olarak indirilip doğrulanabilir.

HTTP indirmeye devam ederken rsync ve bittorent'in diskinizdeki kısmi verileri doğrulayacağını unutmayın. Bu nedenle, kısmi verilerin bozulduğundan şüpheleniyorsanız, bütünlüğü kontrol etmeniz gerekir, örneğin final dosyasını sağlama toplamı. Ancak indirme işlemini kesmek veya ağ bağlantısını kaybetmek, genellikle aktarım sırasında bir elektrik kesintisi meydana gelebilirken, kısmi dosyayı bozmaz.


4

TL; DR: Kullandıkları protokol izin vermediği sürece yapamazlar.

Programlar her zaman isteğe bağlı bir konumdan devam edemez: örneğin, HTTP istekleri yalnızca sunucu destekliyorsa ve istemci bunu uygularsa yeniden başlatılabilir : bu evrensel değildir, bu nedenle programınızın belgelerine bakın. Sunucu destekliyorsa, programlar protokolün bir parçası olarak sorarak aktarımı devam ettirebilir. Genellikle indirme dizininizde kısmi transferler görürsünüz (genellikle ".partial" uzantısıyla işaretlenirler veya benzer bir şeydir.)

Bir dosya indirme işlemi duraklatılırsa veya durdurulursa, müşteri dosyayı diske yazabilir ve nerede devam edeceğine dair kesin bir fikre sahip olabilir. Diğer yandan, istemci çökerse veya dosyaya yazarken bir hata varsa, istemcinin dosyanın bozuk olduğunu varsayması ve baştan başlatması gerekir. BitTorrent , dosyaları "parçalara" bölerek ve hangilerinin başarılı bir şekilde indirildiğini takip ederek bunu hafifletir; yinelemek zorunda kalacağı en fazla şey birkaç topaktır. Rsync benzer bir şey yapar.

Programlar içeriğin aynı olduğunu nasıl biliyor? Bir yöntem, bazı tanımlayıcıların istemci ve sunucu arasında aynı olduğunu doğrulamaktır. Buna bazı örnekler zaman damgası ve büyüklüğü olabilir, ancak bir protokole özgü olabilecek mekanizmalar vardır. Tanımlayıcılar eşleşirse, müşteri devam etmenin işe yarayacağını varsayabilir.

Daha kesin bir doğrulama istiyorsanız, HTTP ve arkadaşlar ilk tercihiniz olmamalıdır. İndirme sağlama toplamını sunucunun bilgisayar sağlama toplamı ile karşılaştırabilmeniz için tüm dosya ve her aktarılan öbek için sağlama toplamı veya karma değerine sahip bir protokol kullanmak isteyeceksiniz: Eşleşmeyen herhangi bir şey yeniden yüklenir. Yine, BitTorrent bu tip bir protokol örneğidir; rsync isteğe bağlı olarak bunu da yapabilir.


rsync örneği için basit olacak çünkü yalnızca bir rsync protokolü var. http indirme için standart olarak menzil isteyen var. Özgeçmiş-yükleme işleminde curl 'ın gerçekte ne yaptığını bilmek isterim, çünkü yükleme işleminin standart anlambilimi çok parçalı / form verisidir (wget ve curl için), ancak yükleme devam et semantiğinin evrensel olarak kararlaştırıldığına inanmıyorum. Örneğin YouTube ve Nginx bunu farklı şekilde yapabilir.
Rob,

1

Aktarmak için kullanılan protokole bağlı. Fakat curl http kullanır ve verileri dosyada göründüğü sırayla sırayla aktarır. Böylece kıvrılma, kısmen tamamlanmış bir aktarımın dosya boyutuna bağlı olarak devam edebilir. Aslında, uzunluğu N (herhangi bir şey) olan bir dosya oluşturarak ve bu dosyayı kısmen tamamlanmış bir indirme işlemi olarak kabul etmesini (ve sonra ilk N baytları atmasını) isteyerek ilk N bayt atlaması için onu kandırabilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.