Removed expiremental LSLockManager class
authorAaron Schulz <aschulz@wikimedia.org>
Fri, 17 Jan 2014 23:15:57 +0000 (15:15 -0800)
committerAaron Schulz <aschulz@wikimedia.org>
Fri, 17 Jan 2014 23:16:01 +0000 (15:16 -0800)
* This is pretty much obsoleted by RedisLockManager

Change-Id: I0feff44b5833072c8eb5a598169e1bb271d49de2

includes/AutoLoader.php
includes/filebackend/lockmanager/LSLockManager.php [deleted file]
maintenance/locking/LockServerDaemon.php [deleted file]

index bab00f9..1fe9c91 100644 (file)
@@ -559,7 +559,6 @@ $wgAutoloadLocalClasses = array(
        'ScopedLock' => 'includes/filebackend/lockmanager/ScopedLock.php',
        'FSLockManager' => 'includes/filebackend/lockmanager/FSLockManager.php',
        'DBLockManager' => 'includes/filebackend/lockmanager/DBLockManager.php',
-       'LSLockManager' => 'includes/filebackend/lockmanager/LSLockManager.php',
        'MemcLockManager' => 'includes/filebackend/lockmanager/MemcLockManager.php',
        'QuorumLockManager' => 'includes/filebackend/lockmanager/QuorumLockManager.php',
        'MySqlLockManager' => 'includes/filebackend/lockmanager/DBLockManager.php',
diff --git a/includes/filebackend/lockmanager/LSLockManager.php b/includes/filebackend/lockmanager/LSLockManager.php
deleted file mode 100644 (file)
index 539a780..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-<?php
-/**
- * Version of LockManager based on using lock daemon servers.
- *
- * 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 LockManager
- */
-
-/**
- * Manage locks using a lock daemon server.
- *
- * Version of LockManager based on using lock daemon servers.
- * This is meant for multi-wiki systems that may share files.
- * All locks are non-blocking, which avoids deadlocks.
- *
- * All lock requests for a resource, identified by a hash string, will map
- * to one bucket. Each bucket maps to one or several peer servers, each
- * running LockServerDaemon.php, listening on a designated TCP port.
- * A majority of peers must agree for a lock to be acquired.
- *
- * @ingroup LockManager
- * @since 1.19
- */
-class LSLockManager extends QuorumLockManager {
-       /** @var array Mapping of lock types to the type actually used */
-       protected $lockTypeMap = array(
-               self::LOCK_SH => self::LOCK_SH,
-               self::LOCK_UW => self::LOCK_SH,
-               self::LOCK_EX => self::LOCK_EX
-       );
-
-       /** @var array Map of server names to server config */
-       protected $lockServers; // (server name => server config array)
-
-       /** @var array Map Server connections (server name => resource) */
-       protected $conns = array();
-
-       protected $connTimeout; // float number of seconds
-       protected $session = ''; // random SHA-1 string
-
-       /**
-        * Construct a new instance from configuration.
-        *
-        * @param array $config Paramaters include:
-        *   - lockServers  : Associative array of server names to configuration.
-        *                    Configuration is an associative array that includes:
-        *                      - host    : IP address/hostname
-        *                      - port    : TCP port
-        *                      - authKey : Secret string the lock server uses
-        *   - srvsByBucket : Array of 1-16 consecutive integer keys, starting from 0,
-        *                    each having an odd-numbered list of server names (peers) as values.
-        *   - connTimeout  : Lock server connection attempt timeout. [optional]
-        */
-       public function __construct( array $config ) {
-               parent::__construct( $config );
-
-               $this->lockServers = $config['lockServers'];
-               // Sanitize srvsByBucket config to prevent PHP errors
-               $this->srvsByBucket = array_filter( $config['srvsByBucket'], 'is_array' );
-               $this->srvsByBucket = array_values( $this->srvsByBucket ); // consecutive
-
-               if ( isset( $config['connTimeout'] ) ) {
-                       $this->connTimeout = $config['connTimeout'];
-               } else {
-                       $this->connTimeout = 3; // use some sane amount
-               }
-
-               $this->session = wfRandomString( 32 ); // 128 bits
-       }
-
-       /**
-        * @see QuorumLockManager::getLocksOnServer()
-        * @param string $lockSrv
-        * @param array $paths
-        * @param int $type
-        * @return Status
-        */
-       protected function getLocksOnServer( $lockSrv, array $paths, $type ) {
-               $status = Status::newGood();
-
-               // Send out the command and get the response...
-               $type = ( $type == self::LOCK_SH ) ? 'SH' : 'EX';
-               $keys = array_unique( array_map( array( $this, 'sha1Base36Absolute' ), $paths ) );
-               $response = $this->sendCommand( $lockSrv, 'ACQUIRE', $type, $keys );
-
-               if ( $response !== 'ACQUIRED' ) {
-                       foreach ( $paths as $path ) {
-                               $status->fatal( 'lockmanager-fail-acquirelock', $path );
-                       }
-               }
-
-               return $status;
-       }
-
-       /**
-        * @see QuorumLockManager::freeLocksOnServer()
-        * @param string $lockSrv
-        * @param array $paths
-        * @param int $type
-        * @return Status
-        */
-       protected function freeLocksOnServer( $lockSrv, array $paths, $type ) {
-               $status = Status::newGood();
-
-               // Send out the command and get the response...
-               $type = ( $type == self::LOCK_SH ) ? 'SH' : 'EX';
-               $keys = array_unique( array_map( array( $this, 'sha1Base36Absolute' ), $paths ) );
-               $response = $this->sendCommand( $lockSrv, 'RELEASE', $type, $keys );
-
-               if ( $response !== 'RELEASED' ) {
-                       foreach ( $paths as $path ) {
-                               $status->fatal( 'lockmanager-fail-releaselock', $path );
-                       }
-               }
-
-               return $status;
-       }
-
-       /**
-        * @see QuorumLockManager::releaseAllLocks()
-        * @return Status
-        */
-       protected function releaseAllLocks() {
-               $status = Status::newGood();
-
-               foreach ( $this->conns as $lockSrv => $conn ) {
-                       $response = $this->sendCommand( $lockSrv, 'RELEASE_ALL', '', array() );
-                       if ( $response !== 'RELEASED_ALL' ) {
-                               $status->fatal( 'lockmanager-fail-svr-release', $lockSrv );
-                       }
-               }
-
-               return $status;
-       }
-
-       /**
-        * @see QuorumLockManager::isServerUp()
-        * @param string $lockSrv
-        * @return bool
-        */
-       protected function isServerUp( $lockSrv ) {
-               return (bool)$this->getConnection( $lockSrv );
-       }
-
-       /**
-        * Send a command and get back the response
-        *
-        * @param string $lockSrv
-        * @param string $action
-        * @param string $type
-        * @param array $values
-        * @return string|bool
-        */
-       protected function sendCommand( $lockSrv, $action, $type, $values ) {
-               $conn = $this->getConnection( $lockSrv );
-               if ( !$conn ) {
-                       return false; // no connection
-               }
-               $authKey = $this->lockServers[$lockSrv]['authKey'];
-               // Build of the command as a flat string...
-               $values = implode( '|', $values );
-               $key = hash_hmac( 'sha1', "{$this->session}\n{$action}\n{$type}\n{$values}", $authKey );
-               // Send out the command...
-               if ( fwrite( $conn, "{$this->session}:$key:$action:$type:$values\n" ) === false ) {
-                       return false;
-               }
-               // Get the response...
-               $response = fgets( $conn );
-               if ( $response === false ) {
-                       return false;
-               }
-
-               return trim( $response );
-       }
-
-       /**
-        * Get (or reuse) a connection to a lock server
-        *
-        * @param string $lockSrv
-        * @return resource
-        */
-       protected function getConnection( $lockSrv ) {
-               if ( !isset( $this->conns[$lockSrv] ) ) {
-                       $cfg = $this->lockServers[$lockSrv];
-                       wfSuppressWarnings();
-                       $errno = $errstr = '';
-                       $conn = fsockopen( $cfg['host'], $cfg['port'], $errno, $errstr, $this->connTimeout );
-                       wfRestoreWarnings();
-                       if ( $conn === false ) {
-                               return null;
-                       }
-                       $sec = floor( $this->connTimeout );
-                       $usec = floor( ( $this->connTimeout - floor( $this->connTimeout ) ) * 1e6 );
-                       stream_set_timeout( $conn, $sec, $usec );
-                       $this->conns[$lockSrv] = $conn;
-               }
-
-               return $this->conns[$lockSrv];
-       }
-
-       /**
-        * Make sure remaining locks get cleared for sanity
-        */
-       function __destruct() {
-               $this->releaseAllLocks();
-               foreach ( $this->conns as $conn ) {
-                       fclose( $conn );
-               }
-       }
-}
diff --git a/maintenance/locking/LockServerDaemon.php b/maintenance/locking/LockServerDaemon.php
deleted file mode 100644 (file)
index d98654e..0000000
+++ /dev/null
@@ -1,640 +0,0 @@
-<?php
-/**
- * Simple lock server daemon that accepts lock/unlock requests.
- *
- * This code should not require MediaWiki setup or PHP files.
- *
- * 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 LockManager Maintenance
- */
-
-if ( PHP_SAPI !== 'cli' ) {
-       die( "This is not a valid entry point.\n" );
-}
-error_reporting( E_ALL );
-
-// Run the server...
-set_time_limit( 0 );
-LockServerDaemon::init(
-       getopt( '', array(
-               'address:', 'port:', 'authKey:',
-               'lockTimeout::', 'maxClients::', 'maxBacklog::', 'maxLocks::',
-       ) )
-)->main();
-
-/**
- * Simple lock server daemon that accepts lock/unlock requests
- *
- * @ingroup LockManager Maintenance
- */
-class LockServerDaemon {
-       /** @var resource */
-       protected $sock; // socket to listen/accept on
-       /** @var Array */
-       protected $sessions = array(); // (session => resource)
-       /** @var Array */
-       protected $deadSessions = array(); // (session => UNIX timestamp)
-
-       /** @var LockHolder */
-       protected $lockHolder;
-
-       protected $address; // string IP address
-       protected $port; // integer
-       protected $authKey; // string key
-       protected $lockTimeout; // integer number of seconds
-       protected $maxBacklog; // integer
-       protected $maxClients; // integer
-
-       protected $startTime; // integer UNIX timestamp
-       protected $ticks = 0; // integer counter
-
-       /* @var LockServerDaemon */
-       protected static $instance = null;
-
-       /**
-        * @params $config Array
-        * @param array $config
-        * @throws Exception
-        * @return LockServerDaemon
-        */
-       public static function init( array $config ) {
-               if ( self::$instance ) {
-                       throw new Exception( 'LockServer already initialized.' );
-               }
-               foreach ( array( 'address', 'port', 'authKey' ) as $par ) {
-                       if ( !isset( $config[$par] ) ) {
-                               die( "Usage: php LockServerDaemon.php " .
-                                       "--address <address> --port <port> --authKey <key> " .
-                                       "[--lockTimeout <seconds>] " .
-                                       "[--maxLocks <integer>] [--maxClients <integer>] [--maxBacklog <integer>]\n"
-                               );
-                       }
-               }
-               self::$instance = new self( $config );
-               return self::$instance;
-       }
-
-       /**
-        * @params $config Array
-        */
-       protected function __construct( array $config ) {
-               // Required parameters...
-               $this->address = $config['address'];
-               $this->port = $config['port'];
-               $this->authKey = $config['authKey'];
-               // Parameters with defaults...
-               $this->lockTimeout = isset( $config['lockTimeout'] )
-                       ? (int)$config['lockTimeout']
-                       : 60;
-               $this->maxClients = isset( $config['maxClients'] )
-                       ? (int)$config['maxClients']
-                       : 1000; // less than default FD_SETSIZE
-               $this->maxBacklog = isset( $config['maxBacklog'] )
-                       ? (int)$config['maxBacklog']
-                       : 100;
-               $maxLocks = isset( $config['maxLocks'] )
-                       ? (int)$config['maxLocks']
-                       : 10000;
-
-               $this->lockHolder = new LockHolder( $maxLocks );
-       }
-
-       /**
-        * @throws Exception
-        * @return void
-        */
-       protected function setupServerSocket() {
-               if ( !function_exists( 'socket_create' ) ) {
-                       throw new Exception( "PHP sockets extension missing from PHP CLI mode." );
-               }
-               $sock = socket_create( AF_INET, SOCK_STREAM, SOL_TCP );
-               if ( $sock === false ) {
-                       throw new Exception( "socket_create(): " . socket_strerror( socket_last_error() ) );
-               }
-               socket_set_option( $sock, SOL_SOCKET, SO_REUSEADDR, 1 ); // bypass 2MLS
-               socket_set_nonblock( $sock ); // don't block on accept()
-               if ( socket_bind( $sock, $this->address, $this->port ) === false ) {
-                       throw new Exception( "socket_bind(): " .
-                               socket_strerror( socket_last_error( $sock ) ) );
-               } elseif ( socket_listen( $sock, $this->maxBacklog ) === false ) {
-                       throw new Exception( "socket_listen(): " .
-                               socket_strerror( socket_last_error( $sock ) ) );
-               }
-               $this->sock = $sock;
-               $this->startTime = time();
-       }
-
-       /**
-        * Entry-point function that listens to the server socket, accepts
-        * new clients, and recieves/responds to requests to lock resources.
-        */
-       public function main() {
-               $this->setupServerSocket(); // setup listening socket
-               $socketArray = new SocketArray(); // sockets being serviced
-               $socketArray->addSocket( $this->sock ); // add listening socket
-               do {
-                       list( $read, $write ) = $socketArray->socketsForSelect();
-                       if ( socket_select( $read, $write, $except = null, null ) < 1 ) {
-                               continue; // wait
-                       }
-                       // Check if there is a client trying to connect...
-                       if ( in_array( $this->sock, $read ) && $socketArray->size() < $this->maxClients ) {
-                               $newSock = socket_accept( $this->sock );
-                               if ( $newSock ) {
-                                       socket_set_option( $newSock, SOL_SOCKET, SO_KEEPALIVE, 1 );
-                                       socket_set_nonblock( $newSock ); // don't block on read()/write()
-                                       $socketArray->addSocket( $newSock );
-                               }
-                       }
-                       // Loop through all the clients that have data to read...
-                       foreach ( $read as $read_sock ) {
-                               if ( $read_sock === $this->sock ) {
-                                       continue; // skip listening socket
-                               }
-                               // Avoids PHP_NORMAL_READ per https://bugs.php.net/bug.php?id=33471
-                               $data = socket_read( $read_sock, 65535 );
-                               // Check if the client is disconnected
-                               if ( $data === false || $data === '' ) {
-                                       $socketArray->closeSocket( $read_sock );
-                                       $this->recordDeadSocket( $read_sock ); // remove session
-                               // Check if we reached the end of a message
-                               } elseif ( substr( $data, -1 ) === "\n" ) {
-                                       // Newline is the last char (given ping-pong message usage)
-                                       $cmd = $socketArray->readRcvBuffer( $read_sock ) . $data;
-                                       // Perform the requested command...
-                                       $response = $this->doCommand( rtrim( $cmd ), $read_sock );
-                                       // Send the response to the client...
-                                       $socketArray->appendSndBuffer( $read_sock, $response . "\n" );
-                               // Otherwise, we just have more message data to append
-                               } elseif ( !$socketArray->appendRcvBuffer( $read_sock, $data ) ) {
-                                       $socketArray->closeSocket( $read_sock ); // too big
-                                       $this->recordDeadSocket( $read_sock ); // remove session
-                               }
-                       }
-                       // Loop through all the clients that have data to write...
-                       foreach ( $write as $write_sock ) {
-                               $bytes = socket_write( $write_sock, $socketArray->readSndBuffer( $write_sock ) );
-                               // Check if the client is disconnected
-                               if ( $bytes === false ) {
-                                       $socketArray->closeSocket( $write_sock );
-                                       $this->recordDeadSocket( $write_sock ); // remove session
-                               // Otherwise, truncate these bytes from the start of the write buffer
-                               } else {
-                                       $socketArray->consumeSndBuffer( $write_sock, $bytes );
-                               }
-                       }
-                       // Prune dead locks every few socket events...
-                       if ( ++$this->ticks >= 9 ) {
-                               $this->ticks = 0;
-                               $this->purgeExpiredLocks();
-                       }
-               } while ( true );
-       }
-
-       /**
-        * @param $data string
-        * @param $sourceSock resource
-        * @return string
-        */
-       protected function doCommand( $data, $sourceSock ) {
-               $cmdArr = $this->getCommand( $data );
-               if ( is_string( $cmdArr ) ) {
-                       return $cmdArr; // error
-               }
-               list( $function, $session, $type, $resources ) = $cmdArr;
-               // On first command, track the session => sock correspondence
-               if ( !isset( $this->sessions[$session] ) ) {
-                       $this->sessions[$session] = $sourceSock;
-                       unset( $this->deadSessions[$session] ); // renew if dead
-               }
-               if ( $function === 'ACQUIRE' ) {
-                       return $this->lockHolder->lock( $session, $type, $resources );
-               } elseif ( $function === 'RELEASE' ) {
-                       return $this->lockHolder->unlock( $session, $type, $resources );
-               } elseif ( $function === 'RELEASE_ALL' ) {
-                       return $this->lockHolder->release( $session );
-               } elseif ( $function === 'STAT' ) {
-                       return $this->stat();
-               }
-               return 'INTERNAL_ERROR';
-       }
-
-       /**
-        * @param $data string
-        * @return Array
-        */
-       protected function getCommand( $data ) {
-               $m = explode( ':', $data ); // <session, key, command, type, values>
-               if ( count( $m ) == 5 ) {
-                       list( $session, $key, $command, $type, $values ) = $m;
-                       $goodKey = hash_hmac( 'sha1',
-                               "{$session}\n{$command}\n{$type}\n{$values}", $this->authKey );
-                       if ( $goodKey !== $key ) {
-                               return 'BAD_KEY';
-                       } elseif ( strlen( $session ) !== 32 ) {
-                               return 'BAD_SESSION';
-                       }
-                       $values = explode( '|', $values );
-                       if ( $command === 'ACQUIRE' ) {
-                               $needsLockArgs = true;
-                       } elseif ( $command === 'RELEASE' ) {
-                               $needsLockArgs = true;
-                       } elseif ( $command === 'RELEASE_ALL' ) {
-                               $needsLockArgs = false;
-                       } elseif ( $command === 'STAT' ) {
-                               $needsLockArgs = false;
-                       } else {
-                               return 'BAD_COMMAND';
-                       }
-                       if ( $needsLockArgs ) {
-                               if ( $type !== 'SH' && $type !== 'EX' ) {
-                                       return 'BAD_TYPE';
-                               }
-                               foreach ( $values as $value ) {
-                                       if ( strlen( $value ) !== 31 ) {
-                                               return 'BAD_FORMAT';
-                                       }
-                               }
-                       }
-                       return array( $command, $session, $type, $values );
-               }
-               return 'BAD_FORMAT';
-       }
-
-       /**
-        * Remove a socket's corresponding session from tracking and
-        * store it in the dead session tracking if it still has locks.
-        *
-        * @param $socket resource
-        * @return bool
-        */
-       protected function recordDeadSocket( $socket ) {
-               $session = array_search( $socket, $this->sessions );
-               if ( $session !== false ) {
-                       unset( $this->sessions[$session] );
-                       // Record recently killed sessions that still have locks
-                       if ( $this->lockHolder->sessionHasLocks( $session ) ) {
-                               $this->deadSessions[$session] = time();
-                       }
-                       return true;
-               }
-               return false;
-       }
-
-       /**
-        * Clear locks for sessions that have been dead for a while
-        *
-        * @return integer Number of sessions purged
-        */
-       protected function purgeExpiredLocks() {
-               $count = 0;
-               $now = time();
-               foreach ( $this->deadSessions as $session => $timestamp ) {
-                       if ( ( $now - $timestamp ) > $this->lockTimeout ) {
-                               $this->lockHolder->release( $session );
-                               unset( $this->deadSessions[$session] );
-                               ++$count;
-                       }
-               }
-               return $count;
-       }
-
-       /**
-        * Get the current timestamp and memory usage
-        *
-        * @return string
-        */
-       protected function stat() {
-               return ( time() - $this->startTime ) . ':' . memory_get_usage();
-       }
-}
-
-/**
- * LockServerDaemon helper class that keeps track socket states
- */
-class SocketArray {
-       /* @var Array */
-       protected $clients = array(); // array of client sockets
-       /* @var Array */
-       protected $rBuffers = array(); // corresponding socket read buffers
-       /* @var Array */
-       protected $wBuffers = array(); // corresponding socket write buffers
-
-       const BUFFER_SIZE = 65535;
-
-       /**
-        * @return Array (list of sockets to read, list of sockets to write)
-        */
-       public function socketsForSelect() {
-               $rSockets = array();
-               $wSockets = array();
-               foreach ( $this->clients as $key => $socket ) {
-                       if ( $this->wBuffers[$key] !== '' ) {
-                               $wSockets[] = $socket; // wait for writing to unblock
-                       } else {
-                               $rSockets[] = $socket; // wait for reading to unblock
-                       }
-               }
-               return array( $rSockets, $wSockets );
-       }
-
-       /**
-        * @return integer Number of client sockets
-        */
-       public function size() {
-               return count( $this->clients );
-       }
-
-       /**
-        * @param $sock resource
-        * @return bool
-        */
-       public function addSocket( $sock ) {
-               $this->clients[] = $sock;
-               $this->rBuffers[] = '';
-               $this->wBuffers[] = '';
-               return true;
-       }
-
-       /**
-        * @param $sock resource
-        * @return bool
-        */
-       public function closeSocket( $sock ) {
-               $key = array_search( $sock, $this->clients );
-               if ( $key === false ) {
-                       return false;
-               }
-               socket_close( $sock );
-               unset( $this->clients[$key] );
-               unset( $this->rBuffers[$key] );
-               unset( $this->wBuffers[$key] );
-               return true;
-       }
-
-       /**
-        * @param $sock resource
-        * @param $data string
-        * @return bool
-        */
-       public function appendRcvBuffer( $sock, $data ) {
-               $key = array_search( $sock, $this->clients );
-               if ( $key === false ) {
-                       return false;
-               } elseif ( ( strlen( $this->rBuffers[$key] ) + strlen( $data ) ) > self::BUFFER_SIZE ) {
-                       return false;
-               }
-               $this->rBuffers[$key] .= $data;
-               return true;
-       }
-
-       /**
-        * @param $sock resource
-        * @return string|bool
-        */
-       public function readRcvBuffer( $sock ) {
-               $key = array_search( $sock, $this->clients );
-               if ( $key === false ) {
-                       return false;
-               }
-               $data = $this->rBuffers[$key];
-               $this->rBuffers[$key] = ''; // consume data
-               return $data;
-       }
-
-       /**
-        * @param $sock resource
-        * @param $data string
-        * @return bool
-        */
-       public function appendSndBuffer( $sock, $data ) {
-               $key = array_search( $sock, $this->clients );
-               if ( $key === false ) {
-                       return false;
-               } elseif ( ( strlen( $this->wBuffers[$key] ) + strlen( $data ) ) > self::BUFFER_SIZE ) {
-                       return false;
-               }
-               $this->wBuffers[$key] .= $data;
-               return true;
-       }
-
-       /**
-        * @param $sock resource
-        * @return bool
-        */
-       public function readSndBuffer( $sock ) {
-               $key = array_search( $sock, $this->clients );
-               if ( $key === false ) {
-                       return false;
-               }
-               return $this->wBuffers[$key];
-       }
-
-       /**
-        * @param $sock resource
-        * @param $bytes integer
-        * @return bool
-        */
-       public function consumeSndBuffer( $sock, $bytes ) {
-               $key = array_search( $sock, $this->clients );
-               if ( $key === false ) {
-                       return false;
-               }
-               $this->wBuffers[$key] = (string)substr( $this->wBuffers[$key], $bytes );
-               return true;
-       }
-}
-
-/**
- * LockServerDaemon helper class that keeps track of the locks
- */
-class LockHolder {
-       /** @var Array */
-       protected $shLocks = array(); // (key => session => 1)
-       /** @var Array */
-       protected $exLocks = array(); // (key => session)
-
-       /** @var Array */
-       protected $sessionIndexSh = array(); // (session => key => 1)
-       /** @var Array */
-       protected $sessionIndexEx = array(); // (session => key => 1)
-       protected $lockCount = 0; // integer
-
-       protected $maxLocks; // integer
-
-       /**
-        * @params $maxLocks integer Maximum number of locks to allow
-        */
-       public function __construct( $maxLocks ) {
-               $this->maxLocks = $maxLocks;
-       }
-
-       /**
-        * @param $session string
-        * @return bool
-        */
-       public function sessionHasLocks( $session ) {
-               return isset( $this->sessionIndexSh[$session] )
-                       || isset( $this->sessionIndexEx[$session] );
-       }
-
-       /**
-        * @param $session string
-        * @param $type string
-        * @param $keys Array
-        * @return string
-        */
-       public function lock( $session, $type, array $keys ) {
-               if ( ( $this->lockCount + count( $keys ) ) > $this->maxLocks ) {
-                       return 'TOO_MANY_LOCKS';
-               }
-               if ( $type === 'SH' ) {
-                       // Check if any keys are already write-locked...
-                       foreach ( $keys as $key ) {
-                               if ( isset( $this->exLocks[$key] ) && $this->exLocks[$key] !== $session ) {
-                                       return 'CANT_ACQUIRE';
-                               }
-                       }
-                       // Acquire the read-locks...
-                       foreach ( $keys as $key ) {
-                               $this->set_sh_lock( $key, $session );
-                       }
-                       return 'ACQUIRED';
-               } elseif ( $type === 'EX' ) {
-                       // Check if any keys are already read-locked or write-locked...
-                       foreach ( $keys as $key ) {
-                               if ( isset( $this->exLocks[$key] ) && $this->exLocks[$key] !== $session ) {
-                                       return 'CANT_ACQUIRE';
-                               }
-                               if ( isset( $this->shLocks[$key] ) ) {
-                                       foreach ( $this->shLocks[$key] as $otherSession => $x ) {
-                                               if ( $otherSession !== $session ) {
-                                                       return 'CANT_ACQUIRE';
-                                               }
-                                       }
-                               }
-                       }
-                       // Acquire the write-locks...
-                       foreach ( $keys as $key ) {
-                               $this->set_ex_lock( $key, $session );
-                       }
-                       return 'ACQUIRED';
-               }
-               return 'INTERNAL_ERROR';
-       }
-
-       /**
-        * @param $session string
-        * @param $type string
-        * @param $keys Array
-        * @return string
-        */
-       public function unlock( $session, $type, array $keys ) {
-               if ( $type === 'SH' ) {
-                       foreach ( $keys as $key ) {
-                               $this->unset_sh_lock( $key, $session );
-                       }
-                       return 'RELEASED';
-               } elseif ( $type === 'EX' ) {
-                       foreach ( $keys as $key ) {
-                               $this->unset_ex_lock( $key, $session );
-                       }
-                       return 'RELEASED';
-               }
-               return 'INTERNAL_ERROR';
-       }
-
-       /**
-        * @param $session string
-        * @return string
-        */
-       public function release( $session ) {
-               if ( isset( $this->sessionIndexSh[$session] ) ) {
-                       foreach ( $this->sessionIndexSh[$session] as $key => $x ) {
-                               $this->unset_sh_lock( $key, $session );
-                       }
-               }
-               if ( isset( $this->sessionIndexEx[$session] ) ) {
-                       foreach ( $this->sessionIndexEx[$session] as $key => $x ) {
-                               $this->unset_ex_lock( $key, $session );
-                       }
-               }
-               return 'RELEASED_ALL';
-       }
-
-       /**
-        * @param $key string
-        * @param $session string
-        * @return void
-        */
-       protected function set_sh_lock( $key, $session ) {
-               if ( !isset( $this->shLocks[$key][$session] ) ) {
-                       $this->shLocks[$key][$session] = 1;
-                       $this->sessionIndexSh[$session][$key] = 1;
-                       ++$this->lockCount; // we are adding a lock
-               }
-       }
-
-       /**
-        * @param $key string
-        * @param $session string
-        * @return void
-        */
-       protected function set_ex_lock( $key, $session ) {
-               if ( !isset( $this->exLocks[$key][$session] ) ) {
-                       $this->exLocks[$key] = $session;
-                       $this->sessionIndexEx[$session][$key] = 1;
-                       ++$this->lockCount; // we are adding a lock
-               }
-       }
-
-       /**
-        * @param $key string
-        * @param $session string
-        * @return void
-        */
-       protected function unset_sh_lock( $key, $session ) {
-               if ( isset( $this->shLocks[$key][$session] ) ) {
-                       unset( $this->shLocks[$key][$session] );
-                       if ( !count( $this->shLocks[$key] ) ) {
-                               unset( $this->shLocks[$key] );
-                       }
-                       unset( $this->sessionIndexSh[$session][$key] );
-                       if ( !count( $this->sessionIndexSh[$session] ) ) {
-                               unset( $this->sessionIndexSh[$session] );
-                       }
-                       --$this->lockCount;
-               }
-       }
-
-       /**
-        * @param $key string
-        * @param $session string
-        * @return void
-        */
-       protected function unset_ex_lock( $key, $session ) {
-               if ( isset( $this->exLocks[$key] ) && $this->exLocks[$key] === $session ) {
-                       unset( $this->exLocks[$key] );
-                       unset( $this->sessionIndexEx[$session][$key] );
-                       if ( !count( $this->sessionIndexEx[$session] ) ) {
-                               unset( $this->sessionIndexEx[$session] );
-                       }
-                       --$this->lockCount;
-               }
-       }
-}