|
1 |
| -From d33447368180a414f17a9a08346857129caf2556 Mon Sep 17 00:00:00 2001 |
| 1 | +From 6ac1d20c8c52f3cbc6d890ed8a008f8f2d4c147b Mon Sep 17 00:00:00 2001 |
2 | 2 | From: Michael Vogt <michael.vogt@gmail.com>
|
3 | 3 | Date: Wed, 13 Dec 2023 17:39:55 +0100
|
4 | 4 | Subject: [PATCH 3/4] fscache: use remove_lru() to reclaim space when the cache
|
5 | 5 | is full
|
6 | 6 |
|
7 | 7 | This commit adds code that will remove the least recently used
|
8 | 8 | entries when a store() operation does not succeeds because the
|
9 |
| -cache is full. |
| 9 | +cache is full. To be more efficient it will try to free |
| 10 | +twice the requested size (this can be configured in the code). |
10 | 11 | ---
|
11 |
| - osbuild/util/fscache.py | 48 ++++++++++++++++++++++++++++++----------- |
12 |
| - 1 file changed, 36 insertions(+), 12 deletions(-) |
| 12 | + osbuild/util/fscache.py | 32 +++++++++++++++++++++----------- |
| 13 | + 1 file changed, 21 insertions(+), 11 deletions(-) |
13 | 14 |
|
14 | 15 | diff --git a/osbuild/util/fscache.py b/osbuild/util/fscache.py
|
15 |
| -index 21e03f95..9057d53c 100644 |
| 16 | +index 32056a35..59039522 100644 |
16 | 17 | --- a/osbuild/util/fscache.py
|
17 | 18 | +++ b/osbuild/util/fscache.py
|
18 |
| -@@ -941,20 +941,31 @@ class FsCache(contextlib.AbstractContextManager, os.PathLike): |
19 |
| - info: Dict[str, Any] = {} |
| 19 | +@@ -683,8 +683,11 @@ class FsCache(contextlib.AbstractContextManager, os.PathLike): |
| 20 | + self._info_maximum_size = -1 |
| 21 | + elif isinstance(info.maximum_size, int): |
| 22 | + self._info_maximum_size = info.maximum_size |
| 23 | +- else: |
| 24 | ++ elif info.maximum_size is None: |
| 25 | + self._info_maximum_size = 0 |
| 26 | ++ else: |
| 27 | ++ raise ValueError( |
| 28 | ++ f"maximum-size can only be set to 'unlimited' or an integer value, got {type(info.maximum_size)}") |
| 29 | + |
| 30 | + def _is_active(self): |
| 31 | + # Internal helper to verify we are in an active context-manager. |
| 32 | +@@ -942,19 +945,27 @@ class FsCache(contextlib.AbstractContextManager, os.PathLike): |
20 | 33 | info["creation-boot-id"] = self._bootid
|
21 | 34 | info["size"] = self._calculate_space(path_data)
|
22 |
| -+ # account for the extra block of the object-information file |
23 |
| -+ # (find a better way to account for the block size) |
24 |
| -+ info["size"] += 4096 |
25 | 35 |
|
26 | 36 | - # Update the total cache-size. If it exceeds the limits, bail out
|
27 | 37 | - # but do not trigger an error. It behaves as if the entry was
|
@@ -56,48 +66,14 @@ index 21e03f95..9057d53c 100644
|
56 | 66 |
|
57 | 67 | try:
|
58 | 68 | # Commit the object-information, thus marking it as fully
|
59 |
| -@@ -1086,8 +1097,12 @@ class FsCache(contextlib.AbstractContextManager, os.PathLike): |
60 |
| - objs.append(FsCacheObjectInfo(name=name, last_used=last_used)) |
61 |
| - return sorted(objs, key=lambda obj: obj.last_used) |
62 |
| - |
63 |
| -- def _remove_lru(self): |
64 |
| -- """"Remove the least recently used entry from the cache.""" |
65 |
| -+ def _remove_lru(self, required_size): |
66 |
| -+ """" |
67 |
| -+ Make room in the cache for "required_size" by remove the least |
68 |
| -+ recently used entry from the cache. Note that the cache may |
69 |
| -+ clear more than required_size. |
70 |
| -+ """ |
71 |
| - # To avoid having to take a global cache lock the strategy is: |
72 |
| - # 1. Get list of (object, last_used) sorted from oldest to newest. |
73 |
| - # This is racy so we need to take care of that in step(2). |
74 |
| -@@ -1101,6 +1116,11 @@ class FsCache(contextlib.AbstractContextManager, os.PathLike): |
75 |
| - # Note that there is a risk to get out-of-sync in (3). If the |
76 |
| - # process dies while removing and before updating the cache |
77 |
| - # size the cache will be over reported. |
78 |
| -+ # |
79 |
| -+ # try to clean at least twice the requested size to avoid having |
80 |
| -+ # to do this all over again |
81 |
| -+ try_to_free = required_size * 2 |
82 |
| -+ freed_so_far = 0 |
83 |
| - for name, last_used in self._last_used_objs(): |
84 |
| - # take write lock for the indivdual object |
85 |
| - rpath = os.path.join(self._dirname_objects, name) |
86 |
| -@@ -1126,9 +1146,13 @@ class FsCache(contextlib.AbstractContextManager, os.PathLike): |
87 |
| - size = self._calculate_space(self._path(rpath)) |
88 |
| - self._rm_r_object(rpath) |
89 |
| - self._update_cache_size(-size) |
90 |
| -- return |
91 |
| -+ freed_so_far += size |
92 |
| -+ if freed_so_far >= try_to_free: |
93 |
| -+ break |
| 69 | +@@ -1146,7 +1157,6 @@ class FsCache(contextlib.AbstractContextManager, os.PathLike): |
| 70 | + break |
94 | 71 | except BlockingIOError:
|
95 | 72 | continue
|
96 |
| -+ # return if at least the required size got freed |
97 |
| -+ return freed_so_far > required_size |
| 73 | +- |
| 74 | + # return True if at least the required size got freed |
| 75 | + return freed_so_far > required_size |
98 | 76 |
|
99 |
| - @property |
100 |
| - def info(self) -> FsCacheInfo: |
101 | 77 | --
|
102 | 78 | 2.43.0
|
103 | 79 |
|
0 commit comments