Search in sources :

Example 1 with PagedDelete

use of com.zimbra.cs.mailbox.util.PagedDelete in project zm-mailbox by Zimbra.

the class PagedDeleteTest method testRemoveBeforeAfterCutoff.

@Test
public void testRemoveBeforeAfterCutoff() {
    TypedIdList tombstone = new TypedIdList();
    tombstone.add(Type.MESSAGE, 3, "", 100);
    tombstone.add(Type.MESSAGE, 4, "", 101);
    tombstone.add(Type.APPOINTMENT, 1, "", 101);
    tombstone.add(Type.APPOINTMENT, 5, "", 100);
    tombstone.add(Type.APPOINTMENT, 9, "", 103);
    tombstone.add(Type.MESSAGE, 2, "", 99);
    tombstone.add(Type.MESSAGE, 22, "", 105);
    tombstone.add(Type.MESSAGE, 24, "", 103);
    tombstone.add(Type.MESSAGE, 28, "", 106);
    PagedDelete pgDelete = new PagedDelete(tombstone, true);
    pgDelete.removeBeforeCutoff(4, 101);
    Collection<Integer> ids = pgDelete.getAllIds();
    Assert.assertEquals(5, ids.size());
    pgDelete.trimDeletesTillPageLimit(5);
    ids = pgDelete.getAllIds();
    Assert.assertEquals(5, ids.size());
    pgDelete.removeAfterCutoff(105);
    ids = pgDelete.getAllIds();
    Assert.assertEquals(4, ids.size());
    Assert.assertTrue(ids.contains(4));
    Assert.assertTrue(ids.contains(9));
    Assert.assertTrue(ids.contains(24));
    Assert.assertTrue(ids.contains(22));
    Assert.assertTrue(pgDelete.isDeleteOverFlow());
    Assert.assertEquals(pgDelete.getCutOffModsequnce(), 106);
    Assert.assertEquals(pgDelete.getLastItemId(), 28);
    Multimap<Type, Integer> ids2Type = pgDelete.getTypedItemIds();
    Assert.assertEquals(4, ids2Type.size());
    Assert.assertTrue(ids2Type.containsEntry(Type.MESSAGE, 4));
    Assert.assertTrue(ids2Type.containsEntry(Type.APPOINTMENT, 9));
    Assert.assertTrue(ids2Type.containsEntry(Type.MESSAGE, 24));
    Assert.assertTrue(ids2Type.containsEntry(Type.MESSAGE, 22));
}
Also used : Type(com.zimbra.cs.mailbox.MailItem.Type) PagedDelete(com.zimbra.cs.mailbox.util.PagedDelete) TypedIdList(com.zimbra.cs.mailbox.util.TypedIdList) Test(org.junit.Test)

Example 2 with PagedDelete

use of com.zimbra.cs.mailbox.util.PagedDelete in project zm-mailbox by Zimbra.

the class PagedDeleteTest method testRemoveBeforeCutoff.

@Test
public void testRemoveBeforeCutoff() {
    TypedIdList tombstone = new TypedIdList();
    tombstone.add(Type.MESSAGE, 3, "", 100);
    tombstone.add(Type.MESSAGE, 4, "", 101);
    tombstone.add(Type.APPOINTMENT, 1, "", 101);
    tombstone.add(Type.APPOINTMENT, 5, "", 100);
    tombstone.add(Type.APPOINTMENT, 9, "", 103);
    tombstone.add(Type.MESSAGE, 2, "", 99);
    tombstone.add(Type.MESSAGE, 22, "", 105);
    tombstone.add(Type.MESSAGE, 24, "", 103);
    PagedDelete pgDelete = new PagedDelete(tombstone, true);
    pgDelete.removeBeforeCutoff(4, 101);
    Collection<Integer> ids = pgDelete.getAllIds();
    Assert.assertEquals(4, ids.size());
    pgDelete.trimDeletesTillPageLimit(3);
    ids = pgDelete.getAllIds();
    Assert.assertEquals(3, ids.size());
    Assert.assertTrue(ids.contains(4));
    Assert.assertTrue(ids.contains(9));
    Assert.assertTrue(ids.contains(24));
    Assert.assertTrue(pgDelete.isDeleteOverFlow());
    Assert.assertEquals(pgDelete.getCutOffModsequnce(), 105);
    Assert.assertEquals(pgDelete.getLastItemId(), 22);
    Multimap<Type, Integer> ids2Type = pgDelete.getTypedItemIds();
    Assert.assertEquals(3, ids2Type.size());
    Assert.assertTrue(ids2Type.containsEntry(Type.MESSAGE, 4));
    Assert.assertTrue(ids2Type.containsEntry(Type.APPOINTMENT, 9));
    Assert.assertTrue(ids2Type.containsEntry(Type.MESSAGE, 24));
}
Also used : Type(com.zimbra.cs.mailbox.MailItem.Type) PagedDelete(com.zimbra.cs.mailbox.util.PagedDelete) TypedIdList(com.zimbra.cs.mailbox.util.TypedIdList) Test(org.junit.Test)

Example 3 with PagedDelete

use of com.zimbra.cs.mailbox.util.PagedDelete in project zm-mailbox by Zimbra.

the class PagedDeleteTest method testTrimDeletesTillPageLimit.

@Test
public void testTrimDeletesTillPageLimit() {
    TypedIdList tombstone = new TypedIdList();
    tombstone.add(Type.MESSAGE, 3, "", 100);
    tombstone.add(Type.MESSAGE, 4, "", 101);
    tombstone.add(Type.MESSAGE, 1, "", 101);
    tombstone.add(Type.MESSAGE, 5, "", 100);
    tombstone.add(Type.MESSAGE, 9, "", 103);
    PagedDelete pgDelete = new PagedDelete(tombstone, false);
    pgDelete.trimDeletesTillPageLimit(3);
    Collection<Integer> ids = pgDelete.getAllIds();
    Assert.assertEquals(3, ids.size());
    Assert.assertTrue(ids.contains(3));
    Assert.assertTrue(ids.contains(5));
    Assert.assertTrue(ids.contains(1));
    Assert.assertTrue(pgDelete.isDeleteOverFlow());
    Assert.assertTrue(pgDelete.getCutOffModsequnce() == 101);
    Assert.assertTrue(pgDelete.getLastItemId() == 4);
}
Also used : PagedDelete(com.zimbra.cs.mailbox.util.PagedDelete) TypedIdList(com.zimbra.cs.mailbox.util.TypedIdList) Test(org.junit.Test)

Example 4 with PagedDelete

use of com.zimbra.cs.mailbox.util.PagedDelete in project zm-mailbox by Zimbra.

the class PagedDeleteTest method testTypedDeletesTillPageLimit.

@Test
public void testTypedDeletesTillPageLimit() {
    TypedIdList tombstone = new TypedIdList();
    tombstone.add(Type.MESSAGE, 3, "", 100);
    tombstone.add(Type.MESSAGE, 4, "", 101);
    tombstone.add(Type.APPOINTMENT, 1, "", 101);
    tombstone.add(Type.APPOINTMENT, 5, "", 100);
    tombstone.add(Type.MESSAGE, 9, "", 103);
    PagedDelete pgDelete = new PagedDelete(tombstone, true);
    pgDelete.trimDeletesTillPageLimit(3);
    Collection<Integer> ids = pgDelete.getAllIds();
    Assert.assertEquals(3, ids.size());
    Assert.assertTrue(ids.contains(3));
    Assert.assertTrue(ids.contains(5));
    Assert.assertTrue(ids.contains(1));
    Assert.assertTrue(pgDelete.isDeleteOverFlow());
    Assert.assertTrue(pgDelete.getCutOffModsequnce() == 101);
    Assert.assertTrue(pgDelete.getLastItemId() == 4);
    Multimap<Type, Integer> ids2Type = pgDelete.getTypedItemIds();
    Assert.assertEquals(3, ids2Type.size());
    Assert.assertTrue(ids2Type.containsEntry(Type.MESSAGE, 3));
    Assert.assertTrue(ids2Type.containsEntry(Type.APPOINTMENT, 5));
    Assert.assertTrue(ids2Type.containsEntry(Type.APPOINTMENT, 1));
}
Also used : Type(com.zimbra.cs.mailbox.MailItem.Type) PagedDelete(com.zimbra.cs.mailbox.util.PagedDelete) TypedIdList(com.zimbra.cs.mailbox.util.TypedIdList) Test(org.junit.Test)

Example 5 with PagedDelete

use of com.zimbra.cs.mailbox.util.PagedDelete in project zm-mailbox by Zimbra.

the class Sync method deltaSync.

private static String deltaSync(Element response, OperationContext octxt, ItemIdFormatter ifmt, Mailbox mbox, SyncToken syncToken, int deleteLimit, int changeLimit, boolean typedDeletes, Folder root, Set<Folder> visible, int messageSyncStart) throws ServiceException {
    int begin = syncToken.getChangeId();
    int deleteModSeqCutoff = syncToken.getDeleteModSeq();
    deleteModSeqCutoff = deleteModSeqCutoff <= 0 ? begin : deleteModSeqCutoff;
    int mboxLastChangeId = mbox.getLastChangeID();
    SyncToken newSyncToken = new SyncToken(mboxLastChangeId);
    if (begin >= mboxLastChangeId && deleteModSeqCutoff >= mboxLastChangeId) {
        return newSyncToken.toString();
    }
    int changeItemIdCutoff = syncToken.getOffsetInNext();
    int deleteItemIdCutoff = syncToken.getDeleteOffsetInNext();
    // first, fetch deleted items
    TypedIdList tombstones = mbox.getTombstones(deleteModSeqCutoff);
    Element eDeleted = response.addElement(MailConstants.E_DELETED);
    // then, put together the requested folder hierarchy in 2 different flavors
    List<Folder> hierarchy = (root == null || root.getId() == Mailbox.ID_FOLDER_USER_ROOT ? null : root.getSubfolderHierarchy());
    Set<Integer> targetIds = (root != null && root.getId() == Mailbox.ID_FOLDER_USER_ROOT ? null : new HashSet<Integer>(hierarchy == null ? 0 : hierarchy.size()));
    if (hierarchy != null) {
        for (Folder folder : hierarchy) {
            targetIds.add(folder.getId());
        }
    }
    // then, handle created/modified folders
    if (octxt.isDelegatedRequest(mbox)) {
        // first, make sure that something changed...
        if (!mbox.getModifiedFolders(begin).isEmpty() || !Collections.disjoint(tombstones.types(), FOLDER_TYPES)) {
            // special-case the folder hierarchy for delegated delta sync
            boolean anyFolders = folderSync(response, octxt, ifmt, mbox, root, visible, -1, messageSyncStart, SyncPhase.DELTA);
            // if no folders are visible, add an empty "<folder/>" as a hint
            if (!anyFolders) {
                response.addElement(MailConstants.E_FOLDER);
            }
        }
    } else {
        for (Folder folder : mbox.getModifiedFolders(begin)) {
            // no case of "synthetic tombstone" (item falling out of the tree being synced)
            if (targetIds == null || targetIds.contains(folder.getId())) {
                ToXML.encodeFolder(response, ifmt, octxt, folder, Change.ALL_FIELDS);
            } else {
                tombstones.add(folder.getType(), folder.getId(), folder.getUuid(), folder.getModifiedSequence());
            }
        }
    }
    // next, handle created/modified tags
    for (Tag tag : mbox.getModifiedTags(octxt, begin)) {
        ToXML.encodeTag(response, ifmt, octxt, tag, Change.ALL_FIELDS);
    }
    // finally, handle created/modified "other items"
    int itemCount = 0;
    Pair<List<Integer>, TypedIdList> changed = mbox.getModifiedItems(octxt, Math.min(begin, deleteModSeqCutoff), messageSyncStart, MailItem.Type.UNKNOWN, targetIds, deleteModSeqCutoff);
    List<Integer> modified = changed.getFirst();
    // items that have been altered in non-visible folders will be returned as "deleted" in order to handle moves
    if (changed.getSecond() != null) {
        tombstones.addAll(changed.getSecond());
    }
    delta: while (!modified.isEmpty()) {
        List<Integer> batch = modified.subList(0, Math.min(modified.size(), FETCH_BATCH_SIZE));
        for (MailItem item : mbox.getItemById(octxt, batch, MailItem.Type.UNKNOWN)) {
            // detect interrupted sync and resume from the appropriate place
            if ((item.getModifiedSequence() == begin + 1 && item.getId() < changeItemIdCutoff) || item.getModifiedSequence() <= begin) {
                //if interrupted delete and un-interrupted modifications.
                continue;
            }
            // if we've overflowed this sync response, set things up so that a subsequent sync starts from where we're cutting off
            if (itemCount >= changeLimit) {
                response.addAttribute(MailConstants.A_QUERY_MORE, true);
                newSyncToken.setChangeModSeq((item.getModifiedSequence() - 1));
                newSyncToken.setChangeItemId(item.getId());
                newSyncToken.setDeleteModSeq(mboxLastChangeId);
                break delta;
            }
            // For items in the system, if the content has changed since the user last sync'ed
            // (because it was edited or created), just send back the folder ID and saved date --
            // the client will request the whole object out of band -- potentially using the
            // content servlet's "include metadata in headers" hack.
            // If it's just the metadata that changed, send back the set of mutable attributes.
            boolean created = item.getSavedSequence() > begin;
            ToXML.encodeItem(response, ifmt, octxt, item, created ? Change.FOLDER | Change.CONFLICT | Change.DATE | Change.PARENT : MUTABLE_FIELDS);
            itemCount++;
        }
        batch.clear();
    }
    // cleanup: only return a <deleted> element if we're sending back deleted item ids
    if ((deleteLimit > 0 && tombstones.size() > deleteLimit) || deleteItemIdCutoff > 0) {
        PagedDelete pgDel = new PagedDelete(tombstones, typedDeletes);
        pgDel.removeBeforeCutoff(deleteItemIdCutoff, deleteModSeqCutoff);
        if (deleteLimit > 0) {
            pgDel.trimDeletesTillPageLimit(deleteLimit);
        }
        encodePagedDelete(eDeleted, pgDel, newSyncToken, tombstones, typedDeletes);
        if (pgDel.isDeleteOverFlow()) {
            response.addAttribute(MailConstants.A_QUERY_MORE, true);
            response.addAttribute(MailConstants.A_QUERY_MORE, true);
        }
    } else {
        encodeUnpagedDelete(eDeleted, tombstones, typedDeletes);
    }
    return newSyncToken.toString();
}
Also used : PagedDelete(com.zimbra.cs.mailbox.util.PagedDelete) Element(com.zimbra.common.soap.Element) Folder(com.zimbra.cs.mailbox.Folder) TypedIdList(com.zimbra.cs.mailbox.util.TypedIdList) SyncToken(com.zimbra.cs.service.util.SyncToken) MailItem(com.zimbra.cs.mailbox.MailItem) TypedIdList(com.zimbra.cs.mailbox.util.TypedIdList) List(java.util.List) Tag(com.zimbra.cs.mailbox.Tag) HashSet(java.util.HashSet)

Aggregations

PagedDelete (com.zimbra.cs.mailbox.util.PagedDelete)5 TypedIdList (com.zimbra.cs.mailbox.util.TypedIdList)5 Test (org.junit.Test)4 Type (com.zimbra.cs.mailbox.MailItem.Type)3 Element (com.zimbra.common.soap.Element)1 Folder (com.zimbra.cs.mailbox.Folder)1 MailItem (com.zimbra.cs.mailbox.MailItem)1 Tag (com.zimbra.cs.mailbox.Tag)1 SyncToken (com.zimbra.cs.service.util.SyncToken)1 HashSet (java.util.HashSet)1 List (java.util.List)1