hbase-stargate 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.textile +79 -0
- data/Rakefile +27 -0
- data/VERSION +1 -0
- data/lib/stargate.rb +7 -0
- data/lib/stargate/client.rb +93 -0
- data/lib/stargate/exception.rb +21 -0
- data/lib/stargate/model.rb +19 -0
- data/lib/stargate/model/column.rb +9 -0
- data/lib/stargate/model/column_descriptor.rb +32 -0
- data/lib/stargate/model/region_descriptor.rb +9 -0
- data/lib/stargate/model/row.rb +18 -0
- data/lib/stargate/model/scanner.rb +16 -0
- data/lib/stargate/model/table_descriptor.rb +8 -0
- data/lib/stargate/operation/meta_operation.rb +20 -0
- data/lib/stargate/operation/row_operation.rb +86 -0
- data/lib/stargate/operation/scanner_operation.rb +90 -0
- data/lib/stargate/operation/table_operation.rb +95 -0
- data/lib/stargate/request.rb +7 -0
- data/lib/stargate/request/basic_request.rb +27 -0
- data/lib/stargate/request/meta_request.rb +25 -0
- data/lib/stargate/request/row_request.rb +34 -0
- data/lib/stargate/request/scanner_request.rb +25 -0
- data/lib/stargate/request/table_request.rb +43 -0
- data/lib/stargate/response.rb +7 -0
- data/lib/stargate/response/basic_response.rb +25 -0
- data/lib/stargate/response/meta_response.rb +35 -0
- data/lib/stargate/response/row_response.rb +47 -0
- data/lib/stargate/response/scanner_response.rb +41 -0
- data/lib/stargate/response/table_response.rb +26 -0
- data/spec/hbase-stargate/model/column_descriptor_spec.rb +23 -0
- data/spec/hbase-stargate/model/column_spec.rb +12 -0
- data/spec/hbase-stargate/model/region_descriptor_spec.rb +4 -0
- data/spec/hbase-stargate/model/row_spec.rb +12 -0
- data/spec/hbase-stargate/model/scanner.rb +5 -0
- data/spec/hbase-stargate/model/table_descriptor_spec.rb +12 -0
- data/spec/hbase-stargate/operation/meta_operation_spec.rb +18 -0
- data/spec/hbase-stargate/operation/row_operation_spec.rb +75 -0
- data/spec/hbase-stargate/operation/scanner_operation_spec.rb +103 -0
- data/spec/hbase-stargate/operation/table_operation_spec.rb +43 -0
- data/spec/hbase-stargate/record_spec.rb +20 -0
- data/spec/hbase-stargate/request/meta_request_spec.rb +10 -0
- data/spec/hbase-stargate/request/row_request_spec.rb +4 -0
- data/spec/hbase-stargate/request/scanner_request_spec.rb +4 -0
- data/spec/hbase-stargate/request/table_request_spec.rb +4 -0
- data/spec/hbase-stargate/response/meta_response_spec.rb +4 -0
- data/spec/hbase-stargate/response/row_response_spec.rb +4 -0
- data/spec/hbase-stargate/response/scanner_response_spec.rb +4 -0
- data/spec/hbase-stargate/response/table_response_spec.rb +4 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +3 -0
- 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
|