readdir()
저는 장난감 파일 시스템을 구현하려고 하며 효율적이고 확장 가능한 방식으로 이를 올바르게 수행하는 방법을 찾으려고 노력하고 있습니다 . FUSE에서 사용하는 인터페이스를 이해하기 위해 주로 설명서를 읽었습니다.파이퓨즈3, 그러나 다른 FUSE 래퍼를 사용해도 문제가 해결될 것이라고 생각하지 않습니다.
내 이해는 내가 구현할 때readdir()
불려지리라고, 불려지길 기대했어readdir_reply()
메서드가 반환될 때까지 연속된 디렉터리 항목을 갖습니다 False
. 이 작업을 수행할 때 각 항목을 이라는 고유한 [1] 64비트 ID와 연결하려고 합니다 next_id
. 다음 호출에서는 readdir()
이러한 ID 중 하나를 받게 되며 이전 호출에서 해당 ID가 반환될 것으로 예상됩니다. ID와 연관된 항목 다음에 시작되는 디렉토리 항목입니다.
호출 사이에 디렉토리가 변경되는 경우(예: 항목 추가 또는 제거) readdir()
연속 호출에서 추가된 항목을 포함하거나 제거된 항목을 생략할지 여부를 자유롭게 선택할 수 있지만 다른 모든 항목은 ID를 유지해야 합니다. 건너뛰거나 두 번 반환됩니다.
의미상으로는 이 모든 것이 나에게는 괜찮은 것 같습니다. 제가 생각할 수 있는 가장 간단한 구현은 모든 디렉토리 항목을 배열로 읽은 opendir()
다음 배열에 있는 각 항목의 인덱스를 ID로 사용하는 것입니다. 모든 항목을 한 번에 읽지 않으려면 readdir()
호출할 때마다 배열을 계속해서 구축할 수 있습니다. 그러나 파일 핸들을 해제하기 전에는 배열[2]을 지울 수 없습니다.
최신 파일 시스템은 수억 개의 파일이 포함된 디렉터리를 쉽게 처리할 수 있습니다. 나는 이러한 구현이 디렉터리 파일 핸들당 디렉터리 항목 수 순서에 따른 메모리 할당을 허용할 수 없다고 가정합니다(예: 천만 파일 × 항목당 100바이트 = 1GB). 이러한 파일 시스템은 일반적으로 FUSE를 통하지 않고 커널에서 거의 독점적으로 구현됩니다.
이 모든 사실은 다음 진술 중 적어도 하나가 사실이라는 결론을 내립니다.
- FUSE 작동 요구사항을 잘못 이해했습니다
readdir()
. - 제가 볼 수 없는 이러한 요구 사항을 충족하는 더 효율적인 솔루션이 있습니다.
- 커널 내의 파일 시스템에 대해 구현할 수 있는 더 나은 API가 있는데, 이 API는 이 모든 상태를 유지할 필요가 없습니다.
- 파일 시스템은
readdir()
동등한 기능을 올바르게 구현하지 않지만 대신 응용 프로그램이 일반적으로 신경 쓰지 않는 방식으로 구현합니다. - 파일 시스템은 디렉터리를 탐색할 때 기가바이트의 메모리를 할당하지만 아무도 이에 대해 신경 쓰지 않습니다.
그래서 그것은 어느 것입니까?
readdir()
다른 파일 시스템 구현이 일반적으로 충족하는 모든 기대를 충족하는 방식으로 FUSE 작업을 효율적으로 구현하는 방법을 이해하고 싶습니다 .
[1]: 단일 파일 핸들 내에서 고유합니다.
[2]: 또는 readdir()
호출 시 start_id
로 설정 될 수도 있습니다 0
.
답변1
동시 수정 및 하드 링크의 경우 효율성을 위해서는 쿠키 B트리가 필요합니다. POSIX에서 다른 올바른 off_t 방법을 모릅니다.
이 의견이 대부분의 답변을 제공한다고 생각합니다.https://github.com/facebookexperimental/eden/blob/5cc682e8ff24ef182be2dbe07e484396539e80f4/eden/fs/inodes/TreeInode.cpp#L1798-L1833
참조 링크를 포함하여 여기에 복사하겠습니다.
디렉토리를 동시에 수정하는 상황에서 readdir을 올바르게 구현하는 것은 쉽지 않습니다. 이 함수는 여러 번 호출됩니다. 첫 번째 읽기에서 제공된 off_t 값은 0이거나 마지막 항목의 오프셋에 해당하는 값입니다. (또는 eekdir 및 Telldir이 지정된 항목의 오프셋 값).
POSIX 규정을 준수하려면 전체 디렉터리 스트림에 걸쳐 일련의 readdir 호출이 주어지면 수정되지 않은 모든 항목이 정확히 한 번 반환되어야 합니다. readdir 호출 사이에 추가되거나 제거된 항목이 반환될 수 있지만 반드시 그럴 필요는 없습니다.
따라서 off_t는 순서가 지정된 항목 목록에 대한 색인으로 충분하지 않습니다. 항목이 연결되지 않은 경우 다음 readdir은 해당 항목을 건너뜁니다.
한 가지 옵션은 off_t를 항목 이름의 해시로 채우는 것입니다. off_t에는 63개의 사용 가능한 비트가 있습니다(초기 요청을 위해 예약된 0 값 제외). 실제로는 SpookyHashV2 63비트로 충분할 수 있지만 충돌이 있는 디렉터리를 생성하여 항목이 중복되거나 무한 루프가 발생할 수 있습니다. 또한
off
다음 readdir 이전에 삭제된 항목을 처리하는 방법도 명확하지 않습니다 . (스트림에서 다시 시작할 위치를 찾는 방법은 무엇입니까?)
현재 Eden은 하드 링크를 지원하지 않습니다. 따라서 단기적으로는 inode 번호를 off_t에 저장하고 이를 inode별로 정렬된 항목 목록의 색인으로 처리할 수 있습니다. 이는 추가 인덱스가 없으면 2차 시간 복잡도를 가지지만 정확합니다.
장기적으로, 특히 Eden의 트리 디렉토리 구조가 SQLite 또는 이와 유사한 것에 저장되어 있는 경우,eekdir/readdir 쿠키 인덱스를 유지하고 해당 쿠키를 사용하여 항목을 열거해야 합니다.