001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.regionserver; 019 020import java.util.List; 021import org.apache.hadoop.hbase.Cell; 022import org.apache.hadoop.hbase.HBaseInterfaceAudience; 023import org.apache.hadoop.hbase.client.metrics.ServerSideScanMetrics; 024import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 025import org.apache.yetus.audience.InterfaceAudience; 026import org.apache.yetus.audience.InterfaceStability; 027 028/** 029 * ScannerContext instances encapsulate limit tracking AND progress towards those limits during 030 * invocations of {@link InternalScanner#next(java.util.List)} and 031 * {@link RegionScanner#next(java.util.List)}. 032 * <p> 033 * A ScannerContext instance should be updated periodically throughout execution whenever progress 034 * towards a limit has been made. Each limit can be checked via the appropriate checkLimit method. 035 * <p> 036 * Once a limit has been reached, the scan will stop. The invoker of 037 * {@link InternalScanner#next(java.util.List)} or {@link RegionScanner#next(java.util.List)} can 038 * use the appropriate check*Limit methods to see exactly which limits have been reached. 039 * Alternatively, {@link #checkAnyLimitReached(LimitScope)} is provided to see if ANY limit was 040 * reached 041 * <p> 042 * {@link NoLimitScannerContext#NO_LIMIT} is an immutable static definition that can be used 043 * whenever a {@link ScannerContext} is needed but limits do not need to be enforced. 044 * <p> 045 * NOTE: It is important that this class only ever expose setter methods that can be safely skipped 046 * when limits should be NOT enforced. This is because of the necessary immutability of the class 047 * {@link NoLimitScannerContext}. If a setter cannot be safely skipped, the immutable nature of 048 * {@link NoLimitScannerContext} will lead to incorrect behavior. 049 */ 050@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.COPROC) 051@InterfaceStability.Evolving 052public class ScannerContext { 053 054 LimitFields limits; 055 /** 056 * A different set of progress fields. Only include batch, dataSize and heapSize. Compare to 057 * LimitFields, ProgressFields doesn't contain time field. As we save a deadline in LimitFields, 058 * so use {@link EnvironmentEdgeManager#currentTime()} directly when check time limit. 059 */ 060 ProgressFields progress; 061 062 /** 063 * The state of the scanner after the invocation of {@link InternalScanner#next(java.util.List)} 064 * or {@link RegionScanner#next(java.util.List)}. 065 */ 066 NextState scannerState; 067 private static final NextState DEFAULT_STATE = NextState.MORE_VALUES; 068 069 /** 070 * Used as an indication to invocations of {@link InternalScanner#next(java.util.List)} and 071 * {@link RegionScanner#next(java.util.List)} that, if true, the progress tracked within this 072 * {@link ScannerContext} instance should be considered while evaluating the limits. Useful for 073 * enforcing a set of limits across multiple calls (i.e. the limit may not be reached in a single 074 * invocation, but any progress made should be considered in future invocations) 075 * <p> 076 * Defaulting this value to false means that, by default, any tracked progress will be wiped clean 077 * on invocations to {@link InternalScanner#next(java.util.List)} and 078 * {@link RegionScanner#next(java.util.List)} and the call will be treated as though no progress 079 * has been made towards the limits so far. 080 * <p> 081 * This is an important mechanism. Users of Internal/Region scanners expect that they can define 082 * some limits and then repeatedly invoke {@link InternalScanner#next(List)} or 083 * {@link RegionScanner#next(List)} where each invocation respects these limits separately. 084 * <p> 085 * For example: 086 * 087 * <pre> 088 * {@code 089 * ScannerContext context = new ScannerContext.newBuilder().setBatchLimit(5).build(); 090 * RegionScanner scanner = ... 091 * List<Cell> results = new ArrayList<Cell>(); 092 * while(scanner.next(results, context)) { 093 * // Do something with a batch of 5 cells 094 * } 095 * } 096 * </pre> 097 * 098 * However, in the case of RPCs, the server wants to be able to define a set of limits for a 099 * particular RPC request and have those limits respected across multiple invocations. This means 100 * that the progress made towards the limits in earlier calls will be saved and considered in 101 * future invocations 102 */ 103 boolean keepProgress; 104 private static boolean DEFAULT_KEEP_PROGRESS = false; 105 106 /** 107 * Allows temporarily ignoring limits and skipping tracking of batch and size progress. Used when 108 * skipping to the next row, in which case all processed cells are thrown away so should not count 109 * towards progress. 110 */ 111 boolean skippingRow = false; 112 113 private Cell lastPeekedCell = null; 114 115 // Set this to true will have the same behavior with reaching the time limit. 116 // This is used when you want to make the current RSRpcService.scan returns immediately. For 117 // example, when we want to switch from pread to stream, we can only do it after the rpc call is 118 // returned. 119 private boolean returnImmediately; 120 121 /** 122 * Tracks the relevant server side metrics during scans. null when metrics should not be tracked 123 */ 124 final ServerSideScanMetrics metrics; 125 126 ScannerContext(boolean keepProgress, LimitFields limitsToCopy, boolean trackMetrics) { 127 this(keepProgress, limitsToCopy, trackMetrics, null); 128 } 129 130 ScannerContext(boolean keepProgress, LimitFields limitsToCopy, boolean trackMetrics, 131 ServerSideScanMetrics scanMetrics) { 132 this.limits = new LimitFields(); 133 if (limitsToCopy != null) { 134 this.limits.copy(limitsToCopy); 135 } 136 137 // Progress fields are initialized to 0 138 progress = new ProgressFields(0, 0, 0, 0); 139 140 this.keepProgress = keepProgress; 141 this.scannerState = DEFAULT_STATE; 142 this.metrics = 143 trackMetrics ? (scanMetrics != null ? scanMetrics : new ServerSideScanMetrics()) : null; 144 } 145 146 public boolean isTrackingMetrics() { 147 return this.metrics != null; 148 } 149 150 /** 151 * Get the metrics instance. Should only be called after a call to {@link #isTrackingMetrics()} 152 * has been made to confirm that metrics are indeed being tracked. 153 * @return {@link ServerSideScanMetrics} instance that is tracking metrics for this scan 154 */ 155 public ServerSideScanMetrics getMetrics() { 156 assert isTrackingMetrics(); 157 return this.metrics; 158 } 159 160 /** 161 * @return true if the progress tracked so far in this instance will be considered during an 162 * invocation of {@link InternalScanner#next(java.util.List)} or 163 * {@link RegionScanner#next(java.util.List)}. false when the progress tracked so far 164 * should not be considered and should instead be wiped away via {@link #clearProgress()}. 165 * This only applies to per-row progress, like batch and data/heap size. Block size is 166 * never reset because it tracks all of the blocks scanned for an entire request. 167 */ 168 boolean getKeepProgress() { 169 return keepProgress; 170 } 171 172 void setKeepProgress(boolean keepProgress) { 173 this.keepProgress = keepProgress; 174 } 175 176 /** 177 * In this mode, only block size progress is tracked, and limits are ignored. We set this mode 178 * when skipping to next row, in which case all cells returned a thrown away so should not count 179 * towards progress. 180 * @return true if we are in skipping row mode. 181 */ 182 public boolean getSkippingRow() { 183 return skippingRow; 184 } 185 186 /** 187 * @param skippingRow set true to cause disabling of collecting per-cell progress or enforcing any 188 * limits. This is used when trying to skip over all cells in a row, in which 189 * case those cells are thrown away so should not count towards progress. 190 */ 191 void setSkippingRow(boolean skippingRow) { 192 this.skippingRow = skippingRow; 193 } 194 195 /** 196 * Progress towards the batch limit has been made. Increment internal tracking of batch progress 197 */ 198 void incrementBatchProgress(int batch) { 199 if (skippingRow) { 200 return; 201 } 202 int currentBatch = progress.getBatch(); 203 progress.setBatch(currentBatch + batch); 204 } 205 206 /** 207 * Progress towards the size limit has been made. Increment internal tracking of size progress 208 */ 209 void incrementSizeProgress(long dataSize, long heapSize) { 210 if (skippingRow) { 211 return; 212 } 213 long curDataSize = progress.getDataSize(); 214 progress.setDataSize(curDataSize + dataSize); 215 long curHeapSize = progress.getHeapSize(); 216 progress.setHeapSize(curHeapSize + heapSize); 217 } 218 219 /** 220 * Progress towards the block limit has been made. Increment internal track of block progress 221 */ 222 void incrementBlockProgress(int blockSize) { 223 if (blockSize > 0) { 224 long curBlockSize = progress.getBlockSize(); 225 progress.setBlockSize(curBlockSize + blockSize); 226 } 227 } 228 229 int getBatchProgress() { 230 return progress.getBatch(); 231 } 232 233 long getDataSizeProgress() { 234 return progress.getDataSize(); 235 } 236 237 long getHeapSizeProgress() { 238 return progress.getHeapSize(); 239 } 240 241 long getBlockSizeProgress() { 242 return progress.getBlockSize(); 243 } 244 245 void setProgress(int batchProgress, long sizeProgress, long heapSizeProgress) { 246 setBatchProgress(batchProgress); 247 setSizeProgress(sizeProgress, heapSizeProgress); 248 } 249 250 void setSizeProgress(long dataSizeProgress, long heapSizeProgress) { 251 progress.setDataSize(dataSizeProgress); 252 progress.setHeapSize(heapSizeProgress); 253 } 254 255 void setBatchProgress(int batchProgress) { 256 progress.setBatch(batchProgress); 257 } 258 259 /** 260 * Clear away any progress that has been made so far. All progress fields are reset to initial 261 * values. Only clears progress that should reset between rows. {@link #getBlockSizeProgress()} is 262 * not reset because it increments for all blocks scanned whether the result is included or 263 * filtered. 264 */ 265 void clearProgress() { 266 progress.setFields(0, 0, 0, getBlockSizeProgress()); 267 } 268 269 /** 270 * Note that this is not a typical setter. This setter returns the {@link NextState} that was 271 * passed in so that methods can be invoked against the new state. Furthermore, this pattern 272 * allows the {@link NoLimitScannerContext} to cleanly override this setter and simply return the 273 * new state, thus preserving the immutability of {@link NoLimitScannerContext} 274 * @return The state that was passed in. 275 */ 276 NextState setScannerState(NextState state) { 277 if (!NextState.isValidState(state)) { 278 throw new IllegalArgumentException("Cannot set to invalid state: " + state); 279 } 280 281 this.scannerState = state; 282 return state; 283 } 284 285 /** 286 * @return true when we have more cells for the current row. This usually because we have reached 287 * a limit in the middle of a row 288 */ 289 boolean mayHaveMoreCellsInRow() { 290 return scannerState == NextState.SIZE_LIMIT_REACHED_MID_ROW 291 || scannerState == NextState.TIME_LIMIT_REACHED_MID_ROW 292 || scannerState == NextState.BATCH_LIMIT_REACHED; 293 } 294 295 /** Returns true if the batch limit can be enforced in the checker's scope */ 296 boolean hasBatchLimit(LimitScope checkerScope) { 297 return limits.canEnforceBatchLimitFromScope(checkerScope) && limits.getBatch() > 0; 298 } 299 300 /** Returns true if the size limit can be enforced in the checker's scope */ 301 boolean hasSizeLimit(LimitScope checkerScope) { 302 return limits.canEnforceSizeLimitFromScope(checkerScope) 303 && (limits.getDataSize() > 0 || limits.getHeapSize() > 0 || limits.getBlockSize() > 0); 304 } 305 306 /** Returns true if the time limit can be enforced in the checker's scope */ 307 boolean hasTimeLimit(LimitScope checkerScope) { 308 return limits.canEnforceTimeLimitFromScope(checkerScope) 309 && (limits.getTime() > 0 || returnImmediately); 310 } 311 312 /** Returns true if any limit can be enforced within the checker's scope */ 313 boolean hasAnyLimit(LimitScope checkerScope) { 314 return hasBatchLimit(checkerScope) || hasSizeLimit(checkerScope) || hasTimeLimit(checkerScope); 315 } 316 317 /** 318 * @param scope The scope in which the size limit will be enforced 319 */ 320 void setSizeLimitScope(LimitScope scope) { 321 limits.setSizeScope(scope); 322 } 323 324 /** 325 * @param scope The scope in which the time limit will be enforced 326 */ 327 void setTimeLimitScope(LimitScope scope) { 328 limits.setTimeScope(scope); 329 } 330 331 int getBatchLimit() { 332 return limits.getBatch(); 333 } 334 335 long getDataSizeLimit() { 336 return limits.getDataSize(); 337 } 338 339 long getTimeLimit() { 340 return limits.getTime(); 341 } 342 343 /** 344 * @param checkerScope The scope that the limit is being checked from 345 * @return true when the limit is enforceable from the checker's scope and it has been reached 346 */ 347 boolean checkBatchLimit(LimitScope checkerScope) { 348 return !skippingRow && hasBatchLimit(checkerScope) && progress.getBatch() >= limits.getBatch(); 349 } 350 351 /** 352 * @param checkerScope The scope that the limit is being checked from 353 * @return true when the limit is enforceable from the checker's scope and it has been reached 354 */ 355 boolean checkSizeLimit(LimitScope checkerScope) { 356 return !skippingRow && hasSizeLimit(checkerScope) 357 && (progress.getDataSize() >= limits.getDataSize() 358 || progress.getHeapSize() >= limits.getHeapSize() 359 || progress.getBlockSize() >= limits.getBlockSize()); 360 } 361 362 /** 363 * @param checkerScope The scope that the limit is being checked from. The time limit is always 364 * checked against {@link EnvironmentEdgeManager.currentTime} 365 * @return true when the limit is enforceable from the checker's scope and it has been reached 366 */ 367 boolean checkTimeLimit(LimitScope checkerScope) { 368 return !skippingRow && hasTimeLimit(checkerScope) 369 && (returnImmediately || EnvironmentEdgeManager.currentTime() >= limits.getTime()); 370 } 371 372 /** 373 * @param checkerScope The scope that the limits are being checked from 374 * @return true when some limit is enforceable from the checker's scope and it has been reached 375 */ 376 boolean checkAnyLimitReached(LimitScope checkerScope) { 377 return checkSizeLimit(checkerScope) || checkBatchLimit(checkerScope) 378 || checkTimeLimit(checkerScope); 379 } 380 381 Cell getLastPeekedCell() { 382 return lastPeekedCell; 383 } 384 385 void setLastPeekedCell(Cell lastPeekedCell) { 386 this.lastPeekedCell = lastPeekedCell; 387 } 388 389 void returnImmediately() { 390 this.returnImmediately = true; 391 } 392 393 @Override 394 public String toString() { 395 StringBuilder sb = new StringBuilder(); 396 sb.append("{"); 397 398 sb.append("limits:"); 399 sb.append(limits); 400 401 sb.append(", progress:"); 402 sb.append(progress); 403 404 sb.append(", keepProgress:"); 405 sb.append(keepProgress); 406 407 sb.append(", state:"); 408 sb.append(scannerState); 409 410 sb.append("}"); 411 return sb.toString(); 412 } 413 414 public static Builder newBuilder() { 415 return new Builder(); 416 } 417 418 public static Builder newBuilder(boolean keepProgress) { 419 return new Builder(keepProgress); 420 } 421 422 public static final class Builder { 423 boolean keepProgress = DEFAULT_KEEP_PROGRESS; 424 boolean trackMetrics = false; 425 LimitFields limits = new LimitFields(); 426 ServerSideScanMetrics scanMetrics = null; 427 428 private Builder() { 429 } 430 431 private Builder(boolean keepProgress) { 432 this.keepProgress = keepProgress; 433 } 434 435 public Builder setKeepProgress(boolean keepProgress) { 436 this.keepProgress = keepProgress; 437 return this; 438 } 439 440 public Builder setTrackMetrics(boolean trackMetrics) { 441 this.trackMetrics = trackMetrics; 442 return this; 443 } 444 445 public Builder setSizeLimit(LimitScope sizeScope, long dataSizeLimit, long heapSizeLimit, 446 long blockSizeLimit) { 447 limits.setDataSize(dataSizeLimit); 448 limits.setHeapSize(heapSizeLimit); 449 limits.setSizeScope(sizeScope); 450 limits.setBlockSize(blockSizeLimit); 451 return this; 452 } 453 454 public Builder setTimeLimit(LimitScope timeScope, long timeLimit) { 455 limits.setTime(timeLimit); 456 limits.setTimeScope(timeScope); 457 return this; 458 } 459 460 public Builder setBatchLimit(int batchLimit) { 461 limits.setBatch(batchLimit); 462 return this; 463 } 464 465 public Builder setScanMetrics(ServerSideScanMetrics scanMetrics) { 466 this.scanMetrics = scanMetrics; 467 return this; 468 } 469 470 public ScannerContext build() { 471 return new ScannerContext(keepProgress, limits, trackMetrics, scanMetrics); 472 } 473 } 474 475 /** 476 * The possible states a scanner may be in following a call to {@link InternalScanner#next(List)} 477 */ 478 public enum NextState { 479 MORE_VALUES(true, false), 480 NO_MORE_VALUES(false, false), 481 SIZE_LIMIT_REACHED(true, true), 482 483 /** 484 * Special case of size limit reached to indicate that the size limit was reached in the middle 485 * of a row and thus a partial results was formed 486 */ 487 SIZE_LIMIT_REACHED_MID_ROW(true, true), 488 TIME_LIMIT_REACHED(true, true), 489 490 /** 491 * Special case of time limit reached to indicate that the time limit was reached in the middle 492 * of a row and thus a partial results was formed 493 */ 494 TIME_LIMIT_REACHED_MID_ROW(true, true), 495 BATCH_LIMIT_REACHED(true, true); 496 497 private final boolean moreValues; 498 private final boolean limitReached; 499 500 private NextState(boolean moreValues, boolean limitReached) { 501 this.moreValues = moreValues; 502 this.limitReached = limitReached; 503 } 504 505 /** 506 * @return true when the state indicates that more values may follow those that have been 507 * returned 508 */ 509 public boolean hasMoreValues() { 510 return this.moreValues; 511 } 512 513 /** Returns true when the state indicates that a limit has been reached and scan should stop */ 514 public boolean limitReached() { 515 return this.limitReached; 516 } 517 518 public static boolean isValidState(NextState state) { 519 return state != null; 520 } 521 522 public static boolean hasMoreValues(NextState state) { 523 return isValidState(state) && state.hasMoreValues(); 524 } 525 } 526 527 /** 528 * The various scopes where a limit can be enforced. Used to differentiate when a limit should be 529 * enforced or not. 530 */ 531 public enum LimitScope { 532 /** 533 * Enforcing a limit between rows means that the limit will not be considered until all the 534 * cells for a particular row have been retrieved 535 */ 536 BETWEEN_ROWS(0), 537 538 /** 539 * Enforcing a limit between cells means that the limit will be considered after each full cell 540 * has been retrieved 541 */ 542 BETWEEN_CELLS(1); 543 544 /** 545 * When enforcing a limit, we must check that the scope is appropriate for enforcement. 546 * <p> 547 * To communicate this concept, each scope has a depth. A limit will be enforced if the depth of 548 * the checker's scope is less than or equal to the limit's scope. This means that when checking 549 * limits, the checker must know their own scope (i.e. are they checking the limits between 550 * rows, between cells, etc...) 551 */ 552 final int depth; 553 554 LimitScope(int depth) { 555 this.depth = depth; 556 } 557 558 final int depth() { 559 return depth; 560 } 561 562 /** 563 * @param checkerScope The scope in which the limit is being checked 564 * @return true when the checker is in a scope that indicates the limit can be enforced. Limits 565 * can be enforced from "higher or equal" scopes (i.e. the checker's scope is at a 566 * lesser depth than the limit) 567 */ 568 boolean canEnforceLimitFromScope(LimitScope checkerScope) { 569 return checkerScope != null && checkerScope.depth() <= depth; 570 } 571 } 572 573 /** 574 * The different fields that can be used as limits in calls to 575 * {@link InternalScanner#next(java.util.List)} and {@link RegionScanner#next(java.util.List)} 576 */ 577 private static class LimitFields { 578 /** 579 * Default values of the limit fields. Defined such that if a field does NOT change from its 580 * default, it will not be enforced 581 */ 582 private static int DEFAULT_BATCH = -1; 583 private static long DEFAULT_SIZE = -1L; 584 private static long DEFAULT_TIME = -1L; 585 586 /** 587 * Default scope that is assigned to a limit if a scope is not specified. 588 */ 589 private static final LimitScope DEFAULT_SCOPE = LimitScope.BETWEEN_ROWS; 590 591 // The batch limit will always be enforced between cells, thus, there isn't a field to hold the 592 // batch scope 593 int batch = DEFAULT_BATCH; 594 595 LimitScope sizeScope = DEFAULT_SCOPE; 596 // The sum of cell data sizes(key + value). The Cell data might be in on heap or off heap area. 597 long dataSize = DEFAULT_SIZE; 598 // The sum of heap space occupied by all tracked cells. This includes Cell POJO's overhead as 599 // such AND data cells of Cells which are in on heap area. 600 long heapSize = DEFAULT_SIZE; 601 // The total amount of block bytes that have been loaded in order to process cells for the 602 // request. 603 long blockSize = DEFAULT_SIZE; 604 605 LimitScope timeScope = DEFAULT_SCOPE; 606 long time = DEFAULT_TIME; 607 608 /** 609 * Fields keep their default values. 610 */ 611 LimitFields() { 612 } 613 614 void copy(LimitFields limitsToCopy) { 615 if (limitsToCopy != null) { 616 setFields(limitsToCopy.getBatch(), limitsToCopy.getSizeScope(), limitsToCopy.getDataSize(), 617 limitsToCopy.getHeapSize(), limitsToCopy.getBlockSize(), limitsToCopy.getTimeScope(), 618 limitsToCopy.getTime()); 619 } 620 } 621 622 /** 623 * Set all fields together. 624 */ 625 void setFields(int batch, LimitScope sizeScope, long dataSize, long heapSize, long blockSize, 626 LimitScope timeScope, long time) { 627 setBatch(batch); 628 setSizeScope(sizeScope); 629 setDataSize(dataSize); 630 setHeapSize(heapSize); 631 setBlockSize(blockSize); 632 setTimeScope(timeScope); 633 setTime(time); 634 } 635 636 int getBatch() { 637 return this.batch; 638 } 639 640 void setBatch(int batch) { 641 this.batch = batch; 642 } 643 644 /** Returns true when the limit can be enforced from the scope of the checker */ 645 boolean canEnforceBatchLimitFromScope(LimitScope checkerScope) { 646 return LimitScope.BETWEEN_CELLS.canEnforceLimitFromScope(checkerScope); 647 } 648 649 long getDataSize() { 650 return this.dataSize; 651 } 652 653 long getHeapSize() { 654 return this.heapSize; 655 } 656 657 long getBlockSize() { 658 return this.blockSize; 659 } 660 661 void setDataSize(long dataSize) { 662 this.dataSize = dataSize; 663 } 664 665 void setHeapSize(long heapSize) { 666 this.heapSize = heapSize; 667 } 668 669 void setBlockSize(long blockSize) { 670 this.blockSize = blockSize; 671 } 672 673 /** Returns {@link LimitScope} indicating scope in which the size limit is enforced */ 674 LimitScope getSizeScope() { 675 return this.sizeScope; 676 } 677 678 /** 679 * Change the scope in which the size limit is enforced 680 */ 681 void setSizeScope(LimitScope scope) { 682 this.sizeScope = scope; 683 } 684 685 /** Returns true when the limit can be enforced from the scope of the checker */ 686 boolean canEnforceSizeLimitFromScope(LimitScope checkerScope) { 687 return this.sizeScope.canEnforceLimitFromScope(checkerScope); 688 } 689 690 long getTime() { 691 return this.time; 692 } 693 694 void setTime(long time) { 695 this.time = time; 696 } 697 698 /** Returns {@link LimitScope} indicating scope in which the time limit is enforced */ 699 LimitScope getTimeScope() { 700 return this.timeScope; 701 } 702 703 /** 704 * Change the scope in which the time limit is enforced 705 */ 706 void setTimeScope(LimitScope scope) { 707 this.timeScope = scope; 708 } 709 710 /** Returns true when the limit can be enforced from the scope of the checker */ 711 boolean canEnforceTimeLimitFromScope(LimitScope checkerScope) { 712 return this.timeScope.canEnforceLimitFromScope(checkerScope); 713 } 714 715 @Override 716 public String toString() { 717 StringBuilder sb = new StringBuilder(); 718 sb.append("{"); 719 720 sb.append("batch:"); 721 sb.append(batch); 722 723 sb.append(", dataSize:"); 724 sb.append(dataSize); 725 726 sb.append(", heapSize:"); 727 sb.append(heapSize); 728 729 sb.append(", blockSize:"); 730 sb.append(blockSize); 731 732 sb.append(", sizeScope:"); 733 sb.append(sizeScope); 734 735 sb.append(", time:"); 736 sb.append(time); 737 738 sb.append(", timeScope:"); 739 sb.append(timeScope); 740 741 sb.append("}"); 742 return sb.toString(); 743 } 744 } 745 746 private static class ProgressFields { 747 748 private static int DEFAULT_BATCH = -1; 749 private static long DEFAULT_SIZE = -1L; 750 751 // The batch limit will always be enforced between cells, thus, there isn't a field to hold the 752 // batch scope 753 int batch = DEFAULT_BATCH; 754 755 // The sum of cell data sizes(key + value). The Cell data might be in on heap or off heap area. 756 long dataSize = DEFAULT_SIZE; 757 // The sum of heap space occupied by all tracked cells. This includes Cell POJO's overhead as 758 // such AND data cells of Cells which are in on heap area. 759 long heapSize = DEFAULT_SIZE; 760 // The total amount of block bytes that have been loaded in order to process cells for the 761 // request. 762 long blockSize = DEFAULT_SIZE; 763 764 ProgressFields(int batch, long size, long heapSize, long blockSize) { 765 setFields(batch, size, heapSize, blockSize); 766 } 767 768 /** 769 * Set all fields together. 770 */ 771 void setFields(int batch, long dataSize, long heapSize, long blockSize) { 772 setBatch(batch); 773 setDataSize(dataSize); 774 setHeapSize(heapSize); 775 setBlockSize(blockSize); 776 } 777 778 int getBatch() { 779 return this.batch; 780 } 781 782 void setBatch(int batch) { 783 this.batch = batch; 784 } 785 786 long getDataSize() { 787 return this.dataSize; 788 } 789 790 long getHeapSize() { 791 return this.heapSize; 792 } 793 794 long getBlockSize() { 795 return this.blockSize; 796 } 797 798 void setDataSize(long dataSize) { 799 this.dataSize = dataSize; 800 } 801 802 void setBlockSize(long blockSize) { 803 this.blockSize = blockSize; 804 } 805 806 void setHeapSize(long heapSize) { 807 this.heapSize = heapSize; 808 } 809 810 @Override 811 public String toString() { 812 StringBuilder sb = new StringBuilder(); 813 sb.append("{"); 814 815 sb.append("batch:"); 816 sb.append(batch); 817 818 sb.append(", dataSize:"); 819 sb.append(dataSize); 820 821 sb.append(", heapSize:"); 822 sb.append(heapSize); 823 824 sb.append(", blockSize:"); 825 sb.append(blockSize); 826 827 sb.append("}"); 828 return sb.toString(); 829 } 830 } 831}