... and here finally comes Predis!

This commit is contained in:
Daniele Alessandri
2009-11-07 13:10:51 +01:00
commit 34a616cd95
10 changed files with 2695 additions and 0 deletions
+22
View File
@@ -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
View File
@@ -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).
+21
View File
@@ -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.
+39
View File
@@ -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
)
)
*/
?>
+30
View File
@@ -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
)
*/
?>
+7
View File
@@ -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;
?>
+17
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+124
View File
@@ -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