[IMP] runbot: improve cleanup perfs

The current version will read ~100000 build

This one will avoid that by checking the date of the gcstamp instead
This commit is contained in:
Xavier-Do 2023-06-30 15:16:33 +02:00
parent ab194610b0
commit 423b34433d

View File

@ -509,7 +509,6 @@ class BuildResult(models.Model):
ignored = set() ignored = set()
icp = self.env['ir.config_parameter'] icp = self.env['ir.config_parameter']
hide_in_logs = icp.get_param('runbot.runbot_db_template', default='template0') hide_in_logs = icp.get_param('runbot.runbot_db_template', default='template0')
full_gc_days = int(icp.get_param('runbot.full_gc_days', default=365))
for dest in dest_list: for dest in dest_list:
build = self._build_from_dest(dest) build = self._build_from_dest(dest)
@ -528,9 +527,8 @@ class BuildResult(models.Model):
for build in existing: for build in existing:
if build.gc_date < fields.datetime.now(): if build.gc_date < fields.datetime.now():
if build.local_state == 'done': if build.local_state == 'done':
full = build.gc_date + datetime.timedelta(days=(full_gc_days)) < fields.datetime.now()
for db in dest_by_builds_ids[build.id]: for db in dest_by_builds_ids[build.id]:
yield (db, full) yield db
elif build.local_state != 'running': elif build.local_state != 'running':
_logger.warning('db (%s) not deleted because state is not done', " ".join(dest_by_builds_ids[build.id])) _logger.warning('db (%s) not deleted because state is not done', " ".join(dest_by_builds_ids[build.id]))
@ -548,7 +546,7 @@ class BuildResult(models.Model):
for dest in dest_list: for dest in dest_list:
build = self._build_from_dest(dest) build = self._build_from_dest(dest)
if build and build in self: if build and build in self:
yield (dest, full) yield dest
elif not build: elif not build:
_logger.info('%s (%s) skipped because not dest format', label, dest) _logger.info('%s (%s) skipped because not dest format', label, dest)
_filter = filter_ids _filter = filter_ids
@ -558,36 +556,45 @@ class BuildResult(models.Model):
log_db = self.env['ir.config_parameter'].get_param('runbot.logdb_name') log_db = self.env['ir.config_parameter'].get_param('runbot.logdb_name')
existing_db = [db for db in list_local_dbs(additionnal_conditions=additionnal_conditions) if db != log_db] existing_db = [db for db in list_local_dbs(additionnal_conditions=additionnal_conditions) if db != log_db]
for db, _ in _filter(dest_list=existing_db, label='db'): for db in _filter(dest_list=existing_db, label='db'):
self._logger('Removing database') self._logger('Removing database')
self._local_pg_dropdb(db) self._local_pg_dropdb(db)
builds_dir = Path(self.env['runbot.runbot']._root()) / 'build' builds_dir = Path(self.env['runbot.runbot']._root()) / 'build'
if force:
if force is True: dest_list = [build.dest for build in self]
dests = [(build.dest, full) for build in self]
else: else:
dests = _filter(dest_list=(p.name for p in builds_dir.iterdir()), label='workspace') dest_list = (p.name for p in builds_dir.iterdir())
for dest, full in dests: icp = self.env['ir.config_parameter']
full_gc_days = int(icp.get_param('runbot.full_gc_days', default=365))
full_gc_secondes = full_gc_days * 24 * 60 * 60
now = time.time()
candidate_for_partial_gc = []
for dest in dest_list:
build_dir = Path(builds_dir) / dest build_dir = Path(builds_dir) / dest
if full:
_logger.info('Removing build dir "%s"', dest)
shutil.rmtree(build_dir, ignore_errors=True)
continue
gcstamp = build_dir / '.gcstamp' gcstamp = build_dir / '.gcstamp'
if gcstamp.exists(): try:
continue if (force and full) or gcstamp.stat().st_ctime + full_gc_secondes < now:
for bdir_file in build_dir.iterdir(): _logger.info('Removing build dir "%s"', dest)
if bdir_file.is_dir() and bdir_file.name not in ('logs', 'tests'): shutil.rmtree(build_dir, ignore_errors=True)
shutil.rmtree(bdir_file) continue
elif bdir_file.name == 'logs': except(FileNotFoundError):
for log_file_path in bdir_file.iterdir(): candidate_for_partial_gc.append(dest)
if log_file_path.is_dir(): if candidate_for_partial_gc:
shutil.rmtree(log_file_path) for dest in _filter(candidate_for_partial_gc, label='workspace'):
elif log_file_path.name in ('run.txt', 'wake_up.txt') or not log_file_path.name.endswith('.txt'): build_dir = Path(builds_dir) / dest
log_file_path.unlink() for bdir_file in build_dir.iterdir():
gcstamp.write_text(f'gc date: {datetime.datetime.now()}') if bdir_file.is_dir() and bdir_file.name not in ('logs', 'tests'):
shutil.rmtree(bdir_file)
elif bdir_file.name == 'logs':
for log_file_path in bdir_file.iterdir():
if log_file_path.is_dir():
shutil.rmtree(log_file_path)
elif log_file_path.name in ('run.txt', 'wake_up.txt') or not log_file_path.name.endswith('.txt'):
log_file_path.unlink()
gcstamp.write_text(f'gc date: {datetime.datetime.now()}')
def _find_port(self): def _find_port(self):
# currently used port # currently used port