mirror of
https://github.com/predis/predis.git
synced 2026-08-30 20:21:31 +00:00
... and here finally comes Predis!
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
Copyright (c) 2009 Daniele Alessandri
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
# Predis #
|
||||
|
||||
## About ##
|
||||
|
||||
Predis is a flexible and feature-complete PHP client library for the Redis key-value
|
||||
database.
|
||||
|
||||
Predis is currently a work-in-progress and it targets PHP >= 5.3, though it is highly
|
||||
due to be backported to PHP >= 5.2.6 as soon as the public API and the internal design
|
||||
on the main branch will be considered stable enough.
|
||||
|
||||
Please refer to the TODO file to see which issues are still pending and what is due
|
||||
to be implemented soon in Predis.
|
||||
|
||||
|
||||
## Features ##
|
||||
|
||||
- Client-side sharding (support for consistent hashing of keys)
|
||||
- Command pipelining on single and multiple connections (transparent)
|
||||
- Lazy connections (connections to Redis instances are only established just in time)
|
||||
- Flexible system to define and register your own set of commands to a client instance
|
||||
|
||||
|
||||
## Quick examples ##
|
||||
|
||||
### Connecting to a local instance of Redis ###
|
||||
|
||||
|
||||
$redis = new Predis\Client();
|
||||
$redis->set('library', 'predis');
|
||||
$value = $redis->get('library');
|
||||
|
||||
|
||||
### Pipelining multiple commands to a remote instance of Redis ##
|
||||
|
||||
|
||||
$redis = new Predis\Client('10.0.0.1', 6379);
|
||||
$replies = $redis->pipeline(function($pipe) {
|
||||
$pipe->ping();
|
||||
$pipe->incrby('counter', 10);
|
||||
$pipe->incrby('counter', 30);
|
||||
$pipe->get('counter');
|
||||
});
|
||||
|
||||
|
||||
### Pipelining multiple commands to multiple instances of Redis (sharding) ##
|
||||
|
||||
|
||||
$redis = Predis\Client::createCluster(
|
||||
array('host' => '10.0.0.1', 'port' => 6379),
|
||||
array('host' => '10.0.0.2', 'port' => 6379)
|
||||
);
|
||||
|
||||
$replies = $redis->pipeline(function($pipe) {
|
||||
for ($i = 0; $i < 1000; $i++) {
|
||||
$pipe->set("key:$i", str_pad($i, 4, '0', 0));
|
||||
$pipe->get("key:$i");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
### Definition and runtime registration of new commands on the client ###
|
||||
|
||||
|
||||
class BrandNewRedisCommand extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'NEWCMD'; }
|
||||
}
|
||||
|
||||
$redis = new Predis\Client();
|
||||
$redis->registerCommand('BrandNewRedisCommand', 'newcmd');
|
||||
$redis->newcmd();
|
||||
|
||||
|
||||
## Development ##
|
||||
|
||||
Predis is fully backed up by a test suite which tries to cover all the aspects of the
|
||||
client library and the interaction of every single command with a Redis server. If you
|
||||
want to work on Predis, it is highly recommended that you first run the test suite to
|
||||
be sure that everything is OK, and report strange behaviours or bugs.
|
||||
|
||||
The recommended way to contribute to Predis is to fork the project on GitHub, fix or
|
||||
add features on your newly created repository and then submit issues on the Predis
|
||||
issue tracker with a link to your repository. Obviously, you can use any other Git
|
||||
hosting provider of you preference. Diff patches will be accepted too, even though
|
||||
they are not the preferred way to contribute to Predis.
|
||||
|
||||
When modifying Predis plrease be sure that no warning or notices are emitted by PHP by
|
||||
running the interpreter in your development environment with the "error_reporting"
|
||||
variable set to E_ALL.
|
||||
|
||||
|
||||
## Dependencies ##
|
||||
|
||||
- PHP >= 5.3
|
||||
- PHPUnit (needed to run the test suite)
|
||||
|
||||
## Links ##
|
||||
|
||||
### Project ###
|
||||
[Source code](https://github.com/nrk/predis/)
|
||||
[Issue tracker](http://github.com/nrk/predis/issues)
|
||||
|
||||
### Related ###
|
||||
[Redis](http://code.google.com/p/redis/)
|
||||
[PHP](http://php.net/)
|
||||
[PHPUnit](http://www.phpunit.de/)
|
||||
[Git](http://git-scm.com/)
|
||||
|
||||
## Author ##
|
||||
|
||||
[Daniele Alessandri](mailto://suppakilla@gmail.com)
|
||||
|
||||
|
||||
## License ##
|
||||
|
||||
The code for Predis is distributed under the terms of the MIT license (see LICENSE).
|
||||
@@ -0,0 +1,21 @@
|
||||
* Authentication and database selection should be handled transparently by
|
||||
the client.
|
||||
|
||||
* The current behaviour of sending, by default, unshardable commands to the
|
||||
first registered connection of a ConnectionCluster instance needs to be
|
||||
verified.
|
||||
|
||||
* The included test suite covers almost all the Redis server commands, but a
|
||||
full battery of tests targeting specific functions of this library is still
|
||||
missing.
|
||||
|
||||
* Support for pipelining commands on one or more connections works, but it
|
||||
could be optimized for better performances with a cache of computed commands
|
||||
hashes, but the memory impact still needs to be evalued.
|
||||
|
||||
* Add the possibility of flushing the command buffer from inside of a pipeline.
|
||||
|
||||
* Switching to/from instances of Connection and ConnectionCluster should be
|
||||
transparent to the user. Using a ConnectionCluster instance when there is
|
||||
only one active connection has an unnecessary overhead.
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
require_once 'SharedConfigurations.php';
|
||||
|
||||
// when you have a whole set of consecutive commands to send to
|
||||
// a redis server, you can use a pipeline to improve performances.
|
||||
|
||||
$redis = new Predis\Client(REDIS_HOST, REDIS_PORT);
|
||||
$redis->select(REDIS_DB);
|
||||
|
||||
$replies = $redis->pipeline(function($pipe) {
|
||||
$pipe->ping();
|
||||
$pipe->flushdb();
|
||||
$pipe->incrby('counter', 10);
|
||||
$pipe->incrby('counter', 30);
|
||||
$pipe->exists('counter');
|
||||
$pipe->get('counter');
|
||||
$pipe->mget('does_not_exist', 'counter');
|
||||
});
|
||||
|
||||
print_r($replies);
|
||||
|
||||
/* OUTPUT:
|
||||
Array
|
||||
(
|
||||
[0] => 1
|
||||
[1] => 1
|
||||
[2] => 10
|
||||
[3] => 40
|
||||
[4] => 1
|
||||
[5] => 40
|
||||
[6] => Array
|
||||
(
|
||||
[0] =>
|
||||
[1] => 40
|
||||
)
|
||||
|
||||
)
|
||||
*/
|
||||
?>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
require_once 'SharedConfigurations.php';
|
||||
|
||||
// redis can set keys and their relative values in one go
|
||||
// using MSET, then the same values can be retrieved with
|
||||
// a single command using MGET.
|
||||
|
||||
$mkv = array(
|
||||
'usr:0001' => 'First user',
|
||||
'usr:0002' => 'Second user',
|
||||
'usr:0003' => 'Third user'
|
||||
);
|
||||
|
||||
$redis = new Predis\Client(REDIS_HOST, REDIS_PORT);
|
||||
$redis->select(REDIS_DB);
|
||||
|
||||
$redis->mset($mkv);
|
||||
$retval = $redis->mget(array_keys($mkv));
|
||||
|
||||
print_r($retval);
|
||||
|
||||
/* OUTPUT:
|
||||
Array
|
||||
(
|
||||
[0] => First user
|
||||
[1] => Second user
|
||||
[2] => Third user
|
||||
)
|
||||
*/
|
||||
?>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
require_once '../lib/Predis.php';
|
||||
|
||||
const REDIS_HOST = '192.168.1.205';
|
||||
const REDIS_PORT = 6379;
|
||||
const REDIS_DB = 15;
|
||||
?>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
require_once 'SharedConfigurations.php';
|
||||
|
||||
// simple set and get scenario
|
||||
|
||||
$redis = new Predis\Client(REDIS_HOST, REDIS_PORT);
|
||||
$redis->select(REDIS_DB);
|
||||
|
||||
$redis->set('library', 'predis');
|
||||
$retval = $redis->get('library');
|
||||
|
||||
print_r($retval);
|
||||
|
||||
/* OUTPUT
|
||||
predis
|
||||
*/
|
||||
?>
|
||||
+1106
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
require_once '../lib/Predis.php';
|
||||
|
||||
if (I_AM_AWARE_OF_THE_DESTRUCTIVE_POWER_OF_THIS_TEST_SUITE !== true) {
|
||||
exit('Please set the I_AM_AWARE_OF_THE_DESTRUCTIVE_POWER_OF_THIS_TEST_SUITE constant to TRUE if you want to proceed.');
|
||||
}
|
||||
|
||||
if (!function_exists('array_union')) {
|
||||
function array_union(Array $a, Array $b) {
|
||||
return array_merge($a, array_diff($b, $a));
|
||||
}
|
||||
}
|
||||
|
||||
class RC {
|
||||
const SERVER_HOST = '127.0.0.1';
|
||||
const SERVER_PORT = 6379;
|
||||
const DEFAULT_DATABASE = 15;
|
||||
|
||||
const WIPE_OUT = 1;
|
||||
const EXCEPTION_WRONG_TYPE = 'Operation against a key holding the wrong kind of value';
|
||||
const EXCEPTION_NO_SUCH_KEY = 'no such key';
|
||||
const EXCEPTION_OUT_OF_RANGE = 'index out of range';
|
||||
const EXCEPTION_INVALID_DB_IDX = 'invalid DB index';
|
||||
|
||||
private static $_connection;
|
||||
|
||||
private static function createConnection() {
|
||||
$connection = new Predis\Client(RC::SERVER_HOST, RC::SERVER_PORT);
|
||||
$connection->connect();
|
||||
$connection->selectDatabase(RC::DEFAULT_DATABASE);
|
||||
return $connection;
|
||||
}
|
||||
|
||||
public static function getConnection() {
|
||||
if (self::$_connection === null || !self::$_connection->isConnected()) {
|
||||
self::$_connection = self::createConnection();
|
||||
}
|
||||
return self::$_connection;
|
||||
}
|
||||
|
||||
public static function resetConnection() {
|
||||
if (self::$_connection !== null && self::$_connection->isConnected()) {
|
||||
self::$_connection->disconnect();
|
||||
self::$_connection = self::createConnection();
|
||||
}
|
||||
}
|
||||
|
||||
public static function getArrayOfNumbers() {
|
||||
return array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
|
||||
}
|
||||
|
||||
public static function getKeyValueArray() {
|
||||
return array(
|
||||
'foo' => 'bar',
|
||||
'hoge' => 'piyo',
|
||||
'foofoo' => 'barbar',
|
||||
);
|
||||
}
|
||||
|
||||
public static function getNamespacedKeyValueArray() {
|
||||
return array(
|
||||
'metavar:foo' => 'bar',
|
||||
'metavar:hoge' => 'piyo',
|
||||
'metavar:foofoo' => 'barbar',
|
||||
);
|
||||
}
|
||||
|
||||
public static function getZSetArray() {
|
||||
return array(
|
||||
'a' => -10, 'b' => 0, 'c' => 10, 'd' => 20, 'e' => 20, 'f' => 30
|
||||
);
|
||||
}
|
||||
|
||||
public static function sameValuesInArrays($arrayA, $arrayB) {
|
||||
if (count($arrayA) != count($arrayB)) {
|
||||
return false;
|
||||
}
|
||||
return count(array_diff($arrayA, $arrayB)) == 0;
|
||||
}
|
||||
|
||||
public static function testForServerException($testcaseInstance, $expectedMessage, $wrapFunction) {
|
||||
$thrownException = null;
|
||||
try {
|
||||
$wrapFunction($testcaseInstance);
|
||||
}
|
||||
catch (Predis\ServerException $exception) {
|
||||
$thrownException = $exception;
|
||||
}
|
||||
$testcaseInstance->assertType('Predis\ServerException', $thrownException);
|
||||
$testcaseInstance->assertEquals($expectedMessage, $thrownException->getMessage());
|
||||
}
|
||||
|
||||
public static function pushTailAndReturn(Predis\Client $client, $keyName, Array $values, $wipeOut = 0) {
|
||||
if ($wipeOut == true) {
|
||||
$client->delete($keyName);
|
||||
}
|
||||
foreach ($values as $value) {
|
||||
$client->pushTail($keyName, $value);
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
public static function setAddAndReturn(Predis\Client $client, $keyName, Array $values, $wipeOut = 0) {
|
||||
if ($wipeOut == true) {
|
||||
$client->delete($keyName);
|
||||
}
|
||||
foreach ($values as $value) {
|
||||
$client->setAdd($keyName, $value);
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
public static function zsetAddAndReturn(Predis\Client $client, $keyName, Array $values, $wipeOut = 0) {
|
||||
// $values: array(SCORE => VALUE, ...);
|
||||
if ($wipeOut == true) {
|
||||
$client->delete($keyName);
|
||||
}
|
||||
foreach ($values as $value => $score) {
|
||||
$client->zsetAdd($keyName, $score, $value);
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
}
|
||||
?>
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user