Bagaimana program yang dapat melanjutkan transfer file yang gagal tahu di mana harus mulai menambahkan data?


23

Beberapa program penyalinan file menyukai rsyncdan curlmemiliki kemampuan untuk melanjutkan kembali transfer / salinan yang gagal.

Memperhatikan bahwa mungkin ada banyak penyebab kegagalan ini, dalam beberapa kasus program dapat melakukan "pembersihan" beberapa kasus program tidak bisa.

Ketika program-program ini dilanjutkan, mereka tampaknya hanya menghitung ukuran file / data yang berhasil ditransfer dan baru mulai membaca byte berikutnya dari sumber dan menambahkan ke fragmen file.

mis. ukuran fragmen file yang "membuatnya" ke tujuan adalah 1378 byte, jadi mereka baru mulai membaca dari byte 1379 pada dokumen asli dan menambahkannya ke fragmen.

Pertanyaan saya adalah, mengetahui bahwa byte terdiri dari bit dan tidak semua file memiliki segmentasi data dalam potongan-potongan berukuran byte bersih, bagaimana program-program ini tahu bahwa titik yang mereka pilih untuk mulai menambahkan data adalah benar?

Saat menulis file tujuan adalah semacam buffering atau "transaksi" mirip dengan database SQL yang terjadi, baik di tingkat program, kernel atau sistem file untuk memastikan bahwa hanya byte bersih yang terbentuk dengan baik yang membuatnya ke perangkat blok yang mendasarinya?
Atau apakah program menganggap byte terbaru akan berpotensi tidak lengkap, sehingga mereka menghapusnya dengan asumsi itu buruk, menyalin ulang byte dan mulai menambahkannya dari sana?

mengetahui bahwa tidak semua data direpresentasikan sebagai byte, tebakan ini tampaknya salah.

Ketika program-program ini "melanjutkan" bagaimana mereka tahu mereka mulai di tempat yang tepat?


21
"tidak semua file memiliki data yang tersegmentasi dalam potongan berukuran byte bersih" tidak? Bagaimana Anda menulis sesuatu yang kurang dari satu byte ke file?
muru

17
Saya tahu tidak ada panggilan sistem yang dapat menulis apa pun kurang dari satu byte, dan untuk disk itu sendiri, saya pikir tidak ada disk saat ini yang menulis kurang dari 512 byte blok (atau 4096 byte blok).
muru

8
Tidak, saya katakan minimum adalah satu byte. Aplikasi waras akan menggunakan potongan 4KB atau 8KB:, head -c 20480 /dev/zero | strace -e write tee foo >/dev/nulldan kemudian OS akan buffer mereka dan mengirimkannya ke disk dalam potongan yang lebih besar.
muru

9
@the_velour_fog: Bagaimana Anda menulis sedikit saja fwrite()?
psmears

9
Untuk semua tujuan praktis, Data yang terdiri dari byte dan semuanya beroperasi dengan mereka sebagai unit terkecil. Beberapa sistem (sebagian besar berkaitan dengan kompresi misalnya gzip, h264) membongkar masing-masing bit dari byte, tetapi sistem operasi dan operasi memori berada pada level byte.
pjc50

Jawaban:


40

Demi kejelasan - mekanisme nyata lebih rumit untuk memberikan keamanan yang lebih baik - Anda dapat membayangkan operasi tulis-ke-disk seperti ini:

  • aplikasi menulis byte (1)
  • kernel (dan / atau sistem file IOSS) mendukung mereka
  • setelah buffer penuh, buffer akan dibuang ke sistem file:
    • blok dialokasikan (2)
    • blok ditulis (3)
    • informasi file dan blokir diperbarui (4)

Jika prosesnya terganggu pada (1), Anda tidak mendapatkan apa pun pada disk, file tersebut utuh dan terpotong di blok sebelumnya. Anda mengirim 5.000 byte, hanya 4.096 pada disk, Anda memulai kembali transfer di offset 4096.

Jika pada (2), tidak ada yang terjadi kecuali dalam memori. Sama seperti (1). Jika pada (3), data ditulis tetapi tidak ada yang mengingatnya . Anda mengirim 9000 byte, 4096 ditulis, 4096 ditulis dan hilang , sisanya hilang. Transfer resume di offset 4096.

Jika pada (4), data seharusnya sudah dikomit di disk. Bytes berikutnya dalam aliran mungkin hilang. Anda mengirim 9000 byte, 8192 ditulis, sisanya hilang, transfer resume di offset 8192.

Ini adalah pengambilan yang disederhanakan . Misalnya, setiap tulisan "logis" dalam tahap 3-4 bukan "atomik", tetapi memunculkan urutan lain (sebut saja nomor # 5) di mana blok tersebut, dibagi lagi menjadi sub-blok yang sesuai untuk perangkat tujuan (mis. Hard disk ) dikirim ke pengontrol host perangkat, yang juga memiliki mekanisme caching , dan akhirnya disimpan di piring magnetik. Sub-urutan ini tidak selalu sepenuhnya di bawah kendali sistem, sehingga mengirim data ke hard disk bukanlah jaminan bahwa itu sebenarnya telah ditulis dan akan dapat dibaca kembali.

Beberapa sistem file menerapkan penjurnalan , untuk memastikan bahwa titik yang paling rentan, (4), sebenarnya tidak rentan, dengan menuliskan meta-data, Anda dapat menebaknya, transaksi yang akan bekerja secara konsisten apa pun yang terjadi pada tahap (5).

Jika sistem diatur ulang di tengah transaksi, ia dapat melanjutkan perjalanan ke pos pemeriksaan terdekat terdekat. Data yang ditulis masih hilang, sama seperti kasus (1), tetapi pembukaan kembali akan menanganinya. Tidak ada informasi yang hilang.


1
Penjelasan yang bagus. itu semua masuk akal. jadi jika suatu proses membuat semua jalan ke (4) info blok file diperbarui, Anda tahu semua byte itu baik. maka setiap byte yang pada tahap sebelumnya tidak berhasil ke disk atau - jika mereka melakukannya - mereka akan "tidak diingat" (tidak ada referensi untuk mereka)
the_velour_fog

4
@the_velour_fog Dan hanya untuk melengkapi paragraf kedua dari belakang - jika Anda menggunakan sistem file yang tidak mengimplementasikan penjurnalan, Anda memang bisa mendapatkan data "rusak", menyebabkan resume gagal dan menghasilkan file yang kacau tanpa memberi Anda kesalahan. Ini biasa terjadi sepanjang waktu di masa lalu, terutama dengan sistem file yang dirancang untuk perangkat latensi tinggi (seperti disket). Masih ada beberapa trik untuk menghindari ini bahkan jika sistem file tidak dapat diandalkan dengan cara ini, tetapi diperlukan aplikasi yang lebih cerdas untuk mengkompensasi dan beberapa asumsi yang mungkin salah pada beberapa sistem.
Luaan

Jawaban ini melebih-lebihkan kegunaan jurnal dalam sistem file. Ini tidak bekerja dengan andal kecuali semuanya mengimplementasikan semantik transaksional, termasuk aplikasi userspace (via fsync) dan pengontrol hard drive (sering rusak, bahkan dalam drive yang dianggap "perusahaan"). Tanpa fsyncbanyak operasi file, yang dipesan secara intuisi dan atom tidak dijamin akan seperti itu oleh POSIX: file, dibuka dengan O_APPENDmungkin berperilaku berbeda dari yang tanpa dll. Dalam praktiknya kunci yang paling penting untuk konsistensi file adalah sistem kernel VFS dan cache disk. Segala sesuatu yang lain kebanyakan bulu.
user1643723

11

Catatan: Saya belum melihat sumber rsyncatau utilitas transfer file lainnya.

Adalah sepele untuk menulis program C yang melompati bagian akhir file dan mendapatkan posisi lokasi itu dalam byte.

Kedua operasi dilakukan dengan satu panggilan ke fungsi pustaka C standar lseek()( lseek(fd, 0, SEEK_END)mengembalikan panjang file yang dibuka untuk deskriptor file fd, diukur dalam byte).

Setelah selesai untuk file target, panggilan mirip dengan lseek()dapat dilakukan pada file sumber untuk melompat ke posisi yang sesuai: lseek(fd, pos, SEEK_SET). Transfer kemudian dapat dilanjutkan pada titik itu, dengan anggapan bagian awal dari file sumber telah diidentifikasi sebagai tidak berubah (utilitas yang berbeda dapat melakukan ini dengan cara yang berbeda).

File mungkin terfragmentasi pada disk, tetapi sistem file akan memastikan bahwa suatu aplikasi menganggap file sebagai urutan sekuensial byte.


Mengenai diskusi dalam komentar tentang bit dan byte: Unit data terkecil yang dapat ditulis ke disk adalah byte . Satu byte membutuhkan setidaknya satu blok data untuk dialokasikan pada disk. Ukuran blok tergantung pada jenis sistem file dan mungkin juga pada parameter yang digunakan oleh administrator ketika menginisialisasi sistem file, tetapi biasanya di suatu tempat antara 512 byte dan 4 KiB. Operasi penulisan dapat disangga oleh kernel, pustaka C yang mendasarinya atau oleh aplikasi itu sendiri dan penulisan ke disk yang sebenarnya dapat terjadi dalam beberapa ukuran blok yang sesuai sebagai pengoptimalan.

Tidak mungkin untuk menulis bit tunggal ke file dan jika operasi penulisan gagal, itu tidak akan meninggalkan "byte setengah ditulis" dalam file.


terima kasih, jadi apa yang memastikan jika operasi penulisan gagal - tidak akan meninggalkan setengah byte yang ditulis? apakah itu yang dijelaskan oleh kernel buffering muru? - yaitu jika suatu proses terputus di tengah pengiriman chunk 8KB ke kernel dan dihentikan secara tak terduga - bahwa chunk 8KB tidak akan pernah mencapai kernel - tetapi ada yang sebelumnya yang mencapai kernel dan filesystem dapat dianggap baik?
the_velour_fog

6
@the_velour_fog penghentian yang tidak terduga semacam itu tidak dapat terjadi, karena prosesnya tidak akan terputus di tengah-tengah panggilan sistem I / O (itu sebabnya tidak biasa untuk melihat proses yang tidak dapat diselesaikan terhenti pada panggilan akses sistem file untuk file NFS). Lihat juga: unix.stackexchange.com/q/62697/70524
muru

2
Mungkin ada masalah jika sistem kehilangan daya pada waktu yang salah. Ini kadang-kadang dapat menghasilkan sampah pada titik penulisan terakhir file. Ini masalah yang sangat sulit dalam desain basis data. Tetapi unit terkecil yang normal yang "valid" atau "tidak valid" adalah blok disk.
pjc50

1
@the_velour_fog Tidak sebanyak Anda tidak bisa mendapatkan " setengah byte yang ditulis " (atau, lebih tepatnya, blok setengah byte yang ditulis ) sebagai blok setengah tertulis tidak akan dicatat sebagai telah ditulis (secara keseluruhan ) - lihat langkah (3) dan (4) jawaban LSerni .
TripeHound

5

Ini pada dasarnya adalah dua pertanyaan, karena program seperti curl dan rsync sangat berbeda.

Untuk klien HTTP seperti curl, mereka memeriksa ukuran file saat ini dan kemudian mengirim Content-Rangeheader dengan permintaan mereka. Server melanjutkan pengiriman kisaran file menggunakan kode status 206(sebagian konten) alih-alih 200(sukses) dan unduhan dilanjutkan atau mengabaikan header dan mulai dari awal dan klien HTTP tidak memiliki pilihan lain selain mengunduh ulang semuanya lagi.

Lebih lanjut server mungkin atau mungkin tidak mengirim Content-Lengthheader. Anda mungkin memperhatikan bahwa beberapa unduhan tidak memperlihatkan persentase dan ukuran file. Ini adalah unduhan di mana server tidak memberi tahu klien panjangnya, jadi klien hanya tahu jumlah yang diunduh tetapi tidak berapa banyak byte yang akan mengikuti.

Menggunakan Content-Rangeheader dengan posisi mulai dan berhenti digunakan oleh beberapa pengelola unduhan untuk mengunduh file dari berbagai sumber sekaligus, yang mempercepat transfer jika setiap mirror dengan sendirinya lebih lambat dari koneksi jaringan Anda.

rsync di sisi lain adalah protokol canggih untuk transfer file tambahan. Ini menghasilkan checksum dari bagian-bagian file di server dan sisi klien untuk mendeteksi byte yang sama. Maka hanya mengirim perbedaan. Ini berarti tidak hanya dapat melanjutkan unduhan, tetapi bahkan dapat mengunduh byte yang diubah jika Anda mengubah beberapa byte di tengah file yang sangat besar tanpa mengunduh ulang file.

Protokol lain yang dibuat untuk melanjutkan transfer adalah bittorrent, di mana .torrentfile berisi daftar checksum untuk blok dari file, sehingga blok dapat diunduh dan diverifikasi dalam urutan sewenang-wenang dan secara paralel dari sumber yang berbeda.

Perhatikan bahwa rsync dan bittorent akan memverifikasi sebagian data pada disk Anda, sementara melanjutkan unduhan HTTP tidak akan. Jadi jika Anda mencurigai sebagian data rusak Anda perlu memeriksa integritas sebaliknya, yaitu menggunakan checksum dari file akhir. Tetapi hanya mengganggu pengunduhan atau kehilangan koneksi jaringan biasanya tidak merusak file parsial sementara kegagalan daya selama transfer mungkin dilakukan.


4

TL; DR: Mereka tidak bisa, kecuali protokol yang mereka gunakan memungkinkan untuk itu.

Program tidak selalu dapat melanjutkan dari lokasi arbitrer: misalnya, permintaan HTTP hanya dapat dimulai kembali jika server mendukungnya dan klien mengimplementasikannya: ini tidak universal, jadi periksa dokumentasi program Anda. Jika server mendukungnya, program dapat melanjutkan transfer hanya dengan bertanya sebagai bagian dari protokol. Anda biasanya akan melihat transfer sebagian dalam direktori unduhan Anda (biasanya ditandai dengan ekstensi ".partial" atau yang serupa.)

Jika unduhan file dijeda atau dihentikan, klien dapat menulis file ke disk dan memiliki ide yang pasti tentang tempat untuk melanjutkan. Jika, di sisi lain, klien macet atau ada kesalahan menulis ke file, klien harus berasumsi bahwa file rusak dan mulai lagi dari awal. BitTorrent agak meredakan ini dengan memecah file menjadi "potongan" dan melacak mana yang telah berhasil diunduh; yang paling harus diulang adalah beberapa bongkahan. Rsync melakukan hal serupa.

Bagaimana program mengetahui bahwa kontennya sama? Salah satu metode adalah untuk memverifikasi bahwa beberapa pengidentifikasi sama antara klien dan server. Beberapa contoh dari hal ini adalah cap waktu dan ukuran, tetapi ada mekanisme yang dapat spesifik untuk protokol. Jika pengidentifikasi cocok, maka klien dapat berasumsi bahwa melanjutkan akan bekerja.

Jika Anda ingin verifikasi yang lebih pasti, HTTP dan teman-teman tidak boleh menjadi pilihan pertama Anda. Anda akan ingin menggunakan protokol yang juga memiliki checksum atau hash untuk seluruh file dan masing-masing potongan yang ditransfer sehingga Anda dapat membandingkan checksum unduhan dengan checksum komputer server: apa pun yang tidak cocok kemudian akan diunduh kembali. Sekali lagi, BitTorrent adalah contoh dari protokol semacam ini; rsync secara opsional dapat melakukan ini juga.


untuk contoh rsync, itu akan langsung karena hanya ada satu protokol rsync. untuk unduhan http, ada range-requesting sebagai standar. Saya ingin tahu apa sebenarnya ikal pada resume-unggah, karena semantik standar unggahan adalah multipart / form-data (untuk wget dan ikal), tapi saya tidak percaya semantik semantik unggah resume disetujui secara universal. YouTube dan Nginx dapat melakukan ini secara berbeda misalnya.
Rob

1

Tergantung pada protokol yang digunakan untuk mentransfer. Tapi curl menggunakan http dan mentransfer data secara berurutan sesuai urutan yang muncul dalam file. Jadi, ikal dapat dilanjutkan berdasarkan ukuran file dari transfer yang sebagian selesai. Faktanya, Anda dapat mengelabunya untuk melewati N byte pertama dengan membuat file dengan panjang N (apa pun) dan memintanya untuk memperlakukan file itu sebagai unduhan yang telah selesai sebagian (dan kemudian membuang byte N pertama).

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.