1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright © 2020 Valve Corporation
3*61046927SAndroid Build Coastguard Worker *
4*61046927SAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining a
5*61046927SAndroid Build Coastguard Worker * copy of this software and associated documentation files (the "Software"),
6*61046927SAndroid Build Coastguard Worker * to deal in the Software without restriction, including without limitation
7*61046927SAndroid Build Coastguard Worker * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*61046927SAndroid Build Coastguard Worker * and/or sell copies of the Software, and to permit persons to whom the
9*61046927SAndroid Build Coastguard Worker * Software is furnished to do so, subject to the following conditions:
10*61046927SAndroid Build Coastguard Worker *
11*61046927SAndroid Build Coastguard Worker * The above copyright notice and this permission notice (including the next
12*61046927SAndroid Build Coastguard Worker * paragraph) shall be included in all copies or substantial portions of the
13*61046927SAndroid Build Coastguard Worker * Software.
14*61046927SAndroid Build Coastguard Worker *
15*61046927SAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*61046927SAndroid Build Coastguard Worker * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*61046927SAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18*61046927SAndroid Build Coastguard Worker * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*61046927SAndroid Build Coastguard Worker * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*61046927SAndroid Build Coastguard Worker * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21*61046927SAndroid Build Coastguard Worker * IN THE SOFTWARE.
22*61046927SAndroid Build Coastguard Worker */
23*61046927SAndroid Build Coastguard Worker
24*61046927SAndroid Build Coastguard Worker /* This is a basic c implementation of a fossilize db like format intended for
25*61046927SAndroid Build Coastguard Worker * use with the Mesa shader cache.
26*61046927SAndroid Build Coastguard Worker *
27*61046927SAndroid Build Coastguard Worker * The format is compatible enough to allow the fossilize db tools to be used
28*61046927SAndroid Build Coastguard Worker * to do things like merge db collections.
29*61046927SAndroid Build Coastguard Worker */
30*61046927SAndroid Build Coastguard Worker
31*61046927SAndroid Build Coastguard Worker #include "fossilize_db.h"
32*61046927SAndroid Build Coastguard Worker
33*61046927SAndroid Build Coastguard Worker #ifdef FOZ_DB_UTIL
34*61046927SAndroid Build Coastguard Worker
35*61046927SAndroid Build Coastguard Worker #include <assert.h>
36*61046927SAndroid Build Coastguard Worker #include <stddef.h>
37*61046927SAndroid Build Coastguard Worker #include <stdlib.h>
38*61046927SAndroid Build Coastguard Worker #include <string.h>
39*61046927SAndroid Build Coastguard Worker #include <sys/file.h>
40*61046927SAndroid Build Coastguard Worker #include <sys/stat.h>
41*61046927SAndroid Build Coastguard Worker #include <sys/types.h>
42*61046927SAndroid Build Coastguard Worker #include <unistd.h>
43*61046927SAndroid Build Coastguard Worker
44*61046927SAndroid Build Coastguard Worker #ifdef FOZ_DB_UTIL_DYNAMIC_LIST
45*61046927SAndroid Build Coastguard Worker #include <sys/inotify.h>
46*61046927SAndroid Build Coastguard Worker #endif
47*61046927SAndroid Build Coastguard Worker
48*61046927SAndroid Build Coastguard Worker #include "util/u_debug.h"
49*61046927SAndroid Build Coastguard Worker
50*61046927SAndroid Build Coastguard Worker #include "crc32.h"
51*61046927SAndroid Build Coastguard Worker #include "hash_table.h"
52*61046927SAndroid Build Coastguard Worker #include "mesa-sha1.h"
53*61046927SAndroid Build Coastguard Worker #include "ralloc.h"
54*61046927SAndroid Build Coastguard Worker
55*61046927SAndroid Build Coastguard Worker #define FOZ_REF_MAGIC_SIZE 16
56*61046927SAndroid Build Coastguard Worker
57*61046927SAndroid Build Coastguard Worker static const uint8_t stream_reference_magic_and_version[FOZ_REF_MAGIC_SIZE] = {
58*61046927SAndroid Build Coastguard Worker 0x81, 'F', 'O', 'S',
59*61046927SAndroid Build Coastguard Worker 'S', 'I', 'L', 'I',
60*61046927SAndroid Build Coastguard Worker 'Z', 'E', 'D', 'B',
61*61046927SAndroid Build Coastguard Worker 0, 0, 0, FOSSILIZE_FORMAT_VERSION, /* 4 bytes to use for versioning. */
62*61046927SAndroid Build Coastguard Worker };
63*61046927SAndroid Build Coastguard Worker
64*61046927SAndroid Build Coastguard Worker /* Mesa uses 160bit hashes to identify cache entries, a hash of this size
65*61046927SAndroid Build Coastguard Worker * makes collisions virtually impossible for our use case. However the foz db
66*61046927SAndroid Build Coastguard Worker * format uses a 64bit hash table to lookup file offsets for reading cache
67*61046927SAndroid Build Coastguard Worker * entries so we must shorten our hash.
68*61046927SAndroid Build Coastguard Worker */
69*61046927SAndroid Build Coastguard Worker static uint64_t
truncate_hash_to_64bits(const uint8_t * cache_key)70*61046927SAndroid Build Coastguard Worker truncate_hash_to_64bits(const uint8_t *cache_key)
71*61046927SAndroid Build Coastguard Worker {
72*61046927SAndroid Build Coastguard Worker uint64_t hash = 0;
73*61046927SAndroid Build Coastguard Worker unsigned shift = 7;
74*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < 8; i++) {
75*61046927SAndroid Build Coastguard Worker hash |= ((uint64_t)cache_key[i]) << shift * 8;
76*61046927SAndroid Build Coastguard Worker shift--;
77*61046927SAndroid Build Coastguard Worker }
78*61046927SAndroid Build Coastguard Worker return hash;
79*61046927SAndroid Build Coastguard Worker }
80*61046927SAndroid Build Coastguard Worker
81*61046927SAndroid Build Coastguard Worker static bool
check_files_opened_successfully(FILE * file,FILE * db_idx)82*61046927SAndroid Build Coastguard Worker check_files_opened_successfully(FILE *file, FILE *db_idx)
83*61046927SAndroid Build Coastguard Worker {
84*61046927SAndroid Build Coastguard Worker if (!file) {
85*61046927SAndroid Build Coastguard Worker if (db_idx)
86*61046927SAndroid Build Coastguard Worker fclose(db_idx);
87*61046927SAndroid Build Coastguard Worker return false;
88*61046927SAndroid Build Coastguard Worker }
89*61046927SAndroid Build Coastguard Worker
90*61046927SAndroid Build Coastguard Worker if (!db_idx) {
91*61046927SAndroid Build Coastguard Worker if (file)
92*61046927SAndroid Build Coastguard Worker fclose(file);
93*61046927SAndroid Build Coastguard Worker return false;
94*61046927SAndroid Build Coastguard Worker }
95*61046927SAndroid Build Coastguard Worker
96*61046927SAndroid Build Coastguard Worker return true;
97*61046927SAndroid Build Coastguard Worker }
98*61046927SAndroid Build Coastguard Worker
99*61046927SAndroid Build Coastguard Worker static bool
create_foz_db_filenames(const char * cache_path,const char * name,char ** filename,char ** idx_filename)100*61046927SAndroid Build Coastguard Worker create_foz_db_filenames(const char *cache_path,
101*61046927SAndroid Build Coastguard Worker const char *name,
102*61046927SAndroid Build Coastguard Worker char **filename,
103*61046927SAndroid Build Coastguard Worker char **idx_filename)
104*61046927SAndroid Build Coastguard Worker {
105*61046927SAndroid Build Coastguard Worker if (asprintf(filename, "%s/%s.foz", cache_path, name) == -1)
106*61046927SAndroid Build Coastguard Worker return false;
107*61046927SAndroid Build Coastguard Worker
108*61046927SAndroid Build Coastguard Worker if (asprintf(idx_filename, "%s/%s_idx.foz", cache_path, name) == -1) {
109*61046927SAndroid Build Coastguard Worker free(*filename);
110*61046927SAndroid Build Coastguard Worker return false;
111*61046927SAndroid Build Coastguard Worker }
112*61046927SAndroid Build Coastguard Worker
113*61046927SAndroid Build Coastguard Worker return true;
114*61046927SAndroid Build Coastguard Worker }
115*61046927SAndroid Build Coastguard Worker
116*61046927SAndroid Build Coastguard Worker
117*61046927SAndroid Build Coastguard Worker /* This looks at stuff that was added to the index since the last time we looked at it. This is safe
118*61046927SAndroid Build Coastguard Worker * to do without locking the file as we assume the file is append only */
119*61046927SAndroid Build Coastguard Worker static void
update_foz_index(struct foz_db * foz_db,FILE * db_idx,unsigned file_idx)120*61046927SAndroid Build Coastguard Worker update_foz_index(struct foz_db *foz_db, FILE *db_idx, unsigned file_idx)
121*61046927SAndroid Build Coastguard Worker {
122*61046927SAndroid Build Coastguard Worker uint64_t offset = ftell(db_idx);
123*61046927SAndroid Build Coastguard Worker fseek(db_idx, 0, SEEK_END);
124*61046927SAndroid Build Coastguard Worker uint64_t len = ftell(db_idx);
125*61046927SAndroid Build Coastguard Worker uint64_t parsed_offset = offset;
126*61046927SAndroid Build Coastguard Worker
127*61046927SAndroid Build Coastguard Worker if (offset == len)
128*61046927SAndroid Build Coastguard Worker return;
129*61046927SAndroid Build Coastguard Worker
130*61046927SAndroid Build Coastguard Worker fseek(db_idx, offset, SEEK_SET);
131*61046927SAndroid Build Coastguard Worker while (offset < len) {
132*61046927SAndroid Build Coastguard Worker char bytes_to_read[FOSSILIZE_BLOB_HASH_LENGTH + sizeof(struct foz_payload_header)];
133*61046927SAndroid Build Coastguard Worker struct foz_payload_header *header;
134*61046927SAndroid Build Coastguard Worker
135*61046927SAndroid Build Coastguard Worker /* Corrupt entry. Our process might have been killed before we
136*61046927SAndroid Build Coastguard Worker * could write all data.
137*61046927SAndroid Build Coastguard Worker */
138*61046927SAndroid Build Coastguard Worker if (offset + sizeof(bytes_to_read) > len)
139*61046927SAndroid Build Coastguard Worker break;
140*61046927SAndroid Build Coastguard Worker
141*61046927SAndroid Build Coastguard Worker /* NAME + HEADER in one read */
142*61046927SAndroid Build Coastguard Worker if (fread(bytes_to_read, 1, sizeof(bytes_to_read), db_idx) !=
143*61046927SAndroid Build Coastguard Worker sizeof(bytes_to_read))
144*61046927SAndroid Build Coastguard Worker break;
145*61046927SAndroid Build Coastguard Worker
146*61046927SAndroid Build Coastguard Worker offset += sizeof(bytes_to_read);
147*61046927SAndroid Build Coastguard Worker header = (struct foz_payload_header*)&bytes_to_read[FOSSILIZE_BLOB_HASH_LENGTH];
148*61046927SAndroid Build Coastguard Worker
149*61046927SAndroid Build Coastguard Worker /* Corrupt entry. Our process might have been killed before we
150*61046927SAndroid Build Coastguard Worker * could write all data.
151*61046927SAndroid Build Coastguard Worker */
152*61046927SAndroid Build Coastguard Worker if (offset + header->payload_size > len ||
153*61046927SAndroid Build Coastguard Worker header->payload_size != sizeof(uint64_t))
154*61046927SAndroid Build Coastguard Worker break;
155*61046927SAndroid Build Coastguard Worker
156*61046927SAndroid Build Coastguard Worker char hash_str[FOSSILIZE_BLOB_HASH_LENGTH + 1] = {0};
157*61046927SAndroid Build Coastguard Worker memcpy(hash_str, bytes_to_read, FOSSILIZE_BLOB_HASH_LENGTH);
158*61046927SAndroid Build Coastguard Worker
159*61046927SAndroid Build Coastguard Worker /* read cache item offset from index file */
160*61046927SAndroid Build Coastguard Worker uint64_t cache_offset;
161*61046927SAndroid Build Coastguard Worker if (fread(&cache_offset, 1, sizeof(cache_offset), db_idx) !=
162*61046927SAndroid Build Coastguard Worker sizeof(cache_offset))
163*61046927SAndroid Build Coastguard Worker break;
164*61046927SAndroid Build Coastguard Worker
165*61046927SAndroid Build Coastguard Worker offset += header->payload_size;
166*61046927SAndroid Build Coastguard Worker parsed_offset = offset;
167*61046927SAndroid Build Coastguard Worker
168*61046927SAndroid Build Coastguard Worker struct foz_db_entry *entry = ralloc(foz_db->mem_ctx,
169*61046927SAndroid Build Coastguard Worker struct foz_db_entry);
170*61046927SAndroid Build Coastguard Worker entry->header = *header;
171*61046927SAndroid Build Coastguard Worker entry->file_idx = file_idx;
172*61046927SAndroid Build Coastguard Worker _mesa_sha1_hex_to_sha1(entry->key, hash_str);
173*61046927SAndroid Build Coastguard Worker
174*61046927SAndroid Build Coastguard Worker /* Truncate the entry's hash string to a 64bit hash for use with a
175*61046927SAndroid Build Coastguard Worker * 64bit hash table for looking up file offsets.
176*61046927SAndroid Build Coastguard Worker */
177*61046927SAndroid Build Coastguard Worker hash_str[16] = '\0';
178*61046927SAndroid Build Coastguard Worker uint64_t key = strtoull(hash_str, NULL, 16);
179*61046927SAndroid Build Coastguard Worker
180*61046927SAndroid Build Coastguard Worker entry->offset = cache_offset;
181*61046927SAndroid Build Coastguard Worker
182*61046927SAndroid Build Coastguard Worker _mesa_hash_table_u64_insert(foz_db->index_db, key, entry);
183*61046927SAndroid Build Coastguard Worker }
184*61046927SAndroid Build Coastguard Worker
185*61046927SAndroid Build Coastguard Worker
186*61046927SAndroid Build Coastguard Worker fseek(db_idx, parsed_offset, SEEK_SET);
187*61046927SAndroid Build Coastguard Worker }
188*61046927SAndroid Build Coastguard Worker
189*61046927SAndroid Build Coastguard Worker /* exclusive flock with timeout. timeout is in nanoseconds */
lock_file_with_timeout(FILE * f,int64_t timeout)190*61046927SAndroid Build Coastguard Worker static int lock_file_with_timeout(FILE *f, int64_t timeout)
191*61046927SAndroid Build Coastguard Worker {
192*61046927SAndroid Build Coastguard Worker int err;
193*61046927SAndroid Build Coastguard Worker int fd = fileno(f);
194*61046927SAndroid Build Coastguard Worker int64_t iterations = MAX2(DIV_ROUND_UP(timeout, 1000000), 1);
195*61046927SAndroid Build Coastguard Worker
196*61046927SAndroid Build Coastguard Worker /* Since there is no blocking flock with timeout and we don't want to totally spin on getting the
197*61046927SAndroid Build Coastguard Worker * lock, use a nonblocking method and retry every millisecond. */
198*61046927SAndroid Build Coastguard Worker for (int64_t iter = 0; iter < iterations; ++iter) {
199*61046927SAndroid Build Coastguard Worker err = flock(fd, LOCK_EX | LOCK_NB);
200*61046927SAndroid Build Coastguard Worker if (err == 0 || errno != EAGAIN)
201*61046927SAndroid Build Coastguard Worker break;
202*61046927SAndroid Build Coastguard Worker usleep(1000);
203*61046927SAndroid Build Coastguard Worker }
204*61046927SAndroid Build Coastguard Worker return err;
205*61046927SAndroid Build Coastguard Worker }
206*61046927SAndroid Build Coastguard Worker
207*61046927SAndroid Build Coastguard Worker static bool
load_foz_dbs(struct foz_db * foz_db,FILE * db_idx,uint8_t file_idx,bool read_only)208*61046927SAndroid Build Coastguard Worker load_foz_dbs(struct foz_db *foz_db, FILE *db_idx, uint8_t file_idx,
209*61046927SAndroid Build Coastguard Worker bool read_only)
210*61046927SAndroid Build Coastguard Worker {
211*61046927SAndroid Build Coastguard Worker /* Scan through the archive and get the list of cache entries. */
212*61046927SAndroid Build Coastguard Worker fseek(db_idx, 0, SEEK_END);
213*61046927SAndroid Build Coastguard Worker size_t len = ftell(db_idx);
214*61046927SAndroid Build Coastguard Worker rewind(db_idx);
215*61046927SAndroid Build Coastguard Worker
216*61046927SAndroid Build Coastguard Worker /* Try not to take the lock if len >= the size of the header, but if it is smaller we take the
217*61046927SAndroid Build Coastguard Worker * lock to potentially initialize the files. */
218*61046927SAndroid Build Coastguard Worker if (len < sizeof(stream_reference_magic_and_version)) {
219*61046927SAndroid Build Coastguard Worker /* Wait for 100 ms in case of contention, after that we prioritize getting the app started. */
220*61046927SAndroid Build Coastguard Worker int err = lock_file_with_timeout(foz_db->file[file_idx], 100000000);
221*61046927SAndroid Build Coastguard Worker if (err == -1)
222*61046927SAndroid Build Coastguard Worker goto fail;
223*61046927SAndroid Build Coastguard Worker
224*61046927SAndroid Build Coastguard Worker /* Compute length again so we know nobody else did it in the meantime */
225*61046927SAndroid Build Coastguard Worker fseek(db_idx, 0, SEEK_END);
226*61046927SAndroid Build Coastguard Worker len = ftell(db_idx);
227*61046927SAndroid Build Coastguard Worker rewind(db_idx);
228*61046927SAndroid Build Coastguard Worker }
229*61046927SAndroid Build Coastguard Worker
230*61046927SAndroid Build Coastguard Worker if (len != 0) {
231*61046927SAndroid Build Coastguard Worker uint8_t magic[FOZ_REF_MAGIC_SIZE];
232*61046927SAndroid Build Coastguard Worker if (fread(magic, 1, FOZ_REF_MAGIC_SIZE, db_idx) != FOZ_REF_MAGIC_SIZE)
233*61046927SAndroid Build Coastguard Worker goto fail;
234*61046927SAndroid Build Coastguard Worker
235*61046927SAndroid Build Coastguard Worker if (memcmp(magic, stream_reference_magic_and_version,
236*61046927SAndroid Build Coastguard Worker FOZ_REF_MAGIC_SIZE - 1))
237*61046927SAndroid Build Coastguard Worker goto fail;
238*61046927SAndroid Build Coastguard Worker
239*61046927SAndroid Build Coastguard Worker int version = magic[FOZ_REF_MAGIC_SIZE - 1];
240*61046927SAndroid Build Coastguard Worker if (version > FOSSILIZE_FORMAT_VERSION ||
241*61046927SAndroid Build Coastguard Worker version < FOSSILIZE_FORMAT_MIN_COMPAT_VERSION)
242*61046927SAndroid Build Coastguard Worker goto fail;
243*61046927SAndroid Build Coastguard Worker
244*61046927SAndroid Build Coastguard Worker } else {
245*61046927SAndroid Build Coastguard Worker /* Appending to a fresh file. Make sure we have the magic. */
246*61046927SAndroid Build Coastguard Worker if (fwrite(stream_reference_magic_and_version, 1,
247*61046927SAndroid Build Coastguard Worker sizeof(stream_reference_magic_and_version), foz_db->file[file_idx]) !=
248*61046927SAndroid Build Coastguard Worker sizeof(stream_reference_magic_and_version))
249*61046927SAndroid Build Coastguard Worker goto fail;
250*61046927SAndroid Build Coastguard Worker
251*61046927SAndroid Build Coastguard Worker if (fwrite(stream_reference_magic_and_version, 1,
252*61046927SAndroid Build Coastguard Worker sizeof(stream_reference_magic_and_version), db_idx) !=
253*61046927SAndroid Build Coastguard Worker sizeof(stream_reference_magic_and_version))
254*61046927SAndroid Build Coastguard Worker goto fail;
255*61046927SAndroid Build Coastguard Worker
256*61046927SAndroid Build Coastguard Worker fflush(foz_db->file[file_idx]);
257*61046927SAndroid Build Coastguard Worker fflush(db_idx);
258*61046927SAndroid Build Coastguard Worker }
259*61046927SAndroid Build Coastguard Worker
260*61046927SAndroid Build Coastguard Worker flock(fileno(foz_db->file[file_idx]), LOCK_UN);
261*61046927SAndroid Build Coastguard Worker
262*61046927SAndroid Build Coastguard Worker if (foz_db->updater.thrd) {
263*61046927SAndroid Build Coastguard Worker /* If MESA_DISK_CACHE_READ_ONLY_FOZ_DBS_DYNAMIC_LIST is enabled, access to
264*61046927SAndroid Build Coastguard Worker * the foz_db hash table requires locking to prevent racing between this
265*61046927SAndroid Build Coastguard Worker * updated thread loading DBs at runtime and cache entry read/writes. */
266*61046927SAndroid Build Coastguard Worker simple_mtx_lock(&foz_db->mtx);
267*61046927SAndroid Build Coastguard Worker update_foz_index(foz_db, db_idx, file_idx);
268*61046927SAndroid Build Coastguard Worker simple_mtx_unlock(&foz_db->mtx);
269*61046927SAndroid Build Coastguard Worker } else {
270*61046927SAndroid Build Coastguard Worker update_foz_index(foz_db, db_idx, file_idx);
271*61046927SAndroid Build Coastguard Worker }
272*61046927SAndroid Build Coastguard Worker
273*61046927SAndroid Build Coastguard Worker foz_db->alive = true;
274*61046927SAndroid Build Coastguard Worker return true;
275*61046927SAndroid Build Coastguard Worker
276*61046927SAndroid Build Coastguard Worker fail:
277*61046927SAndroid Build Coastguard Worker flock(fileno(foz_db->file[file_idx]), LOCK_UN);
278*61046927SAndroid Build Coastguard Worker return false;
279*61046927SAndroid Build Coastguard Worker }
280*61046927SAndroid Build Coastguard Worker
281*61046927SAndroid Build Coastguard Worker static void
load_foz_dbs_ro(struct foz_db * foz_db,char * foz_dbs_ro)282*61046927SAndroid Build Coastguard Worker load_foz_dbs_ro(struct foz_db *foz_db, char *foz_dbs_ro)
283*61046927SAndroid Build Coastguard Worker {
284*61046927SAndroid Build Coastguard Worker uint8_t file_idx = 1;
285*61046927SAndroid Build Coastguard Worker char *filename = NULL;
286*61046927SAndroid Build Coastguard Worker char *idx_filename = NULL;
287*61046927SAndroid Build Coastguard Worker
288*61046927SAndroid Build Coastguard Worker for (unsigned n; n = strcspn(foz_dbs_ro, ","), *foz_dbs_ro;
289*61046927SAndroid Build Coastguard Worker foz_dbs_ro += MAX2(1, n)) {
290*61046927SAndroid Build Coastguard Worker char *foz_db_filename = strndup(foz_dbs_ro, n);
291*61046927SAndroid Build Coastguard Worker
292*61046927SAndroid Build Coastguard Worker filename = NULL;
293*61046927SAndroid Build Coastguard Worker idx_filename = NULL;
294*61046927SAndroid Build Coastguard Worker if (!create_foz_db_filenames(foz_db->cache_path, foz_db_filename,
295*61046927SAndroid Build Coastguard Worker &filename, &idx_filename)) {
296*61046927SAndroid Build Coastguard Worker free(foz_db_filename);
297*61046927SAndroid Build Coastguard Worker continue; /* Ignore invalid user provided filename and continue */
298*61046927SAndroid Build Coastguard Worker }
299*61046927SAndroid Build Coastguard Worker free(foz_db_filename);
300*61046927SAndroid Build Coastguard Worker
301*61046927SAndroid Build Coastguard Worker /* Open files as read only */
302*61046927SAndroid Build Coastguard Worker foz_db->file[file_idx] = fopen(filename, "rb");
303*61046927SAndroid Build Coastguard Worker FILE *db_idx = fopen(idx_filename, "rb");
304*61046927SAndroid Build Coastguard Worker
305*61046927SAndroid Build Coastguard Worker free(filename);
306*61046927SAndroid Build Coastguard Worker free(idx_filename);
307*61046927SAndroid Build Coastguard Worker
308*61046927SAndroid Build Coastguard Worker if (!check_files_opened_successfully(foz_db->file[file_idx], db_idx)) {
309*61046927SAndroid Build Coastguard Worker /* Prevent foz_destroy from destroying it a second time. */
310*61046927SAndroid Build Coastguard Worker foz_db->file[file_idx] = NULL;
311*61046927SAndroid Build Coastguard Worker
312*61046927SAndroid Build Coastguard Worker continue; /* Ignore invalid user provided filename and continue */
313*61046927SAndroid Build Coastguard Worker }
314*61046927SAndroid Build Coastguard Worker
315*61046927SAndroid Build Coastguard Worker if (!load_foz_dbs(foz_db, db_idx, file_idx, true)) {
316*61046927SAndroid Build Coastguard Worker fclose(db_idx);
317*61046927SAndroid Build Coastguard Worker fclose(foz_db->file[file_idx]);
318*61046927SAndroid Build Coastguard Worker foz_db->file[file_idx] = NULL;
319*61046927SAndroid Build Coastguard Worker
320*61046927SAndroid Build Coastguard Worker continue; /* Ignore invalid user provided foz db */
321*61046927SAndroid Build Coastguard Worker }
322*61046927SAndroid Build Coastguard Worker
323*61046927SAndroid Build Coastguard Worker fclose(db_idx);
324*61046927SAndroid Build Coastguard Worker file_idx++;
325*61046927SAndroid Build Coastguard Worker
326*61046927SAndroid Build Coastguard Worker if (file_idx >= FOZ_MAX_DBS)
327*61046927SAndroid Build Coastguard Worker break;
328*61046927SAndroid Build Coastguard Worker }
329*61046927SAndroid Build Coastguard Worker }
330*61046927SAndroid Build Coastguard Worker
331*61046927SAndroid Build Coastguard Worker #ifdef FOZ_DB_UTIL_DYNAMIC_LIST
332*61046927SAndroid Build Coastguard Worker static bool
check_file_already_loaded(struct foz_db * foz_db,FILE * db_file,uint8_t max_file_idx)333*61046927SAndroid Build Coastguard Worker check_file_already_loaded(struct foz_db *foz_db,
334*61046927SAndroid Build Coastguard Worker FILE *db_file,
335*61046927SAndroid Build Coastguard Worker uint8_t max_file_idx)
336*61046927SAndroid Build Coastguard Worker {
337*61046927SAndroid Build Coastguard Worker struct stat new_file_stat;
338*61046927SAndroid Build Coastguard Worker
339*61046927SAndroid Build Coastguard Worker if (fstat(fileno(db_file), &new_file_stat) == -1)
340*61046927SAndroid Build Coastguard Worker return false;
341*61046927SAndroid Build Coastguard Worker
342*61046927SAndroid Build Coastguard Worker for (int i = 0; i < max_file_idx; i++) {
343*61046927SAndroid Build Coastguard Worker struct stat loaded_file_stat;
344*61046927SAndroid Build Coastguard Worker
345*61046927SAndroid Build Coastguard Worker if (fstat(fileno(foz_db->file[i]), &loaded_file_stat) == -1)
346*61046927SAndroid Build Coastguard Worker continue;
347*61046927SAndroid Build Coastguard Worker
348*61046927SAndroid Build Coastguard Worker if ((loaded_file_stat.st_dev == new_file_stat.st_dev) &&
349*61046927SAndroid Build Coastguard Worker (loaded_file_stat.st_ino == new_file_stat.st_ino))
350*61046927SAndroid Build Coastguard Worker return true;
351*61046927SAndroid Build Coastguard Worker }
352*61046927SAndroid Build Coastguard Worker
353*61046927SAndroid Build Coastguard Worker return false;
354*61046927SAndroid Build Coastguard Worker }
355*61046927SAndroid Build Coastguard Worker
356*61046927SAndroid Build Coastguard Worker static bool
load_from_list_file(struct foz_db * foz_db,const char * foz_dbs_list_filename)357*61046927SAndroid Build Coastguard Worker load_from_list_file(struct foz_db *foz_db, const char *foz_dbs_list_filename)
358*61046927SAndroid Build Coastguard Worker {
359*61046927SAndroid Build Coastguard Worker uint8_t file_idx;
360*61046927SAndroid Build Coastguard Worker char list_entry[PATH_MAX];
361*61046927SAndroid Build Coastguard Worker
362*61046927SAndroid Build Coastguard Worker /* Find the first empty file idx slot */
363*61046927SAndroid Build Coastguard Worker for (file_idx = 0; file_idx < FOZ_MAX_DBS; file_idx++) {
364*61046927SAndroid Build Coastguard Worker if (!foz_db->file[file_idx])
365*61046927SAndroid Build Coastguard Worker break;
366*61046927SAndroid Build Coastguard Worker }
367*61046927SAndroid Build Coastguard Worker
368*61046927SAndroid Build Coastguard Worker if (file_idx >= FOZ_MAX_DBS)
369*61046927SAndroid Build Coastguard Worker return false;
370*61046927SAndroid Build Coastguard Worker
371*61046927SAndroid Build Coastguard Worker FILE *foz_dbs_list_file = fopen(foz_dbs_list_filename, "rb");
372*61046927SAndroid Build Coastguard Worker if (!foz_dbs_list_file)
373*61046927SAndroid Build Coastguard Worker return false;
374*61046927SAndroid Build Coastguard Worker
375*61046927SAndroid Build Coastguard Worker while (fgets(list_entry, sizeof(list_entry), foz_dbs_list_file)) {
376*61046927SAndroid Build Coastguard Worker char *db_filename = NULL;
377*61046927SAndroid Build Coastguard Worker char *idx_filename = NULL;
378*61046927SAndroid Build Coastguard Worker FILE *db_file = NULL;
379*61046927SAndroid Build Coastguard Worker FILE *idx_file = NULL;
380*61046927SAndroid Build Coastguard Worker
381*61046927SAndroid Build Coastguard Worker list_entry[strcspn(list_entry, "\n")] = '\0';
382*61046927SAndroid Build Coastguard Worker
383*61046927SAndroid Build Coastguard Worker if (!create_foz_db_filenames(foz_db->cache_path, list_entry,
384*61046927SAndroid Build Coastguard Worker &db_filename, &idx_filename))
385*61046927SAndroid Build Coastguard Worker continue;
386*61046927SAndroid Build Coastguard Worker
387*61046927SAndroid Build Coastguard Worker db_file = fopen(db_filename, "rb");
388*61046927SAndroid Build Coastguard Worker idx_file = fopen(idx_filename, "rb");
389*61046927SAndroid Build Coastguard Worker
390*61046927SAndroid Build Coastguard Worker free(db_filename);
391*61046927SAndroid Build Coastguard Worker free(idx_filename);
392*61046927SAndroid Build Coastguard Worker
393*61046927SAndroid Build Coastguard Worker if (!check_files_opened_successfully(db_file, idx_file))
394*61046927SAndroid Build Coastguard Worker continue;
395*61046927SAndroid Build Coastguard Worker
396*61046927SAndroid Build Coastguard Worker if (check_file_already_loaded(foz_db, db_file, file_idx)) {
397*61046927SAndroid Build Coastguard Worker fclose(db_file);
398*61046927SAndroid Build Coastguard Worker fclose(idx_file);
399*61046927SAndroid Build Coastguard Worker
400*61046927SAndroid Build Coastguard Worker continue;
401*61046927SAndroid Build Coastguard Worker }
402*61046927SAndroid Build Coastguard Worker
403*61046927SAndroid Build Coastguard Worker /* Must be set before calling load_foz_dbs() */
404*61046927SAndroid Build Coastguard Worker foz_db->file[file_idx] = db_file;
405*61046927SAndroid Build Coastguard Worker
406*61046927SAndroid Build Coastguard Worker if (!load_foz_dbs(foz_db, idx_file, file_idx, true)) {
407*61046927SAndroid Build Coastguard Worker fclose(db_file);
408*61046927SAndroid Build Coastguard Worker fclose(idx_file);
409*61046927SAndroid Build Coastguard Worker foz_db->file[file_idx] = NULL;
410*61046927SAndroid Build Coastguard Worker
411*61046927SAndroid Build Coastguard Worker continue;
412*61046927SAndroid Build Coastguard Worker }
413*61046927SAndroid Build Coastguard Worker
414*61046927SAndroid Build Coastguard Worker fclose(idx_file);
415*61046927SAndroid Build Coastguard Worker file_idx++;
416*61046927SAndroid Build Coastguard Worker
417*61046927SAndroid Build Coastguard Worker if (file_idx >= FOZ_MAX_DBS)
418*61046927SAndroid Build Coastguard Worker break;
419*61046927SAndroid Build Coastguard Worker }
420*61046927SAndroid Build Coastguard Worker
421*61046927SAndroid Build Coastguard Worker fclose(foz_dbs_list_file);
422*61046927SAndroid Build Coastguard Worker return true;
423*61046927SAndroid Build Coastguard Worker }
424*61046927SAndroid Build Coastguard Worker
425*61046927SAndroid Build Coastguard Worker static int
foz_dbs_list_updater_thrd(void * data)426*61046927SAndroid Build Coastguard Worker foz_dbs_list_updater_thrd(void *data)
427*61046927SAndroid Build Coastguard Worker {
428*61046927SAndroid Build Coastguard Worker char buf[10 * (sizeof(struct inotify_event) + NAME_MAX + 1)];
429*61046927SAndroid Build Coastguard Worker struct foz_db *foz_db = data;
430*61046927SAndroid Build Coastguard Worker struct foz_dbs_list_updater *updater = &foz_db->updater;
431*61046927SAndroid Build Coastguard Worker
432*61046927SAndroid Build Coastguard Worker while (1) {
433*61046927SAndroid Build Coastguard Worker int len = read(updater->inotify_fd, buf, sizeof(buf));
434*61046927SAndroid Build Coastguard Worker
435*61046927SAndroid Build Coastguard Worker if (len == -1 && errno != EAGAIN)
436*61046927SAndroid Build Coastguard Worker return errno;
437*61046927SAndroid Build Coastguard Worker
438*61046927SAndroid Build Coastguard Worker int i = 0;
439*61046927SAndroid Build Coastguard Worker while (i < len) {
440*61046927SAndroid Build Coastguard Worker struct inotify_event *event = (struct inotify_event *)&buf[i];
441*61046927SAndroid Build Coastguard Worker
442*61046927SAndroid Build Coastguard Worker i += sizeof(struct inotify_event) + event->len;
443*61046927SAndroid Build Coastguard Worker
444*61046927SAndroid Build Coastguard Worker if (event->mask & IN_CLOSE_WRITE)
445*61046927SAndroid Build Coastguard Worker load_from_list_file(foz_db, foz_db->updater.list_filename);
446*61046927SAndroid Build Coastguard Worker
447*61046927SAndroid Build Coastguard Worker /* List file deleted or watch removed by foz destroy */
448*61046927SAndroid Build Coastguard Worker if ((event->mask & IN_DELETE_SELF) || (event->mask & IN_IGNORED))
449*61046927SAndroid Build Coastguard Worker return 0;
450*61046927SAndroid Build Coastguard Worker }
451*61046927SAndroid Build Coastguard Worker }
452*61046927SAndroid Build Coastguard Worker
453*61046927SAndroid Build Coastguard Worker return 0;
454*61046927SAndroid Build Coastguard Worker }
455*61046927SAndroid Build Coastguard Worker
456*61046927SAndroid Build Coastguard Worker static bool
foz_dbs_list_updater_init(struct foz_db * foz_db,char * list_filename)457*61046927SAndroid Build Coastguard Worker foz_dbs_list_updater_init(struct foz_db *foz_db, char *list_filename)
458*61046927SAndroid Build Coastguard Worker {
459*61046927SAndroid Build Coastguard Worker struct foz_dbs_list_updater *updater = &foz_db->updater;
460*61046927SAndroid Build Coastguard Worker
461*61046927SAndroid Build Coastguard Worker /* Initial load */
462*61046927SAndroid Build Coastguard Worker if (!load_from_list_file(foz_db, list_filename))
463*61046927SAndroid Build Coastguard Worker return false;
464*61046927SAndroid Build Coastguard Worker
465*61046927SAndroid Build Coastguard Worker updater->list_filename = list_filename;
466*61046927SAndroid Build Coastguard Worker
467*61046927SAndroid Build Coastguard Worker int fd = inotify_init1(IN_CLOEXEC);
468*61046927SAndroid Build Coastguard Worker if (fd < 0)
469*61046927SAndroid Build Coastguard Worker return false;
470*61046927SAndroid Build Coastguard Worker
471*61046927SAndroid Build Coastguard Worker int wd = inotify_add_watch(fd, foz_db->updater.list_filename,
472*61046927SAndroid Build Coastguard Worker IN_CLOSE_WRITE | IN_DELETE_SELF);
473*61046927SAndroid Build Coastguard Worker if (wd < 0) {
474*61046927SAndroid Build Coastguard Worker close(fd);
475*61046927SAndroid Build Coastguard Worker return false;
476*61046927SAndroid Build Coastguard Worker }
477*61046927SAndroid Build Coastguard Worker
478*61046927SAndroid Build Coastguard Worker updater->inotify_fd = fd;
479*61046927SAndroid Build Coastguard Worker updater->inotify_wd = wd;
480*61046927SAndroid Build Coastguard Worker
481*61046927SAndroid Build Coastguard Worker if (thrd_create(&updater->thrd, foz_dbs_list_updater_thrd, foz_db)) {
482*61046927SAndroid Build Coastguard Worker inotify_rm_watch(fd, wd);
483*61046927SAndroid Build Coastguard Worker close(fd);
484*61046927SAndroid Build Coastguard Worker
485*61046927SAndroid Build Coastguard Worker return false;
486*61046927SAndroid Build Coastguard Worker }
487*61046927SAndroid Build Coastguard Worker
488*61046927SAndroid Build Coastguard Worker return true;
489*61046927SAndroid Build Coastguard Worker }
490*61046927SAndroid Build Coastguard Worker #endif
491*61046927SAndroid Build Coastguard Worker
492*61046927SAndroid Build Coastguard Worker /* Here we open mesa cache foz dbs files. If the files exist we load the index
493*61046927SAndroid Build Coastguard Worker * db into a hash table. The index db contains the offsets needed to later
494*61046927SAndroid Build Coastguard Worker * read cache entries from the foz db containing the actual cache entries.
495*61046927SAndroid Build Coastguard Worker */
496*61046927SAndroid Build Coastguard Worker bool
foz_prepare(struct foz_db * foz_db,char * cache_path)497*61046927SAndroid Build Coastguard Worker foz_prepare(struct foz_db *foz_db, char *cache_path)
498*61046927SAndroid Build Coastguard Worker {
499*61046927SAndroid Build Coastguard Worker char *filename = NULL;
500*61046927SAndroid Build Coastguard Worker char *idx_filename = NULL;
501*61046927SAndroid Build Coastguard Worker
502*61046927SAndroid Build Coastguard Worker simple_mtx_init(&foz_db->mtx, mtx_plain);
503*61046927SAndroid Build Coastguard Worker simple_mtx_init(&foz_db->flock_mtx, mtx_plain);
504*61046927SAndroid Build Coastguard Worker foz_db->mem_ctx = ralloc_context(NULL);
505*61046927SAndroid Build Coastguard Worker foz_db->index_db = _mesa_hash_table_u64_create(NULL);
506*61046927SAndroid Build Coastguard Worker foz_db->cache_path = cache_path;
507*61046927SAndroid Build Coastguard Worker
508*61046927SAndroid Build Coastguard Worker /* Open the default foz dbs for read/write. If the files didn't already exist
509*61046927SAndroid Build Coastguard Worker * create them.
510*61046927SAndroid Build Coastguard Worker */
511*61046927SAndroid Build Coastguard Worker if (debug_get_bool_option("MESA_DISK_CACHE_SINGLE_FILE", false)) {
512*61046927SAndroid Build Coastguard Worker if (!create_foz_db_filenames(cache_path, "foz_cache",
513*61046927SAndroid Build Coastguard Worker &filename, &idx_filename))
514*61046927SAndroid Build Coastguard Worker goto fail;
515*61046927SAndroid Build Coastguard Worker
516*61046927SAndroid Build Coastguard Worker foz_db->file[0] = fopen(filename, "a+b");
517*61046927SAndroid Build Coastguard Worker foz_db->db_idx = fopen(idx_filename, "a+b");
518*61046927SAndroid Build Coastguard Worker
519*61046927SAndroid Build Coastguard Worker free(filename);
520*61046927SAndroid Build Coastguard Worker free(idx_filename);
521*61046927SAndroid Build Coastguard Worker
522*61046927SAndroid Build Coastguard Worker if (foz_db->file[0] == NULL || foz_db->db_idx == NULL)
523*61046927SAndroid Build Coastguard Worker goto fail;
524*61046927SAndroid Build Coastguard Worker
525*61046927SAndroid Build Coastguard Worker if (!load_foz_dbs(foz_db, foz_db->db_idx, 0, false))
526*61046927SAndroid Build Coastguard Worker goto fail;
527*61046927SAndroid Build Coastguard Worker }
528*61046927SAndroid Build Coastguard Worker
529*61046927SAndroid Build Coastguard Worker char *foz_dbs_ro = getenv("MESA_DISK_CACHE_READ_ONLY_FOZ_DBS");
530*61046927SAndroid Build Coastguard Worker if (foz_dbs_ro)
531*61046927SAndroid Build Coastguard Worker load_foz_dbs_ro(foz_db, foz_dbs_ro);
532*61046927SAndroid Build Coastguard Worker
533*61046927SAndroid Build Coastguard Worker #ifdef FOZ_DB_UTIL_DYNAMIC_LIST
534*61046927SAndroid Build Coastguard Worker char *foz_dbs_list =
535*61046927SAndroid Build Coastguard Worker getenv("MESA_DISK_CACHE_READ_ONLY_FOZ_DBS_DYNAMIC_LIST");
536*61046927SAndroid Build Coastguard Worker if (foz_dbs_list)
537*61046927SAndroid Build Coastguard Worker foz_dbs_list_updater_init(foz_db, foz_dbs_list);
538*61046927SAndroid Build Coastguard Worker #endif
539*61046927SAndroid Build Coastguard Worker
540*61046927SAndroid Build Coastguard Worker return true;
541*61046927SAndroid Build Coastguard Worker
542*61046927SAndroid Build Coastguard Worker fail:
543*61046927SAndroid Build Coastguard Worker foz_destroy(foz_db);
544*61046927SAndroid Build Coastguard Worker
545*61046927SAndroid Build Coastguard Worker return false;
546*61046927SAndroid Build Coastguard Worker }
547*61046927SAndroid Build Coastguard Worker
548*61046927SAndroid Build Coastguard Worker void
foz_destroy(struct foz_db * foz_db)549*61046927SAndroid Build Coastguard Worker foz_destroy(struct foz_db *foz_db)
550*61046927SAndroid Build Coastguard Worker {
551*61046927SAndroid Build Coastguard Worker #ifdef FOZ_DB_UTIL_DYNAMIC_LIST
552*61046927SAndroid Build Coastguard Worker struct foz_dbs_list_updater *updater = &foz_db->updater;
553*61046927SAndroid Build Coastguard Worker if (updater->thrd) {
554*61046927SAndroid Build Coastguard Worker inotify_rm_watch(updater->inotify_fd, updater->inotify_wd);
555*61046927SAndroid Build Coastguard Worker /* inotify_rm_watch() triggers the IN_IGNORE event for the thread
556*61046927SAndroid Build Coastguard Worker * to exit.
557*61046927SAndroid Build Coastguard Worker */
558*61046927SAndroid Build Coastguard Worker thrd_join(updater->thrd, NULL);
559*61046927SAndroid Build Coastguard Worker close(updater->inotify_fd);
560*61046927SAndroid Build Coastguard Worker }
561*61046927SAndroid Build Coastguard Worker #endif
562*61046927SAndroid Build Coastguard Worker
563*61046927SAndroid Build Coastguard Worker if (foz_db->db_idx)
564*61046927SAndroid Build Coastguard Worker fclose(foz_db->db_idx);
565*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < FOZ_MAX_DBS; i++) {
566*61046927SAndroid Build Coastguard Worker if (foz_db->file[i])
567*61046927SAndroid Build Coastguard Worker fclose(foz_db->file[i]);
568*61046927SAndroid Build Coastguard Worker }
569*61046927SAndroid Build Coastguard Worker
570*61046927SAndroid Build Coastguard Worker if (foz_db->mem_ctx) {
571*61046927SAndroid Build Coastguard Worker _mesa_hash_table_u64_destroy(foz_db->index_db);
572*61046927SAndroid Build Coastguard Worker ralloc_free(foz_db->mem_ctx);
573*61046927SAndroid Build Coastguard Worker simple_mtx_destroy(&foz_db->flock_mtx);
574*61046927SAndroid Build Coastguard Worker simple_mtx_destroy(&foz_db->mtx);
575*61046927SAndroid Build Coastguard Worker }
576*61046927SAndroid Build Coastguard Worker
577*61046927SAndroid Build Coastguard Worker memset(foz_db, 0, sizeof(*foz_db));
578*61046927SAndroid Build Coastguard Worker }
579*61046927SAndroid Build Coastguard Worker
580*61046927SAndroid Build Coastguard Worker /* Here we lookup a cache entry in the index hash table. If an entry is found
581*61046927SAndroid Build Coastguard Worker * we use the retrieved offset to read the cache entry from disk.
582*61046927SAndroid Build Coastguard Worker */
583*61046927SAndroid Build Coastguard Worker void *
foz_read_entry(struct foz_db * foz_db,const uint8_t * cache_key_160bit,size_t * size)584*61046927SAndroid Build Coastguard Worker foz_read_entry(struct foz_db *foz_db, const uint8_t *cache_key_160bit,
585*61046927SAndroid Build Coastguard Worker size_t *size)
586*61046927SAndroid Build Coastguard Worker {
587*61046927SAndroid Build Coastguard Worker uint64_t hash = truncate_hash_to_64bits(cache_key_160bit);
588*61046927SAndroid Build Coastguard Worker
589*61046927SAndroid Build Coastguard Worker void *data = NULL;
590*61046927SAndroid Build Coastguard Worker
591*61046927SAndroid Build Coastguard Worker if (!foz_db->alive)
592*61046927SAndroid Build Coastguard Worker return NULL;
593*61046927SAndroid Build Coastguard Worker
594*61046927SAndroid Build Coastguard Worker simple_mtx_lock(&foz_db->mtx);
595*61046927SAndroid Build Coastguard Worker
596*61046927SAndroid Build Coastguard Worker struct foz_db_entry *entry =
597*61046927SAndroid Build Coastguard Worker _mesa_hash_table_u64_search(foz_db->index_db, hash);
598*61046927SAndroid Build Coastguard Worker if (!entry && foz_db->db_idx) {
599*61046927SAndroid Build Coastguard Worker update_foz_index(foz_db, foz_db->db_idx, 0);
600*61046927SAndroid Build Coastguard Worker entry = _mesa_hash_table_u64_search(foz_db->index_db, hash);
601*61046927SAndroid Build Coastguard Worker }
602*61046927SAndroid Build Coastguard Worker if (!entry) {
603*61046927SAndroid Build Coastguard Worker simple_mtx_unlock(&foz_db->mtx);
604*61046927SAndroid Build Coastguard Worker return NULL;
605*61046927SAndroid Build Coastguard Worker }
606*61046927SAndroid Build Coastguard Worker
607*61046927SAndroid Build Coastguard Worker uint8_t file_idx = entry->file_idx;
608*61046927SAndroid Build Coastguard Worker if (fseek(foz_db->file[file_idx], entry->offset, SEEK_SET) < 0)
609*61046927SAndroid Build Coastguard Worker goto fail;
610*61046927SAndroid Build Coastguard Worker
611*61046927SAndroid Build Coastguard Worker uint32_t header_size = sizeof(struct foz_payload_header);
612*61046927SAndroid Build Coastguard Worker if (fread(&entry->header, 1, header_size, foz_db->file[file_idx]) !=
613*61046927SAndroid Build Coastguard Worker header_size)
614*61046927SAndroid Build Coastguard Worker goto fail;
615*61046927SAndroid Build Coastguard Worker
616*61046927SAndroid Build Coastguard Worker /* Check for collision using full 160bit hash for increased assurance
617*61046927SAndroid Build Coastguard Worker * against potential collisions.
618*61046927SAndroid Build Coastguard Worker */
619*61046927SAndroid Build Coastguard Worker for (int i = 0; i < 20; i++) {
620*61046927SAndroid Build Coastguard Worker if (cache_key_160bit[i] != entry->key[i])
621*61046927SAndroid Build Coastguard Worker goto fail;
622*61046927SAndroid Build Coastguard Worker }
623*61046927SAndroid Build Coastguard Worker
624*61046927SAndroid Build Coastguard Worker uint32_t data_sz = entry->header.payload_size;
625*61046927SAndroid Build Coastguard Worker data = malloc(data_sz);
626*61046927SAndroid Build Coastguard Worker if (fread(data, 1, data_sz, foz_db->file[file_idx]) != data_sz)
627*61046927SAndroid Build Coastguard Worker goto fail;
628*61046927SAndroid Build Coastguard Worker
629*61046927SAndroid Build Coastguard Worker /* verify checksum */
630*61046927SAndroid Build Coastguard Worker if (entry->header.crc != 0) {
631*61046927SAndroid Build Coastguard Worker if (util_hash_crc32(data, data_sz) != entry->header.crc)
632*61046927SAndroid Build Coastguard Worker goto fail;
633*61046927SAndroid Build Coastguard Worker }
634*61046927SAndroid Build Coastguard Worker
635*61046927SAndroid Build Coastguard Worker simple_mtx_unlock(&foz_db->mtx);
636*61046927SAndroid Build Coastguard Worker
637*61046927SAndroid Build Coastguard Worker if (size)
638*61046927SAndroid Build Coastguard Worker *size = data_sz;
639*61046927SAndroid Build Coastguard Worker
640*61046927SAndroid Build Coastguard Worker return data;
641*61046927SAndroid Build Coastguard Worker
642*61046927SAndroid Build Coastguard Worker fail:
643*61046927SAndroid Build Coastguard Worker free(data);
644*61046927SAndroid Build Coastguard Worker
645*61046927SAndroid Build Coastguard Worker /* reading db entry failed. reset the file offset */
646*61046927SAndroid Build Coastguard Worker simple_mtx_unlock(&foz_db->mtx);
647*61046927SAndroid Build Coastguard Worker
648*61046927SAndroid Build Coastguard Worker return NULL;
649*61046927SAndroid Build Coastguard Worker }
650*61046927SAndroid Build Coastguard Worker
651*61046927SAndroid Build Coastguard Worker /* Here we write the cache entry to disk and store its offset in the index db.
652*61046927SAndroid Build Coastguard Worker */
653*61046927SAndroid Build Coastguard Worker bool
foz_write_entry(struct foz_db * foz_db,const uint8_t * cache_key_160bit,const void * blob,size_t blob_size)654*61046927SAndroid Build Coastguard Worker foz_write_entry(struct foz_db *foz_db, const uint8_t *cache_key_160bit,
655*61046927SAndroid Build Coastguard Worker const void *blob, size_t blob_size)
656*61046927SAndroid Build Coastguard Worker {
657*61046927SAndroid Build Coastguard Worker uint64_t hash = truncate_hash_to_64bits(cache_key_160bit);
658*61046927SAndroid Build Coastguard Worker
659*61046927SAndroid Build Coastguard Worker if (!foz_db->alive || !foz_db->file[0])
660*61046927SAndroid Build Coastguard Worker return false;
661*61046927SAndroid Build Coastguard Worker
662*61046927SAndroid Build Coastguard Worker /* The flock is per-fd, not per thread, we do it outside of the main mutex to avoid having to
663*61046927SAndroid Build Coastguard Worker * wait in the mutex potentially blocking reads. We use the secondary flock_mtx to stop race
664*61046927SAndroid Build Coastguard Worker * conditions between the write threads sharing the same file descriptor. */
665*61046927SAndroid Build Coastguard Worker simple_mtx_lock(&foz_db->flock_mtx);
666*61046927SAndroid Build Coastguard Worker
667*61046927SAndroid Build Coastguard Worker /* Wait for 1 second. This is done outside of the main mutex as I believe there is more potential
668*61046927SAndroid Build Coastguard Worker * for file contention than mtx contention of significant length. */
669*61046927SAndroid Build Coastguard Worker int err = lock_file_with_timeout(foz_db->file[0], 1000000000);
670*61046927SAndroid Build Coastguard Worker if (err == -1)
671*61046927SAndroid Build Coastguard Worker goto fail_file;
672*61046927SAndroid Build Coastguard Worker
673*61046927SAndroid Build Coastguard Worker simple_mtx_lock(&foz_db->mtx);
674*61046927SAndroid Build Coastguard Worker
675*61046927SAndroid Build Coastguard Worker update_foz_index(foz_db, foz_db->db_idx, 0);
676*61046927SAndroid Build Coastguard Worker
677*61046927SAndroid Build Coastguard Worker struct foz_db_entry *entry =
678*61046927SAndroid Build Coastguard Worker _mesa_hash_table_u64_search(foz_db->index_db, hash);
679*61046927SAndroid Build Coastguard Worker if (entry) {
680*61046927SAndroid Build Coastguard Worker simple_mtx_unlock(&foz_db->mtx);
681*61046927SAndroid Build Coastguard Worker flock(fileno(foz_db->file[0]), LOCK_UN);
682*61046927SAndroid Build Coastguard Worker simple_mtx_unlock(&foz_db->flock_mtx);
683*61046927SAndroid Build Coastguard Worker return NULL;
684*61046927SAndroid Build Coastguard Worker }
685*61046927SAndroid Build Coastguard Worker
686*61046927SAndroid Build Coastguard Worker /* Prepare db entry header and blob ready for writing */
687*61046927SAndroid Build Coastguard Worker struct foz_payload_header header;
688*61046927SAndroid Build Coastguard Worker header.uncompressed_size = blob_size;
689*61046927SAndroid Build Coastguard Worker header.format = FOSSILIZE_COMPRESSION_NONE;
690*61046927SAndroid Build Coastguard Worker header.payload_size = blob_size;
691*61046927SAndroid Build Coastguard Worker header.crc = util_hash_crc32(blob, blob_size);
692*61046927SAndroid Build Coastguard Worker
693*61046927SAndroid Build Coastguard Worker fseek(foz_db->file[0], 0, SEEK_END);
694*61046927SAndroid Build Coastguard Worker
695*61046927SAndroid Build Coastguard Worker /* Write hash header to db */
696*61046927SAndroid Build Coastguard Worker char hash_str[FOSSILIZE_BLOB_HASH_LENGTH + 1]; /* 40 digits + null */
697*61046927SAndroid Build Coastguard Worker _mesa_sha1_format(hash_str, cache_key_160bit);
698*61046927SAndroid Build Coastguard Worker if (fwrite(hash_str, 1, FOSSILIZE_BLOB_HASH_LENGTH, foz_db->file[0]) !=
699*61046927SAndroid Build Coastguard Worker FOSSILIZE_BLOB_HASH_LENGTH)
700*61046927SAndroid Build Coastguard Worker goto fail;
701*61046927SAndroid Build Coastguard Worker
702*61046927SAndroid Build Coastguard Worker uint64_t offset = ftell(foz_db->file[0]);
703*61046927SAndroid Build Coastguard Worker
704*61046927SAndroid Build Coastguard Worker /* Write db entry header */
705*61046927SAndroid Build Coastguard Worker if (fwrite(&header, 1, sizeof(header), foz_db->file[0]) != sizeof(header))
706*61046927SAndroid Build Coastguard Worker goto fail;
707*61046927SAndroid Build Coastguard Worker
708*61046927SAndroid Build Coastguard Worker /* Now write the db entry blob */
709*61046927SAndroid Build Coastguard Worker if (fwrite(blob, 1, blob_size, foz_db->file[0]) != blob_size)
710*61046927SAndroid Build Coastguard Worker goto fail;
711*61046927SAndroid Build Coastguard Worker
712*61046927SAndroid Build Coastguard Worker /* Flush everything to file to reduce chance of cache corruption */
713*61046927SAndroid Build Coastguard Worker fflush(foz_db->file[0]);
714*61046927SAndroid Build Coastguard Worker
715*61046927SAndroid Build Coastguard Worker /* Write hash header to index db */
716*61046927SAndroid Build Coastguard Worker if (fwrite(hash_str, 1, FOSSILIZE_BLOB_HASH_LENGTH, foz_db->db_idx) !=
717*61046927SAndroid Build Coastguard Worker FOSSILIZE_BLOB_HASH_LENGTH)
718*61046927SAndroid Build Coastguard Worker goto fail;
719*61046927SAndroid Build Coastguard Worker
720*61046927SAndroid Build Coastguard Worker header.uncompressed_size = sizeof(uint64_t);
721*61046927SAndroid Build Coastguard Worker header.format = FOSSILIZE_COMPRESSION_NONE;
722*61046927SAndroid Build Coastguard Worker header.payload_size = sizeof(uint64_t);
723*61046927SAndroid Build Coastguard Worker header.crc = 0;
724*61046927SAndroid Build Coastguard Worker
725*61046927SAndroid Build Coastguard Worker if (fwrite(&header, 1, sizeof(header), foz_db->db_idx) !=
726*61046927SAndroid Build Coastguard Worker sizeof(header))
727*61046927SAndroid Build Coastguard Worker goto fail;
728*61046927SAndroid Build Coastguard Worker
729*61046927SAndroid Build Coastguard Worker if (fwrite(&offset, 1, sizeof(uint64_t), foz_db->db_idx) !=
730*61046927SAndroid Build Coastguard Worker sizeof(uint64_t))
731*61046927SAndroid Build Coastguard Worker goto fail;
732*61046927SAndroid Build Coastguard Worker
733*61046927SAndroid Build Coastguard Worker /* Flush everything to file to reduce chance of cache corruption */
734*61046927SAndroid Build Coastguard Worker fflush(foz_db->db_idx);
735*61046927SAndroid Build Coastguard Worker
736*61046927SAndroid Build Coastguard Worker entry = ralloc(foz_db->mem_ctx, struct foz_db_entry);
737*61046927SAndroid Build Coastguard Worker entry->header = header;
738*61046927SAndroid Build Coastguard Worker entry->offset = offset;
739*61046927SAndroid Build Coastguard Worker entry->file_idx = 0;
740*61046927SAndroid Build Coastguard Worker _mesa_sha1_hex_to_sha1(entry->key, hash_str);
741*61046927SAndroid Build Coastguard Worker _mesa_hash_table_u64_insert(foz_db->index_db, hash, entry);
742*61046927SAndroid Build Coastguard Worker
743*61046927SAndroid Build Coastguard Worker simple_mtx_unlock(&foz_db->mtx);
744*61046927SAndroid Build Coastguard Worker flock(fileno(foz_db->file[0]), LOCK_UN);
745*61046927SAndroid Build Coastguard Worker simple_mtx_unlock(&foz_db->flock_mtx);
746*61046927SAndroid Build Coastguard Worker
747*61046927SAndroid Build Coastguard Worker return true;
748*61046927SAndroid Build Coastguard Worker
749*61046927SAndroid Build Coastguard Worker fail:
750*61046927SAndroid Build Coastguard Worker simple_mtx_unlock(&foz_db->mtx);
751*61046927SAndroid Build Coastguard Worker fail_file:
752*61046927SAndroid Build Coastguard Worker flock(fileno(foz_db->file[0]), LOCK_UN);
753*61046927SAndroid Build Coastguard Worker simple_mtx_unlock(&foz_db->flock_mtx);
754*61046927SAndroid Build Coastguard Worker return false;
755*61046927SAndroid Build Coastguard Worker }
756*61046927SAndroid Build Coastguard Worker #else
757*61046927SAndroid Build Coastguard Worker
758*61046927SAndroid Build Coastguard Worker bool
foz_prepare(struct foz_db * foz_db,char * filename)759*61046927SAndroid Build Coastguard Worker foz_prepare(struct foz_db *foz_db, char *filename)
760*61046927SAndroid Build Coastguard Worker {
761*61046927SAndroid Build Coastguard Worker fprintf(stderr, "Warning: Mesa single file cache selected but Mesa wasn't "
762*61046927SAndroid Build Coastguard Worker "built with single cache file support. Shader cache will be disabled"
763*61046927SAndroid Build Coastguard Worker "!\n");
764*61046927SAndroid Build Coastguard Worker return false;
765*61046927SAndroid Build Coastguard Worker }
766*61046927SAndroid Build Coastguard Worker
767*61046927SAndroid Build Coastguard Worker void
foz_destroy(struct foz_db * foz_db)768*61046927SAndroid Build Coastguard Worker foz_destroy(struct foz_db *foz_db)
769*61046927SAndroid Build Coastguard Worker {
770*61046927SAndroid Build Coastguard Worker }
771*61046927SAndroid Build Coastguard Worker
772*61046927SAndroid Build Coastguard Worker void *
foz_read_entry(struct foz_db * foz_db,const uint8_t * cache_key_160bit,size_t * size)773*61046927SAndroid Build Coastguard Worker foz_read_entry(struct foz_db *foz_db, const uint8_t *cache_key_160bit,
774*61046927SAndroid Build Coastguard Worker size_t *size)
775*61046927SAndroid Build Coastguard Worker {
776*61046927SAndroid Build Coastguard Worker return false;
777*61046927SAndroid Build Coastguard Worker }
778*61046927SAndroid Build Coastguard Worker
779*61046927SAndroid Build Coastguard Worker bool
foz_write_entry(struct foz_db * foz_db,const uint8_t * cache_key_160bit,const void * blob,size_t size)780*61046927SAndroid Build Coastguard Worker foz_write_entry(struct foz_db *foz_db, const uint8_t *cache_key_160bit,
781*61046927SAndroid Build Coastguard Worker const void *blob, size_t size)
782*61046927SAndroid Build Coastguard Worker {
783*61046927SAndroid Build Coastguard Worker return false;
784*61046927SAndroid Build Coastguard Worker }
785*61046927SAndroid Build Coastguard Worker
786*61046927SAndroid Build Coastguard Worker #endif
787