package freenet.node.simulator;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import freenet.client.ClientMetadata;
import freenet.client.FetchException;
import freenet.client.FetchException.FetchExceptionMode;
import freenet.client.HighLevelSimpleClient;
import freenet.client.InsertBlock;
import freenet.client.InsertException;
import freenet.crypt.RandomSource;
import freenet.keys.FreenetURI;
import freenet.node.Node;
import freenet.node.NodeStarter;
import freenet.node.Version;
import freenet.support.Logger;
import freenet.support.Logger.LogLevel;
import freenet.support.PooledExecutor;
import freenet.support.api.RandomAccessBucket;
import freenet.support.io.FileUtil;
/**
* Push / Pull test over long period of time
*
* Pushes N CHK's and records both their insert time and their CHKs.
*
* Pulls CHK's for (2^n)-1 days ago, from 0 to 8, but obviously only if
* there is a CHK for the given date in the log.
*/
public class LongTermPushPullCHKTest extends LongTermTest {
private static final int TEST_SIZE = 64 * 1024;
private static final int EXIT_NO_SEEDNODES = 257;
private static final int EXIT_FAILED_TARGET = 258;
private static final int EXIT_THREW_SOMETHING = 261;
private static final int DARKNET_PORT1 = 5010;
private static final int OPENNET_PORT1 = 5011;
private static final int DARKNET_PORT2 = 5012;
private static final int OPENNET_PORT2 = 5013;
private static final int MAX_N = 8;
public static void main(String[] args) {
if (args.length != 1) {
System.err.println("Usage: java freenet.node.simulator.LongTermPushPullTest <unique identifier>");
System.exit(1);
}
String uid = args[0];
List<String> csvLine = new ArrayList<String>(3 + 2 * MAX_N);
System.out.println("DATE:" + dateFormat.format(today.getTime()));
csvLine.add(dateFormat.format(today.getTime()));
System.out.println("Version:" + Version.buildNumber());
csvLine.add(String.valueOf(Version.buildNumber()));
int exitCode = 0;
Node node = null;
Node node2 = null;
try {
final File dir = new File("longterm-push-pull-test-" + uid);
FileUtil.removeAll(dir);
RandomSource random = NodeStarter.globalTestInit(dir.getPath(), false, LogLevel.ERROR, "", false);
File seednodes = new File("seednodes.fref");
if (!seednodes.exists() || seednodes.length() == 0 || !seednodes.canRead()) {
System.err.println("Unable to read seednodes.fref, it doesn't exist, or is empty");
System.exit(EXIT_NO_SEEDNODES);
}
final File innerDir = new File(dir, Integer.toString(DARKNET_PORT1));
innerDir.mkdir();
FileInputStream fis = new FileInputStream(seednodes);
FileUtil.writeTo(fis, new File(innerDir, "seednodes.fref"));
fis.close();
// Create one node
node = NodeStarter.createTestNode(DARKNET_PORT1, OPENNET_PORT1, dir.getPath(), false, Node.DEFAULT_MAX_HTL,
0, random, new PooledExecutor(), 1000, 4 * 1024 * 1024, true, true, true, true, true, true, true,
12 * 1024, true, true, false, false, null);
Logger.getChain().setThreshold(LogLevel.ERROR);
// Start it
node.start(true);
long t1 = System.currentTimeMillis();
if (!TestUtil.waitForNodes(node)) {
exitCode = EXIT_FAILED_TARGET;
return;
}
long t2 = System.currentTimeMillis();
System.out.println("SEED-TIME:" + (t2 - t1));
csvLine.add(String.valueOf(t2 - t1));
FreenetURI todaysInsert = null;
// PUSH N+1 BLOCKS
for (int i = 0; i <= MAX_N; i++) {
RandomAccessBucket data = randomData(node);
HighLevelSimpleClient client = node.clientCore.makeClient((short) 0, false, false);
System.out.println("PUSHING " + i);
try {
InsertBlock block = new InsertBlock(data, new ClientMetadata(), FreenetURI.EMPTY_CHK_URI);
t1 = System.currentTimeMillis();
FreenetURI uri = client.insert(block, false, null);
if(i == 0) todaysInsert = uri;
t2 = System.currentTimeMillis();
System.out.println("PUSH-TIME-" + i + ":" + (t2 - t1)+" for "+uri);
csvLine.add(String.valueOf(t2 - t1));
csvLine.add(uri.toASCIIString());
} catch (InsertException e) {
e.printStackTrace();
csvLine.add("N/A");
csvLine.add("N/A");
}
data.free();
}
node.park();
// Node 2
File innerDir2 = new File(dir, Integer.toString(DARKNET_PORT2));
innerDir2.mkdir();
fis = new FileInputStream(seednodes);
FileUtil.writeTo(fis, new File(innerDir2, "seednodes.fref"));
fis.close();
node2 = NodeStarter.createTestNode(DARKNET_PORT2, OPENNET_PORT2, dir.getPath(), false,
Node.DEFAULT_MAX_HTL, 0, random, new PooledExecutor(), 1000, 5 * 1024 * 1024, true, true, true,
true, true, true, true, 12 * 1024, false, true, false, false, null);
node2.start(true);
t1 = System.currentTimeMillis();
if (!TestUtil.waitForNodes(node2)) {
exitCode = EXIT_FAILED_TARGET;
return;
}
t2 = System.currentTimeMillis();
System.out.println("SEED-TIME:" + (t2 - t1));
csvLine.add(String.valueOf(t2 - t1));
// PULL N+1 BLOCKS
for (int i = 0; i <= MAX_N; i++) {
HighLevelSimpleClient client = node2.clientCore.makeClient((short) 0, false, false);
Calendar targetDate = (Calendar) today.clone();
targetDate.add(Calendar.DAY_OF_MONTH, -((1 << i) - 1));
FreenetURI uri = null;
if(i == 0) uri = todaysInsert;
else {
uri = getHistoricURI(uid, i, targetDate);
}
if(uri == null) {
System.out.println("SKIPPING PULL FOR "+i);
continue;
}
System.out.println("PULLING " + uri);
try {
t1 = System.currentTimeMillis();
client.fetch(uri);
t2 = System.currentTimeMillis();
System.out.println("PULL-TIME-" + i + ":" + (t2 - t1));
csvLine.add(String.valueOf(t2 - t1));
} catch (FetchException e) {
if (e.getMode() != FetchExceptionMode.ALL_DATA_NOT_FOUND
&& e.getMode() != FetchExceptionMode.DATA_NOT_FOUND)
e.printStackTrace();
csvLine.add(FetchException.getShortMessage(e.getMode()));
}
}
} catch (Throwable t) {
t.printStackTrace();
exitCode = EXIT_THREW_SOMETHING;
} finally {
try {
if (node != null)
node.park();
} catch (Throwable t1) {
}
try {
if (node2 != null)
node2.park();
} catch (Throwable t1) {
}
File file = new File(uid + ".csv");
writeToStatusLog(file, csvLine);
System.exit(exitCode);
}
}
private static FreenetURI getHistoricURI(String uid, int i, Calendar targetDate) throws IOException {
// Quick and dirty, since we only have 1...8 it's not worth caching it.
File file = new File(uid + ".csv");
FileInputStream fis = new FileInputStream(file);
try {
InputStreamReader isr = new InputStreamReader(fis, ENCODING);
BufferedReader br = new BufferedReader(isr);
String line = null;
String dateString = dateFormat.format(targetDate.getTime());
while((line = br.readLine()) != null) {
String[] split = line.split("!");
if(split.length == 0) continue;
if(!dateString.equals(split[0])) continue;
int fieldnum = 3 + i * 2;
if(line.length() >= fieldnum) continue; // Possible ran twice???
return new FreenetURI(split[fieldnum]);
}
return null;
} finally {
fis.close();
}
}
private static RandomAccessBucket randomData(Node node) throws IOException {
RandomAccessBucket data = node.clientCore.tempBucketFactory.makeBucket(TEST_SIZE);
OutputStream os = data.getOutputStream();
try {
byte[] buf = new byte[4096];
for (long written = 0; written < TEST_SIZE;) {
node.fastWeakRandom.nextBytes(buf);
int toWrite = (int) Math.min(TEST_SIZE - written, buf.length);
os.write(buf, 0, toWrite);
written += toWrite;
}
} finally {
os.close();
}
return data;
}
}