pager-mogilefs-client 1.2.1.20080519

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,11 @@
1
+ = 1.2.1
2
+
3
+ * Switched to Hoe.
4
+ * Moved to p4.
5
+ * Fixed bug #7273 in HTTP mode of client where data would not get
6
+ returned. Submitted by Matthew Willson.
7
+
8
+ = 1.2.0
9
+
10
+ * Changes lost to time.
11
+
@@ -0,0 +1,27 @@
1
+ Copyright 2005 Eric Hodel, The Robot Co-op. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright
8
+ notice, this list of conditions and the following disclaimer.
9
+ 2. Redistributions in binary form must reproduce the above copyright
10
+ notice, this list of conditions and the following disclaimer in the
11
+ documentation and/or other materials provided with the distribution.
12
+ 3. Neither the names of the authors nor the names of their contributors
13
+ may be used to endorse or promote products derived from this software
14
+ without specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
17
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
20
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
22
+ OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+
@@ -0,0 +1,19 @@
1
+ History.txt
2
+ LICENSE.txt
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ lib/mogilefs.rb
7
+ lib/mogilefs/admin.rb
8
+ lib/mogilefs/backend.rb
9
+ lib/mogilefs/client.rb
10
+ lib/mogilefs/httpfile.rb
11
+ lib/mogilefs/mogilefs.rb
12
+ lib/mogilefs/nfsfile.rb
13
+ lib/mogilefs/pool.rb
14
+ test/setup.rb
15
+ test/test_admin.rb
16
+ test/test_backend.rb
17
+ test/test_client.rb
18
+ test/test_mogilefs.rb
19
+ test/test_pool.rb
@@ -0,0 +1,66 @@
1
+ = mogilefs-client
2
+
3
+ A Ruby MogileFS client
4
+
5
+ Rubyforge Project:
6
+
7
+ http://rubyforge.org/projects/seattlerb/
8
+
9
+ Documentation:
10
+
11
+ http://seattlerb.org/mogilefs-client
12
+
13
+ File bugs:
14
+
15
+ http://rubyforge.org/tracker/?func=add&group_id=1513&atid=5921
16
+
17
+ == About
18
+
19
+ A Ruby MogileFS client. MogileFS is a distributed filesystem written
20
+ by Danga Interactive. This client supports NFS and HTTP modes.
21
+
22
+ For information on MogileFS see:
23
+
24
+ http://danga.com/mogilefs/
25
+
26
+ == Installing mogilefs-client
27
+
28
+ First you need a MogileFS setup. You can find information on how to do that at the above URL.
29
+
30
+ Then install the gem:
31
+
32
+ $ sudo gem install mogilefs-client
33
+
34
+ == Using mogilefs-client
35
+
36
+ # Create a new instance that will communicate with these trackers:
37
+ hosts = %w[192.168.1.69:6001 192.168.1.70:6001]
38
+ mg = MogileFS::MogileFS.new(:domain => 'test', :hosts => hosts
39
+ :root => '/mnt/mogilefs')
40
+
41
+ # Stores "A bunch of text to store" into 'some_key' with a class of 'text'.
42
+ mg.store_content 'some_key', 'text', "A bunch of text to store"
43
+
44
+ # Retrieve data from 'some_key'
45
+ data = mg.get_file_data 'some_key'
46
+
47
+ # Store the contents of 'image.jpeg' into the key 'my_image' with a class of
48
+ # 'image'.
49
+ mg.store_file 'my_image', 'image', 'image.jpeg'
50
+
51
+ # Store the contents of 'image.jpeg' into the key 'my_image' with a class of
52
+ # 'image' using an open IO.
53
+ File.open 'image.jpeg' do |fp|
54
+ mg.store_file 'my_image', 'image', fp
55
+ end
56
+
57
+ # Remove the key 'my_image' and 'some_key'.
58
+ mg.delete 'my_image'
59
+ mg.delete 'some_key'
60
+
61
+ == WARNING!
62
+
63
+ This client is only known to work in NFS mode. HTTP mode is implemented but
64
+ only lightly tested in production environments. If you find a bug,
65
+ please report it on the Rubyforge project.
66
+
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'hoe'
3
+
4
+ $:.unshift 'lib'
5
+ require 'mogilefs'
6
+
7
+ Hoe.new 'mogilefs-client', MogileFS::VERSION do |p|
8
+ p.rubyforge_name = 'seattlerb'
9
+ p.author = 'Eric Hodel'
10
+ p.email = 'drbrain@segment7.net'
11
+ p.summary = p.paragraphs_of('README.txt', 1).first
12
+ p.description = p.paragraphs_of('README.txt', 9).first
13
+ p.url = p.paragraphs_of('README.txt', 5).first
14
+ p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
15
+ end
16
+
17
+ # vim: syntax=Ruby
18
+
@@ -0,0 +1,26 @@
1
+ ##
2
+ # MogileFS is a Ruby client for Danga Interactive's open source distributed
3
+ # filesystem.
4
+ #
5
+ # To read more about Danga's MogileFS: http://danga.com/mogilefs/
6
+
7
+ module MogileFS
8
+
9
+ VERSION = '1.2.1'
10
+
11
+ ##
12
+ # Raised when a socket remains unreadable for too long.
13
+
14
+ class UnreadableSocketError < RuntimeError; end
15
+
16
+ end
17
+
18
+ require 'socket'
19
+
20
+ require 'mogilefs/backend'
21
+ require 'mogilefs/nfsfile'
22
+ require 'mogilefs/httpfile'
23
+ require 'mogilefs/client'
24
+ require 'mogilefs/mogilefs'
25
+ require 'mogilefs/admin'
26
+
@@ -0,0 +1,298 @@
1
+ require 'mogilefs/client'
2
+
3
+ ##
4
+ # A MogileFS Administration Client
5
+
6
+ class MogileFS::Admin < MogileFS::Client
7
+
8
+ ##
9
+ # Enumerates fids using #list_fids.
10
+
11
+ def each_fid
12
+ low = 0
13
+ high = nil
14
+
15
+ max = get_stats('fids')['fids']['max']
16
+
17
+ 0.step max, 100 do |high|
18
+ fids = list_fids low, high
19
+ fids.each { |fid| yield fid }
20
+ low = high + 1
21
+ end
22
+ end
23
+
24
+ ##
25
+ # Returns an Array of host status Hashes. If +hostid+ is given only that
26
+ # host is returned.
27
+ #
28
+ # admin.get_hosts 1
29
+ #
30
+ # Returns:
31
+ #
32
+ # [{"status"=>"alive",
33
+ # "http_get_port"=>"",
34
+ # "http_port"=>"",
35
+ # "hostid"=>"1",
36
+ # "hostip"=>"",
37
+ # "hostname"=>"rur-1",
38
+ # "remoteroot"=>"/mnt/mogilefs/rur-1",
39
+ # "altip"=>"",
40
+ # "altmask"=>""}]
41
+
42
+ def get_hosts(hostid = nil)
43
+ args = hostid ? { :hostid => hostid } : {}
44
+ res = @backend.get_hosts args
45
+ return clean('hosts', 'host', res)
46
+ end
47
+
48
+ ##
49
+ # Returns an Array of device status Hashes. If devid is given only that
50
+ # device is returned.
51
+ #
52
+ # admin.get_devices 1
53
+ #
54
+ # Returns:
55
+ #
56
+ # [{"status"=>"alive",
57
+ # "mb_asof"=>"",
58
+ # "mb_free"=>"0",
59
+ # "devid"=>"1",
60
+ # "hostid"=>"1",
61
+ # "mb_used"=>"",
62
+ # "mb_total"=>""}]
63
+
64
+ def get_devices(devid = nil)
65
+ args = devid ? { :devid => devid } : {}
66
+ res = @backend.get_devices args
67
+ return clean('devices', 'dev', res)
68
+ end
69
+
70
+ ##
71
+ # Returns an Array of fid Hashes from +from_fid+ to +to_fid+.
72
+ #
73
+ # admin.list_fids 0, 100
74
+ #
75
+ # Returns:
76
+ #
77
+ # [{"fid"=>"99",
78
+ # "class"=>"normal",
79
+ # "domain"=>"test",
80
+ # "devcount"=>"2",
81
+ # "length"=>"4",
82
+ # "key"=>"file_key"},
83
+ # {"fid"=>"82",
84
+ # "class"=>"normal",
85
+ # "devcount"=>"2",
86
+ # "domain"=>"test",
87
+ # "length"=>"9",
88
+ # "key"=>"new_new_key"}]
89
+
90
+ def list_fids(from_fid, to_fid)
91
+ res = @backend.list_fids :from => from_fid, :to => to_fid
92
+ return clean('fid_count', 'fid_', res)
93
+ end
94
+
95
+ ##
96
+ # Returns a statistics structure representing the state of mogilefs.
97
+ #
98
+ # admin.get_stats
99
+ #
100
+ # Returns:
101
+ #
102
+ # {"fids"=>{"max"=>"99", "count"=>"2"},
103
+ # "device"=>
104
+ # [{"status"=>"alive", "files"=>"2", "id"=>"1", "host"=>"rur-1"},
105
+ # {"status"=>"alive", "files"=>"2", "id"=>"2", "host"=>"rur-2"}],
106
+ # "replication"=>
107
+ # [{"files"=>"2", "class"=>"normal", "devcount"=>"2", "domain"=>"test"}],
108
+ # "file"=>[{"files"=>"2", "class"=>"normal", "domain"=>"test"}]}
109
+
110
+ def get_stats(type = 'all')
111
+ res = @backend.stats type => 1
112
+ stats = {}
113
+
114
+ stats['device'] = clean 'devicescount', 'devices', res, false
115
+ stats['file'] = clean 'filescount', 'files', res, false
116
+ stats['replication'] = clean 'replicationcount', 'replication', res, false
117
+
118
+ if res['fidmax'] or res['fidcount'] then
119
+ stats['fids'] = {
120
+ 'max' => res['fidmax'].to_i,
121
+ 'count' => res['fidcount'].to_i
122
+ }
123
+ end
124
+
125
+ stats.delete 'device' if stats['device'].empty?
126
+ stats.delete 'file' if stats['file'].empty?
127
+ stats.delete 'replication' if stats['replication'].empty?
128
+
129
+ return stats
130
+ end
131
+
132
+ ##
133
+ # Returns the domains present in the mogilefs.
134
+ #
135
+ # admin.get_domains
136
+ #
137
+ # Returns:
138
+ #
139
+ # {"test"=>{"normal"=>3, "default"=>2}}
140
+
141
+ def get_domains
142
+ res = @backend.get_domains
143
+
144
+ domains = {}
145
+ (1..res['domains'].to_i).each do |i|
146
+ domain = clean "domain#{i}classes", "domain#{i}class", res, false
147
+ domain = domain.map { |d| [d.values.first, d.values.last.to_i] }
148
+ domains[res["domain#{i}"]] = Hash[*domain.flatten]
149
+ end
150
+
151
+ return domains
152
+ end
153
+
154
+ ##
155
+ # Creates a new domain named +domain+. Returns nil if creation failed.
156
+
157
+ def create_domain(domain)
158
+ raise 'readonly mogilefs' if readonly?
159
+ res = @backend.create_domain :domain => domain
160
+ return res['domain'] unless res.nil?
161
+ end
162
+
163
+ ##
164
+ # Deletes +domain+. Returns true if successful, false if not.
165
+
166
+ def delete_domain(domain)
167
+ raise 'readonly mogilefs' if readonly?
168
+ res = @backend.delete_domain :domain => domain
169
+ return !res.nil?
170
+ end
171
+
172
+ ##
173
+ # Creates a new class in +domain+ named +klass+ with files replicated to
174
+ # +mindevcount+ devices. Returns nil on failure.
175
+
176
+ def create_class(domain, klass, mindevcount)
177
+ return modify_class(domain, klass, mindevcount, :create)
178
+ end
179
+
180
+ ##
181
+ # Updates class +klass+ in +domain+ to be replicated to +mindevcount+
182
+ # devices. Returns nil on failure.
183
+
184
+ def update_class(domain, klass, mindevcount)
185
+ return modify_class(domain, klass, mindevcount, :update)
186
+ end
187
+
188
+ ##
189
+ # Removes class +klass+ from +domain+. Returns true if successful, false if
190
+ # not.
191
+
192
+ def delete_class(domain, klass)
193
+ res = @backend.delete_class :domain => domain, :class => klass
194
+ return !res.nil?
195
+ end
196
+
197
+ ##
198
+ # Creates a new host named +host+. +args+ must contain :ip and :port.
199
+ # Returns true if successful, false if not.
200
+
201
+ def create_host(host, args = {})
202
+ raise ArgumentError, "Must specify ip and port" unless \
203
+ args.include? :ip and args.include? :port
204
+
205
+ return modify_host(host, args, 'create')
206
+ end
207
+
208
+ ##
209
+ # Updates +host+ with +args+. Returns true if successful, false if not.
210
+
211
+ def update_host(host, args = {})
212
+ return modify_host(host, args, 'update')
213
+ end
214
+
215
+ ##
216
+ # Deletes host +host+. Returns nil on failure.
217
+
218
+ def delete_host(host)
219
+ raise 'readonly mogilefs' if readonly?
220
+ res = @backend.delete_host :host => host
221
+ return !res.nil?
222
+ end
223
+
224
+ ##
225
+ # Changes the device status of +device+ on +host+ to +state+ which can be
226
+ # 'alive', 'down', or 'dead'.
227
+
228
+ def change_device_state(host, device, state)
229
+ raise 'readonly mogilefs' if readonly?
230
+ res = @backend.set_state :host => host, :device => device, :state => state
231
+ return !res.nil?
232
+ end
233
+
234
+ protected unless defined? $TESTING
235
+
236
+ ##
237
+ # Modifies +klass+ on +domain+ to store files on +mindevcount+ devices via
238
+ # +action+. Returns the class name if successful, nil if not.
239
+
240
+ def modify_class(domain, klass, mindevcount, action)
241
+ raise 'readonly mogilefs' if readonly?
242
+ res = @backend.send("#{action}_class", :domain => domain, :class => klass,
243
+ :mindevcount => mindevcount)
244
+
245
+ return res['class'] unless res.nil?
246
+ end
247
+
248
+ ##
249
+ # Modifies +host+ using +args+ via +action+. Returns true if successful,
250
+ # false if not.
251
+
252
+ def modify_host(host, args = {}, action = 'create')
253
+ args[:host] = host
254
+ res = @backend.send "#{action}_host", args
255
+ return !res.nil?
256
+ end
257
+
258
+ ##
259
+ # Turns the response +res+ from the backend into an Array of Hashes from 1
260
+ # to res[+count+]. If +underscore+ is true then a '_' character is assumed
261
+ # between the prefix and the hash key value.
262
+ #
263
+ # res = {"host1_remoteroot"=>"/mnt/mogilefs/rur-1",
264
+ # "host1_hostname"=>"rur-1",
265
+ # "host1_hostid"=>"1",
266
+ # "host1_http_get_port"=>"",
267
+ # "host1_altip"=>"",
268
+ # "hosts"=>"1",
269
+ # "host1_hostip"=>"",
270
+ # "host1_http_port"=>"",
271
+ # "host1_status"=>"alive",
272
+ # "host1_altmask"=>""}
273
+ # admin.clean 'hosts', 'host', res
274
+ #
275
+ # Returns:
276
+ #
277
+ # [{"status"=>"alive",
278
+ # "http_get_port"=>"",
279
+ # "http_port"=>"",
280
+ # "hostid"=>"1",
281
+ # "hostip"=>"",
282
+ # "hostname"=>"rur-1",
283
+ # "remoteroot"=>"/mnt/mogilefs/rur-1",
284
+ # "altip"=>"",
285
+ # "altmask"=>""}]
286
+
287
+ def clean(count, prefix, res, underscore = true)
288
+ underscore = underscore ? '_' : ''
289
+ return (1..res[count].to_i).map do |i|
290
+ dev = res.select { |k,_| k =~ /^#{prefix}#{i}#{underscore}/ }.map do |k,v|
291
+ [k.sub(/^#{prefix}#{i}#{underscore}/, ''), v]
292
+ end
293
+ Hash[*dev.flatten]
294
+ end
295
+ end
296
+
297
+ end
298
+