Class: CRDT::PNCounter
- Inherits:
-
Object
- Object
- CRDT::PNCounter
- Defined in:
- lib/crdt/pn_counter.rb
Overview
A positive negative counter
This counter can be incremented up or down. Each node should only adjust it’s up and down counters. The current value of the counter is calculated by taking the sum of all the positive counters and subtracting the sum of all the negative counters
# Efficiency: value in counter: n, number of nodes: m, number of changes: k Local changes (+/-) are O(1) Merging changes are O(m) The space cost is O(m) The space cost of synchronization is O(m)
# Implementation notes: This implementation is a CvRDT. That means it sends a full copy of the entire structure, rather than messages
Instance Attribute Summary collapse
-
#negative_counters ⇒ Object
Returns the value of attribute negative_counters.
-
#positive_counters ⇒ Object
Returns the value of attribute positive_counters.
Class Method Summary collapse
-
.from_h(hash) ⇒ Object
Expects a Hash in the following format: { “positive” => { “1” => 15, “3” => 4 }, “negative” => { } }.
Instance Method Summary collapse
-
#+(other) ⇒ Object
Add something to this counter.
-
#-(other) ⇒ Object
Subtract something from this counter.
-
#decrease(amount, source = nil) ⇒ Object
Decrease this counter by the given amount.
-
#gc(node) ⇒ Object
Garbage collect a node, removing its counters and folding them into the new base value.
-
#increase(amount, source = nil) ⇒ Object
Increase this counter by the given amount.
-
#initialize(node_identity = Thread.current.object_id, base_value = 0) ⇒ PNCounter
constructor
Create a new counter.
-
#merge(other) ⇒ Object
Merge the counters from the other PNCounter into this one.
-
#to_h ⇒ Object
Get a hash representation of this object, which is suitable for serialization to JSON.
- #to_i ⇒ Object
- #value ⇒ Object
Constructor Details
#initialize(node_identity = Thread.current.object_id, base_value = 0) ⇒ PNCounter
Create a new counter
55 56 57 58 59 60 61 |
# File 'lib/crdt/pn_counter.rb', line 55 def initialize(node_identity = Thread.current.object_id, base_value = 0) @base_value = base_value @cached_value = base_value @positive_counters = {} @negative_counters = {} @node_identity = node_identity end |
Instance Attribute Details
#negative_counters ⇒ Object
Returns the value of attribute negative_counters.
63 64 65 |
# File 'lib/crdt/pn_counter.rb', line 63 def negative_counters @negative_counters end |
#positive_counters ⇒ Object
Returns the value of attribute positive_counters.
63 64 65 |
# File 'lib/crdt/pn_counter.rb', line 63 def positive_counters @positive_counters end |
Class Method Details
.from_h(hash) ⇒ Object
Expects a Hash in the following format: {
"positive" => {
"1" => 15,
"3" => 4
},
"negative" => {
}
}
28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/crdt/pn_counter.rb', line 28 def self.from_h(hash) counter = PNCounter.new(hash["node_identity"], hash["base_value"]) hash["positive"].each do |source, amount| counter.increase(amount, source) end hash["negative"].each do |source, amount| counter.decrease(amount, source) end return counter end |
Instance Method Details
#+(other) ⇒ Object
Add something to this counter
92 93 94 95 96 97 98 99 |
# File 'lib/crdt/pn_counter.rb', line 92 def +(other) if other > 0 increase(other) else decrease(- other) end self end |
#-(other) ⇒ Object
Subtract something from this counter
104 105 106 107 108 109 110 111 |
# File 'lib/crdt/pn_counter.rb', line 104 def -(other) if other > 0 decrease(other) else increase(- other) end self end |
#decrease(amount, source = nil) ⇒ Object
Decrease this counter by the given amount
80 81 82 83 84 85 86 87 |
# File 'lib/crdt/pn_counter.rb', line 80 def decrease(amount, source = nil) source ||= @node_identity negative_counters[source] ||= 0 negative_counters[source] += amount @cached_value -= amount return self end |
#gc(node) ⇒ Object
Garbage collect a node, removing its counters and folding them into the new base value.
This should only be called if your cluster management has indicated that a node has left the cluster permanently.
150 151 152 153 154 155 |
# File 'lib/crdt/pn_counter.rb', line 150 def gc(node) @base_value += @positive_counters[node] @base_value -= @negative_counters[node] @positive_counters.delete(node) @negative_counters.delete(node) end |
#increase(amount, source = nil) ⇒ Object
Increase this counter by the given amount
68 69 70 71 72 73 74 75 |
# File 'lib/crdt/pn_counter.rb', line 68 def increase(amount, source = nil) source ||= @node_identity positive_counters[source] ||= 0 positive_counters[source] += amount @cached_value += amount return self end |
#merge(other) ⇒ Object
Merge the counters from the other PNCounter into this one
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/crdt/pn_counter.rb', line 122 def merge(other) other.positive_counters.each do |source, amount| current_amount = @positive_counters[source] if current_amount if current_amount < amount @positive_counters[source] = amount end else @positive_counters[source] = amount end end other.negative_counters.each do |source, amount| current_amount = @negative_counters[source] if current_amount if current_amount < amount @negative_counters[source] = amount end else @negative_counters[source] = amount end end return self end |
#to_h ⇒ Object
Get a hash representation of this object, which is suitable for serialization to JSON
42 43 44 45 46 47 48 49 50 |
# File 'lib/crdt/pn_counter.rb', line 42 def to_h return { node_identity: @node_identity, base_value: @base_value, cached_value: @cached_value, positive: @positive_counters, negative: @negative_counters, } end |
#to_i ⇒ Object
117 118 119 |
# File 'lib/crdt/pn_counter.rb', line 117 def to_i @cached_value.to_i end |
#value ⇒ Object
113 114 115 |
# File 'lib/crdt/pn_counter.rb', line 113 def value @cached_value end |