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);
}
}