/**
* This file is part of ObjectFabric (http://objectfabric.org).
*
* ObjectFabric is licensed under the Apache License, Version 2.0, the terms
* of which may be found at http://www.apache.org/licenses/LICENSE-2.0.html.
*
* Copyright ObjectFabric Inc.
*
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
* WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
package org.objectfabric;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.objectfabric.TObject.Version;
import org.objectfabric.Workspace.Granularity;
@Ignore
public class SplitRemote {
private int todo;
/**
* If small number, there might be no conflict between threads so use <= instead of <
* when asserting 'successes'.
*/
public static final int DEFAULT_WRITE_COUNT = (int) 1e3;
private volatile TMap<String, String> _map;
private final HashMap<String, Integer> _last = new HashMap<String, Integer>();
private final AtomicInteger _changeCallbackLast = new AtomicInteger();
static {
JVMPlatform.loadClass();
}
protected AtomicInteger getChangeCallbackLast() {
return _changeCallbackLast;
}
@Test
public void run1() {
run(1, DEFAULT_WRITE_COUNT, Granularity.COALESCE);
}
@Test
public void run2() {
run(2, DEFAULT_WRITE_COUNT, Granularity.COALESCE);
}
@Test
public void run3() {
run(2, DEFAULT_WRITE_COUNT, Granularity.ALL);
}
void run(final int threadCount, final int writeCount, final Granularity granularity) {
if (Stats.ENABLED)
Stats.Instance.reset();
Workspace workspace = Platform.get().newTestWorkspace(granularity);
_map = new TMap<String, String>(workspace.open(""));
TestNotifier notifier = new TestNotifier(workspace);
workspace.forceChangeNotifier(notifier);
_map.addListener(new KeyListener<String>() {
@Override
public void onPut(String key) {
String[] parts = key.split(":");
String client = parts[0];
boolean remote = "remote".equals(parts[1]);
int counter = Integer.parseInt(parts[2]);
Assert.assertFalse(remote);
int last = _last.get(client);
Assert.assertTrue(counter == last || counter == last + 1);
_last.put(client, counter);
}
@Override
public void onRemove(String key) {
}
@Override
public void onClear() {
}
});
Log.write("");
Log.write("Starting " + threadCount + " threads, " + writeCount + " writes, listener: " + granularity);
ArrayList<SplitRemoteClient> threads = new ArrayList<SplitRemoteClient>();
CyclicBarrier barrier = new CyclicBarrier(threadCount + 1);
for (int i = 0; i < threadCount; i++) {
_last.put("" + i, 0);
SplitRemoteClient client = new SplitRemoteClient(_map, i, writeCount, barrier);
threads.add(client);
client.start();
}
try {
barrier.await();
} catch (Exception e) {
throw new RuntimeException(e);
}
long start = System.nanoTime();
for (Thread thread : threads) {
try {
thread.join();
} catch (java.lang.InterruptedException e) {
}
}
long time = System.nanoTime() - start;
workspace.flushNotifications();
for (int i = 0; i < threadCount; i++)
Assert.assertEquals((int) _last.get("" + i), threads.get(i)._counter);
double writePerSec = (threads.size() * writeCount) * 1e9 / time;
System.out.println((int) writePerSec + " writes/s");
_last.clear();
workspace.close();
}
static final class TestNotifier extends Notifier {
HashSet<String> _keys = new HashSet<String>();
TestNotifier(Workspace workspace) {
super(workspace);
}
@Override
Action onVisitingMap(int mapIndex) {
Action action = super.onVisitingMap(mapIndex);
if (snapshot().getVersionMaps()[mapIndex].isRemote())
action = Action.SKIP;
return action;
}
@Override
void onVisitingVersion(Version version) {
super.onVisitingVersion(version);
TKeyedVersion keys = (TKeyedVersion) version;
for (int i = 0; i < keys.getEntries().length; i++) {
if (keys.getEntries()[i] != null)
_keys.add((String) keys.getEntries()[i].getKey());
}
}
}
}