pager-mogilefs-client 1.2.1.20080519

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