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