Page MenuHomePhabricator

`bin/hunks migrate` fails on differential_hunks row with NULL changes field
Closed, ResolvedPublic

Description

Spurred by the 2016 Week 52 release, we're running the migration described in T8623. bin/hunks migrate ran for a while and then failed with this error:

Migrating hunk 75810...
[2017-01-10 02:26:21] EXCEPTION: (AphrontQueryException) #1048: Column 'data' cannot be null at [<phutil>/src/aphront/storage/connection/mysql/AphrontBaseMySQLDatabaseConnection.php:355]
arcanist(head=master, ref.master=d6e112aecf93), phabricator(head=master, ref.master=861ac60e1fb5), phutil(head=master, ref.master=ab80dcf99c6b), pytest-phabricator(head=5be92a18cd4d0b72f70303cc862cbc69e49a3af8, ref.master=1939f1e4f656)
  #0 AphrontBaseMySQLDatabaseConnection::throwQueryCodeException(integer, string) called at [<phutil>/src/aphront/storage/connection/mysql/AphrontBaseMySQLDatabaseConnection.php:289]
  #1 AphrontBaseMySQLDatabaseConnection::throwQueryException(mysqli) called at [<phutil>/src/aphront/storage/connection/mysql/AphrontBaseMySQLDatabaseConnection.php:185]
  #2 AphrontBaseMySQLDatabaseConnection::executeRawQuery(string) called at [<phutil>/src/xsprintf/queryfx.php:8]
  #3 queryfx(AphrontMySQLiDatabaseConnection, string, string, string, array, string)
  #4 call_user_func_array(string, array) called at [<phutil>/src/aphront/storage/connection/AphrontDatabaseConnection.php:58]
  #5 AphrontDatabaseConnection::query(string, string, string, array, string) called at [<phabricator>/src/infrastructure/storage/lisk/LiskDAO.php:1261]
  #6 LiskDAO::insertRecordIntoDatabase(string) called at [<phabricator>/src/infrastructure/storage/lisk/LiskDAO.php:1106]
  #7 LiskDAO::insert() called at [<phabricator>/src/infrastructure/storage/lisk/LiskDAO.php:1075]
  #8 LiskDAO::save() called at [<phabricator>/src/applications/differential/storage/DifferentialModernHunk.php:87]
  #9 DifferentialModernHunk::save() called at [<phabricator>/src/applications/differential/management/PhabricatorHunksManagementMigrateWorkflow.php:36]
  #10 PhabricatorHunksManagementMigrateWorkflow::execute(PhutilArgumentParser) called at [<phutil>/src/parser/argument/PhutilArgumentParser.php:438]
  #11 PhutilArgumentParser::parseWorkflowsFull(array) called at [<phutil>/src/parser/argument/PhutilArgumentParser.php:330]
  #12 PhutilArgumentParser::parseWorkflows(array) called at [<phabricator>/scripts/setup/manage_hunks.php:21]
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:78
Stack trace:
#0 [internal function]: AphrontDatabaseTransactionState->__destruct()
#1 {main}
  thrown in /phab_path/libphutil/src/aphront/storage/connection/AphrontDatabaseTransactionState.php on line 78
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:78
Stack trace:
#0 [internal function]: AphrontDatabaseTransactionState->__destruct()
#1 {main}
  thrown in /phab_path/libphutil/src/aphront/storage/connection/AphrontDatabaseTransactionState.php on line 78

I looked up the troublesome hunk in the differential_hunk table, and it has a NULL in the changes field:

+-------+-------------+---------+-----------+--------+-----------+--------+-------------+--------------+
| id    | changesetID | changes | oldOffset | oldLen | newOffset | newLen | dateCreated | dateModified |
+-------+-------------+---------+-----------+--------+-----------+--------+-------------+--------------+
| 75810 |       91956 | NULL    |         0 |      0 |         1 |      7 |  1345512017 |   1345512017 |
+-------+-------------+---------+-----------+--------+-----------+--------+-------------+--------------+

I did some querying to check the extent of this problem and found 89 hunks split across two diffs from 2012.

We're running 1cd64f9975d66a5fff516cd064cd076b0eb7b07f (which is 2016 Week 50 + fixes).

Event Timeline

I'd be happy just to have a good workaround, since I don't think we're particularly attached to these mostly-contentless rows. My ideas for possibilities so far are:

  • Delete the offending differential_hunks rows manually. I worry that this might cause some inconsistency.
  • bin/destroy the revisions containing the offending hunks. This seems a bit heavy-handed though.
jboning added a project: Restricted Project.Jan 10 2017, 7:50 PM

You should be able to safely update these rows to have '' instead of NULL, then continue:

mysql> UPDATE differential_hunks SET changes = '' WHERE changes IS NULL;

The script should be idempotent, so running it again should e safe.

The script has been removed after we forced the migration, but I'll make the migration itself more robust just in case.

I marked D17168 as fixing this -- it just makes the replacement migration more robust, but I think that's the best we can do from the upstream. No idea how null ended up there in the first place, but I'd guess we have no way to figure it out and our lives would be no richer for knowing.