oneliner 0.2.7 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,21 +0,0 @@
1
- # Archipelago - a distributed computing toolkit for ruby
2
- # Copyright (C) 2006 Martin Kihlgren <zond at troja dot ath dot cx>
3
- #
4
- # This program is free software; you can redistribute it and/or
5
- # modify it under the terms of the GNU General Public License
6
- # as published by the Free Software Foundation; either version 2
7
- # of the License, or (at your option) any later version.
8
- #
9
- # This program is distributed in the hope that it will be useful,
10
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
- # GNU General Public License for more details.
13
- #
14
- # You should have received a copy of the GNU General Public License
15
- # along with this program; if not, write to the Free Software
16
- # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
-
18
- $: << File.dirname(File.expand_path(__FILE__))
19
-
20
- require 'oneliner_ext'
21
- require 'oneliner/superstring'
@@ -1,385 +0,0 @@
1
- # Archipelago - a distributed computing toolkit for ruby
2
- # Copyright (C) 2006 Martin Kihlgren <zond at troja dot ath dot cx>
3
- #
4
- # This program is free software; you can redistribute it and/or
5
- # modify it under the terms of the GNU General Public License
6
- # as published by the Free Software Foundation; either version 2
7
- # of the License, or (at your option) any later version.
8
- #
9
- # This program is distributed in the hope that it will be useful,
10
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
- # GNU General Public License for more details.
13
- #
14
- # You should have received a copy of the GNU General Public License
15
- # along with this program; if not, write to the Free Software
16
- # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
-
18
- require 'set'
19
- require 'digest/sha2'
20
-
21
- module Oneliner
22
-
23
- #
24
- # A String subclass providing Online Code functionality.
25
- #
26
- class SuperString < String
27
-
28
- E = 0.01
29
- Q = 3
30
- F = (Math.log((E ** 2) / 4) / Math.log(1 - (E / 2))).abs.to_i
31
- P = [0, (1 - ((1 + (1 / F)) / (1 + E)))]
32
- 2.upto(F) do |i|
33
- P << (((1 - P[1]) * F) / ((F - 1) * i * (i - 1)))
34
- end
35
-
36
- #
37
- # Will return a String containing +requested_size+ nr of bytes
38
- # as an online coded chunk of blocks for this SuperString.
39
- #
40
- def encode(requested_size)
41
- raise "requested size is too small for metadata (8 bytes)" unless requested_size > 7
42
-
43
- ensure_encode_format
44
- srand
45
- seed = rand(Context::INT_MAX)
46
- context = Context.new
47
- context.seed(seed)
48
-
49
- rval = [self.size].pack("i")
50
- rval << [seed].pack("i")
51
-
52
- blocks = []
53
- wanted_blocks = ((requested_size - 8) * 8) / @block_size
54
- 1.upto(wanted_blocks) do |n|
55
- blocks << generate_check_block(context, n - 1)
56
- end
57
-
58
- return rval + compact(blocks)
59
- end
60
-
61
- #
62
- # Will try to decode this SuperString using the given +chunk+ and all
63
- # formerly given chunks.
64
- #
65
- # Returns whether decoding is done.
66
- #
67
- def decode!(chunk)
68
- raise "#{chunk.inspect} is too small for metadata (8 bytes)" unless chunk.size > 7
69
-
70
- @decode_done = nil
71
-
72
- context = Context.new
73
-
74
- requested_size = chunk[0..3].unpack("i").first
75
-
76
- ensure_decode_format(requested_size)
77
-
78
- the_seed = chunk[4..7].unpack("i").first
79
-
80
- chunk_data = build_chunk_data(chunk, context, the_seed)
81
-
82
- @known_nr_of_blocks += chunk_data.size
83
- @known_chunks.unshift(chunk_data)
84
-
85
- if @known_nr_of_blocks > @nr_of_blocks
86
-
87
- nil while do_decode(context)
88
-
89
- if decode_done?
90
- self.replace(compact(@blocks[0...@nr_of_data_blocks])[0...requested_size])
91
- return true
92
- else
93
- return false
94
- end
95
-
96
- else
97
- return false
98
- end
99
- end
100
-
101
- #
102
- # Returns whether decoding is done.
103
- #
104
- def decode_done?
105
- return false unless defined?(@decode_done) && defined?(@nr_of_data_blocks)
106
-
107
- unless @decode_done
108
- data = @blocks[0...@nr_of_data_blocks]
109
- @decode_done = data.compact.size == data.size
110
- end
111
- return @decode_done
112
- end
113
-
114
- private
115
-
116
- #
117
- # Misc stuff
118
- #
119
-
120
- #
121
- # Builds a Hash with index of each block in the +chunk+
122
- # paired with the block itself and the source blocks for
123
- # that block determined using +context+ and +the_seed+.
124
- #
125
- def build_chunk_data(chunk, context, the_seed)
126
- blocks_to_return = {}
127
-
128
- context.seed(the_seed)
129
-
130
- expand(chunk[8..-1]).each_with_index do |block, index|
131
- this_degree = get_degree(context)
132
- these_blocks = []
133
- this_degree.times do |m|
134
- these_blocks << context.random(@nr_of_blocks)
135
- end
136
-
137
- blocks_to_return[index] = [block, these_blocks]
138
- end
139
-
140
- return blocks_to_return
141
- end
142
-
143
- #
144
- # Split +s+ up into @block_size (in bits if less than 8, otherwise closed matching nr of bytes) pieces
145
- # and return them in an array.
146
- #
147
- def expand(s)
148
- if @block_size < 8
149
- rval = s.unpack("b*").first
150
- rval = rval.gsub(/(.{#{@block_size},#{@block_size}})/, "\\1#{"0" * (8 - @block_size)}")
151
- rval += "0" * (8 - (rval.size % 8)) if (rval.size % 8) > 0
152
- rval = [rval].pack("b*")
153
- return rval.split(//)
154
- else
155
- bytes_per_block = @block_size / 8
156
- rval = s
157
- rval += "\000" * (bytes_per_block - (rval.size % bytes_per_block)) if (rval.size % bytes_per_block) > 0
158
- return rval.hack(bytes_per_block)
159
- end
160
- end
161
-
162
- #
163
- # Glue +blocks+ together into a String.
164
- #
165
- def compact(blocks)
166
- if @block_size < 8
167
- rval = blocks.join
168
- rval = rval.unpack("b*")
169
- rval = rval.first.gsub(/(.{#{@block_size},#{@block_size}}).{#{8 - @block_size},#{8 - @block_size}}/,
170
- "\\1")
171
- rval += "0" * (8 - (rval.size % 8)) if (rval.size % 8) > 0
172
- return [rval].pack("b*")
173
- else
174
- return blocks.join
175
- end
176
- end
177
-
178
- #
179
- # Determine and save the nr of aux_blocks we want for this SuperString.
180
- #
181
- def set_nr_of_aux_blocks
182
- @nr_of_aux_blocks ||= (0.55 * Q * E * @nr_of_data_blocks).ceil
183
- end
184
-
185
- #
186
- # Determine and save the block_size we want for this SuperString.
187
- #
188
- def set_block_size
189
- unless defined?(@block_size)
190
- if size < (256 + 128)
191
- @block_size = 1
192
- else
193
- @block_size = size / 256
194
- end
195
- end
196
- return @block_size
197
- end
198
-
199
- #
200
- # Determine and save the nr_of_blocks we want for this SuperString.
201
- #
202
- def set_nr_of_blocks
203
- @nr_of_blocks ||= @blocks.size
204
- end
205
-
206
- #
207
- # Decoding stuff
208
- #
209
-
210
- def do_decode(context)
211
- found_new_block = false
212
- @known_chunks.clone.each_with_index do |chunk_data, i|
213
- this_chunk_found_new_block, this_chunk_informative = decode_chunk(chunk_data)
214
- found_new_block = found_new_block || this_chunk_found_new_block
215
- @known_chunks.delete(i) unless this_chunk_informative
216
- end
217
- return aux_decode || found_new_block
218
- end
219
-
220
- def aux_decode
221
- got_new_block = false
222
-
223
- @nr_of_data_blocks.upto(@nr_of_blocks - 1) do |i|
224
-
225
- aux_block = @blocks[i]
226
- if aux_block
227
-
228
- source_blocks = @aux_hash[i]
229
- if source_blocks.size == 1
230
- block_nr = source_blocks.first
231
-
232
- if @blocks[block_nr].nil?
233
- @blocks[block_nr] = aux_block
234
- got_new_block = true
235
- @blocks[i] = nil
236
- end
237
- else
238
- missing_blocks = source_blocks.size
239
- missing_block = nil
240
- xor_sum = aux_block
241
- source_blocks.each do |block|
242
- source_block = @blocks[block]
243
- if source_block
244
- missing_blocks -= 1
245
- xor_sum ^= source_block
246
- else
247
- missing_block = block
248
- end
249
- end
250
-
251
- if missing_blocks == 1
252
- @blocks[missing_block] = xor_sum
253
- got_new_block = true
254
- @blocks[i] = nil
255
- end
256
- end
257
- end
258
- end
259
-
260
- return got_new_block
261
- end
262
-
263
- def decode_chunk(blocks)
264
- got_new_block = false
265
- got_informative_block = false
266
-
267
- blocks.clone.each do |index, block_data|
268
-
269
- block, block_numbers = block_data
270
-
271
- got_informative_block = true
272
-
273
- if block_numbers.size == 1
274
- block_nr = block_numbers.first
275
-
276
- if @blocks[block_nr].nil?
277
- @blocks[block_nr] = block
278
- got_new_block = true
279
- blocks.delete(index)
280
- end
281
- else
282
- if decode_multiple(block_data, @blocks, @nr_of_blocks)
283
- got_new_block = true
284
- blocks.delete(index)
285
- end
286
- end
287
-
288
- end
289
-
290
- return [got_new_block, got_informative_block]
291
- end
292
-
293
- def generate_aux_hash
294
- rval = Array.new(@nr_of_blocks)
295
-
296
- context = Context.new
297
- context.seed(@nr_of_data_blocks)
298
-
299
- 0.upto(@nr_of_data_blocks - 1) do |i|
300
- 1.upto(Q) do
301
- aux_block_nr = @nr_of_data_blocks + context.random(@nr_of_aux_blocks)
302
- (rval[aux_block_nr] ||= []) << i
303
- end
304
- end
305
-
306
- return rval
307
- end
308
-
309
- def ensure_decode_format(requested_size)
310
- unless defined?(@blocks)
311
- self.concat("\000" * requested_size)
312
- set_block_size
313
- @nr_of_data_blocks = expand(self).size
314
- set_nr_of_aux_blocks
315
- @blocks = Array.new(@nr_of_data_blocks)
316
- @blocks += Array.new(@nr_of_aux_blocks)
317
- set_nr_of_blocks
318
- @aux_hash = generate_aux_hash
319
- @known_chunks = []
320
- @known_nr_of_blocks = 0
321
- @known_block_nrs_by_seed = {}
322
- end
323
- end
324
-
325
- def ensure_size(requested_size)
326
- if size == 0
327
- concat("\000" * requested_size)
328
- @decoded_blocks = Set.new
329
- elsif size != requested_size
330
- raise "size of #{self} (#{size}) is wrong, should be #{requested_size}"
331
- end
332
- end
333
-
334
- #
335
- # Encoding stuff
336
- #
337
-
338
- def generate_check_block(context, n)
339
- degree = get_degree(context)
340
-
341
- block_nr = context.random(@nr_of_blocks)
342
- rval = @blocks[block_nr]
343
-
344
- 2.upto(degree) do
345
- block_nr = context.random(@nr_of_blocks)
346
- rval ^= @blocks[block_nr]
347
- end
348
- return rval
349
- end
350
-
351
- def generate_aux_blocks
352
- rval = Array.new(@nr_of_aux_blocks)
353
-
354
- context = Context.new
355
- context.seed(@nr_of_data_blocks)
356
-
357
- b_size = nil
358
- @blocks.each_with_index do |b, i|
359
- 1.upto(Q) do
360
- aux_block_nr = context.random(@nr_of_aux_blocks)
361
- if rval[aux_block_nr].nil?
362
- rval[aux_block_nr] = b
363
- else
364
- rval[aux_block_nr] ^= b
365
- end
366
- end
367
- end
368
-
369
- return rval
370
- end
371
-
372
- def ensure_encode_format
373
- unless defined?(@blocks)
374
- set_block_size
375
- @blocks = expand(self)
376
- @nr_of_data_blocks = @blocks.size
377
- set_nr_of_aux_blocks
378
- @blocks += generate_aux_blocks
379
- @nr_of_blocks = @blocks.size
380
- end
381
- end
382
-
383
- end
384
-
385
- end