hbase-jruby 0.1.1-java
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/.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
|
+
|