source: benchmark/io/http/filecache.cfa@ 628a7c5

ADT arm-eh ast-experimental enum forall-pointer-decay jacob/cs343-translation new-ast-unique-expr pthread-emulation qualifiedEnum
Last change on this file since 628a7c5 was d9c2284, checked in by Thierry Delisle <tdelisle@…>, 5 years ago

Started doing preliminary work to use Fixed FDs. Starting with the thread pipes.

  • Property mode set to 100644
File size: 4.9 KB
Line 
1#include "filecache.hfa"
2
3#include <assert.h>
4#include <string.h>
5
6#include <stdlib.hfa>
7
8#include <errno.h>
9#include <unistd.h>
10extern "C" {
11 #include <fcntl.h>
12 #include <ftw.h>
13}
14
15#include "options.hfa"
16
17static inline uint32_t murmur_32_scramble(uint32_t k) {
18 k *= 0xcc9e2d51;
19 k = (k << 15) | (k >> 17);
20 k *= 0x1b873593;
21 return k;
22}
23
24uint32_t murmur3_32(const uint8_t* key, size_t len, uint32_t seed)
25{
26 uint32_t h = seed;
27 uint32_t k;
28 /* Read in groups of 4. */
29 for (size_t i = len >> 2; i; i--) {
30 // Here is a source of differing results across endiannesses.
31 // A swap here has no effects on hash properties though.
32 memcpy(&k, key, sizeof(uint32_t));
33 key += sizeof(uint32_t);
34 h ^= murmur_32_scramble(k);
35 h = (h << 13) | (h >> 19);
36 h = h * 5 + 0xe6546b64;
37 }
38 /* Read the rest. */
39 k = 0;
40 for (size_t i = len & 3; i; i--) {
41 k <<= 8;
42 k |= key[i - 1];
43 }
44 // A swap is *not* necessary here because the preceding loop already
45 // places the low bytes in the low places according to whatever endianness
46 // we use. Swaps only apply when the memory is copied in a chunk.
47 h ^= murmur_32_scramble(k);
48 /* Finalize. */
49 h ^= len;
50 h ^= h >> 16;
51 h *= 0x85ebca6b;
52 h ^= h >> 13;
53 h *= 0xc2b2ae35;
54 h ^= h >> 16;
55 return h;
56}
57
58static inline [unsigned size, char unit] human_size( size_t size ) {
59 int idx = 0;
60 static char units [] = { ' ', 'K', 'M', 'G', 'T' };
61 while( size >= 1024 ) {
62 idx++;
63 size /= 1024;
64 if(idx >= 5) {
65 abort("File too large to print\n");
66 }
67 }
68
69 return [size, units[idx]];
70}
71
72struct {
73 cache_line * entries;
74 size_t size;
75} file_cache;
76
77void ?{}( cache_line & this ) with( this ) {
78 file = 0p;
79 size = 0;
80 fd = 0;
81}
82
83[int fd, size_t size] get_file( * const char file, size_t len ) {
84 uint32_t idx = murmur3_32( (const uint8_t *)file, len, options.file_cache.hash_seed ) % file_cache.size;
85
86 for(int i = 0;; i++) {
87 assert( i < file_cache.size );
88 cache_line & entry = file_cache.entries[idx];
89 if( !entry.file ) return [-1, 0];
90 #if !defined(REJECT_CONFLICTS)
91 if( strncmp(entry.file, file, len) != 0 ) {
92 idx = (idx + 1) % file_cache.size;
93 continue;
94 }
95 #endif
96 return [entry.fd, entry.size];
97 }
98}
99
100int put_file( cache_line & entry ) {
101 uint32_t idx = murmur3_32( (const uint8_t *)entry.file, strlen(entry.file), options.file_cache.hash_seed ) % file_cache.size;
102
103 int i = 0;
104 for(;file_cache.entries[idx].file; i++ ) {
105 assert( i < file_cache.size );
106 idx = (idx + 1) % file_cache.size;
107 }
108
109 file_cache.entries[idx] = entry;
110 return i > 0 ? 1 : 0;
111}
112
113// int ftw(const char *dirpath, int (*fn) (const char *fpath, const struct stat *sb, int typeflag), int nopenfd)
114void fill_cache( const char * path ) {
115 int ret;
116 ret = chdir(path);
117 if(ret < 0) {
118 abort( "chdir error: (%d) %s\n", (int)errno, strerror(errno) );
119 }
120
121 size_t fcount = 0;
122 size_t fsize = 16;
123 cache_line * raw = 0p;
124 raw = alloc(raw, fsize, true);
125 // Step 1 get a dense array of all files
126 int walk(const char *fpath, const struct stat *sb, int typeflag) {
127 if(typeflag != FTW_F) return 0;
128
129 int idx = fcount;
130 fcount++;
131 if(fcount > fsize) {
132 fsize *= 2;
133 raw = alloc(raw, fsize, true);
134 }
135
136 raw[idx].file = strdup(fpath+2);
137 raw[idx].size = sb->st_size;
138 if( !options.file_cache.list ) {
139 raw[idx].fd = open( fpath, options.file_cache.open_flags );
140 if(raw[idx].fd < 0) {
141 abort( "open file error: (%d) %s\n", (int)errno, strerror(errno) );
142 }
143 }
144 return 0;
145 }
146
147 ret = ftw(".", walk, 10);
148 if(ret < 0) {
149 abort( "ftw error: (%d) %s\n", (int)errno, strerror(errno) );
150 }
151
152 if(fcount == 0) {
153 abort("No file found in path %s\n", path);
154 }
155
156 // Step 2 create the cache
157 file_cache.size = options.file_cache.size > 0 ? options.file_cache.size : fsize;
158 if( file_cache.size < fcount ) {
159 abort("File Cache too small\n");
160 }
161
162 file_cache.entries = anew(file_cache.size);
163
164 // Step 3 fill the cache
165 int conflicts = 0;
166 for(i; fcount) {
167 conflicts += put_file( raw[i] );
168 }
169 printf("Filled cache from path \"%s\" with %zu files\n", path, fcount);
170 if( conflicts > 0 ) {
171 printf("Found %d conflicts (seed: %u)\n", conflicts, options.file_cache.hash_seed);
172 #if defined(REJECT_CONFLICTS)
173 abort("Conflicts found in the cache");
174 #endif
175 }
176
177 if(options.file_cache.list) {
178 printf("Listing files and exiting\n");
179 for(i; fcount) {
180 int s; char u;
181 [s, u] = human_size(raw[i].size);
182 printf("%4d%c - %s\n", s, u, raw[i].file);
183 free(raw[i].file);
184 }
185 free(raw);
186 adelete(file_cache.size, file_cache.entries);
187 exit(0);
188 }
189
190 // Step 4 clean up
191 free( raw );
192}
193
194[int *, int] filefds(int extra) {
195 if(!file_cache.entries) {
196 abort("File cache not filled!\n");
197 }
198
199 return [aalloc(extra), 0];
200}
201
202
203void close_cache() {
204 for(idx; file_cache.size) {
205 cache_line & entry = file_cache.entries[idx];
206 if( !entry.file ) continue;
207
208 int ret = close( entry.fd );
209 if(ret < 0) {
210 abort( "close file error: (%d) %s\n", (int)errno, strerror(errno) );
211 }
212 }
213
214 delete( file_cache.entries );
215}
Note: See TracBrowser for help on using the repository browser.