hbase-ruby 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/History.txt +11 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.textile +81 -0
  4. data/Rakefile +24 -0
  5. data/VERSION +1 -0
  6. data/lib/hbase.rb +44 -0
  7. data/lib/hbase/client.rb +80 -0
  8. data/lib/hbase/exception.rb +19 -0
  9. data/lib/hbase/model.rb +19 -0
  10. data/lib/hbase/model/column.rb +9 -0
  11. data/lib/hbase/model/column_descriptor.rb +32 -0
  12. data/lib/hbase/model/region_descriptor.rb +9 -0
  13. data/lib/hbase/model/row.rb +11 -0
  14. data/lib/hbase/model/scanner.rb +13 -0
  15. data/lib/hbase/model/table_descriptor.rb +8 -0
  16. data/lib/hbase/operation/meta_operation.rb +10 -0
  17. data/lib/hbase/operation/row_operation.rb +83 -0
  18. data/lib/hbase/operation/scanner_operation.rb +82 -0
  19. data/lib/hbase/operation/table_operation.rb +95 -0
  20. data/lib/hbase/request.rb +7 -0
  21. data/lib/hbase/request/basic_request.rb +27 -0
  22. data/lib/hbase/request/meta_request.rb +17 -0
  23. data/lib/hbase/request/row_request.rb +34 -0
  24. data/lib/hbase/request/scanner_request.rb +25 -0
  25. data/lib/hbase/request/table_request.rb +43 -0
  26. data/lib/hbase/response.rb +7 -0
  27. data/lib/hbase/response/basic_response.rb +16 -0
  28. data/lib/hbase/response/meta_response.rb +35 -0
  29. data/lib/hbase/response/row_response.rb +31 -0
  30. data/lib/hbase/response/scanner_response.rb +37 -0
  31. data/lib/hbase/response/table_response.rb +26 -0
  32. data/spec/hbase/model/column_descriptor_spec.rb +23 -0
  33. data/spec/hbase/model/column_spec.rb +12 -0
  34. data/spec/hbase/model/region_descriptor_spec.rb +4 -0
  35. data/spec/hbase/model/row_spec.rb +12 -0
  36. data/spec/hbase/model/scanner.rb +7 -0
  37. data/spec/hbase/model/table_descriptor_spec.rb +12 -0
  38. data/spec/hbase/operation/meta_operation_spec.rb +18 -0
  39. data/spec/hbase/operation/row_operation_spec.rb +39 -0
  40. data/spec/hbase/operation/scanner_operation_spec.rb +81 -0
  41. data/spec/hbase/operation/table_operation_spec.rb +57 -0
  42. data/spec/hbase/record_spec.rb +25 -0
  43. data/spec/hbase/request/meta_request_spec.rb +10 -0
  44. data/spec/hbase/request/row_request_spec.rb +5 -0
  45. data/spec/hbase/request/scanner_request_spec.rb +5 -0
  46. data/spec/hbase/request/table_request_spec.rb +4 -0
  47. data/spec/hbase/response/meta_response_spec.rb +4 -0
  48. data/spec/hbase/response/row_response_spec.rb +4 -0
  49. data/spec/hbase/response/scanner_response_spec.rb +4 -0
  50. data/spec/hbase/response/table_response_spec.rb +4 -0
  51. data/spec/spec.opts +5 -0
  52. data/spec/spec_helper.rb +7 -0
  53. data/tasks/rspec.rake +7 -0
  54. metadata +147 -0
@@ -0,0 +1,82 @@
1
+ module HBase
2
+ module Operation
3
+ module ScannerOperation
4
+ # Trying to maintain some API stability for now
5
+ def open_scanner(table_name, columns, start_row, stop_row = nil, timestamp = nil)
6
+ warn "[DEPRECATION] This method is deprecated. Use #open_scanner(table_name, options) instead."
7
+
8
+ open_scanner(table_name, {:columns => columns, :start_row => start_row, :stop_row => stop_row, :timestamp => timestamp})
9
+ end
10
+
11
+ def open_scanner(table_name, options = {})
12
+ raise ArgumentError, "options should be given as a Hash" unless options.instance_of? Hash
13
+ columns = options.delete(:columns)
14
+
15
+ begin
16
+ request = Request::ScannerRequest.new(table_name)
17
+
18
+ xml_data = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?><Scanner "
19
+ options.each do |key,value|
20
+ if Model::Scanner::AVAILABLE_OPTS.include? key
21
+ xml_data << "#{Model::Scanner::AVAILABLE_OPTS[key]}='"
22
+ xml_data << ( (key == :batch) ? value.to_s : [value.to_s].flatten.pack('m') )
23
+ xml_data << "' "
24
+ else
25
+ warn "[open_scanner] Received invalid option key :#{key}"
26
+ end
27
+ end
28
+ if columns
29
+ xml_data << ">"
30
+ [columns].flatten.each do |col|
31
+ xml_data << "<column>#{[col].flatten.pack('m')}</column>"
32
+ end
33
+ xml_data << "</Scanner>"
34
+ else
35
+ xml_data << "/>"
36
+ end
37
+
38
+ scanner = Response::ScannerResponse.new(post_response(request.open, xml_data), :open_scanner).parse
39
+ scanner.table_name = table_name
40
+ scanner
41
+ rescue Net::ProtocolError => e
42
+ if e.to_s.include?("TableNotFoundException")
43
+ raise TableNotFoundError, "Table #{table_name} Not Found!"
44
+ else
45
+ raise StandardError, e.to_s
46
+ end
47
+ end
48
+ end
49
+
50
+ def get_rows(scanner, limit = nil)
51
+ warn "[DEPRECATION] Use of 'limit' here is deprecated. Instead, define the batch size when creating the scanner." if limit
52
+ begin
53
+ request = Request::ScannerRequest.new(scanner.table_name)
54
+ rows = Response::ScannerResponse.new(get(request.get_rows(scanner)), :get_rows).parse
55
+ rows.each do |row|
56
+ row.table_name = scanner.table_name
57
+ end
58
+ rows
59
+ rescue StandardError => e
60
+ if e.to_s.include?("TableNotFoundException")
61
+ raise TableNotFoundError, "Table #{table_name} Not Found!"
62
+ else
63
+ raise StandardError, e.to_s
64
+ end
65
+ end
66
+ end
67
+
68
+ def close_scanner(scanner)
69
+ begin
70
+ request = Request::ScannerRequest.new(scanner.table_name)
71
+ Response::ScannerResponse.new(delete_response(request.close(scanner)), :close_scanner).parse
72
+ rescue StandardError => e
73
+ if e.to_s.include?("TableNotFoundException")
74
+ raise TableNotFoundError, "Table #{table_name} Not Found!"
75
+ else
76
+ raise StandardError, e.to_s
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,95 @@
1
+ module HBase
2
+ module Operation
3
+ module TableOperation
4
+ def show_table(name)
5
+ begin
6
+ request = Request::TableRequest.new(name)
7
+ table_descriptor = Response::TableResponse.new(get(request.show)).parse
8
+ rescue Net::ProtocolError => e
9
+ raise TableNotFoundError, "Table '#{name}' Not found"
10
+ end
11
+ end
12
+
13
+ def create_table(name, *args)
14
+ request = Request::TableRequest.new(name)
15
+
16
+ raise StandardError, "Table name must be of type String" unless name.instance_of? String
17
+
18
+ begin
19
+ xml_data = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?><TableSchema name='#{name}' IS_META='false' IS_ROOT='false'>"
20
+ for arg in args
21
+ if arg.instance_of? String
22
+ xml_data << "<ColumnSchema name='#{arg}' />"
23
+ elsif arg.instance_of? Hash
24
+ xml_data << "<ColumnSchema "
25
+
26
+ arg.each do |k,v|
27
+ if Model::ColumnDescriptor::AVAILABLE_OPTS.include? k
28
+ xml_data << "#{Model::ColumnDescriptor::AVAILABLE_OPTS[k]}='#{v}' "
29
+ end
30
+ end
31
+
32
+ xml_data << "/>"
33
+ else
34
+ raise StandardError, "#{arg.class.to_s} of #{arg.to_s} is not of Hash Type"
35
+ end
36
+ end
37
+ xml_data << "</TableSchema>"
38
+ Response::TableResponse.new(post(request.create, xml_data))
39
+ rescue Net::ProtocolError => e
40
+ if e.to_s.include?("TableExistsException")
41
+ raise TableExistsError, "Table '#{name}' already exists"
42
+ else
43
+ raise TableFailCreateError, e.message
44
+ end
45
+ end
46
+ end
47
+
48
+ def alter_table(name, *args)
49
+ raise StandardError, "Table name must be of type String" unless name.instance_of? String
50
+
51
+ request = Request::TableRequest.new(name)
52
+
53
+ begin
54
+ xml_data = construct_xml_stream(name, *args)
55
+ Response::TableResponse.new(put(request.update, xml_data))
56
+ rescue Net::ProtocolError => e
57
+ if e.to_s.include?("TableNotFoundException")
58
+ raise TableNotFoundError, "Table '#{name}' not exists"
59
+ else
60
+ raise TableFailCreateError, e.message
61
+ end
62
+ end
63
+ end
64
+
65
+ def delete_table(name, columns = nil)
66
+ begin
67
+ request = Request::TableRequest.new(name)
68
+ Response::TableResponse.new(delete(request.delete(columns)))
69
+ rescue Net::ProtocolError => e
70
+ if e.to_s.include?("TableNotFoundException")
71
+ raise TableNotFoundError, "Table '#{name}' not exists"
72
+ elsif e.to_s.include?("TableNotDisabledException")
73
+ raise TableNotDisabledError, "Table '#{name}' not disabled"
74
+ end
75
+ end
76
+ end
77
+
78
+ def destroy_table(name, columns = nil)
79
+ delete_table(name, columns)
80
+ end
81
+
82
+ def enable_table(name)
83
+ warn "[DEPRECATION] Explicitly enabling tables isn't required anymore. HBase Stargate will enable/disable as needed."
84
+ end
85
+
86
+ def disable_table(name)
87
+ warn "[DEPRECATION] Explicitly disabling tables isn't required anymore. HBase Stargate will enable/disable as needed."
88
+ end
89
+
90
+ def table_regions(name, start_row = nil, end_row = nil)
91
+ end
92
+
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,7 @@
1
+ module HBase; module Request; end; end
2
+
3
+ require 'hbase/request/basic_request'
4
+ require 'hbase/request/meta_request'
5
+ require 'hbase/request/table_request'
6
+ require 'hbase/request/row_request'
7
+ require 'hbase/request/scanner_request'
@@ -0,0 +1,27 @@
1
+ require 'cgi'
2
+
3
+ module HBase
4
+ module Request
5
+ class BasicRequest
6
+ attr_reader :path
7
+
8
+ def initialize(path)
9
+ @path = path
10
+ end
11
+
12
+
13
+ protected
14
+
15
+ def pack_params columns
16
+ if columns.is_a? String
17
+ columns = [columns]
18
+ elsif columns.is_a? Array
19
+ else
20
+ raise StandardError, "Only String or Array type allows for columns"
21
+ end
22
+
23
+ columns.join(',')
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,17 @@
1
+ module HBase
2
+ module Request
3
+ class MetaRequest < BasicRequest
4
+ def initialize
5
+ super("")
6
+ end
7
+
8
+ def list_tables
9
+ @path << "/"
10
+ end
11
+
12
+ def create_table
13
+ @path << "/tables"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,34 @@
1
+ module HBase
2
+ module Request
3
+ class RowRequest < BasicRequest
4
+ attr_reader :table_name
5
+ attr_reader :name
6
+ attr_reader :timestamp
7
+
8
+ def initialize(table_name, name, timestamp=nil)
9
+ @table_name, @name, @timestamp = CGI.escape(table_name), CGI.escape(name), timestamp
10
+ path = "/#{@table_name}/#{@name}"
11
+ super(path)
12
+ end
13
+
14
+ def show(columns = nil, options = { })
15
+ @path << "/#{pack_params(columns)}" if columns
16
+ @path << "/#{@timestamp}" if @timestamp
17
+ @path << "?v=#{options[:version]}" if options[:version]
18
+ @path
19
+ end
20
+
21
+ def create(columns = nil)
22
+ @path << "/#{pack_params(columns)}" if columns
23
+ @path << "/#{@timestamp}" if @timestamp
24
+ @path
25
+ end
26
+
27
+ def delete(columns = nil)
28
+ @path << "/#{pack_params(columns)}" if columns
29
+ @path << "/#{@timestamp}" if @timestamp
30
+ @path
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,25 @@
1
+ module HBase
2
+ module Request
3
+ class ScannerRequest < BasicRequest
4
+ attr_reader :table_name
5
+
6
+ def initialize(table_name)
7
+ @table_name = CGI.escape(table_name)
8
+ path = "/#{@table_name}/scanner"
9
+ super(path)
10
+ end
11
+
12
+ def open
13
+ @path
14
+ end
15
+
16
+ def get_rows(scanner)
17
+ @path = URI.parse(scanner.scanner_url).path
18
+ end
19
+
20
+ def close(scanner)
21
+ @path = URI.parse(scanner.scanner_url).path
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,43 @@
1
+ module HBase
2
+ module Request
3
+ class TableRequest < BasicRequest
4
+ attr_reader :name
5
+ attr_reader :body
6
+
7
+ def initialize(name)
8
+ super("")
9
+ @name = CGI.escape(name) if name
10
+ end
11
+
12
+ def show
13
+ @path << "/#{name}/schema"
14
+ end
15
+
16
+ def regions(start_row = nil, end_row = nil)
17
+ #TODO no handle the args!
18
+ @path << "/#{name}/regions"
19
+ end
20
+
21
+ def create
22
+ @path << "/#{name}/schema"
23
+ end
24
+
25
+ def update
26
+ @path << "/#{name}"
27
+ end
28
+
29
+ def enable
30
+ @path << "/#{name}/enable"
31
+ end
32
+
33
+ def disable
34
+ @path << "/#{name}/disable"
35
+ end
36
+
37
+ def delete(columns = nil)
38
+ warn "[DEPRECATION] the use of the 'columns' argument is deprecated. Please use the delete method without any arguments." if columns
39
+ @path << "/#{name}/schema"
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,7 @@
1
+ module HBase; module Response; end; end
2
+
3
+ require 'hbase/response/basic_response'
4
+ require 'hbase/response/meta_response'
5
+ require 'hbase/response/table_response'
6
+ require 'hbase/response/row_response'
7
+ require 'hbase/response/scanner_response'
@@ -0,0 +1,16 @@
1
+ require 'json'
2
+
3
+ module HBase
4
+ module Response
5
+ class BasicResponse
6
+
7
+ def initialize(raw_data)
8
+ @raw_data = raw_data
9
+ end
10
+
11
+ def parse
12
+ parse_content @raw_data
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,35 @@
1
+ module HBase
2
+ module Response
3
+ class MetaResponse < BasicResponse
4
+ attr_reader :method
5
+
6
+ def initialize(raw_data, method)
7
+ @method = method
8
+ super(raw_data)
9
+ end
10
+
11
+ def parse_content(raw_data)
12
+ case @method
13
+ when :list_tables
14
+ if raw_data.blank? || raw_data == "null" # "null" from json
15
+ puts "There are no available tables in the HBase"
16
+ return []
17
+ end
18
+
19
+ tables = []
20
+ doc = JSON.parse(raw_data)
21
+
22
+ doc["table"].each do |table|
23
+ name = table["name"].strip rescue nil
24
+ t = Model::TableDescriptor.new(:name => name)
25
+ tables << t
26
+ end
27
+
28
+ tables
29
+ else
30
+ puts "method '#{@method}' not supported yet"
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,31 @@
1
+ module HBase
2
+ module Response
3
+ class RowResponse < BasicResponse
4
+ def parse_content(raw_data)
5
+ doc = JSON.parse(raw_data)
6
+ rows = doc["Row"]
7
+
8
+ model_rows = []
9
+ rows.each do |row|
10
+ rname = row["key"].strip.unpack("m").first
11
+ count = row["Cell"].size
12
+ columns = []
13
+
14
+ row["Cell"].each do |col|
15
+ name = col["column"].strip.unpack('m').first
16
+ value = col["$"].strip.unpack('m').first rescue nil
17
+ timestamp = col["timestamp"].to_i
18
+
19
+ columns << HBase::Model::Column.new( :name => name,
20
+ :value => value,
21
+ :timestamp => timestamp)
22
+ end
23
+
24
+ model_rows << HBase::Model::Row.new(:name => rname, :total_count => count, :columns => columns)
25
+ end
26
+
27
+ model_rows
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,37 @@
1
+ module HBase
2
+ module Response
3
+ class ScannerResponse < BasicResponse
4
+ attr_reader :method
5
+
6
+ def initialize(raw_data, method)
7
+ @method = method
8
+ super(raw_data)
9
+ end
10
+
11
+ def parse_content(raw_data)
12
+ case @method
13
+ when :open_scanner
14
+ case raw_data
15
+ when Net::HTTPCreated
16
+ HBase::Model::Scanner.new(:scanner_url => raw_data["Location"])
17
+ else
18
+ raise StandardError, "Unable to open scanner. Received the following message: #{raw_data.message}"
19
+ end
20
+ when :get_rows
21
+ # Dispatch it to RowResponse, since that method is made
22
+ # to deal with rows already.
23
+ RowResponse.new(raw_data).parse
24
+ when :close_scanner
25
+ case raw_data
26
+ when Net::HTTPOK
27
+ return true
28
+ else
29
+ raise StandardError, "Unable to close scanner. Received the following message: #{raw_data.message}"
30
+ end
31
+ else
32
+ puts "method '#{@method}' not supported yet"
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end