cassandra-mavericks 0.21.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +15 -0
  2. data/CHANGELOG +150 -0
  3. data/Gemfile +7 -0
  4. data/LICENSE +202 -0
  5. data/Manifest +94 -0
  6. data/README.md +373 -0
  7. data/Rakefile +191 -0
  8. data/bin/cassandra_helper +16 -0
  9. data/cassandra.gemspec +29 -0
  10. data/conf/0.6/cassandra.in.sh +47 -0
  11. data/conf/0.6/log4j.properties +38 -0
  12. data/conf/0.6/schema.json +57 -0
  13. data/conf/0.6/storage-conf.xml +352 -0
  14. data/conf/0.7/cassandra.in.sh +46 -0
  15. data/conf/0.7/cassandra.yaml +336 -0
  16. data/conf/0.7/log4j-server.properties +41 -0
  17. data/conf/0.7/schema.json +57 -0
  18. data/conf/0.7/schema.txt +45 -0
  19. data/conf/0.8/cassandra.in.sh +41 -0
  20. data/conf/0.8/cassandra.yaml +61 -0
  21. data/conf/0.8/log4j-server.properties +40 -0
  22. data/conf/0.8/schema.json +72 -0
  23. data/conf/0.8/schema.txt +57 -0
  24. data/conf/1.0/cassandra.in.sh +41 -0
  25. data/conf/1.0/cassandra.yaml +415 -0
  26. data/conf/1.0/log4j-server.properties +40 -0
  27. data/conf/1.0/schema.json +72 -0
  28. data/conf/1.0/schema.txt +57 -0
  29. data/conf/1.1/cassandra.in.sh +41 -0
  30. data/conf/1.1/cassandra.yaml +567 -0
  31. data/conf/1.1/log4j-server.properties +44 -0
  32. data/conf/1.1/schema.json +72 -0
  33. data/conf/1.1/schema.txt +57 -0
  34. data/conf/1.2/cassandra.in.sh +41 -0
  35. data/conf/1.2/cassandra.yaml +643 -0
  36. data/conf/1.2/log4j-server.properties +44 -0
  37. data/conf/1.2/schema.json +72 -0
  38. data/conf/1.2/schema.txt +57 -0
  39. data/ext/cassandra_native.c +69 -0
  40. data/ext/extconf.rb +9 -0
  41. data/lib/cassandra.rb +47 -0
  42. data/lib/cassandra/0.6.rb +7 -0
  43. data/lib/cassandra/0.6/cassandra.rb +113 -0
  44. data/lib/cassandra/0.6/columns.rb +78 -0
  45. data/lib/cassandra/0.6/protocol.rb +91 -0
  46. data/lib/cassandra/0.7.rb +7 -0
  47. data/lib/cassandra/0.7/cassandra.rb +2 -0
  48. data/lib/cassandra/0.7/columns.rb +4 -0
  49. data/lib/cassandra/0.7/protocol.rb +5 -0
  50. data/lib/cassandra/0.8.rb +7 -0
  51. data/lib/cassandra/0.8/cassandra.rb +25 -0
  52. data/lib/cassandra/0.8/columns.rb +28 -0
  53. data/lib/cassandra/0.8/protocol.rb +10 -0
  54. data/lib/cassandra/1.0.rb +7 -0
  55. data/lib/cassandra/1.0/cassandra.rb +1 -0
  56. data/lib/cassandra/1.0/columns.rb +1 -0
  57. data/lib/cassandra/1.0/protocol.rb +1 -0
  58. data/lib/cassandra/1.1.rb +7 -0
  59. data/lib/cassandra/1.1/cassandra.rb +1 -0
  60. data/lib/cassandra/1.1/columns.rb +1 -0
  61. data/lib/cassandra/1.1/protocol.rb +1 -0
  62. data/lib/cassandra/1.2.rb +7 -0
  63. data/lib/cassandra/1.2/cassandra.rb +1 -0
  64. data/lib/cassandra/1.2/columns.rb +1 -0
  65. data/lib/cassandra/1.2/protocol.rb +1 -0
  66. data/lib/cassandra/array.rb +8 -0
  67. data/lib/cassandra/batch.rb +41 -0
  68. data/lib/cassandra/cassandra.rb +1091 -0
  69. data/lib/cassandra/column_family.rb +3 -0
  70. data/lib/cassandra/columns.rb +172 -0
  71. data/lib/cassandra/comparable.rb +28 -0
  72. data/lib/cassandra/composite.rb +137 -0
  73. data/lib/cassandra/constants.rb +11 -0
  74. data/lib/cassandra/debug.rb +9 -0
  75. data/lib/cassandra/dynamic_composite.rb +118 -0
  76. data/lib/cassandra/helpers.rb +41 -0
  77. data/lib/cassandra/keyspace.rb +3 -0
  78. data/lib/cassandra/long.rb +58 -0
  79. data/lib/cassandra/mock.rb +536 -0
  80. data/lib/cassandra/ordered_hash.rb +195 -0
  81. data/lib/cassandra/protocol.rb +137 -0
  82. data/lib/cassandra/time.rb +11 -0
  83. data/test/cassandra_client_test.rb +20 -0
  84. data/test/cassandra_mock_test.rb +128 -0
  85. data/test/cassandra_test.rb +1367 -0
  86. data/test/comparable_types_test.rb +45 -0
  87. data/test/composite_type_test.rb +86 -0
  88. data/test/eventmachine_test.rb +42 -0
  89. data/test/ordered_hash_test.rb +386 -0
  90. data/test/test_helper.rb +19 -0
  91. data/vendor/0.6/gen-rb/cassandra.rb +1481 -0
  92. data/vendor/0.6/gen-rb/cassandra_constants.rb +12 -0
  93. data/vendor/0.6/gen-rb/cassandra_types.rb +482 -0
  94. data/vendor/0.7/gen-rb/cassandra.rb +1936 -0
  95. data/vendor/0.7/gen-rb/cassandra_constants.rb +12 -0
  96. data/vendor/0.7/gen-rb/cassandra_types.rb +681 -0
  97. data/vendor/0.8/gen-rb/cassandra.rb +2215 -0
  98. data/vendor/0.8/gen-rb/cassandra_constants.rb +12 -0
  99. data/vendor/0.8/gen-rb/cassandra_types.rb +824 -0
  100. data/vendor/1.0/gen-rb/cassandra.rb +2215 -0
  101. data/vendor/1.0/gen-rb/cassandra_constants.rb +12 -0
  102. data/vendor/1.0/gen-rb/cassandra_types.rb +857 -0
  103. data/vendor/1.1/gen-rb/cassandra.rb +2571 -0
  104. data/vendor/1.1/gen-rb/cassandra_constants.rb +12 -0
  105. data/vendor/1.1/gen-rb/cassandra_types.rb +928 -0
  106. data/vendor/1.2/gen-rb/cassandra.rb +3013 -0
  107. data/vendor/1.2/gen-rb/cassandra_constants.rb +13 -0
  108. data/vendor/1.2/gen-rb/cassandra_types.rb +965 -0
  109. metadata +288 -0
@@ -0,0 +1,44 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The ASF licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ # for production, you should probably set pattern to %c instead of %l.
18
+ # (%l is slower.)
19
+
20
+ # output messages into a rolling log file as well as stdout
21
+ log4j.rootLogger=INFO,stdout,R
22
+
23
+ # stdout
24
+ log4j.appender.stdout=org.apache.log4j.ConsoleAppender
25
+ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
26
+ log4j.appender.stdout.layout.ConversionPattern=%5p %d{HH:mm:ss,SSS} %m%n
27
+
28
+ # rolling log file
29
+ log4j.appender.R=org.apache.log4j.RollingFileAppender
30
+ log4j.appender.R.maxFileSize=20MB
31
+ log4j.appender.R.maxBackupIndex=50
32
+ log4j.appender.R.layout=org.apache.log4j.PatternLayout
33
+ log4j.appender.R.layout.ConversionPattern=%5p [%t] %d{ISO8601} %F (line %L) %m%n
34
+ # Edit the next line to point to your logs directory
35
+ log4j.appender.R.File=/var/log/cassandra/system.log
36
+
37
+ # Application logging options
38
+ #log4j.logger.org.apache.cassandra=DEBUG
39
+ #log4j.logger.org.apache.cassandra.db=DEBUG
40
+ #log4j.logger.org.apache.cassandra.service.StorageProxy=DEBUG
41
+
42
+ # Adding this to avoid thrift logging disconnect errors.
43
+ log4j.logger.org.apache.thrift.server.TNonblockingServer=ERROR
44
+
@@ -0,0 +1,72 @@
1
+ {"Twitter":{
2
+ "Users":{
3
+ "comparator_type":"org.apache.cassandra.db.marshal.UTF8Type",
4
+ "column_type":"Standard"},
5
+ "UserAudits":{
6
+ "comparator_type":"org.apache.cassandra.db.marshal.UTF8Type",
7
+ "column_type":"Standard"},
8
+ "UserCounters":{
9
+ "comparator_type":"org.apache.cassandra.db.marshal.UTF8Type",
10
+ "column_type":"Standard",
11
+ "default_validation_class":"CounterColumnType"},
12
+ "UserCounterAggregates":{
13
+ "subcomparator_type":"org.apache.cassandra.db.marshal.UTF8Type",
14
+ "comparator_type":"org.apache.cassandra.db.marshal.UTF8Type",
15
+ "column_type":"Super",
16
+ "default_validation_class":"CounterColumnType"},
17
+ "UserRelationships":{
18
+ "subcomparator_type":"org.apache.cassandra.db.marshal.TimeUUIDType",
19
+ "comparator_type":"org.apache.cassandra.db.marshal.UTF8Type",
20
+ "column_type":"Super"},
21
+ "Usernames":{
22
+ "comparator_type":"org.apache.cassandra.db.marshal.UTF8Type",
23
+ "column_type":"Standard"},
24
+ "Statuses":{
25
+ "comparator_type":"org.apache.cassandra.db.marshal.UTF8Type",
26
+ "column_type":"Standard"},
27
+ "StatusAudits":{
28
+ "comparator_type":"org.apache.cassandra.db.marshal.UTF8Type",
29
+ "column_type":"Standard"},
30
+ "StatusRelationships":{
31
+ "subcomparator_type":"org.apache.cassandra.db.marshal.TimeUUIDType",
32
+ "comparator_type":"org.apache.cassandra.db.marshal.UTF8Type",
33
+ "column_type":"Super"},
34
+ "Indexes":{
35
+ "comparator_type":"org.apache.cassandra.db.marshal.UTF8Type",
36
+ "column_type":"Super"},
37
+ "TimelinishThings":{
38
+ "comparator_type":"org.apache.cassandra.db.marshal.BytesType",
39
+ "column_type":"Standard"}
40
+ },
41
+ "Multiblog":{
42
+ "Blogs":{
43
+ "comparator_type":"org.apache.cassandra.db.marshal.TimeUUIDType",
44
+ "column_type":"Standard"},
45
+ "Comments":{
46
+ "comparator_type":"org.apache.cassandra.db.marshal.TimeUUIDType",
47
+ "column_type":"Standard"}
48
+ },
49
+ "MultiblogLong":{
50
+ "Blogs":{
51
+ "comparator_type":"org.apache.cassandra.db.marshal.LongType",
52
+ "column_type":"Standard"},
53
+ "Comments":{
54
+ "comparator_type":"org.apache.cassandra.db.marshal.LongType",
55
+ "column_type":"Standard"}
56
+ },
57
+ "TypeConversions":{
58
+ "UUIDColumnConversion":{
59
+ "comparator_type":"org.apache.cassandra.db.marshal.TimeUUIDType",
60
+ "column_type":"Standard"},
61
+ "SuperUUID":{
62
+ "subcomparator_type":"org.apache.cassandra.db.marshal.TimeUUIDType",
63
+ "comparator_type":"org.apache.cassandra.db.marshal.TimeUUIDType",
64
+ "column_type":"Super"},
65
+ "CompositeColumnConversion":{
66
+ "comparator_type":"org.apache.cassandra.db.marshal.CompositeType(org.apache.cassandra.db.marshal.IntegerType,org.apache.cassandra.db.marshal.UTF8Type)",
67
+ "column_type":"Standard"},
68
+ "DynamicComposite":{
69
+ "comparator_type":"org.apache.cassandra.db.marshal.DynamicCompositeType(u=>org.apache.cassandra.db.marshal.UUIDType,t=>org.apache.cassandra.db.marshal.TimeUUIDType,s=>org.apache.cassandra.db.marshal.UTF8Type,b=>org.apache.cassandra.db.marshal.BytesType,a=>org.apache.cassandra.db.marshal.AsciiType,l=>org.apache.cassandra.db.marshal.LongType,x=>org.apache.cassandra.db.marshal.LexicalUUIDType,i=>org.apache.cassandra.db.marshal.IntegerType)",
70
+ "column_type":"Standard"}
71
+ }
72
+ }
@@ -0,0 +1,57 @@
1
+ create keyspace Twitter with
2
+ placement_strategy = 'org.apache.cassandra.locator.SimpleStrategy' AND
3
+ strategy_options = {replication_factor:1};
4
+ use Twitter;
5
+ create column family Users with comparator = 'UTF8Type';
6
+ create column family UserAudits with comparator = 'UTF8Type';
7
+ create column family UserCounters with comparator = 'UTF8Type' and
8
+ default_validation_class = CounterColumnType;
9
+ create column family UserCounterAggregates with column_type = 'Super'
10
+ and comparator = 'UTF8Type' and
11
+ subcomparator = 'UTF8Type' and
12
+ default_validation_class = CounterColumnType;
13
+ create column family UserRelationships with
14
+ comparator = 'UTF8Type' and
15
+ column_type = 'Super' and
16
+ subcomparator = 'TimeUUIDType';
17
+ create column family Usernames with comparator = 'UTF8Type';
18
+ create column family Statuses
19
+ with comparator = 'UTF8Type'
20
+ and column_metadata = [
21
+ {column_name: 'tags', validation_class: 'BytesType', index_type: 'KEYS'}
22
+ ];
23
+ create column family StatusAudits with comparator = 'UTF8Type';
24
+ create column family StatusRelationships with
25
+ comparator = 'UTF8Type' and
26
+ column_type = 'Super' and
27
+ subcomparator = 'TimeUUIDType';
28
+ create column family Indexes with
29
+ comparator = 'UTF8Type' and
30
+ column_type = 'Super';
31
+ create column family TimelinishThings with
32
+ comparator = 'BytesType';
33
+
34
+ create keyspace Multiblog with
35
+ placement_strategy = 'org.apache.cassandra.locator.SimpleStrategy' AND
36
+ strategy_options = {replication_factor:1};
37
+ use Multiblog;
38
+ create column family Blogs with comparator = 'TimeUUIDType';
39
+ create column family Comments with comparator = 'TimeUUIDType';
40
+
41
+
42
+ create keyspace MultiblogLong with
43
+ placement_strategy = 'org.apache.cassandra.locator.SimpleStrategy' AND
44
+ strategy_options = {replication_factor:1};
45
+ use MultiblogLong;
46
+ create column family Blogs with comparator = 'LongType';
47
+ create column family Comments with comparator = 'LongType';
48
+
49
+ create keyspace TypeConversions with
50
+ placement_strategy = 'org.apache.cassandra.locator.SimpleStrategy' AND
51
+ strategy_options = {replication_factor:1};
52
+ use TypeConversions;
53
+ create column family UUIDColumnConversion with comparator = TimeUUIDType;
54
+ create column family SuperUUID with comparator = TimeUUIDType and column_type = Super;
55
+ create column family CompositeColumnConversion with comparator = 'CompositeType(IntegerType, UTF8Type)';
56
+ create column family DynamicComposite with comparator ='DynamicCompositeType
57
+ (a=>AsciiType,b=>BytesType,i=>IntegerType,x=>LexicalUUIDType,l=>LongType,t=>TimeUUIDType,s=>UTF8Type,u=>UUIDType)';
@@ -0,0 +1,69 @@
1
+ #include <ruby.h>
2
+ #include <arpa/inet.h>
3
+
4
+ VALUE parts_ivar_id, types_ivar_id, hash_ivar_id;
5
+
6
+ VALUE rb_cassandra_composite_fast_unpack(VALUE self, VALUE packed_string_value) {
7
+ int index = 0;
8
+ int message_length = RSTRING_LEN(packed_string_value);
9
+ char *packed_string = (char *)RSTRING_PTR(packed_string_value);
10
+
11
+ VALUE parts = rb_ary_new();
12
+ while (index < message_length) {
13
+ uint16_t length = ntohs(((uint16_t *)(packed_string+index))[0]);
14
+ VALUE part = rb_str_new(packed_string+index+2, length);
15
+ rb_ary_push(parts, part);
16
+ index += length + 3;
17
+ }
18
+
19
+ rb_ivar_set(self, parts_ivar_id, parts);
20
+ rb_ivar_set(self, hash_ivar_id, rb_funcall(packed_string_value, rb_intern("hash"), 0));
21
+
22
+ return Qnil;
23
+ }
24
+
25
+ VALUE rb_cassandra_dynamic_composite_fast_unpack(VALUE self, VALUE packed_string_value) {
26
+ int index = 0;
27
+ int message_length = RSTRING_LEN(packed_string_value);
28
+ char *packed_string = (char *)RSTRING_PTR(packed_string_value);
29
+ uint16_t length;
30
+
31
+ VALUE parts = rb_ary_new();
32
+ VALUE types = rb_ary_new();
33
+ while (index < message_length) {
34
+ if (packed_string[index] & 0x80) {
35
+ VALUE type = rb_str_new(packed_string + index + 1, 1);
36
+ rb_ary_push(types, type);
37
+ index += 2;
38
+ } else {
39
+ length = ntohs(((uint16_t *)(packed_string+index))[0]);
40
+ VALUE type = rb_str_new(packed_string + index + 2, length);
41
+ rb_ary_push(types, type);
42
+ index += 2 + length;
43
+ }
44
+
45
+ length = ntohs(((uint16_t *)(packed_string+index))[0]);
46
+ VALUE part = rb_str_new(packed_string + index + 2, length);
47
+ rb_ary_push(parts, part);
48
+ index += length + 3;
49
+ }
50
+
51
+ rb_ivar_set(self, parts_ivar_id, parts);
52
+ rb_ivar_set(self, types_ivar_id, types);
53
+ rb_ivar_set(self, hash_ivar_id, rb_funcall(packed_string_value, rb_intern("hash"), 0));
54
+
55
+ return Qnil;
56
+ }
57
+
58
+ void Init_cassandra_native(void) {
59
+ VALUE cassandra_module = rb_const_get(rb_cObject, rb_intern("Cassandra"));
60
+ VALUE cassandra_composite_class = rb_define_class_under(cassandra_module, "Composite", rb_cObject);
61
+ rb_define_method(cassandra_composite_class, "fast_unpack", rb_cassandra_composite_fast_unpack, 1);
62
+
63
+ VALUE dynamic_composite = rb_const_get(cassandra_module, rb_intern("DynamicComposite"));
64
+ rb_define_method(dynamic_composite, "fast_unpack", rb_cassandra_dynamic_composite_fast_unpack, 1);
65
+
66
+ parts_ivar_id = rb_intern("@parts");
67
+ types_ivar_id = rb_intern("@types");
68
+ hash_ivar_id = rb_intern("@hash");
69
+ }
@@ -0,0 +1,9 @@
1
+ if (defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/) or ENV['OS'] == "Windows_NT"
2
+ File.open('Makefile', 'w'){|f| f.puts "all:\n\ninstall:\n" }
3
+ else
4
+ require 'mkmf'
5
+
6
+ $CFLAGS = "-g -O2 -Wall -Werror"
7
+
8
+ create_makefile 'cassandra_native'
9
+ end
@@ -0,0 +1,47 @@
1
+ require 'rubygems'
2
+ gem 'thrift_client-mavericks', '~> 0.7'
3
+ require 'thrift_client'
4
+ gem 'simple_uuid' , '~> 0.2.0'
5
+ require 'simple_uuid'
6
+
7
+ require 'json' unless defined?(JSON)
8
+
9
+ here = File.expand_path(File.dirname(__FILE__))
10
+
11
+ class Cassandra ; end
12
+ unless Cassandra.respond_to?(:VERSION)
13
+ require "#{here}/cassandra/0.8"
14
+ end
15
+
16
+ $LOAD_PATH << "#{here}/../vendor/#{Cassandra.VERSION}/gen-rb"
17
+ require "#{here}/../vendor/#{Cassandra.VERSION}/gen-rb/cassandra"
18
+
19
+ $LOAD_PATH << "#{here}"
20
+
21
+ require 'cassandra/helpers'
22
+ require 'cassandra/array'
23
+ require 'cassandra/time'
24
+ require 'cassandra/comparable'
25
+ require 'cassandra/long'
26
+ require 'cassandra/composite'
27
+ require 'cassandra/dynamic_composite'
28
+ require 'cassandra/ordered_hash'
29
+ require 'cassandra/columns'
30
+ require 'cassandra/protocol'
31
+ require 'cassandra/batch'
32
+ require "cassandra/#{Cassandra.VERSION}/columns"
33
+ require "cassandra/#{Cassandra.VERSION}/protocol"
34
+ require "cassandra/cassandra"
35
+ require "cassandra/#{Cassandra.VERSION}/cassandra"
36
+ unless Cassandra.VERSION.eql?("0.6")
37
+ require "cassandra/column_family"
38
+ require "cassandra/keyspace"
39
+ end
40
+ require 'cassandra/constants'
41
+ require 'cassandra/debug' if ENV['DEBUG']
42
+
43
+ begin
44
+ require "cassandra_native"
45
+ rescue LoadError
46
+ puts "Unable to load cassandra_native extension. Defaulting to pure Ruby libraries."
47
+ end
@@ -0,0 +1,7 @@
1
+ class Cassandra
2
+ def self.VERSION
3
+ "0.6"
4
+ end
5
+ end
6
+
7
+ require "#{File.expand_path(File.dirname(__FILE__))}/../cassandra"
@@ -0,0 +1,113 @@
1
+ class Cassandra
2
+ def self.DEFAULT_TRANSPORT_WRAPPER
3
+ Thrift::BufferedTransport
4
+ end
5
+
6
+ ##
7
+ # Issues a login attempt using the username and password specified.
8
+ #
9
+ # * username
10
+ # * password
11
+ #
12
+ def login!(username, password)
13
+ @auth_request = CassandraThrift::AuthenticationRequest.new
14
+ @auth_request.credentials = {'username' => username, 'password' => password}
15
+ client.login(@keyspace, @auth_request)
16
+ end
17
+
18
+ def inspect
19
+ "#<Cassandra:#{object_id}, @keyspace=#{keyspace.inspect}, @schema={#{
20
+ schema(false).map {|name, hash| ":#{name} => #{hash['type'].inspect}"}.join(', ')
21
+ }}, @servers=#{servers.inspect}>"
22
+ end
23
+
24
+ ##
25
+ # Returns an array of available keyspaces.
26
+ #
27
+ def keyspaces
28
+ @keyspaces ||= client.describe_keyspaces()
29
+ end
30
+
31
+ ##
32
+ # Remove all rows in the column family you request.
33
+ #
34
+ # * column_family
35
+ # * options
36
+ # * consitency
37
+ # * timestamp
38
+ #
39
+ def clear_column_family!(column_family, options = {})
40
+ each_key(column_family) do |key|
41
+ remove(column_family, key, options)
42
+ end
43
+ end
44
+ alias truncate! clear_column_family!
45
+
46
+ # Remove all rows in the keyspace. Supports options <tt>:consistency</tt> and
47
+ # <tt>:timestamp</tt>.
48
+ # FIXME May not currently delete all records without multiple calls. Waiting
49
+ # for ranged remove support in Cassandra.
50
+ def clear_keyspace!(options = {})
51
+ schema.keys.each { |column_family| clear_column_family!(column_family, options) }
52
+ end
53
+
54
+ # Open a batch operation and yield self. Inserts and deletes will be queued
55
+ # until the block closes, and then sent atomically to the server. Supports
56
+ # the <tt>:consistency</tt> option, which overrides the consistency set in
57
+ # the individual commands.
58
+ def batch(options = {})
59
+ _, _, _, options =
60
+ extract_and_validate_params(schema.keys.first, "", [options], WRITE_DEFAULTS)
61
+
62
+ @batch = []
63
+ yield(self)
64
+ compacted_map,seen_clevels = compact_mutations!
65
+ clevel = if options[:consistency] != nil # Override any clevel from individual mutations if
66
+ options[:consistency]
67
+ elsif seen_clevels.length > 1 # Cannot choose which CLevel to use if there are several ones
68
+ raise "Multiple consistency levels used in the batch, and no override...cannot pick one"
69
+ else # if no consistency override has been provided but all the clevels in the batch are the same: use that one
70
+ seen_clevels.first
71
+ end
72
+
73
+ _mutate(compacted_map,clevel)
74
+ ensure
75
+ @batch = nil
76
+ end
77
+
78
+ protected
79
+
80
+ def schema(load=true)
81
+ if !load && !@schema
82
+ []
83
+ else
84
+ @schema ||= client.describe_keyspace(@keyspace)
85
+ end
86
+ end
87
+
88
+ def client
89
+ reconnect! if @client.nil?
90
+ @client
91
+ end
92
+
93
+ def reconnect!
94
+ @servers = all_nodes
95
+ @client = new_client
96
+ end
97
+
98
+ def all_nodes
99
+ if @auto_discover_nodes
100
+ temp_client = new_client
101
+ begin
102
+ ips = ::JSON.parse(temp_client.get_string_property('token map')).values
103
+ port = @servers.first.split(':').last
104
+ ips.map{|ip| "#{ip}:#{port}" }
105
+ ensure
106
+ temp_client.disconnect!
107
+ end
108
+ else
109
+ @servers
110
+ end
111
+ end
112
+
113
+ end
@@ -0,0 +1,78 @@
1
+ class Cassandra
2
+ # A bunch of crap, mostly related to introspecting on column types
3
+ module Columns #:nodoc:
4
+ private
5
+
6
+ def is_super(column_family)
7
+ @is_super[column_family] ||= column_family_property(column_family, 'Type') == "Super"
8
+ end
9
+
10
+ def column_name_class(column_family)
11
+ @column_name_class[column_family] ||= column_name_class_for_key(column_family, "CompareWith")
12
+ end
13
+
14
+ def sub_column_name_class(column_family)
15
+ @sub_column_name_class[column_family] ||= column_name_class_for_key(column_family, "CompareSubcolumnsWith")
16
+ end
17
+
18
+ def column_family_property(column_family, key)
19
+ unless schema[column_family]
20
+ raise AccessError, "Invalid column family \"#{column_family}\""
21
+ end
22
+ schema[column_family][key]
23
+ end
24
+
25
+ def _standard_insert_mutation(column_family, column_name, value, timestamp, _=nil)
26
+ CassandraThrift::Mutation.new(
27
+ :column_or_supercolumn => CassandraThrift::ColumnOrSuperColumn.new(
28
+ :column => CassandraThrift::Column.new(
29
+ :name => column_name_class(column_family).new(column_name).to_s,
30
+ :value => value,
31
+ :timestamp => timestamp
32
+ )
33
+ )
34
+ )
35
+ end
36
+
37
+ def _super_insert_mutation(column_family, super_column_name, sub_columns, timestamp, _=nil)
38
+ CassandraThrift::Mutation.new(:column_or_supercolumn =>
39
+ CassandraThrift::ColumnOrSuperColumn.new(
40
+ :super_column => CassandraThrift::SuperColumn.new(
41
+ :name => column_name_class(column_family).new(super_column_name).to_s,
42
+ :columns => sub_columns.collect { |sub_column_name, sub_column_value|
43
+ CassandraThrift::Column.new(
44
+ :name => sub_column_name_class(column_family).new(sub_column_name).to_s,
45
+ :value => sub_column_value.to_s,
46
+ :timestamp => timestamp
47
+ )
48
+ }
49
+ )
50
+ )
51
+ )
52
+ end
53
+
54
+ # General info about a deletion object within a mutation
55
+ # timestamp - required. If this is the only param, it will cause deletion of the whole key at that TS
56
+ # supercolumn - opt. If passed, the deletes will only occur within that supercolumn (only subcolumns
57
+ # will be deleted). Otherwise the normal columns will be deleted.
58
+ # predicate - opt. Defines how to match the columns to delete. if supercolumn passed, the slice will
59
+ # be scoped to subcolumns of that supercolumn.
60
+
61
+ # Deletes a single column from the containing key/CF (and possibly supercolumn), at a given timestamp.
62
+ # Although mutations (as opposed to 'remove' calls) support deleting slices and lists of columns in one shot, this is not implemented here.
63
+ # The main reason being that the batch function takes removes, but removes don't have that capability...so we'd need to change the remove
64
+ # methods to use delete mutation calls...although that might have performance implications. We'll leave that refactoring for later.
65
+ def _delete_mutation(cf, column, subcolumn, timestamp, options={})
66
+ deletion_hash = {:timestamp => timestamp}
67
+ if is_super(cf)
68
+ deletion_hash[:super_column] = column if column
69
+ deletion_hash[:predicate] = CassandraThrift::SlicePredicate.new(:column_names => [subcolumn]) if subcolumn
70
+ else
71
+ deletion_hash[:predicate] = CassandraThrift::SlicePredicate.new(:column_names => [column]) if column
72
+ end
73
+ CassandraThrift::Mutation.new(
74
+ :deletion => CassandraThrift::Deletion.new(deletion_hash)
75
+ )
76
+ end
77
+ end
78
+ end