Skip to content

Commit

Permalink
Merge pull request #1471 from Zimbra/bugfix/ZCS-7111
Browse files Browse the repository at this point in the history
ZCS-7111:  Optimize index data size by "delayed indexing"
  • Loading branch information
gautamdg authored Apr 13, 2023
2 parents 878eec0 + 8470737 commit 7a4f682
Show file tree
Hide file tree
Showing 12 changed files with 508 additions and 12 deletions.
7 changes: 6 additions & 1 deletion common/src/java/com/zimbra/common/soap/AdminConstants.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* ***** BEGIN LICENSE BLOCK *****
* Zimbra Collaboration Suite Server
* Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2021, 2022 Synacor, Inc.
* Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2021, 2022, 2023 Synacor, Inc.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software Foundation,
Expand Down Expand Up @@ -253,6 +253,8 @@ public final class AdminConstants {

public static final String E_REINDEX_REQUEST = "ReIndexRequest";
public static final String E_REINDEX_RESPONSE = "ReIndexResponse";
public static final String E_MANAGE_INDEX_REQUEST = "ManageIndexRequest";
public static final String E_MANAGE_INDEX_RESPONSE = "ManageIndexResponse";
public static final String E_COMPACT_INDEX_REQUEST = "CompactIndexRequest";
public static final String E_COMPACT_INDEX_RESPONSE = "CompactIndexResponse";
public static final String E_GET_INDEX_STATS_REQUEST = "GetIndexStatsRequest";
Expand Down Expand Up @@ -760,6 +762,8 @@ public final class AdminConstants {

public static final QName REINDEX_REQUEST = QName.get(E_REINDEX_REQUEST, NAMESPACE);
public static final QName REINDEX_RESPONSE = QName.get(E_REINDEX_RESPONSE, NAMESPACE);
public static final QName MANAGE_INDEX_REQUEST = QName.get(E_MANAGE_INDEX_REQUEST, NAMESPACE);
public static final QName MANAGE_INDEX_RESPONSE = QName.get(E_MANAGE_INDEX_RESPONSE, NAMESPACE);
public static final QName COMPACT_INDEX_REQUEST = QName.get(E_COMPACT_INDEX_REQUEST, NAMESPACE);
public static final QName COMPACT_INDEX_RESPONSE = QName.get(E_COMPACT_INDEX_RESPONSE, NAMESPACE);
public static final QName GET_INDEX_STATS_REQUEST = QName.get(E_GET_INDEX_STATS_REQUEST, NAMESPACE);
Expand Down Expand Up @@ -1615,4 +1619,5 @@ public final class AdminConstants {
"com_zextras_client", "com_zimbra_connect_classic", "com_zimbra_connect_modern", "com_zextras_docs",
"com_zimbra_docs_modern", "com_zimbra_drive_modern", "com_zextras_drive", "com_zextras_drive_open",
"com_zextras_chat_open", "com_zextras_talk", "zimbra-zimlet-briefcase-edit-lool");

}
4 changes: 3 additions & 1 deletion soap/src/java/com/zimbra/soap/JaxbUtil.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* ***** BEGIN LICENSE BLOCK *****
* Zimbra Collaboration Suite Server
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2018, 2020, 2021 Synacor, Inc.
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2018, 2020, 2021, 2023 Synacor, Inc.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software Foundation,
Expand Down Expand Up @@ -592,6 +592,8 @@ public final class JaxbUtil {
com.zimbra.soap.admin.message.MailQueueActionResponse.class,
com.zimbra.soap.admin.message.MailQueueFlushRequest.class,
com.zimbra.soap.admin.message.MailQueueFlushResponse.class,
com.zimbra.soap.admin.message.ManageIndexRequest.class,
com.zimbra.soap.admin.message.ManageIndexResponse.class,
com.zimbra.soap.admin.message.MigrateAccountRequest.class,
com.zimbra.soap.admin.message.MigrateAccountResponse.class,
com.zimbra.soap.admin.message.ModifyAccountRequest.class,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* ***** BEGIN LICENSE BLOCK *****
* Zimbra Collaboration Suite Server
* Copyright (C) 2023 Synacor, Inc.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software Foundation,
* version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <https://www.gnu.org/licenses/>.
* ***** END LICENSE BLOCK *****
*/

package com.zimbra.soap.admin.message;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

import com.zimbra.common.soap.AdminConstants;
import com.zimbra.soap.admin.type.MailboxByAccountIdSelector;

/**
* @zm-api-command-auth-required true
* @zm-api-command-admin-auth-required true
* @zm-api-command-description Manage index for Delayed Index feature. When disableIndexing is specified,
* zimbraFeatureDelayedIndexEnabled is set to TRUE, zimbraDelayedIndexStatus is set to suppressed, and index data
* except Contacts is removed. When enableIndexing is specified, zimbraDelayedIndexStatus is set to indexing and
* index data is created.
* <br />
* <b>Access</b>: domain admin sufficient
* <br />
* note: this request is by default proxied to the account's home server
*/
@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement(name=AdminConstants.E_MANAGE_INDEX_REQUEST)
public class ManageIndexRequest {

/**
* @zm-api-field-description Specify mailbox to manage
*/
@XmlElement(name=AdminConstants.E_MAILBOX, required=true)
private final MailboxByAccountIdSelector mbox;

/**
* @zm-api-field-tag "disableIndexing|enableIndexing"
* @zm-api-field-description Action to perform
* <table>
* <tr> <td> <b>disableIndexing</b> </td> <td> disable indexing and delete index </td> </tr>
* <tr> <td> <b>enableIndexing</b> </td> <td> enable indexing and create index </td> </tr>
* </table>
*/
@XmlAttribute(name=AdminConstants.E_ACTION, required=true)
private final String action;

/**
* no-argument constructor wanted by JAXB
*/
@SuppressWarnings("unused")
private ManageIndexRequest() {
this((String)null, (MailboxByAccountIdSelector)null);
}

public ManageIndexRequest(String action, MailboxByAccountIdSelector mbox) {
this.action = action;
this.mbox = mbox;
}

public String getAction() { return action; }
public MailboxByAccountIdSelector getMbox() { return mbox; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* ***** BEGIN LICENSE BLOCK *****
* Zimbra Collaboration Suite Server
* Copyright (C) 2023 Synacor, Inc.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software Foundation,
* version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <https://www.gnu.org/licenses/>.
* ***** END LICENSE BLOCK *****
*/

package com.zimbra.soap.admin.message;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;

import com.zimbra.common.soap.AdminConstants;

@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement(name=AdminConstants.E_MANAGE_INDEX_RESPONSE)
public class ManageIndexResponse {

/**
* @zm-api-field-tag status
* @zm-api-field-description <b>started</b> when action is accepted
*/
@XmlAttribute(name=AdminConstants.A_STATUS, required=true)
private final String status;

/**
* no-argument constructor wanted by JAXB
*/
@SuppressWarnings("unused")
private ManageIndexResponse() {
this((String)null);
}

public ManageIndexResponse(String status) {
this.status = status;
}

public String getStatus() { return status; }
}
2 changes: 1 addition & 1 deletion store/conf/attrs/zimbra-attrs.xml
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -10342,7 +10342,7 @@ TODO: delete them permanently from here
</attr>

<attr id="9004" name="zimbraDelayedIndexStatus" type="enum" value="suppressed,waitingForSearch,indexing" cardinality="single" optionalIn="account" flags="accountInfo" since="11.0.0">
<desc>Whether MBS generates index data of the account's mailbox. The key works only when zimbraFeatureDelayedIndexEnabled is TRUE.
<desc>The key works only when zimbraFeatureDelayedIndexEnabled is TRUE.
suppressed - Not generate index. (default)
When administrator accesses the account via admin console, it changes to "waitingForSearch".
When the account logs in via SOAP, IMAP or MobileSync protocol, it changes to "indexing".
Expand Down
98 changes: 98 additions & 0 deletions store/src/java-test/com/zimbra/cs/mailbox/MailboxIndexTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* ***** BEGIN LICENSE BLOCK *****
* Zimbra Collaboration Suite Server
* Copyright (C) 2023 Synacor, Inc.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software Foundation,
* version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <https://www.gnu.org/licenses/>.
* ***** END LICENSE BLOCK *****
*/
package com.zimbra.cs.mailbox;

import java.util.HashMap;

import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import com.zimbra.common.account.ZAttrProvisioning.DelayedIndexStatus;
import com.zimbra.cs.account.Account;
import com.zimbra.cs.account.Provisioning;

/**
* Unit test for {@link Folder}.
*/
public final class MailboxIndexTest {

@BeforeClass
public static void init() throws Exception {
MailboxTestUtil.initServer();
Provisioning prov = Provisioning.getInstance();
prov.createAccount("[email protected]", "secret", new HashMap<String, Object>());
}

@Before
public void setUp() throws Exception {
MailboxTestUtil.clearData();
}

@Test
public void needToReIndexTest() throws Exception {
Account acct = Provisioning.getInstance().getAccountByName("[email protected]");
Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(acct);
MailboxIndex index = mbox.index;
index.deleteIndex();
acct.setFeatureMobileSyncEnabled(false);

acct.unsetFeatureDelayedIndexEnabled();
acct.unsetDelayedIndexStatus();
Assert.assertTrue("zimbraFeatureDelayedIndexEnabled is unset and zimbraDelayedIndex is unset", index.needToReIndex());

acct.setDelayedIndexStatus(DelayedIndexStatus.suppressed);
Assert.assertTrue("zimbraFeatureDelayedIndexEnabled is unset and zimbraDelayedIndex is suppressed", index.needToReIndex());

acct.setDelayedIndexStatus(DelayedIndexStatus.waitingForSearch);
Assert.assertTrue("zimbraFeatureDelayedIndexEnabled is unset and zimbraDelayedIndex is waitingForSearch", index.needToReIndex());

acct.setDelayedIndexStatus(DelayedIndexStatus.indexing);
Assert.assertTrue("zimbraFeatureDelayedIndexEnabled is unset and zimbraDelayedIndex is indexing", index.needToReIndex());

acct.setFeatureDelayedIndexEnabled(false);
acct.unsetDelayedIndexStatus();
Assert.assertTrue("zimbraFeatureDelayedIndexEnabled is FALSE and zimbraDelayedIndex is unset", index.needToReIndex());

acct.setDelayedIndexStatus(DelayedIndexStatus.suppressed);
Assert.assertTrue("zimbraFeatureDelayedIndexEnabled is FALSE and zimbraDelayedIndex is suppressed", index.needToReIndex());

acct.setDelayedIndexStatus(DelayedIndexStatus.waitingForSearch);
Assert.assertTrue("zimbraFeatureDelayedIndexEnabled is FALSE and zimbraDelayedIndex is waitingForSearch", index.needToReIndex());

acct.setDelayedIndexStatus(DelayedIndexStatus.indexing);
Assert.assertTrue("zimbraFeatureDelayedIndexEnabled is FALSE and zimbraDelayedIndex is indexing", index.needToReIndex());

acct.setFeatureDelayedIndexEnabled(true);
acct.unsetDelayedIndexStatus();
Assert.assertFalse("zimbraFeatureDelayedIndexEnabled is TRUE and zimbraDelayedIndex is unset", index.needToReIndex());

acct.setDelayedIndexStatus(DelayedIndexStatus.suppressed);
Assert.assertFalse("zimbraFeatureDelayedIndexEnabled is TRUE and zimbraDelayedIndex is suppressed", index.needToReIndex());

acct.setDelayedIndexStatus(DelayedIndexStatus.waitingForSearch);
Assert.assertTrue("zimbraFeatureDelayedIndexEnabled is TRUE and zimbraDelayedIndex is waitingForSearch", index.needToReIndex());

acct.setDelayedIndexStatus(DelayedIndexStatus.indexing);
Assert.assertFalse("zimbraFeatureDelayedIndexEnabled is TRUE and zimbraDelayedIndex is indexing", index.needToReIndex());

acct.setFeatureMobileSyncEnabled(true);
Assert.assertFalse("zimbraFeatureDelayedIndexEnabled is TRUE, zimbraDelayedIndex is indexing and " +
"zimbraFeatureMobileSyncEnabled is TRUE, but not Mobile Sync Access", index.needToReIndex());
}
}
25 changes: 24 additions & 1 deletion store/src/java/com/zimbra/cs/account/ProvUtil.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* ***** BEGIN LICENSE BLOCK *****
* Zimbra Collaboration Suite Server
* Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2018, 2022 Synacor, Inc.
* Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2018, 2022, 2023 Synacor, Inc.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software Foundation,
Expand Down Expand Up @@ -111,6 +111,7 @@
import com.zimbra.cs.account.soap.SoapProvisioning;
import com.zimbra.cs.account.soap.SoapProvisioning.IndexStatsInfo;
import com.zimbra.cs.account.soap.SoapProvisioning.MailboxInfo;
import com.zimbra.cs.account.soap.SoapProvisioning.ManageIndexType;
import com.zimbra.cs.account.soap.SoapProvisioning.MemcachedClientConfig;
import com.zimbra.cs.account.soap.SoapProvisioning.QuotaUsage;
import com.zimbra.cs.account.soap.SoapProvisioning.ReIndexBy;
Expand Down Expand Up @@ -720,6 +721,9 @@ public enum Command {
HELP("help", "?", "commands",
Category.MISC, 0, 1),
LDAP(".ldap", ".l"),
MANAGE_MAILBOX_INDEX(
"manageMailboxIndex", "mmi",
"{name@domain|id} {disableIndexing|enableIndexing}", Category.MAILBOX, 2, 2),
MODIFY_ACCOUNT("modifyAccount", "ma",
"{name@domain|id} [attr1 value1 [attr2 value2...]]", Category.ACCOUNT, 3, Integer.MAX_VALUE),
MODIFY_ALWAYSONCLUSTER(
Expand Down Expand Up @@ -1537,6 +1541,9 @@ private boolean execute(String args[]) throws ServiceException, ArgException, IO
case REINDEX_MAILBOX:
doReIndexMailbox(args);
break;
case MANAGE_MAILBOX_INDEX:
doManageMailboxIndex(args);
break;
case COMPACT_INBOX_MAILBOX:
doCompactIndexMailbox(args);
break;
Expand Down Expand Up @@ -1992,6 +1999,22 @@ private void doReIndexMailbox(String[] args) throws ServiceException {
}
}

private void doManageMailboxIndex(String[] args) throws ServiceException {
if (!(prov instanceof SoapProvisioning)) {
throwSoapOnly();
}
SoapProvisioning sp = (SoapProvisioning) prov;
Account acct = lookupAccount(args[1]);
ManageIndexType type = null;
try {
type = ManageIndexType.valueOf(args[2]);
} catch (IllegalArgumentException e) {
throw ServiceException.INVALID_REQUEST("invalid argument", null);
}
String status = sp.manageIndex(acct, type);
console.printf("status: %s\n", status);
}

private void doCompactIndexMailbox(String[] args) throws ServiceException {
if (!(prov instanceof SoapProvisioning)) {
throwSoapOnly();
Expand Down
21 changes: 20 additions & 1 deletion store/src/java/com/zimbra/cs/account/soap/SoapProvisioning.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* ***** BEGIN LICENSE BLOCK *****
* Zimbra Collaboration Suite Server
* Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2018, 2019 Synacor, Inc.
* Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2018, 2019, 2023 Synacor, Inc.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software Foundation,
Expand Down Expand Up @@ -222,6 +222,8 @@
import com.zimbra.soap.admin.message.HABOrgUnitRequest;
import com.zimbra.soap.admin.message.HABOrgUnitRequest.HabOp;
import com.zimbra.soap.admin.message.HABOrgUnitResponse;
import com.zimbra.soap.admin.message.ManageIndexRequest;
import com.zimbra.soap.admin.message.ManageIndexResponse;
import com.zimbra.soap.admin.message.ModifyHABGroupRequest;
import com.zimbra.soap.admin.message.PurgeMessagesRequest;
import com.zimbra.soap.admin.message.PurgeMessagesResponse;
Expand Down Expand Up @@ -1442,6 +1444,23 @@ public ReIndexInfo reIndex(Account acct, String action, ReIndexBy by,
return new ReIndexInfo(resp.getStatus(), progress);
}

public static enum ManageIndexType {
disableIndexing, enableIndexing;
}

public String manageIndex(Account acct, ManageIndexType type)
throws ServiceException {
Server server = getServer(acct);
MailboxByAccountIdSelector mbox = new MailboxByAccountIdSelector(acct.getId());
String action = null;
if (type != null) {
action = type.toString();
}
ManageIndexRequest req = new ManageIndexRequest(action, mbox);
ManageIndexResponse resp = this.invokeJaxb(req, server.getAttr(A_zimbraServiceHostname));
return resp.getStatus();
}

public String compactIndex(Account acct, String action)
throws ServiceException {
Server server = getServer(acct);
Expand Down
Loading

0 comments on commit 7a4f682

Please sign in to comment.