001/* 002 * Copyright 2014-2020 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2014-2020 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2014-2020 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.ldap.sdk.unboundidds.controls; 037 038 039 040import java.util.ArrayList; 041 042import com.unboundid.asn1.ASN1Boolean; 043import com.unboundid.asn1.ASN1Element; 044import com.unboundid.asn1.ASN1Integer; 045import com.unboundid.asn1.ASN1Long; 046import com.unboundid.asn1.ASN1OctetString; 047import com.unboundid.asn1.ASN1Sequence; 048import com.unboundid.ldap.sdk.Control; 049import com.unboundid.ldap.sdk.LDAPException; 050import com.unboundid.ldap.sdk.ResultCode; 051import com.unboundid.util.Debug; 052import com.unboundid.util.NotMutable; 053import com.unboundid.util.NotNull; 054import com.unboundid.util.Nullable; 055import com.unboundid.util.StaticUtils; 056import com.unboundid.util.ThreadSafety; 057import com.unboundid.util.ThreadSafetyLevel; 058import com.unboundid.util.Validator; 059 060import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*; 061 062 063 064/** 065 * This class provides a request control which may be included in a search 066 * request to indicate that the server should provide the number of entries that 067 * match the search criteria. The count will be included in the search result 068 * done message, and all search result entries will be suppressed. 069 * <BR> 070 * <BLOCKQUOTE> 071 * <B>NOTE:</B> This class, and other classes within the 072 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 073 * supported for use against Ping Identity, UnboundID, and 074 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 075 * for proprietary functionality or for external specifications that are not 076 * considered stable or mature enough to be guaranteed to work in an 077 * interoperable way with other types of LDAP servers. 078 * </BLOCKQUOTE> 079 * <BR> 080 * Whenever possible, the server will use index information to quickly identify 081 * entries matching the criteria of the associated search request. However, if 082 * the count is only determined using index information, then that count may 083 * include entries that would not actually be returned to the client in the 084 * course of processing that search (e.g., because the client doesn't have 085 * permission to access the entry, or because it is a special "operational" 086 * entry like an LDAP subentry, replication conflict entry, or soft-deleted 087 * entry). Indicating that the server should always examine candidate entries 088 * will increase the length of time to obtain the matching entry count, but will 089 * ensure that the count will not include entries that would not otherwise be 090 * returned by that search. 091 * <BR><BR> 092 * Also note that this control is not compatible for use with other controls 093 * that may cause only a subset of entries to be returned, including the simple 094 * paged results control and the virtual list view control. It is also not 095 * compatible for use with other controls that may cause the server to return 096 * more entries than those that match the search criteria, like the LDAP join 097 * control. 098 * <BR><BR> 099 * The OID for a matching entry count request control is 100 * "1.3.6.1.4.1.30221.2.5.36", and it may have a criticality of either 101 * {@code true} or {@code false}. It must include a value with the following 102 * encoding: 103 * <PRE> 104 * MatchingEntryCountRequest ::= SEQUENCE { 105 * maxCandidatesToExamine [0] INTEGER (0 .. MAX) DEFAULT 0, 106 * alwaysExamineCandidates [1] BOOLEAN DEFAULT FALSE, 107 * processSearchIfUnindexed [2] BOOLEAN DEFAULT FALSE, 108 * includeDebugInfo [3] BOOLEAN DEFAULT FALSE, 109 * skipResolvingExplodedIndexes [4] BOOLEAN DEFAULT FALSE, 110 * fastShortCircuitThreshold [5] INTEGER (0 .. MAX) OPTIONAL, 111 * slowShortCircuitThreshold [6] INTEGER (0 .. MAX) OPTIONAL, 112 * ... } 113 * </PRE> 114 * 115 * @see MatchingEntryCountResponseControl 116 */ 117@NotMutable() 118@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 119public final class MatchingEntryCountRequestControl 120 extends Control 121{ 122 /** 123 * The OID (1.3.6.1.4.1.30221.2.5.36) for the matching entry count request 124 * control. 125 */ 126 @NotNull public static final String MATCHING_ENTRY_COUNT_REQUEST_OID = 127 "1.3.6.1.4.1.30221.2.5.36"; 128 129 130 131 /** 132 * The BER type for the element that specifies the maximum number of candidate 133 * entries to examine. 134 */ 135 private static final byte TYPE_MAX_CANDIDATES_TO_EXAMINE = (byte) 0x80; 136 137 138 139 /** 140 * The BER type for the element that indicates whether always examine 141 * candidate entries to determine whether they would actually be returned to 142 * the client. 143 */ 144 private static final byte TYPE_ALWAYS_EXAMINE_CANDIDATES = (byte) 0x81; 145 146 147 148 /** 149 * The BER type for the element that indicates whether to process an unindexed 150 * search to determine the number of matching entries. 151 */ 152 private static final byte TYPE_PROCESS_SEARCH_IF_UNINDEXED = (byte) 0x82; 153 154 155 156 /** 157 * The BER type for the element that indicates whether to include debug 158 * information in the response. 159 */ 160 private static final byte TYPE_INCLUDE_DEBUG_INFO = (byte) 0x83; 161 162 163 164 /** 165 * The BER type for the element that indicates whether to skip resolving 166 * exploded indexes if the number of matching entries is known. 167 */ 168 private static final byte TYPE_SKIP_RESOLVING_EXPLODED_INDEXES = (byte) 0x84; 169 170 171 172 /** 173 * The BER type for the element that specifies the short-circuit threshold to 174 * use when performing index processing that is expected to be very fast 175 * (e.g., filter components that can be evaluated with a single index lookup, 176 * like presence, equality, and approximate match components). 177 */ 178 private static final byte TYPE_FAST_SHORT_CIRCUIT_THRESHOLD = (byte) 0x85; 179 180 181 182 /** 183 * The BER type for the element that specifies the short-circuit threshold to 184 * use when evaluating filter components that are not covered by the fast 185 * short-circuit threshold. 186 */ 187 private static final byte TYPE_SLOW_SHORT_CIRCUIT_THRESHOLD = (byte) 0x86; 188 189 190 191 /** 192 * The serial version UID for this serializable class. 193 */ 194 private static final long serialVersionUID = 7981532783303485308L; 195 196 197 198 // Indicates whether the server should internally retrieve and examine 199 // candidate entries to determine whether they would actually be returned to 200 // the client. 201 private final boolean alwaysExamineCandidates; 202 203 // Indicates whether to include debug information in the response control. 204 private final boolean includeDebugInfo; 205 206 // Indicates whether the server should attempt to actually iterate through the 207 // entries in the backend in order to obtain the count if the search criteria 208 // is not indexed. 209 private final boolean processSearchIfUnindexed; 210 211 // Indicates whether the server should skip retrieving the entry ID set for 212 // an exploded index key if the number of matching entries is known. 213 private final boolean skipResolvingExplodedIndexes; 214 215 // The maximum number of candidate entries that should be examined if it is 216 // not possible to obtain an exact count using only information contained in 217 // the server indexes. 218 private final int maxCandidatesToExamine; 219 220 // The short-circuit threshold that the server will use when evaluating filter 221 // components that are not categorized as fast. 222 @Nullable private final Long slowShortCircuitThreshold; 223 224 // The short-circuit threshold that the server will for index processing that 225 // should be very fast. 226 @Nullable private final Long fastShortCircuitThreshold; 227 228 229 230 /** 231 * Creates a new matching entry count request control with the default 232 * settings. The control will be critical, no candidate entries will be 233 * examined, and the search will not be processed if it is unindexed. 234 */ 235 public MatchingEntryCountRequestControl() 236 { 237 this(true, 0, false, false, false); 238 } 239 240 241 242 /** 243 * Creates a new matching entry count request control with the provided 244 * information. 245 * 246 * @param isCritical Indicates whether this control should be 247 * critical. 248 * @param maxCandidatesToExamine The maximum number of candidate entries 249 * that the server should retrieve and 250 * examine to determine whether they 251 * actually match the search criteria. If 252 * the search is partially indexed and the 253 * total number of candidate entries is less 254 * than or equal to this value, then these 255 * candidate entries will be examined to 256 * determine which of them match the search 257 * criteria so that an accurate count can 258 * be determined. If the search is fully 259 * indexed such that the all candidate 260 * entries are known to match the search 261 * criteria, then the server may still 262 * examine each of these entries if the 263 * number of candidates is less than 264 * {@code maxCandidatesToExamine} and 265 * {@code alwaysExamineCandidates} is true 266 * in order to allow the entry count that 267 * is returned to be restricted to only 268 * those entries that would actually be 269 * returned to the client. This will be 270 * ignored for searches that are completely 271 * unindexed. 272 * <BR><BR> 273 * The value for this argument must be 274 * greater than or equal to zero. If it 275 * is zero, then the server will not 276 * examine any entries, so a 277 * partially-indexed search will only be 278 * able to return a count that is an upper 279 * bound, and a fully-indexed search will 280 * only be able to return an unexamined 281 * exact count. If there should be no bound 282 * on the number of entries to retrieve, 283 * then a value of {@code Integer.MAX_VALUE} 284 * may be specified. 285 * @param alwaysExamineCandidates Indicates whether the server should 286 * always examine candidate entries to 287 * determine whether they would actually 288 * be returned to the client in a normal 289 * search. This will only be used for 290 * fully-indexed searches in which the 291 * set of matching entries is known. If the 292 * value is {@code true} and the number of 293 * candidates is smaller than 294 * {@code maxCandidatesToExamine}, then each 295 * matching entry will be internally 296 * retrieved and examined to determine 297 * whether it would be returned to the 298 * client based on the details of the search 299 * request (e.g., whether the requester has 300 * permission to access the entry, whether 301 * it's an LDAP subentry, replication 302 * conflict entry, soft-deleted entry, or 303 * other type of entry that is normally 304 * hidden) so that an exact count can be 305 * returned. If this is {@code false} or 306 * the number of candidates exceeds 307 * {@code maxCandidatesToExamine}, then the 308 * server will only be able to return an 309 * unexamined count which may include 310 * entries that match the search criteria 311 * but that would not normally be returned 312 * to the requester. 313 * @param processSearchIfUnindexed Indicates whether the server should 314 * attempt to determine the number of 315 * matching entries if the search criteria 316 * is completely unindexed. If this is 317 * {@code true} and the requester has the 318 * unindexed-search privilege, then the 319 * server will iterate through all entries 320 * in the scope (which may take a very long 321 * time to complete) in order to to 322 * determine which of them match the search 323 * criteria so that it can return an 324 * accurate count. If this is 325 * {@code false} or the requester does not 326 * have the unindexed-search privilege, then 327 * the server will not spend any time 328 * attempting to determine the number of 329 * matching entries and will instead return 330 * a matching entry count response control 331 * indicating that the entry count is 332 * unknown. 333 * @param includeDebugInfo Indicates whether the server should 334 * include debug information in the response 335 * that may help better understand how it 336 * arrived at the result. If any debug 337 * information is returned, it will be in 338 * the form of human-readable text that is 339 * not intended to be machine-parsable. 340 */ 341 public MatchingEntryCountRequestControl(final boolean isCritical, 342 final int maxCandidatesToExamine, 343 final boolean alwaysExamineCandidates, 344 final boolean processSearchIfUnindexed, 345 final boolean includeDebugInfo) 346 { 347 this(isCritical, maxCandidatesToExamine, alwaysExamineCandidates, 348 processSearchIfUnindexed, false, null, null, includeDebugInfo); 349 } 350 351 352 353 /** 354 * Creates a new matching entry count request control with the provided 355 * information. 356 * 357 * @param isCritical Indicates whether this control should 358 * be critical. 359 * @param maxCandidatesToExamine The maximum number of candidate 360 * entries that the server should 361 * retrieve and examine to determine 362 * whether they actually match the 363 * search criteria. If the search is 364 * partially indexed and the total 365 * number of candidate entries is less 366 * than or equal to this value, then 367 * these candidate entries will be 368 * examined to determine which of them 369 * match the search criteria so that an 370 * accurate count can be determined. If 371 * the search is fully indexed such that 372 * the all candidate entries are known 373 * to match the search criteria, then 374 * the server may still examine each of 375 * these entries if the number of 376 * candidates is less than 377 * {@code maxCandidatesToExamine} and 378 * {@code alwaysExamineCandidates} is 379 * true in order to allow the entry 380 * count that is returned to be 381 * restricted to only those entries that 382 * would actually be returned to the 383 * client. This will be ignored for 384 * searches that are completely 385 * unindexed. 386 * <BR><BR> 387 * The value for this argument must be 388 * greater than or equal to zero. If it 389 * is zero, then the server will not 390 * examine any entries, so a 391 * partially-indexed search will only be 392 * able to return a count that is an 393 * upper bound, and a fully-indexed 394 * search will only be able to return an 395 * unexamined exact count. If there 396 * should be no bound on the number of 397 * entries to retrieve, then a value of 398 * {@code Integer.MAX_VALUE} may be 399 * specified. 400 * @param alwaysExamineCandidates Indicates whether the server should 401 * always examine candidate entries to 402 * determine whether they would actually 403 * be returned to the client in a normal 404 * search. This will only be used for 405 * fully-indexed searches in which the 406 * set of matching entries is known. If 407 * the value is {@code true} and the 408 * number of candidates is smaller than 409 * {@code maxCandidatesToExamine}, then 410 * each matching entry will be 411 * internally retrieved and examined to 412 * determine whether it would be 413 * returned to the client based on the 414 * details of the search request (e.g., 415 * whether the requester has permission 416 * to access the entry, whether it's an 417 * LDAP subentry, replication conflict 418 * entry, soft-deleted entry, or other 419 * type of entry that is normally 420 * hidden) so that an exact count can be 421 * returned. If this is {@code false} 422 * or the number of candidates exceeds 423 * {@code maxCandidatesToExamine}, then 424 * the server will only be able to 425 * return an unexamined count which may 426 * include entries that match the search 427 * criteria but that would not normally 428 * be returned to the requester. 429 * @param processSearchIfUnindexed Indicates whether the server should 430 * attempt to determine the number of 431 * matching entries if the search 432 * criteria is completely unindexed. If 433 * this is {@code true} and the 434 * requester has the unindexed-search 435 * privilege, then the server will 436 * iterate through all entries in the 437 * scope (which may take a very long 438 * time to complete) in order to to 439 * determine which of them match the 440 * search criteria so that it can return 441 * an accurate count. If this is 442 * {@code false} or the requester does 443 * not have the unindexed-search 444 * privilege, then the server will not 445 * spend any time attempting to 446 * determine the number of matching 447 * entries and will instead return a 448 * matching entry count response control 449 * indicating that the entry count is 450 * unknown. 451 * @param skipResolvingExplodedIndexes Indicates whether the server should 452 * skip the effort of actually 453 * retrieving the candidate entry IDs 454 * for exploded index keys in which the 455 * number of matching entries is known. 456 * Skipping the process of retrieving 457 * the candidate entry IDs can allow the 458 * server to more quickly estimate the 459 * matching entry count, but the 460 * resulting estimate may be less 461 * accurate. 462 * @param fastShortCircuitThreshold Specifies the short-circuit threshold 463 * that the server should use when 464 * determining whether to continue with 465 * index processing in an attempt to 466 * further pare down a candidate set 467 * that already has a defined superset 468 * of the entries that actually match 469 * the filter. Short-circuiting may 470 * allow the server to skip 471 * potentially-costly index processing 472 * and allow it to obtain the matching 473 * entry count estimate faster, but the 474 * resulting estimate may be less 475 * accurate. The fast short-circuit 476 * threshold will be used for index 477 * processing that is expected to be 478 * very fast (e.g., when performing 479 * index lookups for presence, equality, 480 * and approximate-match components, 481 * which should only require accessing a 482 * single index key). A value that is 483 * less than or equal to zero indicates 484 * that the server should never short 485 * circuit when performing fast index 486 * processing. A value of {@code null} 487 * indicates that the server should 488 * determine the appropriate fast 489 * short-circuit threshold to use. 490 * @param slowShortCircuitThreshold Specifies the short-circuit threshold 491 * that the server should use when 492 * determining whether to continue with 493 * index processing for evaluation that 494 * may be more expensive than what falls 495 * into the "fast" category (e.g., 496 * substring and range filter 497 * components). A value that is less 498 * than or equal to zero indicates that 499 * the server should never short circuit 500 * when performing slow index 501 * processing. A value of {@code null} 502 * indicates that the server should 503 * determine the appropriate fast 504 * short-circuit threshold to use. 505 * @param includeDebugInfo Indicates whether the server should 506 * include debug information in the 507 * response that may help better 508 * understand how it arrived at the 509 * result. If any debug information is 510 * returned, it will be in the form of 511 * human-readable text that is not 512 * intended to be machine-parsable. 513 */ 514 public MatchingEntryCountRequestControl(final boolean isCritical, 515 final int maxCandidatesToExamine, 516 final boolean alwaysExamineCandidates, 517 final boolean processSearchIfUnindexed, 518 final boolean skipResolvingExplodedIndexes, 519 @Nullable final Long fastShortCircuitThreshold, 520 @Nullable final Long slowShortCircuitThreshold, 521 final boolean includeDebugInfo) 522 { 523 super(MATCHING_ENTRY_COUNT_REQUEST_OID, isCritical, 524 encodeValue(maxCandidatesToExamine, alwaysExamineCandidates, 525 processSearchIfUnindexed, skipResolvingExplodedIndexes, 526 fastShortCircuitThreshold, slowShortCircuitThreshold, 527 includeDebugInfo)); 528 529 Validator.ensureTrue(maxCandidatesToExamine >= 0); 530 531 this.maxCandidatesToExamine = maxCandidatesToExamine; 532 this.alwaysExamineCandidates = alwaysExamineCandidates; 533 this.processSearchIfUnindexed = processSearchIfUnindexed; 534 this.skipResolvingExplodedIndexes = skipResolvingExplodedIndexes; 535 this.includeDebugInfo = includeDebugInfo; 536 537 if (fastShortCircuitThreshold == null) 538 { 539 this.fastShortCircuitThreshold = null; 540 } 541 else 542 { 543 this.fastShortCircuitThreshold = Math.max(0L, fastShortCircuitThreshold); 544 } 545 546 if (slowShortCircuitThreshold == null) 547 { 548 this.slowShortCircuitThreshold = null; 549 } 550 else 551 { 552 this.slowShortCircuitThreshold = Math.max(0L, slowShortCircuitThreshold); 553 } 554 } 555 556 557 558 /** 559 * Creates a new matching entry count request control that is decoded from the 560 * provided generic control. 561 * 562 * @param control The control to decode as a matching entry count request 563 * control. 564 * 565 * @throws LDAPException If the provided control cannot be decoded as a 566 * matching entry count request control. 567 */ 568 public MatchingEntryCountRequestControl(@NotNull final Control control) 569 throws LDAPException 570 { 571 super(control); 572 573 final ASN1OctetString value = control.getValue(); 574 if (value == null) 575 { 576 throw new LDAPException(ResultCode.DECODING_ERROR, 577 ERR_MATCHING_ENTRY_COUNT_REQUEST_MISSING_VALUE.get()); 578 } 579 580 try 581 { 582 boolean alwaysExamine = false; 583 boolean debug = false; 584 boolean processUnindexed = false; 585 boolean skipExploded = false; 586 int maxCandidates = 0; 587 Long fastSCThreshold = null; 588 Long slowSCThreshold = null; 589 final ASN1Element[] elements = 590 ASN1Sequence.decodeAsSequence(value.getValue()).elements(); 591 for (final ASN1Element e : elements) 592 { 593 switch (e.getType()) 594 { 595 case TYPE_MAX_CANDIDATES_TO_EXAMINE: 596 maxCandidates = ASN1Integer.decodeAsInteger(e).intValue(); 597 if (maxCandidates < 0) 598 { 599 throw new LDAPException(ResultCode.DECODING_ERROR, 600 ERR_MATCHING_ENTRY_COUNT_REQUEST_INVALID_MAX.get()); 601 } 602 break; 603 604 case TYPE_ALWAYS_EXAMINE_CANDIDATES: 605 alwaysExamine = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 606 break; 607 608 case TYPE_PROCESS_SEARCH_IF_UNINDEXED: 609 processUnindexed = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 610 break; 611 612 case TYPE_INCLUDE_DEBUG_INFO: 613 debug = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 614 break; 615 616 case TYPE_SKIP_RESOLVING_EXPLODED_INDEXES: 617 skipExploded = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 618 break; 619 620 case TYPE_FAST_SHORT_CIRCUIT_THRESHOLD: 621 fastSCThreshold = 622 Math.max(0L, ASN1Long.decodeAsLong(e).longValue()); 623 break; 624 625 case TYPE_SLOW_SHORT_CIRCUIT_THRESHOLD: 626 slowSCThreshold = 627 Math.max(0L, ASN1Long.decodeAsLong(e).longValue()); 628 break; 629 630 default: 631 throw new LDAPException(ResultCode.DECODING_ERROR, 632 ERR_MATCHING_ENTRY_COUNT_REQUEST_INVALID_ELEMENT_TYPE.get( 633 StaticUtils.toHex(e.getType()))); 634 } 635 } 636 637 maxCandidatesToExamine = maxCandidates; 638 alwaysExamineCandidates = alwaysExamine; 639 processSearchIfUnindexed = processUnindexed; 640 includeDebugInfo = debug; 641 skipResolvingExplodedIndexes = skipExploded; 642 fastShortCircuitThreshold = fastSCThreshold; 643 slowShortCircuitThreshold = slowSCThreshold; 644 } 645 catch (final LDAPException le) 646 { 647 Debug.debugException(le); 648 throw le; 649 } 650 catch (final Exception e) 651 { 652 Debug.debugException(e); 653 throw new LDAPException(ResultCode.DECODING_ERROR, 654 ERR_MATCHING_ENTRY_COUNT_REQUEST_CANNOT_DECODE.get( 655 StaticUtils.getExceptionMessage(e)), 656 e); 657 } 658 } 659 660 661 662 /** 663 * Encodes the provided information into an ASN.1 octet string suitable for 664 * use as the control value. 665 * 666 * @param maxCandidatesToExamine The maximum number of candidate 667 * entries that the server should 668 * retrieve and examine to determine 669 * whether they actually match the 670 * search criteria. 671 * @param alwaysExamineCandidates Indicates whether the server should 672 * always examine candidate entries to 673 * determine whether they would actually 674 * be returned to the client in a normal 675 * search with the same criteria. 676 * @param processSearchIfUnindexed Indicates whether the server should 677 * attempt to determine the number of 678 * matching entries if the search 679 * criteria is completely unindexed. 680 * @param skipResolvingExplodedIndexes Indicates whether the server should 681 * skip the effort of actually 682 * retrieving the candidate entry IDs 683 * for exploded index keys in which the 684 * number of matching entries is known. 685 * @param fastShortCircuitThreshold Specifies the short-circuit threshold 686 * that the server should use when 687 * determining whether to continue with 688 * index processing for fast index 689 * processing. 690 * @param slowShortCircuitThreshold Specifies the short-circuit threshold 691 * that the server should use when 692 * determining whether to continue with 693 * index processing for slow index 694 * processing. 695 * @param includeDebugInfo Indicates whether the server should 696 * include debug information in the 697 * response that may help better 698 * understand how it arrived at the 699 * result. 700 * 701 * @return The ASN.1 octet string containing the encoded control value. 702 */ 703 @NotNull() 704 private static ASN1OctetString encodeValue( 705 final int maxCandidatesToExamine, 706 final boolean alwaysExamineCandidates, 707 final boolean processSearchIfUnindexed, 708 final boolean skipResolvingExplodedIndexes, 709 @Nullable final Long fastShortCircuitThreshold, 710 @Nullable final Long slowShortCircuitThreshold, 711 final boolean includeDebugInfo) 712 { 713 final ArrayList<ASN1Element> elements = new ArrayList<>(4); 714 715 if (maxCandidatesToExamine > 0) 716 { 717 elements.add(new ASN1Integer(TYPE_MAX_CANDIDATES_TO_EXAMINE, 718 maxCandidatesToExamine)); 719 } 720 721 if (alwaysExamineCandidates) 722 { 723 elements.add(new ASN1Boolean(TYPE_ALWAYS_EXAMINE_CANDIDATES, true)); 724 } 725 726 if (processSearchIfUnindexed) 727 { 728 elements.add(new ASN1Boolean(TYPE_PROCESS_SEARCH_IF_UNINDEXED, true)); 729 } 730 731 if (includeDebugInfo) 732 { 733 elements.add(new ASN1Boolean(TYPE_INCLUDE_DEBUG_INFO, true)); 734 } 735 736 if (skipResolvingExplodedIndexes) 737 { 738 elements.add(new ASN1Boolean(TYPE_SKIP_RESOLVING_EXPLODED_INDEXES, true)); 739 } 740 741 if (fastShortCircuitThreshold != null) 742 { 743 elements.add(new ASN1Long(TYPE_FAST_SHORT_CIRCUIT_THRESHOLD, 744 Math.max(0L, fastShortCircuitThreshold))); 745 } 746 747 if (slowShortCircuitThreshold != null) 748 { 749 elements.add(new ASN1Long(TYPE_SLOW_SHORT_CIRCUIT_THRESHOLD, 750 Math.max(0L, slowShortCircuitThreshold))); 751 } 752 753 return new ASN1OctetString(new ASN1Sequence(elements).encode()); 754 } 755 756 757 758 /** 759 * Retrieves the maximum number of candidate entries that should be examined 760 * in order to determine accurate count of the number of matching entries. 761 * <BR><BR> 762 * For a fully-indexed search, this property will only be used if 763 * {@link #alwaysExamineCandidates} is true. If the number of candidate 764 * entries identified is less than the maximum number of candidates to 765 * examine, then the server will return an {@code EXAMINED_COUNT} result that 766 * indicates the number of entries matching the criteria that would actually 767 * be returned in a normal search with the same criteria. If the number of 768 * candidate entries exceeds the maximum number of candidates to examine, then 769 * the server will return an {@code UNEXAMINED_COUNT} result that indicates 770 * the number of entries matching the search criteria but that may include 771 * entries that would not actually be returned to the client. 772 * <BR><BR> 773 * For a partially-indexed search, if the upper bound on the number of 774 * candidates is less than or equal to the maximum number of candidates to 775 * examine, then the server will internally retrieve and examine each of those 776 * candidates to determine which of them match the search criteria and would 777 * actually be returned to the client, and will then return an 778 * {@code EXAMINED_COUNT} result with that count. If the upper bound on the 779 * number of candidates is greater than the maximum number of candidates to 780 * examine, then the server will return an {@code UPPER_BOUND} result to 781 * indicate that the exact count is not known but an upper bound is available. 782 * 783 * @return The maximum number of candidate entries to examine in order to 784 * determine an accurate count of the number of matching entries. 785 */ 786 public int getMaxCandidatesToExamine() 787 { 788 return maxCandidatesToExamine; 789 } 790 791 792 793 /** 794 * Indicates whether the server should always examine candidate entries in 795 * fully-indexed searches to determine whether they would actually be returned 796 * to the client in a normal search with the same criteria. 797 * 798 * @return {@code true} if the server should attempt to internally retrieve 799 * and examine matching entries to determine whether they would 800 * normally be returned to the client (i.e.., that the client has 801 * permission to access the entry and that it is not a 802 * normally-hidden entry like an LDAP subentry, a replication 803 * conflict entry, or a soft-deleted entry), or {@code false} if the 804 * server should return an unverified count. 805 */ 806 public boolean alwaysExamineCandidates() 807 { 808 return alwaysExamineCandidates; 809 } 810 811 812 813 /** 814 * Indicates whether the server should internally retrieve and examine all 815 * entries within the search scope in order to obtain an exact matching entry 816 * count for an unindexed search. Note that this value will not be considered 817 * for completely-indexed or partially-indexed searches, nor for searches in 818 * which matching entries should be returned. 819 * 820 * @return {@code true} if the server should internally retrieve and examine 821 * all entries within the search scope in order to obtain an exact 822 * matching entry count for an unindexed search, or {@code false} if 823 * not. 824 */ 825 public boolean processSearchIfUnindexed() 826 { 827 return processSearchIfUnindexed; 828 } 829 830 831 832 /** 833 * Indicates whether the server should skip the effort of actually retrieving 834 * the candidate entry IDs for exploded index keys in which the number of 835 * matching entries is known. Skipping the process of accessing an exploded 836 * index can allow the server to more quickly arrive at the matching entry 837 * count estimate, but that estimate may be less accurate than if it had 838 * actually retrieved those candidates. 839 * 840 * @return {@code true} if the server should skip the effort of actually 841 * retrieving the candidate entry IDs for exploded index keys in 842 * which the number of matching entries is known, or {@code false} if 843 * it may retrieve candidates from an exploded index in the course of 844 * determining the matching entry count. 845 */ 846 public boolean skipResolvingExplodedIndexes() 847 { 848 return skipResolvingExplodedIndexes; 849 } 850 851 852 853 /** 854 * Retrieves the short-circuit threshold that the server should use when 855 * determining whether to continue with index processing in an attempt to 856 * further pare down a candidate set that already has a defined superset of 857 * the entries that actually match the filter. If the number of entries in 858 * that candidate set is less than or equal to the short-circuit threshold, 859 * then the server may simply use that candidate set in the course of 860 * determining the matching entry count, even if there may be additional 861 * processing that can be performed (e.g., further filter components to 862 * evaluate) that may allow the server to pare down the results even further. 863 * Short-circuiting may allow the server to obtain the matching entry count 864 * estimate faster, but may also cause the resulting estimate to be less 865 * accurate. 866 * <BR><BR> 867 * The value returned by this method will be used for cases in which the 868 * server is performing the fastest types of index processing. For example, 869 * this may include evaluating presence, equality, or approximate match 870 * components, which should only require retrieving a single index key to 871 * obtain the candidate set. 872 * 873 * @return The short-circuit threshold that should be used for fast index 874 * processing, zero if the server should not short-circuit at all 875 * during fast index processing, or {@code null} if the server should 876 * determine the appropriate fast short-circuit threshold to use. 877 */ 878 @Nullable() 879 public Long getFastShortCircuitThreshold() 880 { 881 return fastShortCircuitThreshold; 882 } 883 884 885 886 /** 887 * Retrieves the short-circuit threshold that the server should use when 888 * determining whether to continue with index processing in an attempt to 889 * further pare down a candidate set that already has a defined superset of 890 * the entries that actually match the filter. If the number of entries in 891 * that candidate set is less than or equal to the short-circuit threshold, 892 * then the server may simply use that candidate set in the course of 893 * determining the matching entry count, even if there may be additional 894 * processing that can be performed (e.g., further filter components to 895 * evaluate) that may allow the server to pare down the results even further. 896 * Short-circuiting may allow the server to obtain the matching entry count 897 * estimate faster, but may also cause the resulting estimate to be less 898 * accurate. 899 * <BR><BR> 900 * The value returned by this method will be used for cases in which the 901 * server is performing index processing that is not considered to be among 902 * the fastest types of processing. For example, this may include evaluating 903 * substring and range components, as they may require retrieving many index 904 * keys to obtain the full candidate set. 905 * 906 * @return The short-circuit threshold that should be used for slow index 907 * processing, or zero if the server should not short-circuit at all 908 * during slow index processing, or {@code null} if the server should 909 * determine the appropriate slow short-circuit threshold to use. 910 */ 911 @Nullable() 912 public Long getSlowShortCircuitThreshold() 913 { 914 return slowShortCircuitThreshold; 915 } 916 917 918 919 /** 920 * Indicates whether the server should include debug information in the 921 * response control that provides additional information about how the server 922 * arrived at the result. If debug information is to be provided, it will be 923 * in a human-readable rather than machine-parsable form. 924 * 925 * @return {@code true} if the server should include debug information in 926 * the response control, or {@code false} if not. 927 */ 928 public boolean includeDebugInfo() 929 { 930 return includeDebugInfo; 931 } 932 933 934 935 /** 936 * {@inheritDoc} 937 */ 938 @Override() 939 @NotNull() 940 public String getControlName() 941 { 942 return INFO_CONTROL_NAME_MATCHING_ENTRY_COUNT_REQUEST.get(); 943 } 944 945 946 947 /** 948 * {@inheritDoc} 949 */ 950 @Override() 951 public void toString(@NotNull final StringBuilder buffer) 952 { 953 buffer.append("MatchingEntryCountRequestControl(isCritical="); 954 buffer.append(isCritical()); 955 buffer.append(", maxCandidatesToExamine="); 956 buffer.append(maxCandidatesToExamine); 957 buffer.append(", alwaysExamineCandidates="); 958 buffer.append(alwaysExamineCandidates); 959 buffer.append(", processSearchIfUnindexed="); 960 buffer.append(processSearchIfUnindexed); 961 buffer.append(", skipResolvingExplodedIndexes="); 962 buffer.append(skipResolvingExplodedIndexes); 963 buffer.append(", fastShortCircuitThreshold="); 964 buffer.append(fastShortCircuitThreshold); 965 buffer.append(", slowShortCircuitThreshold="); 966 buffer.append(slowShortCircuitThreshold); 967 buffer.append(", includeDebugInfo="); 968 buffer.append(includeDebugInfo); 969 buffer.append(')'); 970 } 971}