use of com.zimbra.cs.session.PendingModifications in project zm-mailbox by Zimbra.
the class Mailbox method isItemModified.
/** Returns whether the given item has been marked dirty for a particular
* reason during the current transaction. Outside of a transaction, this
* method will return {@code false}.
* @param item The {@code MailItem} we're interested in.
* @param how A bitmask of {@link Change} "why" flags (e.g. {@code
* Change#MODIFIED_FLAGS}).
* @see Change */
public boolean isItemModified(MailItem item, int how) {
PendingModifications dirty = currentChange().dirty;
if (!dirty.hasNotifications()) {
return false;
}
PendingModifications.ModificationKey mkey = new PendingModifications.ModificationKey(item);
if (dirty.created != null && dirty.created.containsKey(mkey)) {
return true;
}
Change chg = dirty.modified == null ? null : dirty.modified.get(mkey);
return chg != null && (chg.why & how) != 0;
}
use of com.zimbra.cs.session.PendingModifications in project zm-mailbox by Zimbra.
the class MemcachedCacheManager method notify.
@Override
public void notify(ChangeNotification notification) {
PendingModifications mods = notification.mods;
int changeId = notification.lastChangeId;
// We have to notify calendar cache before checking memcached connectedness
// because a portion of calendar cache is not memcached-based.
CalendarCacheManager.getInstance().notifyCommittedChanges(mods, changeId);
if (MemcachedConnector.isConnected()) {
EffectiveACLCache.getInstance().notifyCommittedChanges(mods, changeId);
}
}
use of com.zimbra.cs.session.PendingModifications in project zm-mailbox by Zimbra.
the class Mailbox method commitCache.
private void commitCache(MailboxChange change) {
if (change == null) {
return;
}
ChangeNotification notification = null;
// save for notifications (below)
PendingModifications dirty = null;
if (change.dirty != null && change.dirty.hasNotifications()) {
assert (lock.isWriteLockedByCurrentThread());
assert (currentChange().writeChange);
dirty = change.dirty;
change.dirty = new PendingModifications();
}
Session source = change.octxt == null ? null : change.octxt.getSession();
assert (!change.hasChanges() || lock.isWriteLockedByCurrentThread());
try {
// the mailbox data has changed, so commit the changes
if (change.sync != null) {
mData.trackSync = change.sync;
}
if (change.imap != null) {
mData.trackImap = change.imap;
}
if (change.size != MailboxChange.NO_CHANGE) {
mData.size = change.size;
}
if (change.itemId != MailboxChange.NO_CHANGE) {
mData.lastItemId = change.itemId;
}
if (change.contacts != MailboxChange.NO_CHANGE) {
mData.contacts = change.contacts;
}
if (change.changeId != MailboxChange.NO_CHANGE && change.changeId > mData.lastChangeId) {
mData.lastChangeId = change.changeId;
mData.lastChangeDate = change.timestamp;
}
if (change.accessed != MailboxChange.NO_CHANGE) {
mData.lastWriteDate = change.accessed;
}
if (change.recent != MailboxChange.NO_CHANGE) {
mData.recentMessages = change.recent;
}
if (change.config != null) {
if (change.config.getSecond() == null) {
if (mData.configKeys != null) {
mData.configKeys.remove(change.config.getFirst());
}
} else {
if (mData.configKeys == null) {
mData.configKeys = new HashSet<String>(1);
}
mData.configKeys.add(change.config.getFirst());
}
}
if (change.deletes != null && change.deletes.blobs != null) {
// remove cached messages
for (String digest : change.deletes.blobDigests) {
MessageCache.purge(digest);
}
}
// committed changes, so notify any listeners
if (dirty != null && dirty.hasNotifications()) {
try {
// try to get a copy of the changeset that *isn't* live
dirty = snapshotModifications(dirty);
} catch (ServiceException e) {
ZimbraLog.mailbox.warn("error copying notifications; will notify with live set", e);
}
try {
notification = new ChangeNotification(getAccount(), dirty, change.octxt, mData.lastChangeId, change.getOperation(), change.timestamp);
} catch (ServiceException e) {
ZimbraLog.mailbox.warn("error getting account for the mailbox", e);
}
}
} catch (RuntimeException e) {
ZimbraLog.mailbox.error("ignoring error during cache commit", e);
} finally {
// keep our MailItem cache at a reasonable size
trimItemCache();
// make sure we're ready for the next change
change.reset();
}
if (notification != null) {
for (Session session : mListeners) {
try {
session.notifyPendingChanges(notification.mods, notification.lastChangeId, source);
} catch (RuntimeException e) {
ZimbraLog.mailbox.error("ignoring error during notification", e);
}
}
// send to the message channel
DbConnection conn = null;
try {
if (Zimbra.isAlwaysOn()) {
conn = DbPool.getConnection();
List<String> serverids = DbSession.get(conn, getId());
for (String serverid : serverids) {
Server server = Provisioning.getInstance().getServerById(serverid);
if (server.isLocalServer()) {
continue;
}
MailboxNotification ntfn = MailboxNotification.create(getAccountId(), mData.lastChangeId, dirty.getSerializedBytes());
MessageChannel.getInstance().sendMessage(server, ntfn);
}
}
} catch (ServiceException e) {
ZimbraLog.session.warn("unable to get target server", e);
} catch (MessageChannelException e) {
ZimbraLog.session.warn("unable to create MailboxNotification", e);
return;
} catch (IOException e) {
ZimbraLog.session.warn("unable to create MailboxNotification", e);
return;
} finally {
if (conn != null) {
conn.closeQuietly();
}
}
MailboxListener.notifyListeners(notification);
}
}
use of com.zimbra.cs.session.PendingModifications in project zm-mailbox by Zimbra.
the class Mailbox method snapshotModifications.
/** Makes a deep copy of the {@code PendingModifications} object with
* {@link Flag#BITMASK_UNCACHED} set on each {@code MailItem} present in
* the {@code created} and {@code modified} hashes. These copied {@code
* MailItem}s are not linked to their {@code Mailbox} and thus will not
* change when modifications are subsequently made to the contents of the
* {@code Mailbox}. The original {@code PendingModifications} object and
* the {@code MailItem}s it references are unchanged.
* <p>
* This method should only be called <i>immediately</i> before notifying
* listeners of the changes from the currently-ending transaction. */
private PendingModifications snapshotModifications(PendingModifications pms) throws ServiceException {
if (pms == null) {
return null;
}
assert (currentChange().depth == 0);
ItemCache cache = mItemCache.get();
FolderCache folders = mFolderCache == null || Collections.disjoint(pms.changedTypes, FOLDER_TYPES) ? mFolderCache : snapshotFolders();
PendingModifications snapshot = new PendingModifications();
if (pms.deleted != null && !pms.deleted.isEmpty()) {
snapshot.recordDeleted(pms.deleted);
}
if (pms.created != null && !pms.created.isEmpty()) {
for (MailItem item : pms.created.values()) {
if (item instanceof Folder && folders != null) {
Folder folder = folders.get(item.getId());
if (folder == null) {
ZimbraLog.mailbox.warn("folder missing from snapshotted folder set: %d", item.getId());
folder = (Folder) item;
}
snapshot.recordCreated(folder);
} else if (item instanceof Tag) {
if (((Tag) item).isListed()) {
snapshot.recordCreated(snapshotItem(item));
}
} else {
// NOTE: if the folder cache is null, folders fall down here and should always get copy == false
if (cache != null && cache.contains(item)) {
item = snapshotItem(item);
}
snapshot.recordCreated(item);
}
}
}
if (pms.modified != null && !pms.modified.isEmpty()) {
for (Map.Entry<PendingModifications.ModificationKey, Change> entry : pms.modified.entrySet()) {
Change chg = entry.getValue();
if (!(chg.what instanceof MailItem)) {
snapshot.recordModified(entry.getKey(), chg);
continue;
}
MailItem item = (MailItem) chg.what;
if (item instanceof Folder && folders != null) {
Folder folder = folders.get(item.getId());
if (folder == null) {
ZimbraLog.mailbox.warn("folder missing from snapshotted folder set: %d", item.getId());
folder = (Folder) item;
}
snapshot.recordModified(folder, chg.why, (MailItem) chg.preModifyObj);
} else if (item instanceof Tag) {
if (((Tag) item).isListed()) {
snapshot.recordModified(snapshotItem(item), chg.why, (MailItem) chg.preModifyObj);
}
} else {
// NOTE: if the folder cache is null, folders fall down here and should always get copy == false
if (cache != null && cache.contains(item)) {
item = snapshotItem(item);
}
snapshot.recordModified(item, chg.why, (MailItem) chg.preModifyObj);
}
}
}
return snapshot;
}
Aggregations