Hoàn Thiện Phần Triển Khai VFS
“Đơn giản đến mức không thể đơn giản hơn, nhưng không quá mức cần thiết” – Albert Einstein
Trong thời gian qua, công việc trọng tâm của tôi là hoàn thiện hệ thống VFS (Hệ thống tệp ảo) đã đề cập trước đó. Động lực viết bài blog này xuất phát từ một cuộc thảo luận trên mạng xã hội, khi có đồng nghiệp đề nghị tôi chia sẻ góc nhìn về bài viết mới nhất của Linus Torvalds liên quan đến chủ đề muôn thuở: C hay C++ tốt hơn? Lần này, giọng điệu của Linus dường như ôn hòa hơn so với những tranh luận cách đây ba năm, dù vẫn giữ nguyên phong cách sắc sảo đặc trưng.
Tôi cho rằng ba đặc tính cốt lõi của ngôn ngữ C (như đã nêu ở đoạn cuối phần trích dẫn) đều mang tính then chốt. Lần này, Linus đặc biệt nhấn mạnh vào đặc điểm thứ ba – yếu tố mà nhiều lập trình viên C++ thường xem nhẹ. Tuy nhiên, trong các dự án phát triển quy mô lớn với sự tham gia của nhiều người, đây lại là khía cạnh mang tính sống còn. Đây không phải vấn đề có thể giải quyết đơn giản bằng trí tuệ cá nhân. Thậm chí, những lập trình viên xuất sắc càng nhận thức rõ chi phí giao tiếp trong quá trình hợp tác. Ngay cả khi bạn làm việc độc lập, phiên bản “bạn của quá khứ”, “bạn của hiện tại” và “bạn của tương lai” cũng tồn tại rào cản giao tiếp (về mặt trí nhớ). Như triết lý Heraclitus: “Không ai tắm hai lần trên một dòng sông”.
Quan điểm của tôi luôn tuân thủ nguyên tắc Occam’s Razor: Trừ phi cần thiết, tuyệt đối không tăng thêm khái niệm mới. Đây cũng chính là động lực thúc đẩy tôi tái cấu trúc hệ thống quản lý tài nguyên lần này. Trong môi trường nhóm dự án, những thay đổi mang tính cách mạng thường gặp phải nhiều phản đối. Dù tôi luôn chủ trương dân chủ trong phát triển phần mềm, nhưng lần này不得不 đưa ra quyết định đơn phương vì nhận thấy đây là lỗi hệ thống nghiêm trọng nhưng khó nhận biết. Thiết kế cũ tuy tinh xảo và vận hành ổn định, nhưng không phù hợp với lộ trình phát triển dài hạn.
Một dự án lý tưởng nên được xây dựng theo mô hình phân mảnh, nơi mỗi thành viên tập trung phát triển module riêng biệt. Các giao diện kết nối với phần ngoài cần được định nghĩa rõ ràng thông qua tài liệu và khái niệm dễ hiểu – bao gồm API, tài nguyên sử dụng, phạm vi áp dụng… Đặc biệt cần hạn chế tối đa sự phụ thuộc vào các framework “khổng lồ” liên kết đa chiều các thành phần.
Quay lại hệ thống VFS vừa triển khai, quá trình hiện thực hóa tương đối đơn giản nhưng thiết kế lại vô cùng phức tạp. Thách thức lớn nhất nằm ở việc cân bằng giữa tính module hóa và hiệu suất giao tiếp giữa các hệ thống tệp cụ thể với framework nhỏ gọn này. Bộ khung này chủ yếu giải quyết hai vấn đề: quản lý tài nguyên bộ nhớ và tăng tốc truy xuất thông qua cơ chế cache.
Tôi định nghĩa hai cấu trúc dữ liệu nội bộ, mượn khái niệm từ VFS của Linux: dentry (mô tả mục录目录项) và inode (mô tả tập tin). Tuy nhiên, tôi không công khai cấu trúc nội tại của hai thành phần này. Khi mở rộng, người dùng chỉ cần cung cấp hai con trỏ dữ liệu bổ sung để phát triển cấu trúc riêng – kỹ thuật đã được tôi trình bày chi tiết trong các bài viết trước. Trong thực tế, phương pháp này không tuân theo khuôn mẫu cố định.
Tất cả hàm xử lý đều đảm bảo tính re-entrancy, tuy nhiên chưa yêu cầu thread safety để hỗ trợ cơ chế mount lồng ghép hệ thống tệp. Ban đầu, tôi dự định triển khai hệ thống zipfs để mount các tập tin zip thông thường. Tuy nhiên trong quá trình phát triển, tôi nhận ra cả thư viện zlib lẫn zziplib đều không cung cấp giao diện seek hiệu quả do vấn đề bản quyền. Sau một đêm nghiên cứu định dạng zip và thuật toán giải nén, tôi nhận thấy với cơ chế nén luồng dữ liệu truyền thống, gần như không thể xây dựng thuật toán seek hiệu suất cao.
Dù tìm được cách tối ưu seek trong zlib bằng API cấp thấp (giảm chi phí seek so với phương pháp giả đọc hiện tại), nhưng hiệu suất vẫn chưa đạt mức O(LogN) lý tưởng. Tôi đành từ bỏ ý định này vì nếu giữ nguyên, hiệu suất truy xuất các tập tin zip lồng ghép sẽ rất kém. Một giải pháp thay thế là lưu trữ zip bên trong zip ở dạng chưa nén, qua đó cải thiện seek lên O(1) bằng cách sửa đổi nhẹ minizip. Tuy nhiên, tôi quyết định dành giải pháp này cho định dạng gói dữ liệu mới trong tương lai – sử dụng kỹ thuật nén theo khối (chunk-based compression).
Kết quả hiện tại bao gồm: rootfs cơ bản, memfs cho phép tạo tập tin/thư mục trong bộ nhớ (dùng để thiết lập điểm mount ban đầu), nativefs ánh xạ thư mục hệ thống gốc sang engine ở chế độ chỉ đọc, cùng zipfs phục vụ nhu cầu đóng gói trong giai đoạn phát triển. Trong tương lai sẽ bổ sung hệ thống tệp ghi được để lưu thiết lập cá nhân và định dạng gói tùy chỉnh mới.
Đáng chú ý, tôi cũng đánh giá một thư viện unrar sửa đổi, nhưng do vướng mắc giấy phép phức tạp nên chưa thể tích hợp. Nếu nguồn lực cho phép, đây có thể là hướng phát triển trong tương lai.
Đặc biệt, nhờ sự hỗ trợ của đồng nghiệp, chúng tôi đã hoàn thành việc chuyển đổi các giao diện thao tác tài nguyên cũ trong engine sang hệ thống mới.