riak-client 2.4.1 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/.document +5 -5
  3. data/.gitignore +3 -0
  4. data/Gemfile +17 -17
  5. data/Guardfile +20 -20
  6. data/LICENSE.md +16 -16
  7. data/RELNOTES.md +4 -0
  8. data/Rakefile +6 -1
  9. data/lib/riak/client/beefcake/crdt/counter_loader.rb +18 -18
  10. data/lib/riak/client/beefcake/crdt/hyper_log_log_loader.rb +18 -0
  11. data/lib/riak/client/beefcake/crdt/map_loader.rb +64 -64
  12. data/lib/riak/client/beefcake/crdt_loader.rb +4 -1
  13. data/lib/riak/client/beefcake/crdt_operator.rb +13 -0
  14. data/lib/riak/client/beefcake/footer +4 -4
  15. data/lib/riak/client/beefcake/header +6 -6
  16. data/lib/riak/client/beefcake/messages.rb +67 -10
  17. data/lib/riak/client/decaying.rb +36 -36
  18. data/lib/riak/client/feature_detection.rb +120 -120
  19. data/lib/riak/client/instrumentation.rb +19 -19
  20. data/lib/riak/client/node.rb +49 -49
  21. data/lib/riak/client/search.rb +27 -27
  22. data/lib/riak/conflict.rb +13 -13
  23. data/lib/riak/core_ext.rb +7 -7
  24. data/lib/riak/core_ext/blank.rb +53 -53
  25. data/lib/riak/core_ext/extract_options.rb +7 -7
  26. data/lib/riak/core_ext/json.rb +15 -15
  27. data/lib/riak/core_ext/slice.rb +18 -18
  28. data/lib/riak/core_ext/stringify_keys.rb +10 -10
  29. data/lib/riak/core_ext/symbolize_keys.rb +10 -10
  30. data/lib/riak/core_ext/to_param.rb +31 -31
  31. data/lib/riak/crdt.rb +23 -21
  32. data/lib/riak/crdt/base.rb +1 -1
  33. data/lib/riak/crdt/hyper_log_log.rb +97 -0
  34. data/lib/riak/crdt/operation.rb +19 -19
  35. data/lib/riak/encoding.rb +6 -6
  36. data/lib/riak/errors/backend_creation.rb +9 -9
  37. data/lib/riak/errors/connection_error.rb +50 -50
  38. data/lib/riak/errors/protobuffs_error.rb +11 -11
  39. data/lib/riak/i18n.rb +7 -7
  40. data/lib/riak/instrumentation.rb +6 -6
  41. data/lib/riak/json.rb +52 -52
  42. data/lib/riak/list_buckets.rb +28 -28
  43. data/lib/riak/locale/en.yml +1 -0
  44. data/lib/riak/locale/fr.yml +51 -51
  45. data/lib/riak/map_reduce/results.rb +49 -49
  46. data/lib/riak/map_reduce_error.rb +7 -7
  47. data/lib/riak/multiget.rb +122 -122
  48. data/lib/riak/robject.rb +17 -1
  49. data/lib/riak/search/result_document.rb +9 -0
  50. data/lib/riak/stamp.rb +77 -77
  51. data/lib/riak/tombstone.rb +13 -0
  52. data/lib/riak/util/tcp_socket_extensions.rb +58 -58
  53. data/lib/riak/version.rb +1 -1
  54. data/spec/failover/failover.rb +59 -59
  55. data/spec/fixtures/bitcask.txt +25 -25
  56. data/spec/fixtures/multipart-basic-conflict.txt +15 -15
  57. data/spec/fixtures/multipart-blank.txt +7 -7
  58. data/spec/fixtures/multipart-mapreduce.txt +10 -10
  59. data/spec/fixtures/multipart-with-body.txt +16 -16
  60. data/spec/fixtures/multipart-with-marked-tombstones.txt +17 -17
  61. data/spec/fixtures/multipart-with-unmarked-tombstone.txt +16 -16
  62. data/spec/fixtures/server.cert.crt +15 -15
  63. data/spec/fixtures/server.cert.key +15 -15
  64. data/spec/fixtures/test.pem +1 -1
  65. data/spec/integration/riak/bucket_types_spec.rb +38 -0
  66. data/spec/integration/riak/crdt/configuration_spec.rb +4 -3
  67. data/spec/integration/riak/crdt_spec.rb +70 -0
  68. data/spec/integration/riak/encodings/crdt_spec.rb +29 -3
  69. data/spec/integration/riak/encodings/yz_spec.rb +2 -1
  70. data/spec/integration/riak/preflist_spec.rb +15 -3
  71. data/spec/integration/riak/protobuffs/timeouts_spec.rb +1 -1
  72. data/spec/integration/riak/security_spec.rb +11 -6
  73. data/spec/integration/riak/threading_spec.rb +154 -150
  74. data/spec/integration/yokozuna/index_spec.rb +61 -61
  75. data/spec/integration/yokozuna/queries_spec.rb +1 -1
  76. data/spec/integration/yokozuna/schema_spec.rb +49 -49
  77. data/spec/riak/beefcake_protobuffs_backend/crdt_operator_spec.rb +22 -0
  78. data/spec/riak/core_ext/to_param_spec.rb +15 -15
  79. data/spec/riak/crdt/hyper_log_log_spec.rb +56 -0
  80. data/spec/riak/crdt/inner_counter_spec.rb +21 -21
  81. data/spec/riak/crdt/inner_set_spec.rb +33 -33
  82. data/spec/riak/crdt/set_spec.rb +61 -61
  83. data/spec/riak/crdt/shared_examples.rb +14 -0
  84. data/spec/riak/escape_spec.rb +72 -72
  85. data/spec/riak/feature_detection_spec.rb +77 -77
  86. data/spec/riak/index_collection_spec.rb +53 -53
  87. data/spec/riak/instrumentation_spec.rb +124 -124
  88. data/spec/riak/link_spec.rb +85 -85
  89. data/spec/riak/list_buckets_spec.rb +41 -41
  90. data/spec/riak/node_spec.rb +26 -26
  91. data/spec/riak/robject_spec.rb +45 -0
  92. data/spec/support/certs/README.md +12 -12
  93. data/spec/support/certs/ca.crt +21 -21
  94. data/spec/support/certs/client.crl +13 -13
  95. data/spec/support/certs/client.crt +94 -94
  96. data/spec/support/certs/client.csr +18 -18
  97. data/spec/support/certs/client.key +27 -27
  98. data/spec/support/certs/empty_ca.crt +21 -21
  99. data/spec/support/certs/server.crl +13 -13
  100. data/spec/support/certs/server.crt +94 -94
  101. data/spec/support/certs/server.key +27 -27
  102. data/spec/support/crdt_search_fixtures.rb +1 -1
  103. data/spec/support/integration_setup.rb +10 -10
  104. data/spec/support/test_client.rb +1 -1
  105. data/spec/support/test_client.yml.example +10 -10
  106. metadata +10 -3
@@ -102,6 +102,7 @@ en:
102
102
  serialize_big_integer: "%{bignum} is out of range for sint64 field"
103
103
  serialize_complex_number: "Cannot serialize Complex numbers"
104
104
  serialize_rational_number: "Cannot serialize Rational numbers without losing precision"
105
+ tombstone_object: "The object is a tombstone (has vclock but no values) and cannot be treated singly or saved: %{robject}"
105
106
  too_few_arguments: "too few arguments: %{params}"
106
107
  walk_spec_invalid_unless_link: "WalkSpec is only valid for a function when the type is :link"
107
108
  wrong_argument_count_walk_spec: "wrong number of arguments (one Hash or bucket,tag,keep required)"
@@ -1,51 +1,51 @@
1
- fr:
2
- riak:
3
- backwards_clock: "L'horloge système a reculé. La génération des ID échouera pour les %{delay} millisecondes à venir."
4
- bucket_link_conversion: "Ne peut convertir un lien de bucket vers un walk spec"
5
- client_type: "argument invalide : %{client} n'est pas un Riak::Client"
6
- conflict_resolver_invalid: "Le résolveur (%{resolver}) n'a pas répondu à :call"
7
- content_type_undefined: "content_type n'est pas défini !"
8
- deprecated:
9
- port: "DEPRECATION: Riak::Client#port ne doit plus être utilisé (deprecated), utilisez #http_port ou #pb_port pour spécifier le protocol.\n%{backtrace}"
10
- search: "DEPRECATION: Les fonctionnalités Riak Search sont désormais inclues dans le client principal. Vous n'avez plus besoin d'inclure 'riak/search'.\n%{backtrace}"
11
- empty_map_reduce_query: "Spécifiez une ou plusieurs requêtes pour MapReduce."
12
- failed_request: "La requête client a échouée."
13
- filter_needs_block: "Le filtre %{filter} nécessite un bloc."
14
- filter_arity_mismatch: "Le filtre %{filter} nécessite %{expected} arguments. Seulement %{received} ont été fournis."
15
- full_bucket_mapred: "Les MapReduce sur un bucket complet, y compris les filtres de clé, invoque 'list-keys' qui est une opération coûteuse et ne doit pas être utilisée en production.\n %{backtrace}"
16
- hash_type: "argument invalide : %{hash} n'est pas un Hash"
17
- http_configuration: "Le moteur HTTP %{backend} ne peut être utilisé. Merci de vérifier ses dépendances et/ou sa configuration."
18
- http_failed_request: "%{expected} attendu depuis Riak mais %{code} reçu. %{body}"
19
- hostname_invalid: "host doit être un nom d'hôte valide"
20
- protocol_invalid: "'%{invalid}' n'est pas un protocole valide. Les valeurs possibles sont %{valid}"
21
- invalid_basic_auth: "L'authentification basique doit être utilisée comme ceci : 'user:pass'"
22
- invalid_client_id: "ID client invalide, doit être une chaîne ou un entier entre 0 et %{max_id}"
23
- invalid_io_object: "Object de type IO invalide assigné à RObject#data. Il devrait plutôt être assigné à raw_data"
24
- invalid_function_value: "Valeur invalide pour la fonction : %{value}"
25
- invalid_options: "Options de configuration invalides."
26
- invalid_phase_type: "type doit être :map, :reduce, ou :link"
27
- invalid_ssl_verify_mode: "%{invalid} n'est pas une option :verify_mode valide pour SSL. Les options valides sont 'peer' and 'none'."
28
- invalid_index_query: "%{value} n'est pas un term de requête valide. Seules les String, Integer et Range de ces types sont autorisés"
29
- indexes_unsupported: "Le serveur Riak ne supporte pas les index secondaires."
30
- loading_bucket: "pendant le chargement du bucket '%{name}'"
31
- list_buckets: "Riak::Client#buckets est une opération coûteuse et ne doit pas être utilisée en production.\n %{backtrace}"
32
- list_keys: "Riak::Bucket#keys est une opération coûteuse et ne doit pas être utilisée en production.\n %{backtrace}"
33
- missing_block: "Un bloc doit être fourni."
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"
35
- module_function_pair_required: "la fonction doit avoir deux élément lorsqu'elle est définie par un tableau"
36
- not_found: "L'objet demandé n'a pas été trouvé."
37
- no_pipes: "Ne peut trouver ou ne peut ouvrir un pipe pour la console Riak dans %{path}."
38
- port_invalid: "le port doit être un entier entre 0 et 65535"
39
- protobuffs_failed_request: "Riak a retourné le code d'erreur %{code} au lieu d'une réponse réussie. %{body}"
40
- request_body_type: "Le corps de la requête doit être une chaine ou répondre à :read."
41
- search_unsupported: "Le serveur Riak ne supporte pas la recherche."
42
- search_docs_require_id: "Search index documents must include the 'id' field."
43
- search_remove_requires_id_or_query: "Les documents d'index de recherche doivent avoir des clés 'id' ou 'query'"
44
- serializer_not_implemented: "Aucun sérialiseur n'a été défini pour le type de contenu %{content_type}"
45
- source_and_root_required: "La configuration de Riak::Node configuration doit inclure les clés :source and :root."
46
- stale_write_prevented: "Le client a empêché une écriture périmée."
47
- stored_function_invalid: "Une fonction définie par un hash doit avoir :bucket et :key"
48
- string_type: "invalid_argument %{string} n'est pas une String"
49
- too_few_arguments: "pas assez d'arguments : %{params}"
50
- walk_spec_invalid_unless_link: "Le WalkSpec n'est valide pour une fonction que lorsque le type est :link"
51
- wrong_argument_count_walk_spec: "nombre d'argument invalide (un Hash ou bucket,tag,keep requis)"
1
+ fr:
2
+ riak:
3
+ backwards_clock: "L'horloge système a reculé. La génération des ID échouera pour les %{delay} millisecondes à venir."
4
+ bucket_link_conversion: "Ne peut convertir un lien de bucket vers un walk spec"
5
+ client_type: "argument invalide : %{client} n'est pas un Riak::Client"
6
+ conflict_resolver_invalid: "Le résolveur (%{resolver}) n'a pas répondu à :call"
7
+ content_type_undefined: "content_type n'est pas défini !"
8
+ deprecated:
9
+ port: "DEPRECATION: Riak::Client#port ne doit plus être utilisé (deprecated), utilisez #http_port ou #pb_port pour spécifier le protocol.\n%{backtrace}"
10
+ search: "DEPRECATION: Les fonctionnalités Riak Search sont désormais inclues dans le client principal. Vous n'avez plus besoin d'inclure 'riak/search'.\n%{backtrace}"
11
+ empty_map_reduce_query: "Spécifiez une ou plusieurs requêtes pour MapReduce."
12
+ failed_request: "La requête client a échouée."
13
+ filter_needs_block: "Le filtre %{filter} nécessite un bloc."
14
+ filter_arity_mismatch: "Le filtre %{filter} nécessite %{expected} arguments. Seulement %{received} ont été fournis."
15
+ full_bucket_mapred: "Les MapReduce sur un bucket complet, y compris les filtres de clé, invoque 'list-keys' qui est une opération coûteuse et ne doit pas être utilisée en production.\n %{backtrace}"
16
+ hash_type: "argument invalide : %{hash} n'est pas un Hash"
17
+ http_configuration: "Le moteur HTTP %{backend} ne peut être utilisé. Merci de vérifier ses dépendances et/ou sa configuration."
18
+ http_failed_request: "%{expected} attendu depuis Riak mais %{code} reçu. %{body}"
19
+ hostname_invalid: "host doit être un nom d'hôte valide"
20
+ protocol_invalid: "'%{invalid}' n'est pas un protocole valide. Les valeurs possibles sont %{valid}"
21
+ invalid_basic_auth: "L'authentification basique doit être utilisée comme ceci : 'user:pass'"
22
+ invalid_client_id: "ID client invalide, doit être une chaîne ou un entier entre 0 et %{max_id}"
23
+ invalid_io_object: "Object de type IO invalide assigné à RObject#data. Il devrait plutôt être assigné à raw_data"
24
+ invalid_function_value: "Valeur invalide pour la fonction : %{value}"
25
+ invalid_options: "Options de configuration invalides."
26
+ invalid_phase_type: "type doit être :map, :reduce, ou :link"
27
+ invalid_ssl_verify_mode: "%{invalid} n'est pas une option :verify_mode valide pour SSL. Les options valides sont 'peer' and 'none'."
28
+ invalid_index_query: "%{value} n'est pas un term de requête valide. Seules les String, Integer et Range de ces types sont autorisés"
29
+ indexes_unsupported: "Le serveur Riak ne supporte pas les index secondaires."
30
+ loading_bucket: "pendant le chargement du bucket '%{name}'"
31
+ list_buckets: "Riak::Client#buckets est une opération coûteuse et ne doit pas être utilisée en production.\n %{backtrace}"
32
+ list_keys: "Riak::Bucket#keys est une opération coûteuse et ne doit pas être utilisée en production.\n %{backtrace}"
33
+ missing_block: "Un bloc doit être fourni."
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"
35
+ module_function_pair_required: "la fonction doit avoir deux élément lorsqu'elle est définie par un tableau"
36
+ not_found: "L'objet demandé n'a pas été trouvé."
37
+ no_pipes: "Ne peut trouver ou ne peut ouvrir un pipe pour la console Riak dans %{path}."
38
+ port_invalid: "le port doit être un entier entre 0 et 65535"
39
+ protobuffs_failed_request: "Riak a retourné le code d'erreur %{code} au lieu d'une réponse réussie. %{body}"
40
+ request_body_type: "Le corps de la requête doit être une chaine ou répondre à :read."
41
+ search_unsupported: "Le serveur Riak ne supporte pas la recherche."
42
+ search_docs_require_id: "Search index documents must include the 'id' field."
43
+ search_remove_requires_id_or_query: "Les documents d'index de recherche doivent avoir des clés 'id' ou 'query'"
44
+ serializer_not_implemented: "Aucun sérialiseur n'a été défini pour le type de contenu %{content_type}"
45
+ source_and_root_required: "La configuration de Riak::Node configuration doit inclure les clés :source and :root."
46
+ stale_write_prevented: "Le client a empêché une écriture périmée."
47
+ stored_function_invalid: "Une fonction définie par un hash doit avoir :bucket et :key"
48
+ string_type: "invalid_argument %{string} n'est pas une String"
49
+ too_few_arguments: "pas assez d'arguments : %{params}"
50
+ walk_spec_invalid_unless_link: "Le WalkSpec n'est valide pour une fonction que lorsque le type est :link"
51
+ wrong_argument_count_walk_spec: "nombre d'argument invalide (un Hash ou bucket,tag,keep requis)"
@@ -1,49 +1,49 @@
1
- module Riak
2
- class MapReduce
3
- # @api private
4
- # Collects and normalizes results from MapReduce requests
5
- class Results
6
- # Creates a new result collector
7
- # @param [MapReduce] mr the MapReduce query
8
- def initialize(mr)
9
- @keep_count = mr.query.select {|p| p.keep }.size
10
- @hash = create_results_hash(mr.query)
11
- end
12
-
13
- # Adds a new result to the collector
14
- # @param [Fixnum] phase the phase index
15
- # @param [Array] result the phase result
16
- def add(phase, result)
17
- @hash[phase] += result
18
- end
19
-
20
- # Coalesces the query results
21
- # @return [Array] the query results, coalesced according to the
22
- # phase configuration
23
- def report
24
- if @keep_count > 1
25
- @hash.to_a.sort.map {|(num, results)| results }
26
- else
27
- @hash[@hash.keys.first]
28
- end
29
- end
30
-
31
- private
32
- def create_results_hash(query)
33
- # When the query is empty, only bucket/key pairs are returned,
34
- # but implicitly in phase 0.
35
- return { 0 => [] } if query.empty?
36
-
37
- # Pre-populate the hash with empty results for kept phases.
38
- # Additionally, the last phase is always implictly kept, even
39
- # when keep is false.
40
- query.inject({}) do |hash, phase|
41
- if phase.keep || query[-1] == phase
42
- hash[query.index(phase)] = []
43
- end
44
- hash
45
- end
46
- end
47
- end
48
- end
49
- end
1
+ module Riak
2
+ class MapReduce
3
+ # @api private
4
+ # Collects and normalizes results from MapReduce requests
5
+ class Results
6
+ # Creates a new result collector
7
+ # @param [MapReduce] mr the MapReduce query
8
+ def initialize(mr)
9
+ @keep_count = mr.query.select {|p| p.keep }.size
10
+ @hash = create_results_hash(mr.query)
11
+ end
12
+
13
+ # Adds a new result to the collector
14
+ # @param [Fixnum] phase the phase index
15
+ # @param [Array] result the phase result
16
+ def add(phase, result)
17
+ @hash[phase] += result
18
+ end
19
+
20
+ # Coalesces the query results
21
+ # @return [Array] the query results, coalesced according to the
22
+ # phase configuration
23
+ def report
24
+ if @keep_count > 1
25
+ @hash.to_a.sort.map {|(num, results)| results }
26
+ else
27
+ @hash[@hash.keys.first]
28
+ end
29
+ end
30
+
31
+ private
32
+ def create_results_hash(query)
33
+ # When the query is empty, only bucket/key pairs are returned,
34
+ # but implicitly in phase 0.
35
+ return { 0 => [] } if query.empty?
36
+
37
+ # Pre-populate the hash with empty results for kept phases.
38
+ # Additionally, the last phase is always implictly kept, even
39
+ # when keep is false.
40
+ query.inject({}) do |hash, phase|
41
+ if phase.keep || query[-1] == phase
42
+ hash[query.index(phase)] = []
43
+ end
44
+ hash
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -1,7 +1,7 @@
1
- require 'riak/util/translation'
2
-
3
- module Riak
4
- # Raised when an error occurred in the Javascript map-reduce chain.
5
- # The message will be the body of the JSON error response.
6
- class MapReduceError < StandardError; end
7
- end
1
+ require 'riak/util/translation'
2
+
3
+ module Riak
4
+ # Raised when an error occurred in the Javascript map-reduce chain.
5
+ # The message will be the body of the JSON error response.
6
+ class MapReduceError < StandardError; end
7
+ end
@@ -1,122 +1,122 @@
1
- require 'riak/client'
2
- require 'riak/bucket'
3
-
4
- module Riak
5
- # Coordinates a parallel fetch operation for multiple values.
6
- class Multiget
7
- include Util::Translation
8
-
9
- # @return [Riak::Client] the associated client
10
- attr_reader :client
11
-
12
- # @return [Array<Bucket, String>] fetch_list an {Array} of {Bucket} and {String} keys to fetch
13
- attr_reader :fetch_list
14
-
15
- # @return [Hash<fetch_list_entry, RObject] result_hash a {Hash} of {Bucket} and {String} key pairs to {RObject} instances
16
- attr_accessor :result_hash
17
-
18
- # @return [Boolean] finished if the fetch operation has completed
19
- attr_reader :finished
20
-
21
- # @return [Integer] The number of threads to use
22
- attr_accessor :thread_count
23
-
24
- # Perform a Riak Multiget operation.
25
- # @param [Client] client the {Riak::Client} that will perform the multiget
26
- # @param [Array<Bucket, String>] fetch_list an {Array} of {Bucket} and {String} keys to fetch
27
- # @return [Hash<fetch_list_entry, RObject] result_hash a {Hash} of {Bucket} and {String} key pairs to {RObject} instances
28
- def self.get_all(client, fetch_list)
29
- multi = new client, fetch_list
30
- multi.fetch
31
- multi.results
32
- end
33
-
34
- # Create a Riak Multiget operation.
35
- # @param [Client] client the {Riak::Client} that will perform the multiget
36
- # @param [Array<Bucket, String>] fetch_list an {Array} of {Bucket} and {String} keys to fetch
37
- def initialize(client, fetch_list)
38
- raise ArgumentError, t('client_type', :client => client.inspect) unless client.is_a? Riak::Client
39
- raise ArgumentError, t('array_type', :array => fetch_list.inspect) unless fetch_list.is_a? Array
40
-
41
- validate_fetch_list fetch_list
42
- @client, @fetch_list = client, fetch_list.uniq
43
- self.result_hash = Hash.new
44
- @finished = false
45
- self.thread_count = client.multiget_threads
46
- end
47
-
48
- # Starts the parallelized fetch operation
49
- # @raise [ArgumentError] when a non-positive-Integer count is given
50
- def fetch
51
- queue = fetch_list.dup
52
- queue_mutex = Mutex.new
53
- result_mutex = Mutex.new
54
-
55
- unless thread_count.is_a?(Integer) && thread_count > 0
56
- raise ArgumentError, t("invalid_multiget_thread_count")
57
- end
58
-
59
- @threads = 1.upto(thread_count).map do |_node|
60
- Thread.new do
61
- loop do
62
- pair = queue_mutex.synchronize do
63
- queue.shift
64
- end
65
-
66
- break if pair.nil?
67
-
68
- found = attempt_fetch(*pair)
69
- result_mutex.synchronize do
70
- result_hash[pair] = found
71
- end
72
- end
73
- end
74
- end
75
- end
76
-
77
- def results
78
- wait_for_finish
79
- result_hash
80
- end
81
-
82
- def finished?
83
- set_finished_for_thread_liveness
84
- finished
85
- end
86
-
87
- def wait_for_finish
88
- return if finished?
89
- @threads.each {|t| t.join }
90
- @finished = true
91
- end
92
-
93
- private
94
-
95
- def attempt_fetch(bucket, key)
96
- bucket[key]
97
- rescue Riak::FailedRequest => e
98
- raise e unless e.not_found?
99
- nil
100
- end
101
-
102
- def set_finished_for_thread_liveness
103
- return if @finished # already done
104
-
105
- all_dead = @threads.none? {|t| t.alive? }
106
- return unless all_dead # still working
107
-
108
- @finished = true
109
- return
110
- end
111
-
112
- def validate_fetch_list(fetch_list)
113
- return unless erroneous = fetch_list.detect do |e|
114
- bucket, key = e
115
- next true unless bucket.is_a? Bucket
116
- next true unless key.is_a? String
117
- end
118
-
119
- raise ArgumentError, t('fetch_list_type', :problem => erroneous)
120
- end
121
- end
122
- end
1
+ require 'riak/client'
2
+ require 'riak/bucket'
3
+
4
+ module Riak
5
+ # Coordinates a parallel fetch operation for multiple values.
6
+ class Multiget
7
+ include Util::Translation
8
+
9
+ # @return [Riak::Client] the associated client
10
+ attr_reader :client
11
+
12
+ # @return [Array<Bucket, String>] fetch_list an {Array} of {Bucket} and {String} keys to fetch
13
+ attr_reader :fetch_list
14
+
15
+ # @return [Hash<fetch_list_entry, RObject] result_hash a {Hash} of {Bucket} and {String} key pairs to {RObject} instances
16
+ attr_accessor :result_hash
17
+
18
+ # @return [Boolean] finished if the fetch operation has completed
19
+ attr_reader :finished
20
+
21
+ # @return [Integer] The number of threads to use
22
+ attr_accessor :thread_count
23
+
24
+ # Perform a Riak Multiget operation.
25
+ # @param [Client] client the {Riak::Client} that will perform the multiget
26
+ # @param [Array<Bucket, String>] fetch_list an {Array} of {Bucket} and {String} keys to fetch
27
+ # @return [Hash<fetch_list_entry, RObject] result_hash a {Hash} of {Bucket} and {String} key pairs to {RObject} instances
28
+ def self.get_all(client, fetch_list)
29
+ multi = new client, fetch_list
30
+ multi.fetch
31
+ multi.results
32
+ end
33
+
34
+ # Create a Riak Multiget operation.
35
+ # @param [Client] client the {Riak::Client} that will perform the multiget
36
+ # @param [Array<Bucket, String>] fetch_list an {Array} of {Bucket} and {String} keys to fetch
37
+ def initialize(client, fetch_list)
38
+ raise ArgumentError, t('client_type', :client => client.inspect) unless client.is_a? Riak::Client
39
+ raise ArgumentError, t('array_type', :array => fetch_list.inspect) unless fetch_list.is_a? Array
40
+
41
+ validate_fetch_list fetch_list
42
+ @client, @fetch_list = client, fetch_list.uniq
43
+ self.result_hash = Hash.new
44
+ @finished = false
45
+ self.thread_count = client.multiget_threads
46
+ end
47
+
48
+ # Starts the parallelized fetch operation
49
+ # @raise [ArgumentError] when a non-positive-Integer count is given
50
+ def fetch
51
+ queue = fetch_list.dup
52
+ queue_mutex = Mutex.new
53
+ result_mutex = Mutex.new
54
+
55
+ unless thread_count.is_a?(Integer) && thread_count > 0
56
+ raise ArgumentError, t("invalid_multiget_thread_count")
57
+ end
58
+
59
+ @threads = 1.upto(thread_count).map do |_node|
60
+ Thread.new do
61
+ loop do
62
+ pair = queue_mutex.synchronize do
63
+ queue.shift
64
+ end
65
+
66
+ break if pair.nil?
67
+
68
+ found = attempt_fetch(*pair)
69
+ result_mutex.synchronize do
70
+ result_hash[pair] = found
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ def results
78
+ wait_for_finish
79
+ result_hash
80
+ end
81
+
82
+ def finished?
83
+ set_finished_for_thread_liveness
84
+ finished
85
+ end
86
+
87
+ def wait_for_finish
88
+ return if finished?
89
+ @threads.each {|t| t.join }
90
+ @finished = true
91
+ end
92
+
93
+ private
94
+
95
+ def attempt_fetch(bucket, key)
96
+ bucket[key]
97
+ rescue Riak::FailedRequest => e
98
+ raise e unless e.not_found?
99
+ nil
100
+ end
101
+
102
+ def set_finished_for_thread_liveness
103
+ return if @finished # already done
104
+
105
+ all_dead = @threads.none? {|t| t.alive? }
106
+ return unless all_dead # still working
107
+
108
+ @finished = true
109
+ return
110
+ end
111
+
112
+ def validate_fetch_list(fetch_list)
113
+ return unless erroneous = fetch_list.detect do |e|
114
+ bucket, key = e
115
+ next true unless bucket.is_a? Bucket
116
+ next true unless key.is_a? String
117
+ end
118
+
119
+ raise ArgumentError, t('fetch_list_type', :problem => erroneous)
120
+ end
121
+ end
122
+ end