ruby-hbase 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ == 0.0.1 2007-10-25
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007 FIXME full name
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ History.txt
2
+ License.txt
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ config/hoe.rb
7
+ config/requirements.rb
8
+ lib/ruby-hbase.rb
9
+ lib/ruby-hbase/version.rb
10
+ lib/ruby-hbase/xml_decoder.rb
11
+ lib/ruby-hbase/hbase_table.rb
12
+ lib/ruby-hbase/scanner.rb
13
+ log/debug.log
14
+ script/destroy
15
+ script/generate
16
+ script/txt2html
17
+ setup.rb
18
+ tasks/deployment.rake
19
+ tasks/environment.rake
20
+ tasks/website.rake
21
+ website/index.html
22
+ website/index.txt
23
+ website/javascripts/rounded_corners_lite.inc.js
24
+ website/stylesheets/screen.css
25
+ website/template.rhtml
26
+ spec/spec_helper.rb
27
+ spec/htable_spec.rb
28
+ spec/scanner_spec.rb
29
+ spec/spec_helper.rb
@@ -0,0 +1 @@
1
+ README
@@ -0,0 +1,4 @@
1
+ require 'config/requirements'
2
+ require 'config/hoe' # setup Hoe + all gem configuration
3
+
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
@@ -0,0 +1,70 @@
1
+ require 'ruby-hbase/version'
2
+
3
+ AUTHOR = 'Bryan Duxbury' # can also be an array of Authors
4
+ EMAIL = "bryan@rapleaf.com"
5
+ DESCRIPTION = "Client library for interacting with HBase the Hadoop database."
6
+ GEM_NAME = 'ruby-hbase' # what ppl will type to install your gem
7
+ RUBYFORGE_PROJECT = 'rapleaf' # The unix name for your project
8
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
9
+ DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
10
+
11
+ @config_file = "~/.rubyforge/user-config.yml"
12
+ @config = nil
13
+ RUBYFORGE_USERNAME = "unknown"
14
+ def rubyforge_username
15
+ unless @config
16
+ begin
17
+ @config = YAML.load(File.read(File.expand_path(@config_file)))
18
+ rescue
19
+ puts <<-EOS
20
+ ERROR: No rubyforge config file found: #{@config_file}
21
+ Run 'rubyforge setup' to prepare your env for access to Rubyforge
22
+ - See http://newgem.rubyforge.org/rubyforge.html for more details
23
+ EOS
24
+ exit
25
+ end
26
+ end
27
+ RUBYFORGE_USERNAME.replace @config["username"]
28
+ end
29
+
30
+
31
+ REV = nil
32
+ # UNCOMMENT IF REQUIRED:
33
+ # REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
34
+ VERS = RubyHbase::VERSION::STRING + (REV ? ".#{REV}" : "")
35
+ RDOC_OPTS = ['--quiet', '--title', 'ruby-hbase documentation',
36
+ "--opname", "index.html",
37
+ "--line-numbers",
38
+ "--main", "README",
39
+ "--inline-source"]
40
+
41
+ class Hoe
42
+ def extra_deps
43
+ @extra_deps.reject! { |x| Array(x).first == 'hoe' }
44
+ @extra_deps
45
+ end
46
+ end
47
+
48
+ # Generate all the Rake tasks
49
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
50
+ hoe = Hoe.new(GEM_NAME, VERS) do |p|
51
+ p.author = AUTHOR
52
+ p.description = DESCRIPTION
53
+ p.email = EMAIL
54
+ p.summary = DESCRIPTION
55
+ p.url = HOMEPATH
56
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
57
+ p.test_globs = ["test/**/test_*.rb"]
58
+ p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
59
+
60
+ # == Optional
61
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\\n\\n")
62
+ #p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
63
+
64
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
65
+
66
+ end
67
+
68
+ CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
69
+ PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
70
+ hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
@@ -0,0 +1,17 @@
1
+ require 'fileutils'
2
+ include FileUtils
3
+
4
+ require 'rubygems'
5
+ %w[rake hoe newgem rubigen].each do |req_gem|
6
+ begin
7
+ require req_gem
8
+ rescue LoadError
9
+ puts "This Rakefile requires the '#{req_gem}' RubyGem."
10
+ puts "Installation: gem install #{req_gem} -y"
11
+ exit
12
+ end
13
+ end
14
+
15
+ $:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
16
+
17
+ require 'ruby-hbase'
@@ -0,0 +1,10 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require "rubygems"
4
+ require "net/http"
5
+ require "erb"
6
+ require "xml/libxml"
7
+
8
+ require "ruby-hbase/xml_decoder"
9
+ require "ruby-hbase/hbase_table"
10
+ require "ruby-hbase/scanner"
@@ -0,0 +1,167 @@
1
+ module HBase
2
+ class RowNotFound < Exception
3
+ def initialize(msg=nil)
4
+ super
5
+ end
6
+ end
7
+
8
+ class HTable
9
+ include XmlDecoder
10
+
11
+ def initialize(table_uri)
12
+ @table_uri = table_uri
13
+
14
+ @uri = URI.parse(table_uri)
15
+
16
+ @host, @table_name = @uri.host, @uri.path.split("/").last
17
+ end
18
+
19
+ def name
20
+ @table_name
21
+ end
22
+
23
+ ######################
24
+ # Meta-type requests
25
+
26
+ def start_keys
27
+ raise NotImplementedError
28
+ end
29
+
30
+
31
+ def column_descriptors
32
+ column_families = []
33
+
34
+ # get the xml for the column descriptors
35
+ response = Net::HTTP.get_response(@uri.host, "/api/#{@table_name}", @uri.port)
36
+ body = response.body
37
+
38
+ # parse the xml into a document
39
+ doc = XML::Parser.string(body).parse
40
+
41
+ doc.find("/table/columnfamilies/columnfamily").each do |node|
42
+ colfam = {}
43
+ colfam[:name] = node.find_first("name").content.strip.chop
44
+ column_families << colfam
45
+ end
46
+ column_families
47
+ end
48
+
49
+
50
+ #####################
51
+ # Standard CRUD ops
52
+
53
+ DEFAULT_GET_OPTIONS = {:timestamp => nil, :columns => nil}
54
+
55
+ def get(key, options = {})
56
+ opts = DEFAULT_GET_OPTIONS.merge(options)
57
+
58
+ columns = Array(opts.delete(:columns)).compact
59
+ timestamp = opts.delete(:timestamp)
60
+ timestamp = (timestamp.to_f * 1000).to_i.to_s if timestamp
61
+
62
+ Net::HTTP.start(@uri.host, @uri.port) do |session|
63
+ columns_query = columns.map{ |name| "column=#{name}" }.join("&")
64
+
65
+ ts_section = timestamp ? "/#{timestamp}" : ""
66
+
67
+ query_string = "?" + columns_query
68
+
69
+ query = "/api/#{@table_name}/row/#{url_encode(key)}#{ts_section}#{query_string}"
70
+ response = session.get(query, {"Accept" => "*/*"})
71
+
72
+ case response.code.to_i
73
+ when 200 #success!
74
+ body = response.body
75
+
76
+ parse_row_result(body).last
77
+ when 204 #no data - probably an incorrect colname
78
+ raise "Didn't get any data back - check your column names!"
79
+ when 404
80
+ raise RowNotFound, "Could not find row '#{key}'"
81
+ else
82
+ nil
83
+ end
84
+ end
85
+ end
86
+
87
+ def put(key, keys_and_values, timestamp = nil)
88
+ Net::HTTP.start(@uri.host, @uri.port) do |session|
89
+ xml = "<columns>"
90
+
91
+ ts_section = timestamp ? "/#{(timestamp.to_f * 1000).to_i}" : ""
92
+
93
+ keys_and_values.each do |name, value|
94
+ xml << "<column><name>#{name}</name><value>#{[value.to_s].pack("m")}</value></column>"
95
+ end
96
+
97
+ xml << "</columns>"
98
+
99
+ query = "/api/#{@table_name}/row/#{url_encode(key)}#{ts_section}"
100
+ response = session.post(query, xml, {"Content-type" => "text/xml"})
101
+
102
+ case response.code.to_i
103
+ when 200
104
+ true
105
+ else
106
+ unexpected_response(response)
107
+ end
108
+ end
109
+ end
110
+
111
+ def delete(row, columns = nil, timestamp = nil)
112
+ Net::HTTP.start(@uri.host, @uri.port) do |session|
113
+ columns_query = Array(columns).compact.map{ |name| "column=#{name}" }.join("&")
114
+
115
+ response = session.delete("/api/#{@table_name}/row/#{row}?#{columns_query}")
116
+ case response.code.to_i
117
+ when 202
118
+ return true
119
+ else
120
+ unexpected_response(response)
121
+ end
122
+
123
+ end
124
+ end
125
+
126
+ #######################
127
+ # Scanning interface
128
+
129
+ def get_scanner(start_row, end_row, timestamp = nil, columns = nil)
130
+ start_row_query = start_row ? "start_row=#{start_row}" : nil
131
+ end_row_query = end_row ? "end_row=#{end_row}" : nil
132
+ timestamp_section = timestamp ? "/#{(timestamp.to_f * 1000).to_i}" : nil
133
+ columns_section = columns ? columns.map{ |col| "column=#{col}" }.join("&") : nil
134
+
135
+ query_string = [start_row_query, end_row_query,
136
+ timestamp_section, columns_section].compact.join("&")
137
+
138
+ path = ""
139
+
140
+ # open the scanner
141
+ Net::HTTP.start(@uri.host, @uri.port) do |session|
142
+ response = session.post("/api/#{@table_name}/scanner?#{query_string}",
143
+ "", {"Accept" => "text/xml"}
144
+ )
145
+
146
+ case response.code.to_i
147
+ when 201
148
+ # redirect - grab the path and send
149
+ Scanner.new(self, "http://#{@uri.host}:#{@uri.port}" + response["Location"])
150
+ else
151
+ unexpected_response(response)
152
+ end
153
+ end
154
+ end
155
+
156
+
157
+ private
158
+
159
+ def url_encode(str)
160
+ ERB::Util.url_encode(str)
161
+ end
162
+
163
+ def unexpected_response(response)
164
+ raise "Unexpected response code #{response.code.to_i}:\n#{response.body}"
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,55 @@
1
+ module HBase
2
+ class Scanner
3
+ include XmlDecoder
4
+
5
+ def initialize(table, scanner_uri)
6
+ @table, @scanner_uri = table, scanner_uri
7
+ end
8
+
9
+ def close
10
+
11
+ end
12
+
13
+ def next
14
+
15
+ end
16
+
17
+ def each
18
+ parsed_uri = URI.parse(@scanner_uri)
19
+ Net::HTTP.start(parsed_uri.host, parsed_uri.port) do |session|
20
+ while true
21
+ response = session.post(@scanner_uri, "")
22
+
23
+ case response.code.to_i
24
+ when 404
25
+ # over
26
+ break
27
+ when 200
28
+ # item
29
+ yield *parse_row_result(response.body)
30
+ else
31
+ # error
32
+ raise "Unexpected response code #{response.code}, body:\n#{response.body}"
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ # def parse_row(xml)
41
+ # doc = REXML::Document.new(xml)
42
+ #
43
+ # result = {}
44
+ #
45
+ # doc.root.each_element("/row/column") do |column|
46
+ # name = column.get_elements("name")[0].text.strip
47
+ # value = column.get_elements("value")[0].text.strip.unpack("m").first
48
+ # result[name] = value
49
+ # end
50
+ #
51
+ # [doc.root.get_elements("name")[0].text.strip, result]
52
+ # end
53
+
54
+ end
55
+ end
@@ -0,0 +1,9 @@
1
+ module RubyHbase #:nodoc:
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ TINY = 4
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
@@ -0,0 +1,18 @@
1
+ module HBase
2
+ module XmlDecoder
3
+ def parse_row_result(xml)
4
+ doc = XML::Parser.string(xml).parse
5
+
6
+ name_node = doc.root.find_first("/row/name")
7
+ name = name_node ? name_node.content.strip : nil
8
+
9
+ values = {}
10
+
11
+ doc.find("/row/column").each do |node|
12
+ values[node.find_first("name").content.strip] = node.find_first("value").content.strip.unpack("m").first
13
+ end
14
+
15
+ [name, values]
16
+ end
17
+ end
18
+ end
File without changes
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.join(File.dirname(__FILE__), '..')
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.join(File.dirname(__FILE__), '..')
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)