1 #include <stdlib.h> 2 #include <assert.h> 3 4 #include "fio.h" 5 #include "flist.h" 6 #include "hash.h" 7 #include "filehash.h" 8 #include "smalloc.h" 9 #include "lib/bloom.h" 10 11 #define HASH_BUCKETS 512 12 #define HASH_MASK (HASH_BUCKETS - 1) 13 14 #define BLOOM_SIZE 16*1024*1024 15 16 static unsigned int file_hash_size = HASH_BUCKETS * sizeof(struct flist_head); 17 18 static struct flist_head *file_hash; 19 static struct fio_mutex *hash_lock; 20 static struct bloom *file_bloom; 21 22 static unsigned short hash(const char *name) 23 { 24 return jhash(name, strlen(name), 0) & HASH_MASK; 25 } 26 27 void fio_file_hash_lock(void) 28 { 29 if (hash_lock) 30 fio_mutex_down(hash_lock); 31 } 32 33 void fio_file_hash_unlock(void) 34 { 35 if (hash_lock) 36 fio_mutex_up(hash_lock); 37 } 38 39 void remove_file_hash(struct fio_file *f) 40 { 41 fio_mutex_down(hash_lock); 42 43 if (fio_file_hashed(f)) { 44 assert(!flist_empty(&f->hash_list)); 45 flist_del_init(&f->hash_list); 46 fio_file_clear_hashed(f); 47 } 48 49 fio_mutex_up(hash_lock); 50 } 51 52 static struct fio_file *__lookup_file_hash(const char *name) 53 { 54 struct flist_head *bucket = &file_hash[hash(name)]; 55 struct flist_head *n; 56 57 flist_for_each(n, bucket) { 58 struct fio_file *f = flist_entry(n, struct fio_file, hash_list); 59 60 if (!f->file_name) 61 continue; 62 63 if (!strcmp(f->file_name, name)) { 64 assert(f->fd != -1); 65 return f; 66 } 67 } 68 69 return NULL; 70 } 71 72 struct fio_file *lookup_file_hash(const char *name) 73 { 74 struct fio_file *f; 75 76 fio_mutex_down(hash_lock); 77 f = __lookup_file_hash(name); 78 fio_mutex_up(hash_lock); 79 return f; 80 } 81 82 struct fio_file *add_file_hash(struct fio_file *f) 83 { 84 struct fio_file *alias; 85 86 if (fio_file_hashed(f)) 87 return NULL; 88 89 INIT_FLIST_HEAD(&f->hash_list); 90 91 fio_mutex_down(hash_lock); 92 93 alias = __lookup_file_hash(f->file_name); 94 if (!alias) { 95 fio_file_set_hashed(f); 96 flist_add_tail(&f->hash_list, &file_hash[hash(f->file_name)]); 97 } 98 99 fio_mutex_up(hash_lock); 100 return alias; 101 } 102 103 bool file_bloom_exists(const char *fname, bool set) 104 { 105 return bloom_string(file_bloom, fname, strlen(fname), set); 106 } 107 108 void file_hash_exit(void) 109 { 110 unsigned int i, has_entries = 0; 111 112 fio_mutex_down(hash_lock); 113 for (i = 0; i < HASH_BUCKETS; i++) 114 has_entries += !flist_empty(&file_hash[i]); 115 fio_mutex_up(hash_lock); 116 117 if (has_entries) 118 log_err("fio: file hash not empty on exit\n"); 119 120 sfree(file_hash); 121 file_hash = NULL; 122 fio_mutex_remove(hash_lock); 123 hash_lock = NULL; 124 bloom_free(file_bloom); 125 file_bloom = NULL; 126 } 127 128 void file_hash_init(void) 129 { 130 unsigned int i; 131 132 file_hash = smalloc(file_hash_size); 133 134 for (i = 0; i < HASH_BUCKETS; i++) 135 INIT_FLIST_HEAD(&file_hash[i]); 136 137 hash_lock = fio_mutex_init(FIO_MUTEX_UNLOCKED); 138 file_bloom = bloom_new(BLOOM_SIZE); 139 } 140