Merge branch 'susimail-loading' into 'master'

Susimail: Speed up initial loading by 35x

See merge request i2p-hackers/i2p.i2p!162
This commit is contained in:
zzz
2024-01-02 13:37:23 +00:00
4 changed files with 53 additions and 15 deletions

View File

@@ -48,6 +48,7 @@ import java.util.Set;
import net.i2p.I2PAppContext; import net.i2p.I2PAppContext;
import net.i2p.app.ClientAppManager; import net.i2p.app.ClientAppManager;
import net.i2p.app.NotificationService; import net.i2p.app.NotificationService;
import net.i2p.data.Base64;
import net.i2p.util.FileUtil; import net.i2p.util.FileUtil;
import net.i2p.util.I2PAppThread; import net.i2p.util.I2PAppThread;
import net.i2p.util.Log; import net.i2p.util.Log;
@@ -61,7 +62,7 @@ import net.i2p.util.Log;
class MailCache { class MailCache {
public enum FetchMode { public enum FetchMode {
HEADER, ALL, CACHE_ONLY HEADER, ALL, CACHE_ONLY, HEADER_CACHE_ONLY
} }
private final POP3MailBox mailbox; private final POP3MailBox mailbox;
@@ -326,12 +327,12 @@ class MailCache {
} }
/** /**
* Fetch any needed data from pop3 server, unless mode is CACHE_ONLY, * Fetch any needed data from pop3 server, unless mode is CACHE_ONLY or HEADER_CACHE_ONLY,
* or this isn't the Inbox. * or this isn't the Inbox.
* Blocking unless mode is CACHE_ONLY. * Blocking for a long time unless mode is CACHE_ONLY or HEADER_CACHE_ONLY.
* *
* @param uidl message id to get * @param uidl message id to get
* @param mode CACHE_ONLY to not pull from pop server * @param mode CACHE_ONLY or HEADER_CACHE_ONLY to not pull from pop server
* @return An e-mail or null * @return An e-mail or null
*/ */
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})
@@ -368,12 +369,35 @@ class MailCache {
if (mode == FetchMode.HEADER) { if (mode == FetchMode.HEADER) {
if (!mail.hasHeader()) { if (!mail.hasHeader()) {
if (_log.shouldInfo()) _log.info("Fetching mail header from server for b64: " + Base64.encode(uidl));
Buffer buf = mailbox.getHeader(uidl); Buffer buf = mailbox.getHeader(uidl);
if (buf != null) if (buf != null)
mail.setHeader(buf); mail.setHeader(buf);
} }
} else if (mode == FetchMode.ALL) { } else if (mode == FetchMode.HEADER_CACHE_ONLY) {
if(!mail.hasBody()) { if (!mail.hasHeader()) {
// shouldn't happen
if (disk.getMail(mail, true)) {
if (_log.shouldWarn()) _log.warn("Loaded deferred header from disk cache for b64: " + Base64.encode(uidl));
return mail;
} else {
if (_log.shouldWarn()) _log.warn("Failed to load deferred header from disk cache for b64: " + Base64.encode(uidl));
}
}
} else if (!mail.hasBody()) {
// CACHE_ONLY or ALL
if (disk.getFullFile(uidl).exists()) {
// body was not loaded at startup but we have it, load it now
if (disk.getMail(mail, false)) {
if (_log.shouldDebug()) _log.debug("Loaded deferred body from disk cache for b64: " + Base64.encode(uidl));
return mail;
}
if (_log.shouldWarn()) _log.warn("Failed to load deferred body from disk cache for b64: " + Base64.encode(uidl));
} else {
if (_log.shouldWarn()) _log.warn("We do not have body in disk cache for b64: " + Base64.encode(uidl));
}
if (mode == FetchMode.ALL) {
if (_log.shouldInfo()) _log.info("Fetching mail body from server for b64: " + Base64.encode(uidl));
File file = new File(_context.getTempDir(), "susimail-new-" + _context.random().nextLong()); File file = new File(_context.getTempDir(), "susimail-new-" + _context.random().nextLong());
Buffer rb = mailbox.getBody(uidl, new FileBuffer(file)); Buffer rb = mailbox.getBody(uidl, new FileBuffer(file));
if (rb != null) { if (rb != null) {
@@ -384,8 +408,6 @@ class MailCache {
} }
} }
} }
} else {
// else if it wasn't in cache, too bad
} }
return mail; return mail;
} }
@@ -405,7 +427,7 @@ class MailCache {
*/ */
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})
public boolean getMail(FetchMode mode) { public boolean getMail(FetchMode mode) {
if (mode == FetchMode.CACHE_ONLY) if (mode == FetchMode.CACHE_ONLY || mode == FetchMode.HEADER_CACHE_ONLY)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
if (mailbox == null) { if (mailbox == null) {
if (_log.shouldDebug()) _log.debug("getMail() mode " + mode + " called on wrong folder " + getFolderName(), new Exception()); if (_log.shouldDebug()) _log.debug("getMail() mode " + mode + " called on wrong folder " + getFolderName(), new Exception());

View File

@@ -462,10 +462,26 @@ class PersistentMailCache {
mail = new Draft(uidl); mail = new Draft(uidl);
else else
mail = new Mail(uidl); mail = new Mail(uidl);
if (headerOnly) if (headerOnly) {
mail.setHeader(rb); mail.setHeader(rb);
else } else if (isDrafts) {
// drafts always have FULL_SUFFIX but
// may not actually have a real body or part.
// If we don't call setBody(), it has
// a null part and we NPE on the compose page.
// Attachments are stored in separate files so
// these are all small.
mail.setBody(rb); mail.setBody(rb);
} else {
// Deferred loading, body will be loaded
// on-demand in MailCache.getMail()
// We set the size of the gzipped file to be the
// size so the UI doesn't have ?? in it.
// The size will be corrected if and when the body is read.
//mail.setBody(rb);
mail.setHeader(rb);
mail.setSize(f.length());
}
return mail; return mail;
} }

View File

@@ -33,8 +33,8 @@ class Sorters {
* Gets mail from the cache, checks for null, then compares * Gets mail from the cache, checks for null, then compares
*/ */
public int compare(String arg0, String arg1) { public int compare(String arg0, String arg1) {
Mail a = mailCache.getMail( arg0, MailCache.FetchMode.CACHE_ONLY ); Mail a = mailCache.getMail(arg0, MailCache.FetchMode.HEADER_CACHE_ONLY);
Mail b = mailCache.getMail( arg1, MailCache.FetchMode.CACHE_ONLY ); Mail b = mailCache.getMail(arg1, MailCache.FetchMode.HEADER_CACHE_ONLY);
if (a == null) if (a == null)
return (b == null) ? 0 : 1; return (b == null) ? 0 : 1;
if (b == null) if (b == null)

View File

@@ -2328,7 +2328,7 @@ public class WebMail extends HttpServlet
if (state == State.LIST) { if (state == State.LIST) {
for (Iterator<String> it = folder.currentPageIterator(); it != null && it.hasNext(); ) { for (Iterator<String> it = folder.currentPageIterator(); it != null && it.hasNext(); ) {
String uidl = it.next(); String uidl = it.next();
Mail mail = mc.getMail(uidl, MailCache.FetchMode.HEADER); Mail mail = mc.getMail(uidl, MailCache.FetchMode.HEADER_CACHE_ONLY);
if( mail != null && mail.error.length() > 0 ) { if( mail != null && mail.error.length() > 0 ) {
sessionObject.error += mail.error; sessionObject.error += mail.error;
mail.error = ""; mail.error = "";
@@ -3300,7 +3300,7 @@ public class WebMail extends HttpServlet
int i = 0; int i = 0;
for (Iterator<String> it = folder.currentPageIterator(); it != null && it.hasNext(); ) { for (Iterator<String> it = folder.currentPageIterator(); it != null && it.hasNext(); ) {
String uidl = it.next(); String uidl = it.next();
Mail mail = mc.getMail(uidl, MailCache.FetchMode.CACHE_ONLY); Mail mail = mc.getMail(uidl, MailCache.FetchMode.HEADER_CACHE_ONLY);
if (mail == null || !mail.hasHeader()) { if (mail == null || !mail.hasHeader()) {
continue; continue;
} }