aboutsummaryrefslogtreecommitdiffstats
path: root/src/util/disk_cache.c
diff options
context:
space:
mode:
authorTimothy Arceri <tarceri@itsqueeze.com>2020-08-05 13:35:39 +1000
committerMarge Bot <eric+marge@anholt.net>2020-09-11 06:03:58 +0000
commitb4a3a80403e6cfe428c17257dc6ba85f1bdbfa02 (patch)
treefdf191c4b2bfdabe2ab50ac508c565a080502e3f /src/util/disk_cache.c
parente1236470dc6e3f52380b6c97a3fdfb74119624b9 (diff)
downloadexternal_mesa3d-b4a3a80403e6cfe428c17257dc6ba85f1bdbfa02.tar.gz
external_mesa3d-b4a3a80403e6cfe428c17257dc6ba85f1bdbfa02.tar.bz2
external_mesa3d-b4a3a80403e6cfe428c17257dc6ba85f1bdbfa02.zip
disk_cache: move evict_lru_item() to an OS specific helper
Reviewed-by: Bas Nieuwenhuizen <bas@basnieuwenhuizen.nl> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6197>
Diffstat (limited to 'src/util/disk_cache.c')
-rw-r--r--src/util/disk_cache.c185
1 files changed, 1 insertions, 184 deletions
diff --git a/src/util/disk_cache.c b/src/util/disk_cache.c
index 943141cb627..a6f6f0590ed 100644
--- a/src/util/disk_cache.c
+++ b/src/util/disk_cache.c
@@ -317,189 +317,6 @@ make_cache_file_directory(struct disk_cache *cache, const cache_key key)
free(dir);
}
-/* Given a directory path and predicate function, find the entry with
- * the oldest access time in that directory for which the predicate
- * returns true.
- *
- * Returns: A malloc'ed string for the path to the chosen file, (or
- * NULL on any error). The caller should free the string when
- * finished.
- */
-static char *
-choose_lru_file_matching(const char *dir_path,
- bool (*predicate)(const char *dir_path,
- const struct stat *,
- const char *, const size_t))
-{
- DIR *dir;
- struct dirent *entry;
- char *filename;
- char *lru_name = NULL;
- time_t lru_atime = 0;
-
- dir = opendir(dir_path);
- if (dir == NULL)
- return NULL;
-
- while (1) {
- entry = readdir(dir);
- if (entry == NULL)
- break;
-
- struct stat sb;
- if (fstatat(dirfd(dir), entry->d_name, &sb, 0) == 0) {
- if (!lru_atime || (sb.st_atime < lru_atime)) {
- size_t len = strlen(entry->d_name);
-
- if (!predicate(dir_path, &sb, entry->d_name, len))
- continue;
-
- char *tmp = realloc(lru_name, len + 1);
- if (tmp) {
- lru_name = tmp;
- memcpy(lru_name, entry->d_name, len + 1);
- lru_atime = sb.st_atime;
- }
- }
- }
- }
-
- if (lru_name == NULL) {
- closedir(dir);
- return NULL;
- }
-
- if (asprintf(&filename, "%s/%s", dir_path, lru_name) < 0)
- filename = NULL;
-
- free(lru_name);
- closedir(dir);
-
- return filename;
-}
-
-/* Is entry a regular file, and not having a name with a trailing
- * ".tmp"
- */
-static bool
-is_regular_non_tmp_file(const char *path, const struct stat *sb,
- const char *d_name, const size_t len)
-{
- if (!S_ISREG(sb->st_mode))
- return false;
-
- if (len >= 4 && strcmp(&d_name[len-4], ".tmp") == 0)
- return false;
-
- return true;
-}
-
-/* Returns the size of the deleted file, (or 0 on any error). */
-static size_t
-unlink_lru_file_from_directory(const char *path)
-{
- struct stat sb;
- char *filename;
-
- filename = choose_lru_file_matching(path, is_regular_non_tmp_file);
- if (filename == NULL)
- return 0;
-
- if (stat(filename, &sb) == -1) {
- free (filename);
- return 0;
- }
-
- unlink(filename);
- free (filename);
-
- return sb.st_blocks * 512;
-}
-
-/* Is entry a directory with a two-character name, (and not the
- * special name of ".."). We also return false if the dir is empty.
- */
-static bool
-is_two_character_sub_directory(const char *path, const struct stat *sb,
- const char *d_name, const size_t len)
-{
- if (!S_ISDIR(sb->st_mode))
- return false;
-
- if (len != 2)
- return false;
-
- if (strcmp(d_name, "..") == 0)
- return false;
-
- char *subdir;
- if (asprintf(&subdir, "%s/%s", path, d_name) == -1)
- return false;
- DIR *dir = opendir(subdir);
- free(subdir);
-
- if (dir == NULL)
- return false;
-
- unsigned subdir_entries = 0;
- struct dirent *d;
- while ((d = readdir(dir)) != NULL) {
- if(++subdir_entries > 2)
- break;
- }
- closedir(dir);
-
- /* If dir only contains '.' and '..' it must be empty */
- if (subdir_entries <= 2)
- return false;
-
- return true;
-}
-
-static void
-evict_lru_item(struct disk_cache *cache)
-{
- char *dir_path;
-
- /* With a reasonably-sized, full cache, (and with keys generated
- * from a cryptographic hash), we can choose two random hex digits
- * and reasonably expect the directory to exist with a file in it.
- * Provides pseudo-LRU eviction to reduce checking all cache files.
- */
- uint64_t rand64 = rand_xorshift128plus(cache->seed_xorshift128plus);
- if (asprintf(&dir_path, "%s/%02" PRIx64 , cache->path, rand64 & 0xff) < 0)
- return;
-
- size_t size = unlink_lru_file_from_directory(dir_path);
-
- free(dir_path);
-
- if (size) {
- p_atomic_add(cache->size, - (uint64_t)size);
- return;
- }
-
- /* In the case where the random choice of directory didn't find
- * something, we choose the least recently accessed from the
- * existing directories.
- *
- * Really, the only reason this code exists is to allow the unit
- * tests to work, (which use an artificially-small cache to be able
- * to force a single cached item to be evicted).
- */
- dir_path = choose_lru_file_matching(cache->path,
- is_two_character_sub_directory);
- if (dir_path == NULL)
- return;
-
- size = unlink_lru_file_from_directory(dir_path);
-
- free(dir_path);
-
- if (size)
- p_atomic_add(cache->size, - (uint64_t)size);
-}
-
void
disk_cache_remove(struct disk_cache *cache, const cache_key key)
{
@@ -728,7 +545,7 @@ cache_put(void *job, int thread_index)
/* 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);
+ disk_cache_evict_lru_item(dc_job->cache);
i++;
}