Reputation: 5247
I need to open more than 10,000 files in a Perl script, so I asked the system administrator to change the limit on my account to 14,000. ulimit -a
now shows these settings:
core file size (blocks, -c) unlimited
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
open files (-n) 14000
pipe size (512 bytes, -p) 10
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 29995
virtual memory (kbytes, -v) unlimited
After the change I ran a test Perl program that opens/creates 256 files and closes 256 file handles at the end of script. When it creates 253 files the program dies saying too many open files. I don't understand why I'm getting this error.
I am working on a Solaris 10 platform. This is my code
my @list;
my $filename = "test";
for ($i = 256; $i >= 0; $i--) {
print "$i " . "\n";
$filename = "test" . "$i";
if (open my $in, ">", ${filename}) {
push @list, $in;
print $in $filename . "\n";
}
else {
warn "Could not open file '$filename'. $!";
die;
}
}
for ($i = 256; $i >= 0; $i--) {
my $retVal = pop @list;
print $retVal . "\n";
close($retVal);
}
Upvotes: 7
Views: 2612
Reputation: 595
you have a limit of 256 files. You forgot about STDIN, STDOUT and STDERR. Your 253 + default 3 = 256.
Upvotes: 0
Reputation: 2103
You might be able to work around the limitation with the FileCache Core module (keep more files open than the system permit).
Using cacheout
instead of open
, i was able to open 100334 files on linux:
#david@:~/Test$ ulimit -n
1024
#david@:~/Test$ perl plimit.pl | head
100333
100332
100331
100330
100329
#david@:~/Test$ perl plimit.pl | tail
test100330
test100331
test100332
test100333
#david@:~/Test$ ls test* | wc -l
100334
modified version of your script (plimit.pl)
my @list;
use FileCache;
$mfile=100333;
my $filename="test";
for($i = $mfile; $i >= 0; $i--) {
print "$i " . "\n" ;
$filename = "test" . "$i";
#if (open my $in, ">", ${filename}) {
if ($in = cacheout( ">", ${filename}) ) {
push @list,$in;
print $in $filename . "\n";
} else {
warn "Could not open file '$filename'. $!";
die;
}
}
for($i = $mfile; $i >= 0; $i--) {
my $retVal = pop @list;
print $retVal . "\n";
close($retVal);
}
update
FileCache
automatically closes and re-opens files if you exceed your system's maximum number of file descriptors, or the suggested maximum maxopen (NOFILE defined in sys/param.h).
In my case, on a linux box, it is 256:
#david@:~/Test$ grep -B 3 NOFILE /usr/include/sys/param.h
/* The following are not really correct but it is a value
we used for a long time and which seems to be usable.
People should not use NOFILE and NCARGS anyway. */
#define NOFILE 256
Using the lsof (list open files) command, the modified version of your script opened at most 260 of the 100334 files:
#david@:~/Test$ bash count_of_plimit.sh
20:41:27 18
new max is 18
20:41:28 196
new max is 196
20:41:29 260
new max is 260
20:41:30 218
20:41:31 258
20:41:32 248
20:41:33 193
max count was 260
count_of_plimit.sh
#!/bin/bash
# count open files with lsof
#
# latest revision:
# ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/
# latest FAQ:
# ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/FAQ
perl plimit.pl > out.txt &
pid=$!
##adapted from http://stackoverflow.com/a/1661498
HOW_MANY=0
MAX=0
while [ -r "/proc/${pid}" ];
do
HOW_MANY=`lsof -p ${pid} | wc -l`
#output for live monitoring
echo `date +%H:%M:%S` $HOW_MANY
# look for max value
if [ $MAX -lt $HOW_MANY ]; then
let MAX=$HOW_MANY
echo new max is $MAX
fi
# test every second
sleep 1
done
echo max count was $MAX
Upvotes: 8
Reputation: 386331
Tested with both your program and the following simpler program on a Windows box and a linux box without encountering the error you describe.
my @files;
for (;;) {
print 1+@files, "\n";
open my $fh, '<', $0 or die $!;
push @files, $fh;
last if @files == 500;
}
Output:
1
2
...
498
499
500
I don't think it's a Perl limitation, but a system limitation.
Note that it fails when you try to open the process's 257th handle (STDIN + STDOUT + STDERR + 253 = 256), which leads me to believe the number of open file handles a process can have must fit in 8 bits on your system. You could try verifying this by writing an equivalent C program and running it on the same machine.
#include <stdio.h>
#include <stdlib.h>
int main() {
int i = 0;
for (;;) {
++i;
printf("%d\n", i);
if (fopen("/bin/sh", "r") == NULL) {
perror("fopen");
exit(1);
}
if (i == 500)
break;
}
return 0;
}
Upd: This has been confirmed here. Thanks, Schwern.
Upvotes: 4
Reputation: 165200
According to this article this is a default limitation of 32-bit Solaris. A program is normally limited to using the first 256 file numbers. STDIN, STDOUT and STDERR take 0, 1 and 2 which leaves you with 253. It's not a simple process to work around it, ulimit won't do it, and I don't know if Perl will honor it.
Here's a discussion about it on Perlmonks with a few suggested work arounds such as FileCache.
While the Solaris limitation is unforgivable, in general having hundreds of open filehandles indicates that your program could be designed better.
Upvotes: 16