Author: toad
Date: 2005-11-11 17:46:41 +0000 (Fri, 11 Nov 2005)
New Revision: 7526
Modified:
trunk/freenet/src/freenet/client/BlockFetcher.java
trunk/freenet/src/freenet/client/BlockInserter.java
trunk/freenet/src/freenet/client/FECCodec.java
trunk/freenet/src/freenet/client/InsertSegment.java
trunk/freenet/src/freenet/client/RetryTracker.java
trunk/freenet/src/freenet/client/SplitInserter.java
trunk/freenet/src/freenet/client/StandardOnionFECCodec.java
trunk/freenet/src/freenet/client/StdSplitfileBlock.java
trunk/freenet/src/freenet/keys/ClientCHKBlock.java
trunk/freenet/src/freenet/node/TextModeClientInterface.java
trunk/freenet/src/freenet/node/Version.java
trunk/freenet/src/freenet/support/Fields.java
trunk/freenet/src/org/spaceroots/mantissa/random/MersenneTwister.java
Log:
162:
Insertion of splitfiles of more than one segment is working.
FEC encoding is at least partially working.
Modified: trunk/freenet/src/freenet/client/BlockFetcher.java
===================================================================
--- trunk/freenet/src/freenet/client/BlockFetcher.java 2005-11-11 15:55:56 UTC
(rev 7525)
+++ trunk/freenet/src/freenet/client/BlockFetcher.java 2005-11-11 17:46:41 UTC
(rev 7526)
@@ -16,7 +16,7 @@
boolean actuallyFetched;
public BlockFetcher(Segment segment, RetryTracker tracker, FreenetURI
freenetURI, int index, boolean dontEnterImplicitArchives) {
- super(tracker, index);
+ super(tracker, index, null);
this.segment = segment;
uri = freenetURI;
completedTries = 0;
Modified: trunk/freenet/src/freenet/client/BlockInserter.java
===================================================================
--- trunk/freenet/src/freenet/client/BlockInserter.java 2005-11-11 15:55:56 UTC
(rev 7525)
+++ trunk/freenet/src/freenet/client/BlockInserter.java 2005-11-11 17:46:41 UTC
(rev 7526)
@@ -23,9 +23,7 @@
* @param num The block number in the splitfile.
*/
public BlockInserter(Bucket bucket, int num, RetryTracker tracker,
InserterContext ctx, boolean getCHKOnly) {
- super(tracker, num);
- this.data = bucket;
- if(bucket == null) throw new NullPointerException();
+ super(tracker, num, bucket);
succeeded = false;
this.ctx = ctx;
block = new InsertBlock(bucket, null, FreenetURI.EMPTY_CHK_URI);
@@ -33,8 +31,7 @@
}
public synchronized void setData(Bucket data) {
- if(this.data != null) throw new
IllegalArgumentException("Cannot set data when already have data");
- this.data = data;
+ if(this.fetchedData != null) throw new
IllegalArgumentException("Cannot set data when already have data");
}
public void kill() {
Modified: trunk/freenet/src/freenet/client/FECCodec.java
===================================================================
--- trunk/freenet/src/freenet/client/FECCodec.java 2005-11-11 15:55:56 UTC
(rev 7525)
+++ trunk/freenet/src/freenet/client/FECCodec.java 2005-11-11 17:46:41 UTC
(rev 7526)
@@ -49,8 +49,7 @@
if(splitfileType == Metadata.SPLITFILE_NONREDUNDANT)
return null;
if(splitfileType == Metadata.SPLITFILE_ONION_STANDARD) {
- int checkBlocks = dataBlocks;
- checkBlocks += (dataBlocks>>1);
+ int checkBlocks = (dataBlocks>>1);
if((dataBlocks & 1) == 1) checkBlocks++;
return StandardOnionFECCodec.getInstance(dataBlocks,
checkBlocks);
}
@@ -61,6 +60,9 @@
* Decode all missing *data* blocks.
* Requires that the total number of available blocks is equal to or
greater than the length of
* the data blocks array. (i.e. it is > k).
+ * Note that the last data bucket may be returned padded.
+ * This is one reason why it is important to set the data length,
+ * and truncate to it, when using FEC codes.
* @param dataBlockStatus The data blocks.
* @param checkBlockStatus The check blocks.
* @param blockLength The block length in bytes.
Modified: trunk/freenet/src/freenet/client/InsertSegment.java
===================================================================
--- trunk/freenet/src/freenet/client/InsertSegment.java 2005-11-11 15:55:56 UTC
(rev 7525)
+++ trunk/freenet/src/freenet/client/InsertSegment.java 2005-11-11 17:46:41 UTC
(rev 7526)
@@ -4,6 +4,7 @@
import freenet.keys.FreenetURI;
import freenet.support.BucketFactory;
+import freenet.support.Logger;
/**
* Segment of a splitfile, for insertion purposes.
@@ -17,14 +18,20 @@
/** Check blocks. Will be created by encode(...). */
final SplitfileBlock[] checkBlocks;
final boolean getCHKOnly;
+ // just for debugging
+ final int segNo;
- public InsertSegment(short splitfileAlgo, SplitfileBlock[]
origDataBlocks, int blockLength, BucketFactory bf, boolean getCHKOnly) {
+ public InsertSegment(short splitfileAlgo, SplitfileBlock[]
origDataBlocks, int blockLength, BucketFactory bf, boolean getCHKOnly, int
segNo) {
this.origDataBlocks = origDataBlocks;
codec = FECCodec.getCodec(splitfileAlgo, origDataBlocks.length);
checkBlocks = new SplitfileBlock[codec.countCheckBlocks()];
this.blockLength = blockLength;
this.bf = bf;
this.getCHKOnly = getCHKOnly;
+ this.segNo = segNo;
+ // FIXME: remove debugging code
+ for(int i=0;i<origDataBlocks.length;i++)
+ if(origDataBlocks[i].getData() == null) throw new
NullPointerException("Block "+i+" of "+origDataBlocks.length+" data blocks of
seg "+segNo+" is null");
}
/**
@@ -46,6 +53,7 @@
* @throws IOException If the encode fails due to a bucket error.
*/
public int encode(int offset, RetryTracker tracker, InserterContext
ctx) throws IOException {
+ Logger.minor(this, "Encoding "+segNo+":
"+origDataBlocks.length+" into "+checkBlocks.length);
if(codec == null) return 0; // no FEC
for(int i=0;i<checkBlocks.length;i++)
checkBlocks[i] = new BlockInserter(null, offset + i,
tracker, ctx, getCHKOnly);
Modified: trunk/freenet/src/freenet/client/RetryTracker.java
===================================================================
--- trunk/freenet/src/freenet/client/RetryTracker.java 2005-11-11 15:55:56 UTC
(rev 7525)
+++ trunk/freenet/src/freenet/client/RetryTracker.java 2005-11-11 17:46:41 UTC
(rev 7526)
@@ -2,6 +2,7 @@
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.Vector;
import freenet.crypt.RandomSource;
@@ -67,6 +68,7 @@
* even if there are threads running and blocks queued. */
final int targetSuccesses;
final boolean killOnFatalError;
+ private boolean killed;
private boolean finishOnEmpty;
private final RetryTrackerCallback callback;
@@ -159,6 +161,7 @@
* Add a block at retry level zero.
*/
public synchronized void addBlock(SplitfileBlock block) {
+ if(killed) return;
Level l = makeLevel(0);
l.add(block);
maybeStart(true);
@@ -170,6 +173,7 @@
* we have run out of retries.
*/
public synchronized void nonfatalError(SplitfileBlock block, int
reasonCode) {
+ if(killed) return;
nonfatalErrors.inc(reasonCode);
runningBlocks.remove(block);
int levelNumber = block.getRetryCount();
@@ -190,6 +194,7 @@
* @param reasonCode A client-specific code indicating the type of
failure.
*/
public synchronized void fatalError(SplitfileBlock block, int
reasonCode) {
+ if(killed) return;
fatalErrors.inc(reasonCode);
runningBlocks.remove(block);
failedBlocksFatalErrors.add(block);
@@ -201,6 +206,7 @@
* Otherwise if we are finished, call the callback's finish method.
*/
public synchronized void maybeStart(boolean cantCallFinished) {
+ if(killed) return;
Logger.minor(this, "succeeded: "+succeededBlocks.size()+",
target: "+targetSuccesses+
", running: "+runningBlocks.size()+", levels:
"+levels.size()+", finishOnEmpty: "+finishOnEmpty);
if(runningBlocks.size() == 1)
@@ -232,6 +238,7 @@
}
public synchronized void success(SplitfileBlock block) {
+ if(killed) return;
runningBlocks.remove(block);
succeededBlocks.add(block);
maybeStart(false);
@@ -242,6 +249,7 @@
* lowest priority currently available. Move it into the running list.
*/
public synchronized SplitfileBlock getBlock() {
+ if(killed) return null;
Level l = (Level) levels.get(new Integer(curMinLevel));
if(l == null) {
if(!levels.isEmpty()) {
@@ -325,4 +333,14 @@
public FailureCodeTracker getAccumulatedNonFatalErrorCodes() {
return nonfatalErrors;
}
+
+ public synchronized void kill() {
+ killed = true;
+ levels.clear();
+ for(Iterator i=runningBlocks.iterator();i.hasNext();) {
+ SplitfileBlock sb = (SplitfileBlock) i.next();
+ sb.kill();
+ }
+ runningBlocks.clear();
+ }
}
Modified: trunk/freenet/src/freenet/client/SplitInserter.java
===================================================================
--- trunk/freenet/src/freenet/client/SplitInserter.java 2005-11-11 15:55:56 UTC
(rev 7525)
+++ trunk/freenet/src/freenet/client/SplitInserter.java 2005-11-11 17:46:41 UTC
(rev 7526)
@@ -7,6 +7,7 @@
import freenet.keys.NodeCHK;
import freenet.support.Bucket;
import freenet.support.BucketTools;
+import freenet.support.Logger;
import freenet.support.compress.Compressor;
/**
@@ -27,7 +28,6 @@
SplitfileBlock[] origDataBlocks;
InsertSegment encodingSegment;
InsertSegment[] segments;
- final Vector unstartedSegments = new Vector();
private boolean finishedInserting = false;
private boolean getCHKOnly;
private int succeeded;
@@ -66,18 +66,25 @@
* @throws InserterException If we are not able to insert the splitfile.
*/
public FreenetURI run() throws InserterException {
- startInsertingDataBlocks();
- splitIntoSegments(segmentSize);
- // Backwards, because the last is the shortest
try {
- for(int i=segments.length-1;i>=0;i--) {
- countCheckBlocks += encodeSegment(i,
origDataBlocks.length + checkSegmentSize * i);
+ startInsertingDataBlocks();
+ splitIntoSegments(segmentSize);
+ // Backwards, because the last is the shortest
+ try {
+ for(int i=segments.length-1;i>=0;i--) {
+ countCheckBlocks += encodeSegment(i,
origDataBlocks.length + checkSegmentSize * i);
+ Logger.minor(this, "Encoded segment
"+i+" of "+segments.length);
+ }
+ } catch (IOException e) {
+ throw new
InserterException(InserterException.BUCKET_ERROR, e);
}
- } catch (IOException e) {
- throw new
InserterException(InserterException.BUCKET_ERROR);
+ // Wait for the insertion thread to finish
+ return waitForCompletion();
+ } catch (Throwable t) {
+ Logger.error(this, "Caught "+t, t);
+ tracker.kill();
+ throw new
InserterException(InserterException.INTERNAL_ERROR, t.toString());
}
- // Wait for the insertion thread to finish
- return waitForCompletion();
}
private FreenetURI waitForCompletion() throws InserterException {
@@ -190,6 +197,8 @@
origDataBlocks = new SplitfileBlock[dataBuckets.length];
for(int i=0;i<origDataBlocks.length;i++) {
origDataBlocks[i] = new BlockInserter(dataBuckets[i],
i, tracker, ctx, getCHKOnly);
+ if(origDataBlocks[i].getData() == null)
+ throw new NullPointerException("Block "+i+" of
"+dataBuckets.length+" is null");
}
}
@@ -204,21 +213,24 @@
// First split the data up
if(dataBlocks < segmentSize || segmentSize == -1) {
// Single segment
- InsertSegment onlySeg = new
InsertSegment(splitfileAlgorithm, origDataBlocks, blockSize, ctx.bf,
getCHKOnly);
+ InsertSegment onlySeg = new
InsertSegment(splitfileAlgorithm, origDataBlocks, blockSize, ctx.bf,
getCHKOnly, 0);
segs.add(onlySeg);
} else {
int j = 0;
+ int segNo = 0;
for(int i=segmentSize;;i+=segmentSize) {
if(i > dataBlocks) i = dataBlocks;
SplitfileBlock[] seg = new SplitfileBlock[i-j];
System.arraycopy(origDataBlocks, j, seg, 0,
i-j);
- unstartedSegments.add(seg);
j = i;
- segs.add(new InsertSegment(splitfileAlgorithm,
seg, blockSize, ctx.bf, getCHKOnly));
+ for(int x=0;x<seg.length;x++)
+ if(seg[x].getData() == null) throw new
NullPointerException("In splitIntoSegs: "+x+" is null of "+seg.length+" of
"+segNo);
+ segs.add(new InsertSegment(splitfileAlgorithm,
seg, blockSize, ctx.bf, getCHKOnly, segNo));
if(i == dataBlocks) break;
+ segNo++;
}
}
- segments = (InsertSegment[]) unstartedSegments.toArray(new
InsertSegment[unstartedSegments.size()]);
+ segments = (InsertSegment[]) segs.toArray(new
InsertSegment[segs.size()]);
}
public void finished(SplitfileBlock[] succeeded, SplitfileBlock[]
failed, SplitfileBlock[] fatalErrors) {
Modified: trunk/freenet/src/freenet/client/StandardOnionFECCodec.java
===================================================================
--- trunk/freenet/src/freenet/client/StandardOnionFECCodec.java 2005-11-11
15:55:56 UTC (rev 7525)
+++ trunk/freenet/src/freenet/client/StandardOnionFECCodec.java 2005-11-11
17:46:41 UTC (rev 7526)
@@ -4,12 +4,16 @@
import java.io.IOException;
import java.io.OutputStream;
+import org.spaceroots.mantissa.random.MersenneTwister;
+
import com.onionnetworks.fec.DefaultFECCodeFactory;
import com.onionnetworks.fec.FECCode;
+import com.onionnetworks.fec.PureCode;
import com.onionnetworks.util.Buffer;
import freenet.support.Bucket;
import freenet.support.BucketFactory;
+import freenet.support.BucketTools;
import freenet.support.LRUHashtable;
import freenet.support.Logger;
@@ -74,11 +78,13 @@
this.k = k;
this.n = n;
code = DefaultFECCodeFactory.getDefault().createFECCode(k,n);
+ // revert to below if above causes JVM crashes
+ //code = new PureCode(k,n);
}
private static Object runningDecodesSync = new Object();
private static int runningDecodes;
-
+
public void decode(SplitfileBlock[] dataBlockStatus, SplitfileBlock[]
checkBlockStatus, int blockLength, BucketFactory bf) throws IOException {
// Ensure that there are only K simultaneous running decodes.
synchronized(runningDecodesSync) {
@@ -120,6 +126,14 @@
for(int i=0;i<dataBlockStatus.length;i++) {
buckets[i] = dataBlockStatus[i].getData();
+ long sz = buckets[i].size();
+ if(sz < blockLength) {
+ if(i != dataBlockStatus.length-1)
+ throw new IllegalArgumentException("All
buckets except the last must be the full size");
+ if(sz < blockLength)
+ buckets[i] = pad(buckets[i],
blockLength, bf, (int) sz);
+ else throw new IllegalArgumentException("Too
big: "+sz+" bigger than "+blockLength);
+ }
if(buckets[i] == null) {
buckets[i] = bf.makeBucket(blockLength);
writers[i] = buckets[i].getOutputStream();
@@ -174,6 +188,7 @@
if(readers[i] != null) readers[i].close();
}
// Set new buckets only after have a successful decode.
+ // Note that the last data bucket will be overwritten padded.
for(int i=0;i<dataBlockStatus.length;i++) {
dataBlockStatus[i].setData(buckets[i]);
}
@@ -207,6 +222,7 @@
* Do the actual encode.
*/
private void realEncode(SplitfileBlock[] dataBlockStatus,
SplitfileBlock[] checkBlockStatus, int blockLength, BucketFactory bf) throws
IOException {
+ System.err.println("************* Encoding
"+dataBlockStatus.length+" -> "+checkBlockStatus.length+"... *************");
Logger.minor(this, "Doing encode: "+dataBlockStatus.length+"
data blocks, "+checkBlockStatus.length+" check blocks, block length
"+blockLength+" with "+this);
if(dataBlockStatus.length + checkBlockStatus.length != n)
throw new IllegalArgumentException();
@@ -229,18 +245,25 @@
for(int i=0;i<dataBlockStatus.length;i++) {
buckets[i] = dataBlockStatus[i].getData();
+ long sz = buckets[i].size();
+ if(sz < blockLength) {
+ if(i != dataBlockStatus.length-1)
+ throw new IllegalArgumentException("All
buckets except the last must be the full size");
+ if(sz < blockLength)
+ buckets[i] = pad(buckets[i],
blockLength, bf, (int) sz);
+ else throw new IllegalArgumentException("Too
big: "+sz+" bigger than "+blockLength);
+ }
readers[i] = new
DataInputStream(buckets[i].getInputStream());
}
+
for(int i=0;i<checkBlockStatus.length;i++) {
buckets[i+k] = checkBlockStatus[i].getData();
if(buckets[i+k] == null) {
buckets[i+k] = bf.makeBucket(blockLength);
- writers[i+k] = buckets[i+k].getOutputStream();
- readers[i+k] = null;
+ writers[i] = buckets[i+k].getOutputStream();
toEncode[numberToEncode++] = i+k;
} else {
- writers[i+k] = null;
- readers[i+k] = new
DataInputStream(buckets[i+k].getInputStream());
+ writers[i] = null;
}
}
@@ -248,7 +271,7 @@
// Do the (striped) decode
for(int
offset=0;offset<blockLength;offset+=STRIPE_SIZE) {
// Read the data in first
- for(int i=0;i<n;i++) {
+ for(int i=0;i<k;i++) {
readers[i].readFully(realBuffer,
i*STRIPE_SIZE, STRIPE_SIZE);
}
// Do the encode
@@ -257,8 +280,8 @@
// packets now contains an array of decoded
blocks, in order
// Write the data out
for(int i=k;i<n;i++) {
- if(writers[i] != null)
- writers[i].write(realBuffer,
i*STRIPE_SIZE, STRIPE_SIZE);
+ if(writers[i-k] != null)
+ writers[i-k].write(realBuffer,
i*STRIPE_SIZE, STRIPE_SIZE);
}
}
}
@@ -270,8 +293,29 @@
for(int i=0;i<checkBlockStatus.length;i++) {
checkBlockStatus[i].setData(buckets[i+k]);
}
+ System.err.println("************* Encoded
"+dataBlockStatus.length+" -> "+checkBlockStatus.length+"... *************");
}
+ private Bucket pad(Bucket oldData, int blockLength, BucketFactory bf,
int l) throws IOException {
+ // FIXME move somewhere else?
+ byte[] hash = BucketTools.hash(oldData);
+ Bucket b = bf.makeBucket(blockLength);
+ MersenneTwister mt = new MersenneTwister(hash);
+ OutputStream os = b.getOutputStream();
+ BucketTools.copyTo(oldData, os, l);
+ byte[] buf = new byte[4096];
+ for(int x=l;x<blockLength;) {
+ int remaining = blockLength - x;
+ int thisCycle = Math.min(remaining, buf.length);
+ mt.nextBytes(buf); // FIXME??
+ os.write(buf, 0, thisCycle);
+ }
+ os.close();
+ if(b.size() != blockLength)
+ throw new IllegalStateException();
+ return b;
+ }
+
public int countCheckBlocks() {
return n-k;
}
Modified: trunk/freenet/src/freenet/client/StdSplitfileBlock.java
===================================================================
--- trunk/freenet/src/freenet/client/StdSplitfileBlock.java 2005-11-11
15:55:56 UTC (rev 7525)
+++ trunk/freenet/src/freenet/client/StdSplitfileBlock.java 2005-11-11
17:46:41 UTC (rev 7526)
@@ -9,12 +9,12 @@
protected final RetryTracker tracker;
/** Splitfile index - [0,k[ is the data blocks, [k,n[ is the check
blocks */
protected final int index;
- protected Bucket data;
- public StdSplitfileBlock(RetryTracker tracker2, int index2) {
+ public StdSplitfileBlock(RetryTracker tracker2, int index2, Bucket
data) {
if(tracker2 == null) throw new NullPointerException();
this.tracker = tracker2;
this.index = index2;
+ this.fetchedData = data;
}
public int getNumber() {
Modified: trunk/freenet/src/freenet/keys/ClientCHKBlock.java
===================================================================
--- trunk/freenet/src/freenet/keys/ClientCHKBlock.java 2005-11-11 15:55:56 UTC
(rev 7525)
+++ trunk/freenet/src/freenet/keys/ClientCHKBlock.java 2005-11-11 17:46:41 UTC
(rev 7526)
@@ -156,16 +156,7 @@
if(finalData.length != 0)
md256.update(finalData);
byte[] digest = md256.digest();
- // Turn digest into a seed array for the MT
- int[] seed = new int[8]; // 32/4=8
- for(int i=0;i<8;i++) {
- int x = digest[i*4] & 0xff;
- x = (x << 8) + (digest[i*4+1] & 0xff);
- x = (x << 8) + (digest[i*4+2] & 0xff);
- x = (x << 8) + (digest[i*4+3] & 0xff);
- seed[i] = x;
- }
- MersenneTwister mt = new MersenneTwister(seed);
+ MersenneTwister mt = new MersenneTwister(digest);
data = new byte[32768];
System.arraycopy(finalData, 0, data, 0, finalData.length);
byte[] randomBytes = new byte[32768-finalData.length];
Modified: trunk/freenet/src/freenet/node/TextModeClientInterface.java
===================================================================
--- trunk/freenet/src/freenet/node/TextModeClientInterface.java 2005-11-11
15:55:56 UTC (rev 7525)
+++ trunk/freenet/src/freenet/node/TextModeClientInterface.java 2005-11-11
17:46:41 UTC (rev 7526)
@@ -253,9 +253,9 @@
} catch (FileNotFoundException e1) {
System.out.println("File not found");
} catch (InserterException e) {
- System.out.println(e.getMessage());
+ System.out.println("Finished insert but: "+e.getMessage());
} catch (Throwable t) {
- System.out.println("Threw: "+t);
+ System.out.println("Insert threw: "+t);
t.printStackTrace();
}
} else if(uline.startsWith("STATUS")) {
Modified: trunk/freenet/src/freenet/node/Version.java
===================================================================
--- trunk/freenet/src/freenet/node/Version.java 2005-11-11 15:55:56 UTC (rev
7525)
+++ trunk/freenet/src/freenet/node/Version.java 2005-11-11 17:46:41 UTC (rev
7526)
@@ -20,10 +20,10 @@
public static final String protocolVersion = "1.0";
/** The build number of the current revision */
- public static final int buildNumber = 161;
+ public static final int buildNumber = 162;
/** Oldest build of Fred we will talk to */
- public static final int lastGoodBuild = 159;
+ public static final int lastGoodBuild = 162;
/** The highest reported build of fred */
public static int highestSeenBuild = buildNumber;
Modified: trunk/freenet/src/freenet/support/Fields.java
===================================================================
--- trunk/freenet/src/freenet/support/Fields.java 2005-11-11 15:55:56 UTC
(rev 7525)
+++ trunk/freenet/src/freenet/support/Fields.java 2005-11-11 17:46:41 UTC
(rev 7526)
@@ -488,6 +488,19 @@
return x;
}
+ /**
+ * Convert an array of bytes to a single int.
+ */
+ public static int bytesToInt(byte[] buf, int offset) {
+ if(buf.length < 4) throw new IllegalArgumentException();
+ int x = 0;
+ for(int j=3;j>=0;j--) {
+ int y = (buf[j+offset] & 0xff);
+ x = (x << 8) + y;
+ }
+ return x;
+ }
+
public static byte[] longToBytes(long x) {
byte[] buf = new byte[8];
for(int j=0;j<8;j++) {
@@ -496,4 +509,5 @@
}
return buf;
}
+
}
Modified: trunk/freenet/src/org/spaceroots/mantissa/random/MersenneTwister.java
===================================================================
--- trunk/freenet/src/org/spaceroots/mantissa/random/MersenneTwister.java
2005-11-11 15:55:56 UTC (rev 7525)
+++ trunk/freenet/src/org/spaceroots/mantissa/random/MersenneTwister.java
2005-11-11 17:46:41 UTC (rev 7526)
@@ -2,6 +2,8 @@
import java.util.Random;
+import freenet.support.Fields;
+
/** This class implements a powerful pseudo-random number generator
* developed by Makoto Matsumoto and Takuji Nishimura during
* 1996-1997.
@@ -97,6 +99,12 @@
setSeed(seed);
}
+ /** Seed from byte[] */
+ public MersenneTwister(byte[] seed) {
+ mt = new int[N];
+ setSeed(seed);
+ }
+
/** Creates a new random number generator using a single long seed.
* @param seed the initial seed (64 bits integer)
*/
@@ -122,6 +130,17 @@
}
}
+ /**
+ * Seed from byte[].
+ */
+ public void setSeed(byte[] seed) {
+ int[] seeds = new int[seed.length/4];
+ for(int i=0;i<seeds.length;i+=4) {
+ seeds[i] = Fields.bytesToInt(seed, i);
+ }
+ setSeed(seeds);
+ }
+
/** Reinitialize the generator as if just built with the given int array
seed.
* <p>The state of the generator is exactly the same as a new
* generator built with the same seed.</p>