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 }