hbase-stargate 1.5.0

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.
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