Page Speed Optimization Libraries  1.13.35.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
redis_cache.h
Go to the documentation of this file.
1 /*
2  * Copyright 2016 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http:///www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
18 
19 #ifndef PAGESPEED_SYSTEM_REDIS_CACHE_H_
20 #define PAGESPEED_SYSTEM_REDIS_CACHE_H_
21 
22 #include <stdarg.h>
23 
24 #include <memory>
25 #include <initializer_list>
26 #include <map>
27 #include <vector>
28 
37 #include "pagespeed/kernel/base/thread_annotations.h"
40 #include "pagespeed/kernel/cache/cache_interface.h"
43 #include "third_party/hiredis/src/hiredis.h"
44 
45 namespace net_instaweb {
46 
75 class RedisCache : public CacheInterface {
76  public:
80  RedisCache(StringPiece host, int port, ThreadSystem* thread_system,
81  MessageHandler* message_handler, Timer* timer,
82  int64 reconnection_delay_ms, int64 timeout_us,
83  Statistics* stats, int database_index);
84  ~RedisCache() override { ShutDown(); }
85 
86  static void InitStats(Statistics* stats);
87 
88  GoogleString ServerDescription() const;
89 
90  void StartUp(bool connect_now = true);
91 
93  GoogleString Name() const override { return FormatName(); }
94  bool IsBlocking() const override { return true; }
95  bool IsHealthy() const override;
96  void ShutDown() override;
97 
98  static GoogleString FormatName() { return "RedisCache"; }
99 
101  void Get(const GoogleString& key, Callback* callback) override;
102  void Put(const GoogleString& key, const SharedString& value) override;
103  void Delete(const GoogleString& key) override;
104 
107  void GetStatus(GoogleString* status_string);
108 
110  static int HashSlot(StringPiece key);
111 
114  int64 Redirections() {
115  return redirections_->Get();
116  }
117 
121  return cluster_slots_fetches_->Get();
122  }
123 
124  private:
125  struct RedisReplyDeleter {
126  void operator()(redisReply* ptr) {
127  if (ptr != nullptr) {
128  freeReplyObject(ptr);
129  }
130  }
131  };
132  typedef std::unique_ptr<redisReply, RedisReplyDeleter> RedisReply;
133 
134  struct RedisContextDeleter {
135  void operator()(redisContext* ptr) {
136  if (ptr != nullptr) {
137  redisFree(ptr);
138  }
139  }
140  };
141  typedef std::unique_ptr<redisContext, RedisContextDeleter> RedisContext;
142 
143  class Connection {
144  public:
145  Connection(RedisCache* redis_cache, StringPiece host, int port,
146  int database_index);
147 
148  void StartUp(bool connect_now = true)
149  LOCKS_EXCLUDED(redis_mutex_, state_mutex_);
150  bool IsHealthy() const LOCKS_EXCLUDED(redis_mutex_, state_mutex_);
151  void ShutDown() LOCKS_EXCLUDED(redis_mutex_, state_mutex_);
152 
153  GoogleString ToString() {
154  return StrCat(host_, ":", IntegerToString(port_));
155  }
156 
157  AbstractMutex* GetOperationMutex() const LOCK_RETURNED(redis_mutex_) {
158  return redis_mutex_.get();
159  }
160 
162  RedisReply RedisCommand(const char* format, va_list args)
163  EXCLUSIVE_LOCKS_REQUIRED(redis_mutex_) LOCKS_EXCLUDED(state_mutex_);
164  RedisReply RedisCommand(const char* format, ...)
165  EXCLUSIVE_LOCKS_REQUIRED(redis_mutex_) LOCKS_EXCLUDED(state_mutex_);
166 
167  bool ValidateRedisReply(const RedisReply& reply,
168  std::initializer_list<int> valid_types,
169  const char* command_executed)
170  EXCLUSIVE_LOCKS_REQUIRED(redis_mutex_) LOCKS_EXCLUDED(state_mutex_);
171 
172  private:
173  enum State {
174  kShutDown,
175  kDisconnected,
176  kConnecting,
177  kConnected
178  };
179 
180  bool IsHealthyLockHeld() const EXCLUSIVE_LOCKS_REQUIRED(state_mutex_);
181  void UpdateState() EXCLUSIVE_LOCKS_REQUIRED(redis_mutex_, state_mutex_);
182 
184  bool EnsureConnectionAndDatabaseSelection()
185  EXCLUSIVE_LOCKS_REQUIRED(redis_mutex_)
186  LOCKS_EXCLUDED(state_mutex_);
187  bool EnsureConnection() EXCLUSIVE_LOCKS_REQUIRED(redis_mutex_)
188  LOCKS_EXCLUDED(state_mutex_);
189  bool EnsureDatabaseSelection() EXCLUSIVE_LOCKS_REQUIRED(state_mutex_)
190  LOCKS_EXCLUDED(state_mutex_);
191 
192  RedisContext TryConnect() LOCKS_EXCLUDED(redis_mutex_, state_mutex_);
193 
194  void LogRedisContextError(redisContext* redis, const char* cause);
195 
196  const RedisCache* redis_cache_;
197  const GoogleString host_;
198  const int port_;
199  const scoped_ptr<AbstractMutex> redis_mutex_;
200  const scoped_ptr<AbstractMutex> state_mutex_;
201 
202  RedisContext redis_ GUARDED_BY(redis_mutex_);
203  State state_ GUARDED_BY(state_mutex_);
204  int64 next_reconnect_at_ms_ GUARDED_BY(state_mutex_);
205 
208  const int database_index_;
209 
210 
211  };
212  typedef std::map<GoogleString, std::unique_ptr<Connection>> ConnectionsMap;
213 
214  struct ClusterMapping {
216  ClusterMapping(int start_slot_range,
217  int end_slot_range,
218  Connection* connection) :
219  start_slot_range_(start_slot_range),
220  end_slot_range_(end_slot_range),
221  connection_(connection) {}
222  int start_slot_range_;
223  int end_slot_range_;
224  Connection* connection_;
225  };
226 
236  RedisReply RedisCommand(Connection* connection, const char* format,
237  std::initializer_list<int> valid_reply_types, ...);
238 
239  ThreadSynchronizer* GetThreadSynchronizerForTesting() const {
240  return thread_synchronizer_.get();
241  }
242 
243  ExternalServerSpec ParseRedirectionError(StringPiece error);
244 
247  Connection* GetOrCreateConnection(ExternalServerSpec spec,
248  const int database_index);
249 
251  void FetchClusterSlotMapping(Connection* connection)
252  LOCKS_EXCLUDED(cluster_map_lock_);
253 
258  Connection* LookupConnection(StringPiece key)
259  LOCKS_EXCLUDED(cluster_map_lock_);
260 
261  const GoogleString main_host_;
262  const int main_port_;
263  ThreadSystem* thread_system_;
264  MessageHandler* message_handler_;
265  Timer* timer_;
266  const int64 reconnection_delay_ms_;
267  const int64 timeout_us_;
268  const scoped_ptr<ThreadSynchronizer> thread_synchronizer_;
269  const scoped_ptr<ThreadSystem::RWLock> connections_lock_;
270  const scoped_ptr<ThreadSystem::RWLock> cluster_map_lock_;
271  Variable* redirections_;
272  Variable* cluster_slots_fetches_;
273 
276  ConnectionsMap connections_ GUARDED_BY(connections_lock_);
277  std::vector<ClusterMapping> cluster_mappings_ GUARDED_BY(cluster_map_lock_);
278 
280  Connection* main_connection_;
281 
282  const int database_index_;
283 
284  friend class RedisCacheTest;
285 
286 };
287 
288 }
289 
290 #endif
void Get(const GoogleString &key, Callback *callback) override
CacheInterface implementations.
int64 ClusterSlotsFetches()
Definition: redis_cache.h:120
Abstract interface for a cache.
Definition: cache_interface.h:32
bool IsHealthy() const override
bool IsBlocking() const override
Definition: redis_cache.h:94
Base class for implementations of monitoring statistics.
Definition: statistics.h:342
GoogleString Name() const override
CacheInterface implementations.
Definition: redis_cache.h:93
Definition: redis_cache.h:75
void ShutDown() override
RedisCache(StringPiece host, int port, ThreadSystem *thread_system, MessageHandler *message_handler, Timer *timer, int64 reconnection_delay_ms, int64 timeout_us, Statistics *stats, int database_index)
std::string GoogleString
PAGESPEED_KERNEL_BASE_STRING_H_.
Definition: string.h:24
static int HashSlot(StringPiece key)
Redis spec defined hasher for keys. Static, since it's a pure function.
void Put(const GoogleString &key, const SharedString &value) override
Definition: thread_system.h:40
Definition: message_handler.h:39
void GetStatus(GoogleString *status_string)
int64 Redirections()
Definition: redis_cache.h:114
Timer interface, made virtual so it can be mocked for tests.
Definition: timer.h:27