Class: Ruster::Node

Inherits:
Object
  • Object
show all
Includes:
Util
Defined in:
lib/ruster/node.rb

Constant Summary collapse

DB0 =

In Redis Cluster only DB 0 is enabled

0

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Util

#parse_info

Constructor Details

#initialize(addr) ⇒ Node

Returns a new instance of Node.



17
18
19
# File 'lib/ruster/node.rb', line 17

def initialize(addr)
  @addr = addr
end

Instance Attribute Details

#addrObject (readonly)

Returns the value of attribute addr.



4
5
6
# File 'lib/ruster/node.rb', line 4

def addr
  @addr
end

#config_epochObject (readonly)

Returns the value of attribute config_epoch.



10
11
12
# File 'lib/ruster/node.rb', line 10

def config_epoch
  @config_epoch
end

#flagsObject (readonly)

Returns the value of attribute flags.



6
7
8
# File 'lib/ruster/node.rb', line 6

def flags
  @flags
end

#friendsObject (readonly)

Returns the value of attribute friends.



15
16
17
# File 'lib/ruster/node.rb', line 15

def friends
  @friends
end

#idObject (readonly)

Returns the value of attribute id.



5
6
7
# File 'lib/ruster/node.rb', line 5

def id
  @id
end

#importingObject (readonly)

Returns the value of attribute importing.



14
15
16
# File 'lib/ruster/node.rb', line 14

def importing
  @importing
end

#master_idObject (readonly)

Returns the value of attribute master_id.



7
8
9
# File 'lib/ruster/node.rb', line 7

def master_id
  @master_id
end

#migratingObject (readonly)

Returns the value of attribute migrating.



13
14
15
# File 'lib/ruster/node.rb', line 13

def migrating
  @migrating
end

#ping_epochObject (readonly)

Returns the value of attribute ping_epoch.



8
9
10
# File 'lib/ruster/node.rb', line 8

def ping_epoch
  @ping_epoch
end

#pong_epochObject (readonly)

Returns the value of attribute pong_epoch.



9
10
11
# File 'lib/ruster/node.rb', line 9

def pong_epoch
  @pong_epoch
end

#slotsObject (readonly)

Returns the value of attribute slots.



12
13
14
# File 'lib/ruster/node.rb', line 12

def slots
  @slots
end

#stateObject (readonly)

Returns the value of attribute state.



11
12
13
# File 'lib/ruster/node.rb', line 11

def state
  @state
end

Class Method Details

.from_info_line(info_line) ⇒ Object



72
73
74
75
# File 'lib/ruster/node.rb', line 72

def self.from_info_line(info_line)
  _, addr, _ = info_line.split
  new(addr).tap { |node| node.read_info_line!(info_line) }
end

Instance Method Details

#add_slots(*slots) ⇒ Object



108
109
110
# File 'lib/ruster/node.rb', line 108

def add_slots(*slots)
  call("CLUSTER", "ADDSLOTS", *slots)
end

#all_slotsObject



64
65
66
# File 'lib/ruster/node.rb', line 64

def all_slots
  slots.map(&:to_a).flatten
end

#call(*args) ⇒ Object



25
26
27
28
29
# File 'lib/ruster/node.rb', line 25

def call(*args)
  res = client.call(*args)
  raise res if res.is_a?(RuntimeError)
  res
end

#clientObject



21
22
23
# File 'lib/ruster/node.rb', line 21

def client
  @client ||= Redic.new("redis://#{addr}")
end

#cluster_infoObject



120
121
122
# File 'lib/ruster/node.rb', line 120

def cluster_info
  parse_info(call("CLUSTER", "INFO"))
end

#del_slots(*slots) ⇒ Object



112
113
114
# File 'lib/ruster/node.rb', line 112

def del_slots(*slots)
  call("CLUSTER", "DELSLOTS", *slots)
end

#empty?Boolean

Returns:

  • (Boolean)


165
166
167
# File 'lib/ruster/node.rb', line 165

def empty?
  call("DBSIZE") == 0
end

#enabled?Boolean

Returns:

  • (Boolean)


31
32
33
# File 'lib/ruster/node.rb', line 31

def enabled?
  parse_info(call("INFO", "cluster"))[:cluster_enabled] == "1"
end

#flush_slots!Object



116
117
118
# File 'lib/ruster/node.rb', line 116

def flush_slots!
  call("CLUSTER", "FLUSHSLOTS")
end

#forget(node) ⇒ Object

Raises:

  • (ArgumentError)


93
94
95
96
# File 'lib/ruster/node.rb', line 93

def forget(node)
  raise ArgumentError, "Node #{node} is not empty" unless node.slots.empty? and node.migrating.empty? and node.importing.empty?
  call("CLUSTER", "FORGET", node.id)
end

#ipObject



124
125
126
# File 'lib/ruster/node.rb', line 124

def ip
  addr.split(":").first
end

#load!Object



77
78
79
80
81
82
83
84
85
86
87
# File 'lib/ruster/node.rb', line 77

def load!
  @friends = []

  call("CLUSTER", "NODES").split("\n").each do |line|
    if line.include?("myself")
      read_info_line!(line)
    else
      @friends << self.class.from_info_line(line)
    end
  end
end

#meet(ip, port) ⇒ Object



89
90
91
# File 'lib/ruster/node.rb', line 89

def meet(ip, port)
  call("CLUSTER", "MEET", ip, port)
end

#move_slot!(slot, target, options = {}) ⇒ Object



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/ruster/node.rb', line 135

def move_slot!(slot, target, options={})
  options[:num_keys] ||= 10
  options[:timeout]  ||= call("CONFIG", "GET", "cluster-node-timeout")

  # Tell the target node to import the slot
  target.call("CLUSTER", "SETSLOT", slot, "IMPORTING", id)

  # Tell the current node to export the slot
  call("CLUSTER", "SETSLOT", slot, "MIGRATING", target.id)

  # Export keys
  done = false
  until done
    keys = call("CLUSTER", "GETKEYSINSLOT", slot, options[:num_keys])

    done = keys.empty?

    keys.each do |key|
      call("MIGRATE", target.ip, target.port, key, DB0, options[:timeout])
    end

    # Tell cluster the location of the new slot
    call("CLUSTER", "SETSLOT", slot, "NODE", target.id)

    friends.each do |node|
      node.call("CLUSTER", "SETSLOT", slot, "NODE", target.id)
    end
  end
end

#only_node?Boolean

Returns:

  • (Boolean)


169
170
171
# File 'lib/ruster/node.rb', line 169

def only_node?
  parse_info(call("CLUSTER", "INFO"))[:cluster_known_nodes] == "1"
end

#portObject



128
129
130
# File 'lib/ruster/node.rb', line 128

def port
  addr.split(":").last
end

#read_info_line!(info_line) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/ruster/node.rb', line 35

def read_info_line!(info_line)
  parts = info_line.split

  @id = parts.shift
  addr = parts.shift
  @flags = parts.shift.split(",")
  @addr = addr unless @flags.include?("myself")
  @master_id = parts.shift
  @ping_epoch = parts.shift.to_i
  @pong_epoch = parts.shift.to_i
  @config_epoch = parts.shift.to_i
  @state = parts.shift
  @slots = []
  @migrating = {}
  @importing = {}

  parts.each do |slots|
    case slots
    when /^(\d+)-(\d+)$/ then @slots << ($1.to_i..$2.to_i)
    when /^\d+$/ then @slots << (slots.to_i..slots.to_i)
    when /^\[(\d+)-([<>])-([a-z0-9]+)\]$/
      case $2
      when ">" then @migrating[$1.to_i] = $3
      when "<" then @importing[$1.to_i] = $3
      end
    end
  end
end

#replicate(node) ⇒ Object



98
99
100
# File 'lib/ruster/node.rb', line 98

def replicate(node)
  call("CLUSTER", "REPLICATE", node.id)
end

#slavesObject



102
103
104
105
106
# File 'lib/ruster/node.rb', line 102

def slaves
  call("CLUSTER", "SLAVES", id).map do |line|
    self.class.from_info_line(line)
  end
end

#to_sObject



68
69
70
# File 'lib/ruster/node.rb', line 68

def to_s
  "#{addr} [#{id}]"
end