http://www.mediawiki.org/wiki/Special:Code/MediaWiki/95786

Revision: 95786
Author:   catrope
Date:     2011-08-30 15:50:30 +0000 (Tue, 30 Aug 2011)
Log Message:
-----------
RL2: Kill GadgetRepo::createGadget() and make modifyGadget() flexible enough to 
handle both creations and modifications

Modified Paths:
--------------
    branches/RL2/extensions/Gadgets/backend/GadgetRepo.php
    branches/RL2/extensions/Gadgets/backend/LocalGadgetRepo.php

Modified: branches/RL2/extensions/Gadgets/backend/GadgetRepo.php
===================================================================
--- branches/RL2/extensions/Gadgets/backend/GadgetRepo.php      2011-08-30 
15:43:19 UTC (rev 95785)
+++ branches/RL2/extensions/Gadgets/backend/GadgetRepo.php      2011-08-30 
15:50:30 UTC (rev 95786)
@@ -56,22 +56,15 @@
        abstract public function getDB();
        
        /**
-        * Add a new gadget to the repository. Will fail if there is already
-        * a gadget with the same name.
-        * @param $gadget Gadget object
-        * @return Status
-        */
-       abstract public function addGadget( Gadget $gadget );
-       
-       /**
-        * Modify an existing gadget, replacing its metadata with the
+        * Modify a gadget, replacing its metadata with the
         * metadata in the provided Gadget object. The name is taken
-        * from the Gadget object as well. Will fail if there is no
-        * gadget by the same name.
+        * from the Gadget object as well. If no Gadget exists by that name,
+        * it will be created.
         * @param $gadget Gadget object
+        * @param $timestamp Timestamp to record for this action, or current 
timestamp if null
         * @return Status
         */
-       abstract public function modifyGadget( Gadget $gadget );
+       abstract public function modifyGadget( Gadget $gadget, $timestamp = 
null );
        
        /**
         * Irrevocably delete a gadget from the repository. Will fail

Modified: branches/RL2/extensions/Gadgets/backend/LocalGadgetRepo.php
===================================================================
--- branches/RL2/extensions/Gadgets/backend/LocalGadgetRepo.php 2011-08-30 
15:43:19 UTC (rev 95785)
+++ branches/RL2/extensions/Gadgets/backend/LocalGadgetRepo.php 2011-08-30 
15:50:30 UTC (rev 95786)
@@ -42,83 +42,50 @@
                return true;
        }
        
-       public function addGadget( Gadget $gadget ) {
+       public function modifyGadget( Gadget $gadget, $timestamp = null ) {
                if ( !$this->isWriteable() ) {
                        return Status::newFatal( 
'gadget-manager-readonly-repository' );
                }
                
-               // Try to detect a naming conflict beforehand
+               $dbw = $this->getMasterDB();
                $this->loadData();
                $name = $gadget->getName();
-               if ( isset( $this->data[$name] ) ) {
-                       return Status::newFatal( 
'gadget-manager-create-exists', $name );
-               }
-               
                $json = $gadget->getJSON();
-               $dbw = $this->getMasterDB();
-               $ts = $dbw->timestamp();
-               // Use INSERT IGNORE so we don't die when there's a race 
condition causing a naming conflict
-               $dbw->insert( 'gadgets', array( array(
-                               'gd_name' => $name,
-                               'gd_blob' => $json,
-                               'gd_shared' => $gadget->isShared(),
-                               'gd_timestamp' => $ts
-                       ) ), __METHOD__, array( 'IGNORE' )
+               $ts = $dbw->timestamp( $gadget->getTimestamp() );
+               $newTs = $dbw->timestamp( $timestamp );
+               $row = array(
+                       'gd_name' => $name,
+                       'gd_blob' => $json,
+                       'gd_shared' => $gadget->isShared(),
+                       'gd_timestamp' => $newTs
                );
                
-               // Detect naming conflict after the fact
-               if ( $dbw->affectedRows() === 0 ) {
-                       return Status::newFatal( 
'gadget-manager-create-exists', $name );
+               // First INSERT IGNORE the row, in case the gadget doesn't 
already exist
+               $dbw->begin();
+               $created = false;
+               $dbw->insert( 'gadgets', $row, __METHOD__, array( 'IGNORE' ) );
+               $created = $dbw->affectedRows() > 0;
+               // Then UPDATE it if it did already exist
+               if ( !$created ) {
+                       $dbw->update( 'gadgets', $row, array(
+                                       'gd_name' => $name,
+                                       'gd_timestamp <= ' . $dbw->addQuotes( 
$ts ) // for conflict detection
+                               ), __METHOD__
+                       );
                }
+               $dbw->commit();
                
-               // Update our in-object cache
-               // This looks stupid: we have an object that we could be 
caching. But I prefer
-               // to keep $this->data in a consistent format and have 
getGadget() always return
-               // a clone. If it returned a reference to a cached object, the 
caller could change
-               // that object and cause weird things to happen.
-               $this->data[$name] = array( 'json' => $json, 'timestamp' => $ts 
);
-               
-               return Status::newGood();
-       }
-       
-       public function modifyGadget( Gadget $gadget ) {
-               if ( !$this->isWriteable() ) {
-                       return Status::newFatal( 
'gadget-manager-readonly-repository' );
-               }
-               
-               $this->loadData();
-               $name = $gadget->getName();
-               if ( !isset( $this->data[$name] ) ) {
-                       return Status::newFatal( 'gadget-manager-nosuchgadget', 
$name );
-               }
-               
-               $json = $gadget->getJSON();
-               $ts = $gadget->getTimestamp();
-               $dbw = $this->getMasterDB();
-               $newTs = $dbw->timestamp();
-               $dbw->update( 'gadgets', array(
-                               'gd_blob' => $json,
-                               'gd_shared' => $gadget->isShared(),
-                               'gd_timestamp' => $dbw->timestamp()
-                       ), array(
-                               'gd_name' => $name,
-                               'gd_timestamp' => $ts // for conflict detection
-                       ), __METHOD__, array( 'IGNORE' )
-               );
-               
                // Detect conflicts
                if ( $dbw->affectedRows() === 0 ) {
-                       // Some conflict occurred. Either the UPDATE failed 
because the
-                       // timestamp condition didn't match, in which case 
someone else
-                       // modified the gadget concurrently, or it failed to 
find a row
-                       // for this gadget name at all, in which case someone 
else deleted
-                       // the gadget entirely. We don't really care what 
happened, we'll
-                       // just return an error and let the caller figure it 
out.
+                       // Some conflict occurred
                        return Status::newFatal( 
'gadgets-manager-modify-conflict', $name, $ts );
                }
                
                // Update our in-object cache
-               // See comment in addGadget() for an explanation of why it's 
done this way
+               // This looks stupid: we have an object that we could be 
caching. But I prefer
+               // to keep $this->data in a consistent format and have 
getGadget() always return
+               // a clone. If it returned a reference to a cached object, the 
caller could change
+               // that object and cause weird things to happen.
                $this->data[$name] = array( 'json' => $json, 'timestamp' => 
$newTs );
                
                return Status::newGood();
@@ -168,6 +135,8 @@
         * $this->data must call this before accessing $this->data .
         */
        protected function loadData() {
+               // FIXME: Make the cache shared somehow, it's getting 
repopulated for every instance now
+               // FIXME: Reconsider the query-everything behavior; maybe use 
memc?
                if ( is_array( $this->data ) ) {
                        // Already loaded
                        return;


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

Reply via email to