Search in sources :

Example 1 with CtagResponseCacheValue

use of com.zimbra.cs.mailbox.calendar.cache.CtagResponseCache.CtagResponseCacheValue in project zm-mailbox by Zimbra.

the class DavServlet method checkCachedResponse.

private CacheStates checkCachedResponse(DavContext ctxt, Account authUser) throws IOException, DavException, ServiceException {
    CacheStates cache = new CacheStates();
    // Are we running with cache enabled, and is this a cachable CalDAV ctag request?
    if (cache.ctagCacheEnabled && isCtagRequest(ctxt)) {
        cache.ctagResponseCache = CalendarCacheManager.getInstance().getCtagResponseCache();
        cache.gzipAccepted = ctxt.isGzipAccepted();
        String targetUser = ctxt.getUser();
        Account targetAcct = Provisioning.getInstance().get(AccountBy.name, targetUser);
        boolean ownAcct = targetAcct != null && targetAcct.getId().equals(authUser.getId());
        String parentPath = ctxt.getPath();
        KnownUserAgent knownUA = ctxt.getKnownUserAgent();
        // Use cache only when requesting own account and User-Agent and path are well-defined.
        if (ownAcct && knownUA != null && parentPath != null) {
            AccountKey accountKey = new AccountKey(targetAcct.getId());
            AccountCtags allCtagsData = CalendarCacheManager.getInstance().getCtags(accountKey);
            // We can't use cache if it doesn't have data for this user.
            if (allCtagsData != null) {
                boolean validRoot = true;
                int rootFolderId = Mailbox.ID_FOLDER_USER_ROOT;
                if (!"/".equals(parentPath)) {
                    CtagInfo calInfoRoot = allCtagsData.getByPath(parentPath);
                    if (calInfoRoot != null)
                        rootFolderId = calInfoRoot.getId();
                    else
                        validRoot = false;
                }
                if (validRoot) {
                    // Is there a previously cached response?
                    cache.ctagCacheKey = new CtagResponseCacheKey(targetAcct.getId(), knownUA.toString(), rootFolderId);
                    CtagResponseCacheValue ctagResponse = cache.ctagResponseCache.get(cache.ctagCacheKey);
                    if (ctagResponse != null) {
                        // Found a cached response.  Let's check if it's stale.
                        // 1. If calendar list has been updated since, cached response is no good.
                        String currentCalListVer = allCtagsData.getVersion();
                        if (currentCalListVer.equals(ctagResponse.getVersion())) {
                            // 2. We have to examine ctags of individual calendars.
                            boolean cacheHit = true;
                            Map<Integer, String> oldCtags = ctagResponse.getCtags();
                            // We're good if ctags from before are unchanged.
                            for (Map.Entry<Integer, String> entry : oldCtags.entrySet()) {
                                int calFolderId = entry.getKey();
                                String ctag = entry.getValue();
                                CtagInfo calInfoCurr = allCtagsData.getById(calFolderId);
                                if (calInfoCurr == null) {
                                    // Just a sanity check.  The cal list version check should have
                                    // already taken care of added/removed calendars.
                                    cacheHit = false;
                                    break;
                                }
                                if (!ctag.equals(calInfoCurr.getCtag())) {
                                    // A calendar has been modified.  Stale!
                                    cacheHit = false;
                                    break;
                                }
                            }
                            if (cacheHit) {
                                ZimbraLog.dav.debug("CTAG REQUEST CACHE HIT");
                                // All good.  Send cached response.
                                ctxt.setStatus(DavProtocol.STATUS_MULTI_STATUS);
                                HttpServletResponse response = ctxt.getResponse();
                                response.setStatus(ctxt.getStatus());
                                response.setContentType(DavProtocol.DAV_CONTENT_TYPE);
                                byte[] respData = ctagResponse.getResponseBody();
                                response.setContentLength(ctagResponse.getRawLength());
                                byte[] unzipped = null;
                                if (ZimbraLog.dav.isDebugEnabled() || (ctagResponse.isGzipped() && !cache.gzipAccepted)) {
                                    if (ctagResponse.isGzipped()) {
                                        ByteArrayInputStream bais = new ByteArrayInputStream(respData);
                                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
                                        GZIPInputStream gzis = null;
                                        try {
                                            gzis = new GZIPInputStream(bais, respData.length);
                                            ByteUtil.copy(gzis, false, baos, true);
                                        } finally {
                                            ByteUtil.closeStream(gzis);
                                        }
                                        unzipped = baos.toByteArray();
                                    } else {
                                        unzipped = respData;
                                    }
                                    if (ZimbraLog.dav.isDebugEnabled()) {
                                        ZimbraLog.dav.debug("RESPONSE:\n" + new String(unzipped, "UTF-8"));
                                    }
                                }
                                if (!ctagResponse.isGzipped()) {
                                    response.getOutputStream().write(respData);
                                } else {
                                    if (cache.gzipAccepted) {
                                        response.addHeader(DavProtocol.HEADER_CONTENT_ENCODING, DavProtocol.ENCODING_GZIP);
                                        response.getOutputStream().write(respData);
                                    } else {
                                        assert (unzipped != null);
                                        response.getOutputStream().write(unzipped);
                                    }
                                }
                                // Tell the context the response has been sent.
                                ctxt.responseSent();
                            }
                        }
                    }
                    if (!ctxt.isResponseSent()) {
                        // Cache miss, or cached response is stale.  We're gonna have to generate the
                        // response the hard way.  Capture a snapshot of current state of calendars
                        // to attach to the response to be cached later.
                        cache.cacheThisCtagResponse = true;
                        cache.acctVerSnapshot = allCtagsData.getVersion();
                        cache.ctagsSnapshot = new HashMap<Integer, String>();
                        Collection<CtagInfo> childCals = allCtagsData.getChildren(rootFolderId);
                        if (rootFolderId != Mailbox.ID_FOLDER_USER_ROOT) {
                            CtagInfo ctagRoot = allCtagsData.getById(rootFolderId);
                            if (ctagRoot != null)
                                cache.ctagsSnapshot.put(rootFolderId, ctagRoot.getCtag());
                        }
                        for (CtagInfo calInfo : childCals) {
                            cache.ctagsSnapshot.put(calInfo.getId(), calInfo.getCtag());
                        }
                    }
                }
            }
            if (!ctxt.isResponseSent())
                ZimbraLog.dav.debug("CTAG REQUEST CACHE MISS");
        }
    }
    return cache;
}
Also used : Account(com.zimbra.cs.account.Account) AccountCtags(com.zimbra.cs.mailbox.calendar.cache.AccountCtags) HttpServletResponse(javax.servlet.http.HttpServletResponse) ByteArrayOutputStream(java.io.ByteArrayOutputStream) CtagResponseCacheKey(com.zimbra.cs.mailbox.calendar.cache.CtagResponseCache.CtagResponseCacheKey) Mountpoint(com.zimbra.cs.mailbox.Mountpoint) CtagInfo(com.zimbra.cs.mailbox.calendar.cache.CtagInfo) GZIPInputStream(java.util.zip.GZIPInputStream) ByteArrayInputStream(java.io.ByteArrayInputStream) KnownUserAgent(com.zimbra.cs.dav.DavContext.KnownUserAgent) AccountKey(com.zimbra.cs.mailbox.calendar.cache.AccountKey) Map(java.util.Map) HashMap(java.util.HashMap) CtagResponseCacheValue(com.zimbra.cs.mailbox.calendar.cache.CtagResponseCache.CtagResponseCacheValue)

Example 2 with CtagResponseCacheValue

use of com.zimbra.cs.mailbox.calendar.cache.CtagResponseCache.CtagResponseCacheValue in project zm-mailbox by Zimbra.

the class DavServlet method cacheCleanUp.

private void cacheCleanUp(DavContext ctxt, CacheStates cache) throws IOException {
    if (cache.ctagCacheEnabled && cache.cacheThisCtagResponse && ctxt.getStatus() == DavProtocol.STATUS_MULTI_STATUS) {
        assert (cache.ctagCacheKey != null && cache.acctVerSnapshot != null && !cache.ctagsSnapshot.isEmpty());
        DavResponse dresp = ctxt.getDavResponse();
        ByteArrayOutputStream baosRaw = null;
        try {
            baosRaw = new ByteArrayOutputStream();
            dresp.writeTo(baosRaw);
        } finally {
            ByteUtil.closeStream(baosRaw);
        }
        byte[] respData = baosRaw.toByteArray();
        int rawLen = respData.length;
        boolean forceGzip = true;
        // Cache gzipped response if client supports it.
        boolean responseGzipped = forceGzip || cache.gzipAccepted;
        if (responseGzipped) {
            ByteArrayOutputStream baosGzipped = new ByteArrayOutputStream();
            GZIPOutputStream gzos = null;
            try {
                gzos = new GZIPOutputStream(baosGzipped);
                gzos.write(respData);
            } finally {
                ByteUtil.closeStream(gzos);
            }
            respData = baosGzipped.toByteArray();
        }
        CtagResponseCacheValue ctagCacheVal = new CtagResponseCacheValue(respData, rawLen, responseGzipped, cache.acctVerSnapshot, cache.ctagsSnapshot);
        try {
            cache.ctagResponseCache.put(cache.ctagCacheKey, ctagCacheVal);
        } catch (ServiceException e) {
            ZimbraLog.dav.warn("Unable to cache ctag response", e);
        // No big deal if we can't cache the response.  Just move on.
        }
    }
}
Also used : ServiceException(com.zimbra.common.service.ServiceException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException) GZIPOutputStream(java.util.zip.GZIPOutputStream) ByteArrayOutputStream(java.io.ByteArrayOutputStream) Mountpoint(com.zimbra.cs.mailbox.Mountpoint) CtagResponseCacheValue(com.zimbra.cs.mailbox.calendar.cache.CtagResponseCache.CtagResponseCacheValue)

Aggregations

Mountpoint (com.zimbra.cs.mailbox.Mountpoint)2 CtagResponseCacheValue (com.zimbra.cs.mailbox.calendar.cache.CtagResponseCache.CtagResponseCacheValue)2 ByteArrayOutputStream (java.io.ByteArrayOutputStream)2 ServiceException (com.zimbra.common.service.ServiceException)1 Account (com.zimbra.cs.account.Account)1 KnownUserAgent (com.zimbra.cs.dav.DavContext.KnownUserAgent)1 MailServiceException (com.zimbra.cs.mailbox.MailServiceException)1 AccountCtags (com.zimbra.cs.mailbox.calendar.cache.AccountCtags)1 AccountKey (com.zimbra.cs.mailbox.calendar.cache.AccountKey)1 CtagInfo (com.zimbra.cs.mailbox.calendar.cache.CtagInfo)1 CtagResponseCacheKey (com.zimbra.cs.mailbox.calendar.cache.CtagResponseCache.CtagResponseCacheKey)1 ByteArrayInputStream (java.io.ByteArrayInputStream)1 HashMap (java.util.HashMap)1 Map (java.util.Map)1 GZIPInputStream (java.util.zip.GZIPInputStream)1 GZIPOutputStream (java.util.zip.GZIPOutputStream)1 HttpServletResponse (javax.servlet.http.HttpServletResponse)1