public void forceDeleteMailbox(Mailbox mbox) throws ServiceException {
    DeleteMailbox redoRecorder = new DeleteMailbox(mbox.getId());
    boolean success = false;
    try {
      beginTransaction("deleteMailbox", null, redoRecorder);
      redoRecorder.log();

      try {
        // remove all the relevant entries from the database
        DbConnection conn = getOperationConnection();
        ZimbraLog.mailbox.info(
            "attempting to remove the zimbra.mailbox row for id " + mbox.getId());
        DbOfflineMailbox.forceDeleteMailbox(conn, mbox.getId());
        success = true;
      } finally {
        // commit the DB transaction before touching the store!  (also ends the operation)
        endTransaction(success);
      }

      if (success) {
        // remove all traces of the mailbox from the Mailbox cache
        //   (so anyone asking for the Mailbox gets NO_SUCH_MBOX or creates a fresh new empty one
        // with a different id)
        MailboxManager.getInstance().markMailboxDeleted(mbox);
      }
    } finally {
      if (success) {
        redoRecorder.commit();
      } else {
        redoRecorder.abort();
      }
    }
  }
 @Override
 public CalendarItem getCalendarItemByUid(OperationContext octxt, String uid)
     throws ServiceException {
   lock.lock();
   try {
     CalendarItem item = super.getCalendarItemByUid(octxt, uid);
     if (item == null
         && Db.supports(Capability.CASE_SENSITIVE_COMPARISON)
         && Invite.isOutlookUid(uid)) {
       if (!uid.toLowerCase().equals(uid)) {
         // maybe stored in db in lower case
         item = super.getCalendarItemByUid(octxt, uid.toLowerCase());
         if (item != null) {
           OfflineLog.offline.debug(
               "coercing Outlook calitem [%d] UID to upper case", item.getId());
           boolean success = false;
           try {
             beginTransaction("forceUpperAppointment", octxt);
             uncache(item);
             DbOfflineMailbox.forceUidUpperCase(this, uid.toLowerCase());
             item = super.getCalendarItemByUid(octxt, uid);
             assert (item != null);
             success = true;
           } finally {
             endTransaction(success);
           }
         }
       } else {
         // possible that we're receiving update from unpatched zcs which is in lower case and our
         // db is
         // already correct return the upper case equivalent; server will keep sending lower until
         // it's
         // patched but should handle pushes in upper since MySQL is case insensitive
         item = super.getCalendarItemByUid(octxt, uid.toUpperCase());
         if (item != null) {
           OfflineLog.offline.debug("received lower case UID but our DB is already in upper case");
         }
       }
     }
     return item;
   } finally {
     lock.release();
   }
 }
  void syncDate(OperationContext octxt, int itemId, MailItem.Type type, int date)
      throws ServiceException {
    if (date < 0) {
      return;
    }
    boolean success = false;
    try {
      beginTransaction("syncChangeIds", octxt);

      MailItem item = getItemById(itemId, type);
      markItemModified(item, Change.INTERNAL_ONLY);

      // update the database
      DbOfflineMailbox.setDate(item, date);

      // ... and update the in-memory item as well
      item.mData.date = date;

      success = true;
    } finally {
      endTransaction(success);
    }
  }
  boolean renumberItem(OperationContext octxt, int id, MailItem.Type type, int newId)
      throws ServiceException {
    if (id == newId) {
      return true;
    } else if (id <= 0 || newId <= 0) {
      throw ServiceException.FAILURE(
          "invalid item id when renumbering (" + id + " => " + newId + ")", null);
    }

    lock.lock();
    try {
      boolean success = false;
      try {
        beginTransaction("renumberItem", octxt);
        MailItem item = getItemById(id, type);
        if (item.getId() == newId) {
          OfflineLog.offline.info(
              "Item already renumbered; no need to renumber (%d => %d)", id, newId);
          return true;
        } else if (item.getId() != id) {
          OfflineLog.offline.warn(
              "renumbering item which may have already been renumbered (%d => %d) : itemId = %d",
              id, newId, item.getId());
        }
        // changing a message's item id needs to purge its Conversation (virtual or real)
        if (item instanceof Message) uncacheItem(item.getParentId());

        // mark old blob as disposable, but don't reindex item because INDEX_ID should still be
        // correct
        MailboxBlob mblob = item.getBlob();
        if (mblob != null) {
          // register old blob for post-commit deletion
          item.markBlobForDeletion();
          item.mBlob = null;

          // copy blob to new id (note that item.getSavedSequence() may change again later)
          try {
            MailboxBlob newBlob =
                StoreManager.getInstance().copy(mblob, this, newId, item.getSavedSequence());
            markOtherItemDirty(newBlob);
          } catch (IOException e) {
            throw ServiceException.FAILURE(
                "could not link blob for renumbered item (" + id + " => " + newId + ")", e);
          }
        }

        // update the id in the database and in memory
        markItemDeleted(item.getType(), id);
        try {
          DbOfflineMailbox.renumberItem(item, newId);
          uncache(item);
        } catch (ServiceException se) {
          throw ServiceException.FAILURE(
              "Failure renumbering item name["
                  + item.getName()
                  + "] subject["
                  + item.getSubject()
                  + "]",
              se);
        }
        item.mId = item.mData.id = newId;
        item.markItemCreated();

        if (item instanceof Folder || item instanceof Tag) {
          // replace with the new item
          cache(item);
          if (item instanceof Folder) {
            // sub folders might have wrong id
            List<Folder> subFolders = ((Folder) item).getSubfolders(octxt);
            for (Folder subFolder : subFolders) {
              subFolder.mData.folderId = newId;
              subFolder.mData.parentId = newId;
              cache(subFolder); // make sure it's in the cache
            }
          }

          // msgs are lazy-loaded so purge is safe
          purge(MailItem.Type.MESSAGE);
        }
        success = true;
      } catch (MailServiceException.NoSuchItemException nsie) {
        // item deleted from local before sync completes renumbering
        OfflineLog.offline.info(
            "item %d deleted from local db before sync completes renumbering to %d", id, newId);
        TypedIdList tombstones = new TypedIdList();
        tombstones.add(type, newId, null);
        DbMailItem.writeTombstones(this, tombstones);
        success = true;
        return false;
      } finally {
        endTransaction(success);
      }
      mRenumbers.put(id, newId);
      return true;
    } finally {
      lock.release();
    }
  }