Page MenuHomePhabricator

AphrontCountQueryException when deleting a draft comment
Closed, InvalidPublic

Description

Over the past month, a number of engineers using our Phabricator installation have reported not being able to delete draft comments. They get a 500 error and in some of these cases, Phabricator hangs.

The logs from the most recent report show:

[2015-01-20 12:54:07] EXCEPTION: (AphrontCountQueryException) More than 1 result from loadOneWhere()! at [<phabricator>/src/infrastructure/storage/lisk/LiskDAO.php:476]
 #0 LiskDAO::loadOneWhere(string, string, string, string) called at [<phabricator>/src/applications/differential/storage/DifferentialDraft.php:46]
 #1 DifferentialDraft::deleteHasDraft(string, string, string) called at [<phabricator>/src/applications/differential/controller/DifferentialInlineCommentEditController.php:82]
 #2 DifferentialInlineCommentEditController::deleteComment(DifferentialInlineComment) called at [<phabricator>/src/infrastructure/diff/PhabricatorInlineCommentController.php:67]
 #3 PhabricatorInlineCommentController::processRequest() called at [<phabricator>/src/aphront/AphrontController.php:33]
 #4 AphrontController::handleRequest(AphrontRequest) called at [<phabricator>/src/aphront/configuration/AphrontApplicationConfiguration.php:196]
 #5 AphrontApplicationConfiguration::processRequest(AphrontRequest, PhutilDeferredLog, AphrontPHPHTTPSink) called at [<phabricator>/src/aphront/configuration/AphrontApplicationConfiguration.php:121]
 #6 AphrontApplicationConfiguration::runHTTPRequest(AphrontPHPHTTPSink) called at [<phabricator>/webroot/index.php:19]

PHP Fatal error: Uncaught exception 'Exception' with message 'Process exited with an open transaction! The transaction will be implicitly rolled back. Calls to openTransaction() must always be paired with a call to saveTransaction() or killTransaction().' in /phab_path/libphutil/src/aphront/storage/connection/AphrontDatabaseTransactionState.php:69\nStack trace:\n#0 [internal function]: AphrontDatabaseTransactionState->__destruct()\n#1 {main}\n thrown in /phab_path/libphutil/src/aphront/storage/connection/AphrontDatabaseTransactionState.php on line 69

And the browser reports seeing a 200 followed by a 500:

pasted_file (119×1 px, 32 KB)

The exception makes me believe that a duplicate comment was created, but I'm not sure why that would happen. Any idea what might be going on here?

Event Timeline

aroravishal raised the priority of this task from to Needs Triage.
aroravishal updated the task description. (Show Details)
aroravishal added a project: Differential.
aroravishal added a subscriber: aroravishal.

Can you provide reproduction instructions that work on this install?
Can you also verify that your installation is 100% up to date and this still reproduces?

My guess is that somehow your database is missing a unique key key_unique on differential_draft.

mysql> show create table differential_draft;
+--------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table              | Create Table                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
+--------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| differential_draft | CREATE TABLE `differential_draft` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `objectPHID` varbinary(64) NOT NULL,
  `authorPHID` varbinary(64) NOT NULL,
  `draftKey` varchar(64) COLLATE utf8mb4_bin NOT NULL,
  `dateCreated` int(10) unsigned NOT NULL,
  `dateModified` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `key_unique` (`objectPHID`,`authorPHID`,`draftKey`)
) ENGINE=InnoDB AUTO_INCREMENT=100 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin |

...as the pertinent bit of code via the trace is making a query on these three columns.

What version of Phabricator are you running?

We're running commit SHA 5b3b9b7182ae4a5ce8e34763bb44711792abcb1d

Can you provide reproduction instructions that work on this install?
Can you also verify that your installation is 100% up to date and this still reproduces?

The stack trace reproduces consistently for any "bad" comment. But it's unclear how comments end up in the "bad" state. Perhaps there's some race condition?

My guess is that somehow your database is missing a unique key key_unique on differential_draft.

Yes, it's missing a unique key key_unique on differential_draft. The last update failed to create that unique key because there were duplicates :-)

What's the best way to remove all duplicates and create the key?

You can do this to remove duplicates and add the key:

phabricator/ $ # First, stop your webserver so users don't mess with stuff while you're doing this.
phabricator/ $ ./bin/storage upgrade --apply phabricator:20141106.uniqdrafts.php --force
phabricator/ $ ./bin/storage adjust --force

The upgrade --apply will delete duplicates. The adjust --force will then be able to add the key.

EDIT - see @epriestley's much better response above

I am no mysql query expert, but you want to write a query that can find these rows, e.g.

http://stackoverflow.com/questions/7076766/select-rows-having-2-columns-equal-value

...and then you'll have to delete them manually or re-jigger the query to just delete them all. If you want to preserve at least one inline comment per revision that would be more complicated / probably best done manually if you just have a few rows.

We have quite a few duplicate rows (a considerable % of our comments apparently from what I can tell). Will the upgrade --apply preserve one comment (and only delete duplicates) or will it delete all copies of a duplicated comment?

Just confirming we won't lose data :-) And that it's expected that Differential might end up with duplicates if this key doesn't exist.

Thank you!

btrahan claimed this task.

It leaves the most recent draft and deletes the rest.

Phabricator requires that the update process is run successfully to completion to work; in your case, skipping this part of the storage upgrade process resulted in this error.