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