source: benchmark/io/http/filecache.cfa@ 5db836e

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

First attempt at webserver, no option support yet

  • Property mode set to 100644
File size: 4.0 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
58
59struct {
60 cache_line * entries;
61 size_t size;
62} file_cache;
63
64void ?{}( cache_line & this ) with( this ) {
65 file = 0p;
66 size = 0;
67 fd = 0;
68}
69
70[int fd, size_t size] get_file( * const char file, size_t len ) {
71 uint32_t idx = murmur3_32( (const uint8_t *)file, len, options.hash_seed ) % file_cache.size;
72
73 for(int i = 0;; i++) {
74 assert( i < file_cache.size );
75 cache_line & entry = file_cache.entries[idx];
76 if( !entry.file ) return [-1, 0];
77 #if !defined(REJECT_CONFLICTS)
78 if( strncmp(entry.file, file, len) != 0 ) {
79 idx = (idx + 1) % file_cache.size;
80 continue;
81 }
82 #endif
83 return [entry.fd, entry.size];
84 }
85}
86
87int put_file( cache_line & entry ) {
88 uint32_t idx = murmur3_32( (const uint8_t *)entry.file, strlen(entry.file), options.hash_seed ) % file_cache.size;
89
90 int i = 0;
91 for(;file_cache.entries[idx].file; i++ ) {
92 assert( i < file_cache.size );
93 idx = (idx + 1) % file_cache.size;
94 }
95
96 file_cache.entries[idx] = entry;
97 return i > 0 ? 1 : 0;
98}
99
100// int ftw(const char *dirpath, int (*fn) (const char *fpath, const struct stat *sb, int typeflag), int nopenfd)
101void fill_cache( const char * path ) {
102 int ret;
103 size_t fcount = 0;
104 size_t fsize = 16;
105 cache_line * raw = 0p;
106 raw = alloc(raw, fsize, true);
107 // Step 1 get a dense array of all files
108 int walk(const char *fpath, const struct stat *sb, int typeflag) {
109 if(typeflag != FTW_F) return 0;
110
111 int idx = fcount;
112 fcount++;
113 if(fcount > fsize) {
114 fsize *= 2;
115 raw = alloc(raw, fsize, true);
116 }
117
118 raw[idx].file = strdup(fpath+2);
119 raw[idx].size = sb->st_size;
120 raw[idx].fd = open( fpath, options.open_flags );
121 if(raw[idx].fd < 0) {
122 abort( "open file error: (%d) %s\n", (int)errno, strerror(errno) );
123 }
124 return 0;
125 }
126
127 ret = ftw(path, walk, 10);
128 if(ret < 0) {
129 abort( "ftw error: (%d) %s\n", (int)errno, strerror(errno) );
130 }
131
132 if(fcount == 0) {
133 abort("No file found in path %s\n", path);
134 }
135
136 // Step 2 create the cache
137 file_cache.size = options.file_cache_size > 0 ? options.file_cache_size : fsize;
138 if( file_cache.size < fcount ) {
139 abort("File Cache too small\n");
140 }
141
142 file_cache.entries = anew(fsize);
143
144 // Step 3 fill the cache
145 int conflicts = 0;
146 for(i; fcount) {
147 printf("Added file %s\n", raw[i].file);
148 conflicts += put_file( raw[i] );
149 }
150 printf("Filled cache from path \"%s\" with %zu files\n", path, fcount);
151 if( conflicts > 0 ) {
152 printf("Found %d conflicts (seed: %u)\n", conflicts, options.hash_seed);
153 #if defined(REJECT_CONFLICTS)
154 abort("Conflicts found in the cache");
155 #endif
156 }
157
158 // Step 4 clean up
159 free( raw );
160}
161
162void close_cache() {
163 for(idx; file_cache.size) {
164 cache_line & entry = file_cache.entries[idx];
165 if( !entry.file ) continue;
166
167 int ret = close( entry.fd );
168 if(ret < 0) {
169 abort( "close file error: (%d) %s\n", (int)errno, strerror(errno) );
170 }
171 }
172
173 delete( file_cache.entries );
174}
Note: See TracBrowser for help on using the repository browser.