Search in sources :

Example 16 with Blob

use of com.zimbra.cs.store.Blob in project zm-mailbox by Zimbra.

the class ExternalBlobConsistencyChecker method check.

@Override
public Results check(Collection<Short> volumeIds, int mboxId, boolean checkSize, boolean reportUsedBlobs) throws ServiceException {
    mailboxId = mboxId;
    this.checkSize = checkSize;
    this.reportUsedBlobs = reportUsedBlobs;
    results = new Results();
    Mailbox mbox = MailboxManager.getInstance().getMailboxById(mailboxId);
    DbConnection conn = null;
    assert (StoreManager.getInstance() instanceof ExternalStoreManager);
    ExternalStoreManager sm = (ExternalStoreManager) StoreManager.getInstance();
    try {
        unexpectedBlobPaths = sm.getAllBlobPaths(mbox);
    } catch (IOException ioe) {
        log.error("IOException getting remote blob list", ioe);
    }
    try {
        conn = DbPool.getConnection();
        int mailboxMaxId = DbBlobConsistency.getMaxId(conn, mbox);
        int minId = 0;
        int maxId = CHUNK_SIZE;
        while (minId <= mailboxMaxId) {
            for (BlobInfo blobInfo : DbBlobConsistency.getExternalMailItemBlobInfo(conn, mbox, minId, maxId)) {
                checkExternalBlob(mbox, checkSize, blobInfo, sm);
            }
            for (BlobInfo blobInfo : DbBlobConsistency.getExternalMailItemDumpsterBlobInfo(conn, mbox, minId, maxId)) {
                checkExternalBlob(mbox, checkSize, blobInfo, sm);
            }
            for (BlobInfo blobInfo : DbBlobConsistency.getExternalRevisionBlobInfo(conn, mbox, minId, maxId)) {
                checkExternalBlob(mbox, checkSize, blobInfo, sm);
            }
            for (BlobInfo blobInfo : DbBlobConsistency.getExternalRevisionDumpsterBlobInfo(conn, mbox, minId, maxId)) {
                checkExternalBlob(mbox, checkSize, blobInfo, sm);
            }
            minId = maxId + 1;
            maxId += CHUNK_SIZE;
        }
    } finally {
        DbPool.quietClose(conn);
    }
    for (String unexpected : unexpectedBlobPaths) {
        BlobInfo bi = new BlobInfo();
        bi.external = true;
        bi.locator = unexpected;
        bi.path = unexpected;
        results.unexpectedBlobs.put(0, bi);
        try {
            Blob blob = sm.getLocalBlob(mbox, unexpected, false);
            bi.fileSize = blob.getFile().length();
        } catch (IOException ioe) {
            //log this?
            bi.fileSize = 0L;
            bi.fetchException = ioe;
        }
    }
    return results;
}
Also used : Blob(com.zimbra.cs.store.Blob) MailboxBlob(com.zimbra.cs.store.MailboxBlob) Mailbox(com.zimbra.cs.mailbox.Mailbox) IOException(java.io.IOException) DbConnection(com.zimbra.cs.db.DbPool.DbConnection)

Example 17 with Blob

use of com.zimbra.cs.store.Blob 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 18 with Blob

use of com.zimbra.cs.store.Blob in project zm-mailbox by Zimbra.

the class Mailbox method addMessage.

private Message addMessage(OperationContext octxt, ParsedMessage pm, int folderId, boolean noICal, int flags, String[] tags, int conversationId, String rcptEmail, Message.DraftInfo dinfo, CustomMetadata customData, DeliveryContext dctxt) throws IOException, ServiceException {
    // and then actually add the message
    long start = ZimbraPerf.STOPWATCH_MBOX_ADD_MSG.start();
    //
    if (!noICal) {
        try {
            CalendarPartInfo cpi = pm.getCalendarPartInfo();
            if (cpi != null && CalendarItem.isAcceptableInvite(getAccount(), cpi)) {
                if (ICalTok.REPLY.equals(cpi.method)) {
                    processICalReplies(octxt, cpi.cal, null);
                } else if (ICalTok.COUNTER.equals(cpi.method)) {
                    processICalReplies(octxt, cpi.cal, pm.getSender());
                }
            }
        } catch (Exception e) {
            ZimbraLog.calendar.warn("Error during calendar processing.  Continuing with message add", e);
        }
    }
    // Store the incoming blob if necessary.
    if (dctxt == null) {
        dctxt = new DeliveryContext();
    }
    StoreManager sm = StoreManager.getInstance();
    Blob blob = dctxt.getIncomingBlob();
    boolean deleteIncoming = false;
    if (blob == null) {
        InputStream in = null;
        try {
            in = pm.getRawInputStream();
            blob = sm.storeIncoming(in);
        } finally {
            ByteUtil.closeStream(in);
        }
        dctxt.setIncomingBlob(blob);
        deleteIncoming = true;
    }
    StagedBlob staged = sm.stage(blob, this);
    lock.lock();
    try {
        try {
            return addMessageInternal(octxt, pm, folderId, noICal, flags, tags, conversationId, rcptEmail, dinfo, customData, dctxt, staged);
        } finally {
            if (deleteIncoming) {
                sm.quietDelete(dctxt.getIncomingBlob());
            }
            sm.quietDelete(staged);
        }
    } finally {
        lock.release();
        ZimbraPerf.STOPWATCH_MBOX_ADD_MSG.stop(start);
    }
}
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) StagedBlob(com.zimbra.cs.store.StagedBlob) Rfc822ValidationInputStream(com.zimbra.common.mime.Rfc822ValidationInputStream) CopyInputStream(com.zimbra.common.util.CopyInputStream) InputStream(java.io.InputStream) CalendarPartInfo(com.zimbra.cs.mime.ParsedMessage.CalendarPartInfo) 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) StoreManager(com.zimbra.cs.store.StoreManager)

Example 19 with Blob

use of com.zimbra.cs.store.Blob in project zm-mailbox by Zimbra.

the class OctopusPatchFormatter method saveCallback.

// Formatter API
@Override
public void saveCallback(UserServletContext context, String contentType, Folder folder, String filename) throws IOException, ServiceException, UserServletException {
    log.info("Uploading patch for " + filename);
    if (filename == null) {
        throw new UserServletException(HttpServletResponse.SC_BAD_REQUEST, "Missing filename");
    }
    MailItem item = null;
    Mailbox mbox = folder.getMailbox();
    try {
        item = mbox.getItemByPath(context.opContext, filename, folder.getId());
        if (!(item instanceof Document))
            throw new UserServletException(HttpServletResponse.SC_BAD_REQUEST, "cannot overwrite existing object at that path");
    } catch (NoSuchItemException e) {
        log.debug("No document found at " + filename + "(folder id=" + folder.getId() + "; will create new one");
    }
    PatchInputStream pis = null;
    PatchStore.IncomingPatch ip = null;
    try {
        ip = patchStore.createIncomingPatch(context.targetAccount.getId());
        int defaultFileId = 0;
        int defaultVersion = 0;
        if (item != null) {
            defaultFileId = item.getId();
            defaultVersion = item.getVersion();
        }
        pis = PatchInputStream.create(context.getRequestInputStream(), // the current (target) user's view
        context.targetMailbox, context.opContext, defaultFileId, defaultVersion, ip.getOutputStream(), ip.getManifest());
        String creator = context.getAuthAccount() == null ? null : context.getAuthAccount().getName();
        if (contentType == null) {
            contentType = MimeDetect.getMimeDetect().detect(filename);
            if (contentType == null)
                contentType = MimeConstants.CT_APPLICATION_OCTET_STREAM;
        }
        log.debug("Storing blob");
        Blob blob = StoreManager.getInstance().storeIncoming(pis);
        log.debug("Creating parsed document; filename=" + filename + ", contentType=" + contentType + ", creator=" + creator);
        ParsedDocument pd = new ParsedDocument(blob, filename, contentType, System.currentTimeMillis(), creator, context.req.getHeader("X-Zimbra-Description"), true);
        log.debug("Parsed document created " + filename);
        // scan upload for viruses
        StringBuffer info = new StringBuffer();
        UploadScanner.Result result = UploadScanner.acceptStream(pis, info);
        if (result == UploadScanner.REJECT)
            throw MailServiceException.UPLOAD_REJECTED(filename, info.toString());
        if (result == UploadScanner.ERROR)
            throw MailServiceException.SCAN_ERROR(filename);
        if (item == null) {
            log.debug("Creating new document " + filename);
            item = mbox.createDocument(context.opContext, folder.getId(), pd, MailItem.Type.DOCUMENT, 0);
        } else {
            log.debug("Creating new version of the document " + filename + ", current version: " + item.getVersion());
            item = mbox.addDocumentRevision(context.opContext, item.getId(), pd);
        }
        patchStore.acceptPatch(ip, item.getId(), item.getVersion());
        NativeFormatter.sendZimbraHeaders(context, context.resp, item);
    } catch (PatchException e) {
        log.error("Patch upload failed: " + e);
        patchStore.rejectPatch(ip);
        throw new UserServletException(HttpServletResponse.SC_CONFLICT, "patch cannot be applied, try uploading whole file", e);
    } finally {
        try {
            pis.close();
        } catch (Exception e) {
            log.error("Exception during PatchInputStream close, ignored: " + e);
        }
    }
}
Also used : Blob(com.zimbra.cs.store.Blob) UserServletException(com.zimbra.cs.service.UserServletException) PatchStore(com.zimbra.cs.octosync.store.PatchStore) Document(com.zimbra.cs.mailbox.Document) ParsedDocument(com.zimbra.cs.mime.ParsedDocument) NoSuchItemException(com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException) UploadScanner(com.zimbra.cs.service.mail.UploadScanner) PatchException(com.zimbra.cs.octosync.PatchException) ServletException(javax.servlet.ServletException) ServiceException(com.zimbra.common.service.ServiceException) NoSuchItemException(com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException) IOException(java.io.IOException) FileNotFoundException(java.io.FileNotFoundException) UserServletException(com.zimbra.cs.service.UserServletException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException) MailItem(com.zimbra.cs.mailbox.MailItem) Mailbox(com.zimbra.cs.mailbox.Mailbox) ParsedDocument(com.zimbra.cs.mime.ParsedDocument) PatchInputStream(com.zimbra.cs.octosync.PatchInputStream) PatchException(com.zimbra.cs.octosync.PatchException)

Example 20 with Blob

use of com.zimbra.cs.store.Blob in project zm-mailbox by Zimbra.

the class TestStoreManager method testStore.

@Test
public void testStore() throws Exception {
    ParsedMessage pm = getMessage();
    byte[] mimeBytes = TestUtil.readInputStream(pm.getRawInputStream());
    Mailbox mbox = TestUtil.getMailbox(USER_NAME);
    StoreManager sm = StoreManager.getInstance();
    Blob blob = sm.storeIncoming(pm.getRawInputStream());
    Assert.assertEquals("blob size = message size", pm.getRawData().length, blob.getRawSize());
    Assert.assertTrue("blob content = mime content", TestUtil.bytesEqual(mimeBytes, blob.getInputStream()));
    StagedBlob staged = sm.stage(blob, mbox);
    Assert.assertEquals("staged size = blob size", blob.getRawSize(), staged.getSize());
    MailboxBlob mblob = sm.link(staged, mbox, 0, 0);
    Assert.assertEquals("link size = staged size", staged.getSize(), mblob.getSize());
    Assert.assertTrue("link content = mime content", TestUtil.bytesEqual(mimeBytes, mblob.getLocalBlob().getInputStream()));
    mblob = sm.getMailboxBlob(mbox, 0, 0, staged.getLocator());
    Assert.assertEquals("mblob size = staged size", staged.getSize(), mblob.getSize());
    Assert.assertTrue("mailboxblob content = mime content", TestUtil.bytesEqual(mimeBytes, mblob.getLocalBlob().getInputStream()));
}
Also used : Blob(com.zimbra.cs.store.Blob) MailboxBlob(com.zimbra.cs.store.MailboxBlob) StagedBlob(com.zimbra.cs.store.StagedBlob) StagedBlob(com.zimbra.cs.store.StagedBlob) Mailbox(com.zimbra.cs.mailbox.Mailbox) MailboxBlob(com.zimbra.cs.store.MailboxBlob) ParsedMessage(com.zimbra.cs.mime.ParsedMessage) StoreManager(com.zimbra.cs.store.StoreManager) Test(org.junit.Test)

Aggregations

Blob (com.zimbra.cs.store.Blob)27 MailboxBlob (com.zimbra.cs.store.MailboxBlob)18 Mailbox (com.zimbra.cs.mailbox.Mailbox)14 StagedBlob (com.zimbra.cs.store.StagedBlob)13 ParsedMessage (com.zimbra.cs.mime.ParsedMessage)12 IOException (java.io.IOException)11 StoreManager (com.zimbra.cs.store.StoreManager)10 ServiceException (com.zimbra.common.service.ServiceException)9 InputStream (java.io.InputStream)7 Test (org.junit.Test)6 MailServiceException (com.zimbra.cs.mailbox.MailServiceException)5 NoSuchItemException (com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException)4 StoreIncomingBlob (com.zimbra.cs.redolog.op.StoreIncomingBlob)4 Rfc822ValidationInputStream (com.zimbra.common.mime.Rfc822ValidationInputStream)3 CopyInputStream (com.zimbra.common.util.CopyInputStream)3 AccountServiceException (com.zimbra.cs.account.AccountServiceException)3 DeliveryContext (com.zimbra.cs.mailbox.DeliveryContext)3 ParsedMessageOptions (com.zimbra.cs.mime.ParsedMessageOptions)3 AbstractStoreManagerTest (com.zimbra.cs.store.AbstractStoreManagerTest)3 BlobInputStream (com.zimbra.cs.store.BlobInputStream)3