From: adam Date: Mon, 18 Oct 2004 05:25:11 +0000 (+0000) Subject: added Prevayler-based cache to FileBasedMailbox X-Git-Url: http://git.megacz.com/?p=org.ibex.mail.git;a=commitdiff_plain;h=ebe5e4d4a750a2c6e52ba7bb79be4664b68c8379 added Prevayler-based cache to FileBasedMailbox darcs-hash:20041018052511-5007d-fdb82768460d8d6f71ad00d7bac551639a62b0d5.gz --- diff --git a/src/org/ibex/mail/target/FileBasedMailbox.java b/src/org/ibex/mail/target/FileBasedMailbox.java index 8bf36ad..43a21c8 100644 --- a/src/org/ibex/mail/target/FileBasedMailbox.java +++ b/src/org/ibex/mail/target/FileBasedMailbox.java @@ -1,8 +1,11 @@ package org.ibex.mail.target; +import org.prevayler.*; import org.ibex.mail.*; import org.ibex.util.*; import org.ibex.io.*; import java.io.*; +import java.nio.*; +import java.nio.channels.*; import java.net.*; import java.util.*; import java.text.*; @@ -14,104 +17,97 @@ import java.text.*; public class FileBasedMailbox extends Mailbox.Default implements Serializable { public String toString() { return "[FileBasedMailbox " + path + "]"; } - private static final char slash = File.separatorChar; - private static final Hashtable instances = new Hashtable(); + private static final WeakHashMap instances = new WeakHashMap(); + public Mailbox slash(String name, boolean create) { return getFileBasedMailbox(path + slash + name, create); } public static FileBasedMailbox getFileBasedMailbox(String path, boolean create) { - FileBasedMailbox ret = (FileBasedMailbox)instances.get(path); - if (ret != null) return ret; - File f = new File(path); - if (!create && !f.exists()) return null; - instances.put(path, ret = new FileBasedMailbox(path)); - return ret; + try { + FileBasedMailbox ret = instances.get(path); + if (ret == null) { + if (!create && !new File(path).exists()) return null; + instances.put(path, ret = new FileBasedMailbox(path)); + } + return ret; + } catch (Exception e) { + Log.error(FileBasedMailbox.class, e); + return null; + } } - public static final FilenameFilter filter = new FilenameFilter() { - public boolean accept(File f, String s) { - return s.indexOf('.') != -1; - } }; - // Instance ////////////////////////////////////////////////////////////////////////////// private String path; - private File uidNext; - private FileBasedMailbox(String path) throws MailException { + private FileLock lock; + private Prevayler prevayler; + private LinkedList cache; + private int uidNext; + + public static class CacheEntry implements Serializable { + public MIME.Headers headers; + public String path; + public boolean seen; + private String name() { return path.indexOf(slash) == -1 ? path : path.substring(path.lastIndexOf(slash)+1); } + public boolean seen() { return name().substring(name().indexOf('.')+1).indexOf('s') != -1; } + public int uid() { return Integer.parseInt(name().substring(0, name().indexOf('.'))); } + public synchronized void seen(boolean seen) { + String newpath = path.substring(0, path.lastIndexOf('.') + 1) + (seen ? "s" : ""); + new File(path).renameTo(new File(newpath)); + path = newpath; + } + public CacheEntry(File f) throws IOException { + path = f.getAbsolutePath(); + headers = new MIME.Headers(new Stream(new FileInputStream(f)), true); + } + } + + private FileBasedMailbox(String path) throws MailException, IOException, ClassNotFoundException { new File(this.path = path).mkdirs(); - uidNext(false); + new File(path + slash + ".cache").mkdirs(); + 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(), path + slash + ".cache"); + cache = (LinkedList)prevayler.prevalentSystem(); + for(int i=0; i 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)c).add(entry); } } } - public Mailbox slash(String name, boolean create) { - return FileBasedMailbox.getFileBasedMailbox(path + slash + name, create); } + public Mailbox.Iterator iterator() { return new Iterator(); } + public int uidValidity() { return (int)(new File(path).lastModified() & 0xffffffL); } + 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); } public String[] children() { Vec vec = new Vec(); String[] list = new File(path).list(); - for(int i=0; i= cache.size()) return true; } return false; } + 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 Message cur() { - if (cur >= names.length) return null; + if (done()) return null; try { - File file = new File(path + File.separatorChar + names[cur]); + File file = new File(entry().path); FileInputStream fis = null; try { fis = new FileInputStream(file); @@ -146,62 +145,19 @@ public class FileBasedMailbox extends Mailbox.Default implements Serializable { } catch (IOException e) { throw new MailException.IOException(e); } catch (Message.Malformed e) { throw new MailException(e.getMessage()); } } - public boolean next() { - cur++; - if (cur >= names.length) return false; - String name = names[cur].substring(names[cur].indexOf('.') + 1); - if (!(new File(path + File.separatorChar + names[cur])).exists()) return next(); - seen = name.indexOf('s') != -1; - deleted = name.indexOf('x') != -1; - flagged = name.indexOf('f') != -1; - draft = name.indexOf('d') != -1; - answered = name.indexOf('a') != -1; - //recent = name.indexOf('r') != -1; - recent = true; - return true; + 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); } }); } - - // EUDORA insists that message numbers start at 1, not 0 - public int num() { return cur+1; } - - public int uid() { - try { return Integer.parseInt(names[cur].substring(0, names[cur].indexOf('.'))); - } catch (NumberFormatException nfe) { - Log.warn(FileBasedMailbox.class, "NumberFormatException: " + names[cur].substring(0, names[cur].length() - 1)); - return -1; } } - - private void fixflags() { - String newName = - names[cur].substring(0, names[cur].indexOf('.') + 1) + - (seen ? "s" : "") + - (deleted ? "x" : "") + - (flagged ? "f" : "") + - (draft ? "d" : "") + - (recent ? "r" : "") + - (answered ? "a" : ""); - new File(path + File.separatorChar + names[cur]).renameTo(new File(path + File.separatorChar + newName)); - names[cur] = newName; - } - - public void delete() { - new File(path + File.separatorChar + names[cur]).delete(); - // FIXME remove from list? + public void delete() { + if (done()) return; + final CacheEntry entry = entry(); + prevayler.execute(new Transaction() { + public void executeOn(Object c, Date d) { + new File(entry.path).delete(); + cache.remove(entry); + }}); } - public void set(String key, String val) { throw new MailException("not supported"); } - public String get(String key) { throw new MailException("not supported"); } - - public boolean seen() { return seen; } - public boolean deleted() { return deleted; } - public boolean flagged() { return flagged; } - public boolean draft() { return draft; } - public boolean answered() { return answered; } - public boolean recent() { return recent; } - public void seen(boolean on) { seen = on; fixflags(); } - public void deleted(boolean on) { deleted = on; fixflags(); } - public void flagged(boolean on) { flagged = on; fixflags(); } - public void draft(boolean on) { draft = on; fixflags(); } - public void answered(boolean on) { answered = on; fixflags(); } - public void recent(boolean on) { recent = on; fixflags(); } - } }