OLD | NEW |
(Empty) | |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is govered by a BSD-style |
| 3 # license that can be found in the LICENSE file or at |
| 4 # https://developers.google.com/open-source/licenses/bsd |
| 5 |
| 6 """A class to handle cron requests to expunge doomed and deletable projects.""" |
| 7 |
| 8 import logging |
| 9 import time |
| 10 |
| 11 from framework import jsonfeed |
| 12 |
| 13 RUN_DURATION_LIMIT = 50 * 60 # 50 minutes |
| 14 |
| 15 |
| 16 class Reap(jsonfeed.InternalTask): |
| 17 """Look for doomed and deletable projects and delete them.""" |
| 18 |
| 19 def HandleRequest(self, mr): |
| 20 """Update/Delete doomed and deletable projects as needed. |
| 21 |
| 22 Args: |
| 23 mr: common information parsed from the HTTP request. |
| 24 |
| 25 Returns: |
| 26 Results dictionary in JSON format. The JSON will look like this: |
| 27 { |
| 28 'doomed_project_ids': <int>, |
| 29 'expunged_project_ids': <int> |
| 30 } |
| 31 doomed_project_ids are the projects which have been marked as deletable. |
| 32 expunged_project_ids are the projects that have either been completely |
| 33 expunged or are in the midst of being expunged. |
| 34 """ |
| 35 doomed_project_ids = self._MarkDoomedProjects(mr.cnxn) |
| 36 expunged_project_ids = self._ExpungeDeletableProjects(mr.cnxn) |
| 37 return { |
| 38 'doomed_project_ids': doomed_project_ids, |
| 39 'expunged_project_ids': expunged_project_ids, |
| 40 } |
| 41 |
| 42 def _MarkDoomedProjects(self, cnxn): |
| 43 """No longer needed projects get doomed, and this marks them deletable.""" |
| 44 now = int(time.time()) |
| 45 doomed_project_rows = self.services.project.project_tbl.Select( |
| 46 cnxn, cols=['project_id'], |
| 47 # We only match projects with real timestamps and not delete_time = 0. |
| 48 where=[('delete_time < %s', [now]), ('delete_time != %s', [0])], |
| 49 state='archived', limit=1000) |
| 50 doomed_project_ids = [row[0] for row in doomed_project_rows] |
| 51 for project_id in doomed_project_ids: |
| 52 self.services.project.MarkProjectDeletable( |
| 53 cnxn, project_id, self.services.config) |
| 54 |
| 55 return doomed_project_ids |
| 56 |
| 57 def _ExpungeDeletableProjects(self, cnxn): |
| 58 """Chip away at deletable projects until they are gone.""" |
| 59 request_deadline = time.time() + RUN_DURATION_LIMIT |
| 60 |
| 61 deletable_project_rows = self.services.project.project_tbl.Select( |
| 62 cnxn, cols=['project_id'], state='deletable', limit=100) |
| 63 deletable_project_ids = [row[0] for row in deletable_project_rows] |
| 64 # expunged_project_ids will contain projects that have either been |
| 65 # completely expunged or are in the midst of being expunged. |
| 66 expunged_project_ids = set() |
| 67 for project_id in deletable_project_ids: |
| 68 for _part in self._ExpungeParts(cnxn, project_id): |
| 69 expunged_project_ids.add(project_id) |
| 70 if time.time() > request_deadline: |
| 71 return list(expunged_project_ids) |
| 72 |
| 73 return list(expunged_project_ids) |
| 74 |
| 75 def _ExpungeParts(self, cnxn, project_id): |
| 76 """Delete all data from the specified project, one part at a time. |
| 77 |
| 78 This method purges all data associated with the specified project. The |
| 79 following is purged: |
| 80 * All issues of the project. |
| 81 * Project config. |
| 82 * Saved queries. |
| 83 * Filter rules. |
| 84 * Former locations. |
| 85 * Local ID counters. |
| 86 * Quick edit history. |
| 87 * Item stars. |
| 88 * Project from the DB. |
| 89 |
| 90 Returns a generator whose return values can be either issue |
| 91 ids or the specified project id. The returned values are intended to be |
| 92 iterated over and not read. |
| 93 """ |
| 94 # Purge all issues of the project. |
| 95 while True: |
| 96 issue_id_rows = self.services.issue.issue_tbl.Select( |
| 97 cnxn, cols=['id'], project_id=project_id, limit=1000) |
| 98 issue_ids = [row[0] for row in issue_id_rows] |
| 99 for issue_id in issue_ids: |
| 100 self.services.issue_star.ExpungeStars(cnxn, issue_id) |
| 101 self.services.issue.ExpungeIssues(cnxn, issue_ids) |
| 102 yield issue_ids |
| 103 break |
| 104 |
| 105 # All project purge functions are called with cnxn and project_id. |
| 106 project_purge_functions = ( |
| 107 self.services.config.ExpungeConfig, |
| 108 self.services.features.ExpungeSavedQueriesExecuteInProject, |
| 109 self.services.features.ExpungeFilterRules, |
| 110 self.services.issue.ExpungeFormerLocations, |
| 111 self.services.issue.ExpungeLocalIDCounters, |
| 112 self.services.features.ExpungeQuickEditHistory, |
| 113 self.services.project_star.ExpungeStars, |
| 114 self.services.project.ExpungeProject, |
| 115 ) |
| 116 |
| 117 for f in project_purge_functions: |
| 118 f(cnxn, project_id) |
| 119 yield project_id |
OLD | NEW |