EBernhardson (WMF) has uploaded a new change for review.
https://gerrit.wikimedia.org/r/78313
Change subject: Remove flow_text table
......................................................................
Remove flow_text table
Merged flow_text into flow_revision, it only exists in core for historical
reasons. Any wiki that expects a reasonable amount of content should set
$wgFlowExternalStore so keep the bulk of content outside the revision table.
Change-Id: I5cf3fe8ef0f6edb4328f4355a4abe5bec439446e
---
M flow.sql
M includes/Data/ObjectManager.php
M includes/Data/RevisionStorage.php
M includes/Model/AbstractRevision.php
4 files changed, 64 insertions(+), 71 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Flow
refs/changes/13/78313/1
diff --git a/flow.sql b/flow.sql
index 22aa4af..161cbf0 100644
--- a/flow.sql
+++ b/flow.sql
@@ -106,9 +106,10 @@
rev_user_text varchar(255) binary not null default '',
-- rev_id of parent or null if no previous revision
rev_parent_id binary(16),
-
+ -- comma separated set of ascii flags.
+ rev_flags tinyblob not null,
-- content of the revision
- rev_text_id int unsigned not null,
+ rev_content mediumblob not null,
-- comment attached to revision's flag change
rev_comment varchar(255) binary null,
@@ -118,16 +119,6 @@
-- Prevents inconsistency, but perhaps will hurt inserts?
CREATE UNIQUE INDEX /*i*/flow_revision_unique_parent ON
/*_*/flow_revision (rev_parent_id);
-
-CREATE TABLE /*_*/flow_text (
- -- undecided on uuid, or if table is even neccessary
- -- large wiki should just use external store to distribute
- -- content
- text_id int(10) unsigned not null auto_increment,
- text_content mediumblob not null,
- text_flags tinyblob not null,
- PRIMARY KEY (text_id)
-) /*$wgDBTableOptions*/;
-- Closure table implementation of tree storage in sql
-- We may be able to go simpler than this
diff --git a/includes/Data/ObjectManager.php b/includes/Data/ObjectManager.php
index 3d1d999..0a5dbaa 100644
--- a/includes/Data/ObjectManager.php
+++ b/includes/Data/ObjectManager.php
@@ -50,7 +50,9 @@
// Note that while ObjectLocator implements the above ObjectStorage interface,
ObjectManger
// cant use this interface because backing stores deal in rows, and OM deals
in objects.
interface WritableObjectStorage extends ObjectStorage {
- function insert( array $row );
+ // this is a reference to allow external store inside RevisionStorage
to utilize
+ // external store and effect updates to the cached values
+ function insert( array &$row );
function update( array $old, array $new );
function remove( array $row );
}
@@ -465,7 +467,7 @@
$this->primaryKey = $primaryKey;
}
- public function insert( array $row ) {
+ public function insert( array &$row ) {
// insert returns boolean true/false
return $this->dbFactory->getDB( DB_MASTER )->insert(
$this->table,
diff --git a/includes/Data/RevisionStorage.php
b/includes/Data/RevisionStorage.php
index aa05ce4..532a12a 100644
--- a/includes/Data/RevisionStorage.php
+++ b/includes/Data/RevisionStorage.php
@@ -10,7 +10,7 @@
use User;
abstract class RevisionStorage implements WritableObjectStorage {
- static protected $allowedUpdateColumns = array( 'text_flags' );
+ static protected $allowedUpdateColumns = array( 'rev_flags' );
protected $dbFactory;
protected $externalStores;
@@ -40,15 +40,12 @@
protected function findInternal( array $attributes, array $options =
array() ) {
$dbr = $this->dbFactory->getDB( DB_MASTER );
$res = $dbr->select(
- array( $this->joinTable(), 'rev' => 'flow_revision',
'text' => 'flow_text' ),
+ array( $this->joinTable(), 'rev' => 'flow_revision' ),
'*',
UUID::convertUUIDs( $attributes ),
__METHOD__,
$options,
- array(
- 'rev' => array( 'JOIN', $this->joinField() . '
= rev_id' ),
- 'text' => array( 'JOIN', "text_id =
rev_text_id" ),
- )
+ array( 'rev' => array( 'JOIN', $this->joinField() . ' =
rev_id' ) )
);
if ( !$res ) {
return null;
@@ -69,7 +66,7 @@
if ( $this->externalStore ) {
$res = Merger::mergeMulti(
$res,
- 'text_content',
+ 'rev_content',
array( 'ExternalStore', 'batchFetchFromURLs' )
);
}
@@ -77,8 +74,8 @@
// decompress content
foreach ( $res as &$record ) {
foreach ( $record as $id => &$row ) {
- $flags = explode( ',', $row['text_flags'] );
- $row['text_content'] =
\Revision::decompressRevisionText( $row['text_content'], $flags );
+ $flags = explode( ',', $row['rev_flags'] );
+ $row['rev_content'] =
\Revision::decompressRevisionText( $row['rev_content'], $flags );
}
}
@@ -167,16 +164,12 @@
// JOIN flow_revision ON tree_rev_id = rev_id
// WHERE tree_rev_id IN (...)
$res = $dbr->select(
- array( 'flow_revision', 'text' => 'flow_text', 'rev' =>
$this->joinTable() ),
+ array( 'flow_revision', 'rev' => $this->joinTable() ),
'*',
array( 'rev_id' => $revisionIds ),
__METHOD__,
array(),
- array(
- 'rev' => array( 'JOIN', "rev_id = $joinField" ),
- // not efficient, likely to pull same content
multiple times.
- 'text' => array( 'JOIN', "text_id =
rev_text_id" ),
- )
+ array( 'rev' => array( 'JOIN', "rev_id = $joinField" ) )
);
if ( !$res ) {
// TODO: dont fail, but dont end up caching bad result
either
@@ -213,12 +206,28 @@
}
}
- public function insert( array $row ) {
- if ( !isset( $row['rev_text_id'] ) ) {
- $row['rev_text_id'] = $this->insertContent(
$row['text_content'], $row['text_flags'] );
- }
- unset( $row['text_content'], $row['text_flags'] );
+ /**
+ * We take $row as a reference because we *must* be able to effect the
cached content
+ * of $row. This is specifically required so that external store can
change the content
+ * into a url pointing to the content and adjust its flags. The other
alternative would
+ * be to invent an onBeforeInsert lifecycle event.
+ */
+ public function insert( array &$row ) {
+ // Check if we need to insert new content
list( $rev, $related ) = $this->splitUpdate( $row );
+ if ( $this->externalStore ) {
+ // There is no rev_content_url field, it exists only
for external store data
+ if ( isset( $row['rev_content_url'] ) ) {
+ $rev['rev_content'] = $row['rev_content_url'];
+ } else {
+ list( $url, $flags ) = $this->insertContent(
$row['rev_content'], $row['rev_flags'] );
+ // This adds, through the $row reference, the
rev_content_url and the flags to the cached values
+ $row['rev_content_url'] = $rev['rev_content'] =
$url;
+ $row['rev_flags'] = $rev['rev_flags'] = $flags;
+ }
+ }
+ // This is a pseudo-field that never goes to database
+ unset( $rev['rev_content_url'] );
$dbw = $this->dbFactory->getDB( DB_MASTER );
$res = $dbw->insert(
'flow_revision',
@@ -236,27 +245,16 @@
protected function insertContent( $data, $flags = '' ) {
$compressionFlags = \Revision::compressRevisionText( $data );
$flags = array_merge( explode( ',', $flags ), explode( ',',
$compressionFlags ) );
- $flags = array_filter( $flags );
+ $flags = array_unique( array_filter( $flags ) );
- if ( $this->externalStore ) {
- // Store and get the URL
- $data = ExternalStore::insertWithFallback(
$this->externalStore, $data );
- if ( !$data ) {
- throw new \MWException( "Unable to store text
to external storage" );
- }
- $flags[] = 'external';
+ // Store and get the URL
+ $url = ExternalStore::insertWithFallback( $this->externalStore,
$data );
+ if ( !$url ) {
+ throw new \MWException( "Unable to store text to
external storage" );
}
+ $flags[] = 'external';
- $dbw = $this->dbFactory->getDB( DB_MASTER );
- $dbw->insert(
- 'flow_text',
- array(
- 'text_content' => $data,
- 'text_flags' => implode( ',', array_unique(
$flags ) ),
- ),
- __METHOD__
- );
- return $dbw->insertId();
+ return array( $url, implode( ',', $flags ) );
}
// This is to *UPDATE* a revision. It should hardly ever be used.
@@ -443,9 +441,10 @@
* @param callable $callable Callable receiving array of foreign keys
returning map
* from foreign key to its value
* @param string $name Name to merge loaded foreign data as. If
null uses $fromKey.
+ * @param string $default Value to use when no matching foreign
value can be located
* @return array $source array with all found foreign key values merged
*/
- static public function merge( array $source, $fromKey, $callable, $name
= null ) {
+ static public function merge( array $source, $fromKey, $callable, $name
= null, $default = '' ) {
if ( $name === null ) {
$name = $fromKey;
}
@@ -458,9 +457,10 @@
}
foreach ( $source as $idx => $row ) {
$id = $row[$fromKey];
- if ( isset( $res[$id] ) ) {
- $source[$idx][$name] = $res[$id];
+ if ( $name === $fromKey ) {
+ $source[$idx]["{$name}_url"] =
$source[$idx][$name];
}
+ $source[$idx][$name] = isset( $res[$id] ) ? $res[$id] :
$default;
}
return $source;
}
@@ -468,7 +468,7 @@
/**
* Same as self::merge, but for 3-dimensional source arrays
*/
- static public function mergeMulti( array $multiSource, $fromKey,
$callable, $name = null ) {
+ static public function mergeMulti( array $multiSource, $fromKey,
$callable, $name = null, $default = '' ) {
if ( $name === null ) {
$name = $fromKey;
}
@@ -484,9 +484,10 @@
foreach ( $multiSource as $i => $source ) {
foreach ( $source as $j => $row ) {
$id = $row[$fromKey];
- if ( isset( $res[$id] ) ) {
- $multiSource[$i][$j][$name] = $res[$id];
+ if ( $name === $fromKey ) {
+ $source[$idx]["{$name}_url"] =
$source[$idx][$name];
}
+ $multiSource[$i][$j][$name] = isset( $res[$id]
) ? $res[$id] : $default;
}
}
return $multiSource;
diff --git a/includes/Model/AbstractRevision.php
b/includes/Model/AbstractRevision.php
index c0fedcd..a981866 100644
--- a/includes/Model/AbstractRevision.php
+++ b/includes/Model/AbstractRevision.php
@@ -6,7 +6,6 @@
abstract class AbstractRevision {
protected $revId;
- protected $textId;
protected $userId;
protected $userText;
protected $flags = array();
@@ -20,6 +19,8 @@
protected $contentModel;
protected $contentFormat;
protected $content;
+ // Only populated when external store is in use
+ protected $contentUrl;
static public function fromStorageRow( array $row ) {
$obj = new static;
@@ -35,10 +36,12 @@
$obj->userText = $row['rev_user_text'];
$obj->prevRevision = UUID::create( $row['rev_parent_id'] );
$obj->comment = $row['rev_comment'];
-
- $obj->textId = $row['rev_text_id'];
- $obj->content = $row['text_content'];
- $obj->flags = explode( ',', $row['text_flags'] );
+ $obj->content = $row['rev_content'];
+ if ( isset( $row['rev_content_url'] ) ) {
+ // only exists when external store is being used
+ $obj->contentUrl = $row['rev_content_url'];
+ }
+ $obj->flags = explode( ',', $row['rev_flags'] );
return $obj;
}
@@ -49,11 +52,11 @@
'rev_user_text' => $obj->userText,
'rev_parent_id' => $obj->prevRevision ?
$obj->prevRevision->getBinary() : null,
'rev_comment' => $obj->comment,
- 'rev_text_id' => $obj->textId,
'rev_type' => $obj->getRevisionType(),
- 'text_content' => $obj->content,
- 'text_flags' => implode( ',', $obj->flags ),
+ 'rev_content' => $obj->content,
+ 'rev_content_url' => $obj->contentUrl,
+ 'rev_flags' => implode( ',', $obj->flags ),
);
}
@@ -73,7 +76,7 @@
$obj->flags = array();
if ( $content !== $obj->content ) {
$obj->content = $content;
- $obj->textId = null;
+ $obj->contentUrl = null;
}
return $obj;
}
@@ -87,10 +90,6 @@
throw new \MWException( 'Content not loaded' );
}
return $this->content;
- }
-
- public function getTextId() {
- return $this->textId; // not available on creation
}
public function getPrevRevisionId() {
--
To view, visit https://gerrit.wikimedia.org/r/78313
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I5cf3fe8ef0f6edb4328f4355a4abe5bec439446e
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Flow
Gerrit-Branch: master
Gerrit-Owner: EBernhardson (WMF) <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits