@@ -62,13 +62,15 @@ OF SUCH DAMAGE.
62
62
63
63
64
64
65
+ #include <errno.h>
65
66
#include <fcntl.h>
66
67
#include <pwd.h>
67
68
#include <stdint.h>
68
69
#include <stdio.h>
69
70
#include <stdlib.h>
70
71
#include <string.h>
71
72
#include <unistd.h>
73
+ #include <sys/resource.h>
72
74
73
75
#include "bf.h"
74
76
#include "dbutils.h"
@@ -590,6 +592,34 @@ INSTALL_NUMBER(INT, int, "%d")
590
592
INSTALL_NUMBER (SIZE , size_t , "%zu" )
591
593
INSTALL_NUMBER (UINT64 , uint64_t , "%" PRIu64 )
592
594
595
+ rlim_t MAX_OPEN_FILES ; /* Maximum number of files that may be held open by dir_rc objects */
596
+ uint64_t CUR_OPEN_FILES ; /* Current number of open files held by dir_rc objects */
597
+
598
+ /*
599
+ * For understanding performance, track how many directories were opened
600
+ * with relative vs. absolute paths.
601
+ */
602
+ static uint64_t n_openats = 0 ;
603
+ static uint64_t n_opens = 0 ;
604
+
605
+ #if defined(DEBUG ) && 0
606
+ __attribute__((destructor )) static void print_openat_stats (void ) {
607
+ uint64_t tot = n_openats + n_opens ;
608
+ if (tot > 0 ) {
609
+ printf ("%" PRIu64 "/%" PRIu64 " (%" PRIu64 "%%) of directories used openat() over open()\n" ,
610
+ n_openats , tot , n_openats * 100 / tot );
611
+ }
612
+ }
613
+ #endif
614
+
615
+ /*
616
+ * Increment the reference count for a dir_rc.
617
+ */
618
+ static void dir_inc (struct dir_rc * dir ) {
619
+ // XXX: is relaxed OK here?
620
+ __atomic_fetch_add (& dir -> rc , 1 , __ATOMIC_ACQ_REL );
621
+ }
622
+
593
623
/*
594
624
* Create a new reference-counted DIR object for the given `struct work`.
595
625
*
@@ -599,31 +629,49 @@ INSTALL_NUMBER(UINT64, uint64_t, "%" PRIu64)
599
629
* Otherwise, just opendir() the path.
600
630
*
601
631
* Increments the refcount on the new object.
632
+ *
633
+ * If we are hitting the limit on the maximum number of open files available,
634
+ * then designate the new dir_rc as "non-clonable" so that it is closed as soon as
635
+ * processing the current directory is complete.
602
636
*/
603
637
struct dir_rc * open_dir_rc (struct work * w ) {
604
638
DIR * dir ;
605
639
606
640
if (w -> parent_dir ) {
641
+ __atomic_add_fetch (& n_openats , 1 , __ATOMIC_RELAXED );
607
642
int d_fd = get_dir_fd (w -> parent_dir );
608
643
char * basename = w -> name + w -> name_len - w -> basename_len ;
609
644
int fd = openat (d_fd , basename , O_RDONLY |O_DIRECTORY );
610
645
if (fd < 0 ) {
611
- return NULL ;
646
+ goto err ;
612
647
}
613
648
dir = fdopendir (fd );
614
649
} else {
650
+ __atomic_add_fetch (& n_opens , 1 , __ATOMIC_RELAXED );
615
651
dir = opendir (w -> name );
616
652
}
617
653
618
654
if (!dir ) {
619
- return NULL ;
655
+ goto err ;
620
656
}
621
657
622
658
struct dir_rc * new = calloc (1 , sizeof (* new ));
623
- // printf("creating dir at %p\n", new);
624
659
new -> dir = dir ;
625
660
dir_inc (new );
661
+
662
+ uint64_t cur_open_files = __atomic_add_fetch (& CUR_OPEN_FILES , 1 , __ATOMIC_ACQ_REL );
663
+ if (cur_open_files >= MAX_OPEN_FILES ) {
664
+ new -> dont_clone = 1 ;
665
+ }
666
+
626
667
return new ;
668
+
669
+ err :
670
+ if (errno == EMFILE ) {
671
+ fprintf (stderr , "Warning: too many open files, index may not be complete!\n" );
672
+ }
673
+
674
+ return NULL ;
627
675
}
628
676
629
677
/*
@@ -634,19 +682,20 @@ int get_dir_fd(struct dir_rc *dir) {
634
682
}
635
683
636
684
/*
637
- * Increment the reference count for a dir_rc.
638
- */
639
- void dir_inc (struct dir_rc * dir ) {
640
- // printf("incrementing dir at %p\n", dir);
641
- // XXX: is relaxed OK here?
642
- __atomic_fetch_add (& dir -> rc , 1 , __ATOMIC_ACQ_REL );
643
- }
644
-
645
- /*
646
- * Clone a `dir_rc`.
647
- * This increments the refcount and returns a pointer to the dir_rc to the caller.
685
+ * Attempt to clone a `dir_rc`.
686
+ *
687
+ * If succesful, this increments the refcount and returns a pointer to the
688
+ * dir_rc to the caller.
689
+ *
690
+ * If unsuccesful, returns NULL.
691
+ *
692
+ * The caller MUST be prepared for cloning to fail!
648
693
*/
649
694
struct dir_rc * dir_clone (struct dir_rc * dir ) {
695
+ if (dir -> dont_clone ) {
696
+ return NULL ;
697
+ }
698
+
650
699
dir_inc (dir );
651
700
return dir ;
652
701
}
@@ -656,10 +705,9 @@ struct dir_rc *dir_clone(struct dir_rc *dir) {
656
705
*/
657
706
void dir_dec (struct dir_rc * dir ) {
658
707
if (dir ) {
659
- // printf("decrementing dir at %p\n", dir);
660
708
if (__atomic_sub_fetch (& dir -> rc , 1 , __ATOMIC_ACQ_REL ) == 0 ) {
661
- // printf("freeing dir at %p\n", dir);
662
709
closedir (dir -> dir );
710
+ __atomic_sub_fetch (& CUR_OPEN_FILES , 1 , __ATOMIC_ACQ_REL );
663
711
free (dir );
664
712
}
665
713
}
0 commit comments