mirror of
https://github.com/predis/predis.git
synced 2026-08-20 04:11:51 +00:00
Compare commits
136 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9ead747663 | |||
| 39cf6abf82 | |||
| dbae384a64 | |||
| d9ea0ce14f | |||
| 55f940e400 | |||
| 648be824d3 | |||
| c4e0f2f037 | |||
| 62f5ce6baf | |||
| 9cd4ed9e1e | |||
| 8491b1d880 | |||
| 8c8261432f | |||
| 5eccd6ee3c | |||
| 3d9588ec1a | |||
| e96f7f748a | |||
| dd0edf761a | |||
| 8cbbd073cb | |||
| 1e521b56cd | |||
| fcacd65576 | |||
| d5488f81f7 | |||
| 188dc6bf62 | |||
| 0bd57ab744 | |||
| b996b005cf | |||
| 82116b0366 | |||
| 5c1ddc9cfa | |||
| ea2fd9700d | |||
| b2ec264ff9 | |||
| bf7a70d6f0 | |||
| 4ecc44e1ee | |||
| 52d5b23db7 | |||
| d31a4c71ba | |||
| c92e305852 | |||
| b075564278 | |||
| f9e817f14c | |||
| 9e568396c6 | |||
| 2a91ebaba9 | |||
| ce15bd22b9 | |||
| b0439e503e | |||
| ffc1c25baa | |||
| ac165194f5 | |||
| 18ae294864 | |||
| 47de667aea | |||
| 588940c5cb | |||
| a1fe4013e1 | |||
| 3328ad76be | |||
| 17b717a8f5 | |||
| 95dbc2bb34 | |||
| 9bb5a1c71f | |||
| 8eb4804a5c | |||
| 5d99914939 | |||
| c45bb15767 | |||
| e0329d6c74 | |||
| 2175d87a96 | |||
| ce85fdadd1 | |||
| b15c0a02de | |||
| d2fbcc6b8c | |||
| 6596460a57 | |||
| 9ab0e31a75 | |||
| 11adccdaeb | |||
| f465792b27 | |||
| 1399d3863c | |||
| 1f1c9cf1a4 | |||
| dae2df0ae9 | |||
| 9338eaf573 | |||
| f378faaf22 | |||
| 8b150fcbf5 | |||
| 84060b9034 | |||
| d4a7bd52be | |||
| 16a9d4e041 | |||
| 0b92e8d156 | |||
| 1f7b534072 | |||
| 0c0cbbafff | |||
| 8aec51b34f | |||
| eeb1e8b7a7 | |||
| c3a44b8e2e | |||
| 255beac137 | |||
| d473328a22 | |||
| 0d25e7b0bb | |||
| be3b84ca14 | |||
| 7d0597c62c | |||
| 833e46b79d | |||
| a22858438d | |||
| f221d0c81e | |||
| 0b5bfdfe33 | |||
| 3700d48771 | |||
| 653d3f08ab | |||
| 2d2de7837b | |||
| fc18e6456a | |||
| 6f2064ed90 | |||
| e2e645a8bd | |||
| 2219964b7e | |||
| 381e44b6e6 | |||
| 808693bfbd | |||
| 33eab38314 | |||
| 82e404660e | |||
| 6d60a42400 | |||
| 95624de5c4 | |||
| 2ee135099c | |||
| e26e3b423a | |||
| 946fac4454 | |||
| 4e976a3eb6 | |||
| baaf26fe5b | |||
| 6a0348fbea | |||
| 8365a6be77 | |||
| f028e428be | |||
| c13b82557d | |||
| 30d01c40d4 | |||
| 6459546e25 | |||
| dede828008 | |||
| 5c0716575e | |||
| 90bffb1a5a | |||
| 64ee96c312 | |||
| bff5a9729e | |||
| 5cd7b774c4 | |||
| 354d1ef921 | |||
| 9e3a8da94d | |||
| 35003713a2 | |||
| cd991e6370 | |||
| c59853afb8 | |||
| d4982b6c43 | |||
| 96f4af816d | |||
| 22ff3ff992 | |||
| 77b75e0738 | |||
| eeea28b275 | |||
| aa067d8fd9 | |||
| ce17c5383a | |||
| c4c36cae7a | |||
| 7a170b3d81 | |||
| 17e7bce22e | |||
| 7a5d6bac3e | |||
| 9d6c031ead | |||
| 692718afb4 | |||
| 0776377412 | |||
| e4b0512d42 | |||
| 75ca2f8111 | |||
| 37b1c88115 | |||
| a4e6130568 |
+2
-5
@@ -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
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
github: tillkruss
|
||||
custom: "https://www.paypal.me/tillkruss"
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -2,7 +2,6 @@
|
||||
*.phar
|
||||
.php-version
|
||||
.php_cs.cache
|
||||
.phpunit.result.cache
|
||||
phpunit.xml
|
||||
package.xml
|
||||
composer.lock
|
||||
|
||||
@@ -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')
|
||||
);
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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? ###
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+2
-2
@@ -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
@@ -59,7 +59,7 @@ spl_autoload_register(function (\$class) {
|
||||
}
|
||||
}
|
||||
});
|
||||
__halt_compiler();
|
||||
__HALT_COMPILER();
|
||||
EOSTUB;
|
||||
}
|
||||
|
||||
|
||||
+7
-34
@@ -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/"}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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]";
|
||||
|
||||
@@ -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
@@ -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',
|
||||
),
|
||||
);
|
||||
|
||||
@@ -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
@@ -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
@@ -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" />
|
||||
|
||||
@@ -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
@@ -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,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
@@ -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>
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,4 +25,12 @@ class HashExists extends Command
|
||||
{
|
||||
return 'HEXISTS';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parseResponse($data)
|
||||
{
|
||||
return (bool) $data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,4 +25,12 @@ class HashSet extends Command
|
||||
{
|
||||
return 'HSET';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parseResponse($data)
|
||||
{
|
||||
return (bool) $data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,4 +25,12 @@ class HashSetPreserve extends Command
|
||||
{
|
||||
return 'HSETNX';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parseResponse($data)
|
||||
{
|
||||
return (bool) $data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,4 +33,12 @@ class HyperLogLogAdd extends Command
|
||||
{
|
||||
return self::normalizeVariadic($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parseResponse($data)
|
||||
{
|
||||
return (bool) $data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,4 +25,12 @@ class KeyExists extends Command
|
||||
{
|
||||
return 'EXISTS';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parseResponse($data)
|
||||
{
|
||||
return (bool) $data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,4 +25,12 @@ class KeyExpire extends Command
|
||||
{
|
||||
return 'EXPIRE';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parseResponse($data)
|
||||
{
|
||||
return (bool) $data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,4 +25,12 @@ class KeyExpireAt extends Command
|
||||
{
|
||||
return 'EXPIREAT';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parseResponse($data)
|
||||
{
|
||||
return (bool) $data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,4 +25,12 @@ class KeyMove extends Command
|
||||
{
|
||||
return 'MOVE';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parseResponse($data)
|
||||
{
|
||||
return (bool) $data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,4 +25,12 @@ class KeyPersist extends Command
|
||||
{
|
||||
return 'PERSIST';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parseResponse($data)
|
||||
{
|
||||
return (bool) $data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,4 +25,12 @@ class KeyRenamePreserve extends KeyRename
|
||||
{
|
||||
return 'RENAMENX';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parseResponse($data)
|
||||
{
|
||||
return (bool) $data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,4 +25,12 @@ class SetIsMember extends Command
|
||||
{
|
||||
return 'SISMEMBER';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parseResponse($data)
|
||||
{
|
||||
return (bool) $data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
*/
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
);
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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') {
|
||||
|
||||
@@ -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
|
||||
{
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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 ------------------------------------------------ //
|
||||
// ******************************************************************** //
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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'));
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user