Compare commits

..

136 Commits

Author SHA1 Message Date
Daniele Alessandri 9ead747663 Update CHANGELOG and bump VERSION. 2016-05-30 17:25:52 +02:00
Daniele Alessandri 39cf6abf82 [tests] Do not allow failures for HHVM on Travis CI. 2016-05-30 17:00:46 +02:00
Daniele Alessandri dbae384a64 [tests] Troubles with HHVM <= 3.6.6 and float timeouts.
HHVM is still being used by Travis CI but this bug makes the build to
take 14 minutes to complete, which is unacceptable.
2016-05-30 17:00:14 +02:00
Daniele Alessandri d9ea0ce14f Update README of test directory.
[ci skip]
2016-05-27 22:01:45 +02:00
Daniele Alessandri 55f940e400 Update README.
[ci skip]
2016-05-27 21:32:47 +02:00
Daniele Alessandri 648be824d3 Fix fetching slots map from unreachable nodes.
When various nodes in the configuration are unreachable while trying
to send a command, we should attempt to contact a reachable node to
fetch an updated slots map up to $retryLimit times or until there are
no more servers in the pool before giving up.

It is possible that the slots map fetched from Redis contains stale
data and points to a dead server, this happens when the nodes still
have to agree that a master server is down before promoting a slave
to the role of master. In this case no further attempts to execute
the command are performed and an exception is thrown.

This still needs some more testing and will delay v1.0.4 a few days
past its scheduled release.
2016-05-27 14:28:12 +02:00
Daniele Alessandri c4e0f2f037 Run php-cs-fixer. 2016-05-26 09:52:18 +02:00
Daniele Alessandri 62f5ce6baf Update CHANGELOG. 2016-05-25 10:57:01 +02:00
Daniele Alessandri 9cd4ed9e1e Update SPOP's @method signature in phpdoc.
SPOP accepts the optional "count" argument since Redis 3.2.
2016-05-24 23:28:40 +02:00
Daniele Alessandri 8491b1d880 Add new command: GEORADIUSBYMEMBER (Redis 3.2.0). 2016-05-24 23:28:23 +02:00
Daniele Alessandri 8c8261432f Add new command: GEORADIUS (Redis 3.2.0). 2016-05-24 23:28:11 +02:00
Daniele Alessandri 5eccd6ee3c Add new command: GEODIST (Redis 3.2.0). 2016-05-24 23:28:01 +02:00
Daniele Alessandri 3d9588ec1a Add new command: GEOPOS (Redis 3.2.0). 2016-05-24 23:27:50 +02:00
Daniele Alessandri e96f7f748a Add new command: GEOHASH (Redis 3.2.0). 2016-05-24 23:27:33 +02:00
Daniele Alessandri dd0edf761a Add new command: GEOADD (Redis 3.2.0). 2016-05-24 23:27:10 +02:00
Daniele Alessandri 8cbbd073cb Add new command: BITFIELD (Redis 3.2.0). 2016-05-24 23:26:48 +02:00
Daniele Alessandri 1e521b56cd [tests] Test count argument for SPOP in Redis 3.2. 2016-05-24 23:25:46 +02:00
Daniele Alessandri fcacd65576 Add new server profile for Redis 3.2 (new stable). 2016-05-24 23:25:31 +02:00
Daniele Alessandri d5488f81f7 Check that STORE key in SORT ends up in same slot. 2016-05-24 22:09:13 +02:00
Daniele Alessandri 188dc6bf62 Improve detection of STORE in SORT command arguments. 2016-05-24 21:39:26 +02:00
Daniele Alessandri 0bd57ab744 [tests] Add missing test for key prefix in HSTRLEN. 2016-05-24 15:28:39 +02:00
Daniele Alessandri b996b005cf Fix cluster strategy to handle variadic EXISTS (Redis >= 3.0.3). 2016-05-24 15:26:35 +02:00
Daniele Alessandri 82116b0366 Fix prefix processor to handle variadic EXISTS (Redis >= 3.0.3).
Backported from master.

Conflicts:
	src/Command/Processor/KeyPrefixProcessor.php
2016-05-24 15:26:01 +02:00
Daniele Alessandri 5c1ddc9cfa Add missing @method tag for HSTRLEN in phpdocs.
[ci skip]
2016-05-24 12:26:50 +02:00
Daniele Alessandri ea2fd9700d [tests] Missing @requiresRedisVersion for HSTRLEN. 2016-05-24 11:50:15 +02:00
Daniele Alessandri b2ec264ff9 Update description in package.ini. 2016-05-24 10:27:37 +02:00
Daniele Alessandri bf7a70d6f0 Update phpunit.xml.* 2016-05-22 20:21:52 +02:00
Daniele Alessandri 4ecc44e1ee Update description in composer.json. 2016-05-22 20:05:31 +02:00
Daniele Alessandri 52d5b23db7 Fix README.
[ci skip]
2016-05-22 15:32:08 +02:00
Daniele Alessandri d31a4c71ba Update CHANGELOG.
[ci skip]
2016-05-22 15:24:39 +02:00
Daniele Alessandri c92e305852 Update README.
Blame copy&paste practices for the noise (or just blame me).

[ci skip]
2016-05-22 15:21:09 +02:00
Daniele Alessandri b075564278 Update and improve README.
[ci skip]
2016-05-22 15:12:14 +02:00
Daniele Alessandri f9e817f14c Run php-cs-fixer. 2016-05-21 15:49:25 +02:00
Daniele Alessandri 9e568396c6 Remove old references about HHVM being unstable. 2016-05-20 20:35:58 +02:00
Daniele Alessandri 2a91ebaba9 [tests] Rename old branch for exclusion.
[ci skip]
2016-05-20 20:15:12 +02:00
Daniele Alessandri ce15bd22b9 Update badges in CHANGELOG.
[ci skip]
2016-05-20 18:33:28 +02:00
Daniele Alessandri b0439e503e Update CHANGELOG. 2016-05-20 16:28:19 +02:00
Daniele Alessandri ffc1c25baa Try again on connection failure to node in cluster.
When the connection to a node in the cluster fails in the attempt to
execute a command, Predis now removes the failed connection from the
cluster pool and contacts a random node to ask for a fresh slots map
and tries to execute the command once again.

When the cluster is configured to have each master replicated to one
or more slaves, one the slaves is automatically promoted to the role
of master by redis-cluster with this change being reflected in the
output of CLUSTER SLOTS, so the next execution should run just fine.

Our current approach is relatively naive as CLUSTER SLOTS is executed
against a random master node, meaning that the client must open a new
connection and execute one more roundtrip only to fetch the new slots
map. For now it is enough, it is still better than having the client
fail when you actually have somes slaves in your redis-cluster setup,
but one improvement could consist in caching the list of slaves for
each master returned in the response of CLUSTER SLOTS so that when a
connection fails the client can try to guess which connection should
use for the next attempt.

This commit closes #173, closes #215, and closes #314.
2016-05-20 13:18:25 +02:00
Daniele Alessandri ac165194f5 Evict connection from slots cache when removed. 2016-05-20 11:43:15 +02:00
Daniele Alessandri 18ae294864 [tests] Fix assertion.
PHPUnit_Util_Type::export() has been removed a while ago...
2016-05-19 11:46:56 +02:00
Daniele Alessandri 47de667aea Bump min. version of PHPUnit (require-dev). 2016-05-19 11:46:52 +02:00
Daniele Alessandri 588940c5cb Update CHANGELOG. 2016-05-18 21:27:37 +02:00
Daniele Alessandri a1fe4013e1 Improve handling of slots mapping via parameters.
When using redis-cluster it is now also possible to pass one slot or
non-contiguous ranges of slots via connection parameters in order to
improve the ability to pre-configure the slots map on the client.

Here is an example:

  $parameters = [
    'tcp://10.0.0.1:6379?slots=0-5460,5500-5600,11000',
    'tcp://10.0.0.2:6379?slots=5461-5499,5600-10921',
    'tcp://10.0.0.3:6379?slots=10922-10999,11001-16383',
  ];

This commit fixes #312 (props to @kenotr0n for the original PR).
2016-05-18 21:16:42 +02:00
Daniele Alessandri 3328ad76be [tests] Fix wrong method in mock. 2016-05-16 15:38:42 +02:00
Daniele Alessandri 17b717a8f5 Fix CHANGELOG. 2016-05-15 21:42:00 +02:00
Daniele Alessandri 95dbc2bb34 Bump year in LICENSE. 2016-05-15 21:40:46 +02:00
Daniele Alessandri 9bb5a1c71f Apply minor styling fix. 2016-05-15 21:40:14 +02:00
Daniele Alessandri 8eb4804a5c Move member variable initialization. 2016-05-15 21:39:51 +02:00
Daniele Alessandri 5d99914939 Prevent warnings picking slave from empty pool. 2016-05-15 21:39:34 +02:00
Ante Lucic c45bb15767 add docblocks to MasterSlaveReplication 2016-05-13 17:00:27 +02:00
Ante Braovic e0329d6c74 added zrevrangebylex in the list of available methods 2016-05-13 16:43:50 +02:00
Daniele Alessandri 2175d87a96 [tests] Fix test executed on current Redis unstable. 2016-05-10 10:59:40 +02:00
Daniele Alessandri ce85fdadd1 [tests] Fix test executed on current Redis unstable. 2016-05-10 10:59:24 +02:00
Daniele Alessandri b15c0a02de [tests] Fix wrong @group annotation 2016-05-09 17:50:22 +02:00
Daniele Alessandri d2fbcc6b8c Prevent failures serializing commands with "holes" in arguments array.
This could be triggered when passing an array with "holes" to variadic commands.
Connection classes based on the protocol serialized exposed by phpiredis were
not affected by this bug.

Fixes #316.
2016-05-08 18:35:06 +02:00
Daniele Alessandri 6596460a57 Merge branch 'issue-tests' into v1.0 2016-05-08 16:50:28 +02:00
Daniele Alessandri 9ab0e31a75 Merge branch 'v1.0-fix-phpDoc-in-ClientInterface' into v1.0 2016-05-08 16:45:49 +02:00
John Maguire 11adccdaeb Update useClusterNodes() docs to indicate default 2016-05-08 15:21:01 +02:00
Daniele Alessandri f465792b27 Update CHANGELOG. 2016-05-08 15:15:48 +02:00
Daniele Alessandri 1399d3863c Fix bug in HSCAN-based iterator when hash have integer fields.
When iterating a hash containing integer fields our iterator abstraction
based on HSCAN was always returning "0" as a field name after the first
$field => $value pair due to a wrong assumption on how the PHP function
array_shift() (which is used internally to advance to the next pair in
our buffered response to HSCAN) works.

The ZSCAN-based iterator had this very same bug which was already fixed
in 24e19a9 so I am not sure how this one went unnoticed until now.
2016-05-08 15:10:09 +02:00
Daniele Alessandri 1f1c9cf1a4 Run php-cs-fixer. 2016-05-08 14:54:29 +02:00
Daniele Alessandri dae2df0ae9 Merge remote-tracking branch 'marvin255/fix_namespace_typo' into v1.0 2016-05-08 14:49:06 +02:00
postbox433@gmail.com 9338eaf573 Fix namespace typo in StreamConnection.php 2016-04-12 15:20:26 +05:00
Remi Collet f378faaf22 fix tests, list of allowed commands have changed (redis 3.0.6) 2015-12-28 10:34:24 +01:00
Alexander Cheprasov 8b150fcbf5 Update ClientInterface.php 2015-10-27 16:37:58 +00:00
Daniele Alessandri 84060b9034 Update CHANGELOG and bump VERSION.
Hotfix release targeting a severe regression on HHVM, see commit d4a7bd5.
2015-07-30 20:34:15 +02:00
Daniele Alessandri d4a7bd52be Fix severe regression on HHVM.
Apparently HHVM is more strict than PHP in stream_socket_client() and does not
like at all IPv4 addresses and hostnames eclosed in square brackets. Note that
it is not that weird as square brackets are mandatory only when IPv6 addresses
are embedded in URI strings, so it is more like a weird incompatiblity of HHVM
with the behaviour of the standard PHP interpreter. The connect() attempt fails
but not due to the server being unavailable or some connectivity issue.

The important lesson is: never rely on undocumented behaviours especially when
targeting different runtimes, and do not forget to run the test suite on every
platform right before release like I unfortunately did.

This commit fixes #269.
2015-07-30 20:23:45 +02:00
Daniele Alessandri 16a9d4e041 Back to development.
[ci skip]
2015-07-30 19:41:27 +02:00
Daniele Alessandri 0b92e8d156 Update CHANGELOG and bump VERSION. 2015-07-30 11:20:39 +02:00
Daniele Alessandri 1f7b534072 Preserve remainder of path in URI after database (redis scheme). 2015-07-30 11:13:42 +02:00
Daniele Alessandri 0c0cbbafff Use PHP_VERSION_ID constant. 2015-07-30 10:56:54 +02:00
Daniele Alessandri 8aec51b34f Implement full support for IPv6.
Using IPv6 with Predis was basically impossible due to various inconsistencies
and bugs through the library, now it is supported by all the connection classes.

Following the standard for IPv6 literal addresses in URI strings, the IP literal
must be enclosed within square brackets when passing the parameters as a string:

  $parameters = 'tcp://[2001:db8:0:f101::1]:6379';

See https://tools.ietf.org/html/rfc3986#section-3.2.2 for further details.

This commit also fixes #239 making redis-cluster usable with nodes using IPv6.
2015-07-29 23:09:52 +02:00
Daniele Alessandri eeb1e8b7a7 Reduce unneeded code duplication in URI parsing. 2015-07-29 17:04:34 +02:00
Daniele Alessandri c3a44b8e2e Strip brackets from host when parsing embedded IPv6 address.
I don't know why PHP's parse_url() does not do that, it does not make
sense when the IP is by itself so maybe it is a bug?
2015-07-29 17:01:19 +02:00
Daniele Alessandri 255beac137 Use static:: for invoking static methods in key prefix processor.
This trivial change makes it possible to use overridden static methods
when extending Predis\Command\Processor\KeyPrefixProcessor. PHP always
invokes the static methods of a parent class when using self:: even if
the extended classes override them.
2015-07-29 14:16:52 +02:00
Daniele Alessandri d473328a22 Update CHANGELOG. 2015-07-29 11:54:08 +02:00
Daniele Alessandri 0d25e7b0bb Add new command: HSTRLEN (Redis 3.2.0).
Also bump the unstable profile version to 3.2.
2015-07-29 11:52:55 +02:00
Daniele Alessandri be3b84ca14 Rephrase latest entries in CHANGELOG by using intelligible English.
[ci skip]
2015-07-26 22:27:57 +02:00
Daniele Alessandri 7d0597c62c Rephrase some parts of the README.
[ci skip]
2015-07-26 22:27:49 +02:00
Daniele Alessandri 833e46b79d [tests] Fix typo. 2015-07-25 21:59:08 +02:00
Daniele Alessandri a22858438d [tests] Require pcntl extension to run blocking PubSub\Consumer test. 2015-07-25 21:58:01 +02:00
Daniele Alessandri f221d0c81e Run php-cs-fixer. 2015-07-25 21:27:05 +02:00
Daniele Alessandri 0b5bfdfe33 [tests] Improve code-reuse in tests for the Predis\Connection namespace. 2015-07-25 21:27:02 +02:00
Daniele Alessandri 3700d48771 [tests] Share common test among connection classes. 2015-07-25 20:54:01 +02:00
Daniele Alessandri 653d3f08ab [tests] Use @requires annotation. 2015-07-25 20:52:01 +02:00
Daniele Alessandri 2d2de7837b [tests] Fix some tests methods names. 2015-07-25 10:07:58 +02:00
Daniele Alessandri fc18e6456a [tests] Apply small changes to commands tests with expirations. 2015-07-25 10:07:55 +02:00
Daniele Alessandri 6f2064ed90 [tests] Cover SET modifiers EX, PX, NX|XX (Redis >= 2.6.12). 2015-07-25 09:11:16 +02:00
Daniele Alessandri e2e645a8bd Update .gitattributes file.
[ci skip]
2015-07-24 23:31:04 +02:00
Daniele Alessandri 2219964b7e Restore alignment for a few equals symbols. 2015-07-24 23:21:23 +02:00
Daniele Alessandri 381e44b6e6 Run php-cs-fixer with new configuration. 2015-07-24 23:21:07 +02:00
Daniele Alessandri 808693bfbd Add .php_cs configuration file for php-cs-fixer. 2015-07-24 23:19:23 +02:00
Daniele Alessandri 33eab38314 Remove unneeded "use" imports. 2015-07-24 21:25:48 +02:00
Daniele Alessandri 82e404660e Run php-cs-fixer against codebase in src/ and tests/. 2015-07-24 17:58:56 +02:00
Daniele Alessandri 6d60a42400 [tests] Fix me being stupid here. 2015-07-24 17:35:53 +02:00
Daniele Alessandri 95624de5c4 [tests] Apply some fixes and improvements and remove old stuff. 2015-07-24 17:27:41 +02:00
Daniele Alessandri 2ee135099c Remove useless if condition. 2015-07-24 12:40:33 +02:00
Daniele Alessandri e26e3b423a Reverting stupid oversight after a merge from master branch.
The culprit is commit 3500371.
2015-07-24 10:49:14 +02:00
Daniele Alessandri 946fac4454 No need to check the scheme here.
Bug introduced in v1.0-dev after changes to support redis scheme.

Fixes #268
2015-07-24 10:45:12 +02:00
Daniele Alessandri 4e976a3eb6 Update CHANGELOG.
[ci skip]
2015-07-23 21:05:05 +02:00
Daniele Alessandri baaf26fe5b Add support for the 'redis://' scheme in URI strings.
The URI string will be handled following the rules as described by the
the provisional IANA registration document that can be found on IANA's
website: http://www.iana.org/assignments/uri-schemes/prov/redis.
2015-07-23 19:21:16 +02:00
Daniele Alessandri 6a0348fbea Add missing command: MIGRATE (Redis 2.6.0).
Fixes #209.
2015-07-23 19:21:03 +02:00
Daniele Alessandri 8365a6be77 [tests] Fix minor oversight. 2015-07-23 19:20:52 +02:00
Daniele Alessandri f028e428be Switch to container-based builds on Travis CI.
We do not need "sudo" anyway.
See http://docs.travis-ci.com/user/migrating-from-legacy/ for details.
2015-07-23 12:16:27 +02:00
Daniele Alessandri c13b82557d Update CHANGELOG. 2015-07-23 11:43:47 +02:00
Daniele Alessandri 30d01c40d4 [tests] Improve assert failure messages for replication stategy tests. 2015-07-23 11:40:52 +02:00
Daniele Alessandri 6459546e25 Fix missing BITPOS in replication strategy. 2015-07-23 11:40:39 +02:00
Daniele Alessandri dede828008 Add missing BITPOS command in key prefix processor.
See #265.
2015-07-23 11:40:27 +02:00
Daniele Alessandri 5c0716575e Exclude .php-version file.
[ci skip]
2015-07-19 13:05:40 +02:00
Richard Heelin 90bffb1a5a Emit socket error if ipredis connection has been lost/reset.
The current code is checking for a failure (return false) or an empty buffer string, however
neither of these will be the case if the connection has been reset or has errored. According
to the docs for socket_recv, $buffer will be set to null if the connection is reset or their
is no data. As currently null is not allowed for, we enter an infinite loop, to prevent this
I've added null to the things we check before we emit a socket error. This prevents the
infinite loop and correctly results in an Exception if the connection is lost/reset.

Conflicts:
	src/Connection/PhpiredisSocketConnection.php
2015-07-07 18:51:44 +02:00
Daniele Alessandri 64ee96c312 [tests] Fix base test case class to handle required Redis versions.
This change is needed due to some internal changes in one of the
latest minor releases of PHPUnit 4.x that essentially broke how we
were checking for the required Redis version from method annotations.
2015-07-07 18:05:55 +02:00
Daniele Alessandri bff5a9729e Update CHANGELOG. 2015-07-07 16:19:46 +02:00
Daniele Alessandri 5cd7b774c4 [tests] Adapt to internal encoding changes for lists in Redis 3.0. 2015-07-07 16:11:49 +02:00
Daniele Alessandri 354d1ef921 Support ZADD modifiers when using simplified command signature.
The NX|XX, CH and INCR modifiers for ZADD are available in Redis since
version 3.0.2. See http://redis.io/commands/ZADD for additional info.
2015-07-07 16:11:43 +02:00
Daniele Alessandri 9e3a8da94d Update CHANGELOG. 2015-07-07 15:01:00 +02:00
Daniele Alessandri 35003713a2 Merge remote-tracking branch 'github/pr/235' into v1.0
Conflicts:
	.travis.yml
	CHANGELOG.md
	VERSION
	package.ini
	src/Client.php
2015-07-07 14:52:09 +02:00
Daniele Alessandri cd991e6370 [tests] Remove hhvm-nightly from Travis CI configuration.
See https://github.com/travis-ci/travis-ci/issues/3788 for details.
2015-07-07 14:44:28 +02:00
Daniele Alessandri c59853afb8 [tests] It's 7.0 and not 5.7! 2015-07-07 14:44:08 +02:00
Daniele Alessandri d4982b6c43 [tests] Add PHP 5.7 to Travis CI configuration. 2015-07-07 13:22:59 +02:00
Daniele Alessandri 96f4af816d Minor tweak in .editorconfig file.
[ci skip]
2015-07-06 18:42:10 +02:00
Daniele Alessandri 22ff3ff992 Commit .editorconfig file.
See http://editorconfig.org for more info about EditorConfig

[ci skip]
2015-07-06 18:38:30 +02:00
Daniele Alessandri 77b75e0738 Fix wrong phpdoc.
Thanks @Aliance for spotting this oversight.
2015-07-03 12:11:45 +02:00
Daniele Alessandri eeea28b275 Update CHANGELOG. 2015-07-03 12:10:44 +02:00
Daniele Alessandri aa067d8fd9 [tests] Implement test for #257 to guard against regressions. 2015-07-03 12:03:15 +02:00
Dominic Scheirlinck ce17c5383a Don't check for __invoke on non-objects
`method_exists` will cause autoloading for strings. Fixes #257
2015-07-03 11:11:53 +02:00
Daniele Alessandri c4c36cae7a Back to development. 2015-01-02 13:54:29 +01:00
Daniele Alessandri 7a170b3d81 Update CHANGELOG and bump VERSION. 2015-01-02 13:51:34 +01:00
Daniele Alessandri 17e7bce22e Bump year in LICENSE.
[ci skip]
2015-01-02 13:45:19 +01:00
Daniele Alessandri 7a5d6bac3e Update CHANGELOG.
[ci skip]
2015-01-02 13:42:50 +01:00
Daniele Alessandri 9d6c031ead Merge remote-tracking branch 'srhnsn/v1.0' into v1.0 2015-01-02 13:33:10 +01:00
Daniele Alessandri 692718afb4 Merge remote-tracking branch 'blocktrail/hhvm-pubsub-blockingread-test-v1.0' into v1.0 2015-01-02 13:00:25 +01:00
Daniele Alessandri 0776377412 Temporarily allow failures for HHVM on Travis-CI.
[ci skip]
2015-01-02 12:56:48 +01:00
Daniele Alessandri e4b0512d42 No need to access a private field used by PHPUnit.
Fixes #207.
2015-01-02 12:20:00 +01:00
Daniele Alessandri 75ca2f8111 Add minimum required Redis version for BITPOS integration tests. 2015-01-02 12:14:05 +01:00
Daniele Alessandri 37b1c88115 Apply minor CS fixes and trim spurious spaces. 2015-01-02 12:13:58 +01:00
Daniele Alessandri a4e6130568 Merge remote-tracking branch 'nicchap/v1.0' into v1.0 2015-01-02 11:58:30 +01:00
123 changed files with 913 additions and 5320 deletions
+2 -5
View File
@@ -1,13 +1,10 @@
* text=auto
/tests/PHPUnit export-ignore
/tests/Predis export-ignore
/tests/bootstrap.php export-ignore
/.github export-ignore
/tests export-ignore
/.editorconfig export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/.php_cs.dist export-ignore
/.php_cs export-ignore
/.travis.yml export-ignore
/phpunit.xml.dist export-ignore
/phpunit.xml.travisci export-ignore
-2
View File
@@ -1,2 +0,0 @@
github: tillkruss
custom: "https://www.paypal.me/tillkruss"
-31
View File
@@ -1,31 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Run command '...'
2. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Versions (please complete the following information):**
- Predis: [e.g. 1.1.2]
- PHP [e.g. 8.0.0]
- Redis Server [e.g. 6.0.0]
- OS [e.g. Ubuntu 20.10]
**Code sample**
If applicable, a small snippet of code that reproduces the issue.
**Additional context**
Add any other context about the problem here.
-20
View File
@@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: feature
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
-1
View File
@@ -2,7 +2,6 @@
*.phar
.php-version
.php_cs.cache
.phpunit.result.cache
phpunit.xml
package.xml
composer.lock
+34
View File
@@ -0,0 +1,34 @@
<?php
$PREDIS_HEADER = <<<EOS
This file is part of the Predis package.
(c) Daniele Alessandri <suppakilla@gmail.com>
For the full copyright and license information, please view the LICENSE
file that was distributed with this source code.
EOS;
Symfony\CS\Fixer\Contrib\HeaderCommentFixer::setHeader($PREDIS_HEADER);
return Symfony\CS\Config\Config::create()
->setUsingCache(true)
->level(Symfony\CS\FixerInterface::SYMFONY_LEVEL)
->fixers(array(
// Symfony
'-unalign_equals',
'-unalign_double_arrow',
// Contribs
'header_comment',
'ordered_use',
'phpdoc_order',
'long_array_syntax',
))
->finder(
Symfony\CS\Finder\DefaultFinder::create()
->in(__DIR__.'/bin')
->in(__DIR__.'/src')
->in(__DIR__.'/tests')
->in(__DIR__.'/examples')
);
-33
View File
@@ -1,33 +0,0 @@
<?php
$PREDIS_HEADER = <<<EOS
This file is part of the Predis package.
(c) Daniele Alessandri <suppakilla@gmail.com>
For the full copyright and license information, please view the LICENSE
file that was distributed with this source code.
EOS;
return PhpCsFixer\Config::create()
->setUsingCache(true)
->setRules(array(
'@Symfony' => true,
'header_comment' => array(
'header' => $PREDIS_HEADER,
),
'ordered_imports' => true,
'phpdoc_order' => true,
'binary_operator_spaces' => array(
'align_double_arrow' => false,
'align_equals' => false,
),
'array_syntax' => array('syntax' => 'long'),
))
->setFinder(
PhpCsFixer\Finder::create()
->in(__DIR__.'/bin')
->in(__DIR__.'/src')
->in(__DIR__.'/tests')
->in(__DIR__.'/examples')
);
+9 -21
View File
@@ -1,35 +1,23 @@
language: php
sudo: false
php:
- 5.3
- 5.4
- 5.5
- 5.6
- 7.0
- hhvm
branches:
except:
- v0.5
- v0.6
- v0.6-PHP_5.2
- documentation
before_install:
- docker run -d --rm -p 127.0.0.1:6379:6379 redis:3
services: redis-server
before_script:
- composer self-update
- composer install --no-interaction --prefer-source --dev
script:
- travis_retry vendor/bin/phpunit -c phpunit.xml.travisci
- vendor/bin/phpunit -c phpunit.xml.travisci
matrix:
fast_finish: true
include:
- php: 5.3
dist: precise
services: redis-server
before_install: skip
- php: 5.4
dist: trusty
- php: 5.5
dist: trusty
- php: 5.6
- php: 7.0
- php: 7.1
- php: 7.2
- php: 7.3
- php: 7.4
- php: nightly # PHP 8.0.0-dev
allow_failures:
- php: nightly
-149
View File
@@ -1,152 +1,3 @@
v1.1.4 (2020-08-31)
================================================================================
- Improved @method annotations for methods responding to Redis commands defined
by `Predis\ClientInterface` and `Predis\ClientContextInterface`. (PR #456 and
PR #497, other fixes applied after further analysys).
- __FIX__: the client can now handle ACL authentication when connecting to Redis
6.x simply by passing both `username` and `password` to connection parameters.
See [the Redis docs](https://redis.io/topics/acl) for details on this topic.
- __FIX__: NULL or zero-length string values passed to `password` and `database`
in the connection parameters list do not trigger spurious `AUTH` and `SELECT`
commands anymore when connecting to Redis (ISSUE #436).
- __FIX__: initializing an iteration over a client instance when it is connected
to a standalone Redis server will not throw an exception anymore, instead it
will return an iterator that will run for just one loop returning a new client
instance using the underlying single-node connection (ISSUE #552, PR #556).
- __FIX__: `Predis\Cluster\Distributor\HashRingaddNodeToRing()` was calculating
the hash required for distribution by using `crc32()` directly instead of the
method `Predis\Cluster\Hash\HashGeneratorInterface::hash()` implemented by the
class itself. This bug fix does not have any impact on existing clusters that
use client-side sharding based on this distributor simply because it does not
take any external hash generators so distribution is not going to be affected.
- __FIX__: `SORT` now always trigger a switch to the master node in replication
configurations instead of just when the `STORE` modifier is specified, this is
because `SORT` is always considered to be a write operation and actually fails
with a `-READONLY` error response when executed against a replica node. (ISSUE
#554).
v1.1.3 (2020-08-18)
================================================================================
- Ensure compatibility with PHP 8.
- Moved repository from `github.com/nrk/predis` to `github.com/predis/predis`.
- __FIX__: Moved `cweagans/composer-patches` dependency to `require-dev`.
- __FIX__: Include PHPUnit `.patch` files in exports.
v1.1.2 (2020-08-11)
================================================================================
- __FIX__: pure CRC16 implementation failed to calculate the correct hash when
the input value passed to the `hash()` method is an integer (PR #450).
- __FIX__: make PHP iterator abstractions for `ZSCAN` and `HSCAN` working with
PHP 7.2 due to a breaking change, namely the removal of `each()` (PR #448).
v1.1.1 (2016-06-16)
================================================================================
- __FIX__: `password` and `database` from the global `parameters` client option
were still being applied to sentinels connections making them fail (sentinels
do not understand the `AUTH` and `SELECT` commands) (PR #346).
- __FIX__: when a sentinel instance reports no sentinel for a service, invoking
`connect()` on the redis-sentinel connection backend should fall back to the
master connection instead of failing (ISSUE #342).
- __FIX__: the two connection backends based on ext-phpiredis has some kind of
issues with the GC and the internal use of closures as reader callbacks that
prevented connections going out of scope from being properly collected and the
underlying stream or socket resources from being closed and freed. This should
not have had any actual effect in real-world scenarios due to the lifecycle of
PHP scripts, but we fixed it anyway (ISSUE #345).
v1.1.0 (2016-06-02)
================================================================================
- The default server profile for the client now targets Redis 3.2.
- Responses to the following commands are not casted into booleans anymore, the
original integer value is returned: `SETNX`, `MSETNX`, `SMOVE`, `SISMEMBER`,
`HSET`, `HSETNX`, `HEXISTS`, `PFADD`, `EXISTS`, `MOVE`, `PERSIST`, `EXPIRE`,
`EXPIREAT`, `RENAMENX`. This change does not have a significant impact unless
when using strict comparisons (=== and !==) the returned value.
- Non-boolean string values passed to the `persistent` connection parameter can
be used to create different persistent connections. Note that this feature was
already present in Predis but required both `persistent` and `path` to be set
as illustrated by [#139](https://github.com/nrk/predis/pull/139). This change
is needed to prevent confusion with how `path` is used to select a database
when using the `redis` scheme.
- The client throws exceptions when Redis returns any kind of error response to
initialization commands (the ones being automatically sent when a connection
is established, such as `SELECT` and `AUTH` when database and password are set
in connection parameters) regardless of the value of the exception option.
- Using `unix:///path/to/socket` in URI strings to specify a UNIX domain socket
file is now deprecated in favor of the format `unix:/path/to/socket` (note the
lack of the double slash after the scheme) and will not be supported starting
with the next major release.
- Implemented full support for redis-sentinel.
- Implemented the ability to specify default connection parameters for aggregate
connections with the new `parameters` client option. These parameters augment
the usual user-supplied connection parameters (but do not take the precedence
over them) when creating new connections and they are mostly useful when the
client is using aggregate connections such as redis-cluster and redis-sentinel
as these backends can create new connections on the fly based on responses and
redirections from Redis.
- Redis servers protected by SSL-encrypted connections can be accessed by using
the `tls` or `rediss` scheme in connection parameters along with SSL-specific
options in the `ssl` parameter (see http://php.net/manual/context.ssl.php).
- `Predis\Client` implements `IteratorAggregate` making it possible to iterate
over traversable aggregate connections and get a new client instance for each
Redis node.
- Iterating over an instance of `Predis\Connection\Aggregate\RedisCluster` will
return all the connections mapped in the slots map instead of just the ones in
the pool. This change makes it possible, when the slots map is retrieved from
Redis, to iterate over all of the master nodes in the cluster. When the use of
`CLUSTER SLOTS` is disabled via the `useClusterSlots()` method, the iteration
returns only the connections with slots ranges associated in their parameters
or the ones initialized by `-MOVED` responses in order to make the behaviour
of the iteration consistent between the two modes of operation.
- Various improvements to `Predis\Connection\Aggregate\MasterSlaveReplication`
(the "basic" replication backend, not the new one based on redis-sentinel):
- When the client is not able to send a read-only command to a slave because
the current connection fails or the slave is resyncing (`-LOADING` response
returned by Redis), the backend discards the failed connection and performs
a new attempt on the next slave. When no other slave is available the master
server is used for read-only commands as last resort.
- It is possible to discover the current replication configuration on the fly
by invoking the `discover()` method which internally relies on the output of
the command `INFO REPLICATION` executed against the master server or one of
the slaves. The backend can also be configured to do this automatically when
it fails to reach one of the servers.
- Implemented the `switchToMaster()` and `switchToSlave()` methods to make it
easier to force a switch to the master server or a random slave when needed.
v1.0.4 (2016-05-30)
================================================================================
+1 -1
View File
@@ -1,6 +1,6 @@
## Filing bug reports ##
Bugs or feature requests can be posted on the [GitHub issues](http://github.com/predis/predis/issues)
Bugs or feature requests can be posted on the [GitHub issues](http://github.com/nrk/predis/issues)
section of the project.
When reporting bugs, in addition to the obvious description of your issue you __must__ always provide
+1 -9
View File
@@ -18,14 +18,6 @@ least to some degree).
Yes. Obviously persistent connections actually work only when using PHP configured as a persistent
process reused by the web server (see [PHP-FPM](http://php-fpm.org)).
### Does Predis support SSL-encrypted connections? ###
Yes. Encrypted connections are mostly useful when connecting to Redis instances exposed by various
cloud hosting providers without the need to configure an SSL proxy, but you should also take into
account the general performances degradation especially during the connect() operation when the TLS
handshake must be performed to secure the connection. Persistent SSL-encrypted connections may help
in that respect, but they are supported only when running on PHP >= 7.0.0.
### Does Predis support transparent (de)serialization of values? ###
No and it will not ever do that by default. The reason behind this decision is that serialization is
@@ -33,7 +25,7 @@ usually something that developers prefer to customize depending on their needs a
generalized when using Redis because of the many possible access patterns for your data. This does
not mean that it is impossible to have such a feature since you can leverage the extensibility of
this library to define your own serialization-aware commands. You can find more details about how to
do that [on this issue](http://github.com/predis/predis/issues/29#issuecomment-1202624).
do that [on this issue](http://github.com/nrk/predis/issues/29#issuecomment-1202624).
### How can I force Predis to connect to Redis before sending any command? ###
+21 -74
View File
@@ -1,16 +1,18 @@
# Predis #
[![Software license][ico-license]](LICENSE)
[![Latest stable][ico-version-stable]][link-packagist]
[![Latest development][ico-version-dev]][link-packagist]
[![Software license][ico-license]](LICENSE)
[![Monthly installs][ico-downloads-monthly]][link-downloads]
[![Build status][ico-travis]][link-travis]
[![HHVM support][ico-hhvm]][link-hhvm]
Flexible and feature-complete [Redis](http://redis.io) client for PHP >= 5.3 and HHVM >= 2.3.0.
Predis does not require any additional C extension by default, but it can be optionally paired with
[phpiredis](https://github.com/nrk/phpiredis) to lower the overhead of the serialization and parsing
of the [Redis RESP Protocol](http://redis.io/topics/protocol).
of the [Redis RESP Protocol](http://redis.io/topics/protocol). For an __experimental__ asynchronous
implementation of the client you can refer to [Predis\Async](https://github.com/nrk/predis-async).
More details about this project can be found on the [frequently asked questions](FAQ.md).
@@ -20,17 +22,17 @@ More details about this project can be found on the [frequently asked questions]
- Support for different versions of Redis (from __2.0__ to __3.2__) using profiles.
- Support for clustering using client-side sharding and pluggable keyspace distributors.
- Support for [redis-cluster](http://redis.io/topics/cluster-tutorial) (Redis >= 3.0).
- Support for master-slave replication setups and [redis-sentinel](http://redis.io/topics/sentinel).
- Support for standalone master-slave replication setups.
- Transparent key prefixing of keys using a customizable prefix strategy.
- Command pipelining on both single nodes and clusters (client-side sharding only).
- Abstraction for Redis transactions (Redis >= 2.0) and CAS operations (Redis >= 2.2).
- Abstraction for Lua scripting (Redis >= 2.6) and automatic switching between `EVALSHA` or `EVAL`.
- Abstraction for `SCAN`, `SSCAN`, `ZSCAN` and `HSCAN` (Redis >= 2.8) based on PHP iterators.
- Connections are established lazily by the client upon the first command and can be persisted.
- Connections can be established via TCP/IP (also TLS/SSL-encrypted) or UNIX domain sockets.
- Connections can be established via TCP/IP or UNIX domain sockets.
- Support for [Webdis](http://webd.is) (requires both `ext-curl` and `ext-phpiredis`).
- Support for custom connection classes for providing different network or protocol backends.
- Flexible system for defining custom commands and profiles and override the default ones.
- Flexible system for defining custom commands and server profiles.
## How to _install_ and use Predis ##
@@ -38,7 +40,7 @@ More details about this project can be found on the [frequently asked questions]
This library can be found on [Packagist](http://packagist.org/packages/predis/predis) for an easier
management of projects dependencies using [Composer](http://packagist.org/about-composer) or on our
[own PEAR channel](http://pear.nrk.io) for a more traditional installation using PEAR. Ultimately,
compressed archives of each release are [available on GitHub](https://github.com/predis/predis/releases).
compressed archives of each release are [available on GitHub](https://github.com/nrk/predis/tags).
### Loading the library ###
@@ -87,37 +89,17 @@ $client = new Predis\Client([
$client = new Predis\Client('tcp://10.0.0.1:6379');
```
Password protected servers can be accessed by adding `password` to the parameters set. When ACLs are
enabled on Redis >= 6.0, both `username` and `password` are required for user authentication.
It is also possible to connect to local instances of Redis using UNIX domain sockets, in this case
the parameters must use the `unix` scheme and specify a path for the socket file:
```php
$client = new Predis\Client(['scheme' => 'unix', 'path' => '/path/to/redis.sock']);
$client = new Predis\Client('unix:/path/to/redis.sock');
```
The client can leverage TLS/SSL encryption to connect to secured remote Redis instances without the
need to configure an SSL proxy like stunnel. This can be useful when connecting to nodes running on
various cloud hosting providers. Encryption can be enabled with using the `tls` scheme and an array
of suitable [options](http://php.net/manual/context.ssl.php) passed via the `ssl` parameter:
```php
// Named array of connection parameters:
$client = new Predis\Client([
'scheme' => 'tls',
'ssl' => ['cafile' => 'private.pem', 'verify_peer' => true],
]);
// Same set of parameters, but using an URI string:
$client = new Predis\Client('tls://127.0.0.1?ssl[cafile]=private.pem&ssl[verify_peer]=1');
$client = new Predis\Client('unix:///path/to/redis.sock');
```
The connection schemes [`redis`](http://www.iana.org/assignments/uri-schemes/prov/redis) (alias of
`tcp`) and [`rediss`](http://www.iana.org/assignments/uri-schemes/prov/rediss) (alias of `tls`) are
also supported, with the difference that URI strings containing these schemes are parsed following
the rules described on their respective IANA provisional registration documents.
`tcp`) is also supported, with the difference that URI strings containing these schemes are parsed
following the rules described on the IANA provisional registration.
The actual list of supported connection parameters can vary depending on each connection backend so
it is recommended to refer to their specific documentation or implementation for details.
@@ -135,12 +117,6 @@ $client = new Predis\Client([
See the [aggregate connections](#aggregate-connections) section of this document for more details.
Connections to Redis are lazy meaning that the client connects to a server only if and when needed.
While it is recommended to let the client do its own stuff under the hood, there may be times when
it is still desired to have control of when the connection is opened or closed: this can easily be
achieved by invoking `$client->connect()` and `$client->disconnect()`. Please note that the effect
of these methods on aggregate connections may differ depending on each specific implementation.
### Client configuration ###
@@ -159,9 +135,8 @@ when needed. The client options supported by default in Predis are:
- `exceptions`: whether the client should throw or return responses upon Redis errors.
- `connections`: list of connection backends or a connection factory instance.
- `cluster`: specifies a cluster backend (`predis`, `redis` or callable object).
- `replication`: specifies a replication backend (`TRUE`, `sentinel` or callable object).
- `replication`: specifies a replication backend (`TRUE` or callable object).
- `aggregate`: overrides `cluster` and `replication` to provide a custom connections aggregator.
- `parameters`: list of default connection parameters for aggregate connections.
Users can also provide custom options with values or callable objects (for lazy initialization) that
are stored in the options container for later use through the library.
@@ -223,35 +198,6 @@ $options = ['replication' => true];
$client = new Predis\Client($parameters, $options);
```
The above configuration has a static list of servers and relies entirely on the client's logic, but
it is possible to rely on [`redis-sentinel`](http://redis.io/topics/sentinel) for a more robust HA
environment with sentinel servers acting as a source of authority for clients for service discovery.
The minimum configuration required by the client to work with redis-sentinel is a list of connection
parameters pointing to a bunch of sentinel instances, the `replication` option set to `sentinel` and
the `service` option set to the name of the service:
```php
$sentinels = ['tcp://10.0.0.1', 'tcp://10.0.0.2', 'tcp://10.0.0.3'];
$options = ['replication' => 'sentinel', 'service' => 'mymaster'];
$client = new Predis\Client($sentinels, $options);
```
If the master and slave nodes are configured to require an authentication from clients, a password
must be provided via the global `parameters` client option. This option can also be used to specify
a different database index. The client options array would then look like this:
```php
$options = [
'replication' => 'sentinel',
'service' => 'mymaster',
'parameters' => [
'password' => $secretpassword,
'database' => 10,
],
];
```
While Predis is able to distinguish commands performing write and read-only operations, `EVAL` and
`EVALSHA` represent a corner case in which the client switches to the master node because it cannot
tell when a Lua script is safe to be executed on slaves. While this is indeed the default behavior,
@@ -447,14 +393,14 @@ Predis has a comprehensive test suite covering every aspect of the library. This
integration tests against a running instance of Redis (>= 2.4.0 is required) to verify the correct
behavior of the implementation of each command and automatically skips commands not defined in the
specified Redis profile. If you do not have Redis up and running, integration tests can be disabled.
By default the test suite is configured to execute integration tests using the profile for Redis 3.2
By default the test suite is configured to execute integration tests using the profile for Redis 2.8
(which is the current stable version of Redis) but can optionally target a Redis instance built from
the `unstable` branch by modifying `phpunit.xml` and setting `REDIS_SERVER_VERSION` to `dev` so that
the development server profile will be used. You can refer to [the tests README](tests/README.md)
for more detailed information about testing Predis.
Predis uses Travis CI for continuous integration and the history for past and current builds can be
found [on its project page](http://travis-ci.org/predis/predis).
found [on its project page](http://travis-ci.org/nrk/predis).
## Other ##
@@ -462,9 +408,9 @@ found [on its project page](http://travis-ci.org/predis/predis).
### Project related links ###
- [Source code](https://github.com/predis/predis)
- [Wiki](https://github.com/predis/predis/wiki)
- [Issue tracker](https://github.com/predis/predis/issues)
- [Source code](https://github.com/nrk/predis)
- [Wiki](https://wiki.github.com/nrk/predis)
- [Issue tracker](https://github.com/nrk/predis/issues)
- [PEAR channel](http://pear.nrk.io)
@@ -477,13 +423,14 @@ found [on its project page](http://travis-ci.org/predis/predis).
The code for Predis is distributed under the terms of the MIT license (see [LICENSE](LICENSE)).
[ico-license]: https://img.shields.io/github/license/predis/predis.svg?style=flat-square
[ico-license]: https://img.shields.io/github/license/nrk/predis.svg?style=flat-square
[ico-version-stable]: https://img.shields.io/packagist/v/predis/predis.svg?style=flat-square
[ico-version-dev]: https://img.shields.io/packagist/vpre/predis/predis.svg?style=flat-square
[ico-downloads-monthly]: https://img.shields.io/packagist/dm/predis/predis.svg?style=flat-square
[ico-travis]: https://img.shields.io/travis/predis/predis.svg?style=flat-square
[ico-travis]: https://img.shields.io/travis/nrk/predis.svg?style=flat-square
[ico-hhvm]: https://img.shields.io/hhvm/predis/predis.svg?style=flat-square
[link-packagist]: https://packagist.org/packages/predis/predis
[link-travis]: https://travis-ci.org/predis/predis
[link-travis]: https://travis-ci.org/nrk/predis
[link-downloads]: https://packagist.org/packages/predis/predis/stats
[link-hhvm]: http://hhvm.h4cc.de/package/predis/predis
+1 -1
View File
@@ -1 +1 @@
1.1.4
1.0.4
+2 -2
View File
@@ -115,7 +115,7 @@ function addPackageFile($pkg, $fileinfo, $role, $baseDir = '')
function generatePackageXml($packageINI)
{
$XML = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0"?>
<package packagerversion="1.4.10" version="2.0"
xmlns="http://pear.php.net/dtd/package-2.0"
xmlns:tasks="http://pear.php.net/dtd/tasks-1.0"
@@ -197,7 +197,7 @@ function rewritePackageInstallAs($pkg)
function savePackageXml($xml)
{
$dom = new DOMDocument("1.0", "UTF-8");
$dom = new DOMDocument("1.0");
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadXML($xml->asXML());
+1 -1
View File
@@ -59,7 +59,7 @@ spl_autoload_register(function (\$class) {
}
}
});
__halt_compiler();
__HALT_COMPILER();
EOSTUB;
}
+7 -34
View File
@@ -3,56 +3,29 @@
"type": "library",
"description": "Flexible and feature-complete Redis client for PHP and HHVM",
"keywords": ["nosql", "redis", "predis"],
"homepage": "http://github.com/predis/predis",
"homepage": "http://github.com/nrk/predis",
"license": "MIT",
"support": {
"issues": "https://github.com/predis/predis/issues"
"issues": "https://github.com/nrk/predis/issues"
},
"authors": [
{
"name": "Daniele Alessandri",
"email": "suppakilla@gmail.com",
"homepage": "http://clorophilla.net",
"role": "Creator & Maintainer"
},
{
"name": "Till Krüss",
"homepage": "https://till.im",
"role": "Maintainer"
}
],
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/tillkruss"
"homepage": "http://clorophilla.net"
}
],
"require": {
"php": ">=5.3.9"
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "~4.8",
"cweagans/composer-patches": "^1.6"
"phpunit/phpunit": "~4.8"
},
"suggest": {
"ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol",
"ext-curl": "Allows access to Webdis when paired with phpiredis"
},
"autoload": {
"psr-4": {
"Predis\\": "src/"
}
},
"extra": {
"composer-exit-on-patch-failure": true,
"patches": {
"phpunit/phpunit-mock-objects": {
"Fix PHP 7 and 8 compatibility": "./tests/phpunit_mock_objects.patch"
},
"phpunit/phpunit": {
"Fix PHP 7 compatibility": "./tests/phpunit_php7.patch",
"Fix PHP 8 compatibility": "./tests/phpunit_php8.patch"
}
}
}
"psr-4": {"Predis\\": "src/"}
}
}
+1 -1
View File
@@ -36,7 +36,7 @@ class SimpleDebuggableConnection extends StreamConnection
$firtsArg = $command->getArgument(0);
$timestamp = round(microtime(true) - $this->tstart, 4);
$debug = $command->getId();
$debug = $command->getId();
$debug .= isset($firtsArg) ? " $firtsArg " : ' ';
$debug .= "$direction $this";
$debug .= " [{$timestamp}s]";
-58
View File
@@ -1,58 +0,0 @@
<?php
/*
* This file is part of the Predis package.
*
* (c) Daniele Alessandri <suppakilla@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
require __DIR__.'/shared.php';
// Predis supports redis-sentinel to provide high availability in master / slave
// scenarios. The only but relevant difference with a basic replication scenario
// is that sentinel servers can manage the master server and its slaves based on
// their state, which means that they are able to provide an authoritative and
// updated configuration to clients thus avoiding static configurations for the
// replication servers and their roles.
// Instead of connection parameters pointing to redis nodes, we provide a list
// of instances of redis-sentinel. Users should always provide a timeout value
// low enough to not hinder operations just in case a sentinel is unreachable
// but Predis uses a default value of 100 milliseconds for sentinel parameters
// without an explicit timeout value.
//
// NOTE: in real-world scenarios sentinels should be running on different hosts!
$sentinels = array(
'tcp://127.0.0.1:5380?timeout=0.100',
'tcp://127.0.0.1:5381?timeout=0.100',
'tcp://127.0.0.1:5382?timeout=0.100',
);
$client = new Predis\Client($sentinels, array(
'replication' => 'sentinel',
'service' => 'mymaster',
));
// Read operation.
$exists = $client->exists('foo') ? 'yes' : 'no';
$current = $client->getConnection()->getCurrent()->getParameters();
echo "Does 'foo' exist on {$current->alias}? $exists.", PHP_EOL;
// Write operation.
$client->set('foo', 'bar');
$current = $client->getConnection()->getCurrent()->getParameters();
echo "Now 'foo' has been set to 'bar' on {$current->alias}!", PHP_EOL;
// Read operation.
$bar = $client->get('foo');
$current = $client->getConnection()->getCurrent()->getParameters();
echo "We fetched 'foo' from {$current->alias} and its value is '$bar'.", PHP_EOL;
/* OUTPUT:
Does 'foo' exist on slave-127.0.0.1:6381? yes.
Now 'foo' has been set to 'bar' on master!
We fetched 'foo' from master and its value is 'bar'.
*/
+8 -12
View File
@@ -9,10 +9,6 @@
* file that was distributed with this source code.
*/
if (PHP_SAPI !== 'cli') {
die("Example scripts are meant to be executed locally via CLI.");
}
require __DIR__.'/../autoload.php';
function redis_version($info)
@@ -27,22 +23,22 @@ function redis_version($info)
}
$single_server = array(
'host' => '127.0.0.1',
'port' => 6379,
'host' => '127.0.0.1',
'port' => 6379,
'database' => 15,
);
$multiple_servers = array(
array(
'host' => '127.0.0.1',
'port' => 6379,
'host' => '127.0.0.1',
'port' => 6379,
'database' => 15,
'alias' => 'first',
'alias' => 'first',
),
array(
'host' => '127.0.0.1',
'port' => 6380,
'host' => '127.0.0.1',
'port' => 6380,
'database' => 15,
'alias' => 'second',
'alias' => 'second',
),
);
+1 -1
View File
@@ -28,7 +28,7 @@ function zpop($client, $key)
{
$element = null;
$options = array(
'cas' => true, // Initialize with support for CAS operations
'cas' => true, // Initialize with support for CAS operations
'watch' => $key, // Key that needs to be WATCHed to detect changes
'retry' => 3, // Number of retries on aborted transactions, after
// which the client bails out with an exception.
+2 -2
View File
@@ -10,14 +10,14 @@ name = "Predis"
desc = "Flexible and feature-complete Redis client for PHP and HHVM"
homepage = "http://github.com/nrk/predis"
license = "MIT"
version = "1.1.4"
version = "1.0.4"
stability = "stable"
channel = "pear.nrk.io"
author = "Daniele Alessandri \"nrk\" <suppakilla@gmail.com>"
[require]
php = ">= 5.3.9"
php = ">= 5.3.2"
pearinstaller = "1.4.1"
[roles]
+1 -1
View File
@@ -38,7 +38,7 @@
<php>
<!-- Redis -->
<const name="REDIS_SERVER_VERSION" value="3.2" />
<const name="REDIS_SERVER_VERSION" value="2.8" />
<const name="REDIS_SERVER_HOST" value="127.0.0.1" />
<const name="REDIS_SERVER_PORT" value="6379" />
<const name="REDIS_SERVER_DBNUM" value="15" />
+1 -1
View File
@@ -42,7 +42,7 @@
<php>
<!-- Redis -->
<const name="REDIS_SERVER_VERSION" value="3.2" />
<const name="REDIS_SERVER_VERSION" value="2.8" />
<const name="REDIS_SERVER_HOST" value="127.0.0.1" />
<const name="REDIS_SERVER_PORT" value="6379" />
<const name="REDIS_SERVER_DBNUM" value="15" />
+10 -36
View File
@@ -38,9 +38,9 @@ use Predis\Transaction\MultiExec as MultiExecTransaction;
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class Client implements ClientInterface, \IteratorAggregate
class Client implements ClientInterface
{
const VERSION = '1.1.4';
const VERSION = '1.0.4';
protected $connection;
protected $options;
@@ -120,18 +120,13 @@ class Client implements ClientInterface, \IteratorAggregate
if ($options->defined('aggregate')) {
$initializer = $this->getConnectionInitializerWrapper($options->aggregate);
$connection = $initializer($parameters, $options);
} elseif ($options->defined('replication')) {
$replication = $options->replication;
if ($replication instanceof AggregateConnectionInterface) {
$connection = $replication;
$options->connections->aggregate($connection, $parameters);
} else {
$initializer = $this->getConnectionInitializerWrapper($replication);
$connection = $initializer($parameters, $options);
}
} else {
$connection = $options->cluster;
if ($options->defined('replication') && $replication = $options->replication) {
$connection = $replication;
} else {
$connection = $options->cluster;
}
$options->connections->aggregate($connection, $parameters);
}
@@ -278,7 +273,7 @@ class Client implements ClientInterface, \IteratorAggregate
* applying any prefix to keys or throwing exceptions on Redis errors even
* regardless of client options.
*
* It is possible to identify Redis error responses from normal responses
* It is possibile to indentify Redis error responses from normal responses
* using the second optional argument which is populated by reference.
*
* @param array $arguments Command arguments as defined by the command signature.
@@ -481,7 +476,7 @@ class Client implements ClientInterface, \IteratorAggregate
}
/**
* Creates a new publish/subscribe context and returns it, or starts its loop
* Creates a new publis/subscribe context and returns it, or starts its loop
* inside the optionally provided callable object.
*
* @param mixed ... Array of options, a callable for execution, or both.
@@ -525,25 +520,4 @@ class Client implements ClientInterface, \IteratorAggregate
{
return new MonitorConsumer($this);
}
/**
* {@inheritdoc}
*/
public function getIterator()
{
$clients = array();
$connection = $this->getConnection();
if (!$connection instanceof \Traversable) {
return new \ArrayIterator(array(
(string) $connection => new static($connection, $this->getOptions())
));
}
foreach ($connection as $node) {
$clients[(string) $node] = new static($node, $this->getOptions());
}
return new \ArrayIterator($clients);
}
}
+16 -17
View File
@@ -16,7 +16,7 @@ use Predis\Command\CommandInterface;
/**
* Interface defining a client-side context such as a pipeline or transaction.
*
* @method $this del(array|string $keys)
* @method $this del(array $keys)
* @method $this dump($key)
* @method $this exists($key)
* @method $this expire($key, $seconds)
@@ -38,8 +38,7 @@ use Predis\Command\CommandInterface;
* @method $this append($key, $value)
* @method $this bitcount($key, $start = null, $end = null)
* @method $this bitop($operation, $destkey, $key)
* @method $this bitfield($key, $subcommand, ...$subcommandArg)
* @method $this bitpos($key, $bit, $start = null, $end = null)
* @method $this bitfield($key, ...)
* @method $this decr($key)
* @method $this decrby($key, $decrement)
* @method $this get($key)
@@ -74,15 +73,15 @@ use Predis\Command\CommandInterface;
* @method $this hsetnx($key, $field, $value)
* @method $this hvals($key)
* @method $this hstrlen($key, $field)
* @method $this blpop(array|string $keys, $timeout)
* @method $this brpop(array|string $keys, $timeout)
* @method $this blpop(array $keys, $timeout)
* @method $this brpop(array $keys, $timeout)
* @method $this brpoplpush($source, $destination, $timeout)
* @method $this lindex($key, $index)
* @method $this linsert($key, $whence, $pivot, $value)
* @method $this llen($key)
* @method $this lpop($key)
* @method $this lpush($key, array $values)
* @method $this lpushx($key, array $values)
* @method $this lpushx($key, $value)
* @method $this lrange($key, $start, $stop)
* @method $this lrem($key, $count, $value)
* @method $this lset($key, $index, $value)
@@ -90,13 +89,13 @@ use Predis\Command\CommandInterface;
* @method $this rpop($key)
* @method $this rpoplpush($source, $destination)
* @method $this rpush($key, array $values)
* @method $this rpushx($key, array $values)
* @method $this rpushx($key, $value)
* @method $this sadd($key, array $members)
* @method $this scard($key)
* @method $this sdiff(array|string $keys)
* @method $this sdiffstore($destination, array|string $keys)
* @method $this sinter(array|string $keys)
* @method $this sinterstore($destination, array|string $keys)
* @method $this sdiff(array $keys)
* @method $this sdiffstore($destination, array $keys)
* @method $this sinter(array $keys)
* @method $this sinterstore($destination, array $keys)
* @method $this sismember($key, $member)
* @method $this smembers($key)
* @method $this smove($source, $destination, $member)
@@ -104,13 +103,13 @@ use Predis\Command\CommandInterface;
* @method $this srandmember($key, $count = null)
* @method $this srem($key, $member)
* @method $this sscan($key, $cursor, array $options = null)
* @method $this sunion(array|string $keys)
* @method $this sunionstore($destination, array|string $keys)
* @method $this sunion(array $keys)
* @method $this sunionstore($destination, array $keys)
* @method $this zadd($key, array $membersAndScoresDictionary)
* @method $this zcard($key)
* @method $this zcount($key, $min, $max)
* @method $this zincrby($key, $increment, $member)
* @method $this zinterstore($destination, array|string $keys, array $options = null)
* @method $this zinterstore($destination, array $keys, array $options = null)
* @method $this zrange($key, $start, $stop, array $options = null)
* @method $this zrangebyscore($key, $min, $max, array $options = null)
* @method $this zrank($key, $member)
@@ -120,7 +119,7 @@ use Predis\Command\CommandInterface;
* @method $this zrevrange($key, $start, $stop, array $options = null)
* @method $this zrevrangebyscore($key, $min, $max, array $options = null)
* @method $this zrevrank($key, $member)
* @method $this zunionstore($destination, array|string $keys, array $options = null)
* @method $this zunionstore($destination, array $keys, array $options = null)
* @method $this zscore($key, $member)
* @method $this zscan($key, $cursor, array $options = null)
* @method $this zrangebylex($key, $start, $stop, array $options = null)
@@ -128,8 +127,8 @@ use Predis\Command\CommandInterface;
* @method $this zremrangebylex($key, $min, $max)
* @method $this zlexcount($key, $min, $max)
* @method $this pfadd($key, array $elements)
* @method $this pfmerge($destinationKey, array|string $sourceKeys)
* @method $this pfcount(array|string $keys)
* @method $this pfmerge($destinationKey, array $sourceKeys)
* @method $this pfcount(array $keys)
* @method $this pubsub($subcommand, $argument)
* @method $this publish($channel, $message)
* @method $this discard()
+147 -148
View File
@@ -24,154 +24,153 @@ use Predis\Profile\ProfileInterface;
* and more friendly interface to ease programming which is described in the
* following list of methods:
*
* @method int del(array|string $keys)
* @method string|null dump($key)
* @method int exists($key)
* @method int expire($key, $seconds)
* @method int expireat($key, $timestamp)
* @method array keys($pattern)
* @method int move($key, $db)
* @method mixed object($subcommand, $key)
* @method int persist($key)
* @method int pexpire($key, $milliseconds)
* @method int pexpireat($key, $timestamp)
* @method int pttl($key)
* @method string|null randomkey()
* @method mixed rename($key, $target)
* @method int renamenx($key, $target)
* @method array scan($cursor, array $options = null)
* @method array sort($key, array $options = null)
* @method int ttl($key)
* @method mixed type($key)
* @method int append($key, $value)
* @method int bitcount($key, $start = null, $end = null)
* @method int bitop($operation, $destkey, $key)
* @method array|null bitfield($key, $subcommand, ...$subcommandArg)
* @method int bitpos($key, $bit, $start = null, $end = null)
* @method int decr($key)
* @method int decrby($key, $decrement)
* @method string|null get($key)
* @method int getbit($key, $offset)
* @method string getrange($key, $start, $end)
* @method string|null getset($key, $value)
* @method int incr($key)
* @method int incrby($key, $increment)
* @method string incrbyfloat($key, $increment)
* @method array mget(array $keys)
* @method mixed mset(array $dictionary)
* @method int msetnx(array $dictionary)
* @method mixed psetex($key, $milliseconds, $value)
* @method mixed set($key, $value, $expireResolution = null, $expireTTL = null, $flag = null)
* @method int setbit($key, $offset, $value)
* @method int setex($key, $seconds, $value)
* @method int setnx($key, $value)
* @method int setrange($key, $offset, $value)
* @method int strlen($key)
* @method int hdel($key, array $fields)
* @method int hexists($key, $field)
* @method string|null hget($key, $field)
* @method array hgetall($key)
* @method int hincrby($key, $field, $increment)
* @method string hincrbyfloat($key, $field, $increment)
* @method array hkeys($key)
* @method int hlen($key)
* @method array hmget($key, array $fields)
* @method mixed hmset($key, array $dictionary)
* @method array hscan($key, $cursor, array $options = null)
* @method int hset($key, $field, $value)
* @method int hsetnx($key, $field, $value)
* @method array hvals($key)
* @method int hstrlen($key, $field)
* @method array|null blpop(array|string $keys, $timeout)
* @method array|null brpop(array|string $keys, $timeout)
* @method string|null brpoplpush($source, $destination, $timeout)
* @method string|null lindex($key, $index)
* @method int linsert($key, $whence, $pivot, $value)
* @method int llen($key)
* @method string|null lpop($key)
* @method int lpush($key, array $values)
* @method int lpushx($key, array $values)
* @method array lrange($key, $start, $stop)
* @method int lrem($key, $count, $value)
* @method mixed lset($key, $index, $value)
* @method mixed ltrim($key, $start, $stop)
* @method string|null rpop($key)
* @method string|null rpoplpush($source, $destination)
* @method int rpush($key, array $values)
* @method int rpushx($key, array $values)
* @method int sadd($key, array $members)
* @method int scard($key)
* @method array sdiff(array|string $keys)
* @method int sdiffstore($destination, array|string $keys)
* @method array sinter(array|string $keys)
* @method int sinterstore($destination, array|string $keys)
* @method int sismember($key, $member)
* @method array smembers($key)
* @method int smove($source, $destination, $member)
* @method string|null spop($key, $count = null)
* @method string|null srandmember($key, $count = null)
* @method int srem($key, $member)
* @method array sscan($key, $cursor, array $options = null)
* @method array sunion(array|string $keys)
* @method int sunionstore($destination, array|string $keys)
* @method int zadd($key, array $membersAndScoresDictionary)
* @method int zcard($key)
* @method string zcount($key, $min, $max)
* @method string zincrby($key, $increment, $member)
* @method int zinterstore($destination, array|string $keys, array $options = null)
* @method array zrange($key, $start, $stop, array $options = null)
* @method array zrangebyscore($key, $min, $max, array $options = null)
* @method int|null zrank($key, $member)
* @method int zrem($key, $member)
* @method int zremrangebyrank($key, $start, $stop)
* @method int zremrangebyscore($key, $min, $max)
* @method array zrevrange($key, $start, $stop, array $options = null)
* @method array zrevrangebyscore($key, $max, $min, array $options = null)
* @method int|null zrevrank($key, $member)
* @method int zunionstore($destination, array|string $keys, array $options = null)
* @method string|null zscore($key, $member)
* @method array zscan($key, $cursor, array $options = null)
* @method array zrangebylex($key, $start, $stop, array $options = null)
* @method array zrevrangebylex($key, $start, $stop, array $options = null)
* @method int zremrangebylex($key, $min, $max)
* @method int zlexcount($key, $min, $max)
* @method int pfadd($key, array $elements)
* @method mixed pfmerge($destinationKey, array|string $sourceKeys)
* @method int pfcount(array|string $keys)
* @method mixed pubsub($subcommand, $argument)
* @method int publish($channel, $message)
* @method mixed discard()
* @method array|null exec()
* @method mixed multi()
* @method mixed unwatch()
* @method mixed watch($key)
* @method mixed eval($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
* @method mixed evalsha($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
* @method mixed script($subcommand, $argument = null)
* @method mixed auth($password)
* @method string echo($message)
* @method mixed ping($message = null)
* @method mixed select($database)
* @method mixed bgrewriteaof()
* @method mixed bgsave()
* @method mixed client($subcommand, $argument = null)
* @method mixed config($subcommand, $argument = null)
* @method int dbsize()
* @method mixed flushall()
* @method mixed flushdb()
* @method array info($section = null)
* @method int lastsave()
* @method mixed save()
* @method mixed slaveof($host, $port)
* @method mixed slowlog($subcommand, $argument = null)
* @method array time()
* @method array command()
* @method int geoadd($key, $longitude, $latitude, $member)
* @method array geohash($key, array $members)
* @method array geopos($key, array $members)
* @method string|null geodist($key, $member1, $member2, $unit = null)
* @method array georadius($key, $longitude, $latitude, $radius, $unit, array $options = null)
* @method array georadiusbymember($key, $member, $radius, $unit, array $options = null)
* @method int del(array $keys)
* @method string dump($key)
* @method int exists($key)
* @method int expire($key, $seconds)
* @method int expireat($key, $timestamp)
* @method array keys($pattern)
* @method int move($key, $db)
* @method mixed object($subcommand, $key)
* @method int persist($key)
* @method int pexpire($key, $milliseconds)
* @method int pexpireat($key, $timestamp)
* @method int pttl($key)
* @method string randomkey()
* @method mixed rename($key, $target)
* @method int renamenx($key, $target)
* @method array scan($cursor, array $options = null)
* @method array sort($key, array $options = null)
* @method int ttl($key)
* @method mixed type($key)
* @method int append($key, $value)
* @method int bitcount($key, $start = null, $end = null)
* @method int bitop($operation, $destkey, $key)
* @method array bitfield($key, ...)
* @method int decr($key)
* @method int decrby($key, $decrement)
* @method string get($key)
* @method int getbit($key, $offset)
* @method string getrange($key, $start, $end)
* @method string getset($key, $value)
* @method int incr($key)
* @method int incrby($key, $increment)
* @method string incrbyfloat($key, $increment)
* @method array mget(array $keys)
* @method mixed mset(array $dictionary)
* @method int msetnx(array $dictionary)
* @method mixed psetex($key, $milliseconds, $value)
* @method mixed set($key, $value, $expireResolution = null, $expireTTL = null, $flag = null)
* @method int setbit($key, $offset, $value)
* @method int setex($key, $seconds, $value)
* @method int setnx($key, $value)
* @method int setrange($key, $offset, $value)
* @method int strlen($key)
* @method int hdel($key, array $fields)
* @method int hexists($key, $field)
* @method string hget($key, $field)
* @method array hgetall($key)
* @method int hincrby($key, $field, $increment)
* @method string hincrbyfloat($key, $field, $increment)
* @method array hkeys($key)
* @method int hlen($key)
* @method array hmget($key, array $fields)
* @method mixed hmset($key, array $dictionary)
* @method array hscan($key, $cursor, array $options = null)
* @method int hset($key, $field, $value)
* @method int hsetnx($key, $field, $value)
* @method array hvals($key)
* @method int hstrlen($key, $field)
* @method array blpop(array $keys, $timeout)
* @method array brpop(array $keys, $timeout)
* @method array brpoplpush($source, $destination, $timeout)
* @method string lindex($key, $index)
* @method int linsert($key, $whence, $pivot, $value)
* @method int llen($key)
* @method string lpop($key)
* @method int lpush($key, array $values)
* @method int lpushx($key, $value)
* @method array lrange($key, $start, $stop)
* @method int lrem($key, $count, $value)
* @method mixed lset($key, $index, $value)
* @method mixed ltrim($key, $start, $stop)
* @method string rpop($key)
* @method string rpoplpush($source, $destination)
* @method int rpush($key, array $values)
* @method int rpushx($key, $value)
* @method int sadd($key, array $members)
* @method int scard($key)
* @method array sdiff(array $keys)
* @method int sdiffstore($destination, array $keys)
* @method array sinter(array $keys)
* @method int sinterstore($destination, array $keys)
* @method int sismember($key, $member)
* @method array smembers($key)
* @method int smove($source, $destination, $member)
* @method string spop($key, $count = null)
* @method string srandmember($key, $count = null)
* @method int srem($key, $member)
* @method array sscan($key, $cursor, array $options = null)
* @method array sunion(array $keys)
* @method int sunionstore($destination, array $keys)
* @method int zadd($key, array $membersAndScoresDictionary)
* @method int zcard($key)
* @method string zcount($key, $min, $max)
* @method string zincrby($key, $increment, $member)
* @method int zinterstore($destination, array $keys, array $options = null)
* @method array zrange($key, $start, $stop, array $options = null)
* @method array zrangebyscore($key, $min, $max, array $options = null)
* @method int zrank($key, $member)
* @method int zrem($key, $member)
* @method int zremrangebyrank($key, $start, $stop)
* @method int zremrangebyscore($key, $min, $max)
* @method array zrevrange($key, $start, $stop, array $options = null)
* @method array zrevrangebyscore($key, $max, $min, array $options = null)
* @method int zrevrank($key, $member)
* @method int zunionstore($destination, array $keys, array $options = null)
* @method string zscore($key, $member)
* @method array zscan($key, $cursor, array $options = null)
* @method array zrangebylex($key, $start, $stop, array $options = null)
* @method array zrevrangebylex($key, $start, $stop, array $options = null)
* @method int zremrangebylex($key, $min, $max)
* @method int zlexcount($key, $min, $max)
* @method int pfadd($key, array $elements)
* @method mixed pfmerge($destinationKey, array $sourceKeys)
* @method int pfcount(array $keys)
* @method mixed pubsub($subcommand, $argument)
* @method int publish($channel, $message)
* @method mixed discard()
* @method array exec()
* @method mixed multi()
* @method mixed unwatch()
* @method mixed watch($key)
* @method mixed eval($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
* @method mixed evalsha($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
* @method mixed script($subcommand, $argument = null)
* @method mixed auth($password)
* @method string echo($message)
* @method mixed ping($message = null)
* @method mixed select($database)
* @method mixed bgrewriteaof()
* @method mixed bgsave()
* @method mixed client($subcommand, $argument = null)
* @method mixed config($subcommand, $argument = null)
* @method int dbsize()
* @method mixed flushall()
* @method mixed flushdb()
* @method array info($section = null)
* @method int lastsave()
* @method mixed save()
* @method mixed slaveof($host, $port)
* @method mixed slowlog($subcommand, $argument = null)
* @method array time()
* @method array command()
* @method int geoadd($key, $longitude, $latitude, $member)
* @method array geohash($key, array $members)
* @method array geopos($key, array $members)
* @method string geodist($key, $member1, $member2, $unit = null)
* @method array georadius($key, $longitude, $latitude, $radius, $unit, array $options = null)
* @method array georadiusbymember($key, $member, $radius, $unit, array $options = null)
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
+1 -1
View File
@@ -161,7 +161,7 @@ class HashRing implements DistributorInterface, HashGeneratorInterface
$replicas = (int) round($weightRatio * $totalNodes * $replicas);
for ($i = 0; $i < $replicas; ++$i) {
$key = $this->hash("$nodeHash:$i");
$key = crc32("$nodeHash:$i");
$ring[$key] = $nodeObject;
}
}
-2
View File
@@ -61,8 +61,6 @@ class CRC16 implements HashGeneratorInterface
// CRC-CCITT-16 algorithm
$crc = 0;
$CCITT_16 = self::$CCITT_16;
$value = (string) $value;
$strlen = strlen($value);
for ($i = 0; $i < $strlen; ++$i) {
+5 -3
View File
@@ -50,9 +50,11 @@ class HashKey extends CursorBasedIterator
*/
protected function extractNext()
{
$this->position = key($this->elements);
$this->current = current($this->elements);
if ($kv = each($this->elements)) {
$this->position = $kv[0];
$this->current = $kv[1];
unset($this->elements[$this->position]);
unset($this->elements[$this->position]);
}
}
}
+5 -3
View File
@@ -50,9 +50,11 @@ class SortedSetKey extends CursorBasedIterator
*/
protected function extractNext()
{
$this->position = key($this->elements);
$this->current = current($this->elements);
if ($kv = each($this->elements)) {
$this->position = $kv[0];
$this->current = $kv[1];
unset($this->elements[$this->position]);
unset($this->elements[$this->position]);
}
}
}
+8
View File
@@ -25,4 +25,12 @@ class HashExists extends Command
{
return 'HEXISTS';
}
/**
* {@inheritdoc}
*/
public function parseResponse($data)
{
return (bool) $data;
}
}
+8
View File
@@ -25,4 +25,12 @@ class HashSet extends Command
{
return 'HSET';
}
/**
* {@inheritdoc}
*/
public function parseResponse($data)
{
return (bool) $data;
}
}
+8
View File
@@ -25,4 +25,12 @@ class HashSetPreserve extends Command
{
return 'HSETNX';
}
/**
* {@inheritdoc}
*/
public function parseResponse($data)
{
return (bool) $data;
}
}
+8
View File
@@ -33,4 +33,12 @@ class HyperLogLogAdd extends Command
{
return self::normalizeVariadic($arguments);
}
/**
* {@inheritdoc}
*/
public function parseResponse($data)
{
return (bool) $data;
}
}
+8
View File
@@ -25,4 +25,12 @@ class KeyExists extends Command
{
return 'EXISTS';
}
/**
* {@inheritdoc}
*/
public function parseResponse($data)
{
return (bool) $data;
}
}
+8
View File
@@ -25,4 +25,12 @@ class KeyExpire extends Command
{
return 'EXPIRE';
}
/**
* {@inheritdoc}
*/
public function parseResponse($data)
{
return (bool) $data;
}
}
+8
View File
@@ -25,4 +25,12 @@ class KeyExpireAt extends Command
{
return 'EXPIREAT';
}
/**
* {@inheritdoc}
*/
public function parseResponse($data)
{
return (bool) $data;
}
}
+8
View File
@@ -25,4 +25,12 @@ class KeyMove extends Command
{
return 'MOVE';
}
/**
* {@inheritdoc}
*/
public function parseResponse($data)
{
return (bool) $data;
}
}
+8
View File
@@ -25,4 +25,12 @@ class KeyPersist extends Command
{
return 'PERSIST';
}
/**
* {@inheritdoc}
*/
public function parseResponse($data)
{
return (bool) $data;
}
}
+8
View File
@@ -25,4 +25,12 @@ class KeyRenamePreserve extends KeyRename
{
return 'RENAMENX';
}
/**
* {@inheritdoc}
*/
public function parseResponse($data)
{
return (bool) $data;
}
}
+8
View File
@@ -25,4 +25,12 @@ class SetIsMember extends Command
{
return 'SISMEMBER';
}
/**
* {@inheritdoc}
*/
public function parseResponse($data)
{
return (bool) $data;
}
}
+8
View File
@@ -25,4 +25,12 @@ class SetMove extends Command
{
return 'SMOVE';
}
/**
* {@inheritdoc}
*/
public function parseResponse($data)
{
return (bool) $data;
}
}
@@ -25,4 +25,12 @@ class StringSetMultiplePreserve extends StringSetMultiple
{
return 'MSETNX';
}
/**
* {@inheritdoc}
*/
public function parseResponse($data)
{
return (bool) $data;
}
}
+8
View File
@@ -25,4 +25,12 @@ class StringSetPreserve extends Command
{
return 'SETNX';
}
/**
* {@inheritdoc}
*/
public function parseResponse($data)
{
return (bool) $data;
}
}
@@ -49,12 +49,6 @@ class ConnectionFactoryOption implements OptionInterface
*/
public function getDefault(OptionsInterface $options)
{
$factory = new Factory();
if ($options->defined('parameters')) {
$factory->setDefaultParameters($options->parameters);
}
return $factory;
return new Factory();
}
}
+7 -13
View File
@@ -11,22 +11,16 @@
namespace Predis\Configuration;
use Predis\Command\Processor\ProcessorInterface;
use Predis\Connection\Aggregate\ClusterInterface;
use Predis\Connection\Aggregate\ReplicationInterface;
use Predis\Connection\FactoryInterface;
use Predis\Profile\ProfileInterface;
/**
* Interface defining a container for client options.
*
* @property-read callable $aggregate Custom connection aggregator.
* @property-read ClusterInterface $cluster Aggregate connection for clustering.
* @property-read FactoryInterface $connections Connection factory.
* @property-read bool $exceptions Toggles exceptions in client for -ERR responses.
* @property-read ProcessorInterface $prefix Key prefixing strategy using the given prefix.
* @property-read ProfileInterface $profile Server profile.
* @property-read ReplicationInterface $replication Aggregate connection for replication.
* @property-read mixed aggregate Custom connection aggregator.
* @property-read mixed cluster Aggregate connection for clustering.
* @property-read mixed connections Connection factory.
* @property-read mixed exceptions Toggles exceptions in client for -ERR responses.
* @property-read mixed prefix Key prefixing strategy using the given prefix.
* @property-read mixed profile Server profile.
* @property-read mixed replication Aggregate connection for replication.
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
+1 -15
View File
@@ -13,7 +13,6 @@ namespace Predis\Configuration;
use Predis\Connection\Aggregate\MasterSlaveReplication;
use Predis\Connection\Aggregate\ReplicationInterface;
use Predis\Connection\Aggregate\SentinelReplication;
/**
* Configures an aggregate connection used for master/slave replication among
@@ -40,12 +39,6 @@ class ReplicationOption implements OptionInterface
return $value ? $this->getDefault($options) : null;
}
if ($value === 'sentinel') {
return function ($sentinels, $options) {
return new SentinelReplication($options->service, $sentinels, $options->connections);
};
}
if (
!is_object($value) &&
null !== $asbool = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)
@@ -63,13 +56,6 @@ class ReplicationOption implements OptionInterface
*/
public function getDefault(OptionsInterface $options)
{
$replication = new MasterSlaveReplication();
if ($options->autodiscovery) {
$replication->setConnectionFactory($options->connections);
$replication->setAutoDiscovery(true);
}
return $replication;
return new MasterSlaveReplication();
}
}
+14 -1
View File
@@ -55,7 +55,20 @@ abstract class AbstractConnection implements NodeConnectionInterface
*
* @return ParametersInterface
*/
abstract protected function assertParameters(ParametersInterface $parameters);
protected function assertParameters(ParametersInterface $parameters)
{
switch ($parameters->scheme) {
case 'tcp':
case 'redis':
case 'unix':
break;
default:
throw new \InvalidArgumentException("Invalid scheme: '$parameters->scheme'.");
}
return $parameters;
}
/**
* Creates the underlying resource used to communicate with Redis.
@@ -11,15 +11,9 @@
namespace Predis\Connection\Aggregate;
use Predis\ClientException;
use Predis\Command\CommandInterface;
use Predis\Command\RawCommand;
use Predis\Connection\ConnectionException;
use Predis\Connection\FactoryInterface;
use Predis\Connection\NodeConnectionInterface;
use Predis\Replication\MissingMasterException;
use Predis\Replication\ReplicationStrategy;
use Predis\Response\ErrorInterface as ResponseErrorInterface;
/**
* Aggregate connection handling replication of Redis nodes configured in a
@@ -49,16 +43,6 @@ class MasterSlaveReplication implements ReplicationInterface
*/
protected $current;
/**
* @var bool
*/
protected $autoDiscovery = false;
/**
* @var FactoryInterface
*/
protected $connectionFactory;
/**
* {@inheritdoc}
*/
@@ -68,28 +52,13 @@ class MasterSlaveReplication implements ReplicationInterface
}
/**
* Configures the automatic discovery of the replication configuration on failure.
*
* @param bool $value Enable or disable auto discovery.
* Checks if one master and at least one slave have been defined.
*/
public function setAutoDiscovery($value)
protected function check()
{
if (!$this->connectionFactory) {
throw new ClientException('Automatic discovery requires a connection factory');
if (!isset($this->master) || !$this->slaves) {
throw new \RuntimeException('Replication needs one master and at least one slave.');
}
$this->autoDiscovery = (bool) $value;
}
/**
* Sets the connection factory used to create the connections by the auto
* discovery procedure.
*
* @param FactoryInterface $connectionFactory Connection factory instance.
*/
public function setConnectionFactory(FactoryInterface $connectionFactory)
{
$this->connectionFactory = $connectionFactory;
}
/**
@@ -110,7 +79,7 @@ class MasterSlaveReplication implements ReplicationInterface
if ($alias === 'master') {
$this->master = $connection;
} else {
$this->slaves[$alias ?: "slave-$connection"] = $connection;
$this->slaves[$alias ?: count($this->slaves)] = $connection;
}
$this->reset();
@@ -143,22 +112,21 @@ class MasterSlaveReplication implements ReplicationInterface
*/
public function getConnection(CommandInterface $command)
{
if (!$this->current) {
if ($this->strategy->isReadOperation($command) && $slave = $this->pickSlave()) {
$this->current = $slave;
} else {
$this->current = $this->getMasterOrDie();
}
if ($this->current === null) {
$this->check();
$this->current = $this->strategy->isReadOperation($command)
? $this->pickSlave()
: $this->master;
return $this->current;
}
if ($this->current === $master = $this->getMasterOrDie()) {
return $master;
if ($this->current === $this->master) {
return $this->current;
}
if (!$this->strategy->isReadOperation($command) || !$this->slaves) {
$this->current = $master;
if (!$this->strategy->isReadOperation($command)) {
$this->current = $this->master;
}
return $this->current;
@@ -185,14 +153,12 @@ class MasterSlaveReplication implements ReplicationInterface
*/
public function switchTo($connection)
{
$this->check();
if (!$connection instanceof NodeConnectionInterface) {
$connection = $this->getConnectionById($connection);
}
if (!$connection) {
throw new \InvalidArgumentException('Invalid connection or connection not found.');
}
if ($connection !== $this->master && !in_array($connection, $this->slaves, true)) {
throw new \InvalidArgumentException('Invalid connection or connection not found.');
}
@@ -200,23 +166,6 @@ class MasterSlaveReplication implements ReplicationInterface
$this->current = $connection;
}
/**
* Switches to the master server.
*/
public function switchToMaster()
{
$this->switchTo('master');
}
/**
* Switches to a random slave server.
*/
public function switchToSlave()
{
$connection = $this->pickSlave();
$this->switchTo($connection);
}
/**
* {@inheritdoc}
*/
@@ -233,20 +182,6 @@ class MasterSlaveReplication implements ReplicationInterface
return $this->master;
}
/**
* Returns the connection associated to the master server.
*
* @return NodeConnectionInterface
*/
private function getMasterOrDie()
{
if (!$connection = $this->getMaster()) {
throw new MissingMasterException('No master server available for replication');
}
return $connection;
}
/**
* {@inheritdoc}
*/
@@ -290,12 +225,9 @@ class MasterSlaveReplication implements ReplicationInterface
*/
public function connect()
{
if (!$this->current) {
if (!$this->current = $this->pickSlave()) {
if (!$this->current = $this->getMaster()) {
throw new ClientException('No available connection for replication');
}
}
if ($this->current === null) {
$this->check();
$this->current = $this->pickSlave();
}
$this->current->connect();
@@ -315,172 +247,12 @@ class MasterSlaveReplication implements ReplicationInterface
}
}
/**
* Handles response from INFO.
*
* @param string $response
*
* @return array
*/
private function handleInfoResponse($response)
{
$info = array();
foreach (preg_split('/\r?\n/', $response) as $row) {
if (strpos($row, ':') === false) {
continue;
}
list($k, $v) = explode(':', $row, 2);
$info[$k] = $v;
}
return $info;
}
/**
* Fetches the replication configuration from one of the servers.
*/
public function discover()
{
if (!$this->connectionFactory) {
throw new ClientException('Discovery requires a connection factory');
}
RETRY_FETCH: {
try {
if ($connection = $this->getMaster()) {
$this->discoverFromMaster($connection, $this->connectionFactory);
} elseif ($connection = $this->pickSlave()) {
$this->discoverFromSlave($connection, $this->connectionFactory);
} else {
throw new ClientException('No connection available for discovery');
}
} catch (ConnectionException $exception) {
$this->remove($connection);
goto RETRY_FETCH;
}
}
}
/**
* Discovers the replication configuration by contacting the master node.
*
* @param NodeConnectionInterface $connection Connection to the master node.
* @param FactoryInterface $connectionFactory Connection factory instance.
*/
protected function discoverFromMaster(NodeConnectionInterface $connection, FactoryInterface $connectionFactory)
{
$response = $connection->executeCommand(RawCommand::create('INFO', 'REPLICATION'));
$replication = $this->handleInfoResponse($response);
if ($replication['role'] !== 'master') {
throw new ClientException("Role mismatch (expected master, got slave) [$connection]");
}
$this->slaves = array();
foreach ($replication as $k => $v) {
$parameters = null;
if (strpos($k, 'slave') === 0 && preg_match('/ip=(?P<host>.*),port=(?P<port>\d+)/', $v, $parameters)) {
$slaveConnection = $connectionFactory->create(array(
'host' => $parameters['host'],
'port' => $parameters['port'],
));
$this->add($slaveConnection);
}
}
}
/**
* Discovers the replication configuration by contacting one of the slaves.
*
* @param NodeConnectionInterface $connection Connection to one of the slaves.
* @param FactoryInterface $connectionFactory Connection factory instance.
*/
protected function discoverFromSlave(NodeConnectionInterface $connection, FactoryInterface $connectionFactory)
{
$response = $connection->executeCommand(RawCommand::create('INFO', 'REPLICATION'));
$replication = $this->handleInfoResponse($response);
if ($replication['role'] !== 'slave') {
throw new ClientException("Role mismatch (expected slave, got master) [$connection]");
}
$masterConnection = $connectionFactory->create(array(
'host' => $replication['master_host'],
'port' => $replication['master_port'],
'alias' => 'master',
));
$this->add($masterConnection);
$this->discoverFromMaster($masterConnection, $connectionFactory);
}
/**
* Retries the execution of a command upon slave failure.
*
* @param CommandInterface $command Command instance.
* @param string $method Actual method.
*
* @return mixed
*/
private function retryCommandOnFailure(CommandInterface $command, $method)
{
RETRY_COMMAND: {
try {
$connection = $this->getConnection($command);
$response = $connection->$method($command);
if ($response instanceof ResponseErrorInterface && $response->getErrorType() === 'LOADING') {
throw new ConnectionException($connection, "Redis is loading the dataset in memory [$connection]");
}
} catch (ConnectionException $exception) {
$connection = $exception->getConnection();
$connection->disconnect();
if ($connection === $this->master && !$this->autoDiscovery) {
// Throw immediately when master connection is failing, even
// when the command represents a read-only operation, unless
// automatic discovery has been enabled.
throw $exception;
} else {
// Otherwise remove the failing slave and attempt to execute
// the command again on one of the remaining slaves...
$this->remove($connection);
}
// ... that is, unless we have no more connections to use.
if (!$this->slaves && !$this->master) {
throw $exception;
} elseif ($this->autoDiscovery) {
$this->discover();
}
goto RETRY_COMMAND;
} catch (MissingMasterException $exception) {
if ($this->autoDiscovery) {
$this->discover();
} else {
throw $exception;
}
goto RETRY_COMMAND;
}
}
return $response;
}
/**
* {@inheritdoc}
*/
public function writeRequest(CommandInterface $command)
{
$this->retryCommandOnFailure($command, __FUNCTION__);
$this->getConnection($command)->writeRequest($command);
}
/**
@@ -488,7 +260,7 @@ class MasterSlaveReplication implements ReplicationInterface
*/
public function readResponse(CommandInterface $command)
{
return $this->retryCommandOnFailure($command, __FUNCTION__);
return $this->getConnection($command)->readResponse($command);
}
/**
@@ -496,7 +268,7 @@ class MasterSlaveReplication implements ReplicationInterface
*/
public function executeCommand(CommandInterface $command)
{
return $this->retryCommandOnFailure($command, __FUNCTION__);
return $this->getConnection($command)->executeCommand($command);
}
/**
+25 -22
View File
@@ -47,6 +47,7 @@ use Predis\Response\ErrorInterface as ErrorResponseInterface;
class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
{
private $useClusterSlots = true;
private $defaultParameters = array();
private $pool = array();
private $slots = array();
private $slotsMap;
@@ -171,8 +172,6 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
* cluster, so it is most effective when all of the connections supplied on
* initialization have the "slots" parameter properly set accordingly to the
* current cluster configuration.
*
* @return array
*/
public function buildSlotsMap()
{
@@ -195,8 +194,6 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
$this->setSlots($slots[0], $slots[1], $connectionID);
}
}
return $this->slotsMap;
}
/**
@@ -363,10 +360,14 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
{
$separator = strrpos($connectionID, ':');
return $this->connections->create(array(
$parameters = array_merge($this->defaultParameters, array(
'host' => substr($connectionID, 0, $separator),
'port' => substr($connectionID, $separator + 1),
));
$connection = $this->connections->create($parameters);
return $connection;
}
/**
@@ -612,23 +613,7 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
*/
public function getIterator()
{
if ($this->useClusterSlots) {
$slotsmap = $this->getSlotsMap() ?: $this->askSlotsMap();
} else {
$slotsmap = $this->getSlotsMap() ?: $this->buildSlotsMap();
}
$connections = array();
foreach (array_unique($slotsmap) as $node) {
if (!$connection = $this->getConnectionById($node)) {
$this->add($connection = $this->createConnection($node));
}
$connections[] = $connection;
}
return new \ArrayIterator($connections);
return new \ArrayIterator(array_values($this->pool));
}
/**
@@ -670,4 +655,22 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
{
$this->useClusterSlots = (bool) $value;
}
/**
* Sets a default array of connection parameters to be applied when creating
* new connection instances on the fly when they are not part of the initial
* pool supplied upon cluster initialization.
*
* These parameters are not applied to connections added to the pool using
* the add() method.
*
* @param array $parameters Array of connection parameters.
*/
public function setDefaultParameters(array $parameters)
{
$this->defaultParameters = array_merge(
$this->defaultParameters,
$parameters ?: array()
);
}
}
@@ -1,722 +0,0 @@
<?php
/*
* This file is part of the Predis package.
*
* (c) Daniele Alessandri <suppakilla@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Predis\Connection\Aggregate;
use Predis\Command\CommandInterface;
use Predis\Command\RawCommand;
use Predis\CommunicationException;
use Predis\Connection\ConnectionException;
use Predis\Connection\FactoryInterface as ConnectionFactoryInterface;
use Predis\Connection\NodeConnectionInterface;
use Predis\Connection\Parameters;
use Predis\Replication\ReplicationStrategy;
use Predis\Replication\RoleException;
use Predis\Response\ErrorInterface as ErrorResponseInterface;
use Predis\Response\ServerException;
/**
* @author Daniele Alessandri <suppakilla@gmail.com>
* @author Ville Mattila <ville@eventio.fi>
*/
class SentinelReplication implements ReplicationInterface
{
/**
* @var NodeConnectionInterface
*/
protected $master;
/**
* @var NodeConnectionInterface[]
*/
protected $slaves = array();
/**
* @var NodeConnectionInterface
*/
protected $current;
/**
* @var string
*/
protected $service;
/**
* @var ConnectionFactoryInterface
*/
protected $connectionFactory;
/**
* @var ReplicationStrategy
*/
protected $strategy;
/**
* @var NodeConnectionInterface[]
*/
protected $sentinels = array();
/**
* @var NodeConnectionInterface
*/
protected $sentinelConnection;
/**
* @var float
*/
protected $sentinelTimeout = 0.100;
/**
* Max number of automatic retries of commands upon server failure.
*
* -1 = unlimited retry attempts
* 0 = no retry attempts (fails immediatly)
* n = fail only after n retry attempts
*
* @var int
*/
protected $retryLimit = 20;
/**
* Time to wait in milliseconds before fetching a new configuration from one
* of the sentinel servers.
*
* @var int
*/
protected $retryWait = 1000;
/**
* Flag for automatic fetching of available sentinels.
*
* @var bool
*/
protected $updateSentinels = false;
/**
* @param string $service Name of the service for autodiscovery.
* @param array $sentinels Sentinel servers connection parameters.
* @param ConnectionFactoryInterface $connectionFactory Connection factory instance.
* @param ReplicationStrategy $strategy Replication strategy instance.
*/
public function __construct(
$service,
array $sentinels,
ConnectionFactoryInterface $connectionFactory,
ReplicationStrategy $strategy = null
) {
$this->sentinels = $sentinels;
$this->service = $service;
$this->connectionFactory = $connectionFactory;
$this->strategy = $strategy ?: new ReplicationStrategy();
}
/**
* Sets a default timeout for connections to sentinels.
*
* When "timeout" is present in the connection parameters of sentinels, its
* value overrides the default sentinel timeout.
*
* @param float $timeout Timeout value.
*/
public function setSentinelTimeout($timeout)
{
$this->sentinelTimeout = (float) $timeout;
}
/**
* Sets the maximum number of retries for commands upon server failure.
*
* -1 = unlimited retry attempts
* 0 = no retry attempts (fails immediatly)
* n = fail only after n retry attempts
*
* @param int $retry Number of retry attempts.
*/
public function setRetryLimit($retry)
{
$this->retryLimit = (int) $retry;
}
/**
* Sets the time to wait (in seconds) before fetching a new configuration
* from one of the sentinels.
*
* @param float $seconds Time to wait before the next attempt.
*/
public function setRetryWait($seconds)
{
$this->retryWait = (float) $seconds;
}
/**
* Set automatic fetching of available sentinels.
*
* @param bool $update Enable or disable automatic updates.
*/
public function setUpdateSentinels($update)
{
$this->updateSentinels = (bool) $update;
}
/**
* Resets the current connection.
*/
protected function reset()
{
$this->current = null;
}
/**
* Wipes the current list of master and slaves nodes.
*/
protected function wipeServerList()
{
$this->reset();
$this->master = null;
$this->slaves = array();
}
/**
* {@inheritdoc}
*/
public function add(NodeConnectionInterface $connection)
{
$alias = $connection->getParameters()->alias;
if ($alias === 'master') {
$this->master = $connection;
} else {
$this->slaves[$alias ?: count($this->slaves)] = $connection;
}
$this->reset();
}
/**
* {@inheritdoc}
*/
public function remove(NodeConnectionInterface $connection)
{
if ($connection === $this->master) {
$this->master = null;
$this->reset();
return true;
}
if (false !== $id = array_search($connection, $this->slaves, true)) {
unset($this->slaves[$id]);
$this->reset();
return true;
}
return false;
}
/**
* Creates a new connection to a sentinel server.
*
* @return NodeConnectionInterface
*/
protected function createSentinelConnection($parameters)
{
if ($parameters instanceof NodeConnectionInterface) {
return $parameters;
}
if (is_string($parameters)) {
$parameters = Parameters::parse($parameters);
}
if (is_array($parameters)) {
// We explicitly set "database" and "password" to null,
// so that no AUTH and SELECT command is send to the sentinels.
$parameters['database'] = null;
$parameters['password'] = null;
if (!isset($parameters['timeout'])) {
$parameters['timeout'] = $this->sentinelTimeout;
}
}
$connection = $this->connectionFactory->create($parameters);
return $connection;
}
/**
* Returns the current sentinel connection.
*
* If there is no active sentinel connection, a new connection is created.
*
* @return NodeConnectionInterface
*/
public function getSentinelConnection()
{
if (!$this->sentinelConnection) {
if (!$this->sentinels) {
throw new \Predis\ClientException('No sentinel server available for autodiscovery.');
}
$sentinel = array_shift($this->sentinels);
$this->sentinelConnection = $this->createSentinelConnection($sentinel);
}
return $this->sentinelConnection;
}
/**
* Fetches an updated list of sentinels from a sentinel.
*/
public function updateSentinels()
{
SENTINEL_QUERY: {
$sentinel = $this->getSentinelConnection();
try {
$payload = $sentinel->executeCommand(
RawCommand::create('SENTINEL', 'sentinels', $this->service)
);
$this->sentinels = array();
// NOTE: sentinel server does not return itself, so we add it back.
$this->sentinels[] = $sentinel->getParameters()->toArray();
foreach ($payload as $sentinel) {
$this->sentinels[] = array(
'host' => $sentinel[3],
'port' => $sentinel[5],
);
}
} catch (ConnectionException $exception) {
$this->sentinelConnection = null;
goto SENTINEL_QUERY;
}
}
}
/**
* Fetches the details for the master and slave servers from a sentinel.
*/
public function querySentinel()
{
$this->wipeServerList();
$this->updateSentinels();
$this->getMaster();
$this->getSlaves();
}
/**
* Handles error responses returned by redis-sentinel.
*
* @param NodeConnectionInterface $sentinel Connection to a sentinel server.
* @param ErrorResponseInterface $error Error response.
*/
private function handleSentinelErrorResponse(NodeConnectionInterface $sentinel, ErrorResponseInterface $error)
{
if ($error->getErrorType() === 'IDONTKNOW') {
throw new ConnectionException($sentinel, $error->getMessage());
} else {
throw new ServerException($error->getMessage());
}
}
/**
* Fetches the details for the master server from a sentinel.
*
* @param NodeConnectionInterface $sentinel Connection to a sentinel server.
* @param string $service Name of the service.
*
* @return array
*/
protected function querySentinelForMaster(NodeConnectionInterface $sentinel, $service)
{
$payload = $sentinel->executeCommand(
RawCommand::create('SENTINEL', 'get-master-addr-by-name', $service)
);
if ($payload === null) {
throw new ServerException('ERR No such master with that name');
}
if ($payload instanceof ErrorResponseInterface) {
$this->handleSentinelErrorResponse($sentinel, $payload);
}
return array(
'host' => $payload[0],
'port' => $payload[1],
'alias' => 'master',
);
}
/**
* Fetches the details for the slave servers from a sentinel.
*
* @param NodeConnectionInterface $sentinel Connection to a sentinel server.
* @param string $service Name of the service.
*
* @return array
*/
protected function querySentinelForSlaves(NodeConnectionInterface $sentinel, $service)
{
$slaves = array();
$payload = $sentinel->executeCommand(
RawCommand::create('SENTINEL', 'slaves', $service)
);
if ($payload instanceof ErrorResponseInterface) {
$this->handleSentinelErrorResponse($sentinel, $payload);
}
foreach ($payload as $slave) {
$flags = explode(',', $slave[9]);
if (array_intersect($flags, array('s_down', 'o_down', 'disconnected'))) {
continue;
}
$slaves[] = array(
'host' => $slave[3],
'port' => $slave[5],
'alias' => "slave-$slave[1]",
);
}
return $slaves;
}
/**
* {@inheritdoc}
*/
public function getCurrent()
{
return $this->current;
}
/**
* {@inheritdoc}
*/
public function getMaster()
{
if ($this->master) {
return $this->master;
}
if ($this->updateSentinels) {
$this->updateSentinels();
}
SENTINEL_QUERY: {
$sentinel = $this->getSentinelConnection();
try {
$masterParameters = $this->querySentinelForMaster($sentinel, $this->service);
$masterConnection = $this->connectionFactory->create($masterParameters);
$this->add($masterConnection);
} catch (ConnectionException $exception) {
$this->sentinelConnection = null;
goto SENTINEL_QUERY;
}
}
return $masterConnection;
}
/**
* {@inheritdoc}
*/
public function getSlaves()
{
if ($this->slaves) {
return array_values($this->slaves);
}
if ($this->updateSentinels) {
$this->updateSentinels();
}
SENTINEL_QUERY: {
$sentinel = $this->getSentinelConnection();
try {
$slavesParameters = $this->querySentinelForSlaves($sentinel, $this->service);
foreach ($slavesParameters as $slaveParameters) {
$this->add($this->connectionFactory->create($slaveParameters));
}
} catch (ConnectionException $exception) {
$this->sentinelConnection = null;
goto SENTINEL_QUERY;
}
}
return array_values($this->slaves ?: array());
}
/**
* Returns a random slave.
*
* @return NodeConnectionInterface
*/
protected function pickSlave()
{
if ($slaves = $this->getSlaves()) {
return $slaves[rand(1, count($slaves)) - 1];
}
}
/**
* Returns the connection instance in charge for the given command.
*
* @param CommandInterface $command Command instance.
*
* @return NodeConnectionInterface
*/
private function getConnectionInternal(CommandInterface $command)
{
if (!$this->current) {
if ($this->strategy->isReadOperation($command) && $slave = $this->pickSlave()) {
$this->current = $slave;
} else {
$this->current = $this->getMaster();
}
return $this->current;
}
if ($this->current === $this->master) {
return $this->current;
}
if (!$this->strategy->isReadOperation($command)) {
$this->current = $this->getMaster();
}
return $this->current;
}
/**
* Asserts that the specified connection matches an expected role.
*
* @param NodeConnectionInterface $connection Connection to a redis server.
* @param string $role Expected role of the server ("master", "slave" or "sentinel").
*
* @throws RoleException
*/
protected function assertConnectionRole(NodeConnectionInterface $connection, $role)
{
$role = strtolower($role);
$actualRole = $connection->executeCommand(RawCommand::create('ROLE'));
if ($role !== $actualRole[0]) {
throw new RoleException($connection, "Expected $role but got $actualRole[0] [$connection]");
}
}
/**
* {@inheritdoc}
*/
public function getConnection(CommandInterface $command)
{
$connection = $this->getConnectionInternal($command);
if (!$connection->isConnected()) {
// When we do not have any available slave in the pool we can expect
// read-only operations to hit the master server.
$expectedRole = $this->strategy->isReadOperation($command) && $this->slaves ? 'slave' : 'master';
$this->assertConnectionRole($connection, $expectedRole);
}
return $connection;
}
/**
* {@inheritdoc}
*/
public function getConnectionById($connectionId)
{
if ($connectionId === 'master') {
return $this->getMaster();
}
$this->getSlaves();
if (isset($this->slaves[$connectionId])) {
return $this->slaves[$connectionId];
}
}
/**
* {@inheritdoc}
*/
public function switchTo($connection)
{
if (!$connection instanceof NodeConnectionInterface) {
$connection = $this->getConnectionById($connection);
}
if ($connection && $connection === $this->current) {
return;
}
if ($connection !== $this->master && !in_array($connection, $this->slaves, true)) {
throw new \InvalidArgumentException('Invalid connection or connection not found.');
}
$connection->connect();
if ($this->current) {
$this->current->disconnect();
}
$this->current = $connection;
}
/**
* Switches to the master server.
*/
public function switchToMaster()
{
$this->switchTo('master');
}
/**
* Switches to a random slave server.
*/
public function switchToSlave()
{
$connection = $this->pickSlave();
$this->switchTo($connection);
}
/**
* {@inheritdoc}
*/
public function isConnected()
{
return $this->current ? $this->current->isConnected() : false;
}
/**
* {@inheritdoc}
*/
public function connect()
{
if (!$this->current) {
if (!$this->current = $this->pickSlave()) {
$this->current = $this->getMaster();
}
}
$this->current->connect();
}
/**
* {@inheritdoc}
*/
public function disconnect()
{
if ($this->master) {
$this->master->disconnect();
}
foreach ($this->slaves as $connection) {
$connection->disconnect();
}
}
/**
* Retries the execution of a command upon server failure after asking a new
* configuration to one of the sentinels.
*
* @param CommandInterface $command Command instance.
* @param string $method Actual method.
*
* @return mixed
*/
private function retryCommandOnFailure(CommandInterface $command, $method)
{
$retries = 0;
SENTINEL_RETRY: {
try {
$response = $this->getConnection($command)->$method($command);
} catch (CommunicationException $exception) {
$this->wipeServerList();
$exception->getConnection()->disconnect();
if ($retries == $this->retryLimit) {
throw $exception;
}
usleep($this->retryWait * 1000);
++$retries;
goto SENTINEL_RETRY;
}
}
return $response;
}
/**
* {@inheritdoc}
*/
public function writeRequest(CommandInterface $command)
{
$this->retryCommandOnFailure($command, __FUNCTION__);
}
/**
* {@inheritdoc}
*/
public function readResponse(CommandInterface $command)
{
return $this->retryCommandOnFailure($command, __FUNCTION__);
}
/**
* {@inheritdoc}
*/
public function executeCommand(CommandInterface $command)
{
return $this->retryCommandOnFailure($command, __FUNCTION__);
}
/**
* Returns the underlying replication strategy.
*
* @return ReplicationStrategy
*/
public function getReplicationStrategy()
{
return $this->strategy;
}
/**
* {@inheritdoc}
*/
public function __sleep()
{
return array(
'master', 'slaves', 'service', 'sentinels', 'connectionFactory', 'strategy',
);
}
}
+4 -45
View File
@@ -20,14 +20,10 @@ use Predis\Command\RawCommand;
*/
class Factory implements FactoryInterface
{
private $defaults = array();
protected $schemes = array(
'tcp' => 'Predis\Connection\StreamConnection',
'unix' => 'Predis\Connection\StreamConnection',
'tls' => 'Predis\Connection\StreamConnection',
'redis' => 'Predis\Connection\StreamConnection',
'rediss' => 'Predis\Connection\StreamConnection',
'http' => 'Predis\Connection\WebdisConnection',
);
@@ -119,29 +115,6 @@ class Factory implements FactoryInterface
}
}
/**
* Assigns a default set of parameters applied to new connections.
*
* The set of parameters passed to create a new connection have precedence
* over the default values set for the connection factory.
*
* @param array $parameters Set of connection parameters.
*/
public function setDefaultParameters(array $parameters)
{
$this->defaults = $parameters;
}
/**
* Returns the default set of parameters applied to new connections.
*
* @return array
*/
public function getDefaultParameters()
{
return $this->defaults;
}
/**
* Creates a connection parameters instance from the supplied argument.
*
@@ -151,17 +124,7 @@ class Factory implements FactoryInterface
*/
protected function createParameters($parameters)
{
if (is_string($parameters)) {
$parameters = Parameters::parse($parameters);
} else {
$parameters = $parameters ?: array();
}
if ($this->defaults) {
$parameters += $this->defaults;
}
return new Parameters($parameters);
return Parameters::create($parameters);
}
/**
@@ -173,17 +136,13 @@ class Factory implements FactoryInterface
{
$parameters = $connection->getParameters();
if (isset($parameters->password) && strlen($parameters->password)) {
$cmdAuthArgs = isset($parameters->username) && strlen($parameters->username)
? array('AUTH', $parameters->username, $parameters->password)
: array('AUTH', $parameters->password);
if (isset($parameters->password)) {
$connection->addConnectCommand(
new RawCommand($cmdAuthArgs)
new RawCommand(array('AUTH', $parameters->password))
);
}
if (isset($parameters->database) && strlen($parameters->database)) {
if (isset($parameters->database)) {
$connection->addConnectCommand(
new RawCommand(array('SELECT', $parameters->database))
);
+5 -5
View File
@@ -26,6 +26,7 @@ class Parameters implements ParametersInterface
'scheme' => 'tcp',
'host' => '127.0.0.1',
'port' => 6379,
'timeout' => 5.0,
);
/**
@@ -73,7 +74,7 @@ class Parameters implements ParametersInterface
* "password" and "database" if they are present in the "query" part.
*
* @link http://www.iana.org/assignments/uri-schemes/prov/redis
* @link http://www.iana.org/assignments/uri-schemes/prov/rediss
* @link http://www.iana.org/assignments/uri-schemes/prov/redis
*
* @param string $uri URI string.
*
@@ -83,10 +84,9 @@ class Parameters implements ParametersInterface
*/
public static function parse($uri)
{
if (stripos($uri, 'unix://') === 0) {
// parse_url() can parse unix:/path/to/sock so we do not need the
// unix:///path/to/sock hack, we will support it anyway until 2.0.
$uri = str_ireplace('unix://', 'unix:', $uri);
if (stripos($uri, 'unix') === 0) {
// Hack to support URIs for UNIX sockets with minimal effort.
$uri = str_ireplace('unix:///', 'unix://localhost/', $uri);
}
if (!$parsed = parse_url($uri)) {
+11 -36
View File
@@ -14,7 +14,6 @@ namespace Predis\Connection;
use Predis\Command\CommandInterface;
use Predis\NotSupportedException;
use Predis\Response\Error as ErrorResponse;
use Predis\Response\ErrorInterface as ErrorResponseInterface;
use Predis\Response\Status as StatusResponse;
/**
@@ -37,7 +36,7 @@ use Predis\Response\Status as StatusResponse;
* - host: hostname or IP address of the server.
* - port: TCP port of the server.
* - path: path of a UNIX domain socket when scheme is 'unix'.
* - timeout: timeout to perform the connection (default is 5 seconds).
* - timeout: timeout to perform the connection.
* - read_write_timeout: timeout of read / write operations.
*
* @link http://github.com/nrk/phpiredis
@@ -94,15 +93,7 @@ class PhpiredisSocketConnection extends AbstractConnection
*/
protected function assertParameters(ParametersInterface $parameters)
{
switch ($parameters->scheme) {
case 'tcp':
case 'redis':
case 'unix':
break;
default:
throw new \InvalidArgumentException("Invalid scheme: '$parameters->scheme'.");
}
parent::assertParameters($parameters);
if (isset($parameters->persistent)) {
throw new NotSupportedException(
@@ -143,17 +134,11 @@ class PhpiredisSocketConnection extends AbstractConnection
*
* @return \Closure
*/
protected function getStatusHandler()
private function getStatusHandler()
{
static $statusHandler;
if (!$statusHandler) {
$statusHandler = function ($payload) {
return StatusResponse::get($payload);
};
}
return $statusHandler;
return function ($payload) {
return StatusResponse::get($payload);
};
}
/**
@@ -163,15 +148,9 @@ class PhpiredisSocketConnection extends AbstractConnection
*/
protected function getErrorHandler()
{
static $errorHandler;
if (!$errorHandler) {
$errorHandler = function ($errorMessage) {
return new ErrorResponse($errorMessage);
};
}
return $errorHandler;
return function ($payload) {
return new ErrorResponse($payload);
};
}
/**
@@ -303,7 +282,7 @@ class PhpiredisSocketConnection extends AbstractConnection
$null = null;
$selectable = array($socket);
$timeout = (isset($parameters->timeout) ? (float) $parameters->timeout : 5.0);
$timeout = (float) $parameters->timeout;
$timeoutSecs = floor($timeout);
$timeoutUSecs = ($timeout - $timeoutSecs) * 1000000;
@@ -329,11 +308,7 @@ class PhpiredisSocketConnection extends AbstractConnection
{
if (parent::connect() && $this->initCommands) {
foreach ($this->initCommands as $command) {
$response = $this->executeCommand($command);
if ($response instanceof ErrorResponseInterface) {
$this->onConnectionError("`{$command->getId()}` failed: $response", 0);
}
$this->executeCommand($command);
}
}
}
+19 -29
View File
@@ -87,20 +87,22 @@ class PhpiredisStreamConnection extends StreamConnection
/**
* {@inheritdoc}
*/
protected function assertSslSupport(ParametersInterface $parameters)
{
throw new \InvalidArgumentException('SSL encryption is not supported by this connection backend.');
}
/**
* {@inheritdoc}
*/
protected function createStreamSocket(ParametersInterface $parameters, $address, $flags, $context = null)
protected function tcpStreamInitializer(ParametersInterface $parameters)
{
$uri = "tcp://[{$parameters->host}]:{$parameters->port}";
$flags = STREAM_CLIENT_CONNECT;
$socket = null;
$timeout = (isset($parameters->timeout) ? (float) $parameters->timeout : 5.0);
$resource = @stream_socket_client($address, $errno, $errstr, $timeout, $flags);
if (isset($parameters->async_connect) && (bool) $parameters->async_connect) {
$flags |= STREAM_CLIENT_ASYNC_CONNECT;
}
if (isset($parameters->persistent) && (bool) $parameters->persistent) {
$flags |= STREAM_CLIENT_PERSISTENT;
$uri .= strpos($path = $parameters->path, '/') === 0 ? $path : "/$path";
}
$resource = @stream_socket_client($uri, $errno, $errstr, (float) $parameters->timeout, $flags);
if (!$resource) {
$this->onConnectionError(trim($errstr), $errno);
@@ -160,15 +162,9 @@ class PhpiredisStreamConnection extends StreamConnection
*/
protected function getStatusHandler()
{
static $statusHandler;
if (!$statusHandler) {
$statusHandler = function ($payload) {
return StatusResponse::get($payload);
};
}
return $statusHandler;
return function ($payload) {
return StatusResponse::get($payload);
};
}
/**
@@ -178,15 +174,9 @@ class PhpiredisStreamConnection extends StreamConnection
*/
protected function getErrorHandler()
{
static $errorHandler;
if (!$errorHandler) {
$errorHandler = function ($errorMessage) {
return new ErrorResponse($errorMessage);
};
}
return $errorHandler;
return function ($errorMessage) {
return new ErrorResponse($errorMessage);
};
}
/**
+38 -143
View File
@@ -13,23 +13,21 @@ namespace Predis\Connection;
use Predis\Command\CommandInterface;
use Predis\Response\Error as ErrorResponse;
use Predis\Response\ErrorInterface as ErrorResponseInterface;
use Predis\Response\Status as StatusResponse;
/**
* Standard connection to Redis servers implemented on top of PHP's streams.
* The connection parameters supported by this class are:.
*
* - scheme: it can be either 'redis', 'tcp', 'rediss', 'tls' or 'unix'.
* - scheme: it can be either 'redis', 'tcp' or 'unix'.
* - host: hostname or IP address of the server.
* - port: TCP port of the server.
* - path: path of a UNIX domain socket when scheme is 'unix'.
* - timeout: timeout to perform the connection (default is 5 seconds).
* - timeout: timeout to perform the connection.
* - read_write_timeout: timeout of read / write operations.
* - async_connect: performs the connection asynchronously.
* - tcp_nodelay: enables or disables Nagle's algorithm for coalescing.
* - persistent: the connection is left intact after a GC collection.
* - ssl: context options array (see http://php.net/manual/en/context.ssl.php)
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
@@ -49,46 +47,6 @@ class StreamConnection extends AbstractConnection
$this->disconnect();
}
/**
* {@inheritdoc}
*/
protected function assertParameters(ParametersInterface $parameters)
{
switch ($parameters->scheme) {
case 'tcp':
case 'redis':
case 'unix':
break;
case 'tls':
case 'rediss':
$this->assertSslSupport($parameters);
break;
default:
throw new \InvalidArgumentException("Invalid scheme: '$parameters->scheme'.");
}
return $parameters;
}
/**
* Checks needed conditions for SSL-encrypted connections.
*
* @param ParametersInterface $parameters Initialization parameters for the connection.
*
* @throws \InvalidArgumentException
*/
protected function assertSslSupport(ParametersInterface $parameters)
{
if (
filter_var($parameters->persistent, FILTER_VALIDATE_BOOLEAN) &&
version_compare(PHP_VERSION, '7.0.0beta') < 0
) {
throw new \InvalidArgumentException('Persistent SSL connections require PHP >= 7.0.0.');
}
}
/**
* {@inheritdoc}
*/
@@ -102,29 +60,40 @@ class StreamConnection extends AbstractConnection
case 'unix':
return $this->unixStreamInitializer($this->parameters);
case 'tls':
case 'rediss':
return $this->tlsStreamInitializer($this->parameters);
default:
throw new \InvalidArgumentException("Invalid scheme: '{$this->parameters->scheme}'.");
}
}
/**
* Creates a connected stream socket resource.
* Initializes a TCP stream resource.
*
* @param ParametersInterface $parameters Connection parameters.
* @param string $address Address for stream_socket_client().
* @param int $flags Flags for stream_socket_client().
* @param ParametersInterface $parameters Initialization parameters for the connection.
*
* @return resource
*/
protected function createStreamSocket(ParametersInterface $parameters, $address, $flags)
protected function tcpStreamInitializer(ParametersInterface $parameters)
{
$timeout = (isset($parameters->timeout) ? (float) $parameters->timeout : 5.0);
if (!filter_var($parameters->host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
$uri = "tcp://$parameters->host:$parameters->port";
} else {
$uri = "tcp://[$parameters->host]:$parameters->port";
}
if (!$resource = @stream_socket_client($address, $errno, $errstr, $timeout, $flags)) {
$flags = STREAM_CLIENT_CONNECT;
if (isset($parameters->async_connect) && (bool) $parameters->async_connect) {
$flags |= STREAM_CLIENT_ASYNC_CONNECT;
}
if (isset($parameters->persistent) && (bool) $parameters->persistent) {
$flags |= STREAM_CLIENT_PERSISTENT;
$uri .= strpos($path = $parameters->path, '/') === 0 ? $path : "/$path";
}
$resource = @stream_socket_client($uri, $errno, $errstr, (float) $parameters->timeout, $flags);
if (!$resource) {
$this->onConnectionError(trim($errstr), $errno);
}
@@ -144,42 +113,6 @@ class StreamConnection extends AbstractConnection
return $resource;
}
/**
* Initializes a TCP stream resource.
*
* @param ParametersInterface $parameters Initialization parameters for the connection.
*
* @return resource
*/
protected function tcpStreamInitializer(ParametersInterface $parameters)
{
if (!filter_var($parameters->host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
$address = "tcp://$parameters->host:$parameters->port";
} else {
$address = "tcp://[$parameters->host]:$parameters->port";
}
$flags = STREAM_CLIENT_CONNECT;
if (isset($parameters->async_connect) && $parameters->async_connect) {
$flags |= STREAM_CLIENT_ASYNC_CONNECT;
}
if (isset($parameters->persistent)) {
if (false !== $persistent = filter_var($parameters->persistent, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)) {
$flags |= STREAM_CLIENT_PERSISTENT;
if ($persistent === null) {
$address = "{$address}/{$parameters->persistent}";
}
}
}
$resource = $this->createStreamSocket($parameters, $address, $flags);
return $resource;
}
/**
* Initializes a UNIX stream resource.
*
@@ -193,58 +126,25 @@ class StreamConnection extends AbstractConnection
throw new \InvalidArgumentException('Missing UNIX domain socket path.');
}
$uri = "unix://{$parameters->path}";
$flags = STREAM_CLIENT_CONNECT;
if (isset($parameters->persistent)) {
if (false !== $persistent = filter_var($parameters->persistent, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)) {
$flags |= STREAM_CLIENT_PERSISTENT;
if ($persistent === null) {
throw new \InvalidArgumentException(
'Persistent connection IDs are not supported when using UNIX domain sockets.'
);
}
}
if ((bool) $parameters->persistent) {
$flags |= STREAM_CLIENT_PERSISTENT;
}
$resource = $this->createStreamSocket($parameters, "unix://{$parameters->path}", $flags);
$resource = @stream_socket_client($uri, $errno, $errstr, (float) $parameters->timeout, $flags);
return $resource;
}
/**
* Initializes a SSL-encrypted TCP stream resource.
*
* @param ParametersInterface $parameters Initialization parameters for the connection.
*
* @return resource
*/
protected function tlsStreamInitializer(ParametersInterface $parameters)
{
$resource = $this->tcpStreamInitializer($parameters);
$metadata = stream_get_meta_data($resource);
// Detect if crypto mode is already enabled for this stream (PHP >= 7.0.0).
if (isset($metadata['crypto'])) {
return $resource;
if (!$resource) {
$this->onConnectionError(trim($errstr), $errno);
}
if (is_array($parameters->ssl)) {
$options = $parameters->ssl;
} else {
$options = array();
}
if (!isset($options['crypto_type'])) {
$options['crypto_type'] = STREAM_CRYPTO_METHOD_TLS_CLIENT;
}
if (!stream_context_set_option($resource, array('ssl' => $options))) {
$this->onConnectionError('Error while setting SSL context options');
}
if (!stream_socket_enable_crypto($resource, true, $options['crypto_type'])) {
$this->onConnectionError('Error while switching to encrypted communication');
if (isset($parameters->read_write_timeout)) {
$rwtimeout = (float) $parameters->read_write_timeout;
$rwtimeout = $rwtimeout > 0 ? $rwtimeout : -1;
$timeoutSeconds = floor($rwtimeout);
$timeoutUSeconds = ($rwtimeout - $timeoutSeconds) * 1000000;
stream_set_timeout($resource, $timeoutSeconds, $timeoutUSeconds);
}
return $resource;
@@ -257,11 +157,7 @@ class StreamConnection extends AbstractConnection
{
if (parent::connect() && $this->initCommands) {
foreach ($this->initCommands as $command) {
$response = $this->executeCommand($command);
if ($response instanceof ErrorResponseInterface) {
$this->onConnectionError("`{$command->getId()}` failed: $response", 0);
}
$this->executeCommand($command);
}
}
}
@@ -360,8 +256,7 @@ class StreamConnection extends AbstractConnection
return $multibulk;
case ':':
$integer = (int) $payload;
return $integer == $payload ? $integer : $payload;
return (int) $payload;
case '-':
return new ErrorResponse($payload);
+8 -21
View File
@@ -33,7 +33,7 @@ use Predis\Response\Status as StatusResponse;
* - scheme: must be 'http'.
* - host: hostname or IP address of the server.
* - port: TCP port of the server.
* - timeout: timeout to perform the connection (default is 5 seconds).
* - timeout: timeout to perform the connection.
* - user: username for authentication.
* - pass: password for authentication.
*
@@ -117,7 +117,6 @@ class WebdisConnection implements NodeConnectionInterface
private function createCurl()
{
$parameters = $this->getParameters();
$timeout = (isset($parameters->timeout) ? (float) $parameters->timeout : 5.0) * 1000;
if (filter_var($host = $parameters->host, FILTER_VALIDATE_IP)) {
$host = "[$host]";
@@ -125,7 +124,7 @@ class WebdisConnection implements NodeConnectionInterface
$options = array(
CURLOPT_FAILONERROR => true,
CURLOPT_CONNECTTIMEOUT_MS => $timeout,
CURLOPT_CONNECTTIMEOUT_MS => $parameters->timeout * 1000,
CURLOPT_URL => "$parameters->scheme://$host:$parameters->port",
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_POST => true,
@@ -163,15 +162,9 @@ class WebdisConnection implements NodeConnectionInterface
*/
protected function getStatusHandler()
{
static $statusHandler;
if (!$statusHandler) {
$statusHandler = function ($payload) {
return StatusResponse::get($payload);
};
}
return $statusHandler;
return function ($payload) {
return StatusResponse::get($payload);
};
}
/**
@@ -181,15 +174,9 @@ class WebdisConnection implements NodeConnectionInterface
*/
protected function getErrorHandler()
{
static $errorHandler;
if (!$errorHandler) {
$errorHandler = function ($errorMessage) {
return new ErrorResponse($errorMessage);
};
}
return $errorHandler;
return function ($payload) {
return new ErrorResponse($payload);
};
}
/**
+1 -1
View File
@@ -29,7 +29,7 @@ final class Factory
'3.0' => 'Predis\Profile\RedisVersion300',
'3.2' => 'Predis\Profile\RedisVersion320',
'dev' => 'Predis\Profile\RedisUnstable',
'default' => 'Predis\Profile\RedisVersion320',
'default' => 'Predis\Profile\RedisVersion300',
);
/**
@@ -31,8 +31,7 @@ class IntegerResponse implements ResponseHandlerInterface
public function handle(CompositeConnectionInterface $connection, $payload)
{
if (is_numeric($payload)) {
$integer = (int) $payload;
return $integer == $payload ? $integer : $payload;
return (int) $payload;
}
if ($payload !== 'nil') {
+1 -2
View File
@@ -90,8 +90,7 @@ class ProtocolProcessor implements ProtocolProcessorInterface
return $multibulk;
case ':':
$integer = (int) $payload;
return $integer == $payload ? $integer : $payload;
return (int) $payload;
case '-':
return new ErrorResponse($payload);
@@ -1,23 +0,0 @@
<?php
/*
* This file is part of the Predis package.
*
* (c) Daniele Alessandri <suppakilla@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Predis\Replication;
use Predis\ClientException;
/**
* Exception class that identifies when master is missing in a replication setup.
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class MissingMasterException extends ClientException
{
}
+26
View File
@@ -89,6 +89,31 @@ class ReplicationStrategy
return isset($this->disallowed[$command->getId()]);
}
/**
* Checks if a SORT command is a readable operation by parsing the arguments
* array of the specified commad instance.
*
* @param CommandInterface $command Command instance.
*
* @return bool
*/
protected function isSortReadOnly(CommandInterface $command)
{
$arguments = $command->getArguments();
$argc = count($arguments);
if ($argc > 1) {
for ($i = 1; $i < $argc; ++$i) {
$argument = strtoupper($arguments[$i]);
if ($argument === 'STORE') {
return false;
}
}
}
return true;
}
/**
* Checks if BITFIELD performs a read-only operation by looking for certain
* SET and INCRYBY modifiers in the arguments array of the command.
@@ -267,6 +292,7 @@ class ReplicationStrategy
'BITPOS' => true,
'TIME' => true,
'PFCOUNT' => true,
'SORT' => array($this, 'isSortReadOnly'),
'BITFIELD' => array($this, 'isBitfieldReadOnly'),
'GEOHASH' => true,
'GEOPOS' => true,
-24
View File
@@ -1,24 +0,0 @@
<?php
/*
* This file is part of the Predis package.
*
* (c) Daniele Alessandri <suppakilla@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Predis\Replication;
use Predis\CommunicationException;
/**
* Exception class that identifies a role mismatch when connecting to node
* managed by redis-sentinel.
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class RoleException extends CommunicationException
{
}
@@ -48,26 +48,6 @@ abstract class PredisConnectionTestCase extends PredisTestCase
$this->assertInstanceOf('Predis\Connection\NodeConnectionInterface', $connection);
}
/**
* @group disconnected
*/
public function testSupportsSchemeTls()
{
$connection = $this->createConnectionWithParams(array('scheme' => 'tls'));
$this->assertInstanceOf('Predis\Connection\NodeConnectionInterface', $connection);
}
/**
* @group disconnected
*/
public function testSupportsSchemeRediss()
{
$connection = $this->createConnectionWithParams(array('scheme' => 'rediss'));
$this->assertInstanceOf('Predis\Connection\NodeConnectionInterface', $connection);
}
/**
* @group disconnected
*/
@@ -554,10 +534,6 @@ abstract class PredisConnectionTestCase extends PredisTestCase
*/
protected function assertPersistentConnection(NodeConnectionInterface $connection)
{
if (version_compare(PHP_VERSION, '5.4.0') < 0 || $this->isHHVM()) {
$this->markTestSkipped('This test does not currently work on HHVM.');
}
$this->assertSame('persistent stream', get_resource_type($connection->getResource()));
}
@@ -571,10 +547,6 @@ abstract class PredisConnectionTestCase extends PredisTestCase
*/
protected function assertNonPersistentConnection(NodeConnectionInterface $connection)
{
if (version_compare(PHP_VERSION, '5.4.0') < 0 || $this->isHHVM()) {
$this->markTestSkipped('This test does not currently work on HHVM.');
}
$this->assertSame('stream', get_resource_type($connection->getResource()));
}
-36
View File
@@ -31,16 +31,6 @@ abstract class PredisTestCase extends \PHPUnit_Framework_TestCase
usleep($seconds * 1000000);
}
/**
* Returns if the current runtime is HHVM.
*
* @return bool
*/
protected function isHHVM()
{
return defined('HHVM_VERSION');
}
/**
* Verifies that a Redis command is a valid Predis\Command\CommandInterface
* instance with the specified ID and command arguments.
@@ -203,32 +193,6 @@ abstract class PredisTestCase extends \PHPUnit_Framework_TestCase
return $client;
}
/**
* Returns a base mocked connection from Predis\Connection\NodeConnectionInterface.
*
* @param mixed $parameters Optional parameters.
*
* @return mixed
*/
protected function getMockConnection($parameters = null)
{
$connection = $this->getMock('Predis\Connection\NodeConnectionInterface');
if ($parameters) {
$parameters = Connection\Parameters::create($parameters);
$hash = "{$parameters->host}:{$parameters->port}";
$connection->expects($this->any())
->method('getParameters')
->will($this->returnValue($parameters));
$connection->expects($this->any())
->method('__toString')
->will($this->returnValue($hash));
}
return $connection;
}
/**
* Returns the server version of the Redis instance used by the test suite.
*
-51
View File
@@ -815,57 +815,6 @@ class ClientTest extends PredisTestCase
$this->assertTrue($client->executeCommand($command));
}
/**
* @group disconnected
*/
public function testGetIteratorWithTraversableConnections()
{
$connection1 = $this->getMockConnection('tcp://127.0.0.1:6381');
$connection2 = $this->getMockConnection('tcp://127.0.0.1:6382');
$connection3 = $this->getMockConnection('tcp://127.0.0.1:6383');
$aggregate = new \Predis\Connection\Aggregate\PredisCluster();
$aggregate->add($connection1);
$aggregate->add($connection2);
$aggregate->add($connection3);
$client = new Client($aggregate);
$iterator = $client->getIterator();
$this->assertInstanceOf('\Predis\Client', $nodeClient = $iterator->current());
$this->assertSame($connection1, $nodeClient->getConnection());
$this->assertSame('127.0.0.1:6381', $iterator->key());
$iterator->next();
$this->assertInstanceOf('\Predis\Client', $nodeClient = $iterator->current());
$this->assertSame($connection2, $nodeClient->getConnection());
$this->assertSame('127.0.0.1:6382', $iterator->key());
$iterator->next();
$this->assertInstanceOf('\Predis\Client', $nodeClient = $iterator->current());
$this->assertSame($connection3, $nodeClient->getConnection());
$this->assertSame('127.0.0.1:6383', $iterator->key());
}
/**
* @group disconnected
*/
public function testGetIteratorWithNonTraversableConnectionNoException()
{
$connection = $this->getMockConnection('tcp://127.0.0.1:6381');
$client = new Client($connection);
$iterator = $client->getIterator();
$this->assertInstanceOf('\Predis\Client', $nodeClient = $iterator->current());
$this->assertSame($connection, $nodeClient->getConnection());
$this->assertSame('127.0.0.1:6381', $iterator->key());
}
// ******************************************************************** //
// ---- HELPER METHODS ------------------------------------------------ //
// ******************************************************************** //
-50
View File
@@ -1,50 +0,0 @@
<?php
/*
* This file is part of the Predis package.
*
* (c) Daniele Alessandri <suppakilla@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Predis\Cluster\Hash;
use PredisTestCase;
/**
*
*/
class CRC16Test extends PredisTestCase
{
/**
* @group disconnected
*/
public function testHashGeneration()
{
$crc16 = new CRC16();
$this->assertSame(58359, $crc16->hash('key:000'));
$this->assertSame(62422, $crc16->hash('key:001'));
$this->assertSame(50101, $crc16->hash('key:002'));
$this->assertSame(54164, $crc16->hash('key:003'));
$this->assertSame(41843, $crc16->hash('key:004'));
$this->assertSame(45906, $crc16->hash('key:005'));
$this->assertSame(33585, $crc16->hash('key:006'));
$this->assertSame(37648, $crc16->hash('key:007'));
$this->assertSame(25343, $crc16->hash('key:008'));
$this->assertSame(29406, $crc16->hash('key:009'));
}
/**
* @group disconnected
*/
public function testHashGenerationWithIntegerValues()
{
$crc16 = new CRC16();
$this->assertSame(13907, $crc16->hash(0));
$this->assertSame(55177, $crc16->hash(1234));
}
}
@@ -57,8 +57,8 @@ class HashKeyTest extends PredisTestCase
}
/**
* @see https://github.com/predis/predis/pull/330
* @see https://github.com/predis/predis/issues/331
* @link https://github.com/nrk/predis/pull/330
* @link https://github.com/nrk/predis/issues/331
* @group disconnected
*/
public function testIterationWithIntegerFields()
@@ -57,7 +57,7 @@ class SortedSetKeyTest extends PredisTestCase
}
/**
* @see https://github.com/predis/predis/issues/216
* @link https://github.com/nrk/predis/issues/216
* @group disconnected
*/
public function testIterationWithIntegerMembers()
+3 -15
View File
@@ -65,19 +65,7 @@ class ConnectionSelectTest extends PredisCommandTestCase
$redis->set('foo', 'bar');
$this->assertEquals('OK', $redis->select(REDIS_SERVER_DBNUM - 1));
$this->assertSame(0, $redis->exists('foo'));
}
/**
* @group connected
* @expectedException \Predis\Response\ServerException
* @expectedExceptionMessageRegExp /ERR.*DB index/
*/
public function testThrowsExceptionOnUnexpectedDatabaseRange()
{
$redis = $this->getClient();
$redis->select(100000000);
$this->assertFalse($redis->exists('foo'));
}
/**
@@ -85,10 +73,10 @@ class ConnectionSelectTest extends PredisCommandTestCase
* @expectedException \Predis\Response\ServerException
* @expectedExceptionMessage ERR invalid DB index
*/
public function testThrowsExceptionOnUnexpectedDatabaseName()
public function testThrowsExceptionOnUnexpectedDatabase()
{
$redis = $this->getClient();
$redis->select('x');
$redis->select(100000000);
}
}
+5 -5
View File
@@ -54,8 +54,8 @@ class HashExistsTest extends PredisCommandTestCase
{
$command = $this->getCommand();
$this->assertSame(0, $command->parseResponse(0));
$this->assertSame(1, $command->parseResponse(1));
$this->assertFalse($command->parseResponse(0));
$this->assertTrue($command->parseResponse(1));
}
/**
@@ -67,9 +67,9 @@ class HashExistsTest extends PredisCommandTestCase
$redis->hmset('metavars', 'foo', 'bar', 'hoge', 'piyo');
$this->assertSame(1, $redis->hexists('metavars', 'foo'));
$this->assertSame(0, $redis->hexists('metavars', 'lol'));
$this->assertSame(0, $redis->hexists('unknown', 'foo'));
$this->assertTrue($redis->hexists('metavars', 'foo'));
$this->assertFalse($redis->hexists('metavars', 'lol'));
$this->assertFalse($redis->hexists('unknown', 'foo'));
}
/**
+5 -5
View File
@@ -54,8 +54,8 @@ class HashSetPreserveTest extends PredisCommandTestCase
{
$command = $this->getCommand();
$this->assertSame(0, $command->parseResponse(0));
$this->assertSame(1, $command->parseResponse(1));
$this->assertTrue($command->parseResponse(1));
$this->assertFalse($command->parseResponse(0));
}
/**
@@ -65,9 +65,9 @@ class HashSetPreserveTest extends PredisCommandTestCase
{
$redis = $this->getClient();
$this->assertSame(1, $redis->hsetnx('metavars', 'foo', 'bar'));
$this->assertSame(1, $redis->hsetnx('metavars', 'hoge', 'piyo'));
$this->assertSame(0, $redis->hsetnx('metavars', 'foo', 'barbar'));
$this->assertTrue($redis->hsetnx('metavars', 'foo', 'bar'));
$this->assertTrue($redis->hsetnx('metavars', 'hoge', 'piyo'));
$this->assertFalse($redis->hsetnx('metavars', 'foo', 'barbar'));
$this->assertSame(array('bar', 'piyo'), $redis->hmget('metavars', 'foo', 'hoge'));
}
+4 -4
View File
@@ -54,8 +54,8 @@ class HashSetTest extends PredisCommandTestCase
{
$command = $this->getCommand();
$this->assertSame(0, $command->parseResponse(0));
$this->assertSame(1, $command->parseResponse(1));
$this->assertTrue($command->parseResponse(1));
$this->assertFalse($command->parseResponse(0));
}
/**
@@ -65,8 +65,8 @@ class HashSetTest extends PredisCommandTestCase
{
$redis = $this->getClient();
$this->assertSame(1, $redis->hset('metavars', 'foo', 'bar'));
$this->assertSame(1, $redis->hset('metavars', 'hoge', 'piyo'));
$this->assertTrue($redis->hset('metavars', 'foo', 'bar'));
$this->assertTrue($redis->hset('metavars', 'hoge', 'piyo'));
$this->assertSame(array('bar', 'piyo'), $redis->hmget('metavars', 'foo', 'hoge'));
}
+2 -2
View File
@@ -70,8 +70,8 @@ class HyperLogLogAddTest extends PredisCommandTestCase
{
$command = $this->getCommand();
$this->assertSame(0, $command->parseResponse(0));
$this->assertSame(1, $command->parseResponse(1));
$this->assertSame(false, $command->parseResponse(0));
$this->assertSame(true, $command->parseResponse(1));
}
/**
+6 -44
View File
@@ -47,20 +47,6 @@ class KeyExistsTest extends PredisCommandTestCase
$this->assertSame($expected, $command->getArguments());
}
/**
* @group disconnected
*/
public function testFilterArgumentsMultipleKeys()
{
$arguments = array('key:1', 'key:2', 'key:3');
$expected = array('key:1', 'key:2', 'key:3');
$command = $this->getCommand();
$command->setArguments($arguments);
$this->assertSame($expected, $command->getArguments());
}
/**
* @group disconnected
*/
@@ -68,52 +54,28 @@ class KeyExistsTest extends PredisCommandTestCase
{
$command = $this->getCommand();
$this->assertSame(0, $command->parseResponse(0));
$this->assertSame(1, $command->parseResponse(1));
$this->assertSame(2, $command->parseResponse(2));
$this->assertTrue($command->parseResponse(1));
$this->assertFalse($command->parseResponse(0));
}
/**
* @group connected
*/
public function testReturnValueWhenKeyExists()
public function testReturnsTrueIfKeyExists()
{
$redis = $this->getClient();
$redis->set('foo', 'bar');
$this->assertSame(1, $redis->exists('foo'));
$this->assertTrue($redis->exists('foo'));
}
/**
* @group connected
*/
public function testReturnValueWhenKeyDoesNotExist()
public function testReturnsFalseIfKeyDoesNotExist()
{
$redis = $this->getClient();
$this->assertSame(0, $redis->exists('foo'));
}
/**
* @group connected
* @requiresRedisVersion >= 3.0.3
*/
public function testReturnValueWhenKeysExist()
{
$redis = $this->getClient();
$redis->mset('foo', 'bar', 'hoge', 'piyo');
$this->assertSame(2, $redis->exists('foo', 'hoge'));
}
/**
* @group connected
* @requiresRedisVersion >= 3.0.3
*/
public function testReturnValueWhenKeyDoNotExist()
{
$redis = $this->getClient();
$this->assertSame(0, $redis->exists('foo', 'bar'));
$this->assertFalse($redis->exists('foo'));
}
}
+8 -8
View File
@@ -54,18 +54,18 @@ class KeyExpireAtTest extends PredisCommandTestCase
{
$command = $this->getCommand();
$this->assertSame(0, $command->parseResponse(0));
$this->assertSame(1, $command->parseResponse(1));
$this->assertTrue($command->parseResponse(1));
$this->assertFalse($command->parseResponse(0));
}
/**
* @group connected
*/
public function testReturnsZeroOnNonExistingKeys()
public function testReturnsFalseOnNonExistingKeys()
{
$redis = $this->getClient();
$this->assertSame(0, $redis->expireat('foo', 2));
$this->assertFalse($redis->expireat('foo', 2));
}
/**
@@ -80,13 +80,13 @@ class KeyExpireAtTest extends PredisCommandTestCase
$now = time();
$this->assertEquals('OK', $redis->set('foo', 'bar'));
$this->assertSame(1, $redis->expireat('foo', $now + 1));
$this->assertTrue($redis->expireat('foo', $now + 1));
$this->assertThat($redis->ttl('foo'), $this->logicalAnd(
$this->greaterThanOrEqual(0), $this->lessThanOrEqual(1)
));
$this->sleep(2.0);
$this->assertSame(0, $redis->exists('foo'));
$this->assertFalse($redis->exists('foo'));
}
/**
@@ -99,7 +99,7 @@ class KeyExpireAtTest extends PredisCommandTestCase
$now = time();
$this->assertEquals('OK', $redis->set('foo', 'bar'));
$this->assertSame(1, $redis->expireat('foo', $now - 100));
$this->assertSame(0, $redis->exists('foo'));
$this->assertTrue($redis->expireat('foo', $now - 100));
$this->assertFalse($redis->exists('foo'));
}
}
+8 -8
View File
@@ -54,18 +54,18 @@ class KeyExpireTest extends PredisCommandTestCase
{
$command = $this->getCommand();
$this->assertSame(0, $command->parseResponse(0));
$this->assertSame(1, $command->parseResponse(1));
$this->assertTrue($command->parseResponse(1));
$this->assertFalse($command->parseResponse(0));
}
/**
* @group connected
*/
public function testReturnsZeroOnNonExistingKeys()
public function testReturnsFalseOnNonExistingKeys()
{
$redis = $this->getClient();
$this->assertSame(0, $redis->expire('foo', 2));
$this->assertFalse($redis->expire('foo', 2));
}
/**
@@ -79,11 +79,11 @@ class KeyExpireTest extends PredisCommandTestCase
$this->assertEquals('OK', $redis->set('foo', 'bar'));
$this->assertSame(1, $redis->expire('foo', 1));
$this->assertTrue($redis->expire('foo', 1));
$this->assertSame(1, $redis->ttl('foo'));
$this->sleep(2.0);
$this->assertSame(0, $redis->exists('foo'));
$this->assertFalse($redis->exists('foo'));
}
/**
@@ -95,7 +95,7 @@ class KeyExpireTest extends PredisCommandTestCase
$this->assertEquals('OK', $redis->set('foo', 'bar'));
$this->assertSame(1, $redis->expire('foo', -10));
$this->assertSame(0, $redis->exists('foo'));
$this->assertTrue($redis->expire('foo', -10));
$this->assertFalse($redis->exists('foo'));
}
}
+5 -5
View File
@@ -54,8 +54,8 @@ class KeyMoveTest extends PredisCommandTestCase
{
$command = $this->getCommand();
$this->assertSame(0, $command->parseResponse(0));
$this->assertSame(1, $command->parseResponse(1));
$this->assertTrue($command->parseResponse(1));
$this->assertFalse($command->parseResponse(0));
}
/**
@@ -70,11 +70,11 @@ class KeyMoveTest extends PredisCommandTestCase
$redis->set('foo', 'bar');
$this->assertSame(1, $redis->move('foo', $db));
$this->assertSame(0, $redis->exists('foo'));
$this->assertTrue($redis->move('foo', $db));
$this->assertFalse($redis->exists('foo'));
$redis->select($db);
$this->assertSame(1, $redis->exists('foo'));
$this->assertTrue($redis->exists('foo'));
$redis->del('foo');
}
+7 -7
View File
@@ -54,8 +54,8 @@ class KeyPersistTest extends PredisCommandTestCase
{
$command = $this->getCommand();
$this->assertSame(0, $command->parseResponse(0));
$this->assertSame(1, $command->parseResponse(1));
$this->assertTrue($command->parseResponse(1));
$this->assertFalse($command->parseResponse(0));
}
/**
@@ -68,29 +68,29 @@ class KeyPersistTest extends PredisCommandTestCase
$redis->set('foo', 'bar');
$redis->expire('foo', 10);
$this->assertSame(1, $redis->persist('foo'));
$this->assertTrue($redis->persist('foo'));
$this->assertSame(-1, $redis->ttl('foo'));
}
/**
* @group connected
*/
public function testReturnsZeroOnNonExpiringKeys()
public function testReturnsFalseOnNonExpiringKeys()
{
$redis = $this->getClient();
$redis->set('foo', 'bar');
$this->assertSame(0, $redis->persist('foo'));
$this->assertFalse($redis->persist('foo'));
}
/**
* @group connected
*/
public function testReturnsZeroOnNonExistentKeys()
public function testReturnsFalseOnNonExistentKeys()
{
$redis = $this->getClient();
$this->assertSame(0, $redis->persist('foo'));
$this->assertFalse($redis->persist('foo'));
}
}
@@ -54,8 +54,8 @@ class KeyPreciseExpireAtTest extends PredisCommandTestCase
{
$command = $this->getCommand();
$this->assertSame(0, $command->parseResponse(0));
$this->assertSame(1, $command->parseResponse(1));
$this->assertTrue($command->parseResponse(1));
$this->assertFalse($command->parseResponse(0));
}
/**
@@ -68,14 +68,13 @@ class KeyPreciseExpireAtTest extends PredisCommandTestCase
$ttl = 1.5;
$redis = $this->getClient();
$redis->set('foo', 'bar');
$this->assertEquals('OK', $redis->set('foo', 'bar'));
$this->assertSame(1, $redis->pexpireat('foo', time() + $ttl * 1000));
$this->assertTrue($redis->pexpireat('foo', time() + $ttl * 1000));
$this->assertLessThan($ttl * 1000, $redis->pttl('foo'));
$this->sleep($ttl + 0.5);
$this->assertSame(0, $redis->exists('foo'));
$this->assertFalse($redis->exists('foo'));
}
/**
@@ -85,9 +84,9 @@ class KeyPreciseExpireAtTest extends PredisCommandTestCase
{
$redis = $this->getClient();
$redis->set('foo', 'bar');
$this->assertEquals('OK', $redis->set('foo', 'bar'));
$this->assertSame(1, $redis->expireat('foo', time() - 100000));
$this->assertSame(0, $redis->exists('foo'));
$this->assertTrue($redis->expireat('foo', time() - 100000));
$this->assertFalse($redis->exists('foo'));
}
}
+21 -22
View File
@@ -54,18 +54,18 @@ class KeyPreciseExpireTest extends PredisCommandTestCase
{
$command = $this->getCommand();
$this->assertSame(0, $command->parseResponse(0));
$this->assertSame(1, $command->parseResponse(1));
$this->assertTrue($command->parseResponse(1));
$this->assertFalse($command->parseResponse(0));
}
/**
* @group connected
*/
public function testReturnsZeroOnNonExistingKeys()
public function testReturnsFalseOnNonExistingKeys()
{
$redis = $this->getClient();
$this->assertSame(0, $redis->pexpire('foo', 20000));
$this->assertFalse($redis->pexpire('foo', 20000));
}
/**
@@ -79,30 +79,29 @@ class KeyPreciseExpireTest extends PredisCommandTestCase
$redis = $this->getClient();
$this->assertEquals('OK', $redis->set('foo', 'bar'));
$this->assertSame(1, $redis->pexpire('foo', $ttl));
$this->assertTrue($redis->pexpire('foo', $ttl));
$this->sleep(1.2);
$this->assertSame(0, $redis->exists('foo'));
$this->assertFalse($redis->exists('foo'));
}
/**
* @medium
* @group connected
* @group slow
*/
public function testConsistencyWithTTL()
{
$ttl = 1000;
$redis = $this->getClient();
/**
* @group connected
* @group slow
*/
public function testConsistencyWithTTL()
{
$ttl = 1000;
$redis = $this->getClient();
$this->assertEquals('OK', $redis->set('foo', 'bar'));
$this->assertSame(1, $redis->pexpire('foo', $ttl));
$this->assertEquals('OK', $redis->set('foo', 'bar'));
$this->assertTrue($redis->pexpire('foo', $ttl));
$this->sleep(0.5);
$this->assertThat($redis->pttl('foo'), $this->logicalAnd(
$this->sleep(0.5);
$this->assertThat($redis->pttl('foo'), $this->logicalAnd(
$this->lessThanOrEqual($ttl), $this->greaterThan($ttl - 800)
));
}
}
/**
* @group connected
@@ -113,7 +112,7 @@ class KeyPreciseExpireTest extends PredisCommandTestCase
$this->assertEquals('OK', $redis->set('foo', 'bar'));
$this->assertSame(1, $redis->pexpire('foo', -10000));
$this->assertSame(0, $redis->exists('foo'));
$this->assertTrue($redis->pexpire('foo', -10000));
$this->assertFalse($redis->exists('foo'));
}
}
+1 -1
View File
@@ -63,7 +63,7 @@ class KeyRandomTest extends PredisCommandTestCase
/**
* @group connected
*/
public function testReturnsZeroOnNonExpiringKeys()
public function testReturnsFalseOnNonExpiringKeys()
{
$keys = array('key:1' => 1, 'key:2' => 2, 'key:3' => 3);
@@ -52,8 +52,8 @@ class KeyRenamePreserveTest extends PredisCommandTestCase
*/
public function testParseResponse()
{
$this->assertSame(0, $this->getCommand()->parseResponse(0));
$this->assertSame(1, $this->getCommand()->parseResponse(1));
$this->assertTrue($this->getCommand()->parseResponse(1));
$this->assertFalse($this->getCommand()->parseResponse(0));
}
/**
@@ -65,9 +65,9 @@ class KeyRenamePreserveTest extends PredisCommandTestCase
$redis->set('foo', 'bar');
$this->assertSame(1, $redis->renamenx('foo', 'foofoo'));
$this->assertSame(0, $redis->exists('foo'));
$this->assertSame(1, $redis->exists('foofoo'));
$this->assertTrue($redis->renamenx('foo', 'foofoo'));
$this->assertFalse($redis->exists('foo'));
$this->assertTrue($redis->exists('foofoo'));
}
/**
@@ -75,10 +75,10 @@ class KeyRenamePreserveTest extends PredisCommandTestCase
* @expectedException \Predis\Response\ServerException
* @expectedExceptionMessage ERR no such key
*/
public function testThrowsExceptionWhenRenamingNonExistingKeys()
public function testThrowsExceptionOnNonExistingKeys()
{
$redis = $this->getClient();
$this->assertSame(0, $redis->renamenx('foo', 'foobar'));
$this->assertFalse($redis->renamenx('foo', 'foobar'));
}
}
+2 -2
View File
@@ -65,8 +65,8 @@ class KeyRenameTest extends PredisCommandTestCase
$redis->set('foo', 'bar');
$this->assertEquals('OK', $redis->rename('foo', 'foofoo'));
$this->assertSame(0, $redis->exists('foo'));
$this->assertSame(1, $redis->exists('foofoo'));
$this->assertFalse($redis->exists('foo'));
$this->assertTrue($redis->exists('foofoo'));
}
/**
+1 -1
View File
@@ -77,7 +77,7 @@ class ListPushHeadXTest extends PredisCommandTestCase
$this->assertSame(0, $redis->lpushx('metavars', 'foo'));
$this->assertSame(0, $redis->lpushx('metavars', 'hoge'));
$this->assertSame(0, $redis->exists('metavars'));
$this->assertFalse($redis->exists('metavars'));
}
/**
+1 -1
View File
@@ -77,7 +77,7 @@ class ListPushTailXTest extends PredisCommandTestCase
$this->assertSame(0, $redis->rpushx('metavars', 'foo'));
$this->assertSame(0, $redis->rpushx('metavars', 'hoge'));
$this->assertSame(0, $redis->exists('metavars'));
$this->assertFalse($redis->exists('metavars'));
}
/**
@@ -145,7 +145,7 @@ class PubSubSubscribeByPatternTest extends PredisCommandTestCase
/**
* @group connected
* @expectedException \Predis\Response\ServerException
* @expectedExceptionMessageRegExp /ERR.*only .* allowed in this context/
* @expectedExceptionMessageRegExp /ERR only .* allowed in this context/
*/
public function testCannotSendOtherCommandsAfterPsubscribe()
{
+1 -1
View File
@@ -145,7 +145,7 @@ class PubSubSubscribeTest extends PredisCommandTestCase
/**
* @group connected
* @expectedException \Predis\Response\ServerException
* @expectedExceptionMessageRegExp /ERR.*only .* allowed in this context/
* @expectedExceptionMessageRegExp /ERR only .* allowed in this context/
*/
public function testCannotSendOtherCommandsAfterSubscribe()
{
+1 -20
View File
@@ -74,29 +74,10 @@ class RawCommandTest extends PredisTestCase
* argument is missing, PHP emits an E_WARNING.
*
* @group disconnected
* @expectedException \PHPUnit_Framework_Error_Warning
*/
public function testPHPWarningOnMissingCommandIDWithStaticCreate()
{
if (version_compare(PHP_VERSION, "7.1", '>')) {
$this->markTestSkipped('only for PHP < 7.1');
}
$this->setExpectedException('PHPUnit_Framework_Error_Warning');
RawCommand::create();
}
/**
* The signature of RawCommand::create() requires one argument which is the
* ID of the command (other arguments are fetched dinamically). If the first
* argument is missing, PHP 7.1 throw an exception
*
* @group disconnected
*/
public function testPHPWarningOnMissingCommandIDWithStaticCreate71()
{
if (version_compare(PHP_VERSION, "7.1", '<')) {
$this->markTestSkipped('only for PHP > 7.1');
}
$this->setExpectedException('ArgumentCountError');
RawCommand::create();
}
+2 -13
View File
@@ -102,24 +102,13 @@ class ServerCommandTest extends PredisCommandTestCase
{
$redis = $this->getClient();
$expected = array(array('get', 2, array('readonly', 'fast'), 1, 1, 1));
// NOTE: starting with Redis 6.0 and the introduction of Access Control
// Lists, COMMAND INFO returns an additional array for each specified
// command in yhe request with a list of the ACL categories associated
// to a command. We simply append this additional array in the expected
// response if the test suite is executed against Redis >= 6.0.
if ($this->isRedisServerVersion('>=', '6.0')) {
$expected[0][] = array('@read', '@string', '@fast');
}
$this->assertCount(1, $response = $redis->command('INFO', 'GET'));
// NOTE: we use assertEquals instead of assertSame because Redis returns
// flags as +STATUS responses, represented by Predis with instances of
// Predis\Response\Status instead of plain strings. This class responds
// to __toString() so the string conversion is implicit, but assertSame
// checks for strict equality while assertEquals is loose.
$expected = array(array('get', 2, array('readonly', 'fast'), 1, 1, 1));
$this->assertCount(1, $response = $redis->command('INFO', 'GET'));
$this->assertEquals($expected, $response);
}
@@ -62,6 +62,6 @@ class ServerFlushDatabaseTest extends PredisCommandTestCase
$redis->set('foo', 'bar');
$this->assertEquals('OK', $redis->flushdb());
$this->assertSame(0, $redis->exists('foo'));
$this->assertFalse($redis->exists('foo'));
}
}
@@ -92,7 +92,7 @@ class SetIntersectionStoreTest extends PredisCommandTestCase
$redis->sadd('letters:1st', 'a', 'b', 'c', 'd', 'e', 'f', 'g');
$this->assertSame(0, $redis->sinterstore('letters:destination', 'letters:1st', 'letters:2nd'));
$this->assertSame(0, $redis->exists('letters:destination'));
$this->assertFalse($redis->exists('letters:destination'));
}
/**
+6 -6
View File
@@ -54,8 +54,8 @@ class SetIsMemberTest extends PredisCommandTestCase
{
$command = $this->getCommand();
$this->assertSame(0, $command->parseResponse(0));
$this->assertSame(1, $command->parseResponse(1));
$this->assertTrue($command->parseResponse(1));
$this->assertFalse($command->parseResponse(0));
}
/**
@@ -67,18 +67,18 @@ class SetIsMemberTest extends PredisCommandTestCase
$redis->sadd('letters', 'a', 'b', 'c');
$this->assertSame(1, $redis->sismember('letters', 'a'));
$this->assertSame(0, $redis->sismember('letters', 'z'));
$this->assertTrue($redis->sismember('letters', 'a'));
$this->assertFalse($redis->sismember('letters', 'z'));
}
/**
* @group connected
*/
public function testReturnsZeroOnNonExistingSet()
public function testReturnsFalseOnNonExistingSet()
{
$redis = $this->getClient();
$this->assertSame(0, $redis->sismember('letters', 'a'));
$this->assertFalse($redis->sismember('letters', 'a'));
}
/**
+4 -4
View File
@@ -54,8 +54,8 @@ class SetMoveTest extends PredisCommandTestCase
{
$command = $this->getCommand();
$this->assertSame(0, $command->parseResponse(0));
$this->assertSame(1, $command->parseResponse(1));
$this->assertTrue($command->parseResponse(1));
$this->assertFalse($command->parseResponse(0));
}
/**
@@ -67,8 +67,8 @@ class SetMoveTest extends PredisCommandTestCase
$redis->sadd('letters:source', 'a', 'b', 'c');
$this->assertSame(1, $redis->smove('letters:source', 'letters:destination', 'b'));
$this->assertSame(0, $redis->smove('letters:source', 'letters:destination', 'z'));
$this->assertTrue($redis->smove('letters:source', 'letters:destination', 'b'));
$this->assertFalse($redis->smove('letters:source', 'letters:destination', 'z'));
$this->assertSameValues(array('a', 'c'), $redis->smembers('letters:source'));
$this->assertSameValues(array('b'), $redis->smembers('letters:destination'));
+2 -2
View File
@@ -75,7 +75,7 @@ class StringGetTest extends PredisCommandTestCase
$redis->set('foo', '');
$this->assertSame(1, $redis->exists('foo'));
$this->assertTrue($redis->exists('foo'));
$this->assertSame('', $redis->get('foo'));
}
@@ -86,7 +86,7 @@ class StringGetTest extends PredisCommandTestCase
{
$redis = $this->getClient();
$this->assertSame(0, $redis->exists('foo'));
$this->assertFalse($redis->exists('foo'));
$this->assertNull($redis->get('foo'));
}
@@ -76,7 +76,7 @@ class StringIncrementByFloatTest extends PredisCommandTestCase
$redis->set('foo', 2);
// We use round() to avoid errors on some platforms, see the following
// issue https://github.com/predis/predis/issues/220 for reference.
// issue https://github.com/nrk/predis/issues/220 for reference.
$this->assertEquals(22.123, $redis->incrbyfloat('foo', 20.123));
$this->assertEquals(10, round($redis->incrbyfloat('foo', -12.123), 5));
$this->assertEquals(-100.01, round($redis->incrbyfloat('foo', -110.01), 5));
@@ -63,8 +63,8 @@ class StringPreciseSetExpireTest extends PredisCommandTestCase
$redis = $this->getClient();
$this->assertEquals('OK', $redis->psetex('foo', 10000, 'bar'));
$this->assertSame(1, $redis->exists('foo'));
$this->assertSame(10, $redis->ttl('foo'));
$this->assertTrue($redis->exists('foo'));
$this->assertEquals(10, $redis->ttl('foo'));
}
/**
@@ -75,10 +75,9 @@ class StringPreciseSetExpireTest extends PredisCommandTestCase
{
$redis = $this->getClient();
$this->assertEquals('OK', $redis->psetex('foo', 50, 'bar'));
$redis->psetex('foo', 50, 'bar');
$this->sleep(0.5);
$this->assertSame(0, $redis->exists('foo'));
$this->assertFalse($redis->exists('foo'));
}
/**
+3 -2
View File
@@ -63,7 +63,8 @@ class StringSetExpireTest extends PredisCommandTestCase
$redis = $this->getClient();
$this->assertEquals('OK', $redis->setex('foo', 10, 'bar'));
$this->assertSame(1, $redis->exists('foo'));
$this->assertTrue($redis->exists('foo'));
$this->assertSame(10, $redis->ttl('foo'));
}
@@ -79,7 +80,7 @@ class StringSetExpireTest extends PredisCommandTestCase
$this->assertEquals('OK', $redis->setex('foo', 1, 'bar'));
$this->sleep(2.0);
$this->assertSame(0, $redis->exists('foo'));
$this->assertFalse($redis->exists('foo'));
}
/**
@@ -66,8 +66,7 @@ class StringSetMultiplePreserveTest extends PredisCommandTestCase
*/
public function testParseResponse()
{
$this->assertSame(0, $this->getCommand()->parseResponse(0));
$this->assertSame(1, $this->getCommand()->parseResponse(1));
$this->assertSame(true, $this->getCommand()->parseResponse(true));
}
/**
@@ -77,7 +76,7 @@ class StringSetMultiplePreserveTest extends PredisCommandTestCase
{
$redis = $this->getClient();
$this->assertSame(1, $redis->msetnx('foo', 'bar', 'hoge', 'piyo'));
$this->assertTrue($redis->msetnx('foo', 'bar', 'hoge', 'piyo'));
$this->assertSame('bar', $redis->get('foo'));
$this->assertSame('piyo', $redis->get('hoge'));
}
@@ -91,8 +90,8 @@ class StringSetMultiplePreserveTest extends PredisCommandTestCase
$redis->set('foo', 'bar');
$this->assertSame(0, $redis->msetnx('foo', 'barbar', 'hoge', 'piyo'));
$this->assertFalse($redis->msetnx('foo', 'barbar', 'hoge', 'piyo'));
$this->assertSame('bar', $redis->get('foo'));
$this->assertSame(0, $redis->exists('hoge'));
$this->assertFalse($redis->exists('hoge'));
}
}
@@ -52,8 +52,7 @@ class StringSetPreserveTest extends PredisCommandTestCase
*/
public function testParseResponse()
{
$this->assertSame(0, $this->getCommand()->parseResponse(0));
$this->assertSame(1, $this->getCommand()->parseResponse(1));
$this->assertTrue($this->getCommand()->parseResponse(1));
}
/**
@@ -63,8 +62,8 @@ class StringSetPreserveTest extends PredisCommandTestCase
{
$redis = $this->getClient();
$this->assertSame(1, $redis->setnx('foo', 'bar'));
$this->assertSame(0, $redis->setnx('foo', 'barbar'));
$this->assertTrue($redis->setnx('foo', 'bar'));
$this->assertFalse($redis->setnx('foo', 'barbar'));
$this->assertEquals('bar', $redis->get('foo'));
}
}

Some files were not shown because too many files have changed in this diff Show More