Search in sources :

Example 1 with PendingDelete

use of com.zimbra.cs.mailbox.MailItem.PendingDelete in project zm-mailbox by Zimbra.

the class DbMailItem method getLeafNodes.

public static PendingDelete getLeafNodes(Mailbox mbox, QueryParams params) throws ServiceException {
    DbConnection conn = mbox.getOperationConnection();
    PreparedStatement stmt = null;
    ResultSet rs = null;
    try {
        StringBuilder buf = new StringBuilder();
        buf.append("SELECT " + LEAF_NODE_FIELDS + " FROM " + getMailItemTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + "type NOT IN " + FOLDER_TYPES);
        String whereClause = params.getWhereClause();
        if (!StringUtil.isNullOrEmpty(whereClause)) {
            buf.append(" AND ").append(whereClause);
        }
        String limitClause = params.getLimitClause();
        if (!StringUtil.isNullOrEmpty(limitClause)) {
            buf.append(" ").append(limitClause);
        }
        stmt = conn.prepareStatement(buf.toString());
        // Assume we're dealing with a very large result set.
        Db.getInstance().enableStreaming(stmt);
        int pos = 1;
        pos = setMailboxId(stmt, mbox, pos);
        PendingDelete info = accumulateDeletionInfo(mbox, stmt);
        stmt = null;
        return info;
    } catch (SQLException e) {
        throw ServiceException.FAILURE("fetching list of items to delete", e);
    } finally {
        DbPool.closeResults(rs);
        DbPool.closeStatement(stmt);
    }
}
Also used : SQLException(java.sql.SQLException) ResultSet(java.sql.ResultSet) PreparedStatement(java.sql.PreparedStatement) DbConnection(com.zimbra.cs.db.DbPool.DbConnection) PendingDelete(com.zimbra.cs.mailbox.MailItem.PendingDelete)

Example 2 with PendingDelete

use of com.zimbra.cs.mailbox.MailItem.PendingDelete in project zm-mailbox by Zimbra.

the class DbMailItem method getLeafNodes.

public static PendingDelete getLeafNodes(Folder folder) throws ServiceException {
    Mailbox mbox = folder.getMailbox();
    int folderId = folder.getId();
    QueryParams params = new QueryParams();
    params.setFolderIds(Collections.singletonList(folderId));
    PendingDelete info = getLeafNodes(mbox, params);
    // make sure that the folder is in the list of deleted items
    info.itemIds.add(folder.getType(), folderId, folder.getUuid());
    return info;
}
Also used : Mailbox(com.zimbra.cs.mailbox.Mailbox) PendingDelete(com.zimbra.cs.mailbox.MailItem.PendingDelete)

Example 3 with PendingDelete

use of com.zimbra.cs.mailbox.MailItem.PendingDelete in project zm-mailbox by Zimbra.

the class Mailbox method deletedBatchOfItemsInFolder.

private boolean deletedBatchOfItemsInFolder(OperationContext octxt, QueryParams params, TargetConstraint tcon) throws ServiceException {
    // Lock this mailbox to make sure that no one modifies the items we're about to delete.
    lock.lock();
    try {
        DeleteItem redoRecorder = new DeleteItem(mId, MailItem.Type.UNKNOWN, tcon);
        boolean success = false;
        try {
            beginTransaction("delete", octxt, redoRecorder);
            setOperationTargetConstraint(tcon);
            PendingDelete info = DbMailItem.getLeafNodes(this, params);
            if (info.itemIds.isEmpty()) {
                return false;
            }
            redoRecorder.setIds(ArrayUtil.toIntArray(info.itemIds.getAllIds()));
            MailItem.delete(this, info, null, true, /* writeTombstones */
            false);
            success = true;
        } finally {
            endTransaction(success);
        }
    } finally {
        lock.release();
    }
    return true;
}
Also used : DeleteItem(com.zimbra.cs.redolog.op.DeleteItem) PendingDelete(com.zimbra.cs.mailbox.MailItem.PendingDelete)

Example 4 with PendingDelete

use of com.zimbra.cs.mailbox.MailItem.PendingDelete in project zm-mailbox by Zimbra.

the class Mailbox method purgeMessages.

/**
     * Purges messages in system folders based on user- and admin-level purge settings on the account.
     * Returns {@code true} if all messages that meet the purge criteria were purged, {@code false} if the number of
     * messages to purge in any folder exceeded {@code maxItemsPerFolder}.
     */
public boolean purgeMessages(OperationContext octxt) throws ServiceException {
    Account acct = getAccount();
    int maxItemsPerFolder = Provisioning.getInstance().getLocalServer().getMailPurgeBatchSize();
    if (ZimbraLog.purge.isDebugEnabled()) {
        ZimbraLog.purge.debug("System retention policy: Trash=%s, Junk=%s, All messages=%s, Dumpster=%s", acct.getMailTrashLifetimeAsString(), acct.getMailSpamLifetimeAsString(), acct.getMailMessageLifetimeAsString(), acct.getMailDumpsterLifetimeAsString());
        ZimbraLog.purge.debug("User-specified retention policy: Inbox read=%s, Inbox unread=%s, Sent=%s, Junk=%s, Trash=%s, Versions=%s, VersionsEnabled=%s", acct.getPrefInboxReadLifetimeAsString(), acct.getPrefInboxUnreadLifetimeAsString(), acct.getPrefSentLifetimeAsString(), acct.getPrefJunkLifetimeAsString(), acct.getPrefTrashLifetimeAsString(), acct.getFileVersionLifetimeAsString(), acct.isFileVersioningEnabled());
    }
    long globalTimeout = acct.getMailMessageLifetime();
    long systemTrashTimeout = acct.getMailTrashLifetime();
    long systemJunkTimeout = acct.getMailSpamLifetime();
    boolean dumpsterPurgeEnabled = acct.isDumpsterPurgeEnabled();
    long systemDumpsterTimeoutMillis = dumpsterPurgeEnabled ? acct.getMailDumpsterLifetime() : 0;
    long userInboxReadTimeout = acct.getPrefInboxReadLifetime();
    long userInboxUnreadTimeout = acct.getPrefInboxUnreadLifetime();
    long userTrashTimeout = acct.getPrefTrashLifetime();
    long userJunkTimeout = acct.getPrefJunkLifetime();
    long userSentTimeout = acct.getPrefSentLifetime();
    long trashTimeout = pickTimeout(systemTrashTimeout, userTrashTimeout);
    long spamTimeout = pickTimeout(systemJunkTimeout, userJunkTimeout);
    boolean userFileVersioningEnabled = acct.isFileVersioningEnabled();
    long userFileVersionLifeTime = acct.getFileVersionLifetime();
    if (globalTimeout <= 0 && trashTimeout <= 0 && spamTimeout <= 0 && userInboxReadTimeout <= 0 && userInboxReadTimeout <= 0 && userInboxUnreadTimeout <= 0 && userSentTimeout <= 0 && systemDumpsterTimeoutMillis <= 0 && (!userFileVersioningEnabled || userFileVersionLifeTime <= 0)) {
        ZimbraLog.purge.debug("Retention policy does not require purge.");
        return true;
    }
    ZimbraLog.purge.info("Purging messages.");
    // sanity-check the really dangerous value...
    if (globalTimeout > 0 && globalTimeout < Constants.MILLIS_PER_MONTH) {
        // this min is also used by POP3 EXPIRE command. update Pop3Handler.MIN_EPXIRE_DAYS if it changes.
        ZimbraLog.purge.warn("global message timeout < 1 month; defaulting to 31 days");
        globalTimeout = Constants.MILLIS_PER_MONTH;
    }
    // call to purge expired messages with IMAP \Deleted flag
    // for expiration check, used zimbraMailTrashLifetime
    purgeExpiredIMAPDeletedMessages(trashTimeout);
    PurgeOldMessages redoRecorder = new PurgeOldMessages(mId);
    boolean success = false;
    try {
        beginTransaction("purgeMessages", octxt, redoRecorder);
        // get the folders we're going to be purging
        Folder trash = getFolderById(ID_FOLDER_TRASH);
        Folder spam = getFolderById(ID_FOLDER_SPAM);
        Folder sent = getFolderById(ID_FOLDER_SENT);
        Folder inbox = getFolderById(ID_FOLDER_INBOX);
        boolean purgedAll = true;
        if (globalTimeout > 0) {
            int numPurged = Folder.purgeMessages(this, null, getOperationTimestampMillis() - globalTimeout, null, false, false, maxItemsPerFolder);
            ZimbraLog.purge.debug("Purged %d messages from All Folders", numPurged);
            purgedAll = updatePurgedAll(purgedAll, numPurged, maxItemsPerFolder);
        }
        if (trashTimeout > 0) {
            boolean useChangeDate = acct.getBooleanAttr(Provisioning.A_zimbraMailPurgeUseChangeDateForTrash, true);
            int numPurged = Folder.purgeMessages(this, trash, getOperationTimestampMillis() - trashTimeout, null, useChangeDate, true, maxItemsPerFolder);
            ZimbraLog.purge.debug("Purged %d messages from Trash", numPurged);
            purgedAll = updatePurgedAll(purgedAll, numPurged, maxItemsPerFolder);
        }
        if (spamTimeout > 0) {
            boolean useChangeDate = acct.isMailPurgeUseChangeDateForSpam();
            int numPurged = Folder.purgeMessages(this, spam, getOperationTimestampMillis() - spamTimeout, null, useChangeDate, false, maxItemsPerFolder);
            purgedAll = updatePurgedAll(purgedAll, numPurged, maxItemsPerFolder);
            ZimbraLog.purge.debug("Purged %d messages from Spam", numPurged);
        }
        if (userInboxReadTimeout > 0) {
            int numPurged = Folder.purgeMessages(this, inbox, getOperationTimestampMillis() - userInboxReadTimeout, false, false, false, maxItemsPerFolder);
            purgedAll = updatePurgedAll(purgedAll, numPurged, maxItemsPerFolder);
            ZimbraLog.purge.debug("Purged %d read messages from Inbox", numPurged);
        }
        if (userInboxUnreadTimeout > 0) {
            int numPurged = Folder.purgeMessages(this, inbox, getOperationTimestampMillis() - userInboxUnreadTimeout, true, false, false, maxItemsPerFolder);
            purgedAll = updatePurgedAll(purgedAll, numPurged, maxItemsPerFolder);
            ZimbraLog.purge.debug("Purged %d unread messages from Inbox", numPurged);
        }
        if (userSentTimeout > 0) {
            int numPurged = Folder.purgeMessages(this, sent, getOperationTimestampMillis() - userSentTimeout, null, false, false, maxItemsPerFolder);
            purgedAll = updatePurgedAll(purgedAll, numPurged, maxItemsPerFolder);
            ZimbraLog.purge.debug("Purged %d messages from Sent", numPurged);
        }
        if (systemDumpsterTimeoutMillis > 0) {
            int numPurged = purgeDumpster(getOperationTimestampMillis() - systemDumpsterTimeoutMillis, maxItemsPerFolder);
            ZimbraLog.purge.debug("Purged %d messages from Dumpster", numPurged);
            purgedAll = updatePurgedAll(purgedAll, numPurged, maxItemsPerFolder);
        }
        if (userFileVersioningEnabled && userFileVersionLifeTime > 0) {
            int numPurged = MailItem.purgeRevisions(this, getOperationTimestampMillis() - userFileVersionLifeTime);
            ZimbraLog.purge.debug("Purged %d revisions", numPurged);
        }
        // Process any folders that have retention policy set.
        for (Folder folder : getFolderList(octxt, SortBy.NONE)) {
            RetentionPolicy rp = RetentionPolicyManager.getInstance().getCompleteRetentionPolicy(acct, folder.getRetentionPolicy());
            for (Policy policy : rp.getPurgePolicy()) {
                long folderLifetime;
                try {
                    folderLifetime = DateUtil.getTimeInterval(policy.getLifetime());
                } catch (ServiceException e) {
                    ZimbraLog.purge.error("Invalid purge lifetime set for folder %s.", folder.getPath(), e);
                    continue;
                }
                long folderTimeout = getOperationTimestampMillis() - folderLifetime;
                int numPurged = Folder.purgeMessages(this, folder, folderTimeout, null, false, false, maxItemsPerFolder);
                purgedAll = updatePurgedAll(purgedAll, numPurged, maxItemsPerFolder);
            }
        }
        // Process any tags that have retention policy set.
        for (Tag tag : getTagList(octxt)) {
            RetentionPolicy rp = RetentionPolicyManager.getInstance().getCompleteRetentionPolicy(acct, tag.getRetentionPolicy());
            for (Policy policy : rp.getPurgePolicy()) {
                long tagLifetime;
                try {
                    tagLifetime = DateUtil.getTimeInterval(policy.getLifetime());
                } catch (ServiceException e) {
                    ZimbraLog.purge.error("Invalid purge lifetime set for tag %s.", tag.getName(), e);
                    continue;
                }
                long tagTimeout = getOperationTimestampMillis() - tagLifetime;
                PendingDelete info = DbTag.getLeafNodes(this, tag, (int) (tagTimeout / 1000), maxItemsPerFolder);
                MailItem.delete(this, info, null, false, false);
                List<Integer> ids = info.itemIds.getIds(MailItem.Type.MESSAGE);
                int numPurged = (ids == null ? 0 : ids.size());
                purgedAll = updatePurgedAll(purgedAll, numPurged, maxItemsPerFolder);
            }
        }
        // deletes have already been collected, so fetch the tombstones and write once
        TypedIdList tombstones = collectPendingTombstones();
        if (tombstones != null && !tombstones.isEmpty()) {
            DbMailItem.writeTombstones(this, tombstones);
        }
        if (Threader.isHashPurgeAllowed(acct)) {
            int convTimeoutSecs = (int) (LC.conversation_max_age_ms.longValue() / Constants.MILLIS_PER_SECOND);
            DbMailItem.closeOldConversations(this, getOperationTimestamp() - convTimeoutSecs);
        }
        if (isTrackingSync()) {
            int tombstoneTimeoutSecs = (int) (LC.tombstone_max_age_ms.longValue() / Constants.MILLIS_PER_SECOND);
            int largestTrimmed = DbMailItem.purgeTombstones(this, getOperationTimestamp() - tombstoneTimeoutSecs);
            if (largestTrimmed > getSyncCutoff()) {
                currentChange().sync = largestTrimmed;
                DbMailbox.setSyncCutoff(this, currentChange().sync);
            }
        }
        // record the purge time.
        if (purgedAll) {
            DbMailbox.updateLastPurgeAt(this, System.currentTimeMillis());
        }
        success = true;
        ZimbraLog.purge.debug("purgedAll=%b", purgedAll);
        return purgedAll;
    } finally {
        endTransaction(success);
    }
}
Also used : PurgeOldMessages(com.zimbra.cs.redolog.op.PurgeOldMessages) RetentionPolicy(com.zimbra.soap.mail.type.RetentionPolicy) SetRetentionPolicy(com.zimbra.cs.redolog.op.SetRetentionPolicy) Policy(com.zimbra.soap.mail.type.Policy) Account(com.zimbra.cs.account.Account) CreateFolder(com.zimbra.cs.redolog.op.CreateFolder) ZFolder(com.zimbra.client.ZFolder) RetentionPolicy(com.zimbra.soap.mail.type.RetentionPolicy) SetRetentionPolicy(com.zimbra.cs.redolog.op.SetRetentionPolicy) TypedIdList(com.zimbra.cs.mailbox.util.TypedIdList) RefreshMountpoint(com.zimbra.cs.redolog.op.RefreshMountpoint) TargetConstraint(com.zimbra.cs.mailbox.MailItem.TargetConstraint) CreateMountpoint(com.zimbra.cs.redolog.op.CreateMountpoint) AccountServiceException(com.zimbra.cs.account.AccountServiceException) ServiceException(com.zimbra.common.service.ServiceException) AlterItemTag(com.zimbra.cs.redolog.op.AlterItemTag) CreateTag(com.zimbra.cs.redolog.op.CreateTag) DbTag(com.zimbra.cs.db.DbTag) PendingDelete(com.zimbra.cs.mailbox.MailItem.PendingDelete)

Example 5 with PendingDelete

use of com.zimbra.cs.mailbox.MailItem.PendingDelete in project zm-mailbox by Zimbra.

the class DbTag method getLeafNodes.

public static PendingDelete getLeafNodes(Mailbox mbox, Tag tag, int before, Integer maxItems) throws ServiceException {
    DbConnection conn = mbox.getOperationConnection();
    PreparedStatement stmt = null;
    ResultSet rs = null;
    try {
        String orderByLimit = "";
        if (maxItems != null && Db.supports(Db.Capability.LIMIT_CLAUSE)) {
            orderByLimit = " ORDER BY date " + Db.getInstance().limit(maxItems);
        }
        String mailboxesMatchAnd = DebugConfig.disableMailboxGroups ? "" : "mi.mailbox_id = ti.mailbox_id AND ";
        stmt = conn.prepareStatement("SELECT " + DbMailItem.LEAF_NODE_FIELDS + " FROM " + DbMailItem.getMailItemTableName(mbox, "mi") + " INNER JOIN " + getTaggedItemTableName(mbox, "ti") + " ON " + mailboxesMatchAnd + "ti.item_id = mi.id" + " WHERE " + inThisMailboxAnd("ti") + "ti.tag_id = ? AND date < ? AND type NOT IN " + DbMailItem.NON_SEARCHABLE_TYPES + orderByLimit);
        int pos = 1;
        pos = DbMailItem.setMailboxId(stmt, mbox, pos);
        stmt.setInt(pos++, tag.getId());
        stmt.setInt(pos++, before);
        PendingDelete info = DbMailItem.accumulateDeletionInfo(mbox, stmt);
        stmt = null;
        return info;
    } catch (SQLException e) {
        throw ServiceException.FAILURE("fetching list of items for purge", e);
    } finally {
        DbPool.closeResults(rs);
        DbPool.closeStatement(stmt);
    }
}
Also used : SQLException(java.sql.SQLException) ResultSet(java.sql.ResultSet) PreparedStatement(java.sql.PreparedStatement) DbConnection(com.zimbra.cs.db.DbPool.DbConnection) PendingDelete(com.zimbra.cs.mailbox.MailItem.PendingDelete)

Aggregations

PendingDelete (com.zimbra.cs.mailbox.MailItem.PendingDelete)10 DbConnection (com.zimbra.cs.db.DbPool.DbConnection)5 ResultSet (java.sql.ResultSet)5 SQLException (java.sql.SQLException)5 PreparedStatement (java.sql.PreparedStatement)4 ZFolder (com.zimbra.client.ZFolder)2 ServiceException (com.zimbra.common.service.ServiceException)2 AccountServiceException (com.zimbra.cs.account.AccountServiceException)2 Folder (com.zimbra.cs.mailbox.Folder)2 TargetConstraint (com.zimbra.cs.mailbox.MailItem.TargetConstraint)2 CreateFolder (com.zimbra.cs.redolog.op.CreateFolder)2 CreateMountpoint (com.zimbra.cs.redolog.op.CreateMountpoint)2 RefreshMountpoint (com.zimbra.cs.redolog.op.RefreshMountpoint)2 Account (com.zimbra.cs.account.Account)1 DbTag (com.zimbra.cs.db.DbTag)1 MessageChannelException (com.zimbra.cs.iochannel.MessageChannelException)1 NoSuchItemException (com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException)1 Mailbox (com.zimbra.cs.mailbox.Mailbox)1 TypedIdList (com.zimbra.cs.mailbox.util.TypedIdList)1 AlterItemTag (com.zimbra.cs.redolog.op.AlterItemTag)1