Fix the deadlock in tags.

This commit is contained in:
Jake Moshenko 2015-02-25 17:49:46 -05:00
parent d973f9df45
commit 6c4e78ec0c

View file

@ -1580,25 +1580,16 @@ def list_repository_tags(namespace_name, repository_name, include_hidden=False):
def _garbage_collect_tags(namespace_name, repository_name): def _garbage_collect_tags(namespace_name, repository_name):
inner = (RepositoryTag # We do this without using a join to prevent holding read locks on the repository table
.select(RepositoryTag.id, repo = _get_repository(namespace_name, repository_name)
RepositoryTag.lifetime_end_ts, now = int(time.time())
RepositoryTag.repository)
.alias('rt'))
to_delete = (RepositoryTag
.select(inner.c.id)
.from_(inner)
.join(Repository, on=(inner.c.repository_id == Repository.id))
.join(Namespace, on=(Repository.namespace_user == Namespace.id))
.where(Repository.name == repository_name, Namespace.username == namespace_name,
~(inner.c.lifetime_end_ts >> None),
(inner.c.lifetime_end_ts + Namespace.removed_tag_expiration_s) <=
int(time.time())))
(RepositoryTag (RepositoryTag
.delete() .delete()
.where(RepositoryTag.id << to_delete) .where(RepositoryTag.repository == repo,
.execute()) ~(RepositoryTag.lifetime_end_ts >> None),
(RepositoryTag.lifetime_end_ts + repo.namespace_user.removed_tag_expiration_s) <= now)
.execute())
def garbage_collect_repository(namespace_name, repository_name): def garbage_collect_repository(namespace_name, repository_name):
@ -1798,20 +1789,23 @@ def create_or_update_tag(namespace_name, repository_name, tag_name,
now_ts = int(time.time()) now_ts = int(time.time())
created = RepositoryTag.create(repository=repo, image=image, name=tag_name,
lifetime_start_ts=now_ts)
try: try:
# When we move a tag, we really end the timeline of the old one and create a new one # When we move a tag, we really end the timeline of the old one and create a new one
query = _tag_alive(RepositoryTag query = _tag_alive(RepositoryTag
.select() .select()
.where(RepositoryTag.repository == repo, RepositoryTag.name == tag_name)) .where(RepositoryTag.repository == repo, RepositoryTag.name == tag_name,
tag = db_for_update(query).get() RepositoryTag.id != created.id))
tag = query.get()
tag.lifetime_end_ts = now_ts tag.lifetime_end_ts = now_ts
tag.save() tag.save()
except RepositoryTag.DoesNotExist: except RepositoryTag.DoesNotExist:
# No tag that needs to be ended # No tag that needs to be ended
pass pass
return RepositoryTag.create(repository=repo, image=image, name=tag_name, return created
lifetime_start_ts=now_ts)
def delete_tag(namespace_name, repository_name, tag_name): def delete_tag(namespace_name, repository_name, tag_name):