One Billion Files: Scalability Limits in Linux File Systems (2010) [pdf]
events.linuxfoundation.org
events.linuxfoundation.org
A typical workaround is to to take a hash (md5 or similar) of the filename and then pick some number of nested directories to store it in.
Like: md5("data-file-one") == "0278c2451c1cd1dd98815260159c44e0"
Assuming you go with 4 levels, then:
mkdir -p "0/2/7/8/c" && mv data-file-one 0/2/7/8/c/data-file-one
I believe apache's mod_cache takes this approach.
We then bought FAST. Microsoft later purchased them and folded into the Windows OS, becoming Windows Search. Which is pretty nice - I have it turned on for my local TFS workspace.
For large directories, I either use 'ls --color=never' or the example C program in 'man 2 getdents'.
ls -U huge_dir | awk 'NR % 100000 == 0 { print NR } END { print NR }'
(prints the count every 100k files and the total at the end). $ mkdir testdir && cd testdir # make 200k files
$ perl -e 'for (1..200000) {open(FOO,">$_");close(FOO)}'
$ time echo * >>/dev/null
real 0m1.607s user 0m1.480s sys 0m0.128s
$ time ls >> /dev/null
real 0m1.458s user 0m1.324s sys 0m0.132s
$ # globs
$ time perl -e 'for (glob("*")) {print "$_\n"}' >>/dev/null
real 0m0.679s user 0m0.404s sys 0m0.272s
$ time find . -maxdepth 1 -print >> /dev/null
real 0m0.239s user 0m0.128s sys 0m0.108s
$ time ls -U >> /dev/null
real 0m0.195s user 0m0.064s sys 0m0.132s[0] this program was an in-house solution that handled some edge cases other programs available at the time didn't handle so well.
[1] which is pretty much standard behaviour in file carvers, but wasn't part of the in-house development yet.
That's at most 16 entries per directory which seems unnecessarily low. Taking 2 chars/level gives 96 entries per directory which seems better, that's what Git uses (3 is 4096 which may be a tad high). Yields a flatter but not too broad hierarchy.
Depends what data you're storing (or not storing) I guess. If you're storing all metadata anyway, you may even discard the original file name entirely and have the full path be composed of hash sections. But you may want to traverse the tree (because you're not storing much/any) data, and split things out because there's a number of APIs which don't deal well with humongous directories.
See: http://php.net/manual/en/session.configuration.php#ini.sessi...
Of course there are still a lot of issues with reading that many files.
Aside from deletion, XFS does perform quite well though.