14.3.3. Kebersihan filesystem¶
Penyimpanan flash dan SD pada kamera yang telah dikirimkan akan terisi file-file yang tidak akan dibersihkan secara manual oleh operator. Dua keputusan mengenai penyimpanan tersebut akan berlaku sepanjang masa produk: permukaan mana yang menyimpan jenis data apa, dan bagaimana direktori disusun agar operasi file tetap berjalan seiring aplikasi mengumpulkan catatan.
14.3.3.1. Ke mana data ditempatkan¶
Kode dan aset disimpan dalam modul beku dan ROMFS yang dikompilasi saat waktu pengiriman. State aplikasi -- apapun yang ditulis oleh aplikasi saat runtime, apapun yang bertambah, apapun yang berubah antar boot -- harus disimpan di tempat lain. Kamera mengekspos dua permukaan yang dapat ditulis untuk itu:
Flash internal di
/flash: filesystem yang dapat ditulis berukuran kecil yang dipasang sebelum kode aplikasi apapun berjalan. Tempat yang tepat untuk catatan berukuran tetap kecil yang bertahan antar reboot: konfigurasi yang diperbarui aplikasi saat runtime, kalibrasi terakhir yang diketahui, penghitung bergulir, file penanda satu baris yang menyatakan "kamera ini telah diprovisioning." Siklus penulisan terbatas -- flash internal modern menoleransi ribuan hingga puluhan ribu penulisan per sektor, bukan jutaan, sehingga penulisan harus jarang, bukan per bingkai.Kartu SD di
/sdcard: filesystem yang dapat ditulis berukuran lebih besar yang dipasang saat kartu tersedia. Tempat yang tepat untuk file variabel berukuran besar: tangkapan citra dan video, file log, data fine-tuning model, apapun yang mungkin tumbuh hingga megabyte atau gigabyte. Kapasitas tulis lebih tinggi dari flash internal namun tetap terbatas; dapat dilepas, dapat diganti, dan permukaan yang paling mungkin menghilang saat aplikasi sedang dalam proses penulisan.
Jawaban yang tepat untuk ke mana menulis sesuatu hampir selalu "flash untuk catatan tetap kecil, SD untuk segalanya." Keduanya tidak dapat dipertukarkan: aplikasi yang menulis file log bergulirnya ke /flash akan menghabiskan daya tahan penulisan flash dalam suatu deployment yang seharusnya baik-baik saja di SD.
14.3.3.2. Perlakukan keduanya sebagai dapat gagal¶
/flash dan /sdcard keduanya bisa gagal. Kartu SD bisa dilepas, flash bisa rusak akibat kehilangan daya saat penulisan berlangsung, keduanya bisa kehabisan ruang, dan operasi apapun pada keduanya dapat memunculkan OSError karena alasan yang tidak akan sempat didiagnosis oleh aplikasi di lapangan.
Dua pola membuat aplikasi dapat bertahan dari hal tersebut:
Bungkus operasi mount dan operasi dalam blok try. Setiap
open(),os.listdir(),os.rename()terhadap jalur data pengguna berpotensi gagal. TangkapOSError, catat, dan kembali ke alternatif yang telah ditentukan -- tulis ke/flashjika/sdcardtidak tersedia, lewati operasi jika tidak ada yang tersedia.Penulisan atomis untuk file yang harus bertahan dari kehilangan daya. Tulis ke jalur sementara, tutup handle-nya, lalu
os.rename()ke nama aktif. Entah rename berhasil dan file adalah versi baru, atau tidak berhasil dan file adalah versi lama. Tidak ada kondisi ketiga di mana file setengah ditulis:import os def write_config_atomic(path, contents): tmp = path + '.tmp' with open(tmp, 'w') as f: f.write(contents) f.flush() os.rename(tmp, path)
Pola ini berfungsi pada flash maupun SD. Pola ini tidak berfungsi untuk file yang cukup besar sehingga file tmp menghabiskan ruang kosong filesystem; cadangkan untuk catatan kecil.
14.3.3.3. Jebakan direktori yang lambat¶
VFS MicroPython tidak mengindeks isi direktori seperti yang dilakukan filesystem desktop. os.listdir() dan os.stat() menelusuri tabel file yang mendasarinya secara linear. Direktori dengan seratus file tidak masalah; direktori dengan sepuluh ribu file sangat lambat digunakan, dengan setiap os.listdir() memakan waktu beberapa detik dan setiap open() memeriksa tabel saat diaksesnya.
Aplikasi yang menulis log atau tangkapan ke disk mengalami masalah ini paling cepat. Skema /sdcard/logs/<timestamp>.log yang naif yang membuka satu file baru per menit akan mengisi direktori logs/ dengan setengah juta file dalam satu tahun deployment. Jauh sebelum itu, aplikasi mulai melewatkan frame rate-nya karena setiap pembukaan file memakan waktu lebih lama dari interval satu bingkai.
Pola yang tepat adalah membagi file di seluruh pohon subdirektori bertanggal sehingga tidak ada satu direktori pun yang pernah menyimpan lebih dari beberapa ratus entri:
import os
import time
LOG_ROOT = '/sdcard/logs'
def log_path(now=None):
if now is None:
now = time.localtime()
year, month, day, hour = now[0], now[1], now[2], now[3]
directory = '{}/{:04d}/{:02d}/{:02d}'.format(
LOG_ROOT, year, month, day)
_makedirs(directory)
return '{}/{:02d}.log'.format(directory, hour)
def _makedirs(path):
# os.makedirs equivalent -- create each level if missing
parts = path.split('/')
for i in range(2, len(parts) + 1):
sub = '/'.join(parts[:i])
try:
os.mkdir(sub)
except OSError:
pass
Satu tahun logging satu-file-per-jam kini tersebar di 365 direktori hari, masing-masing berisi paling banyak 24 file; os.listdir() terhadap direktori mana pun tetap cepat, dan loop bingkai aplikasi tidak terhenti pada operasi file seiring bertambahnya umur deployment.
Prinsip yang sama berlaku untuk tangkapan citra, jejak sensor, atau apapun lainnya yang ditulis aplikasi satu file per peristiwa. Jika tingkat peristiwa tinggi, pohon perlu lebih dalam (year/month/day/hour, atau year/month/day/hour/minute) agar setiap direktori daun tetap kecil. Jika tingkat peristiwa rendah, pohon year/month sudah cukup.
14.3.3.4. Jalur per perangkat¶
Dalam armada yang terdiri lebih dari satu kamera, file log perlu mengidentifikasi unit fisik mana yang menghasilkannya. machine.unique_id() mengembalikan identifikasi perangkat keras yang tertanam pada kamera di pabrik; nilainya sama di seluruh reboot, pembaruan firmware, dan penggantian kartu SD. Sematkan ke jalur log atau ke catatan log dan operator yang melihat tumpukan kartu SD atau log terpusat dapat mengetahui mana yang mana:
import binascii
import machine
UNIT_ID = binascii.hexlify(machine.unique_id()).decode()
LOG_ROOT = '/sdcard/logs/' + UNIT_ID
Dikombinasikan dengan pola subdirektori bertanggal, tata letaknya menjadi /sdcard/logs/<unit-id>/2026/06/09/14.log -- satu jam catatan sebuah unit, dalam direktori yang cukup dangkal untuk ditelusuri, pada jalur yang mencantumkan nama unit pada filesystem itu sendiri.
14.3.3.5. Menggabungkan semuanya¶
Penyimpanan yang dapat ditulis dari kamera yang telah dikirimkan terlihat kira-kira seperti ini:
/flash-- konfigurasi, kalibrasi, penanda provisioning. Jarang ditulis, sering dibaca. Pola atomic-rename untuk file apapun yang kehilangannya akan merusak boot berikutnya./sdcard/logs/<unit-id>/<year>/<month>/<day>/<hour>.log-- log operasional. Ditulis terus-menerus, dirotasi berdasarkan jalur, tidak pernah ditulis melalui direktori dengan ribuan file sejajar./sdcard/captures/<unit-id>/<year>/<month>/<day>/-- tangkapan citra atau video yang dibuat oleh aplikasi. Bentuk pohon yang sama, alasan yang sama.
Tata letak tersebut hanya membutuhkan sekitar dua puluh baris kode dari aplikasi dan menyelamatkannya dari mode kegagalan yang menjatuhkan kamera berbulan-bulan setelah deployment.