hbase-jruby 0.1.1-java
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +623 -0
- data/Rakefile +7 -0
- data/hbase-jruby.gemspec +23 -0
- data/lib/hbase-jruby.rb +16 -0
- data/lib/hbase-jruby/admin.rb +29 -0
- data/lib/hbase-jruby/byte_array.rb +39 -0
- data/lib/hbase-jruby/cell.rb +122 -0
- data/lib/hbase-jruby/column_key.rb +63 -0
- data/lib/hbase-jruby/dependency.rb +69 -0
- data/lib/hbase-jruby/hbase.rb +77 -0
- data/lib/hbase-jruby/pom/cdh3u5.xml +40 -0
- data/lib/hbase-jruby/pom/cdh4.1.2.xml +47 -0
- data/lib/hbase-jruby/result.rb +382 -0
- data/lib/hbase-jruby/scoped.rb +489 -0
- data/lib/hbase-jruby/table.rb +486 -0
- data/lib/hbase-jruby/util.rb +171 -0
- data/lib/hbase-jruby/version.rb +5 -0
- data/test/helper.rb +53 -0
- data/test/test_byte_array.rb +40 -0
- data/test/test_cell.rb +51 -0
- data/test/test_column_key.rb +49 -0
- data/test/test_hbase.rb +36 -0
- data/test/test_scoped.rb +318 -0
- data/test/test_table.rb +211 -0
- data/test/test_table_admin.rb +148 -0
- data/test/test_util.rb +80 -0
- metadata +116 -0
data/Rakefile
ADDED
data/hbase-jruby.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'hbase-jruby/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "hbase-jruby"
|
8
|
+
gem.version = HBase::JRuby::VERSION
|
9
|
+
gem.authors = ["Junegunn Choi"]
|
10
|
+
gem.email = ["junegunn.c@gmail.com"]
|
11
|
+
gem.description = %q{Ruby-esque interface for accessing HBase from JRuby}
|
12
|
+
gem.summary = %q{Ruby-esque interface for accessing HBase from JRuby}
|
13
|
+
gem.homepage = "https://github.com/junegunn/hbase-jruby"
|
14
|
+
gem.platform = 'java'
|
15
|
+
|
16
|
+
gem.files = `git ls-files`.split($/)
|
17
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
18
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
|
+
gem.require_paths = ["lib"]
|
20
|
+
|
21
|
+
gem.add_development_dependency 'test-unit'
|
22
|
+
gem.add_development_dependency 'simplecov'
|
23
|
+
end
|
data/lib/hbase-jruby.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
unless RUBY_PLATFORM =~ /java/
|
2
|
+
raise LoadError, 'Only supports JRuby'
|
3
|
+
end
|
4
|
+
|
5
|
+
require "hbase-jruby/version"
|
6
|
+
require "hbase-jruby/dependency"
|
7
|
+
require "hbase-jruby/util"
|
8
|
+
require "hbase-jruby/byte_array"
|
9
|
+
require "hbase-jruby/column_key"
|
10
|
+
require "hbase-jruby/cell"
|
11
|
+
require "hbase-jruby/admin"
|
12
|
+
require "hbase-jruby/scoped"
|
13
|
+
require "hbase-jruby/table"
|
14
|
+
require "hbase-jruby/result"
|
15
|
+
require 'hbase-jruby/hbase'
|
16
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
class HBase
|
4
|
+
module Admin
|
5
|
+
private
|
6
|
+
def with_admin
|
7
|
+
(@admin_mutex ||= Mutex.new).synchronize do
|
8
|
+
begin
|
9
|
+
admin = HBaseAdmin.new(@config)
|
10
|
+
yield admin
|
11
|
+
ensure
|
12
|
+
admin.close if admin
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def wait_async_admin admin
|
18
|
+
while true
|
19
|
+
pair = admin.getAlterStatus(@name.to_java_bytes)
|
20
|
+
yet = pair.getFirst
|
21
|
+
total = pair.getSecond
|
22
|
+
|
23
|
+
break if yet == 0
|
24
|
+
sleep 1
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end#Admin
|
28
|
+
end#HBase
|
29
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class HBase
|
2
|
+
# @private
|
3
|
+
class ByteArray
|
4
|
+
attr_reader :java
|
5
|
+
|
6
|
+
def initialize value
|
7
|
+
@java = Util.to_bytes value
|
8
|
+
end
|
9
|
+
|
10
|
+
def eql? other
|
11
|
+
Arrays.equals(@java, other.java)
|
12
|
+
end
|
13
|
+
alias == eql?
|
14
|
+
|
15
|
+
def <=> other
|
16
|
+
Bytes.compareTo(@java, other.java)
|
17
|
+
end
|
18
|
+
|
19
|
+
def stopkey_bytes_for_prefix
|
20
|
+
arr = @java.to_a
|
21
|
+
csr = arr.length - 1
|
22
|
+
arr[csr] += 1
|
23
|
+
while csr >= 0 && arr[csr] > 127
|
24
|
+
csr -= 1
|
25
|
+
arr[csr] += 1
|
26
|
+
end
|
27
|
+
if csr < 0
|
28
|
+
nil
|
29
|
+
else
|
30
|
+
arr[0..csr].to_java(Java::byte)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def hash
|
35
|
+
Arrays.java_send(:hashCode, [Util::JAVA_BYTE_ARRAY_CLASS], @java)
|
36
|
+
end
|
37
|
+
end#ByteArray
|
38
|
+
end#HBase
|
39
|
+
|
@@ -0,0 +1,122 @@
|
|
1
|
+
class HBase
|
2
|
+
# Boxed Ruby class for org.apache.hadoop.hbase.KeyValue
|
3
|
+
# @!attribute [r] java
|
4
|
+
# @return [org.apache.hadoop.hbase.KeyValue]
|
5
|
+
class Cell
|
6
|
+
attr_reader :java
|
7
|
+
|
8
|
+
# Creates a boxed object for a KeyValue object
|
9
|
+
# @param [org.apache.hadoop.hbase.KeyValue] key_value
|
10
|
+
def initialize key_value
|
11
|
+
@java = key_value
|
12
|
+
@ck = nil
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the rowkey of the cell decoded as the given type
|
16
|
+
# @param [Symbol] type The type of the rowkey.
|
17
|
+
# Can be one of :string, :symbol, :fixnum, :float, :bignum, :bigdecimal, :boolean and :raw.
|
18
|
+
# @return [String, byte[]]
|
19
|
+
def rowkey type = :string
|
20
|
+
Util.from_bytes type, @java.getRow
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns the ColumnKey object for the cell
|
24
|
+
# @return [ColumnKey]
|
25
|
+
def column_key
|
26
|
+
@ck ||= ColumnKey.new @java.getFamily, @java.getQualifier
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns the name of the column family of the cell
|
30
|
+
# @return [String]
|
31
|
+
def family
|
32
|
+
String.from_java_bytes @java.getFamily
|
33
|
+
end
|
34
|
+
alias cf family
|
35
|
+
|
36
|
+
# Returns the column qualifier of the cell
|
37
|
+
# @param [Symbol] type The type of the qualifier.
|
38
|
+
# Can be one of :string, :symbol, :fixnum, :float, :bignum, :bigdecimal, :boolean and :raw.
|
39
|
+
# @return [Object]
|
40
|
+
def qualifier type = :string
|
41
|
+
Util.from_bytes type, @java.getQualifier
|
42
|
+
end
|
43
|
+
alias cq qualifier
|
44
|
+
|
45
|
+
# Returns the timestamp of the cell
|
46
|
+
# @return [Fixnum]
|
47
|
+
def timestamp
|
48
|
+
@java.getTimestamp
|
49
|
+
end
|
50
|
+
alias ts timestamp
|
51
|
+
|
52
|
+
# Returns the value of the cell as a Java byte array
|
53
|
+
# @return [byte[]]
|
54
|
+
def value
|
55
|
+
@java.getValue
|
56
|
+
end
|
57
|
+
alias raw value
|
58
|
+
|
59
|
+
# Returns the column value as a String
|
60
|
+
# @return [String]
|
61
|
+
def string
|
62
|
+
Util.from_bytes :string, value
|
63
|
+
end
|
64
|
+
alias str string
|
65
|
+
|
66
|
+
# Returns the column value as a Symbol
|
67
|
+
# @return [Symbol]
|
68
|
+
def symbol
|
69
|
+
Util.from_bytes :symbol, value
|
70
|
+
end
|
71
|
+
alias sym symbol
|
72
|
+
|
73
|
+
# Returns the column value as a Fixnum
|
74
|
+
# @return [Fixnum]
|
75
|
+
def fixnum
|
76
|
+
Util.from_bytes :fixnum, value
|
77
|
+
end
|
78
|
+
alias integer fixnum
|
79
|
+
alias int fixnum
|
80
|
+
|
81
|
+
# Returns the column value as a Bignum
|
82
|
+
# @return [Bignum]
|
83
|
+
def bignum
|
84
|
+
Util.from_bytes :bignum, value
|
85
|
+
end
|
86
|
+
alias biginteger bignum
|
87
|
+
alias bigint bignum
|
88
|
+
|
89
|
+
# Returns the column value as a BigDecimal
|
90
|
+
# @return [BigDecimal]
|
91
|
+
def bigdecimal
|
92
|
+
Util.from_bytes :bigdecimal, value
|
93
|
+
end
|
94
|
+
|
95
|
+
# Returns the column value as a Float
|
96
|
+
# @return [Float]
|
97
|
+
def float
|
98
|
+
Util.from_bytes :float, value
|
99
|
+
end
|
100
|
+
alias double float
|
101
|
+
|
102
|
+
# Returns the column value as a boolean value
|
103
|
+
# @return [true, false]
|
104
|
+
def boolean
|
105
|
+
Util.from_bytes :boolean, value
|
106
|
+
end
|
107
|
+
alias bool boolean
|
108
|
+
|
109
|
+
# Implements column key order
|
110
|
+
# @param [Cell] other
|
111
|
+
# @return [Fixnum] -1, 0, or 1
|
112
|
+
def <=> other
|
113
|
+
KeyValue.COMPARATOR.compare(@java, other.java)
|
114
|
+
end
|
115
|
+
|
116
|
+
# @return [String]
|
117
|
+
def inspect
|
118
|
+
%[#{cf}:#{cq} = "#{string}"@#{ts}]
|
119
|
+
end
|
120
|
+
end#Cell
|
121
|
+
end#HBase
|
122
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
class HBase
|
2
|
+
class << self
|
3
|
+
# Shortcut method to HBase::ColumnKey.new
|
4
|
+
# @param [Object] cf Column family
|
5
|
+
# @param [Object] cq Column qualifier
|
6
|
+
def ColumnKey cf, cq
|
7
|
+
ColumnKey.new cf, cq
|
8
|
+
end
|
9
|
+
end
|
10
|
+
# Boxed class for column keys
|
11
|
+
class ColumnKey
|
12
|
+
attr_reader :cf
|
13
|
+
alias family cf
|
14
|
+
|
15
|
+
# Creates a ColumnKey object
|
16
|
+
# @param [Object] cf Column family
|
17
|
+
# @param [Object] cq Column qualifier
|
18
|
+
def initialize cf, cq
|
19
|
+
@cf = String.from_java_bytes Util.to_bytes(cf)
|
20
|
+
@cq = Util.to_bytes(cq)
|
21
|
+
end
|
22
|
+
|
23
|
+
# @param [Symbol] type
|
24
|
+
def cq type = :string
|
25
|
+
Util.from_bytes type, @cq
|
26
|
+
end
|
27
|
+
alias qualifier cq
|
28
|
+
|
29
|
+
# @param [Object] other
|
30
|
+
def eql? other
|
31
|
+
other = other_as_ck(other)
|
32
|
+
@cf == other.cf && Arrays.equals(@cq, other.cq(:raw))
|
33
|
+
end
|
34
|
+
alias == eql?
|
35
|
+
|
36
|
+
# @param [Object] other
|
37
|
+
def <=> other
|
38
|
+
other = other_as_ck(other)
|
39
|
+
d = @cf <=> other.cf
|
40
|
+
d != 0 ? d : Bytes.compareTo(@cq, other.cq(:raw))
|
41
|
+
end
|
42
|
+
|
43
|
+
def hash
|
44
|
+
[@cf, Arrays.java_send(:hashCode, [Util::JAVA_BYTE_ARRAY_CLASS], @cq)].hash
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_s
|
48
|
+
[@cf, @cq.empty? ? nil : cq].compact.join(':')
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
def other_as_ck other
|
53
|
+
case other
|
54
|
+
when ColumnKey
|
55
|
+
other
|
56
|
+
else
|
57
|
+
cf, cq = Util.parse_column_name(other)
|
58
|
+
ColumnKey.new(cf, cq)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end#ColumnKey
|
62
|
+
end#HBase
|
63
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'java'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'tempfile'
|
4
|
+
|
5
|
+
# HBase connection
|
6
|
+
class HBase
|
7
|
+
class << self
|
8
|
+
# Resolve Hadoop and HBase dependency with Maven or hbase command (Experimental)
|
9
|
+
# @param [String] dist Distribution version or path to pom.xml file
|
10
|
+
# @param [true, false] verbose Verbose output
|
11
|
+
# @return [Array<String>] Loaded JAR files
|
12
|
+
def resolve_dependency! dist, verbose = false
|
13
|
+
silencer = verbose ? '' : '> /dev/null'
|
14
|
+
tempfiles = []
|
15
|
+
jars =
|
16
|
+
if dist == :hbase
|
17
|
+
# Check for hbase executable
|
18
|
+
hbase = `which hbase`
|
19
|
+
raise RuntimeError, "Cannot find executable `hbase`" if hbase.empty?
|
20
|
+
`hbase classpath`.split(':')
|
21
|
+
else
|
22
|
+
# Check for Maven executable
|
23
|
+
mvn = `which mvn`
|
24
|
+
raise RuntimeError, "Cannot find executable `mvn`" if mvn.empty?
|
25
|
+
|
26
|
+
distname = dist.downcase.sub(/\.xml$/, '')
|
27
|
+
path = [
|
28
|
+
File.expand_path("../pom/#{distname}.xml", __FILE__),
|
29
|
+
dist.to_s,
|
30
|
+
].select { |f| File.exists? f }.first
|
31
|
+
|
32
|
+
# Try github head
|
33
|
+
unless path
|
34
|
+
begin
|
35
|
+
xml = open("https://raw.github.com/junegunn/hbase-jruby/master/lib/hbase-jruby/pom/#{distname}.xml").read
|
36
|
+
tempfiles << tf = Tempfile.new("#{distname}.xml")
|
37
|
+
tf.close(false)
|
38
|
+
path = tf.path
|
39
|
+
File.open(path, 'w') do |f|
|
40
|
+
f << xml
|
41
|
+
end
|
42
|
+
rescue OpenURI::HTTPError => e
|
43
|
+
# No such distribution anywhere
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
raise ArgumentError, "Invalid distribution: #{dist}" unless path
|
48
|
+
|
49
|
+
# Download dependent JAR files and build classpath string
|
50
|
+
tempfiles << tf = Tempfile.new('hbase-jruby-classpath')
|
51
|
+
tf.close(false)
|
52
|
+
system "mvn org.apache.maven.plugins:maven-dependency-plugin:2.5.1:resolve org.apache.maven.plugins:maven-dependency-plugin:2.5.1:build-classpath -Dsilent=true -Dmdep.outputFile=#{tf.path} -f #{path} #{silencer}"
|
53
|
+
|
54
|
+
raise RuntimeError.new("Error occurred. Set verbose parameter to see the log.") unless $?.exitstatus == 0
|
55
|
+
|
56
|
+
File.read(tf.path).split(':')
|
57
|
+
end
|
58
|
+
|
59
|
+
# Load jars
|
60
|
+
jars.select { |jar| File.exists?(jar) && File.extname(jar) == '.jar' }.select do |jar|
|
61
|
+
require jar
|
62
|
+
end
|
63
|
+
|
64
|
+
Util.import_java_classes!
|
65
|
+
ensure
|
66
|
+
tempfiles.each { |tempfile| tempfile.unlink rescue nil }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'java'
|
2
|
+
|
3
|
+
# @author Junegunn Choi <junegunn.c@gmail.com>
|
4
|
+
# @!attribute [r] config
|
5
|
+
# @return [org.apache.hadoop.conf.Configuration]
|
6
|
+
class HBase
|
7
|
+
attr_reader :config
|
8
|
+
|
9
|
+
include Admin
|
10
|
+
|
11
|
+
# Connects to HBase
|
12
|
+
# @param [Hash] config A key-value pairs to build HBaseConfiguration from
|
13
|
+
def initialize config = {}
|
14
|
+
Util.import_java_classes!
|
15
|
+
|
16
|
+
@config =
|
17
|
+
case config
|
18
|
+
when org.apache.hadoop.conf.Configuration
|
19
|
+
config
|
20
|
+
else
|
21
|
+
HBaseConfiguration.create.tap do |hbcfg|
|
22
|
+
config.each do |k, v|
|
23
|
+
hbcfg.set k.to_s, v.to_s
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
@htable_pool = HTablePool.new @config, java.lang.Integer::MAX_VALUE
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns an HBaseAdmin object for administration
|
31
|
+
# @yield [org.apache.hadoop.hbase.client.HBaseAdmin]
|
32
|
+
# @return [org.apache.hadoop.hbase.client.HBaseAdmin]
|
33
|
+
def admin
|
34
|
+
if block_given?
|
35
|
+
with_admin { |admin| yield admin }
|
36
|
+
else
|
37
|
+
HBaseAdmin.new @config
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Closes HTablePool and connection
|
42
|
+
# @return [nil]
|
43
|
+
def close
|
44
|
+
@htable_pool.close
|
45
|
+
HConnectionManager.deleteConnection(@config, true)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns the list of HBase::Table instances
|
49
|
+
# @return [Array<HBase::Table>]
|
50
|
+
def tables
|
51
|
+
table_names.map { |tn| table(tn) }
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns the list of table names
|
55
|
+
# @return [Array<String>]
|
56
|
+
def table_names
|
57
|
+
with_admin { |admin| admin.list_tables.map(&:name_as_string) }
|
58
|
+
end
|
59
|
+
|
60
|
+
# Creates HBase::Table instance for the specified name
|
61
|
+
# @param [#to_s] table_name The name of the table
|
62
|
+
# @return [HBase::Table]
|
63
|
+
def table table_name
|
64
|
+
ht = HBase::Table.send :new, @config, @htable_pool, table_name
|
65
|
+
|
66
|
+
if block_given?
|
67
|
+
begin
|
68
|
+
yield ht
|
69
|
+
ensure
|
70
|
+
ht.close
|
71
|
+
end
|
72
|
+
else
|
73
|
+
ht
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|