Class: Spinoza::MetaLog

Inherits:
Object
  • Object
show all
Defined in:
lib/spinoza/system/meta-log.rb

Overview

Model of synchronously replicated, linearizable global log, such as Zookeeper.

Defined Under Namespace

Classes: Entry

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dt_quorum: 0.300, dt_replicated: 0.500) ⇒ MetaLog

Returns a new instance of MetaLog.



46
47
48
49
50
51
# File 'lib/spinoza/system/meta-log.rb', line 46

def initialize dt_quorum: 0.300, dt_replicated: 0.500
  @dt_quorum = dt_quorum
  @dt_replicated = dt_replicated
  @store = []
  @replication_listeners = []
end

Instance Attribute Details

#dt_quorumObject (readonly)

Time to replicate a write to a quorum of MetaLog nodes, and for a unique sequence number to be assigned, and for that to be communicated to the writer node.



8
9
10
# File 'lib/spinoza/system/meta-log.rb', line 8

def dt_quorum
  @dt_quorum
end

#dt_replicatedObject (readonly)

Delay for a write to become “completely” replicated: readable at all nodes. Adjust this quantity for your network performance.



12
13
14
# File 'lib/spinoza/system/meta-log.rb', line 12

def dt_replicated
  @dt_replicated
end

Instance Method Details

#append(value, node: raise) ⇒ Object

Append value to the MetaLog, assigning it a unique monotonically increasing ID. In our use case, the value will be a key (or batch of keys) of the Log. Returns an id, which can be used to retrieve the entry in the order it was appended. The returned id should only be used to observe the model, and not used within the model itself, since the id won’t be available to the requesting process until ‘time_quorum(id)`.



83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/spinoza/system/meta-log.rb', line 83

def append value, node: raise
  entry = Entry.new(node: node, value: value,
    time_quorum: node.time_now + dt_quorum,
    time_replicated: node.time_now + dt_replicated)
  @store << entry
  id = @store.size - 1
  @replication_listeners.each do |actor, action|
    node.timeline << Spinoza::Event[
      time: entry.time_replicated, actor: actor, action: action,
      id: id, node: node, value: value]
  end
  id
end

#get(id, node: raise) ⇒ Object

Returns the value if the data has been propagated to node, otherwise, returns nil.



99
100
101
102
# File 'lib/spinoza/system/meta-log.rb', line 99

def get id, node: raise
  entry = @store[id]
  entry && entry.readable_at?(node) ? entry.value : nil
end

#on_entry_available(actor, action) ⇒ Object

Request that, whenever a new entry is created, an event be added to the schedule that will fire at entry.time_replicated. The event will send the method named ‘action` to `actor`, with id, node, and value arguments. Note that events fire in id order (because of the strong consistency guarantees that the meta-log’s underlying store is assumed to have).



73
74
75
# File 'lib/spinoza/system/meta-log.rb', line 73

def on_entry_available actor, action
  @replication_listeners << [actor, action]
end

#quorum?(id) ⇒ Boolean

Returns true if the writing node knows that the data at id has been replicated to a quorum of nodes.

Returns:

  • (Boolean)


55
56
57
58
# File 'lib/spinoza/system/meta-log.rb', line 55

def quorum? id
  entry = @store[id]
  entry && entry.quorum?
end

#time_quorum(id) ⇒ Object



60
61
62
# File 'lib/spinoza/system/meta-log.rb', line 60

def time_quorum id
  @store[id].time_quorum
end

#time_replicated(id) ⇒ Object



64
65
66
# File 'lib/spinoza/system/meta-log.rb', line 64

def time_replicated id
  @store[id].time_replicated
end