Skip to content

Commit 0d955b6

Browse files
Refactor expirable_drafts() and its usage to speed up doc.views_search.recent_drafts view (and discourage inefficient use of the method). Commit ready for merge.
- Legacy-Id: 19490
1 parent 3386e59 commit 0d955b6

3 files changed

Lines changed: 25 additions & 31 deletions

File tree

ietf/bin/expire-ids

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,22 @@ django.setup()
2727
from ietf.utils.log import logger
2828

2929
try:
30-
from ietf.doc.expire import ( in_draft_expire_freeze, get_expired_drafts, expirable_draft,
30+
from ietf.doc.expire import ( in_draft_expire_freeze, get_expired_drafts, expirable_drafts,
3131
send_expire_notice_for_draft, expire_draft, clean_up_draft_files )
32+
from ietf.doc.models import Document
3233

3334
if not in_draft_expire_freeze():
3435
syslog.syslog("Expiring drafts ...")
3536
for doc in get_expired_drafts():
3637
# verify expirability -- it might have changed after get_expired_drafts() was run
3738
# (this whole loop took about 2 minutes on 04 Jan 2018)
38-
if expirable_draft(doc) and doc.expires < datetime.datetime.today() + datetime.timedelta(1):
39+
# N.B., re-running expirable_drafts() repeatedly is fairly expensive. Where possible,
40+
# it's much faster to run it once on a superset query of the objects you are going
41+
# to test and keep its results. That's not desirable here because it would defeat
42+
# the purpose of double-checking that a document is still expirable when it is actually
43+
# being marked as expired.
44+
if (expirable_drafts(Document.objects.filter(pk=doc.pk)).exists()
45+
and doc.expires < datetime.datetime.today() + datetime.timedelta(1)):
3946
send_expire_notice_for_draft(doc)
4047
expire_draft(doc)
4148
syslog.syslog(" Expired draft %s-%s" % (doc.name, doc.rev))

ietf/doc/expire.py

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import datetime, os, shutil, glob, re
99
from pathlib import Path
1010

11-
from typing import List, Tuple # pyflakes:ignore
11+
from typing import List, Optional # pyflakes:ignore
1212

1313
from ietf.utils import log
1414
from ietf.utils.mail import send_mail
@@ -19,15 +19,7 @@
1919
from ietf.mailtrigger.utils import gather_address_lists
2020

2121

22-
def expirable_draft(draft):
23-
"""Return whether draft is in an expirable state or not. This is
24-
the single draft version of the logic in expirable_drafts. These
25-
two functions need to be kept in sync."""
26-
if draft.type_id != 'draft':
27-
return False
28-
return bool(expirable_drafts(Document.objects.filter(pk=draft.pk)))
29-
30-
nonexpirable_states = [] # type: List[State]
22+
nonexpirable_states: Optional[List[State]] = None
3123

3224
def expirable_drafts(queryset=None):
3325
"""Return a queryset with expirable drafts."""
@@ -39,31 +31,25 @@ def expirable_drafts(queryset=None):
3931
queryset = Document.objects.all()
4032

4133
# Populate this first time through (but after django has been set up)
42-
if nonexpirable_states == []:
34+
if nonexpirable_states is None:
4335
# all IESG states except I-D Exists, AD Watching, and Dead block expiry
44-
nonexpirable_states += list(State.objects.filter(used=True, type="draft-iesg").exclude(slug__in=("idexists","watching", "dead")))
36+
nonexpirable_states = list(State.objects.filter(used=True, type="draft-iesg").exclude(slug__in=("idexists","watching", "dead")))
4537
# sent to RFC Editor and RFC Published block expiry (the latter
4638
# shouldn't be possible for an active draft, though)
4739
nonexpirable_states += list(State.objects.filter(used=True, type__in=("draft-stream-iab", "draft-stream-irtf", "draft-stream-ise"), slug__in=("rfc-edit", "pub")))
4840
# other IRTF states that block expiration
4941
nonexpirable_states += list(State.objects.filter(used=True, type_id="draft-stream-irtf", slug__in=("irsgpoll", "iesg-rev",)))
5042

51-
d = queryset.filter(states__type="draft", states__slug="active")
52-
if not d.exists():
53-
return d
54-
55-
d = d.exclude(expires=None)
56-
if not d.exists():
57-
return d
58-
59-
d = d.exclude(states__in=nonexpirable_states)
60-
if not d.exists():
61-
return d
62-
63-
# under review by the RFC Editor blocks expiry
64-
d = d.exclude(tags="rfc-rev")
43+
return queryset.filter(
44+
states__type="draft", states__slug="active"
45+
).exclude(
46+
expires=None
47+
).exclude(
48+
states__in=nonexpirable_states
49+
).exclude(
50+
tags="rfc-rev" # under review by the RFC Editor blocks expiry
51+
).distinct()
6552

66-
return d.distinct()
6753

6854
def get_soon_to_expire_drafts(days_of_warning):
6955
start_date = datetime.date.today() - datetime.timedelta(1)

ietf/doc/utils_search.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import debug # pyflakes:ignore
77

88
from ietf.doc.models import Document, DocAlias, RelatedDocument, DocEvent, TelechatDocEvent, BallotDocEvent
9-
from ietf.doc.expire import expirable_draft
9+
from ietf.doc.expire import expirable_drafts
1010
from ietf.doc.utils import augment_docs_and_user_with_user_info
1111
from ietf.meeting.models import SessionPresentation, Meeting, Session
1212

@@ -80,6 +80,7 @@ def fill_in_document_table_attributes(docs, have_telechat_date=False):
8080
fill_in_document_sessions(docs, doc_dict, doc_ids)
8181

8282
# misc
83+
expirable_pks = expirable_drafts(Document.objects.filter(pk__in=doc_ids)).values_list('pk', flat=True)
8384
for d in docs:
8485
# emulate canonical name which is used by a lot of the utils
8586
d.canonical_name = wrap_value(rfc_aliases[d.pk] if d.pk in rfc_aliases else d.name)
@@ -102,7 +103,7 @@ def fill_in_document_table_attributes(docs, have_telechat_date=False):
102103
else:
103104
d.search_heading = "%s Internet-Draft" % d.get_state()
104105
if state_slug == "active":
105-
d.expirable = expirable_draft(d)
106+
d.expirable = d.pk in expirable_pks
106107
else:
107108
d.expirable = False
108109
else:

0 commit comments

Comments
 (0)