riak-client-noenc 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.gitignore +42 -0
- data/.rspec +1 -0
- data/Gemfile +17 -0
- data/Guardfile +20 -0
- data/LICENSE.md +16 -0
- data/README.markdown +640 -0
- data/RELEASE_NOTES.md +392 -0
- data/Rakefile +119 -0
- data/lib/riak.rb +22 -0
- data/lib/riak/bucket.rb +297 -0
- data/lib/riak/bucket_properties.rb +74 -0
- data/lib/riak/bucket_type.rb +77 -0
- data/lib/riak/bucket_typed/bucket.rb +121 -0
- data/lib/riak/client.rb +433 -0
- data/lib/riak/client/beefcake/bucket_properties_operator.rb +178 -0
- data/lib/riak/client/beefcake/crdt/counter_loader.rb +18 -0
- data/lib/riak/client/beefcake/crdt/map_loader.rb +64 -0
- data/lib/riak/client/beefcake/crdt/set_loader.rb +18 -0
- data/lib/riak/client/beefcake/crdt_loader.rb +84 -0
- data/lib/riak/client/beefcake/crdt_operator.rb +223 -0
- data/lib/riak/client/beefcake/footer +4 -0
- data/lib/riak/client/beefcake/header +6 -0
- data/lib/riak/client/beefcake/message_codes.rb +89 -0
- data/lib/riak/client/beefcake/message_overlay.rb +87 -0
- data/lib/riak/client/beefcake/messages.rb +772 -0
- data/lib/riak/client/beefcake/object_methods.rb +112 -0
- data/lib/riak/client/beefcake/protocol.rb +105 -0
- data/lib/riak/client/beefcake/socket.rb +260 -0
- data/lib/riak/client/beefcake_protobuffs_backend.rb +538 -0
- data/lib/riak/client/decaying.rb +36 -0
- data/lib/riak/client/feature_detection.rb +120 -0
- data/lib/riak/client/instrumentation.rb +19 -0
- data/lib/riak/client/node.rb +49 -0
- data/lib/riak/client/protobuffs_backend.rb +143 -0
- data/lib/riak/client/search.rb +27 -0
- data/lib/riak/client/yokozuna.rb +52 -0
- data/lib/riak/conflict.rb +13 -0
- data/lib/riak/core_ext.rb +7 -0
- data/lib/riak/core_ext/blank.rb +53 -0
- data/lib/riak/core_ext/deep_dup.rb +13 -0
- data/lib/riak/core_ext/extract_options.rb +7 -0
- data/lib/riak/core_ext/json.rb +15 -0
- data/lib/riak/core_ext/slice.rb +18 -0
- data/lib/riak/core_ext/stringify_keys.rb +10 -0
- data/lib/riak/core_ext/symbolize_keys.rb +10 -0
- data/lib/riak/core_ext/to_param.rb +31 -0
- data/lib/riak/counter.rb +101 -0
- data/lib/riak/crdt.rb +21 -0
- data/lib/riak/crdt/base.rb +183 -0
- data/lib/riak/crdt/batch_counter.rb +19 -0
- data/lib/riak/crdt/batch_map.rb +41 -0
- data/lib/riak/crdt/counter.rb +82 -0
- data/lib/riak/crdt/inner_counter.rb +81 -0
- data/lib/riak/crdt/inner_flag.rb +42 -0
- data/lib/riak/crdt/inner_map.rb +75 -0
- data/lib/riak/crdt/inner_register.rb +26 -0
- data/lib/riak/crdt/inner_set.rb +102 -0
- data/lib/riak/crdt/map.rb +121 -0
- data/lib/riak/crdt/operation.rb +19 -0
- data/lib/riak/crdt/set.rb +166 -0
- data/lib/riak/crdt/typed_collection.rb +181 -0
- data/lib/riak/encoding.rb +6 -0
- data/lib/riak/errors/backend_creation.rb +9 -0
- data/lib/riak/errors/base.rb +9 -0
- data/lib/riak/errors/connection_error.rb +50 -0
- data/lib/riak/errors/crdt_error.rb +38 -0
- data/lib/riak/errors/failed_request.rb +58 -0
- data/lib/riak/errors/protobuffs_error.rb +11 -0
- data/lib/riak/errors/search_error.rb +35 -0
- data/lib/riak/i18n.rb +7 -0
- data/lib/riak/index_collection.rb +71 -0
- data/lib/riak/instrumentation.rb +6 -0
- data/lib/riak/json.rb +52 -0
- data/lib/riak/link.rb +96 -0
- data/lib/riak/list_buckets.rb +28 -0
- data/lib/riak/locale/en.yml +107 -0
- data/lib/riak/locale/fr.yml +51 -0
- data/lib/riak/map_reduce.rb +295 -0
- data/lib/riak/map_reduce/filter_builder.rb +103 -0
- data/lib/riak/map_reduce/phase.rb +98 -0
- data/lib/riak/map_reduce/results.rb +49 -0
- data/lib/riak/map_reduce_error.rb +7 -0
- data/lib/riak/multiget.rb +122 -0
- data/lib/riak/preflist_item.rb +7 -0
- data/lib/riak/rcontent.rb +173 -0
- data/lib/riak/robject.rb +222 -0
- data/lib/riak/search.rb +11 -0
- data/lib/riak/search/index.rb +87 -0
- data/lib/riak/search/query.rb +141 -0
- data/lib/riak/search/result_collection.rb +144 -0
- data/lib/riak/search/result_document.rb +129 -0
- data/lib/riak/search/schema.rb +65 -0
- data/lib/riak/secondary_index.rb +81 -0
- data/lib/riak/serializers.rb +73 -0
- data/lib/riak/stamp.rb +77 -0
- data/lib/riak/util/escape.rb +80 -0
- data/lib/riak/util/tcp_socket_extensions.rb +58 -0
- data/lib/riak/util/translation.rb +18 -0
- data/lib/riak/version.rb +3 -0
- data/lib/riak/walk_spec.rb +145 -0
- data/spec/failover/failover.rb +59 -0
- data/spec/fixtures/bitcask.txt +25 -0
- data/spec/fixtures/cat.jpg +0 -0
- data/spec/fixtures/multipart-basic-conflict.txt +15 -0
- data/spec/fixtures/multipart-blank.txt +7 -0
- data/spec/fixtures/multipart-mapreduce.txt +10 -0
- data/spec/fixtures/multipart-with-body.txt +16 -0
- data/spec/fixtures/multipart-with-marked-tombstones.txt +17 -0
- data/spec/fixtures/multipart-with-unmarked-tombstone.txt +16 -0
- data/spec/fixtures/server.cert.crt +15 -0
- data/spec/fixtures/server.cert.key +15 -0
- data/spec/fixtures/test.pem +1 -0
- data/spec/fixtures/yz_schema_template.xml +18 -0
- data/spec/integration/riak/bucket_types_spec.rb +270 -0
- data/spec/integration/riak/conflict_resolution_spec.rb +96 -0
- data/spec/integration/riak/counters_spec.rb +36 -0
- data/spec/integration/riak/crdt/configuration_spec.rb +37 -0
- data/spec/integration/riak/crdt_search_spec.rb +176 -0
- data/spec/integration/riak/crdt_spec.rb +250 -0
- data/spec/integration/riak/crdt_validation/map_spec.rb +63 -0
- data/spec/integration/riak/crdt_validation/set_spec.rb +122 -0
- data/spec/integration/riak/preflist_spec.rb +31 -0
- data/spec/integration/riak/properties_spec.rb +69 -0
- data/spec/integration/riak/protobuffs/interrupted_request_spec.rb +33 -0
- data/spec/integration/riak/protobuffs_backends_spec.rb +40 -0
- data/spec/integration/riak/search_spec.rb +104 -0
- data/spec/integration/riak/secondary_index_spec.rb +72 -0
- data/spec/integration/riak/security_spec.rb +100 -0
- data/spec/integration/riak/threading_spec.rb +150 -0
- data/spec/integration/yokozuna/index_spec.rb +61 -0
- data/spec/integration/yokozuna/queries_spec.rb +115 -0
- data/spec/integration/yokozuna/schema_spec.rb +49 -0
- data/spec/riak/beefcake_protobuffs_backend/bucket_properties_operator_spec.rb +247 -0
- data/spec/riak/beefcake_protobuffs_backend/crdt_operator_spec.rb +222 -0
- data/spec/riak/beefcake_protobuffs_backend/object_methods_spec.rb +23 -0
- data/spec/riak/beefcake_protobuffs_backend/protocol_spec.rb +189 -0
- data/spec/riak/beefcake_protobuffs_backend_spec.rb +162 -0
- data/spec/riak/bucket_properties_spec.rb +135 -0
- data/spec/riak/bucket_spec.rb +275 -0
- data/spec/riak/bucket_type_spec.rb +50 -0
- data/spec/riak/bucket_typed/bucket_spec.rb +62 -0
- data/spec/riak/client_spec.rb +246 -0
- data/spec/riak/core_ext/to_param_spec.rb +15 -0
- data/spec/riak/counter_spec.rb +122 -0
- data/spec/riak/crdt/counter_spec.rb +55 -0
- data/spec/riak/crdt/inner_counter_spec.rb +21 -0
- data/spec/riak/crdt/inner_flag_spec.rb +39 -0
- data/spec/riak/crdt/inner_map_spec.rb +47 -0
- data/spec/riak/crdt/inner_register_spec.rb +40 -0
- data/spec/riak/crdt/inner_set_spec.rb +33 -0
- data/spec/riak/crdt/map_spec.rb +78 -0
- data/spec/riak/crdt/set_spec.rb +61 -0
- data/spec/riak/crdt/shared_examples.rb +74 -0
- data/spec/riak/crdt/typed_collection_spec.rb +225 -0
- data/spec/riak/escape_spec.rb +72 -0
- data/spec/riak/feature_detection_spec.rb +77 -0
- data/spec/riak/index_collection_spec.rb +53 -0
- data/spec/riak/instrumentation_spec.rb +124 -0
- data/spec/riak/link_spec.rb +85 -0
- data/spec/riak/list_buckets_spec.rb +41 -0
- data/spec/riak/map_reduce/filter_builder_spec.rb +32 -0
- data/spec/riak/map_reduce/phase_spec.rb +142 -0
- data/spec/riak/map_reduce_spec.rb +434 -0
- data/spec/riak/multiget_spec.rb +81 -0
- data/spec/riak/node_spec.rb +26 -0
- data/spec/riak/robject_spec.rb +496 -0
- data/spec/riak/search/index_spec.rb +72 -0
- data/spec/riak/search/query_spec.rb +88 -0
- data/spec/riak/search/result_collection_spec.rb +89 -0
- data/spec/riak/search/result_document_spec.rb +106 -0
- data/spec/riak/search/schema_spec.rb +63 -0
- data/spec/riak/search_spec.rb +107 -0
- data/spec/riak/secondary_index_spec.rb +225 -0
- data/spec/riak/serializers_spec.rb +121 -0
- data/spec/riak/stamp_spec.rb +54 -0
- data/spec/riak/walk_spec_spec.rb +203 -0
- data/spec/spec_helper.rb +66 -0
- data/spec/support/certs/README.md +13 -0
- data/spec/support/certs/ca.crt +21 -0
- data/spec/support/certs/client.crl +13 -0
- data/spec/support/certs/client.crt +94 -0
- data/spec/support/certs/client.csr +18 -0
- data/spec/support/certs/client.key +27 -0
- data/spec/support/certs/empty_ca.crt +21 -0
- data/spec/support/certs/server.crl +13 -0
- data/spec/support/certs/server.crt +94 -0
- data/spec/support/certs/server.key +27 -0
- data/spec/support/crdt_search_config.rb +112 -0
- data/spec/support/crdt_search_fixtures.rb +42 -0
- data/spec/support/integration_setup.rb +10 -0
- data/spec/support/search_config.rb +83 -0
- data/spec/support/search_corpus_setup.rb +39 -0
- data/spec/support/test_client.rb +46 -0
- data/spec/support/test_client.yml.example +10 -0
- data/spec/support/unified_backend_examples.rb +380 -0
- data/spec/support/version_filter.rb +12 -0
- data/spec/support/wait_until.rb +20 -0
- metadata +511 -0
@@ -0,0 +1,178 @@
|
|
1
|
+
class Riak::Client::BeefcakeProtobuffsBackend
|
2
|
+
def bucket_properties_operator
|
3
|
+
BucketPropertiesOperator.new(self)
|
4
|
+
end
|
5
|
+
|
6
|
+
|
7
|
+
class BucketPropertiesOperator
|
8
|
+
attr_reader :backend
|
9
|
+
|
10
|
+
QUORUMS = Riak::Client::ProtobuffsBackend::QUORUMS
|
11
|
+
|
12
|
+
def initialize(backend)
|
13
|
+
@backend = backend
|
14
|
+
end
|
15
|
+
|
16
|
+
def get(bucket, options = {})
|
17
|
+
response = backend.protocol do |p|
|
18
|
+
p.write :GetBucketReq, get_request(bucket, options)
|
19
|
+
p.expect :GetBucketResp, RpbGetBucketResp
|
20
|
+
end
|
21
|
+
|
22
|
+
properties = response.props.to_hash.stringify_keys
|
23
|
+
|
24
|
+
return rubyfy(properties)
|
25
|
+
end
|
26
|
+
|
27
|
+
def put(bucket, props = {}, options = {})
|
28
|
+
properties = riakify props
|
29
|
+
|
30
|
+
request = put_request bucket, properties, options
|
31
|
+
|
32
|
+
backend.protocol do |p|
|
33
|
+
p.write :SetBucketReq, request
|
34
|
+
p.expect :SetBucketResp
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def rubyfy(received_properties)
|
40
|
+
props = received_properties.dup
|
41
|
+
|
42
|
+
rubyfy_quorums(props)
|
43
|
+
rubyfy_hooks(props)
|
44
|
+
rubyfy_modfuns(props)
|
45
|
+
|
46
|
+
return props
|
47
|
+
end
|
48
|
+
|
49
|
+
def riakify(requested_properties)
|
50
|
+
props = requested_properties.stringify_keys
|
51
|
+
|
52
|
+
riakify_quorums(props)
|
53
|
+
riakify_hooks(props)
|
54
|
+
riakify_modfuns(props)
|
55
|
+
riakify_repl_mode(props)
|
56
|
+
|
57
|
+
return props
|
58
|
+
end
|
59
|
+
|
60
|
+
def rubyfy_quorums(props)
|
61
|
+
%w{r pr w pw dw rw}.each do |k|
|
62
|
+
next unless props[k]
|
63
|
+
next unless QUORUMS.values.include? props[k]
|
64
|
+
|
65
|
+
props[k] = QUORUMS.invert[props[k]]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def riakify_quorums(props)
|
70
|
+
%w{r pr w pw dw rw}.each do |k|
|
71
|
+
next unless props[k]
|
72
|
+
v = props[k].to_s
|
73
|
+
next unless QUORUMS.keys.include? v
|
74
|
+
|
75
|
+
props[k] = QUORUMS[v]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def rubyfy_hooks(props)
|
80
|
+
%w{precommit postcommit}.each do |k|
|
81
|
+
next unless props[k]
|
82
|
+
props[k] = props[k].map do |v|
|
83
|
+
next v[:name] if v[:name]
|
84
|
+
rubyfy_modfun(v[:modfun])
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def riakify_hooks(props)
|
90
|
+
%w{precommit postcommit}.each do |k|
|
91
|
+
next unless v = props[k]
|
92
|
+
|
93
|
+
if v.is_a? Array
|
94
|
+
props[k] = v.map{ |e| riakify_single_hook(e) }
|
95
|
+
else
|
96
|
+
props[k] = [riakify_single_hook(v)]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def riakify_single_hook(hook)
|
102
|
+
message = RpbCommitHook.new
|
103
|
+
|
104
|
+
if hook.is_a? String
|
105
|
+
message.name = hook
|
106
|
+
elsif hook['name']
|
107
|
+
message.name = hook['name']
|
108
|
+
else
|
109
|
+
message.modfun = riakify_modfun(hook)
|
110
|
+
end
|
111
|
+
return message
|
112
|
+
end
|
113
|
+
|
114
|
+
def rubyfy_modfuns(props)
|
115
|
+
%w{chash_keyfun linkfun}.each do |k|
|
116
|
+
next if props[k].nil?
|
117
|
+
props[k] = rubyfy_modfun(props[k])
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def riakify_modfuns(props)
|
122
|
+
%w{chash_keyfun linkfun}.each do |k|
|
123
|
+
next if props[k].nil?
|
124
|
+
props[k] = riakify_modfun(props[k])
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def rubyfy_modfun(modfun)
|
129
|
+
{
|
130
|
+
'mod' => modfun[:module],
|
131
|
+
'fun' => modfun[:function]
|
132
|
+
}
|
133
|
+
end
|
134
|
+
|
135
|
+
def riakify_modfun(modfun)
|
136
|
+
m = modfun.stringify_keys
|
137
|
+
RpbModFun.new(module: m['mod'], function: m['fun'])
|
138
|
+
end
|
139
|
+
|
140
|
+
def riakify_repl_mode(props)
|
141
|
+
return unless props['repl'].is_a? Symbol
|
142
|
+
|
143
|
+
props['repl'] = case props['repl']
|
144
|
+
when :false
|
145
|
+
0
|
146
|
+
when :realtime
|
147
|
+
1
|
148
|
+
when :fullsync
|
149
|
+
2
|
150
|
+
when :true
|
151
|
+
3
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def name_options(bucket)
|
156
|
+
o = {}
|
157
|
+
if bucket.is_a? Riak::Bucket
|
158
|
+
o[:bucket] = bucket.name
|
159
|
+
o[:type] = bucket.type.name if bucket.needs_type?
|
160
|
+
else
|
161
|
+
o[:bucket] = bucket
|
162
|
+
end
|
163
|
+
|
164
|
+
return o
|
165
|
+
end
|
166
|
+
|
167
|
+
def get_request(bucket, options)
|
168
|
+
RpbGetBucketReq.new options.merge name_options(bucket)
|
169
|
+
end
|
170
|
+
|
171
|
+
def put_request(bucket, props, options)
|
172
|
+
req_options = options.merge name_options(bucket)
|
173
|
+
req_options[:props] = RpbBucketProps.new props.symbolize_keys
|
174
|
+
|
175
|
+
RpbSetBucketReq.new req_options
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Riak::Client::BeefcakeProtobuffsBackend
|
2
|
+
class CrdtLoader
|
3
|
+
class CounterLoader
|
4
|
+
def self.for_value(resp)
|
5
|
+
return nil unless resp.counter_value
|
6
|
+
new resp.counter_value
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(counter_value)
|
10
|
+
@value = counter_value
|
11
|
+
end
|
12
|
+
|
13
|
+
def rubyfy
|
14
|
+
@value
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
class Riak::Client::BeefcakeProtobuffsBackend
|
2
|
+
class CrdtLoader
|
3
|
+
class MapLoader
|
4
|
+
def self.for_value(resp)
|
5
|
+
return nil unless resp.map_value
|
6
|
+
new resp.map_value
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(map_value)
|
10
|
+
@value = map_value
|
11
|
+
end
|
12
|
+
|
13
|
+
def rubyfy
|
14
|
+
accum = {
|
15
|
+
counters: {},
|
16
|
+
flags: {},
|
17
|
+
maps: {},
|
18
|
+
registers: {},
|
19
|
+
sets: {}
|
20
|
+
}
|
21
|
+
|
22
|
+
contents_loop @value, accum
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def rubyfy_inner(accum, map_value)
|
28
|
+
destination = accum[:maps][map_value.field.name]
|
29
|
+
if destination.nil?
|
30
|
+
destination = accum[:maps][map_value.field.name] = {
|
31
|
+
counters: {},
|
32
|
+
flags: {},
|
33
|
+
maps: {},
|
34
|
+
registers: {},
|
35
|
+
sets: {}
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
contents_loop map_value.map_value, destination
|
40
|
+
end
|
41
|
+
|
42
|
+
def contents_loop(rolling_value, destination)
|
43
|
+
return destination if rolling_value.nil?
|
44
|
+
|
45
|
+
rolling_value.each do |inner|
|
46
|
+
case inner.field.type
|
47
|
+
when MapField::MapFieldType::COUNTER
|
48
|
+
destination[:counters][inner.field.name] = inner.counter_value
|
49
|
+
when MapField::MapFieldType::FLAG
|
50
|
+
destination[:flags][inner.field.name] = inner.flag_value
|
51
|
+
when MapField::MapFieldType::MAP
|
52
|
+
rubyfy_inner destination, inner
|
53
|
+
when MapField::MapFieldType::REGISTER
|
54
|
+
destination[:registers][inner.field.name] = inner.register_value
|
55
|
+
when MapField::MapFieldType::SET
|
56
|
+
destination[:sets][inner.field.name] = ::Set.new inner.set_value
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
return destination
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Riak::Client::BeefcakeProtobuffsBackend
|
2
|
+
class CrdtLoader
|
3
|
+
class SetLoader
|
4
|
+
def self.for_value(resp)
|
5
|
+
return nil unless resp.set_value
|
6
|
+
new resp.set_value
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(set_value)
|
10
|
+
@value = set_value
|
11
|
+
end
|
12
|
+
|
13
|
+
def rubyfy
|
14
|
+
::Set.new @value
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'riak/client/beefcake/crdt/counter_loader'
|
2
|
+
require 'riak/client/beefcake/crdt/map_loader'
|
3
|
+
require 'riak/client/beefcake/crdt/set_loader'
|
4
|
+
|
5
|
+
module Riak
|
6
|
+
class Client
|
7
|
+
class BeefcakeProtobuffsBackend
|
8
|
+
|
9
|
+
# Returns a new {CrdtLoader} for deserializing a protobuffs response full
|
10
|
+
# of CRDTs.
|
11
|
+
# @api private
|
12
|
+
def crdt_loader
|
13
|
+
return CrdtLoader.new self
|
14
|
+
end
|
15
|
+
|
16
|
+
# Loads, and deserializes CRDTs from protobuffs into Ruby hashes,
|
17
|
+
# sets, strings, and integers.
|
18
|
+
# @api private
|
19
|
+
class CrdtLoader
|
20
|
+
include Util::Translation
|
21
|
+
|
22
|
+
attr_reader :backend, :context
|
23
|
+
|
24
|
+
def initialize(backend)
|
25
|
+
@backend = backend
|
26
|
+
end
|
27
|
+
|
28
|
+
# Perform the protobuffs request and return a deserialized CRDT.
|
29
|
+
def load(bucket, key, bucket_type, options = {})
|
30
|
+
bucket = bucket.name if bucket.is_a? ::Riak::Bucket
|
31
|
+
fetch_args = options.merge(
|
32
|
+
bucket: bucket,
|
33
|
+
key: key,
|
34
|
+
type: bucket_type
|
35
|
+
)
|
36
|
+
request = DtFetchReq.new fetch_args
|
37
|
+
|
38
|
+
response = backend.protocol do |p|
|
39
|
+
p.write :DtFetchReq, request
|
40
|
+
p.expect :DtFetchResp, DtFetchResp
|
41
|
+
end
|
42
|
+
|
43
|
+
@context = response.context
|
44
|
+
rubyfy response
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_loader_for_value(value)
|
48
|
+
return nil if value.nil?
|
49
|
+
|
50
|
+
[CounterLoader, MapLoader, SetLoader].map do |loader|
|
51
|
+
loader.for_value value
|
52
|
+
end.compact.first
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
# Convert the protobuffs response into low-level Ruby objects.
|
57
|
+
def rubyfy(response)
|
58
|
+
loader = get_loader_for_value response.value
|
59
|
+
return nil_rubyfy(response.type) if loader.nil?
|
60
|
+
|
61
|
+
return loader.rubyfy
|
62
|
+
end
|
63
|
+
|
64
|
+
# Sometimes a CRDT is empty, provide a sane default.
|
65
|
+
def nil_rubyfy(type)
|
66
|
+
case type
|
67
|
+
when DtFetchResp::DataType::COUNTER
|
68
|
+
0
|
69
|
+
when DtFetchResp::DataType::SET
|
70
|
+
::Set.new
|
71
|
+
when DtFetchResp::DataType::MAP
|
72
|
+
{
|
73
|
+
counters: {},
|
74
|
+
flags: {},
|
75
|
+
maps: {},
|
76
|
+
registers: {},
|
77
|
+
sets: {},
|
78
|
+
}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,223 @@
|
|
1
|
+
require 'riak/errors/crdt_error'
|
2
|
+
|
3
|
+
module Riak
|
4
|
+
class Client
|
5
|
+
class BeefcakeProtobuffsBackend
|
6
|
+
|
7
|
+
# Returns a new {CrdtOperator} for serializing CRDT operations into
|
8
|
+
# protobuffs and sending them to a Riak cluster.
|
9
|
+
# @api private
|
10
|
+
def crdt_operator
|
11
|
+
return CrdtOperator.new self
|
12
|
+
end
|
13
|
+
|
14
|
+
# Serializes and writes CRDT operations from {Riak::Crdt::Operation} members
|
15
|
+
# into protobuffs, and writes them to a Riak cluster.
|
16
|
+
# @api private
|
17
|
+
class CrdtOperator
|
18
|
+
include Util::Translation
|
19
|
+
|
20
|
+
attr_reader :backend
|
21
|
+
|
22
|
+
def initialize(backend)
|
23
|
+
@backend = backend
|
24
|
+
end
|
25
|
+
|
26
|
+
# Serializes and writes CRDT operations.
|
27
|
+
def operate(bucket, key, bucket_type, operation, options = {})
|
28
|
+
serialized = serialize(operation)
|
29
|
+
args = {
|
30
|
+
bucket: bucket,
|
31
|
+
key: key,
|
32
|
+
type: bucket_type,
|
33
|
+
op: serialized,
|
34
|
+
return_body: true,
|
35
|
+
}.merge options
|
36
|
+
request = DtUpdateReq.new args
|
37
|
+
begin
|
38
|
+
return backend.protocol do |p|
|
39
|
+
p.write :DtUpdateReq, request
|
40
|
+
p.expect :DtUpdateResp, DtUpdateResp, empty_body_acceptable: true
|
41
|
+
end
|
42
|
+
rescue ProtobuffsErrorResponse => e
|
43
|
+
raise unless e.message =~ /precondition/
|
44
|
+
raise CrdtError::PreconditionError.new e.message
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Serializes CRDT operations without writing them.
|
49
|
+
def serialize(operations)
|
50
|
+
return serialize [operations] unless operations.is_a? Enumerable
|
51
|
+
|
52
|
+
serialize_wrap operations
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
def serialize_wrap(operations)
|
57
|
+
raise ArgumentError, t('crdt.serialize_no_ops') if operations.empty?
|
58
|
+
ops = serialize_group operations
|
59
|
+
|
60
|
+
DtOp.new(wrap_field_for(operations) => ops)
|
61
|
+
end
|
62
|
+
|
63
|
+
def wrap_field_for(ops)
|
64
|
+
"#{ops.first.type.to_s}_op".to_sym
|
65
|
+
end
|
66
|
+
|
67
|
+
def serialize_group(operations)
|
68
|
+
case operations.first.type
|
69
|
+
when :counter
|
70
|
+
serialize_counter operations
|
71
|
+
when :set
|
72
|
+
serialize_set operations
|
73
|
+
when :map
|
74
|
+
serialize_map operations
|
75
|
+
else
|
76
|
+
raise ArgumentError, t('crdt.unknown_field', symbol: operation.type.inspect)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def inner_serialize_group(operations)
|
81
|
+
updates, deletes = operations.partition do |op|
|
82
|
+
op.value.is_a? Riak::Crdt::Operation::Update
|
83
|
+
end
|
84
|
+
serialized_updates = updates.map do |operation|
|
85
|
+
inner_serialize operation.value
|
86
|
+
end
|
87
|
+
serialized_deletes = deletes.map do |operation|
|
88
|
+
inner_serialize_delete operation.value
|
89
|
+
end
|
90
|
+
|
91
|
+
{ updates: serialized_updates,
|
92
|
+
removes: serialized_deletes
|
93
|
+
}
|
94
|
+
end
|
95
|
+
|
96
|
+
def inner_serialize(operation)
|
97
|
+
case operation.type
|
98
|
+
when :counter
|
99
|
+
serialize_inner_counter operation
|
100
|
+
when :flag
|
101
|
+
serialize_flag operation
|
102
|
+
when :register
|
103
|
+
serialize_register operation
|
104
|
+
when :set
|
105
|
+
serialize_inner_set operation
|
106
|
+
when :map
|
107
|
+
serialize_inner_map operation
|
108
|
+
else
|
109
|
+
raise ArgumentError, t('crdt.unknown_inner_field',
|
110
|
+
symbol: operation.type.inspect)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def inner_serialize_delete(operation)
|
115
|
+
MapField.new(
|
116
|
+
name: operation.name,
|
117
|
+
type: type_symbol_to_type_enum(operation.type)
|
118
|
+
)
|
119
|
+
end
|
120
|
+
|
121
|
+
def serialize_counter(counter_ops)
|
122
|
+
amount = counter_ops.inject(0){|m, o| m += o.value }
|
123
|
+
CounterOp.new(increment: amount)
|
124
|
+
end
|
125
|
+
|
126
|
+
def serialize_inner_counter(counter_op)
|
127
|
+
MapUpdate.new(
|
128
|
+
field: MapField.new(
|
129
|
+
name: counter_op.name,
|
130
|
+
type: MapField::MapFieldType::COUNTER
|
131
|
+
),
|
132
|
+
counter_op: CounterOp.new(
|
133
|
+
increment: counter_op.value
|
134
|
+
)
|
135
|
+
)
|
136
|
+
end
|
137
|
+
|
138
|
+
def serialize_flag(flag_op)
|
139
|
+
operation_value = flag_op.value ? MapUpdate::FlagOp::ENABLE : MapUpdate::FlagOp::DISABLE
|
140
|
+
MapUpdate.new(
|
141
|
+
field: MapField.new(
|
142
|
+
name: flag_op.name,
|
143
|
+
type: MapField::MapFieldType::FLAG
|
144
|
+
),
|
145
|
+
flag_op: operation_value
|
146
|
+
)
|
147
|
+
end
|
148
|
+
|
149
|
+
def serialize_register(register_op)
|
150
|
+
MapUpdate.new(
|
151
|
+
field: MapField.new(
|
152
|
+
name: register_op.name,
|
153
|
+
type: MapField::MapFieldType::REGISTER
|
154
|
+
),
|
155
|
+
register_op: register_op.value
|
156
|
+
)
|
157
|
+
end
|
158
|
+
|
159
|
+
def serialize_set(set_ops)
|
160
|
+
adds = ::Set.new
|
161
|
+
removes = ::Set.new
|
162
|
+
set_ops.each do |o|
|
163
|
+
adds.add [o.value[:add]] if o.value[:add]
|
164
|
+
removes.merge [o.value[:remove]] if o.value[:remove]
|
165
|
+
end
|
166
|
+
|
167
|
+
SetOp.new(
|
168
|
+
adds: adds.to_a.flatten,
|
169
|
+
removes: removes.to_a.flatten
|
170
|
+
)
|
171
|
+
end
|
172
|
+
|
173
|
+
def serialize_inner_set(set_op)
|
174
|
+
value = set_op.value or nil
|
175
|
+
|
176
|
+
MapUpdate.new(
|
177
|
+
field: MapField.new(
|
178
|
+
name: set_op.name,
|
179
|
+
type: MapField::MapFieldType::SET
|
180
|
+
),
|
181
|
+
set_op: SetOp.new(
|
182
|
+
adds: value[:add],
|
183
|
+
removes: value[:remove]
|
184
|
+
)
|
185
|
+
)
|
186
|
+
end
|
187
|
+
|
188
|
+
def serialize_map(map_ops)
|
189
|
+
inner_serialized = inner_serialize_group map_ops
|
190
|
+
|
191
|
+
MapOp.new(inner_serialized)
|
192
|
+
end
|
193
|
+
|
194
|
+
def serialize_inner_map(map_op)
|
195
|
+
inner_op = map_op.value
|
196
|
+
if inner_op.is_a? Riak::Crdt::Operation::Delete
|
197
|
+
return MapUpdate.new(field: MapField.new(
|
198
|
+
name: map_op.name,
|
199
|
+
type: MapField::MapFieldType::MAP
|
200
|
+
),
|
201
|
+
map_op: MapOp.new(
|
202
|
+
removes: inner_op.name)
|
203
|
+
)
|
204
|
+
end
|
205
|
+
inner_serialized = inner_serialize inner_op
|
206
|
+
|
207
|
+
MapUpdate.new(
|
208
|
+
field: MapField.new(
|
209
|
+
name: map_op.name,
|
210
|
+
type: MapField::MapFieldType::MAP
|
211
|
+
),
|
212
|
+
map_op: MapOp.new(
|
213
|
+
updates: [inner_serialized]
|
214
|
+
))
|
215
|
+
end
|
216
|
+
|
217
|
+
def type_symbol_to_type_enum(sym)
|
218
|
+
MapField::MapFieldType.const_get sym.to_s.upcase
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|