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.backends.jeb;
028 import org.opends.messages.Message;
029
030 import org.opends.server.api.DirectoryThread;
031
032 import com.sleepycat.je.*;
033
034 import org.opends.server.types.*;
035
036 import static org.opends.messages.JebMessages.
037 ERR_JEB_MISSING_DN2ID_RECORD;
038 import static org.opends.messages.JebMessages.
039 ERR_JEB_REBUILD_INDEX_FAILED;
040 import static org.opends.messages.JebMessages.
041 ERR_JEB_REBUILD_INSERT_ENTRY_FAILED;
042 import static org.opends.server.loggers.ErrorLogger.logError;
043 import static org.opends.server.loggers.debug.DebugLogger.*;
044 import org.opends.server.loggers.debug.DebugTracer;
045 import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
046
047
048 /**
049 * A thread to do the actual work of rebuilding an index.
050 */
051 public class IndexRebuildThread extends DirectoryThread
052 {
053 /**
054 * The tracer object for the debug logger.
055 */
056 private static final DebugTracer TRACER = getTracer();
057
058 /**
059 * The entry container.
060 */
061 EntryContainer ec = null;
062
063 /**
064 * The internal database/indexType to rebuild.
065 */
066 IndexType indexType = null;
067
068 /**
069 * The attribute indexType to rebuild.
070 */
071 AttributeIndex attrIndex = null;
072
073 /**
074 * The VLV index to rebuild.
075 */
076 VLVIndex vlvIndex = null;
077
078 /**
079 * The indexType to rebuild.
080 */
081 Index index = null;
082
083 /**
084 * The ID2ENTRY database.
085 */
086 ID2Entry id2entry = null;
087
088 /**
089 * The number of total entries to rebuild. An negative value indicates this
090 * value is not yet known.
091 */
092 long totalEntries = -1;
093
094 /**
095 * The number of entries processed.
096 */
097 long processedEntries = 0;
098
099 /**
100 * The number of entries rebuilt successfully.
101 */
102 long rebuiltEntries = 0;
103
104 /**
105 * The number of entries rebuilt with possible duplicates.
106 */
107 long duplicatedEntries = 0;
108
109 /**
110 * The number of entries that were skipped because they were not applicable
111 * for the indexType or because an error occurred.
112 */
113 long skippedEntries = 0;
114
115 /**
116 * The types of internal indexes that are rebuildable.
117 */
118 enum IndexType
119 {
120 DN2ID, DN2URI, ID2CHILDREN, ID2SUBTREE, INDEX, ATTRIBUTEINDEX, VLVINDEX
121 }
122
123 /**
124 * Construct a new index rebuild thread to rebuild a system index.
125 *
126 * @param ec The entry container to rebuild in.
127 * @param index The index type to rebuild.
128 */
129 IndexRebuildThread(EntryContainer ec, IndexType index)
130 {
131 super("Index Rebuild Thread " + ec.getDatabasePrefix() + "_" +
132 index.toString());
133 this.ec = ec;
134 this.indexType = index;
135 this.id2entry = ec.getID2Entry();
136 }
137
138 /**
139 * Construct a new index rebuild thread to rebuild an index.
140 *
141 * @param ec The entry container to rebuild in.
142 * @param index The index to rebuild.
143 */
144 IndexRebuildThread(EntryContainer ec, Index index)
145 {
146 super("Index Rebuild Thread " + index.getName());
147 this.ec = ec;
148 this.indexType = IndexType.INDEX;
149 this.index = index;
150 this.id2entry = ec.getID2Entry();
151 }
152
153 /**
154 * Construct a new index rebuild thread to rebuild an attribute index.
155 *
156 * @param ec The entry container to rebuild in.
157 * @param index The attribute index to rebuild.
158 */
159 IndexRebuildThread(EntryContainer ec, AttributeIndex index)
160 {
161 super("Index Rebuild Thread " + index.getName());
162 this.ec = ec;
163 this.indexType = IndexType.ATTRIBUTEINDEX;
164 this.attrIndex = index;
165 this.id2entry = ec.getID2Entry();
166 }
167
168 /**
169 * Construct a new index rebuild thread to rebuild an VLV index.
170 *
171 * @param ec The entry container to rebuild in.
172 * @param vlvIndex The VLV index to rebuild.
173 */
174 IndexRebuildThread(EntryContainer ec, VLVIndex vlvIndex)
175 {
176 super("Index Rebuild Thread " + vlvIndex.getName());
177 this.ec = ec;
178 this.indexType = IndexType.VLVINDEX;
179 this.vlvIndex = vlvIndex;
180 this.id2entry = ec.getID2Entry();
181 }
182
183 /**
184 * Clear the database and prep it for the rebuild.
185 *
186 * @throws DatabaseException if a JE databse error occurs while clearing
187 * the database being rebuilt.
188 */
189 public void clearDatabase() throws DatabaseException
190 {
191 if(indexType == null)
192 {
193 //TODO: throw error
194 if(debugEnabled())
195 {
196 TRACER.debugError("No index type specified. Rebuild process " +
197 "terminated.");
198 }
199
200 return;
201 }
202 if(indexType == IndexType.ATTRIBUTEINDEX && attrIndex == null)
203 {
204 //TODO: throw error
205 if(debugEnabled())
206 {
207 TRACER.debugError("No attribute index specified. Rebuild process " +
208 "terminated.");
209 }
210
211 return;
212 }
213
214 if(indexType == IndexType.INDEX && index == null)
215 {
216 //TODO: throw error
217 if(debugEnabled())
218 {
219 TRACER.debugError("No index specified. Rebuild process terminated.");
220 }
221
222 return;
223 }
224
225 if(indexType == IndexType.VLVINDEX && vlvIndex == null)
226 {
227 //TODO: throw error
228 if(debugEnabled())
229 {
230 TRACER.debugError("No VLV index specified. Rebuild process " +
231 "terminated.");
232 }
233
234 return;
235 }
236
237 switch(indexType)
238 {
239 case DN2ID :
240 ec.clearDatabase(ec.getDN2ID());
241 break;
242 case DN2URI :
243 ec.clearDatabase(ec.getDN2URI());
244 break;
245 case ID2CHILDREN :
246 ec.clearDatabase(ec.getID2Children());
247 ec.getID2Children().setRebuildStatus(true);
248 break;
249 case ID2SUBTREE :
250 ec.clearDatabase(ec.getID2Subtree());
251 ec.getID2Subtree().setRebuildStatus(true);
252 break;
253 case ATTRIBUTEINDEX :
254 ec.clearAttributeIndex(attrIndex);
255 attrIndex.setRebuildStatus(true);
256 break;
257 case VLVINDEX :
258 ec.clearDatabase(vlvIndex);
259 vlvIndex.setRebuildStatus(true);
260 break;
261 case INDEX :
262 ec.clearDatabase(index);
263 index.setRebuildStatus(true);
264 }
265 }
266
267 /**
268 * Start the rebuild process.
269 */
270 public void run()
271 {
272 if(indexType == null)
273 {
274 //TODO: throw error
275 if(debugEnabled())
276 {
277 TRACER.debugError("No index type specified. Rebuild process " +
278 "terminated.");
279 }
280
281 return;
282 }
283 if(indexType == IndexType.ATTRIBUTEINDEX && attrIndex == null)
284 {
285 //TODO: throw error
286 if(debugEnabled())
287 {
288 TRACER.debugError("No attribute index specified. Rebuild process " +
289 "terminated.");
290 }
291
292 return;
293 }
294
295 if(indexType == IndexType.INDEX && index == null)
296 {
297 //TODO: throw error
298 if(debugEnabled())
299 {
300 TRACER.debugError("No index specified. Rebuild process terminated.");
301 }
302
303 return;
304 }
305
306 if(indexType == IndexType.VLVINDEX && vlvIndex == null)
307 {
308 //TODO: throw error
309 if(debugEnabled())
310 {
311 TRACER.debugError("No VLV index specified. Rebuild process " +
312 "terminated.");
313 }
314
315 return;
316 }
317
318 try
319 {
320 totalEntries = getTotalEntries();
321
322 switch(indexType)
323 {
324 case DN2ID : rebuildDN2ID();
325 break;
326 case DN2URI : rebuildDN2URI();
327 break;
328 case ID2CHILDREN : rebuildID2Children();
329 break;
330 case ID2SUBTREE : rebuildID2Subtree();
331 break;
332 case ATTRIBUTEINDEX : rebuildAttributeIndex(attrIndex);
333 break;
334 case VLVINDEX : rebuildVLVIndex(vlvIndex);
335 break;
336 case INDEX : rebuildAttributeIndex(index);
337 }
338
339 if(debugEnabled())
340 {
341 TRACER.debugVerbose("Rebuilt %d entries", rebuiltEntries);
342 }
343 }
344 catch(Exception e)
345 {
346 Message message = ERR_JEB_REBUILD_INDEX_FAILED.get(
347 this.getName(), stackTraceToSingleLineString(e));
348 logError(message);
349
350 if(debugEnabled())
351 {
352 TRACER.debugCaught(DebugLogLevel.ERROR, e);
353 }
354 }
355 }
356
357 /**
358 * Rebuild an interal DN2ID database.
359 *
360 * @throws DatabaseException If an error occurs during the rebuild.
361 */
362 private void rebuildDN2ID() throws DatabaseException
363 {
364 DN2ID dn2id = ec.getDN2ID();
365
366 if(debugEnabled())
367 {
368 TRACER.debugInfo("Initiating rebuild of the %s database",
369 dn2id.getName());
370 TRACER.debugVerbose("%d entries will be rebuilt", totalEntries);
371 }
372
373
374 //Iterate through the id2entry database and insert associated dn2id
375 //records.
376 Cursor cursor = id2entry.openCursor(null, CursorConfig.READ_COMMITTED);
377 try
378 {
379 DatabaseEntry key = new DatabaseEntry();
380 DatabaseEntry data = new DatabaseEntry();
381 LockMode lockMode = LockMode.DEFAULT;
382
383 OperationStatus status;
384 for (status = cursor.getFirst(key, data, lockMode);
385 status == OperationStatus.SUCCESS;
386 status = cursor.getNext(key, data, lockMode))
387 {
388 Transaction txn = ec.beginTransaction();
389 try
390 {
391 EntryID entryID = new EntryID(key);
392 Entry entry = JebFormat.entryFromDatabase(data.getData(),
393 ec.getRootContainer().getCompressedSchema());
394
395 // Insert into dn2id.
396 if (dn2id.insert(txn, entry.getDN(), entryID))
397 {
398 rebuiltEntries++;
399 }
400 else
401 {
402 // The entry ID already exists in the database.
403 // This could happen if some other process got to this entry
404 // before we did. Since the backend should be offline, this
405 // might be a problem.
406 duplicatedEntries++;
407 if(debugEnabled())
408 {
409 TRACER.debugInfo("Unable to insert entry with DN %s and ID %d " +
410 "into the DN2ID database because it already exists.",
411 entry.getDN().toString(), entryID.longValue());
412 }
413 }
414 EntryContainer.transactionCommit(txn);
415 processedEntries++;
416 }
417 catch (Exception e)
418 {
419 EntryContainer.transactionAbort(txn);
420 skippedEntries++;
421
422 Message message = ERR_JEB_REBUILD_INSERT_ENTRY_FAILED.get(
423 dn2id.getName(), stackTraceToSingleLineString(e));
424 logError(message);
425
426 if (debugEnabled())
427 {
428 TRACER.debugCaught(DebugLogLevel.ERROR, e);
429 }
430 }
431 }
432 }
433 finally
434 {
435 cursor.close();
436 }
437 }
438
439 /**
440 * Rebuild the ID2URI internal database.
441 *
442 * @throws DatabaseException if an error occurs during rebuild.
443 */
444 private void rebuildDN2URI() throws DatabaseException
445 {
446 DN2URI dn2uri = ec.getDN2URI();
447
448 if(debugEnabled())
449 {
450 TRACER.debugInfo("Initiating rebuild of the %s database",
451 dn2uri.getName());
452 TRACER.debugVerbose("%d entries will be rebuilt", totalEntries);
453 }
454
455
456 //Iterate through the id2entry database and insert associated dn2uri
457 //records.
458 Cursor cursor = id2entry.openCursor(null, CursorConfig.READ_COMMITTED);
459 try
460 {
461 DatabaseEntry key = new DatabaseEntry();
462 DatabaseEntry data = new DatabaseEntry();
463 LockMode lockMode = LockMode.DEFAULT;
464
465
466 OperationStatus status;
467 for (status = cursor.getFirst(key, data, lockMode);
468 status == OperationStatus.SUCCESS;
469 status = cursor.getNext(key, data, lockMode))
470 {
471 Transaction txn = ec.beginTransaction();
472 try
473 {
474 EntryID entryID = new EntryID(key);
475 Entry entry = JebFormat.entryFromDatabase(data.getData(),
476 ec.getRootContainer().getCompressedSchema());
477
478 // Insert into dn2uri.
479 if (dn2uri.addEntry(txn, entry))
480 {
481 rebuiltEntries++;
482 }
483 else
484 {
485 // The entry DN and URIs already exists in the database.
486 // This could happen if some other process got to this entry
487 // before we did. Since the backend should be offline, this
488 // might be a problem.
489 duplicatedEntries++;
490 if(debugEnabled())
491 {
492 TRACER.debugInfo("Unable to insert entry with DN %s and ID %d " +
493 "into the DN2URI database because it already exists.",
494 entry.getDN().toString(), entryID.longValue());
495 }
496 }
497 EntryContainer.transactionCommit(txn);
498 processedEntries++;
499 }
500 catch (Exception e)
501 {
502 EntryContainer.transactionAbort(txn);
503 skippedEntries++;
504
505 Message message = ERR_JEB_REBUILD_INSERT_ENTRY_FAILED.get(
506 dn2uri.getName(), stackTraceToSingleLineString(e));
507 logError(message);
508
509 if (debugEnabled())
510 {
511 TRACER.debugCaught(DebugLogLevel.ERROR, e);
512 }
513 }
514 }
515 }
516 finally
517 {
518 cursor.close();
519 }
520 }
521
522 /**
523 * Rebuild the ID2Subtree internal index. This depends on the DN2ID and DN2URI
524 * databases being complete.
525 *
526 * @throws DatabaseException if an error occurs during rebuild.
527 */
528 private void rebuildID2Children() throws DatabaseException
529 {
530 Index id2children = ec.getID2Children();
531
532 if(debugEnabled())
533 {
534 TRACER.debugInfo("Initiating rebuild of the %s index",
535 id2children.getName());
536 TRACER.debugVerbose("%d entries will be rebuilt", totalEntries);
537 }
538
539
540 DN2ID dn2id = ec.getDN2ID();
541 DN2URI dn2uri = ec.getDN2URI();
542
543 //Iterate through the id2entry database and insert associated dn2children
544 //records.
545 Cursor cursor = id2entry.openCursor(null, CursorConfig.READ_COMMITTED);
546 try
547 {
548 DatabaseEntry key = new DatabaseEntry();
549 DatabaseEntry data = new DatabaseEntry();
550 LockMode lockMode = LockMode.DEFAULT;
551
552 OperationStatus status;
553 for (status = cursor.getFirst(key, data, lockMode);
554 status == OperationStatus.SUCCESS;
555 status = cursor.getNext(key, data, lockMode))
556 {
557 Transaction txn = ec.beginTransaction();
558 try
559 {
560 EntryID entryID = new EntryID(key);
561 Entry entry = JebFormat.entryFromDatabase(data.getData(),
562 ec.getRootContainer().getCompressedSchema());
563
564 // Check that the parent entry exists.
565 DN parentDN = ec.getParentWithinBase(entry.getDN());
566 if (parentDN != null)
567 {
568 // Check for referral entries above the target.
569 dn2uri.targetEntryReferrals(entry.getDN(), null);
570
571 // Read the parent ID from dn2id.
572 EntryID parentID = dn2id.get(txn, parentDN, LockMode.DEFAULT);
573 if (parentID != null)
574 {
575 // Insert into id2children for parent ID.
576 if(id2children.insertID(txn, parentID.getDatabaseEntry(),
577 entryID))
578 {
579 rebuiltEntries++;
580 }
581 else
582 {
583 // The entry already exists in the database.
584 // This could happen if some other process got to this entry
585 // before we did. Since the backend should be offline, this
586 // might be a problem.
587 if(debugEnabled())
588 {
589 duplicatedEntries++;
590 TRACER.debugInfo("Unable to insert entry with DN %s and " +
591 "ID %d into the DN2Subtree database because it already " +
592 "exists.",
593 entry.getDN().toString(), entryID.longValue());
594 }
595 }
596 }
597 else
598 {
599 Message msg = ERR_JEB_MISSING_DN2ID_RECORD.get(
600 parentDN.toNormalizedString());
601 throw new JebException(msg);
602 }
603 }
604 else
605 {
606 skippedEntries++;
607 }
608 EntryContainer.transactionCommit(txn);
609 processedEntries++;
610 }
611 catch (Exception e)
612 {
613 EntryContainer.transactionAbort(txn);
614 skippedEntries++;
615
616 Message message = ERR_JEB_REBUILD_INSERT_ENTRY_FAILED.get(
617 id2children.getName(), stackTraceToSingleLineString(e));
618 logError(message);
619
620 if (debugEnabled())
621 {
622 TRACER.debugCaught(DebugLogLevel.ERROR, e);
623 }
624 }
625 }
626 id2children.setRebuildStatus(false);
627 id2children.setTrusted(null, true);
628 }
629 finally
630 {
631 cursor.close();
632 }
633 }
634
635 /**
636 * Rebuild the ID2Subtree internal index. This depends on the DN2ID and DN2URI
637 * databases being complete.
638 *
639 * @throws DatabaseException if an error occurs during rebuild.
640 */
641 private void rebuildID2Subtree() throws DatabaseException
642 {
643 Index id2subtree = ec.getID2Subtree();
644
645 if(debugEnabled())
646 {
647 TRACER.debugInfo("Initiating rebuild of the %s index",
648 id2subtree.getName());
649 TRACER.debugVerbose("%d entries will be rebuilt", totalEntries);
650 }
651
652
653 DN2ID dn2id = ec.getDN2ID();
654 DN2URI dn2uri = ec.getDN2URI();
655
656 //Iterate through the id2entry database and insert associated dn2subtree
657 //records.
658 Cursor cursor = id2entry.openCursor(null, CursorConfig.READ_COMMITTED);
659 try
660 {
661 DatabaseEntry key = new DatabaseEntry();
662 DatabaseEntry data = new DatabaseEntry();
663 LockMode lockMode = LockMode.DEFAULT;
664
665 OperationStatus status;
666 for (status = cursor.getFirst(key, data, lockMode);
667 status == OperationStatus.SUCCESS;
668 status = cursor.getNext(key, data, lockMode))
669 {
670 Transaction txn = ec.beginTransaction();
671 try
672 {
673 EntryID entryID = new EntryID(key);
674 Entry entry = JebFormat.entryFromDatabase(data.getData(),
675 ec.getRootContainer().getCompressedSchema());
676
677 // Check that the parent entry exists.
678 DN parentDN = ec.getParentWithinBase(entry.getDN());
679 if (parentDN != null)
680 {
681 boolean success = true;
682
683 // Check for referral entries above the target.
684 dn2uri.targetEntryReferrals(entry.getDN(), null);
685
686 // Read the parent ID from dn2id.
687 EntryID parentID = dn2id.get(txn, parentDN, LockMode.DEFAULT);
688 if (parentID != null)
689 {
690 // Insert into id2subtree for parent ID.
691 if(!id2subtree.insertID(txn, parentID.getDatabaseEntry(),
692 entryID))
693 {
694 success = false;
695 }
696
697 // Iterate up through the superior entries, starting above the
698 // parent.
699 for (DN dn = ec.getParentWithinBase(parentDN); dn != null;
700 dn = ec.getParentWithinBase(dn))
701 {
702 // Read the ID from dn2id.
703 EntryID nodeID = dn2id.get(null, dn, LockMode.DEFAULT);
704 if (nodeID != null)
705 {
706 // Insert into id2subtree for this node.
707 if(!id2subtree.insertID(null, nodeID.getDatabaseEntry(),
708 entryID))
709 {
710 success = false;
711 }
712 }
713 else
714 {
715 Message msg =
716 ERR_JEB_MISSING_DN2ID_RECORD.get(dn.toNormalizedString());
717 throw new JebException(msg);
718 }
719 }
720 }
721 else
722 {
723 Message msg = ERR_JEB_MISSING_DN2ID_RECORD.get(
724 parentDN.toNormalizedString());
725 throw new JebException(msg);
726 }
727
728 if(success)
729 {
730 rebuiltEntries++;
731 }
732 else
733 {
734 // The entry already exists in the database.
735 // This could happen if some other process got to this entry
736 // before we did. Since the backend should be offline, this
737 // might be a problem.
738 if(debugEnabled())
739 {
740 duplicatedEntries++;
741 TRACER.debugInfo("Unable to insert entry with DN %s and ID " +
742 "%d into the DN2Subtree database because it already " +
743 "exists.", entry.getDN().toString(), entryID.longValue());
744 }
745 }
746 }
747 else
748 {
749 skippedEntries++;
750 }
751 EntryContainer.transactionCommit(txn);
752 processedEntries++;
753 }
754 catch (Exception e)
755 {
756 EntryContainer.transactionAbort(txn);
757 skippedEntries++;
758
759 Message message = ERR_JEB_REBUILD_INSERT_ENTRY_FAILED.get(
760 id2subtree.getName(), stackTraceToSingleLineString(e));
761 logError(message);
762
763 if (debugEnabled())
764 {
765 TRACER.debugCaught(DebugLogLevel.ERROR, e);
766 }
767 }
768 }
769 id2subtree.setRebuildStatus(false);
770 id2subtree.setTrusted(null, true);
771 }
772 finally
773 {
774 cursor.close();
775 }
776 }
777
778 /**
779 * Rebuild the attribute index.
780 *
781 * @param index The indexType to rebuild.
782 * @throws DatabaseException if an error occurs during rebuild.
783 */
784 private void rebuildAttributeIndex(AttributeIndex index)
785 throws DatabaseException
786 {
787 if(debugEnabled())
788 {
789 TRACER.debugInfo("Initiating rebuild of the %s index",
790 index.getName());
791 TRACER.debugVerbose("%d entries will be rebuilt", totalEntries);
792 }
793
794 //Iterate through the id2entry database and insert associated indexType
795 //records.
796 Cursor cursor = id2entry.openCursor(null, CursorConfig.READ_COMMITTED);
797 try
798 {
799 DatabaseEntry key = new DatabaseEntry();
800 DatabaseEntry data = new DatabaseEntry();
801 LockMode lockMode = LockMode.DEFAULT;
802
803 OperationStatus status;
804 for (status = cursor.getFirst(key, data, lockMode);
805 status == OperationStatus.SUCCESS;
806 status = cursor.getNext(key, data, lockMode))
807 {
808 Transaction txn = ec.beginTransaction();
809 try
810 {
811 EntryID entryID = new EntryID(key);
812 Entry entry = JebFormat.entryFromDatabase(data.getData(),
813 ec.getRootContainer().getCompressedSchema());
814
815 // Insert into attribute indexType.
816 if(index.addEntry(txn, entryID, entry))
817 {
818 rebuiltEntries++;
819 }
820 else
821 {
822 // The entry already exists in one or more entry sets.
823 // This could happen if some other process got to this entry
824 // before we did. Since the backend should be offline, this
825 // might be a problem.
826 if(debugEnabled())
827 {
828 duplicatedEntries++;
829 TRACER.debugInfo("Unable to insert entry with DN %s and ID %d " +
830 "into the DN2Subtree database because it already " +
831 "exists.",
832 entry.getDN().toString(), entryID.longValue());
833 }
834 }
835 EntryContainer.transactionCommit(txn);
836 processedEntries++;
837 }
838 catch (Exception e)
839 {
840 EntryContainer.transactionAbort(txn);
841 skippedEntries++;
842
843 Message message = ERR_JEB_REBUILD_INSERT_ENTRY_FAILED.get(
844 index.getName(), stackTraceToSingleLineString(e));
845 logError(message);
846
847 if (debugEnabled())
848 {
849 TRACER.debugCaught(DebugLogLevel.ERROR, e);
850 }
851 }
852 }
853 index.setRebuildStatus(false);
854 index.setTrusted(null, true);
855 }
856 finally
857 {
858 cursor.close();
859 }
860 }
861
862 /**
863 * Rebuild the VLV index.
864 *
865 * @param vlvIndex The VLV index to rebuild.
866 * @throws DatabaseException if an error occurs during rebuild.
867 */
868 private void rebuildVLVIndex(VLVIndex vlvIndex)
869 throws DatabaseException
870 {
871
872 //Iterate through the id2entry database and insert associated indexType
873 //records.
874 Cursor cursor = id2entry.openCursor(null, CursorConfig.READ_COMMITTED);
875 try
876 {
877 DatabaseEntry key = new DatabaseEntry();
878 DatabaseEntry data = new DatabaseEntry();
879 LockMode lockMode = LockMode.DEFAULT;
880
881 OperationStatus status;
882 for (status = cursor.getFirst(key, data, lockMode);
883 status == OperationStatus.SUCCESS;
884 status = cursor.getNext(key, data, lockMode))
885 {
886 Transaction txn = ec.beginTransaction();
887 try
888 {
889 EntryID entryID = new EntryID(key);
890 Entry entry = JebFormat.entryFromDatabase(data.getData(),
891 ec.getRootContainer().getCompressedSchema());
892
893 // Insert into attribute indexType.
894 if(vlvIndex.addEntry(txn, entryID, entry))
895 {
896 rebuiltEntries++;
897 }
898 else
899 {
900 // The entry already exists in one or more entry sets.
901 // This could happen if some other process got to this entry
902 // before we did. Since the backend should be offline, this
903 // might be a problem.
904 if(debugEnabled())
905 {
906 duplicatedEntries++;
907 TRACER.debugInfo("Unable to insert entry with DN %s and ID %d " +
908 "into the VLV index %s because it already " +
909 "exists.",
910 entry.getDN().toString(), entryID.longValue(),
911 vlvIndex.getName());
912 }
913 }
914
915 EntryContainer.transactionCommit(txn);
916 processedEntries++;
917 }
918 catch (Exception e)
919 {
920 EntryContainer.transactionAbort(txn);
921 skippedEntries++;
922
923 Message message = ERR_JEB_REBUILD_INSERT_ENTRY_FAILED.get(
924 vlvIndex.getName(), stackTraceToSingleLineString(e));
925 logError(message);
926
927 if (debugEnabled())
928 {
929 TRACER.debugCaught(DebugLogLevel.ERROR, e);
930 }
931 }
932 }
933 vlvIndex.setRebuildStatus(false);
934 vlvIndex.setTrusted(null, true);
935 }
936 finally
937 {
938 cursor.close();
939 }
940 }
941
942 /**
943 * Rebuild the partial attribute index.
944 *
945 * @param index The indexType to rebuild.
946 * @throws DatabaseException if an error occurs during rebuild.
947 */
948 private void rebuildAttributeIndex(Index index)
949 throws DatabaseException
950 {
951 if(debugEnabled())
952 {
953 TRACER.debugInfo("Initiating rebuild of the %s attribute index",
954 index.getName());
955 TRACER.debugVerbose("%d entries will be rebuilt", totalEntries);
956 }
957
958 //Iterate through the id2entry database and insert associated indexType
959 //records.
960 Cursor cursor = id2entry.openCursor(null, CursorConfig.READ_COMMITTED);
961 try
962 {
963 DatabaseEntry key = new DatabaseEntry();
964 DatabaseEntry data = new DatabaseEntry();
965 LockMode lockMode = LockMode.DEFAULT;
966
967 OperationStatus status;
968 for (status = cursor.getFirst(key, data, lockMode);
969 status == OperationStatus.SUCCESS;
970 status = cursor.getNext(key, data, lockMode))
971 {
972 Transaction txn = ec.beginTransaction();
973 try
974 {
975 EntryID entryID = new EntryID(key);
976 Entry entry = JebFormat.entryFromDatabase(data.getData(),
977 ec.getRootContainer().getCompressedSchema());
978
979 // Insert into attribute indexType.
980 if(index.addEntry(txn, entryID, entry))
981 {
982 rebuiltEntries++;
983 }
984 else
985 {
986 // The entry already exists in one or more entry sets.
987 // This could happen if some other process got to this entry
988 // before we did. Since the backend should be offline, this
989 // might be a problem.
990 if(debugEnabled())
991 {
992 duplicatedEntries++;
993 TRACER.debugInfo("Unable to insert entry with DN %s and ID %d " +
994 "into the DN2Subtree database because it already " +
995 "exists.",
996 entry.getDN().toString(), entryID.longValue());
997 }
998 }
999 EntryContainer.transactionCommit(txn);
1000 processedEntries++;
1001 }
1002 catch (Exception e)
1003 {
1004 EntryContainer.transactionAbort(txn);
1005 skippedEntries++;
1006
1007 Message message = ERR_JEB_REBUILD_INSERT_ENTRY_FAILED.get(
1008 index.getName(), stackTraceToSingleLineString(e));
1009 logError(message);
1010
1011 if (debugEnabled())
1012 {
1013 TRACER.debugCaught(DebugLogLevel.ERROR, e);
1014 }
1015 }
1016 }
1017 index.setRebuildStatus(false);
1018 index.setTrusted(null, true);
1019 }
1020 finally
1021 {
1022 cursor.close();
1023 }
1024 }
1025
1026 /**
1027 * Get the total entries to process in the rebuild.
1028 *
1029 * @return The total entries to process.
1030 * @throws DatabaseException if an error occurs while getting the total
1031 * number of entries to process.
1032 */
1033 public long getTotalEntries() throws DatabaseException
1034 {
1035 //If total entries is not calculated yet, do it now.
1036 if(totalEntries < 0)
1037 {
1038 totalEntries = id2entry.getRecordCount();
1039 }
1040 return totalEntries;
1041 }
1042
1043 /**
1044 * Get the number of entries processed in the rebuild.
1045 *
1046 * @return The total entries processed.
1047 */
1048 public long getProcessedEntries()
1049 {
1050 return processedEntries;
1051 }
1052
1053 /**
1054 * Get the number of entries successfully rebuilt.
1055 *
1056 * @return The number of entries successfully rebuilt.
1057 */
1058 public long getRebuiltEntries()
1059 {
1060 return rebuiltEntries;
1061 }
1062
1063 /**
1064 * Get the number of entries that encountered duplicated indexType values in
1065 * the rebuild process.
1066 *
1067 * @return The number of entries that encountered duplicated indexType values
1068 * in the rebuild process.
1069 */
1070 public long getDuplicatedEntries()
1071 {
1072 return duplicatedEntries;
1073 }
1074
1075 /**
1076 * Get the number of entries skipped because they were either not applicable
1077 * or an error occurred during the process.
1078 *
1079 * @return The number of entries skipped.
1080 */
1081 public long getSkippedEntries()
1082 {
1083 return skippedEntries;
1084 }
1085
1086 /**
1087 * Get the index type being rebuilt by this thread.
1088 *
1089 * @return The index type being rebuilt by this thread.
1090 */
1091 public IndexType getIndexType()
1092 {
1093 return indexType;
1094 }
1095 }
1096
1097