riak-client 0.9.8 → 1.0.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +32 -0
- data/Gemfile +17 -11
- data/Guardfile +14 -0
- data/Rakefile +18 -44
- data/erl_src/riak_kv_test_backend.beam +0 -0
- data/erl_src/riak_kv_test_backend.erl +461 -128
- data/erl_src/riak_search_test_backend.beam +0 -0
- data/erl_src/riak_search_test_backend.erl +175 -0
- data/lib/active_support/cache/riak_store.rb +0 -13
- data/lib/riak.rb +11 -16
- data/lib/riak/bucket.rb +59 -41
- data/lib/riak/cache_store.rb +1 -14
- data/lib/riak/client.rb +145 -73
- data/lib/riak/client/beefcake/messages.rb +36 -31
- data/lib/riak/client/beefcake/object_methods.rb +27 -19
- data/lib/riak/client/beefcake_protobuffs_backend.rb +27 -33
- data/lib/riak/client/excon_backend.rb +0 -13
- data/lib/riak/client/http_backend.rb +95 -60
- data/lib/riak/client/http_backend/configuration.rb +144 -19
- data/lib/riak/client/http_backend/key_streamer.rb +1 -14
- data/lib/riak/client/http_backend/object_methods.rb +16 -16
- data/lib/riak/client/http_backend/request_headers.rb +0 -13
- data/lib/riak/client/http_backend/transport_methods.rb +26 -56
- data/lib/riak/client/net_http_backend.rb +11 -13
- data/lib/riak/client/protobuffs_backend.rb +21 -19
- data/lib/riak/client/pump.rb +1 -15
- data/lib/riak/client/search.rb +85 -0
- data/lib/riak/cluster.rb +151 -0
- data/lib/riak/core_ext.rb +1 -0
- data/lib/riak/core_ext/deep_dup.rb +13 -0
- data/lib/riak/core_ext/json.rb +15 -0
- data/lib/riak/core_ext/stringify_keys.rb +1 -1
- data/lib/riak/core_ext/symbolize_keys.rb +1 -1
- data/lib/riak/encoding.rb +6 -0
- data/lib/riak/failed_request.rb +2 -15
- data/lib/riak/i18n.rb +0 -13
- data/lib/riak/json.rb +19 -8
- data/lib/riak/link.rb +18 -20
- data/lib/riak/locale/en.yml +13 -16
- data/lib/riak/map_reduce.rb +40 -20
- data/lib/riak/map_reduce/filter_builder.rb +14 -18
- data/lib/riak/map_reduce/phase.rb +0 -13
- data/lib/riak/map_reduce_error.rb +0 -13
- data/lib/riak/node.rb +38 -0
- data/lib/riak/node/configuration.rb +286 -0
- data/lib/riak/node/console.rb +139 -0
- data/lib/riak/node/control.rb +207 -0
- data/lib/riak/node/defaults.rb +70 -0
- data/lib/riak/node/generation.rb +99 -0
- data/lib/riak/node/log.rb +34 -0
- data/lib/riak/node/version.rb +37 -0
- data/lib/riak/robject.rb +45 -41
- data/lib/riak/search.rb +2 -161
- data/lib/riak/serializers.rb +74 -0
- data/lib/riak/stamp.rb +77 -0
- data/lib/riak/test_server.rb +56 -220
- data/lib/riak/util/escape.rb +58 -17
- data/lib/riak/util/headers.rb +2 -15
- data/lib/riak/util/multipart.rb +0 -13
- data/lib/riak/util/multipart/stream_parser.rb +0 -13
- data/lib/riak/util/tcp_socket_extensions.rb +1 -14
- data/lib/riak/util/translation.rb +0 -13
- data/lib/riak/version.rb +3 -0
- data/lib/riak/walk_spec.rb +0 -13
- data/riak-client.gemspec +27 -47
- data/spec/fixtures/multipart-with-marked-tombstones.txt +17 -0
- data/spec/fixtures/multipart-with-unmarked-tombstone.txt +16 -0
- data/spec/integration/riak/cache_store_spec.rb +2 -40
- data/spec/integration/riak/cluster_spec.rb +88 -0
- data/spec/integration/riak/http_backends_spec.rb +6 -30
- data/spec/integration/riak/node_spec.rb +184 -0
- data/spec/integration/riak/protobuffs_backends_spec.rb +2 -26
- data/spec/integration/riak/test_server_spec.rb +31 -167
- data/spec/riak/beefcake_protobuffs_backend_spec.rb +5 -4
- data/spec/riak/bucket_spec.rb +26 -36
- data/spec/riak/client_spec.rb +44 -38
- data/spec/riak/escape_spec.rb +56 -30
- data/spec/riak/excon_backend_spec.rb +4 -17
- data/spec/riak/headers_spec.rb +1 -14
- data/spec/riak/http_backend/configuration_spec.rb +211 -34
- data/spec/riak/http_backend/object_methods_spec.rb +52 -18
- data/spec/riak/http_backend/transport_methods_spec.rb +5 -38
- data/spec/riak/http_backend_spec.rb +84 -78
- data/spec/riak/link_spec.rb +19 -18
- data/spec/riak/map_reduce/filter_builder_spec.rb +1 -14
- data/spec/riak/map_reduce/phase_spec.rb +1 -14
- data/spec/riak/map_reduce_spec.rb +141 -43
- data/spec/riak/multipart_spec.rb +1 -14
- data/spec/riak/net_http_backend_spec.rb +2 -15
- data/spec/riak/robject_spec.rb +129 -97
- data/spec/riak/search_spec.rb +45 -62
- data/spec/riak/serializers_spec.rb +93 -0
- data/spec/riak/stamp_spec.rb +54 -0
- data/spec/riak/stream_parser_spec.rb +3 -16
- data/spec/riak/walk_spec_spec.rb +1 -14
- data/spec/spec_helper.rb +22 -27
- data/spec/support/http_backend_implementation_examples.rb +49 -79
- data/spec/support/integration_setup.rb +10 -0
- data/spec/support/mock_server.rb +0 -14
- data/spec/support/mocks.rb +0 -13
- data/spec/support/test_server.rb +30 -0
- data/spec/support/test_server.yml.example +14 -2
- data/spec/support/unified_backend_examples.rb +36 -27
- metadata +100 -31
- data/lib/riak/client/curb_backend.rb +0 -89
- data/spec/riak/curb_backend_spec.rb +0 -76
@@ -1,16 +1,3 @@
|
|
1
|
-
# Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
|
2
|
-
#
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
-
# you may not use this file except in compliance with the License.
|
5
|
-
# You may obtain a copy of the License at
|
6
|
-
#
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
-
#
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
-
# See the License for the specific language governing permissions and
|
13
|
-
# limitations under the License.
|
14
1
|
require 'beefcake'
|
15
2
|
|
16
3
|
module Riak
|
@@ -48,6 +35,7 @@ module Riak
|
|
48
35
|
optional :last_mod, :uint32, 7
|
49
36
|
optional :last_mod_usecs, :uint32, 8
|
50
37
|
repeated :usermeta, RpbPair, 9
|
38
|
+
repeated :indexes, RpbPair, 10
|
51
39
|
end
|
52
40
|
|
53
41
|
# Primary messages
|
@@ -75,40 +63,57 @@ module Riak
|
|
75
63
|
|
76
64
|
class RpbGetReq
|
77
65
|
include Beefcake::Message
|
78
|
-
required :bucket,
|
79
|
-
required :key,
|
80
|
-
optional :r,
|
66
|
+
required :bucket, :bytes, 1
|
67
|
+
required :key, :bytes, 2
|
68
|
+
optional :r, :uint32, 3
|
69
|
+
optional :pr, :uint32, 4
|
70
|
+
optional :basic_quorum, :bool, 5
|
71
|
+
optional :notfound_ok, :bool, 6
|
72
|
+
optional :if_modified, :bytes, 7
|
73
|
+
optional :head, :bool, 8
|
74
|
+
optional :deletedvclock, :bool, 9
|
81
75
|
end
|
82
76
|
|
83
77
|
class RpbGetResp
|
84
78
|
include Beefcake::Message
|
85
|
-
repeated :content,
|
86
|
-
optional :vclock,
|
79
|
+
repeated :content, RpbContent, 1
|
80
|
+
optional :vclock, :bytes, 2
|
81
|
+
optional :unchanged, :bool, 3
|
87
82
|
end
|
88
83
|
|
89
84
|
class RpbPutReq
|
90
85
|
include Beefcake::Message
|
91
|
-
required :bucket,
|
92
|
-
|
93
|
-
optional :vclock,
|
94
|
-
required :content,
|
95
|
-
optional :w,
|
96
|
-
optional :dw,
|
97
|
-
optional :
|
86
|
+
required :bucket, :bytes, 1
|
87
|
+
optional :key, :bytes, 2
|
88
|
+
optional :vclock, :bytes, 3
|
89
|
+
required :content, RpbContent, 4
|
90
|
+
optional :w, :uint32, 5
|
91
|
+
optional :dw, :uint32, 6
|
92
|
+
optional :returnbody, :bool, 7
|
93
|
+
optional :pw, :uint32, 8
|
94
|
+
optional :if_not_modified, :bool, 9
|
95
|
+
optional :if_none_match, :bool, 10
|
96
|
+
optional :return_head, :bool, 11
|
98
97
|
end
|
99
98
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
99
|
+
class RpbPutResp
|
100
|
+
include Beefcake::Message
|
101
|
+
repeated :content, RpbContent, 1
|
102
|
+
optional :vclock, :bytes, 2
|
103
|
+
optional :key, :bytes, 3
|
104
|
+
end
|
106
105
|
|
107
106
|
class RpbDelReq
|
108
107
|
include Beefcake::Message
|
109
108
|
required :bucket, :bytes, 1
|
110
109
|
required :key, :bytes, 2
|
111
110
|
optional :rw, :uint32, 3
|
111
|
+
optional :vclock, :bytes, 4
|
112
|
+
optional :r, :uint32, 5
|
113
|
+
optional :w, :uint32, 6
|
114
|
+
optional :pr, :uint32, 7
|
115
|
+
optional :pw, :uint32, 8
|
116
|
+
optional :dw, :uint32, 9
|
112
117
|
end
|
113
118
|
|
114
119
|
class RpbListBucketsResp
|
@@ -1,16 +1,3 @@
|
|
1
|
-
# Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
|
2
|
-
#
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
-
# you may not use this file except in compliance with the License.
|
5
|
-
# You may obtain a copy of the License at
|
6
|
-
#
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
-
#
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
-
# See the License for the specific language governing permissions and
|
13
|
-
# limitations under the License.
|
14
1
|
require 'riak/robject'
|
15
2
|
require 'riak/link'
|
16
3
|
require 'riak/client/beefcake/messages'
|
@@ -22,13 +9,14 @@ module Riak
|
|
22
9
|
ENCODING = "Riak".respond_to?(:encoding)
|
23
10
|
|
24
11
|
# Returns RpbPutReq
|
25
|
-
def dump_object(robject)
|
26
|
-
pbuf = RpbPutReq.new(:bucket => maybe_encode(robject.bucket.name))
|
27
|
-
pbuf.key = maybe_encode(robject.key
|
28
|
-
pbuf.vclock = maybe_encode
|
12
|
+
def dump_object(robject, options={})
|
13
|
+
pbuf = RpbPutReq.new(options.merge(:bucket => maybe_encode(robject.bucket.name)))
|
14
|
+
pbuf.key = maybe_encode(robject.key) if robject.key # Put w/o key supported!
|
15
|
+
pbuf.vclock = maybe_encode(Base64.decode64(robject.vclock)) if robject.vclock
|
29
16
|
pbuf.content = RpbContent.new(:value => maybe_encode(robject.raw_data),
|
30
17
|
:content_type => maybe_encode(robject.content_type),
|
31
|
-
:links => robject.links.map {|l| encode_link(l) }.compact
|
18
|
+
:links => robject.links.map {|l| encode_link(l) }.compact,
|
19
|
+
:indexes => robject.indexes.map {|k,s| encode_index(k,s) }.flatten)
|
32
20
|
|
33
21
|
pbuf.content.usermeta = robject.meta.map {|k,v| encode_meta(k,v)} if robject.meta.any?
|
34
22
|
pbuf.content.vtag = maybe_encode(robject.etag) if robject.etag.present?
|
@@ -40,7 +28,9 @@ module Riak
|
|
40
28
|
|
41
29
|
# Returns RObject
|
42
30
|
def load_object(pbuf, robject)
|
31
|
+
return robject if pbuf.respond_to?(:unchanged) && pbuf.unchanged # Reloading
|
43
32
|
robject.vclock = Base64.encode64(pbuf.vclock).chomp if pbuf.vclock
|
33
|
+
robject.key = maybe_unescape(pbuf.key) if pbuf.respond_to?(:key) && pbuf.key # Put w/o key
|
44
34
|
if pbuf.content.size > 1
|
45
35
|
robject.conflict = true
|
46
36
|
robject.siblings = pbuf.content.map do |c|
|
@@ -48,6 +38,8 @@ module Riak
|
|
48
38
|
sibling.vclock = robject.vclock
|
49
39
|
load_content(c, sibling)
|
50
40
|
end
|
41
|
+
|
42
|
+
return robject.attempt_conflict_resolution
|
51
43
|
else
|
52
44
|
load_content(pbuf.content.first, robject)
|
53
45
|
end
|
@@ -64,6 +56,10 @@ module Riak
|
|
64
56
|
robject.content_type = pbuf.content_type if pbuf.content_type.present?
|
65
57
|
robject.links = pbuf.links.map(&method(:decode_link)) if pbuf.links.present?
|
66
58
|
pbuf.usermeta.each {|pair| decode_meta(pair, robject.meta) } if pbuf.usermeta.present?
|
59
|
+
if pbuf.indexes.present?
|
60
|
+
robject.indexes.clear
|
61
|
+
pbuf.indexes.each {|pair| decode_index(pair, robject.indexes) }
|
62
|
+
end
|
67
63
|
if pbuf.last_mod.present?
|
68
64
|
robject.last_modified = Time.at(pbuf.last_mod)
|
69
65
|
robject.last_modified += pbuf.last_mod_usecs / 1000000 if pbuf.last_mod_usecs.present?
|
@@ -92,8 +88,20 @@ module Riak
|
|
92
88
|
:value => maybe_encode(value.to_s))
|
93
89
|
end
|
94
90
|
|
91
|
+
def decode_index(pbuf, hash)
|
92
|
+
value = pbuf.key =~ /int$/ ? pbuf.value.to_i : pbuf.value
|
93
|
+
hash[pbuf.key] << value
|
94
|
+
end
|
95
|
+
|
96
|
+
def encode_index(key, set)
|
97
|
+
set.map do |v|
|
98
|
+
RpbPair.new(:key => maybe_encode(key),
|
99
|
+
:value => maybe_encode(v.to_s))
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
95
103
|
def maybe_encode(string)
|
96
|
-
ENCODING ? string.
|
104
|
+
ENCODING ? string.dup.force_encoding('BINARY') : string
|
97
105
|
end
|
98
106
|
end
|
99
107
|
|
@@ -1,17 +1,4 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
-
# you may not use this file except in compliance with the License.
|
5
|
-
# You may obtain a copy of the License at
|
6
|
-
#
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
-
#
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
-
# See the License for the specific language governing permissions and
|
13
|
-
# limitations under the License.
|
14
|
-
|
1
|
+
require 'base64'
|
15
2
|
require 'riak/json'
|
16
3
|
require 'riak/client'
|
17
4
|
require 'riak/failed_request'
|
@@ -44,45 +31,49 @@ module Riak
|
|
44
31
|
decode_response
|
45
32
|
end
|
46
33
|
|
47
|
-
def fetch_object(bucket, key,
|
34
|
+
def fetch_object(bucket, key, options={})
|
35
|
+
options = normalize_quorums(options)
|
48
36
|
bucket = Bucket === bucket ? bucket.name : bucket
|
49
|
-
req = RpbGetReq.new(:bucket => bucket, :key => key)
|
50
|
-
req.r = normalize_quorum_value(r) if r
|
37
|
+
req = RpbGetReq.new(options.merge(:bucket => maybe_encode(bucket), :key => maybe_encode(key)))
|
51
38
|
write_protobuff(:GetReq, req)
|
52
39
|
decode_response(RObject.new(client.bucket(bucket), key))
|
53
40
|
end
|
54
41
|
|
55
|
-
def reload_object(robject,
|
56
|
-
|
57
|
-
|
42
|
+
def reload_object(robject, options={})
|
43
|
+
options = normalize_quorums(options)
|
44
|
+
options[:bucket] = maybe_encode(robject.bucket.name)
|
45
|
+
options[:key] = maybe_encode(robject.key)
|
46
|
+
options[:if_modified] = maybe_encode Base64.decode64(robject.vclock) if robject.vclock
|
47
|
+
req = RpbGetReq.new(options)
|
58
48
|
write_protobuff(:GetReq, req)
|
59
49
|
decode_response(robject)
|
60
50
|
end
|
61
51
|
|
62
|
-
def store_object(robject,
|
52
|
+
def store_object(robject, options={})
|
63
53
|
if robject.prevent_stale_writes
|
64
54
|
other = fetch_object(robject.bucket, robject.key)
|
65
55
|
raise Riak::ProtobuffsFailedRequest(:stale_object, t("stale_write_prevented")) unless other.vclock == robject.vclock
|
66
56
|
end
|
67
|
-
|
68
|
-
req
|
69
|
-
req.dw = normalize_quorum_value(dw) if dw
|
70
|
-
req.return_body = returnbody
|
57
|
+
options = normalize_quorums(options)
|
58
|
+
req = dump_object(robject, options)
|
71
59
|
write_protobuff(:PutReq, req)
|
72
60
|
decode_response(robject)
|
73
61
|
end
|
74
62
|
|
75
|
-
def delete_object(bucket, key,
|
63
|
+
def delete_object(bucket, key, options={})
|
76
64
|
bucket = Bucket === bucket ? bucket.name : bucket
|
77
|
-
|
78
|
-
|
65
|
+
options = normalize_quorums(options)
|
66
|
+
options[:bucket] = maybe_encode(bucket)
|
67
|
+
options[:key] = maybe_encode(key)
|
68
|
+
options[:vclock] = Base64.decode64(options[:vclock]) if options[:vclock]
|
69
|
+
req = RpbDelReq.new(options)
|
79
70
|
write_protobuff(:DelReq, req)
|
80
71
|
decode_response
|
81
72
|
end
|
82
73
|
|
83
74
|
def get_bucket_props(bucket)
|
84
75
|
bucket = bucket.name if Bucket === bucket
|
85
|
-
req = RpbGetBucketReq.new(:bucket => bucket)
|
76
|
+
req = RpbGetBucketReq.new(:bucket => maybe_encode(bucket))
|
86
77
|
write_protobuff(:GetBucketReq, req)
|
87
78
|
decode_response
|
88
79
|
end
|
@@ -90,14 +81,14 @@ module Riak
|
|
90
81
|
def set_bucket_props(bucket, props)
|
91
82
|
bucket = bucket.name if Bucket === bucket
|
92
83
|
props = props.slice('n_val', 'allow_mult')
|
93
|
-
req = RpbSetBucketReq.new(:bucket => bucket, :props => RpbBucketProps.new(props))
|
84
|
+
req = RpbSetBucketReq.new(:bucket => maybe_encode(bucket), :props => RpbBucketProps.new(props))
|
94
85
|
write_protobuff(:SetBucketReq, req)
|
95
86
|
decode_response
|
96
87
|
end
|
97
88
|
|
98
89
|
def list_keys(bucket, &block)
|
99
90
|
bucket = bucket.name if Bucket === bucket
|
100
|
-
req = RpbListKeysReq.new(:bucket => bucket)
|
91
|
+
req = RpbListKeysReq.new(:bucket => maybe_encode(bucket))
|
101
92
|
write_protobuff(:ListKeysReq, req)
|
102
93
|
keys = []
|
103
94
|
pump = Pump.new(block) if block_given?
|
@@ -165,9 +156,12 @@ module Riak
|
|
165
156
|
when :GetServerInfoResp
|
166
157
|
res = RpbGetServerInfoResp.decode(message)
|
167
158
|
{:node => res.node, :server_version => res.server_version}
|
168
|
-
when :GetResp
|
159
|
+
when :GetResp
|
169
160
|
res = RpbGetResp.decode(message)
|
170
161
|
load_object(res, args.first)
|
162
|
+
when :PutResp
|
163
|
+
res = RpbPutResp.decode(message)
|
164
|
+
load_object(res, args.first)
|
171
165
|
when :ListBucketsResp
|
172
166
|
res = RpbListBucketsResp.decode(message)
|
173
167
|
res.buckets
|
@@ -180,7 +174,7 @@ module Riak
|
|
180
174
|
RpbMapRedResp.decode(message)
|
181
175
|
end
|
182
176
|
end
|
183
|
-
rescue SocketError => e
|
177
|
+
rescue SystemCallError, SocketError => e
|
184
178
|
reset_socket
|
185
179
|
raise Riak::ProtobuffsFailedRequest.new(:server_error, e.message)
|
186
180
|
end
|
@@ -1,16 +1,3 @@
|
|
1
|
-
# Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
|
2
|
-
#
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
-
# you may not use this file except in compliance with the License.
|
5
|
-
# You may obtain a copy of the License at
|
6
|
-
#
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
-
#
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
-
# See the License for the specific language governing permissions and
|
13
|
-
# limitations under the License.
|
14
1
|
|
15
2
|
require 'riak/failed_request'
|
16
3
|
require 'riak/client/http_backend'
|
@@ -1,17 +1,3 @@
|
|
1
|
-
# Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
|
2
|
-
#
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
-
# you may not use this file except in compliance with the License.
|
5
|
-
# You may obtain a copy of the License at
|
6
|
-
#
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
-
#
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
-
# See the License for the specific language governing permissions and
|
13
|
-
# limitations under the License.
|
14
|
-
|
15
1
|
require 'riak/util/escape'
|
16
2
|
require 'riak/util/translation'
|
17
3
|
require 'riak/util/multipart'
|
@@ -35,7 +21,7 @@ module Riak
|
|
35
21
|
class HTTPBackend
|
36
22
|
include Util::Escape
|
37
23
|
include Util::Translation
|
38
|
-
|
24
|
+
|
39
25
|
include TransportMethods
|
40
26
|
include ObjectMethods
|
41
27
|
include Configuration
|
@@ -53,7 +39,7 @@ module Riak
|
|
53
39
|
# Pings the server
|
54
40
|
# @return [true,false] whether the server is available
|
55
41
|
def ping
|
56
|
-
get(200,
|
42
|
+
get(200, ping_path)
|
57
43
|
true
|
58
44
|
rescue
|
59
45
|
false
|
@@ -63,20 +49,22 @@ module Riak
|
|
63
49
|
# @param [Bucket, String] bucket the bucket where the object is
|
64
50
|
# stored
|
65
51
|
# @param [String] key the key of the object
|
66
|
-
# @param [
|
67
|
-
#
|
52
|
+
# @param [Hash] options request quorums
|
53
|
+
# @option options [Fixnum, String, Symbol] :r the read quorum for the
|
54
|
+
# request - how many nodes should concur on the read
|
55
|
+
# @option options [Fixnum, String, Symbol] :pr the "primary"
|
56
|
+
# read quorum for the request - how many primary partitions
|
57
|
+
# must be available
|
68
58
|
# @return [RObject] the fetched object
|
69
|
-
def fetch_object(bucket, key,
|
59
|
+
def fetch_object(bucket, key, options={})
|
70
60
|
bucket = Bucket.new(client, bucket) if String === bucket
|
71
|
-
|
72
|
-
response = get([200,300],riak_kv_wm_raw, escape(bucket.name), escape(key), options, {})
|
61
|
+
response = get([200,300], object_path(bucket.name, key, options))
|
73
62
|
load_object(RObject.new(bucket, key), response)
|
74
63
|
end
|
75
64
|
|
76
65
|
# Reloads the data for a given RObject, a special case of {#fetch_object}.
|
77
|
-
def reload_object(robject,
|
78
|
-
|
79
|
-
response = get([200,300,304], riak_kv_wm_raw, escape(robject.bucket.name), escape(robject.key), options, reload_headers(robject))
|
66
|
+
def reload_object(robject, options={})
|
67
|
+
response = get([200,300,304], object_path(robject.bucket.name, robject.key, options), reload_headers(robject))
|
80
68
|
if response[:code].to_i == 304
|
81
69
|
robject
|
82
70
|
else
|
@@ -86,35 +74,37 @@ module Riak
|
|
86
74
|
|
87
75
|
# Stores an object
|
88
76
|
# @param [RObject] robject the object to store
|
89
|
-
# @param [
|
77
|
+
# @param [Hash] options quorum and storage options
|
78
|
+
# @option options [true,false] :returnbody (false) whether to update the object
|
90
79
|
# after write with the new value
|
91
|
-
# @
|
92
|
-
# @
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
end
|
104
|
-
response = send(method, codes, riak_kv_wm_raw, path, query, robject.raw_data, store_headers(robject))
|
105
|
-
load_object(robject, response) if returnbody
|
80
|
+
# @option options [Fixnum, String, Symbol] :w the write quorum
|
81
|
+
# @option options [Fixnum, String, Symbol] :pw the "primary"
|
82
|
+
# write quorum - how many primary partitions must be available
|
83
|
+
# @option options [Fixnum, String, Symbol] :dw the durable write quorum
|
84
|
+
def store_object(robject, options={})
|
85
|
+
method, codes = if robject.key.present?
|
86
|
+
[:put, [200,204,300]]
|
87
|
+
else
|
88
|
+
[:post, 201]
|
89
|
+
end
|
90
|
+
response = send(method, codes, object_path(robject.bucket.name, robject.key, options), robject.raw_data, store_headers(robject))
|
91
|
+
load_object(robject, response) if options[:returnbody]
|
106
92
|
end
|
107
93
|
|
108
94
|
# Deletes an object
|
109
95
|
# @param [Bucket, String] bucket the bucket where the object
|
110
|
-
#
|
96
|
+
# lives
|
111
97
|
# @param [String] key the key where the object lives
|
112
|
-
# @param [
|
113
|
-
#
|
114
|
-
|
98
|
+
# @param [Hash] options quorum and delete options
|
99
|
+
# @options options [Fixnum, String, Symbol] :rw the read/write quorum for
|
100
|
+
# the request
|
101
|
+
# @options options [String] :vclock the vector clock of the
|
102
|
+
# object to be deleted
|
103
|
+
def delete_object(bucket, key, options={})
|
115
104
|
bucket = bucket.name if Bucket === bucket
|
116
|
-
|
117
|
-
|
105
|
+
vclock = options.delete(:vclock)
|
106
|
+
headers = vclock ? {"X-Riak-VClock" => vclock} : {}
|
107
|
+
delete([204, 404], object_path(bucket, key, options), headers)
|
118
108
|
end
|
119
109
|
|
120
110
|
# Fetches bucket properties
|
@@ -122,7 +112,7 @@ module Riak
|
|
122
112
|
# @return [Hash] bucket properties
|
123
113
|
def get_bucket_props(bucket)
|
124
114
|
bucket = bucket.name if Bucket === bucket
|
125
|
-
response = get(200,
|
115
|
+
response = get(200, bucket_properties_path(bucket))
|
126
116
|
JSON.parse(response[:body])['props']
|
127
117
|
end
|
128
118
|
|
@@ -132,7 +122,7 @@ module Riak
|
|
132
122
|
def set_bucket_props(bucket, props)
|
133
123
|
bucket = bucket.name if Bucket === bucket
|
134
124
|
body = {'props' => props}.to_json
|
135
|
-
put(204,
|
125
|
+
put(204, bucket_properties_path(bucket), body, {"Content-Type" => "application/json"})
|
136
126
|
end
|
137
127
|
|
138
128
|
# List keys in a bucket
|
@@ -143,10 +133,10 @@ module Riak
|
|
143
133
|
# @return [Array<String>] the list of keys, if no block was given
|
144
134
|
def list_keys(bucket, &block)
|
145
135
|
bucket = bucket.name if Bucket === bucket
|
146
|
-
if block_given?
|
147
|
-
get(200,
|
136
|
+
if block_given?
|
137
|
+
get(200, key_list_path(bucket, :keys => 'stream'), {}, &KeyStreamer.new(block))
|
148
138
|
else
|
149
|
-
response = get(200,
|
139
|
+
response = get(200, key_list_path(bucket))
|
150
140
|
obj = JSON.parse(response[:body])
|
151
141
|
obj && obj['keys'].map {|k| unescape(k) }
|
152
142
|
end
|
@@ -155,7 +145,7 @@ module Riak
|
|
155
145
|
# Lists known buckets
|
156
146
|
# @return [Array<String>] the list of buckets
|
157
147
|
def list_buckets
|
158
|
-
response = get(200,
|
148
|
+
response = get(200, bucket_list_path)
|
159
149
|
JSON.parse(response[:body])['buckets']
|
160
150
|
end
|
161
151
|
|
@@ -171,10 +161,10 @@ module Riak
|
|
171
161
|
result = JSON.parse(response[:body])
|
172
162
|
yield result['phase'], result['data']
|
173
163
|
end
|
174
|
-
post(200,
|
164
|
+
post(200, mapred_path({:chunked => true}), mr.to_json, {"Content-Type" => "application/json", "Accept" => "application/json"}, &parser)
|
175
165
|
nil
|
176
166
|
else
|
177
|
-
response = post(200,
|
167
|
+
response = post(200, mapred_path, mr.to_json, {"Content-Type" => "application/json", "Accept" => "application/json"})
|
178
168
|
begin
|
179
169
|
JSON.parse(response[:body])
|
180
170
|
rescue
|
@@ -186,7 +176,7 @@ module Riak
|
|
186
176
|
# Gets health statistics
|
187
177
|
# @return [Hash] information about the server, including stats
|
188
178
|
def stats
|
189
|
-
response = get(200,
|
179
|
+
response = get(200, stats_path)
|
190
180
|
JSON.parse(response[:body])
|
191
181
|
end
|
192
182
|
|
@@ -197,20 +187,65 @@ module Riak
|
|
197
187
|
# @return [Array<Array<RObject>>] a list of the matched objects,
|
198
188
|
# grouped by phase
|
199
189
|
def link_walk(robject, walk_specs)
|
200
|
-
response = get(200,
|
190
|
+
response = get(200, link_walk_path(robject.bucket.name, robject.key, walk_specs))
|
201
191
|
if boundary = Util::Multipart.extract_boundary(response[:headers]['content-type'].first)
|
202
192
|
Util::Multipart.parse(response[:body], boundary).map do |group|
|
203
193
|
group.map do |obj|
|
204
|
-
if obj[:headers] && obj[:body] && obj[:headers]['location']
|
205
|
-
|
206
|
-
load_object(RObject.new(client.bucket(bucket),
|
194
|
+
if obj[:headers] && !obj[:headers]['x-riak-deleted'] && !obj[:body].blank? && obj[:headers]['location']
|
195
|
+
link = Riak::Link.new(obj[:headers]['location'].first, "")
|
196
|
+
load_object(RObject.new(client.bucket(link.bucket), link.key), obj)
|
207
197
|
end
|
208
|
-
end
|
198
|
+
end.compact
|
209
199
|
end
|
210
200
|
else
|
211
201
|
[]
|
212
202
|
end
|
213
203
|
end
|
204
|
+
|
205
|
+
# Performs a secondary-index query.
|
206
|
+
# @param [String, Bucket] bucket the bucket to query
|
207
|
+
# @param [String] index the index to query
|
208
|
+
# @param [String, Integer, Range] query the equality query or
|
209
|
+
# range query to perform
|
210
|
+
# @return [Array<String>] a list of keys matching the query
|
211
|
+
def get_index(bucket, index, query)
|
212
|
+
bucket = bucket.name if Bucket === bucket
|
213
|
+
path = case query
|
214
|
+
when Range
|
215
|
+
raise ArgumentError, t('invalid_index_query', :value => query.inspect) unless String === query.begin || Integer === query.end
|
216
|
+
index_range_path(bucket, index, query.begin, query.end)
|
217
|
+
when String, Integer
|
218
|
+
index_eq_path(bucket, index, query)
|
219
|
+
else
|
220
|
+
raise ArgumentError, t('invalid_index_query', :value => query.inspect)
|
221
|
+
end
|
222
|
+
response = get(200, path)
|
223
|
+
JSON.parse(response[:body])['keys']
|
224
|
+
end
|
225
|
+
|
226
|
+
# (Riak Search) Performs a search query
|
227
|
+
# @param [String,nil] index the index to query, or nil for the
|
228
|
+
# default
|
229
|
+
# @param [String] query the Lucene query to perform
|
230
|
+
# @param [Hash] options query options
|
231
|
+
# @see Client#search
|
232
|
+
def search(index, query, options={})
|
233
|
+
response = get(200, solr_select_path(index, query, options.stringify_keys))
|
234
|
+
if response[:headers]['content-type'].include?("application/json")
|
235
|
+
JSON.parse(response[:body])
|
236
|
+
else
|
237
|
+
response[:body]
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
# (Riak Search) Updates a search index (includes deletes).
|
242
|
+
# @param [String, nil] index the index to update, or nil for the
|
243
|
+
# default index.
|
244
|
+
# @param [String] updates an XML update string in Solr's required format
|
245
|
+
# @see Client#index
|
246
|
+
def update_search_index(index, updates)
|
247
|
+
post(200, solr_update_path(index), updates, {'Content-Type' => 'text/xml'})
|
248
|
+
end
|
214
249
|
end
|
215
250
|
end
|
216
251
|
end
|