package jelectrum; import java.util.Map; import java.util.TreeMap; import java.util.Set; import java.util.HashSet; import java.util.Collection; import java.util.LinkedList; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ByteArrayOutputStream; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Random; import java.text.DecimalFormat; import com.google.bitcoin.core.Sha256Hash; import java.sql.Connection; import java.sql.ResultSet; import java.sql.PreparedStatement; import java.sql.SQLException; import java.io.IOException; public class SqlMapSet<K> implements MapSet<K, Sha256Hash> { private static StatData put_stats = new StatData(); private static StatData get_stats = new StatData(); private String table_name; public SqlMapSet(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+" ( node char("+max_key_len+") NOT NULL, element char(64))"); ps.execute(); ps.close(); } { PreparedStatement ps = conn.prepareStatement("create unique index "+table_name+"_idx on "+table_name+"(node,element);"); ps.execute(); ps.close(); } } catch(SQLException e) { } finally { DB.safeClose(conn); } } public Set<Sha256Hash> getSet(Object key) { while(true) { try { return tryGetSet(key); } catch(SQLException e) { e.printStackTrace(); try{Thread.sleep(1000);}catch(Exception e2){} } } } public Set<Sha256Hash> tryGetSet(Object key) throws SQLException { long t1 = System.currentTimeMillis(); HashSet<Sha256Hash> set = new HashSet<Sha256Hash>(); Connection conn=null; try { conn = DB.openConnection("jelectrum_db"); PreparedStatement ps = conn.prepareStatement("select * from "+table_name+" where node=?"); ps.setString(1, key.toString()); ResultSet rs = ps.executeQuery(); while(rs.next()) { set.add(new Sha256Hash(rs.getString("element"))); } rs.close(); ps.close(); } finally { DB.safeClose(conn); } long t2 = System.currentTimeMillis(); get_stats.addDataPoint(t2-t1); return set; } public void add(K key, Sha256Hash value) { while(true) { try { tryAdd(key, value, null); return; } catch(SQLException e) { e.printStackTrace(); try{Thread.sleep(1000);}catch(Exception e2){} return; } } } public void tryAdd(K key, Sha256Hash value, Connection conn) throws SQLException { long t1 = System.currentTimeMillis(); 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(node) as count from "+table_name+" where node=? and element=?"); ps.setString(1, key.toString()); ps.setString(2, value.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+" (node,element) values (?,?)"); ps.setString(1, key.toString()); ps.setString(2, value.toString()); ps.execute(); ps.close(); } } finally { if (local_conn_manage) { DB.safeClose(conn); } } long t2 = System.currentTimeMillis(); put_stats.addDataPoint(t2-t1); } public void addAll(Collection<K> keys, Sha256Hash val) { LinkedList<Map.Entry<K, Sha256Hash> > lst = new LinkedList<Map.Entry<K, Sha256Hash> >(); for(K key : keys) { lst.add(new java.util.AbstractMap.SimpleEntry<K,Sha256Hash>(key, val)); } addAll(lst); } public void addAll(Collection<Map.Entry<K,Sha256Hash>> lst) { while(true) { try { tryAddAll(lst); return; } catch(SQLException e) { e.printStackTrace(); try{Thread.sleep(1000);}catch(Exception e2){} } } } private void tryAddAll(Collection<Map.Entry<K,Sha256Hash>> lst) throws SQLException { Connection conn = null; try { conn = DB.openConnection("jelectrum_db"); conn.setAutoCommit(false); for(Map.Entry e : lst) { tryAdd((K)e.getKey(), (Sha256Hash)e.getValue(), conn); } conn.commit(); } finally { DB.safeClose(conn); } } public static void printStats() { DecimalFormat df = new DecimalFormat("0.0"); get_stats.copyAndReset().print("get", df); put_stats.copyAndReset().print("put", df); } }