cassilds-model 0.0.2
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.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.rdoc +57 -0
- data/Rakefile +9 -0
- data/cassandra-model.gemspec +27 -0
- data/lib/cassandra-model/base.rb +183 -0
- data/lib/cassandra-model/batches.rb +89 -0
- data/lib/cassandra-model/callbacks.rb +49 -0
- data/lib/cassandra-model/config.rb +66 -0
- data/lib/cassandra-model/connection.rb +21 -0
- data/lib/cassandra-model/persistence.rb +280 -0
- data/lib/cassandra-model/railtie.rb +15 -0
- data/lib/cassandra-model/types.rb +61 -0
- data/lib/cassandra-model/version.rb +3 -0
- data/lib/cassandra-model.rb +30 -0
- data/test/base_test.rb +45 -0
- data/test/callbacks_test.rb +43 -0
- data/test/cassandra_model_test.rb +84 -0
- data/test/config/cassandra.in.sh +47 -0
- data/test/config/log4j-tools.properties +27 -0
- data/test/config/log4j.properties +40 -0
- data/test/config/storage-conf.xml +368 -0
- data/test/test_helper.rb +10 -0
- metadata +108 -0
@@ -0,0 +1,280 @@
|
|
1
|
+
require 'active_support/core_ext/hash/keys'
|
2
|
+
require 'active_support/core_ext/array/extract_options'
|
3
|
+
module CassandraModel
|
4
|
+
module Persistence
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
7
|
+
base.send :include, InstanceMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
module InstanceMethods
|
11
|
+
def save
|
12
|
+
raise ActiveRecord::ReadOnlyRecord if readonly?
|
13
|
+
return self unless valid?
|
14
|
+
run_callbacks :before_save
|
15
|
+
newrec = new_record?
|
16
|
+
callback = newrec ? :before_create : :before_update
|
17
|
+
run_callbacks callback
|
18
|
+
write(attributes)
|
19
|
+
callback = newrec ? :after_create : :after_update
|
20
|
+
run_callbacks callback
|
21
|
+
run_callbacks :after_save
|
22
|
+
end
|
23
|
+
|
24
|
+
def destroy
|
25
|
+
run_callbacks :before_destroy
|
26
|
+
self.class.send(:remove, key)
|
27
|
+
self.deleted!
|
28
|
+
run_callbacks :after_destroy
|
29
|
+
end
|
30
|
+
|
31
|
+
def reload
|
32
|
+
self.class.get(key)
|
33
|
+
end
|
34
|
+
|
35
|
+
def update_attributes(attrs)
|
36
|
+
self.attributes = attrs
|
37
|
+
save
|
38
|
+
end
|
39
|
+
|
40
|
+
def remove_attributes(attrs)
|
41
|
+
attrs.each {|attr| self.class.remove_column(key, attr) }
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def write(attrs)
|
47
|
+
self.class.send(:write, key, attrs)
|
48
|
+
@new_record = false
|
49
|
+
self
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
module ClassMethods
|
54
|
+
attr_writer :write_consistency_level, :read_consistency_level
|
55
|
+
|
56
|
+
def create(attributes)
|
57
|
+
new(attributes).tap do |object|
|
58
|
+
object.save
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def write_consistency_level(level)
|
63
|
+
@write_consistency_level = level
|
64
|
+
end
|
65
|
+
|
66
|
+
def read_consistency_level(level)
|
67
|
+
@read_consistency_level = level
|
68
|
+
end
|
69
|
+
|
70
|
+
def get(key, options = {})
|
71
|
+
find_one(key, options)
|
72
|
+
end
|
73
|
+
|
74
|
+
def [](key)
|
75
|
+
record = get(key)
|
76
|
+
raise RecordNotFound, "cannot find out key=`#{key}` in `#{column_family}`" unless record
|
77
|
+
record
|
78
|
+
end
|
79
|
+
|
80
|
+
def exists?(key)
|
81
|
+
return false if key.nil? || key == ''
|
82
|
+
#connection.exists?(column_family, key)
|
83
|
+
key = validate_key_type(key)
|
84
|
+
!connection.get(column_family, key).empty?
|
85
|
+
end
|
86
|
+
|
87
|
+
def all(*args)
|
88
|
+
find(:all, *args)
|
89
|
+
end
|
90
|
+
|
91
|
+
def first(*args)
|
92
|
+
find(:first, *args)
|
93
|
+
end
|
94
|
+
|
95
|
+
def last(*args)
|
96
|
+
find(:last, *args)
|
97
|
+
end
|
98
|
+
|
99
|
+
def find(*args)
|
100
|
+
options = args.extract_options!
|
101
|
+
validate_find_options(options)
|
102
|
+
# set_readonly_option!(options) Not Implemented Yet
|
103
|
+
|
104
|
+
case args.first
|
105
|
+
when :first then find_initial(options)
|
106
|
+
when :last then find_last(options)
|
107
|
+
when :all then find_every(options)
|
108
|
+
else find_from_ids(args, options)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def write(key, attributes)
|
115
|
+
benchmark("CassandraModel[#{self.name}].write, key: #{key.to_s}") do
|
116
|
+
connection.insert(column_family, key, attrs2write(attributes),
|
117
|
+
:consistency => @write_consistency_level || Cassandra::Consistency::QUORUM)
|
118
|
+
end
|
119
|
+
key
|
120
|
+
end
|
121
|
+
|
122
|
+
def attrs2write attrs
|
123
|
+
res = {}
|
124
|
+
attrs.each do |key, item|
|
125
|
+
res[key] = item.kind_of?(Integer) ? Cassandra::Long.new(item).to_s : item
|
126
|
+
end
|
127
|
+
return res
|
128
|
+
end
|
129
|
+
|
130
|
+
def remove(key)
|
131
|
+
key = validate_key_type(key)
|
132
|
+
benchmark("CassandraModel[#{self.name}].remove, key: #{key.to_s}") do
|
133
|
+
connection.remove(column_family, key,
|
134
|
+
:consistency => @write_consistency_level || Cassandra::Consistency::QUORUM)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def remove_column(key, column)
|
139
|
+
key = validate_key_type(key)
|
140
|
+
benchmark("CassandraModel[#{self.name}].remove_column, key: #{key.to_s}, #{column.to_s}") do
|
141
|
+
connection.remove(column_family, key, column,
|
142
|
+
:consistency => @write_consistency_level || Cassandra::Consistency::QUORUM)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def init_model(key, attrs)
|
147
|
+
return new(attrs, false).tap do |object|
|
148
|
+
object.key = key
|
149
|
+
object.new_record = false
|
150
|
+
object.deleted! if attrs.empty?
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def find_one(key, options)
|
155
|
+
key = validate_key_type(key)
|
156
|
+
raise RecordNotFound, "Couldn't find #{name} without an ID" if key.blank?
|
157
|
+
options = options || {}
|
158
|
+
readonly = options.delete(:readonly)
|
159
|
+
|
160
|
+
model = nil
|
161
|
+
benchmark("CassandraModel[#{self.name}].find_one, key: #{key.to_s}") do
|
162
|
+
attrs = connection.get_columns(column_family, key, columns.stringify_keys.keys, options)
|
163
|
+
unless attrs.empty?
|
164
|
+
model = init_model(key, attrs)
|
165
|
+
model.readonly! if readonly
|
166
|
+
end
|
167
|
+
end
|
168
|
+
return model
|
169
|
+
end
|
170
|
+
|
171
|
+
def find_initial(options)
|
172
|
+
options = options || {}
|
173
|
+
options.update(:limit => 1)
|
174
|
+
return find_every(options).first
|
175
|
+
end
|
176
|
+
|
177
|
+
def find_last(options)
|
178
|
+
options = options || {}
|
179
|
+
# in practice this does NOT work (Thrift API limitation)
|
180
|
+
options.update({:limit => 1, :order => :desc, :reversed => true})
|
181
|
+
return find_every(options).first
|
182
|
+
end
|
183
|
+
|
184
|
+
def find_every(options)
|
185
|
+
options = options || {}
|
186
|
+
nofilter = options.delete(:no_filter)
|
187
|
+
readonly = options.delete(:readonly)
|
188
|
+
keyrange = options[:keyrange]
|
189
|
+
keyrange = ''..'' if keyrange.blank?
|
190
|
+
|
191
|
+
records = []
|
192
|
+
benchmark("CassandraModel[#{self.name}].find_every, keyrange: #{keyrange.to_s}") do
|
193
|
+
results = connection.get_range_columns(column_family, columns.stringify_keys.keys,
|
194
|
+
:start => keyrange.first, :finish => keyrange.last, :count => (options[:limit] || 100))
|
195
|
+
|
196
|
+
(results || {}).each { |key, columns|
|
197
|
+
model = init_model(key, columns)
|
198
|
+
model.readonly! if readonly
|
199
|
+
records.push(model) unless nofilter && model.deleted?
|
200
|
+
}
|
201
|
+
end
|
202
|
+
return records
|
203
|
+
end
|
204
|
+
|
205
|
+
def find_from_ids(ids, options)
|
206
|
+
if ids.first.kind_of?(Range)
|
207
|
+
find_range(ids.first, options)
|
208
|
+
else
|
209
|
+
expects_array = ids.first.kind_of?(Array)
|
210
|
+
return ids.first if expects_array && ids.first.empty?
|
211
|
+
|
212
|
+
ids = ids.flatten.compact.uniq
|
213
|
+
|
214
|
+
case ids.size
|
215
|
+
when 0
|
216
|
+
raise RecordNotFound, "Couldn't find #{name} without an ID"
|
217
|
+
when 1
|
218
|
+
result = find_one(ids.first, options)
|
219
|
+
expects_array ? [ result ] : result
|
220
|
+
else
|
221
|
+
find_some(ids, options)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def find_range(ids, options)
|
227
|
+
options = options || {}
|
228
|
+
options.update({:keyrange => ids})
|
229
|
+
find_every(options)
|
230
|
+
end
|
231
|
+
|
232
|
+
def find_some(ids, options)
|
233
|
+
options = options || {}
|
234
|
+
result = find_every(options)
|
235
|
+
|
236
|
+
# Determine expected size from limit and offset, not just ids.size.
|
237
|
+
expected_size =
|
238
|
+
if options[:limit] && ids.size > options[:limit]
|
239
|
+
options[:limit]
|
240
|
+
else
|
241
|
+
ids.size
|
242
|
+
end
|
243
|
+
|
244
|
+
# 11 ids with limit 3, offset 9 should give 2 results.
|
245
|
+
if options[:offset] && (ids.size - options[:offset] < expected_size)
|
246
|
+
expected_size = ids.size - options[:offset]
|
247
|
+
end
|
248
|
+
|
249
|
+
if result.size == expected_size
|
250
|
+
result
|
251
|
+
else
|
252
|
+
raise RecordNotFound, "Couldn't find all #{name.pluralize} with IDs (#{ids.inspect}) (found #{result.size} results, but was looking for #{expected_size})"
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
VALID_FIND_OPTIONS = [ :select, :keyrange, :conditions, :limit, :offset,
|
257
|
+
:order, :readonly ]
|
258
|
+
|
259
|
+
def validate_find_options(options) #:nodoc:
|
260
|
+
options.assert_valid_keys(VALID_FIND_OPTIONS)
|
261
|
+
end
|
262
|
+
|
263
|
+
def validate_key_type(key)
|
264
|
+
if !self.key_type.blank? and self.key_type.downcase == 'time_uuid'
|
265
|
+
key = SimpleUUID::UUID.new(key)
|
266
|
+
end
|
267
|
+
return key.to_s
|
268
|
+
end
|
269
|
+
|
270
|
+
# def first(keyrange = ''..'', options = {})
|
271
|
+
# all(keyrange, options.merge(:limit => 1)).first
|
272
|
+
# end
|
273
|
+
|
274
|
+
# def last(keyrange = ''..'', options = {})
|
275
|
+
# all(keyrange, options.merge({:reversed => true, :limit => 1})).first
|
276
|
+
# end
|
277
|
+
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'cassandra-model/config'
|
2
|
+
module CassandraModel
|
3
|
+
if defined? Rails::Railtie
|
4
|
+
require 'rails'
|
5
|
+
class Railtie < Rails::Railtie
|
6
|
+
initializer 'cassandra-model.config_init' do
|
7
|
+
CassandraModel::Config.initialize
|
8
|
+
end
|
9
|
+
rake_tasks do
|
10
|
+
load "tasks/paperclip.rake"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module CassandraModel
|
2
|
+
class StringType
|
3
|
+
def self.dump(v)
|
4
|
+
v && v
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.load(v)
|
8
|
+
v && v.to_s
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class IntegerType
|
13
|
+
def self.dump(v)
|
14
|
+
v && v.to_i
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.load(v)
|
18
|
+
v && Cassandra::Long.new(v).to_i
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class FloatType
|
23
|
+
def self.dump(v)
|
24
|
+
v && v.to_s
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.load(v)
|
28
|
+
v && v.to_f
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class DatetimeType
|
33
|
+
def self.dump(v)
|
34
|
+
!v.blank? && v.strftime('%FT%T%z')
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.load(v)
|
38
|
+
!v.blank? && ::DateTime.strptime(v, '%FT%T%z')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class JsonType
|
43
|
+
def self.dump(v)
|
44
|
+
v && ::JSON.dump(v)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.load(v)
|
48
|
+
v && ::JSON.load(v)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class BooleanType
|
53
|
+
def self.dump(v)
|
54
|
+
v == '1'
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.load(v)
|
58
|
+
v ? '1' : '0'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'cassandra/0.7'
|
2
|
+
require 'forwardable'
|
3
|
+
require 'date'
|
4
|
+
|
5
|
+
$:.unshift(File.dirname(__FILE__))
|
6
|
+
|
7
|
+
module CassandraModel
|
8
|
+
class CassandraModelError < StandardError; end
|
9
|
+
class UnknownRecord < CassandraModelError; end
|
10
|
+
class InvalidRecord < CassandraModelError; end
|
11
|
+
class RecordNotFound < CassandraModelError; end
|
12
|
+
end
|
13
|
+
|
14
|
+
unless Object.respond_to? :tap
|
15
|
+
class Object
|
16
|
+
def tap(value)
|
17
|
+
yield(value)
|
18
|
+
value
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
require 'cassandra-model/types'
|
24
|
+
require 'active_support/callbacks'
|
25
|
+
require 'cassandra-model/config'
|
26
|
+
require 'cassandra-model/connection'
|
27
|
+
require 'cassandra-model/persistence'
|
28
|
+
require 'cassandra-model/batches'
|
29
|
+
require 'cassandra-model/base'
|
30
|
+
#require 'cassandra-model/railtie'
|
data/test/base_test.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
|
2
|
+
|
3
|
+
class CassandraModelCallbacksTest < Test::Unit::TestCase
|
4
|
+
context "CassandraModel::Base" do
|
5
|
+
setup do
|
6
|
+
@klass = Class.new(CassandraModel::Base) do
|
7
|
+
key :name
|
8
|
+
column :age, :integer
|
9
|
+
column :dob, :datetime
|
10
|
+
column :note, :json
|
11
|
+
|
12
|
+
validate do
|
13
|
+
self.errors << "dob required" if dob.nil?
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
@klass.establish_connection 'cassandra-model'
|
18
|
+
end
|
19
|
+
|
20
|
+
should "connect to cassandra" do
|
21
|
+
assert_kind_of Cassandra, @klass.connection
|
22
|
+
end
|
23
|
+
|
24
|
+
should "store all defined columns" do
|
25
|
+
assert_equal({:age => :integer ,
|
26
|
+
:dob => :datetime,
|
27
|
+
:note => :json} , @klass.columns)
|
28
|
+
end
|
29
|
+
|
30
|
+
should "validate model by provided block" do
|
31
|
+
assert_kind_of Proc, @klass.validation
|
32
|
+
|
33
|
+
model = @klass.new()
|
34
|
+
assert !model.valid?
|
35
|
+
|
36
|
+
model = @klass.new(:name => "tl")
|
37
|
+
assert !model.valid?
|
38
|
+
|
39
|
+
model = @klass.new(:name => "tl", :dob => DateTime.now)
|
40
|
+
assert model.valid?
|
41
|
+
assert_equal "tl", model.key
|
42
|
+
assert_kind_of DateTime, model.dob
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
|
2
|
+
|
3
|
+
class CassandraModelCallbacksTest < Test::Unit::TestCase
|
4
|
+
context "CassandraModel::Callbacks" do
|
5
|
+
setup do
|
6
|
+
@base = Class.new(Object) do
|
7
|
+
include CassandraModel::Callbacks
|
8
|
+
define_callbacks :foo
|
9
|
+
end
|
10
|
+
|
11
|
+
@klass = Class.new(@base) do
|
12
|
+
def bar; @n = [:bar]; end
|
13
|
+
|
14
|
+
def foo
|
15
|
+
run_callbacks(:foo) { @n << :foo }
|
16
|
+
end
|
17
|
+
|
18
|
+
def baz(v)
|
19
|
+
@n << :baz if v == [:bar, :foo]
|
20
|
+
end
|
21
|
+
|
22
|
+
def quux; @n << :quux; end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
should "provide before and after callbacks for foo function" do
|
27
|
+
assert @klass.respond_to?(:define_callbacks)
|
28
|
+
assert @klass.respond_to?(:callbacks)
|
29
|
+
assert @klass.respond_to?(:before_foo)
|
30
|
+
assert @klass.respond_to?(:after_foo)
|
31
|
+
assert_equal Hash.new, @klass.callbacks
|
32
|
+
end
|
33
|
+
|
34
|
+
should "invoke callback functions when foo executed" do
|
35
|
+
@klass.send(:before_foo, :bar)
|
36
|
+
@klass.send(:after_foo, :baz, :quux)
|
37
|
+
assert_equal 2, @klass.callbacks.length
|
38
|
+
assert_equal [:bar], @klass.callbacks[:before_foo]
|
39
|
+
assert_equal [:baz, :quux], @klass.callbacks[:after_foo]
|
40
|
+
assert_equal [:bar, :foo, :baz, :quux], @klass.new.foo
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
|
2
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
|
3
|
+
|
4
|
+
class User < CassandraModel::Base
|
5
|
+
column_family :Users
|
6
|
+
|
7
|
+
key :username
|
8
|
+
column :full_name
|
9
|
+
column :created_at, :datetime
|
10
|
+
|
11
|
+
write_consistency_level Cassandra::Consistency::ALL
|
12
|
+
|
13
|
+
before_save :set_default_time
|
14
|
+
|
15
|
+
validate do
|
16
|
+
errors << "full name required" if full_name.nil? || full_name.empty?
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def set_default_time
|
22
|
+
self.created_at = Time.now
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class CassandraModelTest < Test::Unit::TestCase
|
27
|
+
context "CassandraModel" do
|
28
|
+
setup do
|
29
|
+
@connection = CassandraModel::Base.establish_connection("CassandraModel")
|
30
|
+
@connection.clear_keyspace!
|
31
|
+
|
32
|
+
@user = User.create(:username => "tl", :full_name => "tien le")
|
33
|
+
end
|
34
|
+
|
35
|
+
should "be able to connect to Cassandra" do
|
36
|
+
assert_kind_of Cassandra, @connection
|
37
|
+
assert_equal "CassandraModel", @connection.keyspace
|
38
|
+
end
|
39
|
+
|
40
|
+
should "not create a new user when validation fails" do
|
41
|
+
user = User.create(:username => "tl")
|
42
|
+
assert !user.valid?
|
43
|
+
assert user.new_record?
|
44
|
+
|
45
|
+
user = User.new(:username => "tl").save
|
46
|
+
assert user.new_record?
|
47
|
+
assert_equal "full name required", user.errors.first
|
48
|
+
|
49
|
+
user = User.new(:full_name => "tl").save
|
50
|
+
assert_equal "key required", user.errors.first
|
51
|
+
end
|
52
|
+
|
53
|
+
should "create a new user when validation passed" do
|
54
|
+
assert !@user.new_record?
|
55
|
+
assert @user.eql?(User.get("tl"))
|
56
|
+
assert_equal @user, User.get("tl")
|
57
|
+
assert_equal "tien le", User.get("tl").full_name
|
58
|
+
|
59
|
+
user = User.new(:username => "abc", :full_name => "Foo")
|
60
|
+
user.save
|
61
|
+
assert_equal ["created_at", "full_name"], @connection.get(:Users, "abc").keys
|
62
|
+
end
|
63
|
+
|
64
|
+
should "destroy a record" do
|
65
|
+
@user.destroy
|
66
|
+
assert User.get("tl").nil?
|
67
|
+
assert User.get(nil).nil?
|
68
|
+
|
69
|
+
assert_raise(CassandraModel::RecordNotFound) { User["tl"] }
|
70
|
+
assert_raise(CassandraModel::RecordNotFound) { User[nil] }
|
71
|
+
end
|
72
|
+
|
73
|
+
should "return true if record exists and otherwise" do
|
74
|
+
assert User.exists?("tl")
|
75
|
+
assert !User.exists?("foo")
|
76
|
+
end
|
77
|
+
|
78
|
+
should "only take defined attributes" do
|
79
|
+
user = User.new(:username => "abc", :full_name => "Foo", :hachiko => 'dog')
|
80
|
+
user.save
|
81
|
+
assert_equal ["created_at", "full_name"], @connection.get(:Users, "abc").keys
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,47 @@
|
|
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
|
+
# The directory where Cassandra's configs live (required)
|
18
|
+
CASSANDRA_CONF=$CASSANDRA_CONF
|
19
|
+
|
20
|
+
# This can be the path to a jar file, or a directory containing the
|
21
|
+
# compiled classes. NOTE: This isn't needed by the startup script,
|
22
|
+
# it's just used here in constructing the classpath.
|
23
|
+
cassandra_bin=$CASSANDRA_HOME/build/classes
|
24
|
+
|
25
|
+
# The java classpath (required)
|
26
|
+
CLASSPATH=$CASSANDRA_CONF:$CASSANDRA_BIN
|
27
|
+
|
28
|
+
for jar in $CASSANDRA_HOME/lib/*.jar $CASSANDRA_HOME/build/lib/jars/*.jar; do
|
29
|
+
CLASSPATH=$CLASSPATH:$jar
|
30
|
+
done
|
31
|
+
|
32
|
+
# Arguments to pass to the JVM
|
33
|
+
JVM_OPTS=" \
|
34
|
+
-ea \
|
35
|
+
-Xms128M \
|
36
|
+
-Xmx1G \
|
37
|
+
-XX:TargetSurvivorRatio=90 \
|
38
|
+
-XX:+AggressiveOpts \
|
39
|
+
-XX:+UseParNewGC \
|
40
|
+
-XX:+UseConcMarkSweepGC \
|
41
|
+
-XX:+CMSParallelRemarkEnabled \
|
42
|
+
-XX:+HeapDumpOnOutOfMemoryError \
|
43
|
+
-XX:SurvivorRatio=128 \
|
44
|
+
-XX:MaxTenuringThreshold=0 \
|
45
|
+
-Dcom.sun.management.jmxremote.port=8080 \
|
46
|
+
-Dcom.sun.management.jmxremote.ssl=false \
|
47
|
+
-Dcom.sun.management.jmxremote.authenticate=false"
|
@@ -0,0 +1,27 @@
|
|
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 the root to INFO
|
18
|
+
# and the pattern to %c instead of %l. (%l is slower.)
|
19
|
+
|
20
|
+
# output messages into a rolling log file as well as stdout
|
21
|
+
log4j.rootLogger=WARN,stderr
|
22
|
+
|
23
|
+
# stderr
|
24
|
+
log4j.appender.stderr=org.apache.log4j.ConsoleAppender
|
25
|
+
log4j.appender.stderr.target=System.err
|
26
|
+
log4j.appender.stderr.layout=org.apache.log4j.PatternLayout
|
27
|
+
log4j.appender.stderr.layout.ConversionPattern=%5p %d{HH:mm:ss,SSS} %m%n
|
@@ -0,0 +1,40 @@
|
|
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 the root to INFO
|
18
|
+
# and the pattern to %c instead of %l. (%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.file.maxFileSize=20MB
|
31
|
+
log4j.appender.file.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=data/logs/system.log
|
36
|
+
|
37
|
+
# Application logging options
|
38
|
+
#log4j.logger.com.facebook=DEBUG
|
39
|
+
#log4j.logger.com.facebook.infrastructure.gms=DEBUG
|
40
|
+
#log4j.logger.com.facebook.infrastructure.db=DEBUG
|