Skip to content

Commit 8dfb1c1

Browse files
committed
doc updates
1 parent c32e438 commit 8dfb1c1

File tree

2 files changed

+32
-116
lines changed

2 files changed

+32
-116
lines changed

ATOMICITY.rdoc

+3-95
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,6 @@
1-
= Redis Objects - Lightweight object layer around redis-rb you can also use in a model
1+
= An Atomic Rant
22

3-
Redis is great _not_ as a replacement for MySQL, but as a way to perform atomic
4-
operations on _individual_ data structures, like counters, lists, and sets. People
5-
that are wrapping ORM's around Redis are missing the point.
6-
7-
This gem, instead, provides atomic methods that you can use *with* your existing
8-
ActiveRecord/DataMapper/etc models, or in classes that have nothing to do with an
9-
ORM or even a database, but need support for high-performance atomic operations.
10-
11-
The only requirement Redis::Atoms has is that your class must provide an +id+ instance
12-
method which returns the ID for that instance. ActiveRecord, DataMapper, and MongoRecord
13-
all have id methods which are known to be suitable. Since +id+ can be anything as
14-
far as Redis::Atoms is concerned, you can even write an +id+ method of your own that
15-
just returns a string, or an MD5 of the name, or something else unique.
16-
17-
== Installation
18-
19-
gem install gemcutter
20-
gem tumble
21-
gem install redis-atoms
22-
23-
== Example
24-
25-
Somewhere in your app initialization
26-
27-
require 'redis'
28-
require 'redis/atoms'
29-
Redis::Atoms.redis = Redis.new(:host => 127.0.0.1, :port => 6379)
30-
31-
Model class:
32-
33-
class Team < ActiveRecord::Base
34-
include Redis::Atoms
35-
36-
counter :drafted_players
37-
counter :active_players
38-
lock :reorder, :timeout => 5 # seconds
39-
end
40-
41-
Using counters to handle concurrency:
42-
43-
@team = Team.find(1)
44-
if @team.drafted_players.increment <= @team.max_players
45-
# do stuff
46-
@team.team_players.create!(:player_id => 221)
47-
@team.active_players.increment
48-
else
49-
# reset counter state
50-
@team.drafted_players.decrement
51-
end
52-
53-
Atomic block - a cleaner way to do the above. Exceptions or nil results
54-
rewind counter back to previous state:
55-
56-
@team.drafted_players.increment do |val|
57-
raise Team::TeamFullError if val > @team.max_players
58-
@team.team_players.create!(:player_id => 221)
59-
@team.active_players.increment
60-
end
61-
62-
Similar approach, using an if block (failure rewinds counter):
63-
64-
@team.drafted_players.increment do |val|
65-
if val <= @team.max_players
66-
@team.team_players.create!(:player_id => 221)
67-
@team.active_players.increment
68-
end
69-
end
70-
71-
Class methods work too - notice we override ActiveRecord counters:
72-
73-
Team.increment_counter :drafted_players, team_id
74-
Team.decrement_counter :drafted_players, team_id, 2
75-
76-
Class-level atomic block (may save a DB fetch depending on your app):
77-
78-
Team.increment_counter(:drafted_players, team_id) do |val|
79-
TeamPitcher.create!(:team_id => team_id, :pitcher_id => 181)
80-
Team.increment_counter(:active_players, team_id)
81-
end
82-
83-
Locks with Redis. On completion or exception the lock is released:
84-
85-
@team.reorder_lock.lock do
86-
@team.reorder_all_players
87-
end
88-
89-
Class-level lock (same concept)
90-
91-
Team.obtain_lock(:reorder, team_id) do
92-
Team.reorder_all_players(team_id)
93-
end
94-
95-
== You Likely Have Some Huge Bugs
3+
== Brush Up Your Resume
964

975
You are probably not handling atomic operations properly in your app, and
986
probably have some nasty lurking race conditions. The worst part is these
@@ -243,4 +151,4 @@ phone call from your boss. (At least, not about this...)
243151
== Author
244152

245153
Copyright (c) 2009 {Nate Wiger}[http://nate.wiger.org]. All Rights Reserved.
246-
Released under the {Artistic License}[http://www.opensource.org/licenses/artistic-license-2.0.php].
154+
Rant released under {Creative Commons}[http://creativecommons.org/licenses/by/3.0/legalcode].

README.rdoc

+29-21
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
= Redis Objects - Lightweight object layer around redis-rb you can also use in a model
1+
= Redis Objects - Lightweight, atomic object layer around redis-rb
22

33
Redis is great _not_ as a replacement for MySQL, but as a way to perform atomic
44
operations on _individual_ data structures, like counters, lists, and sets. People
@@ -17,16 +17,16 @@ by using +new+ with the type of data structure you want to create.
1717
gem tumble
1818
gem install redis-objects
1919

20-
== Initialization
20+
=== Initialization
2121

2222
# If on Rails, config/initializers/redis.rb is a good place for this
2323
require 'redis'
2424
require 'redis/objects'
2525
Redis::Objects.redis = Redis.new(:host => 127.0.0.1, :port => 6379)
2626

27-
== Examples of Class Usage
27+
== Examples
2828

29-
Model class:
29+
=== Model Class Usage
3030

3131
class Team < ActiveRecord::Base
3232
include Redis::Objects
@@ -35,11 +35,34 @@ Model class:
3535
counter :active_players
3636
counter :total_online_players, :global => true
3737
list :player_stats
38-
set :
38+
set :outfielders
3939
lock :reorder, :timeout => 5 # seconds
4040
end
41+
42+
Familiar Ruby operations Just Work (TM):
4143

42-
Using counters to handle concurrency:
44+
=== Instance Usage
45+
46+
=== Counters
47+
48+
@counter = Redis::Counter.new('counter_name')
49+
@counter.increment
50+
puts @counter
51+
puts @counter.get # force re-fetch
52+
53+
=== Lists
54+
55+
@list = Redis::List.new('list_name')
56+
@list << 'a'
57+
@list << 'b'
58+
puts @list
59+
60+
== Atomicity
61+
62+
You are probably not handling atomicity correctly in your app. For a fun rant
63+
on the topic, see {ATOMICITY}[ATOMICITY.doc]
64+
65+
Atomic counters are a good way to handle concurrency:
4366

4467
@team = Team.find(1)
4568
if @team.drafted_players.increment <= @team.max_players
@@ -94,21 +117,6 @@ Class-level lock (same concept)
94117
Team.reorder_all_players(team_id)
95118
end
96119

97-
== Examples of Instance Usage
98-
99-
=== Counters
100-
101-
@counter = Redis::Counter.new('counter_name')
102-
@counter.increment
103-
puts @counter
104-
puts @counter.get # force re-fetch
105-
106-
=== Lists
107-
108-
@list = Redis::List.new('list_name')
109-
@list << 'a'
110-
@list << 'b'
111-
puts @list
112120

113121
== Author
114122

0 commit comments

Comments
 (0)