This can be used to deal with key hash collisions from different
versions (should we find that to actually happen) and to find
which mesa version produced the cache entry.
---

 I considered creating the cache key blob at cache creation time but since
 we would want a blob with the null terminator dropped for the hash and one
 that includes the terminator for reading the strings from the header, I
 decided just to create it on the fly to keep the code easier to follow.  

 src/util/disk_cache.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 85 insertions(+), 6 deletions(-)

diff --git a/src/util/disk_cache.c b/src/util/disk_cache.c
index 599e58f..f2d67c9 100644
--- a/src/util/disk_cache.c
+++ b/src/util/disk_cache.c
@@ -737,33 +737,60 @@ create_put_job(struct disk_cache *cache, const cache_key 
key,
 }
 
 static void
 destroy_put_job(void *job, int thread_index)
 {
    if (job) {
       free(job);
    }
 }
 
+static size_t
+cache_keys_size(struct disk_cache *cache)
+{
+   /* The 2 is for the terminating null bytes of the strings */
+   return cache->timestamp_size + cache->gpu_name_size +
+      sizeof(cache->ptr_size) + 2;
+}
+
+static uint8_t *
+generate_cache_keys_blob(struct disk_cache *cache, size_t ck_size)
+{
+   uint8_t *key_blob = malloc(ck_size);
+   if (!key_blob)
+      return NULL;
+
+   size_t ts_size = cache->timestamp_size + 1;
+   memcpy(key_blob, cache->timestamp, ts_size);
+
+   size_t gn_size = cache->gpu_name_size + 1;
+   memcpy(key_blob + ts_size, cache->gpu_name, gn_size);
+
+   memcpy(key_blob + ts_size + gn_size, &cache->ptr_size, sizeof(uint8_t));
+
+   return key_blob;
+}
+
 struct cache_entry_file_data {
    uint32_t crc32;
    uint32_t uncompressed_size;
 };
 
 static void
 cache_put(void *job, int thread_index)
 {
    assert(job);
 
    int fd = -1, fd_final = -1, err, ret;
    unsigned i = 0;
    char *filename = NULL, *filename_tmp = NULL;
+   uint8_t *key_blob = NULL;
    struct disk_cache_put_job *dc_job = (struct disk_cache_put_job *) job;
 
    filename = get_cache_file(dc_job->cache, dc_job->key);
    if (filename == NULL)
       goto done;
 
    /* If the cache is too large, evict something else first. */
    while (*dc_job->cache->size + dc_job->size > dc_job->cache->max_size &&
           i < 8) {
       evict_lru_item(dc_job->cache);
@@ -808,23 +835,41 @@ cache_put(void *job, int thread_index)
     */
    fd_final = open(filename, O_RDONLY | O_CLOEXEC);
    if (fd_final != -1) {
       unlink(filename_tmp);
       goto done;
    }
 
    /* OK, we're now on the hook to write out a file that we know is
     * not in the cache, and is also not being written out to the cache
     * by some other process.
-    *
-    * Create CRC of the data and store at the start of the file. We will
-    * read this when restoring the cache and use it to check for corruption.
+    */
+
+   /* Write the key_blob, this can be used find information about the
+    * mesa version that produced the entry or deal with hash collisions,
+    * should that ever become a real problem.
+    */
+   size_t ck_size = cache_keys_size(dc_job->cache);
+   key_blob = generate_cache_keys_blob(dc_job->cache, ck_size);
+   if (!key_blob) {
+      unlink(filename_tmp);
+      goto done;
+   }
+
+   ret = write_all(fd, key_blob, ck_size);
+   if (ret == -1) {
+      unlink(filename_tmp);
+      goto done;
+   }
+
+   /* Create CRC of the data. We will read this when restoring the cache and
+    * use it to check for corruption.
     */
    struct cache_entry_file_data cf_data;
    cf_data.crc32 = util_hash_crc32(dc_job->data, dc_job->size);
    cf_data.uncompressed_size = dc_job->size;
 
    size_t cf_data_size = sizeof(cf_data);
    ret = write_all(fd, &cf_data, cf_data_size);
    if (ret == -1) {
       unlink(filename_tmp);
       goto done;
@@ -839,35 +884,37 @@ cache_put(void *job, int thread_index)
    if (file_size == 0) {
       unlink(filename_tmp);
       goto done;
    }
    ret = rename(filename_tmp, filename);
    if (ret == -1) {
       unlink(filename_tmp);
       goto done;
    }
 
-   file_size += cf_data_size;
+   file_size += cf_data_size + ck_size;
    p_atomic_add(dc_job->cache->size, file_size);
 
  done:
    if (fd_final != -1)
       close(fd_final);
    /* This close finally releases the flock, (now that the final file
     * has been renamed into place and the size has been added).
     */
    if (fd != -1)
       close(fd);
    if (filename_tmp)
       free(filename_tmp);
    if (filename)
       free(filename);
+   if (key_blob)
+      free(key_blob);
 }
 
 void
 disk_cache_put(struct disk_cache *cache, const cache_key key,
                const void *data, size_t size)
 {
    struct disk_cache_put_job *dc_job =
       create_put_job(cache, key, data, size);
 
    if (dc_job) {
@@ -936,32 +983,64 @@ disk_cache_get(struct disk_cache *cache, const cache_key 
key, size_t *size)
    if (fd == -1)
       goto fail;
 
    if (fstat(fd, &sb) == -1)
       goto fail;
 
    data = malloc(sb.st_size);
    if (data == NULL)
       goto fail;
 
+   size_t ck_size = cache_keys_size(cache);
+#ifndef NDEBUG
+   uint8_t *file_header = malloc(ck_size);
+   if (!file_header)
+      goto fail;
+
+   assert(sb.st_size > ck_size);
+   for (len = 0; len < ck_size; len += ret) {
+      ret = read(fd, ((uint8_t *) file_header) + len, ck_size - len);
+      if (ret == -1) {
+         free(file_header);
+         goto fail;
+      }
+   }
+
+   uint8_t *key_blob = generate_cache_keys_blob(cache, ck_size);
+   if (!key_blob) {
+      free(file_header);
+      goto fail;
+   }
+   assert(memcmp(key_blob, file_header, ck_size) == 0);
+
+   free(file_header);
+   free(key_blob);
+#else
+   /* The cache keys are currently just used for distributing precompiled
+    * shaders, they are not used by Mesa so just skip them for now.
+    */
+   ret = lseek(fd, ck_size, SEEK_CUR);
+   if (ret == -1)
+      goto fail;
+#endif
+
    /* Load the CRC that was created when the file was written. */
    struct cache_entry_file_data cf_data;
    size_t cf_data_size = sizeof(cf_data);
-   assert(sb.st_size > cf_data_size);
    for (len = 0; len < cf_data_size; len += ret) {
       ret = read(fd, ((uint8_t *) &cf_data) + len, cf_data_size - len);
       if (ret == -1)
          goto fail;
    }
 
    /* Load the actual cache data. */
-   size_t cache_data_size = sb.st_size - cf_data_size;
+   size_t cache_data_size = sb.st_size - cf_data_size - ck_size;
    for (len = 0; len < cache_data_size; len += ret) {
       ret = read(fd, data + len, cache_data_size - len);
       if (ret == -1)
          goto fail;
    }
 
    /* Uncompress the cache data */
    uncompressed_data = malloc(cf_data.uncompressed_size);
    if (!inflate_cache_data(data, cache_data_size, uncompressed_data,
                            cf_data.uncompressed_size))
-- 
2.9.3

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to