/lib/batsd/redis.rb
Ruby | 153 lines | 95 code | 14 blank | 44 comment | 8 complexity | 7beee084053fc3ac607458c1c1419361 MD5 | raw file
1module Batsd 2 # 3 # This is a thin wrapper around the redis client to 4 # handle multistep procedures that could be executed using 5 # Redis scripting 6 # 7 class Redis 8 9 # Opens a new connection to the redis instance specified 10 # in the configuration or localhost:6379 11 # 12 def initialize(options) 13 @redis = ::Redis.new(options[:redis] || {host: "127.0.0.1", port: 6379} ) 14 @redis.ping 15 @lua_support = @redis.info['redis_version'].to_f >= 2.5 16 @retentions = options[:retentions].keys 17 end 18 19 # Expose the redis client directly 20 def client 21 @redis 22 end 23 24 # Store a counter measurement for each of the specified retentions 25 # 26 # * For shortest retention (where timestep == flush interval), add the 27 # value and timestamp to the appropriate zset 28 # 29 # * For longer retention intervals, increment the appropriate counter 30 # by the value specified. 31 # 32 # TODO: This can be done in a single network request by rewriting 33 # it as a redis script in Lua 34 # 35 def store_and_update_all_counters(timestamp, key, value) 36 @retentions.each_with_index do |t, index| 37 if index.zero? 38 @redis.zadd key, timestamp, "#{timestamp}<X>#{value}" 39 else 40 @redis.incrby "#{key}:#{t}", value 41 @redis.expire "#{key}:#{t}", t.to_i * 2 42 end 43 end 44 end 45 46 # Store a timer to a zset 47 # 48 def store_timer(timestamp, key, value) 49 @redis.zadd key, timestamp, "#{timestamp}<X>#{value}" 50 end 51 52 # Store unaggregated, raw timer values in bucketed keys 53 # so that they can actually be aggregated "raw" 54 # 55 # The set of tiemrs are stored as a single string key delimited by 56 # \x0. In benchmarks, this is more efficient in memory by 2-3x, and 57 # less efficient in time by ~10% 58 # 59 # TODO: can this be done more efficiently with redis scripting? 60 def store_raw_timers_for_aggregations(key, values) 61 @retentions.each_with_index do |t, index| 62 next if index.zero? 63 @redis.append "#{key}:#{t}", "<X>#{values.join("<X>")}" 64 @redis.expire "#{key}:#{t}", t.to_i * 2 65 end 66 end 67 68 # Returns the value of a key and then deletes it. 69 def get_and_clear_key(key) 70 if @lua_support 71 cmd = <<-EOF 72 local str = redis.call('get', KEYS[1]) 73 redis.call('del', KEYS[1]) 74 return str 75 EOF 76 @redis.eval(cmd, [key.to_sym]) 77 else 78 @redis.multi do |multi| 79 multi.get(key) 80 multi.del(key) 81 end.first 82 end 83 end 84 85 # Deletes the given key 86 def clear_key(key) 87 @redis.del(key) 88 end 89 90 # Create an array out of a string of values delimited by <X> 91 def extract_values_from_string(key) 92 if @lua_support 93 cmd = <<-EOF 94 local t={} ; local i=1 95 local str = redis.call('get', KEYS[1]) 96 if (str) then 97 for s in string.gmatch(str, "([^".."<X>".."]+)") do 98 t[i] = s 99 i = i + 1 100 end 101 redis.call('del', KEYS[1]) 102 end 103 return t 104 EOF 105 @redis.eval(cmd, [key.to_sym]) 106 else 107 values = get_and_clear_key(key) 108 values.split('<X>') if values 109 end 110 end 111 112 # Truncate a zset since a treshold time 113 # 114 def truncate_zset(key, since) 115 @redis.zremrangebyscore key, 0, since 116 end 117 118 # Return properly formatted values from the zset 119 def values_from_zset(metric, begin_ts, end_ts) 120 begin 121 values = @redis.zrangebyscore(metric, begin_ts, end_ts) 122 values.collect{|val| ts, val = val.split("<X>"); {timestamp: ts.to_i, value: val.to_f } } 123 rescue 124 [] 125 end 126 end 127 128 # Convenience accessor to members of datapoints set 129 # 130 def datapoints(with_gauges=true) 131 datapoints = @redis.smembers "datapoints" 132 unless with_gauges 133 datapoints.reject!{|d| (d.match(/^gauge/) rescue false) } 134 end 135 datapoints 136 end 137 138 # Stores a reference to the datapoint in 139 # the 'datapoints' set 140 # 141 def add_datapoint(key) 142 @redis.sadd "datapoints", key 143 end 144 145 # Stores a reference to the datapoint in 146 # the 'datapoints' set 147 # 148 def remove_datapoint(key) 149 @redis.srem "datapoints", key 150 end 151 152 end 153end