Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(84)

Side by Side Diff: client/named_cache.py

Issue 2636993002: swarming: Fix named cache support. (Closed)
Patch Set: Fix swarming_test.py Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « appengine/swarming/tools/start_bot.py ('k') | client/swarming.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2016 The LUCI Authors. All rights reserved. 1 # Copyright 2016 The LUCI Authors. All rights reserved.
2 # Use of this source code is governed under the Apache License, Version 2.0 2 # Use of this source code is governed under the Apache License, Version 2.0
3 # that can be found in the LICENSE file. 3 # that can be found in the LICENSE file.
4 4
5 """This file implements Named Caches.""" 5 """This file implements Named Caches."""
6 6
7 import contextlib 7 import contextlib
8 import logging
8 import optparse 9 import optparse
9 import os 10 import os
10 import random 11 import random
11 import re 12 import re
12 import string 13 import string
13 14
14 from utils import lru 15 from utils import lru
15 from utils import file_path 16 from utils import file_path
16 from utils import fs 17 from utils import fs
17 from utils import threading_utils 18 from utils import threading_utils
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 92
92 Requires NamedCache to be open. 93 Requires NamedCache to be open.
93 """ 94 """
94 self._lock.assert_locked() 95 self._lock.assert_locked()
95 assert isinstance(name, basestring), name 96 assert isinstance(name, basestring), name
96 path = self._lru.get(name) 97 path = self._lru.get(name)
97 create_named_link = False 98 create_named_link = False
98 if path is None: 99 if path is None:
99 path = self._allocate_dir() 100 path = self._allocate_dir()
100 create_named_link = True 101 create_named_link = True
102 logging.info('Created %r for %r', path, name)
101 abs_path = os.path.join(self.root_dir, path) 103 abs_path = os.path.join(self.root_dir, path)
102 104
105 # TODO(maruel): That's weird, it should exist already.
103 file_path.ensure_tree(abs_path) 106 file_path.ensure_tree(abs_path)
104 self._lru.add(name, path) 107 self._lru.add(name, path)
105 108
106 if create_named_link: 109 if create_named_link:
107 # Create symlink <root_dir>/<named>/<name> -> <root_dir>/<short name> 110 # Create symlink <root_dir>/<named>/<name> -> <root_dir>/<short name>
108 # for user convenience. 111 # for user convenience.
109 named_path = self._get_named_path(name) 112 named_path = self._get_named_path(name)
110 if os.path.exists(named_path): 113 if os.path.exists(named_path):
111 file_path.remove(named_path) 114 file_path.remove(named_path)
112 else: 115 else:
113 file_path.ensure_tree(os.path.dirname(named_path)) 116 file_path.ensure_tree(os.path.dirname(named_path))
117 logging.info('Symlink %r to %r', named_path, abs_path)
114 fs.symlink(abs_path, named_path) 118 fs.symlink(abs_path, named_path)
115 119
116 return abs_path 120 return abs_path
117 121
118 def get_oldest(self): 122 def get_oldest(self):
119 """Returns name of the LRU cache or None. 123 """Returns name of the LRU cache or None.
120 124
121 Requires NamedCache to be open. 125 Requires NamedCache to be open.
122 """ 126 """
123 self._lock.assert_locked() 127 self._lock.assert_locked()
(...skipping 17 matching lines...) Expand all
141 """Creates symlinks in |root| for specified named_caches. 145 """Creates symlinks in |root| for specified named_caches.
142 146
143 named_caches must be a list of (name, path) tuples. 147 named_caches must be a list of (name, path) tuples.
144 148
145 Requires NamedCache to be open. 149 Requires NamedCache to be open.
146 150
147 Raises Error if cannot create a symlink. 151 Raises Error if cannot create a symlink.
148 """ 152 """
149 self._lock.assert_locked() 153 self._lock.assert_locked()
150 for name, path in named_caches: 154 for name, path in named_caches:
155 logging.info('Named cache %r -> %r', name, path)
151 try: 156 try:
152 if os.path.isabs(path): 157 if os.path.isabs(path):
153 raise Error('named cache path must not be absolute') 158 raise Error('named cache path must not be absolute')
154 if '..' in path.split(os.path.sep): 159 if '..' in path.split(os.path.sep):
155 raise Error('named cache path must not contain ".."') 160 raise Error('named cache path must not contain ".."')
156 symlink_path = os.path.abspath(os.path.join(root, path)) 161 symlink_path = os.path.abspath(os.path.join(root, path))
157 file_path.ensure_tree(os.path.dirname(symlink_path)) 162 file_path.ensure_tree(os.path.dirname(symlink_path))
158 fs.symlink(self.request(name), symlink_path) 163 requested = self.request(name)
164 logging.info('Symlink %r to %r', symlink_path, requested)
165 fs.symlink(requested, symlink_path)
159 except (OSError, Error) as ex: 166 except (OSError, Error) as ex:
160 raise Error( 167 raise Error(
161 'cannot create a symlink for cache named "%s" at "%s": %s' % ( 168 'cannot create a symlink for cache named "%s" at "%s": %s' % (
162 name, symlink_path, ex)) 169 name, symlink_path, ex))
163 170
164 def trim(self, min_free_space): 171 def trim(self, min_free_space):
165 """Purges cache. 172 """Purges cache.
166 173
167 Removes cache directories that were not accessed for a long time 174 Removes cache directories that were not accessed for a long time
168 until there is enough free space and the number of caches is sane. 175 until there is enough free space and the number of caches is sane.
169 176
170 If min_free_space is None, disk free space is not checked. 177 If min_free_space is None, disk free space is not checked.
171 178
172 Requires NamedCache to be open. 179 Requires NamedCache to be open.
173 """ 180 """
174 self._lock.assert_locked() 181 self._lock.assert_locked()
175 if not os.path.isdir(self.root_dir): 182 if not os.path.isdir(self.root_dir):
176 return 183 return
177 184
178 free_space = 0 185 free_space = 0
179 if min_free_space is not None: 186 if min_free_space:
180 file_path.get_free_space(self.root_dir) 187 free_space = file_path.get_free_space(self.root_dir)
181 while ((min_free_space is not None and free_space < min_free_space) 188 while ((min_free_space and free_space < min_free_space)
182 or len(self._lru) > MAX_CACHE_SIZE): 189 or len(self._lru) > MAX_CACHE_SIZE):
190 logging.info(
191 'Making space for named cache %s > %s or %s > %s',
192 free_space, min_free_space, len(self._lru), MAX_CACHE_SIZE)
183 try: 193 try:
184 name, (path, _) = self._lru.get_oldest() 194 name, (path, _) = self._lru.get_oldest()
185 except KeyError: 195 except KeyError:
186 return 196 return
187 named_dir = self._get_named_path(name) 197 named_dir = self._get_named_path(name)
188 if fs.islink(named_dir): 198 if fs.islink(named_dir):
189 fs.unlink(named_dir) 199 fs.unlink(named_dir)
190 path_abs = os.path.join(self.root_dir, path) 200 path_abs = os.path.join(self.root_dir, path)
191 if os.path.isdir(path_abs): 201 if os.path.isdir(path_abs):
202 logging.info('Removing named cache %s', path_abs)
192 file_path.rmtree(path_abs) 203 file_path.rmtree(path_abs)
193 if min_free_space is not None: 204 if min_free_space:
194 free_space = file_path.get_free_space(self.root_dir) 205 free_space = file_path.get_free_space(self.root_dir)
195 self._lru.pop(name) 206 self._lru.pop(name)
196 207
197 _DIR_ALPHABET = string.ascii_letters + string.digits 208 _DIR_ALPHABET = string.ascii_letters + string.digits
198 209
199 def _allocate_dir(self): 210 def _allocate_dir(self):
200 """Creates and returns relative path of a new cache directory.""" 211 """Creates and returns relative path of a new cache directory."""
201 # We randomly generate directory names that have two lower/upper case 212 # We randomly generate directory names that have two lower/upper case
202 # letters or digits. Total number of possibilities is (26*2 + 10)^2 = 3844. 213 # letters or digits. Total number of possibilities is (26*2 + 10)^2 = 3844.
203 abc_len = len(self._DIR_ALPHABET) 214 abc_len = len(self._DIR_ALPHABET)
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
244 parser.error('--named-cache is specified, but --named-cache-root is empty') 255 parser.error('--named-cache is specified, but --named-cache-root is empty')
245 for name, path in options.named_caches: 256 for name, path in options.named_caches:
246 if not CACHE_NAME_RE.match(name): 257 if not CACHE_NAME_RE.match(name):
247 parser.error( 258 parser.error(
248 'cache name "%s" does not match %s' % (name, CACHE_NAME_RE.pattern)) 259 'cache name "%s" does not match %s' % (name, CACHE_NAME_RE.pattern))
249 if not path: 260 if not path:
250 parser.error('cache path cannot be empty') 261 parser.error('cache path cannot be empty')
251 if options.named_cache_root: 262 if options.named_cache_root:
252 return CacheManager(os.path.abspath(options.named_cache_root)) 263 return CacheManager(os.path.abspath(options.named_cache_root))
253 return None 264 return None
OLDNEW
« no previous file with comments | « appengine/swarming/tools/start_bot.py ('k') | client/swarming.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698