1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright © 2022 Collabora, Ltd.
3*61046927SAndroid Build Coastguard Worker *
4*61046927SAndroid Build Coastguard Worker * Based on Fossilize DB:
5*61046927SAndroid Build Coastguard Worker * Copyright © 2020 Valve Corporation
6*61046927SAndroid Build Coastguard Worker *
7*61046927SAndroid Build Coastguard Worker * SPDX-License-Identifier: MIT
8*61046927SAndroid Build Coastguard Worker */
9*61046927SAndroid Build Coastguard Worker
10*61046927SAndroid Build Coastguard Worker #include "detect_os.h"
11*61046927SAndroid Build Coastguard Worker
12*61046927SAndroid Build Coastguard Worker #if DETECT_OS_WINDOWS == 0
13*61046927SAndroid Build Coastguard Worker
14*61046927SAndroid Build Coastguard Worker #include <fcntl.h>
15*61046927SAndroid Build Coastguard Worker #include <stddef.h>
16*61046927SAndroid Build Coastguard Worker #include <stdlib.h>
17*61046927SAndroid Build Coastguard Worker #include <string.h>
18*61046927SAndroid Build Coastguard Worker #include <sys/file.h>
19*61046927SAndroid Build Coastguard Worker #include <unistd.h>
20*61046927SAndroid Build Coastguard Worker
21*61046927SAndroid Build Coastguard Worker #include "crc32.h"
22*61046927SAndroid Build Coastguard Worker #include "disk_cache.h"
23*61046927SAndroid Build Coastguard Worker #include "hash_table.h"
24*61046927SAndroid Build Coastguard Worker #include "mesa-sha1.h"
25*61046927SAndroid Build Coastguard Worker #include "mesa_cache_db.h"
26*61046927SAndroid Build Coastguard Worker #include "os_time.h"
27*61046927SAndroid Build Coastguard Worker #include "ralloc.h"
28*61046927SAndroid Build Coastguard Worker #include "u_debug.h"
29*61046927SAndroid Build Coastguard Worker #include "u_qsort.h"
30*61046927SAndroid Build Coastguard Worker
31*61046927SAndroid Build Coastguard Worker #define MESA_CACHE_DB_VERSION 1
32*61046927SAndroid Build Coastguard Worker #define MESA_CACHE_DB_MAGIC "MESA_DB"
33*61046927SAndroid Build Coastguard Worker
34*61046927SAndroid Build Coastguard Worker struct PACKED mesa_db_file_header {
35*61046927SAndroid Build Coastguard Worker char magic[8];
36*61046927SAndroid Build Coastguard Worker uint32_t version;
37*61046927SAndroid Build Coastguard Worker uint64_t uuid;
38*61046927SAndroid Build Coastguard Worker };
39*61046927SAndroid Build Coastguard Worker
40*61046927SAndroid Build Coastguard Worker struct PACKED mesa_cache_db_file_entry {
41*61046927SAndroid Build Coastguard Worker cache_key key;
42*61046927SAndroid Build Coastguard Worker uint32_t crc;
43*61046927SAndroid Build Coastguard Worker uint32_t size;
44*61046927SAndroid Build Coastguard Worker };
45*61046927SAndroid Build Coastguard Worker
46*61046927SAndroid Build Coastguard Worker struct PACKED mesa_index_db_file_entry {
47*61046927SAndroid Build Coastguard Worker uint64_t hash;
48*61046927SAndroid Build Coastguard Worker uint32_t size;
49*61046927SAndroid Build Coastguard Worker uint64_t last_access_time;
50*61046927SAndroid Build Coastguard Worker uint64_t cache_db_file_offset;
51*61046927SAndroid Build Coastguard Worker };
52*61046927SAndroid Build Coastguard Worker
53*61046927SAndroid Build Coastguard Worker struct mesa_index_db_hash_entry {
54*61046927SAndroid Build Coastguard Worker uint64_t cache_db_file_offset;
55*61046927SAndroid Build Coastguard Worker uint64_t index_db_file_offset;
56*61046927SAndroid Build Coastguard Worker uint64_t last_access_time;
57*61046927SAndroid Build Coastguard Worker uint32_t size;
58*61046927SAndroid Build Coastguard Worker bool evicted;
59*61046927SAndroid Build Coastguard Worker };
60*61046927SAndroid Build Coastguard Worker
mesa_db_seek_end(FILE * file)61*61046927SAndroid Build Coastguard Worker static inline bool mesa_db_seek_end(FILE *file)
62*61046927SAndroid Build Coastguard Worker {
63*61046927SAndroid Build Coastguard Worker return !fseek(file, 0, SEEK_END);
64*61046927SAndroid Build Coastguard Worker }
65*61046927SAndroid Build Coastguard Worker
mesa_db_seek(FILE * file,long pos)66*61046927SAndroid Build Coastguard Worker static inline bool mesa_db_seek(FILE *file, long pos)
67*61046927SAndroid Build Coastguard Worker {
68*61046927SAndroid Build Coastguard Worker return !fseek(file, pos, SEEK_SET);
69*61046927SAndroid Build Coastguard Worker }
70*61046927SAndroid Build Coastguard Worker
mesa_db_seek_cur(FILE * file,long pos)71*61046927SAndroid Build Coastguard Worker static inline bool mesa_db_seek_cur(FILE *file, long pos)
72*61046927SAndroid Build Coastguard Worker {
73*61046927SAndroid Build Coastguard Worker return !fseek(file, pos, SEEK_CUR);
74*61046927SAndroid Build Coastguard Worker }
75*61046927SAndroid Build Coastguard Worker
mesa_db_read_data(FILE * file,void * data,size_t size)76*61046927SAndroid Build Coastguard Worker static inline bool mesa_db_read_data(FILE *file, void *data, size_t size)
77*61046927SAndroid Build Coastguard Worker {
78*61046927SAndroid Build Coastguard Worker return fread(data, 1, size, file) == size;
79*61046927SAndroid Build Coastguard Worker }
80*61046927SAndroid Build Coastguard Worker #define mesa_db_read(file, var) mesa_db_read_data(file, var, sizeof(*(var)))
81*61046927SAndroid Build Coastguard Worker
mesa_db_write_data(FILE * file,const void * data,size_t size)82*61046927SAndroid Build Coastguard Worker static inline bool mesa_db_write_data(FILE *file, const void *data, size_t size)
83*61046927SAndroid Build Coastguard Worker {
84*61046927SAndroid Build Coastguard Worker return fwrite(data, 1, size, file) == size;
85*61046927SAndroid Build Coastguard Worker }
86*61046927SAndroid Build Coastguard Worker #define mesa_db_write(file, var) mesa_db_write_data(file, var, sizeof(*(var)))
87*61046927SAndroid Build Coastguard Worker
mesa_db_truncate(FILE * file,long pos)88*61046927SAndroid Build Coastguard Worker static inline bool mesa_db_truncate(FILE *file, long pos)
89*61046927SAndroid Build Coastguard Worker {
90*61046927SAndroid Build Coastguard Worker return !ftruncate(fileno(file), pos);
91*61046927SAndroid Build Coastguard Worker }
92*61046927SAndroid Build Coastguard Worker
93*61046927SAndroid Build Coastguard Worker static bool
mesa_db_lock(struct mesa_cache_db * db)94*61046927SAndroid Build Coastguard Worker mesa_db_lock(struct mesa_cache_db *db)
95*61046927SAndroid Build Coastguard Worker {
96*61046927SAndroid Build Coastguard Worker simple_mtx_lock(&db->flock_mtx);
97*61046927SAndroid Build Coastguard Worker
98*61046927SAndroid Build Coastguard Worker if (flock(fileno(db->cache.file), LOCK_EX) == -1)
99*61046927SAndroid Build Coastguard Worker goto unlock_mtx;
100*61046927SAndroid Build Coastguard Worker
101*61046927SAndroid Build Coastguard Worker if (flock(fileno(db->index.file), LOCK_EX) == -1)
102*61046927SAndroid Build Coastguard Worker goto unlock_cache;
103*61046927SAndroid Build Coastguard Worker
104*61046927SAndroid Build Coastguard Worker return true;
105*61046927SAndroid Build Coastguard Worker
106*61046927SAndroid Build Coastguard Worker unlock_cache:
107*61046927SAndroid Build Coastguard Worker flock(fileno(db->cache.file), LOCK_UN);
108*61046927SAndroid Build Coastguard Worker unlock_mtx:
109*61046927SAndroid Build Coastguard Worker simple_mtx_unlock(&db->flock_mtx);
110*61046927SAndroid Build Coastguard Worker
111*61046927SAndroid Build Coastguard Worker return false;
112*61046927SAndroid Build Coastguard Worker }
113*61046927SAndroid Build Coastguard Worker
114*61046927SAndroid Build Coastguard Worker static void
mesa_db_unlock(struct mesa_cache_db * db)115*61046927SAndroid Build Coastguard Worker mesa_db_unlock(struct mesa_cache_db *db)
116*61046927SAndroid Build Coastguard Worker {
117*61046927SAndroid Build Coastguard Worker flock(fileno(db->index.file), LOCK_UN);
118*61046927SAndroid Build Coastguard Worker flock(fileno(db->cache.file), LOCK_UN);
119*61046927SAndroid Build Coastguard Worker simple_mtx_unlock(&db->flock_mtx);
120*61046927SAndroid Build Coastguard Worker }
121*61046927SAndroid Build Coastguard Worker
to_mesa_cache_db_hash(const uint8_t * cache_key_160bit)122*61046927SAndroid Build Coastguard Worker static uint64_t to_mesa_cache_db_hash(const uint8_t *cache_key_160bit)
123*61046927SAndroid Build Coastguard Worker {
124*61046927SAndroid Build Coastguard Worker uint64_t hash = 0;
125*61046927SAndroid Build Coastguard Worker
126*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < 8; i++)
127*61046927SAndroid Build Coastguard Worker hash |= ((uint64_t)cache_key_160bit[i]) << i * 8;
128*61046927SAndroid Build Coastguard Worker
129*61046927SAndroid Build Coastguard Worker return hash;
130*61046927SAndroid Build Coastguard Worker }
131*61046927SAndroid Build Coastguard Worker
132*61046927SAndroid Build Coastguard Worker static uint64_t
mesa_db_generate_uuid(void)133*61046927SAndroid Build Coastguard Worker mesa_db_generate_uuid(void)
134*61046927SAndroid Build Coastguard Worker {
135*61046927SAndroid Build Coastguard Worker /* This simple UUID implementation is sufficient for our needs
136*61046927SAndroid Build Coastguard Worker * because UUID is updated rarely. It's nice to make UUID meaningful
137*61046927SAndroid Build Coastguard Worker * and incremental by adding the timestamp to it, which also prevents
138*61046927SAndroid Build Coastguard Worker * the potential collisions. */
139*61046927SAndroid Build Coastguard Worker return ((os_time_get() / 1000000) << 32) | rand();
140*61046927SAndroid Build Coastguard Worker }
141*61046927SAndroid Build Coastguard Worker
142*61046927SAndroid Build Coastguard Worker static bool
mesa_db_read_header(FILE * file,struct mesa_db_file_header * header)143*61046927SAndroid Build Coastguard Worker mesa_db_read_header(FILE *file, struct mesa_db_file_header *header)
144*61046927SAndroid Build Coastguard Worker {
145*61046927SAndroid Build Coastguard Worker rewind(file);
146*61046927SAndroid Build Coastguard Worker fflush(file);
147*61046927SAndroid Build Coastguard Worker
148*61046927SAndroid Build Coastguard Worker if (!mesa_db_read(file, header))
149*61046927SAndroid Build Coastguard Worker return false;
150*61046927SAndroid Build Coastguard Worker
151*61046927SAndroid Build Coastguard Worker if (strncmp(header->magic, MESA_CACHE_DB_MAGIC, sizeof(header->magic)) ||
152*61046927SAndroid Build Coastguard Worker header->version != MESA_CACHE_DB_VERSION || !header->uuid)
153*61046927SAndroid Build Coastguard Worker return false;
154*61046927SAndroid Build Coastguard Worker
155*61046927SAndroid Build Coastguard Worker return true;
156*61046927SAndroid Build Coastguard Worker }
157*61046927SAndroid Build Coastguard Worker
158*61046927SAndroid Build Coastguard Worker static bool
mesa_db_load_header(struct mesa_cache_db_file * db_file)159*61046927SAndroid Build Coastguard Worker mesa_db_load_header(struct mesa_cache_db_file *db_file)
160*61046927SAndroid Build Coastguard Worker {
161*61046927SAndroid Build Coastguard Worker struct mesa_db_file_header header;
162*61046927SAndroid Build Coastguard Worker
163*61046927SAndroid Build Coastguard Worker if (!mesa_db_read_header(db_file->file, &header))
164*61046927SAndroid Build Coastguard Worker return false;
165*61046927SAndroid Build Coastguard Worker
166*61046927SAndroid Build Coastguard Worker db_file->uuid = header.uuid;
167*61046927SAndroid Build Coastguard Worker
168*61046927SAndroid Build Coastguard Worker return true;
169*61046927SAndroid Build Coastguard Worker }
170*61046927SAndroid Build Coastguard Worker
mesa_db_uuid_changed(struct mesa_cache_db * db)171*61046927SAndroid Build Coastguard Worker static bool mesa_db_uuid_changed(struct mesa_cache_db *db)
172*61046927SAndroid Build Coastguard Worker {
173*61046927SAndroid Build Coastguard Worker struct mesa_db_file_header cache_header;
174*61046927SAndroid Build Coastguard Worker struct mesa_db_file_header index_header;
175*61046927SAndroid Build Coastguard Worker
176*61046927SAndroid Build Coastguard Worker if (!mesa_db_read_header(db->cache.file, &cache_header) ||
177*61046927SAndroid Build Coastguard Worker !mesa_db_read_header(db->index.file, &index_header) ||
178*61046927SAndroid Build Coastguard Worker cache_header.uuid != index_header.uuid ||
179*61046927SAndroid Build Coastguard Worker cache_header.uuid != db->uuid)
180*61046927SAndroid Build Coastguard Worker return true;
181*61046927SAndroid Build Coastguard Worker
182*61046927SAndroid Build Coastguard Worker return false;
183*61046927SAndroid Build Coastguard Worker }
184*61046927SAndroid Build Coastguard Worker
185*61046927SAndroid Build Coastguard Worker static bool
mesa_db_write_header(struct mesa_cache_db_file * db_file,uint64_t uuid,bool reset)186*61046927SAndroid Build Coastguard Worker mesa_db_write_header(struct mesa_cache_db_file *db_file,
187*61046927SAndroid Build Coastguard Worker uint64_t uuid, bool reset)
188*61046927SAndroid Build Coastguard Worker {
189*61046927SAndroid Build Coastguard Worker struct mesa_db_file_header header;
190*61046927SAndroid Build Coastguard Worker
191*61046927SAndroid Build Coastguard Worker rewind(db_file->file);
192*61046927SAndroid Build Coastguard Worker
193*61046927SAndroid Build Coastguard Worker sprintf(header.magic, "MESA_DB");
194*61046927SAndroid Build Coastguard Worker header.version = MESA_CACHE_DB_VERSION;
195*61046927SAndroid Build Coastguard Worker header.uuid = uuid;
196*61046927SAndroid Build Coastguard Worker
197*61046927SAndroid Build Coastguard Worker if (!mesa_db_write(db_file->file, &header))
198*61046927SAndroid Build Coastguard Worker return false;
199*61046927SAndroid Build Coastguard Worker
200*61046927SAndroid Build Coastguard Worker if (reset) {
201*61046927SAndroid Build Coastguard Worker if (!mesa_db_truncate(db_file->file, ftell(db_file->file)))
202*61046927SAndroid Build Coastguard Worker return false;
203*61046927SAndroid Build Coastguard Worker }
204*61046927SAndroid Build Coastguard Worker
205*61046927SAndroid Build Coastguard Worker fflush(db_file->file);
206*61046927SAndroid Build Coastguard Worker
207*61046927SAndroid Build Coastguard Worker return true;
208*61046927SAndroid Build Coastguard Worker }
209*61046927SAndroid Build Coastguard Worker
210*61046927SAndroid Build Coastguard Worker /* Wipe out all database cache files.
211*61046927SAndroid Build Coastguard Worker *
212*61046927SAndroid Build Coastguard Worker * Whenever we get an unmanageable error on reading or writing to the
213*61046927SAndroid Build Coastguard Worker * database file, wipe out the whole database and start over. All the
214*61046927SAndroid Build Coastguard Worker * cached entries will be lost, but the broken cache will be auto-repaired
215*61046927SAndroid Build Coastguard Worker * reliably. Normally cache shall never get corrupted and losing cache
216*61046927SAndroid Build Coastguard Worker * entries is acceptable, hence it's more practical to repair DB using
217*61046927SAndroid Build Coastguard Worker * the simplest method.
218*61046927SAndroid Build Coastguard Worker */
219*61046927SAndroid Build Coastguard Worker static bool
mesa_db_zap(struct mesa_cache_db * db)220*61046927SAndroid Build Coastguard Worker mesa_db_zap(struct mesa_cache_db *db)
221*61046927SAndroid Build Coastguard Worker {
222*61046927SAndroid Build Coastguard Worker /* Disable cache to prevent the recurring faults */
223*61046927SAndroid Build Coastguard Worker db->alive = false;
224*61046927SAndroid Build Coastguard Worker
225*61046927SAndroid Build Coastguard Worker /* Zap corrupted database files to start over from a clean slate */
226*61046927SAndroid Build Coastguard Worker if (!mesa_db_truncate(db->cache.file, 0) ||
227*61046927SAndroid Build Coastguard Worker !mesa_db_truncate(db->index.file, 0))
228*61046927SAndroid Build Coastguard Worker return false;
229*61046927SAndroid Build Coastguard Worker
230*61046927SAndroid Build Coastguard Worker fflush(db->cache.file);
231*61046927SAndroid Build Coastguard Worker fflush(db->index.file);
232*61046927SAndroid Build Coastguard Worker
233*61046927SAndroid Build Coastguard Worker return true;
234*61046927SAndroid Build Coastguard Worker }
235*61046927SAndroid Build Coastguard Worker
236*61046927SAndroid Build Coastguard Worker static bool
mesa_db_index_entry_valid(struct mesa_index_db_file_entry * entry)237*61046927SAndroid Build Coastguard Worker mesa_db_index_entry_valid(struct mesa_index_db_file_entry *entry)
238*61046927SAndroid Build Coastguard Worker {
239*61046927SAndroid Build Coastguard Worker return entry->size && entry->hash &&
240*61046927SAndroid Build Coastguard Worker (int64_t)entry->cache_db_file_offset >= sizeof(struct mesa_db_file_header);
241*61046927SAndroid Build Coastguard Worker }
242*61046927SAndroid Build Coastguard Worker
243*61046927SAndroid Build Coastguard Worker static bool
mesa_db_cache_entry_valid(struct mesa_cache_db_file_entry * entry)244*61046927SAndroid Build Coastguard Worker mesa_db_cache_entry_valid(struct mesa_cache_db_file_entry *entry)
245*61046927SAndroid Build Coastguard Worker {
246*61046927SAndroid Build Coastguard Worker return entry->size && entry->crc;
247*61046927SAndroid Build Coastguard Worker }
248*61046927SAndroid Build Coastguard Worker
249*61046927SAndroid Build Coastguard Worker static bool
mesa_db_update_index(struct mesa_cache_db * db)250*61046927SAndroid Build Coastguard Worker mesa_db_update_index(struct mesa_cache_db *db)
251*61046927SAndroid Build Coastguard Worker {
252*61046927SAndroid Build Coastguard Worker struct mesa_index_db_hash_entry *hash_entry;
253*61046927SAndroid Build Coastguard Worker struct mesa_index_db_file_entry index_entry;
254*61046927SAndroid Build Coastguard Worker size_t file_length;
255*61046927SAndroid Build Coastguard Worker
256*61046927SAndroid Build Coastguard Worker if (!mesa_db_seek_end(db->index.file))
257*61046927SAndroid Build Coastguard Worker return false;
258*61046927SAndroid Build Coastguard Worker
259*61046927SAndroid Build Coastguard Worker file_length = ftell(db->index.file);
260*61046927SAndroid Build Coastguard Worker
261*61046927SAndroid Build Coastguard Worker if (!mesa_db_seek(db->index.file, db->index.offset))
262*61046927SAndroid Build Coastguard Worker return false;
263*61046927SAndroid Build Coastguard Worker
264*61046927SAndroid Build Coastguard Worker while (db->index.offset < file_length) {
265*61046927SAndroid Build Coastguard Worker if (!mesa_db_read(db->index.file, &index_entry))
266*61046927SAndroid Build Coastguard Worker break;
267*61046927SAndroid Build Coastguard Worker
268*61046927SAndroid Build Coastguard Worker /* Check whether the index entry looks valid or we have a corrupted DB */
269*61046927SAndroid Build Coastguard Worker if (!mesa_db_index_entry_valid(&index_entry))
270*61046927SAndroid Build Coastguard Worker break;
271*61046927SAndroid Build Coastguard Worker
272*61046927SAndroid Build Coastguard Worker hash_entry = ralloc(db->mem_ctx, struct mesa_index_db_hash_entry);
273*61046927SAndroid Build Coastguard Worker if (!hash_entry)
274*61046927SAndroid Build Coastguard Worker break;
275*61046927SAndroid Build Coastguard Worker
276*61046927SAndroid Build Coastguard Worker hash_entry->cache_db_file_offset = index_entry.cache_db_file_offset;
277*61046927SAndroid Build Coastguard Worker hash_entry->index_db_file_offset = db->index.offset;
278*61046927SAndroid Build Coastguard Worker hash_entry->last_access_time = index_entry.last_access_time;
279*61046927SAndroid Build Coastguard Worker hash_entry->size = index_entry.size;
280*61046927SAndroid Build Coastguard Worker
281*61046927SAndroid Build Coastguard Worker _mesa_hash_table_u64_insert(db->index_db, index_entry.hash, hash_entry);
282*61046927SAndroid Build Coastguard Worker
283*61046927SAndroid Build Coastguard Worker db->index.offset += sizeof(index_entry);
284*61046927SAndroid Build Coastguard Worker }
285*61046927SAndroid Build Coastguard Worker
286*61046927SAndroid Build Coastguard Worker if (!mesa_db_seek(db->index.file, db->index.offset))
287*61046927SAndroid Build Coastguard Worker return false;
288*61046927SAndroid Build Coastguard Worker
289*61046927SAndroid Build Coastguard Worker return db->index.offset == file_length;
290*61046927SAndroid Build Coastguard Worker }
291*61046927SAndroid Build Coastguard Worker
292*61046927SAndroid Build Coastguard Worker static void
mesa_db_hash_table_reset(struct mesa_cache_db * db)293*61046927SAndroid Build Coastguard Worker mesa_db_hash_table_reset(struct mesa_cache_db *db)
294*61046927SAndroid Build Coastguard Worker {
295*61046927SAndroid Build Coastguard Worker _mesa_hash_table_u64_clear(db->index_db);
296*61046927SAndroid Build Coastguard Worker ralloc_free(db->mem_ctx);
297*61046927SAndroid Build Coastguard Worker db->mem_ctx = ralloc_context(NULL);
298*61046927SAndroid Build Coastguard Worker }
299*61046927SAndroid Build Coastguard Worker
300*61046927SAndroid Build Coastguard Worker static bool
mesa_db_recreate_files(struct mesa_cache_db * db)301*61046927SAndroid Build Coastguard Worker mesa_db_recreate_files(struct mesa_cache_db *db)
302*61046927SAndroid Build Coastguard Worker {
303*61046927SAndroid Build Coastguard Worker db->uuid = mesa_db_generate_uuid();
304*61046927SAndroid Build Coastguard Worker
305*61046927SAndroid Build Coastguard Worker if (!mesa_db_write_header(&db->cache, db->uuid, true) ||
306*61046927SAndroid Build Coastguard Worker !mesa_db_write_header(&db->index, db->uuid, true))
307*61046927SAndroid Build Coastguard Worker return false;
308*61046927SAndroid Build Coastguard Worker
309*61046927SAndroid Build Coastguard Worker return true;
310*61046927SAndroid Build Coastguard Worker }
311*61046927SAndroid Build Coastguard Worker
312*61046927SAndroid Build Coastguard Worker static bool
mesa_db_load(struct mesa_cache_db * db,bool reload)313*61046927SAndroid Build Coastguard Worker mesa_db_load(struct mesa_cache_db *db, bool reload)
314*61046927SAndroid Build Coastguard Worker {
315*61046927SAndroid Build Coastguard Worker /* reloading must be done under the held lock */
316*61046927SAndroid Build Coastguard Worker if (!reload) {
317*61046927SAndroid Build Coastguard Worker if (!mesa_db_lock(db))
318*61046927SAndroid Build Coastguard Worker return false;
319*61046927SAndroid Build Coastguard Worker }
320*61046927SAndroid Build Coastguard Worker
321*61046927SAndroid Build Coastguard Worker /* If file headers are invalid, then zap database files and start over */
322*61046927SAndroid Build Coastguard Worker if (!mesa_db_load_header(&db->cache) ||
323*61046927SAndroid Build Coastguard Worker !mesa_db_load_header(&db->index) ||
324*61046927SAndroid Build Coastguard Worker db->cache.uuid != db->index.uuid) {
325*61046927SAndroid Build Coastguard Worker
326*61046927SAndroid Build Coastguard Worker /* This is unexpected to happen on reload, bail out */
327*61046927SAndroid Build Coastguard Worker if (reload)
328*61046927SAndroid Build Coastguard Worker goto fail;
329*61046927SAndroid Build Coastguard Worker
330*61046927SAndroid Build Coastguard Worker if (!mesa_db_recreate_files(db))
331*61046927SAndroid Build Coastguard Worker goto fail;
332*61046927SAndroid Build Coastguard Worker } else {
333*61046927SAndroid Build Coastguard Worker db->uuid = db->cache.uuid;
334*61046927SAndroid Build Coastguard Worker }
335*61046927SAndroid Build Coastguard Worker
336*61046927SAndroid Build Coastguard Worker db->index.offset = ftell(db->index.file);
337*61046927SAndroid Build Coastguard Worker
338*61046927SAndroid Build Coastguard Worker if (reload)
339*61046927SAndroid Build Coastguard Worker mesa_db_hash_table_reset(db);
340*61046927SAndroid Build Coastguard Worker
341*61046927SAndroid Build Coastguard Worker if (!mesa_db_update_index(db))
342*61046927SAndroid Build Coastguard Worker goto fail;
343*61046927SAndroid Build Coastguard Worker
344*61046927SAndroid Build Coastguard Worker if (!reload)
345*61046927SAndroid Build Coastguard Worker mesa_db_unlock(db);
346*61046927SAndroid Build Coastguard Worker
347*61046927SAndroid Build Coastguard Worker db->alive = true;
348*61046927SAndroid Build Coastguard Worker
349*61046927SAndroid Build Coastguard Worker return true;
350*61046927SAndroid Build Coastguard Worker
351*61046927SAndroid Build Coastguard Worker fail:
352*61046927SAndroid Build Coastguard Worker if (!reload)
353*61046927SAndroid Build Coastguard Worker mesa_db_unlock(db);
354*61046927SAndroid Build Coastguard Worker
355*61046927SAndroid Build Coastguard Worker return false;
356*61046927SAndroid Build Coastguard Worker }
357*61046927SAndroid Build Coastguard Worker
358*61046927SAndroid Build Coastguard Worker static bool
mesa_db_reload(struct mesa_cache_db * db)359*61046927SAndroid Build Coastguard Worker mesa_db_reload(struct mesa_cache_db *db)
360*61046927SAndroid Build Coastguard Worker {
361*61046927SAndroid Build Coastguard Worker fflush(db->cache.file);
362*61046927SAndroid Build Coastguard Worker fflush(db->index.file);
363*61046927SAndroid Build Coastguard Worker
364*61046927SAndroid Build Coastguard Worker return mesa_db_load(db, true);
365*61046927SAndroid Build Coastguard Worker }
366*61046927SAndroid Build Coastguard Worker
367*61046927SAndroid Build Coastguard Worker static void
touch_file(const char * path)368*61046927SAndroid Build Coastguard Worker touch_file(const char* path)
369*61046927SAndroid Build Coastguard Worker {
370*61046927SAndroid Build Coastguard Worker close(open(path, O_CREAT | O_CLOEXEC, 0644));
371*61046927SAndroid Build Coastguard Worker }
372*61046927SAndroid Build Coastguard Worker
373*61046927SAndroid Build Coastguard Worker static bool
mesa_db_open_file(struct mesa_cache_db_file * db_file,const char * cache_path,const char * filename)374*61046927SAndroid Build Coastguard Worker mesa_db_open_file(struct mesa_cache_db_file *db_file,
375*61046927SAndroid Build Coastguard Worker const char *cache_path,
376*61046927SAndroid Build Coastguard Worker const char *filename)
377*61046927SAndroid Build Coastguard Worker {
378*61046927SAndroid Build Coastguard Worker if (asprintf(&db_file->path, "%s/%s", cache_path, filename) == -1)
379*61046927SAndroid Build Coastguard Worker return false;
380*61046927SAndroid Build Coastguard Worker
381*61046927SAndroid Build Coastguard Worker /* The fopen("r+b") mode doesn't auto-create new file, hence we need to
382*61046927SAndroid Build Coastguard Worker * explicitly create the file first.
383*61046927SAndroid Build Coastguard Worker */
384*61046927SAndroid Build Coastguard Worker touch_file(db_file->path);
385*61046927SAndroid Build Coastguard Worker
386*61046927SAndroid Build Coastguard Worker db_file->file = fopen(db_file->path, "r+b");
387*61046927SAndroid Build Coastguard Worker if (!db_file->file) {
388*61046927SAndroid Build Coastguard Worker free(db_file->path);
389*61046927SAndroid Build Coastguard Worker return false;
390*61046927SAndroid Build Coastguard Worker }
391*61046927SAndroid Build Coastguard Worker
392*61046927SAndroid Build Coastguard Worker return true;
393*61046927SAndroid Build Coastguard Worker }
394*61046927SAndroid Build Coastguard Worker
395*61046927SAndroid Build Coastguard Worker static void
mesa_db_close_file(struct mesa_cache_db_file * db_file)396*61046927SAndroid Build Coastguard Worker mesa_db_close_file(struct mesa_cache_db_file *db_file)
397*61046927SAndroid Build Coastguard Worker {
398*61046927SAndroid Build Coastguard Worker fclose(db_file->file);
399*61046927SAndroid Build Coastguard Worker free(db_file->path);
400*61046927SAndroid Build Coastguard Worker }
401*61046927SAndroid Build Coastguard Worker
402*61046927SAndroid Build Coastguard Worker static bool
mesa_db_remove_file(struct mesa_cache_db_file * db_file,const char * cache_path,const char * filename)403*61046927SAndroid Build Coastguard Worker mesa_db_remove_file(struct mesa_cache_db_file *db_file,
404*61046927SAndroid Build Coastguard Worker const char *cache_path,
405*61046927SAndroid Build Coastguard Worker const char *filename)
406*61046927SAndroid Build Coastguard Worker {
407*61046927SAndroid Build Coastguard Worker if (asprintf(&db_file->path, "%s/%s", cache_path, filename) == -1)
408*61046927SAndroid Build Coastguard Worker return false;
409*61046927SAndroid Build Coastguard Worker
410*61046927SAndroid Build Coastguard Worker unlink(db_file->path);
411*61046927SAndroid Build Coastguard Worker
412*61046927SAndroid Build Coastguard Worker return true;
413*61046927SAndroid Build Coastguard Worker }
414*61046927SAndroid Build Coastguard Worker
415*61046927SAndroid Build Coastguard Worker static int
entry_sort_lru(const void * _a,const void * _b,void * arg)416*61046927SAndroid Build Coastguard Worker entry_sort_lru(const void *_a, const void *_b, void *arg)
417*61046927SAndroid Build Coastguard Worker {
418*61046927SAndroid Build Coastguard Worker const struct mesa_index_db_hash_entry *a = *((const struct mesa_index_db_hash_entry **)_a);
419*61046927SAndroid Build Coastguard Worker const struct mesa_index_db_hash_entry *b = *((const struct mesa_index_db_hash_entry **)_b);
420*61046927SAndroid Build Coastguard Worker
421*61046927SAndroid Build Coastguard Worker /* In practice it's unlikely that we will get two entries with the
422*61046927SAndroid Build Coastguard Worker * same timestamp, but technically it's possible to happen if OS
423*61046927SAndroid Build Coastguard Worker * timer's resolution is low. */
424*61046927SAndroid Build Coastguard Worker if (a->last_access_time == b->last_access_time)
425*61046927SAndroid Build Coastguard Worker return 0;
426*61046927SAndroid Build Coastguard Worker
427*61046927SAndroid Build Coastguard Worker return a->last_access_time > b->last_access_time ? 1 : -1;
428*61046927SAndroid Build Coastguard Worker }
429*61046927SAndroid Build Coastguard Worker
430*61046927SAndroid Build Coastguard Worker static int
entry_sort_offset(const void * _a,const void * _b,void * arg)431*61046927SAndroid Build Coastguard Worker entry_sort_offset(const void *_a, const void *_b, void *arg)
432*61046927SAndroid Build Coastguard Worker {
433*61046927SAndroid Build Coastguard Worker const struct mesa_index_db_hash_entry *a = *((const struct mesa_index_db_hash_entry **)_a);
434*61046927SAndroid Build Coastguard Worker const struct mesa_index_db_hash_entry *b = *((const struct mesa_index_db_hash_entry **)_b);
435*61046927SAndroid Build Coastguard Worker struct mesa_cache_db *db = arg;
436*61046927SAndroid Build Coastguard Worker
437*61046927SAndroid Build Coastguard Worker /* Two entries will never have the identical offset, otherwise DB is
438*61046927SAndroid Build Coastguard Worker * corrupted. */
439*61046927SAndroid Build Coastguard Worker if (a->cache_db_file_offset == b->cache_db_file_offset)
440*61046927SAndroid Build Coastguard Worker mesa_db_zap(db);
441*61046927SAndroid Build Coastguard Worker
442*61046927SAndroid Build Coastguard Worker return a->cache_db_file_offset > b->cache_db_file_offset ? 1 : -1;
443*61046927SAndroid Build Coastguard Worker }
444*61046927SAndroid Build Coastguard Worker
blob_file_size(uint32_t blob_size)445*61046927SAndroid Build Coastguard Worker static uint32_t blob_file_size(uint32_t blob_size)
446*61046927SAndroid Build Coastguard Worker {
447*61046927SAndroid Build Coastguard Worker return sizeof(struct mesa_cache_db_file_entry) + blob_size;
448*61046927SAndroid Build Coastguard Worker }
449*61046927SAndroid Build Coastguard Worker
450*61046927SAndroid Build Coastguard Worker static bool
mesa_db_compact(struct mesa_cache_db * db,int64_t blob_size,struct mesa_index_db_hash_entry * remove_entry)451*61046927SAndroid Build Coastguard Worker mesa_db_compact(struct mesa_cache_db *db, int64_t blob_size,
452*61046927SAndroid Build Coastguard Worker struct mesa_index_db_hash_entry *remove_entry)
453*61046927SAndroid Build Coastguard Worker {
454*61046927SAndroid Build Coastguard Worker uint32_t num_entries, buffer_size = sizeof(struct mesa_index_db_file_entry);
455*61046927SAndroid Build Coastguard Worker struct mesa_db_file_header cache_header, index_header;
456*61046927SAndroid Build Coastguard Worker FILE *compacted_cache = NULL, *compacted_index = NULL;
457*61046927SAndroid Build Coastguard Worker struct mesa_index_db_file_entry index_entry;
458*61046927SAndroid Build Coastguard Worker struct mesa_index_db_hash_entry **entries;
459*61046927SAndroid Build Coastguard Worker bool success = false, compact = false;
460*61046927SAndroid Build Coastguard Worker void *buffer = NULL;
461*61046927SAndroid Build Coastguard Worker unsigned int i = 0;
462*61046927SAndroid Build Coastguard Worker
463*61046927SAndroid Build Coastguard Worker /* reload index to sync the last access times */
464*61046927SAndroid Build Coastguard Worker if (!remove_entry && !mesa_db_reload(db))
465*61046927SAndroid Build Coastguard Worker return false;
466*61046927SAndroid Build Coastguard Worker
467*61046927SAndroid Build Coastguard Worker num_entries = _mesa_hash_table_num_entries(db->index_db->table);
468*61046927SAndroid Build Coastguard Worker entries = calloc(num_entries, sizeof(*entries));
469*61046927SAndroid Build Coastguard Worker if (!entries)
470*61046927SAndroid Build Coastguard Worker return false;
471*61046927SAndroid Build Coastguard Worker
472*61046927SAndroid Build Coastguard Worker compacted_cache = fopen(db->cache.path, "r+b");
473*61046927SAndroid Build Coastguard Worker compacted_index = fopen(db->index.path, "r+b");
474*61046927SAndroid Build Coastguard Worker if (!compacted_cache || !compacted_index)
475*61046927SAndroid Build Coastguard Worker goto cleanup;
476*61046927SAndroid Build Coastguard Worker
477*61046927SAndroid Build Coastguard Worker /* The database file has been replaced if UUID changed. We opened
478*61046927SAndroid Build Coastguard Worker * some other cache, stop processing this database. */
479*61046927SAndroid Build Coastguard Worker if (!mesa_db_read_header(compacted_cache, &cache_header) ||
480*61046927SAndroid Build Coastguard Worker !mesa_db_read_header(compacted_index, &index_header) ||
481*61046927SAndroid Build Coastguard Worker cache_header.uuid != db->uuid ||
482*61046927SAndroid Build Coastguard Worker index_header.uuid != db->uuid)
483*61046927SAndroid Build Coastguard Worker goto cleanup;
484*61046927SAndroid Build Coastguard Worker
485*61046927SAndroid Build Coastguard Worker hash_table_foreach(db->index_db->table, entry) {
486*61046927SAndroid Build Coastguard Worker entries[i] = entry->data;
487*61046927SAndroid Build Coastguard Worker entries[i]->evicted = (entries[i] == remove_entry);
488*61046927SAndroid Build Coastguard Worker buffer_size = MAX2(buffer_size, blob_file_size(entries[i]->size));
489*61046927SAndroid Build Coastguard Worker i++;
490*61046927SAndroid Build Coastguard Worker }
491*61046927SAndroid Build Coastguard Worker
492*61046927SAndroid Build Coastguard Worker util_qsort_r(entries, num_entries, sizeof(*entries),
493*61046927SAndroid Build Coastguard Worker entry_sort_lru, db);
494*61046927SAndroid Build Coastguard Worker
495*61046927SAndroid Build Coastguard Worker for (i = 0; blob_size > 0 && i < num_entries; i++) {
496*61046927SAndroid Build Coastguard Worker blob_size -= blob_file_size(entries[i]->size);
497*61046927SAndroid Build Coastguard Worker entries[i]->evicted = true;
498*61046927SAndroid Build Coastguard Worker }
499*61046927SAndroid Build Coastguard Worker
500*61046927SAndroid Build Coastguard Worker util_qsort_r(entries, num_entries, sizeof(*entries),
501*61046927SAndroid Build Coastguard Worker entry_sort_offset, db);
502*61046927SAndroid Build Coastguard Worker
503*61046927SAndroid Build Coastguard Worker /* entry_sort_offset() may zap the database */
504*61046927SAndroid Build Coastguard Worker if (!db->alive)
505*61046927SAndroid Build Coastguard Worker goto cleanup;
506*61046927SAndroid Build Coastguard Worker
507*61046927SAndroid Build Coastguard Worker buffer = malloc(buffer_size);
508*61046927SAndroid Build Coastguard Worker if (!buffer)
509*61046927SAndroid Build Coastguard Worker goto cleanup;
510*61046927SAndroid Build Coastguard Worker
511*61046927SAndroid Build Coastguard Worker /* Mark cache file invalid by writing zero-UUID header. If compaction will
512*61046927SAndroid Build Coastguard Worker * fail, then the file will remain to be invalid since we can't repair it. */
513*61046927SAndroid Build Coastguard Worker if (!mesa_db_write_header(&db->cache, 0, false) ||
514*61046927SAndroid Build Coastguard Worker !mesa_db_write_header(&db->index, 0, false))
515*61046927SAndroid Build Coastguard Worker goto cleanup;
516*61046927SAndroid Build Coastguard Worker
517*61046927SAndroid Build Coastguard Worker /* Sync the file pointers */
518*61046927SAndroid Build Coastguard Worker if (!mesa_db_seek(compacted_cache, ftell(db->cache.file)) ||
519*61046927SAndroid Build Coastguard Worker !mesa_db_seek(compacted_index, ftell(db->index.file)))
520*61046927SAndroid Build Coastguard Worker goto cleanup;
521*61046927SAndroid Build Coastguard Worker
522*61046927SAndroid Build Coastguard Worker /* Do the compaction */
523*61046927SAndroid Build Coastguard Worker for (i = 0; i < num_entries; i++) {
524*61046927SAndroid Build Coastguard Worker blob_size = blob_file_size(entries[i]->size);
525*61046927SAndroid Build Coastguard Worker
526*61046927SAndroid Build Coastguard Worker /* Sanity-check the cache-read offset */
527*61046927SAndroid Build Coastguard Worker if (ftell(db->cache.file) != entries[i]->cache_db_file_offset)
528*61046927SAndroid Build Coastguard Worker goto cleanup;
529*61046927SAndroid Build Coastguard Worker
530*61046927SAndroid Build Coastguard Worker if (entries[i]->evicted) {
531*61046927SAndroid Build Coastguard Worker /* Jump over the evicted entry */
532*61046927SAndroid Build Coastguard Worker if (!mesa_db_seek_cur(db->cache.file, blob_size) ||
533*61046927SAndroid Build Coastguard Worker !mesa_db_seek_cur(db->index.file, sizeof(index_entry)))
534*61046927SAndroid Build Coastguard Worker goto cleanup;
535*61046927SAndroid Build Coastguard Worker
536*61046927SAndroid Build Coastguard Worker compact = true;
537*61046927SAndroid Build Coastguard Worker continue;
538*61046927SAndroid Build Coastguard Worker }
539*61046927SAndroid Build Coastguard Worker
540*61046927SAndroid Build Coastguard Worker if (compact) {
541*61046927SAndroid Build Coastguard Worker /* Compact the cache file */
542*61046927SAndroid Build Coastguard Worker if (!mesa_db_read_data(db->cache.file, buffer, blob_size) ||
543*61046927SAndroid Build Coastguard Worker !mesa_db_cache_entry_valid(buffer) ||
544*61046927SAndroid Build Coastguard Worker !mesa_db_write_data(compacted_cache, buffer, blob_size))
545*61046927SAndroid Build Coastguard Worker goto cleanup;
546*61046927SAndroid Build Coastguard Worker
547*61046927SAndroid Build Coastguard Worker /* Compact the index file */
548*61046927SAndroid Build Coastguard Worker if (!mesa_db_read(db->index.file, &index_entry) ||
549*61046927SAndroid Build Coastguard Worker !mesa_db_index_entry_valid(&index_entry) ||
550*61046927SAndroid Build Coastguard Worker index_entry.cache_db_file_offset != entries[i]->cache_db_file_offset ||
551*61046927SAndroid Build Coastguard Worker index_entry.size != entries[i]->size)
552*61046927SAndroid Build Coastguard Worker goto cleanup;
553*61046927SAndroid Build Coastguard Worker
554*61046927SAndroid Build Coastguard Worker index_entry.cache_db_file_offset = ftell(compacted_cache) - blob_size;
555*61046927SAndroid Build Coastguard Worker
556*61046927SAndroid Build Coastguard Worker if (!mesa_db_write(compacted_index, &index_entry))
557*61046927SAndroid Build Coastguard Worker goto cleanup;
558*61046927SAndroid Build Coastguard Worker } else {
559*61046927SAndroid Build Coastguard Worker /* Sanity-check the cache-write offset */
560*61046927SAndroid Build Coastguard Worker if (ftell(compacted_cache) != entries[i]->cache_db_file_offset)
561*61046927SAndroid Build Coastguard Worker goto cleanup;
562*61046927SAndroid Build Coastguard Worker
563*61046927SAndroid Build Coastguard Worker /* Jump over the unchanged entry */
564*61046927SAndroid Build Coastguard Worker if (!mesa_db_seek_cur(db->index.file, sizeof(index_entry)) ||
565*61046927SAndroid Build Coastguard Worker !mesa_db_seek_cur(compacted_index, sizeof(index_entry)) ||
566*61046927SAndroid Build Coastguard Worker !mesa_db_seek_cur(db->cache.file, blob_size) ||
567*61046927SAndroid Build Coastguard Worker !mesa_db_seek_cur(compacted_cache, blob_size))
568*61046927SAndroid Build Coastguard Worker goto cleanup;
569*61046927SAndroid Build Coastguard Worker }
570*61046927SAndroid Build Coastguard Worker }
571*61046927SAndroid Build Coastguard Worker
572*61046927SAndroid Build Coastguard Worker fflush(compacted_cache);
573*61046927SAndroid Build Coastguard Worker fflush(compacted_index);
574*61046927SAndroid Build Coastguard Worker
575*61046927SAndroid Build Coastguard Worker /* Cut off the the freed space left after compaction */
576*61046927SAndroid Build Coastguard Worker if (!mesa_db_truncate(db->cache.file, ftell(compacted_cache)) ||
577*61046927SAndroid Build Coastguard Worker !mesa_db_truncate(db->index.file, ftell(compacted_index)))
578*61046927SAndroid Build Coastguard Worker goto cleanup;
579*61046927SAndroid Build Coastguard Worker
580*61046927SAndroid Build Coastguard Worker /* Set the new UUID to let all cache readers know that the cache was changed */
581*61046927SAndroid Build Coastguard Worker db->uuid = mesa_db_generate_uuid();
582*61046927SAndroid Build Coastguard Worker
583*61046927SAndroid Build Coastguard Worker if (!mesa_db_write_header(&db->cache, db->uuid, false) ||
584*61046927SAndroid Build Coastguard Worker !mesa_db_write_header(&db->index, db->uuid, false))
585*61046927SAndroid Build Coastguard Worker goto cleanup;
586*61046927SAndroid Build Coastguard Worker
587*61046927SAndroid Build Coastguard Worker success = true;
588*61046927SAndroid Build Coastguard Worker
589*61046927SAndroid Build Coastguard Worker cleanup:
590*61046927SAndroid Build Coastguard Worker free(buffer);
591*61046927SAndroid Build Coastguard Worker if (compacted_index)
592*61046927SAndroid Build Coastguard Worker fclose(compacted_index);
593*61046927SAndroid Build Coastguard Worker if (compacted_cache)
594*61046927SAndroid Build Coastguard Worker fclose(compacted_cache);
595*61046927SAndroid Build Coastguard Worker free(entries);
596*61046927SAndroid Build Coastguard Worker
597*61046927SAndroid Build Coastguard Worker /* reload compacted index */
598*61046927SAndroid Build Coastguard Worker if (success && !mesa_db_reload(db))
599*61046927SAndroid Build Coastguard Worker success = false;
600*61046927SAndroid Build Coastguard Worker
601*61046927SAndroid Build Coastguard Worker return success;
602*61046927SAndroid Build Coastguard Worker }
603*61046927SAndroid Build Coastguard Worker
604*61046927SAndroid Build Coastguard Worker bool
mesa_cache_db_open(struct mesa_cache_db * db,const char * cache_path)605*61046927SAndroid Build Coastguard Worker mesa_cache_db_open(struct mesa_cache_db *db, const char *cache_path)
606*61046927SAndroid Build Coastguard Worker {
607*61046927SAndroid Build Coastguard Worker if (!mesa_db_open_file(&db->cache, cache_path, "mesa_cache.db"))
608*61046927SAndroid Build Coastguard Worker return false;
609*61046927SAndroid Build Coastguard Worker
610*61046927SAndroid Build Coastguard Worker if (!mesa_db_open_file(&db->index, cache_path, "mesa_cache.idx"))
611*61046927SAndroid Build Coastguard Worker goto close_cache;
612*61046927SAndroid Build Coastguard Worker
613*61046927SAndroid Build Coastguard Worker db->mem_ctx = ralloc_context(NULL);
614*61046927SAndroid Build Coastguard Worker if (!db->mem_ctx)
615*61046927SAndroid Build Coastguard Worker goto close_index;
616*61046927SAndroid Build Coastguard Worker
617*61046927SAndroid Build Coastguard Worker simple_mtx_init(&db->flock_mtx, mtx_plain);
618*61046927SAndroid Build Coastguard Worker
619*61046927SAndroid Build Coastguard Worker db->index_db = _mesa_hash_table_u64_create(NULL);
620*61046927SAndroid Build Coastguard Worker if (!db->index_db)
621*61046927SAndroid Build Coastguard Worker goto destroy_mtx;
622*61046927SAndroid Build Coastguard Worker
623*61046927SAndroid Build Coastguard Worker if (!mesa_db_load(db, false))
624*61046927SAndroid Build Coastguard Worker goto destroy_hash;
625*61046927SAndroid Build Coastguard Worker
626*61046927SAndroid Build Coastguard Worker return true;
627*61046927SAndroid Build Coastguard Worker
628*61046927SAndroid Build Coastguard Worker destroy_hash:
629*61046927SAndroid Build Coastguard Worker _mesa_hash_table_u64_destroy(db->index_db);
630*61046927SAndroid Build Coastguard Worker destroy_mtx:
631*61046927SAndroid Build Coastguard Worker simple_mtx_destroy(&db->flock_mtx);
632*61046927SAndroid Build Coastguard Worker
633*61046927SAndroid Build Coastguard Worker ralloc_free(db->mem_ctx);
634*61046927SAndroid Build Coastguard Worker close_index:
635*61046927SAndroid Build Coastguard Worker mesa_db_close_file(&db->index);
636*61046927SAndroid Build Coastguard Worker close_cache:
637*61046927SAndroid Build Coastguard Worker mesa_db_close_file(&db->cache);
638*61046927SAndroid Build Coastguard Worker
639*61046927SAndroid Build Coastguard Worker return false;
640*61046927SAndroid Build Coastguard Worker }
641*61046927SAndroid Build Coastguard Worker
642*61046927SAndroid Build Coastguard Worker bool
mesa_db_wipe_path(const char * cache_path)643*61046927SAndroid Build Coastguard Worker mesa_db_wipe_path(const char *cache_path)
644*61046927SAndroid Build Coastguard Worker {
645*61046927SAndroid Build Coastguard Worker struct mesa_cache_db db = {0};
646*61046927SAndroid Build Coastguard Worker bool success = true;
647*61046927SAndroid Build Coastguard Worker
648*61046927SAndroid Build Coastguard Worker if (!mesa_db_remove_file(&db.cache, cache_path, "mesa_cache.db") ||
649*61046927SAndroid Build Coastguard Worker !mesa_db_remove_file(&db.index, cache_path, "mesa_cache.idx"))
650*61046927SAndroid Build Coastguard Worker success = false;
651*61046927SAndroid Build Coastguard Worker
652*61046927SAndroid Build Coastguard Worker free(db.cache.path);
653*61046927SAndroid Build Coastguard Worker free(db.index.path);
654*61046927SAndroid Build Coastguard Worker
655*61046927SAndroid Build Coastguard Worker return success;
656*61046927SAndroid Build Coastguard Worker }
657*61046927SAndroid Build Coastguard Worker
658*61046927SAndroid Build Coastguard Worker void
mesa_cache_db_close(struct mesa_cache_db * db)659*61046927SAndroid Build Coastguard Worker mesa_cache_db_close(struct mesa_cache_db *db)
660*61046927SAndroid Build Coastguard Worker {
661*61046927SAndroid Build Coastguard Worker _mesa_hash_table_u64_destroy(db->index_db);
662*61046927SAndroid Build Coastguard Worker simple_mtx_destroy(&db->flock_mtx);
663*61046927SAndroid Build Coastguard Worker ralloc_free(db->mem_ctx);
664*61046927SAndroid Build Coastguard Worker
665*61046927SAndroid Build Coastguard Worker mesa_db_close_file(&db->index);
666*61046927SAndroid Build Coastguard Worker mesa_db_close_file(&db->cache);
667*61046927SAndroid Build Coastguard Worker }
668*61046927SAndroid Build Coastguard Worker
669*61046927SAndroid Build Coastguard Worker void
mesa_cache_db_set_size_limit(struct mesa_cache_db * db,uint64_t max_cache_size)670*61046927SAndroid Build Coastguard Worker mesa_cache_db_set_size_limit(struct mesa_cache_db *db,
671*61046927SAndroid Build Coastguard Worker uint64_t max_cache_size)
672*61046927SAndroid Build Coastguard Worker {
673*61046927SAndroid Build Coastguard Worker db->max_cache_size = max_cache_size;
674*61046927SAndroid Build Coastguard Worker }
675*61046927SAndroid Build Coastguard Worker
676*61046927SAndroid Build Coastguard Worker unsigned int
mesa_cache_db_file_entry_size(void)677*61046927SAndroid Build Coastguard Worker mesa_cache_db_file_entry_size(void)
678*61046927SAndroid Build Coastguard Worker {
679*61046927SAndroid Build Coastguard Worker return sizeof(struct mesa_cache_db_file_entry);
680*61046927SAndroid Build Coastguard Worker }
681*61046927SAndroid Build Coastguard Worker
682*61046927SAndroid Build Coastguard Worker void *
mesa_cache_db_read_entry(struct mesa_cache_db * db,const uint8_t * cache_key_160bit,size_t * size)683*61046927SAndroid Build Coastguard Worker mesa_cache_db_read_entry(struct mesa_cache_db *db,
684*61046927SAndroid Build Coastguard Worker const uint8_t *cache_key_160bit,
685*61046927SAndroid Build Coastguard Worker size_t *size)
686*61046927SAndroid Build Coastguard Worker {
687*61046927SAndroid Build Coastguard Worker uint64_t hash = to_mesa_cache_db_hash(cache_key_160bit);
688*61046927SAndroid Build Coastguard Worker struct mesa_cache_db_file_entry cache_entry;
689*61046927SAndroid Build Coastguard Worker struct mesa_index_db_file_entry index_entry;
690*61046927SAndroid Build Coastguard Worker struct mesa_index_db_hash_entry *hash_entry;
691*61046927SAndroid Build Coastguard Worker void *data = NULL;
692*61046927SAndroid Build Coastguard Worker
693*61046927SAndroid Build Coastguard Worker if (!mesa_db_lock(db))
694*61046927SAndroid Build Coastguard Worker return NULL;
695*61046927SAndroid Build Coastguard Worker
696*61046927SAndroid Build Coastguard Worker if (!db->alive)
697*61046927SAndroid Build Coastguard Worker goto fail;
698*61046927SAndroid Build Coastguard Worker
699*61046927SAndroid Build Coastguard Worker if (mesa_db_uuid_changed(db) && !mesa_db_reload(db))
700*61046927SAndroid Build Coastguard Worker goto fail_fatal;
701*61046927SAndroid Build Coastguard Worker
702*61046927SAndroid Build Coastguard Worker if (!mesa_db_update_index(db))
703*61046927SAndroid Build Coastguard Worker goto fail_fatal;
704*61046927SAndroid Build Coastguard Worker
705*61046927SAndroid Build Coastguard Worker hash_entry = _mesa_hash_table_u64_search(db->index_db, hash);
706*61046927SAndroid Build Coastguard Worker if (!hash_entry)
707*61046927SAndroid Build Coastguard Worker goto fail;
708*61046927SAndroid Build Coastguard Worker
709*61046927SAndroid Build Coastguard Worker if (!mesa_db_seek(db->cache.file, hash_entry->cache_db_file_offset) ||
710*61046927SAndroid Build Coastguard Worker !mesa_db_read(db->cache.file, &cache_entry) ||
711*61046927SAndroid Build Coastguard Worker !mesa_db_cache_entry_valid(&cache_entry))
712*61046927SAndroid Build Coastguard Worker goto fail_fatal;
713*61046927SAndroid Build Coastguard Worker
714*61046927SAndroid Build Coastguard Worker if (memcmp(cache_entry.key, cache_key_160bit, sizeof(cache_entry.key)))
715*61046927SAndroid Build Coastguard Worker goto fail;
716*61046927SAndroid Build Coastguard Worker
717*61046927SAndroid Build Coastguard Worker data = malloc(cache_entry.size);
718*61046927SAndroid Build Coastguard Worker if (!data)
719*61046927SAndroid Build Coastguard Worker goto fail;
720*61046927SAndroid Build Coastguard Worker
721*61046927SAndroid Build Coastguard Worker if (!mesa_db_read_data(db->cache.file, data, cache_entry.size) ||
722*61046927SAndroid Build Coastguard Worker util_hash_crc32(data, cache_entry.size) != cache_entry.crc)
723*61046927SAndroid Build Coastguard Worker goto fail_fatal;
724*61046927SAndroid Build Coastguard Worker
725*61046927SAndroid Build Coastguard Worker if (!mesa_db_seek(db->index.file, hash_entry->index_db_file_offset) ||
726*61046927SAndroid Build Coastguard Worker !mesa_db_read(db->index.file, &index_entry) ||
727*61046927SAndroid Build Coastguard Worker !mesa_db_index_entry_valid(&index_entry) ||
728*61046927SAndroid Build Coastguard Worker index_entry.cache_db_file_offset != hash_entry->cache_db_file_offset ||
729*61046927SAndroid Build Coastguard Worker index_entry.size != hash_entry->size)
730*61046927SAndroid Build Coastguard Worker goto fail_fatal;
731*61046927SAndroid Build Coastguard Worker
732*61046927SAndroid Build Coastguard Worker index_entry.last_access_time = os_time_get_nano();
733*61046927SAndroid Build Coastguard Worker hash_entry->last_access_time = index_entry.last_access_time;
734*61046927SAndroid Build Coastguard Worker
735*61046927SAndroid Build Coastguard Worker if (!mesa_db_seek(db->index.file, hash_entry->index_db_file_offset) ||
736*61046927SAndroid Build Coastguard Worker !mesa_db_write(db->index.file, &index_entry))
737*61046927SAndroid Build Coastguard Worker goto fail_fatal;
738*61046927SAndroid Build Coastguard Worker
739*61046927SAndroid Build Coastguard Worker fflush(db->index.file);
740*61046927SAndroid Build Coastguard Worker
741*61046927SAndroid Build Coastguard Worker mesa_db_unlock(db);
742*61046927SAndroid Build Coastguard Worker
743*61046927SAndroid Build Coastguard Worker *size = cache_entry.size;
744*61046927SAndroid Build Coastguard Worker
745*61046927SAndroid Build Coastguard Worker return data;
746*61046927SAndroid Build Coastguard Worker
747*61046927SAndroid Build Coastguard Worker fail_fatal:
748*61046927SAndroid Build Coastguard Worker mesa_db_zap(db);
749*61046927SAndroid Build Coastguard Worker fail:
750*61046927SAndroid Build Coastguard Worker free(data);
751*61046927SAndroid Build Coastguard Worker
752*61046927SAndroid Build Coastguard Worker mesa_db_unlock(db);
753*61046927SAndroid Build Coastguard Worker
754*61046927SAndroid Build Coastguard Worker return NULL;
755*61046927SAndroid Build Coastguard Worker }
756*61046927SAndroid Build Coastguard Worker
757*61046927SAndroid Build Coastguard Worker static bool
mesa_cache_db_has_space_locked(struct mesa_cache_db * db,size_t blob_size)758*61046927SAndroid Build Coastguard Worker mesa_cache_db_has_space_locked(struct mesa_cache_db *db, size_t blob_size)
759*61046927SAndroid Build Coastguard Worker {
760*61046927SAndroid Build Coastguard Worker return ftell(db->cache.file) + blob_file_size(blob_size) -
761*61046927SAndroid Build Coastguard Worker sizeof(struct mesa_db_file_header) <= db->max_cache_size;
762*61046927SAndroid Build Coastguard Worker }
763*61046927SAndroid Build Coastguard Worker
764*61046927SAndroid Build Coastguard Worker static size_t
mesa_cache_db_eviction_size(struct mesa_cache_db * db)765*61046927SAndroid Build Coastguard Worker mesa_cache_db_eviction_size(struct mesa_cache_db *db)
766*61046927SAndroid Build Coastguard Worker {
767*61046927SAndroid Build Coastguard Worker return db->max_cache_size / 2 - sizeof(struct mesa_db_file_header);
768*61046927SAndroid Build Coastguard Worker }
769*61046927SAndroid Build Coastguard Worker
770*61046927SAndroid Build Coastguard Worker bool
mesa_cache_db_entry_write(struct mesa_cache_db * db,const uint8_t * cache_key_160bit,const void * blob,size_t blob_size)771*61046927SAndroid Build Coastguard Worker mesa_cache_db_entry_write(struct mesa_cache_db *db,
772*61046927SAndroid Build Coastguard Worker const uint8_t *cache_key_160bit,
773*61046927SAndroid Build Coastguard Worker const void *blob, size_t blob_size)
774*61046927SAndroid Build Coastguard Worker {
775*61046927SAndroid Build Coastguard Worker uint64_t hash = to_mesa_cache_db_hash(cache_key_160bit);
776*61046927SAndroid Build Coastguard Worker struct mesa_index_db_hash_entry *hash_entry = NULL;
777*61046927SAndroid Build Coastguard Worker struct mesa_cache_db_file_entry cache_entry;
778*61046927SAndroid Build Coastguard Worker struct mesa_index_db_file_entry index_entry;
779*61046927SAndroid Build Coastguard Worker
780*61046927SAndroid Build Coastguard Worker if (!mesa_db_lock(db))
781*61046927SAndroid Build Coastguard Worker return false;
782*61046927SAndroid Build Coastguard Worker
783*61046927SAndroid Build Coastguard Worker if (!db->alive)
784*61046927SAndroid Build Coastguard Worker goto fail;
785*61046927SAndroid Build Coastguard Worker
786*61046927SAndroid Build Coastguard Worker if (mesa_db_uuid_changed(db) && !mesa_db_reload(db))
787*61046927SAndroid Build Coastguard Worker goto fail_fatal;
788*61046927SAndroid Build Coastguard Worker
789*61046927SAndroid Build Coastguard Worker if (!mesa_db_seek_end(db->cache.file))
790*61046927SAndroid Build Coastguard Worker goto fail_fatal;
791*61046927SAndroid Build Coastguard Worker
792*61046927SAndroid Build Coastguard Worker if (!mesa_cache_db_has_space_locked(db, blob_size)) {
793*61046927SAndroid Build Coastguard Worker if (!mesa_db_compact(db, MAX2(blob_size, mesa_cache_db_eviction_size(db)),
794*61046927SAndroid Build Coastguard Worker NULL))
795*61046927SAndroid Build Coastguard Worker goto fail_fatal;
796*61046927SAndroid Build Coastguard Worker } else {
797*61046927SAndroid Build Coastguard Worker if (!mesa_db_update_index(db))
798*61046927SAndroid Build Coastguard Worker goto fail_fatal;
799*61046927SAndroid Build Coastguard Worker }
800*61046927SAndroid Build Coastguard Worker
801*61046927SAndroid Build Coastguard Worker hash_entry = _mesa_hash_table_u64_search(db->index_db, hash);
802*61046927SAndroid Build Coastguard Worker if (hash_entry) {
803*61046927SAndroid Build Coastguard Worker hash_entry = NULL;
804*61046927SAndroid Build Coastguard Worker goto fail;
805*61046927SAndroid Build Coastguard Worker }
806*61046927SAndroid Build Coastguard Worker
807*61046927SAndroid Build Coastguard Worker if (!mesa_db_seek_end(db->cache.file) ||
808*61046927SAndroid Build Coastguard Worker !mesa_db_seek_end(db->index.file))
809*61046927SAndroid Build Coastguard Worker goto fail_fatal;
810*61046927SAndroid Build Coastguard Worker
811*61046927SAndroid Build Coastguard Worker memcpy(cache_entry.key, cache_key_160bit, sizeof(cache_entry.key));
812*61046927SAndroid Build Coastguard Worker cache_entry.crc = util_hash_crc32(blob, blob_size);
813*61046927SAndroid Build Coastguard Worker cache_entry.size = blob_size;
814*61046927SAndroid Build Coastguard Worker
815*61046927SAndroid Build Coastguard Worker index_entry.hash = hash;
816*61046927SAndroid Build Coastguard Worker index_entry.size = blob_size;
817*61046927SAndroid Build Coastguard Worker index_entry.last_access_time = os_time_get_nano();
818*61046927SAndroid Build Coastguard Worker index_entry.cache_db_file_offset = ftell(db->cache.file);
819*61046927SAndroid Build Coastguard Worker
820*61046927SAndroid Build Coastguard Worker hash_entry = ralloc(db->mem_ctx, struct mesa_index_db_hash_entry);
821*61046927SAndroid Build Coastguard Worker if (!hash_entry)
822*61046927SAndroid Build Coastguard Worker goto fail;
823*61046927SAndroid Build Coastguard Worker
824*61046927SAndroid Build Coastguard Worker hash_entry->cache_db_file_offset = index_entry.cache_db_file_offset;
825*61046927SAndroid Build Coastguard Worker hash_entry->index_db_file_offset = ftell(db->index.file);
826*61046927SAndroid Build Coastguard Worker hash_entry->last_access_time = index_entry.last_access_time;
827*61046927SAndroid Build Coastguard Worker hash_entry->size = index_entry.size;
828*61046927SAndroid Build Coastguard Worker
829*61046927SAndroid Build Coastguard Worker if (!mesa_db_write(db->cache.file, &cache_entry) ||
830*61046927SAndroid Build Coastguard Worker !mesa_db_write_data(db->cache.file, blob, blob_size) ||
831*61046927SAndroid Build Coastguard Worker !mesa_db_write(db->index.file, &index_entry))
832*61046927SAndroid Build Coastguard Worker goto fail_fatal;
833*61046927SAndroid Build Coastguard Worker
834*61046927SAndroid Build Coastguard Worker fflush(db->cache.file);
835*61046927SAndroid Build Coastguard Worker fflush(db->index.file);
836*61046927SAndroid Build Coastguard Worker
837*61046927SAndroid Build Coastguard Worker db->index.offset = ftell(db->index.file);
838*61046927SAndroid Build Coastguard Worker
839*61046927SAndroid Build Coastguard Worker _mesa_hash_table_u64_insert(db->index_db, hash, hash_entry);
840*61046927SAndroid Build Coastguard Worker
841*61046927SAndroid Build Coastguard Worker mesa_db_unlock(db);
842*61046927SAndroid Build Coastguard Worker
843*61046927SAndroid Build Coastguard Worker return true;
844*61046927SAndroid Build Coastguard Worker
845*61046927SAndroid Build Coastguard Worker fail_fatal:
846*61046927SAndroid Build Coastguard Worker mesa_db_zap(db);
847*61046927SAndroid Build Coastguard Worker fail:
848*61046927SAndroid Build Coastguard Worker mesa_db_unlock(db);
849*61046927SAndroid Build Coastguard Worker
850*61046927SAndroid Build Coastguard Worker if (hash_entry)
851*61046927SAndroid Build Coastguard Worker ralloc_free(hash_entry);
852*61046927SAndroid Build Coastguard Worker
853*61046927SAndroid Build Coastguard Worker return false;
854*61046927SAndroid Build Coastguard Worker }
855*61046927SAndroid Build Coastguard Worker
856*61046927SAndroid Build Coastguard Worker bool
mesa_cache_db_entry_remove(struct mesa_cache_db * db,const uint8_t * cache_key_160bit)857*61046927SAndroid Build Coastguard Worker mesa_cache_db_entry_remove(struct mesa_cache_db *db,
858*61046927SAndroid Build Coastguard Worker const uint8_t *cache_key_160bit)
859*61046927SAndroid Build Coastguard Worker {
860*61046927SAndroid Build Coastguard Worker uint64_t hash = to_mesa_cache_db_hash(cache_key_160bit);
861*61046927SAndroid Build Coastguard Worker struct mesa_cache_db_file_entry cache_entry;
862*61046927SAndroid Build Coastguard Worker struct mesa_index_db_hash_entry *hash_entry;
863*61046927SAndroid Build Coastguard Worker
864*61046927SAndroid Build Coastguard Worker if (!mesa_db_lock(db))
865*61046927SAndroid Build Coastguard Worker return NULL;
866*61046927SAndroid Build Coastguard Worker
867*61046927SAndroid Build Coastguard Worker if (!db->alive)
868*61046927SAndroid Build Coastguard Worker goto fail;
869*61046927SAndroid Build Coastguard Worker
870*61046927SAndroid Build Coastguard Worker if (mesa_db_uuid_changed(db) && !mesa_db_reload(db))
871*61046927SAndroid Build Coastguard Worker goto fail_fatal;
872*61046927SAndroid Build Coastguard Worker
873*61046927SAndroid Build Coastguard Worker if (!mesa_db_update_index(db))
874*61046927SAndroid Build Coastguard Worker goto fail_fatal;
875*61046927SAndroid Build Coastguard Worker
876*61046927SAndroid Build Coastguard Worker hash_entry = _mesa_hash_table_u64_search(db->index_db, hash);
877*61046927SAndroid Build Coastguard Worker if (!hash_entry)
878*61046927SAndroid Build Coastguard Worker goto fail;
879*61046927SAndroid Build Coastguard Worker
880*61046927SAndroid Build Coastguard Worker if (!mesa_db_seek(db->cache.file, hash_entry->cache_db_file_offset) ||
881*61046927SAndroid Build Coastguard Worker !mesa_db_read(db->cache.file, &cache_entry) ||
882*61046927SAndroid Build Coastguard Worker !mesa_db_cache_entry_valid(&cache_entry))
883*61046927SAndroid Build Coastguard Worker goto fail_fatal;
884*61046927SAndroid Build Coastguard Worker
885*61046927SAndroid Build Coastguard Worker if (memcmp(cache_entry.key, cache_key_160bit, sizeof(cache_entry.key)))
886*61046927SAndroid Build Coastguard Worker goto fail;
887*61046927SAndroid Build Coastguard Worker
888*61046927SAndroid Build Coastguard Worker if (!mesa_db_compact(db, 0, hash_entry))
889*61046927SAndroid Build Coastguard Worker goto fail_fatal;
890*61046927SAndroid Build Coastguard Worker
891*61046927SAndroid Build Coastguard Worker mesa_db_unlock(db);
892*61046927SAndroid Build Coastguard Worker
893*61046927SAndroid Build Coastguard Worker return true;
894*61046927SAndroid Build Coastguard Worker
895*61046927SAndroid Build Coastguard Worker fail_fatal:
896*61046927SAndroid Build Coastguard Worker mesa_db_zap(db);
897*61046927SAndroid Build Coastguard Worker fail:
898*61046927SAndroid Build Coastguard Worker mesa_db_unlock(db);
899*61046927SAndroid Build Coastguard Worker
900*61046927SAndroid Build Coastguard Worker return false;
901*61046927SAndroid Build Coastguard Worker }
902*61046927SAndroid Build Coastguard Worker
903*61046927SAndroid Build Coastguard Worker bool
mesa_cache_db_has_space(struct mesa_cache_db * db,size_t blob_size)904*61046927SAndroid Build Coastguard Worker mesa_cache_db_has_space(struct mesa_cache_db *db, size_t blob_size)
905*61046927SAndroid Build Coastguard Worker {
906*61046927SAndroid Build Coastguard Worker bool has_space;
907*61046927SAndroid Build Coastguard Worker
908*61046927SAndroid Build Coastguard Worker if (!mesa_db_lock(db))
909*61046927SAndroid Build Coastguard Worker return false;
910*61046927SAndroid Build Coastguard Worker
911*61046927SAndroid Build Coastguard Worker if (!mesa_db_seek_end(db->cache.file))
912*61046927SAndroid Build Coastguard Worker goto fail_fatal;
913*61046927SAndroid Build Coastguard Worker
914*61046927SAndroid Build Coastguard Worker has_space = mesa_cache_db_has_space_locked(db, blob_size);
915*61046927SAndroid Build Coastguard Worker
916*61046927SAndroid Build Coastguard Worker mesa_db_unlock(db);
917*61046927SAndroid Build Coastguard Worker
918*61046927SAndroid Build Coastguard Worker return has_space;
919*61046927SAndroid Build Coastguard Worker
920*61046927SAndroid Build Coastguard Worker fail_fatal:
921*61046927SAndroid Build Coastguard Worker mesa_db_zap(db);
922*61046927SAndroid Build Coastguard Worker mesa_db_unlock(db);
923*61046927SAndroid Build Coastguard Worker
924*61046927SAndroid Build Coastguard Worker return false;
925*61046927SAndroid Build Coastguard Worker }
926*61046927SAndroid Build Coastguard Worker
927*61046927SAndroid Build Coastguard Worker static uint64_t
mesa_cache_db_eviction_2x_score_period(void)928*61046927SAndroid Build Coastguard Worker mesa_cache_db_eviction_2x_score_period(void)
929*61046927SAndroid Build Coastguard Worker {
930*61046927SAndroid Build Coastguard Worker const uint64_t nsec_per_sec = 1000000000ull;
931*61046927SAndroid Build Coastguard Worker static uint64_t period = 0;
932*61046927SAndroid Build Coastguard Worker
933*61046927SAndroid Build Coastguard Worker if (period)
934*61046927SAndroid Build Coastguard Worker return period;
935*61046927SAndroid Build Coastguard Worker
936*61046927SAndroid Build Coastguard Worker period = debug_get_num_option("MESA_DISK_CACHE_DATABASE_EVICTION_SCORE_2X_PERIOD",
937*61046927SAndroid Build Coastguard Worker 30 * 24 * 60 * 60) * nsec_per_sec;
938*61046927SAndroid Build Coastguard Worker
939*61046927SAndroid Build Coastguard Worker return period;
940*61046927SAndroid Build Coastguard Worker }
941*61046927SAndroid Build Coastguard Worker
942*61046927SAndroid Build Coastguard Worker double
mesa_cache_db_eviction_score(struct mesa_cache_db * db)943*61046927SAndroid Build Coastguard Worker mesa_cache_db_eviction_score(struct mesa_cache_db *db)
944*61046927SAndroid Build Coastguard Worker {
945*61046927SAndroid Build Coastguard Worker int64_t eviction_size = mesa_cache_db_eviction_size(db);
946*61046927SAndroid Build Coastguard Worker struct mesa_index_db_hash_entry **entries;
947*61046927SAndroid Build Coastguard Worker unsigned num_entries, i = 0;
948*61046927SAndroid Build Coastguard Worker double eviction_score = 0;
949*61046927SAndroid Build Coastguard Worker
950*61046927SAndroid Build Coastguard Worker if (!mesa_db_lock(db))
951*61046927SAndroid Build Coastguard Worker return 0;
952*61046927SAndroid Build Coastguard Worker
953*61046927SAndroid Build Coastguard Worker if (!db->alive)
954*61046927SAndroid Build Coastguard Worker goto fail;
955*61046927SAndroid Build Coastguard Worker
956*61046927SAndroid Build Coastguard Worker if (!mesa_db_reload(db))
957*61046927SAndroid Build Coastguard Worker goto fail_fatal;
958*61046927SAndroid Build Coastguard Worker
959*61046927SAndroid Build Coastguard Worker num_entries = _mesa_hash_table_num_entries(db->index_db->table);
960*61046927SAndroid Build Coastguard Worker entries = calloc(num_entries, sizeof(*entries));
961*61046927SAndroid Build Coastguard Worker if (!entries)
962*61046927SAndroid Build Coastguard Worker goto fail;
963*61046927SAndroid Build Coastguard Worker
964*61046927SAndroid Build Coastguard Worker hash_table_foreach(db->index_db->table, entry)
965*61046927SAndroid Build Coastguard Worker entries[i++] = entry->data;
966*61046927SAndroid Build Coastguard Worker
967*61046927SAndroid Build Coastguard Worker util_qsort_r(entries, num_entries, sizeof(*entries),
968*61046927SAndroid Build Coastguard Worker entry_sort_lru, db);
969*61046927SAndroid Build Coastguard Worker
970*61046927SAndroid Build Coastguard Worker for (i = 0; eviction_size > 0 && i < num_entries; i++) {
971*61046927SAndroid Build Coastguard Worker uint64_t entry_age = os_time_get_nano() - entries[i]->last_access_time;
972*61046927SAndroid Build Coastguard Worker unsigned entry_size = blob_file_size(entries[i]->size);
973*61046927SAndroid Build Coastguard Worker
974*61046927SAndroid Build Coastguard Worker /* Eviction score is a sum of weighted cache entry sizes,
975*61046927SAndroid Build Coastguard Worker * where weight doubles for each month of entry's age.
976*61046927SAndroid Build Coastguard Worker */
977*61046927SAndroid Build Coastguard Worker uint64_t period = mesa_cache_db_eviction_2x_score_period();
978*61046927SAndroid Build Coastguard Worker double entry_scale = 1 + (double)entry_age / period;
979*61046927SAndroid Build Coastguard Worker double entry_score = entry_size * entry_scale;
980*61046927SAndroid Build Coastguard Worker
981*61046927SAndroid Build Coastguard Worker eviction_score += entry_score;
982*61046927SAndroid Build Coastguard Worker eviction_size -= entry_size;
983*61046927SAndroid Build Coastguard Worker }
984*61046927SAndroid Build Coastguard Worker
985*61046927SAndroid Build Coastguard Worker free(entries);
986*61046927SAndroid Build Coastguard Worker
987*61046927SAndroid Build Coastguard Worker mesa_db_unlock(db);
988*61046927SAndroid Build Coastguard Worker
989*61046927SAndroid Build Coastguard Worker return eviction_score;
990*61046927SAndroid Build Coastguard Worker
991*61046927SAndroid Build Coastguard Worker fail_fatal:
992*61046927SAndroid Build Coastguard Worker mesa_db_zap(db);
993*61046927SAndroid Build Coastguard Worker fail:
994*61046927SAndroid Build Coastguard Worker mesa_db_unlock(db);
995*61046927SAndroid Build Coastguard Worker
996*61046927SAndroid Build Coastguard Worker return 0;
997*61046927SAndroid Build Coastguard Worker }
998*61046927SAndroid Build Coastguard Worker
999*61046927SAndroid Build Coastguard Worker #endif /* DETECT_OS_WINDOWS */
1000