riak-ruby-ledger 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +9 -1
- data/docs/release_notes.md +16 -12
- data/lib/ledger.rb +2 -4
- data/lib/ledger/version.rb +1 -1
- data/test/lib/ledger_test.rb +11 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NTJhNWMzN2E2NTNiYTQ2MzAzMDM5ODI2NDUwYTZlMjNjZDc1NjE3ZA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NTE5YjllZjJlMWJjMGM4NmZkNzRmNjNjNzEyNmJiY2EyNzg4YjU2OA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MDc5YTA3MGE5MDBhZTc1YTc5Yzc0Y2FjNzQ5YjhmYjgwN2IyZGI0ZGNhYjI0
|
10
|
+
YzI3ZjhhYzZkMTIyOGE4YjU5N2NiNGQ1Njc0YzVhZjI4NzA3ZDI2ZmJiZjA2
|
11
|
+
YTIzNTE4MWQ5YzlkYmMwZjhiZjBmNzcyZjRjZDVjZTk1Zjk5NzA=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZTk4NWM5OWZjYWQ2YjI0NDJmMjA4ODcyZGQ1MjY1YzVjNzFhYjZkNzEwYjQy
|
14
|
+
OWY4OWRiZWZlNzk1ODkzNjNmNTVkMDFlZGViYjFiM2M4YjUzZTk0OTNkMmMw
|
15
|
+
NmU5NjhlYmUzNGM0MTIxZTg5N2NlMDI1YjJmOWIzYmIyOWVlYTA=
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Riak-Ruby-Ledger
|
2
2
|
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/riak-ruby-ledger.png)](http://badge.fury.io/rb/riak-ruby-ledger)
|
4
|
+
|
3
5
|
An alternative to Riak Counters with idempotent writes within a client defined window.
|
4
6
|
|
5
7
|
# Summary
|
@@ -116,6 +118,12 @@ Thread.current["name"] = "ACTOR1"
|
|
116
118
|
# Create a Riak::Client instance
|
117
119
|
client = Riak::Client.new pb_port: 8087
|
118
120
|
|
121
|
+
# Get the Riak::Bucket instance
|
122
|
+
bucket = client["ledgers"]
|
123
|
+
|
124
|
+
# Set allow_mult to true
|
125
|
+
bucket.allow_mult = true unless bucket.allow_mult
|
126
|
+
|
119
127
|
# Default option values
|
120
128
|
options = {
|
121
129
|
:actor => Thread.current["name"], # Actor ID, one per thread or serialized writer
|
@@ -125,7 +133,7 @@ options = {
|
|
125
133
|
|
126
134
|
# Create the ledger object
|
127
135
|
# Riak::Bucket Key Hash
|
128
|
-
ledger = Riak::Ledger.new(
|
136
|
+
ledger = Riak::Ledger.new(bucket, "player_1", options)
|
129
137
|
```
|
130
138
|
|
131
139
|
### Credit and debit
|
data/docs/release_notes.md
CHANGED
@@ -5,24 +5,24 @@
|
|
5
5
|
In version 0.0.4 of this gem, counter drift is still a possibility. Take the following scenario into consideration:
|
6
6
|
|
7
7
|
1. Actor 1 and Actor 2 both are somehow trying to write the same transaction id, possibly because the process writing the transaction took too long, and your application erroneously had a policy of retrying the same transaction before the first actor finished.
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
1. If the Actor 1 is successful in writing the transaction before Actor 2 begins, Actor 2 will see that the transaction id already exists, and will return successful before attempting to write.
|
9
|
+
2. Similarly, if Actor 2 finishes before Actor 1 starts, Actor 1 would disregard the request and report success.
|
10
|
+
3. If Actor 1 and Actor 2 simultaneously and successfully write the same transaction, a result of is two siblings.
|
11
11
|
2. If 1a or 1b happen, there is no problem. If 1c occurs, the second line of defense happens during a merge (merges are triggered prior to every write, and after every read).
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
1. If Actor 1 merges before Actor 2, Actor 1 will remove it's own duplicate transaction in favor of leaving Actor 2's version, knowing it cannot modify any other actors' data.
|
13
|
+
2. Similarly, if Actor 2 merges before Actor 1, it will remove it's own duplicate transaction.
|
14
|
+
3. If Actor 1 and Actor 2 merge simultaneously and successfully, they would both remove their own duplicate (from their point of view) version of the transaction, meaning it would be lost causing negative counter drift (on increments) and positive drift (on decrements)
|
15
15
|
|
16
16
|
This is an unlikely but possible scenario. Here are some ways to reduce or elimiate the possibility of 2c from happening:
|
17
17
|
|
18
18
|
1. The precursor to the condition resulting from 2c can be avoided by serializing writes per transaction, like in the example of a game's application server knowing to only submit one unique transaction at a time. Submitting simultaneous transactions is ok, so long as the same transaction isn't active in more than one actor at the same time.
|
19
|
-
|
19
|
+
1. This is possible using this gem, it's just a matter of implemeting some control over who can write a single unique at the same time.
|
20
20
|
2. Have a no duplicate delete policy, meaning that you could potentially have an infinitely growing list of duplicate transactions if your application causes this situation often.
|
21
|
-
|
21
|
+
1. This is unimplemented in this gem as of now, but depending on the thoughts of others, I may add it as an optional policy.
|
22
22
|
3. Attach a microsecond epoch to each transaction so that during merges the the duplicate transaction with the highest epoch always wins.
|
23
|
-
|
24
|
-
4. Do a string compare on the actor ids, whichever has the highest string compare value always keeps it's version of the duplicate transaction.
|
25
|
-
|
23
|
+
1. This is unimplemented in this gem, and it would only lessen the statistical likelihood of 2c happening, it would still be possible. Because it only lowers the likelihood.
|
24
|
+
4. Do a string compare on the actor ids, whichever has the highest string compare value always keeps it's version of the duplicate transaction. If one the lesser actor is stale and never merges, the actor that should keep the transaction will throw it away knowing that the stale actor will keep it.
|
25
|
+
1. This is now implemented in version 0.0.5, see below.
|
26
26
|
|
27
27
|
##### Version 0.0.5 and Actor Naming [***Important***]
|
28
28
|
|
@@ -30,4 +30,8 @@ Solution 4 has been implemented to the potential counter drift caused by two sim
|
|
30
30
|
|
31
31
|
As a result, keep in mind that when naming actors, they will be compared for ordering purposes
|
32
32
|
|
33
|
-
Example: "ACTOR2" is greater than "ACTOR1", so ACTOR1 will always remove it's version of a duplicate transaction during a merge, and "ACTOR2" will never remove it's version. Avoid using actor ids that could potentially result in string equality.
|
33
|
+
Example: "ACTOR2" is greater than "ACTOR1", so ACTOR1 will always remove it's version of a duplicate transaction during a merge, and "ACTOR2" will never remove it's version unless it thinks actor 1 is stale. Avoid using actor ids that could potentially result in string equality.
|
34
|
+
|
35
|
+
##### Version 0.0.5
|
36
|
+
|
37
|
+
Removed the automatic setting of allow_mult on the bucket in Riak::Ledger. Please remember to set allow_mult to true on your ledger bucket, notes in README.md
|
data/lib/ledger.rb
CHANGED
@@ -16,6 +16,8 @@ module Riak
|
|
16
16
|
# :retry_count [Integer]: default 10
|
17
17
|
# }
|
18
18
|
def initialize(bucket, key, options={})
|
19
|
+
raise ArgumentError, 'Argument "bucket" must have "allow_mult" property set to true' unless bucket.allow_mult
|
20
|
+
|
19
21
|
self.bucket = bucket
|
20
22
|
self.key = key
|
21
23
|
self.retry_count = options[:retry_count] || 10
|
@@ -24,10 +26,6 @@ module Riak
|
|
24
26
|
self.counter_options[:actor] = options[:actor] || Thread.current["name"] || "ACTOR1"
|
25
27
|
self.counter_options[:history_length] = options[:history_length] || 10
|
26
28
|
self.counter = Riak::CRDT::TPNCounter.new(self.counter_options)
|
27
|
-
|
28
|
-
unless bucket.allow_mult
|
29
|
-
self.bucket.allow_mult = true
|
30
|
-
end
|
31
29
|
end
|
32
30
|
|
33
31
|
# Find an existing Ledger object, merge and save it
|
data/lib/ledger/version.rb
CHANGED
data/test/lib/ledger_test.rb
CHANGED
@@ -9,6 +9,7 @@ describe Riak::Ledger do
|
|
9
9
|
before do
|
10
10
|
client = Riak::Client.new pb_port: 8087
|
11
11
|
@bucket = client["ledger_test"]
|
12
|
+
@bucket.allow_mult = true
|
12
13
|
@key = "player_1"
|
13
14
|
|
14
15
|
|
@@ -21,8 +22,17 @@ describe Riak::Ledger do
|
|
21
22
|
@ledger2.delete()
|
22
23
|
end
|
23
24
|
|
24
|
-
it "
|
25
|
+
it "must raise an error if mult is not allowed" do
|
26
|
+
@bucket.allow_mult = false
|
27
|
+
|
28
|
+
assert_raises ArgumentError do
|
29
|
+
Riak::Ledger.new(@bucket, @key, options1)
|
30
|
+
end
|
25
31
|
|
32
|
+
@bucket.allow_mult = true
|
33
|
+
end
|
34
|
+
|
35
|
+
it "have a valid starting state" do
|
26
36
|
assert_equal({:type=>"TGCounter", :c=>{"ACTOR1"=>{"total"=>0, "txns"=>[]}}}, @ledger1.counter.p.to_hash)
|
27
37
|
assert_equal({:type=>"TGCounter", :c=>{"ACTOR1"=>{"total"=>0, "txns"=>[]}}}, @ledger1.counter.n.to_hash)
|
28
38
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: riak-ruby-ledger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- drewkerrigan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-12-
|
11
|
+
date: 2013-12-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|