xref: /aosp_15_r20/external/mesa3d/src/util/fossilize_db.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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