2010-09-21 28 views
14

Cách chính xác để đổi tên một tệp trong hệ thống tệp POSIX là gì? Đặc biệt tự hỏi về fsyncs trên các thư mục . (Nếu điều này phụ thuộc vào hệ điều hành/FS, tôi hỏi về Linux và ext3/ext4).Làm cách nào để đổi tên một tệp trong POSIX?

Lưu ý: còn có các câu hỏi khác về StackOverflow về đổi tên bền, nhưng AFAICT không giải quyết các thư mục (điều này quan trọng đối với tôi - tôi thậm chí không sửa đổi dữ liệu tệp).

Tôi hiện có (bằng Python):

dstdirfd = open(dstdirpath, O_DIRECTORY|O_RDONLY) 
rename(srcdirpath + '/' + filename, dstdirpath + '/' + filename) 
fsync(dstdirfd) 

câu hỏi cụ thể:

  • Liệu điều này cũng ngầm fsync thư mục nguồn? Hoặc tôi có thể kết thúc với tệp hiển thị trong cả hai thư mục sau một chu kỳ nguồn (nghĩa là tôi phải kiểm tra số liên kết cứng và thực hiện khôi phục thủ công), tức là không thể đảm bảo hoạt động di chuyển nguyên tử có thể kéo dài?
  • Nếu tôi fsync thư mục nguồn thay vì thư mục đích, điều đó cũng sẽ ngầm đồng bộ hóa thư mục đích?
  • Có bất kỳ công cụ kiểm tra/gỡ lỗi/học tập có liên quan hữu ích nào (các bộ phun lỗi, công cụ nội soi, hệ thống tệp giả, v.v.) không?

Xin cảm ơn trước.

Trả lời

14

POSIX xác định rằng chức năng đổi tên phải có nguyên tử:

http://pubs.opengroup.org/onlinepubs/009695399/functions/rename.html

Vì vậy, nếu bạn đổi tên (A, B), trong mọi trường hợp bạn sẽ không bao giờ nhìn thấy một trạng thái với các tập tin trong cả hai thư mục hoặc thư mục không. Sẽ luôn có chính xác một, bất kể bạn làm gì với fsync() hoặc hệ thống có bị treo hay không.

Nhưng điều đó không giải quyết được vấn đề đảm bảo thao tác đổi tên() bền. POSIX trả lời câu hỏi này:

Nếu _POSIX_SYNCHRONIZED_IO được định nghĩa, các fsync() chức năng sẽ buộc tất cả các I/O hoạt động hiện xếp hàng liên quan đến các tập tin được chỉ định bởi fildes mô tả tập tin sang trạng thái hoàn I/O đồng bộ. Tất cả các hoạt động I/O sẽ được hoàn thành như được định nghĩa để hoàn thành tính toàn vẹn tệp I/O được đồng bộ.

(từ http://pubs.opengroup.org/onlinepubs/009695399/functions/fsync.html)

Vì vậy, nếu bạn fsync() một thư mục, trong khi chờ đổi tên hoạt động phải được chuyển vào đĩa vào thời điểm lợi nhuận này. fsync() của một trong hai thư mục là đủ bởi vì atomicity của phép đổi tên() sẽ yêu cầu cả hai thư mục 'thay đổi được syncked nguyên tử.

Cuối cùng, trái ngược với tuyên bố trong bài viết trên blog đề cập trong câu trả lời khác, lý do cho điều này giải thích như sau:

Các fsync() chức năng được thiết kế để buộc một ghi vật lý của dữ liệu từ bộ nhớ cache đệm, và để đảm bảo rằng sau khi một hệ thống sụp đổ hoặc thất bại khác mà tất cả dữ liệu lên đến thời gian của fsync() gọi được ghi lại trên đĩa. Vì các khái niệm về "bộ đệm đệm", "sự cố hệ thống", "ghi vật lý" và "bộ nhớ không bay hơi" không được định nghĩa ở đây, từ ngữ phải trừu tượng hơn.

Hệ thống được cho là tuân thủ POSIX và coi đó là hành vi chính xác (nghĩa là lỗi hoặc lỗi phần cứng) để hoàn thành fsync() và không tồn tại những thay đổi đó trong một sự cố hệ thống sẽ phải cố ý xuyên tạc chính nó đối với spec.

(cập nhật thông tin bổ sung lại: Linux-cụ thể khác với hành vi cầm tay)

+1

Lý do ở đây là rất sai. - "atomicity" của rename(), ví dụ, đề cập đến "newpath", theo đó nên là tệp cũ (nếu có) hoặc tệp được đổi tên, không có trạng thái ở giữa (như được xem bởi các quy trình khác) . –

+0

Robert chỉ ra, đổi tên là "nguyên tử" liên quan đến việc gán inode mới để đặt tên, cho dù điểm inode mới cho dữ liệu chưa được quét hay không không được xác định bởi POSIX. – ArekBulski

-1

Câu trả lời cho câu hỏi của bạn phụ thuộc rất nhiều vào hệ điều hành cụ thể đang được sử dụng, loại hệ thống tệp đang được sử dụng và liệu nguồn và đích có trên cùng một thiết bị hay không.

Tôi bắt đầu bằng cách đọc trang đổi tên (2) người đàn ông trên nền tảng bạn đang sử dụng.

+0

Đã tham khảo trang người đàn ông đó - không có gì liên quan. Bạn đang nói không có cách di động để đổi tên qua các thư mục? Tôi sẵn sàng tin rằng nhưng quan tâm đến một tuyên bố rõ ràng hơn và lý tưởng hỗ trợ bằng chứng. Ngoài ra, bạn có biết câu trả lời cho Linux 2.6 gần đây với ext3/4 (vì câu hỏi này đã được gắn thẻ - vừa cập nhật văn bản chính)? – Yang

+0

Ah ok, đơn giản hơn nếu nó chỉ là linux và ext3/4 mà bạn quan tâm. Một trong những báo trước rằng việc đổi tên linux (2) man page đề cập đến là: 'Tuy nhiên, khi ghi đè có thể sẽ có một cửa sổ trong đó cả oldpath và newpath tham chiếu đến tập tin đang được đổi tên.' –

-3

Nghe có vẻ như tôi đang cố gắng thực hiện công việc của hệ thống tệp. Nếu bạn di chuyển một tệp, hạt nhân và hệ thống tệp chịu trách nhiệm cho hoạt động nguyên tử và khôi phục lỗi, không phải mã của bạn.

Dù sao, bài viết này dường như để giải quyết câu hỏi của bạn về fsync: http://blogs.gnome.org/alexl/2009/03/16/ext4-vs-fsync-my-take/

+0

Đọc bài viết đó trước đây, và nó là một trong nhiều đã mang tôi đến đây. Nó đặc biệt nói: "Trong trường hợp hệ thống bị lỗi ngay sau khi viết, có nhiều khả năng chúng tôi nhận được tệp mới hơn tệp cũ (để có cơ hội tối đa cho điều này, bạn cần phải đồng bộ hóa thư mục tệp đó)". Câu hỏi của tôi là về những gì sẽ xảy ra khi bạn đổi tên qua các thư mục. – Yang

11

Đáng tiếc là câu trả lời của Dave là sai.

Không phải tất cả các hệ thống POSIX thậm chí có thể có bộ nhớ bền. Và nếu họ làm, nó vẫn được "cho phép" để được hosed sau khi một hệ thống sụp đổ. Đối với những hệ thống đó, một fsync no-op() có ý nghĩa, và fsync() được cho phép rõ ràng trong POSIX. Nó cũng là hợp pháp cho các tập tin được phục hồi trong thư mục cũ, thư mục mới, cả hai, hoặc bất kỳ vị trí nào khác. POSIX không đảm bảo cho sự cố hệ thống hoặc khôi phục hệ thống tệp.

Câu hỏi thực sự nên là:

Làm thế nào để làm một đổi tên bền trên các hệ thống có hỗ trợ thông qua các API POSIX?

Bạn cần phải thực hiện một fsync() trên cả hai, nguồn thư mục đích, vì tối thiểu những fsync() s được cho là vẫn tồn tại như thế nào thư mục nguồn hoặc đích.

Có một fsync (destdirfd) cũng ngầm hoàn toàn fsync thư mục nguồn không?

  • POSIX nói chung: không có, không có gì ngụ ý rằng
  • ext3/4: Tôi không chắc chắn nếu cả hai thay đổi nguồn và đích dir kết thúc trong cùng một giao dịch trên tạp chí. Nếu họ làm, họ nhận được cả hai cam kết với nhau.

Hoặc tôi có thể kết thúc với tệp hiển thị trong cả hai thư mục sau một chu kỳ nguồn ("crash"), tức là không thể đảm bảo hoạt động di chuyển nguyên tử có thể kéo dài?

  • POSIX nói chung: không có bảo lãnh, nhưng bạn đang phải fsync() cả hai thư mục, trong đó có thể không phải nguyên tử bền
  • ext3/4: bao nhiêu fsync(), bạn có tối thiểu cần phụ thuộc vào các tùy chọn gắn kết. Ví dụ. nếu được gắn với “dirsync”, bạn không cần bất kỳ hai fsync() s nào. Hầu hết bạn cần cả hai fsync() s, nhưng tôi gần như chắc chắn một là đủ (nguyên tử bền sau đó).

Nếu tôi fsync thư mục nguồn thay vì thư mục đích, nó cũng sẽ ngầm đồng bộ hóa thư mục đích?

  • POSIX: không
  • ext3/4: Tôi thực sự tin rằng cả hai kết thúc trong cùng một giao dịch, vì vậy nó không quan trọng mà trong số họ bạn fsync() hạt nhân ext3
  • cũ: (nếu chúng không nằm trong cùng một giao dịch) một số việc triển khai không quá tối ưu đã làm quá nhiều việc đồng bộ hóa trên fsync(), tôi đặt cược nó đã thực hiện mọi giao dịch đến trước đó. Và có, việc triển khai bình thường trước tiên sẽ liên kết nó đến đích và sau đó xóa nó khỏi nguồn. Vì vậy, fsync (srcdirfd) cũng sẽ kích hoạt fsync() của đích.
  • ext4/ext3 mới nhất: nếu họ không nằm trong cùng một giao dịch, bạn có thể có thể hoàn toàn đồng bộ chúng một cách độc lập (do đó làm cả hai)

Có bất kỳ công cụ kiểm tra/gỡ lỗi/học tập hữu ích liên quan (kim phun lỗi, công cụ nội soi, hệ thống tập tin giả, v.v.)?

Để có sự cố thực sự, không. Bằng cách này, một vụ tai nạn thực sự vượt ra ngoài quan điểm của hạt nhân. Các phần cứng có thể sắp xếp lại viết (và không viết tất cả mọi thứ), làm hỏng hệ thống tập tin. Ext4 được chuẩn bị tốt hơn chống lại điều này, bởi vì nó cho phép ghi barries (tùy chọn gắn kết) theo mặc định (ext3 không) và có thể phát hiện tham nhũng với checksums tạp chí (cũng là một tùy chọn gắn kết).

Và để tìm hiểu: hãy tìm hiểu xem cả hai thay đổi có được liên kết bằng cách nào đó trên tạp chí không! :-P

+1

Đây là một điểm tinh tế, nhưng tôi không cho rằng fsync() của một thư mục * ngụ ý * fsync() của thư mục kia. Đó là fsync() của một, kết hợp với atomicity của rename(), yêu cầu * rằng thay đổi cụ thể * vào thư mục khác cũng được sync'd vào đĩa.Tôi có thể tin rằng đó không phải là trường hợp, nhưng đó là đọc của tôi về spec. Bạn có một tham chiếu để sao lưu giải thích của bạn rằng nguyên tử không được đảm bảo trên một vụ tai nạn, ngay cả khi một phần của sự thay đổi "nguyên tử" là fsync'd? –

+0

Có, tôi làm: liên kết của bạn tới [fsync() trên opengroup.org] (http://pubs.opengroup.org/onlinepubs/009695399/functions/fsync.html). "Nó được dự định rõ ràng rằng một thực hiện null được cho phép." Đó là: không có bảo đảm. - Và liên kết mơ ước đổi tên() và fsync() là sáng chế của bạn. Và không, nó không phải là một điểm tinh tế. –

+1

Đồng ý rằng các hệ thống POSIX không bắt buộc phải thực hiện bất kỳ thay đổi nào như vậy, và câu hỏi thực sự là cách sử dụng API để thực hiện thay đổi bền vững trên các hệ thống hỗ trợ nó. Trong khi yêu cầu một tham chiếu, tôi đã đề cập đến yêu cầu của bạn rằng ngay cả trên các hệ thống * làm * hỗ trợ sync'ing thay đổi vào đĩa, một thành công fsync() của một trong hai thư mục vẫn có thể dẫn đến tệp hiển thị ở cả hai vị trí (hoặc không) sau một sự cố. –