001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.tasks;
028    import org.opends.messages.Message;
029    import org.opends.messages.TaskMessages;
030    
031    import org.opends.server.backends.task.Task;
032    import org.opends.server.backends.task.TaskState;
033    import org.opends.server.backends.jeb.RebuildConfig;
034    import org.opends.server.backends.jeb.BackendImpl;
035    import org.opends.server.types.Attribute;
036    import org.opends.server.types.AttributeType;
037    import org.opends.server.types.DN;
038    import org.opends.server.types.DebugLogLevel;
039    import org.opends.server.types.DirectoryException;
040    import org.opends.server.types.Entry;
041    
042    
043    import org.opends.server.types.Operation;
044    import org.opends.server.types.Privilege;
045    import org.opends.server.types.ResultCode;
046    import org.opends.server.core.DirectoryServer;
047    import org.opends.server.core.LockFileManager;
048    import org.opends.server.api.ClientConnection;
049    import org.opends.server.api.Backend;
050    
051    import static org.opends.server.core.DirectoryServer.getAttributeType;
052    import static org.opends.server.util.StaticUtils.*;
053    import static org.opends.server.loggers.debug.DebugLogger.*;
054    import org.opends.server.loggers.debug.DebugTracer;
055    import static org.opends.messages.TaskMessages.
056        ERR_TASK_INDEXREBUILD_INSUFFICIENT_PRIVILEGES;
057    import static org.opends.messages.ToolMessages.
058        ERR_REBUILDINDEX_ERROR_DURING_REBUILD;
059    import static org.opends.messages.ToolMessages.
060        ERR_REBUILDINDEX_WRONG_BACKEND_TYPE;
061    import static org.opends.messages.ToolMessages.
062        ERR_NO_BACKENDS_FOR_BASE;
063    import static org.opends.messages.ToolMessages.
064        ERR_CANNOT_DECODE_BASE_DN;
065    import static org.opends.messages.ToolMessages.
066        ERR_REBUILDINDEX_CANNOT_EXCLUSIVE_LOCK_BACKEND;
067    import static org.opends.messages.ToolMessages.
068        ERR_REBUILDINDEX_CANNOT_SHARED_LOCK_BACKEND;
069    import static org.opends.messages.ToolMessages.
070        WARN_REBUILDINDEX_CANNOT_UNLOCK_BACKEND;
071    import static org.opends.server.config.ConfigConstants.
072        ATTR_REBUILD_BASE_DN;
073    import static org.opends.server.config.ConfigConstants.
074        ATTR_REBUILD_INDEX;
075    import static org.opends.server.config.ConfigConstants.
076        ATTR_REBUILD_MAX_THREADS;
077    
078    import java.util.List;
079    import java.util.ArrayList;
080    
081    /**
082     * This class provides an implementation of a Directory Server task that can
083     * be used to rebuild indexes in the JEB backend..
084     */
085    public class RebuildTask extends Task
086    {
087      /**
088       * The tracer object for the debug logger.
089       */
090      private static final DebugTracer TRACER = getTracer();
091    
092      String baseDN = null;
093      ArrayList<String> indexes = null;
094      int maxThreads = -1;
095    
096      /**
097       * {@inheritDoc}
098       */
099      public Message getDisplayName() {
100        return TaskMessages.INFO_TASK_REBUILD_NAME.get();
101      }
102    
103      /**
104       * {@inheritDoc}
105       */
106      @Override public void initializeTask() throws DirectoryException
107      {
108        // If the client connection is available, then make sure the associated
109        // client has the INDEX_REBUILD privilege.
110    
111        Operation operation = getOperation();
112        if (operation != null)
113        {
114          ClientConnection clientConnection = operation.getClientConnection();
115          if (! clientConnection.hasPrivilege(Privilege.LDIF_IMPORT, operation))
116          {
117            Message message = ERR_TASK_INDEXREBUILD_INSUFFICIENT_PRIVILEGES.get();
118            throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
119                                         message);
120          }
121        }
122    
123    
124        Entry taskEntry = getTaskEntry();
125    
126        AttributeType typeBaseDN;
127        AttributeType typeIndex;
128        AttributeType typeMaxThreads;
129    
130        typeBaseDN =
131             getAttributeType(ATTR_REBUILD_BASE_DN, true);
132        typeIndex =
133             getAttributeType(ATTR_REBUILD_INDEX, true);
134        typeMaxThreads =
135             getAttributeType(ATTR_REBUILD_MAX_THREADS, true);
136    
137        List<Attribute> attrList;
138    
139        attrList = taskEntry.getAttribute(typeBaseDN);
140        baseDN = TaskUtils.getSingleValueString(attrList);
141    
142        attrList = taskEntry.getAttribute(typeIndex);
143        indexes = TaskUtils.getMultiValueString(attrList);
144    
145    
146        attrList = taskEntry.getAttribute(typeMaxThreads);
147        maxThreads = TaskUtils.getSingleValueInteger(attrList, -1);
148      }
149    
150      /**
151       * {@inheritDoc}
152       */
153      protected TaskState runTask()
154      {
155        RebuildConfig rebuildConfig = new RebuildConfig();
156    
157        try
158        {
159          rebuildConfig.setBaseDN(DN.decode(baseDN));
160        }
161        catch(DirectoryException de)
162        {
163          Message message =
164              ERR_CANNOT_DECODE_BASE_DN.get(baseDN, de.getMessageObject());
165          logError(message);
166          return TaskState.STOPPED_BY_ERROR;
167        }
168    
169        for(String index : indexes)
170        {
171          rebuildConfig.addRebuildIndex(index);
172        }
173    
174        rebuildConfig.setMaxRebuildThreads(maxThreads);
175    
176        Backend backend =
177            DirectoryServer.getBackendWithBaseDN(rebuildConfig.getBaseDN());
178    
179        if(backend == null)
180        {
181          Message message = ERR_NO_BACKENDS_FOR_BASE.get(baseDN);
182          logError(message);
183          return TaskState.STOPPED_BY_ERROR;
184        }
185    
186        if (!(backend instanceof BackendImpl))
187        {
188          Message message = ERR_REBUILDINDEX_WRONG_BACKEND_TYPE.get();
189          logError(message);
190          return TaskState.STOPPED_BY_ERROR;
191        }
192    
193        // Acquire a shared lock for the backend if we are rebuilding attribute
194        // indexes only. If we are rebuilding one or more system indexes, we have
195        // to aquire exclusive lock.
196        String lockFile = LockFileManager.getBackendLockFileName(backend);
197        StringBuilder failureReason = new StringBuilder();
198        if(rebuildConfig.includesSystemIndex())
199        {
200          // Disable the backend.
201          try
202          {
203            TaskUtils.disableBackend(backend.getBackendID());
204          }
205          catch (DirectoryException e)
206          {
207            if (debugEnabled())
208            {
209              TRACER.debugCaught(DebugLogLevel.ERROR, e);
210            }
211    
212            logError(e.getMessageObject());
213            return TaskState.STOPPED_BY_ERROR;
214          }
215    
216          try
217          {
218            if(! LockFileManager.acquireExclusiveLock(lockFile, failureReason))
219            {
220              Message message = ERR_REBUILDINDEX_CANNOT_EXCLUSIVE_LOCK_BACKEND.get(
221                  backend.getBackendID(), String.valueOf(failureReason));
222              logError(message);
223              return TaskState.STOPPED_BY_ERROR;
224            }
225          }
226          catch (Exception e)
227          {
228            Message message = ERR_REBUILDINDEX_CANNOT_EXCLUSIVE_LOCK_BACKEND.get(
229                backend.getBackendID(), getExceptionMessage(e));
230            logError(message);
231            return TaskState.STOPPED_BY_ERROR;
232          }
233        }
234        else
235        {
236          try
237          {
238            if(! LockFileManager.acquireSharedLock(lockFile, failureReason))
239            {
240              Message message = ERR_REBUILDINDEX_CANNOT_SHARED_LOCK_BACKEND.get(
241                  backend.getBackendID(), String.valueOf(failureReason));
242              logError(message);
243              return TaskState.STOPPED_BY_ERROR;
244            }
245          }
246          catch (Exception e)
247          {
248            Message message = ERR_REBUILDINDEX_CANNOT_SHARED_LOCK_BACKEND.get(
249                backend.getBackendID(), getExceptionMessage(e));
250            logError(message);
251            return TaskState.STOPPED_BY_ERROR;
252          }
253    
254        }
255    
256    
257        // Launch the rebuild process.
258        try
259        {
260          BackendImpl jebBackend = (BackendImpl)backend;
261          jebBackend.rebuildBackend(rebuildConfig);
262        }
263        catch (Exception e)
264        {
265          if (debugEnabled())
266          {
267            TRACER.debugCaught(DebugLogLevel.ERROR, e);
268          }
269    
270          Message message =
271              ERR_REBUILDINDEX_ERROR_DURING_REBUILD.get(e.getMessage());
272          logError(message);
273          return TaskState.STOPPED_BY_ERROR;
274        }
275    
276        // Release the lock on the backend.
277        try
278        {
279          lockFile = LockFileManager.getBackendLockFileName(backend);
280          failureReason = new StringBuilder();
281          if (! LockFileManager.releaseLock(lockFile, failureReason))
282          {
283            Message message = WARN_REBUILDINDEX_CANNOT_UNLOCK_BACKEND.get(
284                backend.getBackendID(), String.valueOf(failureReason));
285            logError(message);
286            return TaskState.COMPLETED_WITH_ERRORS;
287          }
288        }
289        catch (Exception e)
290        {
291          Message message = WARN_REBUILDINDEX_CANNOT_UNLOCK_BACKEND.get(
292              backend.getBackendID(), getExceptionMessage(e));
293          logError(message);
294          return TaskState.COMPLETED_WITH_ERRORS;
295        }
296    
297        if(rebuildConfig.includesSystemIndex())
298        {
299          // Enable the backend.
300          try
301          {
302            TaskUtils.enableBackend(backend.getBackendID());
303          }
304          catch (DirectoryException e)
305          {
306            if (debugEnabled())
307            {
308              TRACER.debugCaught(DebugLogLevel.ERROR, e);
309            }
310    
311            logError(e.getMessageObject());
312            return TaskState.STOPPED_BY_ERROR;
313          }
314        }
315    
316        return TaskState.COMPLETED_SUCCESSFULLY;
317      }
318    }