Class: SimpleFeed::Providers::Redis::Provider

Inherits:
Base::Provider show all
Includes:
Driver
Defined in:
lib/simplefeed/providers/redis/provider.rb

Overview

Internal data structure:

```YAML
  u.afkj234.data:
    - [ 'John liked Robert', '2016-11-20 23:32:56 -0800' ]
    - [ 'Debbie liked Robert', '2016-11-20 23:35:56 -0800' ]
  u.afkj234.meta: { total: 2, unread: 2, last_read: 2016-11-20 22:00:34 -08:00 GMT }
```

Constant Summary collapse

FEED_METHODS =
total_memory_bytes total_users last_disk_save_time

Instance Attribute Summary

Attributes included from Driver

#pool

Instance Method Summary collapse

Methods included from Driver

#debug?, #exec, #initialize, #on_error, #with_multi, #with_pipelined, #with_redis, #with_retries

Instance Method Details

#delete_if(user_ids:) ⇒ Object

Raises:

  • (ArgumentError)

51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/simplefeed/providers/redis/provider.rb', line 51

def delete_if(user_ids:)
  raise ArgumentError, '#delete_if must be called with a block that receives (user_id, event) as arguments.' unless block_given?
  with_response_batched(user_ids) do |key|
    fetch(user_ids: [key.user_id])[key.user_id].map do |event|
      with_redis do |redis|
        if yield(event, key.user_id)
          redis.zrem(key.data, event.value) ? event : nil
        end
      end
    end.compact
  end
end

#fetch(user_ids:, since: nil) ⇒ Object


79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/simplefeed/providers/redis/provider.rb', line 79

def fetch(user_ids:, since: nil)
  if since == :unread
    last_read_response = with_response_pipelined(user_ids) do |redis, key|
      get_users_last_read(redis, key)
    end
    reset_last_read(user_ids: user_ids)
  end
  with_response_pipelined(user_ids) do |redis, key|
    if since == :unread
      redis.zrevrangebyscore(key.data, '+inf', (last_read_response.delete(key.user_id) || 0).to_f, withscores: true)
    elsif since
      redis.zrevrangebyscore(key.data, '+inf', since.to_f, withscores: true)
    else
      redis.zrevrange(key.data, 0, -1, withscores: true)
    end
  end
end

#last_read(user_ids:) ⇒ Object


119
120
121
122
123
# File 'lib/simplefeed/providers/redis/provider.rb', line 119

def last_read(user_ids:)
  with_response_pipelined(user_ids) do |redis, key, *|
    get_users_last_read(redis, key)
  end
end

#paginate(user_ids:, page:, per_page: feed.per_page, peek: false, with_total: false) ⇒ Object


70
71
72
73
74
75
76
77
# File 'lib/simplefeed/providers/redis/provider.rb', line 70

def paginate(user_ids:, page:, per_page: feed.per_page, peek: false, with_total: false)
  reset_last_read(user_ids: user_ids) unless peek
  with_response_pipelined(user_ids) do |redis, key|
    events = paginated_events(page, per_page, redis, key)
    with_total ? { events:      events,
                   total_count: redis.zcard(key.data) } : events
  end
end

#reset_last_read(user_ids:, at: Time.now) ⇒ Object


97
98
99
100
101
# File 'lib/simplefeed/providers/redis/provider.rb', line 97

def reset_last_read(user_ids:, at: Time.now)
  with_response_pipelined(user_ids) do |redis, key, *|
    reset_users_last_read(redis, key, at.to_f)
  end
end

#store(user_ids:, value:, at: Time.now) ⇒ Object


37
38
39
40
41
42
43
# File 'lib/simplefeed/providers/redis/provider.rb', line 37

def store(user_ids:, value:, at: Time.now)
  with_response_pipelined(user_ids) do |redis, key|
    tap redis.zadd(key.data, at.to_f, value) do
      redis.zremrangebyrank(key.data, 0, -feed.max_size - 1)
    end
  end
end

#total_count(user_ids:) ⇒ Object


103
104
105
106
107
# File 'lib/simplefeed/providers/redis/provider.rb', line 103

def total_count(user_ids:)
  with_response_pipelined(user_ids) do |redis, key|
    redis.zcard(key.data)
  end
end

#total_memory_bytesObject


127
128
129
# File 'lib/simplefeed/providers/redis/provider.rb', line 127

def total_memory_bytes
  with_stats(:used_memory_since_boot)
end

#total_usersObject


131
132
133
# File 'lib/simplefeed/providers/redis/provider.rb', line 131

def total_users
  with_redis { |redis| redis.dbsize / 2 }
end

#transform_response(user_id = nil, result) ⇒ Object


141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/simplefeed/providers/redis/provider.rb', line 141

def transform_response(user_id = nil, result)
  case result
    when ::Redis::Future
      transform_response(user_id, result.value)

    when ::Hash

      if result.values.any? { |v| transformable_type?(v) }
        result.each { |k, v| result[k] = transform_response(user_id, v) }
      else
        result
      end

    when ::Array

      if result.any? { |v| transformable_type?(v) }
        result = result.map { |v| transform_response(user_id, v) }
      end

      if result.size == 2 && result[1].is_a?(Float)
        SimpleFeed::Event.new(value: result[0], at: Time.at(result[1]))
      else
        result
      end

    when ::String
      if result =~ /^\d+\.\d+$/
        result.to_f
      elsif result =~ /^\d+$/
        result.to_i
      else
        result
      end
    else
      result
  end
end

#transformable_type?(value) ⇒ Boolean

Returns:

  • (Boolean)

179
180
181
182
183
184
185
186
# File 'lib/simplefeed/providers/redis/provider.rb', line 179

def transformable_type?(value)
  [
    ::Redis::Future,
    ::Hash,
    ::Array,
    ::String
  ].include?(value.class)
end

#unread_count(user_ids:) ⇒ Object


109
110
111
112
113
114
115
116
117
# File 'lib/simplefeed/providers/redis/provider.rb', line 109

def unread_count(user_ids:)
  response = with_response_pipelined(user_ids) do |redis, key|
    get_users_last_read(redis, key)
  end
  with_response_pipelined(response.user_ids, response) do |redis, key, _response|
    last_read = _response.delete(key.user_id).to_f
    redis.zcount(key.data, last_read, '+inf')
  end
end

#wipe(user_ids:) ⇒ Object


64
65
66
67
68
# File 'lib/simplefeed/providers/redis/provider.rb', line 64

def wipe(user_ids:)
  with_response_pipelined(user_ids) do |redis, key|
    key.keys.all? { |redis_key| redis.del(redis_key) }
  end
end

#with_stats(operation) ⇒ Object


135
136
137
138
139
# File 'lib/simplefeed/providers/redis/provider.rb', line 135

def with_stats(operation)
  with_redis do |redis|
    SimpleFeed::Providers::Redis::Stats.new(redis).send(operation)
  end
end