You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

96 lines
2.6 KiB

require "./ring.cr"
require "mutex"
require "openssl"
module Crystal::Scatter
class Daemon
getter weight : UInt64
getter location : Array(Int32)
getter url : String
def initialize(@weight : UInt64, @location : Array(Int32), @url : String)
end
end
class MetaRing
getter rings : Array(Ring)
getter ring_graph : RingGraph
def initialize(@shards : UInt32)
@rings = Array(Ring).new
@ring_graph = RingGraph.new
@lock = Mutex.new
end
private def add_impl(element : Daemon)
@ring_graph.add(element.weight, element.location, element.url)
end
private def update_impl
@ring_graph.generate_ring
ring = Ring.new
@ring_graph.snapshot do |daemon|
ring.push RingSlice.new(daemon.range_effector.not_nil!.[0],daemon.range_effector.not_nil!.[1],daemon.react_at)
end
@rings.push ring
end
private def hash_impl(data : String)
ctx = OpenSSL::Digest.new("md4")
ctx << data
digest = ctx.digest
tag = IO::ByteFormat::BigEndian.decode(UInt64, digest)
tag ^= IO::ByteFormat::BigEndian.decode(UInt64, digest+8)
return tag
end
private def get_slice_from_hash(h : UInt64)
end
def add(element : Daemon)
@lock.synchronize do
add_impl element
update_impl
end
end
def add(elements : Array(Daemon))
@lock.synchronize do
elements.each do |element|
add_impl element
end
update_impl
end
end
def hash(data : String)
hash_impl data
end
def get_slices_for(data : String)
ret = Array.new(@shards)
ring? : Ring | Nil
@lock.synchronize do
ring? = @rings.last
end
ring = ring?.not_nil!
h = hash_impl data
space=UInt64::MAX/@shards
targets = Array(UInt64).new
(1..shards).each do ||
targets << h
h+=space
end
slices = Array(Slice).new
targets.each do |h|
value = ring.find do |slice|
h>=slice.s_begin && slice.s_end>=h
end
slices << value.not_nil!
end
return slices
end
end
end