riak-client 1.0.5 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +4 -3
- data/.rspec +1 -0
- data/Gemfile +1 -0
- data/RELEASE_NOTES.md +47 -0
- data/Rakefile +0 -1
- data/erl_src/riak_kv_test_backend.erl +34 -0
- data/lib/riak/client.rb +3 -1
- data/lib/riak/client/beefcake/messages.rb +49 -1
- data/lib/riak/client/beefcake/object_methods.rb +14 -21
- data/lib/riak/client/beefcake_protobuffs_backend.rb +58 -12
- data/lib/riak/client/decaying.rb +31 -23
- data/lib/riak/client/feature_detection.rb +88 -0
- data/lib/riak/client/http_backend.rb +27 -6
- data/lib/riak/client/http_backend/configuration.rb +13 -0
- data/lib/riak/client/http_backend/object_methods.rb +33 -25
- data/lib/riak/client/node.rb +7 -2
- data/lib/riak/client/protobuffs_backend.rb +54 -3
- data/lib/riak/client/search.rb +2 -2
- data/lib/riak/conflict.rb +13 -0
- data/lib/riak/locale/en.yml +2 -0
- data/lib/riak/map_reduce.rb +1 -1
- data/lib/riak/map_reduce/filter_builder.rb +2 -2
- data/lib/riak/map_reduce/results.rb +49 -0
- data/lib/riak/node/console.rb +17 -16
- data/lib/riak/node/generation.rb +9 -0
- data/lib/riak/rcontent.rb +168 -0
- data/lib/riak/robject.rb +37 -157
- data/lib/riak/util/escape.rb +5 -1
- data/lib/riak/version.rb +1 -1
- data/riak-client.gemspec +37 -5
- data/spec/fixtures/multipart-basic-conflict.txt +15 -0
- data/spec/fixtures/munchausen.txt +1033 -0
- data/spec/integration/riak/cluster_spec.rb +1 -1
- data/spec/integration/riak/http_backends_spec.rb +23 -2
- data/spec/integration/riak/node_spec.rb +2 -2
- data/spec/integration/riak/protobuffs_backends_spec.rb +17 -2
- data/spec/integration/riak/test_server_spec.rb +1 -1
- data/spec/integration/riak/threading_spec.rb +3 -3
- data/spec/riak/beefcake_protobuffs_backend_spec.rb +58 -25
- data/spec/riak/escape_spec.rb +3 -0
- data/spec/riak/feature_detection_spec.rb +61 -0
- data/spec/riak/http_backend/object_methods_spec.rb +4 -13
- data/spec/riak/http_backend_spec.rb +6 -5
- data/spec/riak/map_reduce_spec.rb +0 -5
- data/spec/riak/robject_spec.rb +12 -11
- data/spec/spec_helper.rb +3 -1
- data/spec/support/riak_test.rb +77 -0
- data/spec/support/search_corpus_setup.rb +18 -0
- data/spec/support/sometimes.rb +1 -1
- data/spec/support/test_server.rb +1 -1
- data/spec/support/unified_backend_examples.rb +53 -7
- data/spec/support/version_filter.rb +4 -11
- metadata +56 -22
- data/lib/riak/client/pool.rb +0 -180
- data/spec/riak/pool_spec.rb +0 -306
data/.document
ADDED
data/.gitignore
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
## NOTE: This file must be manually kept in sync with the gemspec, but
|
2
|
+
## should not normally need to be modified unless new top-level files
|
3
|
+
## or directory trees are being added.
|
4
|
+
|
1
5
|
## MAC OS
|
2
6
|
.DS_Store
|
3
7
|
|
@@ -18,9 +22,6 @@ coverage
|
|
18
22
|
rdoc
|
19
23
|
pkg
|
20
24
|
|
21
|
-
## This line is for the dirglob only
|
22
|
-
pkg/*
|
23
|
-
|
24
25
|
## PROJECT::SPECIFIC
|
25
26
|
_notes
|
26
27
|
doc
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
CHANGED
data/RELEASE_NOTES.md
CHANGED
@@ -1,5 +1,52 @@
|
|
1
1
|
# Riak Ruby Client Release Notes
|
2
2
|
|
3
|
+
## 1.1.0 Feature Release - 2012-11-07
|
4
|
+
|
5
|
+
Release 1.1.0 includes full Riak 1.2 compatibility, and includes
|
6
|
+
improvements to the handling of siblings, the node generation
|
7
|
+
tools, and resolves a number of important bugs.
|
8
|
+
|
9
|
+
Features:
|
10
|
+
|
11
|
+
* Client features are enabled or disabled based on the detected Riak
|
12
|
+
version.
|
13
|
+
* Riak 1.2 compatibility, including search and 2I over Protocol
|
14
|
+
Buffers.
|
15
|
+
* Phaseless MapReduce (which was available in 1.1) is allowed, using
|
16
|
+
feature detection to determine whether an exception is raised.
|
17
|
+
* Conditional store_object operations on Protocol Buffers use the
|
18
|
+
message features available since Riak 1.0.
|
19
|
+
* The integration test-suite can be run without generating a test
|
20
|
+
node, which lets us support riak_test.
|
21
|
+
|
22
|
+
Bugfixes:
|
23
|
+
|
24
|
+
* URL-escaping now allows some normally URI-safe characters to be
|
25
|
+
escaped.
|
26
|
+
* JRuby should be more reliable when attaching to a generated node's
|
27
|
+
console.
|
28
|
+
* The client backend pool has been extracted to the Innertube gem,
|
29
|
+
which is now a dependency.
|
30
|
+
* Fix a documentation issue around key-filters.
|
31
|
+
* Fix RSpec formatter and deprecation errors.
|
32
|
+
* Object siblings are now a separate class (RContent) rather than
|
33
|
+
being unclean copies of the parent RObject. If only one sibling
|
34
|
+
exists, the original accessors (e.g. `content_type`, `data`) will
|
35
|
+
behave as expected. When more than one sibling exists, they will
|
36
|
+
raise `Riak::Conflict`. This should prevent unintentional storing of
|
37
|
+
unresolved objects back into Riak as `multipart/mixed` values.
|
38
|
+
* `Riak::Client#ssl=` won't blow away existing `ssl_options` if set to
|
39
|
+
`true`.
|
40
|
+
* Generated nodes will ensure that the source's
|
41
|
+
`ssl_distribution.args_file` exists by invoking `riak chkconfig`.
|
42
|
+
* Copy fixes for the `$key` index on the memory/test backend from
|
43
|
+
riak_kv.
|
44
|
+
* The shape of MapReduce results will no longer be changed by the
|
45
|
+
Protocol Buffers backend, which manifested as kept phases without
|
46
|
+
results being removed from the return value. Implementing this
|
47
|
+
required all HTTP requests to use streaming, even if invoked without
|
48
|
+
a block.
|
49
|
+
|
3
50
|
## 1.0.5 Packaging Fix Release - 2012-10-12
|
4
51
|
|
5
52
|
Release 1.0.5 fixes a bug with the RubyGems packaging that
|
data/Rakefile
CHANGED
@@ -61,6 +61,7 @@
|
|
61
61
|
|
62
62
|
-ifdef(TEST).
|
63
63
|
-include_lib("eunit/include/eunit.hrl").
|
64
|
+
-compile([export_all]).
|
64
65
|
-endif.
|
65
66
|
|
66
67
|
-define(API_VERSION, 1).
|
@@ -427,6 +428,9 @@ fold_keys_fun(FoldKeysFun, {index, FilterBucket, {eq, <<"$bucket">>, _}}) ->
|
|
427
428
|
fold_keys_fun(FoldKeysFun, {index, FilterBucket, {range, <<"$key">>, _, _}}) ->
|
428
429
|
%% 2I range query on special $key field...
|
429
430
|
fold_keys_fun(FoldKeysFun, {bucket, FilterBucket});
|
431
|
+
fold_keys_fun(FoldKeysFun, {index, FilterBucket, {eq, <<"$key">>, _}}) ->
|
432
|
+
%% 2I eq query on special $key field...
|
433
|
+
fold_keys_fun(FoldKeysFun, {bucket, FilterBucket});
|
430
434
|
fold_keys_fun(FoldKeysFun, {index, _FilterBucket, _Query}) ->
|
431
435
|
fun({{Bucket, _FilterField, _FilterTerm, Key}, _}, Acc) ->
|
432
436
|
FoldKeysFun(Bucket, Key, Acc);
|
@@ -469,6 +473,8 @@ get_index_folder(Folder, Acc0, {index, Bucket, {range, <<"$key">>, Min, Max}}, D
|
|
469
473
|
fun() ->
|
470
474
|
key_range_folder(Folder, Acc0, DataRef, {Bucket, Min}, {Bucket, Min, Max})
|
471
475
|
end;
|
476
|
+
get_index_folder(Folder, Acc0, {index, Bucket, {eq, <<"$key">>, Val}}, DataRef, IndexRef) ->
|
477
|
+
get_index_folder(Folder, Acc0, {index, Bucket, {range, <<"$key">>, Val, Val}}, DataRef, IndexRef);
|
472
478
|
get_index_folder(Folder, Acc0, {index, Bucket, {eq, Field, Term}}, _, IndexRef) ->
|
473
479
|
fun() ->
|
474
480
|
index_range_folder(Folder, Acc0, IndexRef, {Bucket, Field, Term, undefined}, {Bucket, Field, Term, Term})
|
@@ -668,6 +674,34 @@ max_memory_test_() ->
|
|
668
674
|
?_assertEqual({ok, Value2, State2}, get(Bucket, Key2, State2))
|
669
675
|
].
|
670
676
|
|
677
|
+
regression_367_key_range_test_() ->
|
678
|
+
{ok, State} = start(142, []),
|
679
|
+
Keys = [begin
|
680
|
+
Bin = list_to_binary(integer_to_list(I)),
|
681
|
+
if I < 10 ->
|
682
|
+
<<"obj0", Bin/binary>>;
|
683
|
+
true -> <<"obj", Bin/binary>>
|
684
|
+
end
|
685
|
+
end || I <- lists:seq(1,30) ],
|
686
|
+
Bucket = <<"keyrange">>,
|
687
|
+
Value = <<"foobarbaz">>,
|
688
|
+
State1 = lists:foldl(fun(Key, IState) ->
|
689
|
+
{ok, NewState} = put(Bucket, Key, [], Value, IState),
|
690
|
+
NewState
|
691
|
+
end, State, Keys),
|
692
|
+
Folder = fun(_B, K, Acc) ->
|
693
|
+
Acc ++ [K]
|
694
|
+
end,
|
695
|
+
[
|
696
|
+
?_assertEqual({ok, [<<"obj01">>]}, fold_keys(Folder, [], [{index, Bucket, {range, <<"$key">>, <<"obj01">>, <<"obj01">>}}], State1)),
|
697
|
+
?_assertEqual({ok, [<<"obj10">>,<<"obj11">>]}, fold_keys(Folder, [], [{index, Bucket, {range, <<"$key">>, <<"obj10">>, <<"obj11">>}}], State1)),
|
698
|
+
?_assertEqual({ok, [<<"obj01">>]}, fold_keys(Folder, [], [{index, Bucket, {range, <<"$key">>, <<"obj00">>, <<"obj01">>}}], State1)),
|
699
|
+
?_assertEqual({ok, lists:sort(Keys)}, fold_keys(Folder, [], [{index, Bucket, {range, <<"$key">>, <<"obj0">>, <<"obj31">>}}], State1)),
|
700
|
+
?_assertEqual({ok, []}, fold_keys(Folder, [], [{index, Bucket, {range, <<"$key">>, <<"obj31">>, <<"obj32">>}}], State1)),
|
701
|
+
?_assertEqual({ok, [<<"obj01">>]}, fold_keys(Folder, [], [{index, Bucket, {eq, <<"$key">>, <<"obj01">>}}], State1)),
|
702
|
+
?_assertEqual(ok, stop(State1))
|
703
|
+
].
|
704
|
+
|
671
705
|
-ifdef(EQC).
|
672
706
|
|
673
707
|
eqc_test_() ->
|
data/lib/riak/client.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'tempfile'
|
2
2
|
require 'delegate'
|
3
|
+
require 'innertube'
|
3
4
|
require 'riak'
|
4
5
|
require 'riak/util/translation'
|
5
6
|
require 'riak/util/escape'
|
6
7
|
require 'riak/failed_request'
|
7
|
-
require 'riak/client/pool'
|
8
8
|
require 'riak/client/decaying'
|
9
9
|
require 'riak/client/node'
|
10
10
|
require 'riak/client/search'
|
@@ -47,6 +47,8 @@ module Riak
|
|
47
47
|
SystemCallError,
|
48
48
|
]
|
49
49
|
|
50
|
+
Pool = ::Innertube::Pool
|
51
|
+
|
50
52
|
# @return [String] The protocol to use for the Riak endpoint
|
51
53
|
attr_reader :protocol
|
52
54
|
|
@@ -89,7 +89,7 @@ module Riak
|
|
89
89
|
required :content, RpbContent, 4
|
90
90
|
optional :w, :uint32, 5
|
91
91
|
optional :dw, :uint32, 6
|
92
|
-
optional :returnbody,
|
92
|
+
optional :returnbody, :bool, 7
|
93
93
|
optional :pw, :uint32, 8
|
94
94
|
optional :if_not_modified, :bool, 9
|
95
95
|
optional :if_none_match, :bool, 10
|
@@ -160,6 +160,54 @@ module Riak
|
|
160
160
|
optional :response, :bytes, 2
|
161
161
|
optional :done, :bool, 3
|
162
162
|
end
|
163
|
+
|
164
|
+
class RpbIndexReq
|
165
|
+
include Beefcake::Message
|
166
|
+
module IndexQueryType
|
167
|
+
EQ = 0
|
168
|
+
RANGE = 1
|
169
|
+
end
|
170
|
+
|
171
|
+
required :bucket, :bytes, 1
|
172
|
+
required :index, :bytes, 2
|
173
|
+
required :qtype, IndexQueryType, 3
|
174
|
+
optional :key, :bytes, 4
|
175
|
+
optional :range_min, :bytes, 5
|
176
|
+
optional :range_max, :bytes, 6
|
177
|
+
end
|
178
|
+
|
179
|
+
class RpbIndexResp
|
180
|
+
include Beefcake::Message
|
181
|
+
repeated :keys, :bytes, 1
|
182
|
+
end
|
183
|
+
|
184
|
+
class RpbSearchDoc
|
185
|
+
include Beefcake::Message
|
186
|
+
# We have to name this differently than the .proto file does
|
187
|
+
# because Beefcake uses 'fields' as an instance method.
|
188
|
+
repeated :properties, RpbPair, 1
|
189
|
+
end
|
190
|
+
|
191
|
+
class RpbSearchQueryReq
|
192
|
+
include Beefcake::Message
|
193
|
+
required :q, :bytes, 1
|
194
|
+
required :index, :bytes, 2
|
195
|
+
optional :rows, :uint32, 3
|
196
|
+
optional :start, :uint32, 4
|
197
|
+
optional :sort, :bytes, 5
|
198
|
+
optional :filter, :bytes, 6
|
199
|
+
optional :df, :bytes, 7
|
200
|
+
optional :op, :bytes, 8
|
201
|
+
repeated :fl, :bytes, 9
|
202
|
+
optional :presort, :bytes, 10
|
203
|
+
end
|
204
|
+
|
205
|
+
class RpbSearchQueryResp
|
206
|
+
include Beefcake::Message
|
207
|
+
repeated :docs, RpbSearchDoc, 1, :default => []
|
208
|
+
optional :max_score, :float, 2
|
209
|
+
optional :num_found, :uint32, 3
|
210
|
+
end
|
163
211
|
end
|
164
212
|
end
|
165
213
|
end
|
@@ -31,40 +31,33 @@ module Riak
|
|
31
31
|
return robject if pbuf.respond_to?(:unchanged) && pbuf.unchanged # Reloading
|
32
32
|
robject.vclock = Base64.encode64(pbuf.vclock).chomp if pbuf.vclock
|
33
33
|
robject.key = maybe_unescape(pbuf.key) if pbuf.respond_to?(:key) && pbuf.key # Put w/o key
|
34
|
-
|
35
|
-
robject
|
36
|
-
robject.siblings = pbuf.content.map do |c|
|
37
|
-
sibling = RObject.new(robject.bucket, robject.key)
|
38
|
-
sibling.vclock = robject.vclock
|
34
|
+
robject.siblings = pbuf.content.map do |c|
|
35
|
+
RContent.new(robject) do |sibling|
|
39
36
|
load_content(c, sibling)
|
40
37
|
end
|
41
|
-
|
42
|
-
return robject.attempt_conflict_resolution
|
43
|
-
else
|
44
|
-
load_content(pbuf.content.first, robject)
|
45
38
|
end
|
46
|
-
robject
|
39
|
+
robject.conflict? ? robject.attempt_conflict_resolution : robject
|
47
40
|
end
|
48
41
|
|
49
42
|
private
|
50
|
-
def load_content(pbuf,
|
43
|
+
def load_content(pbuf, rcontent)
|
51
44
|
if ENCODING && pbuf.charset.present?
|
52
45
|
pbuf.value.force_encoding(pbuf.charset) if Encoding.find(pbuf.charset)
|
53
46
|
end
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
pbuf.usermeta.each {|pair| decode_meta(pair,
|
47
|
+
rcontent.raw_data = pbuf.value
|
48
|
+
rcontent.etag = pbuf.vtag if pbuf.vtag.present?
|
49
|
+
rcontent.content_type = pbuf.content_type if pbuf.content_type.present?
|
50
|
+
rcontent.links = pbuf.links.map(&method(:decode_link)) if pbuf.links.present?
|
51
|
+
pbuf.usermeta.each {|pair| decode_meta(pair, rcontent.meta) } if pbuf.usermeta.present?
|
59
52
|
if pbuf.indexes.present?
|
60
|
-
|
61
|
-
pbuf.indexes.each {|pair| decode_index(pair,
|
53
|
+
rcontent.indexes.clear
|
54
|
+
pbuf.indexes.each {|pair| decode_index(pair, rcontent.indexes) }
|
62
55
|
end
|
63
56
|
if pbuf.last_mod.present?
|
64
|
-
|
65
|
-
|
57
|
+
rcontent.last_modified = Time.at(pbuf.last_mod)
|
58
|
+
rcontent.last_modified += pbuf.last_mod_usecs / 1000000 if pbuf.last_mod_usecs.present?
|
66
59
|
end
|
67
|
-
|
60
|
+
rcontent
|
68
61
|
end
|
69
62
|
|
70
63
|
def decode_link(pbuf)
|
@@ -31,7 +31,7 @@ module Riak
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def fetch_object(bucket, key, options={})
|
34
|
-
options = normalize_quorums(options)
|
34
|
+
options = prune_unsupported_options(:GetReq, normalize_quorums(options))
|
35
35
|
bucket = Bucket === bucket ? bucket.name : bucket
|
36
36
|
req = RpbGetReq.new(options.merge(:bucket => maybe_encode(bucket), :key => maybe_encode(key)))
|
37
37
|
write_protobuff(:GetReq, req)
|
@@ -43,18 +43,25 @@ module Riak
|
|
43
43
|
options[:bucket] = maybe_encode(robject.bucket.name)
|
44
44
|
options[:key] = maybe_encode(robject.key)
|
45
45
|
options[:if_modified] = maybe_encode Base64.decode64(robject.vclock) if robject.vclock
|
46
|
-
req = RpbGetReq.new(options)
|
46
|
+
req = RpbGetReq.new(prune_unsupported_options(:GetReq, options))
|
47
47
|
write_protobuff(:GetReq, req)
|
48
48
|
decode_response(robject)
|
49
49
|
end
|
50
50
|
|
51
51
|
def store_object(robject, options={})
|
52
|
+
options = normalize_quorums(options)
|
52
53
|
if robject.prevent_stale_writes
|
53
|
-
|
54
|
-
|
54
|
+
unless pb_conditionals?
|
55
|
+
other = fetch_object(robject.bucket, robject.key)
|
56
|
+
raise Riak::ProtobuffsFailedRequest.new(:stale_object, t("stale_write_prevented")) unless other.vclock == robject.vclock
|
57
|
+
end
|
58
|
+
if robject.vclock
|
59
|
+
options[:if_not_modified] = true
|
60
|
+
else
|
61
|
+
options[:if_none_match] = true
|
62
|
+
end
|
55
63
|
end
|
56
|
-
|
57
|
-
req = dump_object(robject, options)
|
64
|
+
req = dump_object(robject, prune_unsupported_options(:PutReq, options))
|
58
65
|
write_protobuff(:PutReq, req)
|
59
66
|
decode_response(robject)
|
60
67
|
end
|
@@ -65,7 +72,7 @@ module Riak
|
|
65
72
|
options[:bucket] = maybe_encode(bucket)
|
66
73
|
options[:key] = maybe_encode(key)
|
67
74
|
options[:vclock] = Base64.decode64(options[:vclock]) if options[:vclock]
|
68
|
-
req = RpbDelReq.new(options)
|
75
|
+
req = RpbDelReq.new(prune_unsupported_options(:DelReq, options))
|
69
76
|
write_protobuff(:DelReq, req)
|
70
77
|
decode_response
|
71
78
|
end
|
@@ -102,19 +109,47 @@ module Riak
|
|
102
109
|
end
|
103
110
|
|
104
111
|
def mapred(mr, &block)
|
112
|
+
raise MapReduceError.new(t("empty_map_reduce_query")) if mr.query.empty? && !mapred_phaseless?
|
105
113
|
req = RpbMapRedReq.new(:request => mr.to_json, :content_type => "application/json")
|
106
114
|
write_protobuff(:MapRedReq, req)
|
107
|
-
results =
|
115
|
+
results = MapReduce::Results.new(mr)
|
108
116
|
while msg = decode_response
|
109
117
|
break if msg.done
|
110
118
|
if block_given?
|
111
119
|
yield msg.phase, JSON.parse(msg.response)
|
112
120
|
else
|
113
|
-
results
|
114
|
-
results[msg.phase] += JSON.parse(msg.response)
|
121
|
+
results.add msg.phase, JSON.parse(msg.response)
|
115
122
|
end
|
116
123
|
end
|
117
|
-
block_given? || results.
|
124
|
+
block_given? || results.report
|
125
|
+
end
|
126
|
+
|
127
|
+
def get_index(bucket, index, query)
|
128
|
+
return super unless pb_indexes?
|
129
|
+
if Range === query
|
130
|
+
options = {
|
131
|
+
:qtype => RpbIndexReq::IndexQueryType::RANGE,
|
132
|
+
:range_min => query.begin.to_s,
|
133
|
+
:range_max => query.end.to_s
|
134
|
+
}
|
135
|
+
else
|
136
|
+
options = {
|
137
|
+
:qtype => RpbIndexReq::IndexQueryType::EQ,
|
138
|
+
:key => query.to_s
|
139
|
+
}
|
140
|
+
end
|
141
|
+
req = RpbIndexReq.new(options.merge(:bucket => bucket, :index => index))
|
142
|
+
write_protobuff(:IndexReq, req)
|
143
|
+
decode_response
|
144
|
+
end
|
145
|
+
|
146
|
+
def search(index, query, options={})
|
147
|
+
return super unless pb_search?
|
148
|
+
options = options.symbolize_keys
|
149
|
+
options[:op] = options.delete(:'q.op') if options[:'q.op']
|
150
|
+
req = RpbSearchQueryReq.new(options.merge(:index => index || 'search', :q => query))
|
151
|
+
write_protobuff(:SearchQueryReq, req)
|
152
|
+
decode_response
|
118
153
|
end
|
119
154
|
|
120
155
|
private
|
@@ -167,12 +202,23 @@ module Riak
|
|
167
202
|
{'n_val' => res.props.n_val, 'allow_mult' => res.props.allow_mult}
|
168
203
|
when :MapRedResp
|
169
204
|
RpbMapRedResp.decode(message)
|
205
|
+
when :IndexResp
|
206
|
+
res = RpbIndexResp.decode(message)
|
207
|
+
res.keys
|
208
|
+
when :SearchQueryResp
|
209
|
+
res = RpbSearchQueryResp.decode(message)
|
210
|
+
{ 'docs' => res.docs.map {|d| decode_doc(d) },
|
211
|
+
'max_score' => res.max_score,
|
212
|
+
'num_found' => res.num_found }
|
170
213
|
end
|
171
214
|
end
|
172
215
|
rescue SystemCallError, SocketError => e
|
173
216
|
reset_socket
|
174
217
|
raise
|
175
|
-
|
218
|
+
end
|
219
|
+
|
220
|
+
def decode_doc(doc)
|
221
|
+
Hash[doc.properties.map {|p| [ p.key, p.value ] }]
|
176
222
|
end
|
177
223
|
end
|
178
224
|
end
|
data/lib/riak/client/decaying.rb
CHANGED
@@ -1,28 +1,36 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
module Riak
|
2
|
+
class Client
|
3
|
+
# A float value which decays exponentially toward 0 over time.
|
4
|
+
# @private
|
5
|
+
class Decaying
|
6
|
+
attr_accessor :e
|
7
|
+
attr_accessor :p
|
3
8
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
# @param [Hash] opts options
|
10
|
+
# @option options [Float] :p (0.0) The initial value
|
11
|
+
# @option options [Float] :e (Math::E) Exponent base
|
12
|
+
# @option options [Float] :r (Math.log(0.5) / 10) Timescale
|
13
|
+
# factor - defaulting to decay 50% every 10 seconds
|
14
|
+
def initialize(opts = {})
|
15
|
+
@p = opts[:p] || 0.0
|
16
|
+
@e = opts[:e] || Math::E
|
17
|
+
@r = opts[:r] || Math.log(0.5) / 10
|
18
|
+
@t0 = Time.now
|
19
|
+
end
|
15
20
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
21
|
+
# Add to current value.
|
22
|
+
# @param [Float] d the value to add
|
23
|
+
def <<(d)
|
24
|
+
@p = value + d
|
25
|
+
end
|
20
26
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
+
# @return [Float] the current value (adjusted for the time decay)
|
28
|
+
def value
|
29
|
+
now = Time.now
|
30
|
+
dt = now - @t0
|
31
|
+
@t0 = now
|
32
|
+
@p = @p * (@e ** (@r * dt))
|
33
|
+
end
|
34
|
+
end
|
27
35
|
end
|
28
36
|
end
|