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;
}
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);
}
}
}
}
}
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);
}
}
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);
}
}
}
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()));
}
Aggregations