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 legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2006-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2013-2015 ForgeRock AS. 026 */ 027package org.opends.server.backends.jeb; 028 029import static org.opends.messages.ToolMessages.*; 030import static org.opends.server.util.StaticUtils.*; 031 032import static com.forgerock.opendj.cli.ArgumentConstants.*; 033import static com.forgerock.opendj.cli.Utils.*; 034 035import java.io.OutputStream; 036import java.io.PrintStream; 037import java.text.ParseException; 038import java.util.ArrayList; 039import java.util.Collection; 040import java.util.Comparator; 041import java.util.HashMap; 042import java.util.LinkedHashMap; 043import java.util.List; 044import java.util.Map; 045 046import org.forgerock.i18n.LocalizableMessage; 047import org.forgerock.opendj.config.server.ConfigException; 048import org.forgerock.opendj.ldap.ByteSequence; 049import org.forgerock.opendj.ldap.ByteString; 050import org.forgerock.opendj.ldap.ByteStringBuilder; 051import org.opends.server.admin.std.server.BackendCfg; 052import org.opends.server.admin.std.server.LocalDBBackendCfg; 053import org.opends.server.api.Backend; 054import org.opends.server.core.CoreConfigManager; 055import org.opends.server.core.DirectoryServer; 056import org.opends.server.core.DirectoryServer.DirectoryServerVersionHandler; 057import org.opends.server.core.LockFileManager; 058import org.opends.server.extensions.ConfigFileHandler; 059import org.opends.server.loggers.JDKLogging; 060import org.opends.server.tools.BackendToolUtils; 061import org.opends.server.types.DN; 062import org.opends.server.types.DirectoryException; 063import org.opends.server.types.InitializationException; 064import org.opends.server.types.NullOutputStream; 065import org.opends.server.types.SortKey; 066import org.opends.server.util.BuildVersion; 067import org.opends.server.util.StaticUtils; 068 069import com.forgerock.opendj.cli.Argument; 070import com.forgerock.opendj.cli.ArgumentException; 071import com.forgerock.opendj.cli.BooleanArgument; 072import com.forgerock.opendj.cli.CommonArguments; 073import com.forgerock.opendj.cli.IntegerArgument; 074import com.forgerock.opendj.cli.StringArgument; 075import com.forgerock.opendj.cli.SubCommand; 076import com.forgerock.opendj.cli.SubCommandArgumentParser; 077import com.forgerock.opendj.cli.TableBuilder; 078import com.forgerock.opendj.cli.TextTablePrinter; 079import com.sleepycat.je.Cursor; 080import com.sleepycat.je.CursorConfig; 081import com.sleepycat.je.DatabaseEntry; 082import com.sleepycat.je.DatabaseException; 083import com.sleepycat.je.LockMode; 084import com.sleepycat.je.OperationStatus; 085 086/** 087 * This program provides a utility that may be used to debug a JE backend. This 088 * tool provides the ability list various containers in the backend as well as 089 * dump the contents of database containers. This will be 090 * a process that is intended to run separate from Directory Server and not 091 * internally within the server process (e.g., via the tasks interface). 092 */ 093public class DBTest 094{ 095 /** The error stream which this application should use. */ 096 private final PrintStream err; 097 098 /** The output stream which this application should use. */ 099 private final PrintStream out; 100 101 /** 102 * Flag indicating whether or not the global arguments have already been 103 * initialized. 104 */ 105 private boolean globalArgumentsInitialized; 106 107 /** The command-line argument parser. */ 108 private final SubCommandArgumentParser parser; 109 110 /** The argument which should be used to request usage information. */ 111 private BooleanArgument showUsageArgument; 112 113 /** The argument which should be used to specify the config class. */ 114 private StringArgument configClass; 115 116 /** THe argument which should be used to specify the config file. */ 117 private StringArgument configFile; 118 119 /** 120 * Flag indicating whether or not the sub-commands have already been 121 * initialized. 122 */ 123 private boolean subCommandsInitialized; 124 125 126 127 /** 128 * Provides the command-line arguments to the main application for 129 * processing. 130 * 131 * @param args 132 * The set of command-line arguments provided to this 133 * program. 134 */ 135 public static void main(String[] args) { 136 int exitCode = main(args, true, System.out, System.err); 137 if (exitCode != 0) { 138 System.exit(filterExitCode(exitCode)); 139 } 140 } 141 142 143 /** 144 * Provides the command-line arguments to the main application for 145 * processing and returns the exit code as an integer. 146 * 147 * @param args 148 * The set of command-line arguments provided to this 149 * program. 150 * @param initializeServer 151 * Indicates whether to perform basic initialization (which 152 * should not be done if the tool is running in the same 153 * JVM as the server). 154 * @param outStream 155 * The output stream for standard output. 156 * @param errStream 157 * The output stream for standard error. 158 * @return Zero to indicate that the program completed successfully, 159 * or non-zero to indicate that an error occurred. 160 */ 161 public static int main(String[] args, boolean initializeServer, 162 OutputStream outStream, OutputStream errStream) { 163 DBTest app = new DBTest(outStream, errStream); 164 165 // Run the application. 166 return app.run(args, initializeServer); 167 } 168 169 /** 170 * Creates a new dsconfig application instance. 171 * 172 * @param out 173 * The application output stream. 174 * @param err 175 * The application error stream. 176 */ 177 public DBTest(OutputStream out, OutputStream err) 178 { 179 this.out = NullOutputStream.wrapOrNullStream(out); 180 this.err = NullOutputStream.wrapOrNullStream(err); 181 JDKLogging.disableLogging(); 182 183 LocalizableMessage toolDescription = INFO_DESCRIPTION_DBTEST_TOOL.get(); 184 this.parser = new SubCommandArgumentParser(getClass().getName(), toolDescription, false); 185 this.parser.setShortToolDescription(REF_SHORT_DESC_DBTEST.get()); 186 this.parser.setVersionHandler(new DirectoryServerVersionHandler()); 187 } 188 189 /** 190 * Registers the global arguments with the argument parser. 191 * 192 * @throws ArgumentException 193 * If a global argument could not be registered. 194 */ 195 private void initializeGlobalArguments() throws ArgumentException { 196 if (!globalArgumentsInitialized) { 197 configClass = 198 new StringArgument("configclass", OPTION_SHORT_CONFIG_CLASS, 199 OPTION_LONG_CONFIG_CLASS, true, false, 200 true, INFO_CONFIGCLASS_PLACEHOLDER.get(), 201 ConfigFileHandler.class.getName(), null, 202 INFO_DESCRIPTION_CONFIG_CLASS.get()); 203 configClass.setHidden(true); 204 205 configFile = 206 new StringArgument("configfile", 'f', "configFile", true, false, 207 true, INFO_CONFIGFILE_PLACEHOLDER.get(), null, 208 null, 209 INFO_DESCRIPTION_CONFIG_FILE.get()); 210 configFile.setHidden(true); 211 212 213 showUsageArgument = CommonArguments.getShowUsage(); 214 215 // Register the global arguments. 216 parser.addGlobalArgument(showUsageArgument); 217 parser.setUsageArgument(showUsageArgument, out); 218 parser.addGlobalArgument(configClass); 219 parser.addGlobalArgument(configFile); 220 221 globalArgumentsInitialized = true; 222 } 223 } 224 225 226 227 /** 228 * Registers the sub-commands with the argument parser. 229 * 230 * @throws ArgumentException 231 * If a sub-command could not be created. 232 */ 233 private void initializeSubCommands() throws ArgumentException { 234 if (!subCommandsInitialized) { 235 StringArgument backendID; 236 StringArgument baseDN; 237 StringArgument databaseName; 238 BooleanArgument skipDecode; 239 BooleanArgument statsOnly; 240 StringArgument maxKeyValue; 241 StringArgument minKeyValue; 242 IntegerArgument maxDataSize; 243 IntegerArgument minDataSize; 244 SubCommand sub; 245 246 sub = new SubCommand(parser, "list-root-containers", 247 INFO_DESCRIPTION_DBTEST_SUBCMD_LIST_ROOT_CONTAINERS.get()); 248 249 250 sub = new SubCommand(parser, "list-entry-containers", 251 INFO_DESCRIPTION_DBTEST_SUBCMD_LIST_ENTRY_CONTAINERS.get()); 252 backendID = 253 new StringArgument("backendid", 'n', "backendID", true, false, true, 254 INFO_BACKENDNAME_PLACEHOLDER.get(), null, null, 255 INFO_DESCRIPTION_DBTEST_BACKEND_ID.get()); 256 sub.addArgument(backendID); 257 258 259 sub = new SubCommand(parser, "list-database-containers", 260 INFO_DESCRIPTION_DBTEST_SUBCMD_LIST_DATABASE_CONTAINERS.get()); 261 backendID = 262 new StringArgument("backendid", 'n', "backendID", true, false, true, 263 INFO_BACKENDNAME_PLACEHOLDER.get(), null, null, 264 INFO_DESCRIPTION_DBTEST_BACKEND_ID.get()); 265 sub.addArgument(backendID); 266 baseDN = 267 new StringArgument("basedn", 'b', "baseDN", false, 268 false, true, INFO_BASEDN_PLACEHOLDER.get(), null, 269 null, 270 INFO_DESCRIPTION_DBTEST_BASE_DN.get()); 271 sub.addArgument(baseDN); 272 273 274 sub = new SubCommand(parser, "dump-database-container", 275 INFO_DESCRIPTION_DBTEST_SUBCMD_DUMP_DATABASE_CONTAINER.get()); 276 backendID = 277 new StringArgument("backendid", 'n', "backendID", true, false, true, 278 INFO_BACKENDNAME_PLACEHOLDER.get(), null, null, 279 INFO_DESCRIPTION_DBTEST_BACKEND_ID.get()); 280 sub.addArgument(backendID); 281 baseDN = 282 new StringArgument("basedn", 'b', "baseDN", true, 283 false, true, INFO_BASEDN_PLACEHOLDER.get(), null, 284 null, 285 INFO_DESCRIPTION_DBTEST_BASE_DN.get()); 286 sub.addArgument(baseDN); 287 databaseName = 288 new StringArgument("databasename", 'd', "databaseName", true, 289 false, true, INFO_DATABASE_NAME_PLACEHOLDER.get(), 290 null, null, 291 INFO_DESCRIPTION_DBTEST_DATABASE_NAME.get()); 292 sub.addArgument(databaseName); 293 skipDecode = 294 new BooleanArgument("skipdecode", 'p', "skipDecode", 295 INFO_DESCRIPTION_DBTEST_SKIP_DECODE.get()); 296 sub.addArgument(skipDecode); 297 statsOnly = 298 new BooleanArgument("statsonly", 'q', "statsOnly", 299 INFO_DESCRIPTION_DBTEST_STATS_ONLY.get()); 300 sub.addArgument(statsOnly); 301 maxKeyValue = new StringArgument("maxkeyvalue", 'K', "maxKeyValue", false, 302 false, true, 303 INFO_MAX_KEY_VALUE_PLACEHOLDER.get(), 304 null, null, 305 INFO_DESCRIPTION_DBTEST_MAX_KEY_VALUE.get()); 306 sub.addArgument(maxKeyValue); 307 minKeyValue = new StringArgument("minkeyvalue", 'k', "minKeyValue", false, 308 false, true, 309 INFO_MIN_KEY_VALUE_PLACEHOLDER.get(), 310 null, 311 null, 312 INFO_DESCRIPTION_DBTEST_MIN_KEY_VALUE.get()); 313 sub.addArgument(minKeyValue); 314 maxDataSize = new IntegerArgument("maxdatasize", 'S', "maxDataSize", 315 false, false, true, 316 INFO_MAX_DATA_SIZE_PLACEHOLDER.get(), 317 -1, 318 null, 319 INFO_DESCRIPTION_DBTEST_MAX_DATA_SIZE.get()); 320 sub.addArgument(maxDataSize); 321 minDataSize = new IntegerArgument("mindatasize", 's', "minDataSize", 322 false, false, true, 323 INFO_MIN_DATA_SIZE_PLACEHOLDER.get(), 324 -1, 325 null, 326 INFO_DESCRIPTION_DBTEST_MIN_DATA_SIZE.get()); 327 sub.addArgument(minDataSize); 328 329 330 sub = new SubCommand(parser, "list-index-status", 331 INFO_DESCRIPTION_DBTEST_SUBCMD_LIST_INDEX_STATUS.get()); 332 sub.setDocDescriptionSupplement( 333 SUPPLEMENT_DESCRIPTION_DBTEST_SUBCMD_LIST_INDEX_STATUS.get()); 334 backendID = 335 new StringArgument("backendid", 'n', "backendID", true, false, true, 336 INFO_BACKENDNAME_PLACEHOLDER.get(), null, null, 337 INFO_DESCRIPTION_DBTEST_BACKEND_ID.get()); 338 sub.addArgument(backendID); 339 baseDN = 340 new StringArgument("basedn", 'b', "baseDN", true, 341 true, true, INFO_BASEDN_PLACEHOLDER.get(), null, 342 null, 343 INFO_DESCRIPTION_DBTEST_BASE_DN.get()); 344 sub.addArgument(baseDN); 345 346 subCommandsInitialized = true; 347 } 348 } 349 350 351 /** 352 * Parses the provided command-line arguments and makes the 353 * appropriate changes to the Directory Server configuration. 354 * 355 * @param args 356 * The command-line arguments provided to this program. 357 * @param initializeServer 358 * Indicates whether to perform basic initialization (which 359 * should not be done if the tool is running in the same 360 * JVM as the server). 361 * @return The exit code from the configuration processing. A 362 * nonzero value indicates that there was some kind of 363 * problem during the configuration processing. 364 */ 365 private int run(String[] args, boolean initializeServer) { 366 367 // Register global arguments and sub-commands. 368 try { 369 initializeGlobalArguments(); 370 initializeSubCommands(); 371 } catch (ArgumentException e) { 372 printWrappedText(err, ERR_CANNOT_INITIALIZE_ARGS.get(e.getMessage())); 373 return 1; 374 } 375 376 // Parse the command-line arguments provided to this program. 377 try { 378 parser.parseArguments(args); 379 } catch (ArgumentException ae) { 380 parser.displayMessageAndUsageReference(err, ERR_ERROR_PARSING_ARGS.get(ae.getMessage())); 381 return 1; 382 } 383 384 // If the usage/version argument was provided, then we don't need 385 // to do anything else. 386 if (parser.usageOrVersionDisplayed()) { 387 return 0; 388 } 389 390 // Checks the version - if upgrade required, the tool is unusable 391 try 392 { 393 BuildVersion.checkVersionMismatch(); 394 } 395 catch (InitializationException e) 396 { 397 printWrappedText(err, e.getMessageObject()); 398 return 1; 399 } 400 401 // Only initialize the server when run as a standalone 402 // application. 403 if (initializeServer) { 404 // Perform the initial bootstrap of the Directory Server and process the 405 // configuration. 406 DirectoryServer directoryServer = DirectoryServer.getInstance(); 407 try 408 { 409 DirectoryServer.bootstrapClient(); 410 DirectoryServer.initializeJMX(); 411 } 412 catch (Exception e) 413 { 414 printWrappedText(err, ERR_SERVER_BOOTSTRAP_ERROR.get(getExceptionMessage(e))); 415 return 1; 416 } 417 418 try 419 { 420 directoryServer.initializeConfiguration(configClass.getValue(), 421 configFile.getValue()); 422 } 423 catch (InitializationException ie) 424 { 425 printWrappedText(err, ERR_CANNOT_LOAD_CONFIG.get(ie.getMessage())); 426 return 1; 427 } 428 catch (Exception e) 429 { 430 printWrappedText(err, ERR_CANNOT_LOAD_CONFIG.get(getExceptionMessage(e))); 431 return 1; 432 } 433 434 435 436 // Initialize the Directory Server schema elements. 437 try 438 { 439 directoryServer.initializeSchema(); 440 } 441 catch (ConfigException | InitializationException e) 442 { 443 printWrappedText(err, ERR_CANNOT_LOAD_SCHEMA.get(e.getMessage())); 444 return 1; 445 } 446 catch (Exception e) 447 { 448 printWrappedText(err, ERR_CANNOT_LOAD_SCHEMA.get(getExceptionMessage(e))); 449 return 1; 450 } 451 452 453 454 // Initialize the Directory Server core configuration. 455 try 456 { 457 CoreConfigManager coreConfigManager = new CoreConfigManager(directoryServer.getServerContext()); 458 coreConfigManager.initializeCoreConfig(); 459 } 460 catch (ConfigException | InitializationException e) 461 { 462 printWrappedText(err, ERR_CANNOT_INITIALIZE_CORE_CONFIG.get(e.getMessage())); 463 return 1; 464 } 465 catch (Exception e) 466 { 467 printWrappedText(err, ERR_CANNOT_INITIALIZE_CORE_CONFIG.get(getExceptionMessage(e))); 468 return 1; 469 } 470 471 472 // Initialize the Directory Server crypto manager. 473 try 474 { 475 directoryServer.initializeCryptoManager(); 476 } 477 catch (ConfigException | InitializationException e) 478 { 479 printWrappedText(err, ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER.get(e.getMessage())); 480 return 1; 481 } 482 catch (Exception e) 483 { 484 printWrappedText(err, ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER.get(getExceptionMessage(e))); 485 return 1; 486 } 487 } 488 489 // Make sure that we have a sub-command. 490 if (parser.getSubCommand() == null) 491 { 492 parser.displayMessageAndUsageReference(err, ERR_DBTEST_MISSING_SUBCOMMAND.get()); 493 return 1; 494 } 495 496 // Retrieve the sub-command implementation and run it. 497 SubCommand subCommand = parser.getSubCommand(); 498 try { 499 if("list-root-containers".equals(subCommand.getName())) 500 { 501 return listRootContainers(); 502 } 503 else if("list-entry-containers".equals(subCommand.getName())) 504 { 505 return listEntryContainers(subCommand.getArgument("backendid")); 506 } 507 else if("list-database-containers".equals(subCommand.getName())) 508 { 509 return listDatabaseContainers(subCommand.getArgument("backendid"), 510 subCommand.getArgument("basedn")); 511 } 512 else if("dump-database-container".equals(subCommand.getName())) 513 { 514 return dumpDatabaseContainer(subCommand.getArgument("backendid"), 515 subCommand.getArgument("basedn"), 516 subCommand.getArgument("databasename"), 517 subCommand.getArgument("skipdecode"), 518 subCommand.getArgument("statsonly"), 519 subCommand.getArgument("maxkeyvalue"), 520 subCommand.getArgument("minkeyvalue"), 521 subCommand.getArgument("maxdatasize"), 522 subCommand.getArgument("mindatasize")); 523 } 524 else if("list-index-status".equals(subCommand.getName())) 525 { 526 return listIndexStatus(subCommand.getArgument("backendid"), 527 subCommand.getArgument("basedn")); 528 } 529 return 0; 530 } catch (Exception e) { 531 printWrappedText(err, LocalizableMessage.raw(StaticUtils.stackTraceToString(e))); 532 return 1; 533 } 534 } 535 536 private int listRootContainers() 537 { 538 final Map<LocalDBBackendCfg, BackendImpl> jeBackends = getJEBackends(null); 539 int count = 0; 540 541 // Create a table of their properties. 542 TableBuilder builder = new TableBuilder(); 543 544 builder.appendHeading(INFO_LABEL_DBTEST_BACKEND_ID.get()); 545 builder.appendHeading(INFO_LABEL_DBTEST_DB_DIRECTORY.get()); 546 547 for(Map.Entry<LocalDBBackendCfg, BackendImpl> backend : 548 jeBackends.entrySet()) 549 { 550 builder.startRow(); 551 builder.appendCell(backend.getValue().getBackendID()); 552 builder.appendCell(backend.getKey().getDBDirectory()); 553 count++; 554 } 555 556 TextTablePrinter printer = new TextTablePrinter(out); 557 builder.print(printer); 558 out.format("%nTotal: %d%n", count); 559 560 return 0; 561 } 562 563 private int listEntryContainers(Argument backendID) 564 { 565 BackendImpl backend = getBackendById(backendID); 566 if(backend == null) 567 { 568 return 1; 569 } 570 571 // Acquire an shared lock for the backend. 572 try 573 { 574 String lockFile = LockFileManager.getBackendLockFileName(backend); 575 StringBuilder failureReason = new StringBuilder(); 576 if (! LockFileManager.acquireSharedLock(lockFile, failureReason)) 577 { 578 printWrappedText(err, ERR_DBTEST_CANNOT_LOCK_BACKEND.get(backend.getBackendID(), failureReason)); 579 return 1; 580 } 581 } 582 catch (Exception e) 583 { 584 printWrappedText(err, ERR_DBTEST_CANNOT_LOCK_BACKEND.get(backend.getBackendID(), getExceptionMessage(e))); 585 return 1; 586 } 587 588 RootContainer rc; 589 try 590 { 591 rc = backend.getReadOnlyRootContainer(); 592 } 593 catch(Exception e) 594 { 595 printWrappedText( 596 err, ERR_DBTEST_ERROR_INITIALIZING_BACKEND.get(backend.getBackendID(), stackTraceToSingleLineString(e))); 597 return 1; 598 } 599 600 try 601 { 602 // Create a table of their properties. 603 TableBuilder builder = new TableBuilder(); 604 int count = 0; 605 606 builder.appendHeading(INFO_LABEL_DBTEST_BASE_DN.get()); 607 builder.appendHeading(INFO_LABEL_DBTEST_JE_DATABASE_PREFIX.get()); 608 builder.appendHeading(INFO_LABEL_DBTEST_ENTRY_COUNT.get()); 609 610 for(EntryContainer ec : rc.getEntryContainers()) 611 { 612 builder.startRow(); 613 builder.appendCell(ec.getBaseDN()); 614 builder.appendCell(ec.getDatabasePrefix()); 615 builder.appendCell(ec.getEntryCount()); 616 count++; 617 } 618 619 TextTablePrinter printer = new TextTablePrinter(out); 620 builder.print(printer); 621 out.format("%nTotal: %d%n", count); 622 623 return 0; 624 } 625 catch(DatabaseException de) 626 { 627 printWrappedText(err, ERR_DBTEST_ERROR_READING_DATABASE.get(stackTraceToSingleLineString(de))); 628 return 1; 629 } 630 finally 631 { 632 close(rc); 633 releaseSharedLock(backend); 634 } 635 } 636 637 private int listDatabaseContainers(Argument backendID, Argument baseDN) 638 { 639 BackendImpl backend = getBackendById(backendID); 640 if(backend == null) 641 { 642 return 1; 643 } 644 645 DN base = null; 646 if(baseDN.isPresent()) 647 { 648 try 649 { 650 base = DN.valueOf(baseDN.getValue()); 651 } 652 catch(DirectoryException de) 653 { 654 printWrappedText(err, ERR_DBTEST_DECODE_BASE_DN.get(baseDN.getValue(), getExceptionMessage(de))); 655 return 1; 656 } 657 } 658 659 // Acquire an shared lock for the backend. 660 try 661 { 662 String lockFile = LockFileManager.getBackendLockFileName(backend); 663 StringBuilder failureReason = new StringBuilder(); 664 if (! LockFileManager.acquireSharedLock(lockFile, failureReason)) 665 { 666 printWrappedText(err, ERR_DBTEST_CANNOT_LOCK_BACKEND.get(backend.getBackendID(), failureReason)); 667 return 1; 668 } 669 } 670 catch (Exception e) 671 { 672 printWrappedText(err, ERR_DBTEST_CANNOT_LOCK_BACKEND.get(backend.getBackendID(), getExceptionMessage(e))); 673 return 1; 674 } 675 676 RootContainer rc; 677 try 678 { 679 rc = backend.getReadOnlyRootContainer(); 680 } 681 catch(Exception e) 682 { 683 printWrappedText( 684 err, ERR_DBTEST_ERROR_INITIALIZING_BACKEND.get(backend.getBackendID(), stackTraceToSingleLineString(e))); 685 return 1; 686 } 687 688 689 try 690 { 691 // Create a table of their properties. 692 TableBuilder builder = new TableBuilder(); 693 int count = 0; 694 695 builder.appendHeading(INFO_LABEL_DBTEST_DATABASE_NAME.get()); 696 builder.appendHeading(INFO_LABEL_DBTEST_DATABASE_TYPE.get()); 697 builder.appendHeading(INFO_LABEL_DBTEST_JE_DATABASE_NAME.get()); 698 builder.appendHeading(INFO_LABEL_DBTEST_ENTRY_COUNT.get()); 699 700 if(base != null) 701 { 702 EntryContainer ec = rc.getEntryContainer(base); 703 if(ec == null) 704 { 705 printWrappedText(err, ERR_DBTEST_NO_ENTRY_CONTAINERS_FOR_BASE_DN.get(base, backend.getBackendID())); 706 return 1; 707 } 708 709 count = appendDatabaseContainerRows(builder, ec, count); 710 } 711 else 712 { 713 for(EntryContainer ec : rc.getEntryContainers()) 714 { 715 builder.startRow(); 716 builder.appendCell("Base DN: " + ec.getBaseDN()); 717 count = appendDatabaseContainerRows(builder, ec, count); 718 } 719 } 720 721 TextTablePrinter printer = new TextTablePrinter(out); 722 builder.print(printer); 723 out.format("%nTotal: %d%n", count); 724 725 return 0; 726 } 727 catch(DatabaseException de) 728 { 729 printWrappedText(err, ERR_DBTEST_ERROR_READING_DATABASE.get(stackTraceToSingleLineString(de))); 730 return 1; 731 } 732 finally 733 { 734 close(rc); 735 releaseSharedLock(backend); 736 } 737 } 738 739 private int appendDatabaseContainerRows(TableBuilder builder, EntryContainer ec, int count) 740 { 741 ArrayList<DatabaseContainer> databaseContainers = new ArrayList<>(); 742 ec.listDatabases(databaseContainers); 743 String toReplace = ec.getDatabasePrefix() + "_"; 744 for(DatabaseContainer dc : databaseContainers) 745 { 746 builder.startRow(); 747 builder.appendCell(dc.getName().replace(toReplace, "")); 748 builder.appendCell(dc.getClass().getSimpleName()); 749 builder.appendCell(dc.getName()); 750 builder.appendCell(dc.getRecordCount()); 751 count++; 752 } 753 return count; 754 } 755 756 private void close(RootContainer rc) 757 { 758 try 759 { 760 rc.close(); 761 } 762 catch(DatabaseException ignored) 763 { 764 // Ignore. 765 } 766 } 767 768 private void releaseSharedLock(BackendImpl backend) 769 { 770 try 771 { 772 String lockFile = LockFileManager.getBackendLockFileName(backend); 773 StringBuilder failureReason = new StringBuilder(); 774 if (!LockFileManager.releaseLock(lockFile, failureReason)) 775 { 776 printWrappedText(err, WARN_DBTEST_CANNOT_UNLOCK_BACKEND.get(backend.getBackendID(), failureReason)); 777 } 778 } 779 catch (Exception e) 780 { 781 printWrappedText(err, WARN_DBTEST_CANNOT_UNLOCK_BACKEND.get(backend.getBackendID(), getExceptionMessage(e))); 782 } 783 } 784 785 private BackendImpl getBackendById(Argument backendId) 786 { 787 final String backendID = backendId.getValue(); 788 final List<Backend<?>> otherBackends = new ArrayList<>(); 789 final Map<LocalDBBackendCfg, BackendImpl> jeBackends = getJEBackends(otherBackends); 790 791 for (BackendImpl b : jeBackends.values()) 792 { 793 if (b.getBackendID().equalsIgnoreCase(backendID)) 794 { 795 return b; 796 } 797 } 798 799 for (Backend<?> b : otherBackends) 800 { 801 if (b.getBackendID().equalsIgnoreCase(backendID)) 802 { 803 printWrappedText(err, ERR_DBTEST_NOT_JE_BACKEND.get(backendID)); 804 return null; 805 } 806 } 807 printWrappedText(err, ERR_DBTEST_NO_BACKENDS_FOR_ID.get(backendID)); 808 return null; 809 } 810 811 private int listIndexStatus(Argument backendID, Argument baseDN) 812 { 813 BackendImpl backend = getBackendById(backendID); 814 if(backend == null) 815 { 816 return 1; 817 } 818 819 DN base = null; 820 if(baseDN.isPresent()) 821 { 822 try 823 { 824 base = DN.valueOf(baseDN.getValue()); 825 } 826 catch(DirectoryException de) 827 { 828 printWrappedText(err, ERR_DBTEST_DECODE_BASE_DN.get(baseDN.getValue(), getExceptionMessage(de))); 829 return 1; 830 } 831 } 832 833 // Acquire an shared lock for the backend. 834 try 835 { 836 String lockFile = LockFileManager.getBackendLockFileName(backend); 837 StringBuilder failureReason = new StringBuilder(); 838 if (! LockFileManager.acquireSharedLock(lockFile, failureReason)) 839 { 840 printWrappedText(err, ERR_DBTEST_CANNOT_LOCK_BACKEND.get(backend.getBackendID(), failureReason)); 841 return 1; 842 } 843 } 844 catch (Exception e) 845 { 846 printWrappedText(err, ERR_DBTEST_CANNOT_LOCK_BACKEND.get(backend.getBackendID(), getExceptionMessage(e))); 847 return 1; 848 } 849 850 RootContainer rc; 851 try 852 { 853 rc = backend.getReadOnlyRootContainer(); 854 } 855 catch(Exception e) 856 { 857 printWrappedText( 858 err, ERR_DBTEST_ERROR_INITIALIZING_BACKEND.get(backend.getBackendID(), stackTraceToSingleLineString(e))); 859 return 1; 860 } 861 862 863 try 864 { 865 // Create a table of their properties. 866 TableBuilder builder = new TableBuilder(); 867 int count = 0; 868 869 builder.appendHeading(INFO_LABEL_DBTEST_INDEX_NAME.get()); 870 builder.appendHeading(INFO_LABEL_DBTEST_INDEX_TYPE.get()); 871 builder.appendHeading(INFO_LABEL_DBTEST_JE_DATABASE_NAME.get()); 872 builder.appendHeading(INFO_LABEL_DBTEST_INDEX_STATUS.get()); 873 builder.appendHeading(INFO_LABEL_DBTEST_JE_RECORD_COUNT.get()); 874 builder.appendHeading( 875 INFO_LABEL_DBTEST_INDEX_UNDEFINED_RECORD_COUNT.get()); 876 builder.appendHeading(LocalizableMessage.raw("95%")); 877 builder.appendHeading(LocalizableMessage.raw("90%")); 878 builder.appendHeading(LocalizableMessage.raw("85%")); 879 880 881 EntryContainer ec = rc.getEntryContainer(base); 882 if(ec == null) 883 { 884 printWrappedText(err, ERR_DBTEST_NO_ENTRY_CONTAINERS_FOR_BASE_DN.get(base, backend.getBackendID())); 885 return 1; 886 } 887 888 ArrayList<DatabaseContainer> databaseContainers = new ArrayList<>(); 889 Map<Index, StringBuilder> undefinedKeys = new HashMap<>(); 890 ec.listDatabases(databaseContainers); 891 String toReplace = ec.getDatabasePrefix() + "_"; 892 for(DatabaseContainer dc : databaseContainers) 893 { 894 if(dc instanceof Index || dc instanceof VLVIndex) 895 { 896 builder.startRow(); 897 builder.appendCell(dc.getName().replace(toReplace, "")); 898 builder.appendCell(dc.getClass().getSimpleName()); 899 builder.appendCell(dc.getName()); 900 builder.appendCell(ec.getState().getIndexTrustState(null, dc)); 901 builder.appendCell(dc.getRecordCount()); 902 903 if(dc instanceof Index) 904 { 905 Index index = (Index)dc; 906 long undefined = 0, ninetyFive = 0, ninety = 0, eighty = 0; 907 DatabaseEntry key = new DatabaseEntry(); 908 DatabaseEntry data = new DatabaseEntry(); 909 LockMode lockMode = LockMode.DEFAULT; 910 OperationStatus status; 911 912 Cursor cursor = dc.openCursor(null, CursorConfig.DEFAULT); 913 status = cursor.getFirst(key, data, lockMode); 914 while(status == OperationStatus.SUCCESS) 915 { 916 byte[] bytes = data.getData(); 917 if (bytes.length == 0 || (bytes[0] & 0x80) == 0x80) 918 { 919 // Entry limit has exceeded and there is no encoded 920 // undefined set size. 921 undefined ++; 922 StringBuilder keyList = undefinedKeys.get(index); 923 if(keyList == null) 924 { 925 keyList = new StringBuilder(); 926 undefinedKeys.put(index, keyList); 927 } 928 else 929 { 930 keyList.append(" "); 931 } 932 if(index == ec.getID2Children() || index == ec.getID2Subtree()) 933 { 934 keyList.append("[").append( 935 JebFormat.entryIDFromDatabase(key.getData())).append("]"); 936 } 937 else 938 { 939 keyList.append("[").append( 940 new String(key.getData())).append("]"); 941 } 942 } 943 else 944 { 945 // Seems like entry limit has not been exceeded and the bytes 946 // is a list of entry IDs. 947 double percentFull = 948 (bytes.length / (double)8) / index.getIndexEntryLimit(); 949 if(percentFull >= .8) 950 { 951 if(percentFull < .9) 952 { 953 eighty++; 954 } 955 else if(percentFull < .95) 956 { 957 ninety++; 958 } 959 else 960 { 961 ninetyFive++; 962 } 963 } 964 } 965 status = cursor.getNext(key, data, lockMode); 966 } 967 builder.appendCell(undefined); 968 builder.appendCell(ninetyFive); 969 builder.appendCell(ninety); 970 builder.appendCell(eighty); 971 cursor.close(); 972 } 973 else 974 { 975 builder.appendCell("-"); 976 builder.appendCell("-"); 977 builder.appendCell("-"); 978 builder.appendCell("-"); 979 } 980 981 count++; 982 } 983 } 984 985 TextTablePrinter printer = new TextTablePrinter(out); 986 builder.print(printer); 987 out.format("%nTotal: %d%n", count); 988 for(Map.Entry<Index, StringBuilder> e : undefinedKeys.entrySet()) 989 { 990 out.format("%nIndex: %s%n", e.getKey().getName().replace(toReplace, "")); 991 out.format("Undefined keys: %s%n", e.getValue().toString()); 992 } 993 return 0; 994 } 995 catch(DatabaseException de) 996 { 997 printWrappedText(err, ERR_DBTEST_ERROR_READING_DATABASE.get(stackTraceToSingleLineString(de))); 998 return 1; 999 } 1000 finally 1001 { 1002 close(rc); 1003 releaseSharedLock(backend); 1004 } 1005 } 1006 1007 private int dumpDatabaseContainer(Argument backendID, Argument baseDN, 1008 Argument databaseName, Argument skipDecode, 1009 Argument statsOnly, 1010 Argument maxKeyValue, Argument minKeyValue, 1011 Argument maxDataSize, Argument minDataSize) 1012 { 1013 BackendImpl backend = getBackendById(backendID); 1014 if(backend == null) 1015 { 1016 return 1; 1017 } 1018 1019 DN base = null; 1020 try 1021 { 1022 base = DN.valueOf(baseDN.getValue()); 1023 } 1024 catch(DirectoryException de) 1025 { 1026 printWrappedText(err, ERR_DBTEST_DECODE_BASE_DN.get(baseDN.getValue(), getExceptionMessage(de))); 1027 return 1; 1028 } 1029 1030 // Acquire an shared lock for the backend. 1031 try 1032 { 1033 String lockFile = LockFileManager.getBackendLockFileName(backend); 1034 StringBuilder failureReason = new StringBuilder(); 1035 if (! LockFileManager.acquireSharedLock(lockFile, failureReason)) 1036 { 1037 printWrappedText(err, ERR_DBTEST_CANNOT_LOCK_BACKEND.get(backend.getBackendID(), failureReason)); 1038 return 1; 1039 } 1040 } 1041 catch (Exception e) 1042 { 1043 printWrappedText(err, ERR_DBTEST_CANNOT_LOCK_BACKEND.get(backend.getBackendID(), getExceptionMessage(e))); 1044 return 1; 1045 } 1046 1047 RootContainer rc; 1048 try 1049 { 1050 rc = backend.getReadOnlyRootContainer(); 1051 } 1052 catch(Exception e) 1053 { 1054 printWrappedText( 1055 err, ERR_DBTEST_ERROR_INITIALIZING_BACKEND.get(backend.getBackendID(), stackTraceToSingleLineString(e))); 1056 return 1; 1057 } 1058 1059 try 1060 { 1061 EntryContainer ec = rc.getEntryContainer(base); 1062 if(ec == null) 1063 { 1064 printWrappedText(err, ERR_DBTEST_NO_ENTRY_CONTAINERS_FOR_BASE_DN.get(base, backend.getBackendID())); 1065 return 1; 1066 } 1067 1068 DatabaseContainer databaseContainer = null; 1069 ArrayList<DatabaseContainer> databaseContainers = new ArrayList<>(); 1070 ec.listDatabases(databaseContainers); 1071 String toReplace = ec.getDatabasePrefix() + "_"; 1072 for(DatabaseContainer dc : databaseContainers) 1073 { 1074 if(dc.getName().replace(toReplace, "").equalsIgnoreCase(databaseName.getValue())) 1075 { 1076 databaseContainer = dc; 1077 break; 1078 } 1079 } 1080 1081 if(databaseContainer == null) 1082 { 1083 printWrappedText( 1084 err, ERR_DBTEST_NO_DATABASE_CONTAINERS_FOR_NAME.get(databaseName.getValue(), base, backend.getBackendID())); 1085 return 1; 1086 } 1087 1088 int count = 0; 1089 long totalKeySize = 0; 1090 long totalDataSize = 0; 1091 int indent = 4; 1092 1093 Cursor cursor = databaseContainer.openCursor(null, CursorConfig.DEFAULT); 1094 try 1095 { 1096 DatabaseEntry key = new DatabaseEntry(); 1097 DatabaseEntry data = new DatabaseEntry(); 1098 LockMode lockMode = LockMode.DEFAULT; 1099 OperationStatus status; 1100 byte[] start = null; 1101 byte[] end = null; 1102 int minSize = -1; 1103 int maxSize = -1; 1104 1105 if(maxDataSize.isPresent()) 1106 { 1107 try 1108 { 1109 maxSize = maxDataSize.getIntValue(); 1110 } 1111 catch(Exception e) 1112 { 1113 printWrappedText(err, ERR_DBTEST_CANNOT_DECODE_SIZE.get(maxDataSize.getValue(), getExceptionMessage(e))); 1114 return 1; 1115 } 1116 } 1117 1118 if(minDataSize.isPresent()) 1119 { 1120 try 1121 { 1122 minSize = minDataSize.getIntValue(); 1123 } 1124 catch(Exception e) 1125 { 1126 printWrappedText(err, ERR_DBTEST_CANNOT_DECODE_SIZE.get(minDataSize.getValue(), getExceptionMessage(e))); 1127 return 1; 1128 } 1129 } 1130 1131 // Parse the min value if given 1132 if(minKeyValue.isPresent()) 1133 { 1134 try 1135 { 1136 start = parseKeyValue(minKeyValue.getValue(), databaseContainer); 1137 } 1138 catch(Exception e) 1139 { 1140 printWrappedText(err, ERR_DBTEST_CANNOT_DECODE_KEY.get(minKeyValue.getValue(), getExceptionMessage(e))); 1141 return 1; 1142 } 1143 } 1144 1145 // Parse the max value if given 1146 if(maxKeyValue.isPresent()) 1147 { 1148 try 1149 { 1150 end = parseKeyValue(maxKeyValue.getValue(), databaseContainer); 1151 } 1152 catch(Exception e) 1153 { 1154 printWrappedText(err, ERR_DBTEST_CANNOT_DECODE_KEY.get(maxKeyValue.getValue(), getExceptionMessage(e))); 1155 return 1; 1156 } 1157 } 1158 1159 1160 if(start != null) 1161 { 1162 key.setData(start); 1163 status = cursor.getSearchKey(key, data, lockMode); 1164 } 1165 else 1166 { 1167 status = cursor.getFirst(key, data, lockMode); 1168 } 1169 1170 final String lineSep = System.getProperty("line.separator"); 1171 while(status == OperationStatus.SUCCESS) 1172 { 1173 // Make sure this record is within the value size params 1174 if((minSize > 0 && data.getSize() < minSize) || 1175 (maxSize > 0 && data.getSize() > maxSize)) 1176 { 1177 status = cursor.getNext(key, data, lockMode); 1178 continue; 1179 } 1180 1181 // Make sure we haven't gone pass the max value yet 1182 if(end != null 1183 && getComparator(databaseContainer).compare(key.getData(), end) > 0) 1184 { 1185 break; 1186 } 1187 1188 if (!statsOnly.isPresent()) 1189 { 1190 LocalizableMessage keyLabel = INFO_LABEL_DBTEST_KEY.get(); 1191 LocalizableMessage dataLabel = INFO_LABEL_DBTEST_DATA.get(); 1192 1193 String formatedKey = null; 1194 String formatedData = null; 1195 1196 if(!skipDecode.isPresent()) 1197 { 1198 if(databaseContainer instanceof DN2ID) 1199 { 1200 try 1201 { 1202 formatedKey = new String(key.getData()) + ec.getBaseDN(); 1203 keyLabel = INFO_LABEL_DBTEST_ENTRY_DN.get(); 1204 } 1205 catch(Exception e) 1206 { 1207 printWrappedText(err, ERR_DBTEST_DECODE_FAIL.get(getExceptionMessage(e))); 1208 } 1209 formatedData = String.valueOf( 1210 JebFormat.entryIDFromDatabase(data.getData())); 1211 dataLabel = INFO_LABEL_DBTEST_ENTRY_ID.get(); 1212 } 1213 else if(databaseContainer instanceof ID2Entry) 1214 { 1215 formatedKey = String.valueOf( 1216 JebFormat.entryIDFromDatabase(key.getData())); 1217 keyLabel = INFO_LABEL_DBTEST_ENTRY_ID.get(); 1218 try 1219 { 1220 formatedData = lineSep + 1221 ID2Entry.entryFromDatabase( 1222 ByteString.wrap(data.getData()), 1223 ec.getRootContainer().getCompressedSchema()).toLDIFString(); 1224 dataLabel = INFO_LABEL_DBTEST_ENTRY.get(); 1225 } 1226 catch(Exception e) 1227 { 1228 printWrappedText(err, ERR_DBTEST_DECODE_FAIL.get(getExceptionMessage(e))); 1229 } 1230 } 1231 else if(databaseContainer instanceof DN2URI) 1232 { 1233 try 1234 { 1235 formatedKey = new String(key.getData()); 1236 keyLabel = INFO_LABEL_DBTEST_ENTRY_DN.get(); 1237 } 1238 catch(Exception e) 1239 { 1240 printWrappedText(err, ERR_DBTEST_DECODE_FAIL.get(getExceptionMessage(e))); 1241 } 1242 formatedData = new String(key.getData()); 1243 dataLabel = INFO_LABEL_DBTEST_URI.get(); 1244 } 1245 else if(databaseContainer instanceof Index) 1246 { 1247 formatedKey = new String(key.getData()); 1248 keyLabel = INFO_LABEL_DBTEST_INDEX_VALUE.get(); 1249 1250 EntryIDSet idSet = new EntryIDSet(key.getData(), data.getData()); 1251 if(idSet.isDefined()) 1252 { 1253 int lineCount = 0; 1254 StringBuilder builder = new StringBuilder(); 1255 1256 for (EntryID entryID : idSet) 1257 { 1258 builder.append(entryID); 1259 if(lineCount == 10) 1260 { 1261 builder.append(lineSep); 1262 lineCount = 0; 1263 } 1264 else 1265 { 1266 builder.append(" "); 1267 lineCount++; 1268 } 1269 } 1270 formatedData = builder.toString(); 1271 } 1272 else 1273 { 1274 formatedData = idSet.toString(); 1275 } 1276 dataLabel = INFO_LABEL_DBTEST_INDEX_ENTRY_ID_LIST.get(); 1277 } 1278 else if(databaseContainer instanceof VLVIndex) 1279 { 1280 VLVIndex index = (VLVIndex)databaseContainer; 1281 SortKey[] sortKeys = index.sortOrder.getSortKeys(); 1282 1283 int pos = 0; 1284 byte[] keyBytes = key.getData(); 1285 if(keyBytes.length > 0) 1286 { 1287 StringBuilder builder = new StringBuilder(); 1288 1289 // Decode the attribute values 1290 for(SortKey sortKey : sortKeys) 1291 { 1292 int valueLength = keyBytes[pos] & 0x7F; 1293 if (keyBytes[pos++] != valueLength) 1294 { 1295 int numLengthBytes = valueLength; 1296 valueLength = 0; 1297 for (int k=0; k < numLengthBytes; k++, pos++) 1298 { 1299 valueLength = (valueLength << 8) | 1300 (keyBytes[pos] & 0xFF); 1301 } 1302 } 1303 1304 byte[] valueBytes = new byte[valueLength]; 1305 System.arraycopy(keyBytes, pos, valueBytes, 0, valueLength); 1306 builder.append(sortKey.getAttributeType().getNameOrOID()); 1307 builder.append(": "); 1308 if(valueBytes.length == 0) 1309 { 1310 builder.append("NULL"); 1311 } 1312 else 1313 { 1314 builder.append(new String(valueBytes)); 1315 } 1316 builder.append(" "); 1317 pos += valueLength; 1318 } 1319 1320 byte[] entryIDBytes = new byte[8]; 1321 System.arraycopy(keyBytes, pos, entryIDBytes, 0, 1322 entryIDBytes.length); 1323 long entryID = JebFormat.entryIDFromDatabase(entryIDBytes); 1324 1325 formatedKey = lineSep + entryID + ": " + builder; 1326 } 1327 else 1328 { 1329 formatedKey = "UNBOUNDED"; 1330 } 1331 keyLabel = INFO_LABEL_DBTEST_VLV_INDEX_LAST_SORT_KEYS.get(); 1332 1333 try 1334 { 1335 StringBuilder builder = new StringBuilder(); 1336 SortValuesSet svs = new SortValuesSet(key.getData(), 1337 data.getData(), 1338 index); 1339 long[] entryIDs = svs.getEntryIDs(); 1340 for(int i = 0; i < entryIDs.length; i++) 1341 { 1342 builder.append(entryIDs[i]); 1343 builder.append(": "); 1344 for(int j = 0; j < sortKeys.length; j++) 1345 { 1346 SortKey sortKey = index.sortOrder.getSortKeys()[j]; 1347 ByteString value = svs.getValue(i * sortKeys.length + j); 1348 builder.append(sortKey.getAttributeType().getNameOrOID()); 1349 builder.append(": "); 1350 if(value == null) 1351 { 1352 builder.append("NULL"); 1353 } 1354 else if(value.length() == 0) 1355 { 1356 builder.append("SIZE-EXCEEDED"); 1357 } 1358 else 1359 { 1360 builder.append(value); 1361 } 1362 builder.append(" "); 1363 } 1364 builder.append(lineSep); 1365 } 1366 formatedData = lineSep + builder; 1367 dataLabel = INFO_LABEL_DBTEST_INDEX_ENTRY_ID_LIST.get(); 1368 } 1369 catch(Exception e) 1370 { 1371 printWrappedText(err, ERR_DBTEST_DECODE_FAIL.get(getExceptionMessage(e))); 1372 } 1373 } 1374 } 1375 1376 if(formatedKey == null) 1377 { 1378 StringBuilder keyBuilder = new StringBuilder(); 1379 StaticUtils.byteArrayToHexPlusAscii(keyBuilder, key.getData(), indent); 1380 formatedKey = lineSep + keyBuilder; 1381 } 1382 if(formatedData == null) 1383 { 1384 StringBuilder dataBuilder = new StringBuilder(); 1385 StaticUtils.byteArrayToHexPlusAscii(dataBuilder, data.getData(), indent); 1386 formatedData = lineSep + dataBuilder; 1387 } 1388 1389 out.format("%s (%d bytes): %s%n", keyLabel, 1390 key.getData().length, formatedKey); 1391 out.format("%s (%d bytes): %s%n%n", dataLabel, 1392 data.getData().length, formatedData); 1393 } 1394 status = cursor.getNext(key, data, lockMode); 1395 count++; 1396 totalKeySize += key.getData().length; 1397 totalDataSize += data.getData().length; 1398 } 1399 } 1400 finally 1401 { 1402 cursor.close(); 1403 } 1404 out.format("%nTotal Records: %d%n", count); 1405 if(count > 0) 1406 { 1407 out.format("Total / Average Key Size: %d bytes / %d bytes%n", 1408 totalKeySize, totalKeySize / count); 1409 out.format("Total / Average Data Size: %d bytes / %d bytes%n", 1410 totalDataSize, totalDataSize / count); 1411 } 1412 return 0; 1413 } 1414 catch(DatabaseException de) 1415 { 1416 printWrappedText(err, ERR_DBTEST_ERROR_READING_DATABASE.get(stackTraceToSingleLineString(de))); 1417 return 1; 1418 } 1419 finally 1420 { 1421 close(rc); 1422 releaseSharedLock(backend); 1423 } 1424 } 1425 1426 private byte[] parseKeyValue(String value, DatabaseContainer databaseContainer) 1427 throws ParseException, DirectoryException 1428 { 1429 if(value.startsWith("0x")) 1430 { 1431 return hexStringToByteArray(value.substring(2)); 1432 } 1433 else if(databaseContainer instanceof DN2ID 1434 || databaseContainer instanceof DN2URI) 1435 { 1436 // Encode the value as a DN 1437 return DN.valueOf(value).toNormalizedByteString().toByteArray(); 1438 } 1439 else if(databaseContainer instanceof ID2Entry) 1440 { 1441 // Encode the value as an entryID 1442 return JebFormat.entryIDToDatabase( 1443 Long.parseLong(value)); 1444 } 1445 else if(databaseContainer instanceof VLVIndex) 1446 { 1447 // Encode the value as a size/value pair 1448 byte[] vBytes = StaticUtils.getBytes(value); 1449 ByteStringBuilder builder = new ByteStringBuilder(); 1450 builder.appendBERLength(vBytes.length); 1451 builder.append(vBytes); 1452 return builder.toByteArray(); 1453 } 1454 else 1455 { 1456 return StaticUtils.getBytes(value); 1457 } 1458 } 1459 1460 private Comparator<byte[]> getComparator(DatabaseContainer databaseContainer) 1461 { 1462 if(databaseContainer instanceof Index) 1463 { 1464 return ((Index) databaseContainer).getComparator(); 1465 } 1466 else if(databaseContainer instanceof VLVIndex) 1467 { 1468 return ((VLVIndex)databaseContainer).comparator; 1469 } 1470 else 1471 { // default comparator 1472 return ByteSequence.BYTE_ARRAY_COMPARATOR; 1473 } 1474 } 1475 1476 private static Map<LocalDBBackendCfg, BackendImpl> getJEBackends(Collection<Backend<?>> otherBackends) 1477 { 1478 ArrayList<Backend> backendList = new ArrayList<>(); 1479 ArrayList<BackendCfg> entryList = new ArrayList<>(); 1480 ArrayList<List<DN>> dnList = new ArrayList<>(); 1481 BackendToolUtils.getBackends(backendList, entryList, dnList); 1482 1483 final Map<LocalDBBackendCfg, BackendImpl> jeBackends = new LinkedHashMap<>(); 1484 for(int i = 0; i < backendList.size(); i++) 1485 { 1486 Backend<?> backend = backendList.get(i); 1487 if(backend instanceof BackendImpl) 1488 { 1489 jeBackends.put((LocalDBBackendCfg)entryList.get(i), 1490 (BackendImpl)backend); 1491 } 1492 else if (otherBackends != null) 1493 { 1494 otherBackends.add(backend); 1495 } 1496 } 1497 return jeBackends; 1498 } 1499}