diff options
author | Rich Hickey <richhickey@gmail.com> | 2007-08-01 15:27:02 +0000 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2007-08-01 15:27:02 +0000 |
commit | 3fb1ffaceed047e58d219065deed567930ebeb15 (patch) | |
tree | f5c49ce909f72e4bfcd1b840f8b70db42d8b6dd2 | |
parent | 5b0755d04339f1724a9b88c9fb6ee0c751eb80b6 (diff) |
first cut at stateful, transactional collection built on Ref + persistent collection
-rw-r--r-- | src/jvm/clojure/lang/TransactionalHashMap.java | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/src/jvm/clojure/lang/TransactionalHashMap.java b/src/jvm/clojure/lang/TransactionalHashMap.java new file mode 100644 index 00000000..c8486947 --- /dev/null +++ b/src/jvm/clojure/lang/TransactionalHashMap.java @@ -0,0 +1,254 @@ +/** + * Copyright (c) Rich Hickey. All rights reserved. + * The use and distribution terms for this software are covered by the + * Common Public License 1.0 (http://opensource.org/licenses/cpl.php) + * which can be found in the file CPL.TXT at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +/* rich Jul 31, 2007 */ + +package clojure.lang; + +import java.util.*; +import java.util.concurrent.CyclicBarrier; + +public class TransactionalHashMap<K, V> extends AbstractMap<K, V>{ +final Ref mapref; + +public TransactionalHashMap(){ + mapref = new Ref(PersistentHashMap.EMPTY); +} + +public TransactionalHashMap(Map<? extends K, ? extends V> m){ + IPersistentMap map = PersistentHashMap.EMPTY; + for(Entry<? extends K, ? extends V> e : m.entrySet()) + { + map = map.assoc(e.getKey(), e.getValue()); + } + mapref = new Ref(map); +} + +public void commute(final K key, final IFn fn) throws Exception{ + mapref.commute( + new AFn(){ + public Object invoke(Object arg1) throws Exception{ + IPersistentMap map = (IPersistentMap) arg1; + V val = (V) map.valAt(key); + return map.assoc(key, fn.invoke(val)); + } + } + ); +} + +public void commutePut(final K key, final V value){ + try + { + mapref.commute( + new AFn(){ + public Object invoke(Object arg1) throws Exception{ + IPersistentMap map = (IPersistentMap) arg1; + return map.assoc(key, value); + } + } + ); + } + catch(Exception e) + { + throw new RuntimeException(e); + } +} + +public void commuteRemove(final Object key){ + try + { + mapref.commute( + new AFn(){ + + public Object invoke(Object arg1) throws Exception{ + IPersistentMap map = (IPersistentMap) arg1; + return map.without(key); + } + + public Obj withMeta(IPersistentMap meta){ + throw new UnsupportedOperationException(); + } + } + ); + } + catch(Exception e) + { + throw new RuntimeException(e); + } +} + +public void clear(){ + mapref.set(PersistentHashMap.EMPTY); +} + +public boolean containsKey(Object key){ + return persistentMap().contains(key); +} + +public V get(Object key){ + return (V) persistentMap().valAt(key); +} + +public boolean isEmpty(){ + return persistentMap().count() == 0; +} + +public V put(K key, V value){ + V ret = (V) persistentMap().valAt(key); + mapref.set(persistentMap().assoc(key, value)); + return ret; +} + +public V remove(Object key){ + V ret = (V) persistentMap().valAt(key); + mapref.set(persistentMap().without(key)); + return ret; +} + +public int size(){ + return persistentMap().count(); +} + +public IPersistentMap persistentMap(){ + return (IPersistentMap) mapref.get(); +} + +public Set<Entry<K, V>> entrySet(){ + return new AbstractSet<Entry<K, V>>(){ + + public Iterator<Entry<K, V>> iterator(){ + return new Iterator<Entry<K, V>>(){ + + ISeq seq = persistentMap().seq(); + Entry<K, V> last = null; + + public boolean hasNext(){ + return seq != null; + } + + public Entry<K, V> next(){ + final IMapEntry e = (IMapEntry) seq.first(); + last = + new Entry<K, V>(){ + + public K getKey(){ + return (K) e.key(); + } + + public V getValue(){ + return (V) e.val(); + } + + public V setValue(V value){ + return put(getKey(), value); + } + + }; + seq = seq.rest(); + return last; + } + + public void remove(){ + mapref.set(persistentMap().without(last.getKey())); + } + }; + } + + public int size(){ + return persistentMap().count(); + } + }; +} + +public static void main(String[] args){ + try + { + if(args.length != 1) + System.err.println("Usage: TransactionalHashMap n"); + final int n = Integer.parseInt(args[0]); + final int[] xs = {3, 5, 7}; + final TransactionalHashMap<Integer, Integer>[] maps = new TransactionalHashMap[]{ + new TransactionalHashMap<Integer, Integer>(), + new TransactionalHashMap<Integer, Integer>(), + new TransactionalHashMap<Integer, Integer>()}; + + LockingTransaction.runInTransaction(new AFn(){ + public Object invoke() throws Exception{ + for(int i = 0; i < n; i++) + for(TransactionalHashMap<Integer, Integer> map : maps) + map.put(i, i); + return null; + } + }); + + + final CyclicBarrier barrier = new CyclicBarrier(xs.length + 1); + + for(int x : xs) + { + final int t = x; + new Thread(new Runnable(){ + public void run(){ + try + { + System.err.println("Waiting to start"); + barrier.await(); + LockingTransaction.runInTransaction(new AFn(){ + public Object invoke() throws Exception{ + for(TransactionalHashMap<Integer, Integer> map : maps) + { + Iterator<Entry<Integer, Integer>> iter = + map.entrySet().iterator(); + while(iter.hasNext()) + { + Entry<Integer, Integer> e = iter.next(); + if(e.getKey() % t == 0) + iter.remove(); + else + e.setValue(e.getValue() * t); + } + System.out.printf("%s\n", map); + } + return null; + } + }); + System.err.println("Waiting to finish"); + barrier.await(); + } + catch(Exception e) + { + throw new RuntimeException(e); + } + } + } + ).start(); + } + System.err.println("Waiting to start"); + barrier.await(); + System.err.println("Waiting to finish"); + barrier.await(); + +// LockingTransaction.runInTransaction(new AFn(){ +// public Object invoke() throws Exception{ +// for(TransactionalHashMap<Integer, Integer> map : maps) +// { +// System.out.printf("%s\n", map); +// } +// return null; +// } +// }); + } + catch(Exception e) + { + e.printStackTrace(); + } +} + +} |