Class: Frivol::Backend::Multi

Inherits:
Object
  • Object
show all
Defined in:
lib/frivol/backend/multi.rb

Overview

Configuration

This backend is used to migrate from one backend to another (and another) (and another). Essentially, this backend will check for the existence of the key in the newest backend, and if not found check in the older backends in order. If it’s found in an older backend it will move the value to the new backend.

I have used this in production to move from Redis to RedisDistributed.

old_backend = Frivol::Backend::Redis.new(:db => 10)
new_backend = Frivol::Backend::RedisDistributed.new(["redis://127.0.0.1:6379/11", "redis://127.0.0.1:6379/12"])
Frivol::Config.backend = Frivol::Backend::Multi.new([ new_backend, old_backend ])

Constant Summary collapse

BackendsNotUniqueError =

:nodoc:

Class.new(StandardError)

Instance Method Summary collapse

Constructor Details

#initialize(backends) ⇒ Multi

Returns a new instance of Multi.



17
18
19
20
21
22
23
# File 'lib/frivol/backend/multi.rb', line 17

def initialize(backends)
  unless backends.map(&:inspect).uniq.size == backends.size
    raise BackendsNotUniqueError, "Backends are not unique: #{backends.map(&:inspect).join(', ')}"
  end
  @primary_backend = backends.shift
  @other_backends = backends
end

Instance Method Details

#connectionObject



125
126
127
# File 'lib/frivol/backend/multi.rb', line 125

def connection
  @primary_backend.connection
end

#decr(key, expiry = Frivol::NEVER_EXPIRE) ⇒ Object



77
78
79
80
81
82
83
# File 'lib/frivol/backend/multi.rb', line 77

def decr(key, expiry = Frivol::NEVER_EXPIRE)
  if @primary_backend.existsc(key)
    @primary_backend.decr(key)
  else
    migratec(key, :decrby, 1, expiry)
  end
end

#decrby(key, amt, expiry = Frivol::NEVER_EXPIRE) ⇒ Object



93
94
95
96
97
98
99
# File 'lib/frivol/backend/multi.rb', line 93

def decrby(key, amt, expiry = Frivol::NEVER_EXPIRE)
  if @primary_backend.existsc(key)
    @primary_backend.decrby(key, amt)
  else
    migratec(key, :decrby, amt, expiry)
  end
end

#del(key) ⇒ Object



37
38
39
40
# File 'lib/frivol/backend/multi.rb', line 37

def del(key)
  @primary_backend.del(key)
  @other_backends.each { |be| be.del(key) }
end

#delc(key) ⇒ Object



59
60
61
62
# File 'lib/frivol/backend/multi.rb', line 59

def delc(key)
  @primary_backend.delc(key)
  @other_backends.each { |be| be.delc(key) }
end

#exists(key) ⇒ Object



42
43
44
45
# File 'lib/frivol/backend/multi.rb', line 42

def exists(key)
  @primary_backend.exists(key) ||
    @other_backends.detect { |be| be.exists(key) }
end

#existsc(key) ⇒ Object



64
65
66
67
# File 'lib/frivol/backend/multi.rb', line 64

def existsc(key)
  @primary_backend.existsc(key) ||
    @other_backends.detect { |be| be.existsc(key) }
end

#expire(key, ttl) ⇒ Object

Expiry/TTL



102
103
104
# File 'lib/frivol/backend/multi.rb', line 102

def expire(key, ttl)
  @primary_backend.expire(key, ttl)
end

#flushdbObject

Connection



120
121
122
123
# File 'lib/frivol/backend/multi.rb', line 120

def flushdb
  @primary_backend.flushdb
  @other_backends.each { |be| be.flushdb }
end

#get(key, expiry = Frivol::NEVER_EXPIRE) ⇒ Object

Hashes



26
27
28
29
30
# File 'lib/frivol/backend/multi.rb', line 26

def get(key, expiry = Frivol::NEVER_EXPIRE)
  val = @primary_backend.get(key)
  val = migrate(key, expiry) if val.nil?
  val
end

#getc(key, expiry = Frivol::NEVER_EXPIRE) ⇒ Object

Counters



48
49
50
51
52
# File 'lib/frivol/backend/multi.rb', line 48

def getc(key, expiry = Frivol::NEVER_EXPIRE)
  val = @primary_backend.getc(key)
  val = migratec(key, :getc, 0, expiry) if val.nil?
  val
end

#incr(key, expiry = Frivol::NEVER_EXPIRE) ⇒ Object



69
70
71
72
73
74
75
# File 'lib/frivol/backend/multi.rb', line 69

def incr(key, expiry = Frivol::NEVER_EXPIRE)
  if @primary_backend.existsc(key)
    @primary_backend.incr(key)
  else
    migratec(key, :incrby, 1, expiry)
  end
end

#incrby(key, amt, expiry = Frivol::NEVER_EXPIRE) ⇒ Object



85
86
87
88
89
90
91
# File 'lib/frivol/backend/multi.rb', line 85

def incrby(key, amt, expiry = Frivol::NEVER_EXPIRE)
  if @primary_backend.existsc(key)
    @primary_backend.incrby(key, amt)
  else
    migratec(key, :incrby, amt, expiry)
  end
end

#migrate(key, expiry = Frivol::NEVER_EXPIRE) ⇒ Object

Migration



130
131
132
133
134
135
136
137
138
139
# File 'lib/frivol/backend/multi.rb', line 130

def migrate(key, expiry = Frivol::NEVER_EXPIRE)
  backend = @other_backends.detect { |be| be.exists(key) }
  if backend
    val = backend.get(key)
    ttl = backend.ttl(key)
    @primary_backend.set(key, val, ttl)
    @other_backends.each { |be| be.del key }
    val
  end
end

#migratec(key, method = :incrby, amt = 0, expiry = Frivol::NEVER_EXPIRE) ⇒ Object



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/frivol/backend/multi.rb', line 141

def migratec(key, method = :incrby, amt = 0, expiry = Frivol::NEVER_EXPIRE)
  backend = @other_backends.detect { |be| be.existsc(key) }
  if backend
    val = backend.getc(key).to_i
    ttl = backend.ttl(key)
    @primary_backend.incrby(key, val) unless val.zero?
    val = @primary_backend.send(method, key, amt) unless amt.zero? || method == :getc
    @primary_backend.expire(key, ttl) if ttl
    @other_backends.each { |be| be.delc key }
    val
  elsif method != :getc
    @primary_backend.send(method, key, amt, expiry)
  else
    nil
  end
end

#set(key, val, expiry = Frivol::NEVER_EXPIRE) ⇒ Object



32
33
34
35
# File 'lib/frivol/backend/multi.rb', line 32

def set(key, val, expiry = Frivol::NEVER_EXPIRE)
  @other_backends.each { |be| be.del(key) }
  @primary_backend.set(key, val, expiry)
end

#setc(key, val, expiry = Frivol::NEVER_EXPIRE) ⇒ Object



54
55
56
57
# File 'lib/frivol/backend/multi.rb', line 54

def setc(key, val, expiry = Frivol::NEVER_EXPIRE)
  @other_backends.each { |be| be.delc(key) }
  @primary_backend.setc(key, val, expiry)
end

#ttl(key) ⇒ Object



106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/frivol/backend/multi.rb', line 106

def ttl(key)
  expiry = @primary_backend.ttl(key)
  if expiry.nil?
    @other_backends.each do |be|
      expiry = be.ttl(key)
      return expiry unless expiry.nil?
    end
    nil
  else
    expiry
  end
end