aerospike 0.1.3 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ee7d4805db6b56945a1f5112c62272f3371c79f8
4
+ data.tar.gz: ab922b1acac8a4aa5b09d5605886127c12af60cf
5
+ SHA512:
6
+ metadata.gz: 6879a1edd54bcdb9ad82e5cc3f484cbe5f56034eed1058c9aeb556b2d7b1ca93f663f2260a7d1818b311d5ab65f11a5ab2b8fbae1b85bbaaf277fc5c01234df0
7
+ data.tar.gz: 911f4c56dfe6e1d6eb801e560f87732db0309dd5e80bec9969bd5f1af17f0ec3ecfdb249ea865178b619afa6eccbaaa956bc199eba2b9b2bce7d3bdafffe22a9
data/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ ## Dec 8 2014 (0.1.5)
2
+
3
+ Major features added, minor fixes and improvements.
4
+
5
+ * **New Features**:
6
+
7
+ * Added `Client.scan_node`, `Client.scan_all`
8
+ * Added `Client.query`
9
+
10
+ * **Fixes**
11
+
12
+ * Fixed getting back results only for specified bin names.
13
+
1
14
  ## Oct 27 2014 (0.1.3)
2
15
 
3
16
  Minor fix.
data/README.md CHANGED
@@ -28,15 +28,15 @@ include Aerospike
28
28
 
29
29
  client = Client.new("127.0.0.1", 3000)
30
30
 
31
- key = Key.new('test', 'set name', 'key value')
32
- bins = {
31
+ key = Key.new('test', 'test', 'key value')
32
+ bin_map = {
33
33
  'bin1' => 'value1',
34
34
  'bin2' => 2,
35
35
  'bin4' => ['value4', {'map1' => 'map val'}],
36
36
  'bin5' => {'value5' => [124, "string value"]},
37
37
  }
38
38
 
39
- client.put(key, bins)
39
+ client.put(key, bin_map)
40
40
  record = client.get(key)
41
41
  record.bins['bin1'] = 'other value'
42
42
 
@@ -83,6 +83,13 @@ Supported operating systems:
83
83
  5. Build and Install the gem locally: ```rake build && rake install```
84
84
  6. Run the benchmark: ```./tools/benchmark/benchmark.rb -u```
85
85
 
86
+ <a name="Performance"></a>
87
+ ## Performance Tweaking
88
+
89
+ We are bending all efforts to improve the client's performance. In out reference benchmarks, Go client performs almost as good as the C client.
90
+
91
+ To read about performance variables, please refer to [`docs/performance.md`](docs/performance.md)
92
+
86
93
  <a name="Tests"></a>
87
94
  ## Tests
88
95
 
@@ -100,13 +107,13 @@ A variety of example applications are provided in the [`examples`](examples) dir
100
107
  See the [`examples/README.md`](examples/README.md) for details.
101
108
 
102
109
  <a name="Tools"></a>
103
- ## Tools
110
+ ### Tools
104
111
 
105
112
  A variety of clones of original tools are provided in the [`tools`](tools) directory.
106
113
  They show how to use more advanced features of the library to reimplement the same functionality in a more concise way.
107
114
 
108
115
  <a name="Benchmarks"></a>
109
- #### Benchmarks
116
+ ## Benchmarks
110
117
 
111
118
  Benchmark utility is provided in the [`tools/benchmark`](tools/benchmark) directory.
112
119
  See the [`tools/benchmark/README.md`](tools/benchmark/README.md) for details.
data/lib/aerospike.rb CHANGED
@@ -5,7 +5,8 @@ require "monitor"
5
5
  require "timeout"
6
6
  require 'resolv'
7
7
  require 'msgpack'
8
- require 'atomic'
8
+
9
+ require 'aerospike/atomic/atomic'
9
10
 
10
11
  require 'aerospike/client'
11
12
  require 'aerospike/utils/pool'
@@ -36,12 +37,16 @@ require 'aerospike/command/read_command'
36
37
  require 'aerospike/command/delete_command'
37
38
  require 'aerospike/key'
38
39
  require 'aerospike/operation'
40
+
39
41
  require 'aerospike/policy/client_policy'
40
42
  require 'aerospike/policy/priority'
41
43
  require 'aerospike/policy/record_exists_action'
42
44
  require 'aerospike/policy/generation_policy'
43
45
  require 'aerospike/policy/policy'
44
46
  require 'aerospike/policy/write_policy'
47
+ require 'aerospike/policy/scan_policy'
48
+ require 'aerospike/policy/query_policy'
49
+
45
50
  require 'aerospike/cluster/connection'
46
51
  require 'aerospike/cluster/cluster'
47
52
  require 'aerospike/cluster/node_validator'
@@ -64,6 +69,12 @@ require 'aerospike/task/udf_register_task'
64
69
  require 'aerospike/task/task'
65
70
  require 'aerospike/language'
66
71
 
72
+ require 'aerospike/query/recordset'
73
+ require 'aerospike/query/filter'
74
+ require 'aerospike/query/stream_command'
75
+ require 'aerospike/query/query_command'
76
+ require 'aerospike/query/scan_command'
77
+
67
78
  module Aerospike
68
79
  extend Loggable
69
80
  end
@@ -0,0 +1,51 @@
1
+ # encoding: utf-8
2
+ # Copyright 2014 Aerospike, Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http:#www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ module Aerospike
17
+
18
+ # Container object for client policy command.
19
+ class Atomic
20
+
21
+ def initialize(value)
22
+ @value = value
23
+
24
+ @mutex = Mutex.new
25
+ end
26
+
27
+ def update(&block)
28
+ @mutex.synchronize do
29
+ @value = block.call(@value)
30
+ end
31
+ end
32
+
33
+ def get
34
+ ret = nil
35
+ @mutex.synchronize do
36
+ ret = @value
37
+ end
38
+ ret
39
+ end
40
+ alias_method :value, :get
41
+
42
+ def set(value)
43
+ @mutex.synchronize do
44
+ @value = value
45
+ end
46
+ end
47
+ alias_method 'value='.to_sym, :set
48
+
49
+ end # class
50
+
51
+ end # module
@@ -41,6 +41,8 @@ module Aerospike
41
41
  def initialize(host, port, options={})
42
42
  @default_policy = Policy.new
43
43
  @default_write_policy = WritePolicy.new
44
+ @default_scan_policy = ScanPolicy.new
45
+ @default_query_policy = QueryPolicy.new
44
46
 
45
47
  policy = opt_to_client_policy(options)
46
48
 
@@ -402,13 +404,14 @@ module Aerospike
402
404
  str_cmd << "content-len=#{content.length};udf-type=#{language};"
403
405
  # Send UDF to one node. That node will distribute the UDF to other nodes.
404
406
  response_map = @cluster.request_info(@default_policy, str_cmd)
405
- response, _ = response_map.first
406
407
 
407
408
  res = {}
408
- vals = response.split(';')
409
- vals.each do |pair|
410
- k, v = pair.split("=", 2)
411
- res[k] = v
409
+ response_map.each do |k, response|
410
+ vals = response.to_s.split(';')
411
+ vals.each do |pair|
412
+ k, v = pair.split("=", 2)
413
+ res[k] = v
414
+ end
412
415
  end
413
416
 
414
417
  if res['error']
@@ -500,7 +503,7 @@ module Aerospike
500
503
  raise Aerospike::Exceptions::Aerospike.new(UDF_BAD_RESPONSE, "#{obj}")
501
504
  end
502
505
 
503
- raise Aerospike::Exception::Aerospike.new(UDF_BAD_RESPONSE, "Invalid UDF return value")
506
+ raise Aerospike::Exceptions::Aerospike.new(UDF_BAD_RESPONSE, "Invalid UDF return value")
504
507
  end
505
508
 
506
509
  # Create secondary index.
@@ -560,6 +563,141 @@ module Aerospike
560
563
  @cluster.request_info(@default_policy, *commands)
561
564
  end
562
565
 
566
+ #-------------------------------------------------------
567
+ # Scan Operations
568
+ #-------------------------------------------------------
569
+
570
+ def scan_all(namespace, set_name, bin_names=[], options={})
571
+ policy = opt_to_scan_policy(options)
572
+
573
+ # wait until all migrations are finished
574
+ # TODO: implement
575
+ # @cluster.WaitUntillMigrationIsFinished(policy.timeout)
576
+
577
+ # Retry policy must be one-shot for scans.
578
+ # copy on write for policy
579
+ new_policy = policy.clone
580
+
581
+ nodes = @cluster.nodes
582
+ if nodes.length == 0
583
+ raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_NOT_AVAILABLE, "Scan failed because cluster is empty.")
584
+ end
585
+
586
+ recordset = Recordset.new(policy.record_queue_size, nodes.length, :scan)
587
+
588
+ if policy.concurrent_nodes
589
+ # Use a thread per node
590
+ nodes.each do |node|
591
+ Thread.new do
592
+ abort_on_exception = true
593
+ command = ScanCommand.new(node, new_policy, namespace, set_name, bin_names, recordset)
594
+ begin
595
+ command.execute
596
+ rescue => e
597
+ Aerospike.logger.error(e) unless e == Rescordset::SCAN_TERMINATED_EXCEPTION
598
+ recordset.cancel(e)
599
+ ensure
600
+ recordset.thread_finished
601
+ end
602
+ end
603
+ end
604
+ else
605
+ Thread.new do
606
+ abort_on_exception = true
607
+ nodes.each do |node|
608
+ command = ScanCommand.new(node, new_policy, namespace, set_name, bin_names, recordset)
609
+ begin
610
+ command.execute
611
+ rescue => e
612
+ Aerospike.logger.error(e) unless e == Rescordset::SCAN_TERMINATED_EXCEPTION
613
+ recordset.cancel(e)
614
+ ensure
615
+ recordset.thread_finished
616
+ end
617
+ end
618
+ end
619
+ end
620
+
621
+ recordset
622
+ end
623
+
624
+ # ScanNode reads all records in specified namespace and set, from one node only.
625
+ # The policy can be used to specify timeouts.
626
+ def scan_node(node, namespace, set_name, bin_names=[], options={})
627
+ policy = opt_to_scan_policy(options)
628
+ # wait until all migrations are finished
629
+ # TODO: implement
630
+ # @cluster.WaitUntillMigrationIsFinished(policy.timeout)
631
+
632
+ # Retry policy must be one-shot for scans.
633
+ # copy on write for policy
634
+ new_policy = policy.clone
635
+ new_policy.max_retries = 0
636
+
637
+ node = @cluster.get_node_by_name(node) if !node.is_a?(Aerospike::Node)
638
+
639
+ recordset = Recordset.new(policy.record_queue_size, 1, :scan)
640
+
641
+ Thread.new do
642
+ abort_on_exception = true
643
+ command = ScanCommand.new(node, new_policy, namespace, set_name, bin_names, recordset)
644
+ begin
645
+ command.execute
646
+ rescue => e
647
+ Aerospike.logger.error(e) unless e == Rescordset::SCAN_TERMINATED_EXCEPTION
648
+ recordset.cancel(e)
649
+ ensure
650
+ recordset.thread_finished
651
+ end
652
+ end
653
+
654
+ recordset
655
+ end
656
+
657
+ #--------------------------------------------------------
658
+ # Query functions (Supported by Aerospike 3 servers only)
659
+ #--------------------------------------------------------
660
+
661
+ # Query executes a query and returns a recordset.
662
+ # The query executor puts records on a channel from separate goroutines.
663
+ # The caller can concurrently pops records off the channel through the
664
+ # record channel.
665
+ #
666
+ # This method is only supported by Aerospike 3 servers.
667
+ # If the policy is nil, a default policy will be generated.
668
+ def query(statement, options={})
669
+ policy = opt_to_query_policy(options)
670
+ new_policy = policy.clone
671
+
672
+ # Always set a taskId
673
+ statement.task_id = Time.now.to_i if statement.task_id == 0
674
+
675
+ nodes = @cluster.nodes
676
+ if nodes.length == 0
677
+ raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_NOT_AVAILABLE, "Scan failed because cluster is empty.")
678
+ end
679
+
680
+ recordset = Recordset.new(policy.record_queue_size, nodes.length, :query)
681
+
682
+ # Use a thread per node
683
+ nodes.each do |node|
684
+ Thread.new do
685
+ abort_on_exception = true
686
+ command = QueryCommand.new(node, new_policy, statement, recordset)
687
+ begin
688
+ command.execute
689
+ rescue => e
690
+ Aerospike.logger.error(e) unless e == Rescordset::QUERY_TERMINATED_EXCEPTION
691
+ recordset.cancel(e)
692
+ ensure
693
+ recordset.thread_finished
694
+ end
695
+ end
696
+ end
697
+
698
+ recordset
699
+ end
700
+
563
701
  private
564
702
 
565
703
  def send_info_command(policy, command)
@@ -580,7 +718,7 @@ module Aerospike
580
718
  end
581
719
 
582
720
  def opt_to_client_policy(options)
583
- if options == {} || options.nil?
721
+ if options.nil? || options == {}
584
722
  ClientPolicy.new
585
723
  elsif options.is_a?(ClientPolicy)
586
724
  options
@@ -594,7 +732,7 @@ module Aerospike
594
732
  end
595
733
 
596
734
  def opt_to_policy(options)
597
- if options == {} || options.nil?
735
+ if options.nil? || options == {}
598
736
  @default_policy
599
737
  elsif options.is_a?(Policy)
600
738
  options
@@ -609,7 +747,7 @@ module Aerospike
609
747
  end
610
748
 
611
749
  def opt_to_write_policy(options)
612
- if options == {} || options.nil?
750
+ if options.nil? || options == {}
613
751
  @default_write_policy
614
752
  elsif options.is_a?(WritePolicy)
615
753
  options
@@ -624,6 +762,31 @@ module Aerospike
624
762
  end
625
763
  end
626
764
 
765
+ def opt_to_scan_policy(options)
766
+ if options.nil? || options == {}
767
+ @default_scan_policy
768
+ elsif options.is_a?(ScanPolicy)
769
+ options
770
+ elsif options.is_a?(Hash)
771
+ ScanPolicy.new(
772
+ options[:scan_percent],
773
+ options[:concurrent_nodes],
774
+ options[:include_bin_data],
775
+ options[:fail_on_cluster_change]
776
+ )
777
+ end
778
+ end
779
+
780
+ def opt_to_query_policy(options)
781
+ if options.nil? || options == {}
782
+ @default_query_policy
783
+ elsif options.is_a?(QueryPolicy)
784
+ options
785
+ elsif options.is_a?(Hash)
786
+ QueryPolicy.new()
787
+ end
788
+ end
789
+
627
790
  def batch_execute(keys, &cmd_gen)
628
791
  batch_nodes = BatchNode.generate_list(@cluster, keys)
629
792
  threads = []
@@ -17,7 +17,7 @@
17
17
  require 'thread'
18
18
  require 'timeout'
19
19
 
20
- require 'atomic'
20
+ require 'aerospike/atomic/atomic'
21
21
 
22
22
  module Aerospike
23
23
 
@@ -210,7 +210,7 @@ module Aerospike
210
210
  refresh_count += 1
211
211
  friend_list.concat(friends) if friends
212
212
  rescue => e
213
- Aerospike.logger.warn("Node `#{node}` refresh failed: #{e.to_s}")
213
+ Aerospike.logger.error("Node `#{node}` refresh failed: #{e.to_s}")
214
214
  end
215
215
  end
216
216
  end
@@ -285,7 +285,7 @@ module Aerospike
285
285
  begin
286
286
  seed_node_validator = NodeValidator.new(seed, @connection_timeout)
287
287
  rescue => e
288
- Aerospike.logger.warn("Seed #{seed.to_s} failed: #{e}")
288
+ Aerospike.logger.error("Seed #{seed.to_s} failed: #{e}")
289
289
  next
290
290
  end
291
291
 
@@ -299,7 +299,7 @@ module Aerospike
299
299
  begin
300
300
  nv = NodeValidator.new(aliass, @connection_timeout)
301
301
  rescue Exection => e
302
- Aerospike.logger.warn("Seed #{seed.to_s} failed: #{e}")
302
+ Aerospike.logger.error("Seed #{seed.to_s} failed: #{e}")
303
303
  next
304
304
  end
305
305
  end
@@ -368,7 +368,7 @@ module Aerospike
368
368
  list << node
369
369
 
370
370
  rescue => e
371
- Aerospike.logger.warn("Add node #{node.to_s} failed: #{e}")
371
+ Aerospike.logger.error("Add node #{node.to_s} failed: #{e}")
372
372
  end
373
373
  end
374
374
 
@@ -398,7 +398,7 @@ module Aerospike
398
398
 
399
399
  when 2
400
400
  # Two node clusters require at least one successful refresh before removing.
401
- if refresh_count == 1 && node.reference_count.value == 0 && !node.responded.value
401
+ if refresh_count == 2 && node.reference_count.value == 0 && !node.responded.value
402
402
  # Node is not referenced nor did it respond.
403
403
  remove_list << node
404
404
  end