hbase-stargate 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/LICENSE +20 -0
  2. data/README.textile +79 -0
  3. data/Rakefile +27 -0
  4. data/VERSION +1 -0
  5. data/lib/stargate.rb +7 -0
  6. data/lib/stargate/client.rb +93 -0
  7. data/lib/stargate/exception.rb +21 -0
  8. data/lib/stargate/model.rb +19 -0
  9. data/lib/stargate/model/column.rb +9 -0
  10. data/lib/stargate/model/column_descriptor.rb +32 -0
  11. data/lib/stargate/model/region_descriptor.rb +9 -0
  12. data/lib/stargate/model/row.rb +18 -0
  13. data/lib/stargate/model/scanner.rb +16 -0
  14. data/lib/stargate/model/table_descriptor.rb +8 -0
  15. data/lib/stargate/operation/meta_operation.rb +20 -0
  16. data/lib/stargate/operation/row_operation.rb +86 -0
  17. data/lib/stargate/operation/scanner_operation.rb +90 -0
  18. data/lib/stargate/operation/table_operation.rb +95 -0
  19. data/lib/stargate/request.rb +7 -0
  20. data/lib/stargate/request/basic_request.rb +27 -0
  21. data/lib/stargate/request/meta_request.rb +25 -0
  22. data/lib/stargate/request/row_request.rb +34 -0
  23. data/lib/stargate/request/scanner_request.rb +25 -0
  24. data/lib/stargate/request/table_request.rb +43 -0
  25. data/lib/stargate/response.rb +7 -0
  26. data/lib/stargate/response/basic_response.rb +25 -0
  27. data/lib/stargate/response/meta_response.rb +35 -0
  28. data/lib/stargate/response/row_response.rb +47 -0
  29. data/lib/stargate/response/scanner_response.rb +41 -0
  30. data/lib/stargate/response/table_response.rb +26 -0
  31. data/spec/hbase-stargate/model/column_descriptor_spec.rb +23 -0
  32. data/spec/hbase-stargate/model/column_spec.rb +12 -0
  33. data/spec/hbase-stargate/model/region_descriptor_spec.rb +4 -0
  34. data/spec/hbase-stargate/model/row_spec.rb +12 -0
  35. data/spec/hbase-stargate/model/scanner.rb +5 -0
  36. data/spec/hbase-stargate/model/table_descriptor_spec.rb +12 -0
  37. data/spec/hbase-stargate/operation/meta_operation_spec.rb +18 -0
  38. data/spec/hbase-stargate/operation/row_operation_spec.rb +75 -0
  39. data/spec/hbase-stargate/operation/scanner_operation_spec.rb +103 -0
  40. data/spec/hbase-stargate/operation/table_operation_spec.rb +43 -0
  41. data/spec/hbase-stargate/record_spec.rb +20 -0
  42. data/spec/hbase-stargate/request/meta_request_spec.rb +10 -0
  43. data/spec/hbase-stargate/request/row_request_spec.rb +4 -0
  44. data/spec/hbase-stargate/request/scanner_request_spec.rb +4 -0
  45. data/spec/hbase-stargate/request/table_request_spec.rb +4 -0
  46. data/spec/hbase-stargate/response/meta_response_spec.rb +4 -0
  47. data/spec/hbase-stargate/response/row_response_spec.rb +4 -0
  48. data/spec/hbase-stargate/response/scanner_response_spec.rb +4 -0
  49. data/spec/hbase-stargate/response/table_response_spec.rb +4 -0
  50. data/spec/spec.opts +4 -0
  51. data/spec/spec_helper.rb +3 -0
  52. metadata +144 -0
@@ -0,0 +1,90 @@
1
+ module Stargate
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
+ batch = options.delete(:batch) || "10"
15
+
16
+ begin
17
+ request = Request::ScannerRequest.new(table_name)
18
+
19
+ xml_data = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?><Scanner batch='#{batch}' "
20
+ options.each do |key,value|
21
+ if Model::Scanner::AVAILABLE_OPTS.include? key
22
+ xml_data << "#{Model::Scanner::AVAILABLE_OPTS[key]}='#{[value.to_s].flatten.pack('m')}' "
23
+ else
24
+ warn "[open_scanner] Received invalid option key :#{key}"
25
+ end
26
+ end
27
+ if columns
28
+ xml_data << ">"
29
+ [columns].flatten.each do |col|
30
+ xml_data << "<column>#{[col].flatten.pack('m')}</column>"
31
+ end
32
+ xml_data << "</Scanner>"
33
+ else
34
+ xml_data << "/>"
35
+ end
36
+
37
+ scanner = Response::ScannerResponse.new(post_response(request.open, xml_data), :open_scanner).parse
38
+ scanner.table_name = table_name
39
+ scanner.batch_size = batch
40
+ scanner
41
+ rescue Net::ProtocolError => e
42
+ raise StandardError, e.to_s
43
+ end
44
+ end
45
+
46
+ def get_rows(scanner, limit = nil)
47
+ begin
48
+ request = Request::ScannerRequest.new(scanner.table_name)
49
+ request_url = request.get_rows(scanner) # The url to the scanner is the same for each batch
50
+
51
+ rows = []
52
+ begin
53
+ # Loop until we've reached the limit, or the scanner was exhausted (HTTP 204 returned)
54
+ until (limit && rows.size >= limit) || (response = get_response(request_url)).code == "204"
55
+ rows.concat Response::ScannerResponse.new(response.body, :get_rows).parse
56
+
57
+ rows.each do |row|
58
+ row.table_name = scanner.table_name
59
+ end
60
+ end
61
+ rescue Exception => e
62
+ raise Stargate::ScannerError, "Scanner failed while getting rows. #{e.message}"
63
+ end
64
+
65
+ # Prune the last few rows if the limit was passed.
66
+ (limit) ? rows.slice(0, limit) : rows
67
+ rescue StandardError => e
68
+ if e.to_s.include?("TableNotFoundException")
69
+ raise TableNotFoundError, "Table #{table_name} Not Found!"
70
+ else
71
+ raise StandardError, e.to_s
72
+ end
73
+ end
74
+ end
75
+
76
+ def close_scanner(scanner)
77
+ begin
78
+ request = Request::ScannerRequest.new(scanner.table_name)
79
+ Response::ScannerResponse.new(delete_response(request.close(scanner)), :close_scanner).parse
80
+ rescue StandardError => e
81
+ if e.to_s.include?("TableNotFoundException")
82
+ raise TableNotFoundError, "Table #{table_name} Not Found!"
83
+ else
84
+ raise StandardError, e.to_s
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,95 @@
1
+ module Stargate
2
+ module Operation
3
+ module TableOperation
4
+ def show_table(name)
5
+ begin
6
+ request = Request::TableRequest.new(name)
7
+ Response::TableResponse.new(get(request.show)).parse
8
+ rescue Net::ProtocolError
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 Stargate module Request; end; end
2
+
3
+ require File.dirname(__FILE__) + '/request/basic_request'
4
+ require File.dirname(__FILE__) + '/request/meta_request'
5
+ require File.dirname(__FILE__) + '/request/table_request'
6
+ require File.dirname(__FILE__) + '/request/row_request'
7
+ require File.dirname(__FILE__) + '/request/scanner_request'
@@ -0,0 +1,27 @@
1
+ require 'cgi'
2
+
3
+ module Stargate
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,25 @@
1
+ module Stargate
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
+
16
+ def version
17
+ @path << "/version"
18
+ end
19
+
20
+ def cluster_version
21
+ @path << "/version/cluster"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,34 @@
1
+ module Stargate
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 << (columns ? "/#{pack_params(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 << (columns ? "/#{pack_params(columns)}" : "/")
23
+ @path << "/#{@timestamp}" if @timestamp
24
+ @path
25
+ end
26
+
27
+ def delete(columns = nil)
28
+ @path << (columns ? "/#{pack_params(columns)}" : "/")
29
+ @path << "/#{@timestamp}" if @timestamp
30
+ @path
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,25 @@
1
+ module Stargate
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 Stargate
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 Stargate module Response; end; end
2
+
3
+ require File.dirname(__FILE__) + '/response/basic_response'
4
+ require File.dirname(__FILE__) + '/response/meta_response'
5
+ require File.dirname(__FILE__) + '/response/table_response'
6
+ require File.dirname(__FILE__) + '/response/row_response'
7
+ require File.dirname(__FILE__) + '/response/scanner_response'
@@ -0,0 +1,25 @@
1
+ require 'json'
2
+
3
+ module Stargate
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
+
15
+ def verify_success(response)
16
+ case response
17
+ when Net::HTTPSuccess
18
+ true
19
+ else
20
+ false
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,35 @@
1
+ module Stargate
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.to_s.empty? || 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,47 @@
1
+ module Stargate
2
+ module Response
3
+ class RowResponse < 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 :show_row
14
+ doc = JSON.parse(raw_data)
15
+ rows = doc["Row"]
16
+
17
+ model_rows = []
18
+ rows.each do |row|
19
+ rname = row["key"].strip.unpack("m").first
20
+ count = row["Cell"].size
21
+ columns = []
22
+
23
+ row["Cell"].each do |col|
24
+ name = col["column"].strip.unpack('m').first
25
+ value = col["$"].strip.unpack('m').first rescue nil
26
+ timestamp = col["timestamp"].to_i
27
+
28
+ columns << Stargate::Model::Column.new( :name => name,
29
+ :value => value,
30
+ :timestamp => timestamp)
31
+ end
32
+
33
+ model_rows << Stargate::Model::Row.new(:name => rname, :total_count => count, :columns => columns)
34
+ end
35
+
36
+ model_rows
37
+ when :create_row
38
+ verify_success(raw_data)
39
+ when :delete_row
40
+ verify_success(raw_data)
41
+ else
42
+ puts "method '#{@method}' not supported yet"
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end