Class: Riak::CRDT::TGCounter
- Inherits:
-
Object
- Object
- Riak::CRDT::TGCounter
- Defined in:
- lib/crdt/tgcounter.rb
Instance Attribute Summary collapse
-
#actor ⇒ Object
Returns the value of attribute actor.
-
#counts ⇒ Object
Returns the value of attribute counts.
-
#history_length ⇒ Object
Returns the value of attribute history_length.
Class Method Summary collapse
Instance Method Summary collapse
-
#compress_history ⇒ Object
Compress this actor’s data based on history_length.
-
#duplicate_transactions ⇒ Hash
Get unique list of all duplicate transactions for all actors other than self.
-
#duplicate_transactions_by_actor ⇒ Hash
Get unique list of all duplicate transactions per actor other than self.
- #has_transaction?(transaction) ⇒ Boolean
-
#increment(transaction, value) ⇒ Object
Increment this actor’s transaction array, overwriting if the value exists.
-
#initialize(options) ⇒ TGCounter
constructor
Create a new Transaction GCounter.
-
#merge(other) ⇒ Object
Merge actor data from a sibling into self, additionally remove duplicate transactions and compress oldest transactions that exceed the :history_length param into actor’s total.
-
#merge_actors(other) ⇒ Object
Combine all actors’ data.
-
#remove_duplicates ⇒ Object
Remove duplicate transactions if other actors have claimed them.
- #to_hash ⇒ Object
- #to_json ⇒ Object
-
#unique_transactions(for_actor = nil) ⇒ Hash
Get unique list of all transactions and values across all known actors, or optionally for a single actor.
-
#value ⇒ Integer
Sum of totals and currently tracked transactions.
Constructor Details
#initialize(options) ⇒ TGCounter
Create a new Transaction GCounter
11 12 13 14 15 16 17 18 |
# File 'lib/crdt/tgcounter.rb', line 11 def initialize() self.actor = [:actor] self.history_length = [:history_length] self.counts = Hash.new() self.counts[self.actor] = Hash.new() self.counts[self.actor]["total"] = 0 self.counts[self.actor]["txns"] = TransactionArray.new() end |
Instance Attribute Details
#actor ⇒ Object
Returns the value of attribute actor.
3 4 5 |
# File 'lib/crdt/tgcounter.rb', line 3 def actor @actor end |
#counts ⇒ Object
Returns the value of attribute counts.
3 4 5 |
# File 'lib/crdt/tgcounter.rb', line 3 def counts @counts end |
#history_length ⇒ Object
Returns the value of attribute history_length.
3 4 5 |
# File 'lib/crdt/tgcounter.rb', line 3 def history_length @history_length end |
Class Method Details
.from_hash(h, options) ⇒ Object
38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/crdt/tgcounter.rb', line 38 def self.from_hash(h, ) gc = new() h['c'].each do |a, values| gc.counts[a] = Hash.new() unless gc.counts[a] gc.counts[a]["total"] = values["total"] gc.counts[a]["txns"] = TransactionArray.new(values["txns"]) end return gc end |
.from_json(json, options) ⇒ Object
50 51 52 53 54 55 |
# File 'lib/crdt/tgcounter.rb', line 50 def self.from_json(json, ) h = JSON.parse json raise ArgumentError.new 'unexpected type field in JSON' unless h['type'] == 'TGCounter' from_hash(h, ) end |
Instance Method Details
#compress_history ⇒ Object
Compress this actor’s data based on history_length
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/crdt/tgcounter.rb', line 169 def compress_history() total = 0 duplicates = self.duplicate_transactions() if self.counts[actor]["txns"].length > self.history_length to_delete = self.counts[actor]["txns"].length - self.history_length self.counts[actor]["txns"].arr.slice!(0..to_delete - 1).each do |arr| txn, val = arr total += val unless duplicates.member? txn end end self.counts[actor]["total"] += total end |
#duplicate_transactions ⇒ Hash
Get unique list of all duplicate transactions for all actors other than self
98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/crdt/tgcounter.rb', line 98 def duplicate_transactions() duplicates = Hash.new() self.duplicate_transactions_by_actor().each do |a, txns| txns.each do |txn, val| duplicates[txn] = val end end duplicates end |
#duplicate_transactions_by_actor ⇒ Hash
Get unique list of all duplicate transactions per actor other than self
82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/crdt/tgcounter.rb', line 82 def duplicate_transactions_by_actor() actor_txns = Hash.new() my_transactions = self.unique_transactions(self.actor).keys self.counts.keys.each do |a| next if a == self.actor uniques = self.unique_transactions(a).keys actor_txns[a] = (my_transactions & uniques) end actor_txns end |
#has_transaction?(transaction) ⇒ Boolean
110 111 112 |
# File 'lib/crdt/tgcounter.rb', line 110 def has_transaction?(transaction) self.unique_transactions().keys.member?(transaction) end |
#increment(transaction, value) ⇒ Object
Increment this actor’s transaction array, overwriting if the value exists
60 61 62 |
# File 'lib/crdt/tgcounter.rb', line 60 def increment(transaction, value) self.counts[actor]["txns"][transaction] = value end |
#merge(other) ⇒ Object
Merge actor data from a sibling into self, additionally remove duplicate transactions and compress oldest transactions that exceed the :history_length param into actor’s total
130 131 132 133 134 |
# File 'lib/crdt/tgcounter.rb', line 130 def merge(other) self.merge_actors(other) self.remove_duplicates() self.compress_history() end |
#merge_actors(other) ⇒ Object
Combine all actors’ data
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/crdt/tgcounter.rb', line 137 def merge_actors(other) other.counts.each do |other_actor, other_values| if self.counts[other_actor] # Max of totals mine = self.counts[other_actor]["total"] self.counts[other_actor]["total"] = [mine, other_values["total"]].max # Max of unique transactions other_values["txns"].arr.each do |arr| other_txn, other_value = arr mine = (self.counts[other_actor]["txns"][other_txn]) ? self.counts[other_actor]["txns"][other_txn] : 0 self.counts[other_actor]["txns"][other_txn] = [mine, other_value].max end else self.counts[other_actor] = other_values end end end |
#remove_duplicates ⇒ Object
Remove duplicate transactions if other actors have claimed them
158 159 160 161 162 163 164 165 166 |
# File 'lib/crdt/tgcounter.rb', line 158 def remove_duplicates() self.duplicate_transactions_by_actor().each do |a, txns| # Spaceship operator, if my actor is of greater value than theirs, skip because they should remove the dupe next if (self.actor <=> a) == 1 txns.each do |txn| self.counts[self.actor]["txns"].delete(txn) end end end |
#to_hash ⇒ Object
20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/crdt/tgcounter.rb', line 20 def to_hash c = Hash.new() self.counts.each do |a, values| c[a] = Hash.new() c[a]["total"] = values["total"] c[a]["txns"] = values["txns"].arr end { type: 'TGCounter', c: c } end |
#to_json ⇒ Object
34 35 36 |
# File 'lib/crdt/tgcounter.rb', line 34 def to_json self.to_hash.to_json end |
#unique_transactions(for_actor = nil) ⇒ Hash
Get unique list of all transactions and values across all known actors, or optionally for a single actor
67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/crdt/tgcounter.rb', line 67 def unique_transactions(for_actor=nil) txns = Hash.new() self.counts.each do |a, values| next if for_actor && a != for_actor values["txns"].arr.each do |arr| txns[arr[0]] = arr[1] end end txns end |
#value ⇒ Integer
Sum of totals and currently tracked transactions
116 117 118 119 120 121 122 123 124 |
# File 'lib/crdt/tgcounter.rb', line 116 def value() total = self.unique_transactions().values.inject(0, &:+) self.counts.values.each do |a| total += a["total"] end total end |