fr.aliasource.webmail.common.cache.CacheManager.java Source code

Java tutorial

Introduction

Here is the source code for fr.aliasource.webmail.common.cache.CacheManager.java

Source

/* ***** BEGIN LICENSE BLOCK *****
 * Version: GPL 2.0
 *
 * The contents of this file are subject to the GNU General Public
 * License Version 2 or later (the "GPL").
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Initial Developer of the Original Code is
 *   MiniG.org project members
 *
 * ***** END LICENSE BLOCK ***** */

package fr.aliasource.webmail.common.cache;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import fr.aliasource.webmail.common.IAccount;
import fr.aliasource.webmail.common.folders.IFolder;
import fr.aliasource.webmail.common.uid.UIDCache;
import fr.aliasource.webmail.common.uid.UIDChanges;

/**
 * Implements cache update policy.
 * 
 * The following policy is used for cache updates : refresh the list of
 * subscribed folders, then refresh each folder.
 * 
 * Folder refresh loads a list of cached uids, then this list is compared to the
 * uid list on the server. Added & removed uids are calculated for an
 * incremental update of cached conversations.
 * 
 * 
 * @author tom
 * 
 */
public class CacheManager {

    private AccountCache cache;

    private IAccount account;
    private Log logger;
    private Map<IFolder, UIDCache> uidc;
    private Semaphore firstIndexingRoundLock;
    private Semaphore refreshLock;
    private int skipCount;

    public CacheManager(AccountCache cache, IAccount account) {
        this.logger = LogFactory.getLog(getClass());
        this.account = account;
        this.cache = cache;
        this.skipCount = 0;
        this.uidc = new HashMap<IFolder, UIDCache>();
        firstIndexingRoundLock = new Semaphore(1);
        refreshLock = new Semaphore(1);
        grabFirstLock();
    }

    private void grabRefreshLock() {
        try {
            refreshLock.acquire();
        } catch (InterruptedException e) {
        }
    }

    private void releaseRefreshLock() {
        refreshLock.release();
    }

    private void grabFirstLock() {
        logger.info("taking for first indexing round lock...");
        try {
            firstIndexingRoundLock.acquire();
        } catch (InterruptedException e) {
        }
        logger.info("first indexing round lock acquired.");
    }

    public UIDCache cache(IFolder f) {
        UIDCache ret = uidc.get(f);
        if (ret == null) {
            if (f.getId() == 0) {
                cache.getSubscribedFolderCache().get(f);
            }
            ret = new UIDCache(account, f);
            uidc.put(f, ret);
        }
        return ret;
    }

    public void refreshAll() {
        long time = System.currentTimeMillis();
        grabRefreshLock();
        SubscribedFolderCache fc = cache.getSubscribedFolderCache();
        SummaryCache sc = cache.getSummaryCache();
        try {
            List<IFolder> folders = fc.update();
            for (IFolder folder : folders) {
                if (folder.getName().equalsIgnoreCase("INBOX") || ((skipCount % 5) == 0)) {
                    refreshUnlocked(folder);
                }
            }
            skipCount++;
            sc.update();
        } catch (InterruptedException e) {
            logger.error(e.getMessage(), e);
        }
        time = System.currentTimeMillis() - time;
        logger.info("[" + account.getUserId() + "] refreshAll in " + time + "ms.");
        releaseRefreshLock();
        firstIndexingRoundLock.release();
    }

    public boolean isFirstIndexingComplete() {
        try {
            boolean get = firstIndexingRoundLock.tryAcquire(10, TimeUnit.SECONDS);
            firstIndexingRoundLock.release();
            return get;
        } catch (InterruptedException e) {
            throw new RuntimeException("interrupted while waiting for first indexing round.");
        }
    }

    public void refresh(IFolder folder) throws InterruptedException {
        grabRefreshLock();
        refreshUnlocked(folder);
        refreshLock.release();
    }

    private void refreshUnlocked(IFolder folder) throws InterruptedException {
        long time = System.currentTimeMillis();
        UIDCache uc = cache(folder);
        long ct = System.currentTimeMillis();
        Set<Long> cached = uc.getCachedData();
        ct = System.currentTimeMillis() - ct;
        long upd = System.currentTimeMillis();
        Set<Long> current = uc.update();
        upd = System.currentTimeMillis() - upd;

        if (uc.flagResyncNeeded()) {
            time = System.currentTimeMillis() - time;
            logger.info("[" + account.getUserId() + "]: [flagSync] " + folder.getName() + " changes found. (" + time
                    + "ms (loadCache: " + ct + "ms, updCache: " + upd + "ms))");

            cache.getConversationCache().fastUpdate(folder, current, new ArrayList<Long>(0));
        } else {
            UIDChanges sync = uc.computeChanges(cached, current);
            time = System.currentTimeMillis() - time;
            logger.info("[" + account.getUserId() + "]: " + folder.getName() + " changes found. (" + time
                    + "ms (loadCache: " + ct + "ms, updCache: " + upd + "ms))");

            cache.getConversationCache().fastUpdate(folder, sync.getAdded(), sync.getRemoved());
        }

    }

    public void shutdown() {
        logger.info("Cache mgr shutdown, waiting for first lock...");
        grabFirstLock();
        logger.info("Cache mgr shutdown, waiting for refresh lock...");
        grabRefreshLock();
    }

    public void forgetFolders(HashSet<IFolder> toRemove) {
        for (IFolder f : toRemove) {
            uidc.remove(f);
        }
    }

}