Search in sources :

Example 6 with PendingDelete

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

the class Mailbox method endTransaction.

/**
     * Be very careful when changing code in this method.  The order of almost
     * every line of code is important to ensure correct redo logging and crash
     * recovery.
     *
     * @param success true to commit the transaction, false to rollback
     * @throws ServiceException error
     */
protected void endTransaction(boolean success) throws ServiceException {
    assert !Thread.holdsLock(this) : "Use MailboxLock";
    if (lock.isUnlocked()) {
        ZimbraLog.mailbox.warn("transaction canceled because of lock failure");
        assert (!success);
        return;
    }
    // blob and index to delete
    PendingDelete deletes = null;
    // blob to delete for failure cases
    List<Object> rollbackDeletes = null;
    try {
        if (!currentChange().isActive()) {
            // would like to throw here, but it might cover another
            // exception...
            ZimbraLog.mailbox.warn("cannot end a transaction when not inside a transaction", new Exception());
            return;
        }
        if (!currentChange().endChange()) {
            return;
        }
        ServiceException exception = null;
        if (success) {
            List<IndexItemEntry> indexItems = currentChange().indexItems;
            if (!indexItems.isEmpty()) {
                assert (currentChange().writeChange);
                //TODO: See bug 15072 - we need to clear mCurrentChange.indexItems (it is stored in a temporary) here,
                // just in case item.reindex() recurses into a new transaction...
                currentChange().indexItems = new ArrayList<IndexItemEntry>();
                index.add(indexItems);
            }
            // update mailbox size, folder unread/message counts
            try {
                snapshotCounts();
            } catch (ServiceException e) {
                exception = e;
                success = false;
            }
        }
        DbConnection conn = currentChange().conn;
        // transaction, so no redo cleanup is necessary.
        if (!success) {
            DbPool.quietRollback(conn);
            rollbackDeletes = rollbackCache(currentChange());
            if (exception != null) {
                throw exception;
            }
            return;
        }
        RedoableOp redoRecorder = currentChange().recorder;
        boolean needRedo = needRedo(currentChange().octxt, redoRecorder);
        // Log the change redo record for main transaction.
        if (redoRecorder != null && needRedo) {
            redoRecorder.log(true);
        }
        boolean dbCommitSuccess = false;
        try {
            // Commit the main transaction in database.
            if (conn != null) {
                try {
                    conn.commit();
                } catch (Throwable t) {
                    // Any exception during database commit is a disaster
                    // because we don't know if the change is committed or
                    // not.  Force the server to abort.  Next restart will
                    // redo the operation to ensure the change is made and
                    // committed.  (bug 2121)
                    Zimbra.halt("Unable to commit database transaction.  Forcing server to abort.", t);
                }
            }
            dbCommitSuccess = true;
        } finally {
            if (!dbCommitSuccess) {
                // recovery will try to redo the operation.
                if (needRedo) {
                    if (redoRecorder != null) {
                        redoRecorder.abort();
                    }
                }
                DbPool.quietRollback(conn);
                rollbackDeletes = rollbackCache(currentChange());
                return;
            }
        }
        if (needRedo) {
            // case would result in a redo error, and the second case would index the wrong value.
            if (redoRecorder != null) {
                if (currentChange().dirty != null && !currentChange().dirty.changedTypes.isEmpty()) {
                    // if an "all accounts" waitset is active, and this change has an appropriate type,
                    // then we'll need to set a commit-callback
                    AllAccountsRedoCommitCallback cb = AllAccountsRedoCommitCallback.getRedoCallbackIfNecessary(getAccountId(), currentChange().dirty.changedTypes);
                    if (cb != null) {
                        redoRecorder.setCommitCallback(cb);
                    }
                }
                redoRecorder.commit();
            }
        }
        boolean changeMade = currentChange().changeId != MailboxChange.NO_CHANGE;
        // keep a reference for cleanup
        deletes = currentChange().deletes;
        // deletes outside the lock
        // We are finally done with database and redo commits. Cache update
        // comes last.
        commitCache(currentChange());
        // down in its call stack.
        if (changeMade) {
            index.maybeIndexDeferredItems();
        }
    } finally {
        lock.release();
        // entail a blocking network operation
        if (deletes != null) {
            if (!deletes.indexIds.isEmpty()) {
                // delete any index entries associated with items deleted from db
                index.delete(deletes.indexIds);
            }
            if (deletes.blobs != null) {
                // delete any blobs associated with items deleted from db/index
                StoreManager sm = StoreManager.getInstance();
                for (MailboxBlob blob : deletes.blobs) {
                    sm.quietDelete(blob);
                }
            }
        }
        if (rollbackDeletes != null) {
            StoreManager sm = StoreManager.getInstance();
            for (Object obj : rollbackDeletes) {
                if (obj instanceof MailboxBlob) {
                    sm.quietDelete((MailboxBlob) obj);
                } else if (obj instanceof Blob) {
                    sm.quietDelete((Blob) obj);
                }
            }
        }
    }
}
Also used : StoreIncomingBlob(com.zimbra.cs.redolog.op.StoreIncomingBlob) StagedBlob(com.zimbra.cs.store.StagedBlob) MailboxBlob(com.zimbra.cs.store.MailboxBlob) Blob(com.zimbra.cs.store.Blob) MailboxBlob(com.zimbra.cs.store.MailboxBlob) AllAccountsRedoCommitCallback(com.zimbra.cs.session.AllAccountsRedoCommitCallback) AccountServiceException(com.zimbra.cs.account.AccountServiceException) IOException(java.io.IOException) NoSuchItemException(com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException) MessageChannelException(com.zimbra.cs.iochannel.MessageChannelException) ServiceException(com.zimbra.common.service.ServiceException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) DbConnection(com.zimbra.cs.db.DbPool.DbConnection) StoreManager(com.zimbra.cs.store.StoreManager) AccountServiceException(com.zimbra.cs.account.AccountServiceException) ServiceException(com.zimbra.common.service.ServiceException) RedoableOp(com.zimbra.cs.redolog.op.RedoableOp) PendingDelete(com.zimbra.cs.mailbox.MailItem.PendingDelete)

Example 7 with PendingDelete

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

the class Mailbox method purgeImapDeleted.

public void purgeImapDeleted(OperationContext octxt) throws ServiceException {
    PurgeImapDeleted redoRecorder = new PurgeImapDeleted(mId);
    boolean success = false;
    try {
        beginTransaction("purgeImapDeleted", octxt, redoRecorder);
        Set<Folder> purgeable = getAccessibleFolders((short) (ACL.RIGHT_READ | ACL.RIGHT_DELETE));
        // short-circuit the DB call if we're tracking \Deleted counts and they're all 0
        boolean skipDB = false;
        if (getVersion().atLeast(1, 9)) {
            int deleted = 0;
            for (Folder folder : purgeable != null ? purgeable : listAllFolders()) {
                deleted += folder.getDeletedCount();
            }
            skipDB = deleted == 0;
        }
        if (!skipDB) {
            PendingDelete info = DbTag.getImapDeleted(this, purgeable);
            MailItem.delete(this, info, null, true, false);
        }
        success = true;
    } finally {
        endTransaction(success);
    }
}
Also used : PurgeImapDeleted(com.zimbra.cs.redolog.op.PurgeImapDeleted) CreateFolder(com.zimbra.cs.redolog.op.CreateFolder) ZFolder(com.zimbra.client.ZFolder) RefreshMountpoint(com.zimbra.cs.redolog.op.RefreshMountpoint) TargetConstraint(com.zimbra.cs.mailbox.MailItem.TargetConstraint) CreateMountpoint(com.zimbra.cs.redolog.op.CreateMountpoint) PendingDelete(com.zimbra.cs.mailbox.MailItem.PendingDelete)

Example 8 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, List<Folder> folders, int before, boolean globalMessages, Boolean unread, boolean useChangeDate, Integer maxItems) throws ServiceException {
    DbConnection conn = mbox.getOperationConnection();
    PreparedStatement stmt = null;
    ResultSet rs = null;
    if (folders == null) {
        folders = Collections.emptyList();
    }
    try {
        StringBuilder constraint = new StringBuilder();
        String dateColumn = (useChangeDate ? "change_date" : "date");
        if (globalMessages) {
            constraint.append(dateColumn).append(" < ? AND ").append(typeIn(MailItem.Type.MESSAGE));
        } else {
            constraint.append(dateColumn).append(" < ? AND type NOT IN ").append(NON_SEARCHABLE_TYPES);
            if (!folders.isEmpty()) {
                constraint.append(" AND ").append(DbUtil.whereIn("folder_id", folders.size()));
            }
        }
        if (unread != null) {
            constraint.append(" AND unread = ?");
        }
        String orderByLimit = "";
        if (maxItems != null && Db.supports(Db.Capability.LIMIT_CLAUSE)) {
            orderByLimit = " ORDER BY " + dateColumn + " " + Db.getInstance().limit(maxItems);
        }
        stmt = conn.prepareStatement("SELECT " + LEAF_NODE_FIELDS + " FROM " + getMailItemTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + constraint + orderByLimit);
        if (globalMessages || getTotalFolderSize(folders) > RESULTS_STREAMING_MIN_ROWS) {
            Db.getInstance().enableStreaming(stmt);
        }
        int pos = 1;
        pos = setMailboxId(stmt, mbox, pos);
        stmt.setInt(pos++, before);
        if (!globalMessages) {
            for (Folder folder : folders) {
                stmt.setInt(pos++, folder.getId());
            }
        }
        if (unread != null) {
            stmt.setBoolean(pos++, unread);
        }
        PendingDelete info = 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) Folder(com.zimbra.cs.mailbox.Folder) DbConnection(com.zimbra.cs.db.DbPool.DbConnection) PendingDelete(com.zimbra.cs.mailbox.MailItem.PendingDelete)

Example 9 with PendingDelete

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

the class DbMailItem method accumulateDeletionInfo.

/** Note: In all cases, this method closes the passed-in {@code Statement}.
     *  The caller must take care not to close it a second time. */
static PendingDelete accumulateDeletionInfo(Mailbox mbox, PreparedStatement stmt) throws ServiceException {
    ResultSet rs = null;
    try {
        rs = stmt.executeQuery();
        PendingDelete info = new PendingDelete();
        info.size = 0;
        List<Integer> versionedIds = accumulateLeafNodes(info, mbox, rs);
        rs.close();
        rs = null;
        stmt.close();
        stmt = null;
        accumulateLeafRevisions(info, mbox, versionedIds);
        accumulateComments(info, mbox);
        return info;
    } catch (SQLException e) {
        throw ServiceException.FAILURE("accumulating deletion info", e);
    } finally {
        DbPool.closeResults(rs);
        DbPool.closeStatement(stmt);
    }
}
Also used : SQLException(java.sql.SQLException) ResultSet(java.sql.ResultSet) PendingDelete(com.zimbra.cs.mailbox.MailItem.PendingDelete)

Example 10 with PendingDelete

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

the class DbTag method getImapDeleted.

public static PendingDelete getImapDeleted(Mailbox mbox, Set<Folder> folders) throws ServiceException {
    if (folders != null && folders.isEmpty()) {
        return new PendingDelete();
    }
    DbConnection conn = mbox.getOperationConnection();
    PreparedStatement stmt = null;
    ResultSet rs = null;
    try {
        String mailboxesMatchAnd = DebugConfig.disableMailboxGroups ? "" : "mi.mailbox_id = ti.mailbox_id AND ";
        String folderconstraint = folders == null ? "" : " AND " + DbUtil.whereIn("folder_id", folders.size());
        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 = " + Flag.ID_DELETED + " AND type IN " + DbMailItem.IMAP_TYPES + folderconstraint);
        if (DbMailItem.getTotalFolderSize(folders) > DbMailItem.RESULTS_STREAMING_MIN_ROWS) {
            Db.getInstance().enableStreaming(stmt);
        }
        int pos = 1;
        pos = DbMailItem.setMailboxId(stmt, mbox, pos);
        if (folders != null) {
            for (Folder folder : folders) {
                stmt.setInt(pos++, folder.getId());
            }
        }
        PendingDelete info = DbMailItem.accumulateDeletionInfo(mbox, stmt);
        stmt = null;
        return info;
    } catch (SQLException e) {
        throw ServiceException.FAILURE("fetching list of \\Deleted 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) Folder(com.zimbra.cs.mailbox.Folder) 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