Class: Ciri::P2P::Kad::KBucket

Inherits:
Object
  • Object
show all
Defined in:
lib/ciri/p2p/kad.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(start_id:, end_id:, k_size: K_BUCKET_SIZE) ⇒ KBucket

Returns a new instance of KBucket.



70
71
72
73
74
75
76
77
# File 'lib/ciri/p2p/kad.rb', line 70

def initialize(start_id:, end_id:, k_size: K_BUCKET_SIZE)
  @start_id = start_id
  @end_id = end_id
  @k_size = k_size
  @nodes = []
  @replacement_cache = []
  @last_updated = Time.now.to_i
end

Instance Attribute Details

#end_idObject (readonly)

Returns the value of attribute end_id.



68
69
70
# File 'lib/ciri/p2p/kad.rb', line 68

def end_id
  @end_id
end

#k_sizeObject (readonly)

Returns the value of attribute k_size.



68
69
70
# File 'lib/ciri/p2p/kad.rb', line 68

def k_size
  @k_size
end

#last_updatedObject (readonly)

Returns the value of attribute last_updated.



68
69
70
# File 'lib/ciri/p2p/kad.rb', line 68

def last_updated
  @last_updated
end

#nodesObject (readonly)

Returns the value of attribute nodes.



68
69
70
# File 'lib/ciri/p2p/kad.rb', line 68

def nodes
  @nodes
end

#replacement_cacheObject (readonly)

Returns the value of attribute replacement_cache.



68
69
70
# File 'lib/ciri/p2p/kad.rb', line 68

def replacement_cache
  @replacement_cache
end

#start_idObject (readonly)

Returns the value of attribute start_id.



68
69
70
# File 'lib/ciri/p2p/kad.rb', line 68

def start_id
  @start_id
end

Instance Method Details

#add(node) ⇒ Object

Try add node into bucket if node is exists, it is moved to the tail if the node is node exists and bucket not full, it is added at tail if the bucket is full, node will added to replacement_cache, and return the head of the list, which should be evicted if it failed to respond to a ping.



133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/ciri/p2p/kad.rb', line 133

def add(node)
  @last_updated = Time.now.to_i
  if @nodes.include?(node)
    @nodes.delete(node)
    @nodes << node
  elsif @nodes.size < k_size
    @nodes << node
  else
    @replacement_cache << node
    return head
  end
  nil
end

#cover?(node) ⇒ Boolean

Returns:

  • (Boolean)


121
122
123
# File 'lib/ciri/p2p/kad.rb', line 121

def cover?(node)
  @start_id <= node.id && node.id <= @end_id
end

#delete(node) ⇒ Object



117
118
119
# File 'lib/ciri/p2p/kad.rb', line 117

def delete(node)
  @nodes.delete(node)
end

#distance_to(id) ⇒ Object



84
85
86
# File 'lib/ciri/p2p/kad.rb', line 84

def distance_to(id)
  midpoint ^ id
end

#full?Boolean

Returns:

  • (Boolean)


125
126
127
# File 'lib/ciri/p2p/kad.rb', line 125

def full?
  @nodes.size == k_size
end

#headObject



147
148
149
# File 'lib/ciri/p2p/kad.rb', line 147

def head
  @nodes[0]
end

#include?(node) ⇒ Boolean

Returns:

  • (Boolean)


151
152
153
# File 'lib/ciri/p2p/kad.rb', line 151

def include?(node)
  @nodes.include?(node)
end

#midpointObject

use to compute node distance with kbucket



80
81
82
# File 'lib/ciri/p2p/kad.rb', line 80

def midpoint
  @start_id + (@end_id - @start_id) / 2
end

#nodes_by_distance_to(id) ⇒ Object

find neighbour nodes



89
90
91
92
93
# File 'lib/ciri/p2p/kad.rb', line 89

def nodes_by_distance_to(id)
  @nodes.sort_by do |node|
    node.distance_to(id)
  end
end

#sizeObject



155
156
157
# File 'lib/ciri/p2p/kad.rb', line 155

def size
  @nodes.size
end

#splitObject

split to two kbucket by midpoint



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/ciri/p2p/kad.rb', line 96

def split
  split_point = midpoint
  lower = KBucket.new(start_id: @start_id, end_id: split_point)
  upper = KBucket.new(start_id: split_point + 1, end_id: @end_id)
  @nodes.each do |node|
    if node.id <= split_point
      lower.add(node)
    else
      upper.add(node)
    end
  end
  @replacement_cache.each do |node|
    if node.id <= split_point
      lower.replacement_cache << node
    else
      upper.replacement_cache << node
    end
  end
  [lower, upper]
end