riak-client 1.4.5 → 2.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/Gemfile +0 -1
- data/{LICENSE → LICENSE.md} +0 -0
- data/README.markdown +211 -66
- data/RELEASE_NOTES.md +22 -47
- data/Rakefile +45 -0
- data/lib/riak.rb +1 -1
- data/lib/riak/bucket.rb +2 -2
- data/lib/riak/client.rb +22 -195
- data/lib/riak/client/beefcake/crdt_loader.rb +127 -0
- data/lib/riak/client/beefcake/crdt_operator.rb +222 -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 +29 -0
- data/lib/riak/client/beefcake/message_overlay.rb +61 -0
- data/lib/riak/client/beefcake/messages.rb +733 -371
- data/lib/riak/client/beefcake/object_methods.rb +1 -1
- data/lib/riak/client/beefcake/protocol.rb +105 -0
- data/lib/riak/client/beefcake/socket.rb +243 -0
- data/lib/riak/client/beefcake_protobuffs_backend.rb +262 -122
- data/lib/riak/client/node.rb +4 -75
- data/lib/riak/client/protobuffs_backend.rb +6 -14
- data/lib/riak/client/search.rb +0 -64
- data/lib/riak/client/yokozuna.rb +52 -0
- data/lib/riak/counter.rb +1 -1
- data/lib/riak/crdt.rb +21 -0
- data/lib/riak/crdt/base.rb +97 -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 +71 -0
- data/lib/riak/crdt/inner_counter.rb +74 -0
- data/lib/riak/crdt/inner_flag.rb +42 -0
- data/lib/riak/crdt/inner_map.rb +53 -0
- data/lib/riak/crdt/inner_register.rb +26 -0
- data/lib/riak/crdt/inner_set.rb +95 -0
- data/lib/riak/crdt/map.rb +88 -0
- data/lib/riak/crdt/operation.rb +19 -0
- data/lib/riak/crdt/set.rb +156 -0
- data/lib/riak/crdt/typed_collection.rb +131 -0
- data/lib/riak/errors/base.rb +9 -0
- data/lib/riak/errors/connection_error.rb +44 -0
- data/lib/riak/errors/crdt_error.rb +18 -0
- data/lib/riak/errors/failed_request.rb +56 -0
- data/lib/riak/errors/protobuffs_error.rb +11 -0
- data/lib/riak/i18n.rb +2 -0
- data/lib/riak/json.rb +1 -1
- data/lib/riak/locale/en.yml +26 -1
- data/lib/riak/locale/fr.yml +0 -1
- data/lib/riak/map_reduce.rb +1 -1
- data/lib/riak/map_reduce/results.rb +1 -1
- data/lib/riak/multiget.rb +1 -2
- data/lib/riak/rcontent.rb +8 -3
- data/lib/riak/robject.rb +2 -8
- data/lib/riak/secondary_index.rb +4 -4
- data/lib/riak/serializers.rb +1 -1
- data/lib/riak/util/escape.rb +3 -5
- data/lib/riak/version.rb +1 -1
- data/lib/riak/walk_spec.rb +7 -3
- data/riak-client.gemspec +10 -8
- data/spec/fixtures/bitcask.txt +25 -0
- data/spec/integration/riak/bucket_types_spec.rb +61 -0
- data/spec/integration/riak/counters_spec.rb +17 -32
- data/spec/integration/riak/crdt_spec.rb +181 -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/protobuffs_backends_spec.rb +9 -26
- data/spec/integration/riak/security_spec.rb +94 -0
- data/spec/integration/riak/threading_spec.rb +24 -67
- data/spec/integration/yokozuna/index_spec.rb +61 -0
- data/spec/integration/yokozuna/queries_spec.rb +116 -0
- data/spec/integration/yokozuna/schema_spec.rb +49 -0
- data/spec/riak/beefcake_protobuffs_backend/crdt_operator_spec.rb +222 -0
- data/spec/riak/beefcake_protobuffs_backend/object_methods_spec.rb +4 -4
- data/spec/riak/beefcake_protobuffs_backend/protocol_spec.rb +189 -0
- data/spec/riak/beefcake_protobuffs_backend/socket_spec.rb +151 -0
- data/spec/riak/beefcake_protobuffs_backend_spec.rb +68 -106
- data/spec/riak/bucket_spec.rb +81 -77
- data/spec/riak/client_spec.rb +43 -340
- data/spec/riak/core_ext/to_param_spec.rb +2 -2
- data/spec/riak/counter_spec.rb +20 -20
- data/spec/riak/crdt/counter_spec.rb +52 -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 +77 -0
- data/spec/riak/crdt/set_spec.rb +58 -0
- data/spec/riak/crdt/shared_examples.rb +74 -0
- data/spec/riak/crdt/typed_collection_spec.rb +231 -0
- data/spec/riak/escape_spec.rb +33 -37
- data/spec/riak/feature_detection_spec.rb +45 -45
- data/spec/riak/index_collection_spec.rb +12 -12
- data/spec/riak/link_spec.rb +34 -34
- data/spec/riak/list_buckets_spec.rb +7 -7
- data/spec/riak/map_reduce/filter_builder_spec.rb +6 -6
- data/spec/riak/map_reduce/phase_spec.rb +35 -35
- data/spec/riak/map_reduce_spec.rb +89 -87
- data/spec/riak/multiget_spec.rb +20 -15
- data/spec/riak/node_spec.rb +5 -152
- data/spec/riak/robject_spec.rb +95 -108
- data/spec/riak/search_spec.rb +17 -139
- data/spec/riak/secondary_index_spec.rb +49 -49
- data/spec/riak/serializers_spec.rb +9 -9
- data/spec/riak/stamp_spec.rb +9 -9
- data/spec/riak/walk_spec_spec.rb +46 -46
- data/spec/spec_helper.rb +14 -22
- data/spec/support/certs/README.md +13 -0
- data/spec/support/certs/ca.crt +22 -0
- data/spec/support/certs/client.crt +95 -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 +95 -0
- data/spec/support/certs/server.key +27 -0
- data/spec/support/integration_setup.rb +1 -1
- data/spec/support/search_corpus_setup.rb +29 -8
- data/spec/support/test_client.rb +46 -0
- data/spec/support/test_client.yml.example +10 -0
- data/spec/support/unified_backend_examples.rb +104 -83
- data/spec/support/version_filter.rb +2 -2
- data/spec/support/wait_until.rb +14 -0
- metadata +134 -132
- data/erl_src/riak_kv_test014_backend.beam +0 -0
- data/erl_src/riak_kv_test014_backend.erl +0 -189
- data/erl_src/riak_kv_test_backend.beam +0 -0
- data/erl_src/riak_kv_test_backend.erl +0 -731
- data/erl_src/riak_search_test_backend.beam +0 -0
- data/erl_src/riak_search_test_backend.erl +0 -175
- data/lib/riak/client/excon_backend.rb +0 -172
- data/lib/riak/client/http_backend.rb +0 -413
- data/lib/riak/client/http_backend/bucket_streamer.rb +0 -15
- data/lib/riak/client/http_backend/chunked_json_streamer.rb +0 -42
- data/lib/riak/client/http_backend/configuration.rb +0 -227
- data/lib/riak/client/http_backend/key_streamer.rb +0 -15
- data/lib/riak/client/http_backend/object_methods.rb +0 -114
- data/lib/riak/client/http_backend/request_headers.rb +0 -34
- data/lib/riak/client/http_backend/transport_methods.rb +0 -201
- data/lib/riak/client/instrumentation.rb +0 -25
- data/lib/riak/client/net_http_backend.rb +0 -82
- data/lib/riak/cluster.rb +0 -151
- data/lib/riak/failed_request.rb +0 -81
- data/lib/riak/instrumentation.rb +0 -6
- data/lib/riak/node.rb +0 -40
- data/lib/riak/node/configuration.rb +0 -304
- data/lib/riak/node/console.rb +0 -133
- data/lib/riak/node/control.rb +0 -207
- data/lib/riak/node/defaults.rb +0 -85
- data/lib/riak/node/generation.rb +0 -127
- data/lib/riak/node/log.rb +0 -34
- data/lib/riak/node/version.rb +0 -29
- data/lib/riak/search.rb +0 -3
- data/lib/riak/test_server.rb +0 -89
- data/lib/riak/util/headers.rb +0 -32
- data/lib/riak/util/multipart.rb +0 -52
- data/lib/riak/util/multipart/stream_parser.rb +0 -62
- data/spec/fixtures/munchausen.txt +0 -1033
- data/spec/integration/riak/cluster_spec.rb +0 -88
- data/spec/integration/riak/http_backends_spec.rb +0 -180
- data/spec/integration/riak/node_spec.rb +0 -170
- data/spec/integration/riak/test_server_spec.rb +0 -57
- data/spec/riak/excon_backend_spec.rb +0 -102
- data/spec/riak/headers_spec.rb +0 -21
- data/spec/riak/http_backend/configuration_spec.rb +0 -273
- data/spec/riak/http_backend/object_methods_spec.rb +0 -243
- data/spec/riak/http_backend/transport_methods_spec.rb +0 -97
- data/spec/riak/http_backend_spec.rb +0 -367
- data/spec/riak/instrumentation_spec.rb +0 -167
- data/spec/riak/multipart_spec.rb +0 -23
- data/spec/riak/net_http_backend_spec.rb +0 -15
- data/spec/riak/stream_parser_spec.rb +0 -53
- data/spec/support/drb_mock_server.rb +0 -39
- data/spec/support/http_backend_implementation_examples.rb +0 -253
- data/spec/support/mock_server.rb +0 -81
- data/spec/support/mocks.rb +0 -4
- data/spec/support/riak_test.rb +0 -77
- data/spec/support/sometimes.rb +0 -46
- data/spec/support/test_server.rb +0 -61
- data/spec/support/test_server.yml.example +0 -14
data/lib/riak/i18n.rb
CHANGED
data/lib/riak/json.rb
CHANGED
@@ -9,7 +9,7 @@ require 'riak/core_ext/json'
|
|
9
9
|
module Riak
|
10
10
|
class << self
|
11
11
|
# Options that will be passed to the JSON parser and encoder.
|
12
|
-
# Defaults to {:max_nesting => 20}
|
12
|
+
# Defaults to `{:max_nesting => 20}`
|
13
13
|
attr_accessor :json_options
|
14
14
|
end
|
15
15
|
self.json_options = {:max_nesting => 20}
|
data/lib/riak/locale/en.yml
CHANGED
@@ -9,6 +9,14 @@ en:
|
|
9
9
|
counter:
|
10
10
|
bucket_needs_allow_mult: "Counters require allow_mult to be enabled on their bucket."
|
11
11
|
increment_by_integer: "Counters can only be incremented or decremented by integers."
|
12
|
+
crdt:
|
13
|
+
precondition_error: "Riak server returned precondition error: %{message}"
|
14
|
+
set_removal_without_context: "CRDT Sets do not support removal without context. Store and reload the set before removing members."
|
15
|
+
unknown_field: "Unknown field type %{symbol}, expected one of :counter, :map, or :set."
|
16
|
+
unknown_inner_field: "Unknown field type %{symbol}, expected one of :counter, :flag, :map, :register, or :set."
|
17
|
+
serialize_no_ops: "Can't serialize an empty list of CRDT operations."
|
18
|
+
flag:
|
19
|
+
not_boolean: "Flags can only be true or false."
|
12
20
|
deprecated:
|
13
21
|
port: "DEPRECATION: Riak::Client#port has been deprecated, use #http_port or #pb_port for the appropriate protocol.\n%{backtrace}"
|
14
22
|
search: "DEPRECATION: Riak Search features are included in the main client, you no longer need to require 'riak/search'.\n%{backtrace}"
|
@@ -42,13 +50,19 @@ en:
|
|
42
50
|
loading_bucket: "while loading bucket '%{name}'"
|
43
51
|
list_buckets: "Riak::Client#buckets is an expensive operation that should not be used in production.\n %{backtrace}"
|
44
52
|
list_keys: "Riak::Bucket#keys is an expensive operation that should not be used in production.\n %{backtrace}"
|
45
|
-
luwak_unsupported: "Riak server does not support Luwak. Enable it in app.config before using."
|
46
53
|
missing_block: "A block must be given."
|
47
54
|
missing_host_and_port: "You must specify a host and port, or use the defaults of 127.0.0.1:8098"
|
48
55
|
module_function_pair_required: "function must have two elements when an array"
|
49
56
|
not_found: "The requested object was not found."
|
50
57
|
no_pipes: "Could not find or open pipes for Riak console in %{path}."
|
51
58
|
object_in_conflict: "The object is in conflict (has siblings) and cannot be treated singly or saved: %{robject}"
|
59
|
+
pbc:
|
60
|
+
failed_header: "Failed to receive a header from Riak."
|
61
|
+
unexpected_eof: "Unexpected EOF on PBC socket"
|
62
|
+
user_not_username: "Authentication hash expects :user, not :username."
|
63
|
+
wanted_index_resp: "Expected IndexResp during secondary index query"
|
64
|
+
wanted_dt_fetch_resp: "Expected PBC DtFetchResp during CRDT fetch"
|
65
|
+
wanted_dt_update_resp: "Expected PBC DtUpdateResp during CRDT update"
|
52
66
|
port_invalid: "port must be an integer between 0 and 65535"
|
53
67
|
protobuffs_failed_request: "Expected success from Riak but received %{code}. %{body}"
|
54
68
|
protobuffs_configuration: "The %{backend} Protobuffs backend cannot be used. Please check its requirements."
|
@@ -58,6 +72,14 @@ en:
|
|
58
72
|
search_remove_requires_id_or_query: "Search index documents to be removed must have 'id' or 'query' keys."
|
59
73
|
serializer_not_implemented: "No serializer has been registered for content type %{content_type}"
|
60
74
|
source_and_root_required: "Riak::Node configuration must include :source and :root keys."
|
75
|
+
ssl:
|
76
|
+
cert_host_mismatch: "The presented SSL/TLS certificate did not match the hostname."
|
77
|
+
cert_not_in_valid_range: "The presented SSL/TLS certificate is either expired or premature."
|
78
|
+
cert_revoked: "The presented SSL/TLS certificate has been revoked."
|
79
|
+
eof_during_init: "Unexpected EOF during SSL/TLS initialization."
|
80
|
+
read_data_error: "Tried to read cert or key from %{candidate}, caught error %{actual}."
|
81
|
+
unexpected_during_init: "Expected %{expected}, got %{actual} with body %{body} during SSL/TLS initialization."
|
82
|
+
unknown_key_type: "Can't figure out what the client key is. Expected it to be some kind of OpenSSL::PKey::PKey subclass, a filename string, or string data representing the key itself."
|
61
83
|
stale_write_prevented: "Stale write prevented by client."
|
62
84
|
stored_function_invalid: "function must have :bucket and :key when a hash"
|
63
85
|
streaming_bucket_list_without_block: "Streaming bucket list was requested but no block was given."
|
@@ -67,3 +89,6 @@ en:
|
|
67
89
|
wrong_argument_count_walk_spec: "wrong number of arguments (one Hash or bucket,tag,keep required)"
|
68
90
|
zero_length_bucket: "bucket name cannot be a String of zero length"
|
69
91
|
zero_length_key: "key cannot be a String of zero length"
|
92
|
+
zero_length_index: "index name cannot be a String of zero length"
|
93
|
+
zero_length_schema: "schema name cannot be a String of zero length"
|
94
|
+
zero_length_content: "content cannot be a String of zero length"
|
data/lib/riak/locale/fr.yml
CHANGED
@@ -30,7 +30,6 @@ fr:
|
|
30
30
|
loading_bucket: "pendant le chargement du bucket '%{name}'"
|
31
31
|
list_buckets: "Riak::Client#buckets est une opération coûteuse et ne doit pas être utilisée en production.\n %{backtrace}"
|
32
32
|
list_keys: "Riak::Bucket#keys est une opération coûteuse et ne doit pas être utilisée en production.\n %{backtrace}"
|
33
|
-
luwak_unsupported: "Le serveur Riak ne supporte pas Luwak. Activez-le dans app.config avant de l'utiliser"
|
34
33
|
missing_block: "Un bloc doit être fourni."
|
35
34
|
missing_host_and_port: "Vous devez spécifier un hôte et un port, utiliser la valeur par défaut : 127.0.0.1:8098"
|
36
35
|
module_function_pair_required: "la fonction doit avoir deux élément lorsqu'elle est définie par un tableau"
|
data/lib/riak/map_reduce.rb
CHANGED
@@ -5,7 +5,7 @@ require 'riak/client'
|
|
5
5
|
require 'riak/bucket'
|
6
6
|
require 'riak/robject'
|
7
7
|
require 'riak/walk_spec'
|
8
|
-
require 'riak/failed_request'
|
8
|
+
require 'riak/errors/failed_request'
|
9
9
|
require 'riak/map_reduce_error'
|
10
10
|
require 'riak/map_reduce/phase'
|
11
11
|
require 'riak/map_reduce/filter_builder'
|
data/lib/riak/multiget.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'riak/client'
|
2
2
|
require 'riak/bucket'
|
3
|
-
require 'riak/cluster'
|
4
3
|
|
5
4
|
module Riak
|
6
5
|
# Coordinates a parallel fetch operation for multiple values.
|
@@ -25,7 +24,7 @@ module Riak
|
|
25
24
|
# Perform a Riak Multiget operation.
|
26
25
|
# @param [Client] client the {Riak::Client} that will perform the multiget
|
27
26
|
# @param [Array<Bucket, String>] fetch_list an {Array} of {Bucket} and {String} keys to fetch
|
28
|
-
# @return [Hash<fetch_list_entry, RObject] result_hash a {Hash} of {Bucket} and {String} key pairs to {
|
27
|
+
# @return [Hash<fetch_list_entry, RObject] result_hash a {Hash} of {Bucket} and {String} key pairs to {RObject} instances
|
29
28
|
def self.get_all(client, fetch_list)
|
30
29
|
multi = new client, fetch_list
|
31
30
|
multi.fetch
|
data/lib/riak/rcontent.rb
CHANGED
@@ -68,7 +68,10 @@ module Riak
|
|
68
68
|
@data
|
69
69
|
end
|
70
70
|
|
71
|
-
# @param [Object] unmarshaled form of the data to be stored in
|
71
|
+
# @param [Object] new_data unmarshaled form of the data to be stored in
|
72
|
+
# Riak. Object will be serialized using {#serialize} if a known
|
73
|
+
# content_type is used. Setting this overrides values stored with
|
74
|
+
# {#raw_data=}
|
72
75
|
# @return [Object] the object stored
|
73
76
|
def data=(new_data)
|
74
77
|
if new_data.respond_to?(:read)
|
@@ -89,7 +92,9 @@ module Riak
|
|
89
92
|
@raw_data
|
90
93
|
end
|
91
94
|
|
92
|
-
# @param [String, IO-like] the raw data to be stored in
|
95
|
+
# @param [String, IO-like] new_raw_data the raw data to be stored in Riak
|
96
|
+
# at this key, will not be marshaled or manipulated prior to storage.
|
97
|
+
# Overrides any data stored by {#data=}
|
93
98
|
# @return [String] the data stored
|
94
99
|
def raw_data=(new_raw_data)
|
95
100
|
@data = nil
|
@@ -130,7 +135,7 @@ module Riak
|
|
130
135
|
"#<#{self.class.name} [#{@content_type}]:#{body}>"
|
131
136
|
end
|
132
137
|
|
133
|
-
# @
|
138
|
+
# @api private
|
134
139
|
def load_map_reduce_value(hash)
|
135
140
|
metadata = hash['metadata']
|
136
141
|
extract_if_present(metadata, 'X-Riak-VTag', :etag)
|
data/lib/riak/robject.rb
CHANGED
@@ -29,7 +29,8 @@ module Riak
|
|
29
29
|
alias :vector_clock :vclock
|
30
30
|
alias :vector_clock= :vclock=
|
31
31
|
|
32
|
-
# @return [Boolean] whether to attempt to prevent stale writes using
|
32
|
+
# @return [Boolean] whether to attempt to prevent stale writes using
|
33
|
+
# conditional PUT semantics, If-None-Match: * or If-Match: etag
|
33
34
|
# @see http://wiki.basho.com/display/RIAK/REST+API#RESTAPI-Storeaneworexistingobjectwithakey Riak Rest API Docs
|
34
35
|
attr_accessor :prevent_stale_writes
|
35
36
|
|
@@ -182,13 +183,6 @@ module Riak
|
|
182
183
|
"#<#{self.class.name} {#{bucket.name}#{"," + @key if @key}} [#{body}]>"
|
183
184
|
end
|
184
185
|
|
185
|
-
# Walks links from this object to other objects in Riak.
|
186
|
-
# @param [Array<Hash,WalkSpec>] link specifications for the query
|
187
|
-
def walk(*params)
|
188
|
-
specs = WalkSpec.normalize(*params)
|
189
|
-
@bucket.client.link_walk(self, specs)
|
190
|
-
end
|
191
|
-
|
192
186
|
# Converts the object to a link suitable for linking other objects
|
193
187
|
# to it
|
194
188
|
# @param [String] tag the tag to apply to the link
|
data/lib/riak/secondary_index.rb
CHANGED
@@ -5,10 +5,10 @@ module Riak
|
|
5
5
|
include Client::FeatureDetection
|
6
6
|
|
7
7
|
# Create a Riak Secondary Index operation
|
8
|
-
# @param [Bucket] the {Riak::Bucket} we'll query against
|
9
|
-
# @param [String] the index name
|
10
|
-
# @param [String,Integer,Range<String,Integer>]
|
11
|
-
# range of values to query for
|
8
|
+
# @param [Bucket] bucket the {Riak::Bucket} we'll query against
|
9
|
+
# @param [String] index the index name
|
10
|
+
# @param [String,Integer,Range<String,Integer>] query
|
11
|
+
# a single value or range of values to query for
|
12
12
|
def initialize(bucket, index, query, options={})
|
13
13
|
@bucket = bucket
|
14
14
|
@client = @bucket.client
|
data/lib/riak/serializers.rb
CHANGED
@@ -23,7 +23,7 @@ module Riak
|
|
23
23
|
|
24
24
|
def serializer_for(content_type)
|
25
25
|
serializers.fetch(content_type[/^[^;\s]+/]) do
|
26
|
-
raise
|
26
|
+
raise IOError.new(t('serializer_not_implemented', :content_type => content_type.inspect))
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
data/lib/riak/util/escape.rb
CHANGED
@@ -25,12 +25,12 @@ module Riak
|
|
25
25
|
# being stored. This increases compatibility with the Protocol
|
26
26
|
# Buffers transport and reduces inconsistency of link-walking
|
27
27
|
# vs. regular operations. If the node you are connecting to has
|
28
|
-
# set {http_url_encoding, on}
|
28
|
+
# set `{http_url_encoding, on}`, set this to true. Default is false.
|
29
29
|
# @return [true,false] Whether Riak decodes URL-encoded paths and headers
|
30
30
|
attr_accessor :url_decoding
|
31
31
|
end
|
32
32
|
|
33
|
-
self.escaper =
|
33
|
+
self.escaper = URI
|
34
34
|
self.url_decoding = false
|
35
35
|
|
36
36
|
module Util
|
@@ -52,9 +52,7 @@ module Riak
|
|
52
52
|
# @return [String] the escaped path segment
|
53
53
|
def escape(bucket_or_key)
|
54
54
|
if Riak.escaper == URI
|
55
|
-
Riak.escaper.escape(bucket_or_key.to_s).
|
56
|
-
gsub(" ", "%20").gsub("+", "%2B").gsub("/", "%2F").
|
57
|
-
gsub("[", "%5B").gsub("]", "%5D")
|
55
|
+
Riak.escaper.escape(bucket_or_key.to_s).gsub(" ", "%20").gsub("+", "%2B").gsub('/', "%2F")
|
58
56
|
else #CGI
|
59
57
|
Riak.escaper.escape(bucket_or_key.to_s).gsub("+", "%20").gsub('/', "%2F")
|
60
58
|
end
|
data/lib/riak/version.rb
CHANGED
data/lib/riak/walk_spec.rb
CHANGED
@@ -6,10 +6,14 @@ module Riak
|
|
6
6
|
# The specification of how to follow links from one object to another in Riak,
|
7
7
|
# when using the link-walker resource.
|
8
8
|
# Example link-walking operation:
|
9
|
-
#
|
9
|
+
#
|
10
|
+
# GET /riak/artists/REM/albums,_,_/tracks,_,1
|
11
|
+
#
|
10
12
|
# This operation would have two WalkSpecs:
|
11
|
-
#
|
12
|
-
#
|
13
|
+
#
|
14
|
+
# Riak::WalkSpec.new({:bucket => 'albums'})
|
15
|
+
# Riak::WalkSpec.new({:bucket => 'tracks', :result => true})
|
16
|
+
#
|
13
17
|
class WalkSpec
|
14
18
|
include Util::Translation
|
15
19
|
extend Util::Translation
|
data/riak-client.gemspec
CHANGED
@@ -12,18 +12,20 @@ Gem::Specification.new do |gem|
|
|
12
12
|
gem.authors = ["Sean Cribbs", 'Bryce Kerley']
|
13
13
|
gem.license = 'Apache 2.0'
|
14
14
|
|
15
|
+
gem.required_ruby_version = '>= 1.9.3'
|
16
|
+
|
15
17
|
# Deps
|
16
|
-
gem.add_development_dependency "rspec", "~>
|
17
|
-
gem.add_development_dependency
|
18
|
-
gem.add_development_dependency
|
19
|
-
gem.add_development_dependency
|
20
|
-
gem.add_development_dependency '
|
21
|
-
|
18
|
+
gem.add_development_dependency "rspec", "~> 3.0.0"
|
19
|
+
gem.add_development_dependency 'rake', '~> 10.1.1'
|
20
|
+
gem.add_development_dependency 'yard', '~> 0.8.7'
|
21
|
+
gem.add_development_dependency 'redcarpet', '~> 3.0.0'
|
22
|
+
gem.add_development_dependency 'simplecov', '~> 0.8.2'
|
23
|
+
|
22
24
|
gem.add_runtime_dependency "i18n", ">=0.4.0"
|
23
|
-
gem.add_runtime_dependency "
|
24
|
-
gem.add_runtime_dependency "beefcake", "~>1.0.0"
|
25
|
+
gem.add_runtime_dependency "beefcake", ">= 1.0.0.pre1"
|
25
26
|
gem.add_runtime_dependency "multi_json", "~>1.0"
|
26
27
|
gem.add_runtime_dependency "innertube", "~>1.0.2"
|
28
|
+
gem.add_runtime_dependency 'r509-cert-validator', '~> 0.0.4'
|
27
29
|
|
28
30
|
# Files
|
29
31
|
|
@@ -0,0 +1,25 @@
|
|
1
|
+
Bitcask is an Erlang application that provides an API for storing and retrieving key/value data into a log-structured hash table that provides very fast access. The design owes a lot to the principles found in log-structured file systems and draws inspiration from a number of designs that involve log file merging.
|
2
|
+
|
3
|
+
Strengths
|
4
|
+
Low latency per item read or written
|
5
|
+
This is due to the write-once, append-only nature of the Bitcask database files. High throughput, especially when writing an incoming stream of random items Because the data being written doesn't need to be ordered on disk and because the log structured design allows for minimal disk head movement during writes these operations generally saturate the I/O and disk bandwidth.
|
6
|
+
|
7
|
+
Ability to handle datasets larger than RAM w/o degradation
|
8
|
+
Because access to data in Bitcask is direct lookup from an in-memory hash table finding data on disk is very efficient, even when data sets are very large.
|
9
|
+
|
10
|
+
Single Seek to Retrieve Any Value
|
11
|
+
Bitcask's in-memory hash-table of keys point directly to locations on disk where the data lives. Bitcask never uses more than one disk seek to read a value and sometimes, due to file-system caching done by the operating system, even that isn't necessary.
|
12
|
+
|
13
|
+
Predictable Lookup and Insert Performance
|
14
|
+
As you might expect from the description above, read operations have a fixed, predictable behavior. What you might not expect is that this is also true for writes. Write operations are at most a seek to the end of the current file open writing and an append to that file.
|
15
|
+
|
16
|
+
Fast, bounded Crash Recovery
|
17
|
+
Due to the append-only write once nature of Bitcask files, recovery is easy and fast. The only items that might be lost are partially written records at the tail of the file last opened for writes. Recovery need only review the last record or two written and verify CRC data to ensure that the data is consistent.
|
18
|
+
|
19
|
+
Easy Backup
|
20
|
+
In most systems backup can be very complicated but here again Bitcask simplifies this process due to its append-only write once disk format. Any utility that archives or copies files in disk-block order will properly backup or copy a Bitcask database.
|
21
|
+
|
22
|
+
Weakness
|
23
|
+
Keys Must Fit In Memory
|
24
|
+
Bitcask keeps all keys in memory at all times, this means that your system must have enough memory to contain your entire keyspace with room for other operational components and operating system resident filesystem buffer space.
|
25
|
+
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'riak'
|
3
|
+
|
4
|
+
describe 'Bucket Types', test_client: true, integration: true do
|
5
|
+
let(:bucket){ random_bucket 'bucket_type_spec' }
|
6
|
+
|
7
|
+
describe 'performing key-value operations' do
|
8
|
+
# for the sake of having a non-default one, not search
|
9
|
+
let(:bucket_type){ 'yokozuna' }
|
10
|
+
let(:object) do
|
11
|
+
object = bucket.new random_key
|
12
|
+
object.data = 'hello'
|
13
|
+
object.content_type = 'text/plain'
|
14
|
+
object.store type: bucket_type
|
15
|
+
object
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'only retrieves with a bucket type' do
|
19
|
+
expect{ bucket.get object.key, type: bucket_type }.to_not raise_error
|
20
|
+
expect{ bucket.get object.key }.to raise_error /not_found/
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'deletes from the bucket only with a bucket type' do
|
24
|
+
expect(bucket.delete object.key).to eq true
|
25
|
+
expect{ bucket.get object.key, type: bucket_type }.to_not raise_error
|
26
|
+
|
27
|
+
expect{ bucket.delete object.key, type: bucket_type }.to_not raise_error
|
28
|
+
expect{ bucket.get object.key, type: bucket_type }.to raise_error /not_found/
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'self-deletes only with a bucket type' do
|
32
|
+
expect(object.delete).to be
|
33
|
+
expect{ object.reload type: bucket_type }.to_not raise_error
|
34
|
+
|
35
|
+
expect(object.delete type: bucket_type).to be
|
36
|
+
expect{ object.reload type: bucket_type }.to raise_error /not_found/
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe 'performing CRDT set operations' do
|
41
|
+
let(:bucket_type){ Riak::Crdt::DEFAULT_BUCKET_TYPES[:set] }
|
42
|
+
let(:set) do
|
43
|
+
set = Riak::Crdt::Set.new bucket, random_key
|
44
|
+
set.add random_key
|
45
|
+
set
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'retrieves the set blob via key-value using a bucket type' do
|
49
|
+
expect{ bucket.get set.key }.to raise_error /not_found/
|
50
|
+
expect(bucket.get set.key, type: bucket_type).to be
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'deletes the set blob through the bucket type' do
|
54
|
+
expect(bucket.delete set.key).to be
|
55
|
+
expect{ bucket.get set.key, type: bucket_type }.to_not raise_error
|
56
|
+
|
57
|
+
expect(bucket.delete set.key, type: bucket_type).to be
|
58
|
+
expect{ bucket.get set.key, type: bucket_type }.to raise_error /not_found/
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -1,51 +1,36 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'riak'
|
3
3
|
|
4
|
-
describe Riak::Counter,
|
4
|
+
describe Riak::Counter, test_client: true, integration: true do
|
5
5
|
before :all do
|
6
|
-
|
7
|
-
http_port: test_server.http_port,
|
8
|
-
pb_port: test_server.pb_port,
|
9
|
-
protocol: 'pbc'
|
10
|
-
}
|
11
|
-
test_server.start
|
12
|
-
@client = Riak::Client.new opts
|
13
|
-
@bucket = @client['counter_spec']
|
6
|
+
@bucket = random_bucket 'counter_spec'
|
14
7
|
@bucket.allow_mult = true
|
15
8
|
|
16
9
|
@counter = Riak::Counter.new @bucket, 'counter_spec'
|
17
10
|
end
|
18
11
|
|
12
|
+
it 'should read and update' do
|
13
|
+
initial = @counter.value
|
19
14
|
|
20
|
-
|
21
|
-
|
22
|
-
before :all do
|
23
|
-
@client.protocol = protocol
|
24
|
-
end
|
25
|
-
it 'should read and update' do
|
26
|
-
initial = @counter.value
|
15
|
+
@counter.increment
|
16
|
+
@counter.increment
|
27
17
|
|
28
|
-
|
29
|
-
@counter.increment
|
18
|
+
expect(@counter.value).to eq(initial + 2)
|
30
19
|
|
31
|
-
|
20
|
+
@counter.decrement 2
|
32
21
|
|
33
|
-
|
22
|
+
expect(@counter.value).to eq(initial)
|
34
23
|
|
35
|
-
|
24
|
+
5.times do
|
25
|
+
amt = rand(10_000)
|
26
|
+
|
27
|
+
@counter.increment amt
|
28
|
+
expect(@counter.value).to eq(initial + amt)
|
36
29
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
@counter.increment amt
|
41
|
-
@counter.value.should == (initial + amt)
|
30
|
+
@counter.decrement (amt * 2)
|
31
|
+
expect(@counter.value).to eq(initial - amt)
|
42
32
|
|
43
|
-
|
44
|
-
@counter.value.should == (initial - amt)
|
45
|
-
|
46
|
-
@counter.increment_and_return(amt).should == initial
|
47
|
-
end
|
48
|
-
end
|
33
|
+
expect(@counter.increment_and_return(amt)).to eq(initial)
|
49
34
|
end
|
50
35
|
end
|
51
36
|
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'riak'
|
3
|
+
|
4
|
+
describe "CRDTs", integration: true, test_client: true do
|
5
|
+
let(:bucket) { random_bucket }
|
6
|
+
|
7
|
+
describe 'configuration' do
|
8
|
+
it "should allow default bucket-types to be configured for each data type" do
|
9
|
+
expect(Riak::Crdt::Set.new(bucket, 'set').bucket_type).to eq 'sets'
|
10
|
+
|
11
|
+
Riak::Crdt::DEFAULT_BUCKET_TYPES[:set] = 'new_set_default'
|
12
|
+
expect(Riak::Crdt::Set.new(bucket, 'set').bucket_type).to eq 'new_set_default'
|
13
|
+
|
14
|
+
Riak::Crdt::DEFAULT_BUCKET_TYPES[:set] = 'sets'
|
15
|
+
expect(Riak::Crdt::Set.new(bucket, 'set').bucket_type).to eq 'sets'
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should allow override bucket-types for instances" do
|
19
|
+
expect(Riak::Crdt::Set.new(bucket, 'set', 'other_bucket_type').bucket_type).to eq 'other_bucket_type'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'an anonymous counter' do
|
24
|
+
subject { Riak::Crdt::Counter.new bucket, nil }
|
25
|
+
it 'accepts a Riak-assigned name' do
|
26
|
+
subject.increment
|
27
|
+
expect(subject.key).to be
|
28
|
+
expect(subject.value).to eq 1
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'counters' do
|
33
|
+
subject { Riak::Crdt::Counter.new bucket, random_key }
|
34
|
+
it 'should allow straightforward counter ops' do
|
35
|
+
start = subject.value
|
36
|
+
subject.increment
|
37
|
+
expect(subject.value).to eq(start + 1)
|
38
|
+
subject.increment
|
39
|
+
expect(subject.value).to eq(start + 2)
|
40
|
+
subject.increment -1
|
41
|
+
expect(subject.value).to eq(start + 1)
|
42
|
+
subject.decrement
|
43
|
+
expect(subject.value).to eq(start)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should allow batched counter ops' do
|
47
|
+
start = subject.value
|
48
|
+
subject.batch do |s|
|
49
|
+
s.increment
|
50
|
+
s.increment 2
|
51
|
+
s.increment
|
52
|
+
s.increment
|
53
|
+
end
|
54
|
+
expect(subject.value).to eq(start + 5)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
describe 'sets' do
|
58
|
+
|
59
|
+
subject { Riak::Crdt::Set.new bucket, random_key }
|
60
|
+
|
61
|
+
it 'should allow straightforward set ops' do
|
62
|
+
start = subject.members
|
63
|
+
addition = random_key
|
64
|
+
|
65
|
+
subject.add addition
|
66
|
+
expect(subject.include? addition).to be
|
67
|
+
expect(subject.members).to include(addition)
|
68
|
+
|
69
|
+
subject.remove addition
|
70
|
+
expect(subject.include? addition).to_not be
|
71
|
+
expect(subject.members).to_not include(addition)
|
72
|
+
expect(subject.members).to eq(start)
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'lets Riak silently accept removals after reload' do
|
76
|
+
addition = random_key
|
77
|
+
subject.add addition
|
78
|
+
|
79
|
+
other = Riak::Crdt::Set.new subject.bucket, subject.key
|
80
|
+
expect{ other.remove addition }.to raise_error(Riak::CrdtError::SetRemovalWithoutContextError)
|
81
|
+
other.reload
|
82
|
+
expect{ other.remove addition }.to_not raise_error
|
83
|
+
other.reload
|
84
|
+
expect{ other.remove 'an element not in the set' }.to_not raise_error
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should allow batched set ops' do
|
88
|
+
subject.add 'zero'
|
89
|
+
subject.reload
|
90
|
+
|
91
|
+
subject.batch do |s|
|
92
|
+
s.add 'first'
|
93
|
+
s.remove 'zero'
|
94
|
+
end
|
95
|
+
|
96
|
+
expect(subject.members.to_a).to eq %w{first}
|
97
|
+
end
|
98
|
+
end
|
99
|
+
describe 'maps' do
|
100
|
+
subject { Riak::Crdt::Map.new bucket, random_key }
|
101
|
+
|
102
|
+
it 'should allow straightforward map ops' do
|
103
|
+
subject.registers['first'] = 'hello'
|
104
|
+
expect(subject.registers['first']).to eq('hello')
|
105
|
+
|
106
|
+
subject.sets['arnold'].add 'commando'
|
107
|
+
subject.sets['arnold'].add 'terminator'
|
108
|
+
expect(subject.sets['arnold'].members).to include('commando')
|
109
|
+
subject.sets['arnold'].remove 'commando'
|
110
|
+
expect(subject.sets['arnold'].members).to_not include('commando')
|
111
|
+
expect(subject.sets['arnold'].members).to include('terminator')
|
112
|
+
|
113
|
+
subject.maps['first'].registers['second'] = 'good evening'
|
114
|
+
subject.maps['first'].maps['third'].counters['fourth'].increment
|
115
|
+
|
116
|
+
expect(subject.maps['first'].registers['second']).to eq('good evening')
|
117
|
+
expect(subject.maps['first'].maps['third'].counters['fourth'].value).to eq(1)
|
118
|
+
|
119
|
+
subject.counters['hits'].increment
|
120
|
+
expect(subject.counters['hits'].value).to eq 1
|
121
|
+
|
122
|
+
subject.flags['yes'] = true
|
123
|
+
expect(subject.flags['yes']).to eq true
|
124
|
+
|
125
|
+
expect do
|
126
|
+
subject.registers.delete 'first'
|
127
|
+
subject.sets.delete 'arnold'
|
128
|
+
subject.maps.delete 'first'
|
129
|
+
subject.counters.delete 'hits'
|
130
|
+
subject.flags.delete 'yes'
|
131
|
+
end.to_not raise_error
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'should allow batched map ops' do
|
135
|
+
subject.batch do |s|
|
136
|
+
s.registers['condiment'] = 'ketchup'
|
137
|
+
s.counters['banana'].increment
|
138
|
+
end
|
139
|
+
|
140
|
+
expect(subject.registers['condiment']).to eq 'ketchup'
|
141
|
+
expect(subject.counters['banana'].value).to eq 1
|
142
|
+
end
|
143
|
+
|
144
|
+
describe 'containing a map' do
|
145
|
+
it 'should bubble straightforward map ops up' do
|
146
|
+
street_map = subject.maps['street']
|
147
|
+
|
148
|
+
street_map.registers['bird'] = 'avenue'
|
149
|
+
street_map.flags['traffic_light'] = false
|
150
|
+
|
151
|
+
expect(subject.maps['street'])
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'should include inner-map ops in the outer-map batch' do
|
155
|
+
subject.batch do |m|
|
156
|
+
m.maps['road'].counters['speedbumps'].increment 4
|
157
|
+
m.maps['road'].sets['signs'].add 'yield'
|
158
|
+
end
|
159
|
+
|
160
|
+
expect(subject.maps['road'].counters['speedbumps'].value).to eq 4
|
161
|
+
expect(subject.maps['road'].sets['signs'].include? 'yield').to be
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe 'containing a register' do
|
166
|
+
it 'should bubble straightforward register ops up' do
|
167
|
+
subject.registers['hkey_local_machine'] = 'registry'
|
168
|
+
|
169
|
+
expect(subject.registers['hkey_local_machine']).to eq 'registry'
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe 'containing a flag' do
|
174
|
+
it 'should bubble straightforward flag ops up' do
|
175
|
+
subject.flags['enable_magic'] = true
|
176
|
+
|
177
|
+
expect(subject.flags['enable_magic']).to be
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|