Compare commits

...

338 Commits

Author SHA1 Message Date
Daniele Alessandri 3c33c74b35 Update CHANGELOG. Time to release! 2010-05-24 19:35:35 +02:00
Daniele Alessandri 0e69438c0b Remove dots at the end of exception messages. 2010-05-23 09:08:55 +02:00
Daniele Alessandri 761e3a2527 Add an optional argument to MultiBulkResponseIterator::sync() to specify if the synchronization of an iterable multibulk response should be performed by consuming the rest of the reply or by closing the underlying connection. 2010-05-23 09:03:17 +02:00
Daniele Alessandri 316d3de10e Add static method Predis\RedisServerProfile::getDevelopment() to create a new instance of the 'dev' server profile. 2010-05-23 08:47:29 +02:00
Daniele Alessandri 5757318c9b Remove Predis\RedisServerProfile::compareWith() since it is useless and it is broken anyway. 2010-05-23 08:45:22 +02:00
Daniele Alessandri 340dca8f8d Update CHANGELOG. 2010-05-23 08:44:19 +02:00
Daniele Alessandri c781e91c2e Fix typos. 2010-05-22 16:10:17 +02:00
Daniele Alessandri d04a95395d Update CHANGELOG. 2010-05-22 15:38:33 +02:00
Daniele Alessandri dad3704488 Examples: bulk update. 2010-05-22 14:48:37 +02:00
Daniele Alessandri d585b11bf5 Examples: add CustomDistributionStrategy.php 2010-05-22 14:34:28 +02:00
Daniele Alessandri 9f21cb12a2 Rename Predis\Distribution\IDistributionAlgorithm to Predis\Distribution\IDistributionStrategy. 2010-05-22 14:32:29 +02:00
Daniele Alessandri f60208eb54 Examples: updated PubSubContext.php 2010-05-22 13:59:16 +02:00
Daniele Alessandri f53ffbf42b Update TODO. 2010-05-22 13:52:30 +02:00
Daniele Alessandri c2a6350ff2 Update CHANGELOG. 2010-05-22 13:45:51 +02:00
Daniele Alessandri 57fc3cf30e Add VERSION file. 2010-05-22 13:30:56 +02:00
Daniele Alessandri 2aecdf25e5 Update README. 2010-05-22 13:24:04 +02:00
Daniele Alessandri 8ad161dc34 Update CHANGELOG. Start preparing for the release of Predis 0.6.0. 2010-05-22 13:07:10 +02:00
Daniele Alessandri 69a0ed6d2f Suppress PHP notices in Predis\ConnectionCluster::getConnectionById() if the specified connection alias/index does not exist. 2010-05-22 12:27:14 +02:00
Daniele Alessandri 1f663f06be Implement Predis\Client::getClientFor() to initialize a new client from a single connection of a cluster by its alias. 2010-05-22 12:22:34 +02:00
Daniele Alessandri 5427bdcf22 Fast fail on exceptions different than Predis\ServerException or Predis\CommunicationException. 2010-05-22 11:56:45 +02:00
Daniele Alessandri 6c512784cb Merge branch 'pipeline_partial_failures'
Conflicts:
	lib/Predis.php
2010-05-22 11:34:57 +02:00
Daniele Alessandri e70b8ed38b Fix an old but harmless glitch in the serialization of inline commands with 0 arguments. 2010-05-21 21:10:34 +02:00
Daniele Alessandri 40d5b04278 Change the behavior of a test and add a reminder for a later in-depth examination of alternatives. 2010-05-21 21:02:09 +02:00
Daniele Alessandri 71dab9a249 Update CHANGELOG. 2010-05-21 20:45:14 +02:00
Daniele Alessandri f0d2551244 Fix a wrong namespace path in SafeExecutor::execute(). 2010-05-21 20:34:20 +02:00
Daniele Alessandri 4c8ecc02e5 Force disconnection in Predis\Pipeline\StandardExecutor when a Predis\ServerException is thrown to prevent protocol desynchronization between the client and the server. 2010-05-21 20:31:40 +02:00
Daniele Alessandri 84cb28e3ac Merge branch 'pubsub_experimental' 2010-05-18 12:25:10 +02:00
Daniele Alessandri 6e321a3530 Add the Predis\Client::pubSubContext() method to initialize a PubSub context from a client instance. 2010-05-18 12:23:53 +02:00
Daniele Alessandri ea7e9a37c6 Remove unused variable in the pubsub example. 2010-05-18 11:54:59 +02:00
Daniele Alessandri 658272fe4b Fix wrong namespace path for EmptyRingException. 2010-05-18 11:46:42 +02:00
Daniele Alessandri fa6400dc22 Rename the \Predis\Utilities namespace to \Predis\Shared. 2010-05-17 20:05:10 +02:00
Daniele Alessandri 376dfe3451 Move IDistributionAlgorithm, HashRing and KetamaPureRing to the new Predis\Distribution namespace. 2010-05-17 19:59:54 +02:00
Daniele Alessandri a26932b3b5 Throw a more appropriate InvalidArgumentException when a non-callable argument is passed to instances of Predis\CommandPipeline and Predis\MultiExecBlock. 2010-05-17 19:46:28 +02:00
Daniele Alessandri eab70fb134 Implement the new EmptyRingException exception class. 2010-05-17 19:42:08 +02:00
Daniele Alessandri 23b68d9415 Test suite: add test for the HASH type. 2010-05-17 19:19:53 +02:00
Daniele Alessandri 5def6bebe3 Rename Predis\Pipeline\IExecutor to Predis\Pipeline\IPipelineExecutor. 2010-05-17 18:38:38 +02:00
Daniele Alessandri 35f7ea2895 Test suite: minor code formatting changes. 2010-05-16 13:00:01 +02:00
Daniele Alessandri 37d4aa3d94 Test suite: test creation of the server profile for Redis 2.0. 2010-05-16 12:29:19 +02:00
Daniele Alessandri f1890c93a6 Test suite: PredisClientFeaturesTestSuite and same signature of PHPUnit_Framework_TestCase::onNotSuccessfulTest. 2010-05-16 12:23:50 +02:00
Daniele Alessandri d69a872359 Test suite: minor code formatting changes. 2010-05-16 12:20:20 +02:00
Daniele Alessandri c01d185448 Bugfix: using the right variable in Predis\Pipeline\SafeExecutor makes things work. 2010-05-15 13:52:05 +02:00
Daniele Alessandri e4aec82836 Garbage in the LICENSE file. Seriously, what was that? 2010-05-15 13:08:06 +02:00
Daniele Alessandri 82619b4dd0 Updated CHANGELOG. 2010-05-15 13:06:08 +02:00
Daniele Alessandri b3f340f830 Handling of partial failures and server errors in pipelines. 2010-05-15 12:30:33 +02:00
Daniele Alessandri f7bdd9d64b The default server profile for Predis\Client is now 2.0 (supports for Redis v2.0 out of the box). 2010-05-15 08:30:55 +02:00
Daniele Alessandri 4f0f2ca3eb ZUNION and ZINTER have been changed to ZUNIONSTORE and ZINTERSTORE for consistency (see Redis commit 5d373da). 2010-05-15 08:25:50 +02:00
Daniele Alessandri 72ef71d2df Merge branch 'test_library_features' 2010-05-13 18:53:21 +02:00
Daniele Alessandri 1a9454a4f2 Updated the tests to reflect the changes that has been made in the internal design of the library in the latest weeks (preparing to merge into master). 2010-05-13 18:52:51 +02:00
Daniele Alessandri f6b3912783 Updated TODO. 2010-05-13 16:11:40 +02:00
Daniele Alessandri a0f441f21b Added an example to show how to use the \Predis\PubSubContext class. 2010-05-13 16:10:18 +02:00
Daniele Alessandri 7312dbe7fc Implemented the new \Predis\PubSubContext class. 2010-05-13 16:07:42 +02:00
Daniele Alessandri 27ebb1ddb5 New commands: PSUBSCRIBE and PUNSUBSCRIBE (Redis v2.0-dev). 2010-05-13 11:21:59 +02:00
Daniele Alessandri 08afdfac1b Trying to increment a string value associated to an hash now raises an error. 2010-05-10 11:27:26 +02:00
Daniele Alessandri 0664bde7e9 Bugfix: replies to DEL commands must not be converted to a boolean response as DEL returns the number of keys removed. 2010-05-10 11:20:51 +02:00
Daniele Alessandri ddafa2a101 Updated TODO. 2010-04-27 21:55:07 +02:00
Daniele Alessandri 2787905024 Test suite: updated tests for ZUNION and ZINTER with the new options style. 2010-04-27 21:54:37 +02:00
Daniele Alessandri b623144881 Better support for options for ZUNION and ZINTER. 2010-04-27 21:49:03 +02:00
Daniele Alessandri c73918b991 Fix a couple of command aliases in the DEV profile. 2010-04-24 14:01:24 +02:00
Daniele Alessandri b4e4ca0f0b Updated TODO. 2010-04-24 13:59:11 +02:00
Daniele Alessandri db6b8a3fc8 Parse response to HGETALL as an array of key => value. 2010-04-24 13:56:00 +02:00
Daniele Alessandri 0d4426c052 Test suite: added HKEYS, HVALS, HGETALL. 2010-04-24 13:54:06 +02:00
Daniele Alessandri 08adcb478d Test suite: added HLEN. 2010-04-24 13:16:34 +02:00
Daniele Alessandri 513baa556c Process responses to HDEL as boolean values. 2010-04-24 13:09:18 +02:00
Daniele Alessandri ead414c530 Test suite: added HDEL. 2010-04-24 13:09:05 +02:00
Daniele Alessandri 290e51877c Test suite: added HINCRBY. 2010-04-24 13:03:14 +02:00
Daniele Alessandri de2d75e1d7 Process responses to HEXISTS as boolean values. 2010-04-24 12:47:09 +02:00
Daniele Alessandri 7e61ac6f30 Test suite: added HEXISTS. 2010-04-24 12:45:34 +02:00
Daniele Alessandri 4f25e568cf Test suite: minor code formatting fix. 2010-04-24 12:42:37 +02:00
Daniele Alessandri 83ffdc8bc8 Various fixes for HMSET and HMSET. 2010-04-24 12:00:46 +02:00
Daniele Alessandri 7f138dfcef Test suite: added HMSET and HMGET. 2010-04-24 11:59:30 +02:00
Daniele Alessandri 55404a2400 Test suite: added HSETNX. 2010-04-24 11:37:09 +02:00
Daniele Alessandri 69bce63453 Test suite: added HGET. 2010-04-24 11:33:48 +02:00
Daniele Alessandri d79321ac8c Process responses to HSET as boolean values. 2010-04-24 11:26:35 +02:00
Daniele Alessandri c227eedbb7 Test suite: added HSET. 2010-04-24 11:24:55 +02:00
Daniele Alessandri 887fea87e5 Test suite: added ZREMRANGEBYRANK. 2010-04-24 11:12:35 +02:00
Daniele Alessandri 4b2400b570 Test suite: added ZINTER. 2010-04-24 10:26:34 +02:00
Daniele Alessandri a1c8568ccf Test suite: added ZUNION. 2010-04-24 10:21:29 +02:00
Daniele Alessandri fa039fe500 Test suite: renamed ZRANK test method. 2010-04-24 09:47:10 +02:00
Daniele Alessandri 9c587b6f1d Test suite: added ZREVRANK. 2010-04-24 09:46:32 +02:00
Daniele Alessandri 2f6b24c098 Test suite: added SETEX. 2010-04-24 09:37:54 +02:00
Daniele Alessandri 23de93582e Code formatting. 2010-04-24 09:19:51 +02:00
Daniele Alessandri e8a443200b Updated CHANGELOG. 2010-04-23 21:38:43 +02:00
Daniele Alessandri 2eb68a0fee New command: SETEX (Redis v2.0-dev). 2010-04-23 21:38:22 +02:00
Daniele Alessandri 77c8b702b6 Updated CHANGELOG. 2010-04-23 21:33:30 +02:00
Daniele Alessandri a092ad46a3 New command: HSETNX (Redis v2.0-dev). 2010-04-23 21:32:10 +02:00
Daniele Alessandri b5e2b9eee9 New command: HMGET (Redis v2.0-dev). 2010-04-23 21:28:43 +02:00
Daniele Alessandri 7c2866f9fc Updating comments. 2010-04-23 21:23:23 +02:00
Daniele Alessandri 801c4647fd Slight code reorganization. 2010-04-23 21:22:46 +02:00
Daniele Alessandri 0e224ec492 Updated CHANGELOG. 2010-04-23 21:18:33 +02:00
Daniele Alessandri b93b13133d New command: HMSET (Redis v2.0-dev). 2010-04-23 21:12:46 +02:00
Daniele Alessandri d9542c21c3 New commands: PUBLISH, SUBSCRIBE and UNSUBSCRIBE (Redis v2.0-dev). 2010-04-23 21:07:36 +02:00
Daniele Alessandri 0a0afec0ec Reminder for ZUNION. 2010-04-23 20:54:41 +02:00
Daniele Alessandri 7ae94ca6fb New \Predis\Protocol class. It's not really used right now... 2010-04-23 20:37:57 +02:00
Daniele Alessandri df9fef8900 Moved the IDistributionAlgorithm interface one level up in the namespace chain, from \Predis\Utilities to \Predis. 2010-04-23 20:27:59 +02:00
Daniele Alessandri d369f8bb74 Renamed the \Predis\Utilities\IRing interface to \Predis\Utilities\IDistributionAlgorithm. 2010-04-21 22:13:13 +02:00
Daniele Alessandri 8ae5197a38 Moved the initialization of the default \Predis\ResponseReader instance. 2010-04-21 21:32:19 +02:00
Daniele Alessandri b662b36e95 Updated CHANGELOG. 2010-04-19 20:51:17 +02:00
Daniele Alessandri ce790071fd Providing optional support for Redis 1.0. 2010-04-19 16:52:49 +02:00
Daniele Alessandri f729793a9a Drop default support for Redis 1.0 and switch to the multi-bulk type for all of the Redis commands. 2010-04-19 16:50:50 +02:00
Daniele Alessandri ad2381a305 Users can now register their own \Predis\RedisServerProfile class with one or more aliases. 2010-04-19 15:37:43 +02:00
Daniele Alessandri 3121b1761e Changed the way arguments of SORT are prepared before serialization to be compatible with an eventual switch to multi-bulk requests. 2010-04-18 14:33:22 +02:00
Daniele Alessandri 81aef81b55 Changed the way arguments of SLAVEOF are prepared before serialization to be compatible with an eventual switch to multi-bulk requests. 2010-04-18 13:09:03 +02:00
Daniele Alessandri ea9c3388da No more implicit serialization for an array instance passed as the single argument of a MultiBulkCommand. 2010-04-18 12:49:38 +02:00
Daniele Alessandri 24bf10c691 Some performance improvements in the serialization of multibulk commands. 2010-04-18 10:53:38 +02:00
Daniele Alessandri ea75b168d1 Re-enabled the test for SORT in the test suite. 2010-04-17 20:12:39 +02:00
Daniele Alessandri 9fc0fbdb8c Converted the test suite to invoke commands on the client instance as they are defined in the command reference of Redis instead of using their aliases. 2010-04-17 19:50:24 +02:00
Daniele Alessandri a35faf2df6 Fixed a bug in the registration of the RPOPLPUSH command. 2010-04-17 18:48:13 +02:00
Daniele Alessandri 471102253a Updated the tests to reflect the changes that has been made in the internal design of the library in the latest weeks. 2010-04-17 17:04:06 +02:00
Daniele Alessandri 4cce99d388 Merge branch 'test_client_feats' into test_library_features 2010-04-17 17:02:36 +02:00
Daniele Alessandri 39052b181e Merge branch 'hyves_contribs_port' into master. Huge thanks to Lorenzo Castelli for a lot of awesome improvements and ideas. 2010-04-17 15:26:21 +02:00
Daniele Alessandri fd0732ca33 Updated CHANGELOG. 2010-04-17 15:14:03 +02:00
Daniele Alessandri 14c9d36bdf Updated CHANGELOG. 2010-04-17 15:13:48 +02:00
Daniele Alessandri 323b6f9eff Updated README. 2010-04-17 15:12:31 +02:00
Daniele Alessandri 835f5a5cbc Added Lorenzo to the contributors list. 2010-04-17 14:51:43 +02:00
Daniele Alessandri fa22d9667c Get a Predis\ResponseError instance from a Predis\ServerException instance. 2010-04-17 09:13:32 +02:00
Daniele Alessandri 67a27a7f05 Fixed a bug in the test suite discovered thanks to the validation of numeric inputs introduced in Redis with commit bbe025e. 2010-04-15 11:55:15 +02:00
Daniele Alessandri bdf4dfb54e Fixed the test suite to comply with the changes introduced in Redis with commit 4e27f26. 2010-04-15 11:51:33 +02:00
Daniele Alessandri a3ead444b2 Removed a spurious new line. 2010-04-14 15:52:35 +02:00
Daniele Alessandri 9facda2678 Updated CHANGELOG. 2010-04-14 15:51:08 +02:00
Daniele Alessandri 8f50c5f69a User-configurable key distribution algorithm to be used for clustered connections. 2010-04-14 15:03:27 +02:00
Daniele Alessandri 0e52825d97 Merge branch 'client_options' into hyves_contribs_port 2010-04-14 14:36:39 +02:00
Daniele Alessandri 5842c57b28 Merge branch 'hashring_rework' into hyves_contribs_port 2010-04-14 14:36:10 +02:00
Daniele Alessandri c89e222fd2 Removed the setOption and getOption methods from ResponseReader as their implementation was clumsy. 2010-04-10 19:10:20 +02:00
Daniele Alessandri c8509dd068 Exposed ResponseReader::setHandler as a public method and implemented ResponseReader::getHandler. 2010-04-10 18:48:42 +02:00
Daniele Alessandri 9e97c15a50 \Predis\Client now uses the new \Predis\ClientOptions class to define various options for a client instance. 2010-04-10 17:45:40 +02:00
Daniele Alessandri c4341eafaa Implemented the new \Predis\ClientOptions class. 2010-04-10 16:53:19 +02:00
Daniele Alessandri a2617af24a Removed a spurious space character. 2010-04-10 16:45:58 +02:00
Daniele Alessandri ea04aa67c6 Bugfix: missing backslash for root namespace. 2010-04-10 16:44:50 +02:00
Daniele Alessandri 994258b4c2 Slightly changed the arguments order of HashRing::addNodeToRing. 2010-04-10 11:01:03 +02:00
Daniele Alessandri 2272982364 Updated CHANGELOG. 2010-04-10 10:55:43 +02:00
Daniele Alessandri 3a44f766c2 Close the underlying connection also on MalformedServerResponse exceptions. 2010-04-10 10:15:05 +02:00
Daniele Alessandri bac4be648f Added support for persistent connections (optional and experimental). 2010-04-10 10:13:01 +02:00
Daniele Alessandri a1c827cb2d Precalculate the total count of the keys in the ring. 2010-04-10 09:25:58 +02:00
Daniele Alessandri 1ba033879a Bugfix: wrap-around differences for HashRing and KetamaPureRing. 2010-04-10 09:05:49 +02:00
Daniele Alessandri 79e7b0b209 Predis\ConnectionCluster now accepts an instance of Predis\Utilities\IRing as an optional parameter. 2010-04-04 23:32:21 +02:00
Daniele Alessandri 6d5060b226 Introduced the new KetamaPureRing class with the same key distribution algorithm of libketama. 2010-04-04 23:14:57 +02:00
Daniele Alessandri a6c246ac7c Small refactoring of the HashRing class. 2010-04-04 23:13:22 +02:00
Daniele Alessandri 18e181d9a1 Introduced the new IRing interface. 2010-04-04 20:13:07 +02:00
Daniele Alessandri aafddece15 Removed code duplication. 2010-04-03 14:01:53 +02:00
Daniele Alessandri 45ed2a9f96 Changed the parameters order for the constructor of the \Predis\CommunicationException class. 2010-04-03 13:31:49 +02:00
Daniele Alessandri 958c0a3b33 Disallow length parameter <= 0 for Connection::readBytes. 2010-04-03 13:23:42 +02:00
Daniele Alessandri f7f9e3483c Reworked the CommunicationException class and its derivates; When specified, close the underlying connection after a CommunicationException has been trown. 2010-04-02 18:53:42 +02:00
Daniele Alessandri 5040ce7d18 New exceptions hierarchy. 2010-04-02 16:58:19 +02:00
Daniele Alessandri 41f2065287 Removed a couple of redundant destructors. 2010-04-02 14:57:14 +02:00
Daniele Alessandri 617d5f69b6 Added support for async connections. 2010-04-02 14:28:15 +02:00
Daniele Alessandri c87fc91fb4 Bugfix: close the connection on Connection::rawCommand when the parameter is set to TRUE. 2010-04-02 14:15:10 +02:00
Daniele Alessandri 4cc43775b0 Added support for partial reads/writes. Note that stream_get_contents is not used because it doesn't seem to respect the timeout. 2010-04-02 13:51:46 +02:00
Daniele Alessandri 1b5e148d96 \Predis\Client::setProfile now accepts also a string value to specify the target server profile. 2010-03-31 12:23:10 +02:00
Daniele Alessandri 981b64fe21 Added support for weight parameter in server configuration, that allows to balance the keys asymmetrically across multiple servers. 2010-03-31 12:04:11 +02:00
Daniele Alessandri 6ea96dcfea Added support for optionally weighted nodes in the hashring. 2010-03-31 11:47:33 +02:00
Daniele Alessandri 435fdeab75 Add support for microsecond read/write timeouts. 2010-03-31 10:40:14 +02:00
Daniele Alessandri 4f3ffe1217 Made ConnectionCluster::getConnection public, so client code can check to which server a command would be sent. 2010-03-30 15:47:39 +02:00
Daniele Alessandri 486244be8d Reworked HashRing::remove to handle hash collisions in a consistent way. 2010-03-30 15:41:31 +02:00
Daniele Alessandri 2cd056cab6 Added wrapping around for the consistent hashing algorithm. 2010-03-30 15:03:49 +02:00
Daniele Alessandri 1c286f29d1 executeCommand is now part of the IConnection interface; Moved the actual implementation of executeCommand() from Predis\Client to Predis\Connection. 2010-03-30 12:53:11 +02:00
Daniele Alessandri 631832eaf9 Updated CHANGELOG. 2010-03-29 12:48:54 +02:00
Daniele Alessandri 17dff871bc New command: HINCRBY (Redis v2.0-dev). 2010-03-29 12:46:43 +02:00
Daniele Alessandri f3d7e5d31b New command: HEXISTS (Redis v2.0-dev). 2010-03-29 12:46:37 +02:00
Daniele Alessandri 2d8007448f New command: CONFIG (Redis v2.0-dev). 2010-03-29 12:46:30 +02:00
Daniele Alessandri de1b8f45bc Fixed failing tests due to changes introduced in Redis commits 3ea27d3, cc3b01c and 653c924. 2010-03-29 12:46:23 +02:00
Daniele Alessandri a0350b2726 Updated CHANGELOG. 2010-03-17 08:20:13 +01:00
Daniele Alessandri 70907adcce Wrong parameters passed to ClientException on write errors over the network. 2010-03-16 22:53:50 +01:00
Daniele Alessandri 8391326de6 New command: HLEN (Redis v2.0-dev). 2010-03-16 17:40:24 +01:00
Daniele Alessandri 9e417d9bcf New command: HGETALL (Redis v2.0-dev). 2010-03-16 17:24:58 +01:00
Daniele Alessandri 13ae4c4ca0 New command: HVALS (Redis v2.0-dev). 2010-03-16 17:22:46 +01:00
Daniele Alessandri cd8674c2f7 New command: HKEYS (Redis v2.0-dev). 2010-03-16 17:21:55 +01:00
Daniele Alessandri 5787b4b9fd New command: HDEL (Redis v2.0-dev). 2010-03-16 17:20:25 +01:00
Daniele Alessandri 0fed80279a Renamed \Predis\Commands\HSet and \Predis\Commands\HGet to \Predis\Commands\HashSet and \Predis\Commands\HashGet for naming consistency. 2010-03-16 17:18:25 +01:00
Daniele Alessandri 1fe49863b4 Do not parse ResponseError instances. 2010-03-11 19:08:47 +01:00
Daniele Alessandri ee9868c123 Instead of passing around the actual socket resource, pass the Connection instance as argument. 2010-03-11 11:23:35 +01:00
Daniele Alessandri ce00cb14b9 Bugfix: the response parser for KEYS raises a E_WARNING when using iterators for multi bulk responses against Redis v2.0. 2010-03-10 23:45:04 +01:00
Daniele Alessandri daf6dbd7c2 // TODO stuff. 2010-03-10 18:48:32 +01:00
Daniele Alessandri ff103b385d Tests for Predis\CommandPipeline. 2010-03-10 18:46:45 +01:00
Daniele Alessandri 4dc9affda2 Minor adjustments in a few tests. 2010-03-10 17:48:28 +01:00
Daniele Alessandri e9e2b8ca5a Tests for Predis\ResponseReader. 2010-03-10 17:46:35 +01:00
Daniele Alessandri 1394df5625 Tests for Predis\Connection. 2010-03-10 16:24:09 +01:00
Daniele Alessandri 5b039c8ee8 Tests for Predis\Command. 2010-03-10 14:59:34 +01:00
Daniele Alessandri 90078b95c7 Tests for Predis\ResponseError. 2010-03-10 14:18:28 +01:00
Daniele Alessandri 83ab54e9fc Tests for Predis\ResponseQueued. 2010-03-10 14:18:15 +01:00
Daniele Alessandri ea9f83d4c0 Tests for Predis\RedisServerProfile. 2010-03-10 14:04:43 +01:00
Daniele Alessandri 95664719a6 Tests for Predis\ConnectionParameters. 2010-03-10 12:04:17 +01:00
Daniele Alessandri f02b5494c7 New set of tests for client-specific features. 2010-03-10 11:47:41 +01:00
Daniele Alessandri c95125bae1 Allow a null parameters argument for the ConnectionParameters constructor (set to default). 2010-03-10 11:44:22 +01:00
Daniele Alessandri 53970bd006 Constants defined for Redis reply types in ResponseReader. 2010-03-10 11:27:28 +01:00
Daniele Alessandri 3b150d4d86 Get ResponseReader options values. 2010-03-10 11:18:25 +01:00
Daniele Alessandri 83c071b7ff Updated CHANGELOG. 2010-03-09 16:47:42 +01:00
Daniele Alessandri cadb7f8a3f Updated TODO. 2010-03-09 16:47:21 +01:00
Daniele Alessandri 52a1c06ac2 New command: ZINTER (Redis v2.0-dev). 2010-03-09 16:43:23 +01:00
Daniele Alessandri b21b6f8029 New command: ZUNION (Redis v2.0-dev). 2010-03-09 16:41:32 +01:00
Daniele Alessandri fa62b75b9a New command: ZREMRANGEBYRANK (Redis v2.0-dev). 2010-03-09 16:37:54 +01:00
Daniele Alessandri 52815adc0f New command: ZREVRANK (Redis v2.0-dev). 2010-03-09 16:33:03 +01:00
Daniele Alessandri 4e4c26c4e6 Updated CHANGELOG. 2010-03-09 16:17:32 +01:00
Daniele Alessandri 38e8c94f8b Enhancement: set how to handle errors returned by the server (throw a ServerException or return a ResponseError instance that holds the error message). 2010-03-09 16:01:33 +01:00
Daniele Alessandri c281891641 Enhancement: set how to handle multibulk replies (fetch the whole reply or stream it down to the user code). 2010-03-09 15:48:41 +01:00
Daniele Alessandri 425c9ade31 Fixed internal API divergences between the two merged branches. 2010-03-09 15:19:22 +01:00
Daniele Alessandri d03c7c42b2 Merge branch 'multibulk_streaming_new'
Conflicts:
	lib/Predis.php
2010-03-09 14:57:38 +01:00
Daniele Alessandri 9086cfc284 Merge branch 'response_reader' into integration 2010-03-09 14:53:53 +01:00
Daniele Alessandri d8b0c7f40c Reverting some obsoleted changes in preparation for a merge into the master branch. 2010-03-09 14:47:15 +01:00
Daniele Alessandri 51c7ef4566 Get the current ResponseReader associated to a Connection instance. 2010-03-09 14:07:41 +01:00
Daniele Alessandri 84ea64a9ee Enhanchement: added the ability to set options on a ResponseReader instance. 2010-03-09 14:06:10 +01:00
Daniele Alessandri e04ed827d4 Get the current ResponseReader associated to a Client instance. 2010-03-09 13:00:43 +01:00
Daniele Alessandri 5cae45282d Fixed tests against the current Redis master branch. 2010-03-09 12:54:18 +01:00
Daniele Alessandri 011d544d06 Fixed a small oversight. 2010-03-09 12:44:37 +01:00
Daniele Alessandri c6f97a7946 New commands: HSET and HGET (Redis v2.0-dev). NOTE: this is the beginning of the Hashes awesomeness in Redis! 2010-03-06 09:30:37 +01:00
Daniele Alessandri c06f9e34bf Added tests for DISCARD. 2010-03-04 14:18:38 +01:00
Daniele Alessandri ac8172235f Added tests for ZRANK. 2010-03-04 14:09:56 +01:00
Daniele Alessandri 5aaec9d11b Added a test for SUBSTR on integer-encoded values. 2010-03-04 13:58:05 +01:00
Daniele Alessandri 3e0d9c8400 Added tests for SUBSTR. 2010-03-04 12:41:51 +01:00
Daniele Alessandri 9ac0d26a48 Minor code rearrangements. 2010-03-04 12:29:23 +01:00
Daniele Alessandri 4645e7508e Updated CHANGELOG. 2010-03-04 12:21:06 +01:00
Daniele Alessandri 46d2344d42 Renamed \Predis\Commands\ZCount to \Predis\Commands\ZSetCount for naming consistency. 2010-03-04 12:17:09 +01:00
Daniele Alessandri 28bac3b3b0 New command: ZRANK (Redis v2.0-dev). 2010-03-04 12:16:14 +01:00
Daniele Alessandri 0b229a5057 New command: SUBSTR (Redis v2.0-dev). 2010-03-04 12:12:10 +01:00
Daniele Alessandri 460dfce7f6 Minor code rearrangements. 2010-03-04 11:58:19 +01:00
Daniele Alessandri 138a171f6c Updated CHANGELOG. 2010-03-02 17:21:38 +01:00
Daniele Alessandri 03ce35f5d9 Enhancement: added support for DISCARD in a MULTI / EXEC context initialized inside of an instance of MultiExecBlock. 2010-03-02 17:15:49 +01:00
Daniele Alessandri c325707559 New command: DISCARD (Redis v2.0-dev). 2010-03-02 16:49:15 +01:00
Daniele Alessandri e114f86d64 Predis\Commands\Keys has been adjusted to handle the change in its reply type in a backwards-compatible way (the KEYS command will return a multibulk reply starting from Redis 2.0). 2010-03-02 16:47:18 +01:00
Daniele Alessandri 8a79343f12 Private utility method ResponseReader->setHandler. 2010-03-01 18:52:34 +01:00
Daniele Alessandri f0d5dad2c1 Non-static response reader 2010-03-01 12:22:39 +01:00
Daniele Alessandri 6e5c495b26 MultiBulkResponseIterator and MultiBulkResponseKVIterator inherit from a common MultiBulkResponseIteratorBase class. 2010-02-27 12:44:36 +01:00
Daniele Alessandri f65cb529ec Enhancement: when using multibulk response iterators, ZRANGE and ZSETRANGE now return a MultiBulkResponseKVIterator when called with the WITHSCORES parameter. 2010-02-27 11:52:14 +01:00
Daniele Alessandri 47db5075ec Implemented MultiBulkResponseKVIterator to wrap iterators that should be seen as $k => array($MBIterator, $MBIterator++) by external code (think of ZRANGE .. WITHSCORES as a practical example). 2010-02-27 11:46:52 +01:00
Daniele Alessandri c8554f2c8b Added tests for APPEND. 2010-02-27 11:15:31 +01:00
Daniele Alessandri 4c6dedabe0 Added tests for ZCOUNT. 2010-02-27 11:08:05 +01:00
Daniele Alessandri 5ad2abd149 Added test for ZRANGEBYSCORE with the WITHSCORES parameter. 2010-02-27 10:59:34 +01:00
Daniele Alessandri 7f8ba42717 Enhancement: ZRANGEBYSCORE now handles the WITHSCORES (Redis v2.0-dev) just like ZRANGE and ZREVRANGE. 2010-02-27 10:54:42 +01:00
Daniele Alessandri ad540776ac New command: ZCOUNT (Redis v2.0-dev). 2010-02-27 10:39:47 +01:00
Daniele Alessandri 90d7b252ae New command: APPEND (Redis v2.0-dev). 2010-02-27 10:31:57 +01:00
Daniele Alessandri 90dc794780 Updated CHANGELOG. 2010-02-27 09:49:04 +01:00
Daniele Alessandri 21abe8bf02 Enhancement: connections can now be identified by an alias (useful when connected to a cluster of Redis servers). 2010-02-27 09:43:49 +01:00
Daniele Alessandri 806ef6058d Increased the default connection timeout from 2 to 5 seconds and moved the initialization of its value in ConnectionParameters->filterConnectionParams. 2010-02-26 23:22:13 +01:00
Daniele Alessandri e229153800 Use instanceof instead of the deprecated is_a(). 2010-02-26 23:04:42 +01:00
Daniele Alessandri 7579b2c6b7 Updated CHANGELOG. 2010-02-26 22:53:25 +01:00
Daniele Alessandri ee5e978a6c Enhancement: allows method chaining with multi-exec blocks. 2010-02-26 22:47:39 +01:00
Daniele Alessandri dac4d87a60 Bugfix: the pipeline command buffer is not correctly reinitialized after CommandPipeline->flushPipeline. 2010-02-26 22:42:09 +01:00
Daniele Alessandri 47d34531e3 Enhancement: allows method chaining with commands pipelines. 2010-02-26 22:30:57 +01:00
Daniele Alessandri 0cd7b446c6 Users can now choose at runtime how to handle multibulk responses. The new (and optional) iterator-based approach is slightly slower than the usual fetch-all behaviour, but in certain scenarios (e.g. when dealing with massive multibulk responses) it can save a lot of memory on the client. 2010-02-25 12:46:10 +01:00
Daniele Alessandri 8df4eaf7b3 Predis\Client::multiExec is now aware of iterable multi-bulk responses. 2010-02-25 12:44:13 +01:00
Daniele Alessandri 701e06443c Ensure that iterators returned by multi-bulk replies inside a pipeline are stored in the replies buffer as arrays. 2010-02-25 12:43:16 +01:00
Daniele Alessandri a1aaf73b78 MultiBulkResponseIterator now implements the Countable interface. 2010-02-25 12:41:57 +01:00
Daniele Alessandri b7203d97e7 MultiBulkResponseIterator::current must be pre-fetched. 2010-02-25 12:41:19 +01:00
Daniele Alessandri a4720dc721 Implemented the new Predis\Utilities\MultiBulkResponseIterator. 2010-02-25 12:40:15 +01:00
Daniele Alessandri 2b0bd88d8f Updated CHANGELOG 2010-02-25 11:39:52 +01:00
Daniele Alessandri 4ee965ab83 Switched from anonymous functions to classes extending the IResponseHandler interface to handle server responses. 2010-02-25 11:28:14 +01:00
Daniele Alessandri 40df90007d Miss typings, oh my... 2010-02-25 11:27:07 +01:00
Daniele Alessandri 2c7a99df55 Added missing test for SORT ... GET 2010-02-25 11:24:50 +01:00
Daniele Alessandri 6e3b1c835d Enhancement: support multiple GET parameters for the SORT command (see also my comment in ISSUE #1) 2010-02-25 10:57:41 +01:00
Daniele Alessandri f5f06d643f Fixed a dangerous oversight in the test suite (seriously, testing FLUSHALL was indeed stupid). 2010-01-27 23:56:26 +01:00
Daniele Alessandri 1be9bef159 Updated CHANGELOG 2010-01-23 16:01:03 +01:00
Daniele Alessandri 7fa935f827 Implemented a factory method for creating server profiles instances. 2010-01-23 15:55:34 +01:00
Daniele Alessandri afdc79f97f Added tests for BGREWRITEAOF. 2010-01-23 15:31:53 +01:00
Daniele Alessandri 6cb9663539 Added missing support for BGREWRITEAOF for Redis >= 1.2.0 2010-01-23 12:54:58 +01:00
Daniele Alessandri 8622dd8b05 Added the CHANGELOG file. 2010-01-23 12:41:45 +01:00
Daniele Alessandri 21acb300a7 The command ListPopLastPushHead (RPOPLPUSH) is now defined as an inline command instead of bulk after a change in Redis 1.2.1. The old bulk RPOPLPUSH has been preserved and renamed in ListPopLastPushHeadBulk, so that you can override the current server profile if you need the old (and uncorrect) behaviour when connecting to a Redis 1.2.0 instance. 2010-01-23 12:33:10 +01:00
Daniele Alessandri 35016ba4b0 Changed the naming convention of the predefined RedisServerProfile derived classes. 2010-01-09 12:36:46 +01:00
Daniele Alessandri ab2842c100 Minor changes in code formatting. 2010-01-09 12:14:40 +01:00
Daniele Alessandri 91543d776f Adjusted Predis\Commands\BackgroundSave according to the new behavior of BGSAVE in Redis 1.2. 2010-01-09 12:00:36 +01:00
Daniele Alessandri 84fb4390f9 Using isset to check if prefix handlers have been initialized is faster. 2010-01-09 11:42:16 +01:00
Daniele Alessandri 8b152f0ea3 Added checks for errors returned by read and write operations on sockets. 2010-01-09 11:28:57 +01:00
Daniele Alessandri e01feda91f Updated the README. 2010-01-09 10:01:47 +01:00
Daniele Alessandri 15c81fca6f Bumping year in the LICENSE file. 2010-01-09 09:49:20 +01:00
Daniele Alessandri 75fad0a027 Implemented Response::read. This new method groups Response::getPrefix and Response::getHeader (and reduces the overhead of unnecessary method calls). 2010-01-07 13:48:14 +01:00
Daniele Alessandri 46dd3d6f19 Improved the internals of MultiExecBlock::execute (slight reduction in memory usage; check for out-of-sync conditions between the client and the server) 2010-01-06 12:13:51 +01:00
Daniele Alessandri d51e8e0c25 Greatly improved the code that initially handles replies getting the correct reply handler. Also, performances might have improved a bit. 2010-01-06 11:47:05 +01:00
Daniele Alessandri 1d3e8cea59 Reduced memory consumption for pipelines 2010-01-06 11:03:27 +01:00
Daniele Alessandri 03886d9a78 Merge branch 'blpop'
Conflicts:
	lib/Predis.php
2010-01-06 10:37:03 +01:00
Daniele Alessandri 2577f6a2cb Added tests for BLPOP and BRPOP. They are not really that great as they are missing a concurrent RPUSHing client, but they are enough for now. 2010-01-02 22:09:27 +01:00
Daniele Alessandri 5641983059 Fixed E_NOTICE messages in Predis\Response::getPrefixHandler on undefined handlers (unknown prefixes received from the server). 2010-01-01 20:44:28 +01:00
Daniele Alessandri 0bac9308b5 Fixed E_NOTICE messages in Predis\RedisServerProfile::createCommand on undefined commands. 2010-01-01 20:32:24 +01:00
Daniele Alessandri d12694c271 Predis\CommandPipeline::execute and Predis\MultiExecBlock::execute are no more limited to accepting only instances of Closure, now every kind of callable object can be passed as argument. 2010-01-01 20:19:34 +01:00
Daniele Alessandri 362cdf4d5a Use the new ternary short cut "?:" where it helps with readability. 2010-01-01 18:55:32 +01:00
Daniele Alessandri 04c481b3d7 Removed a bunch of unmeaningful TODOs end notes. 2010-01-01 18:42:13 +01:00
Daniele Alessandri 238baf7dc8 Implemented Predis\RedisServerProfile::compareWith, usefult to compare two different profiles. Its current behavior is the very same as PHP's version_compare. 2010-01-01 18:35:15 +01:00
Daniele Alessandri 9dae351819 Casting a instance of Predis\RedisServerProfile to string returns its associated version string. 2010-01-01 18:11:37 +01:00
Daniele Alessandri d34fc18ea8 Reverted a bad versioning idea. The Predis\RedisServer__Futures class will always be availabe and it represents the current development branch of Redis. 2010-01-01 18:09:03 +01:00
Daniele Alessandri cd8604b489 Removed Predis\Client::registerCommand and Predis\Client::registerCommands as they are rarely used. The methods of the same name available in RedisServerProfile (and its derivates) serve the same purpose, use them from now on. 2010-01-01 17:46:34 +01:00
Daniele Alessandri 99ad5aa4a5 Implemented Predis\Client::getProfile. 2010-01-01 17:37:26 +01:00
Daniele Alessandri 2e5549b316 Renamed Predis\Client::setServerProfile to Predis\Client::setProfile. 2010-01-01 17:35:42 +01:00
Daniele Alessandri d719a26406 Switch to string-based versions for RedisServerProfile classes. 2010-01-01 17:25:27 +01:00
Daniele Alessandri 2a06d84a7b Throw a more meaningful exception if the server does not respond with a +QUEUED status reply to commands issued in a MULTI / EXEC context. 2009-12-31 14:11:24 +01:00
Daniele Alessandri 1f9e6143bf Commands issued with a MultiExecBlock now return ResponseQueued instances to the caller. 2009-12-31 14:05:12 +01:00
Daniele Alessandri 77f885c233 Merge branch 'multi_exec' 2009-12-31 13:48:20 +01:00
Daniele Alessandri db6e40df98 Added tests for MULTI / EXEC. 2009-12-31 13:00:27 +01:00
Daniele Alessandri e637881c2d Force the test suite to load the server profile for Redis edge versions (development unstable). 2009-12-31 12:18:34 +01:00
Daniele Alessandri 31234d694e Bugfix: ListPopFirstBlocking is actually BLPOP, not BRPOP. This is what happens when you write code while thinking about something else... 2009-12-30 21:57:51 +01:00
Daniele Alessandri a4e067891a Implemented RedisServerProfile::supportsCommand. 2009-12-30 13:49:48 +01:00
Daniele Alessandri bf19df180c Introduced a first draft of a new way to internally check for responses to enqueued commands. 2009-12-30 11:51:39 +01:00
Daniele Alessandri 7c6e03edae Removed the default value for the read_write_timeout when initializing the connection stream. Now the timeout for r/w operations on the stream is set only if it has been set in the ConnectionParameters instance, otherwise the system default will be implicitly used (the default is usually 60 seconds). 2009-12-30 10:38:56 +01:00
Daniele Alessandri ee739ff843 Implemented the __isset magic method for the ConnectionParameters class (it is useful to check if a parameter has been set). 2009-12-30 10:30:08 +01:00
Daniele Alessandri fcecd2579a Added "connection_timeout" and "read_write_timeout" as optional arguments for the ConnectionParameters class. 2009-12-30 10:25:06 +01:00
Daniele Alessandri f3aeecef37 Added BLPOP and BRPOP. 2009-12-30 09:35:46 +01:00
Daniele Alessandri 55c40afcd8 Bugfix: return an empty string instead of null when the data length of a bulk reply is 0. 2009-12-29 14:55:26 +01:00
Daniele Alessandri 1626f9658c New Predis\Client::multiExec method added. 2009-12-28 00:29:51 +01:00
Daniele Alessandri f4b0f664e7 Implemented the new Predis\MultiExecBlock class to wrap commands issued inside of MULTI + EXEC. 2009-12-28 00:23:00 +01:00
Daniele Alessandri 5c95b9cdcc Do not parse the response to a command if we get a QUEUED status reply from the server. 2009-12-27 23:21:46 +01:00
Daniele Alessandri a13d0e4d72 Started hacking a bit on the new MULTI and EXEC commands. 2009-12-27 22:44:47 +01:00
Daniele Alessandri abbc9108e0 Fixed another E_STRICT notice that was being raised when using a pipeline. 2009-12-27 11:42:18 +01:00
Daniele Alessandri b757afe492 Removed a superfluous method call. 2009-12-27 10:57:23 +01:00
Daniele Alessandri 75a06019f8 Fixed E_STRICT notices that were being raised by PHP due to a slightly different method signature used for two command classes. 2009-12-27 10:53:29 +01:00
Daniele Alessandri 51710682c7 ZSetReverseRange now inherits from ZSetRange as the two commands share the same behaviour. This change allowed us to remove some code duplication. 2009-12-27 10:48:41 +01:00
Daniele Alessandri f82d11a8db Changed the name of Predis\Client::createCommandInstance into Predis\Client::createCommand. 2009-12-27 10:33:02 +01:00
Daniele Alessandri 6814845e3f Removed a wrong type-check in Predis\Client::setupConnection that was breaking the initialization of a cluster of connections when using an array of URI strings as parameters. 2009-12-26 19:42:45 +01:00
Daniele Alessandri e8a0f3f627 Fix for a warning emitted by PHP when passing an array of strings parameters to Predis\Client::create. 2009-12-26 19:39:18 +01:00
Daniele Alessandri 6e39491692 Changed the returned string used to hash a Connection instance when using a cluster of connections. IMPORTANT NOTE: if you are using a version of Predis older than this commit, then this change will surely have an impact on your existing partitioned data as it changes the distribution of server nodes over the ring. 2009-12-25 22:04:24 +01:00
Daniele Alessandri e5c3123d88 Updated TODO. 2009-12-25 21:54:04 +01:00
Daniele Alessandri 6d43827af9 Merge branch 'server_compat'
Conflicts:
	lib/Predis.php
2009-12-25 21:25:40 +01:00
Daniele Alessandri 4a4e4b5a72 Updated the README with the new parameters for Predis\Client. The old signature Predis\Client(, ) is now completely deprecated and it does not work anymore. 2009-12-25 21:12:54 +01:00
Daniele Alessandri 8eb51ec0d1 Updated the test suite to work with the new parameters for Predis\Client. 2009-12-25 21:11:08 +01:00
Daniele Alessandri 47bb83bbb2 Type checking + minor fixes + more readable code for Predis\Client::__construct and Predis\Client::create. 2009-12-25 20:51:17 +01:00
Daniele Alessandri e64333d77b Complete rewrite of the client construction and initialization bits. 2009-12-25 19:54:12 +01:00
Daniele Alessandri 627433cef8 Extended the tests for ZRANGE and ZREVRANGE to cover the newly added "WITHSCORES" option. 2009-12-23 22:05:04 +01:00
Daniele Alessandri 822a3e56e2 Implemented the "WITHSCORES" option for ZRANGE and ZREVRANGE. 2009-12-23 21:54:53 +01:00
Daniele Alessandri d9b304f9e3 Merge branch 'cmd_zincrby' 2009-12-19 10:49:34 +01:00
Daniele Alessandri 81484b3351 Added tests for Predis\Commands\ZSetIncrementBy (ZINCRBY). 2009-12-19 10:46:09 +01:00
Daniele Alessandri d3a62d68bb Fixed the return value of Predis\Commands\ZSetIncrementBy as it does not return a boolean value but the current score after the increment operation. 2009-12-19 10:45:19 +01:00
Daniele Alessandri 20e416306c Added support for key tags: instead of hashing the full key, we hash only the portion enclosed within curly brackets. 2009-12-18 22:57:16 +01:00
Daniele Alessandri 3ccbff4277 The second parameter for RedisServerProfile::createCommandInstance is now optional. 2009-12-18 22:02:30 +01:00
Daniele Alessandri 6e76fbf660 Moved the default server profile class name to a private static variable of the Client class. 2009-12-18 21:59:00 +01:00
Daniele Alessandri 88cda9e52c Added the new public method Client::setServerProfile. 2009-12-18 21:29:44 +01:00
Daniele Alessandri 876ac2ec7c Renamed class RedisServerCompatibility to RedisServerProfile. 2009-12-18 21:24:19 +01:00
Daniele Alessandri e57348720f Just removed a bunch of unuseful comments... 2009-12-18 21:16:24 +01:00
Daniele Alessandri f811877c87 More trivial changes for HashRing::add and HashRing::remove. 2009-12-18 21:08:42 +01:00
Daniele Alessandri d3115e6259 Trivial changes in HashRing::getNodeKey. 2009-12-18 21:04:44 +01:00
Daniele Alessandri ca7f3e294c Removed the rather superfluous private method ConnectionCluster::getConnectionFromRing. 2009-12-18 20:48:04 +01:00
Daniele Alessandri bcfa64f431 Moved the hash calculation for a command from ConnectionCluster to the command instance itself. 2009-12-18 20:43:35 +01:00
Daniele Alessandri 3428529be6 Client::executeCommandInternal must accept IConnection types! Stupid bugs are indeed stupid. 2009-12-16 00:23:55 +01:00
Daniele Alessandri b1edc31af3 When using a ConnectionCluster (sharding data over multiple servers), disallow sending commands that cannot be hashed by a key argument. 2009-12-14 18:15:10 +01:00
Daniele Alessandri 344ec44059 Refactored Client::executeCommand and introduced the new method Client::executeCommandOnShards which is useful to execute commands on all the connections registered in a ConnectionCluster instance. 2009-12-14 18:02:54 +01:00
Daniele Alessandri 8d4958a516 The second parameter for Client::createCommandInstance is now optional. 2009-12-14 17:57:17 +01:00
Daniele Alessandri b777daa535 Slightly improved the internals of Command::getArgument and Command::getArguments. 2009-12-14 17:54:11 +01:00
Daniele Alessandri 177120e1a2 The private method computeHash of ConnectionCluster is now a static method. 2009-12-14 17:47:10 +01:00
Daniele Alessandri a84c9bdac7 ConnectionCluster now implements the IteratorAggregate interface, thus enabling iterations over the registered connections simply by using a foreach loop. 2009-12-14 17:43:30 +01:00
Daniele Alessandri c7cd2b67e0 Same fix as commit 755c252 in master for the short alias of \Predis\Commands\Decrement 2009-12-04 21:09:38 +01:00
Daniele Alessandri cfcb635c24 Predis\Client now uses the new compatibility profiles, though it is still hardcoded which profile to load. 2009-11-29 13:38:04 +01:00
Daniele Alessandri d0d51257c9 Added compatibility profiles for Redis server versions 1.0 and the upcoming 1.2. 2009-11-29 13:16:42 +01:00
Daniele Alessandri a70c5b0800 Added the new abstract class 'RedisServerCompatibility'. Its subclassess will be used to define a set compatibility profiles for each version of the Redis server. The only drawback is that the selected compatibility profile will be shared among multiple connections when using client-side sharding. 2009-11-29 13:09:08 +01:00
Daniele Alessandri af810d9613 Implemented ZINCRBY (Class: \Predis\Commands\ZSetIncrementBy) 2009-11-20 22:23:42 +01:00
16 changed files with 4305 additions and 986 deletions
+124
View File
@@ -0,0 +1,124 @@
v0.6.0 (2010-05-24)
* Switched to the new multi-bulk request protocol for all of the commands
in the Redis 1.2 and Redis 2.0 profiles. Inline and bulk requests are now
deprecated as they will be removed in future releases of Redis.
* The default server profile is "2.0" (targeting Redis 2.0.x). If you are
using older versions of Redis, it is highly recommended that you specify
which server profile the client should use (e.g. "1.2" when connecting
to instances of Redis 1.2.x).
* Support for Redis 1.0 is now optional and it is provided by requiring
'Predis_Compatibility.php' before creating an instance of Predis\Client.
* New commands added to the Redis 2.0 profile since Predis 0.5.1:
- Strings: SETEX, APPEND, SUBSTR
- ZSets : ZCOUNT, ZRANK, ZUNIONSTORE, ZINTERSTORE, ZREMBYRANK, ZREVRANK
- Hashes : HSET, HSETNX, HMSET, HINCRBY, HGET, HMGET, HDEL, HEXISTS,
HLEN, HKEYS, HVALS, HGETALL
- PubSub : PUBLISH, SUBSCRIBE, UNSUBSCRIBE
- Misc. : DISCARD, CONFIG
* Introduced client-level options with the new Predis\ClientOptions class.
Options can be passed to Predis\Client::__construct in its second argument
as an array or an instance of Predis\ClientOptions. For brevity's sake and
compatibility with older versions, the constructor of Predis\Client still
accepts an instance of Predis\RedisServerProfile in its second argument.
The currently supported client options are:
- profile [default: "2.0" as of Predis 0.6.0]
specifies which server profile to use when connecting to Redis. This
option accepts an instance of Predis\RedisServerProfile or a string
that indicates the target version.
- key_distribution [default: Predis\Distribution\HashRing]
specifies which key distribution strategy to use to distribute keys
among the servers that compose a cluster. This option accepts an
instance of Predis\Distribution\IDistributionStrategy so that users
can implement their own key distribution strategy. Optionally, the new
Predis\Distribution\KetamaPureRing class also provides a pure-PHP
implementation of the same algorithm used by libketama.
- throw_on_error [default: TRUE]
server errors can optionally be handled "silently": instead of throwing
an exception, the client returns an error response type.
- iterable_multibulk [EXPERIMENTAL - default: FALSE]
in addition to the classic way of fetching a whole multibulk reply
into an array, the client can now optionally stream a multibulk reply
down to the user code by using PHP iterators. It is just a little bit
slower, but it can save a lot of memory in certain scenarios.
* New parameters for connections:
- alias [default: not set]
every connection can now be identified by an alias that is useful to
get a certain connection when connected to a cluster of Redis servers.
- weight [default: not set]
allows the client to balance the keys asymmetrically across multiple
servers. This might be useful when you have servers with different
amounts of memory and you want to distribute the load of your keys
accordingly.
- connection_async [default: FALSE]
estabilish connections to servers in a non-blocking way, so that the
client is not blocked while the underlying resource performs the actual
connection.
- connection_persistent [default: FALSE]
the underlying connection resource is left open when a script ends its
lifecycle. Persistent connections can lead to unpredictable or strange
behaviours, so they should be used with extreme care.
* Introduced the Predis\Pipeline\IPipelineExecutor interface. Classes that
implements this interface are used internally by the Predis\CommandPipeline
class to change the behaviour of the pipeline when writing/reading commands
from one or multiple servers. Here is the list of the default executors:
- Predis\Pipeline\StandardExecutor
Exceptions generated by server errors might be thrown depending on the
options passed to the client (see "throw_on_error"). Instead, protocol
or network errors always throw exceptions. This is the default executor
for single and clustered connections and shares the same behaviour of
Predis 0.5.x.
- Predis\Pipeline\SafeExecutor
Exceptions generated by server, protocol or network errors are not
thrown, instead they are returned in the response array as instances of
ResponseError or CommunicationException.
- Predis\Pipeline\SafeClusterExecutor
This executor shares the same behaviour of Predis\Pipeline\SafeExecutor
but it is geared towards clustered connections.
* Support for PUBSUB is handled by the new Predis\PubSubContext class, which
could also be used to build a callback dispatcher for PUBSUB scenarios.
* When connected to a cluster of connections, it is now possible to get a
new Predis\Client instance for a single connection of the cluster by
passing its alias/index to the new Predis\Client::getClientFor() method.
* CommandPipeline and MultiExecBlock return their instances when invoking
commands, thus allowing method chaining in pipelines and multi-exec blocks.
* MultiExecBlock instances can handle the new DISCARD command.
* Connections now support float values for the connection_timeout parameter
to express timeouts with a microsecond resolution.
* FIX: TCP connections now respect the read/write timeout parameter when
reading the payload of server responses. Previously, stream_get_contents()
was being used internally to read data from a connection but it looks like
PHP does not honour the specified timeout for socket streams when inside
this function.
* FIX: The GET parameter for the SORT command now accepts also multiple key
patterns by passing an array of strings. (ISSUE #1).
* FIX: Replies to the DEL command return the number of elements deleted by
the server and not 0 or 1 interpreted as a boolean response. (ISSUE #4).
v0.5.1 (2010-01-23)
* RPOPLPUSH has been changed from bulk command to inline command in Redis
1.2.1, so ListPopLastPushHead now extends InlineCommand. The old RPOPLPUSH
behavior is still available via the ListPopLastPushHeadBulk class so that
you can override the server profile if you need the old (and uncorrect)
behaviour when connecting to a Redis 1.2.0 instance.
* Added missing support for BGREWRITEAOF for Redis >= 1.2.0
* Implemented a factory method for the RedisServerProfile class to ease the
creation of new server profile instances based on a version string.
v0.5.0 (2010-01-09)
* First versioned release of Predis
+2 -2
View File
@@ -1,4 +1,4 @@
Copyright (c) 2009 Daniele Alessandri
Copyright (c) 2009-2010 Daniele Alessandri
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
@@ -19,4 +19,4 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
OTHER DEALINGS IN THE SOFTWARE.
+25 -14
View File
@@ -3,26 +3,32 @@
## About ##
Predis is a flexible and feature-complete PHP client library for the Redis key-value
database.
database. It currently comes in two flavors:
Predis is currently a work-in-progress and it targets PHP >= 5.3, though it is highly
due to be backported to PHP >= 5.2.6 as soon as the public API and the internal design
on the main branch will be considered stable enough.
- the mainline client library, which targets PHP 5.3.x and leverages a lot of the
features introduced in this new version of the PHP interpreter.
- a backport to PHP 5.2.x for those who can not upgrade their environment yet
(it admittedly has a lower priority compared to the mainline library, although we
try to keep the two versions aligned as much as possible).
Please refer to the TODO file to see which issues are still pending and what is due
to be implemented soon in Predis.
## Features ##
## Main features ##
- Client-side sharding (support for consistent hashing of keys)
- Command pipelining on single and multiple connections (transparent)
- Lazy connections (connections to Redis instances are only established just in time)
- Flexible system to define and register your own set of commands to a client instance
- Full support for Redis 2.0. Different versions of Redis are supported via server profiles.
- Client-side sharding (support for consistent hashing and custom distribution strategies).
- Command pipelining on single and multiple connections (transparent).
- Lazy connections (connections to Redis instances are only established just in time).
- Flexible system to define and register your own set of commands to a client instance.
## Quick examples ##
See the [official wiki](http://wiki.github.com/nrk/predis) of the project for a more
complete coverage of all the features available in Predis.
### Connecting to a local instance of Redis ###
You don't have to specify a tcp host and port when connecting to Redis instances
@@ -38,7 +44,7 @@ running on the localhost on the default port:
Pipelining helps with performances when there is the need to issue many commands
to a server in one go:
$redis = new Predis\Client('10.0.0.1', 6379);
$redis = new Predis\Client('redis://10.0.0.1:6379/');
$replies = $redis->pipeline(function($pipe) {
$pipe->ping();
$pipe->incrby('counter', 10);
@@ -76,12 +82,12 @@ its way into a stable Predis release, then you can start off by creating a new
class that matches the command type and its behaviour and then bind it to a
client instance at runtime. Actually, it is easier done than said:
class BrandNewRedisCommand extends \Predis\InlineCommand {
class BrandNewRedisCommand extends \Predis\MultiBulkCommand {
public function getCommandId() { return 'NEWCMD'; }
}
$redis = new Predis\Client();
$redis->registerCommand('BrandNewRedisCommand', 'newcmd');
$redis->getProfile()->registerCommand('BrandNewRedisCommand', 'newcmd');
$redis->newcmd();
@@ -100,18 +106,20 @@ they are not the preferred way to contribute to Predis.
When modifying Predis please be sure that no warnings or notices are emitted by PHP
by running the interpreter in your development environment with the "error_reporting"
variable set to E_ALL.
variable set to E_ALL | E_STRICT.
## Dependencies ##
- PHP >= 5.3
- PHP >= 5.3.0 (for the mainline client library)
- PHP >= 5.2.6 (for the backported client library)
- PHPUnit (needed to run the test suite)
## Links ##
### Project ###
- [Source code](http://github.com/nrk/predis/)
- [Wiki](http://wiki.github.com/nrk/predis/)
- [Issue tracker](http://github.com/nrk/predis/issues)
### Related ###
@@ -124,6 +132,9 @@ variable set to E_ALL.
[Daniele Alessandri](mailto:suppakilla@gmail.com)
## Contributors ##
[Lorenzo Castelli](http://github.com/lcastelli)
## License ##
+5 -19
View File
@@ -1,21 +1,7 @@
* Authentication and database selection should be handled transparently by
the client.
* Documentation! The README is obviously not enought to show how to use
Predis as it does not cover all of its features.
* The current behaviour of sending, by default, unshardable commands to the
first registered connection of a ConnectionCluster instance needs to be
verified.
* The included test suite covers almost all the Redis server commands, but a
full battery of tests targeting specific functions of this library is still
missing.
* Support for pipelining commands on one or more connections works, but it
could be optimized for better performances with a cache of computed commands
hashes, but the memory impact still needs to be evalued.
* Add the possibility of flushing the command buffer from inside of a pipeline.
* Switching to/from instances of Connection and ConnectionCluster should be
transparent to the user. Using a ConnectionCluster instance when there is
only one active connection has an unnecessary overhead.
* Add more tests targeting specific functions of the library.
* Missing tests for commands:
PUBLISH, SUBSCRIBE, UNSUBSCRIBE, PSUBSCRIBE, PUNSUBSCRIBE
+1
View File
@@ -0,0 +1 @@
0.6.0
+3 -3
View File
@@ -1,10 +1,10 @@
<?php
require_once 'SharedConfigurations.php';
// when you have a whole set of consecutive commands to send to
// When you have a whole set of consecutive commands to send to
// a redis server, you can use a pipeline to improve performances.
$redis = Predis\Client::create($configurations);
$redis = new Predis\Client($single_server);
$replies = $redis->pipeline(function($pipe) {
$pipe->ping();
@@ -35,4 +35,4 @@ Array
)
*/
?>
?>
+60
View File
@@ -0,0 +1,60 @@
<?php
require_once 'SharedConfigurations.php';
// Developers can customize the distribution strategy used by the client
// to distribute keys among a cluster of servers simply by creating a class
// that implements the Predis\Distribution\IDistributionAlgorithm interface.
class NaiveDistributionStrategy
implements Predis\Distribution\IDistributionStrategy {
private $_nodes, $_nodesCount;
public function __constructor() {
$this->_nodes = array();
$this->_nodesCount = 0;
}
public function add($node, $weight = null) {
$this->_nodes[] = $node;
$this->_nodesCount++;
}
public function remove($node) {
$this->_nodes = array_filter($this->_nodes, function($n) use($node) {
return $n !== $node;
});
$this->_nodesCount = count($this->_nodes);
}
public function get($key) {
$count = $this->_nodesCount;
if ($count === 0) {
throw new RuntimeException('No connections');
}
return $this->_nodes[$count > 1 ? abs(crc32($key) % $count) : 0];
}
public function generateKey($value) {
return crc32($value);
}
}
$options = array(
'key_distribution' => new NaiveDistributionStrategy(),
);
$redis = new Predis\Client($multiple_servers, $options);
for ($i = 0; $i < 100; $i++) {
$redis->set("key:$i", str_pad($i, 4, '0', 0));
$redis->get("key:$i");
}
$server1 = $redis->getClientFor('first')->info();
$server2 = $redis->getClientFor('second')->info();
printf("Server '%s' has %d keys while server '%s' has %d keys.\n",
'first', $server1['db15']['keys'], 'second', $server2['db15']['keys']
);
?>
+2 -2
View File
@@ -11,7 +11,7 @@ $mkv = array(
'usr:0003' => 'Third user'
);
$redis = Predis\Client::create($configurations);
$redis = new Predis\Client($single_server);
$redis->mset($mkv);
$retval = $redis->mget(array_keys($mkv));
@@ -26,4 +26,4 @@ Array
[2] => Third user
)
*/
?>
?>
+52
View File
@@ -0,0 +1,52 @@
<?php
require_once 'SharedConfigurations.php';
// Redis 2.0 features new commands that allow clients to subscribe for
// events published on certain channels (PUBSUB).
// Create a client and disable r/w timeout on the socket
$redis = new Predis\Client($single_server + array('read_write_timeout' => -1));
// Initialize a new pubsub context
$pubsub = $redis->pubSubContext();
// Subscribe to your channels
$pubsub->subscribe('control_channel');
$pubsub->subscribe('notifications');
// Start processing the pubsup messages. Open a terminal and use redis-cli
// to push messages to the channels. Examples:
// ./redis-cli PUBLISH notifications "this is a test"
// ./redis-cli PUBLISH control_channel quit_loop
foreach ($pubsub as $message) {
switch ($message->kind) {
case 'subscribe':
echo "Subscribed to {$message->channel}\n";
break;
case 'message':
if ($message->channel == 'control_channel') {
if ($message->payload == 'quit_loop') {
echo "Aborting pubsub loop...\n";
$pubsub->unsubscribe();
}
else {
echo "Received an unrecognized command: {$message->payload}.\n";
}
}
else {
echo "Received the following message from {$message->channel}:\n",
" {$message->payload}\n\n";
}
break;
}
}
// Always unset the pubsub context instance when you are done! The
// class destructor will take care of cleanups and prevent protocol
// desynchronizations between the client and the server.
unset($pubsub);
// Say goodbye :-)
$info = $redis->info();
print_r("Goodbye from Redis v{$info['redis_version']}!\n");
?>
+17 -2
View File
@@ -1,9 +1,24 @@
<?php
require_once '../lib/Predis.php';
$configurations = array(
$single_server = array(
'host' => '127.0.0.1',
'port' => 6379,
'database' => 15
);
?>
$multiple_servers = array(
array(
'host' => '127.0.0.1',
'port' => 6379,
'database' => 15,
'alias' => 'first',
),
array(
'host' => '127.0.0.1',
'port' => 6380,
'database' => 15,
'alias' => 'second',
),
);
?>
+2 -2
View File
@@ -3,7 +3,7 @@ require_once 'SharedConfigurations.php';
// simple set and get scenario
$redis = Predis\Client::create($configurations);
$redis = new Predis\Client($single_server);
$redis->set('library', 'predis');
$retval = $redis->get('library');
@@ -13,4 +13,4 @@ print_r($retval);
/* OUTPUT
predis
*/
?>
?>
+2112 -626
View File
File diff suppressed because it is too large Load Diff
+500
View File
@@ -0,0 +1,500 @@
<?php
namespace Predis;
RedisServerProfile::registerProfile('\Predis\RedisServer_v1_0', '1.0');
class RedisServer_v1_0 extends \Predis\RedisServerProfile {
public function getVersion() { return '1.0'; }
public function getSupportedCommands() {
return array(
/* miscellaneous commands */
'ping' => '\Predis\Compatibility\v1_0\Commands\Ping',
'echo' => '\Predis\Compatibility\v1_0\Commands\DoEcho',
'auth' => '\Predis\Compatibility\v1_0\Commands\Auth',
/* connection handling */
'quit' => '\Predis\Compatibility\v1_0\Commands\Quit',
/* commands operating on string values */
'set' => '\Predis\Compatibility\v1_0\Commands\Set',
'setnx' => '\Predis\Compatibility\v1_0\Commands\SetPreserve',
'setPreserve' => '\Predis\Compatibility\v1_0\Commands\SetPreserve',
'get' => '\Predis\Compatibility\v1_0\Commands\Get',
'mget' => '\Predis\Compatibility\v1_0\Commands\GetMultiple',
'getMultiple' => '\Predis\Compatibility\v1_0\Commands\GetMultiple',
'getset' => '\Predis\Compatibility\v1_0\Commands\GetSet',
'getSet' => '\Predis\Compatibility\v1_0\Commands\GetSet',
'incr' => '\Predis\Compatibility\v1_0\Commands\Increment',
'increment' => '\Predis\Compatibility\v1_0\Commands\Increment',
'incrby' => '\Predis\Compatibility\v1_0\Commands\IncrementBy',
'incrementBy' => '\Predis\Compatibility\v1_0\Commands\IncrementBy',
'decr' => '\Predis\Compatibility\v1_0\Commands\Decrement',
'decrement' => '\Predis\Compatibility\v1_0\Commands\Decrement',
'decrby' => '\Predis\Compatibility\v1_0\Commands\DecrementBy',
'decrementBy' => '\Predis\Compatibility\v1_0\Commands\DecrementBy',
'exists' => '\Predis\Compatibility\v1_0\Commands\Exists',
'del' => '\Predis\Compatibility\v1_0\Commands\Delete',
'delete' => '\Predis\Compatibility\v1_0\Commands\Delete',
'type' => '\Predis\Compatibility\v1_0\Commands\Type',
/* commands operating on the key space */
'keys' => '\Predis\Compatibility\v1_0\Commands\Keys',
'randomkey' => '\Predis\Compatibility\v1_0\Commands\RandomKey',
'randomKey' => '\Predis\Compatibility\v1_0\Commands\RandomKey',
'rename' => '\Predis\Compatibility\v1_0\Commands\Rename',
'renamenx' => '\Predis\Compatibility\v1_0\Commands\RenamePreserve',
'renamePreserve' => '\Predis\Compatibility\v1_0\Commands\RenamePreserve',
'expire' => '\Predis\Compatibility\v1_0\Commands\Expire',
'expireat' => '\Predis\Compatibility\v1_0\Commands\ExpireAt',
'expireAt' => '\Predis\Compatibility\v1_0\Commands\ExpireAt',
'dbsize' => '\Predis\Compatibility\v1_0\Commands\DatabaseSize',
'databaseSize' => '\Predis\Compatibility\v1_0\Commands\DatabaseSize',
'ttl' => '\Predis\Compatibility\v1_0\Commands\TimeToLive',
'timeToLive' => '\Predis\Compatibility\v1_0\Commands\TimeToLive',
/* commands operating on lists */
'rpush' => '\Predis\Compatibility\v1_0\Commands\ListPushTail',
'pushTail' => '\Predis\Compatibility\v1_0\Commands\ListPushTail',
'lpush' => '\Predis\Compatibility\v1_0\Commands\ListPushHead',
'pushHead' => '\Predis\Compatibility\v1_0\Commands\ListPushHead',
'llen' => '\Predis\Compatibility\v1_0\Commands\ListLength',
'listLength' => '\Predis\Compatibility\v1_0\Commands\ListLength',
'lrange' => '\Predis\Compatibility\v1_0\Commands\ListRange',
'listRange' => '\Predis\Compatibility\v1_0\Commands\ListRange',
'ltrim' => '\Predis\Compatibility\v1_0\Commands\ListTrim',
'listTrim' => '\Predis\Compatibility\v1_0\Commands\ListTrim',
'lindex' => '\Predis\Compatibility\v1_0\Commands\ListIndex',
'listIndex' => '\Predis\Compatibility\v1_0\Commands\ListIndex',
'lset' => '\Predis\Compatibility\v1_0\Commands\ListSet',
'listSet' => '\Predis\Compatibility\v1_0\Commands\ListSet',
'lrem' => '\Predis\Compatibility\v1_0\Commands\ListRemove',
'listRemove' => '\Predis\Compatibility\v1_0\Commands\ListRemove',
'lpop' => '\Predis\Compatibility\v1_0\Commands\ListPopFirst',
'popFirst' => '\Predis\Compatibility\v1_0\Commands\ListPopFirst',
'rpop' => '\Predis\Compatibility\v1_0\Commands\ListPopLast',
'popLast' => '\Predis\Compatibility\v1_0\Commands\ListPopLast',
/* commands operating on sets */
'sadd' => '\Predis\Compatibility\v1_0\Commands\SetAdd',
'setAdd' => '\Predis\Compatibility\v1_0\Commands\SetAdd',
'srem' => '\Predis\Compatibility\v1_0\Commands\SetRemove',
'setRemove' => '\Predis\Compatibility\v1_0\Commands\SetRemove',
'spop' => '\Predis\Compatibility\v1_0\Commands\SetPop',
'setPop' => '\Predis\Compatibility\v1_0\Commands\SetPop',
'smove' => '\Predis\Compatibility\v1_0\Commands\SetMove',
'setMove' => '\Predis\Compatibility\v1_0\Commands\SetMove',
'scard' => '\Predis\Compatibility\v1_0\Commands\SetCardinality',
'setCardinality' => '\Predis\Compatibility\v1_0\Commands\SetCardinality',
'sismember' => '\Predis\Compatibility\v1_0\Commands\SetIsMember',
'setIsMember' => '\Predis\Compatibility\v1_0\Commands\SetIsMember',
'sinter' => '\Predis\Compatibility\v1_0\Commands\SetIntersection',
'setIntersection' => '\Predis\Compatibility\v1_0\Commands\SetIntersection',
'sinterstore' => '\Predis\Compatibility\v1_0\Commands\SetIntersectionStore',
'setIntersectionStore' => '\Predis\Compatibility\v1_0\Commands\SetIntersectionStore',
'sunion' => '\Predis\Compatibility\v1_0\Commands\SetUnion',
'setUnion' => '\Predis\Compatibility\v1_0\Commands\SetUnion',
'sunionstore' => '\Predis\Compatibility\v1_0\Commands\SetUnionStore',
'setUnionStore' => '\Predis\Compatibility\v1_0\Commands\SetUnionStore',
'sdiff' => '\Predis\Compatibility\v1_0\Commands\SetDifference',
'setDifference' => '\Predis\Compatibility\v1_0\Commands\SetDifference',
'sdiffstore' => '\Predis\Compatibility\v1_0\Commands\SetDifferenceStore',
'setDifferenceStore' => '\Predis\Compatibility\v1_0\Commands\SetDifferenceStore',
'smembers' => '\Predis\Compatibility\v1_0\Commands\SetMembers',
'setMembers' => '\Predis\Compatibility\v1_0\Commands\SetMembers',
'srandmember' => '\Predis\Compatibility\v1_0\Commands\SetRandomMember',
'setRandomMember' => '\Predis\Compatibility\v1_0\Commands\SetRandomMember',
/* multiple databases handling commands */
'select' => '\Predis\Compatibility\v1_0\Commands\SelectDatabase',
'selectDatabase' => '\Predis\Compatibility\v1_0\Commands\SelectDatabase',
'move' => '\Predis\Compatibility\v1_0\Commands\MoveKey',
'moveKey' => '\Predis\Compatibility\v1_0\Commands\MoveKey',
'flushdb' => '\Predis\Compatibility\v1_0\Commands\FlushDatabase',
'flushDatabase' => '\Predis\Compatibility\v1_0\Commands\FlushDatabase',
'flushall' => '\Predis\Compatibility\v1_0\Commands\FlushAll',
'flushDatabases' => '\Predis\Compatibility\v1_0\Commands\FlushAll',
/* sorting */
'sort' => '\Predis\Compatibility\v1_0\Commands\Sort',
/* remote server control commands */
'info' => '\Predis\Compatibility\v1_0\Commands\Info',
'slaveof' => '\Predis\Compatibility\v1_0\Commands\SlaveOf',
'slaveOf' => '\Predis\Compatibility\v1_0\Commands\SlaveOf',
/* persistence control commands */
'save' => '\Predis\Compatibility\v1_0\Commands\Save',
'bgsave' => '\Predis\Compatibility\v1_0\Commands\BackgroundSave',
'backgroundSave' => '\Predis\Compatibility\v1_0\Commands\BackgroundSave',
'lastsave' => '\Predis\Compatibility\v1_0\Commands\LastSave',
'lastSave' => '\Predis\Compatibility\v1_0\Commands\LastSave',
'shutdown' => '\Predis\Compatibility\v1_0\Commands\Shutdown',
);
}
}
/* ------------------------------------------------------------------------- */
namespace Predis\Compatibility\v1_0\Commands;
/* miscellaneous commands */
class Ping extends \Predis\InlineCommand {
public function canBeHashed() { return false; }
public function getCommandId() { return 'PING'; }
public function parseResponse($data) {
return $data === 'PONG' ? true : false;
}
}
class DoEcho extends \Predis\BulkCommand {
public function canBeHashed() { return false; }
public function getCommandId() { return 'ECHO'; }
}
class Auth extends \Predis\InlineCommand {
public function canBeHashed() { return false; }
public function getCommandId() { return 'AUTH'; }
}
/* connection handling */
class Quit extends \Predis\InlineCommand {
public function canBeHashed() { return false; }
public function getCommandId() { return 'QUIT'; }
public function closesConnection() { return true; }
}
/* commands operating on string values */
class Set extends \Predis\BulkCommand {
public function getCommandId() { return 'SET'; }
}
class SetPreserve extends \Predis\BulkCommand {
public function getCommandId() { return 'SETNX'; }
public function parseResponse($data) { return (bool) $data; }
}
class Get extends \Predis\InlineCommand {
public function getCommandId() { return 'GET'; }
}
class GetMultiple extends \Predis\InlineCommand {
public function canBeHashed() { return false; }
public function getCommandId() { return 'MGET'; }
}
class GetSet extends \Predis\BulkCommand {
public function getCommandId() { return 'GETSET'; }
}
class Increment extends \Predis\InlineCommand {
public function getCommandId() { return 'INCR'; }
}
class IncrementBy extends \Predis\InlineCommand {
public function getCommandId() { return 'INCRBY'; }
}
class Decrement extends \Predis\InlineCommand {
public function getCommandId() { return 'DECR'; }
}
class DecrementBy extends \Predis\InlineCommand {
public function getCommandId() { return 'DECRBY'; }
}
class Exists extends \Predis\InlineCommand {
public function getCommandId() { return 'EXISTS'; }
public function parseResponse($data) { return (bool) $data; }
}
class Delete extends \Predis\InlineCommand {
public function getCommandId() { return 'DEL'; }
}
class Type extends \Predis\InlineCommand {
public function getCommandId() { return 'TYPE'; }
}
/* commands operating on the key space */
class Keys extends \Predis\InlineCommand {
public function canBeHashed() { return false; }
public function getCommandId() { return 'KEYS'; }
public function parseResponse($data) {
return strlen($data) > 0 ? explode(' ', $data) : array();
}
}
class RandomKey extends \Predis\InlineCommand {
public function canBeHashed() { return false; }
public function getCommandId() { return 'RANDOMKEY'; }
public function parseResponse($data) { return $data !== '' ? $data : null; }
}
class Rename extends \Predis\InlineCommand {
public function canBeHashed() { return false; }
public function getCommandId() { return 'RENAME'; }
}
class RenamePreserve extends \Predis\InlineCommand {
public function canBeHashed() { return false; }
public function getCommandId() { return 'RENAMENX'; }
public function parseResponse($data) { return (bool) $data; }
}
class Expire extends \Predis\InlineCommand {
public function getCommandId() { return 'EXPIRE'; }
public function parseResponse($data) { return (bool) $data; }
}
class ExpireAt extends \Predis\InlineCommand {
public function getCommandId() { return 'EXPIREAT'; }
public function parseResponse($data) { return (bool) $data; }
}
class DatabaseSize extends \Predis\InlineCommand {
public function canBeHashed() { return false; }
public function getCommandId() { return 'DBSIZE'; }
}
class TimeToLive extends \Predis\InlineCommand {
public function getCommandId() { return 'TTL'; }
}
/* commands operating on lists */
class ListPushTail extends \Predis\BulkCommand {
public function getCommandId() { return 'RPUSH'; }
}
class ListPushHead extends \Predis\BulkCommand {
public function getCommandId() { return 'LPUSH'; }
}
class ListLength extends \Predis\InlineCommand {
public function getCommandId() { return 'LLEN'; }
}
class ListRange extends \Predis\InlineCommand {
public function getCommandId() { return 'LRANGE'; }
}
class ListTrim extends \Predis\InlineCommand {
public function getCommandId() { return 'LTRIM'; }
}
class ListIndex extends \Predis\InlineCommand {
public function getCommandId() { return 'LINDEX'; }
}
class ListSet extends \Predis\BulkCommand {
public function getCommandId() { return 'LSET'; }
}
class ListRemove extends \Predis\BulkCommand {
public function getCommandId() { return 'LREM'; }
}
class ListPopFirst extends \Predis\InlineCommand {
public function getCommandId() { return 'LPOP'; }
}
class ListPopLast extends \Predis\InlineCommand {
public function getCommandId() { return 'RPOP'; }
}
/* commands operating on sets */
class SetAdd extends \Predis\BulkCommand {
public function getCommandId() { return 'SADD'; }
public function parseResponse($data) { return (bool) $data; }
}
class SetRemove extends \Predis\BulkCommand {
public function getCommandId() { return 'SREM'; }
public function parseResponse($data) { return (bool) $data; }
}
class SetPop extends \Predis\InlineCommand {
public function getCommandId() { return 'SPOP'; }
}
class SetMove extends \Predis\BulkCommand {
public function canBeHashed() { return false; }
public function getCommandId() { return 'SMOVE'; }
public function parseResponse($data) { return (bool) $data; }
}
class SetCardinality extends \Predis\InlineCommand {
public function getCommandId() { return 'SCARD'; }
}
class SetIsMember extends \Predis\BulkCommand {
public function getCommandId() { return 'SISMEMBER'; }
public function parseResponse($data) { return (bool) $data; }
}
class SetIntersection extends \Predis\InlineCommand {
public function getCommandId() { return 'SINTER'; }
}
class SetIntersectionStore extends \Predis\InlineCommand {
public function getCommandId() { return 'SINTERSTORE'; }
}
class SetUnion extends \Predis\InlineCommand {
public function getCommandId() { return 'SUNION'; }
}
class SetUnionStore extends \Predis\InlineCommand {
public function getCommandId() { return 'SUNIONSTORE'; }
}
class SetDifference extends \Predis\InlineCommand {
public function getCommandId() { return 'SDIFF'; }
}
class SetDifferenceStore extends \Predis\InlineCommand {
public function getCommandId() { return 'SDIFFSTORE'; }
}
class SetMembers extends \Predis\InlineCommand {
public function getCommandId() { return 'SMEMBERS'; }
}
class SetRandomMember extends \Predis\InlineCommand {
public function getCommandId() { return 'SRANDMEMBER'; }
}
/* multiple databases handling commands */
class SelectDatabase extends \Predis\InlineCommand {
public function canBeHashed() { return false; }
public function getCommandId() { return 'SELECT'; }
}
class MoveKey extends \Predis\InlineCommand {
public function canBeHashed() { return false; }
public function getCommandId() { return 'MOVE'; }
public function parseResponse($data) { return (bool) $data; }
}
class FlushDatabase extends \Predis\InlineCommand {
public function canBeHashed() { return false; }
public function getCommandId() { return 'FLUSHDB'; }
}
class FlushAll extends \Predis\InlineCommand {
public function canBeHashed() { return false; }
public function getCommandId() { return 'FLUSHALL'; }
}
/* sorting */
class Sort extends \Predis\InlineCommand {
public function getCommandId() { return 'SORT'; }
public function filterArguments(Array $arguments) {
if (count($arguments) === 1) {
return $arguments;
}
// TODO: add more parameters checks
$query = array($arguments[0]);
$sortParams = $arguments[1];
if (isset($sortParams['by'])) {
$query[] = 'BY';
$query[] = $sortParams['by'];
}
if (isset($sortParams['get'])) {
$getargs = $sortParams['get'];
if (is_array($getargs)) {
foreach ($getargs as $getarg) {
$query[] = 'GET';
$query[] = $getarg;
}
}
else {
$query[] = 'GET';
$query[] = $getargs;
}
}
if (isset($sortParams['limit']) && is_array($sortParams['limit'])) {
$query[] = 'LIMIT';
$query[] = $sortParams['limit'][0];
$query[] = $sortParams['limit'][1];
}
if (isset($sortParams['sort'])) {
$query[] = strtoupper($sortParams['sort']);
}
if (isset($sortParams['alpha']) && $sortParams['alpha'] == true) {
$query[] = 'ALPHA';
}
if (isset($sortParams['store']) && $sortParams['store'] == true) {
$query[] = 'STORE';
$query[] = $sortParams['store'];
}
return $query;
}
}
/* persistence control commands */
class Save extends \Predis\InlineCommand {
public function canBeHashed() { return false; }
public function getCommandId() { return 'SAVE'; }
}
class BackgroundSave extends \Predis\InlineCommand {
public function canBeHashed() { return false; }
public function getCommandId() { return 'BGSAVE'; }
public function parseResponse($data) {
if ($data == 'Background saving started') {
return true;
}
return $data;
}
}
class LastSave extends \Predis\InlineCommand {
public function canBeHashed() { return false; }
public function getCommandId() { return 'LASTSAVE'; }
}
class Shutdown extends \Predis\InlineCommand {
public function canBeHashed() { return false; }
public function getCommandId() { return 'SHUTDOWN'; }
public function closesConnection() { return true; }
}
/* remote server control commands */
class Info extends \Predis\InlineCommand {
public function canBeHashed() { return false; }
public function getCommandId() { return 'INFO'; }
public function parseResponse($data) {
$info = array();
$infoLines = explode("\r\n", $data, -1);
foreach ($infoLines as $row) {
list($k, $v) = explode(':', $row);
if (!preg_match('/^db\d+$/', $k)) {
$info[$k] = $v;
}
else {
$db = array();
foreach (explode(',', $v) as $dbvar) {
list($dbvk, $dbvv) = explode('=', $dbvar);
$db[trim($dbvk)] = $dbvv;
}
$info[$k] = $db;
}
}
return $info;
}
}
class SlaveOf extends \Predis\InlineCommand {
public function canBeHashed() { return false; }
public function getCommandId() { return 'SLAVEOF'; }
public function filterArguments(Array $arguments) {
if (count($arguments) === 0 || $arguments[0] === 'NO ONE') {
return array('NO', 'ONE');
}
return $arguments;
}
}
?>
+475
View File
@@ -0,0 +1,475 @@
<?php
define('I_AM_AWARE_OF_THE_DESTRUCTIVE_POWER_OF_THIS_TEST_SUITE', false);
require_once 'PHPUnit/Framework.php';
require_once 'PredisShared.php';
require_once '../lib/Predis_Compatibility.php';
class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
public $redis;
protected function setUp() {
$this->redis = RC::getConnection();
$this->redis->flushDatabase();
}
protected function tearDown() {
}
protected function onNotSuccessfulTest(Exception $exception) {
// drops and reconnect to a redis server on uncaught exceptions
RC::resetConnection();
parent::onNotSuccessfulTest($exception);
}
/* ConnectionParameters */
function testConnectionParametersDefaultValues() {
$params = new \Predis\ConnectionParameters();
$this->assertEquals(\Predis\ConnectionParameters::DEFAULT_HOST, $params->host);
$this->assertEquals(\Predis\ConnectionParameters::DEFAULT_PORT, $params->port);
$this->assertEquals(\Predis\ConnectionParameters::DEFAULT_TIMEOUT, $params->connection_timeout);
$this->assertNull($params->read_write_timeout);
$this->assertNull($params->database);
$this->assertNull($params->password);
$this->assertNull($params->alias);
}
function testConnectionParametersSetupValuesArray() {
$paramsArray = RC::getConnectionParametersArgumentsArray();
$params = new \Predis\ConnectionParameters($paramsArray);
$this->assertEquals($paramsArray['host'], $params->host);
$this->assertEquals($paramsArray['port'], $params->port);
$this->assertEquals($paramsArray['connection_timeout'], $params->connection_timeout);
$this->assertEquals($paramsArray['read_write_timeout'], $params->read_write_timeout);
$this->assertEquals($paramsArray['database'], $params->database);
$this->assertEquals($paramsArray['password'], $params->password);
$this->assertEquals($paramsArray['alias'], $params->alias);
}
function testConnectionParametersSetupValuesString() {
$paramsArray = RC::getConnectionParametersArgumentsArray();
$paramsString = RC::getConnectionParametersArgumentsString($paramsArray);
$params = new \Predis\ConnectionParameters($paramsArray);
$this->assertEquals($paramsArray['host'], $params->host);
$this->assertEquals($paramsArray['port'], $params->port);
$this->assertEquals($paramsArray['connection_timeout'], $params->connection_timeout);
$this->assertEquals($paramsArray['read_write_timeout'], $params->read_write_timeout);
$this->assertEquals($paramsArray['database'], $params->database);
$this->assertEquals($paramsArray['password'], $params->password);
$this->assertEquals($paramsArray['alias'], $params->alias);
}
/* Command and derivates */
function testCommand_TestArguments() {
$cmdArgs = array('key1', 'key2', 'key3');
$cmd = new \Predis\Commands\GetMultiple();
$cmd->setArgumentsArray($cmdArgs);
$this->assertEquals($cmdArgs[0], $cmd->getArgument(0));
$this->assertEquals($cmdArgs[1], $cmd->getArgument(1));
$this->assertEquals($cmdArgs[2], $cmd->getArgument(2));
$cmd = new \Predis\Commands\GetMultiple();
$cmd->setArguments('key1', 'key2', 'key3');
$this->assertEquals($cmdArgs[0], $cmd->getArgument(0));
$this->assertEquals($cmdArgs[1], $cmd->getArgument(1));
$this->assertEquals($cmdArgs[2], $cmd->getArgument(2));
$cmd = new \Predis\Commands\Ping();
$this->assertNull($cmd->getArgument(0));
}
function testCommand_InlineWithNoArguments() {
$cmd = new \Predis\Compatibility\v1_0\Commands\Ping();
$this->assertType('\Predis\InlineCommand', $cmd);
$this->assertEquals('PING', $cmd->getCommandId());
$this->assertFalse($cmd->closesConnection());
$this->assertFalse($cmd->canBeHashed());
$this->assertNull($cmd->getHash(new \Predis\Distribution\HashRing()));
$this->assertEquals("PING\r\n", $cmd());
}
function testCommand_InlineWithArguments() {
$cmd = new \Predis\Compatibility\v1_0\Commands\Get();
$cmd->setArgumentsArray(array('key'));
$this->assertType('\Predis\InlineCommand', $cmd);
$this->assertEquals('GET', $cmd->getCommandId());
$this->assertFalse($cmd->closesConnection());
$this->assertTrue($cmd->canBeHashed());
$this->assertNotNull($cmd->getHash(new \Predis\Distribution\HashRing()));
$this->assertEquals("GET key\r\n", $cmd());
}
function testCommand_BulkWithArguments() {
$cmd = new \Predis\Compatibility\v1_0\Commands\Set();
$cmd->setArgumentsArray(array('key', 'value'));
$this->assertType('\Predis\BulkCommand', $cmd);
$this->assertEquals('SET', $cmd->getCommandId());
$this->assertFalse($cmd->closesConnection());
$this->assertTrue($cmd->canBeHashed());
$this->assertNotNull($cmd->getHash(new \Predis\Distribution\HashRing()));
$this->assertEquals("SET key 5\r\nvalue\r\n", $cmd());
}
function testCommand_MultiBulkWithArguments() {
$cmd = new \Predis\Commands\SetMultiple();
$cmd->setArgumentsArray(array('key1', 'value1', 'key2', 'value2'));
$this->assertType('\Predis\MultiBulkCommand', $cmd);
$this->assertEquals('MSET', $cmd->getCommandId());
$this->assertFalse($cmd->closesConnection());
$this->assertFalse($cmd->canBeHashed());
$this->assertNotNull($cmd->getHash(new \Predis\Distribution\HashRing()));
$this->assertEquals("*5\r\n$4\r\nMSET\r\n$4\r\nkey1\r\n$6\r\nvalue1\r\n$4\r\nkey2\r\n$6\r\nvalue2\r\n", $cmd());
}
function testCommand_ParseResponse() {
// default parser
$cmd = new \Predis\Commands\Get();
$this->assertEquals('test', $cmd->parseResponse('test'));
// overridden parser (boolean)
$cmd = new \Predis\Commands\Exists();
$this->assertTrue($cmd->parseResponse('1'));
$this->assertFalse($cmd->parseResponse('0'));
// overridden parser (boolean)
$cmd = new \Predis\Commands\Ping();
$this->assertTrue($cmd->parseResponse('PONG'));
// overridden parser (complex)
// TODO: emulate a respons to INFO
}
/* RedisServerProfile and derivates */
function testRedisServerProfile_GetSpecificVersions() {
$this->assertType('\Predis\RedisServer_v1_0', \Predis\RedisServerProfile::get('1.0'));
$this->assertType('\Predis\RedisServer_v1_2', \Predis\RedisServerProfile::get('1.2'));
$this->assertType('\Predis\RedisServer_v2_0', \Predis\RedisServerProfile::get('2.0'));
$this->assertType('\Predis\RedisServer_vNext', \Predis\RedisServerProfile::get('dev'));
$this->assertType('\Predis\RedisServerProfile', \Predis\RedisServerProfile::get('default'));
$this->assertEquals(\Predis\RedisServerProfile::get('default'), \Predis\RedisServerProfile::getDefault());
}
function testRedisServerProfile_SupportedCommands() {
$profile_10 = \Predis\RedisServerProfile::get('1.0');
$profile_12 = \Predis\RedisServerProfile::get('1.2');
$this->assertTrue($profile_10->supportsCommand('info'));
$this->assertTrue($profile_12->supportsCommand('info'));
$this->assertFalse($profile_10->supportsCommand('mset'));
$this->assertTrue($profile_12->supportsCommand('mset'));
$this->assertFalse($profile_10->supportsCommand('multi'));
$this->assertFalse($profile_12->supportsCommand('multi'));
}
function testRedisServerProfile_CommandsCreation() {
$profile = \Predis\RedisServerProfile::get('1.0');
$cmdNoArgs = $profile->createCommand('info');
$this->assertType('\Predis\Compatibility\v1_0\Commands\Info', $cmdNoArgs);
$this->assertNull($cmdNoArgs->getArgument());
$args = array('key1', 'key2');
$cmdWithArgs = $profile->createCommand('mget', $args);
$this->assertType('\Predis\Compatibility\v1_0\Commands\GetMultiple', $cmdWithArgs);
$this->assertEquals($args[0], $cmdWithArgs->getArgument()); // TODO: why?
$this->assertEquals($args[0], $cmdWithArgs->getArgument(0));
$this->assertEquals($args[1], $cmdWithArgs->getArgument(1));
$bogusCommand = 'not_existing_command';
$expectedMessage = "'$bogusCommand' is not a registered Redis command";
RC::testForClientException($this, $expectedMessage, function()
use($profile, $bogusCommand) {
$profile->createCommand($bogusCommand);
});
}
function testRedisServerProfile_CommandsRegistration() {
$profile = \Predis\RedisServerProfile::get('1.0');
$cmdId = 'mset';
$cmdClass = '\Predis\Commands\SetMultiple';
$this->assertFalse($profile->supportsCommand($cmdId));
$profile->registerCommand(new $cmdClass(), $cmdId);
$this->assertTrue($profile->supportsCommand($cmdId));
$this->assertType($cmdClass, $profile->createCommand($cmdId));
}
/* ResponseQueued */
function testResponseQueued() {
$response = new \Predis\ResponseQueued();
$this->assertTrue($response->queued);
$this->assertEquals(\Predis\Protocol::QUEUED, (string)$response);
}
/* ResponseError */
function testResponseError() {
$errorMessage = 'ERROR MESSAGE';
$response = new \Predis\ResponseError($errorMessage);
$this->assertTrue($response->error);
$this->assertEquals($errorMessage, $response->message);
$this->assertEquals($errorMessage, (string)$response);
}
/* Connection */
function testConnection_StringCastReturnsIPAndPort() {
$connection = new \Predis\Connection(RC::getConnectionParameters());
$this->assertEquals(RC::SERVER_HOST . ':' . RC::SERVER_PORT, (string) $connection);
}
function testConnection_ConnectDisconnect() {
$connection = new \Predis\Connection(RC::getConnectionParameters());
$this->assertFalse($connection->isConnected());
$connection->connect();
$this->assertTrue($connection->isConnected());
$connection->disconnect();
$this->assertFalse($connection->isConnected());
}
function testConnection_WriteAndReadCommand() {
$cmd = \Predis\RedisServerProfile::getDefault()->createCommand('ping');
$connection = new \Predis\Connection(RC::getConnectionParameters());
$connection->connect();
$connection->writeCommand($cmd);
$this->assertTrue($connection->readResponse($cmd));
}
function testConnection_WriteCommandAndCloseConnection() {
$cmd = \Predis\RedisServerProfile::getDefault()->createCommand('quit');
$connection = new \Predis\Connection(RC::getConnectionParameters());
$connection->connect();
$this->assertTrue($connection->isConnected());
$connection->writeCommand($cmd);
$exceptionMessage = 'Error while reading line from the server';
RC::testForCommunicationException($this, $exceptionMessage, function() use($connection, $cmd) {
$connection->readResponse($cmd);
});
//$this->assertFalse($connection->isConnected());
}
function testConnection_GetSocketOpensConnection() {
$connection = new \Predis\Connection(RC::getConnectionParameters());
$this->assertFalse($connection->isConnected());
$this->assertType('resource', $connection->getSocket());
$this->assertTrue($connection->isConnected());
}
function testConnection_LazyConnect() {
$cmd = \Predis\RedisServerProfile::getDefault()->createCommand('ping');
$connection = new \Predis\Connection(RC::getConnectionParameters());
$this->assertFalse($connection->isConnected());
$connection->writeCommand($cmd);
$this->assertTrue($connection->isConnected());
$this->assertTrue($connection->readResponse($cmd));
}
function testConnection_RawCommand() {
$connection = new \Predis\Connection(RC::getConnectionParameters());
$this->assertEquals('PONG', $connection->rawCommand("PING\r\n"));
}
function testConnection_Alias() {
$connection1 = new \Predis\Connection(RC::getConnectionParameters());
$this->assertNull($connection1->getParameters()->alias);
$args = array_merge(RC::getConnectionArguments(), array('alias' => 'servername'));
$connection2 = new \Predis\Connection(new \Predis\ConnectionParameters($args));
$this->assertEquals('servername', $connection2->getParameters()->alias);
}
function testConnection_ConnectionTimeout() {
$timeout = 3;
$args = array('host' => '1.0.0.1', 'connection_timeout' => $timeout);
$connection = new \Predis\Connection(new \Predis\ConnectionParameters($args));
$start = time();
RC::testForCommunicationException($this, null, function() use($connection) {
$connection->connect();
});
$this->assertEquals((float)(time() - $start), $timeout, '', 1);
}
function testConnection_ReadTimeout() {
$timeout = 1;
$args = array_merge(RC::getConnectionArguments(), array('read_write_timeout' => $timeout));
$cmdFake = \Predis\RedisServerProfile::getDefault()->createCommand('ping');
$connection = new \Predis\Connection(new \Predis\ConnectionParameters($args));
$expectedMessage = 'Error while reading line from the server';
$start = time();
RC::testForCommunicationException($this, $expectedMessage, function() use($connection, $cmdFake) {
$connection->readResponse($cmdFake);
});
$this->assertEquals((float)(time() - $start), $timeout, '', 1);
}
/* ResponseReader */
function testResponseReader_OptionIterableMultiBulkReplies() {
$connection = new \Predis\Connection(RC::getConnectionParameters());
$responseReader = $connection->getResponseReader();
$responseReader->setHandler(
\Predis\Protocol::PREFIX_MULTI_BULK,
new \Predis\ResponseMultiBulkHandler()
);
$this->assertType('array', $connection->rawCommand("KEYS *\r\n"));
$responseReader->setHandler(
\Predis\Protocol::PREFIX_MULTI_BULK,
new \Predis\ResponseMultiBulkStreamHandler()
);
$this->assertType('\Iterator', $connection->rawCommand("KEYS *\r\n"));
}
function testResponseReader_OptionExceptionOnError() {
$connection = new \Predis\Connection(RC::getConnectionParameters());
$responseReader = $connection->getResponseReader();
$connection->rawCommand("SET key 5\r\nvalue\r\n");
$rawCmdUnexpected = "LPUSH key 5\r\nvalue\r\n";
$responseReader->setHandler(
\Predis\Protocol::PREFIX_ERROR,
new \Predis\ResponseErrorSilentHandler()
);
$errorReply = $connection->rawCommand($rawCmdUnexpected);
$this->assertType('\Predis\ResponseError', $errorReply);
$this->assertEquals(RC::EXCEPTION_WRONG_TYPE, $errorReply->message);
$responseReader->setHandler(
\Predis\Protocol::PREFIX_ERROR,
new \Predis\ResponseErrorHandler()
);
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function()
use ($connection, $rawCmdUnexpected) {
$connection->rawCommand($rawCmdUnexpected);
});
}
/* Client + CommandPipeline */
function testCommandPipeline_Simple() {
$client = RC::getConnection();
$client->flushdb();
$pipe = $client->pipeline();
$this->assertType('\Predis\CommandPipeline', $pipe);
$this->assertType('\Predis\CommandPipeline', $pipe->set('foo', 'bar'));
$this->assertType('\Predis\CommandPipeline', $pipe->set('hoge', 'piyo'));
$this->assertType('\Predis\CommandPipeline', $pipe->mset(array(
'foofoo' => 'barbar', 'hogehoge' => 'piyopiyo'
)));
$this->assertType('\Predis\CommandPipeline', $pipe->mget(array(
'foo', 'hoge', 'foofoo', 'hogehoge'
)));
$replies = $pipe->execute();
$this->assertType('array', $replies);
$this->assertEquals(4, count($replies));
$this->assertEquals(4, count($replies[3]));
$this->assertEquals('barbar', $replies[3][2]);
}
function testCommandPipeline_FluentInterface() {
$client = RC::getConnection();
$client->flushdb();
$replies = $client->pipeline()->ping()->set('foo', 'bar')->get('foo')->execute();
$this->assertType('array', $replies);
$this->assertEquals('bar', $replies[2]);
}
function testCommandPipeline_CallableAnonymousBlock() {
$client = RC::getConnection();
$client->flushdb();
$replies = $client->pipeline(function($pipe) {
$pipe->ping();
$pipe->set('foo', 'bar');
$pipe->get('foo');
});
$this->assertType('array', $replies);
$this->assertEquals('bar', $replies[2]);
}
function testCommandPipeline_ClientExceptionInCallableBlock() {
$client = RC::getConnection();
$client->flushdb();
RC::testForClientException($this, 'TEST', function() use($client) {
$client->pipeline(function($pipe) {
$pipe->ping();
$pipe->set('foo', 'bar');
throw new \Predis\ClientException("TEST");
});
});
$this->assertFalse($client->exists('foo'));
}
function testCommandPipeline_ServerExceptionInCallableBlock() {
$client = RC::getConnection();
$client->flushdb();
$client->getResponseReader()->setHandler('-', new \Predis\ResponseErrorSilentHandler());
$replies = $client->pipeline(function($pipe) {
$pipe->set('foo', 'bar');
$pipe->lpush('foo', 'piyo'); // LIST operation on STRING type returns an ERROR
$pipe->set('hoge', 'piyo');
});
$this->assertType('array', $replies);
$this->assertType('\Predis\ResponseError', $replies[1]);
$this->assertTrue($client->exists('foo'));
$this->assertTrue($client->exists('hoge'));
}
function testCommandPipeline_Flush() {
$client = RC::getConnection();
$client->flushdb();
$pipe = $client->pipeline();
$pipe->set('foo', 'bar')->set('hoge', 'piyo');
$pipe->flushPipeline();
$pipe->ping()->mget(array('foo', 'hoge'));
$replies = $pipe->execute();
$this->assertType('array', $replies);
$this->assertEquals(4, count($replies));
$this->assertEquals('bar', $replies[3][0]);
$this->assertEquals('piyo', $replies[3][1]);
}
}
?>
+84 -9
View File
@@ -21,13 +21,26 @@ class RC {
const EXCEPTION_NO_SUCH_KEY = 'no such key';
const EXCEPTION_OUT_OF_RANGE = 'index out of range';
const EXCEPTION_INVALID_DB_IDX = 'invalid DB index';
const EXCEPTION_VALUE_NOT_INT = 'value is not an integer';
const EXCEPTION_EXEC_NO_MULTI = 'EXEC without MULTI';
const EXCEPTION_SETEX_TTL = 'invalid expire time in SETEX';
const EXCEPTION_HASH_VALNOTINT = 'hash value is not an integer';
private static $_connection;
public static function getConnectionArguments() {
return array('host' => RC::SERVER_HOST, 'port' => RC::SERVER_PORT);
}
public static function getConnectionParameters() {
return new Predis\ConnectionParameters(array('host' => RC::SERVER_HOST, 'port' => RC::SERVER_PORT));
}
private static function createConnection() {
$connection = new Predis\Client(RC::SERVER_HOST, RC::SERVER_PORT);
$serverProfile = Predis\RedisServerProfile::get('dev');
$connection = new Predis\Client(RC::getConnectionArguments(), $serverProfile);
$connection->connect();
$connection->selectDatabase(RC::DEFAULT_DATABASE);
$connection->select(RC::DEFAULT_DATABASE);
return $connection;
}
@@ -45,6 +58,22 @@ class RC {
}
}
public static function helperForBlockingPops($op) {
// TODO: I admit that this helper is kinda lame and it does not run
// in a separate process to properly test BLPOP/BRPOP
$redisUri = sprintf('redis://%s:%d/?database=%d', RC::SERVER_HOST, RC::SERVER_PORT, RC::DEFAULT_DATABASE);
$handle = popen('php', 'w');
fwrite($handle, "<?php
require '../lib/Predis.php';
\$redis = Predis\Client::create('$redisUri');
\$redis->rpush('{$op}1', 'a');
\$redis->rpush('{$op}2', 'b');
\$redis->rpush('{$op}3', 'c');
\$redis->rpush('{$op}1', 'd');
?>");
pclose($handle);
}
public static function getArrayOfNumbers() {
return array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
}
@@ -87,25 +116,55 @@ class RC {
$thrownException = $exception;
}
$testcaseInstance->assertType('Predis\ServerException', $thrownException);
$testcaseInstance->assertEquals($expectedMessage, $thrownException->getMessage());
if (isset($expectedMessage)) {
$testcaseInstance->assertEquals($expectedMessage, $thrownException->getMessage());
}
}
public static function testForClientException($testcaseInstance, $expectedMessage, $wrapFunction) {
$thrownException = null;
try {
$wrapFunction($testcaseInstance);
}
catch (Predis\ClientException $exception) {
$thrownException = $exception;
}
$testcaseInstance->assertType('Predis\ClientException', $thrownException);
if (isset($expectedMessage)) {
$testcaseInstance->assertEquals($expectedMessage, $thrownException->getMessage());
}
}
public static function testForCommunicationException($testcaseInstance, $expectedMessage, $wrapFunction) {
$thrownException = null;
try {
$wrapFunction($testcaseInstance);
}
catch (Predis\CommunicationException $exception) {
$thrownException = $exception;
}
$testcaseInstance->assertType('Predis\CommunicationException', $thrownException);
if (isset($expectedMessage)) {
$testcaseInstance->assertEquals($expectedMessage, $thrownException->getMessage());
}
}
public static function pushTailAndReturn(Predis\Client $client, $keyName, Array $values, $wipeOut = 0) {
if ($wipeOut == true) {
$client->delete($keyName);
$client->del($keyName);
}
foreach ($values as $value) {
$client->pushTail($keyName, $value);
$client->rpush($keyName, $value);
}
return $values;
}
public static function setAddAndReturn(Predis\Client $client, $keyName, Array $values, $wipeOut = 0) {
if ($wipeOut == true) {
$client->delete($keyName);
$client->del($keyName);
}
foreach ($values as $value) {
$client->setAdd($keyName, $value);
$client->sadd($keyName, $value);
}
return $values;
}
@@ -113,12 +172,28 @@ class RC {
public static function zsetAddAndReturn(Predis\Client $client, $keyName, Array $values, $wipeOut = 0) {
// $values: array(SCORE => VALUE, ...);
if ($wipeOut == true) {
$client->delete($keyName);
$client->del($keyName);
}
foreach ($values as $value => $score) {
$client->zsetAdd($keyName, $score, $value);
$client->zadd($keyName, $score, $value);
}
return $values;
}
public static function getConnectionParametersArgumentsArray() {
return array(
'host' => '10.0.0.1', 'port' => 6380, 'connection_timeout' => 10, 'read_write_timeout' => 30,
'database' => 5, 'password' => 'dbpassword', 'alias' => 'connection_alias'
);
}
public static function getConnectionParametersArgumentsString($arguments = null) {
// TODO: must be improved
$args = $arguments ?: RC::getConnectionParametersArgumentsArray();
$paramsString = "redis://{$args['host']}:{$args['port']}/";
$paramsString .= "?connection_timeout={$args['connection_timeout']}&read_write_timeout={$args['read_write_timeout']}";
$paramsString .= "&database={$args['database']}&password={$args['password']}&alias={$args['alias']}";
return $paramsString;
}
}
?>
+841 -307
View File
File diff suppressed because it is too large Load Diff