2010-06-30 14 views
5

Tôi cần cách nhanh nhất để định kỳ đồng bộ tệp với bộ nhớ.Cách có tệp kiểm tra bằng mmap chỉ được đồng bộ hóa với đĩa theo cách thủ công

Điều tôi nghĩ tôi muốn là có tệp mmap'd, tệp này chỉ được đồng bộ hóa với đĩa theo cách thủ công. Tôi không chắc chắn làm thế nào để ngăn chặn bất kỳ đồng bộ hóa tự động nào xảy ra.

Không thể sửa đổi tệp trừ khi tôi chỉ định theo cách thủ công. Vấn đề là để có một tập tin checkpoint giữ một bản chụp của trạng thái trong bộ nhớ. Tôi muốn tránh sao chép càng nhiều càng tốt, vì điều này sẽ cần phải được gọi khá thường xuyên và tốc độ là quan trọng.

Trả lời

2

mmap không thể được sử dụng cho mục đích này. Không có cách nào để ngăn chặn dữ liệu được ghi vào đĩa. Trong thực tế, sử dụng mlock() để làm cho bộ nhớ không thể thay thế có thể có tác dụng phụ ngăn không cho nó được ghi vào đĩa trừ khi bạn yêu cầu nó được viết, nhưng không đảm bảo. Chắc chắn nếu một quá trình khác mở tệp, nó sẽ thấy bản sao được lưu trong bộ nhớ (với các thay đổi mới nhất của bạn), không phải bản sao trên đĩa vật lý. Trong nhiều cách, những gì bạn nên làm phụ thuộc vào việc bạn đang cố gắng để làm đồng bộ hóa với các quá trình khác hoặc chỉ cho an toàn trong trường hợp sụp đổ hoặc mất điện.

Nếu kích thước dữ liệu của bạn nhỏ, bạn có thể thử một số phương pháp khác để đồng bộ hóa nguyên tử vào đĩa. Một cách là lưu trữ toàn bộ tập dữ liệu trong tên tệp và tạo tệp trống theo tên đó, sau đó xóa tệp cũ. Nếu 2 tập tin tồn tại khi khởi động (do thời gian va chạm rất khó), hãy xóa tệp cũ hơn và tiếp tục từ tệp mới hơn. write()có thể cũng là nguyên tử nếu kích thước dữ liệu của bạn nhỏ hơn khối hệ thống tệp, kích thước trang hoặc khối đĩa, nhưng tôi không biết bất kỳ đảm bảo nào về hiệu ứng đó ngay lập tức. Bạn sẽ phải làm một số nghiên cứu.

Một cách tiếp cận rất chuẩn khác hoạt động miễn là dữ liệu của bạn không lớn đến mức 2 bản sao sẽ không vừa trên đĩa: chỉ cần tạo một bản sao thứ hai có tên tạm thời, sau đó là rename() trên đầu trang cũ. rename() luôn là nguyên tử. Đây có lẽ là cách tiếp cận tốt nhất trừ khi bạn có lý do để không làm theo cách đó.

+0

Không cần để đồng bộ hóa quá trình này. Đó là một bản sao lưu. Tôi cũng muốn tránh làm bất kỳ loại sao chép nào nếu có thể. Dữ liệu cũng ít nhất 50MB. – arsenm

4

Bất cứ điều gì bạn ghi vào bộ nhớ trong một ánh xạ MAP_SHARED của một tệp được coi là được ghi vào tệp tại thời điểm đó, chắc chắn như thể bạn đã sử dụng write(). msync() theo nghĩa này là hoàn toàn analagous để fsync() - nó chỉ đảm bảo rằng những thay đổi bạn có đã được thực hiện vào tệp thực sự được đẩy ra bộ nhớ vĩnh viễn. Bạn không thể thay đổi điều này - đó là cách mmap() được xác định để hoạt động. Nói chung, cách an toàn để thực hiện việc này là viết một bản sao dữ liệu nhất quán hoàn chỉnh vào một tệp tạm thời, đồng bộ hóa tệp tạm thời, sau đó đổi tên nguyên tử nó trên tệp trạm kiểm soát trước đó. Đây là cách duy nhất để đảm bảo rằng sự cố giữa các trạm kiểm soát không khiến bạn bị mất tập tin. Bất kỳ giải pháp nào sao chép ít hơn sẽ yêu cầu cả định dạng tệp giao dịch-log phức tạp hơn và có nhiều xâm nhập vào phần còn lại của ứng dụng của bạn (yêu cầu các móc cụ thể được gọi ở mỗi nơi mà trạng thái trong bộ nhớ bị thay đổi) .

0

Tôi rất nghi ngờ rằng có thể không bị lợi dụng bởi bất kỳ hệ điều hành, nhưng nó sẽ có thể cho một hệ điều hành để ý tối ưu hóa cho:

int fd = open("file", O_RDWR | O_SYNC | O_DIRECT); 

size_t length = get_lenght(fd); 

uint8_t * map_addr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 

... 

// This represents all of the changes that could possibly happen before you 
// want to update the on disk file. 
change_various_data(map_addr); 

if (is_time_to_update()) { 
    write(fd, map_addr, length); 
    lseek(fd, 0, SEEK_SET); 
    // you could have just used pwrite here and not seeked 
} 

Những lý do mà một hệ điều hành thể có thể tận dụng lợi thế của điều này là cho đến khi bạn viết vào một trang cụ thể (và không ai khác đã làm một trong hai) hệ điều hành có lẽ sẽ chỉ sử dụng trang của tập tin thực tế tại vị trí đó như là trao đổi cho trang đó.

Sau đó, khi bạn đã viết thư cho một số thiết lập của các trang hệ điều hành sẽ Sao chépOnViết những trang cho quá trình của bạn, nhưng vẫn giữ các trang bất thành văn được sao lưu bởi các tập tin gốc. Sau đó, khi gọi write hệ điều hành có thể nhận thấy rằng việc ghi được chặn liên kết cả trong bộ nhớ và trên đĩa, và sau đó nó có thể nhận thấy rằng một số trang bộ nhớ nguồn đã được đồng bộ với các trang hệ thống tệp chính xác mà chúng đã được viết và chỉ viết ra các trang đã thay đổi.

Tất cả điều đó được nói, nó sẽ không làm tôi ngạc nhiên nếu tối ưu hóa này không được thực hiện bởi bất kỳ hệ điều hành nào, và loại mã này kết thúc lên rất chậm và gây ra nhiều ghi đĩa khi bạn gọi 'viết'. Sẽ rất tuyệt nếu nó bị lợi dụng.

+0

wtf ಠ_ಠ ಠ_ಠ ಠ_ಠ –

+0

@Matt Joiner: 'Wtf' của bạn là gì? Điều này về cơ bản giống như phần B của câu trả lời của James Caccese mà bạn nói đã đóng đinh suy nghĩ của bạn ngoại trừ nó cho phép hạt nhân hệ điều hành, có quyền truy cập vào các bit bẩn làm cho quyết định viết hoặc không viết mỗi trang. Ngoại trừ phần mà tôi không biết nếu có bất kỳ * nix nào thực sự làm điều này. Đó là ý tưởng tương tự, mặc dù. – nategoose

+0

@nategoose, Bạn đã thực hiện bất kỳ thử nghiệm nào để cho thấy rằng bất kỳ hệ điều hành nào cũng có thể tận dụng thực tế là vùng mmap riêng giống với tệp cơ bản sau tệp pwrite của bạn để nó chỉ giữ một bản sao bộ nhớ cho tệp và tệp riêng tư cache? Tôi không tin rằng hệ điều hành hiện tại có thể thực hiện tối ưu hóa này. –

2

Như những người trả lời khác đã đề xuất, tôi không nghĩ rằng có một cách di động để làm những gì bạn muốn mà không cần sao chép. Nếu bạn đang tìm cách làm điều này trong một môi trường có mục đích đặc biệt, nơi bạn có thể điều khiển hệ điều hành, bạn có thể làm điều đó dưới Linux với hệ thống tập tin btrfs.

btrfs hỗ trợ thao tác reflink() mới cần thiết cho việc sao chép hệ thống tệp sao chép. Bạn có thể reflink() tệp của mình tạm thời khi khởi động, mmap() tạm thời, sau đó msync()reflink() tạm thời trở lại bản gốc để kiểm tra.

2

Bạn có thể mmap nội dung tập tin bản sao trên ghi để cho bất kỳ bản cập nhật bạn làm trong bộ nhớ không được ghi chép lại các tập tin, sau đó khi bạn muốn đồng bộ hóa, bạn có thể:

A) Thực hiện một bản đồ bộ nhớ mới đó không phải là bản sao viết và sao chép của bạn chỉ là các trang bạn sửa đổi vào nó.

Hoặc

B) Mở tập tin (file thường xuyên mở) với io trực tiếp (khối kích thước phù đọc kích thước và văn bản) và chỉ viết những trang mà bạn sửa đổi. Trực tiếp io sẽ được tốt đẹp và nhanh chóng bởi vì bạn đang viết toàn bộ trang (kích thước trang bộ nhớ là một bội số của kích thước khối đĩa) và không có đệm. Phương pháp này có lợi ích của việc không sử dụng không gian địa chỉ trong đó mmap của bạn là lớn và không có chỗ để mmap một tập tin lớn.

Sau khi đồng bộ hóa, bản sao của bạn trên ghi mmap cũng giống như tệp đĩa của bạn, nhưng hạt nhân vẫn có các trang bạn cần đồng bộ được đánh dấu là không được chia sẻ (với đĩa). Vì vậy, sau đó bạn có thể đóng và tạo lại các mmap (vẫn còn sao chép trên ghi) theo cách hạt nhân có thể loại bỏ các trang của bạn nếu cần thiết (thay vì phân trang chúng ra để trao đổi không gian) nếu có áp lực bộ nhớ.

Tất nhiên, bạn phải theo dõi trang nào bạn đã tự sửa đổi vì tôi không thể nghĩ cách bạn truy cập vào nơi hệ điều hành giữ thông tin đó.(Sẽ không có được một syscall tiện dụng)

- chỉnh sửa -

thực sự, xem Can the dirtiness of pages of a mmap be found from userspace? cho ý tưởng về làm thế nào để xem những trang nào là bẩn

+1

Câu trả lời của bạn đã đóng đinh suy nghĩ của tôi về điều này cho đến nay. Móc sắt là điểm đánh dấu trang bẩn. Làm thế nào để bạn biết khi nào nó bẩn? –

Các vấn đề liên quan