Phân bổ không gian trong Firebird 2.1 trở lên
Vlad Khorsun, 20-THU-2010
Ngay từ đầu, Firebird không có quy tắc nào về cách phân bổ dung lượng đĩa cho (các) tệp cơ sở dữ liệu. Nó chỉ ghi các trang mới được cấp phát theo thứ tự không xác định (do sự phụ thuộc giữa các trang để phục vụ chiến lược «ghi cẩn thận»).
Cách tiếp cận này rất đơn giản nhưng có một số nhược điểm:
• do thứ tự ghi không xác định, có thể xảy ra tình huống bộ nhớ đệm trang chứa nhiều trang bẩn tại thời điểm một trang mới được cấp phát phải được ghi nhưng không thể vì hết dung lượng đĩa. Trong những trường hợp như vậy, thường tất cả các trang bẩn khác bị mất vì quản trị viên thích tắt cơ sở dữ liệu trước khi giải phóng một số dung lượng trên đĩa. Điều này dẫn đến hỏng hóc nghiêm trọng.
• việc phân bổ dung lượng đĩa theo các khối tương đối nhỏ có thể dẫn đến phân mảnh tệp đáng kể ở cấp độ hệ thống tệp và làm giảm hiệu suất của các lần quét lớn (ví dụ trong quá trình sao lưu).
Sử dụng ODS 11.1 mới, Firebird thay đổi thuật toán phân bổ dung lượng đĩa của mình để tránh hỏng hóc trong điều kiện hết dung lượng đĩa và tạo cơ hội cho hệ thống tệp tránh phân mảnh. Những thay đổi này được mô tả dưới đây.
a) Mọi trang mới được cấp phát được ghi lên đĩa ngay lập tức trước khi trả về cho engine. Nếu trang không thể được ghi thì việc cấp phát không xảy ra, bit PIP không bị xóa và lỗi IO thích hợp được đưa ra. Lỗi này không thể dẫn đến hỏng hóc vì chúng tôi có đảm bảo rằng tất cả các trang bẩn trong bộ nhớ đệm đã có dung lượng đĩa được cấp phát và có thể được ghi an toàn.
Thay đổi này tạo ra một lần ghi bổ sung cho mỗi trang mới được cấp phát so với hành vi cũ. Vì vậy, hiệu suất bị giảm dự kiến trong quá trình tăng trưởng tệp cơ sở dữ liệu. Để giảm thiểu sự giảm hiệu suất này, Firebird nhóm các lần ghi của các trang mới được cấp phát lên đến 128KB mỗi lần và theo dõi số lượng trang «đã khởi tạo» tại tiêu đề PIP.
Lưu ý : trang mới được cấp phát sẽ được ghi lên đĩa hai lần chỉ khi trang này được cấp phát lần đầu tiên. Tức là, nếu trang được cấp phát, giải phóng và cấp phát lại thì nó sẽ không được ghi hai lần trong lần cấp phát thứ hai.
b) Để tránh phân mảnh tệp, Firebird sử dụng API thích hợp của hệ thống tệp để phân bổ trước dung lượng đĩa theo các khối tương đối lớn. Hiện tại, API như vậy chỉ tồn tại trong Windows nhưng gần đây nó đã được thêm vào API Linux và có thể được triển khai trong các hệ thống tệp phổ biến như ext2, v.v. trong tương lai. Vì vậy, tính năng này hiện chỉ được triển khai trong các bản dựng Windows của Firebird và có thể được triển khai trong các bản dựng Linux trong tương lai.
Để kiểm soát tốt hơn việc phân bổ trước dung lượng đĩa, một cài đặt mới trong Firebird.conf đã được giới thiệu : DatabaseGrowthIncrement. Đây là giới hạn trên của kích thước khối phân bổ trước tính bằng byte. Giá trị mặc định là 128MB. Khi engine cần thêm dung lượng đĩa, nó phân bổ 1/16 dung lượng đã được cấp phát nhưng không ít hơn 128KB và không nhiều hơn giá trị DatabaseGrowthIncrement. Nếu DatabaseGrowthIncrement được đặt bằng 0 thì việc phân bổ trước bị vô hiệu hóa. Dung lượng cho các tệp bóng của cơ sở dữ liệu không được phân bổ trước.
Ngoài ra, việc phân bổ trước bị vô hiệu hóa nếu tùy chọn «No reserve» được đặt cho cơ sở dữ liệu.
Lưu ý : việc phân bổ trước cũng cho phép tránh hỏng hóc trong điều kiện hết dung lượng đĩa - trong trường hợp như vậy, có khả năng lớn là cơ sở dữ liệu có đủ dung lượng được phân bổ trước để hoạt động cho đến khi quản trị viên giải phóng một số dung lượng đĩa.
Tác giả: Vlad Khorsun,