package jelectrum;
import java.util.Map;
import java.util.Set;
import java.util.Collection;
import java.util.HashMap;
public class BandingMap<K,V> implements Map<K, V>
{
private Map<K, V> inner;
private long gatherWaitMs;
private Map<K, V> waiting_map;
private SimpleFuture<V> future;
private Object magic_lock;
public BandingMap(Map<K,V> inner, long gatherWaitMs)
{
this.inner = inner;
this.gatherWaitMs = gatherWaitMs;
magic_lock = new Object();
waiting_map = new HashMap<K, V>(1024, 0.5f);
new BandThread().start();
}
public void clear()
{
inner.clear();
}
public boolean containsKey(Object key)
{
return inner.containsKey(key);
}
public boolean containsValue(Object value)
{
return inner.containsValue(value);
}
public Set<Map.Entry<K,V>> entrySet()
{
return inner.entrySet();
}
public boolean equals(Object o)
{
return inner.equals(o);
}
public V get(Object key)
{
return inner.get(key);
}
public int hashCode()
{
return inner.hashCode();
}
public boolean isEmpty()
{
return inner.isEmpty();
}
public int size()
{
return inner.size();
}
public Set<K> keySet()
{
return inner.keySet();
}
public V put(K key, V value)
{
SimpleFuture<V> f = null;
synchronized(magic_lock)
{
if (future != null)
{
waiting_map.put(key, value);
f = future;
}
magic_lock.notifyAll();
}
if (f != null) return f.get();
return inner.put(key,value);
}
public void putAll(Map<? extends K,? extends V> m)
{
inner.putAll(m);
}
public V remove(Object key)
{
return inner.remove(key);
}
public Collection<V> values()
{
return inner.values();
}
public class BandThread extends Thread
{
public BandThread()
{
setDaemon(true);
setName("Bandthread");
}
public void run()
{
while(true)
{
doRun();
}
}
private void doRun()
{
SimpleFuture<V> f = new SimpleFuture<V>();
try
{
synchronized(magic_lock)
{
future = f;
magic_lock.wait();
}
sleep(gatherWaitMs);
synchronized(magic_lock)
{
future = null;
}
//System.out.println("Banding: " + waiting_map.size());
inner.putAll(waiting_map);
f.setResult(null);
waiting_map.clear();
}
catch(Throwable t)
{
if (t instanceof RuntimeException)
{
f.setException((RuntimeException)t);
}
else
{
f.setException(new RuntimeException(t));
}
}
}
}
}