Skynet 1.6.0 - Bản Cập Nhật Mùa Thu 2023
Trong nửa tháng vừa qua, do chính sách phòng dịch mới tại Quảng Châu, tôi đã làm việc tại nhà và tranh thủ hoàn thiện phiên bản Skynet 1.6.0 sau đúng một năm kể từ bản 1.5.0 ra mắt năm ngoái. Dù không mang đến những thay đổi đột phá, bản cập nhật lần này tập trung khắc phục hàng loạt lỗi nhỏ tích tụ trong quá trình sử dụng, đồng thời cập nhật toàn bộ các thư viện phụ trợ quan trọng như Lua và jemalloc lên phiên bản mới nhất.
Nâng cấp trình điều khiển MongoDB
Một điểm đáng chú ý là việc cập nhật driver MongoDB. Phiên bản mới nhất của MongoDB đã chính thức khai tử giao thức truyền tải cũ (wire protocol), khiến các driver không được cập nhật không thể kết nối với server MongoDB phiên bản 6.0 trở lên. Chi tiết quá trình nâng cấp có thể theo dõi tại PR #1649. Do kiến trúc đặc thù của MongoDB, chúng tôi không thể xây dựng giải pháp tương thích ngược với cả hai phiên bản giao thức. Qua trải nghiệm này, tôi nhận thấy thiết kế giao thức底层 của Redis ổn định hơn đáng kể - suốt hơn một thập kỷ qua gần như không cần điều chỉnh gì đáng kể.
Hành trình đồng hành cùng Lua
Trong nhiều năm qua, tôi luôn theo dõi sát sao các bản cập nhật của Lua - ngôn ngữ lập trình được tôi đánh giá là có mã nguồn “trong mơ” cho các developer yêu thích sự tinh tế. Phong cách lập trình của đội ngũ phát triển Lua vô cùng cẩn trọng: không chỉ đảm bảo tính chính xác trong môi trường hiện tại, mà còn tuân thủ nghiêm ngặt các tiêu chuẩn lập trình dù là chi tiết nhỏ nhất. Thái độ nghiêm túc này không tự nhiên mà có, mà là kết quả của quá trình mài giũa kéo dài hơn 20 năm.
Trên ổ cứng của tôi lưu trữ đầy đủ mã nguồn của mọi phiên bản Lua từ những ngày đầu. Việc so sánh đối chiếu giữa các phiên bản không chỉ giúp tôi hiểu sâu hơn về ngôn ngữ này, mà còn học hỏi được nhiều kỹ thuật lập trình tinh tế. Đặc biệt kể từ khi kho mã nguồn chính thức được mirror lên GitHub, tôi đã hình thành thói quen xem xét từng commit mới - một hình thức “tu luyện” kiến thức lập trình không thể thay thế.
Bài học từ realloc trong Lua
Một commit gần đây đã khiến tôi phải suy ngẫm sâu sắc: thay vì dùng cách tiếp cận truyền thống (free/copy/alloc) để mở rộng stack, đội ngũ Lua đã chuyển sang dùng realloc. Vấn đề phức tạp nằm ở chỗ realloc có thể di chuyển vùng nhớ, dẫn đến việc các con trỏ tham chiếu stack cần được tính toán lại. Nếu làm theo cách thông thường, tôi sẽ tính khoảng cách giữa địa chỉ mới/cũ rồi hiệu chỉnh con trỏ tương ứng.
Tuy nhiên, cách tiếp cận của Lua lại hoàn toàn khác biệt: trước khi realloc, tất cả con trỏ đều được chuyển thành offset; sau khi realloc xong mới chuyển ngược lại thành con trỏ. Lý do cho quyết định này được chính tác giả giải thích rất rõ ràng:
“Theo tiêu chuẩn ISO C, mọi thao tác trên con trỏ đã bị giải phóng đều là hành vi không xác định (undefined behavior). Vì vậy trước khi thực hiện reallocation, tất cả con trỏ cần chuyển thành offset, sau đó mới khôi phục lại thành con trỏ.”
Không chỉ dừng lại ở việc dereference, ngay cả việc tính toán địa chỉ từ con trỏ đã bị giải phóng cũng vi phạm tiêu chuẩn C. Dù trên thực tế phần cứng hiện tại cho phép thao tác này, nhưng về mặt lý thuyết đây vẫn là hành vi không nên sử dụng.
Triết lý lập trình từ tác giả Lua
Một thảo luận thú vị khác trên mailing list Lua gần đây đã làm sáng tỏ triết lý lập trình của đội ngũ phát triển. Khi được hỏi tại sao không dùng memset(0) để khởi tạo các cấu trúc dữ liệu chứa con trỏ, tác giả Lua giải thích: “Theo tiêu chuẩn C, giá trị NULL không nhất thiết phải là số 0. Do đó bắt buộc phải dùng = NULL để khởi tạo con trỏ, thay vì dựa vào các giá trị số học.”
Những chi tiết nhỏ như vậy chính là yếu tố tạo nên chất lượng vượt trội cho Lua - một ngôn ngữ nhỏ gọn nhưng vô cùng chắc chắn, xứng đáng là tấm gương về phong cách lập trình chuyên nghiệp.