lots of fixes to FileBasedMailbox
authoradam <adam@megacz.com>
Mon, 18 Oct 2004 07:12:54 +0000 (07:12 +0000)
committeradam <adam@megacz.com>
Mon, 18 Oct 2004 07:12:54 +0000 (07:12 +0000)
darcs-hash:20041018071254-5007d-da0cd1fdae2718c1b94786e2f6f66974616e938b.gz

src/org/ibex/mail/Main.java
src/org/ibex/mail/target/FileBasedMailbox.java

index 7a58382..821bff5 100644 (file)
@@ -26,11 +26,11 @@ public class Main implements Listener {
     private static class Auth implements Login {
         public Account anonymous() { return null; }
         public Object login(String user, String pass, Class protocol) {
-            if (protocol == IMAP.class && user.endsWith("@gmail.com")) return GMail.getGMail(user, pass).getIMAP();
+            //if (protocol == IMAP.class && user.endsWith("@gmail.com")) return GMail.getGMail(user, pass).getIMAP();
             return login(user, pass);
         }
         public Account login(String user, String pass) {
-            if (user.indexOf("@gmail.com") != -1) return GMail.getGMail(user, pass);
+            //if (user.indexOf("@gmail.com") != -1) return GMail.getGMail(user, pass);
             if (!EtcPasswd.verify(user, pass)) return null;
             final Mailbox root =
                 FileBasedMailbox.getFileBasedMailbox(Mailbox.STORAGE_ROOT + "/user", true);
index 43a21c8..10dd7f9 100644 (file)
@@ -20,7 +20,7 @@ public class FileBasedMailbox extends Mailbox.Default implements Serializable {
     private static final char slash = File.separatorChar;
     private static final WeakHashMap<String,FileBasedMailbox> instances = new WeakHashMap<String,FileBasedMailbox>();
     public Mailbox slash(String name, boolean create) { return getFileBasedMailbox(path + slash + name, create); }
-    public static FileBasedMailbox getFileBasedMailbox(String path, boolean create) {
+    public static synchronized FileBasedMailbox getFileBasedMailbox(String path, boolean create) {
         try {
             FileBasedMailbox ret = instances.get(path);
             if (ret == null) {
@@ -38,10 +38,11 @@ public class FileBasedMailbox extends Mailbox.Default implements Serializable {
     // Instance //////////////////////////////////////////////////////////////////////////////
 
     private String path;
-    private FileLock lock;
-    private Prevayler prevayler;
-    private LinkedList<CacheEntry> cache;
-    private int uidNext;
+    private transient FileLock lock;
+    private transient Prevayler prevayler;
+    private transient ArrayList<CacheEntry> cache;
+    private transient int uidValidity;
+    private transient int uidNext;
 
     public static class CacheEntry implements Serializable {
         public MIME.Headers headers;
@@ -64,34 +65,53 @@ public class FileBasedMailbox extends Mailbox.Default implements Serializable {
     private FileBasedMailbox(String path) throws MailException, IOException, ClassNotFoundException {
         new File(this.path = path).mkdirs();
         new File(path + slash + ".cache").mkdirs();
+        File uidValidityFile = new File(path + slash + ".uidValidity");
+        if (!uidValidityFile.exists()) uidValidityFile.createNewFile();
+        uidValidity = (int)(uidValidityFile.lastModified() & 0xffffffff);
         lock = new RandomAccessFile(this.path + slash + ".cache" + slash + "lock", "rw").getChannel().tryLock();
         if (lock == null) throw new IOException("unable to lock FileBasedMailbox");
-        prevayler = PrevaylerFactory.createPrevayler(new LinkedList<CacheEntry>(), path + slash + ".cache");
-        cache = (LinkedList<CacheEntry>)prevayler.prevalentSystem();
-        for(int i=0; i<cache.size(); i++) uidNext = Math.max(uidNext, cache.get(i).uid()+1);
-        if (cache.size() > 0) return;
-
-        Log.warn(this, "rebuilding cache for " + path);
-        String[] files = new File(path).list(new FilenameFilter() {
-                public boolean accept(File f, String s) {
-                    return s.substring(1).indexOf('.') != -1 && !s.equals("..");
-                } });
-        for(int i=0; i<files.length; i++) {
-            CacheEntry ce = new CacheEntry(new File(path + slash + files[i]));
-            prevayler.execute(new Rebuild(ce));
-            uidNext = Math.max(uidNext, ce.uid()+1);
+        prevayler = PrevaylerFactory.createPrevayler(new ArrayList<CacheEntry>(), path + slash + ".cache");
+        cache = (ArrayList<CacheEntry>)prevayler.prevalentSystem();
+        for(int i=0; i<cache.size(); i++) if (cache.get(i) != null) uidNext = Math.max(uidNext, cache.get(i).uid()+1);
+        if (cache.size() == 0) {
+            Log.warn(this, "rebuilding cache for " + path);
+            String[] files = new File(path).list(new FilenameFilter() {
+                    public boolean accept(File f, String s) {
+                        return s.substring(1).indexOf('.') != -1 && !s.equals("..");
+                    } });
+            long last = System.currentTimeMillis();
+            CacheEntry[] entries = new CacheEntry[files.length];
+            for(int i=0; i<files.length; i++) {
+                if (System.currentTimeMillis() - last > 1000 * 1) {
+                    Log.warn(this, "rebuilding cache for " + path + ": " + Math.ceil((((float)i)/((float)files.length)) * 100)+ "%");
+                    last = System.currentTimeMillis();
+                }
+                CacheEntry ce = new CacheEntry(new File(path + slash + files[i]));
+                entries[i] = ce;
+                uidNext = Math.max(uidNext, ce.uid()+1);
+            }
+            prevayler.execute(new Rebuild(entries));
         }
+        Log.warn(this, "taking snapshot for " + path);
         prevayler.takeSnapshot();
     }
 
     private static class Rebuild implements Transaction {
-        public final CacheEntry entry;
-        public Rebuild(CacheEntry entry) { this.entry = entry; }
-        public void executeOn(Object c, Date now) { synchronized(c) { ((LinkedList<CacheEntry>)c).add(entry); } }
+        public final CacheEntry[] entries;
+        public Rebuild(CacheEntry entry) { this.entries = new CacheEntry[] { entry }; }
+        public Rebuild(CacheEntry[] entries) { this.entries = entries; }
+        public void executeOn(Object c, Date now) {
+            synchronized(c) {
+                for(int i=0; i<entries.length; i++) {
+                    ((ArrayList<CacheEntry>)c).add(entries[i]);
+                }
+            } }
     }
 
     public Mailbox.Iterator  iterator()           { return new Iterator(); }
-    public int               uidValidity()        { return (int)(new File(path).lastModified() & 0xffffffL); }
+
+    public int               uidValidity()        { return uidValidity; }
+
     public int               uidNext()            { return uidNext(false); }
     public int               uidNext(boolean inc) { return inc ? uidNext++ : uidNext; }
     public synchronized void add(Message message) { add(message, Mailbox.Flag.RECENT); }
@@ -99,7 +119,11 @@ public class FileBasedMailbox extends Mailbox.Default implements Serializable {
     public String[] children() {
         Vec vec = new Vec();
         String[] list = new File(path).list();
-        for(int i=0; i<list.length; i++) if ((new File(path + slash + list[i]).isDirectory())) vec.addElement(list[i]);
+        for(int i=0; i<list.length; i++) {
+            File f = new File(path + slash + list[i]);
+            if (f.isDirectory() && f.getName().charAt(0) != '.')
+                vec.addElement(list[i]);
+        }
         return (String[])vec.copyInto(new String[vec.size()]);
     }
 
@@ -132,7 +156,7 @@ public class FileBasedMailbox extends Mailbox.Default implements Serializable {
         public boolean next() { cur++; return !done(); }
         public boolean seen() { return done() ? false : entry().seen(); }
         public int num() { return cur+1; }  // EUDORA insists that message numbers start at 1, not 0
-        public int uid() { return entry().uid(); }
+        public int uid() { return done() ? -1 : entry().uid(); }
         public Message cur() {
             if (done()) return null;
             try {
@@ -147,8 +171,10 @@ public class FileBasedMailbox extends Mailbox.Default implements Serializable {
         }
         public void seen(final boolean on) {
             if (done()) return;
-            final CacheEntry entry = entry();
-            prevayler.execute(new Transaction() { public void executeOn(Object c, Date d) { entry.seen(on); } });
+            final int ptr = this.cur;
+            prevayler.execute(new Transaction() {
+                    public void executeOn(Object c, Date d) {
+                        ((ArrayList<CacheEntry>)c).get(ptr).seen(on); } });
         }
         public void delete() {
             if (done()) return;