package jelectrum; import java.util.Map; import java.util.Set; import java.util.Collection; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ByteArrayOutputStream; import java.io.ByteArrayInputStream; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Random; import java.text.DecimalFormat; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.io.IOException; public class SqlMap<K,V> implements Map<K, V> { private String table_name; private static StatData put_stats = new StatData(); private static StatData get_stats = new StatData(); public SqlMap(String table_name, int max_key_len) { this.table_name = table_name; createTable(max_key_len); } public void createTable(int max_key_len) { Connection conn = null; try { conn = DB.openConnection("jelectrum_db"); PreparedStatement ps = conn.prepareStatement("create table "+table_name+" ( key char("+max_key_len+") PRIMARY KEY, data BYTEA)"); ps.execute(); ps.close(); } catch(SQLException e) { } finally { DB.safeClose(conn); } } public void clear() { while(true) { try { tryClear(); return; } catch(SQLException e) { e.printStackTrace(); try{Thread.sleep(1000);}catch(Exception e2){} } } } private void tryClear() throws SQLException { Connection conn = null; try { conn = DB.openConnection("jelectrum_db"); PreparedStatement ps = conn.prepareStatement("delete from "+table_name); ps.execute(); ps.close(); } finally { DB.safeClose(conn); } } public boolean containsKey(Object key) { while(true) { try { return tryContainsKey(key); } catch(SQLException e) { e.printStackTrace(); try{Thread.sleep(1000);}catch(Exception e2){} } } } private boolean tryContainsKey(Object key) throws SQLException { long t1 = System.currentTimeMillis(); boolean c = false; Connection conn = null; try { conn = DB.openConnection("jelectrum_db"); PreparedStatement ps = conn.prepareStatement("select count(key) as count from "+table_name+" where key=?"); ps.setString(1, key.toString()); ResultSet rs = ps.executeQuery(); rs.next(); int count = rs.getInt("count"); if (count > 0) c = true; rs.close(); ps.close(); } finally { DB.safeClose(conn); } long t2 = System.currentTimeMillis(); get_stats.addDataPoint(t2-t1); return c; } public boolean containsValue(Object value) { throw new RuntimeException("not implemented - is stupid"); } public Set<Map.Entry<K,V>> entrySet() { throw new RuntimeException("not implemented - is stupid"); } public boolean equals(Object o) { throw new RuntimeException("not implemented - is stupid"); } public V get(Object key) { while(true) { try { return tryGet(key); } catch(SQLException e) { e.printStackTrace(); try{Thread.sleep(1000);}catch(Exception e2){} } catch(IOException e) { throw new RuntimeException(e); } catch(ClassNotFoundException e) { throw new RuntimeException(e); } } } private V tryGet(Object key) throws SQLException, IOException, ClassNotFoundException { long t1 = System.currentTimeMillis(); V ret = null; byte[] data = null; Connection conn = null; try { conn = DB.openConnection("jelectrum_db"); PreparedStatement ps = conn.prepareStatement("select * from "+table_name+" where key=?"); ps.setString(1, key.toString()); ResultSet rs = ps.executeQuery(); if (rs.next()) { data = rs.getBytes("data"); } rs.close(); ps.close(); } finally { DB.safeClose(conn); } long t2 = System.currentTimeMillis(); if (data != null) { ret = (V) (new ObjectInputStream(new ByteArrayInputStream(data)).readObject()); } return ret; } public int hashCode() { throw new RuntimeException("not implemented - is stupid"); } public boolean isEmpty() { return (size()==0); } public int size() { while(true) { try { return trySize(); } catch(SQLException e) { e.printStackTrace(); try{Thread.sleep(1000);}catch(Exception e2){} } } } private int trySize() throws SQLException { long t1 = System.currentTimeMillis(); int count = 0; Connection conn = null; try { conn = DB.openConnection("jelectrum_db"); PreparedStatement ps = conn.prepareStatement("select count(key) as count from "+table_name); ResultSet rs = ps.executeQuery(); rs.next(); count = rs.getInt("count"); rs.close(); ps.close(); } finally { DB.safeClose(conn); } long t2 = System.currentTimeMillis(); get_stats.addDataPoint(t2-t1); return count; } public Set<K> keySet() { throw new RuntimeException("not implemented - is stupid"); } public V put(K key, V value) { while(true) { try { return tryPut(key,value,null); } catch(SQLException e) { e.printStackTrace(); try{Thread.sleep(1000);}catch(Exception e2){} } catch(IOException e) { throw new RuntimeException(e); } } } public V tryPut(K key, V value, Connection conn) throws SQLException, IOException { long t1 = System.currentTimeMillis(); ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream oout = new ObjectOutputStream(bout); oout.writeObject(value); oout.flush(); byte[] data = bout.toByteArray(); oout.close(); boolean local_conn_manage=false; try { if (conn == null) { local_conn_manage=true; conn = DB.openConnection("jelectrum_db"); } boolean insert=true; { PreparedStatement ps = conn.prepareStatement("select count(key) as count from "+table_name+" where key=?"); ps.setString(1, key.toString()); ResultSet rs = ps.executeQuery(); rs.next(); int count = rs.getInt("count"); if (count > 0) insert=false; } if (insert) { PreparedStatement ps = conn.prepareStatement("insert into "+table_name+" (key,data) values (?,?)"); ps.setString(1, key.toString()); ps.setBytes(2, data); ps.execute(); ps.close(); } else { PreparedStatement ps = conn.prepareStatement("update "+table_name+" set data=? where key = ?"); ps.setBytes(1, data); ps.setString(2, key.toString()); ps.execute(); ps.close(); } } finally { if (local_conn_manage) { DB.safeClose(conn); } } long t2 = System.currentTimeMillis(); put_stats.addDataPoint(t2-t1); return null; } public void putAll(Map<? extends K,? extends V> m) { while(true) { try { tryPutAll(m); return; } catch(SQLException e) { e.printStackTrace(); try{Thread.sleep(1000);}catch(Exception e2){} } catch(IOException e) { throw new RuntimeException(e); } } } private void tryPutAll(Map<? extends K,? extends V> m) throws SQLException, IOException { Connection conn = null; try { conn = DB.openConnection("jelectrum_db"); conn.setAutoCommit(false); for(Map.Entry e : m.entrySet()) { tryPut((K)e.getKey(), (V)e.getValue(), conn); } conn.commit(); } finally { DB.safeClose(conn); } } public V remove(Object key) { throw new RuntimeException("not implemented - is stupid"); } public Collection<V> values() { throw new RuntimeException("not implemented - is stupid"); } public static void printStats() { DecimalFormat df = new DecimalFormat("0.0"); get_stats.copyAndReset().print("get", df); put_stats.copyAndReset().print("put", df); } }