Aaron Schulz has uploaded a new change for review.
https://gerrit.wikimedia.org/r/188476
Change subject: [WIP] Added WANObectStash class with cassandra subclass
......................................................................
[WIP] Added WANObectStash class with cassandra subclass
bug: T88445
Change-Id: I5e020112954e69fec21c11309847cdcd00330597
---
M autoload.php
A includes/objectstash/WANObjectStash.php
A includes/objectstash/WANObjectStashCassandra.php
3 files changed, 280 insertions(+), 0 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core
refs/changes/76/188476/1
diff --git a/autoload.php b/autoload.php
index 90cd074..4104956 100644
--- a/autoload.php
+++ b/autoload.php
@@ -1275,6 +1275,8 @@
'ViewAction' => __DIR__ . '/includes/actions/ViewAction.php',
'VirtualRESTService' => __DIR__ .
'/includes/libs/virtualrest/VirtualRESTService.php',
'VirtualRESTServiceClient' => __DIR__ .
'/includes/libs/virtualrest/VirtualRESTServiceClient.php',
+ 'WANObjectStash' => __DIR__ .
'/includes/objectstash/WANObjectStash.php',
+ 'WANObjectStashCassandra' => __DIR__ .
'/includes/objectstash/WANObjectStashCassandra.php',
'WaitForSlave' => __DIR__ . '/maintenance/waitForSlave.php',
'WantedCategoriesPage' => __DIR__ .
'/includes/specials/SpecialWantedcategories.php',
'WantedFilesPage' => __DIR__ .
'/includes/specials/SpecialWantedfiles.php',
diff --git a/includes/objectstash/WANObjectStash.php
b/includes/objectstash/WANObjectStash.php
new file mode 100755
index 0000000..57a5dc6
--- /dev/null
+++ b/includes/objectstash/WANObjectStash.php
@@ -0,0 +1,102 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Stash
+ * @author Aaron Schulz
+ */
+
+/**
+ * @defgroup Stash Stash
+ */
+
+/**
+ * Multi-datacenter aware stashing interface
+ *
+ * All operations write to the local cluster stash immediately,
+ * and are broadcasted to the other data centers asynchronously.
+ *
+ * This class is intended for use as an ephemeral primary store.
+ * Callers should also be aware of the increased risk of race
+ * conditions as writes to the same key can happen in different
+ * data centers at the same time, one of them eventually winning.
+ * This store is generally appropriate for temporary data where:
+ * - a) The value is immutable (stored once); or
+ * - b) The value is validated on get(); or
+ * - c) Anti-dependencies are expected to be serialized with
+ * sufficient delay between r-w pairs to avoid races; or
+ * - d) Race conditions are expected to be otherwise rare
+ * or don't really matter that much
+ *
+ * Instances of this class must be configured to point to a valid
+ * PubSub endpoint, and there must be listeners that subscribe to
+ * the endpoint and update the caches. The listeners should be aware
+ * of any consistent hashing scheme used by the client so that writes
+ * do not need to go to every server.
+ *
+ * When used with memcached/redis, it might be simplest to point
+ * both MediaWiki and the purge daemon to twemproxy, mcrouter,
+ * or the like, to handle the consistent hashing. With memcached,
+ * one must be careful to deal with the usage of the "flags" field.
+ *
+ * @ingroup Cache
+ * @since 1.25
+ */
+abstract class WANObjectStash {
+ /** Possible values for getLastError() */
+ const ERR_NONE = 0; // no error
+ const ERR_NO_RESPONSE = 1; // no response
+ const ERR_UNREACHABLE = 2; // can't connect
+ const ERR_UNEXPECTED = 3; // response gave some error
+
+ /**
+ * Fetch the value of a key from the stash
+ *
+ * @param string $key Cache key
+ * @return mixed Returns false on failure
+ */
+ abstract public function get( $key );
+
+ /**
+ * Set the value of a key from stash
+ *
+ * @param string $key Cache key
+ * @param mixed $value
+ * @param integer $ttl Seconds to live [0=forever]
+ * @return bool Success
+ */
+ abstract public function set( $key, $value, $ttl = 0 );
+
+ /**
+ * Delete the value of a key from stash
+ *
+ * @param string $key Cache key
+ * @return bool True if the item was deleted or not found, false on
failure
+ */
+ abstract public function delete( $key );
+
+ /**
+ * Get the "last error" registered; clearLastError() should be called
manually
+ * @return int ERR_* constant for the "last error" registry
+ */
+ abstract public function getLastError();
+
+ /**
+ * Clear the "last error" registry
+ */
+ abstract public function clearLastError();
+}
diff --git a/includes/objectstash/WANObjectStashCassandra.php
b/includes/objectstash/WANObjectStashCassandra.php
new file mode 100755
index 0000000..09cbb11
--- /dev/null
+++ b/includes/objectstash/WANObjectStashCassandra.php
@@ -0,0 +1,176 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Stash
+ * @author Aaron Schulz
+ */
+
+/**
+ * @defgroup Stash Stash
+ */
+
+/**
+ * Multi-datacenter aware stashing interface using Cassandra
+ *
+ * All read/writes use LOCAL_ONE consistency, to avoid cross-DC traffic
+ *
+ * @ingroup Cache
+ * @since 1.25
+ */
+abstract class WANObjectStashCassandra extends WANObectStash {
+ /** Possible values for getLastError() */
+ const ERR_NONE = 0; // no error
+ const ERR_NO_RESPONSE = 1; // no response
+ const ERR_UNREACHABLE = 2; // can't connect
+ const ERR_UNEXPECTED = 3; // response gave some error
+
+ /** @var evseevnn\Cassandra\Database */
+ protected $db;
+ /** @var ConnectionException */
+ protected $lastConnError;
+ /** @var integer UNIX timestamp */
+ protected $lastConnErrorTime;
+ /** @var integer ERR_* constant */
+ protected $lastError = self::ERR_NONE;
+
+ /**
+ * @param array $params
+ */
+ function __construct( array $params ) {
+ if ( !class_exists( 'evseevnn\Cassandra\Database' ) ) {
+ throw new Exception( "Missing cassandra binding; " .
+ "see
https://github.com/evseevnn/php-cassandra-binary" );
+ }
+
+ $this->db = new evseevnn\Cassandra\Database(
+ $params['cassandraConfig']['nodes'],
+ $params['cassandraConfig']['keyspace']
+ );
+ }
+
+ /**
+ * Fetch the value of a key from the stash
+ *
+ * @param string $key Cache key
+ * @return mixed Returns false on failure
+ */
+ public function get( $key ) {
+ $res = array();
+ try {
+ $this->connect();
+ $res = $this->db->query(
+ 'SELECT value FROM "objectstash" WHERE "key" =
:key LIMIT 1',
+ array( 'key' => $key ),
+ ConsistencyEnum::CONSISTENCY_LOCAL_ONE
+ );
+ } catch ( evseevnn\Cassandra\ConnectionException $e ) {
+ $this->lastError = self::ERR_UNREACHABLE;
+ } catch ( evseevnn\Cassandra\QueryException $e ) {
+ $this->lastError = self::ERR_NO_RESPONSE;
+ } catch ( evseevnn\Cassandra\CassandraException $e ) {
+ $this->lastError = self::ERR_UNEXPECTED;
+ }
+
+ return isset( $res[0] ) ? $res[0]['value'] : false;
+ }
+
+ /**
+ * Set the value of a key from stash
+ *
+ * @param string $key Cache key
+ * @param mixed $value
+ * @param integer $ttl Seconds to live [0=forever]
+ * @return bool Success
+ */
+ public function set( $key, $value, $ttl = 0 ) {
+ try {
+ $this->connect();
+ $res = $this->db->query(
+ 'INSERT INTO "objectstash" (key,value) VALUES
(:key, :value)',
+ array( 'key' => $key, 'value' => $value ),
+ ConsistencyEnum::CONSISTENCY_LOCAL_ONE
+ );
+ return true;
+ } catch ( evseevnn\Cassandra\ConnectionException $e ) {
+ $this->lastError = self::ERR_UNREACHABLE;
+ } catch ( evseevnn\Cassandra\QueryException $e ) {
+ $this->lastError = self::ERR_NO_RESPONSE;
+ } catch ( evseevnn\Cassandra\CassandraException $e ) {
+ $this->lastError = self::ERR_UNEXPECTED;
+ }
+
+ return false;
+ }
+
+ /**
+ * Delete the value of a key from stash
+ *
+ * @param string $key Cache key
+ * @return bool True if the item was deleted or not found, false on
failure
+ */
+ public function delete( $key ) {
+ try {
+ $this->connect();
+ $this->db->query(
+ 'DELETE FROM "objectstash" WHERE "key" = :key',
+ array( 'key' => $key ),
+ ConsistencyEnum::CONSISTENCY_LOCAL_ONE
+ );
+ return true;
+ } catch ( evseevnn\Cassandra\ConnectionException $e ) {
+ $this->lastError = self::ERR_UNREACHABLE;
+ } catch ( evseevnn\Cassandra\QueryException $e ) {
+ $this->lastError = self::ERR_NO_RESPONSE;
+ } catch ( evseevnn\Cassandra\CassandraException $e ) {
+ $this->lastError = self::ERR_UNEXPECTED;
+ }
+
+ return false;
+ }
+
+ /**
+ * Try to connect to Cassandra, remebering recent failures
+ *
+ * @throws evseevnn\Cassandra\ConnectionException
+ */
+ protected function connect() {
+ if ( $this->lastConnError && ( time() -
$this->lastConnErrorTime ) < 5 ) {
+ throw $this->lastConnError;
+ }
+ try {
+ $this->db->connect();
+ $this->lastConnError = null;
+ $this->lastConnErrorTime = null;
+ } catch ( evseevnn\Cassandra\ConnectionException $e ) {
+ $this->lastConnError = $e;
+ $this->lastConnErrorTime = time();
+ throw $e;
+ }
+ }
+
+ /**
+ * Get the "last error" registered; clearLastError() should be called
manually
+ * @return int ERR_* constant for the "last error" registry
+ */
+ public function getLastError();
+
+ /**
+ * Clear the "last error" registry
+ */
+ public function clearLastError();
+}
--
To view, visit https://gerrit.wikimedia.org/r/188476
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I5e020112954e69fec21c11309847cdcd00330597
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Aaron Schulz <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits