Skip to content

Commit

Permalink
reworking of redis article
Browse files Browse the repository at this point in the history
  • Loading branch information
2shortplanks committed Dec 20, 2015
1 parent a645671 commit 5779dca
Show file tree
Hide file tree
Showing 2 changed files with 217 additions and 24 deletions.
117 changes: 93 additions & 24 deletions 2015/articles/2015-12-20.pod
Expand Up @@ -2,48 +2,100 @@ Title: Perl and Redis
Topic: Redis::*
Author: Masayuki Matsuki <songmu@cpan.org>

Redis is high performance in memory Key Value store and known as data structure
server. It is very useful for not only caching but als susppo rstuss pmpaon yr
sdtautsas pm psaeotns yso, has affinity with our application codes. We can use
redis variables as "super global variables". It is very useful and powerful (and
dangerous :p).
=pod

Redis is high performance in memory key-value-store and data structure server.
It runs as a simple daemon alongside your Perl code that you can talk to over
the network sending data back and forward for it to persist between invocations
and between processes.

We find that it has affinity with the way we write our application code: We can
use Redis variables and data structures as I<super global variables> that are
not only accessible from everywhere in a Perl script but from every process on
every server in our infrastructure every time they run. It is very useful and
powerful (and dangerous :p).

These global variables have lots of use, from a simple shared cache, to things
like global work queues, process synchronization, or shared leader boards.

shell$ redis-cli ping
PONG
shell$ redis-cli set snowman frosty
OK
shell$ redis-cli get snowman
"frosty"
shell$ redis-cli lpush gifts gold
(integer) 1
shell$ redis-cli lpush gifts frankincense
(integer) 2
shell$ redis-cli lpush gifts myrrh
(integer) 3
shell$ redis-cli lpop gifts
"myrrh"
shell$ redis-cli lpop gifts
"frankincense"
shell$ redis-cli lpop gifts
"gold"
shell$ redis-cli lpop gifts
(nil)
shell$

L<< Redis's documentation| http://redis.io/documentation >> is very full and we
can try the commands in L<< interactive console|http://redis.io/commands>> on
web browser!
can try the commands in L<< interactive console|http://redis.io/commands>> in
a web browser!

I introduce the CPAN modules around redis.
Let's introduce the CPAN modules around Redis.

=head2 L<Redis::Fast>
=head2 L<Redis>

L<Redis::Fast> is a client module for Redis. It has Redis.pm compatible
interfaces using XS, so "Fast".
The original Redis module is an Perl interface to talk to a Redis server:

Redis.pm is pure perl implementation so, stable and easy to understand, but
little a bit slow, especially for caching.
#!perl
my $redis = Redis->new;
$redis->incr('blah');

In my work (online games, SNS and so on), Redis::Fast is also stable and very
fast, so you can use Redis::Fast instead of Redis.pm in relief.
Redis.pm is pure Perl implementation so, stable and easy to understand, but
little a bit slow, especially for caching where you don't want a lot of
overhead.

=head2 L<Redis::Fast>

L<Redis::Fast> is an alternative faster client module for Redis. It has
the same Redis.pm interfaces built using XS, so "Fast". You can use
Redis::Fast instead of Redis.pm without making an code changes other than
initially instantiating a different object.

#!perl
my $redis = Redis::Fast->new;
$redis->incr('blah');

In my work (online games, SNS and so on), Redis::Fast is also stable and very
fast.

=head2 L<Cache::Redis>

I want to use Redis as caching storage and I wrote L<Cache::Cache> compatible
interface client library for Redis.
L<Cache::Cache> is a standard caching interface while allows you to easily swap
out backend caching technologies - in memory stores, on disk files, memcache,
etc - without making changes to your code.

I wanted to use Redis as caching storage so I wrote L<Cache::Cache> compatible
interface client library for Redis called Cache::Redis:

#!perl
my $redis = Redis::Fast->new; # you can use Redis.pm too.
my $cache = Cache::Redis->new(redis => $redis);
$cache->set(blah => 1);
say $cache->get('blah'); # 1

By using Cache::Redis, we can easil
Redis also has an interface, L<CHI::Driver::Redis>, to the L<CHI> caching
framework.

=head2 L<Redis::LeaderBoard>

Redis not only allows you to store simple key/value pairs on the server, but
has a rich API that allows you to manipulate more complex data structures that
it can store.

Redis's "sorted set" is very useful for creating leaderboards but, which don't
return "unique" rank (cf. L<https://github.com/antirez/redis/issues/943>>). So I
wrote the ranking module using Redis which care "unique" rank.
Expand Down Expand Up @@ -76,18 +128,35 @@ I introduce a technique. That is "using epoch as score".

=head2 L<Redis::Namespace>

Generally, key management of the KVS is very difficult and confusing (easy to
conflict, typo and so on). KVS is very cool, but it is "super global variables
store" in almost, so we must appropriately manage them.
Generally, key management of a key-value-store is very difficult and confusing
(easy to conflict with existing keys used elsewhere in code or other
applications using the same Redis server, typo and so on). Key-value-store is
very cool, but with this "super global variables store" we must appropriately
manage the keys.

We can use Redis::Namespace for better key name managements.
We can use Redis::Namespace for better key name management.

#!perl
my $redis = Redis::Fast->new;
my $ns = Redis::Namespace->new(redis => $redis, namespace => 'ranking');
$ns->set(foo => 'bar'); # will call $redis->set('fugu:foo', 'bar');
my $foo = $ns->get('foo'); # will call $redis->get('fugu:foo');

The object of Redis::Namespace fill up the prefix namespace automatically.
The object of Redis::Namespace is to fill up the prefix namespace automatically.
I recommend the all Redis objects are wrapped by Redis::Namespace.

=head2 Conclusion

CPAN's Redis modules allow you to quickly, easily, and safely leverage the
power of Redis from Perl.

=head1 SEE ALSO

I recommend the all redis objects are wrapped by Redis::Namespace.
=for :list
* L<Redis>
* L<Redis::Fast>
* L<CHI::Driver::Redis> and L<CHI>
* L<Cache::Redis> an L<Cache::Cache>
* L<Redis::LeaderBoard>
* L<Redis::Namespace>
* L<< Redis's documentation| http://redis.io/documentation >>
124 changes: 124 additions & 0 deletions 2015/articles/2015-12-24.pod
@@ -0,0 +1,124 @@
Title: The Perl Powered Christmas Tree
Topic: Device::Chip::Adapter
Author: Olaf Alders <olaf@wundersolutions.com>

So, you want to run some Christmas tree lights. Not just any lights, but
flashy blinky ones. And while you're at it, give them some nice pretty
patterns using a few separate chains of lamps. Maybe Perl can help run
those patterns?

It's simple enough of course to define some blinky patterns, perhaps by
naming the light chains A to D, and using a sequence of strings to
define the patterns of which ones should be on or off:

#!perl
my @patterns = qw(
AB CD AB CD AB CD AC BD AC BD AC BD BC AD BC AD BC AD ...
);

We could then use this string of patterns to drive the lights in some
manner. For example, we could do something simple:

#!perl
use Time::HiRes 'sleep';

while(1) {
foreach my $pattern ( @patterns ) {
set_lights( $pattern );
sleep 0.5;
}
}

Here we've got a nice simple repeating pattern that just runs all day
long. But how might we implement this C<set_lights> function? We'll have
to actually communicate with the outside world somehow; some actual
piece of hardware.

Two specific pieces of hardware that could be useful here are the FTDI FT232H
(most conveniently on a breakout board, such as the
L<one made by Adafruit|https://www.adafruit.com/products/2264>) and the Bus
Pirate Made by
L<Dangerous Prototypes|http://dangerousprototypes.com/docs/Bus_Pirate>,
available from several places

These two devices are somewhat different in many respects, but both of
them may be described as a USB-attached board, which has several
digital logic IO pins on board. They each support a mode of operation
whereby several pins on the board (16 in the FTDI's case, 5 in the Bus
Pirate) can be controlled directly by the computer, setting them
directly high or low as required by the program.

The L<Device::Chip> module on CPAN describes an abstraction layer
around various mechanisms that might be employed to talk to real
hardware. It's still in its early phases yet, so it doesn't have too
many actual implementations, but it does support these two hardware
boards, exposing in each case an interface called a GPIO adapter (a
"General Purpose Input/Output" - the most basic form of digital IO pin control),
which allows us to directly control the high or low state of these pins.


Using this module, we can obtain a object that represents the GPIO
ability of the hardware, and use the C<write_gpios> method on it, to set
the state of each GPIO pin. As a little technicality, because the
Device::Chip distribution uses L<Future> to make it possible to use
asynchronously, we'll just have to call the C<get> method on the Future
returned by C<write_gpios> to actually force it to run. We'll also have
to make sure to use names of the GPIO pins that the particular device
will recognise.

#!perl
# Convert names of our strings of lights to GPIO pin names on
# the adapter
my %CHAIN_TO_GPIO = (
# If we're using the FT232H
A => "D0", B => "D1", C => "D2", D => "D3",

# If we're using the Bus Pirate
A => "MISO", B => "CS", C => "MOSI", D => "CLK",
);

sub set_lights
{
my ( $pattern ) = @_;

# $pattern says what light chains to turn on; we'll also\
# have to turn the others off

my %want_chains = map { $_ => 0 } qw( A B C D );
$want_chains{$_} = 1 for split //, $pattern;

# Now convert to the pin names required by Device::Chip
my %gpios = map { $CHAIN_TO_GPIO{$_} => $want_chains{$_} }
keys %want_chains;

$gpio->write_gpios( \%gpios )->get;
}

All we need now to make our program complete, is to initialise this
C<$gpio> object at the beginning, by opening the actual hardware object.
This too comes from Device::Chip, using the handy utility constructor
on the Device::Chip::Adapter class called C<new_from_description> to
first obtain an object representing the hardware adapter itself, and
then calling its C<make_protocol> method to switch it into GPIO mode and
obtain an object specifically representing that.

#!perl
use Device::Chip::Adapter;

my $adapter = Device::Chip::Adapter->new_from_description(
"FTDI", # Or BusPirate, or whatever...
);

my $gpio = $adapter->make_protocol( "GPIO" )->get;

=head2 The Hardware



=head1 SEE ALSO

=for :list
* L<Device::Chip>
* L<Device::Chip::Adapter>
* L<FT232H on AdaFruit|https://www.adafruit.com/products/2264>
* L<The Bus Pirate|http://dangerousprototypes.com/docs/Bus_Pirate>

0 comments on commit 5779dca

Please sign in to comment.