@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ManiphestReportController: Separate legacy and synthetic data handling

Summary:
Due to code additions in rPcb957f8d and rPadbd7d4f required due to rPd321cc81, the code intertwines handling legacy data with handling/creating modern data.
Make things more understandable by clearly separating between both (handle one after the other) and by renaming some variables for clarity, so it will become slightly easier in the future to investigate this bottleneck (it is the only code querying the ManiphestTransaction table, leading to timeouts in large Phorge installations).

Also add a specific reference to the corresponding code change in a code comment, instead of a vague "late 2017".
Also, don't use the variable name `$table` for two different things (database vs AphrontTableView) in the same function.

Test Plan: Carefully read the code. Optionally, play with http://phorge.localhost/maniphest/report/burn/ with and without setting a project filter having tasks created in the codebase before 2017-11-22, and compare that the output is still the same.

Reviewers: O1 Blessed Committers, 20after4

Reviewed By: O1 Blessed Committers, 20after4

Subscribers: 20after4, tobiaswiese, valerio.bozzolan, Matthew, Cigaryno

Differential Revision: https://we.phorge.it/D25828

+60 -45
+60 -45
src/applications/maniphest/controller/ManiphestReportController.php
··· 71 71 72 72 } 73 73 74 + /** 75 + * @return array<AphrontListFilterView, PHUIObjectBoxView> 76 + */ 74 77 public function renderBurn() { 75 78 $request = $this->getRequest(); 76 79 $viewer = $request->getUser(); ··· 84 87 $handle = $handles[$project_phid]; 85 88 } 86 89 87 - $table = new ManiphestTransaction(); 88 - $conn = $table->establishConnection('r'); 90 + $xtable = new ManiphestTransaction(); 91 + $conn = $xtable->establishConnection('r'); 89 92 93 + // Get legacy data: Querying the task transaction table is only needed for 94 + // code before rPd321cc81 got merged on 2017-11-22. 90 95 if ($project_phid) { 91 - $joins = qsprintf( 96 + $legacy_joins = qsprintf( 92 97 $conn, 93 98 'JOIN %T t ON x.objectPHID = t.phid 94 99 JOIN %T p ON p.src = t.phid AND p.type = %d AND p.dst = %s', ··· 96 101 PhabricatorEdgeConfig::TABLE_NAME_EDGE, 97 102 PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, 98 103 $project_phid); 99 - $create_joins = qsprintf( 100 - $conn, 101 - 'JOIN %T p ON p.src = t.phid AND p.type = %d AND p.dst = %s', 102 - PhabricatorEdgeConfig::TABLE_NAME_EDGE, 103 - PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, 104 - $project_phid); 105 104 } else { 106 - $joins = qsprintf($conn, ''); 107 - $create_joins = qsprintf($conn, ''); 105 + $legacy_joins = qsprintf($conn, ''); 108 106 } 109 107 110 - $data = queryfx_all( 108 + $legacy_data = queryfx_all( 111 109 $conn, 112 110 'SELECT x.transactionType, x.oldValue, x.newValue, x.dateCreated 113 111 FROM %T x %Q 114 112 WHERE transactionType IN (%Ls) 115 113 ORDER BY x.dateCreated ASC', 116 - $table->getTableName(), 117 - $joins, 114 + $xtable->getTableName(), 115 + $legacy_joins, 118 116 array( 119 117 ManiphestTaskStatusTransaction::TRANSACTIONTYPE, 120 118 ManiphestTaskMergedIntoTransaction::TRANSACTIONTYPE, 121 119 )); 122 120 123 - // See PHI273. After the move to EditEngine, we no longer create a 124 - // "status" transaction if a task is created directly into the default 125 - // status. This likely impacted API/email tasks after 2016 and all other 126 - // tasks after late 2017. Until Facts can fix this properly, use the 127 - // task creation dates to generate synthetic transactions which look like 128 - // the older transactions that this page expects. 129 - 130 - $default_status = ManiphestTaskStatus::getDefaultStatus(); 131 - $duplicate_status = ManiphestTaskStatus::getDuplicateStatus(); 132 - 133 - // Build synthetic transactions which take status from `null` to the 134 - // default value. 135 - $create_rows = queryfx_all( 136 - $conn, 137 - 'SELECT t.dateCreated FROM %T t %Q', 138 - id(new ManiphestTask())->getTableName(), 139 - $create_joins); 140 - foreach ($create_rows as $key => $create_row) { 141 - $create_rows[$key] = array( 142 - 'transactionType' => 'status', 143 - 'oldValue' => null, 144 - 'newValue' => $default_status, 145 - 'dateCreated' => $create_row['dateCreated'], 146 - ); 147 - } 148 - 149 121 // Remove any actual legacy status transactions which take status from 150 122 // `null` to any open status. 151 - foreach ($data as $key => $row) { 123 + foreach ($legacy_data as $key => $row) { 152 124 if ($row['transactionType'] != 'status') { 153 125 continue; 154 126 } ··· 168 140 } 169 141 170 142 // If this is a legacy "create" transaction, discard it in favor of the 171 - // synthetic one. 172 - unset($data[$key]); 143 + // synthetic transaction to be created below. 144 + unset($legacy_data[$key]); 173 145 } 174 146 175 - // Merge the synthetic rows into the real transactions. 176 - $data = array_merge($create_rows, $data); 147 + // Since rPd321cc81, after the move to EditEngine, we no longer create a 148 + // "status" transaction if a task is created directly into the default 149 + // status. This likely impacted API/email tasks after 2016 and all other 150 + // tasks after deploying the Phorge codebase from 2017-11-22. 151 + // Until Facts can fix this properly, use the task creation dates to 152 + // generate synthetic transactions which look like the older transactions 153 + // that this page expects. 154 + 155 + $default_status = ManiphestTaskStatus::getDefaultStatus(); 156 + $duplicate_status = ManiphestTaskStatus::getDuplicateStatus(); 157 + 158 + if ($project_phid) { 159 + $synth_joins = qsprintf( 160 + $conn, 161 + 'JOIN %T p ON p.src = t.phid AND p.type = %d AND p.dst = %s', 162 + PhabricatorEdgeConfig::TABLE_NAME_EDGE, 163 + PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, 164 + $project_phid); 165 + } else { 166 + $synth_joins = qsprintf($conn, ''); 167 + } 168 + 169 + // Build synthetic transactions which take status from `null` to the 170 + // default value. 171 + $synth_data = queryfx_all( 172 + $conn, 173 + 'SELECT t.dateCreated FROM %T t %Q', 174 + id(new ManiphestTask())->getTableName(), 175 + $synth_joins); 176 + foreach ($synth_data as $key => $synth_row) { 177 + $synth_data[$key] = array( 178 + 'transactionType' => 'status', 179 + 'oldValue' => null, 180 + 'newValue' => $default_status, 181 + 'dateCreated' => $synth_row['dateCreated'], 182 + ); 183 + } 184 + 185 + // Merge the synthetic transactions into the legacy transactions. 186 + $data = array_merge($synth_data, $legacy_data); 177 187 $data = array_values($data); 178 188 $data = isort($data, 'dateCreated'); 179 189 ··· 412 422 return array($filter, $chart_view); 413 423 } 414 424 425 + /** 426 + * @param array $tokens 427 + * @param bool $has_window 428 + * @return AphrontListFilterView 429 + */ 415 430 private function renderReportFilters(array $tokens, $has_window) { 416 431 $request = $this->getRequest(); 417 432 $viewer = $request->getUser();