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