@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.

Clean up some log spam caused by races in VersionedDraft

Summary:
Two minor issues that I caught in the log while fixing Phame permissions:

- We had a JS bug which would cause us to immediately generate two comment previews at the exact same time -- one for loading the page, and one for "switching to desktop". Instead, only generate the "switch to desktop" preview if we really switched to desktop from a different device layout.
- These two requests could end up reading/writing the VersionedDraft table at exactly the same time fairly often (e.g., after a comment submission, the page would load, send two preview requests at exactly the same time, and they'd race fairly reliably for me locally). If we do race, recover from the race.

Test Plan:
Submitted some Phame comments.

- No more error log errors about VersionedDraft keys.
- Saw only one preview request when loading the page instead of two.

Here's the specific stack trace I caught:

```
[Mon Sep 05 12:15:33.639930 2016] [:error] [pid 50608] [client 127.0.0.1:55278] [2016-09-05 14:15:33] EXCEPTION: (AphrontDuplicateKeyQueryException) #1062: Duplicate entry 'PHID-POST-fknnpzjnsdgc3rqobhst-PHID-USER-pr5rjpuilpfserepsd2k-13' for key 'key_object' at [<phutil>/src/aphront/storage/connection/mysql/AphrontBaseMySQLDatabaseConnection.php:314]
[Mon Sep 05 12:15:33.640801 2016] [:error] [pid 50608] [client 127.0.0.1:55278] arcanist(head=master, ref.master=9e82ef979e81), corgi(head=master, ref.master=5b9171222bc9), instances(head=stable, ref.master=485bc8128198, ref.stable=2983bc917601), ledger(head=master, ref.master=4da4a24b8779), libcore(), phabricator(head=phame2, ref.master=4b6da9735ba7, ref.phame2=4b6da9735ba7), phutil(head=stable, ref.master=97f05269fdb1, ref.stable=c14343ee620e), services(head=stable, ref.master=1fcb5cdb7582, ref.stable=2d8088a5b4b3)
[Mon Sep 05 12:15:33.640815 2016] [:error] [pid 50608] [client 127.0.0.1:55278] #0 <#2> AphrontBaseMySQLDatabaseConnection::throwCommonException(integer, string) called at [<phutil>/src/aphront/storage/connection/mysql/AphrontBaseMySQLDatabaseConnection.php:348]
[Mon Sep 05 12:15:33.640830 2016] [:error] [pid 50608] [client 127.0.0.1:55278] #1 <#2> AphrontBaseMySQLDatabaseConnection::throwQueryCodeException(integer, string) called at [<phutil>/src/aphront/storage/connection/mysql/AphrontBaseMySQLDatabaseConnection.php:289]
[Mon Sep 05 12:15:33.640833 2016] [:error] [pid 50608] [client 127.0.0.1:55278] #2 <#2> AphrontBaseMySQLDatabaseConnection::throwQueryException(mysqli) called at [<phutil>/src/aphront/storage/connection/mysql/AphrontBaseMySQLDatabaseConnection.php:185]
[Mon Sep 05 12:15:33.640836 2016] [:error] [pid 50608] [client 127.0.0.1:55278] #3 <#2> AphrontBaseMySQLDatabaseConnection::executeRawQuery(string) called at [<phutil>/src/xsprintf/queryfx.php:8]
[Mon Sep 05 12:15:33.640839 2016] [:error] [pid 50608] [client 127.0.0.1:55278] #4 <#2> queryfx(AphrontMySQLiDatabaseConnection, string, string, string, array, string)
[Mon Sep 05 12:15:33.640841 2016] [:error] [pid 50608] [client 127.0.0.1:55278] #5 <#2> call_user_func_array(string, array) called at [<phutil>/src/aphront/storage/connection/AphrontDatabaseConnection.php:42]
[Mon Sep 05 12:15:33.640844 2016] [:error] [pid 50608] [client 127.0.0.1:55278] #6 <#2> AphrontDatabaseConnection::query(string, string, string, array, string) called at [<phabricator>/src/infrastructure/storage/lisk/LiskDAO.php:1261]
[Mon Sep 05 12:15:33.640846 2016] [:error] [pid 50608] [client 127.0.0.1:55278] #7 <#2> LiskDAO::insertRecordIntoDatabase(string) called at [<phabricator>/src/infrastructure/storage/lisk/LiskDAO.php:1106]
[Mon Sep 05 12:15:33.640849 2016] [:error] [pid 50608] [client 127.0.0.1:55278] #8 <#2> LiskDAO::insert() called at [<phabricator>/src/infrastructure/storage/lisk/LiskDAO.php:1075]
[Mon Sep 05 12:15:33.640851 2016] [:error] [pid 50608] [client 127.0.0.1:55278] #9 <#2> LiskDAO::save() called at [<phabricator>/src/applications/draft/storage/PhabricatorVersionedDraft.php:65]
[Mon Sep 05 12:15:33.640854 2016] [:error] [pid 50608] [client 127.0.0.1:55278] #10 <#2> PhabricatorVersionedDraft::loadOrCreateDraft(string, string, integer) called at [<phabricator>/src/applications/transactions/editengine/PhabricatorEditEngine.php:1669]
[Mon Sep 05 12:15:33.640857 2016] [:error] [pid 50608] [client 127.0.0.1:55278] #11 <#2> PhabricatorEditEngine::buildCommentResponse(PhamePost) called at [<phabricator>/src/applications/transactions/editengine/PhabricatorEditEngine.php:894]
[Mon Sep 05 12:15:33.640859 2016] [:error] [pid 50608] [client 127.0.0.1:55278] #12 <#2> PhabricatorEditEngine::buildResponse() called at [<phabricator>/src/applications/phame/controller/post/PhamePostEditController.php:60]
[Mon Sep 05 12:15:33.640862 2016] [:error] [pid 50608] [client 127.0.0.1:55278] #13 <#2> PhamePostEditController::handleRequest(AphrontRequest) called at [<phabricator>/src/aphront/configuration/AphrontApplicationConfiguration.php:237]
[Mon Sep 05 12:15:33.640865 2016] [:error] [pid 50608] [client 127.0.0.1:55278] #14 phlog(AphrontDuplicateKeyQueryException) called at [<phabricator>/src/aphront/handler/PhabricatorAjaxRequestExceptionHandler.php:27]
[Mon Sep 05 12:15:33.640868 2016] [:error] [pid 50608] [client 127.0.0.1:55278] #15 PhabricatorAjaxRequestExceptionHandler::handleRequestException(AphrontRequest, AphrontDuplicateKeyQueryException) called at [<phabricator>/src/aphront/configuration/AphrontApplicationConfiguration.php:644]
[Mon Sep 05 12:15:33.640870 2016] [:error] [pid 50608] [client 127.0.0.1:55278] #16 AphrontApplicationConfiguration::handleException(AphrontDuplicateKeyQueryException) called at [<phabricator>/src/aphront/configuration/AphrontApplicationConfiguration.php:242]
[Mon Sep 05 12:15:33.640873 2016] [:error] [pid 50608] [client 127.0.0.1:55278] #17 AphrontApplicationConfiguration::processRequest(AphrontRequest, PhutilDeferredLog, AphrontPHPHTTPSink, MultimeterControl) called at [<phabricator>/src/aphront/configuration/AphrontApplicationConfiguration.php:149]
[Mon Sep 05 12:15:33.640879 2016] [:error] [pid 50608] [client 127.0.0.1:55278] #18 AphrontApplicationConfiguration::runHTTPRequest(AphrontPHPHTTPSink) called at [<phabricator>/webroot/index.php:17]
```

Reviewers: chad

Reviewed By: chad

Differential Revision: https://secure.phabricator.com/D16494

+45 -18
+11 -11
resources/celerity/map.php
··· 437 437 'rsrc/js/application/search/behavior-reorder-profile-menu-items.js' => 'e2e0a072', 438 438 'rsrc/js/application/search/behavior-reorder-queries.js' => 'e9581f08', 439 439 'rsrc/js/application/slowvote/behavior-slowvote-embed.js' => '887ad43f', 440 - 'rsrc/js/application/transactions/behavior-comment-actions.js' => '06460e71', 440 + 'rsrc/js/application/transactions/behavior-comment-actions.js' => '0300eae6', 441 441 'rsrc/js/application/transactions/behavior-reorder-configs.js' => 'd7a74243', 442 442 'rsrc/js/application/transactions/behavior-reorder-fields.js' => 'b59e1e96', 443 443 'rsrc/js/application/transactions/behavior-show-older-transactions.js' => '94c65b72', ··· 594 594 'javelin-behavior-bulk-job-reload' => 'edf8a145', 595 595 'javelin-behavior-calendar-month-view' => 'fe33e256', 596 596 'javelin-behavior-choose-control' => '327a00d1', 597 - 'javelin-behavior-comment-actions' => '06460e71', 597 + 'javelin-behavior-comment-actions' => '0300eae6', 598 598 'javelin-behavior-config-reorder-fields' => 'b6993408', 599 599 'javelin-behavior-conpherence-drag-and-drop-photo' => 'cf86d16a', 600 600 'javelin-behavior-conpherence-menu' => '1d45c74d', ··· 931 931 'javelin-dom', 932 932 'phabricator-keyboard-shortcut', 933 933 ), 934 + '0300eae6' => array( 935 + 'javelin-behavior', 936 + 'javelin-stratcom', 937 + 'javelin-workflow', 938 + 'javelin-dom', 939 + 'phuix-form-control-view', 940 + 'phuix-icon-view', 941 + 'javelin-behavior-phabricator-gesture', 942 + ), 934 943 '05270951' => array( 935 944 'javelin-util', 936 945 'javelin-magical-init', ··· 944 953 '056da01b' => array( 945 954 'aphront-typeahead-control-css', 946 955 'phui-tag-view-css', 947 - ), 948 - '06460e71' => array( 949 - 'javelin-behavior', 950 - 'javelin-stratcom', 951 - 'javelin-workflow', 952 - 'javelin-dom', 953 - 'phuix-form-control-view', 954 - 'phuix-icon-view', 955 - 'javelin-behavior-phabricator-gesture', 956 956 ), 957 957 '065227cc' => array( 958 958 'javelin-behavior',
+21 -5
src/applications/draft/storage/PhabricatorVersionedDraft.php
··· 55 55 return $draft; 56 56 } 57 57 58 - return id(new PhabricatorVersionedDraft()) 59 - ->setObjectPHID($object_phid) 60 - ->setAuthorPHID($viewer_phid) 61 - ->setVersion((int)$version) 62 - ->save(); 58 + try { 59 + return id(new self()) 60 + ->setObjectPHID($object_phid) 61 + ->setAuthorPHID($viewer_phid) 62 + ->setVersion((int)$version) 63 + ->save(); 64 + } catch (AphrontDuplicateKeyQueryException $ex) { 65 + $duplicate_exception = $ex; 66 + } 67 + 68 + // In rare cases we can race ourselves, and at one point there was a bug 69 + // which caused the browser to submit two preview requests at exactly 70 + // the same time. If the insert failed with a duplicate key exception, 71 + // try to load the colliding row to recover from it. 72 + 73 + $draft = self::loadDraft($object_phid, $viewer_phid); 74 + if ($draft) { 75 + return $draft; 76 + } 77 + 78 + throw $duplicate_exception; 63 79 } 64 80 65 81 public static function purgeDrafts(
+13 -2
webroot/rsrc/js/application/transactions/behavior-comment-actions.js
··· 176 176 JX.DOM.listen(form_node, 'shouldRefresh', null, always_trigger); 177 177 request.start(); 178 178 179 + var old_device = JX.Device.getDevice(); 180 + 179 181 var ondevicechange = function() { 182 + var new_device = JX.Device.getDevice(); 183 + 180 184 var panel = JX.$(config.panelID); 181 - if (JX.Device.getDevice() == 'desktop') { 185 + if (new_device == 'desktop') { 182 186 request.setRateLimit(500); 183 - always_trigger(); 187 + 188 + // Force an immediate refresh if we switched from another device type 189 + // to desktop. 190 + if (old_device != new_device) { 191 + always_trigger(); 192 + } 184 193 } else { 185 194 // On mobile, don't show live previews and only save drafts every 186 195 // 10 seconds. 187 196 request.setRateLimit(10000); 188 197 JX.DOM.hide(panel); 189 198 } 199 + 200 + old_device = new_device; 190 201 }; 191 202 192 203 ondevicechange();