Class: Riak::Ledger

Inherits:
Object
  • Object
show all
Defined in:
lib/ledger.rb,
lib/ledger/version.rb

Constant Summary collapse

VERSION =
"0.0.5"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(bucket, key, options = {}) ⇒ Ledger

Create a new Ledger object

Parameters:

  • bucket (Riak::Bucket)
  • key (String)
  • options (Hash) (defaults to: {})

    :actor [String]: default Thread.current["name"] || "ACTOR1"
    :history_length [Integer]: default 10
    :retry_count [Integer]: default 10
    



18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/ledger.rb', line 18

def initialize(bucket, key, options={})
  self.bucket = bucket
  self.key = key
  self.retry_count = options[:retry_count] || 10

  self.counter_options = {}
  self.counter_options[:actor] = options[:actor] || Thread.current["name"] || "ACTOR1"
  self.counter_options[:history_length] = options[:history_length] || 10
  self.counter = Riak::CRDT::TPNCounter.new(self.counter_options)

  unless bucket.allow_mult
    self.bucket.allow_mult = true
  end
end

Instance Attribute Details

#bucketObject

Returns the value of attribute bucket.



7
8
9
# File 'lib/ledger.rb', line 7

def bucket
  @bucket
end

#counterObject

Returns the value of attribute counter.



7
8
9
# File 'lib/ledger.rb', line 7

def counter
  @counter
end

#counter_optionsObject

Returns the value of attribute counter_options.



7
8
9
# File 'lib/ledger.rb', line 7

def counter_options
  @counter_options
end

#keyObject

Returns the value of attribute key.



7
8
9
# File 'lib/ledger.rb', line 7

def key
  @key
end

#retry_countObject

Returns the value of attribute retry_count.



7
8
9
# File 'lib/ledger.rb', line 7

def retry_count
  @retry_count
end

Class Method Details

.find!(bucket, key, options = {}) ⇒ Riak::Ledger

Find an existing Ledger object, merge and save it

Parameters:

  • bucket (Riak::Bucket)
  • key (String)
  • options (Hash) (defaults to: {})

    :actor [String]: default Thread.current["name"] || "ACTOR1"
    :history_length [Integer]: default 10
    :retry_count [Integer]: default 10
    

Returns:



43
44
45
46
47
48
49
# File 'lib/ledger.rb', line 43

def self.find!(bucket, key, options={})
  candidate = new(bucket, key, options)
  vclock = candidate.refresh()
  candidate.save(vclock)

  return candidate
end

Instance Method Details

#credit!(transaction, value) ⇒ Boolean

Increment the counter, merge and save it

Parameters:

  • transaction (String)
  • value (Positive Integer)

Returns:

  • (Boolean)

See Also:

  • value)


56
57
58
# File 'lib/ledger.rb', line 56

def credit!(transaction, value)
  self.update!(transaction, value)
end

#debit!(transaction, value) ⇒ Boolean

Decrement the counter, merge and save it

Parameters:

  • transaction (String)
  • value (Positive Integer)

Returns:

  • (Boolean)

See Also:

  • value)


65
66
67
# File 'lib/ledger.rb', line 65

def debit!(transaction, value)
  self.update!(transaction, value * -1)
end

#deleteBoolean

Delete the counter

Returns:

  • (Boolean)


121
122
123
124
125
126
127
128
# File 'lib/ledger.rb', line 121

def delete()
  begin
    self.bucket.delete(self.key)
    return true
  rescue => e
    return false
  end
end

#has_transaction?(transaction) ⇒ Boolean

Check if the counter has transaction

Parameters:

  • transaction (String)

Returns:

  • (Boolean)


109
110
111
# File 'lib/ledger.rb', line 109

def has_transaction?(transaction)
  self.counter.has_transaction?(transaction)
end

#refreshString

Get the current state of the counter and merge it

Returns:

  • (String)


132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/ledger.rb', line 132

def refresh()
  obj = self.bucket.get_or_new(self.key)
  return if obj.nil?

  self.counter = Riak::CRDT::TPNCounter.new(self.counter_options)

  if obj.siblings.length > 1
    obj.siblings.each do | sibling |
      unless sibling.raw_data.nil? or sibling.raw_data.empty?
        self.counter.merge(Riak::CRDT::TPNCounter.from_json(sibling.raw_data, self.counter_options))
      end
    end
  elsif !obj.raw_data.nil?
    self.counter.merge(Riak::CRDT::TPNCounter.from_json(obj.raw_data, self.counter_options))
  end

  return obj.vclock
end

#save(vclock = nil) ⇒ Boolean

Save the counter with an optional vclock

Parameters:

  • vclock (String) (defaults to: nil)

Returns:

  • (Boolean)


154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/ledger.rb', line 154

def save(vclock=nil)
  object = self.bucket.new(self.key)
  object.vclock = vclock if vclock
  object.content_type = 'application/json'
  object.raw_data = self.to_json()

  begin
    options = {:returnbody => false}
    object.store(options)
    return true
  rescue => e
    return false
  end
end

#to_jsonObject



169
170
171
# File 'lib/ledger.rb', line 169

def to_json()
  self.counter.to_json
end

#update!(transaction, value, current_retry = nil) ⇒ Boolean

Update the counter, merge and save it. Retry if unsuccessful

Parameters:

  • transaction (String)
  • value (Integer)
  • current_retry (Integer) (defaults to: nil)

Returns:

  • (Boolean)


74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/ledger.rb', line 74

def update!(transaction, value, current_retry=nil)
  # Failure case, not able to successfully complete the operation, retry a.s.a.p.
  if current_retry && current_retry <= 0
    return false
  end

  # Get the current merged state of this counter
  vclock = self.refresh()


  if self.has_transaction?(transaction)
    # If the transaction already exists in the counter, no problem
    return true
  else
    # If the transaction doesn't exist, attempt to add it and save
    if value < 0
      self.counter.decrement(transaction, value * -1)
    else
      self.counter.increment(transaction, value)
    end

    unless self.save(vclock)
      # If the save wasn't successful, retry
      current_retry = self.retry_count unless current_retry
      self.update!(transaction, value, current_retry - 1)
    else
      # If the save succeeded, no problem
      return true
    end
  end
end

#valueInteger

Calculate the current value of the counter

Returns:

  • (Integer)


115
116
117
# File 'lib/ledger.rb', line 115

def value()
  self.counter.value
end