~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/scripts/garbo.py

Merged db-devel into staging.

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
import multiprocessing
26
26
from psycopg2 import IntegrityError
27
27
import pytz
 
28
from storm.expr import (
 
29
    In,
 
30
    )
28
31
from storm.locals import (
29
32
    Max,
30
33
    Min,
74
77
from lp.registry.model.person import Person
75
78
from lp.services.job.model.job import Job
76
79
from lp.services.log.logger import PrefixFilter
 
80
from lp.services.propertycache import cachedproperty
77
81
from lp.services.scripts.base import (
78
82
    LaunchpadCronScript,
79
83
    LOCK_PATH,
82
86
from lp.services.session.model import SessionData
83
87
from lp.translations.interfaces.potemplate import IPOTemplateSet
84
88
from lp.translations.model.potranslation import POTranslation
 
89
from lp.translations.model.potmsgset import POTMsgSet
 
90
from lp.translations.model.translationmessage import TranslationMessage
 
91
from lp.translations.model.translationtemplateitem import (
 
92
    TranslationTemplateItem,
 
93
    )
85
94
 
86
95
 
87
96
ONE_DAY_IN_SECONDS = 24*60*60
859
868
        self.done = True
860
869
 
861
870
 
 
871
class UnusedPOTMsgSetPruner(TunableLoop):
 
872
    """Cleans up unused POTMsgSets."""
 
873
 
 
874
    done = False
 
875
    offset = 0
 
876
    maximum_chunk_size = 50000
 
877
 
 
878
    def isDone(self):
 
879
        """See `TunableLoop`."""
 
880
        return self.offset >= len(self.msgset_ids_to_remove)
 
881
 
 
882
    @cachedproperty
 
883
    def msgset_ids_to_remove(self):
 
884
        """Return the IDs of the POTMsgSets to remove."""
 
885
        query = """
 
886
            -- Get all POTMsgSet IDs which are obsolete (sequence == 0)
 
887
            -- and are not used (sequence != 0) in any other template.
 
888
            SELECT DISTINCT POTMsgSet
 
889
              FROM TranslationTemplateItem tti
 
890
              WHERE sequence=0 AND
 
891
              NOT EXISTS(
 
892
                SELECT id
 
893
                  FROM TranslationTemplateItem
 
894
                  WHERE potmsgset = tti.potmsgset AND
 
895
                  sequence != 0)
 
896
            UNION
 
897
            -- Get all POTMsgSet IDs which are not referenced
 
898
            -- by any of the templates (they must have TTI rows for that).
 
899
            (SELECT POTMsgSet.id
 
900
              FROM POTMsgSet
 
901
             EXCEPT
 
902
             SELECT potmsgset
 
903
               FROM TranslationTemplateItem)
 
904
            LIMIT 50000;
 
905
            """
 
906
        store = IMasterStore(POTMsgSet)
 
907
        results = store.execute(query)
 
908
        ids_to_remove = [id for (id,) in results.get_all()]
 
909
        return ids_to_remove
 
910
 
 
911
    def __call__(self, chunk_size):
 
912
        """See `TunableLoop`."""
 
913
        # We cast chunk_size to an int to avoid issues with slicing
 
914
        # (DBLoopTuner passes in a float).
 
915
        chunk_size = int(chunk_size)
 
916
        msgset_ids_to_remove = (
 
917
            self.msgset_ids_to_remove[self.offset:][:chunk_size])
 
918
        # Remove related TranslationTemplateItems.
 
919
        store = IMasterStore(POTMsgSet)
 
920
        related_ttis = store.find(
 
921
            TranslationTemplateItem,
 
922
            In(TranslationTemplateItem.potmsgsetID, msgset_ids_to_remove))
 
923
        related_ttis.remove()
 
924
        # Remove related TranslationMessages.
 
925
        related_translation_messages = store.find(
 
926
            TranslationMessage,
 
927
            In(TranslationMessage.potmsgsetID, msgset_ids_to_remove))
 
928
        related_translation_messages.remove()
 
929
        store.find(
 
930
            POTMsgSet, In(POTMsgSet.id, msgset_ids_to_remove)).remove()
 
931
        self.offset = self.offset + chunk_size
 
932
        transaction.commit()
 
933
 
 
934
 
862
935
class BaseDatabaseGarbageCollector(LaunchpadCronScript):
863
936
    """Abstract base class to run a collection of TunableLoops."""
864
937
    script_name = None # Script name for locking and database user. Override.
1108
1181
        RevisionAuthorEmailLinker,
1109
1182
        SuggestiveTemplatesCacheUpdater,
1110
1183
        POTranslationPruner,
 
1184
        UnusedPOTMsgSetPruner,
1111
1185
        ]
1112
1186
    experimental_tunable_loops = [
1113
1187
        PersonPruner,