use ThreadPool and Cron
[org.ibex.mail.git] / src / org / ibex / mail / SqliteTable.java
1 package org.ibex.mail;
2
3 import org.ibex.io.*;
4 import org.ibex.mail.protocol.*;
5 import org.ibex.util.*;
6 import org.ibex.net.*;
7 import java.sql.*;
8 import java.net.*;
9 import java.io.*;
10 import java.util.*;
11 import java.sql.Timestamp;
12 import java.sql.Connection;
13
14 public class SqliteTable {
15
16     protected Connection conn;
17     private String filename;
18     private String reapTable;
19     private String reapColumn;
20
21     // check upstream: PRAGMA encoding = "UTF-8"; 
22     // create indices
23     // PRAGMA auto_vacuum=1  (can only be set before any tables are created)
24     // periodic "PRAGMA integrity_check; "?
25
26     public void setCacheSize(int kilobytes) throws SQLException {
27         conn.prepareStatement("PRAGMA cache_size="+Math.ceil(kilobytes/1.5)+";").executeUpdate();
28     }
29
30     public SqliteTable(String filename, String[] tables, String reapTable, String reapColumn) {
31         this(filename, tables, false, reapTable, reapColumn);
32     }
33     public SqliteTable(String filename, String[] tables, boolean fastButDangerous,
34                        String reapTable, String reapColumn) {
35         this.filename = filename;
36         try {
37             Class.forName("org.sqlite.JDBC");
38             conn = DriverManager.getConnection("jdbc:sqlite:"+filename);
39             for(String s : tables)
40                 conn.prepareStatement(s).executeUpdate();
41             conn.prepareStatement("PRAGMA temp_store = MEMORY").executeUpdate();
42             conn.prepareStatement("PRAGMA page_size=4096").executeUpdate();
43             conn.prepareStatement("PRAGMA cache_size=2000").executeUpdate();
44             if (fastButDangerous)
45                 conn.prepareStatement("PRAGMA synchronous = OFF").executeUpdate();
46         }
47         catch (SQLException e) { throw new RuntimeException(e); }
48         catch (ClassNotFoundException e) { throw new RuntimeException(e); }
49         this.reapTable = reapTable;
50         this.reapColumn = reapColumn;
51         if (reapTable != null && reapColumn != null)
52             Main.cron.executeLater(1000 * REAPER_INTERVAL_SECONDS, new Reaper());
53     }
54
55     public static final int REAPER_INTERVAL_SECONDS = 60 * 60;
56
57     private class Reaper implements Runnable {
58         public void run() {
59             try {
60                 Log.warn(Reaper.class, filename + " reaping...");
61                 long when = System.currentTimeMillis();
62                 when -= 5 * 24 * 60 * 60 * 1000;
63                 synchronized(SqliteTable.this) {
64                     PreparedStatement ps =
65                         conn.prepareStatement("select count(*) from "+reapTable+" where "+reapColumn+"<?");
66                     ps.setTimestamp(1, new Timestamp(when));
67                     ResultSet rs = ps.executeQuery();
68                     if (rs.next())
69                         Log.warn(Reaper.class, filename + " reaping " + rs.getInt(1) + " entries");
70                     Log.warn(Reaper.class, filename + ": " + "delete from "+reapTable+" where "+reapColumn+"<"+when);
71                     ps = conn.prepareStatement("delete from "+reapTable+" where "+reapColumn+"<?");
72                     ps.setTimestamp(1, new Timestamp(when));
73                     int rows = ps.executeUpdate();
74                     Log.warn(Reaper.class, filename + " done reaping; removed " + rows + " rows");
75                 }
76             } catch (Exception e) { Log.error(Reaper.class, e); }
77             Main.cron.executeLater(1000 * REAPER_INTERVAL_SECONDS, this);
78         }
79     }
80
81 }