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 }