Mattflaschen has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/251415

Change subject: Add artificial primary key to flow_wiki_ref and flow_ext_ref
......................................................................

Add artificial primary key to flow_wiki_ref and flow_ext_ref

The newly added ref_id is not used in the code, it's
only meant to make DB maintenance easier.
There shouldn't be any conflicts with old/new records being
confused with each other since the code is mostly unaware
of this ID: it still uses all the other columns as "fake"
PK (to compare records when figuring out if references are
new)

Deployment plan:
* Run db-patches/patch-ref_id-phase1.sql (prepare schema)
* Merge & deploy this code (start writing to ref_id)
* Run maintenance/FlowPopulateRefId.php (migrate existing ref_id)
* Run db-patches/patch-ref_id-phase2.sql (make not null & PK)

Bug: T109676
Change-Id: Icd1673ed642efc838809ae249f9544a364962886
(cherry picked from commit 9ca081f7675cd3a1e23bac1eb9c04d539fb47f6d)
---
M Hooks.php
A db_patches/patch-ref_id-phase1.sql
A db_patches/patch-ref_id-phase2.sql
A db_patches/patch-ref_id-phase2.sqlite.sql
M flow.sql
M includes/Model/Reference.php
M includes/Model/URLReference.php
M includes/Model/WikiReference.php
M includes/Parsoid/ReferenceFactory.php
A maintenance/FlowPopulateRefId.php
10 files changed, 198 insertions(+), 16 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Flow 
refs/changes/15/251415/1

diff --git a/Hooks.php b/Hooks.php
index c3249b1..f94bc0b 100644
--- a/Hooks.php
+++ b/Hooks.php
@@ -230,6 +230,7 @@
                $updater->dropExtensionIndex( 'flow_ext_ref', 
'flow_ext_ref_pk', "$dir/db_patches/patch-remove_unique_ref_indices.sql" );
                $updater->addExtensionIndex( 'flow_workflow', 
'flow_workflow_update_timestamp', 
"$dir/db_patches/patch-flow_workflow_update_timestamp_idx.sql" );
                $updater->addExtensionField( 'flow_wiki_ref', 'ref_src_wiki', 
"$dir/db_patches/patch-reference_wiki.sql" );
+               $updater->addExtensionField( 'flow_wiki_ref', 'ref_id', 
"$dir/db_patches/patch-ref_id-phase1.sql" );
 
                require_once __DIR__.'/maintenance/FlowUpdateRecentChanges.php';
                $updater->addPostDatabaseUpdateMaintenance( 
'FlowUpdateRecentChanges' );
@@ -272,6 +273,21 @@
                require_once 
__DIR__.'/maintenance/FlowUpdateBetaFeaturePreference.php';
                $updater->addPostDatabaseUpdateMaintenance( 
'FlowUpdateBetaFeaturePreference' );
 
+               require_once __DIR__.'/maintenance/FlowPopulateRefId.php';
+               $updater->addPostDatabaseUpdateMaintenance( 'FlowPopulateRefId' 
);
+
+               /*
+                * Add primary key, but only after we've made sure the newly 
added
+                * column has been populated (otherwise they'd all be null 
values)
+                */
+               if ( $updater->updateRowExists( 'FlowPopulateRefId' ) ) {
+                       if ( $updater->getDB()->getType() === 'sqlite' ) {
+                               $updater->addExtensionIndex( 'flow_wiki_ref', 
'PRIMARY', "$dir/db_patches/patch-ref_id-phase2.sqlite.sql" );
+                       } else {
+                               $updater->addExtensionIndex( 'flow_wiki_ref', 
'PRIMARY', "$dir/db_patches/patch-ref_id-phase2.sql" );
+                       }
+               }
+
                return true;
        }
 
diff --git a/db_patches/patch-ref_id-phase1.sql 
b/db_patches/patch-ref_id-phase1.sql
new file mode 100644
index 0000000..4ab5393
--- /dev/null
+++ b/db_patches/patch-ref_id-phase1.sql
@@ -0,0 +1,2 @@
+ALTER TABLE /*_*/flow_wiki_ref ADD COLUMN ref_id binary(11) null;
+ALTER TABLE /*_*/flow_ext_ref ADD COLUMN ref_id binary(11) null;
diff --git a/db_patches/patch-ref_id-phase2.sql 
b/db_patches/patch-ref_id-phase2.sql
new file mode 100644
index 0000000..6ae67e5
--- /dev/null
+++ b/db_patches/patch-ref_id-phase2.sql
@@ -0,0 +1,5 @@
+ALTER TABLE /*_*/flow_wiki_ref CHANGE ref_id ref_id BINARY(11) NOT NULL;
+ALTER TABLE /*_*/flow_ext_ref CHANGE ref_id ref_id BINARY(11) NOT NULL;
+
+ALTER TABLE /*_*/flow_wiki_ref ADD PRIMARY KEY (ref_id);
+ALTER TABLE /*_*/flow_ext_ref ADD PRIMARY KEY (ref_id);
diff --git a/db_patches/patch-ref_id-phase2.sqlite.sql 
b/db_patches/patch-ref_id-phase2.sqlite.sql
new file mode 100644
index 0000000..cbfebc6
--- /dev/null
+++ b/db_patches/patch-ref_id-phase2.sqlite.sql
@@ -0,0 +1,65 @@
+-- SQLite won't allow us to just alter the columns, so we'll move this table
+-- out of the way, create it anew the way we want it, and then copy the
+-- data over before dropping the old table
+ALTER TABLE /*_*/flow_wiki_ref RENAME TO /*_*/temp_flow_wiki_ref;
+ALTER TABLE /*_*/flow_ext_ref RENAME TO /*_*/temp_flow_ext_ref;
+
+
+CREATE TABLE /*_*/flow_wiki_ref (
+       ref_id binary(11) not null,
+       ref_src_wiki varchar(16) binary not null,
+       ref_src_object_id binary(11) not null,
+       ref_src_object_type varbinary(32) not null,
+       ref_src_workflow_id binary(11) not null,
+       ref_src_namespace int not null,
+       ref_src_title varbinary(255) not null,
+       ref_target_namespace int not null,
+       ref_target_title varbinary(255) not null,
+       ref_type varbinary(16) not null,
+
+       PRIMARY KEY (ref_id)
+) /*$wgDBTableOptions*/;
+
+CREATE INDEX /*i*/flow_wiki_ref_idx_v2 ON /*_*/flow_wiki_ref
+       (ref_src_wiki, ref_src_namespace, ref_src_title, ref_type, 
ref_target_namespace, ref_target_title, ref_src_object_type, ref_src_object_id);
+
+CREATE INDEX /*i*/flow_wiki_ref_revision_v2 ON /*_*/flow_wiki_ref
+       (ref_src_wiki, ref_src_namespace, ref_src_title, ref_src_object_type, 
ref_src_object_id, ref_type, ref_target_namespace, ref_target_title);
+
+CREATE TABLE /*_*/flow_ext_ref (
+       ref_id binary(11) not null,
+       ref_src_wiki varchar(16) binary not null,
+       ref_src_object_id binary(11) not null,
+       ref_src_object_type varbinary(32) not null,
+       ref_src_workflow_id binary(11) not null,
+       ref_src_namespace int not null,
+       ref_src_title varbinary(255) not null,
+       ref_target blob not null,
+       ref_type varbinary(16) not null,
+
+       PRIMARY KEY (ref_id)
+) /*$wgDBTableOptions*/;
+
+CREATE INDEX /*i*/flow_ext_ref_idx_v2 ON /*_*/flow_ext_ref
+       (ref_src_wiki, ref_src_namespace, ref_src_title, ref_type, 
ref_target(255), ref_src_object_type, ref_src_object_id);
+
+CREATE INDEX /*i*/flow_ext_ref_revision_v2 ON /*_*/flow_ext_ref
+       (ref_src_wiki, ref_src_namespace, ref_src_title, ref_src_object_type, 
ref_src_object_id, ref_type, ref_target(255));
+
+
+INSERT INTO /*_*/flow_wiki_ref
+       (ref_id, ref_src_wiki, ref_src_object_id, ref_src_object_type, 
ref_src_workflow_id, ref_src_namespace, ref_src_title, ref_target_namespace, 
ref_target_title, ref_type)
+SELECT
+       ref_id, ref_src_wiki, ref_src_object_id, ref_src_object_type, 
ref_src_workflow_id, ref_src_namespace, ref_src_title, ref_target_namespace, 
ref_target_title, ref_type
+FROM
+       /*_*/temp_flow_wiki_ref;
+
+INSERT INTO /*_*/flow_ext_ref
+       (ref_id, ref_src_wiki, ref_src_object_id, ref_src_object_type, 
ref_src_workflow_id, ref_src_namespace, ref_src_title, ref_target, ref_type)
+SELECT
+       ref_id, ref_src_wiki, ref_src_object_id, ref_src_object_type, 
ref_src_workflow_id, ref_src_namespace, ref_src_title, ref_target, ref_type
+FROM
+       /*_*/temp_flow_ext_ref;
+
+DROP TABLE /*_*/temp_flow_wiki_ref;
+DROP TABLE /*_*/temp_flow_ext_ref;
diff --git a/flow.sql b/flow.sql
index cb48050..f6365b1 100644
--- a/flow.sql
+++ b/flow.sql
@@ -139,6 +139,7 @@
 CREATE UNIQUE INDEX /*i*/flow_tree_constraint ON /*_*/flow_tree_node 
(tree_descendant_id, tree_depth);
 
 CREATE TABLE /*_*/flow_wiki_ref (
+       ref_id binary(11) not null,
        ref_src_wiki varchar(16) binary not null,
        ref_src_object_id binary(11) not null,
        ref_src_object_type varbinary(32) not null,
@@ -147,7 +148,9 @@
        ref_src_title varbinary(255) not null,
        ref_target_namespace int not null,
        ref_target_title varbinary(255) not null,
-       ref_type varbinary(16) not null
+       ref_type varbinary(16) not null,
+
+       PRIMARY KEY (ref_id)
 ) /*$wgDBTableOptions*/;
 
 CREATE INDEX /*i*/flow_wiki_ref_idx_v2 ON /*_*/flow_wiki_ref
@@ -157,6 +160,7 @@
        (ref_src_wiki, ref_src_namespace, ref_src_title, ref_src_object_type, 
ref_src_object_id, ref_type, ref_target_namespace, ref_target_title);
 
 CREATE TABLE /*_*/flow_ext_ref (
+       ref_id binary(11) not null,
        ref_src_wiki varchar(16) binary not null,
        ref_src_object_id binary(11) not null,
        ref_src_object_type varbinary(32) not null,
@@ -164,7 +168,9 @@
        ref_src_namespace int not null,
        ref_src_title varbinary(255) not null,
        ref_target blob not null,
-       ref_type varbinary(16) not null
+       ref_type varbinary(16) not null,
+
+       PRIMARY KEY (ref_id)
 ) /*$wgDBTableOptions*/;
 
 CREATE INDEX /*i*/flow_ext_ref_idx_v2 ON /*_*/flow_ext_ref
diff --git a/includes/Model/Reference.php b/includes/Model/Reference.php
index 8853954..fa52657 100644
--- a/includes/Model/Reference.php
+++ b/includes/Model/Reference.php
@@ -11,6 +11,11 @@
        /**
         * @var UUID
         */
+       protected $id;
+
+       /**
+        * @var UUID
+        */
        protected $workflowId;
 
        /**
@@ -43,15 +48,17 @@
        /**
         * Standard constructor. Called from subclasses only
         *
-        * @param String $wiki Wiki ID of the reference source
+        * @param UUID   $id          Id of the reference
+        * @param string $wiki        Wiki ID of the reference source
         * @param UUID   $srcWorkflow Source Workflow's ID
         * @param Title  $srcTitle    Title of the Workflow from which this 
reference comes.
-        * @param String $objectType  Output of getRevisionType for the 
AbstractRevision that this reference comes from.
+        * @param string $objectType  Output of getRevisionType for the 
AbstractRevision that this reference comes from.
         * @param UUID   $objectId    Unique identifier for the revisioned 
object containing the reference.
         * @param string $type        The type of reference
         * @throws InvalidReferenceException
         */
-       protected function __construct( $wiki, UUID $srcWorkflow, Title 
$srcTitle, $objectType, UUID $objectId, $type ) {
+       protected function __construct( UUID $id, $wiki, UUID $srcWorkflow, 
Title $srcTitle, $objectType, UUID $objectId, $type ) {
+               $this->id = $id;
                $this->wikiId = $wiki;
                $this->workflowId = $srcWorkflow;
                $this->objectType = $objectType;
@@ -125,6 +132,7 @@
         */
        public function getStorageRow() {
                return array(
+                       'ref_id' => $this->id->getAlphadecimal(),
                        'ref_src_wiki' => $this->wikiId,
                        'ref_src_workflow_id' => 
$this->workflowId->getAlphadecimal(),
                        'ref_src_namespace' => $this->srcTitle->getNamespace(),
diff --git a/includes/Model/URLReference.php b/includes/Model/URLReference.php
index 9111d3f..de4c13f 100644
--- a/includes/Model/URLReference.php
+++ b/includes/Model/URLReference.php
@@ -9,16 +9,17 @@
        protected $url;
 
        /**
-        * @param String $wiki Wiki ID of the reference source
+        * @param UUID   $id          Id of the reference
+        * @param string $wiki        Wiki ID of the reference source
         * @param UUID   $srcWorkflow ID of the source Workflow
         * @param Title  $srcTitle    Title of the page that the Workflow 
exists on
-        * @param String $objectType  Output of getRevisionType for the 
AbstractRevision that this reference comes from.
+        * @param string $objectType  Output of getRevisionType for the 
AbstractRevision that this reference comes from.
         * @param UUID   $objectId    Unique identifier for the revisioned 
object containing the reference.
         * @param string $type        Type of reference
         * @param string $url         URL of the reference's target.
         * @throws InvalidReferenceException
         */
-       public function __construct( $wiki, UUID $srcWorkflow, Title $srcTitle, 
$objectType, UUID $objectId, $type, $url ) {
+       public function __construct( UUID $id, $wiki, UUID $srcWorkflow, Title 
$srcTitle, $objectType, UUID $objectId, $type, $url ) {
                $this->url = $url;
 
                if ( !is_array( wfParseUrl( $url ) ) ) {
@@ -27,7 +28,7 @@
                        );
                }
 
-               parent::__construct( $wiki, $srcWorkflow, $srcTitle, 
$objectType, $objectId, $type );
+               parent::__construct( $id, $wiki, $srcWorkflow, $srcTitle, 
$objectType, $objectId, $type );
        }
 
        /**
@@ -44,10 +45,13 @@
        /**
         * Instantiates a URLReference object from a storage row.
         *
-        * @param  \StdClass $row
+        * @param  array $row
         * @return URLReference
         */
        public static function fromStorageRow( $row ) {
+               // TODO: Remove this UUID::create() call when the field is 
populated
+               // everywhere relevant.
+               $id = $row['ref_id'] === null ? UUID::create() : UUID::create( 
$row['ref_id'] );
                $workflow = UUID::create( $row['ref_src_workflow_id'] );
                $objectType = $row['ref_src_object_type'];
                $objectId = UUID::create( $row['ref_src_object_id'] );
@@ -56,7 +60,7 @@
                $srcTitle = Title::makeTitle( $row['ref_src_namespace'], 
$row['ref_src_title'] );
                $wiki = $row['ref_src_wiki'];
 
-               return new URLReference( $wiki, $workflow, $srcTitle, 
$objectType, $objectId, $type, $url );
+               return new URLReference( $id, $wiki, $workflow, $srcTitle, 
$objectType, $objectId, $type, $url );
        }
 
        /**
diff --git a/includes/Model/WikiReference.php b/includes/Model/WikiReference.php
index d36e2d0..086c31f 100644
--- a/includes/Model/WikiReference.php
+++ b/includes/Model/WikiReference.php
@@ -13,7 +13,8 @@
        protected $target;
 
        /**
-        * @param String $wiki Wiki ID of the reference source
+        * @param UUID   $id          Id of the reference
+        * @param string $wiki        Wiki ID of the reference source
         * @param UUID   $srcWorkflow ID of the source Workflow
         * @param Title  $srcTitle    Title of the Workflow from which this 
reference comes.
         * @param string $objectType  Output of getRevisionType for the 
AbstractRevision that this reference comes from.
@@ -21,7 +22,7 @@
         * @param string $type        Type of reference
         * @param Title  $targetTitle Title of the reference's target.
         */
-       public function __construct( $wiki, UUID $srcWorkflow, Title $srcTitle, 
$objectType, UUID $objectId, $type, Title $targetTitle ) {
+       public function __construct( UUID $id, $wiki, UUID $srcWorkflow, Title 
$srcTitle, $objectType, UUID $objectId, $type, Title $targetTitle ) {
                $this->target = $targetTitle;
 
                $this->validTypes = array_merge( $this->validTypes,
@@ -32,7 +33,7 @@
                        )
                );
 
-               parent::__construct( $wiki, $srcWorkflow, $srcTitle, 
$objectType, $objectId, $type );
+               parent::__construct( $id, $wiki, $srcWorkflow, $srcTitle, 
$objectType, $objectId, $type );
        }
 
        /**
@@ -50,10 +51,13 @@
        /**
         * Instantiates a WikiReference object from a storage row.
         *
-        * @param  \StdClass $row
+        * @param  array $row
         * @return WikiReference
         */
        public static function fromStorageRow( $row ) {
+               // TODO: Remove this UUID::create() call when the field is 
populated
+               // everywhere relevant.
+               $id = $row['ref_id'] === null ? UUID::create() : UUID::create( 
$row['ref_id'] );
                $workflow = UUID::create( $row['ref_src_workflow_id'] );
                $objectType = $row['ref_src_object_type'];
                $objectId = UUID::create( $row['ref_src_object_id'] );
@@ -62,7 +66,7 @@
                $type = $row['ref_type'];
                $wiki = $row['ref_src_wiki'];
 
-               return new WikiReference( $wiki, $workflow, $srcTitle, 
$objectType, $objectId, $type, $targetTitle );
+               return new WikiReference( $id, $wiki, $workflow, $srcTitle, 
$objectType, $objectId, $type, $targetTitle );
        }
 
        /**
diff --git a/includes/Parsoid/ReferenceFactory.php 
b/includes/Parsoid/ReferenceFactory.php
index 5e768be..1646faa 100644
--- a/includes/Parsoid/ReferenceFactory.php
+++ b/includes/Parsoid/ReferenceFactory.php
@@ -54,6 +54,7 @@
         */
        public function createUrlReference( $refType, $value ) {
                return new URLReference(
+                       UUID::create(),
                        $this->wikiId,
                        $this->workflowId,
                        $this->title,
@@ -82,6 +83,7 @@
                }
 
                return new WikiReference(
+                       UUID::create(),
                        $this->wikiId,
                        $this->workflowId,
                        $this->title,
diff --git a/maintenance/FlowPopulateRefId.php 
b/maintenance/FlowPopulateRefId.php
new file mode 100644
index 0000000..1879170
--- /dev/null
+++ b/maintenance/FlowPopulateRefId.php
@@ -0,0 +1,70 @@
+<?php
+
+use Flow\Container;
+use Flow\Data\ObjectManager;
+
+$installPath = getenv( 'MW_INSTALL_PATH' ) !== false ?
+       getenv( 'MW_INSTALL_PATH' ) :
+       __DIR__ . '/../../..';
+
+require_once( $installPath . '/maintenance/Maintenance.php' );
+// extending these - autoloader not yet wired up at the point these are 
interpreted
+require_once( $installPath .'/includes/utils/BatchRowWriter.php' );
+require_once( $installPath . '/includes/utils/RowUpdateGenerator.php' );
+
+/**
+ * Populates ref_id in flow_wiki_ref & flow_ext_ref.
+ *
+ * @ingroup Maintenance
+ */
+class FlowPopulateRefId extends LoggedUpdateMaintenance {
+       public function __construct() {
+               parent::__construct();
+
+               $this->mDescription = 'Populates ref_id in flow_wiki_ref & 
flow_ext_ref';
+
+               $this->setBatchSize( 300 );
+       }
+
+       protected function getUpdateKey() {
+               return __CLASS__;
+       }
+
+       protected function doDBUpdates() {
+               $types = array(
+                       'flow_wiki_ref' => Container::get( 
'storage.wiki_reference' ),
+                       'flow_ext_ref' => Container::get( 
'storage.url_reference' ),
+               );
+
+               foreach ( $types as $table => $storage ) {
+                       $this->update( $storage );
+               }
+
+               $this->output( "Completed\n" );
+
+               return true;
+       }
+
+       /**
+        * @param ObjectManager $storage
+        * @throws \Flow\Exception\InvalidInputException
+        */
+       protected function update( ObjectManager $storage ) {
+               global $wgFlowCluster;
+
+               while ( true ) {
+                       $references = (array) $storage->find( array( 'ref_id' 
=> null ), array( 'limit' => $this->mBatchSize ) );
+                       if ( !$references ) {
+                               break;
+                       }
+
+                       $storage->multiPut( $references, array() );
+                       $this->output( "Ensured ref_id for " . count( 
$references ) . " " . get_class( $references[0] ) . " references...\n" );
+                       wfWaitForSlaves( false, false, $wgFlowCluster );
+               }
+
+       }
+}
+
+$maintClass = 'FlowPopulateRefId';
+require_once( RUN_MAINTENANCE_IF_MAIN );

-- 
To view, visit https://gerrit.wikimedia.org/r/251415
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Icd1673ed642efc838809ae249f9544a364962886
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Flow
Gerrit-Branch: wmf/1.27.0-wmf.4
Gerrit-Owner: Mattflaschen <[email protected]>
Gerrit-Reviewer: Matthias Mullie <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to