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