package peergos.server.tests.slow; import org.junit.*; import org.junit.runner.*; import org.junit.runners.*; import peergos.server.*; import peergos.server.corenode.*; import peergos.server.storage.*; import peergos.shared.*; import peergos.shared.corenode.*; import peergos.shared.crypto.*; import peergos.shared.storage.*; import peergos.shared.user.*; import peergos.shared.user.fs.*; import peergos.shared.util.*; import java.lang.reflect.*; import java.net.*; import java.util.*; import java.util.stream.*; @RunWith(Parameterized.class) public class MkdirSpeed { private static int RANDOM_SEED = 666; private final NetworkAccess network; private final Crypto crypto = Crypto.initJava(); private static Random random = new Random(RANDOM_SEED); public MkdirSpeed(boolean useHttp, String useIPFS, Random r) throws Exception { this.network = ! useHttp ? buildInProcessAccess(r) : buildHttpNetworkAccess(useIPFS.equals("IPFS"), r); // use insecure random otherwise tests take ages setFinalStatic(TweetNaCl.class.getDeclaredField("prng"), new Random(1)); } private static NetworkAccess buildInProcessAccess(Random r) throws Exception { JDBCCoreNode core = SQLiteCoreNode.build(":memory:"); ContentAddressedStorage dht = new RAMStorage(); Btree btree = new BtreeImpl(core, dht); return new NetworkAccess(core, dht, core, btree, Collections.emptyList()); } private static NetworkAccess buildHttpNetworkAccess(boolean useIpfs, Random r) throws Exception { int portMin = 9000; int portRange = 2000; int webPort = portMin + r.nextInt(portRange); int corePort = portMin + portRange + r.nextInt(portRange); Args args = Args.parse(new String[]{"useIPFS", "" + useIpfs, "-port", Integer.toString(webPort), "-corenodePort", Integer.toString(corePort)}); Start.local(args); return NetworkAccess.buildJava(new URL("http://localhost:" + webPort)).get(); } @Parameterized.Parameters() public static Collection<Object[]> parameters() { return Arrays.asList(new Object[][] { // {true, "IPFS", new Random(0)} {true, "NOTIPFS", new Random(0)} // {false, "IPFS", new Random(0)} }); } static void setFinalStatic(Field field, Object newValue) throws Exception { field.setAccessible(true); Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); field.set(null, newValue); } private String generateUsername() { return "test" + (random.nextInt() % 10000); } public static UserContext ensureSignedUp(String username, String password, NetworkAccess network, Crypto crypto) throws Exception { return UserContext.ensureSignedUp(username, password, network, crypto).get(); } // (0 - 100 mkdirs) // All ram, not http => 40 - 54 ms // All ram, http => 400 - 416 ms // IPFS, http => 660 - 840 ms @Test public void hugeFolder() throws Exception { String username = generateUsername(); String password = "test01"; UserContext context = ensureSignedUp(username, password, network, crypto); FileTreeNode userRoot = context.getUserRoot().get(); List<String> names = new ArrayList<>(); IntStream.range(0, 100).forEach(i -> names.add(randomString())); long worst = 0, best = Long.MAX_VALUE, start = System.currentTimeMillis(); for (int i=0; i < names.size(); i++) { String filename = names.get(i); long t1 = System.currentTimeMillis(); userRoot.mkdir(filename, context.network, false, context.crypto.random).get(); long duration = System.currentTimeMillis() - t1; worst = Math.max(worst, duration); best = Math.min(best, duration); System.err.printf("MKDIR(%d) duration: %d mS, best: %d mS, worst: %d mS, av: %d mS\n", i, duration, best, worst, (t1 + duration - start) / (i + 1)); } } private static String randomString() { return UUID.randomUUID().toString(); } }