aerospike 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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